diff options
Diffstat (limited to 'internal/db')
17 files changed, 755 insertions, 50 deletions
diff --git a/internal/db/bundb/account_test.go b/internal/db/bundb/account_test.go index 2caffdeb1..7dcc0f9e7 100644 --- a/internal/db/bundb/account_test.go +++ b/internal/db/bundb/account_test.go @@ -106,7 +106,7 @@ func (suite *AccountTestSuite) populateTestStatus(testAccountKey string, status  	status.URI = fmt.Sprintf("http://localhost:8080/users/%s/statuses/%s", testAccount.Username, status.ID)  	status.Local = util.Ptr(true) -	if status.Visibility == "" { +	if status.Visibility == 0 {  		status.Visibility = gtsmodel.VisibilityDefault  	}  	if status.ActivityStreamsType == "" { diff --git a/internal/db/bundb/instance.go b/internal/db/bundb/instance.go index bbfd82ffb..613a2b13a 100644 --- a/internal/db/bundb/instance.go +++ b/internal/db/bundb/instance.go @@ -104,7 +104,7 @@ func (i *instanceDB) CountInstanceStatuses(ctx context.Context, domain string) (  	q = q.Where("NOT ? = ?", bun.Ident("status.pending_approval"), true)  	// Ignore statuses that are direct messages. -	q = q.Where("NOT ? = ?", bun.Ident("status.visibility"), "direct") +	q = q.Where("NOT ? = ?", bun.Ident("status.visibility"), gtsmodel.VisibilityDirect)  	count, err := q.Count(ctx)  	if err != nil { diff --git a/internal/db/bundb/migrations/20231002153327_add_status_polls.go b/internal/db/bundb/migrations/20231002153327_add_status_polls.go index 5e525cc27..019a369d4 100644 --- a/internal/db/bundb/migrations/20231002153327_add_status_polls.go +++ b/internal/db/bundb/migrations/20231002153327_add_status_polls.go @@ -21,7 +21,8 @@ import (  	"context"  	"strings" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	gtsmodel "github.com/superseriousbusiness/gotosocial/internal/db/bundb/migrations/20231002153327_add_status_polls" +  	"github.com/uptrace/bun"  ) diff --git a/internal/db/bundb/migrations/20231002153327_add_status_polls/polls.go b/internal/db/bundb/migrations/20231002153327_add_status_polls/polls.go new file mode 100644 index 000000000..c3e03d267 --- /dev/null +++ b/internal/db/bundb/migrations/20231002153327_add_status_polls/polls.go @@ -0,0 +1,48 @@ +// 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" +) + +// Poll represents an attached (to) Status poll, i.e. a questionaire. Can be remote / local. +type Poll struct { +	ID         string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // Unique identity string. +	Multiple   *bool     `bun:",nullzero,notnull,default:false"`          // Is this a multiple choice poll? i.e. can you vote on multiple options. +	HideCounts *bool     `bun:",nullzero,notnull,default:false"`          // Hides vote counts until poll ends. +	Options    []string  `bun:",nullzero,notnull"`                        // The available options for this poll. +	Votes      []int     `bun:",nullzero,notnull"`                        // Vote counts per choice. +	Voters     *int      `bun:",nullzero,notnull"`                        // Total no. voters count. +	StatusID   string    `bun:"type:CHAR(26),nullzero,notnull,unique"`    // Status ID of which this Poll is attached to. +	ExpiresAt  time.Time `bun:"type:timestamptz,nullzero,notnull"`        // The expiry date of this Poll. +	ClosedAt   time.Time `bun:"type:timestamptz,nullzero"`                // The closure date of this poll, will be zerotime until set. +	Closing    bool      `bun:"-"`                                        // An ephemeral field only set on Polls in the middle of closing. +	// no creation date, use attached Status.CreatedAt. +} + +// PollVote represents a single instance of vote(s) in a Poll by an account. +// If the Poll is single-choice, len(.Choices) = 1, if multiple-choice then +// len(.Choices) >= 1. Can be remote or local. +type PollVote struct { +	ID        string    `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // Unique identity string. +	Choices   []int     `bun:",nullzero,notnull"`                                           // The Poll's option indices of which these are votes for. +	AccountID string    `bun:"type:CHAR(26),nullzero,notnull,unique:in_poll_by_account"`    // Account ID from which this vote originated. +	PollID    string    `bun:"type:CHAR(26),nullzero,notnull,unique:in_poll_by_account"`    // Poll ID of which this is a vote in. +	CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // The creation date of this PollVote. +} diff --git a/internal/db/bundb/migrations/20231002153327_add_status_polls/status.go b/internal/db/bundb/migrations/20231002153327_add_status_polls/status.go new file mode 100644 index 000000000..8e3252e82 --- /dev/null +++ b/internal/db/bundb/migrations/20231002153327_add_status_polls/status.go @@ -0,0 +1,75 @@ +// 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" + +// Status represents a user-created 'post' or 'status' in the database, either remote or local +type Status struct { +	ID                       string     `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt                time.Time  `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt                time.Time  `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	FetchedAt                time.Time  `bun:"type:timestamptz,nullzero"`                                   // when was item (remote) last fetched. +	PinnedAt                 time.Time  `bun:"type:timestamptz,nullzero"`                                   // Status was pinned by owning account at this time. +	URI                      string     `bun:",unique,nullzero,notnull"`                                    // activitypub URI of this status +	URL                      string     `bun:",nullzero"`                                                   // web url for viewing this status +	Content                  string     `bun:""`                                                            // content of this status; likely html-formatted but not guaranteed +	AttachmentIDs            []string   `bun:"attachments,array"`                                           // Database IDs of any media attachments associated with this status +	TagIDs                   []string   `bun:"tags,array"`                                                  // Database IDs of any tags used in this status +	MentionIDs               []string   `bun:"mentions,array"`                                              // Database IDs of any mentions in this status +	EmojiIDs                 []string   `bun:"emojis,array"`                                                // Database IDs of any emojis used in this status +	Local                    *bool      `bun:",nullzero,notnull,default:false"`                             // is this status from a local account? +	AccountID                string     `bun:"type:CHAR(26),nullzero,notnull"`                              // which account posted this status? +	AccountURI               string     `bun:",nullzero,notnull"`                                           // activitypub uri of the owner of this status +	InReplyToID              string     `bun:"type:CHAR(26),nullzero"`                                      // id of the status this status replies to +	InReplyToURI             string     `bun:",nullzero"`                                                   // activitypub uri of the status this status is a reply to +	InReplyToAccountID       string     `bun:"type:CHAR(26),nullzero"`                                      // id of the account that this status replies to +	BoostOfID                string     `bun:"type:CHAR(26),nullzero"`                                      // id of the status this status is a boost of +	BoostOfAccountID         string     `bun:"type:CHAR(26),nullzero"`                                      // id of the account that owns the boosted status +	ThreadID                 string     `bun:"type:CHAR(26),nullzero"`                                      // id of the thread to which this status belongs; only set for remote statuses if a local account is involved at some point in the thread, otherwise null +	PollID                   string     `bun:"type:CHAR(26),nullzero"`                                      // +	ContentWarning           string     `bun:",nullzero"`                                                   // cw string for this status +	Visibility               Visibility `bun:",nullzero,notnull"`                                           // visibility entry for this status +	Sensitive                *bool      `bun:",nullzero,notnull,default:false"`                             // mark the status as sensitive? +	Language                 string     `bun:",nullzero"`                                                   // what language is this status written in? +	CreatedWithApplicationID string     `bun:"type:CHAR(26),nullzero"`                                      // Which application was used to create this status? +	ActivityStreamsType      string     `bun:",nullzero,notnull"`                                           // What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types. Will probably almost always be Note but who knows!. +	Text                     string     `bun:""`                                                            // Original text of the status without formatting +	Federated                *bool      `bun:",notnull"`                                                    // This status will be federated beyond the local timeline(s) +	Boostable                *bool      `bun:",notnull"`                                                    // This status can be boosted/reblogged +	Replyable                *bool      `bun:",notnull"`                                                    // This status can be replied to +	Likeable                 *bool      `bun:",notnull"`                                                    // This status can be liked/faved +} + +// Visibility represents the visibility granularity of a status. +type Visibility string + +const ( +	// VisibilityPublic means this status will be visible to everyone on all timelines. +	VisibilityPublic Visibility = "public" +	// VisibilityUnlocked means this status will be visible to everyone, but will only show on home timeline to followers, and in lists. +	VisibilityUnlocked Visibility = "unlocked" +	// VisibilityFollowersOnly means this status is viewable to followers only. +	VisibilityFollowersOnly Visibility = "followers_only" +	// VisibilityMutualsOnly means this status is visible to mutual followers only. +	VisibilityMutualsOnly Visibility = "mutuals_only" +	// VisibilityDirect means this status is visible only to mentioned recipients. +	VisibilityDirect Visibility = "direct" +	// VisibilityDefault is used when no other setting can be found. +	VisibilityDefault Visibility = VisibilityUnlocked +) diff --git a/internal/db/bundb/migrations/20240620074530_interaction_policy.go b/internal/db/bundb/migrations/20240620074530_interaction_policy.go index bbc75d9ec..7678af7ed 100644 --- a/internal/db/bundb/migrations/20240620074530_interaction_policy.go +++ b/internal/db/bundb/migrations/20240620074530_interaction_policy.go @@ -161,11 +161,14 @@ func init() {  				return err  			} +			// Get the mapping of old enum string values to new integer values. +			visibilityMapping := visibilityEnumMapping[oldmodel.Visibility]() +  			// 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) +				v := visibilityMapping[oldStatus.Visibility]  				policy := gtsmodel.DefaultInteractionPolicyFor(v)  				if !*oldStatus.Likeable { diff --git a/internal/db/bundb/migrations/20240620074530_interaction_policy/status.go b/internal/db/bundb/migrations/20240620074530_interaction_policy/status.go index ae96d047d..615c81b66 100644 --- a/internal/db/bundb/migrations/20240620074530_interaction_policy/status.go +++ b/internal/db/bundb/migrations/20240620074530_interaction_policy/status.go @@ -22,40 +22,61 @@ import (  )  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"` +	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               Visibility `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"`  } + +// Visibility represents the visibility granularity of a status. +type Visibility string + +const ( +	// VisibilityNone means nobody can see this. +	// It's only used for web status visibility. +	VisibilityNone Visibility = "none" +	// VisibilityPublic means this status will be visible to everyone on all timelines. +	VisibilityPublic Visibility = "public" +	// VisibilityUnlocked means this status will be visible to everyone, but will only show on home timeline to followers, and in lists. +	VisibilityUnlocked Visibility = "unlocked" +	// VisibilityFollowersOnly means this status is viewable to followers only. +	VisibilityFollowersOnly Visibility = "followers_only" +	// VisibilityMutualsOnly means this status is visible to mutual followers only. +	VisibilityMutualsOnly Visibility = "mutuals_only" +	// VisibilityDirect means this status is visible only to mentioned recipients. +	VisibilityDirect Visibility = "direct" +	// VisibilityDefault is used when no other setting can be found. +	VisibilityDefault Visibility = VisibilityUnlocked +) diff --git a/internal/db/bundb/migrations/20240904084406_fedi_api_reject_interaction.go b/internal/db/bundb/migrations/20240904084406_fedi_api_reject_interaction.go index d97d35372..d3c0f49a4 100644 --- a/internal/db/bundb/migrations/20240904084406_fedi_api_reject_interaction.go +++ b/internal/db/bundb/migrations/20240904084406_fedi_api_reject_interaction.go @@ -20,7 +20,7 @@ package migrations  import (  	"context" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	gtsmodel "github.com/superseriousbusiness/gotosocial/internal/db/bundb/migrations/20240904084406_fedi_api_reject_interaction"  	"github.com/uptrace/bun"  ) diff --git a/internal/db/bundb/migrations/20240904084406_fedi_api_reject_interaction/sinbinstatus.go b/internal/db/bundb/migrations/20240904084406_fedi_api_reject_interaction/sinbinstatus.go new file mode 100644 index 000000000..e18affa9b --- /dev/null +++ b/internal/db/bundb/migrations/20240904084406_fedi_api_reject_interaction/sinbinstatus.go @@ -0,0 +1,66 @@ +// 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" + +// SinBinStatus represents a status that's been rejected and/or reported + quarantined. +// +// Automatically rejected statuses are not put in the sin bin, only statuses that were +// stored on the instance and which someone (local or remote) has subsequently rejected. +type SinBinStatus struct { +	ID                  string     `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // ID of this item in the database. +	CreatedAt           time.Time  `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Creation time of this item. +	UpdatedAt           time.Time  `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Last-updated time of this item. +	URI                 string     `bun:",unique,nullzero,notnull"`                                    // ActivityPub URI/ID of this status. +	URL                 string     `bun:",nullzero"`                                                   // Web url for viewing this status. +	Domain              string     `bun:",nullzero"`                                                   // Domain of the status, will be null if this is a local status, otherwise something like `example.org`. +	AccountURI          string     `bun:",nullzero,notnull"`                                           // ActivityPub uri of the author of this status. +	InReplyToURI        string     `bun:",nullzero"`                                                   // ActivityPub uri of the status this status is a reply to. +	Content             string     `bun:",nullzero"`                                                   // Content of this status. +	AttachmentLinks     []string   `bun:",nullzero,array"`                                             // Links to attachments of this status. +	MentionTargetURIs   []string   `bun:",nullzero,array"`                                             // URIs of mentioned accounts. +	EmojiLinks          []string   `bun:",nullzero,array"`                                             // Links to any emoji images used in this status. +	PollOptions         []string   `bun:",nullzero,array"`                                             // String values of any poll options used in this status. +	ContentWarning      string     `bun:",nullzero"`                                                   // CW / subject string for this status. +	Visibility          Visibility `bun:",nullzero,notnull"`                                           // Visibility level of this status. +	Sensitive           *bool      `bun:",nullzero,notnull,default:false"`                             // Mark the status as sensitive. +	Language            string     `bun:",nullzero"`                                                   // Language code for this status. +	ActivityStreamsType string     `bun:",nullzero,notnull"`                                           // ActivityStreams type of this status. +} + +// Visibility represents the visibility granularity of a status. +type Visibility string + +const ( +	// VisibilityNone means nobody can see this. +	// It's only used for web status visibility. +	VisibilityNone Visibility = "none" +	// VisibilityPublic means this status will be visible to everyone on all timelines. +	VisibilityPublic Visibility = "public" +	// VisibilityUnlocked means this status will be visible to everyone, but will only show on home timeline to followers, and in lists. +	VisibilityUnlocked Visibility = "unlocked" +	// VisibilityFollowersOnly means this status is viewable to followers only. +	VisibilityFollowersOnly Visibility = "followers_only" +	// VisibilityMutualsOnly means this status is visible to mutual followers only. +	VisibilityMutualsOnly Visibility = "mutuals_only" +	// VisibilityDirect means this status is visible only to mentioned recipients. +	VisibilityDirect Visibility = "direct" +	// VisibilityDefault is used when no other setting can be found. +	VisibilityDefault Visibility = VisibilityUnlocked +) diff --git a/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints.go b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints.go new file mode 100644 index 000000000..10ae95c17 --- /dev/null +++ b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints.go @@ -0,0 +1,249 @@ +// 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" +	"errors" + +	old_gtsmodel "github.com/superseriousbusiness/gotosocial/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints" +	"github.com/superseriousbusiness/gotosocial/internal/gtserror" +	new_gtsmodel "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/log" +	"github.com/superseriousbusiness/gotosocial/internal/util" + +	"github.com/uptrace/bun" +) + +func init() { +	up := func(ctx context.Context, db *bun.DB) error { +		return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { + +			// Tables with visibility types. +			var visTables = []struct { +				Table   string +				Column  string +				Default *new_gtsmodel.Visibility +			}{ +				{Table: "statuses", Column: "visibility"}, +				{Table: "sin_bin_statuses", Column: "visibility"}, +				{Table: "account_settings", Column: "privacy", Default: util.Ptr(new_gtsmodel.VisibilityDefault)}, +				{Table: "account_settings", Column: "web_visibility", Default: util.Ptr(new_gtsmodel.VisibilityDefault)}, +			} + +			// Visibility type indices. +			var visIndices = []struct { +				name  string +				cols  []string +				order string +			}{ +				{ +					name:  "statuses_visibility_idx", +					cols:  []string{"visibility"}, +					order: "", +				}, +				{ +					name:  "statuses_profile_web_view_idx", +					cols:  []string{"account_id", "visibility"}, +					order: "id DESC", +				}, +				{ +					name:  "statuses_public_timeline_idx", +					cols:  []string{"visibility"}, +					order: "id DESC", +				}, +			} + +			// Before making changes to the visibility col +			// we must drop all indices that rely on it. +			for _, index := range visIndices { +				if _, err := tx.NewDropIndex(). +					Index(index.name). +					Exec(ctx); err != nil { +					return err +				} +			} + +			// Get the mapping of old enum string values to new integer values. +			visibilityMapping := visibilityEnumMapping[old_gtsmodel.Visibility]() + +			// Convert all visibility tables. +			for _, table := range visTables { +				if err := convertEnums(ctx, tx, table.Table, table.Column, +					visibilityMapping, table.Default); err != nil { +					return err +				} +			} + +			// Recreate the visibility indices. +			for _, index := range visIndices { +				q := tx.NewCreateIndex(). +					Table("statuses"). +					Index(index.name). +					Column(index.cols...) +				if index.order != "" { +					q = q.ColumnExpr(index.order) +				} +				if _, err := q.Exec(ctx); err != nil { +					return err +				} +			} + +			// Get the mapping of old enum string values to the new integer value types. +			notificationMapping := notificationEnumMapping[old_gtsmodel.NotificationType]() + +			// Migrate over old notifications table column over to new column type. +			if err := convertEnums(ctx, tx, "notifications", "notification_type", //nolint:revive +				notificationMapping, nil); 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) +	} +} + +// convertEnums performs a transaction that converts +// a table's column of our old-style enums (strings) to +// more performant and space-saving integer types. +func convertEnums[OldType ~string, NewType ~int16]( +	ctx context.Context, +	tx bun.Tx, +	table string, +	column string, +	mapping map[OldType]NewType, +	defaultValue *NewType, +) error { +	if len(mapping) == 0 { +		return errors.New("empty mapping") +	} + +	// Generate new column name. +	newColumn := column + "_new" + +	log.Infof(ctx, "converting %s.%s enums; "+ +		"this may take a while, please don't interrupt!", +		table, column, +	) + +	// Ensure a default value. +	if defaultValue == nil { +		var zero NewType +		defaultValue = &zero +	} + +	// Add new column to database. +	if _, err := tx.NewAddColumn(). +		Table(table). +		ColumnExpr("? SMALLINT NOT NULL DEFAULT ?", +			bun.Ident(newColumn), +			*defaultValue). +		Exec(ctx); err != nil { +		return gtserror.Newf("error adding new column: %w", err) +	} + +	// Get a count of all in table. +	total, err := tx.NewSelect(). +		Table(table). +		Count(ctx) +	if err != nil { +		return gtserror.Newf("error selecting total count: %w", err) +	} + +	var updated int +	for old, new := range mapping { + +		// Update old to new values. +		res, err := tx.NewUpdate(). +			Table(table). +			Where("? = ?", bun.Ident(column), old). +			Set("? = ?", bun.Ident(newColumn), new). +			Exec(ctx) +		if err != nil { +			return gtserror.Newf("error updating old column values: %w", err) +		} + +		// Count number items updated. +		n, _ := res.RowsAffected() +		updated += int(n) +	} + +	// Check total updated. +	if total != updated { +		log.Warnf(ctx, "total=%d does not match updated=%d", total, updated) +	} + +	// Drop the old column from table. +	if _, err := tx.NewDropColumn(). +		Table(table). +		ColumnExpr("?", bun.Ident(column)). +		Exec(ctx); err != nil { +		return gtserror.Newf("error dropping old column: %w", err) +	} + +	// Rename new to old name. +	if _, err := tx.NewRaw( +		"ALTER TABLE ? RENAME COLUMN ? TO ?", +		bun.Ident(table), +		bun.Ident(newColumn), +		bun.Ident(column), +	).Exec(ctx); err != nil { +		return gtserror.Newf("error renaming new column: %w", err) +	} + +	return nil +} + +// visibilityEnumMapping maps old Visibility enum values to their newer integer type. +func visibilityEnumMapping[T ~string]() map[T]new_gtsmodel.Visibility { +	return map[T]new_gtsmodel.Visibility{ +		T(old_gtsmodel.VisibilityNone):          new_gtsmodel.VisibilityNone, +		T(old_gtsmodel.VisibilityPublic):        new_gtsmodel.VisibilityPublic, +		T(old_gtsmodel.VisibilityUnlocked):      new_gtsmodel.VisibilityUnlocked, +		T(old_gtsmodel.VisibilityFollowersOnly): new_gtsmodel.VisibilityFollowersOnly, +		T(old_gtsmodel.VisibilityMutualsOnly):   new_gtsmodel.VisibilityMutualsOnly, +		T(old_gtsmodel.VisibilityDirect):        new_gtsmodel.VisibilityDirect, +	} +} + +// notificationEnumMapping maps old NotificationType enum values to their newer integer type. +func notificationEnumMapping[T ~string]() map[T]new_gtsmodel.NotificationType { +	return map[T]new_gtsmodel.NotificationType{ +		T(old_gtsmodel.NotificationFollow):        new_gtsmodel.NotificationFollow, +		T(old_gtsmodel.NotificationFollowRequest): new_gtsmodel.NotificationFollowRequest, +		T(old_gtsmodel.NotificationMention):       new_gtsmodel.NotificationMention, +		T(old_gtsmodel.NotificationReblog):        new_gtsmodel.NotificationReblog, +		T(old_gtsmodel.NotificationFave):          new_gtsmodel.NotificationFave, +		T(old_gtsmodel.NotificationPoll):          new_gtsmodel.NotificationPoll, +		T(old_gtsmodel.NotificationStatus):        new_gtsmodel.NotificationStatus, +		T(old_gtsmodel.NotificationSignup):        new_gtsmodel.NotificationSignup, +		T(old_gtsmodel.NotificationPendingFave):   new_gtsmodel.NotificationPendingFave, +		T(old_gtsmodel.NotificationPendingReply):  new_gtsmodel.NotificationPendingReply, +		T(old_gtsmodel.NotificationPendingReblog): new_gtsmodel.NotificationPendingReblog, +	} +} diff --git a/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/accountsettings.go b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/accountsettings.go new file mode 100644 index 000000000..9a9cfd8e1 --- /dev/null +++ b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/accountsettings.go @@ -0,0 +1,45 @@ +// 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" + +	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +// AccountSettings models settings / preferences for a local, non-instance account. +type AccountSettings struct { +	AccountID                      string                      `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // AccountID that owns this settings. +	CreatedAt                      time.Time                   `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created. +	UpdatedAt                      time.Time                   `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item was last updated. +	Privacy                        Visibility                  `bun:",nullzero,default:3"`                                         // Default post privacy for this account +	Sensitive                      *bool                       `bun:",nullzero,notnull,default:false"`                             // Set posts from this account to sensitive by default? +	Language                       string                      `bun:",nullzero,notnull,default:'en'"`                              // What language does this account post in? +	StatusContentType              string                      `bun:",nullzero"`                                                   // What is the default format for statuses posted by this account (only for local accounts). +	Theme                          string                      `bun:",nullzero"`                                                   // Preset CSS theme filename selected by this Account (empty string if nothing set). +	CustomCSS                      string                      `bun:",nullzero"`                                                   // Custom CSS that should be displayed for this Account's profile and statuses. +	EnableRSS                      *bool                       `bun:",nullzero,notnull,default:false"`                             // enable RSS feed subscription for this account's public posts at [URL]/feed +	HideCollections                *bool                       `bun:",nullzero,notnull,default:false"`                             // Hide this account's followers/following collections. +	WebVisibility                  Visibility                  `bun:",nullzero,notnull,default:3"`                                 // Visibility level of statuses that visitors can view via the web profile. +	InteractionPolicyDirect        *gtsmodel.InteractionPolicy `bun:""`                                                            // Interaction policy to use for new direct visibility statuses by this account. If null, assume default policy. +	InteractionPolicyMutualsOnly   *gtsmodel.InteractionPolicy `bun:""`                                                            // Interaction policy to use for new mutuals only visibility statuses. If null, assume default policy. +	InteractionPolicyFollowersOnly *gtsmodel.InteractionPolicy `bun:""`                                                            // Interaction policy to use for new followers only visibility statuses. If null, assume default policy. +	InteractionPolicyUnlocked      *gtsmodel.InteractionPolicy `bun:""`                                                            // Interaction policy to use for new unlocked visibility statuses. If null, assume default policy. +	InteractionPolicyPublic        *gtsmodel.InteractionPolicy `bun:""`                                                            // Interaction policy to use for new public visibility statuses. If null, assume default policy. +} diff --git a/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/notification.go b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/notification.go new file mode 100644 index 000000000..77166a35d --- /dev/null +++ b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/notification.go @@ -0,0 +1,57 @@ +// 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" + +	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +// Notification models an alert/notification sent to an account about something like a reblog, like, new follow request, etc. +type Notification struct { +	ID               string            `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt        time.Time         `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt        time.Time         `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	NotificationType NotificationType  `bun:",nullzero,notnull"`                                           // Type of this notification +	TargetAccountID  string            `bun:"type:CHAR(26),nullzero,notnull"`                              // ID of the account targeted by the notification (ie., who will receive the notification?) +	TargetAccount    *gtsmodel.Account `bun:"-"`                                                           // Account corresponding to TargetAccountID. Can be nil, always check first + select using ID if necessary. +	OriginAccountID  string            `bun:"type:CHAR(26),nullzero,notnull"`                              // ID of the account that performed the action that created the notification. +	OriginAccount    *gtsmodel.Account `bun:"-"`                                                           // Account corresponding to OriginAccountID. Can be nil, always check first + select using ID if necessary. +	StatusID         string            `bun:"type:CHAR(26),nullzero"`                                      // If the notification pertains to a status, what is the database ID of that status? +	Status           *Status           `bun:"-"`                                                           // Status corresponding to StatusID. Can be nil, always check first + select using ID if necessary. +	Read             *bool             `bun:",nullzero,notnull,default:false"`                             // Notification has been seen/read +} + +// NotificationType describes the reason/type of this notification. +type NotificationType string + +// Notification Types +const ( +	NotificationFollow        NotificationType = "follow"            // NotificationFollow -- someone followed you +	NotificationFollowRequest NotificationType = "follow_request"    // NotificationFollowRequest -- someone requested to follow you +	NotificationMention       NotificationType = "mention"           // NotificationMention -- someone mentioned you in their status +	NotificationReblog        NotificationType = "reblog"            // NotificationReblog -- someone boosted one of your statuses +	NotificationFave          NotificationType = "favourite"         // NotificationFave -- someone faved/liked one of your statuses +	NotificationPoll          NotificationType = "poll"              // NotificationPoll -- a poll you voted in or created has ended +	NotificationStatus        NotificationType = "status"            // NotificationStatus -- someone you enabled notifications for has posted a status. +	NotificationSignup        NotificationType = "admin.sign_up"     // NotificationSignup -- someone has submitted a new account sign-up to the instance. +	NotificationPendingFave   NotificationType = "pending.favourite" // Someone has faved a status of yours, which requires approval by you. +	NotificationPendingReply  NotificationType = "pending.reply"     // Someone has replied to a status of yours, which requires approval by you. +	NotificationPendingReblog NotificationType = "pending.reblog"    // Someone has boosted a status of yours, which requires approval by you. +) diff --git a/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/sinbinstatus.go b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/sinbinstatus.go new file mode 100644 index 000000000..d1dfcddd1 --- /dev/null +++ b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/sinbinstatus.go @@ -0,0 +1,45 @@ +// 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" + +// SinBinStatus represents a status that's been rejected and/or reported + quarantined. +// +// Automatically rejected statuses are not put in the sin bin, only statuses that were +// stored on the instance and which someone (local or remote) has subsequently rejected. +type SinBinStatus struct { +	ID                  string     `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // ID of this item in the database. +	CreatedAt           time.Time  `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Creation time of this item. +	UpdatedAt           time.Time  `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Last-updated time of this item. +	URI                 string     `bun:",unique,nullzero,notnull"`                                    // ActivityPub URI/ID of this status. +	URL                 string     `bun:",nullzero"`                                                   // Web url for viewing this status. +	Domain              string     `bun:",nullzero"`                                                   // Domain of the status, will be null if this is a local status, otherwise something like `example.org`. +	AccountURI          string     `bun:",nullzero,notnull"`                                           // ActivityPub uri of the author of this status. +	InReplyToURI        string     `bun:",nullzero"`                                                   // ActivityPub uri of the status this status is a reply to. +	Content             string     `bun:",nullzero"`                                                   // Content of this status. +	AttachmentLinks     []string   `bun:",nullzero,array"`                                             // Links to attachments of this status. +	MentionTargetURIs   []string   `bun:",nullzero,array"`                                             // URIs of mentioned accounts. +	EmojiLinks          []string   `bun:",nullzero,array"`                                             // Links to any emoji images used in this status. +	PollOptions         []string   `bun:",nullzero,array"`                                             // String values of any poll options used in this status. +	ContentWarning      string     `bun:",nullzero"`                                                   // CW / subject string for this status. +	Visibility          Visibility `bun:",nullzero,notnull"`                                           // Visibility level of this status. +	Sensitive           *bool      `bun:",nullzero,notnull,default:false"`                             // Mark the status as sensitive. +	Language            string     `bun:",nullzero"`                                                   // Language code for this status. +	ActivityStreamsType string     `bun:",nullzero,notnull"`                                           // ActivityStreams type of this status. +} diff --git a/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/status.go b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/status.go new file mode 100644 index 000000000..38583c7fc --- /dev/null +++ b/internal/db/bundb/migrations/20241121121623_enum_strings_to_ints/status.go @@ -0,0 +1,95 @@ +// 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" + +	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +// Status represents a user-created 'post' or 'status' in the database, either remote or local +type Status struct { +	ID                       string                      `bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                    // id of this item in the database +	CreatedAt                time.Time                   `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created +	UpdatedAt                time.Time                   `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated +	FetchedAt                time.Time                   `bun:"type:timestamptz,nullzero"`                                   // when was item (remote) last fetched. +	PinnedAt                 time.Time                   `bun:"type:timestamptz,nullzero"`                                   // Status was pinned by owning account at this time. +	URI                      string                      `bun:",unique,nullzero,notnull"`                                    // activitypub URI of this status +	URL                      string                      `bun:",nullzero"`                                                   // web url for viewing this status +	Content                  string                      `bun:""`                                                            // content of this status; likely html-formatted but not guaranteed +	AttachmentIDs            []string                    `bun:"attachments,array"`                                           // Database IDs of any media attachments associated with this status +	Attachments              []*gtsmodel.MediaAttachment `bun:"attached_media,rel:has-many"`                                 // Attachments corresponding to attachmentIDs +	TagIDs                   []string                    `bun:"tags,array"`                                                  // Database IDs of any tags used in this status +	Tags                     []*gtsmodel.Tag             `bun:"attached_tags,m2m:status_to_tags"`                            // Tags corresponding to tagIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation +	MentionIDs               []string                    `bun:"mentions,array"`                                              // Database IDs of any mentions in this status +	Mentions                 []*gtsmodel.Mention         `bun:"attached_mentions,rel:has-many"`                              // Mentions corresponding to mentionIDs +	EmojiIDs                 []string                    `bun:"emojis,array"`                                                // Database IDs of any emojis used in this status +	Emojis                   []*gtsmodel.Emoji           `bun:"attached_emojis,m2m:status_to_emojis"`                        // Emojis corresponding to emojiIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation +	Local                    *bool                       `bun:",nullzero,notnull,default:false"`                             // is this status from a local account? +	AccountID                string                      `bun:"type:CHAR(26),nullzero,notnull"`                              // which account posted this status? +	Account                  *gtsmodel.Account           `bun:"rel:belongs-to"`                                              // account corresponding to accountID +	AccountURI               string                      `bun:",nullzero,notnull"`                                           // activitypub uri of the owner of this status +	InReplyToID              string                      `bun:"type:CHAR(26),nullzero"`                                      // id of the status this status replies to +	InReplyToURI             string                      `bun:",nullzero"`                                                   // activitypub uri of the status this status is a reply to +	InReplyToAccountID       string                      `bun:"type:CHAR(26),nullzero"`                                      // id of the account that this status replies to +	InReplyTo                *Status                     `bun:"-"`                                                           // status corresponding to inReplyToID +	InReplyToAccount         *gtsmodel.Account           `bun:"rel:belongs-to"`                                              // account corresponding to inReplyToAccountID +	BoostOfID                string                      `bun:"type:CHAR(26),nullzero"`                                      // id of the status this status is a boost of +	BoostOfURI               string                      `bun:"-"`                                                           // URI of the status this status is a boost of; field not inserted in the db, just for dereferencing purposes. +	BoostOfAccountID         string                      `bun:"type:CHAR(26),nullzero"`                                      // id of the account that owns the boosted status +	BoostOf                  *Status                     `bun:"-"`                                                           // status that corresponds to boostOfID +	BoostOfAccount           *gtsmodel.Account           `bun:"rel:belongs-to"`                                              // account that corresponds to boostOfAccountID +	ThreadID                 string                      `bun:"type:CHAR(26),nullzero"`                                      // id of the thread to which this status belongs; only set for remote statuses if a local account is involved at some point in the thread, otherwise null +	PollID                   string                      `bun:"type:CHAR(26),nullzero"`                                      // +	Poll                     *gtsmodel.Poll              `bun:"-"`                                                           // +	ContentWarning           string                      `bun:",nullzero"`                                                   // cw string for this status +	Visibility               Visibility                  `bun:",nullzero,notnull"`                                           // visibility entry for this status +	Sensitive                *bool                       `bun:",nullzero,notnull,default:false"`                             // mark the status as sensitive? +	Language                 string                      `bun:",nullzero"`                                                   // what language is this status written in? +	CreatedWithApplicationID string                      `bun:"type:CHAR(26),nullzero"`                                      // Which application was used to create this status? +	CreatedWithApplication   *gtsmodel.Application       `bun:"rel:belongs-to"`                                              // application corresponding to createdWithApplicationID +	ActivityStreamsType      string                      `bun:",nullzero,notnull"`                                           // What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types. Will probably almost always be Note but who knows!. +	Text                     string                      `bun:""`                                                            // Original text of the status without formatting +	Federated                *bool                       `bun:",notnull"`                                                    // This status will be federated beyond the local timeline(s) +	InteractionPolicy        *gtsmodel.InteractionPolicy `bun:""`                                                            // InteractionPolicy for this status. If null then the default InteractionPolicy should be assumed for this status's Visibility. Always null for boost wrappers. +	PendingApproval          *bool                       `bun:",nullzero,notnull,default:false"`                             // If true then status is a reply or boost wrapper that must be Approved by the reply-ee or boost-ee before being fully distributed. +	PreApproved              bool                        `bun:"-"`                                                           // If true, then status is a reply to or boost wrapper of a status on our instance, has permission to do the interaction, and an Accept should be sent out for it immediately. Field not stored in the DB. +	ApprovedByURI            string                      `bun:",nullzero"`                                                   // URI of an Accept Activity that approves the Announce or Create Activity that this status was/will be attached to. +} + +// Visibility represents the visibility granularity of a status. +type Visibility string + +const ( +	// VisibilityNone means nobody can see this. +	// It's only used for web status visibility. +	VisibilityNone Visibility = "none" +	// VisibilityPublic means this status will be visible to everyone on all timelines. +	VisibilityPublic Visibility = "public" +	// VisibilityUnlocked means this status will be visible to everyone, but will only show on home timeline to followers, and in lists. +	VisibilityUnlocked Visibility = "unlocked" +	// VisibilityFollowersOnly means this status is viewable to followers only. +	VisibilityFollowersOnly Visibility = "followers_only" +	// VisibilityMutualsOnly means this status is visible to mutual followers only. +	VisibilityMutualsOnly Visibility = "mutuals_only" +	// VisibilityDirect means this status is visible only to mentioned recipients. +	VisibilityDirect Visibility = "direct" +	// VisibilityDefault is used when no other setting can be found. +	VisibilityDefault Visibility = VisibilityUnlocked +) diff --git a/internal/db/bundb/notification.go b/internal/db/bundb/notification.go index ef2527637..a20ab7e3f 100644 --- a/internal/db/bundb/notification.go +++ b/internal/db/bundb/notification.go @@ -196,8 +196,8 @@ func (n *notificationDB) GetAccountNotifications(  	sinceID string,  	minID string,  	limit int, -	types []string, -	excludeTypes []string, +	types []gtsmodel.NotificationType, +	excludeTypes []gtsmodel.NotificationType,  ) ([]*gtsmodel.Notification, error) {  	// Ensure reasonable  	if limit < 0 { @@ -303,7 +303,7 @@ func (n *notificationDB) DeleteNotificationByID(ctx context.Context, id string)  	return nil  } -func (n *notificationDB) DeleteNotifications(ctx context.Context, types []string, targetAccountID string, originAccountID string) error { +func (n *notificationDB) DeleteNotifications(ctx context.Context, types []gtsmodel.NotificationType, targetAccountID string, originAccountID string) error {  	if targetAccountID == "" && originAccountID == "" {  		return gtserror.New("one of targetAccountID or originAccountID must be set")  	} diff --git a/internal/db/bundb/relationship_follow_req.go b/internal/db/bundb/relationship_follow_req.go index 030c99c58..f36d626ca 100644 --- a/internal/db/bundb/relationship_follow_req.go +++ b/internal/db/bundb/relationship_follow_req.go @@ -265,8 +265,8 @@ func (r *relationshipDB) AcceptFollowRequest(ctx context.Context, sourceAccountI  	}  	// Delete original follow request notification -	if err := r.state.DB.DeleteNotifications(ctx, []string{ -		string(gtsmodel.NotificationFollowRequest), +	if err := r.state.DB.DeleteNotifications(ctx, []gtsmodel.NotificationType{ +		gtsmodel.NotificationFollowRequest,  	}, targetAccountID, sourceAccountID); err != nil {  		return nil, err  	} @@ -281,8 +281,8 @@ func (r *relationshipDB) RejectFollowRequest(ctx context.Context, sourceAccountI  	}  	// Delete follow request notification -	return r.state.DB.DeleteNotifications(ctx, []string{ -		string(gtsmodel.NotificationFollowRequest), +	return r.state.DB.DeleteNotifications(ctx, []gtsmodel.NotificationType{ +		gtsmodel.NotificationFollowRequest,  	}, targetAccountID, sourceAccountID)  } diff --git a/internal/db/notification.go b/internal/db/notification.go index deb58835a..c962023be 100644 --- a/internal/db/notification.go +++ b/internal/db/notification.go @@ -29,7 +29,7 @@ type Notification interface {  	//  	// Returned notifications will be ordered ID descending (ie., highest/newest to lowest/oldest).  	// If types is empty, *all* notification types will be included. -	GetAccountNotifications(ctx context.Context, accountID string, maxID string, sinceID string, minID string, limit int, types []string, excludeTypes []string) ([]*gtsmodel.Notification, error) +	GetAccountNotifications(ctx context.Context, accountID string, maxID string, sinceID string, minID string, limit int, types []gtsmodel.NotificationType, excludeTypes []gtsmodel.NotificationType) ([]*gtsmodel.Notification, error)  	// GetNotificationByID returns one notification according to its id.  	GetNotificationByID(ctx context.Context, id string) (*gtsmodel.Notification, error) @@ -64,7 +64,7 @@ type Notification interface {  	// originate from originAccountID will be deleted.  	//  	// At least one parameter must not be an empty string. -	DeleteNotifications(ctx context.Context, types []string, targetAccountID string, originAccountID string) error +	DeleteNotifications(ctx context.Context, types []gtsmodel.NotificationType, targetAccountID string, originAccountID string) error  	// DeleteNotificationsForStatus deletes all notifications that relate to  	// the given statusID. This function is useful when a status has been deleted,  | 
