package main
import (
+ "context"
"fmt"
"git.vexingworkshop.com/signal9/dead-tooter/pkg/mastodon"
panic(err.Error())
}
+ type appContextKey string
+ appkey := appContextKey("Application")
+ ctx := context.WithValue(context.TODO(), appkey, app)
+
var account mastodon.Account
- code := account.Authorize(app)
- token, err = account.RequestToken(app, code)
+ code, err := account.Authorize(ctx)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ token, err = account.RequestToken(ctx, code)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ type tokenContextKey string
+ tokenkey := tokenContextKey("Token")
+ ctx = context.WithValue(ctx, tokenkey, token)
+
+ err = account.VerifyCredentials(ctx)
if err != nil {
panic(err.Error())
}
- err = account.VerifyCredentials(token)
+ followers, err := account.GetFollowers(ctx)
if err != nil {
panic(err.Error())
}
- fmt.Printf("%+v\n", token)
+ fmt.Printf("%+v", followers)
}
package mastodon
import (
+ "context"
"encoding/json"
"errors"
"fmt"
"os/exec"
)
+// Account represents the basic data structure for accounts handled by the
+// Mastodon API
type Account struct {
ID string `json:"id"`
UserName string `json:"username"`
type Emoji struct {
ShortCode string `json:"shortcode"`
- Url string `json:"url"`
- StaticUrl string `json:"static_url"`
+ URL string `json:"url"`
+ StaticURL string `json:"static_url"`
VisibleInPicker bool `json:"visible_in_picker"`
}
-func (a *Account) Authorize(app Application) (code string) {
+func (a *Account) Authorize(ctx context.Context) (code string, err error) {
+ app := ctx.Value("Application").(Application)
+
v := url.Values{}
v.Set("client_id", app.ClientID)
v.Set("response_type", "code")
}
u.Scheme = "https"
- err := exec.Command("xdg-open", u.String()).Start()
+ err = exec.Command("xdg-open", u.String()).Start()
if err != nil {
- panic(err.Error())
+ return
}
fmt.Print("Enter returned code: ")
_, err = fmt.Scanln(&code)
if err != nil {
- panic(err.Error())
+ return
}
return
}
-func (a *Account) RequestToken(app Application, code string) (token Token, err error) {
+func (a *Account) RequestToken(ctx context.Context, code string) (token Token, err error) {
+ app := ctx.Value("Application").(Application)
+
v := url.Values{}
v.Set("client_id", app.ClientID)
v.Set("client_secret", app.ClientSecret)
return
}
-func (a *Account) VerifyCredentials(token Token) (err error) {
+func (a *Account) VerifyCredentials(ctx context.Context) (err error) {
+ token := ctx.Value("Token").(Token)
client := &http.Client{}
u := url.URL{
return
}
+
+func (a *Account) GetFollowers(ctx context.Context) (followers []Account, err error) {
+ token := ctx.Value("Token").(Token)
+ client := &http.Client{}
+
+ u := url.URL{
+ Host: "hackers.town",
+ Path: fmt.Sprintf("api/v1/accounts/%s/followers", url.PathEscape(a.ID)),
+ }
+ u.Scheme = "https"
+
+ req, err := http.NewRequest("GET", u.String(), nil)
+ if err != nil {
+ return
+ }
+ req.Header.Add("Authorization", "Bearer "+token.AccessToken)
+
+ resp, err := client.Do(req)
+ if err != nil {
+ return
+ }
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return
+ }
+
+ err = json.Unmarshal(body, &followers)
+ if err != nil {
+ return
+ }
+
+ return
+}