gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

statusbookmark.go (5822B)


      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 bundb
     19 
     20 import (
     21 	"context"
     22 	"errors"
     23 	"fmt"
     24 
     25 	"github.com/superseriousbusiness/gotosocial/internal/db"
     26 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
     27 	"github.com/superseriousbusiness/gotosocial/internal/log"
     28 	"github.com/superseriousbusiness/gotosocial/internal/state"
     29 	"github.com/uptrace/bun"
     30 )
     31 
     32 type statusBookmarkDB struct {
     33 	conn  *DBConn
     34 	state *state.State
     35 }
     36 
     37 func (s *statusBookmarkDB) GetStatusBookmark(ctx context.Context, id string) (*gtsmodel.StatusBookmark, db.Error) {
     38 	bookmark := new(gtsmodel.StatusBookmark)
     39 
     40 	err := s.conn.
     41 		NewSelect().
     42 		Model(bookmark).
     43 		Where("? = ?", bun.Ident("status_bookmark.id"), id).
     44 		Scan(ctx)
     45 	if err != nil {
     46 		return nil, s.conn.ProcessError(err)
     47 	}
     48 
     49 	bookmark.Account, err = s.state.DB.GetAccountByID(ctx, bookmark.AccountID)
     50 	if err != nil {
     51 		return nil, fmt.Errorf("error getting status bookmark account %q: %w", bookmark.AccountID, err)
     52 	}
     53 
     54 	bookmark.TargetAccount, err = s.state.DB.GetAccountByID(ctx, bookmark.TargetAccountID)
     55 	if err != nil {
     56 		return nil, fmt.Errorf("error getting status bookmark target account %q: %w", bookmark.TargetAccountID, err)
     57 	}
     58 
     59 	bookmark.Status, err = s.state.DB.GetStatusByID(ctx, bookmark.StatusID)
     60 	if err != nil {
     61 		return nil, fmt.Errorf("error getting status bookmark status %q: %w", bookmark.StatusID, err)
     62 	}
     63 
     64 	return bookmark, nil
     65 }
     66 
     67 func (s *statusBookmarkDB) GetStatusBookmarkID(ctx context.Context, accountID string, statusID string) (string, db.Error) {
     68 	var id string
     69 
     70 	q := s.conn.
     71 		NewSelect().
     72 		TableExpr("? AS ?", bun.Ident("status_bookmarks"), bun.Ident("status_bookmark")).
     73 		Column("status_bookmark.id").
     74 		Where("? = ?", bun.Ident("status_bookmark.account_id"), accountID).
     75 		Where("? = ?", bun.Ident("status_bookmark.status_id"), statusID).
     76 		Limit(1)
     77 
     78 	if err := q.Scan(ctx, &id); err != nil {
     79 		return "", s.conn.ProcessError(err)
     80 	}
     81 
     82 	return id, nil
     83 }
     84 
     85 func (s *statusBookmarkDB) GetStatusBookmarks(ctx context.Context, accountID string, limit int, maxID string, minID string) ([]*gtsmodel.StatusBookmark, db.Error) {
     86 	// Ensure reasonable
     87 	if limit < 0 {
     88 		limit = 0
     89 	}
     90 
     91 	// Guess size of IDs based on limit.
     92 	ids := make([]string, 0, limit)
     93 
     94 	q := s.conn.
     95 		NewSelect().
     96 		TableExpr("? AS ?", bun.Ident("status_bookmarks"), bun.Ident("status_bookmark")).
     97 		Column("status_bookmark.id").
     98 		Where("? = ?", bun.Ident("status_bookmark.account_id"), accountID).
     99 		Order("status_bookmark.id DESC")
    100 
    101 	if accountID == "" {
    102 		return nil, errors.New("must provide an account")
    103 	}
    104 
    105 	if maxID != "" {
    106 		q = q.Where("? < ?", bun.Ident("status_bookmark.id"), maxID)
    107 	}
    108 
    109 	if minID != "" {
    110 		q = q.Where("? > ?", bun.Ident("status_bookmark.id"), minID)
    111 	}
    112 
    113 	if limit != 0 {
    114 		q = q.Limit(limit)
    115 	}
    116 
    117 	if err := q.Scan(ctx, &ids); err != nil {
    118 		return nil, s.conn.ProcessError(err)
    119 	}
    120 
    121 	bookmarks := make([]*gtsmodel.StatusBookmark, 0, len(ids))
    122 
    123 	for _, id := range ids {
    124 		bookmark, err := s.GetStatusBookmark(ctx, id)
    125 		if err != nil {
    126 			log.Errorf(ctx, "error getting bookmark %q: %v", id, err)
    127 			continue
    128 		}
    129 
    130 		bookmarks = append(bookmarks, bookmark)
    131 	}
    132 
    133 	return bookmarks, nil
    134 }
    135 
    136 func (s *statusBookmarkDB) PutStatusBookmark(ctx context.Context, statusBookmark *gtsmodel.StatusBookmark) db.Error {
    137 	_, err := s.conn.
    138 		NewInsert().
    139 		Model(statusBookmark).
    140 		Exec(ctx)
    141 
    142 	return s.conn.ProcessError(err)
    143 }
    144 
    145 func (s *statusBookmarkDB) DeleteStatusBookmark(ctx context.Context, id string) db.Error {
    146 	_, err := s.conn.
    147 		NewDelete().
    148 		TableExpr("? AS ?", bun.Ident("status_bookmarks"), bun.Ident("status_bookmark")).
    149 		Where("? = ?", bun.Ident("status_bookmark.id"), id).
    150 		Exec(ctx)
    151 
    152 	return s.conn.ProcessError(err)
    153 }
    154 
    155 func (s *statusBookmarkDB) DeleteStatusBookmarks(ctx context.Context, targetAccountID string, originAccountID string) db.Error {
    156 	if targetAccountID == "" && originAccountID == "" {
    157 		return errors.New("DeleteBookmarks: one of targetAccountID or originAccountID must be set")
    158 	}
    159 
    160 	// TODO: Capture bookmark IDs in a RETURNING
    161 	// statement (when bookmarks have a cache),
    162 	// + use the IDs to invalidate cache entries.
    163 
    164 	q := s.conn.
    165 		NewDelete().
    166 		TableExpr("? AS ?", bun.Ident("status_bookmarks"), bun.Ident("status_bookmark"))
    167 
    168 	if targetAccountID != "" {
    169 		q = q.Where("? = ?", bun.Ident("status_bookmark.target_account_id"), targetAccountID)
    170 	}
    171 
    172 	if originAccountID != "" {
    173 		q = q.Where("? = ?", bun.Ident("status_bookmark.account_id"), originAccountID)
    174 	}
    175 
    176 	if _, err := q.Exec(ctx); err != nil {
    177 		return s.conn.ProcessError(err)
    178 	}
    179 
    180 	return nil
    181 }
    182 
    183 func (s *statusBookmarkDB) DeleteStatusBookmarksForStatus(ctx context.Context, statusID string) db.Error {
    184 	// TODO: Capture bookmark IDs in a RETURNING
    185 	// statement (when bookmarks have a cache),
    186 	// + use the IDs to invalidate cache entries.
    187 
    188 	q := s.conn.
    189 		NewDelete().
    190 		TableExpr("? AS ?", bun.Ident("status_bookmarks"), bun.Ident("status_bookmark")).
    191 		Where("? = ?", bun.Ident("status_bookmark.status_id"), statusID)
    192 
    193 	if _, err := q.Exec(ctx); err != nil {
    194 		return s.conn.ProcessError(err)
    195 	}
    196 
    197 	return nil
    198 }