Skip to content
22 changes: 18 additions & 4 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2811,6 +2811,7 @@ team_permission_desc = Permission
team_unit_desc = Allow Access to Repository Sections
team_unit_disabled = (Disabled)

form.name_been_taken = The organisation name "%s" has already been taken.
form.name_reserved = The organization name "%s" is reserved.
form.name_pattern_not_allowed = The pattern "%s" is not allowed in an organization name.
form.create_org_not_allowed = You are not allowed to create an organization.
Expand All @@ -2832,15 +2833,28 @@ settings.visibility.private_shortname = Private

settings.update_settings = Update Settings
settings.update_setting_success = Organization settings have been updated.
settings.change_orgname_prompt = Note: Changing the organization name will also change your organization's URL and free the old name.
settings.change_orgname_redirect_prompt = The old name will redirect until it is claimed.

settings.rename = Rename Organization
settings.rename_desc = Changing the organization name will also change your organization's URL and free the old name.
settings.rename_success = Organization %[1]s have been renamed to %[2]s successfully.
settings.rename_no_change = Organization name is no change.
settings.rename_new_org_name = New Organization Name
settings.rename_failed = Rename Organization failed because of internal error
settings.rename_notices_1 = This operation <strong>CANNOT</strong> be undone.
settings.rename_notices_2 = The old name will redirect until it is claimed.

settings.update_avatar_success = The organization's avatar has been updated.
settings.delete = Delete Organization
settings.delete_account = Delete This Organization
settings.delete_prompt = The organization will be permanently removed. This <strong>CANNOT</strong> be undone!
settings.name_confirm = Enter the organization name as confirmation:
settings.delete_notices_1 = This operation <strong>CANNOT</strong> be undone.
settings.delete_notices_2 = This operation will permanently delete all the <strong>repositories</strong> of <strong>%s</strong> including code, issues, comments, wiki data and collaborator settings.
settings.delete_notices_3 = This operation will permanently delete all the <strong>packages</strong> of <strong>%s</strong>.
settings.delete_notices_4 = This operation will permanently delete all the <strong>projects</strong> of <strong>%s</strong>.
settings.confirm_delete_account = Confirm Deletion
settings.delete_org_title = Delete Organization
settings.delete_org_desc = This organization will be deleted permanently. Continue?
settings.delete_failed = Delete Organization failed because of internal error
settings.delete_successful = Organization <b>%s</b> has been deleted successfully.
settings.hooks_desc = Add webhooks which will be triggered for <strong>all repositories</strong> under this organization.

settings.labels_desc = Add labels which can be used on issues for <strong>all repositories</strong> under this organization.
Expand Down
105 changes: 53 additions & 52 deletions routers/web/org/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
shared_user "code.gitea.io/gitea/routers/web/shared/user"
user_setting "code.gitea.io/gitea/routers/web/user/setting"
Expand All @@ -31,8 +32,6 @@ import (
const (
// tplSettingsOptions template path for render settings
tplSettingsOptions templates.TplName = "org/settings/options"
// tplSettingsDelete template path for render delete repository
tplSettingsDelete templates.TplName = "org/settings/delete"
// tplSettingsHooks template path for render hook settings
tplSettingsHooks templates.TplName = "org/settings/hooks"
// tplSettingsLabels template path for render labels settings
Expand Down Expand Up @@ -71,26 +70,6 @@ func SettingsPost(ctx *context.Context) {

org := ctx.Org.Organization

if org.Name != form.Name {
if err := user_service.RenameUser(ctx, org.AsUser(), form.Name); err != nil {
if user_model.IsErrUserAlreadyExist(err) {
ctx.Data["Err_Name"] = true
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tplSettingsOptions, &form)
} else if db.IsErrNameReserved(err) {
ctx.Data["Err_Name"] = true
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplSettingsOptions, &form)
} else if db.IsErrNamePatternNotAllowed(err) {
ctx.Data["Err_Name"] = true
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplSettingsOptions, &form)
} else {
ctx.ServerError("RenameUser", err)
}
return
}

ctx.Org.OrgLink = setting.AppSubURL + "/org/" + url.PathEscape(org.Name)
}

