fix: use the account name instead of account ID

The user will now specify the account name instead of the account ID
when performing operations such as following and blocking. Enbas will
lookup the account and retrieve the account ID before sending the
request to GoToSocial. This prevents the user from having to retrieve
the account ID themselves which should make it a bit easier to use.
This commit is contained in:
Dan Anglin 2024-05-21 21:06:18 +01:00
parent f9f817eaa1
commit f6d67a98e0
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
9 changed files with 177 additions and 128 deletions

76
cmd/enbas/account.go Normal file
View file

@ -0,0 +1,76 @@
package main
import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
)
func getAccountID(gtsClient *client.Client, myAccount bool, accountName string) (string, error) {
var (
accountID string
err error
)
switch {
case myAccount:
accountID, err = getMyAccountID(gtsClient)
if err != nil {
return "", fmt.Errorf("unable to get your account ID; %w", err)
}
case accountName != "":
accountID, err = getTheirAccountID(gtsClient, accountName)
if err != nil {
return "", fmt.Errorf("unable to get their account ID; %w", err)
}
default:
return "", noAccountSpecifiedError{}
}
return accountID, nil
}
func getTheirAccountID(gtsClient *client.Client, accountURI string) (string, error) {
account, err := getAccount(gtsClient, accountURI)
if err != nil {
return "", fmt.Errorf("unable to retrieve your account; %w", err)
}
return account.ID, nil
}
func getMyAccountID(gtsClient *client.Client) (string, error) {
account, err := getMyAccount(gtsClient)
if err != nil {
return "", fmt.Errorf("received an error while getting your account details; %w", err)
}
return account.ID, nil
}
func getMyAccount(gtsClient *client.Client) (model.Account, error) {
authConfig, err := config.NewAuthenticationConfigFromFile()
if err != nil {
return model.Account{}, fmt.Errorf("unable to retrieve the authentication configuration; %w", err)
}
accountURI := authConfig.CurrentAccount
account, err := getAccount(gtsClient, accountURI)
if err != nil {
return model.Account{}, fmt.Errorf("unable to retrieve your account; %w", err)
}
return account, nil
}
func getAccount(gtsClient *client.Client, accountURI string) (model.Account, error) {
account, err := gtsClient.GetAccount(accountURI)
if err != nil {
return model.Account{}, fmt.Errorf("unable to retrieve the account details; %w", err)
}
return account, nil
}

View file

