bookmarks.go (3490B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package account 19 20 import ( 21 "context" 22 "errors" 23 24 apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" 25 "github.com/superseriousbusiness/gotosocial/internal/db" 26 "github.com/superseriousbusiness/gotosocial/internal/gtserror" 27 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 28 "github.com/superseriousbusiness/gotosocial/internal/id" 29 "github.com/superseriousbusiness/gotosocial/internal/log" 30 "github.com/superseriousbusiness/gotosocial/internal/util" 31 ) 32 33 // BookmarksGet returns a pageable response of statuses that are bookmarked by requestingAccount. 34 // Paging for this response is done based on bookmark ID rather than status ID. 35 func (p *Processor) BookmarksGet(ctx context.Context, requestingAccount *gtsmodel.Account, limit int, maxID string, minID string) (*apimodel.PageableResponse, gtserror.WithCode) { 36 bookmarks, err := p.state.DB.GetStatusBookmarks(ctx, requestingAccount.ID, limit, maxID, minID) 37 if err != nil { 38 return nil, gtserror.NewErrorInternalError(err) 39 } 40 41 var ( 42 count = len(bookmarks) 43 items = make([]interface{}, 0, count) 44 nextMaxIDValue = id.Highest 45 prevMinIDValue = id.Lowest 46 ) 47 48 for _, bookmark := range bookmarks { 49 status, err := p.state.DB.GetStatusByID(ctx, bookmark.StatusID) 50 if err != nil { 51 if errors.Is(err, db.ErrNoEntries) { 52 // We just don't have the status for some reason. 53 // Skip this one. 54 continue 55 } 56 return nil, gtserror.NewErrorInternalError(err) // A real error has occurred. 57 } 58 59 visible, err := p.filter.StatusVisible(ctx, requestingAccount, status) 60 if err != nil { 61 log.Errorf(ctx, "error checking bookmarked status visibility: %s", err) 62 continue 63 } 64 65 if !visible { 66 continue 67 } 68 69 // Convert the status. 70 item, err := p.tc.StatusToAPIStatus(ctx, status, requestingAccount) 71 if err != nil { 72 log.Errorf(ctx, "error converting bookmarked status to api: %s", err) 73 continue 74 } 75 items = append(items, item) 76 77 // Page based on bookmark ID, not status ID. 78 // Note that we only set these values here 79 // when we're certain that the caller is able 80 // to see the status, *and* we're sure that 81 // we can produce an api model representation. 82 if bookmark.ID < nextMaxIDValue { 83 nextMaxIDValue = bookmark.ID // Lowest ID (for paging down). 84 } 85 if bookmark.ID > prevMinIDValue { 86 prevMinIDValue = bookmark.ID // Highest ID (for paging up). 87 } 88 } 89 90 if len(items) == 0 { 91 return util.EmptyPageableResponse(), nil 92 } 93 94 return util.PackagePageableResponse(util.PageableResponseParams{ 95 Items: items, 96 Path: "/api/v1/bookmarks", 97 NextMaxIDValue: nextMaxIDValue, 98 PrevMinIDValue: prevMinIDValue, 99 Limit: limit, 100 }) 101 }