@@ -345,8 +345,14 @@ func runWeb(ctx *cli.Context) error { | |||||
// ***** START: Organization ***** | // ***** START: Organization ***** | ||||
m.Group("/org", func() { | m.Group("/org", func() { | ||||
m.Get("/create", org.Create) | |||||
m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost) | |||||
m.Group("", func() { | |||||
m.Get("/create", org.Create) | |||||
m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost) | |||||
}, func(ctx *context.Context) { | |||||
if !ctx.User.CanCreateOrganization() { | |||||
ctx.NotFound() | |||||
} | |||||
}) | |||||
m.Group("/:org", func() { | m.Group("/:org", func() { | ||||
m.Get("/dashboard", user.Dashboard) | m.Get("/dashboard", user.Dashboard) | ||||
@@ -163,6 +163,8 @@ ISSUE_INDEXER_PATH = indexers/issues.bleve | |||||
UPDATE_BUFFER_LEN = 20 | UPDATE_BUFFER_LEN = 20 | ||||
[admin] | [admin] | ||||
; Disable regular (non-admin) users to create organizations | |||||
DISABLE_REGULAR_ORG_CREATION = false | |||||
[security] | [security] | ||||
; Whether the installer is disabled | ; Whether the installer is disabled | ||||
@@ -223,7 +223,7 @@ func (u *User) CanCreateRepo() bool { | |||||
// CanCreateOrganization returns true if user can create organisation. | // CanCreateOrganization returns true if user can create organisation. | ||||
func (u *User) CanCreateOrganization() bool { | func (u *User) CanCreateOrganization() bool { | ||||
return u.IsAdmin || u.AllowCreateOrganization | |||||
return u.IsAdmin || (u.AllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation) | |||||
} | } | ||||
// CanEditGitHook returns true if user can edit Git hooks. | // CanEditGitHook returns true if user can edit Git hooks. | ||||
@@ -7,6 +7,8 @@ package models | |||||
import ( | import ( | ||||
"testing" | "testing" | ||||
"code.gitea.io/gitea/modules/setting" | |||||
"github.com/stretchr/testify/assert" | "github.com/stretchr/testify/assert" | ||||
) | ) | ||||
@@ -17,3 +19,22 @@ func TestGetUserEmailsByNames(t *testing.T) { | |||||
assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user9"})) | assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user9"})) | ||||
assert.Equal(t, []string{"user8@example.com", "user5@example.com"}, GetUserEmailsByNames([]string{"user8", "user5"})) | assert.Equal(t, []string{"user8@example.com", "user5@example.com"}, GetUserEmailsByNames([]string{"user8", "user5"})) | ||||
} | } | ||||
func TestCanCreateOrganization(t *testing.T) { | |||||
assert.NoError(t, PrepareTestDatabase()) | |||||
admin := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User) | |||||
assert.True(t, admin.CanCreateOrganization()) | |||||
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) | |||||
assert.True(t, user.CanCreateOrganization()) | |||||
// Disable user create organization permission. | |||||
user.AllowCreateOrganization = false | |||||
assert.False(t, user.CanCreateOrganization()) | |||||
setting.Admin.DisableRegularOrgCreation = true | |||||
user.AllowCreateOrganization = true | |||||
assert.True(t, admin.CanCreateOrganization()) | |||||
assert.False(t, user.CanCreateOrganization()) | |||||
} |
@@ -257,6 +257,11 @@ var ( | |||||
FileExtensions: strings.Split(".md,.markdown,.mdown,.mkd", ","), | FileExtensions: strings.Split(".md,.markdown,.mdown,.mkd", ","), | ||||
} | } | ||||
// Admin settings | |||||
Admin struct { | |||||
DisableRegularOrgCreation bool | |||||
} | |||||
// Picture settings | // Picture settings | ||||
AvatarUploadPath string | AvatarUploadPath string | ||||
GravatarSource string | GravatarSource string | ||||
@@ -855,6 +860,8 @@ please consider changing to GITEA_CUSTOM`) | |||||
log.Fatal(4, "Failed to map UI settings: %v", err) | log.Fatal(4, "Failed to map UI settings: %v", err) | ||||
} else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil { | } else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil { | ||||
log.Fatal(4, "Failed to map Markdown settings: %v", err) | log.Fatal(4, "Failed to map Markdown settings: %v", err) | ||||
} else if err = Cfg.Section("admin").MapTo(&Admin); err != nil { | |||||
log.Fatal(4, "Fail to map Admin settings: %v", err) | |||||
} else if err = Cfg.Section("cron").MapTo(&Cron); err != nil { | } else if err = Cfg.Section("cron").MapTo(&Cron); err != nil { | ||||
log.Fatal(4, "Failed to map Cron settings: %v", err) | log.Fatal(4, "Failed to map Cron settings: %v", err) | ||||
} else if err = Cfg.Section("git").MapTo(&Git); err != nil { | } else if err = Cfg.Section("git").MapTo(&Git); err != nil { | ||||
@@ -158,6 +158,7 @@ func EditUser(ctx *context.Context) { | |||||
ctx.Data["Title"] = ctx.Tr("admin.users.edit_account") | ctx.Data["Title"] = ctx.Tr("admin.users.edit_account") | ||||
ctx.Data["PageIsAdmin"] = true | ctx.Data["PageIsAdmin"] = true | ||||
ctx.Data["PageIsAdminUsers"] = true | ctx.Data["PageIsAdminUsers"] = true | ||||
ctx.Data["DisableRegularOrgCreation"] = setting.Admin.DisableRegularOrgCreation | |||||
prepareUserInfo(ctx) | prepareUserInfo(ctx) | ||||
if ctx.Written() { | if ctx.Written() { | ||||
@@ -97,12 +97,14 @@ | |||||
<input name="allow_import_local" type="checkbox" {{if .User.CanImportLocal}}checked{{end}}> | <input name="allow_import_local" type="checkbox" {{if .User.CanImportLocal}}checked{{end}}> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
{{if not .DisableRegularOrgCreation}} | |||||
<div class="inline field"> | <div class="inline field"> | ||||
<div class="ui checkbox"> | <div class="ui checkbox"> | ||||
<label><strong>{{.i18n.Tr "admin.users.allow_create_organization"}}</strong></label> | <label><strong>{{.i18n.Tr "admin.users.allow_create_organization"}}</strong></label> | ||||
<input name="allow_create_organization" type="checkbox" {{if .User.CanCreateOrganization}}checked{{end}}> | <input name="allow_create_organization" type="checkbox" {{if .User.CanCreateOrganization}}checked{{end}}> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
{{end}} | |||||
<div class="ui divider"></div> | <div class="ui divider"></div> | ||||