@ -12,20 +12,20 @@ type addCommand struct {
toResourceType string
listID string
accountIDs accountIDs
accountNames accountNames
}
func newAddCommand(name, summary string) *addCommand {
emptyArr := make([]string, 0, 3)
command := addCommand{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
accountIDs: accountIDs(emptyArr),
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
accountNames: accountNames(emptyArr),
}
command.StringVar(&command.toResourceType, addToFlag, "", "specify the type of resource to add to")
command.StringVar(&command.listID, listIDFlag, "", "the ID of the list to add to")
command.Var(&command.accountIDs, accountIDFlag, "the ID of the account to add to the list")
command.Var(&command.accountNames, accountNameFlag, "the name of the account to add to the resource")
command.Usage = commandUsageFunc(name, summary, command.FlagSet)
@ -34,7 +34,7 @@ func newAddCommand(name, summary string) *addCommand {
func (c *addCommand) Execute() error {
if c.toResourceType == "" {
return flagNotSetError{flagText: "add-to"}
return flagNotSetError{flagText: addToFlag}
}
funcMap := map[string]func(*client.Client) error{
@ -59,11 +59,21 @@ func (c *addCommand) addAccountsToList(gtsClient *client.Client) error {
return flagNotSetError{flagText: listIDFlag}
}
if len(c.accountIDs) == 0 {
return noAccountIDsSpecifiedError{}
if len(c.accountNames) == 0 {
return noAccountSpecifiedError{}
}
if err := gtsClient.AddAccountsToList(c.listID, []string(c.accountIDs)); err != nil {
accountIDs := make([]string, len(c.accountNames))
for i := range c.accountNames {
accountID, err := getTheirAccountID(gtsClient, c.accountNames[i])
if err != nil {
return fmt.Errorf("unable to get the account ID for %s, %w", c.accountNames[i], err)
}
accountIDs[i] = accountID
}
if err := gtsClient.AddAccountsToList(c.listID, accountIDs); err != nil {
return fmt.Errorf("unable to add the accounts to the list; %w", err)
}

View file

@ -11,7 +11,7 @@ type blockCommand struct {
*flag.FlagSet
resourceType string
accountID string
accountName string
unblock bool
}
@ -23,7 +23,7 @@ func newBlockCommand(name, summary string, unblock bool) *blockCommand {
}
command.StringVar(&command.resourceType, resourceTypeFlag, "", "specify the type of resource to block or unblock")
command.StringVar(&command.accountID, accountIDFlag, "", "specify the ID of the account you want to block or unblock")
command.StringVar(&command.accountName, accountNameFlag, "", "specify the account name in full (username@domain)")
command.Usage = commandUsageFunc(name, summary, command.FlagSet)
@ -48,16 +48,17 @@ func (c *blockCommand) Execute() error {
return doFunc(gtsClient)
}
func (c *blockCommand) blockAccount(gts *client.Client) error {
if c.accountID == "" {
return flagNotSetError{flagText: accountIDFlag}
func (c *blockCommand) blockAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, c.accountName)
if err != nil {
return fmt.Errorf("received an error while getting the account ID; %w", err)
}
if c.unblock {
return c.unblockAccount(gts)
return c.unblockAccount(gtsClient, accountID)
}
if err := gts.BlockAccount(c.accountID); err != nil {
if err := gtsClient.BlockAccount(accountID); err != nil {
return fmt.Errorf("unable to block the account; %w", err)
}
@ -66,8 +67,8 @@ func (c *blockCommand) blockAccount(gts *client.Client) error {
return nil
}
func (c *blockCommand) unblockAccount(gts *client.Client) error {
if err := gts.UnblockAccount(c.accountID); err != nil {
func (c *blockCommand) unblockAccount(gtsClient *client.Client, accountID string) error {
if err := gtsClient.UnblockAccount(accountID); err != nil {
return fmt.Errorf("unable to unblock the account; %w", err)
}

View file

@ -32,8 +32,8 @@ func (e unknownSubcommandError) Error() string {
return "unknown subcommand '" + e.subcommand + "'"
}
type noAccountIDsSpecifiedError struct{}
type noAccountSpecifiedError struct{}
func (e noAccountIDsSpecifiedError) Error() string {
return "no account IDs specified"
func (e noAccountSpecifiedError) Error() string {
return "no account specified in this request"
}

View file

@ -2,13 +2,13 @@ package main
import "strings"
type accountIDs []string
type accountNames []string
func (a *accountIDs) String() string {
func (a *accountNames) String() string {
return strings.Join(*a, ", ")
}
func (a *accountIDs) Set(value string) error {
func (a *accountNames) Set(value string) error {
if len(value) > 0 {
*a = append(*a, value)
}

View file

@ -11,7 +11,7 @@ type followCommand struct {
*flag.FlagSet
resourceType string
accountID string
accountName string
showReposts bool
notify bool
unfollow bool
@ -25,7 +25,7 @@ func newFollowCommand(name, summary string, unfollow bool) *followCommand {
}
command.StringVar(&command.resourceType, resourceTypeFlag, "", "specify the type of resource to follow")
command.StringVar(&command.accountID, accountIDFlag, "", "specify the ID of the account you want to follow")
command.StringVar(&command.accountName, accountNameFlag, "", "specify the account name in full (username@domain)")
command.BoolVar(&command.showReposts, showRepostsFlag, true, "show reposts from the account you want to follow")
command.BoolVar(&command.notify, notifyFlag, false, "get notifications when the account you want to follow posts a status")
@ -52,16 +52,17 @@ func (c *followCommand) Execute() error {
return doFunc(gtsClient)
}
func (c *followCommand) followAccount(gts *client.Client) error {
if c.accountID == "" {
return flagNotSetError{flagText: accountIDFlag}
func (c *followCommand) followAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, c.accountName)
if err != nil {
return fmt.Errorf("received an error while getting the account ID; %w", err)
}
if c.unfollow {
return c.unfollowAccount(gts)
return c.unfollowAccount(gtsClient, accountID)
}
if err := gts.FollowAccount(c.accountID, c.showReposts, c.notify); err != nil {
if err := gtsClient.FollowAccount(accountID, c.showReposts, c.notify); err != nil {
return fmt.Errorf("unable to follow the account; %w", err)
}
@ -70,8 +71,8 @@ func (c *followCommand) followAccount(gts *client.Client) error {
return nil
}
func (c *followCommand) unfollowAccount(gts *client.Client) error {
if err := gts.UnfollowAccount(c.accountID); err != nil {
func (c *followCommand) unfollowAccount(gtsClient *client.Client, accountID string) error {
if err := gtsClient.UnfollowAccount(accountID); err != nil {
return fmt.Errorf("unable to unfollow the account; %w", err)
}

View file

@ -4,15 +4,10 @@ import (
"flag"
"fmt"
"os"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
)
const (
accountFlag = "account"
accountIDFlag = "account-id"
accountNameFlag = "account-name"
addToFlag = "add-to"
instanceFlag = "instance"
listIDFlag = "list-id"
@ -151,19 +146,3 @@ func run() error {
return nil
}
func getMyAccount(gts *client.Client) (model.Account, error) {
authConfig, err := config.NewAuthenticationConfigFromFile()
if err != nil {
return model.Account{}, fmt.Errorf("unable to retrieve the authentication configuration; %w", err)
}
accountURI := authConfig.CurrentAccount
account, err := gts.GetAccount(accountURI)
if err != nil {
return model.Account{}, fmt.Errorf("unable to retrieve the account details; %w", err)
}
return account, nil
}

View file

@ -12,20 +12,20 @@ type removeCommand struct {
fromResourceType string
listID string
accountIDs accountIDs
accountNames accountNames
}
func newRemoveCommand(name, summary string) *removeCommand {
emptyArr := make([]string, 0, 3)
command := removeCommand{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
accountIDs: accountIDs(emptyArr),
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
accountNames: accountNames(emptyArr),
}
command.StringVar(&command.fromResourceType, removeFromFlag, "", "specify the type of resource to remove from")
command.StringVar(&command.listID, listIDFlag, "", "the ID of the list to remove from")
command.Var(&command.accountIDs, accountIDFlag, "the ID of the account to remove from the list")
command.Var(&command.accountNames, accountNameFlag, "the name of the account to remove from the resource")
command.Usage = commandUsageFunc(name, summary, command.FlagSet)
@ -34,7 +34,7 @@ func newRemoveCommand(name, summary string) *removeCommand {
func (c *removeCommand) Execute() error {
if c.fromResourceType == "" {
return flagNotSetError{flagText: "remove-from"}
return flagNotSetError{flagText: removeFromFlag}
}
funcMap := map[string]func(*client.Client) error{
@ -59,11 +59,21 @@ func (c *removeCommand) removeAccountsFromList(gtsClient *client.Client) error {
return flagNotSetError{flagText: listIDFlag}
}
if len(c.accountIDs) == 0 {
return noAccountIDsSpecifiedError{}
if len(c.accountNames) == 0 {
return noAccountSpecifiedError{}
}
if err := gtsClient.RemoveAccountsFromList(c.listID, []string(c.accountIDs)); err != nil {
accountIDs := make([]string, len(c.accountNames))
for i := range c.accountNames {
accountID, err := getTheirAccountID(gtsClient, c.accountNames[i])
if err != nil {
return fmt.Errorf("unable to get the account ID for %s, %w", c.accountNames[i], err)
}
accountIDs[i] = accountID
}
if err := gtsClient.RemoveAccountsFromList(c.listID, accountIDs); err != nil {
return fmt.Errorf("unable to remove the accounts from the list; %w", err)
}

View file

@ -15,8 +15,7 @@ type showCommand struct {
showAccountRelationship bool
showUserPreferences bool
resourceType string
account string
accountID string
accountName string
statusID string
timelineCategory string
listID string
@ -33,8 +32,7 @@ func newShowCommand(name, summary string) *showCommand {
command.BoolVar(&command.showAccountRelationship, showAccountRelationshipFlag, false, "show your relationship to the specified account")
command.BoolVar(&command.showUserPreferences, showUserPreferencesFlag, false, "show your preferences")
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.accountName, accountNameFlag, "", "specify the account name in full (username@domain)")
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")
@ -75,8 +73,8 @@ func (c *showCommand) Execute() error {
return doFunc(gtsClient)
}
func (c *showCommand) showInstance(gts *client.Client) error {
instance, err := gts.GetInstance()
func (c *showCommand) showInstance(gtsClient *client.Client) error {
instance, err := gtsClient.GetInstance()
if err != nil {
return fmt.Errorf("unable to retrieve the instance details; %w", err)
}
@ -86,34 +84,32 @@ func (c *showCommand) showInstance(gts *client.Client) error {
return nil
}
func (c *showCommand) showAccount(gts *client.Client) error {
func (c *showCommand) showAccount(gtsClient *client.Client) error {
var (
account model.Account
err error
)
if c.myAccount {
account, err = getMyAccount(gts)
account, err = getMyAccount(gtsClient)
if err != nil {
return fmt.Errorf("received an error while getting account details; %w", err)
return fmt.Errorf("received an error while getting the account details; %w", err)
}
} else {
if c.account == "" {
return flagNotSetError{flagText: accountFlag}
if c.accountName == "" {
return flagNotSetError{flagText: accountNameFlag}
}
accountURI := c.account
account, err = gts.GetAccount(accountURI)
account, err = getAccount(gtsClient, c.accountName)
if err != nil {
return fmt.Errorf("unable to retrieve the account details; %w", err)
return fmt.Errorf("received an error while getting the account details; %w", err)
}
}
fmt.Println(account)
if !c.myAccount && c.showAccountRelationship {
relationship, err := gts.GetAccountRelationship(account.ID)
relationship, err := gtsClient.GetAccountRelationship(account.ID)
if err != nil {
return fmt.Errorf("unable to retrieve the relationship to this account; %w", err)
}
@ -122,7 +118,7 @@ func (c *showCommand) showAccount(gts *client.Client) error {
}
if c.myAccount && c.showUserPreferences {
preferences, err := gts.GetUserPreferences()
preferences, err := gtsClient.GetUserPreferences()
if err != nil {
return fmt.Errorf("unable to retrieve the user preferences; %w", err)
}
@ -133,12 +129,12 @@ func (c *showCommand) showAccount(gts *client.Client) error {
return nil
}
func (c *showCommand) showStatus(gts *client.Client) error {
func (c *showCommand) showStatus(gtsClient *client.Client) error {
if c.statusID == "" {
return flagNotSetError{flagText: statusIDFlag}
}
status, err := gts.GetStatus(c.statusID)
status, err := gtsClient.GetStatus(c.statusID)
if err != nil {
return fmt.Errorf("unable to retrieve the status; %w", err)
}
@ -148,7 +144,7 @@ func (c *showCommand) showStatus(gts *client.Client) error {
return nil
}
func (c *showCommand) showTimeline(gts *client.Client) error {
func (c *showCommand) showTimeline(gtsClient *client.Client) error {
var (
timeline model.Timeline
err error
@ -156,21 +152,21 @@ func (c *showCommand) showTimeline(gts *client.Client) error {
switch c.timelineCategory {
case "home":
timeline, err = gts.GetHomeTimeline(c.limit)
timeline, err = gtsClient.GetHomeTimeline(c.limit)
case "public":
timeline, err = gts.GetPublicTimeline(c.limit)
timeline, err = gtsClient.GetPublicTimeline(c.limit)
case "list":
if c.listID == "" {
return flagNotSetError{flagText: listIDFlag}
}
timeline, err = gts.GetListTimeline(c.listID, c.limit)
timeline, err = gtsClient.GetListTimeline(c.listID, c.limit)
case "tag":
if c.tag == "" {
return flagNotSetError{flagText: tagFlag}
}
timeline, err = gts.GetTagTimeline(c.tag, c.limit)
timeline, err = gtsClient.GetTagTimeline(c.tag, c.limit)
default:
return invalidTimelineCategoryError{category: c.timelineCategory}
}
@ -190,17 +186,17 @@ func (c *showCommand) showTimeline(gts *client.Client) error {
return nil
}
func (c *showCommand) showList(gts *client.Client) error {
func (c *showCommand) showList(gtsClient *client.Client) error {
if c.listID == "" {
return c.showLists(gts)
return c.showLists(gtsClient)
}
list, err := gts.GetList(c.listID)
list, err := gtsClient.GetList(c.listID)
if err != nil {
return fmt.Errorf("unable to retrieve the list; %w", err)
}
accounts, err := gts.GetAccountsFromList(c.listID, 0)
accounts, err := gtsClient.GetAccountsFromList(c.listID, 0)
if err != nil {
return fmt.Errorf("unable to retrieve the accounts from the list; %w", err)
}
@ -219,8 +215,8 @@ func (c *showCommand) showList(gts *client.Client) error {
return nil
}
func (c *showCommand) showLists(gts *client.Client) error {
lists, err := gts.GetAllLists()
func (c *showCommand) showLists(gtsClient *client.Client) error {
lists, err := gtsClient.GetAllLists()
if err != nil {
return fmt.Errorf("unable to retrieve the lists; %w", err)
}
@ -237,25 +233,13 @@ func (c *showCommand) showLists(gts *client.Client) error {
return nil
}
func (c *showCommand) showFollowers(gts *client.Client) error {
var accountID string
if c.myAccount {
account, err := getMyAccount(gts)
if err != nil {
return fmt.Errorf("received an error while getting account details; %w", err)
}
accountID = account.ID
} else {
if c.accountID == "" {
return flagNotSetError{flagText: accountIDFlag}
}
accountID = c.accountID
func (c *showCommand) showFollowers(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, c.myAccount, c.accountName)
if err != nil {
return fmt.Errorf("received an error while getting the account ID; %w", err)
}
followers, err := gts.GetFollowers(accountID, c.limit)
followers, err := gtsClient.GetFollowers(accountID, c.limit)
if err != nil {
return fmt.Errorf("unable to retrieve the list of followers; %w", err)
}
@ -269,25 +253,13 @@ func (c *showCommand) showFollowers(gts *client.Client) error {
return nil
}
func (c *showCommand) showFollowing(gts *client.Client) error {
var accountID string
if c.myAccount {
account, err := getMyAccount(gts)
if err != nil {
return fmt.Errorf("received an error while getting account details; %w", err)
}
accountID = account.ID
} else {
if c.accountID == "" {
return flagNotSetError{flagText: accountIDFlag}
}
accountID = c.accountID
func (c *showCommand) showFollowing(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, c.myAccount, c.accountName)
if err != nil {
return fmt.Errorf("received an error while getting the account ID; %w", err)
}
following, err := gts.GetFollowing(accountID, c.limit)
following, err := gtsClient.GetFollowing(accountID, c.limit)
if err != nil {
return fmt.Errorf("unable to retrieve the list of followed accounts; %w", err)
}
@ -301,8 +273,8 @@ func (c *showCommand) showFollowing(gts *client.Client) error {
return nil
}
func (c *showCommand) showBlocked(gts *client.Client) error {
blocked, err := gts.GetBlockedAccounts(c.limit)
func (c *showCommand) showBlocked(gtsClient *client.Client) error {
blocked, err := gtsClient.GetBlockedAccounts(c.limit)
if err != nil {
return fmt.Errorf("unable to retrieve the list of blocked accounts; %w", err)
}