diff --git a/docs/api/swagger.yaml b/docs/api/swagger.yaml
index 88ad8eb55..0eca007ea 100644
--- a/docs/api/swagger.yaml
+++ b/docs/api/swagger.yaml
@@ -1581,9 +1581,7 @@ definitions:
type: integer
x-go-name: MaxFeaturedTags
max_profile_fields:
- description: |-
- The maximum number of profile fields allowed for each account.
- Currently not configurable, so this is hardcoded to 6. (https://codeberg.org/superseriousbusiness/gotosocial/issues/1876)
+ description: The maximum number of profile fields allowed for each account.
format: int64
type: integer
x-go-name: MaxProfileFields
diff --git a/docs/configuration/accounts.md b/docs/configuration/accounts.md
index 788cf79ac..b9f72252c 100644
--- a/docs/configuration/accounts.md
+++ b/docs/configuration/accounts.md
@@ -64,4 +64,12 @@ accounts-allow-custom-css: false
# Examples: [500, 5000, 9999]
# Default: 10000
accounts-custom-css-length: 10000
+
+# Int. The maximum number of profile fields allowed for each account.
+#
+# Note that going way higher than the default might break federation.
+#
+# Examples: [4, 6, 12]
+# Default: 6
+accounts-max-profile-fields: 6
```
diff --git a/example/config.yaml b/example/config.yaml
index 209e2dc9d..ce81da1fe 100644
--- a/example/config.yaml
+++ b/example/config.yaml
@@ -533,6 +533,14 @@ accounts-allow-custom-css: false
# Default: 10000
accounts-custom-css-length: 10000
+# Int. The maximum number of profile fields allowed for each account.
+#
+# Note that going way higher than the default might break federation.
+#
+# Examples: [4, 6, 12]
+# Default: 6
+accounts-max-profile-fields: 6
+
########################
##### MEDIA CONFIG #####
########################
diff --git a/internal/api/client/instance/instancepatch_test.go b/internal/api/client/instance/instancepatch_test.go
index 5b2b71d37..1139ac6d2 100644
--- a/internal/api/client/instance/instancepatch_test.go
+++ b/internal/api/client/instance/instancepatch_test.go
@@ -147,7 +147,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch1() {
"accounts": {
"allow_custom_css": true,
"max_featured_tags": 10,
- "max_profile_fields": 6
+ "max_profile_fields": 8
},
"emojis": {
"emoji_size_limit": 51200
@@ -290,7 +290,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch2() {
"accounts": {
"allow_custom_css": true,
"max_featured_tags": 10,
- "max_profile_fields": 6
+ "max_profile_fields": 8
},
"emojis": {
"emoji_size_limit": 51200
@@ -433,7 +433,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch3() {
"accounts": {
"allow_custom_css": true,
"max_featured_tags": 10,
- "max_profile_fields": 6
+ "max_profile_fields": 8
},
"emojis": {
"emoji_size_limit": 51200
@@ -627,7 +627,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch6() {
"accounts": {
"allow_custom_css": true,
"max_featured_tags": 10,
- "max_profile_fields": 6
+ "max_profile_fields": 8
},
"emojis": {
"emoji_size_limit": 51200
@@ -792,7 +792,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch8() {
"accounts": {
"allow_custom_css": true,
"max_featured_tags": 10,
- "max_profile_fields": 6
+ "max_profile_fields": 8
},
"emojis": {
"emoji_size_limit": 51200
@@ -976,7 +976,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch9() {
"accounts": {
"allow_custom_css": true,
"max_featured_tags": 10,
- "max_profile_fields": 6
+ "max_profile_fields": 8
},
"emojis": {
"emoji_size_limit": 51200
diff --git a/internal/api/model/instance.go b/internal/api/model/instance.go
index 73aa8ef82..ab8c83d1b 100644
--- a/internal/api/model/instance.go
+++ b/internal/api/model/instance.go
@@ -60,7 +60,6 @@ type InstanceConfigurationAccounts struct {
// Currently not implemented, so this is hardcoded to 10.
MaxFeaturedTags int `json:"max_featured_tags"`
// The maximum number of profile fields allowed for each account.
- // Currently not configurable, so this is hardcoded to 6. (https://codeberg.org/superseriousbusiness/gotosocial/issues/1876)
MaxProfileFields int `json:"max_profile_fields"`
}
diff --git a/internal/config/config.go b/internal/config/config.go
index 0aa90ce44..dd03b1104 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -105,6 +105,7 @@ type Configuration struct {
AccountsRegistrationBacklogLimit int `name:"accounts-registration-backlog-limit" usage:"Limit how big the 'accounts pending approval' queue can grow before registration is closed. 0 or less = no limit."`
AccountsAllowCustomCSS bool `name:"accounts-allow-custom-css" usage:"Allow accounts to enable custom CSS for their profile pages and statuses."`
AccountsCustomCSSLength int `name:"accounts-custom-css-length" usage:"Maximum permitted length (characters) of custom CSS for accounts."`
+ AccountsMaxProfileFields int `name:"accounts-max-profile-fields" usage:"Maximum number of profile fields allowed for each account."`
MediaDescriptionMinChars int `name:"media-description-min-chars" usage:"Min required chars for an image description"`
MediaDescriptionMaxChars int `name:"media-description-max-chars" usage:"Max permitted chars for an image description"`
diff --git a/internal/config/defaults.go b/internal/config/defaults.go
index 100738253..81242996d 100644
--- a/internal/config/defaults.go
+++ b/internal/config/defaults.go
@@ -75,6 +75,7 @@ var Defaults = Configuration{
AccountsRegistrationBacklogLimit: 20,
AccountsAllowCustomCSS: false,
AccountsCustomCSSLength: 10000,
+ AccountsMaxProfileFields: 6,
MediaDescriptionMinChars: 0,
MediaDescriptionMaxChars: 1500,
diff --git a/internal/config/helpers.gen.go b/internal/config/helpers.gen.go
index d38458304..a41c95861 100644
--- a/internal/config/helpers.gen.go
+++ b/internal/config/helpers.gen.go
@@ -79,6 +79,7 @@ func (cfg *Configuration) RegisterFlags(flags *pflag.FlagSet) {
flags.Int("accounts-registration-backlog-limit", cfg.AccountsRegistrationBacklogLimit, "Limit how big the 'accounts pending approval' queue can grow before registration is closed. 0 or less = no limit.")
flags.Bool("accounts-allow-custom-css", cfg.AccountsAllowCustomCSS, "Allow accounts to enable custom CSS for their profile pages and statuses.")
flags.Int("accounts-custom-css-length", cfg.AccountsCustomCSSLength, "Maximum permitted length (characters) of custom CSS for accounts.")
+ flags.Int("accounts-max-profile-fields", cfg.AccountsMaxProfileFields, "Maximum amount of profile fields an account can have.")
flags.Int("media-description-min-chars", cfg.MediaDescriptionMinChars, "Min required chars for an image description")
flags.Int("media-description-max-chars", cfg.MediaDescriptionMaxChars, "Max permitted chars for an image description")
flags.Int("media-remote-cache-days", cfg.MediaRemoteCacheDays, "Number of days to locally cache media from remote instances. If set to 0, remote media will be kept indefinitely.")
@@ -206,7 +207,7 @@ func (cfg *Configuration) RegisterFlags(flags *pflag.FlagSet) {
}
func (cfg *Configuration) MarshalMap() map[string]any {
- cfgmap := make(map[string]any, 181)
+ cfgmap := make(map[string]any, 182)
cfgmap["log-level"] = cfg.LogLevel
cfgmap["log-timestamp-format"] = cfg.LogTimestampFormat
cfgmap["log-db-queries"] = cfg.LogDbQueries
@@ -257,6 +258,7 @@ func (cfg *Configuration) MarshalMap() map[string]any {
cfgmap["accounts-registration-backlog-limit"] = cfg.AccountsRegistrationBacklogLimit
cfgmap["accounts-allow-custom-css"] = cfg.AccountsAllowCustomCSS
cfgmap["accounts-custom-css-length"] = cfg.AccountsCustomCSSLength
+ cfgmap["accounts-max-profile-fields"] = cfg.AccountsMaxProfileFields
cfgmap["media-description-min-chars"] = cfg.MediaDescriptionMinChars
cfgmap["media-description-max-chars"] = cfg.MediaDescriptionMaxChars
cfgmap["media-remote-cache-days"] = cfg.MediaRemoteCacheDays
@@ -805,6 +807,14 @@ func (cfg *Configuration) UnmarshalMap(cfgmap map[string]any) error {
}
}
+ if ival, ok := cfgmap["accounts-max-profile-fields"]; ok {
+ var err error
+ cfg.AccountsMaxProfileFields, err = cast.ToIntE(ival)
+ if err != nil {
+ return fmt.Errorf("error casting %#v -> int for 'accounts-max-profile-fields': %w", ival, err)
+ }
+ }
+
if ival, ok := cfgmap["media-description-min-chars"]; ok {
var err error
cfg.MediaDescriptionMinChars, err = cast.ToIntE(ival)
@@ -3138,6 +3148,31 @@ func GetAccountsCustomCSSLength() int { return global.GetAccountsCustomCSSLength
// SetAccountsCustomCSSLength safely sets the value for global configuration 'AccountsCustomCSSLength' field
func SetAccountsCustomCSSLength(v int) { global.SetAccountsCustomCSSLength(v) }
+// AccountsMaxProfileFieldsFlag returns the flag name for the 'AccountsMaxProfileFields' field
+func AccountsMaxProfileFieldsFlag() string { return "accounts-max-profile-fields" }
+
+// GetAccountsMaxProfileFields safely fetches the Configuration value for state's 'AccountsMaxProfileFields' field
+func (st *ConfigState) GetAccountsMaxProfileFields() (v int) {
+ st.mutex.RLock()
+ v = st.config.AccountsMaxProfileFields
+ st.mutex.RUnlock()
+ return
+}
+
+// SetAccountsMaxProfileFields safely sets the Configuration value for state's 'AccountsMaxProfileFields' field
+func (st *ConfigState) SetAccountsMaxProfileFields(v int) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.AccountsMaxProfileFields = v
+ st.reloadToViper()
+}
+
+// GetAccountsMaxProfileFields safely fetches the value for global configuration 'AccountsMaxProfileFields' field
+func GetAccountsMaxProfileFields() int { return global.GetAccountsMaxProfileFields() }
+
+// SetAccountsMaxProfileFields safely sets the value for global configuration 'AccountsMaxProfileFields' field
+func SetAccountsMaxProfileFields(v int) { global.SetAccountsMaxProfileFields(v) }
+
// MediaDescriptionMinCharsFlag returns the flag name for the 'MediaDescriptionMinChars' field
func MediaDescriptionMinCharsFlag() string { return "media-description-min-chars" }
diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go
index 6da78ed83..bef44e32f 100644
--- a/internal/typeutils/internaltofrontend.go
+++ b/internal/typeutils/internaltofrontend.go
@@ -50,7 +50,6 @@ const (
instancePollsMinExpiration = 300 // seconds
instancePollsMaxExpiration = 2629746 // seconds
instanceAccountsMaxFeaturedTags = 10
- instanceAccountsMaxProfileFields = 6 // FIXME: https://codeberg.org/superseriousbusiness/gotosocial/issues/1876
instanceSourceURL = "https://codeberg.org/superseriousbusiness/gotosocial"
instanceMastodonVersion = "3.5.3"
)
@@ -1814,7 +1813,7 @@ func (c *Converter) InstanceToAPIV1Instance(ctx context.Context, i *gtsmodel.Ins
instance.Configuration.Polls.MaxExpiration = instancePollsMaxExpiration
instance.Configuration.Accounts.AllowCustomCSS = config.GetAccountsAllowCustomCSS()
instance.Configuration.Accounts.MaxFeaturedTags = instanceAccountsMaxFeaturedTags
- instance.Configuration.Accounts.MaxProfileFields = instanceAccountsMaxProfileFields
+ instance.Configuration.Accounts.MaxProfileFields = config.GetAccountsMaxProfileFields()
instance.Configuration.Emojis.EmojiSizeLimit = int(config.GetMediaEmojiLocalMaxSize()) // #nosec G115 -- Already validated.
instance.Configuration.OIDCEnabled = config.GetOIDCEnabled()
@@ -1992,7 +1991,7 @@ func (c *Converter) InstanceToAPIV2Instance(ctx context.Context, i *gtsmodel.Ins
instance.Configuration.Polls.MaxExpiration = instancePollsMaxExpiration
instance.Configuration.Accounts.AllowCustomCSS = config.GetAccountsAllowCustomCSS()
instance.Configuration.Accounts.MaxFeaturedTags = instanceAccountsMaxFeaturedTags
- instance.Configuration.Accounts.MaxProfileFields = instanceAccountsMaxProfileFields
+ instance.Configuration.Accounts.MaxProfileFields = config.GetAccountsMaxProfileFields()
instance.Configuration.Emojis.EmojiSizeLimit = int(config.GetMediaEmojiLocalMaxSize()) // #nosec G115 -- Already validated.
instance.Configuration.OIDCEnabled = config.GetOIDCEnabled()
diff --git a/internal/typeutils/internaltofrontend_test.go b/internal/typeutils/internaltofrontend_test.go
index 6a5503e83..74250769b 100644
--- a/internal/typeutils/internaltofrontend_test.go
+++ b/internal/typeutils/internaltofrontend_test.go
@@ -2517,7 +2517,7 @@ func (suite *InternalToFrontendTestSuite) TestInstanceV1ToFrontend() {
"accounts": {
"allow_custom_css": true,
"max_featured_tags": 10,
- "max_profile_fields": 6
+ "max_profile_fields": 8
},
"emojis": {
"emoji_size_limit": 51200
@@ -2621,7 +2621,7 @@ func (suite *InternalToFrontendTestSuite) TestInstanceV2ToFrontend() {
"accounts": {
"allow_custom_css": true,
"max_featured_tags": 10,
- "max_profile_fields": 6
+ "max_profile_fields": 8
},
"statuses": {
"max_characters": 5000,
diff --git a/internal/validate/formvalidation.go b/internal/validate/formvalidation.go
index 08fa23dcb..42c231491 100644
--- a/internal/validate/formvalidation.go
+++ b/internal/validate/formvalidation.go
@@ -42,7 +42,6 @@ const (
maximumUsernameLength = 64
maximumEmojiCategoryLength = 64
maximumProfileFieldLength = 255
- maximumProfileFields = 6
maximumListTitleLength = 200
maximumFilterKeywordLength = 40
maximumFilterTitleLength = 200
@@ -269,6 +268,7 @@ func ULID(i string, name string) error {
// and also iterates through the fields and trims each name + value
// to maximumProfileFieldLength, if they were above.
func ProfileFields(fields []*gtsmodel.Field) error {
+ maximumProfileFields := config.GetAccountsMaxProfileFields()
if len(fields) > maximumProfileFields {
return fmt.Errorf("cannot have more than %d profile fields", maximumProfileFields)
}
diff --git a/test/envparsing.sh b/test/envparsing.sh
index ccbc65cac..21abe5f51 100755
--- a/test/envparsing.sh
+++ b/test/envparsing.sh
@@ -7,6 +7,7 @@ EXPECT=$(cat << "EOF"
"account-domain": "peepee",
"accounts-allow-custom-css": true,
"accounts-custom-css-length": 5000,
+ "accounts-max-profile-fields": 8,
"accounts-reason-required": false,
"accounts-registration-backlog-limit": 100,
"accounts-registration-daily-limit": 50,
@@ -247,6 +248,7 @@ GTS_INSTANCE_LANGUAGES="nl,en-gb" \
GTS_INSTANCE_STATS_MODE="baffle" \
GTS_ACCOUNTS_ALLOW_CUSTOM_CSS=true \
GTS_ACCOUNTS_CUSTOM_CSS_LENGTH=5000 \
+GTS_ACCOUNTS_MAX_PROFILE_FIELDS=8 \
GTS_ACCOUNTS_REGISTRATION_BACKLOG_LIMIT=100 \
GTS_ACCOUNTS_REGISTRATION_DAILY_LIMIT=50 \
GTS_ACCOUNTS_REGISTRATION_OPEN=true \
diff --git a/testrig/config.go b/testrig/config.go
index 3e949ed89..3f8f22430 100644
--- a/testrig/config.go
+++ b/testrig/config.go
@@ -109,6 +109,7 @@ func testDefaults() config.Configuration {
AccountsRegistrationBacklogLimit: 20,
AccountsAllowCustomCSS: true,
AccountsCustomCSSLength: 10000,
+ AccountsMaxProfileFields: 8,
MediaDescriptionMinChars: 0,
MediaDescriptionMaxChars: 500,
diff --git a/web/template/about.tmpl b/web/template/about.tmpl
index 37d115256..c263d73a7 100644
--- a/web/template/about.tmpl
+++ b/web/template/about.tmpl
@@ -81,6 +81,11 @@ Polls can have up to
{{- .instance.Configuration.Polls.MaxCharactersPerOption }} characters per option.
{{- end -}}
+{{- define "profileLimits" -}}
+Profiles can have up to
+{{- .instance.Configuration.Accounts.MaxProfileFields }} profile fields.
+{{- end -}}
+
{{- with . }}