Skip to content

Commit a142034

Browse files
markwyldeClaude
and
Claude
committed
Add ALLOWED_ORG_VISIBILITY_MODES setting
Similar to ALLOWED_USER_VISIBILITY_MODES, this setting restricts which visibility modes (public, limited, private) can be selected for organizations. - Added new settings in service.go - Updated settings loading to parse the config - Modified org templates to filter visibility options - Added validation in controllers and service layer - Added translation for error message 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 27ff5e2 commit a142034

File tree

7 files changed

+94
-31
lines changed

7 files changed

+94
-31
lines changed

modules/setting/service.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ var Service = struct {
3232
AllowedUserVisibilityModesSlice AllowedVisibility `ini:"-"`
3333
DefaultOrgVisibility string
3434
DefaultOrgVisibilityMode structs.VisibleType
35+
AllowedOrgVisibilityModes []string
36+
AllowedOrgVisibilityModesSlice AllowedVisibility `ini:"-"`
3537
ActiveCodeLives int
3638
ResetPwdCodeLives int
3739
RegisterEmailConfirm bool
@@ -108,6 +110,7 @@ var Service = struct {
108110
}
109111
}{
110112
AllowedUserVisibilityModesSlice: []bool{true, true, true},
113+
AllowedOrgVisibilityModesSlice: []bool{true, true, true},
111114
}
112115

113116
// AllowedVisibility store in a 3 item bool array what is allowed
@@ -245,7 +248,34 @@ func loadServiceFrom(rootCfg ConfigProvider) {
245248
Service.DefaultUserVisibility = Service.AllowedUserVisibilityModes[0]
246249
}
247250
Service.DefaultUserVisibilityMode = structs.VisibilityModes[Service.DefaultUserVisibility]
248-
Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes))
251+
252+
// Process allowed organization visibility modes
253+
modes = sec.Key("ALLOWED_ORG_VISIBILITY_MODES").Strings(",")
254+
if len(modes) != 0 {
255+
Service.AllowedOrgVisibilityModes = []string{}
256+
Service.AllowedOrgVisibilityModesSlice = []bool{false, false, false}
257+
for _, sMode := range modes {
258+
if tp, ok := structs.VisibilityModes[sMode]; ok { // remove unsupported modes
259+
Service.AllowedOrgVisibilityModes = append(Service.AllowedOrgVisibilityModes, sMode)
260+
Service.AllowedOrgVisibilityModesSlice[tp] = true
261+
} else {
262+
log.Warn("ALLOWED_ORG_VISIBILITY_MODES %s is unsupported", sMode)
263+
}
264+
}
265+
}
266+
267+
if len(Service.AllowedOrgVisibilityModes) == 0 {
268+
Service.AllowedOrgVisibilityModes = []string{"public", "limited", "private"}
269+
Service.AllowedOrgVisibilityModesSlice = []bool{true, true, true}
270+
}
271+
272+
Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").String()
273+
if Service.DefaultOrgVisibility == "" {
274+
Service.DefaultOrgVisibility = Service.AllowedOrgVisibilityModes[0]
275+
} else if !Service.AllowedOrgVisibilityModesSlice[structs.VisibilityModes[Service.DefaultOrgVisibility]] {
276+
log.Warn("DEFAULT_ORG_VISIBILITY %s is wrong or not in ALLOWED_ORG_VISIBILITY_MODES, using first allowed", Service.DefaultOrgVisibility)
277+
Service.DefaultOrgVisibility = Service.AllowedOrgVisibilityModes[0]
278+
}
249279
Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility]
250280
Service.DefaultOrgMemberVisible = sec.Key("DEFAULT_ORG_MEMBER_VISIBLE").MustBool()
251281
Service.UserDeleteWithCommentsMaxTime = sec.Key("USER_DELETE_WITH_COMMENTS_MAX_TIME").MustDuration(0)

options/locale/locale_en-US.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2808,6 +2808,7 @@ team_unit_disabled = (Disabled)
28082808
form.name_reserved = The organization name "%s" is reserved.
28092809
form.name_pattern_not_allowed = The pattern "%s" is not allowed in an organization name.
28102810
form.create_org_not_allowed = You are not allowed to create an organization.
2811+
form.visibility_not_allowed = The selected visibility mode is not allowed.
28112812

