From 3037af60edf31d48252798f736e52594e0796e2a Mon Sep 17 00:00:00 2001 From: Dan Anglin Date: Fri, 16 Aug 2024 14:42:57 +0100 Subject: [PATCH] feat: mute and unmute statuses This commit adds support for muting and unmuting statuses. When viewing a status the user can now see whether they've muted the status or not. A status can only be muted by the user if they own it or are mentioned in it. PR: apollo/enbas#47 Resolves: apollo/enbas#46 --- docs/manual.md | 22 ++++++++++++++-- internal/client/statuses.go | 46 ++++++++++++++++++++++++++++++++-- internal/executor/executors.go | 4 +++ internal/executor/mute.go | 43 +++++++++++++++++++++++++++++++ internal/executor/unmute.go | 43 +++++++++++++++++++++++++++++++ internal/printer/status.go | 1 + schema/enbas_cli_schema.json | 2 ++ 7 files changed, 157 insertions(+), 4 deletions(-) diff --git a/docs/manual.md b/docs/manual.md index 6a8e864..a89a464 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -604,11 +604,29 @@ enbas show --type liked ### Mute a status -_Not yet supported_ +Mutes a status in order to stop receiving future notifications for replies, likes, boosts, etc. + +``` +enbas mute --type status --status-id 01J56ZJAGEWG967GS1EK0TV3GA +``` + +| flag | type | required | description | default | +|------|------|----------|-------------|---------| +| `type` | string | true | The resource you want to mute.
Here this should be `status`. | | +| `status-id` | string | true | The ID of the status that you want to mute. | | ### Unmute a status -_Not yet supported_ +Unmute a status in order to start receiving future notification from the status' thread. + +``` +enbas mute --type status --status-id 01J56ZJAGEWG967GS1EK0TV3GA +``` + +| flag | type | required | description | default | +|------|------|----------|-------------|---------| +| `type` | string | true | The resource you want to unmute.
Here this should be `status`. | | +| `status-id` | string | true | The ID of the status that you want to unmute. | | ### Vote in a poll within a status diff --git a/internal/client/statuses.go b/internal/client/statuses.go index 0b8d60a..9dc1e16 100644 --- a/internal/client/statuses.go +++ b/internal/client/statuses.go @@ -241,7 +241,7 @@ func (g *Client) ReblogStatus(statusID string) error { if err := g.sendRequest(params); err != nil { return fmt.Errorf( - "received an error after sending the request to reblog the status; %w", + "received an error after sending the request to reblog the status: %w", err, ) } @@ -262,7 +262,49 @@ func (g *Client) UnreblogStatus(statusID string) error { if err := g.sendRequest(params); err != nil { return fmt.Errorf( - "received an error after sending the request to un-reblog the status; %w", + "received an error after sending the request to un-reblog the status: %w", + err, + ) + } + + return nil +} + +func (g *Client) MuteStatus(statusID string) error { + url := g.Authentication.Instance + baseStatusesPath + "/" + statusID + "/mute" + + params := requestParameters{ + httpMethod: http.MethodPost, + url: url, + requestBody: nil, + contentType: "", + output: nil, + } + + if err := g.sendRequest(params); err != nil { + return fmt.Errorf( + "received an error after sending the request to mute the status: %w", + err, + ) + } + + return nil +} + +func (g *Client) UnmuteStatus(statusID string) error { + url := g.Authentication.Instance + baseStatusesPath + "/" + statusID + "/unmute" + + params := requestParameters{ + httpMethod: http.MethodPost, + url: url, + requestBody: nil, + contentType: "", + output: nil, + } + + if err := g.sendRequest(params); err != nil { + return fmt.Errorf( + "received an error after sending the request to unmute the status: %w", err, ) } diff --git a/internal/executor/executors.go b/internal/executor/executors.go index 1ef1ee1..2b48d57 100644 --- a/internal/executor/executors.go +++ b/internal/executor/executors.go @@ -347,6 +347,7 @@ type MuteExecutor struct { accountName internalFlag.StringSliceValue muteDuration internalFlag.TimeDurationValue muteNotifications bool + statusID string resourceType string } @@ -367,6 +368,7 @@ func NewMuteExecutor( exe.Var(&exe.accountName, "account-name", "The name of the account") exe.Var(&exe.muteDuration, "mute-duration", "Specify how long the mute should last for. To mute indefinitely, set this to 0s") exe.BoolVar(&exe.muteNotifications, "mute-notifications", false, "Set to true to mute notifications as well as posts") + exe.StringVar(&exe.statusID, "status-id", "", "The ID of the status") exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)") return &exe @@ -591,6 +593,7 @@ type UnmuteExecutor struct { printer *printer.Printer config *config.Config accountName internalFlag.StringSliceValue + statusID string resourceType string } @@ -608,6 +611,7 @@ func NewUnmuteExecutor( exe.Usage = usage.ExecutorUsageFunc("unmute", "Umutes a specific resource (e.g. an account)", exe.FlagSet) exe.Var(&exe.accountName, "account-name", "The name of the account") + exe.StringVar(&exe.statusID, "status-id", "", "The ID of the status") exe.StringVar(&exe.resourceType, "type", "", "The type of resource you want to action on (e.g. account, status)") return &exe diff --git a/internal/executor/mute.go b/internal/executor/mute.go index 2416f76..f8cd30d 100644 --- a/internal/executor/mute.go +++ b/internal/executor/mute.go @@ -1,6 +1,7 @@ package executor import ( + "errors" "fmt" "codeflow.dananglin.me.uk/apollo/enbas/internal/client" @@ -9,6 +10,7 @@ import ( func (m *MuteExecutor) Execute() error { funcMap := map[string]func(*client.Client) error{ resourceAccount: m.muteAccount, + resourceStatus: m.muteStatus, } doFunc, ok := funcMap[m.resourceType] @@ -43,3 +45,44 @@ func (m *MuteExecutor) muteAccount(gtsClient *client.Client) error { return nil } + +func (m *MuteExecutor) muteStatus(gtsClient *client.Client) error { + if m.statusID == "" { + return FlagNotSetError{flagText: flagStatusID} + } + + status, err := gtsClient.GetStatus(m.statusID) + if err != nil { + return fmt.Errorf("unable to retrieve the status: %w", err) + } + + myAccountID, err := getAccountID(gtsClient, true, nil) + if err != nil { + return fmt.Errorf("unable to get your account ID: %w", err) + } + + canMute := false + + if status.Account.ID == myAccountID { + canMute = true + } else { + for _, mention := range status.Mentions { + if mention.ID == myAccountID { + canMute = true + break + } + } + } + + if !canMute { + return errors.New("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 { + return fmt.Errorf("unable to mute the status: %w", err) + } + + m.printer.PrintSuccess("Successfully muted the status.") + + return nil +} diff --git a/internal/executor/unmute.go b/internal/executor/unmute.go index ae19720..d643e46 100644 --- a/internal/executor/unmute.go +++ b/internal/executor/unmute.go @@ -1,6 +1,7 @@ package executor import ( + "errors" "fmt" "codeflow.dananglin.me.uk/apollo/enbas/internal/client" @@ -9,6 +10,7 @@ import ( func (m *UnmuteExecutor) Execute() error { funcMap := map[string]func(*client.Client) error{ resourceAccount: m.unmuteAccount, + resourceStatus: m.unmuteStatus, } doFunc, ok := funcMap[m.resourceType] @@ -38,3 +40,44 @@ func (m *UnmuteExecutor) unmuteAccount(gtsClient *client.Client) error { return nil } + +func (m *UnmuteExecutor) unmuteStatus(gtsClient *client.Client) error { + if m.statusID == "" { + return FlagNotSetError{flagText: flagStatusID} + } + + status, err := gtsClient.GetStatus(m.statusID) + if err != nil { + return fmt.Errorf("unable to retrieve the status: %w", err) + } + + myAccountID, err := getAccountID(gtsClient, true, nil) + if err != nil { + return fmt.Errorf("unable to get your account ID: %w", err) + } + + canUnmute := false + + if status.Account.ID == myAccountID { + canUnmute = true + } else { + for _, mention := range status.Mentions { + if mention.ID == myAccountID { + canUnmute = true + break + } + } + } + + if !canUnmute { + return errors.New("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 { + return fmt.Errorf("unable to unmute the status: %w", err) + } + + m.printer.PrintSuccess("Successfully unmuted the status.") + + return nil +} diff --git a/internal/printer/status.go b/internal/printer/status.go index 9b847aa..d083e21 100644 --- a/internal/printer/status.go +++ b/internal/printer/status.go @@ -66,6 +66,7 @@ func (p Printer) PrintStatus(status model.Status, userAccountID string) { builder.WriteString("\n" + p.fieldFormat("Boosted: ") + strconv.FormatBool(status.Reblogged)) builder.WriteString("\n" + p.fieldFormat("Liked: ") + strconv.FormatBool(status.Favourited)) builder.WriteString("\n" + p.fieldFormat("Bookmarked: ") + strconv.FormatBool(status.Bookmarked)) + builder.WriteString("\n" + p.fieldFormat("Muted: ") + strconv.FormatBool(status.Muted)) // Status visibility builder.WriteString("\n\n" + p.headerFormat("VISIBILITY:")) diff --git a/schema/enbas_cli_schema.json b/schema/enbas_cli_schema.json index 3199e0a..13762f4 100644 --- a/schema/enbas_cli_schema.json +++ b/schema/enbas_cli_schema.json @@ -335,6 +335,7 @@ { "flag": "account-name" }, { "flag": "mute-duration" }, { "flag": "mute-notifications", "default": "false" }, + { "flag": "status-id", "fieldName": "statusID", "default": "" }, { "flag": "type", "fieldName": "resourceType", "default": "" } ], "summary": "Mutes a specific resource (e.g. an account)", @@ -427,6 +428,7 @@ "additionalFields": [], "flags": [ { "flag": "account-name" }, + { "flag": "status-id", "fieldName": "statusID", "default": "" }, { "flag": "type", "fieldName": "resourceType", "default": "" } ], "summary": "Umutes a specific resource (e.g. an account)", -- 2.45.2