From c080568c2dd05a6d84933a65e07d8634a020adb8 Mon Sep 17 00:00:00 2001 From: Dan Anglin Date: Mon, 20 May 2024 14:59:03 +0100 Subject: [PATCH] checkpoint: show followers --- cmd/enbas/main.go | 13 ++++++------ cmd/enbas/show.go | 44 +++++++++++++++++++++++++++++---------- internal/client/follow.go | 14 +++++++++++++ internal/model/follows.go | 24 +++++++++++++++++++++ 4 files changed, 78 insertions(+), 17 deletions(-) create mode 100644 internal/model/follows.go diff --git a/cmd/enbas/main.go b/cmd/enbas/main.go index 820890b..fe5ff8b 100644 --- a/cmd/enbas/main.go +++ b/cmd/enbas/main.go @@ -20,16 +20,17 @@ const ( statusIDFlag = "status-id" tagFlag = "tag" timelineCategoryFlag = "timeline-category" - timelineLimitFlag = "timeline-limit" + limitFlag = "limit" toAccountFlag = "to-account" ) const ( - accountResource = "account" - instanceResource = "instance" - listResource = "list" - statusResource = "status" - timelineResource = "timeline" + accountResource = "account" + instanceResource = "instance" + listResource = "list" + statusResource = "status" + timelineResource = "timeline" + followersResource = "followers" ) type Executor interface { diff --git a/cmd/enbas/show.go b/cmd/enbas/show.go index c29138f..79643b3 100644 --- a/cmd/enbas/show.go +++ b/cmd/enbas/show.go @@ -16,11 +16,12 @@ type showCommand struct { showAccountRelationship bool resourceType string account string + accountID string statusID string timelineCategory string listID string tag string - timelineLimit int + limit int } func newShowCommand(name, summary string) *showCommand { @@ -32,11 +33,12 @@ func newShowCommand(name, summary string) *showCommand { command.BoolVar(&command.showAccountRelationship, "show-account-relationship", false, "show your relationship to the specified account") command.StringVar(&command.resourceType, resourceTypeFlag, "", "specify the type of resource to display") command.StringVar(&command.account, accountFlag, "", "specify the account URI to lookup") + command.StringVar(&command.accountID, accountIDFlag, "", "specify the account ID") command.StringVar(&command.statusID, statusIDFlag, "", "specify the ID of the status to display") command.StringVar(&command.timelineCategory, timelineCategoryFlag, "home", "specify the type of timeline to display (valid values are home, public, list and tag)") command.StringVar(&command.listID, listIDFlag, "", "specify the ID of the list to display") command.StringVar(&command.tag, tagFlag, "", "specify the name of the tag to use") - command.IntVar(&command.timelineLimit, timelineLimitFlag, 5, "specify the number of statuses to display") + command.IntVar(&command.limit, limitFlag, 20, "specify the limit of items to display") command.Usage = commandUsageFunc(name, summary, command.FlagSet) @@ -49,11 +51,12 @@ func (c *showCommand) Execute() error { } funcMap := map[string]func(*client.Client) error{ - instanceResource: c.showInstance, - accountResource: c.showAccount, - statusResource: c.showStatus, - timelineResource: c.showTimeline, - listResource: c.showList, + instanceResource: c.showInstance, + accountResource: c.showAccount, + statusResource: c.showStatus, + timelineResource: c.showTimeline, + listResource: c.showList, + followersResource: c.showFollowers, } doFunc, ok := funcMap[c.resourceType] @@ -140,21 +143,21 @@ func (c *showCommand) showTimeline(gts *client.Client) error { switch c.timelineCategory { case "home": - timeline, err = gts.GetHomeTimeline(c.timelineLimit) + timeline, err = gts.GetHomeTimeline(c.limit) case "public": - timeline, err = gts.GetPublicTimeline(c.timelineLimit) + timeline, err = gts.GetPublicTimeline(c.limit) case "list": if c.listID == "" { return flagNotSetError{flagText: listIDFlag} } - timeline, err = gts.GetListTimeline(c.listID, c.timelineLimit) + timeline, err = gts.GetListTimeline(c.listID, c.limit) case "tag": if c.tag == "" { return flagNotSetError{flagText: tagFlag} } - timeline, err = gts.GetTagTimeline(c.tag, c.timelineLimit) + timeline, err = gts.GetTagTimeline(c.tag, c.limit) default: return invalidTimelineCategoryError{category: c.timelineCategory} } @@ -219,3 +222,22 @@ func (c *showCommand) showLists(gts *client.Client) error { return nil } + +func (c *showCommand) showFollowers(gts *client.Client) error { + if c.accountID == "" { + return flagNotSetError{flagText: accountIDFlag} + } + + followers, err := gts.GetFollowers(c.accountID, c.limit) + if err != nil { + return fmt.Errorf("unable to retrieve the list of followers; %w", err) + } + + if len(followers) > 0 { + fmt.Println(followers) + } else { + fmt.Println("There are no followers for this account or the list is hidden.") + } + + return nil +} diff --git a/internal/client/follow.go b/internal/client/follow.go index afc5449..cf1b4a5 100644 --- a/internal/client/follow.go +++ b/internal/client/follow.go @@ -5,6 +5,8 @@ import ( "encoding/json" "fmt" "net/http" + + "codeflow.dananglin.me.uk/apollo/enbas/internal/model" ) func (g *Client) FollowAccount(accountID string, reblogs, notify bool) error { @@ -42,3 +44,15 @@ func (g *Client) UnfollowAccount(accountID string) error { return nil } + +func (g *Client) GetFollowers(accountID string, limit int) (model.Followers, error) { + url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/followers?limit=%d", accountID, limit) + + var followers model.Followers + + if err := g.sendRequest(http.MethodGet, url, nil, &followers); err != nil { + return nil, fmt.Errorf("received an error after sending the request to get followers; %w", err) + } + + return followers, nil +} diff --git a/internal/model/follows.go b/internal/model/follows.go new file mode 100644 index 0000000..77a5d74 --- /dev/null +++ b/internal/model/follows.go @@ -0,0 +1,24 @@ +package model + +import ( + "fmt" + + "codeflow.dananglin.me.uk/apollo/enbas/internal/utilities" +) + +type Followers []Account + +func (f Followers) String() string { + output := "\n" + output += utilities.HeaderFormat("FOLLOWERS:") + + for i := range f { + output += fmt.Sprintf( + "\n • %s (%s)", + utilities.DisplayNameFormat(f[i].DisplayName), + f[i].Acct, + ) + } + + return output +}