diff options
Diffstat (limited to 'internal/db')
-rw-r--r-- | internal/db/bundb/account_test.go | 9 | ||||
-rw-r--r-- | internal/db/bundb/bundb.go | 5 | ||||
-rw-r--r-- | internal/db/bundb/interaction.go | 149 | ||||
-rw-r--r-- | internal/db/bundb/migrations/20240620074530_interaction_policy.go | 264 | ||||
-rw-r--r-- | internal/db/bundb/migrations/20240620074530_interaction_policy/status.go | 61 | ||||
-rw-r--r-- | internal/db/bundb/status_test.go | 18 | ||||
-rw-r--r-- | internal/db/bundb/statusfave.go | 36 | ||||
-rw-r--r-- | internal/db/bundb/timeline_test.go | 4 | ||||
-rw-r--r-- | internal/db/db.go | 1 | ||||
-rw-r--r-- | internal/db/interaction.go | 41 | ||||
-rw-r--r-- | internal/db/statusfave.go | 8 |
11 files changed, 565 insertions, 31 deletions
diff --git a/internal/db/bundb/account_test.go b/internal/db/bundb/account_test.go index 5ed5d91a1..a9554e0d7 100644 --- a/internal/db/bundb/account_test.go +++ b/internal/db/bundb/account_test.go @@ -115,15 +115,6 @@ func (suite *AccountTestSuite) populateTestStatus(testAccountKey string, status if status.Federated == nil { status.Federated = util.Ptr(true) } - if status.Boostable == nil { - status.Boostable = util.Ptr(true) - } - if status.Likeable == nil { - status.Likeable = util.Ptr(true) - } - if status.Replyable == nil { - status.Replyable = util.Ptr(true) - } if inReplyTo != nil { status.InReplyToAccountID = inReplyTo.AccountID diff --git a/internal/db/bundb/bundb.go b/internal/db/bundb/bundb.go index e7256c276..57fb661df 100644 --- a/internal/db/bundb/bundb.go +++ b/internal/db/bundb/bundb.go @@ -60,6 +60,7 @@ type DBService struct { db.Emoji db.HeaderFilter db.Instance + db.Interaction db.Filter db.List db.Marker @@ -203,6 +204,10 @@ func NewBunDBService(ctx context.Context, state *state.State) (db.DB, error) { db: db, state: state, }, + Interaction: &interactionDB{ + db: db, + state: state, + }, Filter: &filterDB{ db: db, state: state, diff --git a/internal/db/bundb/interaction.go b/internal/db/bundb/interaction.go new file mode 100644 index 000000000..b818f7a60 --- /dev/null +++ b/internal/db/bundb/interaction.go @@ -0,0 +1,149 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package bundb + +import ( + "context" + + "github.com/superseriousbusiness/gotosocial/internal/gtscontext" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/state" + "github.com/uptrace/bun" +) + +type interactionDB struct { + db *bun.DB + state *state.State +} + +func (r *interactionDB) newInteractionApprovalQ(approval interface{}) *bun.SelectQuery { + return r.db. + NewSelect(). + Model(approval) +} + +func (r *interactionDB) GetInteractionApprovalByID(ctx context.Context, id string) (*gtsmodel.InteractionApproval, error) { + return r.getInteractionApproval( + ctx, + "ID", + func(approval *gtsmodel.InteractionApproval) error { + return r. + newInteractionApprovalQ(approval). + Where("? = ?", bun.Ident("interaction_approval.id"), id). + Scan(ctx) + }, + id, + ) +} + +func (r *interactionDB) GetInteractionApprovalByURI(ctx context.Context, uri string) (*gtsmodel.InteractionApproval, error) { + return r.getInteractionApproval( + ctx, + "URI", + func(approval *gtsmodel.InteractionApproval) error { + return r. + newInteractionApprovalQ(approval). + Where("? = ?", bun.Ident("interaction_approval.uri"), uri). + Scan(ctx) + }, + uri, + ) +} + +func (r *interactionDB) getInteractionApproval( + ctx context.Context, + lookup string, + dbQuery func(*gtsmodel.InteractionApproval) error, + keyParts ...any, +) (*gtsmodel.InteractionApproval, error) { + // Fetch approval from database cache with loader callback + approval, err := r.state.Caches.GTS.InteractionApproval.LoadOne(lookup, func() (*gtsmodel.InteractionApproval, error) { + var approval gtsmodel.InteractionApproval + + // Not cached! Perform database query + if err := dbQuery(&approval); err != nil { + return nil, err + } + + return &approval, nil + }, keyParts...) + if err != nil { + // Error already processed. + return nil, err + } + + if gtscontext.Barebones(ctx) { + // Only a barebones model was requested. + return approval, nil + } + + if err := r.PopulateInteractionApproval(ctx, approval); err != nil { + return nil, err + } + + return approval, nil +} + +func (r *interactionDB) PopulateInteractionApproval(ctx context.Context, approval *gtsmodel.InteractionApproval) error { + var ( + err error + errs = gtserror.NewMultiError(2) + ) + + if approval.Account == nil { + // Account is not set, fetch from the database. + approval.Account, err = r.state.DB.GetAccountByID( + gtscontext.SetBarebones(ctx), + approval.AccountID, + ) + if err != nil { + errs.Appendf("error populating interactionApproval account: %w", err) + } + } + + if approval.InteractingAccount == nil { + // InteractingAccount is not set, fetch from the database. + approval.InteractingAccount, err = r.state.DB.GetAccountByID( + gtscontext.SetBarebones(ctx), + approval.InteractingAccountID, + ) + if err != nil { + errs.Appendf("error populating interactionApproval interacting account: %w", err) + } + } + + return errs.Combine() +} + +func (r *interactionDB) PutInteractionApproval(ctx context.Context, approval *gtsmodel.InteractionApproval) error { + return r.state.Caches.GTS.InteractionApproval.Store(approval, func() error { + _, err := r.db.NewInsert().Model(approval).Exec(ctx) + return err + }) +} + +func (r *interactionDB) DeleteInteractionApprovalByID(ctx context.Context, id string) error { + defer r.state.Caches.GTS.InteractionApproval.Invalidate("ID", id) + + _, err := r.db.NewDelete(). + TableExpr("? AS ?", bun.Ident("interaction_approvals"), bun.Ident("interaction_approval")). + Where("? = ?", bun.Ident("interaction_approval.id"), id). + Exec(ctx) + return err +} diff --git a/internal/db/bundb/migrations/20240620074530_interaction_policy.go b/internal/db/bundb/migrations/20240620074530_interaction_policy.go new file mode 100644 index 000000000..424039a52 --- /dev/null +++ b/internal/db/bundb/migrations/20240620074530_interaction_policy.go @@ -0,0 +1,264 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package migrations + +import ( + "context" + + "github.com/superseriousbusiness/gotosocial/internal/log" + + oldmodel "github.com/superseriousbusiness/gotosocial/internal/db/bundb/migrations/20240620074530_interaction_policy" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + + "github.com/uptrace/bun" +) + +func init() { + up := func(ctx context.Context, db *bun.DB) error { + log.Info(ctx, "migrating statuses and account settings to interaction policy model, please wait...") + return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { + + // Add new columns for interaction + // policies + related fields. + type spec struct { + table string + column string + columnType string + defaultVal string + } + for _, spec := range []spec{ + // Statuses. + { + table: "statuses", + column: "interaction_policy", + columnType: "JSONB", + defaultVal: "", + }, + { + table: "statuses", + column: "pending_approval", + columnType: "BOOLEAN", + defaultVal: "DEFAULT false", + }, + { + table: "statuses", + column: "approved_by_uri", + columnType: "varchar", + defaultVal: "", + }, + + // Status faves. + { + table: "status_faves", + column: "pending_approval", + columnType: "BOOLEAN", + defaultVal: "DEFAULT false", + }, + { + table: "status_faves", + column: "approved_by_uri", + columnType: "varchar", + defaultVal: "", + }, + + // Columns that must be added to the + // `account_settings` table to populate + // default interaction policies for + // different status visibilities. + { + table: "account_settings", + column: "interaction_policy_direct", + columnType: "JSONB", + defaultVal: "", + }, + { + table: "account_settings", + column: "interaction_policy_mutuals_only", + columnType: "JSONB", + defaultVal: "", + }, + { + table: "account_settings", + column: "interaction_policy_followers_only", + columnType: "JSONB", + defaultVal: "", + }, + { + table: "account_settings", + column: "interaction_policy_unlocked", + columnType: "JSONB", + defaultVal: "", + }, + { + table: "account_settings", + column: "interaction_policy_public", + columnType: "JSONB", + defaultVal: "", + }, + } { + exists, err := doesColumnExist(ctx, tx, + spec.table, spec.column, + ) + if err != nil { + // Real error. + return err + } else if exists { + // Already created. + continue + } + + args := []any{ + bun.Ident(spec.table), + bun.Ident(spec.column), + bun.Safe(spec.columnType), + } + + qStr := "ALTER TABLE ? ADD COLUMN ? ?" + if spec.defaultVal != "" { + qStr += " ?" + args = append(args, bun.Safe(spec.defaultVal)) + } + + if _, err := tx.ExecContext(ctx, qStr, args...); err != nil { + return err + } + } + + // Select each locally-created status + // with non-default old flags set. + oldStatuses := []oldmodel.Status{} + + if err := tx. + NewSelect(). + Model(&oldStatuses). + Column("id", "likeable", "replyable", "boostable", "visibility"). + Where("? = ?", bun.Ident("local"), true). + WhereGroup(" AND ", func(sq *bun.SelectQuery) *bun.SelectQuery { + return sq. + Where("? = ?", bun.Ident("likeable"), false). + WhereOr("? = ?", bun.Ident("replyable"), false). + WhereOr("? = ?", bun.Ident("boostable"), false) + }). + Scan(ctx); err != nil { + return err + } + + // For each status found in this way, update + // to new version of interaction policy. + for _, oldStatus := range oldStatuses { + // Start with default policy for this visibility. + v := gtsmodel.Visibility(oldStatus.Visibility) + policy := gtsmodel.DefaultInteractionPolicyFor(v) + + if !*oldStatus.Likeable { + // Only author can like. + policy.CanLike = gtsmodel.PolicyRules{ + Always: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + }, + WithApproval: make(gtsmodel.PolicyValues, 0), + } + } + + if !*oldStatus.Replyable { + // Only author + mentioned can Reply. + policy.CanReply = gtsmodel.PolicyRules{ + Always: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + gtsmodel.PolicyValueMentioned, + }, + WithApproval: make(gtsmodel.PolicyValues, 0), + } + } + + if !*oldStatus.Boostable { + // Only author can Announce. + policy.CanAnnounce = gtsmodel.PolicyRules{ + Always: gtsmodel.PolicyValues{ + gtsmodel.PolicyValueAuthor, + }, + WithApproval: make(gtsmodel.PolicyValues, 0), + } + } + + // Update status with the new interaction policy. + newStatus := >smodel.Status{ + ID: oldStatus.ID, + InteractionPolicy: policy, + } + if _, err := tx. + NewUpdate(). + Model(newStatus). + Column("interaction_policy"). + Where("? = ?", bun.Ident("id"), newStatus.ID). + Exec(ctx); err != nil { + return err + } + } + + // Drop now unused columns from statuses table. + oldColumns := []string{ + "likeable", + "replyable", + "boostable", + } + for _, column := range oldColumns { + if _, err := tx. + NewDropColumn(). + Table("statuses"). + Column(column). + Exec(ctx); err != nil { + return err + } + } + + // Add new indexes. + if _, err := tx. + NewCreateIndex(). + Table("statuses"). + Index("statuses_pending_approval_idx"). + Column("pending_approval"). + IfNotExists(). + Exec(ctx); err != nil { + return err + } + + if _, err := tx. + NewCreateIndex(). + Table("status_faves"). + Index("status_faves_pending_approval_idx"). + Column("pending_approval"). + IfNotExists(). + Exec(ctx); err != nil { + return err + } + + return nil + }) + } + + down := func(ctx context.Context, db *bun.DB) error { + return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { + return nil + }) + } + + if err := Migrations.Register(up, down); err != nil { + panic(err) + } +} diff --git a/internal/db/bundb/migrations/20240620074530_interaction_policy/status.go b/internal/db/bundb/migrations/20240620074530_interaction_policy/status.go new file mode 100644 index 000000000..ae96d047d --- /dev/null +++ b/internal/db/bundb/migrations/20240620074530_interaction_policy/status.go @@ -0,0 +1,61 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package gtsmodel + +import ( + "time" +) + +type Status struct { + ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` + CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` + UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` + FetchedAt time.Time `bun:"type:timestamptz,nullzero"` + PinnedAt time.Time `bun:"type:timestamptz,nullzero"` + URI string `bun:",unique,nullzero,notnull"` + URL string `bun:",nullzero"` + Content string `bun:""` + AttachmentIDs []string `bun:"attachments,array"` + TagIDs []string `bun:"tags,array"` + MentionIDs []string `bun:"mentions,array"` + EmojiIDs []string `bun:"emojis,array"` + Local *bool `bun:",nullzero,notnull,default:false"` + AccountID string `bun:"type:CHAR(26),nullzero,notnull"` + AccountURI string `bun:",nullzero,notnull"` + InReplyToID string `bun:"type:CHAR(26),nullzero"` + InReplyToURI string `bun:",nullzero"` + InReplyToAccountID string `bun:"type:CHAR(26),nullzero"` + InReplyTo *Status `bun:"-"` + BoostOfID string `bun:"type:CHAR(26),nullzero"` + BoostOfURI string `bun:"-"` + BoostOfAccountID string `bun:"type:CHAR(26),nullzero"` + BoostOf *Status `bun:"-"` + ThreadID string `bun:"type:CHAR(26),nullzero"` + PollID string `bun:"type:CHAR(26),nullzero"` + ContentWarning string `bun:",nullzero"` + Visibility string `bun:",nullzero,notnull"` + Sensitive *bool `bun:",nullzero,notnull,default:false"` + Language string `bun:",nullzero"` + CreatedWithApplicationID string `bun:"type:CHAR(26),nullzero"` + ActivityStreamsType string `bun:",nullzero,notnull"` + Text string `bun:""` + Federated *bool `bun:",notnull"` + Boostable *bool `bun:",notnull"` + Replyable *bool `bun:",notnull"` + Likeable *bool `bun:",notnull"` +} diff --git a/internal/db/bundb/status_test.go b/internal/db/bundb/status_test.go index 4f0db5e2c..0111dc6e7 100644 --- a/internal/db/bundb/status_test.go +++ b/internal/db/bundb/status_test.go @@ -44,9 +44,6 @@ func (suite *StatusTestSuite) TestGetStatusByID() { suite.Nil(status.InReplyTo) suite.Nil(status.InReplyToAccount) suite.True(*status.Federated) - suite.True(*status.Boostable) - suite.True(*status.Replyable) - suite.True(*status.Likeable) } func (suite *StatusTestSuite) TestGetStatusesByIDs() { @@ -73,9 +70,6 @@ func (suite *StatusTestSuite) TestGetStatusesByIDs() { suite.Nil(status1.InReplyTo) suite.Nil(status1.InReplyToAccount) suite.True(*status1.Federated) - suite.True(*status1.Boostable) - suite.True(*status1.Replyable) - suite.True(*status1.Likeable) status2 := statuses[1] suite.NotNil(status2) @@ -86,9 +80,6 @@ func (suite *StatusTestSuite) TestGetStatusesByIDs() { suite.Nil(status2.InReplyTo) suite.Nil(status2.InReplyToAccount) suite.True(*status2.Federated) - suite.True(*status2.Boostable) - suite.False(*status2.Replyable) - suite.False(*status2.Likeable) } func (suite *StatusTestSuite) TestGetStatusByURI() { @@ -104,9 +95,6 @@ func (suite *StatusTestSuite) TestGetStatusByURI() { suite.Nil(status.InReplyTo) suite.Nil(status.InReplyToAccount) suite.True(*status.Federated) - suite.True(*status.Boostable) - suite.False(*status.Replyable) - suite.False(*status.Likeable) } func (suite *StatusTestSuite) TestGetStatusWithExtras() { @@ -121,9 +109,6 @@ func (suite *StatusTestSuite) TestGetStatusWithExtras() { suite.NotEmpty(status.Attachments) suite.NotEmpty(status.Emojis) suite.True(*status.Federated) - suite.True(*status.Boostable) - suite.True(*status.Replyable) - suite.True(*status.Likeable) } func (suite *StatusTestSuite) TestGetStatusWithMention() { @@ -138,9 +123,6 @@ func (suite *StatusTestSuite) TestGetStatusWithMention() { suite.NotEmpty(status.InReplyToID) suite.NotEmpty(status.InReplyToAccountID) suite.True(*status.Federated) - suite.True(*status.Boostable) - suite.True(*status.Replyable) - suite.True(*status.Likeable) } // The below test was originally used to ensure that a second diff --git a/internal/db/bundb/statusfave.go b/internal/db/bundb/statusfave.go index 8e9ff501c..e3daa876b 100644 --- a/internal/db/bundb/statusfave.go +++ b/internal/db/bundb/statusfave.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" "slices" + "time" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtscontext" @@ -77,6 +78,21 @@ func (s *statusFaveDB) GetStatusFaveByID(ctx context.Context, id string) (*gtsmo ) } +func (s *statusFaveDB) GetStatusFaveByURI(ctx context.Context, uri string) (*gtsmodel.StatusFave, error) { + return s.getStatusFave( + ctx, + "URI", + func(fave *gtsmodel.StatusFave) error { + return s.db. + NewSelect(). + Model(fave). + Where("? = ?", bun.Ident("uri"), uri). + Scan(ctx) + }, + uri, + ) +} + func (s *statusFaveDB) getStatusFave(ctx context.Context, lookup string, dbQuery func(*gtsmodel.StatusFave) error, keyParts ...any) (*gtsmodel.StatusFave, error) { // Fetch status fave from database cache with loader callback fave, err := s.state.Caches.GTS.StatusFave.LoadOne(lookup, func() (*gtsmodel.StatusFave, error) { @@ -242,6 +258,26 @@ func (s *statusFaveDB) PutStatusFave(ctx context.Context, fave *gtsmodel.StatusF }) } +func (s *statusFaveDB) UpdateStatusFave(ctx context.Context, fave *gtsmodel.StatusFave, columns ...string) error { + fave.UpdatedAt = time.Now() + if len(columns) > 0 { + // If we're updating by column, + // ensure "updated_at" is included. + columns = append(columns, "updated_at") + } + + // Update the status fave model in the database. + return s.state.Caches.GTS.StatusFave.Store(fave, func() error { + _, err := s.db. + NewUpdate(). + Model(fave). + Where("? = ?", bun.Ident("status_fave.id"), fave.ID). + Column(columns...). + Exec(ctx) + return err + }) +} + func (s *statusFaveDB) DeleteStatusFaveByID(ctx context.Context, id string) error { var statusID string diff --git a/internal/db/bundb/timeline_test.go b/internal/db/bundb/timeline_test.go index 98ae6b20f..0a014d321 100644 --- a/internal/db/bundb/timeline_test.go +++ b/internal/db/bundb/timeline_test.go @@ -65,9 +65,7 @@ func getFutureStatus() *gtsmodel.Status { Language: "en", CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", Federated: util.Ptr(true), - Boostable: util.Ptr(true), - Replyable: util.Ptr(true), - Likeable: util.Ptr(true), + InteractionPolicy: gtsmodel.DefaultInteractionPolicyPublic(), ActivityStreamsType: ap.ObjectNote, } } diff --git a/internal/db/db.go b/internal/db/db.go index 330766306..a148d778a 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -32,6 +32,7 @@ type DB interface { Emoji HeaderFilter Instance + Interaction Filter List Marker diff --git a/internal/db/interaction.go b/internal/db/interaction.go new file mode 100644 index 000000000..6f595c54e --- /dev/null +++ b/internal/db/interaction.go @@ -0,0 +1,41 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package db + +import ( + "context" + + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +type Interaction interface { + // GetInteractionApprovalByID gets one approval with the given id. + GetInteractionApprovalByID(ctx context.Context, id string) (*gtsmodel.InteractionApproval, error) + + // GetInteractionApprovalByID gets one approval with the given uri. + GetInteractionApprovalByURI(ctx context.Context, id string) (*gtsmodel.InteractionApproval, error) + + // PopulateInteractionApproval ensures that the approval's struct fields are populated. + PopulateInteractionApproval(ctx context.Context, approval *gtsmodel.InteractionApproval) error + + // PutInteractionApproval puts a new approval in the database. + PutInteractionApproval(ctx context.Context, approval *gtsmodel.InteractionApproval) error + + // DeleteInteractionApprovalByID deletes one approval with the given ID. + DeleteInteractionApprovalByID(ctx context.Context, id string) error +} diff --git a/internal/db/statusfave.go b/internal/db/statusfave.go index 343a80caa..192ef436b 100644 --- a/internal/db/statusfave.go +++ b/internal/db/statusfave.go @@ -27,9 +27,12 @@ type StatusFave interface { // GetStatusFaveByAccountID gets one status fave created by the given accountID, targeting the given statusID. GetStatusFave(ctx context.Context, accountID string, statusID string) (*gtsmodel.StatusFave, error) - // GetStatusFave returns one status fave with the given id. + // GetStatusFaveByID returns one status fave with the given id. GetStatusFaveByID(ctx context.Context, id string) (*gtsmodel.StatusFave, error) + // GetStatusFaveByURI returns one status fave with the given uri. + GetStatusFaveByURI(ctx context.Context, uri string) (*gtsmodel.StatusFave, error) + // GetStatusFaves returns a slice of faves/likes of the status with given ID. // This slice will be unfiltered, not taking account of blocks and whatnot, so filter it before serving it back to a user. GetStatusFaves(ctx context.Context, statusID string) ([]*gtsmodel.StatusFave, error) @@ -40,6 +43,9 @@ type StatusFave interface { // PutStatusFave inserts the given statusFave into the database. PutStatusFave(ctx context.Context, statusFave *gtsmodel.StatusFave) error + // UpdateStatusFave updates one statusFave in the database. + UpdateStatusFave(ctx context.Context, statusFave *gtsmodel.StatusFave, columns ...string) error + // DeleteStatusFave deletes one status fave with the given id. DeleteStatusFaveByID(ctx context.Context, id string) error |