if form.Email != "" {
if err := user_service.ReplacePrimaryEmailAddress(ctx, org.AsUser(), form.Email); err != nil {
ctx.Data["Err_Email"] = true
Expand Down Expand Up @@ -163,42 +142,27 @@ func SettingsDeleteAvatar(ctx *context.Context) {
ctx.JSONRedirect(ctx.Org.OrgLink + "/settings")
}

// SettingsDelete response for deleting an organization
func SettingsDelete(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("org.settings")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsDelete"] = true

if ctx.Req.Method == http.MethodPost {
if ctx.Org.Organization.Name != ctx.FormString("org_name") {
ctx.Data["Err_OrgName"] = true
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_org_name"), tplSettingsDelete, nil)
return
}

if err := org_service.DeleteOrganization(ctx, ctx.Org.Organization, false); err != nil {
if repo_model.IsErrUserOwnRepos(err) {
ctx.Flash.Error(ctx.Tr("form.org_still_own_repo"))
ctx.Redirect(ctx.Org.OrgLink + "/settings/delete")
} else if packages_model.IsErrUserOwnPackages(err) {
ctx.Flash.Error(ctx.Tr("form.org_still_own_packages"))
ctx.Redirect(ctx.Org.OrgLink + "/settings/delete")
} else {
ctx.ServerError("DeleteOrganization", err)
}
} else {
log.Trace("Organization deleted: %s", ctx.Org.Organization.Name)
ctx.Redirect(setting.AppSubURL + "/")
}
// SettingsDeleteOrgPost response for deleting an organization
func SettingsDeleteOrgPost(ctx *context.Context) {
if ctx.Org.Organization.Name != ctx.FormString("org_name") {
ctx.JSONError(ctx.Tr("form.enterred_invalid_org_name"))
return
}

if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
if err := org_service.DeleteOrganization(ctx, ctx.Org.Organization, false /* no purge */); err != nil {
if repo_model.IsErrUserOwnRepos(err) {
ctx.JSONError(ctx.Tr("form.org_still_own_repo"))
} else if packages_model.IsErrUserOwnPackages(err) {
ctx.JSONError(ctx.Tr("form.org_still_own_packages"))
} else {
log.Error("DeleteOrganization: %v", err)
ctx.JSONError(util.Iif(ctx.Doer.IsAdmin, err.Error(), string(ctx.Tr("org.settings.delete_failed"))))
}
return
}

ctx.HTML(http.StatusOK, tplSettingsDelete)
ctx.Flash.Success(ctx.Tr("org.settings.delete_successful", ctx.Org.Organization.Name))
ctx.JSONRedirect(setting.AppSubURL + "/")
}

// Webhooks render webhook list page
Expand Down Expand Up @@ -250,3 +214,40 @@ func Labels(ctx *context.Context) {

ctx.HTML(http.StatusOK, tplSettingsLabels)
}

// SettingsRenamePost response for renaming organization
func SettingsRenamePost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.RenameOrgForm)
if ctx.HasError() {
ctx.JSONError(ctx.GetErrMsg())
return
}

oldOrgName, newOrgName := ctx.Org.Organization.Name, form.NewOrgName

if form.OrgName != oldOrgName {
ctx.JSONError(ctx.Tr("form.enterred_invalid_org_name"))
return
}
if newOrgName == oldOrgName {
ctx.JSONError(ctx.Tr("org.settings.rename_no_change"))
return
}

if err := user_service.RenameUser(ctx, ctx.Org.Organization.AsUser(), newOrgName); err != nil {
if user_model.IsErrUserAlreadyExist(err) {
ctx.JSONError(ctx.Tr("org.form.name_been_taken", newOrgName))
} else if db.IsErrNameReserved(err) {
ctx.JSONError(ctx.Tr("org.form.name_reserved", newOrgName))
} else if db.IsErrNamePatternNotAllowed(err) {
ctx.JSONError(ctx.Tr("org.form.name_pattern_not_allowed", newOrgName))
} else {
log.Error("RenameOrganization: %v", err)
ctx.JSONError(util.Iif(ctx.Doer.IsAdmin, err.Error(), string(ctx.Tr("org.settings.rename_failed"))))
}
return
}

ctx.Flash.Success(ctx.Tr("org.settings.rename_success", oldOrgName, newOrgName))
ctx.JSONRedirect(setting.AppSubURL + "/org/" + url.PathEscape(newOrgName) + "/settings")
}
3 changes: 2 additions & 1 deletion routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,8 @@ func registerWebRoutes(m *web.Router) {
addSettingsVariablesRoutes()
}, actions.MustEnableActions)

m.Methods("GET,POST", "/delete", org.SettingsDelete)
m.Post("/rename", web.Bind(forms.RenameOrgForm{}), org.SettingsRenamePost)
m.Post("/delete", org.SettingsDeleteOrgPost)

m.Group("/packages", func() {
m.Get("", org.Packages)
Expand Down
6 changes: 5 additions & 1 deletion services/forms/org.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ func (f *CreateOrgForm) Validate(req *http.Request, errs binding.Errors) binding

// UpdateOrgSettingForm form for updating organization settings
type UpdateOrgSettingForm struct {
Name string `binding:"Required;Username;MaxSize(40)" locale:"org.org_name_holder"`
FullName string `binding:"MaxSize(100)"`
Email string `binding:"MaxSize(255)"`
Description string `binding:"MaxSize(255)"`
Expand All @@ -53,6 +52,11 @@ func (f *UpdateOrgSettingForm) Validate(req *http.Request, errs binding.Errors)
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
}

type RenameOrgForm struct {
OrgName string `binding:"Required"`
NewOrgName string `binding:"Required;Username;MaxSize(40)" locale:"org.org_name_holder"`
}

// ___________
// \__ ___/___ _____ _____
// | |_/ __ \\__ \ / \
Expand Down
35 changes: 0 additions & 35 deletions templates/org/settings/delete.tmpl

This file was deleted.

3 changes: 0 additions & 3 deletions templates/org/settings/navbar.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,5 @@
</div>
</details>
{{end}}
<a class="{{if .PageIsSettingsDelete}}active {{end}}item" href="{{.OrgLink}}/settings/delete">
{{ctx.Locale.Tr "org.settings.delete"}}
</a>
</div>
</div>
Loading