Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2831,15 +2831,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 %s have been renamed to %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
108 changes: 58 additions & 50 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 @@ -165,40 +144,28 @@ func SettingsDeleteAvatar(ctx *context.Context) {

// 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 + "/")
}
if ctx.Org.Organization.Name != ctx.FormString("org_name") {
ctx.Flash.Error(ctx.Tr("form.enterred_invalid_org_name"))
ctx.JSONRedirect(ctx.Org.OrgLink + "/settings")
return
}

if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
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"))
} else if packages_model.IsErrUserOwnPackages(err) {
ctx.Flash.Error(ctx.Tr("form.org_still_own_packages"))
} else {
log.Error("DeleteOrganization: %v", err)
ctx.Flash.Error(util.Iif(ctx.Doer.IsAdmin, err.Error(), string(ctx.Tr("org.settings.delete_failed"))))
}
ctx.JSONRedirect(ctx.Org.OrgLink + "/settings")
return
}

ctx.HTML(http.StatusOK, tplSettingsDelete)
log.Trace("Organization deleted: %s", ctx.Org.Organization.Name)
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 +217,44 @@ func Labels(ctx *context.Context) {

ctx.HTML(http.StatusOK, tplSettingsLabels)
}

// SettingsRename response for renaming organization
func SettingsRename(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.RenameOrgForm)
org := ctx.Org.Organization

if org.Name != form.OrgName {
ctx.Flash.Error(ctx.Tr("form.enterred_invalid_org_name"))
ctx.JSONRedirect(ctx.Org.OrgLink + "/settings")
return
}

if org.Name == form.NewOrgName {
ctx.Flash.Error(ctx.Tr("org.settings.rename_no_change"))
ctx.JSONRedirect(ctx.Org.OrgLink + "/settings")
return
}

oldOrgName := org.Name

if err := user_service.RenameUser(ctx, org.AsUser(), form.NewOrgName); err != nil {
if user_model.IsErrUserAlreadyExist(err) {
ctx.Flash.Error(ctx.Tr("form.username_been_taken"))
} else if db.IsErrNameReserved(err) {
ctx.Flash.Error(ctx.Tr("repo.form.name_reserved"))
} else if db.IsErrNamePatternNotAllowed(err) {
ctx.Flash.Error(ctx.Tr("repo.form.name_pattern_not_allowed"))
} else {
log.Error("RenameOrganization: %v", err)
ctx.Flash.Error(util.Iif(ctx.Doer.IsAdmin, err.Error(), string(ctx.Tr("org.settings.rename_failed"))))
}
ctx.JSONRedirect(ctx.Org.OrgLink + "/settings")
return
}

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

log.Trace("Organization renamed to %s", org.Name)
ctx.Flash.Success(ctx.Tr("org.settings.rename_success", oldOrgName, org.Name))
ctx.JSONRedirect(ctx.Org.OrgLink + "/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.SettingsRename)
m.Post("/delete", org.SettingsDelete)

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;Username;MaxSize(40)"`
NewOrgName string `binding:"Required;Username;MaxSize(40)"`
}

// ___________
// \__ ___/___ _____ _____
// | |_/ __ \\__ \ / \
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>
103 changes: 95 additions & 8 deletions templates/org/settings/options.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@
<div class="ui attached segment">
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<div class="required field {{if .Err_Name}}error{{end}}">
<label for="org_name">{{ctx.Locale.Tr "org.org_name_holder"}}
<span class="text red tw-hidden" id="org-name-change-prompt">
<br>{{ctx.Locale.Tr "org.settings.change_orgname_prompt"}}<br>{{ctx.Locale.Tr "org.settings.change_orgname_redirect_prompt"}}
</span>
</label>
<input id="org_name" name="name" value="{{.Org.Name}}" data-org-name="{{.Org.Name}}" required maxlength="40">
</div>
<div class="field {{if .Err_FullName}}error{{end}}">
<label for="full_name">{{ctx.Locale.Tr "org.org_full_name_holder"}}</label>
<input id="full_name" name="full_name" value="{{.Org.FullName}}" maxlength="100">
Expand Down Expand Up @@ -97,5 +89,100 @@
</div>
</form>
</div>

