mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2024-11-10 06:54:16 +00:00
[chore] Move local account settings to separate db table (#2770)
* [chore] Move local account settings to separate database model * don't use separate settings_id
This commit is contained in:
parent
0767647056
commit
7f4a0a1aeb
36 changed files with 525 additions and 191 deletions
|
@ -395,12 +395,8 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
|
|||
suite.EqualValues(requestingAccount.AlsoKnownAsURIs, dbUpdatedAccount.AlsoKnownAsURIs)
|
||||
suite.EqualValues(requestingAccount.MovedToURI, dbUpdatedAccount.MovedToURI)
|
||||
suite.EqualValues(requestingAccount.Bot, dbUpdatedAccount.Bot)
|
||||
suite.EqualValues(requestingAccount.Reason, dbUpdatedAccount.Reason)
|
||||
suite.EqualValues(requestingAccount.Locked, dbUpdatedAccount.Locked)
|
||||
suite.EqualValues(requestingAccount.Discoverable, dbUpdatedAccount.Discoverable)
|
||||
suite.EqualValues(requestingAccount.Privacy, dbUpdatedAccount.Privacy)
|
||||
suite.EqualValues(requestingAccount.Sensitive, dbUpdatedAccount.Sensitive)
|
||||
suite.EqualValues(requestingAccount.Language, dbUpdatedAccount.Language)
|
||||
suite.EqualValues(requestingAccount.URI, dbUpdatedAccount.URI)
|
||||
suite.EqualValues(requestingAccount.URL, dbUpdatedAccount.URL)
|
||||
suite.EqualValues(requestingAccount.InboxURI, dbUpdatedAccount.InboxURI)
|
||||
|
@ -414,7 +410,6 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
|
|||
suite.EqualValues(requestingAccount.SensitizedAt, dbUpdatedAccount.SensitizedAt)
|
||||
suite.EqualValues(requestingAccount.SilencedAt, dbUpdatedAccount.SilencedAt)
|
||||
suite.EqualValues(requestingAccount.SuspendedAt, dbUpdatedAccount.SuspendedAt)
|
||||
suite.EqualValues(requestingAccount.HideCollections, dbUpdatedAccount.HideCollections)
|
||||
suite.EqualValues(requestingAccount.SuspensionOrigin, dbUpdatedAccount.SuspensionOrigin)
|
||||
}
|
||||
|
||||
|
@ -464,9 +459,7 @@ func (suite *InboxPostTestSuite) TestPostDelete() {
|
|||
suite.Empty(dbAccount.AvatarRemoteURL)
|
||||
suite.Empty(dbAccount.HeaderMediaAttachmentID)
|
||||
suite.Empty(dbAccount.HeaderRemoteURL)
|
||||
suite.Empty(dbAccount.Reason)
|
||||
suite.Empty(dbAccount.Fields)
|
||||
suite.True(*dbAccount.HideCollections)
|
||||
suite.False(*dbAccount.Discoverable)
|
||||
suite.WithinDuration(time.Now(), dbAccount.SuspendedAt, 30*time.Second)
|
||||
suite.Equal(dbAccount.ID, dbAccount.SuspensionOrigin)
|
||||
|
|
|
@ -481,7 +481,7 @@ func (suite *AccountUpdateTestSuite) TestUpdateAccountSourceBadContentTypeFormDa
|
|||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
suite.Equal(data["source[status_content_type]"][0], dbAccount.StatusContentType)
|
||||
suite.Equal(data["source[status_content_type]"][0], dbAccount.Settings.StatusContentType)
|
||||
}
|
||||
|
||||
func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpdateStatusContentTypeBad() {
|
||||
|
|
|
@ -81,7 +81,7 @@ func (suite *AccountVerifyTestSuite) TestAccountVerifyGet() {
|
|||
suite.Equal(2, apimodelAccount.FollowingCount)
|
||||
suite.Equal(7, apimodelAccount.StatusesCount)
|
||||
suite.EqualValues(gtsmodel.VisibilityPublic, apimodelAccount.Source.Privacy)
|
||||
suite.Equal(testAccount.Language, apimodelAccount.Source.Language)
|
||||
suite.Equal(testAccount.Settings.Language, apimodelAccount.Source.Language)
|
||||
suite.Equal(testAccount.NoteRaw, apimodelAccount.Source.Note)
|
||||
}
|
||||
|
||||
|
|
|
@ -103,16 +103,22 @@ func (suite *StatusCreateTestSuite) TestPostNewStatus() {
|
|||
}
|
||||
|
||||
func (suite *StatusCreateTestSuite) TestPostNewStatusMarkdown() {
|
||||
// set default post language of account 1 to markdown
|
||||
testAccount := suite.testAccounts["local_account_1"]
|
||||
testAccount.StatusContentType = "text/markdown"
|
||||
a := testAccount
|
||||
// Copy zork.
|
||||
testAccount := >smodel.Account{}
|
||||
*testAccount = *suite.testAccounts["local_account_1"]
|
||||
|
||||
err := suite.db.UpdateAccount(context.Background(), a)
|
||||
// Copy zork's settings.
|
||||
settings := >smodel.AccountSettings{}
|
||||
*settings = *suite.testAccounts["local_account_1"].Settings
|
||||
testAccount.Settings = settings
|
||||
|
||||
// set default post language of zork to markdown
|
||||
testAccount.Settings.StatusContentType = "text/markdown"
|
||||
err := suite.db.UpdateAccountSettings(context.Background(), testAccount.Settings)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
suite.Equal(a.StatusContentType, "text/markdown")
|
||||
suite.Equal(testAccount.Settings.StatusContentType, "text/markdown")
|
||||
|
||||
t := suite.testTokens["local_account_1"]
|
||||
oauthToken := oauth.DBTokenToToken(t)
|
||||
|
@ -122,7 +128,7 @@ func (suite *StatusCreateTestSuite) TestPostNewStatusMarkdown() {
|
|||
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
|
||||
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
|
||||
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
|
||||
ctx.Set(oauth.SessionAuthorizedAccount, a)
|
||||
ctx.Set(oauth.SessionAuthorizedAccount, testAccount)
|
||||
|
||||
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080/%s", statuses.BasePath), nil)
|
||||
ctx.Request.Header.Set("accept", "application/json")
|
||||
|
|
|
@ -100,7 +100,6 @@ func (suite *WebfingerGetTestSuite) funkifyAccountDomain(host string, accountDom
|
|||
targetAccount := >smodel.Account{
|
||||
ID: "01FG1K8EA7SYHEC7V6XKVNC4ZA",
|
||||
Username: "new_account_domain_user",
|
||||
Privacy: gtsmodel.VisibilityDefault,
|
||||
URI: "http://" + host + "/users/new_account_domain_user",
|
||||
URL: "http://" + host + "/@new_account_domain_user",
|
||||
InboxURI: "http://" + host + "/users/new_account_domain_user/inbox",
|
||||
|
@ -118,6 +117,10 @@ func (suite *WebfingerGetTestSuite) funkifyAccountDomain(host string, accountDom
|
|||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
if err := suite.db.PutAccountSettings(context.Background(), >smodel.AccountSettings{AccountID: targetAccount.ID}); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
return targetAccount
|
||||
}
|
||||
|
||||
|
|
2
internal/cache/cache.go
vendored
2
internal/cache/cache.go
vendored
|
@ -53,6 +53,7 @@ func (c *Caches) Init() {
|
|||
c.initAccount()
|
||||
c.initAccountCounts()
|
||||
c.initAccountNote()
|
||||
c.initAccountSettings()
|
||||
c.initApplication()
|
||||
c.initBlock()
|
||||
c.initBlockIDs()
|
||||
|
@ -119,6 +120,7 @@ func (c *Caches) Stop() {
|
|||
func (c *Caches) Sweep(threshold float64) {
|
||||
c.GTS.Account.Trim(threshold)
|
||||
c.GTS.AccountNote.Trim(threshold)
|
||||
c.GTS.AccountSettings.Trim(threshold)
|
||||
c.GTS.Block.Trim(threshold)
|
||||
c.GTS.BlockIDs.Trim(threshold)
|
||||
c.GTS.Emoji.Trim(threshold)
|
||||
|
|
27
internal/cache/db.go
vendored
27
internal/cache/db.go
vendored
|
@ -43,6 +43,9 @@ type GTSCaches struct {
|
|||
Pinned int
|
||||
}]
|
||||
|
||||
// AccountSettings provides access to the gtsmodel AccountSettings database cache.
|
||||
AccountSettings structr.Cache[*gtsmodel.AccountSettings]
|
||||
|
||||
// Application provides access to the gtsmodel Application database cache.
|
||||
Application structr.Cache[*gtsmodel.Application]
|
||||
|
||||
|
@ -190,6 +193,7 @@ func (c *Caches) initAccount() {
|
|||
a2.Emojis = nil
|
||||
a2.AlsoKnownAs = nil
|
||||
a2.Move = nil
|
||||
a2.Settings = nil
|
||||
|
||||
return a2
|
||||
}
|
||||
|
@ -262,6 +266,29 @@ func (c *Caches) initAccountNote() {
|
|||
})
|
||||
}
|
||||
|
||||
func (c *Caches) initAccountSettings() {
|
||||
// Calculate maximum cache size.
|
||||
cap := calculateResultCacheMax(
|
||||
sizeofAccountSettings(), // model in-mem size.
|
||||
config.GetCacheAccountSettingsMemRatio(),
|
||||
)
|
||||
|
||||
log.Infof(nil, "cache size = %d", cap)
|
||||
|
||||
c.GTS.AccountSettings.Init(structr.Config[*gtsmodel.AccountSettings]{
|
||||
Indices: []structr.IndexConfig{
|
||||
{Fields: "AccountID"},
|
||||
},
|
||||
MaxSize: cap,
|
||||
IgnoreErr: ignoreErrors,
|
||||
CopyValue: func(s1 *gtsmodel.AccountSettings) *gtsmodel.AccountSettings {
|
||||
s2 := new(gtsmodel.AccountSettings)
|
||||
*s2 = *s1
|
||||
return s2
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Caches) initApplication() {
|
||||
// Calculate maximum cache size.
|
||||
cap := calculateResultCacheMax(
|
||||
|
|
22
internal/cache/size.go
vendored
22
internal/cache/size.go
vendored
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/id"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -219,9 +220,6 @@ func sizeofAccount() uintptr {
|
|||
Bot: func() *bool { ok := true; return &ok }(),
|
||||
Locked: func() *bool { ok := true; return &ok }(),
|
||||
Discoverable: func() *bool { ok := false; return &ok }(),
|
||||
Privacy: gtsmodel.VisibilityFollowersOnly,
|
||||
Sensitive: func() *bool { ok := true; return &ok }(),
|
||||
Language: "fr",
|
||||
URI: exampleURI,
|
||||
URL: exampleURI,
|
||||
InboxURI: exampleURI,
|
||||
|
@ -236,9 +234,7 @@ func sizeofAccount() uintptr {
|
|||
SensitizedAt: exampleTime,
|
||||
SilencedAt: exampleTime,
|
||||
SuspendedAt: exampleTime,
|
||||
HideCollections: func() *bool { ok := true; return &ok }(),
|
||||
SuspensionOrigin: exampleID,
|
||||
EnableRSS: func() *bool { ok := true; return &ok }(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -251,6 +247,22 @@ func sizeofAccountNote() uintptr {
|
|||
}))
|
||||
}
|
||||
|
||||
func sizeofAccountSettings() uintptr {
|
||||
return uintptr(size.Of(>smodel.AccountSettings{
|
||||
AccountID: exampleID,
|
||||
CreatedAt: exampleTime,
|
||||
UpdatedAt: exampleTime,
|
||||
Reason: exampleText,
|
||||
Privacy: gtsmodel.VisibilityFollowersOnly,
|
||||
Sensitive: util.Ptr(true),
|
||||
Language: "fr",
|
||||
StatusContentType: "text/plain",
|
||||
CustomCSS: exampleText,
|
||||
EnableRSS: util.Ptr(true),
|
||||
HideCollections: util.Ptr(false),
|
||||
}))
|
||||
}
|
||||
|
||||
func sizeofApplication() uintptr {
|
||||
return uintptr(size.Of(>smodel.Application{
|
||||
ID: exampleID,
|
||||
|
|
|
@ -195,6 +195,7 @@ type CacheConfiguration struct {
|
|||
MemoryTarget bytesize.Size `name:"memory-target"`
|
||||
AccountMemRatio float64 `name:"account-mem-ratio"`
|
||||
AccountNoteMemRatio float64 `name:"account-note-mem-ratio"`
|
||||
AccountSettingsMemRatio float64 `name:"account-settings-mem-ratio"`
|
||||
ApplicationMemRatio float64 `name:"application-mem-ratio"`
|
||||
BlockMemRatio float64 `name:"block-mem-ratio"`
|
||||
BlockIDsMemRatio float64 `name:"block-mem-ratio"`
|
||||
|
|
|
@ -159,6 +159,7 @@ var Defaults = Configuration{
|
|||
// be able to make some more sense :D
|
||||
AccountMemRatio: 5,
|
||||
AccountNoteMemRatio: 1,
|
||||
AccountSettingsMemRatio: 0.1,
|
||||
ApplicationMemRatio: 0.1,
|
||||
BlockMemRatio: 2,
|
||||
BlockIDsMemRatio: 3,
|
||||
|
|
|
@ -2825,6 +2825,31 @@ func GetCacheAccountNoteMemRatio() float64 { return global.GetCacheAccountNoteMe
|
|||
// SetCacheAccountNoteMemRatio safely sets the value for global configuration 'Cache.AccountNoteMemRatio' field
|
||||
func SetCacheAccountNoteMemRatio(v float64) { global.SetCacheAccountNoteMemRatio(v) }
|
||||
|
||||
// GetCacheAccountSettingsMemRatio safely fetches the Configuration value for state's 'Cache.AccountSettingsMemRatio' field
|
||||
func (st *ConfigState) GetCacheAccountSettingsMemRatio() (v float64) {
|
||||
st.mutex.RLock()
|
||||
v = st.config.Cache.AccountSettingsMemRatio
|
||||
st.mutex.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// SetCacheAccountSettingsMemRatio safely sets the Configuration value for state's 'Cache.AccountSettingsMemRatio' field
|
||||
func (st *ConfigState) SetCacheAccountSettingsMemRatio(v float64) {
|
||||
st.mutex.Lock()
|
||||
defer st.mutex.Unlock()
|
||||
st.config.Cache.AccountSettingsMemRatio = v
|
||||
st.reloadToViper()
|
||||
}
|
||||
|
||||
// CacheAccountSettingsMemRatioFlag returns the flag name for the 'Cache.AccountSettingsMemRatio' field
|
||||
func CacheAccountSettingsMemRatioFlag() string { return "cache-account-settings-mem-ratio" }
|
||||
|
||||
// GetCacheAccountSettingsMemRatio safely fetches the value for global configuration 'Cache.AccountSettingsMemRatio' field
|
||||
func GetCacheAccountSettingsMemRatio() float64 { return global.GetCacheAccountSettingsMemRatio() }
|
||||
|
||||
// SetCacheAccountSettingsMemRatio safely sets the value for global configuration 'Cache.AccountSettingsMemRatio' field
|
||||
func SetCacheAccountSettingsMemRatio(v float64) { global.SetCacheAccountSettingsMemRatio(v) }
|
||||
|
||||
// GetCacheApplicationMemRatio safely fetches the Configuration value for state's 'Cache.ApplicationMemRatio' field
|
||||
func (st *ConfigState) GetCacheApplicationMemRatio() (v float64) {
|
||||
st.mutex.RLock()
|
||||
|
|
|
@ -117,4 +117,13 @@ type Account interface {
|
|||
// GetInstanceAccount returns the instance account for the given domain.
|
||||
// If domain is empty, this instance account will be returned.
|
||||
GetInstanceAccount(ctx context.Context, domain string) (*gtsmodel.Account, error)
|
||||
|
||||
// Get local account settings with the given ID.
|
||||
GetAccountSettings(ctx context.Context, id string) (*gtsmodel.AccountSettings, error)
|
||||
|
||||
// Store local account settings.
|
||||
PutAccountSettings(ctx context.Context, settings *gtsmodel.AccountSettings) error
|
||||
|
||||
// Update local account settings.
|
||||
UpdateAccountSettings(ctx context.Context, settings *gtsmodel.AccountSettings, columns ...string) error
|
||||
}
|
||||
|
|
|
@ -338,6 +338,17 @@ func (a *accountDB) PopulateAccount(ctx context.Context, account *gtsmodel.Accou
|
|||
}
|
||||
}
|
||||
|
||||
if account.IsLocal() && account.Settings == nil && !account.IsInstance() {
|
||||
// Account settings not set, fetch from db.
|
||||
account.Settings, err = a.state.DB.GetAccountSettings(
|
||||
ctx, // these are already barebones
|
||||
account.ID,
|
||||
)
|
||||
if err != nil {
|
||||
errs.Appendf("error populating account settings: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return errs.Combine()
|
||||
}
|
||||
|
||||
|
@ -504,12 +515,22 @@ func (a *accountDB) SetAccountHeaderOrAvatar(ctx context.Context, mediaAttachmen
|
|||
}
|
||||
|
||||
func (a *accountDB) GetAccountCustomCSSByUsername(ctx context.Context, username string) (string, error) {
|
||||
// Get local account.
|
||||
account, err := a.GetAccountByUsernameDomain(ctx, username, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return account.CustomCSS, nil
|
||||
// Ensure settings populated, in case
|
||||
// barebones context was passed.
|
||||
if account.Settings == nil {
|
||||
account.Settings, err = a.GetAccountSettings(ctx, account.ID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return account.Settings.CustomCSS, nil
|
||||
}
|
||||
|
||||
func (a *accountDB) GetAccountsUsingEmoji(ctx context.Context, emojiID string) ([]*gtsmodel.Account, error) {
|
||||
|
@ -780,3 +801,68 @@ func (a *accountDB) GetAccountWebStatuses(ctx context.Context, accountID string,
|
|||
|
||||
return a.state.DB.GetStatusesByIDs(ctx, statusIDs)
|
||||
}
|
||||
|
||||
func (a *accountDB) GetAccountSettings(
|
||||
ctx context.Context,
|
||||
accountID string,
|
||||
) (*gtsmodel.AccountSettings, error) {
|
||||
// Fetch settings from db cache with loader callback.
|
||||
return a.state.Caches.GTS.AccountSettings.LoadOne(
|
||||
"AccountID",
|
||||
func() (*gtsmodel.AccountSettings, error) {
|
||||
// Not cached! Perform database query.
|
||||
var settings gtsmodel.AccountSettings
|
||||
if err := a.db.
|
||||
NewSelect().
|
||||
Model(&settings).
|
||||
Where("? = ?", bun.Ident("account_settings.account_id"), accountID).
|
||||
Scan(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings, nil
|
||||
},
|
||||
accountID,
|
||||
)
|
||||
}
|
||||
|
||||
func (a *accountDB) PutAccountSettings(
|
||||
ctx context.Context,
|
||||
settings *gtsmodel.AccountSettings,
|
||||
) error {
|
||||
return a.state.Caches.GTS.AccountSettings.Store(settings, func() error {
|
||||
if _, err := a.db.
|
||||
NewInsert().
|
||||
Model(settings).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (a *accountDB) UpdateAccountSettings(
|
||||
ctx context.Context,
|
||||
settings *gtsmodel.AccountSettings,
|
||||
columns ...string,
|
||||
) error {
|
||||
return a.state.Caches.GTS.AccountSettings.Store(settings, func() error {
|
||||
settings.UpdatedAt = time.Now()
|
||||
if len(columns) > 0 {
|
||||
// If we're updating by column,
|
||||
// ensure "updated_at" is included.
|
||||
columns = append(columns, "updated_at")
|
||||
}
|
||||
|
||||
if _, err := a.db.
|
||||
NewUpdate().
|
||||
Model(settings).
|
||||
Column(columns...).
|
||||
Where("? = ?", bun.Ident("account_settings.account_id"), settings.AccountID).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
|
@ -216,6 +216,8 @@ func (suite *AccountTestSuite) TestGetAccountBy() {
|
|||
a2.AvatarMediaAttachment = nil
|
||||
a1.Emojis = nil
|
||||
a2.Emojis = nil
|
||||
a1.Settings = nil
|
||||
a2.Settings = nil
|
||||
|
||||
// Clear database-set fields.
|
||||
a1.CreatedAt = time.Time{}
|
||||
|
@ -439,15 +441,11 @@ func (suite *AccountTestSuite) TestInsertAccountWithDefaults() {
|
|||
err = suite.db.Put(context.Background(), newAccount)
|
||||
suite.NoError(err)
|
||||
|
||||
suite.Equal("en", newAccount.Language)
|
||||
suite.WithinDuration(time.Now(), newAccount.CreatedAt, 30*time.Second)
|
||||
suite.WithinDuration(time.Now(), newAccount.UpdatedAt, 30*time.Second)
|
||||
suite.True(*newAccount.Locked)
|
||||
suite.False(*newAccount.Memorial)
|
||||
suite.False(*newAccount.Bot)
|
||||
suite.False(*newAccount.Discoverable)
|
||||
suite.False(*newAccount.Sensitive)
|
||||
suite.False(*newAccount.HideCollections)
|
||||
}
|
||||
|
||||
func (suite *AccountTestSuite) TestGetAccountPinnedStatusesSomeResults() {
|
||||
|
|
|
@ -119,12 +119,21 @@ func (a *adminDB) NewSignup(ctx context.Context, newSignup gtsmodel.NewSignup) (
|
|||
return nil, err
|
||||
}
|
||||
|
||||
settings := >smodel.AccountSettings{
|
||||
AccountID: accountID,
|
||||
Reason: newSignup.Reason,
|
||||
Privacy: gtsmodel.VisibilityDefault,
|
||||
}
|
||||
|
||||
// Insert the settings!
|
||||
if err := a.state.DB.PutAccountSettings(ctx, settings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
account = >smodel.Account{
|
||||
ID: accountID,
|
||||
Username: newSignup.Username,
|
||||
DisplayName: newSignup.Username,
|
||||
Reason: newSignup.Reason,
|
||||
Privacy: gtsmodel.VisibilityDefault,
|
||||
URI: uris.UserURI,
|
||||
URL: uris.UserURL,
|
||||
InboxURI: uris.InboxURI,
|
||||
|
@ -136,6 +145,7 @@ func (a *adminDB) NewSignup(ctx context.Context, newSignup gtsmodel.NewSignup) (
|
|||
PrivateKey: privKey,
|
||||
PublicKey: &privKey.PublicKey,
|
||||
PublicKeyURI: uris.PublicKeyURI,
|
||||
Settings: settings,
|
||||
}
|
||||
|
||||
// Insert the new account!
|
||||
|
|
|
@ -85,19 +85,13 @@ func (suite *BasicTestSuite) TestPutAccountWithBunDefaultFields() {
|
|||
suite.Nil(a.Fields)
|
||||
suite.Empty(a.Note)
|
||||
suite.Empty(a.NoteRaw)
|
||||
suite.False(*a.Memorial)
|
||||
suite.Empty(a.AlsoKnownAsURIs)
|
||||
suite.Empty(a.MovedToURI)
|
||||
suite.False(*a.Bot)
|
||||
suite.Empty(a.Reason)
|
||||
// Locked is especially important, since it's a bool that defaults
|
||||
// to true, which is why we use pointers for bools in the first place
|
||||
suite.True(*a.Locked)
|
||||
suite.False(*a.Discoverable)
|
||||
suite.Empty(a.Privacy)
|
||||
suite.False(*a.Sensitive)
|
||||
suite.Equal("en", a.Language)
|
||||
suite.Empty(a.StatusContentType)
|
||||
suite.Equal(testAccount.URI, a.URI)
|
||||
suite.Equal(testAccount.URL, a.URL)
|
||||
suite.Zero(testAccount.FetchedAt)
|
||||
|
@ -113,7 +107,6 @@ func (suite *BasicTestSuite) TestPutAccountWithBunDefaultFields() {
|
|||
suite.Zero(a.SensitizedAt)
|
||||
suite.Zero(a.SilencedAt)
|
||||
suite.Zero(a.SuspendedAt)
|
||||
suite.False(*a.HideCollections)
|
||||
suite.Empty(a.SuspensionOrigin)
|
||||
}
|
||||
|
||||
|
|
122
internal/db/bundb/migrations/20240318115336_account_settings.go
Normal file
122
internal/db/bundb/migrations/20240318115336_account_settings.go
Normal file
|
@ -0,0 +1,122 @@
|
|||
// 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"
|
||||
|
||||
oldgtsmodel "github.com/superseriousbusiness/gotosocial/internal/db/bundb/migrations/20230328203024_migration_fix"
|
||||
newgtsmodel "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 {
|
||||
log.Info(ctx, "migrating account settings to new table, please wait...")
|
||||
return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
|
||||
// Columns we'll be moving
|
||||
// to AccountSettings.
|
||||
var columns = []string{
|
||||
"reason",
|
||||
"privacy",
|
||||
"sensitive",
|
||||
"language",
|
||||
"status_content_type",
|
||||
"custom_css",
|
||||
"enable_rss",
|
||||
"hide_collections",
|
||||
}
|
||||
|
||||
// Create the new account settings table.
|
||||
if _, err := tx.
|
||||
NewCreateTable().
|
||||
Model(&newgtsmodel.AccountSettings{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Select each local account.
|
||||
accounts := []*oldgtsmodel.Account{}
|
||||
if err := tx.
|
||||
NewSelect().
|
||||
TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")).
|
||||
Column("account.id").
|
||||
Column(columns...).
|
||||
Join(
|
||||
"JOIN ? AS ? ON ? = ?",
|
||||
bun.Ident("users"), bun.Ident("user"),
|
||||
bun.Ident("user.account_id"), bun.Ident("account.id"),
|
||||
).
|
||||
Scan(ctx, &accounts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a settings entry for each existing account, taking
|
||||
// values from the old account model (with sensible defaults).
|
||||
for _, account := range accounts {
|
||||
settings := &newgtsmodel.AccountSettings{
|
||||
AccountID: account.ID,
|
||||
CreatedAt: account.CreatedAt,
|
||||
Reason: account.Reason,
|
||||
Privacy: newgtsmodel.Visibility(account.Privacy),
|
||||
Sensitive: util.Ptr(util.PtrValueOr(account.Sensitive, false)),
|
||||
Language: account.Language,
|
||||
StatusContentType: account.StatusContentType,
|
||||
CustomCSS: account.CustomCSS,
|
||||
EnableRSS: util.Ptr(util.PtrValueOr(account.EnableRSS, false)),
|
||||
HideCollections: util.Ptr(util.PtrValueOr(account.HideCollections, false)),
|
||||
}
|
||||
|
||||
// Insert the settings model.
|
||||
if _, err := tx.
|
||||
NewInsert().
|
||||
Model(settings).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Drop now unused columns from accounts table.
|
||||
for _, column := range columns {
|
||||
if _, err := tx.
|
||||
NewDropColumn().
|
||||
Table("accounts").
|
||||
Column(column).
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -743,9 +743,6 @@ func (d *Dereferencer) enrichAccount(
|
|||
// Set time of update from the last-fetched date.
|
||||
latestAcc.UpdatedAt = latestAcc.FetchedAt
|
||||
|
||||
// Carry over existing account language.
|
||||
latestAcc.Language = account.Language
|
||||
|
||||
// This is an existing account, update the model in the database.
|
||||
if err := d.state.DB.UpdateAccount(ctx, latestAcc); err != nil {
|
||||
return nil, nil, gtserror.Newf("error updating database: %w", err)
|
||||
|
|
|
@ -48,45 +48,38 @@ type Account struct {
|
|||
DisplayName string `bun:""` // DisplayName for this account. Can be empty, then just the Username will be used for display purposes.
|
||||
EmojiIDs []string `bun:"emojis,array"` // Database IDs of any emojis used in this account's bio, display name, etc
|
||||
Emojis []*Emoji `bun:"attached_emojis,m2m:account_to_emojis"` // Emojis corresponding to emojiIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation
|
||||
Fields []*Field // A slice of of fields that this account has added to their profile.
|
||||
FieldsRaw []*Field // The raw (unparsed) content of fields that this account has added to their profile, without conversion to HTML, only available when requester = target
|
||||
Note string `bun:""` // A note that this account has on their profile (ie., the account's bio/description of themselves)
|
||||
NoteRaw string `bun:""` // The raw contents of .Note without conversion to HTML, only available when requester = target
|
||||
Memorial *bool `bun:",default:false"` // Is this a memorial account, ie., has the user passed away?
|
||||
AlsoKnownAsURIs []string `bun:"also_known_as_uris,array"` // This account is associated with these account URIs.
|
||||
AlsoKnownAs []*Account `bun:"-"` // This account is associated with these accounts (field not stored in the db).
|
||||
MovedToURI string `bun:",nullzero"` // This account has (or claims to have) moved to this account URI. Even if this field is set the move may not yet have been processed. Check `move` for this.
|
||||
MovedTo *Account `bun:"-"` // This account has moved to this account (field not stored in the db).
|
||||
MoveID string `bun:"type:CHAR(26),nullzero"` // ID of a Move in the database for this account. Only set if we received or created a Move activity for which this account URI was the origin.
|
||||
Move *Move `bun:"-"` // Move corresponding to MoveID, if set.
|
||||
Bot *bool `bun:",default:false"` // Does this account identify itself as a bot?
|
||||
Reason string `bun:""` // What reason was given for signing up when this account was created?
|
||||
Locked *bool `bun:",default:true"` // Does this account need an approval for new followers?
|
||||
Discoverable *bool `bun:",default:false"` // Should this account be shown in the instance's profile directory?
|
||||
Privacy Visibility `bun:",nullzero"` // Default post privacy for this account
|
||||
Sensitive *bool `bun:",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).
|
||||
CustomCSS string `bun:",nullzero"` // Custom CSS that should be displayed for this Account's profile and statuses.
|
||||
URI string `bun:",nullzero,notnull,unique"` // ActivityPub URI for this account.
|
||||
URL string `bun:",nullzero,unique"` // Web URL for this account's profile
|
||||
InboxURI string `bun:",nullzero,unique"` // Address of this account's ActivityPub inbox, for sending activity to
|
||||
SharedInboxURI *string `bun:""` // Address of this account's ActivityPub sharedInbox. Gotcha warning: this is a string pointer because it has three possible states: 1. We don't know yet if the account has a shared inbox -- null. 2. We know it doesn't have a shared inbox -- empty string. 3. We know it does have a shared inbox -- url string.
|
||||
OutboxURI string `bun:",nullzero,unique"` // Address of this account's activitypub outbox
|
||||
FollowingURI string `bun:",nullzero,unique"` // URI for getting the following list of this account
|
||||
FollowersURI string `bun:",nullzero,unique"` // URI for getting the followers list of this account
|
||||
FeaturedCollectionURI string `bun:",nullzero,unique"` // URL for getting the featured collection list of this account
|
||||
ActorType string `bun:",nullzero,notnull"` // What type of activitypub actor is this account?
|
||||
PrivateKey *rsa.PrivateKey `bun:""` // Privatekey for signing activitypub requests, will only be defined for local accounts
|
||||
PublicKey *rsa.PublicKey `bun:",notnull"` // Publickey for authorizing signed activitypub requests, will be defined for both local and remote accounts
|
||||
PublicKeyURI string `bun:",nullzero,notnull,unique"` // Web-reachable location of this account's public key
|
||||
PublicKeyExpiresAt time.Time `bun:"type:timestamptz,nullzero"` // PublicKey will expire/has expired at given time, and should be fetched again as appropriate. Only ever set for remote accounts.
|
||||
SensitizedAt time.Time `bun:"type:timestamptz,nullzero"` // When was this account set to have all its media shown as sensitive?
|
||||
SilencedAt time.Time `bun:"type:timestamptz,nullzero"` // When was this account silenced (eg., statuses only visible to followers, not public)?
|
||||
SuspendedAt time.Time `bun:"type:timestamptz,nullzero"` // When was this account suspended (eg., don't allow it to log in/post, don't accept media/posts from this account)
|
||||
HideCollections *bool `bun:",default:false"` // Hide this account's collections
|
||||
SuspensionOrigin string `bun:"type:CHAR(26),nullzero"` // id of the database entry that caused this account to become suspended -- can be an account ID or a domain block ID
|
||||
EnableRSS *bool `bun:",default:false"` // enable RSS feed subscription for this account's public posts at [URL]/feed
|
||||
Fields []*Field `bun:""` // A slice of of fields that this account has added to their profile.
|
||||
FieldsRaw []*Field `bun:""` // The raw (unparsed) content of fields that this account has added to their profile, without conversion to HTML, only available when requester = target
|
||||
Note string `bun:""` // A note that this account has on their profile (ie., the account's bio/description of themselves)
|
||||
NoteRaw string `bun:""` // The raw contents of .Note without conversion to HTML, only available when requester = target
|
||||
Memorial *bool `bun:",default:false"` // Is this a memorial account, ie., has the user passed away?
|
||||
AlsoKnownAsURIs []string `bun:"also_known_as_uris,array"` // This account is associated with these account URIs.
|
||||
AlsoKnownAs []*Account `bun:"-"` // This account is associated with these accounts (field not stored in the db).
|
||||
MovedToURI string `bun:",nullzero"` // This account has (or claims to have) moved to this account URI. Even if this field is set the move may not yet have been processed. Check `move` for this.
|
||||
MovedTo *Account `bun:"-"` // This account has moved to this account (field not stored in the db).
|
||||
MoveID string `bun:"type:CHAR(26),nullzero"` // ID of a Move in the database for this account. Only set if we received or created a Move activity for which this account URI was the origin.
|
||||
Move *Move `bun:"-"` // Move corresponding to MoveID, if set.
|
||||
Bot *bool `bun:",default:false"` // Does this account identify itself as a bot?
|
||||
Locked *bool `bun:",default:true"` // Does this account need an approval for new followers?
|
||||
Discoverable *bool `bun:",default:false"` // Should this account be shown in the instance's profile directory?
|
||||
URI string `bun:",nullzero,notnull,unique"` // ActivityPub URI for this account.
|
||||
URL string `bun:",nullzero,unique"` // Web URL for this account's profile
|
||||
InboxURI string `bun:",nullzero,unique"` // Address of this account's ActivityPub inbox, for sending activity to
|
||||
SharedInboxURI *string `bun:""` // Address of this account's ActivityPub sharedInbox. Gotcha warning: this is a string pointer because it has three possible states: 1. We don't know yet if the account has a shared inbox -- null. 2. We know it doesn't have a shared inbox -- empty string. 3. We know it does have a shared inbox -- url string.
|
||||
OutboxURI string `bun:",nullzero,unique"` // Address of this account's activitypub outbox
|
||||
FollowingURI string `bun:",nullzero,unique"` // URI for getting the following list of this account
|
||||
FollowersURI string `bun:",nullzero,unique"` // URI for getting the followers list of this account
|
||||
FeaturedCollectionURI string `bun:",nullzero,unique"` // URL for getting the featured collection list of this account
|
||||
ActorType string `bun:",nullzero,notnull"` // What type of activitypub actor is this account?
|
||||
PrivateKey *rsa.PrivateKey `bun:""` // Privatekey for signing activitypub requests, will only be defined for local accounts
|
||||
PublicKey *rsa.PublicKey `bun:",notnull"` // Publickey for authorizing signed activitypub requests, will be defined for both local and remote accounts
|
||||
PublicKeyURI string `bun:",nullzero,notnull,unique"` // Web-reachable location of this account's public key
|
||||
PublicKeyExpiresAt time.Time `bun:"type:timestamptz,nullzero"` // PublicKey will expire/has expired at given time, and should be fetched again as appropriate. Only ever set for remote accounts.
|
||||
SensitizedAt time.Time `bun:"type:timestamptz,nullzero"` // When was this account set to have all its media shown as sensitive?
|
||||
SilencedAt time.Time `bun:"type:timestamptz,nullzero"` // When was this account silenced (eg., statuses only visible to followers, not public)?
|
||||
SuspendedAt time.Time `bun:"type:timestamptz,nullzero"` // When was this account suspended (eg., don't allow it to log in/post, don't accept media/posts from this account)
|
||||
SuspensionOrigin string `bun:"type:CHAR(26),nullzero"` // id of the database entry that caused this account to become suspended -- can be an account ID or a domain block ID
|
||||
Settings *AccountSettings `bun:"-"` // gtsmodel.AccountSettings for this account.
|
||||
}
|
||||
|
||||
// IsLocal returns whether account is a local user account.
|
||||
|
|
35
internal/gtsmodel/accountsettings.go
Normal file
35
internal/gtsmodel/accountsettings.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
// 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"
|
||||
|
||||
// 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.
|
||||
Reason string `bun:",nullzero"` // What reason was given for signing up when this account was created?
|
||||
Privacy Visibility `bun:",nullzero"` // 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).
|
||||
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.
|
||||
}
|
|
@ -518,14 +518,9 @@ func stubbifyAccount(account *gtsmodel.Account, origin string) []string {
|
|||
account.Memorial = util.Ptr(false)
|
||||
account.AlsoKnownAsURIs = nil
|
||||
account.MovedToURI = ""
|
||||
account.Reason = ""
|
||||
account.Discoverable = util.Ptr(false)
|
||||
account.StatusContentType = ""
|
||||
account.CustomCSS = ""
|
||||
account.SuspendedAt = now
|
||||
account.SuspensionOrigin = origin
|
||||
account.HideCollections = util.Ptr(true)
|
||||
account.EnableRSS = util.Ptr(false)
|
||||
|
||||
return []string{
|
||||
"fetched_at",
|
||||
|
@ -541,14 +536,9 @@ func stubbifyAccount(account *gtsmodel.Account, origin string) []string {
|
|||
"memorial",
|
||||
"also_known_as_uris",
|
||||
"moved_to_uri",
|
||||
"reason",
|
||||
"discoverable",
|
||||
"status_content_type",
|
||||
"custom_css",
|
||||
"suspended_at",
|
||||
"suspension_origin",
|
||||
"hide_collections",
|
||||
"enable_rss",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,14 +66,9 @@ func (suite *AccountDeleteTestSuite) TestAccountDeleteLocal() {
|
|||
suite.Zero(updatedAccount.NoteRaw)
|
||||
suite.False(*updatedAccount.Memorial)
|
||||
suite.Empty(updatedAccount.AlsoKnownAsURIs)
|
||||
suite.Zero(updatedAccount.Reason)
|
||||
suite.False(*updatedAccount.Discoverable)
|
||||
suite.Zero(updatedAccount.StatusContentType)
|
||||
suite.Zero(updatedAccount.CustomCSS)
|
||||
suite.WithinDuration(time.Now(), updatedAccount.SuspendedAt, 1*time.Minute)
|
||||
suite.Equal(suspensionOrigin, updatedAccount.SuspensionOrigin)
|
||||
suite.True(*updatedAccount.HideCollections)
|
||||
suite.False(*updatedAccount.EnableRSS)
|
||||
|
||||
updatedUser, err := suite.db.GetUserByAccountID(ctx, testAccount.ID)
|
||||
if err != nil {
|
||||
|
|
|
@ -64,7 +64,7 @@ func (p *Processor) GetRSSFeedForUsername(ctx context.Context, username string)
|
|||
}
|
||||
|
||||
// Ensure account has rss feed enabled.
|
||||
if !*account.EnableRSS {
|
||||
if !*account.Settings.EnableRSS {
|
||||
err = gtserror.New("account RSS feed not enabled")
|
||||
return nil, never, gtserror.NewErrorNotFound(err)
|
||||
}
|
||||
|
|
|
@ -47,6 +47,11 @@ func (p *Processor) selectNoteFormatter(contentType string) text.FormatFunc {
|
|||
|
||||
// Update processes the update of an account with the given form.
|
||||
func (p *Processor) Update(ctx context.Context, account *gtsmodel.Account, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, gtserror.WithCode) {
|
||||
// Ensure account populated; we'll need settings.
|
||||
if err := p.state.DB.PopulateAccount(ctx, account); err != nil {
|
||||
log.Errorf(ctx, "error(s) populating account, will continue: %s", err)
|
||||
}
|
||||
|
||||
if form.Discoverable != nil {
|
||||
account.Discoverable = form.Discoverable
|
||||
}
|
||||
|
@ -146,7 +151,7 @@ func (p *Processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
}
|
||||
|
||||
// Format + set note according to user prefs.
|
||||
f := p.selectNoteFormatter(account.StatusContentType)
|
||||
f := p.selectNoteFormatter(account.Settings.StatusContentType)
|
||||
formatNoteResult := f(ctx, p.parseMention, account.ID, "", account.NoteRaw)
|
||||
account.Note = formatNoteResult.HTML
|
||||
|
||||
|
@ -227,11 +232,11 @@ func (p *Processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
if err != nil {
|
||||
return nil, gtserror.NewErrorBadRequest(err)
|
||||
}
|
||||
account.Language = language
|
||||
account.Settings.Language = language
|
||||
}
|
||||
|
||||
if form.Source.Sensitive != nil {
|
||||
account.Sensitive = form.Source.Sensitive
|
||||
account.Settings.Sensitive = form.Source.Sensitive
|
||||
}
|
||||
|
||||
if form.Source.Privacy != nil {
|
||||
|
@ -239,7 +244,7 @@ func (p *Processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
return nil, gtserror.NewErrorBadRequest(err)
|
||||
}
|
||||
privacy := typeutils.APIVisToVis(apimodel.Visibility(*form.Source.Privacy))
|
||||
account.Privacy = privacy
|
||||
account.Settings.Privacy = privacy
|
||||
}
|
||||
|
||||
if form.Source.StatusContentType != nil {
|
||||
|
@ -247,7 +252,7 @@ func (p *Processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
||||
}
|
||||
|
||||
account.StatusContentType = *form.Source.StatusContentType
|
||||
account.Settings.StatusContentType = *form.Source.StatusContentType
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,18 +261,21 @@ func (p *Processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
if err := validate.CustomCSS(customCSS); err != nil {
|
||||
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
||||
}
|
||||
account.CustomCSS = text.SanitizeToPlaintext(customCSS)
|
||||
account.Settings.CustomCSS = text.SanitizeToPlaintext(customCSS)
|
||||
}
|
||||
|
||||
if form.EnableRSS != nil {
|
||||
account.EnableRSS = form.EnableRSS
|
||||
account.Settings.EnableRSS = form.EnableRSS
|
||||
}
|
||||
|
||||
err := p.state.DB.UpdateAccount(ctx, account)
|
||||
if err != nil {
|
||||
if err := p.state.DB.UpdateAccount(ctx, account); err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("could not update account %s: %s", account.ID, err))
|
||||
}
|
||||
|
||||
if err := p.state.DB.UpdateAccountSettings(ctx, account.Settings); err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("could not update account settings %s: %s", account.ID, err))
|
||||
}
|
||||
|
||||
p.state.Workers.EnqueueClientAPI(ctx, messages.FromClientAPI{
|
||||
APObjectType: ap.ObjectProfile,
|
||||
APActivityType: ap.ActivityUpdate,
|
||||
|
|
|
@ -126,9 +126,15 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMention() {
|
|||
}
|
||||
|
||||
func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMarkdownNote() {
|
||||
// Copy zork.
|
||||
testAccount := >smodel.Account{}
|
||||
*testAccount = *suite.testAccounts["local_account_1"]
|
||||
|
||||
// Copy zork's settings.
|
||||
settings := >smodel.AccountSettings{}
|
||||
*settings = *suite.testAccounts["local_account_1"].Settings
|
||||
testAccount.Settings = settings
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
note = "*hello* ~~here~~ i am!"
|
||||
|
@ -136,8 +142,8 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMarkdownNote() {
|
|||
)
|
||||
|
||||
// Set status content type of account 1 to markdown for this test.
|
||||
testAccount.StatusContentType = "text/markdown"
|
||||
if err := suite.db.UpdateAccount(ctx, testAccount, "status_content_type"); err != nil {
|
||||
testAccount.Settings.StatusContentType = "text/markdown"
|
||||
if err := suite.db.UpdateAccountSettings(ctx, testAccount.Settings, "status_content_type"); err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
|
||||
|
|
|
@ -32,9 +32,9 @@ func (p *Processor) PreferencesGet(ctx context.Context, accountID string) (*apim
|
|||
}
|
||||
|
||||
return &apimodel.Preferences{
|
||||
PostingDefaultVisibility: mastoPrefVisibility(act.Privacy),
|
||||
PostingDefaultSensitive: *act.Sensitive,
|
||||
PostingDefaultLanguage: act.Language,
|
||||
PostingDefaultVisibility: mastoPrefVisibility(act.Settings.Privacy),
|
||||
PostingDefaultSensitive: *act.Settings.Sensitive,
|
||||
PostingDefaultLanguage: act.Settings.Language,
|
||||
// The Reading* preferences don't appear to actually be settable by the
|
||||
// client, so forcing some sensible defaults here
|
||||
ReadingExpandMedia: "default",
|
||||
|
|
|
@ -50,6 +50,11 @@ func (p *Processor) Create(
|
|||
*apimodel.Status,
|
||||
gtserror.WithCode,
|
||||
) {
|
||||
// Ensure account populated; we'll need settings.
|
||||
if err := p.state.DB.PopulateAccount(ctx, requester); err != nil {
|
||||
log.Errorf(ctx, "error(s) populating account, will continue: %s", err)
|
||||
}
|
||||
|
||||
// Generate new ID for status.
|
||||
statusID := id.NewULID()
|
||||
|
||||
|
@ -112,11 +117,11 @@ func (p *Processor) Create(
|
|||
return nil, errWithCode
|
||||
}
|
||||
|
||||
if err := processVisibility(form, requester.Privacy, status); err != nil {
|
||||
if err := processVisibility(form, requester.Settings.Privacy, status); err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
if err := processLanguage(form, requester.Language, status); err != nil {
|
||||
if err := processLanguage(form, requester.Settings.Language, status); err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
@ -369,7 +374,7 @@ func processLanguage(form *apimodel.AdvancedStatusCreateForm, accountDefaultLang
|
|||
func (p *Processor) processContent(ctx context.Context, parseMention gtsmodel.ParseMentionFunc, form *apimodel.AdvancedStatusCreateForm, status *gtsmodel.Status) error {
|
||||
if form.ContentType == "" {
|
||||
// If content type wasn't specified, use the author's preferred content-type.
|
||||
contentType := apimodel.StatusContentType(status.Account.StatusContentType)
|
||||
contentType := apimodel.StatusContentType(status.Account.Settings.StatusContentType)
|
||||
form.ContentType = contentType
|
||||
}
|
||||
|
||||
|
|
|
@ -362,9 +362,7 @@ func (suite *FromFediAPITestSuite) TestProcessAccountDelete() {
|
|||
suite.Empty(dbAccount.AvatarRemoteURL)
|
||||
suite.Empty(dbAccount.HeaderMediaAttachmentID)
|
||||
suite.Empty(dbAccount.HeaderRemoteURL)
|
||||
suite.Empty(dbAccount.Reason)
|
||||
suite.Empty(dbAccount.Fields)
|
||||
suite.True(*dbAccount.HideCollections)
|
||||
suite.False(*dbAccount.Discoverable)
|
||||
suite.WithinDuration(time.Now(), dbAccount.SuspendedAt, 30*time.Second)
|
||||
suite.Equal(dbAccount.ID, dbAccount.SuspensionOrigin)
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
transmodel "github.com/superseriousbusiness/gotosocial/internal/trans/model"
|
||||
)
|
||||
|
@ -73,6 +74,14 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
|
|||
if err := i.putInDB(ctx, account); err != nil {
|
||||
return fmt.Errorf("inputEntry: error adding account to database: %s", err)
|
||||
}
|
||||
if account.Domain == "" && account.Username != config.GetHost() {
|
||||
// Local, non-instance account.
|
||||
// Insert barebones settings model.
|
||||
settings := &transmodel.AccountSettings{AccountID: account.ID}
|
||||
if err := i.putInDB(ctx, settings); err != nil {
|
||||
return fmt.Errorf("inputEntry: error adding account settings to database: %s", err)
|
||||
}
|
||||
}
|
||||
log.Infof(ctx, "added account with id %s", account.ID)
|
||||
return nil
|
||||
case transmodel.TransBlock:
|
||||
|
|
|
@ -106,11 +106,6 @@ func (suite *ImportMinimalTestSuite) TestImportMinimalOK() {
|
|||
suite.Equal(testAccountBefore.Memorial, testAccountAfter.Memorial)
|
||||
suite.Equal(testAccountBefore.Bot, testAccountAfter.Bot)
|
||||
suite.Equal(testAccountBefore.Locked, testAccountAfter.Locked)
|
||||
suite.Equal(testAccountBefore.Reason, testAccountAfter.Reason)
|
||||
suite.Equal(testAccountBefore.Privacy, testAccountAfter.Privacy)
|
||||
suite.Equal(testAccountBefore.Sensitive, testAccountAfter.Sensitive)
|
||||
suite.Equal(testAccountBefore.Language, testAccountAfter.Language)
|
||||
suite.Equal(testAccountBefore.StatusContentType, testAccountAfter.StatusContentType)
|
||||
suite.Equal(testAccountBefore.URI, testAccountAfter.URI)
|
||||
suite.Equal(testAccountBefore.URL, testAccountAfter.URL)
|
||||
suite.Equal(testAccountBefore.InboxURI, testAccountAfter.InboxURI)
|
||||
|
@ -123,7 +118,6 @@ func (suite *ImportMinimalTestSuite) TestImportMinimalOK() {
|
|||
suite.Equal(testAccountBefore.PublicKey, testAccountAfter.PublicKey)
|
||||
suite.Equal(testAccountBefore.PublicKeyURI, testAccountAfter.PublicKeyURI)
|
||||
suite.Equal(testAccountBefore.SuspendedAt, testAccountAfter.SuspendedAt)
|
||||
suite.Equal(testAccountBefore.HideCollections, testAccountAfter.HideCollections)
|
||||
suite.Equal(testAccountBefore.SuspensionOrigin, testAccountAfter.SuspensionOrigin)
|
||||
}
|
||||
|
||||
|
|
|
@ -36,13 +36,8 @@ type Account struct {
|
|||
NoteRaw string `json:"noteRaw,omitempty" bun:",nullzero"`
|
||||
Memorial *bool `json:"memorial"`
|
||||
Bot *bool `json:"bot"`
|
||||
Reason string `json:"reason,omitempty" bun:",nullzero"`
|
||||
Locked *bool `json:"locked"`
|
||||
Discoverable *bool `json:"discoverable"`
|
||||
Privacy string `json:"privacy,omitempty" bun:",nullzero"`
|
||||
Sensitive *bool `json:"sensitive"`
|
||||
Language string `json:"language,omitempty" bun:",nullzero"`
|
||||
StatusContentType string `json:"statusContentType,omitempty" bun:",nullzero"`
|
||||
URI string `json:"uri" bun:",nullzero"`
|
||||
URL string `json:"url" bun:",nullzero"`
|
||||
InboxURI string `json:"inboxURI" bun:",nullzero"`
|
||||
|
@ -59,6 +54,9 @@ type Account struct {
|
|||
SensitizedAt *time.Time `json:"sensitizedAt,omitempty" bun:",nullzero"`
|
||||
SilencedAt *time.Time `json:"silencedAt,omitempty" bun:",nullzero"`
|
||||
SuspendedAt *time.Time `json:"suspendedAt,omitempty" bun:",nullzero"`
|
||||
HideCollections *bool `json:"hideCollections"`
|
||||
SuspensionOrigin string `json:"suspensionOrigin,omitempty" bun:",nullzero"`
|
||||
}
|
||||
|
||||
type AccountSettings struct {
|
||||
AccountID string
|
||||
}
|
||||
|
|
|
@ -130,13 +130,8 @@ func (c *Converter) ASRepresentationToAccount(ctx context.Context, accountable a
|
|||
// Extract account note (bio / summary).
|
||||
acct.Note = ap.ExtractSummary(accountable)
|
||||
|
||||
// Assume:
|
||||
// - memorial (TODO)
|
||||
// - sensitive (TODO)
|
||||
// - hide collections (TODO)
|
||||
// Assume not memorial (todo)
|
||||
acct.Memorial = util.Ptr(false)
|
||||
acct.Sensitive = util.Ptr(false)
|
||||
acct.HideCollections = util.Ptr(false)
|
||||
|
||||
// Extract 'manuallyApprovesFollowers' aka locked account (default = true).
|
||||
manuallyApprovesFollowers := ap.GetManuallyApprovesFollowers(accountable)
|
||||
|
@ -146,9 +141,6 @@ func (c *Converter) ASRepresentationToAccount(ctx context.Context, accountable a
|
|||
discoverable := ap.GetDiscoverable(accountable)
|
||||
acct.Discoverable = &discoverable
|
||||
|
||||
// Assume not an RSS feed.
|
||||
acct.EnableRSS = util.Ptr(false)
|
||||
|
||||
// Extract the URL property.
|
||||
urls := ap.GetURL(accountable)
|
||||
if len(urls) == 0 {
|
||||
|
|
|
@ -78,14 +78,14 @@ func (c *Converter) AccountToAPIAccountSensitive(ctx context.Context, a *gtsmode
|
|||
}
|
||||
|
||||
statusContentType := string(apimodel.StatusContentTypeDefault)
|
||||
if a.StatusContentType != "" {
|
||||
statusContentType = a.StatusContentType
|
||||
if a.Settings.StatusContentType != "" {
|
||||
statusContentType = a.Settings.StatusContentType
|
||||
}
|
||||
|
||||
apiAccount.Source = &apimodel.Source{
|
||||
Privacy: c.VisToAPIVis(ctx, a.Privacy),
|
||||
Sensitive: *a.Sensitive,
|
||||
Language: a.Language,
|
||||
Privacy: c.VisToAPIVis(ctx, a.Settings.Privacy),
|
||||
Sensitive: *a.Settings.Sensitive,
|
||||
Language: a.Settings.Language,
|
||||
StatusContentType: statusContentType,
|
||||
Note: a.NoteRaw,
|
||||
Fields: c.fieldsToAPIFields(a.FieldsRaw),
|
||||
|
@ -170,10 +170,13 @@ func (c *Converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
|||
// Bits that vary between remote + local accounts:
|
||||
// - Account (acct) string.
|
||||
// - Role.
|
||||
// - Settings things (enableRSS, customCSS).
|
||||
|
||||
var (
|
||||
acct string
|
||||
role *apimodel.AccountRole
|
||||
acct string
|
||||
role *apimodel.AccountRole
|
||||
enableRSS bool
|
||||
customCSS string
|
||||
)
|
||||
|
||||
if a.IsRemote() {
|
||||
|
@ -203,6 +206,9 @@ func (c *Converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
|||
default:
|
||||
role = &apimodel.AccountRole{Name: apimodel.AccountRoleUser}
|
||||
}
|
||||
|
||||
enableRSS = *a.Settings.EnableRSS
|
||||
customCSS = a.Settings.CustomCSS
|
||||
}
|
||||
|
||||
acct = a.Username // omit domain
|
||||
|
@ -239,7 +245,6 @@ func (c *Converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
|||
locked = boolPtrDef("locked", a.Locked, true)
|
||||
discoverable = boolPtrDef("discoverable", a.Discoverable, false)
|
||||
bot = boolPtrDef("bot", a.Bot, false)
|
||||
enableRSS = boolPtrDef("enableRSS", a.EnableRSS, false)
|
||||
)
|
||||
|
||||
// Remaining properties are simple and
|
||||
|
@ -267,7 +272,7 @@ func (c *Converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
|||
Emojis: apiEmojis,
|
||||
Fields: fields,
|
||||
Suspended: !a.SuspendedAt.IsZero(),
|
||||
CustomCSS: a.CustomCSS,
|
||||
CustomCSS: customCSS,
|
||||
EnableRSS: enableRSS,
|
||||
Role: role,
|
||||
Moved: moved,
|
||||
|
@ -376,6 +381,10 @@ func (c *Converter) AccountToAdminAPIAccount(ctx context.Context, a *gtsmodel.Ac
|
|||
createdByApplicationID string
|
||||
)
|
||||
|
||||
if err := c.state.DB.PopulateAccount(ctx, a); err != nil {
|
||||
log.Errorf(ctx, "error(s) populating account, will continue: %s", err)
|
||||
}
|
||||
|
||||
if a.IsRemote() {
|
||||
// Domain may be in Punycode,
|
||||
// de-punify it just in case.
|
||||
|
@ -404,8 +413,8 @@ func (c *Converter) AccountToAdminAPIAccount(ctx context.Context, a *gtsmodel.Ac
|
|||
}
|
||||
|
||||
locale = user.Locale
|
||||
if user.Account.Reason != "" {
|
||||
inviteRequest = &user.Account.Reason
|
||||
if a.Settings.Reason != "" {
|
||||
inviteRequest = &a.Settings.Reason
|
||||
}
|
||||
|
||||
if *user.Admin {
|
||||
|
|
|
@ -26,6 +26,7 @@ EXPECT=$(cat << "EOF"
|
|||
"cache": {
|
||||
"account-mem-ratio": 5,
|
||||
"account-note-mem-ratio": 1,
|
||||
"account-settings-mem-ratio": 0.1,
|
||||
"application-mem-ratio": 0.1,
|
||||
"block-mem-ratio": 3,
|
||||
"boost-of-ids-mem-ratio": 3,
|
||||
|
|
|
@ -70,6 +70,7 @@ var testModels = []interface{}{
|
|||
>smodel.Report{},
|
||||
>smodel.Rule{},
|
||||
>smodel.AccountNote{},
|
||||
>smodel.AccountSettings{},
|
||||
}
|
||||
|
||||
// NewTestDB returns a new initialized, empty database for testing.
|
||||
|
@ -206,6 +207,12 @@ func StandardDBSetup(db db.DB, accounts map[string]*gtsmodel.Account) {
|
|||
}
|
||||
}
|
||||
|
||||
for _, v := range NewTestAccountSettings() {
|
||||
if err := db.Put(ctx, v); err != nil {
|
||||
log.Panic(nil, err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range NewTestAttachments() {
|
||||
if err := db.Put(ctx, v); err != nil {
|
||||
log.Panic(nil, err)
|
||||
|
|
|
@ -286,6 +286,8 @@ func NewTestUsers() map[string]*gtsmodel.User {
|
|||
|
||||
// NewTestAccounts returns a map of accounts keyed by what type of account they are.
|
||||
func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||
settings := NewTestAccountSettings()
|
||||
|
||||
accounts := map[string]*gtsmodel.Account{
|
||||
"instance_account": {
|
||||
ID: "01AY6P665V14JJR0AFVRT7311Y",
|
||||
|
@ -301,12 +303,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
CreatedAt: TimeMustParse("2020-05-17T13:10:59Z"),
|
||||
UpdatedAt: TimeMustParse("2020-05-17T13:10:59Z"),
|
||||
Bot: util.Ptr(false),
|
||||
Reason: "",
|
||||
Locked: util.Ptr(false),
|
||||
Discoverable: util.Ptr(true),
|
||||
Privacy: gtsmodel.VisibilityPublic,
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
URI: "http://localhost:8080/users/localhost:8080",
|
||||
URL: "http://localhost:8080/@localhost:8080",
|
||||
PublicKeyURI: "http://localhost:8080/users/localhost:8080#main-key",
|
||||
|
@ -322,9 +320,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
SensitizedAt: time.Time{},
|
||||
SilencedAt: time.Time{},
|
||||
SuspendedAt: time.Time{},
|
||||
HideCollections: util.Ptr(false),
|
||||
SuspensionOrigin: "",
|
||||
EnableRSS: util.Ptr(false),
|
||||
},
|
||||
"unconfirmed_account": {
|
||||
ID: "01F8MH0BBE4FHXPH513MBVFHB0",
|
||||
|
@ -339,12 +335,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||
Bot: util.Ptr(false),
|
||||
Reason: "hi, please let me in! I'm looking for somewhere neato bombeato to hang out.",
|
||||
Locked: util.Ptr(false),
|
||||
Discoverable: util.Ptr(false),
|
||||
Privacy: gtsmodel.VisibilityPublic,
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
URI: "http://localhost:8080/users/weed_lord420",
|
||||
URL: "http://localhost:8080/@weed_lord420",
|
||||
FetchedAt: time.Time{},
|
||||
|
@ -360,9 +352,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
SensitizedAt: time.Time{},
|
||||
SilencedAt: time.Time{},
|
||||
SuspendedAt: time.Time{},
|
||||
HideCollections: util.Ptr(false),
|
||||
SuspensionOrigin: "",
|
||||
EnableRSS: util.Ptr(false),
|
||||
Settings: settings["unconfirmed_account"],
|
||||
},
|
||||
"admin_account": {
|
||||
ID: "01F8MH17FWEB39HZJ76B6VXSKF",
|
||||
|
@ -378,12 +369,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
CreatedAt: TimeMustParse("2022-05-17T13:10:59Z"),
|
||||
UpdatedAt: TimeMustParse("2022-05-17T13:10:59Z"),
|
||||
Bot: util.Ptr(false),
|
||||
Reason: "",
|
||||
Locked: util.Ptr(false),
|
||||
Discoverable: util.Ptr(true),
|
||||
Privacy: gtsmodel.VisibilityPublic,
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
URI: "http://localhost:8080/users/admin",
|
||||
URL: "http://localhost:8080/@admin",
|
||||
PublicKeyURI: "http://localhost:8080/users/admin#main-key",
|
||||
|
@ -399,9 +386,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
SensitizedAt: time.Time{},
|
||||
SilencedAt: time.Time{},
|
||||
SuspendedAt: time.Time{},
|
||||
HideCollections: util.Ptr(false),
|
||||
SuspensionOrigin: "",
|
||||
EnableRSS: util.Ptr(true),
|
||||
Settings: settings["admin_account"],
|
||||
},
|
||||
"local_account_1": {
|
||||
ID: "01F8MH1H7YV1Z7D2C8K2730QBF",
|
||||
|
@ -417,12 +403,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
CreatedAt: TimeMustParse("2022-05-20T11:09:18Z"),
|
||||
UpdatedAt: TimeMustParse("2022-05-20T11:09:18Z"),
|
||||
Bot: util.Ptr(false),
|
||||
Reason: "I wanna be on this damned webbed site so bad! Please! Wow",
|
||||
Locked: util.Ptr(false),
|
||||
Discoverable: util.Ptr(true),
|
||||
Privacy: gtsmodel.VisibilityPublic,
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
URI: "http://localhost:8080/users/the_mighty_zork",
|
||||
URL: "http://localhost:8080/@the_mighty_zork",
|
||||
FetchedAt: time.Time{},
|
||||
|
@ -438,9 +420,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
SensitizedAt: time.Time{},
|
||||
SilencedAt: time.Time{},
|
||||
SuspendedAt: time.Time{},
|
||||
HideCollections: util.Ptr(false),
|
||||
SuspensionOrigin: "",
|
||||
EnableRSS: util.Ptr(true),
|
||||
Settings: settings["local_account_1"],
|
||||
},
|
||||
"local_account_2": {
|
||||
ID: "01F8MH5NBDF2MV7CTC4Q5128HF",
|
||||
|
@ -475,12 +456,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||
Bot: util.Ptr(false),
|
||||
Reason: "",
|
||||
Locked: util.Ptr(true),
|
||||
Discoverable: util.Ptr(false),
|
||||
Privacy: gtsmodel.VisibilityFollowersOnly,
|
||||
Sensitive: util.Ptr(true),
|
||||
Language: "fr",
|
||||
URI: "http://localhost:8080/users/1happyturtle",
|
||||
URL: "http://localhost:8080/@1happyturtle",
|
||||
FetchedAt: time.Time{},
|
||||
|
@ -496,9 +473,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
SensitizedAt: time.Time{},
|
||||
SilencedAt: time.Time{},
|
||||
SuspendedAt: time.Time{},
|
||||
HideCollections: util.Ptr(false),
|
||||
SuspensionOrigin: "",
|
||||
EnableRSS: util.Ptr(false),
|
||||
Settings: settings["local_account_2"],
|
||||
},
|
||||
"remote_account_1": {
|
||||
ID: "01F8MH5ZK5VRH73AKHQM6Y9VNX",
|
||||
|
@ -514,8 +490,6 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
Bot: util.Ptr(false),
|
||||
Locked: util.Ptr(false),
|
||||
Discoverable: util.Ptr(true),
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
URI: "http://fossbros-anonymous.io/users/foss_satan",
|
||||
URL: "http://fossbros-anonymous.io/@foss_satan",
|
||||
FetchedAt: time.Time{},
|
||||
|
@ -532,9 +506,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
SensitizedAt: time.Time{},
|
||||
SilencedAt: time.Time{},
|
||||
SuspendedAt: time.Time{},
|
||||
HideCollections: util.Ptr(false),
|
||||
SuspensionOrigin: "",
|
||||
EnableRSS: util.Ptr(false),
|
||||
},
|
||||
"remote_account_2": {
|
||||
ID: "01FHMQX3GAABWSM0S2VZEC2SWC",
|
||||
|
@ -550,8 +522,6 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
Bot: util.Ptr(false),
|
||||
Locked: util.Ptr(true),
|
||||
Discoverable: util.Ptr(true),
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
URI: "http://example.org/users/Some_User",
|
||||
URL: "http://example.org/@Some_User",
|
||||
FetchedAt: time.Time{},
|
||||
|
@ -568,9 +538,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
SensitizedAt: time.Time{},
|
||||
SilencedAt: time.Time{},
|
||||
SuspendedAt: time.Time{},
|
||||
HideCollections: util.Ptr(false),
|
||||
SuspensionOrigin: "",
|
||||
EnableRSS: util.Ptr(false),
|
||||
},
|
||||
"remote_account_3": {
|
||||
ID: "062G5WYKY35KKD12EMSM3F8PJ8",
|
||||
|
@ -586,8 +554,6 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
Bot: util.Ptr(false),
|
||||
Locked: util.Ptr(true),
|
||||
Discoverable: util.Ptr(true),
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
URI: "http://thequeenisstillalive.technology/users/her_fuckin_maj",
|
||||
URL: "http://thequeenisstillalive.technology/@her_fuckin_maj",
|
||||
FetchedAt: time.Time{},
|
||||
|
@ -604,10 +570,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
SensitizedAt: time.Time{},
|
||||
SilencedAt: time.Time{},
|
||||
SuspendedAt: time.Time{},
|
||||
HideCollections: util.Ptr(false),
|
||||
SuspensionOrigin: "",
|
||||
HeaderMediaAttachmentID: "01PFPMWK2FF0D9WMHEJHR07C3R",
|
||||
EnableRSS: util.Ptr(false),
|
||||
},
|
||||
"remote_account_4": {
|
||||
ID: "07GZRBAEMBNKGZ8Z9VSKSXKR98",
|
||||
|
@ -622,8 +586,6 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
Bot: util.Ptr(false),
|
||||
Locked: util.Ptr(false),
|
||||
Discoverable: util.Ptr(false),
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "de",
|
||||
URI: "https://xn--xample-ova.org/users/%C3%BCser",
|
||||
URL: "https://xn--xample-ova.org/users/@%C3%BCser",
|
||||
FetchedAt: time.Time{},
|
||||
|
@ -640,10 +602,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
SensitizedAt: time.Time{},
|
||||
SilencedAt: time.Time{},
|
||||
SuspendedAt: time.Time{},
|
||||
HideCollections: util.Ptr(false),
|
||||
SuspensionOrigin: "",
|
||||
HeaderMediaAttachmentID: "",
|
||||
EnableRSS: util.Ptr(false),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -698,6 +658,55 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
|||
return accounts
|
||||
}
|
||||
|
||||
func NewTestAccountSettings() map[string]*gtsmodel.AccountSettings {
|
||||
return map[string]*gtsmodel.AccountSettings{
|
||||
"unconfirmed_account": {
|
||||
AccountID: "01F8MH0BBE4FHXPH513MBVFHB0",
|
||||
CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||
Reason: "hi, please let me in! I'm looking for somewhere neato bombeato to hang out.",
|
||||
Privacy: gtsmodel.VisibilityPublic,
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
EnableRSS: util.Ptr(false),
|
||||
HideCollections: util.Ptr(false),
|
||||
},
|
||||
"admin_account": {
|
||||
AccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
|
||||
CreatedAt: TimeMustParse("2022-05-17T13:10:59Z"),
|
||||
UpdatedAt: TimeMustParse("2022-05-17T13:10:59Z"),
|
||||
Reason: "",
|
||||
Privacy: gtsmodel.VisibilityPublic,
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
EnableRSS: util.Ptr(true),
|
||||
HideCollections: util.Ptr(false),
|
||||
},
|
||||
"local_account_1": {
|
||||
AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
|
||||
CreatedAt: TimeMustParse("2022-05-20T11:09:18Z"),
|
||||
UpdatedAt: TimeMustParse("2022-05-20T11:09:18Z"),
|
||||
Reason: "I wanna be on this damned webbed site so bad! Please! Wow",
|
||||
Privacy: gtsmodel.VisibilityPublic,
|
||||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
EnableRSS: util.Ptr(true),
|
||||
HideCollections: util.Ptr(false),
|
||||
},
|
||||
"local_account_2": {
|
||||
AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
|
||||
CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||
Reason: "",
|
||||
Privacy: gtsmodel.VisibilityFollowersOnly,
|
||||
Sensitive: util.Ptr(true),
|
||||
Language: "fr",
|
||||
EnableRSS: util.Ptr(false),
|
||||
HideCollections: util.Ptr(false),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewTestTombstones() map[string]*gtsmodel.Tombstone {
|
||||
return map[string]*gtsmodel.Tombstone{
|
||||
"https://somewhere.mysterious/users/rest_in_piss#main-key": {
|
||||
|
|
Loading…
Reference in a new issue