feat: accept or reject follow requests

Add support to allow users to accept or reject follow requests.
This commit is contained in:
Dan Anglin 2024-06-10 10:58:43 +01:00
parent d21f1fbf6a
commit 5fb55ed2cf
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
6 changed files with 205 additions and 29 deletions

View file

@ -28,6 +28,8 @@ const (
commandUnfollow string = "unfollow"
commandBlock string = "block"
commandUnblock string = "unblock"
commandAccept string = "accept"
commandReject string = "reject"
)
var (
@ -60,6 +62,8 @@ func run() error {
commandUnfollow: "Unfollow a resource (e.g. an account)",
commandBlock: "Block a resource (e.g. an account)",
commandUnblock: "Unblock a resource (e.g. an account)",
commandAccept: "Accept a request (e.g. a follow request)",
commandReject: "Reject a request (e.g. a follow request)",
}
topLevelFlags := executor.TopLevelFlags{
@ -108,6 +112,13 @@ func run() error {
var err error
switch command {
case commandAccept:
exe := executor.NewAcceptOrRejectExecutor(
topLevelFlags,
commandAccept,
commandSummaries[commandAccept],
)
err = executor.Execute(exe, args)
case commandAdd:
exe := executor.NewAddExecutor(
topLevelFlags,
@ -159,6 +170,13 @@ func run() error {
commandSummaries[commandLogin],
)
err = executor.Execute(exe, args)
case commandReject:
exe := executor.NewAcceptOrRejectExecutor(
topLevelFlags,
commandReject,
commandSummaries[commandReject],
)
err = executor.Execute(exe, args)
case commandRemove:
exe := executor.NewRemoveExecutor(
topLevelFlags,
@ -174,10 +192,20 @@ func run() error {
)
err = executor.Execute(exe, args)
case commandUnfollow:
exe := executor.NewFollowExecutor(topLevelFlags, commandUnfollow, commandSummaries[commandUnfollow], true)
exe := executor.NewFollowExecutor(
topLevelFlags,
commandUnfollow,
commandSummaries[commandUnfollow],
true,
)
err = executor.Execute(exe, args)
case commandUnblock:
exe := executor.NewBlockExecutor(topLevelFlags, commandUnblock, commandSummaries[commandUnblock], true)
exe := executor.NewBlockExecutor(
topLevelFlags,
commandUnblock,
commandSummaries[commandUnblock],
true,
)
err = executor.Execute(exe, args)
case commandShow:
exe := executor.NewShowExecutor(topLevelFlags, commandShow, commandSummaries[commandShow])

View file

@ -145,7 +145,7 @@ func (g *Client) UnblockAccount(accountID string) error {
func (g *Client) GetBlockedAccounts(limit int) (model.AccountList, error) {
url := g.Authentication.Instance + fmt.Sprintf("/api/v1/blocks?limit=%d", limit)
accounts := make([]model.Account, limit)
var accounts []model.Account
if err := g.sendRequest(http.MethodGet, url, nil, &accounts); err != nil {
return model.AccountList{}, fmt.Errorf("received an error after sending the request to get the list of blocked accounts: %w", err)
@ -180,3 +180,40 @@ func (g *Client) SetPrivateNote(accountID, note string) error {
return nil
}
func (g *Client) GetFollowRequests(limit int) (model.AccountList, error) {
url := g.Authentication.Instance + fmt.Sprintf("/api/v1/follow_requests?limit=%d", limit)
var accounts []model.Account
if err := g.sendRequest(http.MethodGet, url, nil, &accounts); err != nil {
return model.AccountList{}, fmt.Errorf("received an error after sending the request to get the list of follow requests: %w", err)
}
requests := model.AccountList{
Type: model.AccountListFollowRequests,
Accounts: accounts,
}
return requests, nil
}
func (g *Client) AcceptFollowRequest(accountID string) error {
url := g.Authentication.Instance + "/api/v1/follow_requests/" + accountID + "/authorize"
if err := g.sendRequest(http.MethodPost, url, nil, nil); err != nil {
return fmt.Errorf("received an error after sending the request to accept the follow request: %w", err)
}
return nil
}
func (g *Client) RejectFollowRequest(accountID string) error {
url := g.Authentication.Instance + "/api/v1/follow_requests/" + accountID + "/reject"
if err := g.sendRequest(http.MethodPost, url, nil, nil); err != nil {
return fmt.Errorf("received an error after sending the request to reject the follow request: %w", err)
}
return nil
}

View file

@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
//
// SPDX-License-Identifier: GPL-3.0-or-later
package executor
import (
"flag"
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
)
type AcceptOrRejectExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
resourceType string
accountName string
action string
}
func NewAcceptOrRejectExecutor(tlf TopLevelFlags, name, summary string) *AcceptOrRejectExecutor {
acceptExe := AcceptOrRejectExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
topLevelFlags: tlf,
action: name,
}
acceptExe.StringVar(&acceptExe.resourceType, flagType, "", "Specify the type of resource to accept or reject")
acceptExe.StringVar(&acceptExe.accountName, flagAccountName, "", "Specify the account name in full (username@domain)")
acceptExe.Usage = commandUsageFunc(name, summary, acceptExe.FlagSet)
return &acceptExe
}
func (a *AcceptOrRejectExecutor) Execute() error {
funcMap := map[string]func(*client.Client) error{
resourceFollowRequest: a.acceptOrRejectFollowRequest,
}
doFunc, ok := funcMap[a.resourceType]
if !ok {
return UnsupportedTypeError{resourceType: a.resourceType}
}
gtsClient, err := client.NewClientFromConfig(a.topLevelFlags.ConfigDir)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
return doFunc(gtsClient)
}
func (a *AcceptOrRejectExecutor) acceptOrRejectFollowRequest(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, a.accountName, a.topLevelFlags.ConfigDir)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}
switch a.action {
case "accept":
return a.acceptFollowRequest(gtsClient, accountID)
case "reject":
return a.rejectFollowRequest(gtsClient, accountID)
default:
return nil
}
}
func (a *AcceptOrRejectExecutor) acceptFollowRequest(gtsClient *client.Client, accountID string) error {
if err := gtsClient.AcceptFollowRequest(accountID); err != nil {
return fmt.Errorf("unable to accept the follow request: %w", err)
}
fmt.Println("Successfully accepted the follow request.")
return nil
}
func (a *AcceptOrRejectExecutor) rejectFollowRequest(gtsClient *client.Client, accountID string) error {
if err := gtsClient.RejectFollowRequest(accountID); err != nil {
return fmt.Errorf("unable to reject the follow request: %w", err)
}
fmt.Println("Successfully rejected the follow request.")
return nil
}

View file

@ -41,6 +41,7 @@ const (
resourceBoost = "boost"
resourceFollowers = "followers"
resourceFollowing = "following"
resourceFollowRequest = "follow-request"
resourceInstance = "instance"
resourceLike = "like"
resourceLiked = "liked"

View file

@ -69,6 +69,7 @@ func (s *ShowExecutor) Execute() error {
resourceBookmarks: s.showBookmarks,
resourceLiked: s.showLiked,
resourceStarred: s.showLiked,
resourceFollowRequest: s.showFollowRequests,
}
doFunc, ok := funcMap[s.resourceType]
@ -346,3 +347,18 @@ func (s *ShowExecutor) showLiked(gtsClient *client.Client) error {
return nil
}
func (s *ShowExecutor) showFollowRequests(gtsClient *client.Client) error {
accounts, err := gtsClient.GetFollowRequests(s.limit)
if err != nil {
return fmt.Errorf("unable to retrieve the list of follow requests: %w", err)
}
if len(accounts.Accounts) > 0 {
utilities.Display(accounts, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
} else {
fmt.Println("You have no follow requests.")
}
return nil
}

View file

@ -186,6 +186,7 @@ const (
AccountListFollowers AccountListType = iota
AccountListFollowing
AccountListBlockedAccount
AccountListFollowRequests
)
type AccountList struct {
@ -203,6 +204,8 @@ func (a AccountList) Display(noColor bool) string {
output += utilities.HeaderFormat(noColor, "FOLLOWING:")
case AccountListBlockedAccount:
output += utilities.HeaderFormat(noColor, "BLOCKED ACCOUNTS:")
case AccountListFollowRequests:
output += utilities.HeaderFormat(noColor, "ACCOUNTS THAT HAVE REQUESTED TO FOLLOW YOU:")
default:
output += utilities.HeaderFormat(noColor, "ACCOUNTS:")
}