[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
|
@ -395,12 +395,8 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
|
||||||
suite.EqualValues(requestingAccount.AlsoKnownAsURIs, dbUpdatedAccount.AlsoKnownAsURIs)
|
suite.EqualValues(requestingAccount.AlsoKnownAsURIs, dbUpdatedAccount.AlsoKnownAsURIs)
|
||||||
suite.EqualValues(requestingAccount.MovedToURI, dbUpdatedAccount.MovedToURI)
|
suite.EqualValues(requestingAccount.MovedToURI, dbUpdatedAccount.MovedToURI)
|
||||||
suite.EqualValues(requestingAccount.Bot, dbUpdatedAccount.Bot)
|
suite.EqualValues(requestingAccount.Bot, dbUpdatedAccount.Bot)
|
||||||
suite.EqualValues(requestingAccount.Reason, dbUpdatedAccount.Reason)
|
|
||||||
suite.EqualValues(requestingAccount.Locked, dbUpdatedAccount.Locked)
|
suite.EqualValues(requestingAccount.Locked, dbUpdatedAccount.Locked)
|
||||||
suite.EqualValues(requestingAccount.Discoverable, dbUpdatedAccount.Discoverable)
|
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.URI, dbUpdatedAccount.URI)
|
||||||
suite.EqualValues(requestingAccount.URL, dbUpdatedAccount.URL)
|
suite.EqualValues(requestingAccount.URL, dbUpdatedAccount.URL)
|
||||||
suite.EqualValues(requestingAccount.InboxURI, dbUpdatedAccount.InboxURI)
|
suite.EqualValues(requestingAccount.InboxURI, dbUpdatedAccount.InboxURI)
|
||||||
|
@ -414,7 +410,6 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
|
||||||
suite.EqualValues(requestingAccount.SensitizedAt, dbUpdatedAccount.SensitizedAt)
|
suite.EqualValues(requestingAccount.SensitizedAt, dbUpdatedAccount.SensitizedAt)
|
||||||
suite.EqualValues(requestingAccount.SilencedAt, dbUpdatedAccount.SilencedAt)
|
suite.EqualValues(requestingAccount.SilencedAt, dbUpdatedAccount.SilencedAt)
|
||||||
suite.EqualValues(requestingAccount.SuspendedAt, dbUpdatedAccount.SuspendedAt)
|
suite.EqualValues(requestingAccount.SuspendedAt, dbUpdatedAccount.SuspendedAt)
|
||||||
suite.EqualValues(requestingAccount.HideCollections, dbUpdatedAccount.HideCollections)
|
|
||||||
suite.EqualValues(requestingAccount.SuspensionOrigin, dbUpdatedAccount.SuspensionOrigin)
|
suite.EqualValues(requestingAccount.SuspensionOrigin, dbUpdatedAccount.SuspensionOrigin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,9 +459,7 @@ func (suite *InboxPostTestSuite) TestPostDelete() {
|
||||||
suite.Empty(dbAccount.AvatarRemoteURL)
|
suite.Empty(dbAccount.AvatarRemoteURL)
|
||||||
suite.Empty(dbAccount.HeaderMediaAttachmentID)
|
suite.Empty(dbAccount.HeaderMediaAttachmentID)
|
||||||
suite.Empty(dbAccount.HeaderRemoteURL)
|
suite.Empty(dbAccount.HeaderRemoteURL)
|
||||||
suite.Empty(dbAccount.Reason)
|
|
||||||
suite.Empty(dbAccount.Fields)
|
suite.Empty(dbAccount.Fields)
|
||||||
suite.True(*dbAccount.HideCollections)
|
|
||||||
suite.False(*dbAccount.Discoverable)
|
suite.False(*dbAccount.Discoverable)
|
||||||
suite.WithinDuration(time.Now(), dbAccount.SuspendedAt, 30*time.Second)
|
suite.WithinDuration(time.Now(), dbAccount.SuspendedAt, 30*time.Second)
|
||||||
suite.Equal(dbAccount.ID, dbAccount.SuspensionOrigin)
|
suite.Equal(dbAccount.ID, dbAccount.SuspensionOrigin)
|
||||||
|
|
|
@ -481,7 +481,7 @@ func (suite *AccountUpdateTestSuite) TestUpdateAccountSourceBadContentTypeFormDa
|
||||||
if err != nil {
|
if err != nil {
|
||||||
suite.FailNow(err.Error())
|
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() {
|
func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpdateStatusContentTypeBad() {
|
||||||
|
|
|
@ -81,7 +81,7 @@ func (suite *AccountVerifyTestSuite) TestAccountVerifyGet() {
|
||||||
suite.Equal(2, apimodelAccount.FollowingCount)
|
suite.Equal(2, apimodelAccount.FollowingCount)
|
||||||
suite.Equal(7, apimodelAccount.StatusesCount)
|
suite.Equal(7, apimodelAccount.StatusesCount)
|
||||||
suite.EqualValues(gtsmodel.VisibilityPublic, apimodelAccount.Source.Privacy)
|
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)
|
suite.Equal(testAccount.NoteRaw, apimodelAccount.Source.Note)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,16 +103,22 @@ func (suite *StatusCreateTestSuite) TestPostNewStatus() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *StatusCreateTestSuite) TestPostNewStatusMarkdown() {
|
func (suite *StatusCreateTestSuite) TestPostNewStatusMarkdown() {
|
||||||
// set default post language of account 1 to markdown
|
// Copy zork.
|
||||||
testAccount := suite.testAccounts["local_account_1"]
|
testAccount := >smodel.Account{}
|
||||||
testAccount.StatusContentType = "text/markdown"
|
*testAccount = *suite.testAccounts["local_account_1"]
|
||||||
a := testAccount
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
}
|
}
|
||||||
suite.Equal(a.StatusContentType, "text/markdown")
|
suite.Equal(testAccount.Settings.StatusContentType, "text/markdown")
|
||||||
|
|
||||||
t := suite.testTokens["local_account_1"]
|
t := suite.testTokens["local_account_1"]
|
||||||
oauthToken := oauth.DBTokenToToken(t)
|
oauthToken := oauth.DBTokenToToken(t)
|
||||||
|
@ -122,7 +128,7 @@ func (suite *StatusCreateTestSuite) TestPostNewStatusMarkdown() {
|
||||||
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
|
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
|
||||||
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
|
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
|
||||||
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
|
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 = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080/%s", statuses.BasePath), nil)
|
||||||
ctx.Request.Header.Set("accept", "application/json")
|
ctx.Request.Header.Set("accept", "application/json")
|
||||||
|
|
|
@ -100,7 +100,6 @@ func (suite *WebfingerGetTestSuite) funkifyAccountDomain(host string, accountDom
|
||||||
targetAccount := >smodel.Account{
|
targetAccount := >smodel.Account{
|
||||||
ID: "01FG1K8EA7SYHEC7V6XKVNC4ZA",
|
ID: "01FG1K8EA7SYHEC7V6XKVNC4ZA",
|
||||||
Username: "new_account_domain_user",
|
Username: "new_account_domain_user",
|
||||||
Privacy: gtsmodel.VisibilityDefault,
|
|
||||||
URI: "http://" + host + "/users/new_account_domain_user",
|
URI: "http://" + host + "/users/new_account_domain_user",
|
||||||
URL: "http://" + host + "/@new_account_domain_user",
|
URL: "http://" + host + "/@new_account_domain_user",
|
||||||
InboxURI: "http://" + host + "/users/new_account_domain_user/inbox",
|
InboxURI: "http://" + host + "/users/new_account_domain_user/inbox",
|
||||||
|
@ -118,6 +117,10 @@ func (suite *WebfingerGetTestSuite) funkifyAccountDomain(host string, accountDom
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := suite.db.PutAccountSettings(context.Background(), >smodel.AccountSettings{AccountID: targetAccount.ID}); err != nil {
|
||||||
|
suite.FailNow(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return targetAccount
|
return targetAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ func (c *Caches) Init() {
|
||||||
c.initAccount()
|
c.initAccount()
|
||||||
c.initAccountCounts()
|
c.initAccountCounts()
|
||||||
c.initAccountNote()
|
c.initAccountNote()
|
||||||
|
c.initAccountSettings()
|
||||||
c.initApplication()
|
c.initApplication()
|
||||||
c.initBlock()
|
c.initBlock()
|
||||||
c.initBlockIDs()
|
c.initBlockIDs()
|
||||||
|
@ -119,6 +120,7 @@ func (c *Caches) Stop() {
|
||||||
func (c *Caches) Sweep(threshold float64) {
|
func (c *Caches) Sweep(threshold float64) {
|
||||||
c.GTS.Account.Trim(threshold)
|
c.GTS.Account.Trim(threshold)
|
||||||
c.GTS.AccountNote.Trim(threshold)
|
c.GTS.AccountNote.Trim(threshold)
|
||||||
|
c.GTS.AccountSettings.Trim(threshold)
|
||||||
c.GTS.Block.Trim(threshold)
|
c.GTS.Block.Trim(threshold)
|
||||||
c.GTS.BlockIDs.Trim(threshold)
|
c.GTS.BlockIDs.Trim(threshold)
|
||||||
c.GTS.Emoji.Trim(threshold)
|
c.GTS.Emoji.Trim(threshold)
|
||||||
|
|
|
@ -43,6 +43,9 @@ type GTSCaches struct {
|
||||||
Pinned int
|
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 provides access to the gtsmodel Application database cache.
|
||||||
Application structr.Cache[*gtsmodel.Application]
|
Application structr.Cache[*gtsmodel.Application]
|
||||||
|
|
||||||
|
@ -190,6 +193,7 @@ func (c *Caches) initAccount() {
|
||||||
a2.Emojis = nil
|
a2.Emojis = nil
|
||||||
a2.AlsoKnownAs = nil
|
a2.AlsoKnownAs = nil
|
||||||
a2.Move = nil
|
a2.Move = nil
|
||||||
|
a2.Settings = nil
|
||||||
|
|
||||||
return a2
|
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() {
|
func (c *Caches) initApplication() {
|
||||||
// Calculate maximum cache size.
|
// Calculate maximum cache size.
|
||||||
cap := calculateResultCacheMax(
|
cap := calculateResultCacheMax(
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/id"
|
"github.com/superseriousbusiness/gotosocial/internal/id"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -219,9 +220,6 @@ func sizeofAccount() uintptr {
|
||||||
Bot: func() *bool { ok := true; return &ok }(),
|
Bot: func() *bool { ok := true; return &ok }(),
|
||||||
Locked: func() *bool { ok := true; return &ok }(),
|
Locked: func() *bool { ok := true; return &ok }(),
|
||||||
Discoverable: func() *bool { ok := false; return &ok }(),
|
Discoverable: func() *bool { ok := false; return &ok }(),
|
||||||
Privacy: gtsmodel.VisibilityFollowersOnly,
|
|
||||||
Sensitive: func() *bool { ok := true; return &ok }(),
|
|
||||||
Language: "fr",
|
|
||||||
URI: exampleURI,
|
URI: exampleURI,
|
||||||
URL: exampleURI,
|
URL: exampleURI,
|
||||||
InboxURI: exampleURI,
|
InboxURI: exampleURI,
|
||||||
|
@ -236,9 +234,7 @@ func sizeofAccount() uintptr {
|
||||||
SensitizedAt: exampleTime,
|
SensitizedAt: exampleTime,
|
||||||
SilencedAt: exampleTime,
|
SilencedAt: exampleTime,
|
||||||
SuspendedAt: exampleTime,
|
SuspendedAt: exampleTime,
|
||||||
HideCollections: func() *bool { ok := true; return &ok }(),
|
|
||||||
SuspensionOrigin: exampleID,
|
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 {
|
func sizeofApplication() uintptr {
|
||||||
return uintptr(size.Of(>smodel.Application{
|
return uintptr(size.Of(>smodel.Application{
|
||||||
ID: exampleID,
|
ID: exampleID,
|
||||||
|
|
|
@ -195,6 +195,7 @@ type CacheConfiguration struct {
|
||||||
MemoryTarget bytesize.Size `name:"memory-target"`
|
MemoryTarget bytesize.Size `name:"memory-target"`
|
||||||
AccountMemRatio float64 `name:"account-mem-ratio"`
|
AccountMemRatio float64 `name:"account-mem-ratio"`
|
||||||
AccountNoteMemRatio float64 `name:"account-note-mem-ratio"`
|
AccountNoteMemRatio float64 `name:"account-note-mem-ratio"`
|
||||||
|
AccountSettingsMemRatio float64 `name:"account-settings-mem-ratio"`
|
||||||
ApplicationMemRatio float64 `name:"application-mem-ratio"`
|
ApplicationMemRatio float64 `name:"application-mem-ratio"`
|
||||||
BlockMemRatio float64 `name:"block-mem-ratio"`
|
BlockMemRatio float64 `name:"block-mem-ratio"`
|
||||||
BlockIDsMemRatio 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
|
// be able to make some more sense :D
|
||||||
AccountMemRatio: 5,
|
AccountMemRatio: 5,
|
||||||
AccountNoteMemRatio: 1,
|
AccountNoteMemRatio: 1,
|
||||||
|
AccountSettingsMemRatio: 0.1,
|
||||||
ApplicationMemRatio: 0.1,
|
ApplicationMemRatio: 0.1,
|
||||||
BlockMemRatio: 2,
|
BlockMemRatio: 2,
|
||||||
BlockIDsMemRatio: 3,
|
BlockIDsMemRatio: 3,
|
||||||
|
|
|
@ -2825,6 +2825,31 @@ func GetCacheAccountNoteMemRatio() float64 { return global.GetCacheAccountNoteMe
|
||||||
// SetCacheAccountNoteMemRatio safely sets the value for global configuration 'Cache.AccountNoteMemRatio' field
|
// SetCacheAccountNoteMemRatio safely sets the value for global configuration 'Cache.AccountNoteMemRatio' field
|
||||||
func SetCacheAccountNoteMemRatio(v float64) { global.SetCacheAccountNoteMemRatio(v) }
|
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
|
// GetCacheApplicationMemRatio safely fetches the Configuration value for state's 'Cache.ApplicationMemRatio' field
|
||||||
func (st *ConfigState) GetCacheApplicationMemRatio() (v float64) {
|
func (st *ConfigState) GetCacheApplicationMemRatio() (v float64) {
|
||||||
st.mutex.RLock()
|
st.mutex.RLock()
|
||||||
|
|
|
@ -117,4 +117,13 @@ type Account interface {
|
||||||
// GetInstanceAccount returns the instance account for the given domain.
|
// GetInstanceAccount returns the instance account for the given domain.
|
||||||
// If domain is empty, this instance account will be returned.
|
// If domain is empty, this instance account will be returned.
|
||||||
GetInstanceAccount(ctx context.Context, domain string) (*gtsmodel.Account, error)
|
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()
|
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) {
|
func (a *accountDB) GetAccountCustomCSSByUsername(ctx context.Context, username string) (string, error) {
|
||||||
|
// Get local account.
|
||||||
account, err := a.GetAccountByUsernameDomain(ctx, username, "")
|
account, err := a.GetAccountByUsernameDomain(ctx, username, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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) {
|
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)
|
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
|
a2.AvatarMediaAttachment = nil
|
||||||
a1.Emojis = nil
|
a1.Emojis = nil
|
||||||
a2.Emojis = nil
|
a2.Emojis = nil
|
||||||
|
a1.Settings = nil
|
||||||
|
a2.Settings = nil
|
||||||
|
|
||||||
// Clear database-set fields.
|
// Clear database-set fields.
|
||||||
a1.CreatedAt = time.Time{}
|
a1.CreatedAt = time.Time{}
|
||||||
|
@ -439,15 +441,11 @@ func (suite *AccountTestSuite) TestInsertAccountWithDefaults() {
|
||||||
err = suite.db.Put(context.Background(), newAccount)
|
err = suite.db.Put(context.Background(), newAccount)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
suite.Equal("en", newAccount.Language)
|
|
||||||
suite.WithinDuration(time.Now(), newAccount.CreatedAt, 30*time.Second)
|
suite.WithinDuration(time.Now(), newAccount.CreatedAt, 30*time.Second)
|
||||||
suite.WithinDuration(time.Now(), newAccount.UpdatedAt, 30*time.Second)
|
suite.WithinDuration(time.Now(), newAccount.UpdatedAt, 30*time.Second)
|
||||||
suite.True(*newAccount.Locked)
|
suite.True(*newAccount.Locked)
|
||||||
suite.False(*newAccount.Memorial)
|
|
||||||
suite.False(*newAccount.Bot)
|
suite.False(*newAccount.Bot)
|
||||||
suite.False(*newAccount.Discoverable)
|
suite.False(*newAccount.Discoverable)
|
||||||
suite.False(*newAccount.Sensitive)
|
|
||||||
suite.False(*newAccount.HideCollections)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *AccountTestSuite) TestGetAccountPinnedStatusesSomeResults() {
|
func (suite *AccountTestSuite) TestGetAccountPinnedStatusesSomeResults() {
|
||||||
|
|
|
@ -119,12 +119,21 @@ func (a *adminDB) NewSignup(ctx context.Context, newSignup gtsmodel.NewSignup) (
|
||||||
return nil, err
|
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{
|
account = >smodel.Account{
|
||||||
ID: accountID,
|
ID: accountID,
|
||||||
Username: newSignup.Username,
|
Username: newSignup.Username,
|
||||||
DisplayName: newSignup.Username,
|
DisplayName: newSignup.Username,
|
||||||
Reason: newSignup.Reason,
|
|
||||||
Privacy: gtsmodel.VisibilityDefault,
|
|
||||||
URI: uris.UserURI,
|
URI: uris.UserURI,
|
||||||
URL: uris.UserURL,
|
URL: uris.UserURL,
|
||||||
InboxURI: uris.InboxURI,
|
InboxURI: uris.InboxURI,
|
||||||
|
@ -136,6 +145,7 @@ func (a *adminDB) NewSignup(ctx context.Context, newSignup gtsmodel.NewSignup) (
|
||||||
PrivateKey: privKey,
|
PrivateKey: privKey,
|
||||||
PublicKey: &privKey.PublicKey,
|
PublicKey: &privKey.PublicKey,
|
||||||
PublicKeyURI: uris.PublicKeyURI,
|
PublicKeyURI: uris.PublicKeyURI,
|
||||||
|
Settings: settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the new account!
|
// Insert the new account!
|
||||||
|
|
|
@ -85,19 +85,13 @@ func (suite *BasicTestSuite) TestPutAccountWithBunDefaultFields() {
|
||||||
suite.Nil(a.Fields)
|
suite.Nil(a.Fields)
|
||||||
suite.Empty(a.Note)
|
suite.Empty(a.Note)
|
||||||
suite.Empty(a.NoteRaw)
|
suite.Empty(a.NoteRaw)
|
||||||
suite.False(*a.Memorial)
|
|
||||||
suite.Empty(a.AlsoKnownAsURIs)
|
suite.Empty(a.AlsoKnownAsURIs)
|
||||||
suite.Empty(a.MovedToURI)
|
suite.Empty(a.MovedToURI)
|
||||||
suite.False(*a.Bot)
|
suite.False(*a.Bot)
|
||||||
suite.Empty(a.Reason)
|
|
||||||
// Locked is especially important, since it's a bool that defaults
|
// 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
|
// to true, which is why we use pointers for bools in the first place
|
||||||
suite.True(*a.Locked)
|
suite.True(*a.Locked)
|
||||||
suite.False(*a.Discoverable)
|
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.URI, a.URI)
|
||||||
suite.Equal(testAccount.URL, a.URL)
|
suite.Equal(testAccount.URL, a.URL)
|
||||||
suite.Zero(testAccount.FetchedAt)
|
suite.Zero(testAccount.FetchedAt)
|
||||||
|
@ -113,7 +107,6 @@ func (suite *BasicTestSuite) TestPutAccountWithBunDefaultFields() {
|
||||||
suite.Zero(a.SensitizedAt)
|
suite.Zero(a.SensitizedAt)
|
||||||
suite.Zero(a.SilencedAt)
|
suite.Zero(a.SilencedAt)
|
||||||
suite.Zero(a.SuspendedAt)
|
suite.Zero(a.SuspendedAt)
|
||||||
suite.False(*a.HideCollections)
|
|
||||||
suite.Empty(a.SuspensionOrigin)
|
suite.Empty(a.SuspensionOrigin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
// Set time of update from the last-fetched date.
|
||||||
latestAcc.UpdatedAt = latestAcc.FetchedAt
|
latestAcc.UpdatedAt = latestAcc.FetchedAt
|
||||||
|
|
||||||
// Carry over existing account language.
|
|
||||||
latestAcc.Language = account.Language
|
|
||||||
|
|
||||||
// This is an existing account, update the model in the database.
|
// This is an existing account, update the model in the database.
|
||||||
if err := d.state.DB.UpdateAccount(ctx, latestAcc); err != nil {
|
if err := d.state.DB.UpdateAccount(ctx, latestAcc); err != nil {
|
||||||
return nil, nil, gtserror.Newf("error updating database: %w", err)
|
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.
|
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
|
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
|
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.
|
Fields []*Field `bun:""` // 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
|
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)
|
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
|
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?
|
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.
|
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).
|
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.
|
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).
|
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.
|
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.
|
Move *Move `bun:"-"` // Move corresponding to MoveID, if set.
|
||||||
Bot *bool `bun:",default:false"` // Does this account identify itself as a bot?
|
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?
|
||||||
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?
|
||||||
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.
|
||||||
Privacy Visibility `bun:",nullzero"` // Default post privacy for this account
|
URL string `bun:",nullzero,unique"` // Web URL for this account's profile
|
||||||
Sensitive *bool `bun:",default:false"` // Set posts from this account to sensitive by default?
|
InboxURI string `bun:",nullzero,unique"` // Address of this account's ActivityPub inbox, for sending activity to
|
||||||
Language string `bun:",nullzero,notnull,default:'en'"` // What language does this account post in?
|
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.
|
||||||
StatusContentType string `bun:",nullzero"` // What is the default format for statuses posted by this account (only for local accounts).
|
OutboxURI string `bun:",nullzero,unique"` // Address of this account's activitypub outbox
|
||||||
CustomCSS string `bun:",nullzero"` // Custom CSS that should be displayed for this Account's profile and statuses.
|
FollowingURI string `bun:",nullzero,unique"` // URI for getting the following list of this account
|
||||||
URI string `bun:",nullzero,notnull,unique"` // ActivityPub URI for this account.
|
FollowersURI string `bun:",nullzero,unique"` // URI for getting the followers list of this account
|
||||||
URL string `bun:",nullzero,unique"` // Web URL for this account's profile
|
FeaturedCollectionURI string `bun:",nullzero,unique"` // URL for getting the featured collection list of this account
|
||||||
InboxURI string `bun:",nullzero,unique"` // Address of this account's ActivityPub inbox, for sending activity to
|
ActorType string `bun:",nullzero,notnull"` // What type of activitypub actor is this account?
|
||||||
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.
|
PrivateKey *rsa.PrivateKey `bun:""` // Privatekey for signing activitypub requests, will only be defined for local accounts
|
||||||
OutboxURI string `bun:",nullzero,unique"` // Address of this account's activitypub outbox
|
PublicKey *rsa.PublicKey `bun:",notnull"` // Publickey for authorizing signed activitypub requests, will be defined for both local and remote accounts
|
||||||
FollowingURI string `bun:",nullzero,unique"` // URI for getting the following list of this account
|
PublicKeyURI string `bun:",nullzero,notnull,unique"` // Web-reachable location of this account's public key
|
||||||
FollowersURI string `bun:",nullzero,unique"` // URI for getting the followers list of this account
|
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.
|
||||||
FeaturedCollectionURI string `bun:",nullzero,unique"` // URL for getting the featured collection list of this account
|
SensitizedAt time.Time `bun:"type:timestamptz,nullzero"` // When was this account set to have all its media shown as sensitive?
|
||||||
ActorType string `bun:",nullzero,notnull"` // What type of activitypub actor is this account?
|
SilencedAt time.Time `bun:"type:timestamptz,nullzero"` // When was this account silenced (eg., statuses only visible to followers, not public)?
|
||||||
PrivateKey *rsa.PrivateKey `bun:""` // Privatekey for signing activitypub requests, will only be defined for local accounts
|
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)
|
||||||
PublicKey *rsa.PublicKey `bun:",notnull"` // Publickey for authorizing signed activitypub requests, will be defined for both local and remote accounts
|
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
|
||||||
PublicKeyURI string `bun:",nullzero,notnull,unique"` // Web-reachable location of this account's public key
|
Settings *AccountSettings `bun:"-"` // gtsmodel.AccountSettings for this account.
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsLocal returns whether account is a local user account.
|
// IsLocal returns whether account is a local user account.
|
||||||
|
|
|
@ -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.Memorial = util.Ptr(false)
|
||||||
account.AlsoKnownAsURIs = nil
|
account.AlsoKnownAsURIs = nil
|
||||||
account.MovedToURI = ""
|
account.MovedToURI = ""
|
||||||
account.Reason = ""
|
|
||||||
account.Discoverable = util.Ptr(false)
|
account.Discoverable = util.Ptr(false)
|
||||||
account.StatusContentType = ""
|
|
||||||
account.CustomCSS = ""
|
|
||||||
account.SuspendedAt = now
|
account.SuspendedAt = now
|
||||||
account.SuspensionOrigin = origin
|
account.SuspensionOrigin = origin
|
||||||
account.HideCollections = util.Ptr(true)
|
|
||||||
account.EnableRSS = util.Ptr(false)
|
|
||||||
|
|
||||||
return []string{
|
return []string{
|
||||||
"fetched_at",
|
"fetched_at",
|
||||||
|
@ -541,14 +536,9 @@ func stubbifyAccount(account *gtsmodel.Account, origin string) []string {
|
||||||
"memorial",
|
"memorial",
|
||||||
"also_known_as_uris",
|
"also_known_as_uris",
|
||||||
"moved_to_uri",
|
"moved_to_uri",
|
||||||
"reason",
|
|
||||||
"discoverable",
|
"discoverable",
|
||||||
"status_content_type",
|
|
||||||
"custom_css",
|
|
||||||
"suspended_at",
|
"suspended_at",
|
||||||
"suspension_origin",
|
"suspension_origin",
|
||||||
"hide_collections",
|
|
||||||
"enable_rss",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,14 +66,9 @@ func (suite *AccountDeleteTestSuite) TestAccountDeleteLocal() {
|
||||||
suite.Zero(updatedAccount.NoteRaw)
|
suite.Zero(updatedAccount.NoteRaw)
|
||||||
suite.False(*updatedAccount.Memorial)
|
suite.False(*updatedAccount.Memorial)
|
||||||
suite.Empty(updatedAccount.AlsoKnownAsURIs)
|
suite.Empty(updatedAccount.AlsoKnownAsURIs)
|
||||||
suite.Zero(updatedAccount.Reason)
|
|
||||||
suite.False(*updatedAccount.Discoverable)
|
suite.False(*updatedAccount.Discoverable)
|
||||||
suite.Zero(updatedAccount.StatusContentType)
|
|
||||||
suite.Zero(updatedAccount.CustomCSS)
|
|
||||||
suite.WithinDuration(time.Now(), updatedAccount.SuspendedAt, 1*time.Minute)
|
suite.WithinDuration(time.Now(), updatedAccount.SuspendedAt, 1*time.Minute)
|
||||||
suite.Equal(suspensionOrigin, updatedAccount.SuspensionOrigin)
|
suite.Equal(suspensionOrigin, updatedAccount.SuspensionOrigin)
|
||||||
suite.True(*updatedAccount.HideCollections)
|
|
||||||
suite.False(*updatedAccount.EnableRSS)
|
|
||||||
|
|
||||||
updatedUser, err := suite.db.GetUserByAccountID(ctx, testAccount.ID)
|
updatedUser, err := suite.db.GetUserByAccountID(ctx, testAccount.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -64,7 +64,7 @@ func (p *Processor) GetRSSFeedForUsername(ctx context.Context, username string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure account has rss feed enabled.
|
// Ensure account has rss feed enabled.
|
||||||
if !*account.EnableRSS {
|
if !*account.Settings.EnableRSS {
|
||||||
err = gtserror.New("account RSS feed not enabled")
|
err = gtserror.New("account RSS feed not enabled")
|
||||||
return nil, never, gtserror.NewErrorNotFound(err)
|
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.
|
// 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) {
|
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 {
|
if form.Discoverable != nil {
|
||||||
account.Discoverable = form.Discoverable
|
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.
|
// 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)
|
formatNoteResult := f(ctx, p.parseMention, account.ID, "", account.NoteRaw)
|
||||||
account.Note = formatNoteResult.HTML
|
account.Note = formatNoteResult.HTML
|
||||||
|
|
||||||
|
@ -227,11 +232,11 @@ func (p *Processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorBadRequest(err)
|
return nil, gtserror.NewErrorBadRequest(err)
|
||||||
}
|
}
|
||||||
account.Language = language
|
account.Settings.Language = language
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.Source.Sensitive != nil {
|
if form.Source.Sensitive != nil {
|
||||||
account.Sensitive = form.Source.Sensitive
|
account.Settings.Sensitive = form.Source.Sensitive
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.Source.Privacy != nil {
|
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)
|
return nil, gtserror.NewErrorBadRequest(err)
|
||||||
}
|
}
|
||||||
privacy := typeutils.APIVisToVis(apimodel.Visibility(*form.Source.Privacy))
|
privacy := typeutils.APIVisToVis(apimodel.Visibility(*form.Source.Privacy))
|
||||||
account.Privacy = privacy
|
account.Settings.Privacy = privacy
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.Source.StatusContentType != nil {
|
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())
|
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 {
|
if err := validate.CustomCSS(customCSS); err != nil {
|
||||||
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
||||||
}
|
}
|
||||||
account.CustomCSS = text.SanitizeToPlaintext(customCSS)
|
account.Settings.CustomCSS = text.SanitizeToPlaintext(customCSS)
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.EnableRSS != nil {
|
if form.EnableRSS != nil {
|
||||||
account.EnableRSS = form.EnableRSS
|
account.Settings.EnableRSS = form.EnableRSS
|
||||||
}
|
}
|
||||||
|
|
||||||
err := p.state.DB.UpdateAccount(ctx, account)
|
if err := p.state.DB.UpdateAccount(ctx, account); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("could not update account %s: %s", account.ID, err))
|
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{
|
p.state.Workers.EnqueueClientAPI(ctx, messages.FromClientAPI{
|
||||||
APObjectType: ap.ObjectProfile,
|
APObjectType: ap.ObjectProfile,
|
||||||
APActivityType: ap.ActivityUpdate,
|
APActivityType: ap.ActivityUpdate,
|
||||||
|
|
|
@ -126,9 +126,15 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMention() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMarkdownNote() {
|
func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMarkdownNote() {
|
||||||
|
// Copy zork.
|
||||||
testAccount := >smodel.Account{}
|
testAccount := >smodel.Account{}
|
||||||
*testAccount = *suite.testAccounts["local_account_1"]
|
*testAccount = *suite.testAccounts["local_account_1"]
|
||||||
|
|
||||||
|
// Copy zork's settings.
|
||||||
|
settings := >smodel.AccountSettings{}
|
||||||
|
*settings = *suite.testAccounts["local_account_1"].Settings
|
||||||
|
testAccount.Settings = settings
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
note = "*hello* ~~here~~ i am!"
|
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.
|
// Set status content type of account 1 to markdown for this test.
|
||||||
testAccount.StatusContentType = "text/markdown"
|
testAccount.Settings.StatusContentType = "text/markdown"
|
||||||
if err := suite.db.UpdateAccount(ctx, testAccount, "status_content_type"); err != nil {
|
if err := suite.db.UpdateAccountSettings(ctx, testAccount.Settings, "status_content_type"); err != nil {
|
||||||
suite.FailNow(err.Error())
|
suite.FailNow(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,9 @@ func (p *Processor) PreferencesGet(ctx context.Context, accountID string) (*apim
|
||||||
}
|
}
|
||||||
|
|
||||||
return &apimodel.Preferences{
|
return &apimodel.Preferences{
|
||||||
PostingDefaultVisibility: mastoPrefVisibility(act.Privacy),
|
PostingDefaultVisibility: mastoPrefVisibility(act.Settings.Privacy),
|
||||||
PostingDefaultSensitive: *act.Sensitive,
|
PostingDefaultSensitive: *act.Settings.Sensitive,
|
||||||
PostingDefaultLanguage: act.Language,
|
PostingDefaultLanguage: act.Settings.Language,
|
||||||
// The Reading* preferences don't appear to actually be settable by the
|
// The Reading* preferences don't appear to actually be settable by the
|
||||||
// client, so forcing some sensible defaults here
|
// client, so forcing some sensible defaults here
|
||||||
ReadingExpandMedia: "default",
|
ReadingExpandMedia: "default",
|
||||||
|
|
|
@ -50,6 +50,11 @@ func (p *Processor) Create(
|
||||||
*apimodel.Status,
|
*apimodel.Status,
|
||||||
gtserror.WithCode,
|
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.
|
// Generate new ID for status.
|
||||||
statusID := id.NewULID()
|
statusID := id.NewULID()
|
||||||
|
|
||||||
|
@ -112,11 +117,11 @@ func (p *Processor) Create(
|
||||||
return nil, errWithCode
|
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)
|
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)
|
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 {
|
func (p *Processor) processContent(ctx context.Context, parseMention gtsmodel.ParseMentionFunc, form *apimodel.AdvancedStatusCreateForm, status *gtsmodel.Status) error {
|
||||||
if form.ContentType == "" {
|
if form.ContentType == "" {
|
||||||
// If content type wasn't specified, use the author's preferred content-type.
|
// 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
|
form.ContentType = contentType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -362,9 +362,7 @@ func (suite *FromFediAPITestSuite) TestProcessAccountDelete() {
|
||||||
suite.Empty(dbAccount.AvatarRemoteURL)
|
suite.Empty(dbAccount.AvatarRemoteURL)
|
||||||
suite.Empty(dbAccount.HeaderMediaAttachmentID)
|
suite.Empty(dbAccount.HeaderMediaAttachmentID)
|
||||||
suite.Empty(dbAccount.HeaderRemoteURL)
|
suite.Empty(dbAccount.HeaderRemoteURL)
|
||||||
suite.Empty(dbAccount.Reason)
|
|
||||||
suite.Empty(dbAccount.Fields)
|
suite.Empty(dbAccount.Fields)
|
||||||
suite.True(*dbAccount.HideCollections)
|
|
||||||
suite.False(*dbAccount.Discoverable)
|
suite.False(*dbAccount.Discoverable)
|
||||||
suite.WithinDuration(time.Now(), dbAccount.SuspendedAt, 30*time.Second)
|
suite.WithinDuration(time.Now(), dbAccount.SuspendedAt, 30*time.Second)
|
||||||
suite.Equal(dbAccount.ID, dbAccount.SuspensionOrigin)
|
suite.Equal(dbAccount.ID, dbAccount.SuspensionOrigin)
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||||
transmodel "github.com/superseriousbusiness/gotosocial/internal/trans/model"
|
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 {
|
if err := i.putInDB(ctx, account); err != nil {
|
||||||
return fmt.Errorf("inputEntry: error adding account to database: %s", err)
|
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)
|
log.Infof(ctx, "added account with id %s", account.ID)
|
||||||
return nil
|
return nil
|
||||||
case transmodel.TransBlock:
|
case transmodel.TransBlock:
|
||||||
|
|
|
@ -106,11 +106,6 @@ func (suite *ImportMinimalTestSuite) TestImportMinimalOK() {
|
||||||
suite.Equal(testAccountBefore.Memorial, testAccountAfter.Memorial)
|
suite.Equal(testAccountBefore.Memorial, testAccountAfter.Memorial)
|
||||||
suite.Equal(testAccountBefore.Bot, testAccountAfter.Bot)
|
suite.Equal(testAccountBefore.Bot, testAccountAfter.Bot)
|
||||||
suite.Equal(testAccountBefore.Locked, testAccountAfter.Locked)
|
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.URI, testAccountAfter.URI)
|
||||||
suite.Equal(testAccountBefore.URL, testAccountAfter.URL)
|
suite.Equal(testAccountBefore.URL, testAccountAfter.URL)
|
||||||
suite.Equal(testAccountBefore.InboxURI, testAccountAfter.InboxURI)
|
suite.Equal(testAccountBefore.InboxURI, testAccountAfter.InboxURI)
|
||||||
|
@ -123,7 +118,6 @@ func (suite *ImportMinimalTestSuite) TestImportMinimalOK() {
|
||||||
suite.Equal(testAccountBefore.PublicKey, testAccountAfter.PublicKey)
|
suite.Equal(testAccountBefore.PublicKey, testAccountAfter.PublicKey)
|
||||||
suite.Equal(testAccountBefore.PublicKeyURI, testAccountAfter.PublicKeyURI)
|
suite.Equal(testAccountBefore.PublicKeyURI, testAccountAfter.PublicKeyURI)
|
||||||
suite.Equal(testAccountBefore.SuspendedAt, testAccountAfter.SuspendedAt)
|
suite.Equal(testAccountBefore.SuspendedAt, testAccountAfter.SuspendedAt)
|
||||||
suite.Equal(testAccountBefore.HideCollections, testAccountAfter.HideCollections)
|
|
||||||
suite.Equal(testAccountBefore.SuspensionOrigin, testAccountAfter.SuspensionOrigin)
|
suite.Equal(testAccountBefore.SuspensionOrigin, testAccountAfter.SuspensionOrigin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,8 @@ type Account struct {
|
||||||
NoteRaw string `json:"noteRaw,omitempty" bun:",nullzero"`
|
NoteRaw string `json:"noteRaw,omitempty" bun:",nullzero"`
|
||||||
Memorial *bool `json:"memorial"`
|
Memorial *bool `json:"memorial"`
|
||||||
Bot *bool `json:"bot"`
|
Bot *bool `json:"bot"`
|
||||||
Reason string `json:"reason,omitempty" bun:",nullzero"`
|
|
||||||
Locked *bool `json:"locked"`
|
Locked *bool `json:"locked"`
|
||||||
Discoverable *bool `json:"discoverable"`
|
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"`
|
URI string `json:"uri" bun:",nullzero"`
|
||||||
URL string `json:"url" bun:",nullzero"`
|
URL string `json:"url" bun:",nullzero"`
|
||||||
InboxURI string `json:"inboxURI" bun:",nullzero"`
|
InboxURI string `json:"inboxURI" bun:",nullzero"`
|
||||||
|
@ -59,6 +54,9 @@ type Account struct {
|
||||||
SensitizedAt *time.Time `json:"sensitizedAt,omitempty" bun:",nullzero"`
|
SensitizedAt *time.Time `json:"sensitizedAt,omitempty" bun:",nullzero"`
|
||||||
SilencedAt *time.Time `json:"silencedAt,omitempty" bun:",nullzero"`
|
SilencedAt *time.Time `json:"silencedAt,omitempty" bun:",nullzero"`
|
||||||
SuspendedAt *time.Time `json:"suspendedAt,omitempty" bun:",nullzero"`
|
SuspendedAt *time.Time `json:"suspendedAt,omitempty" bun:",nullzero"`
|
||||||
HideCollections *bool `json:"hideCollections"`
|
|
||||||
SuspensionOrigin string `json:"suspensionOrigin,omitempty" bun:",nullzero"`
|
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).
|
// Extract account note (bio / summary).
|
||||||
acct.Note = ap.ExtractSummary(accountable)
|
acct.Note = ap.ExtractSummary(accountable)
|
||||||
|
|
||||||
// Assume:
|
// Assume not memorial (todo)
|
||||||
// - memorial (TODO)
|
|
||||||
// - sensitive (TODO)
|
|
||||||
// - hide collections (TODO)
|
|
||||||
acct.Memorial = util.Ptr(false)
|
acct.Memorial = util.Ptr(false)
|
||||||
acct.Sensitive = util.Ptr(false)
|
|
||||||
acct.HideCollections = util.Ptr(false)
|
|
||||||
|
|
||||||
// Extract 'manuallyApprovesFollowers' aka locked account (default = true).
|
// Extract 'manuallyApprovesFollowers' aka locked account (default = true).
|
||||||
manuallyApprovesFollowers := ap.GetManuallyApprovesFollowers(accountable)
|
manuallyApprovesFollowers := ap.GetManuallyApprovesFollowers(accountable)
|
||||||
|
@ -146,9 +141,6 @@ func (c *Converter) ASRepresentationToAccount(ctx context.Context, accountable a
|
||||||
discoverable := ap.GetDiscoverable(accountable)
|
discoverable := ap.GetDiscoverable(accountable)
|
||||||
acct.Discoverable = &discoverable
|
acct.Discoverable = &discoverable
|
||||||
|
|
||||||
// Assume not an RSS feed.
|
|
||||||
acct.EnableRSS = util.Ptr(false)
|
|
||||||
|
|
||||||
// Extract the URL property.
|
// Extract the URL property.
|
||||||
urls := ap.GetURL(accountable)
|
urls := ap.GetURL(accountable)
|
||||||
if len(urls) == 0 {
|
if len(urls) == 0 {
|
||||||
|
|
|
@ -78,14 +78,14 @@ func (c *Converter) AccountToAPIAccountSensitive(ctx context.Context, a *gtsmode
|
||||||
}
|
}
|
||||||
|
|
||||||
statusContentType := string(apimodel.StatusContentTypeDefault)
|
statusContentType := string(apimodel.StatusContentTypeDefault)
|
||||||
if a.StatusContentType != "" {
|
if a.Settings.StatusContentType != "" {
|
||||||
statusContentType = a.StatusContentType
|
statusContentType = a.Settings.StatusContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
apiAccount.Source = &apimodel.Source{
|
apiAccount.Source = &apimodel.Source{
|
||||||
Privacy: c.VisToAPIVis(ctx, a.Privacy),
|
Privacy: c.VisToAPIVis(ctx, a.Settings.Privacy),
|
||||||
Sensitive: *a.Sensitive,
|
Sensitive: *a.Settings.Sensitive,
|
||||||
Language: a.Language,
|
Language: a.Settings.Language,
|
||||||
StatusContentType: statusContentType,
|
StatusContentType: statusContentType,
|
||||||
Note: a.NoteRaw,
|
Note: a.NoteRaw,
|
||||||
Fields: c.fieldsToAPIFields(a.FieldsRaw),
|
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:
|
// Bits that vary between remote + local accounts:
|
||||||
// - Account (acct) string.
|
// - Account (acct) string.
|
||||||
// - Role.
|
// - Role.
|
||||||
|
// - Settings things (enableRSS, customCSS).
|
||||||
|
|
||||||
var (
|
var (
|
||||||
acct string
|
acct string
|
||||||
role *apimodel.AccountRole
|
role *apimodel.AccountRole
|
||||||
|
enableRSS bool
|
||||||
|
customCSS string
|
||||||
)
|
)
|
||||||
|
|
||||||
if a.IsRemote() {
|
if a.IsRemote() {
|
||||||
|
@ -203,6 +206,9 @@ func (c *Converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
||||||
default:
|
default:
|
||||||
role = &apimodel.AccountRole{Name: apimodel.AccountRoleUser}
|
role = &apimodel.AccountRole{Name: apimodel.AccountRoleUser}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableRSS = *a.Settings.EnableRSS
|
||||||
|
customCSS = a.Settings.CustomCSS
|
||||||
}
|
}
|
||||||
|
|
||||||
acct = a.Username // omit domain
|
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)
|
locked = boolPtrDef("locked", a.Locked, true)
|
||||||
discoverable = boolPtrDef("discoverable", a.Discoverable, false)
|
discoverable = boolPtrDef("discoverable", a.Discoverable, false)
|
||||||
bot = boolPtrDef("bot", a.Bot, false)
|
bot = boolPtrDef("bot", a.Bot, false)
|
||||||
enableRSS = boolPtrDef("enableRSS", a.EnableRSS, false)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Remaining properties are simple and
|
// Remaining properties are simple and
|
||||||
|
@ -267,7 +272,7 @@ func (c *Converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
||||||
Emojis: apiEmojis,
|
Emojis: apiEmojis,
|
||||||
Fields: fields,
|
Fields: fields,
|
||||||
Suspended: !a.SuspendedAt.IsZero(),
|
Suspended: !a.SuspendedAt.IsZero(),
|
||||||
CustomCSS: a.CustomCSS,
|
CustomCSS: customCSS,
|
||||||
EnableRSS: enableRSS,
|
EnableRSS: enableRSS,
|
||||||
Role: role,
|
Role: role,
|
||||||
Moved: moved,
|
Moved: moved,
|
||||||
|
@ -376,6 +381,10 @@ func (c *Converter) AccountToAdminAPIAccount(ctx context.Context, a *gtsmodel.Ac
|
||||||
createdByApplicationID string
|
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() {
|
if a.IsRemote() {
|
||||||
// Domain may be in Punycode,
|
// Domain may be in Punycode,
|
||||||
// de-punify it just in case.
|
// de-punify it just in case.
|
||||||
|
@ -404,8 +413,8 @@ func (c *Converter) AccountToAdminAPIAccount(ctx context.Context, a *gtsmodel.Ac
|
||||||
}
|
}
|
||||||
|
|
||||||
locale = user.Locale
|
locale = user.Locale
|
||||||
if user.Account.Reason != "" {
|
if a.Settings.Reason != "" {
|
||||||
inviteRequest = &user.Account.Reason
|
inviteRequest = &a.Settings.Reason
|
||||||
}
|
}
|
||||||
|
|
||||||
if *user.Admin {
|
if *user.Admin {
|
||||||
|
|
|
@ -26,6 +26,7 @@ EXPECT=$(cat << "EOF"
|
||||||
"cache": {
|
"cache": {
|
||||||
"account-mem-ratio": 5,
|
"account-mem-ratio": 5,
|
||||||
"account-note-mem-ratio": 1,
|
"account-note-mem-ratio": 1,
|
||||||
|
"account-settings-mem-ratio": 0.1,
|
||||||
"application-mem-ratio": 0.1,
|
"application-mem-ratio": 0.1,
|
||||||
"block-mem-ratio": 3,
|
"block-mem-ratio": 3,
|
||||||
"boost-of-ids-mem-ratio": 3,
|
"boost-of-ids-mem-ratio": 3,
|
||||||
|
|
|
@ -70,6 +70,7 @@ var testModels = []interface{}{
|
||||||
>smodel.Report{},
|
>smodel.Report{},
|
||||||
>smodel.Rule{},
|
>smodel.Rule{},
|
||||||
>smodel.AccountNote{},
|
>smodel.AccountNote{},
|
||||||
|
>smodel.AccountSettings{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTestDB returns a new initialized, empty database for testing.
|
// 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() {
|
for _, v := range NewTestAttachments() {
|
||||||
if err := db.Put(ctx, v); err != nil {
|
if err := db.Put(ctx, v); err != nil {
|
||||||
log.Panic(nil, err)
|
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.
|
// NewTestAccounts returns a map of accounts keyed by what type of account they are.
|
||||||
func NewTestAccounts() map[string]*gtsmodel.Account {
|
func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
|
settings := NewTestAccountSettings()
|
||||||
|
|
||||||
accounts := map[string]*gtsmodel.Account{
|
accounts := map[string]*gtsmodel.Account{
|
||||||
"instance_account": {
|
"instance_account": {
|
||||||
ID: "01AY6P665V14JJR0AFVRT7311Y",
|
ID: "01AY6P665V14JJR0AFVRT7311Y",
|
||||||
|
@ -301,12 +303,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
CreatedAt: TimeMustParse("2020-05-17T13:10:59Z"),
|
CreatedAt: TimeMustParse("2020-05-17T13:10:59Z"),
|
||||||
UpdatedAt: TimeMustParse("2020-05-17T13:10:59Z"),
|
UpdatedAt: TimeMustParse("2020-05-17T13:10:59Z"),
|
||||||
Bot: util.Ptr(false),
|
Bot: util.Ptr(false),
|
||||||
Reason: "",
|
|
||||||
Locked: util.Ptr(false),
|
Locked: util.Ptr(false),
|
||||||
Discoverable: util.Ptr(true),
|
Discoverable: util.Ptr(true),
|
||||||
Privacy: gtsmodel.VisibilityPublic,
|
|
||||||
Sensitive: util.Ptr(false),
|
|
||||||
Language: "en",
|
|
||||||
URI: "http://localhost:8080/users/localhost:8080",
|
URI: "http://localhost:8080/users/localhost:8080",
|
||||||
URL: "http://localhost:8080/@localhost:8080",
|
URL: "http://localhost:8080/@localhost:8080",
|
||||||
PublicKeyURI: "http://localhost:8080/users/localhost:8080#main-key",
|
PublicKeyURI: "http://localhost:8080/users/localhost:8080#main-key",
|
||||||
|
@ -322,9 +320,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
SensitizedAt: time.Time{},
|
SensitizedAt: time.Time{},
|
||||||
SilencedAt: time.Time{},
|
SilencedAt: time.Time{},
|
||||||
SuspendedAt: time.Time{},
|
SuspendedAt: time.Time{},
|
||||||
HideCollections: util.Ptr(false),
|
|
||||||
SuspensionOrigin: "",
|
SuspensionOrigin: "",
|
||||||
EnableRSS: util.Ptr(false),
|
|
||||||
},
|
},
|
||||||
"unconfirmed_account": {
|
"unconfirmed_account": {
|
||||||
ID: "01F8MH0BBE4FHXPH513MBVFHB0",
|
ID: "01F8MH0BBE4FHXPH513MBVFHB0",
|
||||||
|
@ -339,12 +335,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||||
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||||
Bot: util.Ptr(false),
|
Bot: util.Ptr(false),
|
||||||
Reason: "hi, please let me in! I'm looking for somewhere neato bombeato to hang out.",
|
|
||||||
Locked: util.Ptr(false),
|
Locked: util.Ptr(false),
|
||||||
Discoverable: util.Ptr(false),
|
Discoverable: util.Ptr(false),
|
||||||
Privacy: gtsmodel.VisibilityPublic,
|
|
||||||
Sensitive: util.Ptr(false),
|
|
||||||
Language: "en",
|
|
||||||
URI: "http://localhost:8080/users/weed_lord420",
|
URI: "http://localhost:8080/users/weed_lord420",
|
||||||
URL: "http://localhost:8080/@weed_lord420",
|
URL: "http://localhost:8080/@weed_lord420",
|
||||||
FetchedAt: time.Time{},
|
FetchedAt: time.Time{},
|
||||||
|
@ -360,9 +352,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
SensitizedAt: time.Time{},
|
SensitizedAt: time.Time{},
|
||||||
SilencedAt: time.Time{},
|
SilencedAt: time.Time{},
|
||||||
SuspendedAt: time.Time{},
|
SuspendedAt: time.Time{},
|
||||||
HideCollections: util.Ptr(false),
|
|
||||||
SuspensionOrigin: "",
|
SuspensionOrigin: "",
|
||||||
EnableRSS: util.Ptr(false),
|
Settings: settings["unconfirmed_account"],
|
||||||
},
|
},
|
||||||
"admin_account": {
|
"admin_account": {
|
||||||
ID: "01F8MH17FWEB39HZJ76B6VXSKF",
|
ID: "01F8MH17FWEB39HZJ76B6VXSKF",
|
||||||
|
@ -378,12 +369,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
CreatedAt: TimeMustParse("2022-05-17T13:10:59Z"),
|
CreatedAt: TimeMustParse("2022-05-17T13:10:59Z"),
|
||||||
UpdatedAt: TimeMustParse("2022-05-17T13:10:59Z"),
|
UpdatedAt: TimeMustParse("2022-05-17T13:10:59Z"),
|
||||||
Bot: util.Ptr(false),
|
Bot: util.Ptr(false),
|
||||||
Reason: "",
|
|
||||||
Locked: util.Ptr(false),
|
Locked: util.Ptr(false),
|
||||||
Discoverable: util.Ptr(true),
|
Discoverable: util.Ptr(true),
|
||||||
Privacy: gtsmodel.VisibilityPublic,
|
|
||||||
Sensitive: util.Ptr(false),
|
|
||||||
Language: "en",
|
|
||||||
URI: "http://localhost:8080/users/admin",
|
URI: "http://localhost:8080/users/admin",
|
||||||
URL: "http://localhost:8080/@admin",
|
URL: "http://localhost:8080/@admin",
|
||||||
PublicKeyURI: "http://localhost:8080/users/admin#main-key",
|
PublicKeyURI: "http://localhost:8080/users/admin#main-key",
|
||||||
|
@ -399,9 +386,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
SensitizedAt: time.Time{},
|
SensitizedAt: time.Time{},
|
||||||
SilencedAt: time.Time{},
|
SilencedAt: time.Time{},
|
||||||
SuspendedAt: time.Time{},
|
SuspendedAt: time.Time{},
|
||||||
HideCollections: util.Ptr(false),
|
|
||||||
SuspensionOrigin: "",
|
SuspensionOrigin: "",
|
||||||
EnableRSS: util.Ptr(true),
|
Settings: settings["admin_account"],
|
||||||
},
|
},
|
||||||
"local_account_1": {
|
"local_account_1": {
|
||||||
ID: "01F8MH1H7YV1Z7D2C8K2730QBF",
|
ID: "01F8MH1H7YV1Z7D2C8K2730QBF",
|
||||||
|
@ -417,12 +403,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
CreatedAt: TimeMustParse("2022-05-20T11:09:18Z"),
|
CreatedAt: TimeMustParse("2022-05-20T11:09:18Z"),
|
||||||
UpdatedAt: TimeMustParse("2022-05-20T11:09:18Z"),
|
UpdatedAt: TimeMustParse("2022-05-20T11:09:18Z"),
|
||||||
Bot: util.Ptr(false),
|
Bot: util.Ptr(false),
|
||||||
Reason: "I wanna be on this damned webbed site so bad! Please! Wow",
|
|
||||||
Locked: util.Ptr(false),
|
Locked: util.Ptr(false),
|
||||||
Discoverable: util.Ptr(true),
|
Discoverable: util.Ptr(true),
|
||||||
Privacy: gtsmodel.VisibilityPublic,
|
|
||||||
Sensitive: util.Ptr(false),
|
|
||||||
Language: "en",
|
|
||||||
URI: "http://localhost:8080/users/the_mighty_zork",
|
URI: "http://localhost:8080/users/the_mighty_zork",
|
||||||
URL: "http://localhost:8080/@the_mighty_zork",
|
URL: "http://localhost:8080/@the_mighty_zork",
|
||||||
FetchedAt: time.Time{},
|
FetchedAt: time.Time{},
|
||||||
|
@ -438,9 +420,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
SensitizedAt: time.Time{},
|
SensitizedAt: time.Time{},
|
||||||
SilencedAt: time.Time{},
|
SilencedAt: time.Time{},
|
||||||
SuspendedAt: time.Time{},
|
SuspendedAt: time.Time{},
|
||||||
HideCollections: util.Ptr(false),
|
|
||||||
SuspensionOrigin: "",
|
SuspensionOrigin: "",
|
||||||
EnableRSS: util.Ptr(true),
|
Settings: settings["local_account_1"],
|
||||||
},
|
},
|
||||||
"local_account_2": {
|
"local_account_2": {
|
||||||
ID: "01F8MH5NBDF2MV7CTC4Q5128HF",
|
ID: "01F8MH5NBDF2MV7CTC4Q5128HF",
|
||||||
|
@ -475,12 +456,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||||
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
|
||||||
Bot: util.Ptr(false),
|
Bot: util.Ptr(false),
|
||||||
Reason: "",
|
|
||||||
Locked: util.Ptr(true),
|
Locked: util.Ptr(true),
|
||||||
Discoverable: util.Ptr(false),
|
Discoverable: util.Ptr(false),
|
||||||
Privacy: gtsmodel.VisibilityFollowersOnly,
|
|
||||||
Sensitive: util.Ptr(true),
|
|
||||||
Language: "fr",
|
|
||||||
URI: "http://localhost:8080/users/1happyturtle",
|
URI: "http://localhost:8080/users/1happyturtle",
|
||||||
URL: "http://localhost:8080/@1happyturtle",
|
URL: "http://localhost:8080/@1happyturtle",
|
||||||
FetchedAt: time.Time{},
|
FetchedAt: time.Time{},
|
||||||
|
@ -496,9 +473,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
SensitizedAt: time.Time{},
|
SensitizedAt: time.Time{},
|
||||||
SilencedAt: time.Time{},
|
SilencedAt: time.Time{},
|
||||||
SuspendedAt: time.Time{},
|
SuspendedAt: time.Time{},
|
||||||
HideCollections: util.Ptr(false),
|
|
||||||
SuspensionOrigin: "",
|
SuspensionOrigin: "",
|
||||||
EnableRSS: util.Ptr(false),
|
Settings: settings["local_account_2"],
|
||||||
},
|
},
|
||||||
"remote_account_1": {
|
"remote_account_1": {
|
||||||
ID: "01F8MH5ZK5VRH73AKHQM6Y9VNX",
|
ID: "01F8MH5ZK5VRH73AKHQM6Y9VNX",
|
||||||
|
@ -514,8 +490,6 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
Bot: util.Ptr(false),
|
Bot: util.Ptr(false),
|
||||||
Locked: util.Ptr(false),
|
Locked: util.Ptr(false),
|
||||||
Discoverable: util.Ptr(true),
|
Discoverable: util.Ptr(true),
|
||||||
Sensitive: util.Ptr(false),
|
|
||||||
Language: "en",
|
|
||||||
URI: "http://fossbros-anonymous.io/users/foss_satan",
|
URI: "http://fossbros-anonymous.io/users/foss_satan",
|
||||||
URL: "http://fossbros-anonymous.io/@foss_satan",
|
URL: "http://fossbros-anonymous.io/@foss_satan",
|
||||||
FetchedAt: time.Time{},
|
FetchedAt: time.Time{},
|
||||||
|
@ -532,9 +506,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
SensitizedAt: time.Time{},
|
SensitizedAt: time.Time{},
|
||||||
SilencedAt: time.Time{},
|
SilencedAt: time.Time{},
|
||||||
SuspendedAt: time.Time{},
|
SuspendedAt: time.Time{},
|
||||||
HideCollections: util.Ptr(false),
|
|
||||||
SuspensionOrigin: "",
|
SuspensionOrigin: "",
|
||||||
EnableRSS: util.Ptr(false),
|
|
||||||
},
|
},
|
||||||
"remote_account_2": {
|
"remote_account_2": {
|
||||||
ID: "01FHMQX3GAABWSM0S2VZEC2SWC",
|
ID: "01FHMQX3GAABWSM0S2VZEC2SWC",
|
||||||
|
@ -550,8 +522,6 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
Bot: util.Ptr(false),
|
Bot: util.Ptr(false),
|
||||||
Locked: util.Ptr(true),
|
Locked: util.Ptr(true),
|
||||||
Discoverable: util.Ptr(true),
|
Discoverable: util.Ptr(true),
|
||||||
Sensitive: util.Ptr(false),
|
|
||||||
Language: "en",
|
|
||||||
URI: "http://example.org/users/Some_User",
|
URI: "http://example.org/users/Some_User",
|
||||||
URL: "http://example.org/@Some_User",
|
URL: "http://example.org/@Some_User",
|
||||||
FetchedAt: time.Time{},
|
FetchedAt: time.Time{},
|
||||||
|
@ -568,9 +538,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
SensitizedAt: time.Time{},
|
SensitizedAt: time.Time{},
|
||||||
SilencedAt: time.Time{},
|
SilencedAt: time.Time{},
|
||||||
SuspendedAt: time.Time{},
|
SuspendedAt: time.Time{},
|
||||||
HideCollections: util.Ptr(false),
|
|
||||||
SuspensionOrigin: "",
|
SuspensionOrigin: "",
|
||||||
EnableRSS: util.Ptr(false),
|
|
||||||
},
|
},
|
||||||
"remote_account_3": {
|
"remote_account_3": {
|
||||||
ID: "062G5WYKY35KKD12EMSM3F8PJ8",
|
ID: "062G5WYKY35KKD12EMSM3F8PJ8",
|
||||||
|
@ -586,8 +554,6 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
Bot: util.Ptr(false),
|
Bot: util.Ptr(false),
|
||||||
Locked: util.Ptr(true),
|
Locked: util.Ptr(true),
|
||||||
Discoverable: util.Ptr(true),
|
Discoverable: util.Ptr(true),
|
||||||
Sensitive: util.Ptr(false),
|
|
||||||
Language: "en",
|
|
||||||
URI: "http://thequeenisstillalive.technology/users/her_fuckin_maj",
|
URI: "http://thequeenisstillalive.technology/users/her_fuckin_maj",
|
||||||
URL: "http://thequeenisstillalive.technology/@her_fuckin_maj",
|
URL: "http://thequeenisstillalive.technology/@her_fuckin_maj",
|
||||||
FetchedAt: time.Time{},
|
FetchedAt: time.Time{},
|
||||||
|
@ -604,10 +570,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
SensitizedAt: time.Time{},
|
SensitizedAt: time.Time{},
|
||||||
SilencedAt: time.Time{},
|
SilencedAt: time.Time{},
|
||||||
SuspendedAt: time.Time{},
|
SuspendedAt: time.Time{},
|
||||||
HideCollections: util.Ptr(false),
|
|
||||||
SuspensionOrigin: "",
|
SuspensionOrigin: "",
|
||||||
HeaderMediaAttachmentID: "01PFPMWK2FF0D9WMHEJHR07C3R",
|
HeaderMediaAttachmentID: "01PFPMWK2FF0D9WMHEJHR07C3R",
|
||||||
EnableRSS: util.Ptr(false),
|
|
||||||
},
|
},
|
||||||
"remote_account_4": {
|
"remote_account_4": {
|
||||||
ID: "07GZRBAEMBNKGZ8Z9VSKSXKR98",
|
ID: "07GZRBAEMBNKGZ8Z9VSKSXKR98",
|
||||||
|
@ -622,8 +586,6 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
Bot: util.Ptr(false),
|
Bot: util.Ptr(false),
|
||||||
Locked: util.Ptr(false),
|
Locked: util.Ptr(false),
|
||||||
Discoverable: util.Ptr(false),
|
Discoverable: util.Ptr(false),
|
||||||
Sensitive: util.Ptr(false),
|
|
||||||
Language: "de",
|
|
||||||
URI: "https://xn--xample-ova.org/users/%C3%BCser",
|
URI: "https://xn--xample-ova.org/users/%C3%BCser",
|
||||||
URL: "https://xn--xample-ova.org/users/@%C3%BCser",
|
URL: "https://xn--xample-ova.org/users/@%C3%BCser",
|
||||||
FetchedAt: time.Time{},
|
FetchedAt: time.Time{},
|
||||||
|
@ -640,10 +602,8 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
SensitizedAt: time.Time{},
|
SensitizedAt: time.Time{},
|
||||||
SilencedAt: time.Time{},
|
SilencedAt: time.Time{},
|
||||||
SuspendedAt: time.Time{},
|
SuspendedAt: time.Time{},
|
||||||
HideCollections: util.Ptr(false),
|
|
||||||
SuspensionOrigin: "",
|
SuspensionOrigin: "",
|
||||||
HeaderMediaAttachmentID: "",
|
HeaderMediaAttachmentID: "",
|
||||||
EnableRSS: util.Ptr(false),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,6 +658,55 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
return accounts
|
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 {
|
func NewTestTombstones() map[string]*gtsmodel.Tombstone {
|
||||||
return map[string]*gtsmodel.Tombstone{
|
return map[string]*gtsmodel.Tombstone{
|
||||||
"https://somewhere.mysterious/users/rest_in_piss#main-key": {
|
"https://somewhere.mysterious/users/rest_in_piss#main-key": {
|
||||||
|
|
Loading…
Reference in New Issue