diff options
Diffstat (limited to '')
-rw-r--r-- | routers/web/org/setting.go | 258 | ||||
-rw-r--r-- | routers/web/org/setting/blocked_users.go | 85 | ||||
-rw-r--r-- | routers/web/org/setting/runners.go | 12 | ||||
-rw-r--r-- | routers/web/org/setting_oauth2.go | 102 | ||||
-rw-r--r-- | routers/web/org/setting_packages.go | 131 |
5 files changed, 588 insertions, 0 deletions
diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go new file mode 100644 index 0000000..0be734a --- /dev/null +++ b/routers/web/org/setting.go @@ -0,0 +1,258 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2019 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package org + +import ( + "net/http" + "net/url" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/models/webhook" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" + repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/setting" + "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" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/forms" + org_service "code.gitea.io/gitea/services/org" + repo_service "code.gitea.io/gitea/services/repository" + user_service "code.gitea.io/gitea/services/user" + webhook_service "code.gitea.io/gitea/services/webhook" +) + +const ( + // tplSettingsOptions template path for render settings + tplSettingsOptions base.TplName = "org/settings/options" + // tplSettingsDelete template path for render delete repository + tplSettingsDelete base.TplName = "org/settings/delete" + // tplSettingsHooks template path for render hook settings + tplSettingsHooks base.TplName = "org/settings/hooks" + // tplSettingsLabels template path for render labels settings + tplSettingsLabels base.TplName = "org/settings/labels" +) + +// Settings render the main settings page +func Settings(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("org.settings") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsOptions"] = true + ctx.Data["CurrentVisibility"] = ctx.Org.Organization.Visibility + ctx.Data["RepoAdminChangeTeamAccess"] = ctx.Org.Organization.RepoAdminChangeTeamAccess + ctx.Data["ContextUser"] = ctx.ContextUser + + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + + ctx.HTML(http.StatusOK, tplSettingsOptions) +} + +// SettingsPost response for settings change submitted +func SettingsPost(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.UpdateOrgSettingForm) + ctx.Data["Title"] = ctx.Tr("org.settings") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsOptions"] = true + ctx.Data["CurrentVisibility"] = ctx.Org.Organization.Visibility + + if ctx.HasError() { + ctx.HTML(http.StatusOK, tplSettingsOptions) + return + } + + 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 + ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsOptions, &form) + return + } + } + + opts := &user_service.UpdateOptions{ + FullName: optional.Some(form.FullName), + Description: optional.Some(form.Description), + Website: optional.Some(form.Website), + Location: optional.Some(form.Location), + Visibility: optional.Some(form.Visibility), + RepoAdminChangeTeamAccess: optional.Some(form.RepoAdminChangeTeamAccess), + } + if ctx.Doer.IsAdmin { + opts.MaxRepoCreation = optional.Some(form.MaxRepoCreation) + } + + visibilityChanged := org.Visibility != form.Visibility + + if err := user_service.UpdateUser(ctx, org.AsUser(), opts); err != nil { + ctx.ServerError("UpdateUser", err) + return + } + + // update forks visibility + if visibilityChanged { + repos, _, err := repo_model.GetUserRepositories(ctx, &repo_model.SearchRepoOptions{ + Actor: org.AsUser(), Private: true, ListOptions: db.ListOptions{Page: 1, PageSize: org.NumRepos}, + }) + if err != nil { + ctx.ServerError("GetRepositories", err) + return + } + for _, repo := range repos { + repo.OwnerName = org.Name + if err := repo_service.UpdateRepository(ctx, repo, true); err != nil { + ctx.ServerError("UpdateRepository", err) + return + } + } + } + + log.Trace("Organization setting updated: %s", org.Name) + ctx.Flash.Success(ctx.Tr("org.settings.update_setting_success")) + ctx.Redirect(ctx.Org.OrgLink + "/settings") +} + +// SettingsAvatar response for change avatar on settings page +func SettingsAvatar(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.AvatarForm) + form.Source = forms.AvatarLocal + if err := user_setting.UpdateAvatarSetting(ctx, form, ctx.Org.Organization.AsUser()); err != nil { + ctx.Flash.Error(err.Error()) + } else { + ctx.Flash.Success(ctx.Tr("org.settings.update_avatar_success")) + } + + ctx.Redirect(ctx.Org.OrgLink + "/settings") +} + +// SettingsDeleteAvatar response for delete avatar on settings page +func SettingsDeleteAvatar(ctx *context.Context) { + if err := user_service.DeleteAvatar(ctx, ctx.Org.Organization.AsUser()); err != nil { + ctx.Flash.Error(err.Error()) + } + + 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 == "POST" { + 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 models.IsErrUserOwnRepos(err) { + ctx.Flash.Error(ctx.Tr("form.org_still_own_repo")) + ctx.Redirect(ctx.Org.OrgLink + "/settings/delete") + } else if models.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 + "/") + } + return + } + + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + + ctx.HTML(http.StatusOK, tplSettingsDelete) +} + +// Webhooks render webhook list page +func Webhooks(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("org.settings") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsHooks"] = true + ctx.Data["BaseLink"] = ctx.Org.OrgLink + "/settings/hooks" + ctx.Data["BaseLinkNew"] = ctx.Org.OrgLink + "/settings/hooks" + ctx.Data["WebhookList"] = webhook_service.List() + ctx.Data["Description"] = ctx.Tr("org.settings.hooks_desc") + + ws, err := db.Find[webhook.Webhook](ctx, webhook.ListWebhookOptions{OwnerID: ctx.Org.Organization.ID}) + if err != nil { + ctx.ServerError("ListWebhooksByOpts", err) + return + } + + err = shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + + ctx.Data["Webhooks"] = ws + ctx.HTML(http.StatusOK, tplSettingsHooks) +} + +// DeleteWebhook response for delete webhook +func DeleteWebhook(ctx *context.Context) { + if err := webhook.DeleteWebhookByOwnerID(ctx, ctx.Org.Organization.ID, ctx.FormInt64("id")); err != nil { + ctx.Flash.Error("DeleteWebhookByOwnerID: " + err.Error()) + } else { + ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success")) + } + + ctx.JSONRedirect(ctx.Org.OrgLink + "/settings/hooks") +} + +// Labels render organization labels page +func Labels(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("repo.labels") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsOrgSettingsLabels"] = true + ctx.Data["LabelTemplateFiles"] = repo_module.LabelTemplateFiles + + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + + ctx.HTML(http.StatusOK, tplSettingsLabels) +} diff --git a/routers/web/org/setting/blocked_users.go b/routers/web/org/setting/blocked_users.go new file mode 100644 index 0000000..0c7f245 --- /dev/null +++ b/routers/web/org/setting/blocked_users.go @@ -0,0 +1,85 @@ +// Copyright 2023 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "fmt" + "net/http" + "strings" + + "code.gitea.io/gitea/models/db" + user_model "code.gitea.io/gitea/models/user" + shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" + user_service "code.gitea.io/gitea/services/user" +) + +const tplBlockedUsers = "org/settings/blocked_users" + +// BlockedUsers renders the blocked users page. +func BlockedUsers(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("settings.blocked_users") + ctx.Data["PageIsSettingsBlockedUsers"] = true + + blockedUsers, err := user_model.ListBlockedUsers(ctx, ctx.Org.Organization.ID, db.ListOptions{}) + if err != nil { + ctx.ServerError("ListBlockedUsers", err) + return + } + + err = shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + + ctx.Data["BlockedUsers"] = blockedUsers + + ctx.HTML(http.StatusOK, tplBlockedUsers) +} + +// BlockedUsersBlock blocks a particular user from the organization. +func BlockedUsersBlock(ctx *context.Context) { + uname := strings.ToLower(ctx.FormString("uname")) + u, err := user_model.GetUserByName(ctx, uname) + if err != nil { + ctx.ServerError("GetUserByName", err) + return + } + + if u.IsOrganization() { + ctx.ServerError("IsOrganization", fmt.Errorf("%s is an organization not a user", u.Name)) + return + } + + if err := user_service.BlockUser(ctx, ctx.Org.Organization.ID, u.ID); err != nil { + ctx.ServerError("BlockUser", err) + return + } + + ctx.Flash.Success(ctx.Tr("settings.user_block_success")) + ctx.Redirect(ctx.Org.OrgLink + "/settings/blocked_users") +} + +// BlockedUsersUnblock unblocks a particular user from the organization. +func BlockedUsersUnblock(ctx *context.Context) { + u, err := user_model.GetUserByID(ctx, ctx.FormInt64("user_id")) + if err != nil { + ctx.ServerError("GetUserByID", err) + return + } + + if u.IsOrganization() { + ctx.ServerError("IsOrganization", fmt.Errorf("%s is an organization not a user", u.Name)) + return + } + + if err := user_model.UnblockUser(ctx, ctx.Org.Organization.ID, u.ID); err != nil { + ctx.ServerError("UnblockUser", err) + return + } + + ctx.Flash.Success(ctx.Tr("settings.user_unblock_success")) + ctx.Redirect(ctx.Org.OrgLink + "/settings/blocked_users") +} diff --git a/routers/web/org/setting/runners.go b/routers/web/org/setting/runners.go new file mode 100644 index 0000000..fe05709 --- /dev/null +++ b/routers/web/org/setting/runners.go @@ -0,0 +1,12 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "code.gitea.io/gitea/services/context" +) + +func RedirectToDefaultSetting(ctx *context.Context) { + ctx.Redirect(ctx.Org.OrgLink + "/settings/actions/runners") +} diff --git a/routers/web/org/setting_oauth2.go b/routers/web/org/setting_oauth2.go new file mode 100644 index 0000000..7f85579 --- /dev/null +++ b/routers/web/org/setting_oauth2.go @@ -0,0 +1,102 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package org + +import ( + "fmt" + "net/http" + + "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/setting" + shared_user "code.gitea.io/gitea/routers/web/shared/user" + user_setting "code.gitea.io/gitea/routers/web/user/setting" + "code.gitea.io/gitea/services/context" +) + +const ( + tplSettingsApplications base.TplName = "org/settings/applications" + tplSettingsOAuthApplicationEdit base.TplName = "org/settings/applications_oauth2_edit" +) + +func newOAuth2CommonHandlers(org *context.Organization) *user_setting.OAuth2CommonHandlers { + return &user_setting.OAuth2CommonHandlers{ + OwnerID: org.Organization.ID, + BasePathList: fmt.Sprintf("%s/org/%s/settings/applications", setting.AppSubURL, org.Organization.Name), + BasePathEditPrefix: fmt.Sprintf("%s/org/%s/settings/applications/oauth2", setting.AppSubURL, org.Organization.Name), + TplAppEdit: tplSettingsOAuthApplicationEdit, + } +} + +// Applications render org applications page (for org, at the moment, there are only OAuth2 applications) +func Applications(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("settings.applications") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsApplications"] = true + + apps, err := db.Find[auth.OAuth2Application](ctx, auth.FindOAuth2ApplicationsOptions{ + OwnerID: ctx.Org.Organization.ID, + }) + if err != nil { + ctx.ServerError("GetOAuth2ApplicationsByUserID", err) + return + } + ctx.Data["Applications"] = apps + + err = shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + + ctx.HTML(http.StatusOK, tplSettingsApplications) +} + +// OAuthApplicationsPost response for adding an oauth2 application +func OAuthApplicationsPost(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("settings.applications") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsApplications"] = true + + oa := newOAuth2CommonHandlers(ctx.Org) + oa.AddApp(ctx) +} + +// OAuth2ApplicationShow displays the given application +func OAuth2ApplicationShow(ctx *context.Context) { + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsApplications"] = true + + oa := newOAuth2CommonHandlers(ctx.Org) + oa.EditShow(ctx) +} + +// OAuth2ApplicationEdit response for editing oauth2 application +func OAuth2ApplicationEdit(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("settings.applications") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsApplications"] = true + + oa := newOAuth2CommonHandlers(ctx.Org) + oa.EditSave(ctx) +} + +// OAuthApplicationsRegenerateSecret handles the post request for regenerating the secret +func OAuthApplicationsRegenerateSecret(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("settings") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsApplications"] = true + + oa := newOAuth2CommonHandlers(ctx.Org) + oa.RegenerateSecret(ctx) +} + +// DeleteOAuth2Application deletes the given oauth2 application +func DeleteOAuth2Application(ctx *context.Context) { + oa := newOAuth2CommonHandlers(ctx.Org) + oa.DeleteApp(ctx) +} + +// TODO: revokes the grant with the given id diff --git a/routers/web/org/setting_packages.go b/routers/web/org/setting_packages.go new file mode 100644 index 0000000..af9836e --- /dev/null +++ b/routers/web/org/setting_packages.go @@ -0,0 +1,131 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package org + +import ( + "fmt" + "net/http" + + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/setting" + shared "code.gitea.io/gitea/routers/web/shared/packages" + shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" +) + +const ( + tplSettingsPackages base.TplName = "org/settings/packages" + tplSettingsPackagesRuleEdit base.TplName = "org/settings/packages_cleanup_rules_edit" + tplSettingsPackagesRulePreview base.TplName = "org/settings/packages_cleanup_rules_preview" +) + +func Packages(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + + shared.SetPackagesContext(ctx, ctx.ContextUser) + + ctx.HTML(http.StatusOK, tplSettingsPackages) +} + +func PackagesRuleAdd(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + + shared.SetRuleAddContext(ctx) + + ctx.HTML(http.StatusOK, tplSettingsPackagesRuleEdit) +} + +func PackagesRuleEdit(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + + shared.SetRuleEditContext(ctx, ctx.ContextUser) + + ctx.HTML(http.StatusOK, tplSettingsPackagesRuleEdit) +} + +func PackagesRuleAddPost(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + shared.PerformRuleAddPost( + ctx, + ctx.ContextUser, + fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name), + tplSettingsPackagesRuleEdit, + ) +} + +func PackagesRuleEditPost(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + shared.PerformRuleEditPost( + ctx, + ctx.ContextUser, + fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name), + tplSettingsPackagesRuleEdit, + ) +} + +func PackagesRulePreview(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + + shared.SetRulePreviewContext(ctx, ctx.ContextUser) + + ctx.HTML(http.StatusOK, tplSettingsPackagesRulePreview) +} + +func InitializeCargoIndex(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + shared.InitializeCargoIndex(ctx, ctx.ContextUser) + + ctx.Redirect(fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name)) +} + +func RebuildCargoIndex(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("packages.title") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsPackages"] = true + + shared.RebuildCargoIndex(ctx, ctx.ContextUser) + + ctx.Redirect(fmt.Sprintf("%s/org/%s/settings/packages", setting.AppSubURL, ctx.ContextUser.Name)) +} |