diff --git a/internal/client/errors.go b/internal/client/errors.go index b2f2617..53ace80 100644 --- a/internal/client/errors.go +++ b/internal/client/errors.go @@ -30,3 +30,11 @@ func (e ResponseError) Error() string { e.Message, ) } + +type Error struct { + message string +} + +func (e Error) Error() string { + return e.message +} diff --git a/internal/client/token.go b/internal/client/token.go index b2902f4..f23a242 100644 --- a/internal/client/token.go +++ b/internal/client/token.go @@ -3,15 +3,12 @@ package client import ( "bytes" "encoding/json" - "errors" "fmt" "net/http" "codeflow.dananglin.me.uk/apollo/enbas/internal" ) -var errEmptyAccessToken = errors.New("received an empty access token") - type tokenRequest struct { RedirectURI string `json:"redirect_uri"` ClientID string `json:"client_id"` @@ -59,7 +56,7 @@ func (g *Client) UpdateToken(code string) error { } if response.AccessToken == "" { - return errEmptyAccessToken + return Error{"received an empty access token"} } g.Authentication.AccessToken = response.AccessToken diff --git a/internal/executor/add.go b/internal/executor/add.go index f18a733..cb87992 100644 --- a/internal/executor/add.go +++ b/internal/executor/add.go @@ -1,7 +1,6 @@ package executor import ( - "errors" "fmt" "codeflow.dananglin.me.uk/apollo/enbas/internal/client" @@ -40,8 +39,8 @@ func (a *AddExecutor) addToList(gtsClient *client.Client) error { doFunc, ok := funcMap[a.resourceType] if !ok { return UnsupportedAddOperationError{ - ResourceType: a.resourceType, - AddToResourceType: a.toResourceType, + resourceType: a.resourceType, + addToResourceType: a.toResourceType, } } @@ -71,7 +70,7 @@ func (a *AddExecutor) addAccountsToList(gtsClient *client.Client) error { } if !relationship.Following { - return NotFollowingError{Account: accounts[ind].Acct} + return NotFollowingError{account: accounts[ind].Acct} } accountIDs[ind] = accounts[ind].ID @@ -94,8 +93,8 @@ func (a *AddExecutor) addToAccount(gtsClient *client.Client) error { doFunc, ok := funcMap[a.resourceType] if !ok { return UnsupportedAddOperationError{ - ResourceType: a.resourceType, - AddToResourceType: a.toResourceType, + resourceType: a.resourceType, + addToResourceType: a.toResourceType, } } @@ -109,7 +108,7 @@ func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error { } if a.content == "" { - return errors.New("please add content to the status that you want to create") + return Error{"please add content to the note you want to add"} } if err := gtsClient.SetPrivateNote(accountID, a.content); err != nil { @@ -129,8 +128,8 @@ func (a *AddExecutor) addToBookmarks(gtsClient *client.Client) error { doFunc, ok := funcMap[a.resourceType] if !ok { return UnsupportedAddOperationError{ - ResourceType: a.resourceType, - AddToResourceType: a.toResourceType, + resourceType: a.resourceType, + addToResourceType: a.toResourceType, } } @@ -166,8 +165,8 @@ func (a *AddExecutor) addToStatus(gtsClient *client.Client) error { doFunc, ok := funcMap[a.resourceType] if !ok { return UnsupportedAddOperationError{ - ResourceType: a.resourceType, - AddToResourceType: a.toResourceType, + resourceType: a.resourceType, + addToResourceType: a.toResourceType, } } @@ -196,7 +195,7 @@ func (a *AddExecutor) addBoostToStatus(gtsClient *client.Client) error { func (a *AddExecutor) addVoteToStatus(gtsClient *client.Client) error { if a.votes.Empty() { - return NoVotesError{} + return Error{"please add your vote(s) to the poll"} } status, err := gtsClient.GetStatus(a.statusID) @@ -205,15 +204,15 @@ func (a *AddExecutor) addVoteToStatus(gtsClient *client.Client) error { } if status.Poll == nil { - return NoPollInStatusError{} + return Error{"this status does not have a poll"} } if status.Poll.Expired { - return PollClosedError{} + return Error{"this poll is closed"} } if !status.Poll.Multiple && !a.votes.ExpectedLength(1) { - return MultipleChoiceError{} + return Error{"this poll does not allow multiple choices"} } myAccountID, err := getAccountID(gtsClient, true, nil) @@ -222,7 +221,7 @@ func (a *AddExecutor) addVoteToStatus(gtsClient *client.Client) error { } if status.Account.ID == myAccountID { - return PollOwnerVoteError{} + return Error{"you cannot vote in your own poll"} } pollID := status.Poll.ID diff --git a/internal/executor/create.go b/internal/executor/create.go index a49bb09..3f0c85c 100644 --- a/internal/executor/create.go +++ b/internal/executor/create.go @@ -1,7 +1,6 @@ package executor import ( - "errors" "fmt" "codeflow.dananglin.me.uk/apollo/enbas/internal/client" @@ -72,27 +71,35 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error { if !c.mediaFiles.Empty() { descriptionsExists := false focusValuesExists := false - expectedLength := len(c.mediaFiles) - mediaDescriptions := make([]string, expectedLength) + numMediaFiles := len(c.mediaFiles) + mediaDescriptions := make([]string, numMediaFiles) if !c.mediaDescriptions.Empty() { descriptionsExists = true - if !c.mediaDescriptions.ExpectedLength(expectedLength) { - return errors.New("the number of media descriptions does not match the number of media files") + if !c.mediaDescriptions.ExpectedLength(numMediaFiles) { + return MismatchedNumMediaArgs{ + argType: "media descriptions", + numArgs: len(c.mediaDescriptions), + numMediaFiles: numMediaFiles, + } } } if !c.mediaFocusValues.Empty() { focusValuesExists = true - if !c.mediaFocusValues.ExpectedLength(expectedLength) { - return errors.New("the number of media focus values does not match the number of media files") + if !c.mediaFocusValues.ExpectedLength(numMediaFiles) { + return MismatchedNumMediaArgs{ + argType: "media focus values", + numArgs: len(c.mediaFocusValues), + numMediaFiles: numMediaFiles, + } } } if descriptionsExists { - for ind := 0; ind < expectedLength; ind++ { + for ind := 0; ind < numMediaFiles; ind++ { mediaDesc, err := utilities.ReadContents(c.mediaDescriptions[ind]) if err != nil { return fmt.Errorf("unable to read the contents from %s: %w", c.mediaDescriptions[ind], err) @@ -102,7 +109,7 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error { } } - for ind := 0; ind < expectedLength; ind++ { + for ind := 0; ind < numMediaFiles; ind++ { var ( mediaFile string description string @@ -133,7 +140,7 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error { } if c.content == "" && len(attachmentIDs) == 0 { - return errors.New("please add content to the status that you want to create") + return Error{"please add content to the status that you want to create"} } content, err := utilities.ReadContents(c.content) @@ -144,7 +151,7 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error { numAttachmentIDs := len(attachmentIDs) if c.addPoll && numAttachmentIDs > 0 { - return fmt.Errorf("attaching media to a poll is not allowed") + return Error{"attaching media to a poll is not allowed"} } preferences, err := gtsClient.GetUserPreferences() @@ -202,7 +209,7 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error { if c.addPoll { if len(c.pollOptions) == 0 { - return NoPollOptionError{} + return Error{"no options were provided for this poll"} } poll := client.CreateStatusPollForm{ @@ -244,11 +251,13 @@ func (c *CreateExecutor) createMediaAttachment(gtsClient *client.Client) error { } var err error + description, err = utilities.ReadContents(c.mediaDescriptions[0]) if err != nil { return fmt.Errorf( "unable to read the contents from %s: %w", c.mediaDescriptions[0], + err, ) } } @@ -261,6 +270,7 @@ func (c *CreateExecutor) createMediaAttachment(gtsClient *client.Client) error { expectedNumValues, ) } + focus = c.mediaFocusValues[0] } diff --git a/internal/executor/delete.go b/internal/executor/delete.go index 8bfe8a9..5ddd00f 100644 --- a/internal/executor/delete.go +++ b/internal/executor/delete.go @@ -1,7 +1,6 @@ package executor import ( - "errors" "fmt" "path/filepath" @@ -62,7 +61,7 @@ func (d *DeleteExecutor) deleteStatus(gtsClient *client.Client) error { } if status.Account.ID != myAccountID { - return errors.New("unable to delete the status because the status does not belong to you") + return Error{"unable to delete the status because the status does not belong to you"} } text, err := gtsClient.DeleteStatus(d.statusID) diff --git a/internal/executor/errors.go b/internal/executor/errors.go index 45edce8..fe08df7 100644 --- a/internal/executor/errors.go +++ b/internal/executor/errors.go @@ -1,5 +1,15 @@ package executor +import "fmt" + +type Error struct { + message string +} + +func (e Error) Error() string { + return e.message +} + type FlagNotSetError struct { flagText string } @@ -23,94 +33,72 @@ func (e NoAccountSpecifiedError) Error() string { } type UnsupportedAddOperationError struct { - ResourceType string - AddToResourceType string + resourceType string + addToResourceType string } func (e UnsupportedAddOperationError) Error() string { return "adding '" + - e.ResourceType + + e.resourceType + "' to '" + - e.AddToResourceType + + e.addToResourceType + "' is not supported" } type UnsupportedRemoveOperationError struct { - ResourceType string - RemoveFromResourceType string + resourceType string + removeFromResourceType string } func (e UnsupportedRemoveOperationError) Error() string { return "removing '" + - e.ResourceType + + e.resourceType + "' from '" + - e.RemoveFromResourceType + + e.removeFromResourceType + "' is not supported" } type UnsupportedShowOperationError struct { - ResourceType string - ShowFromResourceType string + resourceType string + showFromResourceType string } func (e UnsupportedShowOperationError) Error() string { return "showing '" + - e.ResourceType + + e.resourceType + "' from '" + - e.ShowFromResourceType + + e.showFromResourceType + "' is not supported" } type UnknownCommandError struct { - Command string + command string } func (e UnknownCommandError) Error() string { - return "unknown command '" + e.Command + "'" -} - -type PollClosedError struct{} - -func (e PollClosedError) Error() string { - return "this poll is closed" -} - -type MultipleChoiceError struct{} - -func (e MultipleChoiceError) Error() string { - return "this poll does not allow multiple choices" -} - -type NoPollOptionError struct{} - -func (e NoPollOptionError) Error() string { - return "no options were provided for this poll, please use the --" + - flagPollOption + - " flag to add options to the poll" -} - -type NoVotesError struct{} - -func (e NoVotesError) Error() string { - return "no votes were made, please add your vote(s) using the --vote flag" -} - -type NoPollInStatusError struct{} - -func (e NoPollInStatusError) Error() string { - return "this status does not have a poll" -} - -type PollOwnerVoteError struct{} - -func (e PollOwnerVoteError) Error() string { - return "you cannot vote in your own poll" + return "unknown command '" + e.command + "'" } type NotFollowingError struct { - Account string + account string } func (e NotFollowingError) Error() string { - return "you are not following " + e.Account + return "you are not following " + e.account +} + +type MismatchedNumMediaArgs struct { + argType string + numArgs int + numMediaFiles int +} + +func (e MismatchedNumMediaArgs) Error() string { + return fmt.Sprintf( + "unexpected number of %s: received %d media files but got %d %s", + e.argType, + e.numMediaFiles, + e.numArgs, + e.argType, + ) } diff --git a/internal/executor/execute.go b/internal/executor/execute.go index 8ffa917..d42d3c2 100644 --- a/internal/executor/execute.go +++ b/internal/executor/execute.go @@ -145,7 +145,7 @@ func execute( exe, ok := executorMap[command] if !ok { - return UnknownCommandError{Command: command} + return UnknownCommandError{command: command} } if err := exe.Parse(args); err != nil { diff --git a/internal/executor/flags.go b/internal/executor/flags.go index efd07a0..8f22c75 100644 --- a/internal/executor/flags.go +++ b/internal/executor/flags.go @@ -7,7 +7,6 @@ const ( flagInstance = "instance" flagListID = "list-id" flagListTitle = "list-title" - flagPollOption = "poll-option" flagStatusID = "status-id" flagTag = "tag" flagTo = "to" diff --git a/internal/executor/mute.go b/internal/executor/mute.go index f8cd30d..121b1a4 100644 --- a/internal/executor/mute.go +++ b/internal/executor/mute.go @@ -1,7 +1,6 @@ package executor import ( - "errors" "fmt" "codeflow.dananglin.me.uk/apollo/enbas/internal/client" @@ -75,7 +74,7 @@ func (m *MuteExecutor) muteStatus(gtsClient *client.Client) error { } if !canMute { - return errors.New("unable to mute the status because you are not the owner and you are not mentioned in it") + return Error{"unable to mute the status because you are not the owner and you are not mentioned in it"} } if err := gtsClient.MuteStatus(m.statusID); err != nil { diff --git a/internal/executor/remove.go b/internal/executor/remove.go index 69aa841..bd1bd74 100644 --- a/internal/executor/remove.go +++ b/internal/executor/remove.go @@ -39,8 +39,8 @@ func (r *RemoveExecutor) removeFromList(gtsClient *client.Client) error { doFunc, ok := funcMap[r.resourceType] if !ok { return UnsupportedRemoveOperationError{ - ResourceType: r.resourceType, - RemoveFromResourceType: r.fromResourceType, + resourceType: r.resourceType, + removeFromResourceType: r.fromResourceType, } } @@ -84,8 +84,8 @@ func (r *RemoveExecutor) removeFromAccount(gtsClient *client.Client) error { doFunc, ok := funcMap[r.resourceType] if !ok { return UnsupportedRemoveOperationError{ - ResourceType: r.resourceType, - RemoveFromResourceType: r.fromResourceType, + resourceType: r.resourceType, + removeFromResourceType: r.fromResourceType, } } @@ -115,8 +115,8 @@ func (r *RemoveExecutor) removeFromBookmarks(gtsClient *client.Client) error { doFunc, ok := funcMap[r.resourceType] if !ok { return UnsupportedRemoveOperationError{ - ResourceType: r.resourceType, - RemoveFromResourceType: r.fromResourceType, + resourceType: r.resourceType, + removeFromResourceType: r.fromResourceType, } } @@ -151,8 +151,8 @@ func (r *RemoveExecutor) removeFromStatus(gtsClient *client.Client) error { doFunc, ok := funcMap[r.resourceType] if !ok { return UnsupportedRemoveOperationError{ - ResourceType: r.resourceType, - RemoveFromResourceType: r.fromResourceType, + resourceType: r.resourceType, + removeFromResourceType: r.fromResourceType, } } diff --git a/internal/executor/show.go b/internal/executor/show.go index 665386a..2c86c6b 100644 --- a/internal/executor/show.go +++ b/internal/executor/show.go @@ -257,8 +257,8 @@ func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error { doFunc, ok := funcMap[s.fromResourceType] if !ok { return UnsupportedShowOperationError{ - ResourceType: s.resourceType, - ShowFromResourceType: s.fromResourceType, + resourceType: s.resourceType, + showFromResourceType: s.fromResourceType, } } @@ -297,8 +297,8 @@ func (s *ShowExecutor) showFollowing(gtsClient *client.Client) error { doFunc, ok := funcMap[s.fromResourceType] if !ok { return UnsupportedShowOperationError{ - ResourceType: s.resourceType, - ShowFromResourceType: s.fromResourceType, + resourceType: s.resourceType, + showFromResourceType: s.fromResourceType, } } @@ -444,8 +444,8 @@ func (s *ShowExecutor) showMedia(gtsClient *client.Client) error { doFunc, ok := funcMap[s.fromResourceType] if !ok { return UnsupportedShowOperationError{ - ResourceType: s.resourceType, - ShowFromResourceType: s.fromResourceType, + resourceType: s.resourceType, + showFromResourceType: s.fromResourceType, } } diff --git a/internal/executor/unmute.go b/internal/executor/unmute.go index d643e46..17a082d 100644 --- a/internal/executor/unmute.go +++ b/internal/executor/unmute.go @@ -1,7 +1,6 @@ package executor import ( - "errors" "fmt" "codeflow.dananglin.me.uk/apollo/enbas/internal/client" @@ -70,7 +69,7 @@ func (m *UnmuteExecutor) unmuteStatus(gtsClient *client.Client) error { } if !canUnmute { - return errors.New("unable to unmute the status because you are not the owner and you are not mentioned in it") + return Error{"unable to unmute the status because you are not the owner and you are not mentioned in it"} } if err := gtsClient.UnmuteStatus(m.statusID); err != nil {