diff options
Diffstat (limited to 'internal/db/bundb')
6 files changed, 446 insertions, 31 deletions
diff --git a/internal/db/bundb/account.go b/internal/db/bundb/account.go index 66dc3b307..603740f17 100644 --- a/internal/db/bundb/account.go +++ b/internal/db/bundb/account.go @@ -1054,10 +1054,21 @@ func (a *accountDB) GetAccountWebStatuses( return nil, nil } - // Check for an easy case: account exposes no statuses via the web. - webVisibility := account.Settings.WebVisibility - if webVisibility == gtsmodel.VisibilityNone { - return nil, db.ErrNoEntries + // Derive visibility of statuses on the web. + // + // We don't account for situations where someone + // hides public statuses but shows unlocked/unlisted, + // since that's only an option for remote accts. + var ( + hideAll = *account.HidesToPublicFromUnauthedWeb + publicOnly = *account.HidesCcPublicFromUnauthedWeb + ) + + if hideAll { + // Account hides all + // statuses from web, + // nothing to do. + return nil, nil } // Ensure reasonable @@ -1075,27 +1086,18 @@ func (a *accountDB) GetAccountWebStatuses( Column("status.id"). Where("? = ?", bun.Ident("status.account_id"), account.ID) - // Select statuses for this account according - // to their web visibility preference. - switch webVisibility { - - case gtsmodel.VisibilityPublic: + // Select statuses according to + // account's web visibility prefs. + if publicOnly { // Only Public statuses. q = q.Where("? = ?", bun.Ident("status.visibility"), gtsmodel.VisibilityPublic) - - case gtsmodel.VisibilityUnlocked: + } else { // Public or Unlocked. visis := []gtsmodel.Visibility{ gtsmodel.VisibilityPublic, gtsmodel.VisibilityUnlocked, } q = q.Where("? IN (?)", bun.Ident("status.visibility"), bun.In(visis)) - - default: - return nil, gtserror.Newf( - "unrecognized web visibility for account %s: %s", - account.ID, webVisibility, - ) } // Don't show replies, boosts, or diff --git a/internal/db/bundb/admin.go b/internal/db/bundb/admin.go index 0666cf8a8..dcf51c6a5 100644 --- a/internal/db/bundb/admin.go +++ b/internal/db/bundb/admin.go @@ -120,20 +120,21 @@ func (a *adminDB) NewSignup(ctx context.Context, newSignup gtsmodel.NewSignup) ( } account = >smodel.Account{ - ID: accountID, - Username: newSignup.Username, - DisplayName: newSignup.Username, - URI: uris.UserURI, - URL: uris.UserURL, - InboxURI: uris.InboxURI, - OutboxURI: uris.OutboxURI, - FollowingURI: uris.FollowingURI, - FollowersURI: uris.FollowersURI, - FeaturedCollectionURI: uris.FeaturedCollectionURI, - ActorType: gtsmodel.AccountActorTypePerson, - PrivateKey: privKey, - PublicKey: &privKey.PublicKey, - PublicKeyURI: uris.PublicKeyURI, + ID: accountID, + Username: newSignup.Username, + DisplayName: newSignup.Username, + URI: uris.UserURI, + URL: uris.UserURL, + InboxURI: uris.InboxURI, + OutboxURI: uris.OutboxURI, + FollowingURI: uris.FollowingURI, + FollowersURI: uris.FollowersURI, + FeaturedCollectionURI: uris.FeaturedCollectionURI, + ActorType: gtsmodel.AccountActorTypePerson, + PrivateKey: privKey, + PublicKey: &privKey.PublicKey, + PublicKeyURI: uris.PublicKeyURI, + HidesCcPublicFromUnauthedWeb: util.Ptr(true), // GtS default to hide unlisted. } // Insert the new account! diff --git a/internal/db/bundb/migrations/20250708074906_unauthed_web_updates.go b/internal/db/bundb/migrations/20250708074906_unauthed_web_updates.go new file mode 100644 index 000000000..f69dbac86 --- /dev/null +++ b/internal/db/bundb/migrations/20250708074906_unauthed_web_updates.go @@ -0,0 +1,164 @@ +// 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" + "fmt" + "reflect" + + "code.superseriousbusiness.org/gotosocial/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/common" + newmodel "code.superseriousbusiness.org/gotosocial/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/new" + oldmodel "code.superseriousbusiness.org/gotosocial/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/old" + "code.superseriousbusiness.org/gotosocial/internal/log" + "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 { + + var account *newmodel.Account + accountType := reflect.TypeOf(account) + + // Add new columns to accounts + // table if they don't exist already. + for _, new := range []struct { + dbCol string + fieldName string + }{ + { + dbCol: "hides_to_public_from_unauthed_web", + fieldName: "HidesToPublicFromUnauthedWeb", + }, + { + dbCol: "hides_cc_public_from_unauthed_web", + fieldName: "HidesCcPublicFromUnauthedWeb", + }, + } { + exists, err := doesColumnExist( + ctx, + tx, + "accounts", + new.dbCol, + ) + if err != nil { + return err + } + + if exists { + // Column already exists. + continue + } + + // Column doesn't exist yet, add it. + colDef, err := getBunColumnDef(tx, accountType, new.fieldName) + if err != nil { + return fmt.Errorf("error making column def: %w", err) + } + + log.Infof(ctx, "adding accounts.%s column...", new.dbCol) + if _, err := tx. + NewAddColumn(). + Model(account). + ColumnExpr(colDef). + Exec(ctx); err != nil { + return fmt.Errorf("error adding column: %w", err) + } + } + + // For each account settings we have + // stored on this instance, set the + // new account columns to values + // corresponding to the setting. + allSettings := []*oldmodel.AccountSettings{} + if err := tx. + NewSelect(). + Model(&allSettings). + Column("account_id", "web_visibility"). + Scan(ctx); err != nil { + return fmt.Errorf("error selecting settings: %w", err) + } + + for _, settings := range allSettings { + + // Derive web visibility. + var ( + hidesToPublicFromUnauthedWeb bool + hidesCcPublicFromUnauthedWeb bool + ) + + switch settings.WebVisibility { + + // Show nothing. + case common.VisibilityNone: + hidesToPublicFromUnauthedWeb = true + hidesCcPublicFromUnauthedWeb = true + + // Show public only (GtS default). + case common.VisibilityPublic: + hidesToPublicFromUnauthedWeb = false + hidesCcPublicFromUnauthedWeb = true + + // Show public + unlisted (Masto default). + case common.VisibilityUnlocked: + hidesToPublicFromUnauthedWeb = false + hidesCcPublicFromUnauthedWeb = false + + default: + log.Warnf(ctx, + "local account %s had unrecognized settings.WebVisibility %d, skipping...", + settings.AccountID, settings.WebVisibility, + ) + continue + } + + // Update account. + if _, err := tx. + NewUpdate(). + Table("accounts"). + Set("? = ?", bun.Ident("hides_to_public_from_unauthed_web"), hidesToPublicFromUnauthedWeb). + Set("? = ?", bun.Ident("hides_cc_public_from_unauthed_web"), hidesCcPublicFromUnauthedWeb). + Where("? = ?", bun.Ident("id"), settings.AccountID).Exec(ctx); err != nil { + return fmt.Errorf("error updating local account: %w", err) + } + } + + // Drop the old web_visibility column. + if _, err := tx. + NewDropColumn(). + Model((*oldmodel.AccountSettings)(nil)). + Column("web_visibility"). + Exec(ctx); err != nil { + return fmt.Errorf("error dropping old web_visibility column: %w", 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/20250708074906_unauthed_web_updates/common/visibility.go b/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/common/visibility.go new file mode 100644 index 000000000..51cb13d87 --- /dev/null +++ b/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/common/visibility.go @@ -0,0 +1,50 @@ +// 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 common + +// Visibility represents the +// visibility granularity of a status. +type Visibility int16 + +const ( + // VisibilityNone means nobody can see this. + // It's only used for web status visibility. + VisibilityNone Visibility = 1 + + // VisibilityPublic means this status will + // be visible to everyone on all timelines. + VisibilityPublic Visibility = 2 + + // VisibilityUnlocked means this status will be visible to everyone, + // but will only show on home timeline to followers, and in lists. + VisibilityUnlocked Visibility = 3 + + // VisibilityFollowersOnly means this status is viewable to followers only. + VisibilityFollowersOnly Visibility = 4 + + // VisibilityMutualsOnly means this status + // is visible to mutual followers only. + VisibilityMutualsOnly Visibility = 5 + + // VisibilityDirect means this status is + // visible only to mentioned recipients. + VisibilityDirect Visibility = 6 + + // VisibilityDefault is used when no other setting can be found. + VisibilityDefault Visibility = VisibilityUnlocked +) diff --git a/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/new/account.go b/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/new/account.go new file mode 100644 index 000000000..ad25a5bc9 --- /dev/null +++ b/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/new/account.go @@ -0,0 +1,102 @@ +// 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 ( + "crypto/rsa" + "time" + + "code.superseriousbusiness.org/gotosocial/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/common" +) + +type Account 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"` + Username string `bun:",nullzero,notnull,unique:accounts_username_domain_uniq"` + Domain string `bun:",nullzero,unique:accounts_username_domain_uniq"` + AvatarMediaAttachmentID string `bun:"type:CHAR(26),nullzero"` + AvatarRemoteURL string `bun:",nullzero"` + HeaderMediaAttachmentID string `bun:"type:CHAR(26),nullzero"` + HeaderRemoteURL string `bun:",nullzero"` + DisplayName string `bun:",nullzero"` + EmojiIDs []string `bun:"emojis,array"` + Fields []*Field `bun:",nullzero"` + FieldsRaw []*Field `bun:",nullzero"` + Note string `bun:",nullzero"` + NoteRaw string `bun:",nullzero"` + AlsoKnownAsURIs []string `bun:"also_known_as_uris,array"` + AlsoKnownAs []*Account `bun:"-"` + MovedToURI string `bun:",nullzero"` + MovedTo *Account `bun:"-"` + MoveID string `bun:"type:CHAR(26),nullzero"` + Locked *bool `bun:",nullzero,notnull,default:true"` + Discoverable *bool `bun:",nullzero,notnull,default:false"` + URI string `bun:",nullzero,notnull,unique"` + URL string `bun:",nullzero"` + InboxURI string `bun:",nullzero"` + SharedInboxURI *string `bun:""` + OutboxURI string `bun:",nullzero"` + FollowingURI string `bun:",nullzero"` + FollowersURI string `bun:",nullzero"` + FeaturedCollectionURI string `bun:",nullzero"` + ActorType int16 `bun:",nullzero,notnull"` + PrivateKey *rsa.PrivateKey `bun:""` + PublicKey *rsa.PublicKey `bun:",notnull"` + PublicKeyURI string `bun:",nullzero,notnull,unique"` + PublicKeyExpiresAt time.Time `bun:"type:timestamptz,nullzero"` + MemorializedAt time.Time `bun:"type:timestamptz,nullzero"` + SensitizedAt time.Time `bun:"type:timestamptz,nullzero"` + SilencedAt time.Time `bun:"type:timestamptz,nullzero"` + SuspendedAt time.Time `bun:"type:timestamptz,nullzero"` + SuspensionOrigin string `bun:"type:CHAR(26),nullzero"` + + // Added in this migration: + HidesToPublicFromUnauthedWeb *bool `bun:",nullzero,notnull,default:false"` + HidesCcPublicFromUnauthedWeb *bool `bun:",nullzero,notnull,default:false"` +} + +type Field struct { + Name string + Value string + VerifiedAt time.Time `bun:",nullzero"` +} + +type AccountSettings struct { + AccountID 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"` + Privacy common.Visibility `bun:",nullzero,default:3"` + Sensitive *bool `bun:",nullzero,notnull,default:false"` + Language string `bun:",nullzero,notnull,default:'en'"` + StatusContentType string `bun:",nullzero"` + Theme string `bun:",nullzero"` + CustomCSS string `bun:",nullzero"` + EnableRSS *bool `bun:",nullzero,notnull,default:false"` + HideCollections *bool `bun:",nullzero,notnull,default:false"` + WebLayout int16 `bun:",nullzero,notnull,default:1"` + InteractionPolicyDirect *struct{} `bun:""` + InteractionPolicyMutualsOnly *struct{} `bun:""` + InteractionPolicyFollowersOnly *struct{} `bun:""` + InteractionPolicyUnlocked *struct{} `bun:""` + InteractionPolicyPublic *struct{} `bun:""` + + // Removed in this migration: + // WebVisibility common.Visibility `bun:",nullzero,notnull,default:3"` +} diff --git a/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/old/account.go b/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/old/account.go new file mode 100644 index 000000000..0086b1464 --- /dev/null +++ b/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/old/account.go @@ -0,0 +1,96 @@ +// 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 ( + "crypto/rsa" + "time" + + "code.superseriousbusiness.org/gotosocial/internal/db/bundb/migrations/20250708074906_unauthed_web_updates/common" +) + +type Account 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"` + Username string `bun:",nullzero,notnull,unique:accounts_username_domain_uniq"` + Domain string `bun:",nullzero,unique:accounts_username_domain_uniq"` + AvatarMediaAttachmentID string `bun:"type:CHAR(26),nullzero"` + AvatarRemoteURL string `bun:",nullzero"` + HeaderMediaAttachmentID string `bun:"type:CHAR(26),nullzero"` + HeaderRemoteURL string `bun:",nullzero"` + DisplayName string `bun:",nullzero"` + EmojiIDs []string `bun:"emojis,array"` + Fields []*Field `bun:",nullzero"` + FieldsRaw []*Field `bun:",nullzero"` + Note string `bun:",nullzero"` + NoteRaw string `bun:",nullzero"` + AlsoKnownAsURIs []string `bun:"also_known_as_uris,array"` + AlsoKnownAs []*Account `bun:"-"` + MovedToURI string `bun:",nullzero"` + MovedTo *Account `bun:"-"` + MoveID string `bun:"type:CHAR(26),nullzero"` + Locked *bool `bun:",nullzero,notnull,default:true"` + Discoverable *bool `bun:",nullzero,notnull,default:false"` + URI string `bun:",nullzero,notnull,unique"` + URL string `bun:",nullzero"` + InboxURI string `bun:",nullzero"` + SharedInboxURI *string `bun:""` + OutboxURI string `bun:",nullzero"` + FollowingURI string `bun:",nullzero"` + FollowersURI string `bun:",nullzero"` + FeaturedCollectionURI string `bun:",nullzero"` + ActorType int16 `bun:",nullzero,notnull"` + PrivateKey *rsa.PrivateKey `bun:""` + PublicKey *rsa.PublicKey `bun:",notnull"` + PublicKeyURI string `bun:",nullzero,notnull,unique"` + PublicKeyExpiresAt time.Time `bun:"type:timestamptz,nullzero"` + MemorializedAt time.Time `bun:"type:timestamptz,nullzero"` + SensitizedAt time.Time `bun:"type:timestamptz,nullzero"` + SilencedAt time.Time `bun:"type:timestamptz,nullzero"` + SuspendedAt time.Time `bun:"type:timestamptz,nullzero"` + SuspensionOrigin string `bun:"type:CHAR(26),nullzero"` +} + +type Field struct { + Name string + Value string + VerifiedAt time.Time `bun:",nullzero"` +} + +type AccountSettings struct { + AccountID 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"` + Privacy common.Visibility `bun:",nullzero,default:3"` + Sensitive *bool `bun:",nullzero,notnull,default:false"` + Language string `bun:",nullzero,notnull,default:'en'"` + StatusContentType string `bun:",nullzero"` + Theme string `bun:",nullzero"` + CustomCSS string `bun:",nullzero"` + EnableRSS *bool `bun:",nullzero,notnull,default:false"` + HideCollections *bool `bun:",nullzero,notnull,default:false"` + WebVisibility common.Visibility `bun:",nullzero,notnull,default:3"` + WebLayout int16 `bun:",nullzero,notnull,default:1"` + InteractionPolicyDirect *struct{} `bun:""` + InteractionPolicyMutualsOnly *struct{} `bun:""` + InteractionPolicyFollowersOnly *struct{} `bun:""` + InteractionPolicyUnlocked *struct{} `bun:""` + InteractionPolicyPublic *struct{} `bun:""` +} |
