diff --git a/models/organization/team.go b/models/organization/team.go index ff33b799853..b419aa32252 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -117,8 +117,8 @@ func (t *Team) CanNonMemberReadMeta(ctx context.Context, org, doer *user_model.U } } -func NormalizeTeamVisibility(s string) structs.VisibleType { - if vt, ok := structs.VisibilityModes[s]; ok { +func NormalizeTeamVisibility[T ~string](v T) structs.VisibleType { + if vt, ok := structs.VisibilityModes[structs.VisibilityString(v)]; ok { return vt } return structs.VisibleTypePrivate diff --git a/modules/setting/service.go b/modules/setting/service.go index b578ce4d2e6..ad5c73556e9 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -25,12 +25,9 @@ const ( // Service settings var Service = struct { - DefaultUserVisibility string - DefaultUserVisibilityMode structs.VisibleType - AllowedUserVisibilityModes []string - AllowedUserVisibilityModesSlice AllowedVisibility `ini:"-"` - DefaultOrgVisibility string - DefaultOrgVisibilityMode structs.VisibleType + DefaultUserVisibilityMode structs.VisibleType `ini:"-"` + AllowedUserVisibilityModesSlice AllowedVisibility `ini:"-"` + DefaultOrgVisibilityMode structs.VisibleType `ini:"-"` ActiveCodeLives int ResetPwdCodeLives int RegisterEmailConfirm bool @@ -217,36 +214,35 @@ func loadServiceFrom(rootCfg ConfigProvider) { Service.EnableUserHeatmap = sec.Key("ENABLE_USER_HEATMAP").MustBool(true) Service.AutoWatchNewRepos = sec.Key("AUTO_WATCH_NEW_REPOS").MustBool(true) Service.AutoWatchOnChanges = sec.Key("AUTO_WATCH_ON_CHANGES").MustBool(false) - modes := sec.Key("ALLOWED_USER_VISIBILITY_MODES").Strings(",") - if len(modes) != 0 { - Service.AllowedUserVisibilityModes = []string{} - Service.AllowedUserVisibilityModesSlice = []bool{false, false, false} - for _, sMode := range modes { - if tp, ok := structs.VisibilityModes[sMode]; ok { // remove unsupported modes - Service.AllowedUserVisibilityModes = append(Service.AllowedUserVisibilityModes, sMode) - Service.AllowedUserVisibilityModesSlice[tp] = true - } else { - log.Warn("ALLOWED_USER_VISIBILITY_MODES %s is unsupported", sMode) - } + + Service.AllowedUserVisibilityModesSlice = AllowedVisibility{false, false, false} + var allowedUserVisibilityModes []structs.VisibilityString + for _, allowedMode := range sec.Key("ALLOWED_USER_VISIBILITY_MODES").Strings(",") { + if tp, ok := structs.VisibilityModes[structs.VisibilityString(allowedMode)]; ok { // remove unsupported modes + allowedUserVisibilityModes = append(allowedUserVisibilityModes, structs.VisibilityString(allowedMode)) + Service.AllowedUserVisibilityModesSlice[tp] = true + } else { + log.Warn("ALLOWED_USER_VISIBILITY_MODES %s is unsupported", allowedMode) } } - - if len(Service.AllowedUserVisibilityModes) == 0 { - Service.AllowedUserVisibilityModes = []string{"public", "limited", "private"} - Service.AllowedUserVisibilityModesSlice = []bool{true, true, true} + if len(allowedUserVisibilityModes) == 0 { + allowedUserVisibilityModes = []structs.VisibilityString{structs.VisibilityStringPublic, structs.VisibilityStringLimited, structs.VisibilityStringPrivate} + Service.AllowedUserVisibilityModesSlice = AllowedVisibility{true, true, true} } - Service.DefaultUserVisibility = sec.Key("DEFAULT_USER_VISIBILITY").String() - if Service.DefaultUserVisibility == "" { - Service.DefaultUserVisibility = Service.AllowedUserVisibilityModes[0] - } else if !Service.AllowedUserVisibilityModesSlice[structs.VisibilityModes[Service.DefaultUserVisibility]] { - log.Warn("DEFAULT_USER_VISIBILITY %s is wrong or not in ALLOWED_USER_VISIBILITY_MODES, using first allowed", Service.DefaultUserVisibility) - Service.DefaultUserVisibility = Service.AllowedUserVisibilityModes[0] + defaultUserVisibility := structs.VisibilityString(sec.Key("DEFAULT_USER_VISIBILITY").String()) + if defaultUserVisibility == "" { + defaultUserVisibility = allowedUserVisibilityModes[0] + } else if vt, ok := structs.VisibilityModes[defaultUserVisibility]; !ok || !Service.AllowedUserVisibilityModesSlice[vt] { + log.Warn("DEFAULT_USER_VISIBILITY %s is wrong or not in ALLOWED_USER_VISIBILITY_MODES, using first allowed", defaultUserVisibility) + defaultUserVisibility = allowedUserVisibilityModes[0] } - Service.DefaultUserVisibilityMode = structs.VisibilityModes[Service.DefaultUserVisibility] - Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes)) - Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility] + Service.DefaultUserVisibilityMode = structs.VisibilityModes[defaultUserVisibility] + + defaultOrgVisibility := structs.VisibilityString(sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.VisibilityModeKeys())) + Service.DefaultOrgVisibilityMode = structs.VisibilityModes[defaultOrgVisibility] Service.DefaultOrgMemberVisible = sec.Key("DEFAULT_ORG_MEMBER_VISIBLE").MustBool() + Service.UserDeleteWithCommentsMaxTime = sec.Key("USER_DELETE_WITH_COMMENTS_MAX_TIME").MustDuration(0) sec.Key("VALID_SITE_URL_SCHEMES").MustString("http,https") Service.ValidSiteURLSchemes = sec.Key("VALID_SITE_URL_SCHEMES").Strings(",") diff --git a/modules/setting/service_test.go b/modules/setting/service_test.go index 4358f0db679..1527d4f263b 100644 --- a/modules/setting/service_test.go +++ b/modules/setting/service_test.go @@ -48,80 +48,83 @@ EMAIL_DOMAIN_BLOCKLIST = d3, *.b func TestLoadServiceVisibilityModes(t *testing.T) { defer test.MockVariableValue(&Service)() - kases := map[string]func(){ + visibleTypeSlice := func(s ...structs.VisibilityString) (ret []structs.VisibleType) { + for _, v := range s { + ret = append(ret, structs.VisibilityModes[v]) + } + return ret + } + testCases := map[string]func(){ ` [service] DEFAULT_USER_VISIBILITY = public ALLOWED_USER_VISIBILITY_MODES = public,limited,private `: func() { - assert.Equal(t, "public", Service.DefaultUserVisibility) assert.Equal(t, structs.VisibleTypePublic, Service.DefaultUserVisibilityMode) - assert.Equal(t, []string{"public", "limited", "private"}, Service.AllowedUserVisibilityModes) + assert.Equal(t, visibleTypeSlice("public", "limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()) }, ` [service] DEFAULT_USER_VISIBILITY = public `: func() { - assert.Equal(t, "public", Service.DefaultUserVisibility) assert.Equal(t, structs.VisibleTypePublic, Service.DefaultUserVisibilityMode) - assert.Equal(t, []string{"public", "limited", "private"}, Service.AllowedUserVisibilityModes) + assert.Equal(t, visibleTypeSlice("public", "limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()) }, ` [service] DEFAULT_USER_VISIBILITY = limited `: func() { - assert.Equal(t, "limited", Service.DefaultUserVisibility) assert.Equal(t, structs.VisibleTypeLimited, Service.DefaultUserVisibilityMode) - assert.Equal(t, []string{"public", "limited", "private"}, Service.AllowedUserVisibilityModes) + assert.Equal(t, visibleTypeSlice("public", "limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()) }, ` [service] ALLOWED_USER_VISIBILITY_MODES = public,limited,private `: func() { - assert.Equal(t, "public", Service.DefaultUserVisibility) assert.Equal(t, structs.VisibleTypePublic, Service.DefaultUserVisibilityMode) - assert.Equal(t, []string{"public", "limited", "private"}, Service.AllowedUserVisibilityModes) + assert.Equal(t, visibleTypeSlice("public", "limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()) }, ` [service] DEFAULT_USER_VISIBILITY = public ALLOWED_USER_VISIBILITY_MODES = limited,private `: func() { - assert.Equal(t, "limited", Service.DefaultUserVisibility) assert.Equal(t, structs.VisibleTypeLimited, Service.DefaultUserVisibilityMode) - assert.Equal(t, []string{"limited", "private"}, Service.AllowedUserVisibilityModes) + assert.Equal(t, visibleTypeSlice("limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()) }, ` [service] DEFAULT_USER_VISIBILITY = my_type ALLOWED_USER_VISIBILITY_MODES = limited,private `: func() { - assert.Equal(t, "limited", Service.DefaultUserVisibility) assert.Equal(t, structs.VisibleTypeLimited, Service.DefaultUserVisibilityMode) - assert.Equal(t, []string{"limited", "private"}, Service.AllowedUserVisibilityModes) + assert.Equal(t, visibleTypeSlice("limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()) + }, + ` +[service] +DEFAULT_USER_VISIBILITY = my_type +`: func() { + assert.Equal(t, structs.VisibleTypePublic, Service.DefaultUserVisibilityMode) + assert.Equal(t, visibleTypeSlice("public", "limited", "private"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()) }, ` [service] DEFAULT_USER_VISIBILITY = public ALLOWED_USER_VISIBILITY_MODES = public, limit, privated `: func() { - assert.Equal(t, "public", Service.DefaultUserVisibility) assert.Equal(t, structs.VisibleTypePublic, Service.DefaultUserVisibilityMode) - assert.Equal(t, []string{"public"}, Service.AllowedUserVisibilityModes) + assert.Equal(t, visibleTypeSlice("public"), Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()) }, } - for kase, fun := range kases { - t.Run(kase, func(t *testing.T) { - cfg, err := NewConfigProviderFromData(kase) + for tc, fn := range testCases { + t.Run(tc, func(t *testing.T) { + Service.AllowedUserVisibilityModesSlice = []bool{true, true, true} + Service.DefaultUserVisibilityMode = structs.VisibleTypePublic + cfg, err := NewConfigProviderFromData(tc) assert.NoError(t, err) loadServiceFrom(cfg) - fun() - // reset - Service.AllowedUserVisibilityModesSlice = []bool{true, true, true} - Service.AllowedUserVisibilityModes = []string{} - Service.DefaultUserVisibility = "" - Service.DefaultUserVisibilityMode = structs.VisibleTypePublic + fn() }) } } diff --git a/modules/structs/admin_user.go b/modules/structs/admin_user.go index aa4f7550054..4fd10aa5805 100644 --- a/modules/structs/admin_user.go +++ b/modules/structs/admin_user.go @@ -29,7 +29,7 @@ type CreateUserOption struct { // Whether the user has restricted access privileges Restricted *bool `json:"restricted"` // User visibility level: public, limited, or private - Visibility UserVisibility `json:"visibility" binding:"In(,public,limited,private)"` + Visibility VisibilityString `json:"visibility" binding:"In(,public,limited,private)"` // For explicitly setting the user creation timestamp. Useful when users are // migrated from other systems. When omitted, the user's creation timestamp @@ -78,5 +78,5 @@ type EditUserOption struct { // Whether the user has restricted access privileges Restricted *bool `json:"restricted"` // User visibility level: public, limited, or private - Visibility UserVisibility `json:"visibility" binding:"In(,public,limited,private)"` + Visibility VisibilityString `json:"visibility" binding:"In(,public,limited,private)"` } diff --git a/modules/structs/org.go b/modules/structs/org.go index b93f68b6009..162a47904ff 100644 --- a/modules/structs/org.go +++ b/modules/structs/org.go @@ -22,7 +22,7 @@ type Organization struct { // The location of the organization Location string `json:"location"` // The visibility level of the organization (public, limited, private) - Visibility UserVisibility `json:"visibility"` + Visibility VisibilityString `json:"visibility"` // Whether repository administrators can change team access RepoAdminChangeTeamAccess bool `json:"repo_admin_change_team_access"` // username of the organization @@ -60,7 +60,7 @@ type CreateOrgOption struct { // The location of the organization Location string `json:"location" binding:"MaxSize(50)"` // possible values are `public` (default), `limited` or `private` - Visibility UserVisibility `json:"visibility" binding:"In(,public,limited,private)"` + Visibility VisibilityString `json:"visibility" binding:"In(,public,limited,private)"` // Whether repository administrators can change team access RepoAdminChangeTeamAccess bool `json:"repo_admin_change_team_access"` } @@ -78,7 +78,7 @@ type EditOrgOption struct { // The location of the organization Location *string `json:"location" binding:"MaxSize(50)"` // possible values are `public`, `limited` or `private` - Visibility *UserVisibility `json:"visibility" binding:"In(,public,limited,private)"` + Visibility *VisibilityString `json:"visibility" binding:"In(,public,limited,private)"` // Whether repository administrators can change team access RepoAdminChangeTeamAccess *bool `json:"repo_admin_change_team_access"` } diff --git a/modules/structs/user.go b/modules/structs/user.go index 852d2c4bdd4..1c1fc68f8b8 100644 --- a/modules/structs/user.go +++ b/modules/structs/user.go @@ -51,7 +51,7 @@ type User struct { // the user's description Description string `json:"description"` // User visibility level option: public, limited, private - Visibility UserVisibility `json:"visibility"` + Visibility VisibilityString `json:"visibility"` // user counts Followers int `json:"followers_count"` diff --git a/modules/structs/visible_type.go b/modules/structs/visible_type.go index f537884963d..5031809e74e 100644 --- a/modules/structs/visible_type.go +++ b/modules/structs/visible_type.go @@ -18,10 +18,10 @@ const ( ) // VisibilityModes is a map of Visibility types -var VisibilityModes = map[string]VisibleType{ - "public": VisibleTypePublic, - "limited": VisibleTypeLimited, - "private": VisibleTypePrivate, +var VisibilityModes = map[VisibilityString]VisibleType{ + VisibilityStringPublic: VisibleTypePublic, + VisibilityStringLimited: VisibleTypeLimited, + VisibilityStringPrivate: VisibleTypePrivate, } // IsPublic returns true if VisibleType is public @@ -43,27 +43,27 @@ func (vt VisibleType) IsPrivate() bool { func (vt VisibleType) String() string { for k, v := range VisibilityModes { if vt == v { - return k + return string(k) } } return "" } -// ExtractKeysFromMapString provides a slice of keys from map -func ExtractKeysFromMapString(in map[string]VisibleType) (keys []string) { - for k := range in { - keys = append(keys, k) +// VisibilityModeKeys returns the visibility mode names (public, limited, private) +func VisibilityModeKeys() (keys []string) { + for k := range VisibilityModes { + keys = append(keys, string(k)) } return keys } -// UserVisibility defines the visibility level of a user or organization as -// rendered in API payloads. The DB representation is VisibleType (int). -// swagger:enum UserVisibility -type UserVisibility string +// VisibilityString defines the visibility level of a user/organization/team as +// rendered in API and config payloads. The DB representation is VisibleType (int). +// swagger:enum VisibilityString +type VisibilityString string const ( - UserVisibilityPublic UserVisibility = "public" - UserVisibilityLimited UserVisibility = "limited" - UserVisibilityPrivate UserVisibility = "private" + VisibilityStringPublic VisibilityString = "public" + VisibilityStringLimited VisibilityString = "limited" + VisibilityStringPrivate VisibilityString = "private" ) diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index 055933bf3c2..587d166caee 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -3306,7 +3306,6 @@ "admin.config.default_enable_timetracking": "Enable Time Tracking by Default", "admin.config.default_allow_only_contributors_to_track_time": "Let Only Contributors Track Time", "admin.config.no_reply_address": "Hidden Email Domain", - "admin.config.default_visibility_organization": "Default visibility for new Organizations", "admin.config.default_enable_dependencies": "Enable Issue Dependencies by Default", "admin.config.webhook_config": "Webhook Configuration", "admin.config.queue_length": "Queue Length", diff --git a/routers/api/v1/admin/org.go b/routers/api/v1/admin/org.go index 4713c7a1c78..2e1262589d5 100644 --- a/routers/api/v1/admin/org.go +++ b/routers/api/v1/admin/org.go @@ -48,7 +48,7 @@ func CreateOrg(ctx *context.APIContext) { visibility := api.VisibleTypePublic if form.Visibility != "" { - visibility = api.VisibilityModes[string(form.Visibility)] + visibility = api.VisibilityModes[form.Visibility] } org := &organization.Organization{ diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 9441fe0c18e..ec0d5eb3ced 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -121,7 +121,7 @@ func CreateUser(ctx *context.APIContext) { } if form.Visibility != "" { - visibility := api.VisibilityModes[string(form.Visibility)] + visibility := api.VisibilityModes[form.Visibility] overwriteDefault.Visibility = &visibility } @@ -237,7 +237,7 @@ func EditUser(ctx *context.APIContext) { Description: optional.FromPtr(form.Description), IsActive: optional.FromPtr(form.Active), IsAdmin: user_service.UpdateOptionFieldFromPtr(form.Admin), - Visibility: optional.FromMapLookup(api.VisibilityModes, string(form.Visibility)), + Visibility: optional.FromMapLookup(api.VisibilityModes, form.Visibility), AllowGitHook: optional.FromPtr(form.AllowGitHook), AllowImportLocal: optional.FromPtr(form.AllowImportLocal), MaxRepoCreation: optional.FromPtr(form.MaxRepoCreation), @@ -469,7 +469,7 @@ func SearchUsers(ctx *context.APIContext) { var visible []api.VisibleType visibilityParam := ctx.FormString("visibility") - if visibility, ok := api.VisibilityModes[visibilityParam]; ok { + if visibility, ok := api.VisibilityModes[api.VisibilityString(visibilityParam)]; ok { visible = []api.VisibleType{visibility} } else if visibilityParam != "" { ctx.APIError(http.StatusUnprocessableEntity, "invalid visibility") diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index c4f513d0bbe..196b1c0fc92 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -269,7 +269,7 @@ func Create(ctx *context.APIContext) { visibility := api.VisibleTypePublic if form.Visibility != "" { - visibility = api.VisibilityModes[string(form.Visibility)] + visibility = api.VisibilityModes[form.Visibility] } org := &organization.Organization{ @@ -413,7 +413,7 @@ func Edit(ctx *context.APIContext) { Description: optional.FromPtr(form.Description), Website: optional.FromPtr(form.Website), Location: optional.FromPtr(form.Location), - Visibility: optional.FromMapLookup(api.VisibilityModes, string(optional.FromPtr(form.Visibility).Value())), + Visibility: optional.FromMapLookup(api.VisibilityModes, optional.FromPtr(form.Visibility).Value()), RepoAdminChangeTeamAccess: optional.FromPtr(form.RepoAdminChangeTeamAccess), } if err := user_service.UpdateUser(ctx, ctx.Org.Organization.AsUser(), opts); err != nil { diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index 5d64a9164aa..f57b997a152 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -223,7 +223,7 @@ func CreateTeam(ctx *context.APIContext) { IncludesAllRepositories: form.IncludesAllRepositories, CanCreateOrgRepo: form.CanCreateOrgRepo, AccessMode: teamPermission, - Visibility: organization.NormalizeTeamVisibility(string(form.Visibility)), + Visibility: organization.NormalizeTeamVisibility(form.Visibility), } if team.AccessMode < perm.AccessModeAdmin { @@ -302,7 +302,7 @@ func EditTeam(ctx *context.APIContext) { } if form.Visibility != nil && !team.IsOwnerTeam() { - team.Visibility = organization.NormalizeTeamVisibility(string(*form.Visibility)) + team.Visibility = organization.NormalizeTeamVisibility(*form.Visibility) } isAuthChanged := false diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 2dafe88cc50..9e656350d2c 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -235,9 +235,10 @@ func SettingsRenamePost(ctx *context.Context) { // SettingsChangeVisibilityPost response for change organization visibility func SettingsChangeVisibilityPost(ctx *context.Context) { - visibility, ok := structs.VisibilityModes[ctx.FormString("visibility")] + visibilityStr := ctx.FormString("visibility") + visibility, ok := structs.VisibilityModes[structs.VisibilityString(visibilityStr)] if !ok { - ctx.Flash.Error(ctx.Tr("invalid_data", visibility)) + ctx.Flash.Error(ctx.Tr("invalid_data", visibilityStr)) ctx.JSONRedirect(setting.AppSubURL + "/org/" + url.PathEscape(ctx.Org.Organization.Name) + "/settings") return } diff --git a/services/convert/convert.go b/services/convert/convert.go index 140af9ffa34..3122cd931fd 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -864,7 +864,7 @@ func ToOrganization(ctx context.Context, org *organization.Organization) *api.Or Description: org.Description, Website: org.Website, Location: org.Location, - Visibility: api.UserVisibility(org.Visibility.String()), + Visibility: api.VisibilityString(org.Visibility.String()), RepoAdminChangeTeamAccess: org.RepoAdminChangeTeamAccess, } } diff --git a/services/convert/user.go b/services/convert/user.go index 525eb46818a..d9ed124f04b 100644 --- a/services/convert/user.go +++ b/services/convert/user.go @@ -65,7 +65,7 @@ func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *ap StarredRepos: user.NumStars, } - result.Visibility = api.UserVisibility(user.Visibility.String()) + result.Visibility = api.VisibilityString(user.Visibility.String()) // hide primary email if API caller is anonymous or user keep email private if signed && (!user.KeepEmailPrivate || authed) { diff --git a/services/convert/user_test.go b/services/convert/user_test.go index 3ef7609f042..c42fc1455f4 100644 --- a/services/convert/user_test.go +++ b/services/convert/user_test.go @@ -29,11 +29,11 @@ func TestUser_ToUser(t *testing.T) { apiUser = toUser(t.Context(), user1, false, false) assert.False(t, apiUser.IsAdmin) - assert.Equal(t, api.UserVisibilityPublic, apiUser.Visibility) + assert.Equal(t, api.VisibilityStringPublic, apiUser.Visibility) user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31, IsAdmin: false, Visibility: api.VisibleTypePrivate}) apiUser = toUser(t.Context(), user31, true, true) assert.False(t, apiUser.IsAdmin) - assert.Equal(t, api.UserVisibilityPrivate, apiUser.Visibility) + assert.Equal(t, api.VisibilityStringPrivate, apiUser.Visibility) } diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index ae37950fb51..14fbf448fab 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -155,8 +155,6 @@
{{ctx.Locale.Tr "admin.config.default_allow_only_contributors_to_track_time"}}
{{svg (Iif .Service.DefaultAllowOnlyContributorsToTrackTime "octicon-check" "octicon-x")}}
{{end}} -
{{ctx.Locale.Tr "admin.config.default_visibility_organization"}}
-
{{.Service.DefaultOrgVisibility}}
{{ctx.Locale.Tr "admin.config.no_reply_address"}}
{{if .Service.NoReplyAddress}}{{.Service.NoReplyAddress}}{{else}}-{{end}}
diff --git a/templates/swagger/openapi-viewer.tmpl b/templates/swagger/openapi-viewer.tmpl index 2e3e9bf1499..d329fe75007 100644 --- a/templates/swagger/openapi-viewer.tmpl +++ b/templates/swagger/openapi-viewer.tmpl @@ -4,13 +4,17 @@ {{ctx.HeadMetaContentSecurityPolicy}} Gitea API - {{/* HINT: SWAGGER-CSS-IMPORT: load swagger styles ahead to avoid flicker (e.g. the swagger-back-link) */}} + {{/* HINT: SWAGGER-CSS-IMPORT: load swagger styles ahead to avoid flicker (e.g. the swagger-page-links) */}} {{AssetCSSLinks "web_src/js/swagger.ts" "web_src/css/swagger-standalone.css"}} {{/* TODO: add Help & Glossary to help users understand the API, and explain some concepts like "Owner" */}} - {{svg "octicon-reply"}}{{ctx.Locale.Tr "return_to_gitea"}} -
+ +
{{ctx.ScriptImport "web_src/js/swagger.ts" "module"}} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 7d19ba86754..ad7f387e1e2 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -24561,7 +24561,7 @@ "limited", "private" ], - "x-go-enum-desc": "public UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate", + "x-go-enum-desc": "public VisibilityStringPublic\nlimited VisibilityStringLimited\nprivate VisibilityStringPrivate", "x-go-name": "Visibility" }, "website": { @@ -25131,7 +25131,7 @@ "limited", "private" ], - "x-go-enum-desc": "public UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate", + "x-go-enum-desc": "public VisibilityStringPublic\nlimited VisibilityStringLimited\nprivate VisibilityStringPrivate", "x-go-name": "Visibility" } }, @@ -25833,7 +25833,7 @@ "limited", "private" ], - "x-go-enum-desc": "public UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate", + "x-go-enum-desc": "public VisibilityStringPublic\nlimited VisibilityStringLimited\nprivate VisibilityStringPrivate", "x-go-name": "Visibility" }, "website": { @@ -26375,7 +26375,7 @@ "limited", "private" ], - "x-go-enum-desc": "public UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate", + "x-go-enum-desc": "public VisibilityStringPublic\nlimited VisibilityStringLimited\nprivate VisibilityStringPrivate", "x-go-name": "Visibility" }, "website": { @@ -28227,7 +28227,7 @@ "limited", "private" ], - "x-go-enum-desc": "public UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate", + "x-go-enum-desc": "public VisibilityStringPublic\nlimited VisibilityStringLimited\nprivate VisibilityStringPrivate", "x-go-name": "Visibility" }, "website": { @@ -30590,7 +30590,7 @@ "limited", "private" ], - "x-go-enum-desc": "public UserVisibilityPublic\nlimited UserVisibilityLimited\nprivate UserVisibilityPrivate", + "x-go-enum-desc": "public VisibilityStringPublic\nlimited VisibilityStringLimited\nprivate VisibilityStringPrivate", "x-go-name": "Visibility" }, "website": { diff --git a/templates/swagger/v1_openapi3_json.tmpl b/templates/swagger/v1_openapi3_json.tmpl index 1f9539527ef..559aaee0667 100644 --- a/templates/swagger/v1_openapi3_json.tmpl +++ b/templates/swagger/v1_openapi3_json.tmpl @@ -4304,7 +4304,7 @@ "visibility": { "allOf": [ { - "$ref": "#/components/schemas/UserVisibility" + "$ref": "#/components/schemas/VisibilityString" } ], "description": "possible values are `public` (default), `limited` or `private`" @@ -4845,7 +4845,7 @@ "visibility": { "allOf": [ { - "$ref": "#/components/schemas/UserVisibility" + "$ref": "#/components/schemas/VisibilityString" } ], "description": "User visibility level: public, limited, or private" @@ -5549,7 +5549,7 @@ "visibility": { "allOf": [ { - "$ref": "#/components/schemas/UserVisibility" + "$ref": "#/components/schemas/VisibilityString" } ], "description": "possible values are `public`, `limited` or `private`" @@ -6075,7 +6075,7 @@ "visibility": { "allOf": [ { - "$ref": "#/components/schemas/UserVisibility" + "$ref": "#/components/schemas/VisibilityString" } ], "description": "User visibility level: public, limited, or private" @@ -7949,7 +7949,7 @@ "visibility": { "allOf": [ { - "$ref": "#/components/schemas/UserVisibility" + "$ref": "#/components/schemas/VisibilityString" } ], "description": "The visibility level of the organization (public, limited, private)" @@ -10343,7 +10343,7 @@ "visibility": { "allOf": [ { - "$ref": "#/components/schemas/UserVisibility" + "$ref": "#/components/schemas/VisibilityString" } ], "description": "User visibility level option: public, limited, private" @@ -10496,7 +10496,7 @@ "type": "object", "x-go-package": "gitea.dev/modules/structs" }, - "UserVisibility": { + "VisibilityString": { "enum": [ "public", "limited", diff --git a/tests/integration/api_org_test.go b/tests/integration/api_org_test.go index f0250c5d5a5..7d048d8788c 100644 --- a/tests/integration/api_org_test.go +++ b/tests/integration/api_org_test.go @@ -128,7 +128,7 @@ func testAPIOrgGeneral(t *testing.T) { apiOrgList := DecodeJSON(t, resp, []*api.Organization{}) assert.Len(t, apiOrgList, 13) assert.Equal(t, "Limited Org 36", apiOrgList[1].FullName) - assert.Equal(t, api.UserVisibilityLimited, apiOrgList[1].Visibility) + assert.Equal(t, api.VisibilityStringLimited, apiOrgList[1].Visibility) // accessing without a token will return only public orgs req = NewRequest(t, "GET", "/api/v1/orgs") @@ -137,7 +137,7 @@ func testAPIOrgGeneral(t *testing.T) { apiOrgList = DecodeJSON(t, resp, []*api.Organization{}) assert.Len(t, apiOrgList, 9) assert.Equal(t, "org 17", apiOrgList[0].FullName) - assert.Equal(t, api.UserVisibilityPublic, apiOrgList[0].Visibility) + assert.Equal(t, api.VisibilityStringPublic, apiOrgList[0].Visibility) }) t.Run("OrgEdit", func(t *testing.T) { @@ -149,7 +149,7 @@ func testAPIOrgGeneral(t *testing.T) { Description: new("new description"), Website: new("https://org3-new-website.example.com"), Location: new("new location"), - Visibility: new(api.UserVisibilityLimited), + Visibility: new(api.VisibilityStringLimited), Email: new("org3-new-email@example.com"), } req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org3Edit).AddTokenAuth(user1Token) @@ -179,7 +179,7 @@ func testAPIOrgGeneral(t *testing.T) { t.Run("OrgEditInvalidVisibility", func(t *testing.T) { org := api.EditOrgOption{ - Visibility: new(api.UserVisibility("invalid-visibility")), + Visibility: new(api.VisibilityString("invalid-visibility")), } req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org).AddTokenAuth(user1Token) MakeRequest(t, req, http.StatusUnprocessableEntity) diff --git a/tests/integration/api_user_search_test.go b/tests/integration/api_user_search_test.go index 2e8e552a1a4..5cbf62ebec9 100644 --- a/tests/integration/api_user_search_test.go +++ b/tests/integration/api_user_search_test.go @@ -47,7 +47,7 @@ func TestAPIUserSearchLoggedIn(t *testing.T) { for _, user := range results.Data { assert.Contains(t, user.UserName, query) assert.NotEmpty(t, user.Email) - assert.Equal(t, api.UserVisibilityPublic, user.Visibility) + assert.Equal(t, api.VisibilityStringPublic, user.Visibility) } } @@ -103,7 +103,7 @@ func TestAPIUserSearchAdminLoggedInUserHidden(t *testing.T) { for _, user := range results.Data { assert.Contains(t, user.UserName, query) assert.NotEmpty(t, user.Email) - assert.Equal(t, api.UserVisibilityPrivate, user.Visibility) + assert.Equal(t, api.VisibilityStringPrivate, user.Visibility) } } diff --git a/web_src/css/swagger-standalone.css b/web_src/css/swagger-standalone.css index ae36ab49cf5..ad5aefc2178 100644 --- a/web_src/css/swagger-standalone.css +++ b/web_src/css/swagger-standalone.css @@ -4,26 +4,57 @@ body { margin: 0; } -.swagger-back-link { - color: var(--color-primary); - text-decoration: none; +.swagger-page-links { + /* overlay the top-right of the info block by replicating swagger-ui's ".wrapper" and ".info" metrics */ position: absolute; - top: 1rem; - right: 1.5rem; + top: 50px; + left: 0; + right: 0; + max-width: 1460px; + margin: 0 auto; + padding: 0 20px; + box-sizing: border-box; display: flex; + justify-content: flex-end; + gap: 8px; + font-family: sans-serif; + font-size: 14px; + pointer-events: none; /* only the links themselves are clickable */ +} + +/* below this width the links would overlap the title, flow above swagger-ui instead */ +@media (max-width: 991.98px) { + .swagger-page-links { + position: static; + padding: 10px 20px 0; + flex-wrap: wrap; + } +} + +/* mimic the regular gitea button, the main site CSS is not loaded on this page */ +.swagger-page-links a { + pointer-events: auto; + display: inline-flex; align-items: center; + gap: 6px; + height: 32px; + padding: 0 12px; + border-radius: 4px; + background: var(--color-button); + border: 1px solid var(--color-light-border); + color: var(--color-text); + text-decoration: none; + white-space: nowrap; } -.swagger-back-link:hover { - text-decoration: underline; +.swagger-page-links a:hover { + background: var(--color-hover); } -.swagger-back-link svg { - color: inherit; +.swagger-page-links a:active { + background: var(--color-active); +} + +.swagger-page-links svg { fill: currentcolor; - margin-right: 0.5rem; -} - -.swagger-spec-content { - display: none; }