28122813
settings = Settings
28132814
settings.options = Organization

routers/web/org/org.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func Create(ctx *context.Context) {
3333
}
3434

3535
ctx.Data["visibility"] = setting.Service.DefaultOrgVisibilityMode
36+
ctx.Data["AllowedOrgVisibilityModes"] = setting.Service.AllowedOrgVisibilityModesSlice.ToVisibleTypeSlice()
3637
ctx.Data["repo_admin_change_team_access"] = true
3738

3839
ctx.HTML(http.StatusOK, tplCreateOrg)
@@ -48,6 +49,13 @@ func CreatePost(ctx *context.Context) {
4849
return
4950
}
5051

52+
// Check if the visibility is allowed
53+
if !setting.Service.AllowedOrgVisibilityModesSlice.IsAllowedVisibility(form.Visibility) {
54+
ctx.Data["Err_OrgVisibility"] = true
55+
ctx.RenderWithErr(ctx.Tr("org.form.visibility_not_allowed"), tplCreateOrg, &form)
56+
return
57+
}
58+
5159
if ctx.HasError() {
5260
ctx.HTML(http.StatusOK, tplCreateOrg)
5361
return

routers/web/org/setting.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func Settings(ctx *context.Context) {
4747
ctx.Data["CurrentVisibility"] = ctx.Org.Organization.Visibility
4848
ctx.Data["RepoAdminChangeTeamAccess"] = ctx.Org.Organization.RepoAdminChangeTeamAccess
4949
ctx.Data["ContextUser"] = ctx.ContextUser
50+
ctx.Data["AllowedOrgVisibilityModes"] = setting.Service.AllowedOrgVisibilityModesSlice.ToVisibleTypeSlice()
5051

5152
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
5253
ctx.ServerError("RenderUserOrgHeader", err)
@@ -63,6 +64,14 @@ func SettingsPost(ctx *context.Context) {
6364
ctx.Data["PageIsOrgSettings"] = true
6465
ctx.Data["PageIsSettingsOptions"] = true
6566
ctx.Data["CurrentVisibility"] = ctx.Org.Organization.Visibility
67+
ctx.Data["AllowedOrgVisibilityModes"] = setting.Service.AllowedOrgVisibilityModesSlice.ToVisibleTypeSlice()
68+
69+
// Check if the visibility is allowed
70+
if !setting.Service.AllowedOrgVisibilityModesSlice.IsAllowedVisibility(form.Visibility) {
71+
ctx.Data["Err_Visibility"] = true
72+
ctx.RenderWithErr(ctx.Tr("org.form.visibility_not_allowed"), tplSettingsOptions, form)
73+
return
74+
}
6675

6776
if ctx.HasError() {
6877
ctx.HTML(http.StatusOK, tplSettingsOptions)

services/user/update.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) er
124124
if !u.IsOrganization() && !setting.Service.AllowedUserVisibilityModesSlice.IsAllowedVisibility(opts.Visibility.Value()) {
125125
return fmt.Errorf("visibility mode not allowed: %s", opts.Visibility.Value().String())
126126
}
127+
if u.IsOrganization() && !setting.Service.AllowedOrgVisibilityModesSlice.IsAllowedVisibility(opts.Visibility.Value()) {
128+
return fmt.Errorf("visibility mode not allowed for organization: %s", opts.Visibility.Value().String())
129+
}
127130
u.Visibility = opts.Visibility.Value()
128131

129132
cols = append(cols, "visibility")

templates/org/create.tmpl

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,24 @@
1717
<div class="inline field required {{if .Err_OrgVisibility}}error{{end}}">
1818
<label for="visibility">{{ctx.Locale.Tr "org.settings.visibility"}}</label>
1919
<div class="inline-right">
20-
<div class="ui radio checkbox">
21-
<input class="enable-system-radio" name="visibility" type="radio" value="0" {{if .visibility.IsPublic}}checked{{end}}>
22-
<label>{{ctx.Locale.Tr "org.settings.visibility.public"}}</label>
23-
</div>
24-
<div class="ui radio checkbox">
25-
<input class="enable-system-radio" name="visibility" type="radio" value="1" {{if .visibility.IsLimited}}checked{{end}}>
26-
<label>{{ctx.Locale.Tr "org.settings.visibility.limited"}}</label>
27-
</div>
28-
<div class="ui radio checkbox">
29-
<input class="enable-system-radio" name="visibility" type="radio" value="2" {{if .visibility.IsPrivate}}checked{{end}}>
30-
<label>{{ctx.Locale.Tr "org.settings.visibility.private"}}</label>
31-
</div>
20+
{{range $mode := .AllowedOrgVisibilityModes}}
21+
{{if $mode.IsPublic}}
22+
<div class="ui radio checkbox">
23+
<input class="enable-system-radio" name="visibility" type="radio" value="0" {{if $.visibility.IsPublic}}checked{{end}}>
24+
<label>{{ctx.Locale.Tr "org.settings.visibility.public"}}</label>
25+
</div>
26+
{{else if $mode.IsLimited}}
27+
<div class="ui radio checkbox">
28+
<input class="enable-system-radio" name="visibility" type="radio" value="1" {{if $.visibility.IsLimited}}checked{{end}}>
29+
<label>{{ctx.Locale.Tr "org.settings.visibility.limited"}}</label>
30+
</div>
31+
{{else if $mode.IsPrivate}}
32+
<div class="ui radio checkbox">
33+
<input class="enable-system-radio" name="visibility" type="radio" value="2" {{if $.visibility.IsPrivate}}checked{{end}}>
34+
<label>{{ctx.Locale.Tr "org.settings.visibility.private"}}</label>
35+
</div>
36+
{{end}}
37+
{{end}}
3238
</div>
3339
</div>
3440

templates/org/settings/options.tmpl

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,30 @@
3939
<div class="divider"></div>
4040
<div class="field" id="visibility_box">
4141
<label for="visibility">{{ctx.Locale.Tr "org.settings.visibility"}}</label>
42-
<div class="field">
43-
<div class="ui radio checkbox">
44-
<input class="enable-system-radio" name="visibility" type="radio" value="0" {{if eq .CurrentVisibility 0}}checked{{end}}>
45-
<label>{{ctx.Locale.Tr "org.settings.visibility.public"}}</label>
46-
</div>
47-
</div>
48-
<div class="field">
49-
<div class="ui radio checkbox">
50-
<input class="enable-system-radio" name="visibility" type="radio" value="1" {{if eq .CurrentVisibility 1}}checked{{end}}>
51-
<label>{{ctx.Locale.Tr "org.settings.visibility.limited"}}</label>
52-
</div>
53-
</div>
54-
<div class="field">
55-
<div class="ui radio checkbox">
56-
<input class="enable-system-radio" name="visibility" type="radio" value="2" {{if eq .CurrentVisibility 2}}checked{{end}}>
57-
<label>{{ctx.Locale.Tr "org.settings.visibility.private"}}</label>
58-
</div>
59-
</div>
42+
{{range $mode := .AllowedOrgVisibilityModes}}
43+
{{if $mode.IsPublic}}
44+
<div class="field">
45+
<div class="ui radio checkbox">
46+
<input class="enable-system-radio" name="visibility" type="radio" value="0" {{if eq $.CurrentVisibility 0}}checked{{end}}>
47+
<label>{{ctx.Locale.Tr "org.settings.visibility.public"}}</label>
48+
</div>
49+
</div>
50+
{{else if $mode.IsLimited}}
51+
<div class="field">
52+
<div class="ui radio checkbox">
53+
<input class="enable-system-radio" name="visibility" type="radio" value="1" {{if eq $.CurrentVisibility 1}}checked{{end}}>
54+
<label>{{ctx.Locale.Tr "org.settings.visibility.limited"}}</label>
55+
</div>
56+
</div>
57+
{{else if $mode.IsPrivate}}
58+
<div class="field">
59+
<div class="ui radio checkbox">
60+
<input class="enable-system-radio" name="visibility" type="radio" value="2" {{if eq $.CurrentVisibility 2}}checked{{end}}>
61+
<label>{{ctx.Locale.Tr "org.settings.visibility.private"}}</label>
62+
</div>
63+
</div>
64+
{{end}}
65+
{{end}}
6066
</div>
6167

6268
<div class="field" id="permission_box">

0 commit comments

Comments
 (0)