<h4 class="ui top attached error header">
{{ctx.Locale.Tr "repo.settings.danger_zone"}}
</h4>
<div class="ui attached error danger segment">
<div class="flex-list">
<div class="flex-item tw-items-center">
<div class="flex-item-main">
<div class="flex-item-title">{{ctx.Locale.Tr "org.settings.rename"}}</div>
<div class="flex-item-body">{{ctx.Locale.Tr "org.settings.rename_desc"}}</div>
</div>
<div class="flex-item-trailing">
<button class="ui basic red show-modal button" data-modal="#rename-org-modal">{{ctx.Locale.Tr "org.settings.rename"}}</button>
</div>
</div>

<div class="flex-item">
<div class="flex-item-main">
<div class="flex-item-title">{{ctx.Locale.Tr "org.settings.delete_account"}}</div>
<div class="flex-item-body">{{ctx.Locale.Tr "org.settings.delete_prompt"}}</div>
</div>
<div class="flex-item-trailing">
<button class="ui basic red show-modal button" data-modal="#delete-org-modal">{{ctx.Locale.Tr "org.settings.delete_account"}}</button>
</div>
</div>
</div>
</div>
</div>

<div class="ui small modal" id="rename-org-modal">
<div class="header">
{{ctx.Locale.Tr "org.settings.rename"}}
</div>
<div class="content">
<div class="ui warning message">
{{ctx.Locale.Tr "org.settings.rename_notices_1"}}<br>
{{ctx.Locale.Tr "org.settings.rename_notices_2"}}
</div>
<form class="ui form form-fetch-action" action="{{.Link}}/rename" method="post">
{{.CsrfTokenHtml}}
<div class="field">
<label>
{{ctx.Locale.Tr "org.settings.name_confirm"}}
<span class="text red">{{.Org.Name}}</span>
</label>
</div>
<div class="required field">
<label for="org_name_to_rename">{{ctx.Locale.Tr "org.org_name_holder"}}</label>
<input id="org_name_to_rename" name="org_name" required>
</div>

<div class="required field">
<label for="repo_name_to_delete">{{ctx.Locale.Tr "org.settings.rename_new_org_name"}}</label>
<input id="new_org_name" name="new_org_name" required>
</div>

<div class="actions">
<button class="ui cancel button">{{ctx.Locale.Tr "settings.cancel"}}</button>
<button class="ui red button">{{ctx.Locale.Tr "org.settings.rename"}}</button>
</div>
</form>
</div>
</div>

<div class="ui small modal" id="delete-org-modal">
<div class="header">
{{ctx.Locale.Tr "org.settings.delete_account"}}
</div>
<div class="content">
<div class="ui warning message">
{{ctx.Locale.Tr "org.settings.delete_notices_1"}}<br/>
{{ctx.Locale.Tr "org.settings.delete_notices_2" .Org.Name}}<br/>
{{ctx.Locale.Tr "org.settings.delete_notices_3" .Org.Name}}<br/>
{{ctx.Locale.Tr "org.settings.delete_notices_4" .Org.Name}}
</div>
<form class="ui form form-fetch-action" action="{{.Link}}/delete" method="post">
{{.CsrfTokenHtml}}
<div class="field">
<label>
{{ctx.Locale.Tr "org.settings.name_confirm"}}
<span class="text red">{{.Org.Name}}</span>
</label>
</div>
<div class="required field">
<label for="org_name_to_delete">{{ctx.Locale.Tr "org.org_name_holder"}}</label>
<input id="org_name_to_delete" name="org_name" required>
</div>

<div class="actions">
<button class="ui cancel button">{{ctx.Locale.Tr "settings.cancel"}}</button>
<button class="ui red button">{{ctx.Locale.Tr "org.settings.delete_account"}}</button>
</div>
</form>
</div>
</div>

{{template "org/settings/layout_footer" .}}