fix: update error handling

Changes:

- Move InvalidListRepliesPolicyError, InvalidTimelineCategory,
  InvalidStatusVisibility and InvalidStatusContentTypeError type to the
  model package.
- Clean up some code in regards to the parsing of the Enum types.
- Clean up the error messages sent back to the user.
- Use colons instead of semicolons when unwrapping error messages.
- Print errors to Standard Error (os.Stderr)
This commit is contained in:
Dan Anglin 2024-06-02 11:35:43 +01:00
parent c05cce9154
commit c6c711c29b
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
31 changed files with 234 additions and 189 deletions

View file

@ -39,7 +39,7 @@ var (
func main() { func main() {
if err := run(); err != nil { if err := run(); err != nil {
fmt.Printf("ERROR: %v.\n", err) fmt.Fprintf(os.Stderr, "ERROR: %v.\n", err)
os.Exit(1) os.Exit(1)
} }
} }
@ -71,7 +71,7 @@ func run() error {
flag.BoolFunc("no-color", "disable ANSI colour output when displaying text on screen", func(value string) error { flag.BoolFunc("no-color", "disable ANSI colour output when displaying text on screen", func(value string) error {
boolVal, err := strconv.ParseBool(value) boolVal, err := strconv.ParseBool(value)
if err != nil { if err != nil {
return fmt.Errorf("unable to parse %q as a boolean; %w", value, err) return fmt.Errorf("unable to parse %q as a boolean: %w", value, err)
} }
topLevelFlags.NoColor = new(bool) topLevelFlags.NoColor = new(bool)
@ -200,7 +200,7 @@ func run() error {
} }
if err != nil { if err != nil {
return fmt.Errorf("received an error executing the command; %w", err) return fmt.Errorf("(%s) %w", command, err)
} }
return nil return nil

View file

@ -20,7 +20,7 @@ func (g *Client) VerifyCredentials() (model.Account, error) {
var account model.Account var account model.Account
if err := g.sendRequest(http.MethodGet, url, nil, &account); err != nil { if err := g.sendRequest(http.MethodGet, url, nil, &account); err != nil {
return model.Account{}, fmt.Errorf("received an error after sending the request to verify the credentials; %w", err) return model.Account{}, fmt.Errorf("received an error after sending the request to verify the credentials: %w", err)
} }
return account, nil return account, nil
@ -33,7 +33,7 @@ func (g *Client) GetAccount(accountURI string) (model.Account, error) {
var account model.Account var account model.Account
if err := g.sendRequest(http.MethodGet, url, nil, &account); err != nil { if err := g.sendRequest(http.MethodGet, url, nil, &account); err != nil {
return model.Account{}, fmt.Errorf("received an error after sending the request to get the account information; %w", err) return model.Account{}, fmt.Errorf("received an error after sending the request to get the account information: %w", err)
} }
return account, nil return account, nil
@ -46,11 +46,11 @@ func (g *Client) GetAccountRelationship(accountID string) (model.AccountRelation
var relationships []model.AccountRelationship var relationships []model.AccountRelationship
if err := g.sendRequest(http.MethodGet, url, nil, &relationships); err != nil { if err := g.sendRequest(http.MethodGet, url, nil, &relationships); err != nil {
return model.AccountRelationship{}, fmt.Errorf("received an error after sending the request to get the account relationship; %w", err) return model.AccountRelationship{}, fmt.Errorf("received an error after sending the request to get the account relationship: %w", err)
} }
if len(relationships) != 1 { if len(relationships) != 1 {
return model.AccountRelationship{}, fmt.Errorf("unexpected number of account relationships returned; want 1, got %d", len(relationships)) return model.AccountRelationship{}, fmt.Errorf("unexpected number of account relationships returned: want 1, got %d", len(relationships))
} }
return relationships[0], nil return relationships[0], nil
@ -65,14 +65,14 @@ type FollowAccountForm struct {
func (g *Client) FollowAccount(form FollowAccountForm) error { func (g *Client) FollowAccount(form FollowAccountForm) error {
data, err := json.Marshal(form) data, err := json.Marshal(form)
if err != nil { if err != nil {
return fmt.Errorf("unable to marshal the form; %w", err) return fmt.Errorf("unable to marshal the form: %w", err)
} }
requestBody := bytes.NewBuffer(data) requestBody := bytes.NewBuffer(data)
url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/follow", form.AccountID) url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/follow", form.AccountID)
if err := g.sendRequest(http.MethodPost, url, requestBody, nil); err != nil { if err := g.sendRequest(http.MethodPost, url, requestBody, nil); err != nil {
return fmt.Errorf("received an error after sending the follow request; %w", err) return fmt.Errorf("received an error after sending the follow request: %w", err)
} }
return nil return nil
@ -82,7 +82,7 @@ func (g *Client) UnfollowAccount(accountID string) error {
url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/unfollow", accountID) url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/unfollow", accountID)
if err := g.sendRequest(http.MethodPost, url, nil, nil); err != nil { if err := g.sendRequest(http.MethodPost, url, nil, nil); err != nil {
return fmt.Errorf("received an error after sending the request to unfollow the account; %w", err) return fmt.Errorf("received an error after sending the request to unfollow the account: %w", err)
} }
return nil return nil
@ -94,7 +94,7 @@ func (g *Client) GetFollowers(accountID string, limit int) (model.AccountList, e
accounts := make([]model.Account, limit) accounts := make([]model.Account, limit)
if err := g.sendRequest(http.MethodGet, url, nil, &accounts); err != nil { 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 followers; %w", err) return model.AccountList{}, fmt.Errorf("received an error after sending the request to get the list of followers: %w", err)
} }
followers := model.AccountList{ followers := model.AccountList{
@ -111,7 +111,7 @@ func (g *Client) GetFollowing(accountID string, limit int) (model.AccountList, e
accounts := make([]model.Account, limit) accounts := make([]model.Account, limit)
if err := g.sendRequest(http.MethodGet, url, nil, &accounts); err != nil { 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 followed accounts; %w", err) return model.AccountList{}, fmt.Errorf("received an error after sending the request to get the list of followed accounts: %w", err)
} }
following := model.AccountList{ following := model.AccountList{
@ -126,7 +126,7 @@ func (g *Client) BlockAccount(accountID string) error {
url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/block", accountID) url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/block", accountID)
if err := g.sendRequest(http.MethodPost, url, nil, nil); err != nil { if err := g.sendRequest(http.MethodPost, url, nil, nil); err != nil {
return fmt.Errorf("received an error after sending the request to block the account; %w", err) return fmt.Errorf("received an error after sending the request to block the account: %w", err)
} }
return nil return nil
@ -136,7 +136,7 @@ func (g *Client) UnblockAccount(accountID string) error {
url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/unblock", accountID) url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/unblock", accountID)
if err := g.sendRequest(http.MethodPost, url, nil, nil); err != nil { if err := g.sendRequest(http.MethodPost, url, nil, nil); err != nil {
return fmt.Errorf("received an error after sending the request to unblock the account; %w", err) return fmt.Errorf("received an error after sending the request to unblock the account: %w", err)
} }
return nil return nil
@ -148,7 +148,7 @@ func (g *Client) GetBlockedAccounts(limit int) (model.AccountList, error) {
accounts := make([]model.Account, limit) accounts := make([]model.Account, limit)
if err := g.sendRequest(http.MethodGet, url, nil, &accounts); err != nil { 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) return model.AccountList{}, fmt.Errorf("received an error after sending the request to get the list of blocked accounts: %w", err)
} }
blocked := model.AccountList{ blocked := model.AccountList{
@ -168,14 +168,14 @@ func (g *Client) SetPrivateNote(accountID, note string) error {
data, err := json.Marshal(form) data, err := json.Marshal(form)
if err != nil { if err != nil {
return fmt.Errorf("unable to marshal the form; %w", err) return fmt.Errorf("unable to marshal the form: %w", err)
} }
requestBody := bytes.NewBuffer(data) requestBody := bytes.NewBuffer(data)
url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/note", accountID) url := g.Authentication.Instance + fmt.Sprintf("/api/v1/accounts/%s/note", accountID)
if err := g.sendRequest(http.MethodPost, url, requestBody, nil); err != nil { if err := g.sendRequest(http.MethodPost, url, requestBody, nil); err != nil {
return fmt.Errorf("received an error after sending the request to set the private note; %w", err) return fmt.Errorf("received an error after sending the request to set the private note: %w", err)
} }
return nil return nil

View file

@ -27,7 +27,7 @@ type Client struct {
func NewClientFromConfig(configDir string) (*Client, error) { func NewClientFromConfig(configDir string) (*Client, error) {
config, err := config.NewCredentialsConfigFromFile(configDir) config, err := config.NewCredentialsConfigFromFile(configDir)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to get the authentication configuration; %w", err) return nil, fmt.Errorf("unable to get the authentication configuration: %w", err)
} }
currentAuthentication := config.Credentials[config.CurrentAccount] currentAuthentication := config.Credentials[config.CurrentAccount]
@ -79,14 +79,14 @@ func (g *Client) sendRequest(method string, url string, requestBody io.Reader, o
response, err := g.HTTPClient.Do(request) response, err := g.HTTPClient.Do(request)
if err != nil { if err != nil {
return fmt.Errorf("received an error after sending the request; %w", err) return fmt.Errorf("received an error after sending the request: %w", err)
} }
defer response.Body.Close() defer response.Body.Close()
if response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusBadRequest { if response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusBadRequest {
return fmt.Errorf( return fmt.Errorf(
"did not receive an OK response from the GoToSocial server; got %d", "did not receive an OK response from the GoToSocial server: got %d",
response.StatusCode, response.StatusCode,
) )
} }
@ -97,7 +97,7 @@ func (g *Client) sendRequest(method string, url string, requestBody io.Reader, o
if err := json.NewDecoder(response.Body).Decode(object); err != nil { if err := json.NewDecoder(response.Body).Decode(object); err != nil {
return fmt.Errorf( return fmt.Errorf(
"unable to decode the response from the GoToSocial server; %w", "unable to decode the response from the GoToSocial server: %w",
err, err,
) )
} }

View file

@ -18,7 +18,7 @@ func (g *Client) GetInstance() (model.InstanceV2, error) {
var instance model.InstanceV2 var instance model.InstanceV2
if err := g.sendRequest(http.MethodGet, url, nil, &instance); err != nil { if err := g.sendRequest(http.MethodGet, url, nil, &instance); err != nil {
return model.InstanceV2{}, fmt.Errorf("received an error after sending the request to get the instance details; %w", err) return model.InstanceV2{}, fmt.Errorf("received an error after sending the request to get the instance details: %w", err)
} }
return instance, nil return instance, nil

View file

@ -24,7 +24,7 @@ func (g *Client) GetAllLists() (model.Lists, error) {
if err := g.sendRequest(http.MethodGet, url, nil, &lists); err != nil { if err := g.sendRequest(http.MethodGet, url, nil, &lists); err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"received an error after sending the request to get the list of lists; %w", "received an error after sending the request to get the list of lists: %w",
err, err,
) )
} }
@ -39,7 +39,7 @@ func (g *Client) GetList(listID string) (model.List, error) {
if err := g.sendRequest(http.MethodGet, url, nil, &list); err != nil { if err := g.sendRequest(http.MethodGet, url, nil, &list); err != nil {
return model.List{}, fmt.Errorf( return model.List{}, fmt.Errorf(
"received an error after sending the request to get the list; %w", "received an error after sending the request to get the list: %w",
err, err,
) )
} }
@ -55,7 +55,7 @@ type CreateListForm struct {
func (g *Client) CreateList(form CreateListForm) (model.List, error) { func (g *Client) CreateList(form CreateListForm) (model.List, error) {
data, err := json.Marshal(form) data, err := json.Marshal(form)
if err != nil { if err != nil {
return model.List{}, fmt.Errorf("unable to marshal the form; %w", err) return model.List{}, fmt.Errorf("unable to marshal the form: %w", err)
} }
requestBody := bytes.NewBuffer(data) requestBody := bytes.NewBuffer(data)
@ -65,7 +65,7 @@ func (g *Client) CreateList(form CreateListForm) (model.List, error) {
if err := g.sendRequest(http.MethodPost, url, requestBody, &list); err != nil { if err := g.sendRequest(http.MethodPost, url, requestBody, &list); err != nil {
return model.List{}, fmt.Errorf( return model.List{}, fmt.Errorf(
"received an error after sending the request to create the list; %w", "received an error after sending the request to create the list: %w",
err, err,
) )
} }
@ -84,7 +84,7 @@ func (g *Client) UpdateList(listToUpdate model.List) (model.List, error) {
data, err := json.Marshal(form) data, err := json.Marshal(form)
if err != nil { if err != nil {
return model.List{}, fmt.Errorf("unable to marshal the form; %w", err) return model.List{}, fmt.Errorf("unable to marshal the form: %w", err)
} }
requestBody := bytes.NewBuffer(data) requestBody := bytes.NewBuffer(data)
@ -94,7 +94,7 @@ func (g *Client) UpdateList(listToUpdate model.List) (model.List, error) {
if err := g.sendRequest(http.MethodPut, url, requestBody, &updatedList); err != nil { if err := g.sendRequest(http.MethodPut, url, requestBody, &updatedList); err != nil {
return model.List{}, fmt.Errorf( return model.List{}, fmt.Errorf(
"received an error after sending the request to update the list; %w", "received an error after sending the request to update the list: %w",
err, err,
) )
} }
@ -117,7 +117,7 @@ func (g *Client) AddAccountsToList(listID string, accountIDs []string) error {
data, err := json.Marshal(form) data, err := json.Marshal(form)
if err != nil { if err != nil {
return fmt.Errorf("unable to marshal the form; %w", err) return fmt.Errorf("unable to marshal the form: %w", err)
} }
requestBody := bytes.NewBuffer(data) requestBody := bytes.NewBuffer(data)
@ -125,7 +125,7 @@ func (g *Client) AddAccountsToList(listID string, accountIDs []string) error {
if err := g.sendRequest(http.MethodPost, url, requestBody, nil); err != nil { if err := g.sendRequest(http.MethodPost, url, requestBody, nil); err != nil {
return fmt.Errorf( return fmt.Errorf(
"received an error after sending the request to add the accounts to the list; %w", "received an error after sending the request to add the accounts to the list: %w",
err, err,
) )
} }
@ -142,7 +142,7 @@ func (g *Client) RemoveAccountsFromList(listID string, accountIDs []string) erro
data, err := json.Marshal(form) data, err := json.Marshal(form)
if err != nil { if err != nil {
return fmt.Errorf("unable to marshal the form; %w", err) return fmt.Errorf("unable to marshal the form: %w", err)
} }
requestBody := bytes.NewBuffer(data) requestBody := bytes.NewBuffer(data)
@ -150,7 +150,7 @@ func (g *Client) RemoveAccountsFromList(listID string, accountIDs []string) erro
if err := g.sendRequest(http.MethodDelete, url, requestBody, nil); err != nil { if err := g.sendRequest(http.MethodDelete, url, requestBody, nil); err != nil {
return fmt.Errorf( return fmt.Errorf(
"received an error after sending the request to remove the accounts from the list; %w", "received an error after sending the request to remove the accounts from the list: %w",
err, err,
) )
} }
@ -166,7 +166,7 @@ func (g *Client) GetAccountsFromList(listID string, limit int) ([]model.Account,
if err := g.sendRequest(http.MethodGet, url, nil, &accounts); err != nil { if err := g.sendRequest(http.MethodGet, url, nil, &accounts); err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"received an error after sending the request to get the accounts from the list; %w", "received an error after sending the request to get the accounts from the list: %w",
err, err,
) )
} }

View file

@ -17,7 +17,7 @@ func (g *Client) GetUserPreferences() (model.Preferences, error) {
var preferences model.Preferences var preferences model.Preferences
if err := g.sendRequest(http.MethodGet, url, nil, &preferences); err != nil { if err := g.sendRequest(http.MethodGet, url, nil, &preferences); err != nil {
return model.Preferences{}, fmt.Errorf("received an error after sending the request to get the user preferences; %w", err) return model.Preferences{}, fmt.Errorf("received an error after sending the request to get the user preferences: %w", err)
} }
return preferences, nil return preferences, nil

View file

@ -31,7 +31,7 @@ func (g *Client) Register() error {
data, err := json.Marshal(params) data, err := json.Marshal(params)
if err != nil { if err != nil {
return fmt.Errorf("unable to marshal the request body; %w", err) return fmt.Errorf("unable to marshal the request body: %w", err)
} }
requestBody := bytes.NewBuffer(data) requestBody := bytes.NewBuffer(data)
@ -40,7 +40,7 @@ func (g *Client) Register() error {
var app model.Application var app model.Application
if err := g.sendRequest(http.MethodPost, url, requestBody, &app); err != nil { if err := g.sendRequest(http.MethodPost, url, requestBody, &app); err != nil {
return fmt.Errorf("received an error after sending the registration request; %w", err) return fmt.Errorf("received an error after sending the registration request: %w", err)
} }
g.Authentication.ClientID = app.ClientID g.Authentication.ClientID = app.ClientID

View file

@ -21,7 +21,7 @@ func (g *Client) GetStatus(statusID string) (model.Status, error) {
if err := g.sendRequest(http.MethodGet, url, nil, &status); err != nil { if err := g.sendRequest(http.MethodGet, url, nil, &status); err != nil {
return model.Status{}, fmt.Errorf( return model.Status{}, fmt.Errorf(
"received an error after sending the request to get the status information; %w", "received an error after sending the request to get the status information: %w",
err, err,
) )
} }
@ -45,7 +45,7 @@ type CreateStatusForm struct {
func (g *Client) CreateStatus(form CreateStatusForm) (model.Status, error) { func (g *Client) CreateStatus(form CreateStatusForm) (model.Status, error) {
data, err := json.Marshal(form) data, err := json.Marshal(form)
if err != nil { if err != nil {
return model.Status{}, fmt.Errorf("unable to create the JSON form; %w", err) return model.Status{}, fmt.Errorf("unable to create the JSON form: %w", err)
} }
requestBody := bytes.NewBuffer(data) requestBody := bytes.NewBuffer(data)
@ -55,7 +55,7 @@ func (g *Client) CreateStatus(form CreateStatusForm) (model.Status, error) {
if err := g.sendRequest(http.MethodPost, url, requestBody, &status); err != nil { if err := g.sendRequest(http.MethodPost, url, requestBody, &status); err != nil {
return model.Status{}, fmt.Errorf( return model.Status{}, fmt.Errorf(
"received an error after sending the request to create the status; %w", "received an error after sending the request to create the status: %w",
err, err,
) )
} }

View file

@ -61,7 +61,7 @@ func (g *Client) getTimeline(path string, timeline model.Timeline) (model.Timeli
var statuses []model.Status var statuses []model.Status
if err := g.sendRequest(http.MethodGet, url, nil, &statuses); err != nil { if err := g.sendRequest(http.MethodGet, url, nil, &statuses); err != nil {
return timeline, fmt.Errorf("received an error after sending the request to get the timeline; %w", err) return timeline, fmt.Errorf("received an error after sending the request to get the timeline: %w", err)
} }
timeline.Statuses = statuses timeline.Statuses = statuses

View file

@ -42,7 +42,7 @@ func (g *Client) UpdateToken(code string) error {
data, err := json.Marshal(params) data, err := json.Marshal(params)
if err != nil { if err != nil {
return fmt.Errorf("unable to marshal the request body; %w", err) return fmt.Errorf("unable to marshal the request body: %w", err)
} }
requestBody := bytes.NewBuffer(data) requestBody := bytes.NewBuffer(data)
@ -51,7 +51,7 @@ func (g *Client) UpdateToken(code string) error {
var response tokenResponse var response tokenResponse
if err := g.sendRequest(http.MethodPost, url, requestBody, &response); err != nil { if err := g.sendRequest(http.MethodPost, url, requestBody, &response); err != nil {
return fmt.Errorf("received an error after sending the token request; %w", err) return fmt.Errorf("received an error after sending the token request: %w", err)
} }
if response.AccessToken == "" { if response.AccessToken == "" {

View file

@ -42,7 +42,7 @@ func (e CredentialsNotFoundError) Error() string {
// is not present, it will be created. // is not present, it will be created.
func SaveCredentials(configDir, username string, credentials Credentials) (string, error) { func SaveCredentials(configDir, username string, credentials Credentials) (string, error) {
if err := ensureConfigDir(calculateConfigDir(configDir)); err != nil { if err := ensureConfigDir(calculateConfigDir(configDir)); err != nil {
return "", fmt.Errorf("unable to ensure the configuration directory; %w", err) return "", fmt.Errorf("unable to ensure the configuration directory: %w", err)
} }
var authConfig CredentialsConfig var authConfig CredentialsConfig
@ -51,14 +51,14 @@ func SaveCredentials(configDir, username string, credentials Credentials) (strin
if _, err := os.Stat(filepath); err != nil { if _, err := os.Stat(filepath); err != nil {
if !errors.Is(err, os.ErrNotExist) { if !errors.Is(err, os.ErrNotExist) {
return "", fmt.Errorf("unknown error received when running stat on %s; %w", filepath, err) return "", fmt.Errorf("unknown error received when running stat on %s: %w", filepath, err)
} }
authConfig.Credentials = make(map[string]Credentials) authConfig.Credentials = make(map[string]Credentials)
} else { } else {
authConfig, err = NewCredentialsConfigFromFile(configDir) authConfig, err = NewCredentialsConfigFromFile(configDir)
if err != nil { if err != nil {
return "", fmt.Errorf("unable to retrieve the existing authentication configuration; %w", err) return "", fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
} }
} }
@ -77,7 +77,7 @@ func SaveCredentials(configDir, username string, credentials Credentials) (strin
authConfig.Credentials[authenticationName] = credentials authConfig.Credentials[authenticationName] = credentials
if err := saveCredentialsConfigFile(authConfig, configDir); err != nil { if err := saveCredentialsConfigFile(authConfig, configDir); err != nil {
return "", fmt.Errorf("unable to save the authentication configuration to file; %w", err) return "", fmt.Errorf("unable to save the authentication configuration to file: %w", err)
} }
return authenticationName, nil return authenticationName, nil
@ -86,7 +86,7 @@ func SaveCredentials(configDir, username string, credentials Credentials) (strin
func UpdateCurrentAccount(account string, configDir string) error { func UpdateCurrentAccount(account string, configDir string) error {
credentialsConfig, err := NewCredentialsConfigFromFile(configDir) credentialsConfig, err := NewCredentialsConfigFromFile(configDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the existing authentication configuration; %w", err) return fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
} }
if _, ok := credentialsConfig.Credentials[account]; !ok { if _, ok := credentialsConfig.Credentials[account]; !ok {
@ -96,7 +96,7 @@ func UpdateCurrentAccount(account string, configDir string) error {
credentialsConfig.CurrentAccount = account credentialsConfig.CurrentAccount = account
if err := saveCredentialsConfigFile(credentialsConfig, configDir); err != nil { if err := saveCredentialsConfigFile(credentialsConfig, configDir); err != nil {
return fmt.Errorf("unable to save the authentication configuration to file; %w", err) return fmt.Errorf("unable to save the authentication configuration to file: %w", err)
} }
return nil return nil
@ -114,7 +114,7 @@ func NewCredentialsConfigFromFile(configDir string) (CredentialsConfig, error) {
var authConfig CredentialsConfig var authConfig CredentialsConfig
if err := json.NewDecoder(file).Decode(&authConfig); err != nil { if err := json.NewDecoder(file).Decode(&authConfig); err != nil {
return CredentialsConfig{}, fmt.Errorf("unable to decode the JSON data; %w", err) return CredentialsConfig{}, fmt.Errorf("unable to decode the JSON data: %w", err)
} }
return authConfig, nil return authConfig, nil
@ -125,7 +125,7 @@ func saveCredentialsConfigFile(authConfig CredentialsConfig, configDir string) e
file, err := os.Create(path) file, err := os.Create(path)
if err != nil { if err != nil {
return fmt.Errorf("unable to open %s; %w", path, err) return fmt.Errorf("unable to open %s: %w", path, err)
} }
defer file.Close() defer file.Close()
@ -134,7 +134,7 @@ func saveCredentialsConfigFile(authConfig CredentialsConfig, configDir string) e
encoder.SetIndent("", " ") encoder.SetIndent("", " ")
if err := encoder.Encode(authConfig); err != nil { if err := encoder.Encode(authConfig); err != nil {
return fmt.Errorf("unable to save the JSON data to the authentication config file; %w", err) return fmt.Errorf("unable to save the JSON data to the authentication config file: %w", err)
} }
return nil return nil

View file

@ -30,10 +30,10 @@ func ensureConfigDir(configDir string) error {
if _, err := os.Stat(configDir); err != nil { if _, err := os.Stat(configDir); err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
if err := os.MkdirAll(configDir, 0o750); err != nil { if err := os.MkdirAll(configDir, 0o750); err != nil {
return fmt.Errorf("unable to create %s; %w", configDir, err) return fmt.Errorf("unable to create %s: %w", configDir, err)
} }
} else { } else {
return fmt.Errorf("unknown error received when running stat on %s; %w", configDir, err) return fmt.Errorf("unknown error received after getting the config directory information: %w", err)
} }
} }

View file

@ -22,12 +22,12 @@ func getAccountID(gtsClient *client.Client, myAccount bool, accountName, configD
case myAccount: case myAccount:
accountID, err = getMyAccountID(gtsClient, configDir) accountID, err = getMyAccountID(gtsClient, configDir)
if err != nil { if err != nil {
return "", fmt.Errorf("unable to get your account ID; %w", err) return "", fmt.Errorf("unable to get your account ID: %w", err)
} }
case accountName != "": case accountName != "":
accountID, err = getTheirAccountID(gtsClient, accountName) accountID, err = getTheirAccountID(gtsClient, accountName)
if err != nil { if err != nil {
return "", fmt.Errorf("unable to get their account ID; %w", err) return "", fmt.Errorf("unable to get their account ID: %w", err)
} }
default: default:
return "", NoAccountSpecifiedError{} return "", NoAccountSpecifiedError{}
@ -39,7 +39,7 @@ func getAccountID(gtsClient *client.Client, myAccount bool, accountName, configD
func getTheirAccountID(gtsClient *client.Client, accountURI string) (string, error) { func getTheirAccountID(gtsClient *client.Client, accountURI string) (string, error) {
account, err := getAccount(gtsClient, accountURI) account, err := getAccount(gtsClient, accountURI)
if err != nil { if err != nil {
return "", fmt.Errorf("unable to retrieve your account; %w", err) return "", fmt.Errorf("unable to retrieve your account: %w", err)
} }
return account.ID, nil return account.ID, nil
@ -48,7 +48,7 @@ func getTheirAccountID(gtsClient *client.Client, accountURI string) (string, err
func getMyAccountID(gtsClient *client.Client, configDir string) (string, error) { func getMyAccountID(gtsClient *client.Client, configDir string) (string, error) {
account, err := getMyAccount(gtsClient, configDir) account, err := getMyAccount(gtsClient, configDir)
if err != nil { if err != nil {
return "", fmt.Errorf("received an error while getting your account details; %w", err) return "", fmt.Errorf("received an error while getting your account details: %w", err)
} }
return account.ID, nil return account.ID, nil
@ -57,14 +57,14 @@ func getMyAccountID(gtsClient *client.Client, configDir string) (string, error)
func getMyAccount(gtsClient *client.Client, configDir string) (model.Account, error) { func getMyAccount(gtsClient *client.Client, configDir string) (model.Account, error) {
authConfig, err := config.NewCredentialsConfigFromFile(configDir) authConfig, err := config.NewCredentialsConfigFromFile(configDir)
if err != nil { if err != nil {
return model.Account{}, fmt.Errorf("unable to retrieve the authentication configuration; %w", err) return model.Account{}, fmt.Errorf("unable to retrieve the authentication configuration: %w", err)
} }
accountURI := authConfig.CurrentAccount accountURI := authConfig.CurrentAccount
account, err := getAccount(gtsClient, accountURI) account, err := getAccount(gtsClient, accountURI)
if err != nil { if err != nil {
return model.Account{}, fmt.Errorf("unable to retrieve your account; %w", err) return model.Account{}, fmt.Errorf("unable to retrieve your account: %w", err)
} }
return account, nil return account, nil
@ -73,7 +73,7 @@ func getMyAccount(gtsClient *client.Client, configDir string) (model.Account, er
func getAccount(gtsClient *client.Client, accountURI string) (model.Account, error) { func getAccount(gtsClient *client.Client, accountURI string) (model.Account, error) {
account, err := gtsClient.GetAccount(accountURI) account, err := gtsClient.GetAccount(accountURI)
if err != nil { if err != nil {
return model.Account{}, fmt.Errorf("unable to retrieve the account details; %w", err) return model.Account{}, fmt.Errorf("unable to retrieve the account details: %w", err)
} }
return account, nil return account, nil

View file

@ -59,7 +59,7 @@ func (a *AddExecutor) Execute() error {
gtsClient, err := client.NewClientFromConfig(a.topLevelFlags.ConfigDir) gtsClient, err := client.NewClientFromConfig(a.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to create the GoToSocial client; %w", err) return fmt.Errorf("unable to create the GoToSocial client: %w", err)
} }
return doFunc(gtsClient) return doFunc(gtsClient)
@ -102,7 +102,7 @@ func (a *AddExecutor) addAccountsToList(gtsClient *client.Client) error {
} }
if err := gtsClient.AddAccountsToList(a.listID, accountIDs); err != nil { if err := gtsClient.AddAccountsToList(a.listID, accountIDs); err != nil {
return fmt.Errorf("unable to add the accounts to the list; %w", err) return fmt.Errorf("unable to add the accounts to the list: %w", err)
} }
fmt.Println("Successfully added the account(s) to the list.") fmt.Println("Successfully added the account(s) to the list.")
@ -128,12 +128,12 @@ func (a *AddExecutor) addToAccount(gtsClient *client.Client) error {
func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error { func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error {
if len(a.accountNames) != 1 { if len(a.accountNames) != 1 {
return fmt.Errorf("unexpected number of accounts specified; want 1, got %d", len(a.accountNames)) return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(a.accountNames))
} }
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.topLevelFlags.ConfigDir) accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID; %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }
if a.content == "" { if a.content == "" {
@ -144,7 +144,7 @@ func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error {
} }
if err := gtsClient.SetPrivateNote(accountID, a.content); err != nil { if err := gtsClient.SetPrivateNote(accountID, a.content); err != nil {
return fmt.Errorf("unable to add the private note to the account; %w", err) return fmt.Errorf("unable to add the private note to the account: %w", err)
} }
fmt.Println("Successfully added the private note to the account.") fmt.Println("Successfully added the private note to the account.")

View file

@ -48,7 +48,7 @@ func (b *BlockExecutor) Execute() error {
gtsClient, err := client.NewClientFromConfig(b.topLevelFlags.ConfigDir) gtsClient, err := client.NewClientFromConfig(b.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to create the GoToSocial client; %w", err) return fmt.Errorf("unable to create the GoToSocial client: %w", err)
} }
return doFunc(gtsClient) return doFunc(gtsClient)
@ -57,7 +57,7 @@ func (b *BlockExecutor) Execute() error {
func (b *BlockExecutor) blockAccount(gtsClient *client.Client) error { func (b *BlockExecutor) blockAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, b.accountName, b.topLevelFlags.ConfigDir) accountID, err := getAccountID(gtsClient, false, b.accountName, b.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID; %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }
if b.unblock { if b.unblock {
@ -65,7 +65,7 @@ func (b *BlockExecutor) blockAccount(gtsClient *client.Client) error {
} }
if err := gtsClient.BlockAccount(accountID); err != nil { if err := gtsClient.BlockAccount(accountID); err != nil {
return fmt.Errorf("unable to block the account; %w", err) return fmt.Errorf("unable to block the account: %w", err)
} }
fmt.Println("Successfully blocked the account.") fmt.Println("Successfully blocked the account.")
@ -75,7 +75,7 @@ func (b *BlockExecutor) blockAccount(gtsClient *client.Client) error {
func (b *BlockExecutor) unblockAccount(gtsClient *client.Client, accountID string) error { func (b *BlockExecutor) unblockAccount(gtsClient *client.Client, accountID string) error {
if err := gtsClient.UnblockAccount(accountID); err != nil { if err := gtsClient.UnblockAccount(accountID); err != nil {
return fmt.Errorf("unable to unblock the account; %w", err) return fmt.Errorf("unable to unblock the account: %w", err)
} }
fmt.Println("Successfully unblocked the account.") fmt.Println("Successfully unblocked the account.")

View file

@ -58,7 +58,7 @@ func NewCreateExecutor(tlf TopLevelFlags, name, summary string) *CreateExecutor
createExe.BoolFunc(flagSensitive, "specify if the status should be marked as sensitive", func(value string) error { createExe.BoolFunc(flagSensitive, "specify if the status should be marked as sensitive", func(value string) error {
boolVal, err := strconv.ParseBool(value) boolVal, err := strconv.ParseBool(value)
if err != nil { if err != nil {
return fmt.Errorf("unable to parse %q as a boolean value; %w", value, err) return fmt.Errorf("unable to parse %q as a boolean value: %w", value, err)
} }
createExe.sensitive = new(bool) createExe.sensitive = new(bool)
@ -79,7 +79,7 @@ func (c *CreateExecutor) Execute() error {
gtsClient, err := client.NewClientFromConfig(c.topLevelFlags.ConfigDir) gtsClient, err := client.NewClientFromConfig(c.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to create the GoToSocial client; %w", err) return fmt.Errorf("unable to create the GoToSocial client: %w", err)
} }
funcMap := map[string]func(*client.Client) error{ funcMap := map[string]func(*client.Client) error{
@ -100,9 +100,9 @@ func (c *CreateExecutor) createList(gtsClient *client.Client) error {
return FlagNotSetError{flagText: flagListTitle} return FlagNotSetError{flagText: flagListTitle}
} }
parsedListRepliesPolicy := model.ParseListRepliesPolicy(c.listRepliesPolicy) parsedListRepliesPolicy, err := model.ParseListRepliesPolicy(c.listRepliesPolicy)
if parsedListRepliesPolicy == model.ListRepliesPolicyUnknown { if err != nil {
return InvalidListRepliesPolicyError{Policy: c.listRepliesPolicy} return err
} }
form := client.CreateListForm{ form := client.CreateListForm{
@ -112,7 +112,7 @@ func (c *CreateExecutor) createList(gtsClient *client.Client) error {
list, err := gtsClient.CreateList(form) list, err := gtsClient.CreateList(form)
if err != nil { if err != nil {
return fmt.Errorf("unable to create the list; %w", err) return fmt.Errorf("unable to create the list: %w", err)
} }
fmt.Println("Successfully created the following list:") fmt.Println("Successfully created the following list:")
@ -136,7 +136,7 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
case c.fromFile != "": case c.fromFile != "":
content, err = utilities.ReadFile(c.fromFile) content, err = utilities.ReadFile(c.fromFile)
if err != nil { if err != nil {
return fmt.Errorf("unable to get the status contents from %q; %w", c.fromFile, err) return fmt.Errorf("unable to get the status contents from %q: %w", c.fromFile, err)
} }
default: default:
return EmptyContentError{ return EmptyContentError{
@ -147,7 +147,7 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
preferences, err := gtsClient.GetUserPreferences() preferences, err := gtsClient.GetUserPreferences()
if err != nil { if err != nil {
fmt.Println("WARNING: Unable to get your posting preferences; %w", err) fmt.Println("WARNING: Unable to get your posting preferences: %w", err)
} }
if c.language != "" { if c.language != "" {
@ -168,14 +168,14 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
sensitive = preferences.PostingDefaultSensitive sensitive = preferences.PostingDefaultSensitive
} }
parsedVisibility := model.ParseStatusVisibility(visibility) parsedVisibility, err := model.ParseStatusVisibility(visibility)
if parsedVisibility == model.StatusVisibilityUnknown { if err != nil {
return InvalidStatusVisibilityError{Visibility: visibility} return err
} }
parsedContentType := model.ParseStatusContentType(c.contentType) parsedContentType, err := model.ParseStatusContentType(c.contentType)
if parsedContentType == model.StatusContentTypeUnknown { if err != nil {
return InvalidStatusContentTypeError{ContentType: c.contentType} return err
} }
form := client.CreateStatusForm{ form := client.CreateStatusForm{
@ -193,7 +193,7 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
status, err := gtsClient.CreateStatus(form) status, err := gtsClient.CreateStatus(form)
if err != nil { if err != nil {
return fmt.Errorf("unable to create the status; %w", err) return fmt.Errorf("unable to create the status: %w", err)
} }
fmt.Println("Successfully created the following status:") fmt.Println("Successfully created the following status:")

View file

@ -49,7 +49,7 @@ func (d *DeleteExecutor) Execute() error {
gtsClient, err := client.NewClientFromConfig(d.topLevelFlags.ConfigDir) gtsClient, err := client.NewClientFromConfig(d.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to create the GoToSocial client; %w", err) return fmt.Errorf("unable to create the GoToSocial client: %w", err)
} }
return doFunc(gtsClient) return doFunc(gtsClient)
@ -61,7 +61,7 @@ func (d *DeleteExecutor) deleteList(gtsClient *client.Client) error {
} }
if err := gtsClient.DeleteList(d.listID); err != nil { if err := gtsClient.DeleteList(d.listID); err != nil {
return fmt.Errorf("unable to delete the list; %w", err) return fmt.Errorf("unable to delete the list: %w", err)
} }
fmt.Println("The list was successfully deleted.") fmt.Println("The list was successfully deleted.")

View file

@ -55,7 +55,7 @@ func (e *EditExecutor) Execute() error {
gtsClient, err := client.NewClientFromConfig(e.topLevelFlags.ConfigDir) gtsClient, err := client.NewClientFromConfig(e.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to create the GoToSocial client; %w", err) return fmt.Errorf("unable to create the GoToSocial client: %w", err)
} }
return doFunc(gtsClient) return doFunc(gtsClient)
@ -68,7 +68,7 @@ func (e *EditExecutor) editList(gtsClient *client.Client) error {
list, err := gtsClient.GetList(e.listID) list, err := gtsClient.GetList(e.listID)
if err != nil { if err != nil {
return fmt.Errorf("unable to get the list; %w", err) return fmt.Errorf("unable to get the list: %w", err)
} }
if e.listTitle != "" { if e.listTitle != "" {
@ -76,9 +76,9 @@ func (e *EditExecutor) editList(gtsClient *client.Client) error {
} }
if e.listRepliesPolicy != "" { if e.listRepliesPolicy != "" {
parsedListRepliesPolicy := model.ParseListRepliesPolicy(e.listRepliesPolicy) parsedListRepliesPolicy, err := model.ParseListRepliesPolicy(e.listRepliesPolicy)
if parsedListRepliesPolicy == model.ListRepliesPolicyUnknown { if err != nil {
return InvalidListRepliesPolicyError{Policy: e.listRepliesPolicy} return err
} }
list.RepliesPolicy = parsedListRepliesPolicy list.RepliesPolicy = parsedListRepliesPolicy
@ -86,7 +86,7 @@ func (e *EditExecutor) editList(gtsClient *client.Client) error {
updatedList, err := gtsClient.UpdateList(list) updatedList, err := gtsClient.UpdateList(list)
if err != nil { if err != nil {
return fmt.Errorf("unable to update the list; %w", err) return fmt.Errorf("unable to update the list: %w", err)
} }
fmt.Println("Successfully updated the list.") fmt.Println("Successfully updated the list.")

View file

@ -9,7 +9,7 @@ type FlagNotSetError struct {
} }
func (e FlagNotSetError) Error() string { func (e FlagNotSetError) Error() string {
return "the flag '" + e.flagText + "' is not set" return "please use the required --" + e.flagText + " flag"
} }
type UnsupportedTypeError struct { type UnsupportedTypeError struct {
@ -17,15 +17,7 @@ type UnsupportedTypeError struct {
} }
func (e UnsupportedTypeError) Error() string { func (e UnsupportedTypeError) Error() string {
return "unsupported resource type '" + e.resourceType + "'" return "'" + e.resourceType + "' is not supported for this operation"
}
type InvalidTimelineCategoryError struct {
category string
}
func (e InvalidTimelineCategoryError) Error() string {
return "'" + e.category + "' is not a valid timeline category (please choose home, public, tag or list)"
} }
type NoAccountSpecifiedError struct{} type NoAccountSpecifiedError struct{}
@ -52,7 +44,7 @@ func (e UnsupportedRemoveOperationError) Error() string {
return "removing '" + e.ResourceType + "' from '" + e.RemoveFromResourceType + "' is not supported" return "removing '" + e.ResourceType + "' from '" + e.RemoveFromResourceType + "' is not supported"
} }
type EmptyContentError struct{ type EmptyContentError struct {
ResourceType string ResourceType string
Hint string Hint string
} }
@ -66,27 +58,3 @@ func (e EmptyContentError) Error() string {
return message return message
} }
type InvalidStatusVisibilityError struct {
Visibility string
}
func (e InvalidStatusVisibilityError) Error() string {
return "'" + e.Visibility + "' is an invalid status visibility (valid values are public, unlisted, private, mutuals_only and direct)"
}
type InvalidStatusContentTypeError struct {
ContentType string
}
func (e InvalidStatusContentTypeError) Error() string {
return "'" + e.ContentType + "' is an invalid status content type (valid values are plain and markdown)"
}
type InvalidListRepliesPolicyError struct {
Policy string
}
func (e InvalidListRepliesPolicyError) Error() string {
return "'" + e.Policy + "' is an invalid list replies policy"
}

View file

@ -14,11 +14,11 @@ type Executor interface {
func Execute(executor Executor, args []string) error { func Execute(executor Executor, args []string) error {
if err := executor.Parse(args); err != nil { if err := executor.Parse(args); err != nil {
return fmt.Errorf("unable to parse the command line flags; %w", err) return fmt.Errorf("flag parsing error: %w", err)
} }
if err := executor.Execute(); err != nil { if err := executor.Execute(); err != nil {
return fmt.Errorf("unable to execute the command %q; %w", executor.Name(), err) return fmt.Errorf("execution error: %w", err)
} }
return nil return nil

View file

@ -51,7 +51,7 @@ func (c *FollowExecutor) Execute() error {
gtsClient, err := client.NewClientFromConfig(c.topLevelFlags.ConfigDir) gtsClient, err := client.NewClientFromConfig(c.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to create the GoToSocial client; %w", err) return fmt.Errorf("unable to create the GoToSocial client: %w", err)
} }
return doFunc(gtsClient) return doFunc(gtsClient)
@ -60,7 +60,7 @@ func (c *FollowExecutor) Execute() error {
func (c *FollowExecutor) followAccount(gtsClient *client.Client) error { func (c *FollowExecutor) followAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, c.accountName, c.topLevelFlags.ConfigDir) accountID, err := getAccountID(gtsClient, false, c.accountName, c.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID; %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }
if c.unfollow { if c.unfollow {
@ -74,7 +74,7 @@ func (c *FollowExecutor) followAccount(gtsClient *client.Client) error {
} }
if err := gtsClient.FollowAccount(form); err != nil { if err := gtsClient.FollowAccount(form); err != nil {
return fmt.Errorf("unable to follow the account; %w", err) return fmt.Errorf("unable to follow the account: %w", err)
} }
fmt.Println("The follow request was sent successfully.") fmt.Println("The follow request was sent successfully.")
@ -84,7 +84,7 @@ func (c *FollowExecutor) followAccount(gtsClient *client.Client) error {
func (c *FollowExecutor) unfollowAccount(gtsClient *client.Client, accountID string) error { func (c *FollowExecutor) unfollowAccount(gtsClient *client.Client, accountID string) error {
if err := gtsClient.UnfollowAccount(accountID); err != nil { if err := gtsClient.UnfollowAccount(accountID); err != nil {
return fmt.Errorf("unable to unfollow the account; %w", err) return fmt.Errorf("unable to unfollow the account: %w", err)
} }
fmt.Println("Successfully unfollowed the account.") fmt.Println("Successfully unfollowed the account.")

View file

@ -59,7 +59,7 @@ func (c *LoginExecutor) Execute() error {
gtsClient := client.NewClient(credentials) gtsClient := client.NewClient(credentials)
if err := gtsClient.Register(); err != nil { if err := gtsClient.Register(); err != nil {
return fmt.Errorf("unable to register the application; %w", err) return fmt.Errorf("unable to register the application: %w", err)
} }
consentPageURL := gtsClient.AuthCodeURL() consentPageURL := gtsClient.AuthCodeURL()
@ -83,21 +83,21 @@ Once you have the code please copy and paste it below.
fmt.Print("Out-of-band token: ") fmt.Print("Out-of-band token: ")
if _, err := fmt.Scanln(&code); err != nil { if _, err := fmt.Scanln(&code); err != nil {
return fmt.Errorf("failed to read access code; %w", err) return fmt.Errorf("failed to read access code: %w", err)
} }
if err := gtsClient.UpdateToken(code); err != nil { if err := gtsClient.UpdateToken(code); err != nil {
return fmt.Errorf("unable to update the client's access token; %w", err) return fmt.Errorf("unable to update the client's access token: %w", err)
} }
account, err := gtsClient.VerifyCredentials() account, err := gtsClient.VerifyCredentials()
if err != nil { if err != nil {
return fmt.Errorf("unable to verify the credentials; %w", err) return fmt.Errorf("unable to verify the credentials: %w", err)
} }
loginName, err := config.SaveCredentials(c.topLevelFlags.ConfigDir, account.Username, gtsClient.Authentication) loginName, err := config.SaveCredentials(c.topLevelFlags.ConfigDir, account.Username, gtsClient.Authentication)
if err != nil { if err != nil {
return fmt.Errorf("unable to save the authentication details; %w", err) return fmt.Errorf("unable to save the authentication details: %w", err)
} }
fmt.Printf("Successfully logged into %s\n", loginName) fmt.Printf("Successfully logged into %s\n", loginName)

View file

@ -57,7 +57,7 @@ func (r *RemoveExecutor) Execute() error {
gtsClient, err := client.NewClientFromConfig(r.topLevelFlags.ConfigDir) gtsClient, err := client.NewClientFromConfig(r.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to create the GoToSocial client; %w", err) return fmt.Errorf("unable to create the GoToSocial client: %w", err)
} }
return doFunc(gtsClient) return doFunc(gtsClient)
@ -100,7 +100,7 @@ func (r *RemoveExecutor) removeAccountsFromList(gtsClient *client.Client) error
} }
if err := gtsClient.RemoveAccountsFromList(r.listID, accountIDs); err != nil { if err := gtsClient.RemoveAccountsFromList(r.listID, accountIDs); err != nil {
return fmt.Errorf("unable to remove the accounts from the list; %w", err) return fmt.Errorf("unable to remove the accounts from the list: %w", err)
} }
fmt.Println("Successfully removed the account(s) from the list.") fmt.Println("Successfully removed the account(s) from the list.")
@ -126,16 +126,16 @@ func (r *RemoveExecutor) removeFromAccount(gtsClient *client.Client) error {
func (r *RemoveExecutor) removeNoteFromAccount(gtsClient *client.Client) error { func (r *RemoveExecutor) removeNoteFromAccount(gtsClient *client.Client) error {
if len(r.accountNames) != 1 { if len(r.accountNames) != 1 {
return fmt.Errorf("unexpected number of accounts specified; want 1, got %d", len(r.accountNames)) return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(r.accountNames))
} }
accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.topLevelFlags.ConfigDir) accountID, err := getAccountID(gtsClient, false, r.accountNames[0], r.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID; %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }
if err := gtsClient.SetPrivateNote(accountID, ""); err != nil { if err := gtsClient.SetPrivateNote(accountID, ""); err != nil {
return fmt.Errorf("unable to remove the private note from the account; %w", err) return fmt.Errorf("unable to remove the private note from the account: %w", err)
} }
fmt.Println("Successfully removed the private note from the account.") fmt.Println("Successfully removed the private note from the account.")

View file

@ -42,7 +42,7 @@ func NewShowExecutor(tlf TopLevelFlags, name, summary string) *ShowExecutor {
command.StringVar(&command.resourceType, flagType, "", "specify the type of resource to display") command.StringVar(&command.resourceType, flagType, "", "specify the type of resource to display")
command.StringVar(&command.accountName, flagAccountName, "", "specify the account name in full (username@domain)") command.StringVar(&command.accountName, flagAccountName, "", "specify the account name in full (username@domain)")
command.StringVar(&command.statusID, flagStatusID, "", "specify the ID of the status to display") command.StringVar(&command.statusID, flagStatusID, "", "specify the ID of the status to display")
command.StringVar(&command.timelineCategory, flagTimelineCategory, "home", "specify the type of timeline to display (valid values are home, public, list and tag)") command.StringVar(&command.timelineCategory, flagTimelineCategory, model.TimelineCategoryHome, "specify the timeline category to view")
command.StringVar(&command.listID, flagListID, "", "specify the ID of the list to display") command.StringVar(&command.listID, flagListID, "", "specify the ID of the list to display")
command.StringVar(&command.tag, flagTag, "", "specify the name of the tag to use") command.StringVar(&command.tag, flagTag, "", "specify the name of the tag to use")
command.IntVar(&command.limit, flagLimit, 20, "specify the limit of items to display") command.IntVar(&command.limit, flagLimit, 20, "specify the limit of items to display")
@ -75,7 +75,7 @@ func (c *ShowExecutor) Execute() error {
gtsClient, err := client.NewClientFromConfig(c.topLevelFlags.ConfigDir) gtsClient, err := client.NewClientFromConfig(c.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to create the GoToSocial client; %w", err) return fmt.Errorf("unable to create the GoToSocial client: %w", err)
} }
return doFunc(gtsClient) return doFunc(gtsClient)
@ -84,7 +84,7 @@ func (c *ShowExecutor) Execute() error {
func (c *ShowExecutor) showInstance(gtsClient *client.Client) error { func (c *ShowExecutor) showInstance(gtsClient *client.Client) error {
instance, err := gtsClient.GetInstance() instance, err := gtsClient.GetInstance()
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the instance details; %w", err) return fmt.Errorf("unable to retrieve the instance details: %w", err)
} }
utilities.Display(instance, *c.topLevelFlags.NoColor) utilities.Display(instance, *c.topLevelFlags.NoColor)
@ -101,7 +101,7 @@ func (c *ShowExecutor) showAccount(gtsClient *client.Client) error {
if c.myAccount { if c.myAccount {
account, err = getMyAccount(gtsClient, c.topLevelFlags.ConfigDir) account, err = getMyAccount(gtsClient, c.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account details; %w", err) return fmt.Errorf("received an error while getting the account details: %w", err)
} }
} else { } else {
if c.accountName == "" { if c.accountName == "" {
@ -110,7 +110,7 @@ func (c *ShowExecutor) showAccount(gtsClient *client.Client) error {
account, err = getAccount(gtsClient, c.accountName) account, err = getAccount(gtsClient, c.accountName)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account details; %w", err) return fmt.Errorf("received an error while getting the account details: %w", err)
} }
} }
@ -125,7 +125,7 @@ func (c *ShowExecutor) showAccount(gtsClient *client.Client) error {
if !c.myAccount && !c.skipAccountRelationship { if !c.myAccount && !c.skipAccountRelationship {
relationship, err := gtsClient.GetAccountRelationship(account.ID) relationship, err := gtsClient.GetAccountRelationship(account.ID)
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the relationship to this account; %w", err) return fmt.Errorf("unable to retrieve the relationship to this account: %w", err)
} }
utilities.Display(relationship, *c.topLevelFlags.NoColor) utilities.Display(relationship, *c.topLevelFlags.NoColor)
@ -134,7 +134,7 @@ func (c *ShowExecutor) showAccount(gtsClient *client.Client) error {
if c.myAccount && c.showUserPreferences { if c.myAccount && c.showUserPreferences {
preferences, err := gtsClient.GetUserPreferences() preferences, err := gtsClient.GetUserPreferences()
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the user preferences; %w", err) return fmt.Errorf("unable to retrieve the user preferences: %w", err)
} }
utilities.Display(preferences, *c.topLevelFlags.NoColor) utilities.Display(preferences, *c.topLevelFlags.NoColor)
@ -150,7 +150,7 @@ func (c *ShowExecutor) showStatus(gtsClient *client.Client) error {
status, err := gtsClient.GetStatus(c.statusID) status, err := gtsClient.GetStatus(c.statusID)
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the status; %w", err) return fmt.Errorf("unable to retrieve the status: %w", err)
} }
if c.showInBrowser { if c.showInBrowser {
@ -171,28 +171,28 @@ func (c *ShowExecutor) showTimeline(gtsClient *client.Client) error {
) )
switch c.timelineCategory { switch c.timelineCategory {
case "home": case model.TimelineCategoryHome:
timeline, err = gtsClient.GetHomeTimeline(c.limit) timeline, err = gtsClient.GetHomeTimeline(c.limit)
case "public": case model.TimelineCategoryPublic:
timeline, err = gtsClient.GetPublicTimeline(c.limit) timeline, err = gtsClient.GetPublicTimeline(c.limit)
case "list": case model.TimelineCategoryList:
if c.listID == "" { if c.listID == "" {
return FlagNotSetError{flagText: flagListID} return FlagNotSetError{flagText: flagListID}
} }
timeline, err = gtsClient.GetListTimeline(c.listID, c.limit) timeline, err = gtsClient.GetListTimeline(c.listID, c.limit)
case "tag": case model.TimelineCategoryTag:
if c.tag == "" { if c.tag == "" {
return FlagNotSetError{flagText: flagTag} return FlagNotSetError{flagText: flagTag}
} }
timeline, err = gtsClient.GetTagTimeline(c.tag, c.limit) timeline, err = gtsClient.GetTagTimeline(c.tag, c.limit)
default: default:
return InvalidTimelineCategoryError{category: c.timelineCategory} return model.InvalidTimelineCategoryError{Value: c.timelineCategory}
} }
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the %s timeline; %w", c.timelineCategory, err) return fmt.Errorf("unable to retrieve the %s timeline: %w", c.timelineCategory, err)
} }
if len(timeline.Statuses) == 0 { if len(timeline.Statuses) == 0 {
@ -213,12 +213,12 @@ func (c *ShowExecutor) showList(gtsClient *client.Client) error {
list, err := gtsClient.GetList(c.listID) list, err := gtsClient.GetList(c.listID)
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the list; %w", err) return fmt.Errorf("unable to retrieve the list: %w", err)
} }
accounts, err := gtsClient.GetAccountsFromList(c.listID, 0) accounts, err := gtsClient.GetAccountsFromList(c.listID, 0)
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the accounts from the list; %w", err) return fmt.Errorf("unable to retrieve the accounts from the list: %w", err)
} }
if len(accounts) > 0 { if len(accounts) > 0 {
@ -238,7 +238,7 @@ func (c *ShowExecutor) showList(gtsClient *client.Client) error {
func (c *ShowExecutor) showLists(gtsClient *client.Client) error { func (c *ShowExecutor) showLists(gtsClient *client.Client) error {
lists, err := gtsClient.GetAllLists() lists, err := gtsClient.GetAllLists()
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the lists; %w", err) return fmt.Errorf("unable to retrieve the lists: %w", err)
} }
if len(lists) == 0 { if len(lists) == 0 {
@ -255,12 +255,12 @@ func (c *ShowExecutor) showLists(gtsClient *client.Client) error {
func (c *ShowExecutor) showFollowers(gtsClient *client.Client) error { func (c *ShowExecutor) showFollowers(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, c.myAccount, c.accountName, c.topLevelFlags.ConfigDir) accountID, err := getAccountID(gtsClient, c.myAccount, c.accountName, c.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID; %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }
followers, err := gtsClient.GetFollowers(accountID, c.limit) followers, err := gtsClient.GetFollowers(accountID, c.limit)
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the list of followers; %w", err) return fmt.Errorf("unable to retrieve the list of followers: %w", err)
} }
if len(followers.Accounts) > 0 { if len(followers.Accounts) > 0 {
@ -275,12 +275,12 @@ func (c *ShowExecutor) showFollowers(gtsClient *client.Client) error {
func (c *ShowExecutor) showFollowing(gtsClient *client.Client) error { func (c *ShowExecutor) showFollowing(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, c.myAccount, c.accountName, c.topLevelFlags.ConfigDir) accountID, err := getAccountID(gtsClient, c.myAccount, c.accountName, c.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("received an error while getting the account ID; %w", err) return fmt.Errorf("received an error while getting the account ID: %w", err)
} }
following, err := gtsClient.GetFollowing(accountID, c.limit) following, err := gtsClient.GetFollowing(accountID, c.limit)
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the list of followed accounts; %w", err) return fmt.Errorf("unable to retrieve the list of followed accounts: %w", err)
} }
if len(following.Accounts) > 0 { if len(following.Accounts) > 0 {
@ -295,7 +295,7 @@ func (c *ShowExecutor) showFollowing(gtsClient *client.Client) error {
func (c *ShowExecutor) showBlocked(gtsClient *client.Client) error { func (c *ShowExecutor) showBlocked(gtsClient *client.Client) error {
blocked, err := gtsClient.GetBlockedAccounts(c.limit) blocked, err := gtsClient.GetBlockedAccounts(c.limit)
if err != nil { if err != nil {
return fmt.Errorf("unable to retrieve the list of blocked accounts; %w", err) return fmt.Errorf("unable to retrieve the list of blocked accounts: %w", err)
} }
if len(blocked.Accounts) > 0 { if len(blocked.Accounts) > 0 {

View file

@ -52,7 +52,7 @@ func (s *SwitchExecutor) switchToAccount() error {
} }
if err := config.UpdateCurrentAccount(s.accountName, s.topLevelFlags.ConfigDir); err != nil { if err := config.UpdateCurrentAccount(s.accountName, s.topLevelFlags.ConfigDir); err != nil {
return fmt.Errorf("unable to switch account to the account; %w", err) return fmt.Errorf("unable to switch account to the account: %w", err)
} }
fmt.Printf("The current account is now set to %q.\n", s.accountName) fmt.Printf("The current account is now set to %q.\n", s.accountName)

View file

@ -31,7 +31,7 @@ func NewWhoAmIExecutor(tlf TopLevelFlags, name, summary string) *WhoAmIExecutor
func (c *WhoAmIExecutor) Execute() error { func (c *WhoAmIExecutor) Execute() error {
config, err := config.NewCredentialsConfigFromFile(c.topLevelFlags.ConfigDir) config, err := config.NewCredentialsConfigFromFile(c.topLevelFlags.ConfigDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to load the credential config; %w", err) return fmt.Errorf("unable to load the credential config: %w", err)
} }
fmt.Printf("You are logged in as %q.\n", config.CurrentAccount) fmt.Printf("You are logged in as %q.\n", config.CurrentAccount)

View file

@ -41,7 +41,7 @@ func (l ListRepliesPolicy) String() string {
return output return output
} }
func ParseListRepliesPolicy(value string) ListRepliesPolicy { func ParseListRepliesPolicy(value string) (ListRepliesPolicy, error) {
mapped := map[string]ListRepliesPolicy{ mapped := map[string]ListRepliesPolicy{
listRepliesPolicyFollowedValue: ListRepliesPolicyFollowed, listRepliesPolicyFollowedValue: ListRepliesPolicyFollowed,
listRepliesPolicyListValue: ListRepliesPolicyList, listRepliesPolicyListValue: ListRepliesPolicyList,
@ -50,19 +50,24 @@ func ParseListRepliesPolicy(value string) ListRepliesPolicy {
output, ok := mapped[value] output, ok := mapped[value]
if !ok { if !ok {
return ListRepliesPolicyUnknown return ListRepliesPolicyUnknown, InvalidListRepliesPolicyError{value}
} }
return output return output, nil
} }
func (l ListRepliesPolicy) MarshalJSON() ([]byte, error) { func (l ListRepliesPolicy) MarshalJSON() ([]byte, error) {
value := l.String() value := l.String()
if value == unknownValue { if value == unknownValue {
return nil, fmt.Errorf("%q is not a valid list replies policy") return nil, InvalidListRepliesPolicyError{value}
} }
return json.Marshal(value) data, err := json.Marshal(value)
if err != nil {
return nil, fmt.Errorf("unable to encode %s to JSON: %w", value, err)
}
return data, nil
} }
func (l *ListRepliesPolicy) UnmarshalJSON(data []byte) error { func (l *ListRepliesPolicy) UnmarshalJSON(data []byte) error {
@ -72,14 +77,30 @@ func (l *ListRepliesPolicy) UnmarshalJSON(data []byte) error {
) )
if err = json.Unmarshal(data, &value); err != nil { if err = json.Unmarshal(data, &value); err != nil {
return fmt.Errorf("unable to unmarshal the data; %w", err) return fmt.Errorf("unable to decode the JSON data: %w", err)
} }
*l = ParseListRepliesPolicy(value) *l, err = ParseListRepliesPolicy(value)
if err != nil {
return err
}
return nil return nil
} }
type InvalidListRepliesPolicyError struct {
Value string
}
func (e InvalidListRepliesPolicyError) Error() string {
return "'" +
e.Value +
"' is not a valid list replies policy: valid values are " +
listRepliesPolicyFollowedValue + ", " +
listRepliesPolicyListValue + ", " +
listRepliesPolicyNoneValue
}
type List struct { type List struct {
ID string `json:"id"` ID string `json:"id"`
RepliesPolicy ListRepliesPolicy `json:"replies_policy"` RepliesPolicy ListRepliesPolicy `json:"replies_policy"`

View file

@ -38,22 +38,37 @@ func (s StatusContentType) String() string {
return output return output
} }
func ParseStatusContentType(value string) StatusContentType { func ParseStatusContentType(value string) (StatusContentType, error) {
switch value { switch value {
case statusContentTypePlainValue, statusContentTypeTextPlainValue: case statusContentTypePlainValue, statusContentTypeTextPlainValue:
return StatusContentTypePlainText return StatusContentTypePlainText, nil
case statusContentTypeMarkdownValue, statusContentTypeTextMarkdownValue: case statusContentTypeMarkdownValue, statusContentTypeTextMarkdownValue:
return StatusContentTypeMarkdown return StatusContentTypeMarkdown, nil
} }
return StatusContentTypeUnknown return StatusContentTypeUnknown, InvalidStatusContentTypeError{Value: value}
} }
func (s StatusContentType) MarshalJSON() ([]byte, error) { func (s StatusContentType) MarshalJSON() ([]byte, error) {
value := s.String() value := s.String()
if value == unknownValue { if value == unknownValue {
return nil, fmt.Errorf("%q is not a valid status content type", value) return nil, InvalidStatusContentTypeError{Value: value}
} }
return json.Marshal(value) data, err := json.Marshal(value)
if err != nil {
return nil, fmt.Errorf("unable to encode %s to JSON: %w", value, err)
}
return data, nil
}
type InvalidStatusContentTypeError struct {
Value string
}
func (e InvalidStatusContentTypeError) Error() string {
return "'" + e.Value + "' is an invalid status content type: valid values are " +
statusContentTypePlainValue + " or " + statusContentTypeTextPlainValue + " for plain text, or " +
statusContentTypeMarkdownValue + " or " + statusContentTypeTextMarkdownValue + " for Markdown"
} }

View file

@ -45,7 +45,7 @@ func (s StatusVisibility) String() string {
return output return output
} }
func ParseStatusVisibility(value string) StatusVisibility { func ParseStatusVisibility(value string) (StatusVisibility, error) {
mapped := map[string]StatusVisibility{ mapped := map[string]StatusVisibility{
statusVisibilityPublicValue: StatusVisibilityPublic, statusVisibilityPublicValue: StatusVisibilityPublic,
statusVisibilityPrivateValue: StatusVisibilityPrivate, statusVisibilityPrivateValue: StatusVisibilityPrivate,
@ -56,19 +56,24 @@ func ParseStatusVisibility(value string) StatusVisibility {
output, ok := mapped[value] output, ok := mapped[value]
if !ok { if !ok {
return StatusVisibilityUnknown return StatusVisibilityUnknown, InvalidStatusVisibilityError{Value: value}
} }
return output return output, nil
} }
func (s StatusVisibility) MarshalJSON() ([]byte, error) { func (s StatusVisibility) MarshalJSON() ([]byte, error) {
value := s.String() value := s.String()
if value == unknownValue { if value == unknownValue {
return nil, fmt.Errorf("%q is not a valid status visibility", value) return nil, InvalidStatusVisibilityError{Value: value}
} }
return json.Marshal(value) data, err := json.Marshal(value)
if err != nil {
return nil, fmt.Errorf("unable to encode %s to JSON: %w", value, err)
}
return data, nil
} }
func (s *StatusVisibility) UnmarshalJSON(data []byte) error { func (s *StatusVisibility) UnmarshalJSON(data []byte) error {
@ -78,10 +83,25 @@ func (s *StatusVisibility) UnmarshalJSON(data []byte) error {
) )
if err = json.Unmarshal(data, &value); err != nil { if err = json.Unmarshal(data, &value); err != nil {
return fmt.Errorf("unable to unmarshal the data; %w", err) return fmt.Errorf("unable to decode the JSON data: %w", err)
} }
*s = ParseStatusVisibility(value) // Ignore the error if the visibility from another service is
// not known by enbas. It will be replaced with 'unknown'.
*s, _ = ParseStatusVisibility(value)
return nil return nil
} }
type InvalidStatusVisibilityError struct {
Value string
}
func (e InvalidStatusVisibilityError) Error() string {
return "'" + e.Value + "' is not a valid status visibility value: valid values are " +
statusVisibilityPublicValue + ", " +
statusVisibilityUnlistedValue + ", " +
statusVisibilityPrivateValue + ", " +
statusVisibilityMutualsOnlyValue + ", " +
statusVisibilityDirectValue
}

View file

@ -10,6 +10,27 @@ import (
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities" "codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
) )
const (
TimelineCategoryHome = "home"
TimelineCategoryPublic = "public"
TimelineCategoryTag = "tag"
TimelineCategoryList = "list"
)
type InvalidTimelineCategoryError struct {
Value string
}
func (e InvalidTimelineCategoryError) Error() string {
return "'" +
e.Value +
"' is not a valid timeline category (valid values are " +
TimelineCategoryHome + ", " +
TimelineCategoryPublic + ", " +
TimelineCategoryTag + ", " +
TimelineCategoryList + ")"
}
type Timeline struct { type Timeline struct {
Name string Name string
Statuses []Status Statuses []Status

View file

@ -12,7 +12,7 @@ import (
func ReadFile(path string) (string, error) { func ReadFile(path string) (string, error) {
data, err := os.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
return "", fmt.Errorf("unable to read the data from the file; %w", err) return "", fmt.Errorf("unable to read the data from the file: %w", err)
} }
return string(data), nil return string(data), nil