diff --git a/internal/client/statuses.go b/internal/client/statuses.go index 89e1655..ea75e12 100644 --- a/internal/client/statuses.go +++ b/internal/client/statuses.go @@ -68,8 +68,7 @@ func (g *Client) GetBookmarks(limit int) (model.StatusList, error) { url := g.Authentication.Instance + path bookmarks := model.StatusList{ - Type: model.StatusListBookMarks, - Name: "BOOKMARKS", + Name: "Your Bookmarks", Statuses: nil, } @@ -110,3 +109,47 @@ func (g *Client) RemoveStatusFromBookmarks(statusID string) error { return nil } + +func (g *Client) LikeStatus(statusID string) error { + url := g.Authentication.Instance + "/api/v1/statuses/" + statusID + "/favourite" + + if err := g.sendRequest(http.MethodPost, url, nil, nil); err != nil { + return fmt.Errorf( + "received an error after sending the request to like the status: %w", + err, + ) + } + + return nil +} + +func (g *Client) UnlikeStatus(statusID string) error { + url := g.Authentication.Instance + "/api/v1/statuses/" + statusID + "/unfavourite" + + if err := g.sendRequest(http.MethodPost, url, nil, nil); err != nil { + return fmt.Errorf( + "received an error after sending the request to unlike the status: %w", + err, + ) + } + + return nil +} + +func (g *Client) GetLikedStatuses(limit int, resourceName string) (model.StatusList, error) { + url := g.Authentication.Instance + fmt.Sprintf("/api/v1/favourites?limit=%d", limit) + + liked := model.StatusList{ + Name: "Your " + resourceName + " statuses", + Statuses: nil, + } + + if err := g.sendRequest(http.MethodGet, url, nil, &liked.Statuses); err != nil { + return model.StatusList{}, fmt.Errorf( + "received an error after sending the request to get the list of statuses: %w", + err, + ) + } + + return liked, nil +} diff --git a/internal/client/timelines.go b/internal/client/timelines.go index d27454f..8bfe753 100644 --- a/internal/client/timelines.go +++ b/internal/client/timelines.go @@ -15,8 +15,7 @@ func (g *Client) GetHomeTimeline(limit int) (model.StatusList, error) { path := fmt.Sprintf("/api/v1/timelines/home?limit=%d", limit) timeline := model.StatusList{ - Type: model.StatusListTimeline, - Name: "HOME", + Name: "Timeline: Home", Statuses: nil, } @@ -27,8 +26,7 @@ func (g *Client) GetPublicTimeline(limit int) (model.StatusList, error) { path := fmt.Sprintf("/api/v1/timelines/public?limit=%d", limit) timeline := model.StatusList{ - Type: model.StatusListTimeline, - Name: "PUBLIC", + Name: "Timeline: Public", Statuses: nil, } @@ -39,8 +37,7 @@ func (g *Client) GetListTimeline(listID, title string, limit int) (model.StatusL path := fmt.Sprintf("/api/v1/timelines/list/%s?limit=%d", listID, limit) timeline := model.StatusList{ - Type: model.StatusListTimeline, - Name: "LIST (" + title + ")", + Name: "Timeline: List (" + title + ")", Statuses: nil, } @@ -51,8 +48,7 @@ func (g *Client) GetTagTimeline(tag string, limit int) (model.StatusList, error) path := fmt.Sprintf("/api/v1/timelines/tag/%s?limit=%d", tag, limit) timeline := model.StatusList{ - Type: model.StatusListTimeline, - Name: "TAG (" + tag + ")", + Name: "Timeline: Tag (" + tag + ")", Statuses: nil, } diff --git a/internal/executor/add.go b/internal/executor/add.go index 46fa0fb..9c2b317 100644 --- a/internal/executor/add.go +++ b/internal/executor/add.go @@ -53,6 +53,7 @@ func (a *AddExecutor) Execute() error { resourceList: a.addToList, resourceAccount: a.addToAccount, resourceBookmarks: a.addToBookmarks, + resourceStatus: a.addToStatus, } doFunc, ok := funcMap[a.toResourceType] @@ -184,3 +185,34 @@ func (a *AddExecutor) addStatusToBookmarks(gtsClient *client.Client) error { return nil } + +func (a *AddExecutor) addToStatus(gtsClient *client.Client) error { + funcMap := map[string]func(*client.Client) error{ + resourceStar: a.addStarToStatus, + resourceLike: a.addStarToStatus, + } + + doFunc, ok := funcMap[a.resourceType] + if !ok { + return UnsupportedAddOperationError{ + ResourceType: a.resourceType, + AddToResourceType: a.toResourceType, + } + } + + return doFunc(gtsClient) +} + +func (a *AddExecutor) addStarToStatus(gtsClient *client.Client) error { + if a.statusID == "" { + return FlagNotSetError{flagText: flagStatusID} + } + + if err := gtsClient.LikeStatus(a.statusID); err != nil { + return fmt.Errorf("unable to add the %s to the status: %w", a.resourceType, err) + } + + fmt.Printf("Successfully added a %s to the status.\n", a.resourceType) + + return nil +} diff --git a/internal/executor/const.go b/internal/executor/const.go index 58263f7..c020684 100644 --- a/internal/executor/const.go +++ b/internal/executor/const.go @@ -37,12 +37,16 @@ const ( resourceAccount = "account" resourceBlocked = "blocked" + resourceBookmarks = "bookmarks" resourceFollowers = "followers" resourceFollowing = "following" resourceInstance = "instance" + resourceLike = "like" + resourceLiked = "liked" resourceList = "list" resourceNote = "note" resourceStatus = "status" + resourceStar = "star" + resourceStarred = "starred" resourceTimeline = "timeline" - resourceBookmarks = "bookmarks" ) diff --git a/internal/executor/remove.go b/internal/executor/remove.go index a4dad01..2f249e8 100644 --- a/internal/executor/remove.go +++ b/internal/executor/remove.go @@ -51,6 +51,7 @@ func (r *RemoveExecutor) Execute() error { resourceList: r.removeFromList, resourceAccount: r.removeFromAccount, resourceBookmarks: r.removeFromBookmarks, + resourceStatus: r.removeFromStatus, } doFunc, ok := funcMap[r.fromResourceType] @@ -175,3 +176,34 @@ func (r *RemoveExecutor) removeStatusFromBookmarks(gtsClient *client.Client) err return nil } + +func (r *RemoveExecutor) removeFromStatus(gtsClient *client.Client) error { + funcMap := map[string]func(*client.Client) error{ + resourceStar: r.removeStarFromStatus, + resourceLike: r.removeStarFromStatus, + } + + doFunc, ok := funcMap[r.resourceType] + if !ok { + return UnsupportedRemoveOperationError{ + ResourceType: r.resourceType, + RemoveFromResourceType: r.fromResourceType, + } + } + + return doFunc(gtsClient) +} + +func (r *RemoveExecutor) removeStarFromStatus(gtsClient *client.Client) error { + if r.statusID == "" { + return FlagNotSetError{flagText: flagStatusID} + } + + if err := gtsClient.UnlikeStatus(r.statusID); err != nil { + return fmt.Errorf("unable to remove the %s from the status: %w", r.resourceType, err) + } + + fmt.Printf("Successfully removed the %s from the status.\n", r.resourceType) + + return nil +} diff --git a/internal/executor/show.go b/internal/executor/show.go index a51cb97..10a7069 100644 --- a/internal/executor/show.go +++ b/internal/executor/show.go @@ -67,6 +67,8 @@ func (s *ShowExecutor) Execute() error { resourceFollowing: s.showFollowing, resourceBlocked: s.showBlocked, resourceBookmarks: s.showBookmarks, + resourceLiked: s.showLiked, + resourceStarred: s.showLiked, } doFunc, ok := funcMap[s.resourceType] @@ -329,3 +331,18 @@ func (s *ShowExecutor) showBookmarks(gtsClient *client.Client) error { return nil } + +func (s *ShowExecutor) showLiked(gtsClient *client.Client) error { + liked, err := gtsClient.GetLikedStatuses(s.limit, s.resourceType) + if err != nil { + return fmt.Errorf("unable to retrieve the list of your %s statuses: %w", s.resourceType, err) + } + + if len(liked.Statuses) > 0 { + utilities.Display(liked, *s.topLevelFlags.NoColor) + } else { + fmt.Printf("You have no %s statuses.\n", s.resourceType) + } + + return nil +} diff --git a/internal/model/status.go b/internal/model/status.go index 85fb8be..486e0e5 100644 --- a/internal/model/status.go +++ b/internal/model/status.go @@ -201,32 +201,17 @@ func (s Status) Display(noColor bool) string { ) } -type StatusListType int - -const ( - StatusListTimeline StatusListType = iota - StatusListBookMarks -) - type StatusList struct { - Type StatusListType Name string Statuses []Status } func (s StatusList) Display(noColor bool) string { var builder strings.Builder - var name string separator := "────────────────────────────────────────────────────────────────────────────────" - if s.Type == StatusListTimeline { - name = "TIMELINE: " + s.Name - } else { - name = s.Name - } - - builder.WriteString(utilities.HeaderFormat(noColor, name) + "\n") + builder.WriteString(utilities.HeaderFormat(noColor, s.Name) + "\n") for _, status := range s.Statuses { builder.WriteString("\n" + utilities.DisplayNameFormat(noColor, status.Account.DisplayName) + " (@" + status.Account.Acct + ")\n")