feat: vendor gitea 1.16.2
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"code.gitea.io/gitea/services/contexttest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestShadowPassword(t *testing.T) {
|
||||
@@ -74,19 +75,29 @@ func TestShadowPassword(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSelfCheckPost(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.PublicURLDetection)()
|
||||
defer test.MockVariableValue(&setting.AppURL, "http://config/sub/")()
|
||||
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
||||
|
||||
ctx, resp := contexttest.MockContext(t, "GET http://host/sub/admin/self_check?location_origin=http://frontend")
|
||||
SelfCheckPost(ctx)
|
||||
assert.Equal(t, http.StatusOK, resp.Code)
|
||||
|
||||
data := struct {
|
||||
Problems []string `json:"problems"`
|
||||
}{}
|
||||
err := json.Unmarshal(resp.Body.Bytes(), &data)
|
||||
assert.NoError(t, err)
|
||||
|
||||
setting.PublicURLDetection = setting.PublicURLLegacy
|
||||
ctx, resp := contexttest.MockContext(t, "GET http://host/sub/admin/self_check?location_origin=http://frontend")
|
||||
SelfCheckPost(ctx)
|
||||
assert.Equal(t, http.StatusOK, resp.Code)
|
||||
require.NoError(t, json.Unmarshal(resp.Body.Bytes(), &data))
|
||||
assert.Equal(t, []string{
|
||||
ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://config/sub/"),
|
||||
}, data.Problems)
|
||||
|
||||
setting.PublicURLDetection = setting.PublicURLAuto
|
||||
ctx, resp = contexttest.MockContext(t, "GET http://host/sub/admin/self_check?location_origin=http://frontend")
|
||||
SelfCheckPost(ctx)
|
||||
assert.Equal(t, http.StatusOK, resp.Code)
|
||||
require.NoError(t, json.Unmarshal(resp.Body.Bytes(), &data))
|
||||
assert.Equal(t, []string{
|
||||
ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://host/sub/"),
|
||||
}, data.Problems)
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func EditApplicationPost(ctx *context.Context) {
|
||||
|
||||
// ApplicationsRegenerateSecret handles the post request for regenerating the secret
|
||||
func ApplicationsRegenerateSecret(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["Title"] = ctx.Tr("settings_title")
|
||||
ctx.Data["PageIsAdminApplications"] = true
|
||||
|
||||
oa := newOAuth2CommonHandlers()
|
||||
|
||||
@@ -136,6 +136,7 @@ func parseLDAPConfig(form forms.AuthenticationForm) *ldap.Source {
|
||||
AttributesInBind: form.AttributesInBind,
|
||||
AttributeSSHPublicKey: form.AttributeSSHPublicKey,
|
||||
AttributeAvatar: form.AttributeAvatar,
|
||||
SSHKeysAreVerified: form.SSHKeysAreVerified,
|
||||
SearchPageSize: pageSize,
|
||||
Filter: form.Filter,
|
||||
GroupsEnabled: form.GroupsEnabled,
|
||||
@@ -272,7 +273,7 @@ func NewAuthSourcePost(ctx *context.Context) {
|
||||
discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL)
|
||||
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
|
||||
ctx.Data["Err_DiscoveryURL"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthNew, form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthNew, form)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -280,13 +281,13 @@ func NewAuthSourcePost(ctx *context.Context) {
|
||||
var err error
|
||||
config, err = parseSSPIConfig(ctx, form)
|
||||
if err != nil {
|
||||
ctx.RenderWithErr(err.Error(), tplAuthNew, form)
|
||||
ctx.RenderWithErrDeprecated(err.Error(), tplAuthNew, form)
|
||||
return
|
||||
}
|
||||
existing, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{LoginType: auth.SSPI})
|
||||
if err != nil || len(existing) > 0 {
|
||||
ctx.Data["Err_Type"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_of_type_exist"), tplAuthNew, form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.login_source_of_type_exist"), tplAuthNew, form)
|
||||
return
|
||||
}
|
||||
default:
|
||||
@@ -310,11 +311,11 @@ func NewAuthSourcePost(ctx *context.Context) {
|
||||
}); err != nil {
|
||||
if auth.IsErrSourceAlreadyExist(err) {
|
||||
ctx.Data["Err_Name"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthNew, form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthNew, form)
|
||||
} else if oauth2.IsErrOpenIDConnectInitialize(err) {
|
||||
ctx.Data["Err_DiscoveryURL"] = true
|
||||
unwrapped := err.(oauth2.ErrOpenIDConnectInitialize).Unwrap()
|
||||
ctx.RenderWithErr(ctx.Tr("admin.auths.unable_to_initialize_openid", unwrapped), tplAuthNew, form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.unable_to_initialize_openid", unwrapped), tplAuthNew, form)
|
||||
} else {
|
||||
ctx.ServerError("auth.CreateSource", err)
|
||||
}
|
||||
@@ -402,14 +403,14 @@ func EditAuthSourcePost(ctx *context.Context) {
|
||||
discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL)
|
||||
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
|
||||
ctx.Data["Err_DiscoveryURL"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthEdit, form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthEdit, form)
|
||||
return
|
||||
}
|
||||
}
|
||||
case auth.SSPI:
|
||||
config, err = parseSSPIConfig(ctx, form)
|
||||
if err != nil {
|
||||
ctx.RenderWithErr(err.Error(), tplAuthEdit, form)
|
||||
ctx.RenderWithErrDeprecated(err.Error(), tplAuthEdit, form)
|
||||
return
|
||||
}
|
||||
default:
|
||||
@@ -425,7 +426,7 @@ func EditAuthSourcePost(ctx *context.Context) {
|
||||
if err := auth.UpdateSource(ctx, source); err != nil {
|
||||
if auth.IsErrSourceAlreadyExist(err) {
|
||||
ctx.Data["Err_Name"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthEdit, form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthEdit, form)
|
||||
} else if oauth2.IsErrOpenIDConnectInitialize(err) {
|
||||
ctx.Flash.Error(err.Error(), true)
|
||||
ctx.Data["Err_DiscoveryURL"] = true
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
// Copyright 2026 The Gitea Authors.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
)
|
||||
|
||||
const (
|
||||
tplBadges templates.TplName = "admin/badge/list"
|
||||
tplBadgeNew templates.TplName = "admin/badge/new"
|
||||
tplBadgeView templates.TplName = "admin/badge/view"
|
||||
tplBadgeEdit templates.TplName = "admin/badge/edit"
|
||||
tplBadgeUsers templates.TplName = "admin/badge/users"
|
||||
)
|
||||
|
||||
// BadgeSearchDefaultAdminSort is the default sort type for admin view
|
||||
const BadgeSearchDefaultAdminSort = "oldest"
|
||||
|
||||
// Badges show all the badges
|
||||
func Badges(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.badges")
|
||||
ctx.Data["PageIsAdminBadges"] = true
|
||||
|
||||
RenderBadgeSearch(ctx, &user_model.SearchBadgeOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: max(ctx.FormInt("page"), 1),
|
||||
PageSize: setting.UI.Admin.UserPagingNum,
|
||||
},
|
||||
}, tplBadges)
|
||||
}
|
||||
|
||||
// NewBadge render adding a new badge
|
||||
func NewBadge(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.badges.new_badge")
|
||||
ctx.Data["PageIsAdminBadges"] = true
|
||||
|
||||
ctx.HTML(http.StatusOK, tplBadgeNew)
|
||||
}
|
||||
|
||||
// NewBadgePost response for adding a new badge
|
||||
func NewBadgePost(ctx *context.Context) {
|
||||
form := web.GetForm(ctx).(*forms.AdminCreateBadgeForm)
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.JSONError(ctx.GetErrMsg())
|
||||
return
|
||||
}
|
||||
|
||||
b := &user_model.Badge{
|
||||
Slug: form.Slug,
|
||||
Description: form.Description,
|
||||
ImageURL: form.ImageURL,
|
||||
}
|
||||
|
||||
if err := user_model.CreateBadge(ctx, b); err != nil {
|
||||
if errors.Is(err, util.ErrAlreadyExist) {
|
||||
ctx.JSONError(ctx.Tr("admin.badges.slug_been_taken"))
|
||||
} else {
|
||||
ctx.ServerError("CreateBadge", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("Badge created by admin (%s): %s", ctx.Doer.Name, b.Slug)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("admin.badges.new_success", b.Slug))
|
||||
ctx.JSONRedirect(setting.AppSubURL + "/-/admin/badges/slug/" + url.PathEscape(b.Slug))
|
||||
}
|
||||
|
||||
func prepareBadgeInfo(ctx *context.Context) *user_model.Badge {
|
||||
b, err := user_model.GetBadge(ctx, ctx.PathParam("badge_slug"))
|
||||
if err != nil {
|
||||
if errors.Is(err, util.ErrNotExist) {
|
||||
ctx.Redirect(setting.AppSubURL + "/-/admin/badges")
|
||||
} else {
|
||||
ctx.ServerError("GetBadge", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
ctx.Data["Badge"] = b
|
||||
return b
|
||||
}
|
||||
|
||||
func ViewBadge(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.badges.details")
|
||||
ctx.Data["PageIsAdminBadges"] = true
|
||||
|
||||
prepareBadgeInfo(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
badge := ctx.Data["Badge"].(*user_model.Badge)
|
||||
opts := &user_model.GetBadgeUsersOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: setting.UI.Admin.UserPagingNum,
|
||||
},
|
||||
BadgeSlug: badge.Slug,
|
||||
}
|
||||
users, count, err := user_model.GetBadgeUsers(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBadgeUsers", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Users"] = users
|
||||
ctx.Data["UsersTotal"] = int(count)
|
||||
|
||||
ctx.HTML(http.StatusOK, tplBadgeView)
|
||||
}
|
||||
|
||||
// EditBadge show editing badge page
|
||||
func EditBadge(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.badges.edit_badge")
|
||||
ctx.Data["PageIsAdminBadges"] = true
|
||||
prepareBadgeInfo(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.HTML(http.StatusOK, tplBadgeEdit)
|
||||
}
|
||||
|
||||
// EditBadgePost response for editing badge
|
||||
func EditBadgePost(ctx *context.Context) {
|
||||
b := prepareBadgeInfo(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
form := web.GetForm(ctx).(*forms.AdminEditBadgeForm)
|
||||
if ctx.HasError() {
|
||||
ctx.JSONError(ctx.GetErrMsg())
|
||||
return
|
||||
}
|
||||
|
||||
b.ImageURL = form.ImageURL
|
||||
b.Description = form.Description
|
||||
|
||||
if err := user_model.UpdateBadge(ctx, b); err != nil {
|
||||
ctx.ServerError("UpdateBadge", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("Badge updated by admin (%s): %s", ctx.Doer.Name, b.Slug)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("admin.badges.update_success"))
|
||||
ctx.JSONRedirect(setting.AppSubURL + "/-/admin/badges/slug/" + url.PathEscape(ctx.PathParam("badge_slug")))
|
||||
}
|
||||
|
||||
// DeleteBadge response for deleting a badge
|
||||
func DeleteBadge(ctx *context.Context) {
|
||||
b, err := user_model.GetBadge(ctx, ctx.PathParam("badge_slug"))
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBadge", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = user_model.DeleteBadge(ctx, b); err != nil {
|
||||
ctx.ServerError("DeleteBadge", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("Badge deleted by admin (%s): %s", ctx.Doer.Name, b.Slug)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("admin.badges.deletion_success"))
|
||||
ctx.Redirect(setting.AppSubURL + "/-/admin/badges")
|
||||
}
|
||||
|
||||
func BadgeUsers(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.badges.users_with_badge", ctx.PathParam("badge_slug"))
|
||||
ctx.Data["PageIsAdminBadges"] = true
|
||||
|
||||
page := max(ctx.FormInt("page"), 1)
|
||||
|
||||
badge := &user_model.Badge{Slug: ctx.PathParam("badge_slug")}
|
||||
opts := &user_model.GetBadgeUsersOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: page,
|
||||
PageSize: setting.UI.Admin.UserPagingNum,
|
||||
},
|
||||
BadgeSlug: badge.Slug,
|
||||
}
|
||||
users, count, err := user_model.GetBadgeUsers(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBadgeUsers", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Users"] = users
|
||||
ctx.Data["Total"] = count
|
||||
ctx.Data["Page"] = context.NewPagination(count, setting.UI.Admin.UserPagingNum, page, 5)
|
||||
|
||||
ctx.HTML(http.StatusOK, tplBadgeUsers)
|
||||
}
|
||||
|
||||
// BadgeUsersPost response for actions for user badges
|
||||
func BadgeUsersPost(ctx *context.Context) {
|
||||
name := strings.ToLower(ctx.FormString("user"))
|
||||
|
||||
u, err := user_model.GetUserByName(ctx, name)
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.user_not_exist"))
|
||||
ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
|
||||
} else {
|
||||
ctx.ServerError("GetUserByName", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err = user_model.AddUserBadge(ctx, u, &user_model.Badge{Slug: ctx.PathParam("badge_slug")}); err != nil {
|
||||
if errors.Is(err, util.ErrNotExist) {
|
||||
ctx.Flash.Error(ctx.Tr("admin.badges.not_found"))
|
||||
ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
|
||||
} else if errors.Is(err, util.ErrAlreadyExist) {
|
||||
ctx.Flash.Error(ctx.Tr("admin.badges.user_already_has"))
|
||||
ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
|
||||
} else {
|
||||
ctx.ServerError("AddUserBadge", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("admin.badges.user_add_success"))
|
||||
ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
|
||||
}
|
||||
|
||||
// DeleteBadgeUser delete a badge from a user
|
||||
func DeleteBadgeUser(ctx *context.Context) {
|
||||
badgeUsersURL := setting.AppSubURL + "/-/admin/badges/slug/" + url.PathEscape(ctx.PathParam("badge_slug")) + "/users"
|
||||
|
||||
user, err := user_model.GetUserByID(ctx, ctx.FormInt64("id"))
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.user_not_exist"))
|
||||
ctx.JSONRedirect(badgeUsersURL)
|
||||
return
|
||||
} else {
|
||||
ctx.ServerError("GetUserByID", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := user_model.RemoveUserBadge(ctx, user, &user_model.Badge{Slug: ctx.PathParam("badge_slug")}); err == nil {
|
||||
ctx.Flash.Success(ctx.Tr("admin.badges.user_remove_success"))
|
||||
} else {
|
||||
ctx.ServerError("RemoveUserBadge", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSONRedirect(badgeUsersURL)
|
||||
}
|
||||
|
||||
func RenderBadgeSearch(ctx *context.Context, opts *user_model.SearchBadgeOptions, tplName templates.TplName) {
|
||||
var (
|
||||
badges []*user_model.Badge
|
||||
count int64
|
||||
err error
|
||||
orderBy db.SearchOrderBy
|
||||
)
|
||||
|
||||
sortOrder := ctx.FormString("sort")
|
||||
if sortOrder == "" {
|
||||
sortOrder = BadgeSearchDefaultAdminSort
|
||||
}
|
||||
ctx.Data["SortType"] = sortOrder
|
||||
|
||||
switch sortOrder {
|
||||
case "newest":
|
||||
orderBy = "`badge`.id DESC"
|
||||
case "oldest":
|
||||
orderBy = "`badge`.id ASC"
|
||||
case "reversealphabetically":
|
||||
orderBy = "`badge`.slug DESC"
|
||||
case "alphabetically":
|
||||
orderBy = "`badge`.slug ASC"
|
||||
default:
|
||||
// In case the sort type is invalid, keep admin default sorting.
|
||||
ctx.Data["SortType"] = "oldest"
|
||||
orderBy = "`badge`.id ASC"
|
||||
}
|
||||
|
||||
opts.Keyword = ctx.FormTrim("q")
|
||||
opts.OrderBy = orderBy
|
||||
if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) {
|
||||
badges, count, err = user_model.SearchBadges(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchBadges", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["Keyword"] = opts.Keyword
|
||||
ctx.Data["Total"] = count
|
||||
ctx.Data["Badges"] = badges
|
||||
|
||||
pager := context.NewPagination(count, opts.PageSize, opts.Page, 5)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
ctx.HTML(http.StatusOK, tplName)
|
||||
}
|
||||
@@ -5,9 +5,9 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
system_model "code.gitea.io/gitea/models/system"
|
||||
@@ -123,10 +123,7 @@ func Config(ctx *context.Context) {
|
||||
ctx.Data["PageIsAdminConfigSummary"] = true
|
||||
|
||||
ctx.Data["CustomConf"] = setting.CustomConf
|
||||
ctx.Data["AppUrl"] = setting.AppURL
|
||||
ctx.Data["AppBuiltWith"] = setting.AppBuiltWith
|
||||
ctx.Data["Domain"] = setting.Domain
|
||||
ctx.Data["OfflineMode"] = setting.OfflineMode
|
||||
ctx.Data["RunUser"] = setting.RunUser
|
||||
ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode)
|
||||
ctx.Data["GitVersion"] = git.DefaultFeatures().VersionInfo()
|
||||
@@ -145,7 +142,6 @@ func Config(ctx *context.Context) {
|
||||
ctx.Data["Service"] = setting.Service
|
||||
ctx.Data["DbCfg"] = setting.Database
|
||||
ctx.Data["Webhook"] = setting.Webhook
|
||||
|
||||
ctx.Data["MailerEnabled"] = false
|
||||
if setting.MailService != nil {
|
||||
ctx.Data["MailerEnabled"] = true
|
||||
@@ -191,52 +187,27 @@ func ConfigSettings(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.config_settings")
|
||||
ctx.Data["PageIsAdminConfig"] = true
|
||||
ctx.Data["PageIsAdminConfigSettings"] = true
|
||||
ctx.Data["DefaultOpenWithEditorAppsString"] = setting.DefaultOpenWithEditorApps().ToTextareaString()
|
||||
ctx.HTML(http.StatusOK, tplConfigSettings)
|
||||
}
|
||||
|
||||
func validateConfigKeyValue(dynKey, input string) error {
|
||||
opt := config.GetConfigOption(dynKey)
|
||||
if opt == nil {
|
||||
return util.NewInvalidArgumentErrorf("unknown config key: %s", dynKey)
|
||||
}
|
||||
|
||||
const limit = 64 * 1024
|
||||
if len(input) > limit {
|
||||
return util.NewInvalidArgumentErrorf("value length exceeds limit of %d", limit)
|
||||
}
|
||||
|
||||
if !json.Valid([]byte(input)) {
|
||||
return util.NewInvalidArgumentErrorf("invalid json value for key: %s", dynKey)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ChangeConfig(ctx *context.Context) {
|
||||
cfg := setting.Config()
|
||||
|
||||
marshalBool := func(v string) ([]byte, error) {
|
||||
b, _ := strconv.ParseBool(v)
|
||||
return json.Marshal(b)
|
||||
}
|
||||
|
||||
marshalString := func(emptyDefault string) func(v string) ([]byte, error) {
|
||||
return func(v string) ([]byte, error) {
|
||||
return json.Marshal(util.IfZero(v, emptyDefault))
|
||||
}
|
||||
}
|
||||
|
||||
marshalOpenWithApps := func(value string) ([]byte, error) {
|
||||
// TODO: move the block alongside OpenWithEditorAppsType.ToTextareaString
|
||||
lines := strings.Split(value, "\n")
|
||||
var openWithEditorApps setting.OpenWithEditorAppsType
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
displayName, openURL, ok := strings.Cut(line, "=")
|
||||
displayName, openURL = strings.TrimSpace(displayName), strings.TrimSpace(openURL)
|
||||
if !ok || displayName == "" || openURL == "" {
|
||||
continue
|
||||
}
|
||||
openWithEditorApps = append(openWithEditorApps, setting.OpenWithEditorApp{
|
||||
DisplayName: strings.TrimSpace(displayName),
|
||||
OpenURL: strings.TrimSpace(openURL),
|
||||
})
|
||||
}
|
||||
return json.Marshal(openWithEditorApps)
|
||||
}
|
||||
marshallers := map[string]func(string) ([]byte, error){
|
||||
cfg.Picture.DisableGravatar.DynKey(): marshalBool,
|
||||
cfg.Picture.EnableFederatedAvatar.DynKey(): marshalBool,
|
||||
cfg.Repository.OpenWithEditorApps.DynKey(): marshalOpenWithApps,
|
||||
cfg.Repository.GitGuideRemoteName.DynKey(): marshalString(cfg.Repository.GitGuideRemoteName.DefaultValue()),
|
||||
}
|
||||
|
||||
_ = ctx.Req.ParseForm()
|
||||
configKeys := ctx.Req.Form["key"]
|
||||
configValues := ctx.Req.Form["value"]
|
||||
@@ -249,18 +220,16 @@ loop:
|
||||
}
|
||||
value := configValues[i]
|
||||
|
||||
marshaller, hasMarshaller := marshallers[key]
|
||||
if !hasMarshaller {
|
||||
ctx.JSONError(ctx.Tr("admin.config.set_setting_failed", key))
|
||||
break loop
|
||||
}
|
||||
|
||||
marshaledValue, err := marshaller(value)
|
||||
err := validateConfigKeyValue(key, value)
|
||||
if err != nil {
|
||||
ctx.JSONError(ctx.Tr("admin.config.set_setting_failed", key))
|
||||
if errors.Is(err, util.ErrInvalidArgument) {
|
||||
ctx.JSONError(err.Error())
|
||||
} else {
|
||||
ctx.JSONError(ctx.Tr("admin.config.set_setting_failed", key))
|
||||
}
|
||||
break loop
|
||||
}
|
||||
configSettings[key] = string(marshaledValue)
|
||||
configSettings[key] = value
|
||||
}
|
||||
if ctx.Written() {
|
||||
return
|
||||
|
||||
@@ -18,10 +18,10 @@ import (
|
||||
func MonitorDiagnosis(ctx *context.Context) {
|
||||
seconds := min(max(ctx.FormInt64("seconds"), 1), 300)
|
||||
|
||||
httplib.ServeSetHeaders(ctx.Resp, &httplib.ServeHeaderOptions{
|
||||
ContentType: "application/zip",
|
||||
Disposition: "attachment",
|
||||
Filename: fmt.Sprintf("gitea-diagnosis-%s.zip", time.Now().Format("20060102-150405")),
|
||||
httplib.ServeSetHeaders(ctx.Resp, httplib.ServeHeaderOptions{
|
||||
ContentType: "application/zip",
|
||||
Filename: fmt.Sprintf("gitea-diagnosis-%s.zip", time.Now().Format("20060102-150405")),
|
||||
ContentDisposition: httplib.ContentDispositionAttachment,
|
||||
})
|
||||
|
||||
zipWriter := zip.NewWriter(ctx.Resp)
|
||||
|
||||
@@ -93,7 +93,7 @@ func Emails(ctx *context.Context) {
|
||||
ctx.Data["Total"] = count
|
||||
ctx.Data["Emails"] = emails
|
||||
|
||||
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
|
||||
pager := context.NewPagination(count, opts.PageSize, opts.Page, 5)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ func Notices(ctx *context.Context) {
|
||||
|
||||
ctx.Data["Total"] = total
|
||||
|
||||
ctx.Data["Page"] = context.NewPagination(int(total), setting.UI.Admin.NoticePagingNum, page, 5)
|
||||
ctx.Data["Page"] = context.NewPagination(total, setting.UI.Admin.NoticePagingNum, page, 5)
|
||||
|
||||
ctx.HTML(http.StatusOK, tplNotices)
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func Organizations(ctx *context.Context) {
|
||||
|
||||
explore.RenderUserSearch(ctx, user_model.SearchUserOptions{
|
||||
Actor: ctx.Doer,
|
||||
Type: user_model.UserTypeOrganization,
|
||||
Types: []user_model.UserType{user_model.UserTypeOrganization},
|
||||
IncludeReserved: true, // administrator needs to list all accounts include reserved
|
||||
ListOptions: db.ListOptions{
|
||||
PageSize: setting.UI.Admin.OrgPagingNum,
|
||||
|
||||
@@ -73,7 +73,7 @@ func Packages(ctx *context.Context) {
|
||||
ctx.Data["TotalBlobSize"] = totalBlobSize - totalUnreferencedBlobSize
|
||||
ctx.Data["TotalUnreferencedBlobSize"] = totalUnreferencedBlobSize
|
||||
|
||||
pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5)
|
||||
pager := context.NewPagination(total, setting.UI.PackagesPagingNum, page, 5)
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
|
||||
@@ -93,7 +93,7 @@ func DeletePackageVersion(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("packages.settings.delete.success"))
|
||||
ctx.Flash.Success(ctx.Tr("packages.settings.delete.version.success"))
|
||||
ctx.JSONRedirect(setting.AppSubURL + "/-/admin/packages?page=" + url.QueryEscape(ctx.FormString("page")) + "&q=" + url.QueryEscape(ctx.FormString("q")) + "&type=" + url.QueryEscape(ctx.FormString("type")))
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ import (
|
||||
"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/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers/web/explore"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
@@ -134,12 +134,12 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
|
||||
ctx.ServerError("IsRepositoryExist", err)
|
||||
return
|
||||
}
|
||||
isDir, err := util.IsDir(repo_model.RepoPath(ctxUser.Name, repoName))
|
||||
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(repo_model.RelativePath(ctxUser.Name, repoName)))
|
||||
if err != nil {
|
||||
ctx.ServerError("IsDir", err)
|
||||
return
|
||||
}
|
||||
if has || !isDir {
|
||||
if has || !exist {
|
||||
// Fallthrough to failure mode
|
||||
} else if action == "adopt" {
|
||||
if _, err := repo_service.AdoptRepository(ctx, ctx.Doer, ctxUser, repo_service.CreateRepoOptions{
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
)
|
||||
|
||||
func RedirectToDefaultSetting(ctx *context.Context) {
|
||||
ctx.Redirect(setting.AppSubURL + "/-/admin/actions/runners")
|
||||
}
|
||||
@@ -67,7 +67,7 @@ func Users(ctx *context.Context) {
|
||||
|
||||
explore.RenderUserSearch(ctx, user_model.SearchUserOptions{
|
||||
Actor: ctx.Doer,
|
||||
Type: user_model.UserTypeIndividual,
|
||||
Types: []user_model.UserType{user_model.UserTypeIndividual},
|
||||
ListOptions: db.ListOptions{
|
||||
PageSize: setting.UI.Admin.UserPagingNum,
|
||||
},
|
||||
@@ -151,12 +151,12 @@ func NewUserPost(ctx *context.Context) {
|
||||
if u.LoginType == auth.NoType || u.LoginType == auth.Plain {
|
||||
if len(form.Password) < setting.MinPasswordLength {
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserNew, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserNew, &form)
|
||||
return
|
||||
}
|
||||
if !password.IsComplexEnough(form.Password) {
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(password.BuildComplexityError(ctx.Locale), tplUserNew, &form)
|
||||
ctx.RenderWithErrDeprecated(password.BuildComplexityError(ctx.Locale), tplUserNew, &form)
|
||||
return
|
||||
}
|
||||
if err := password.IsPwned(ctx, form.Password); err != nil {
|
||||
@@ -166,7 +166,7 @@ func NewUserPost(ctx *context.Context) {
|
||||
log.Error(err.Error())
|
||||
errMsg = ctx.Tr("auth.password_pwned_err")
|
||||
}
|
||||
ctx.RenderWithErr(errMsg, tplUserNew, &form)
|
||||
ctx.RenderWithErrDeprecated(errMsg, tplUserNew, &form)
|
||||
return
|
||||
}
|
||||
u.MustChangePassword = form.MustChangePassword
|
||||
@@ -176,22 +176,22 @@ func NewUserPost(ctx *context.Context) {
|
||||
switch {
|
||||
case user_model.IsErrUserAlreadyExist(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tplUserNew, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("form.username_been_taken"), tplUserNew, &form)
|
||||
case user_model.IsErrEmailAlreadyUsed(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserNew, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("form.email_been_used"), tplUserNew, &form)
|
||||
case user_model.IsErrEmailInvalid(err), user_model.IsErrEmailCharIsNotSupported(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("form.email_invalid"), tplUserNew, &form)
|
||||
case db.IsErrNameReserved(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(db.ErrNameReserved).Name), tplUserNew, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_reserved", err.(db.ErrNameReserved).Name), tplUserNew, &form)
|
||||
case db.IsErrNamePatternNotAllowed(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplUserNew, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplUserNew, &form)
|
||||
case db.IsErrNameCharsNotAllowed(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("user.form.name_chars_not_allowed", err.(db.ErrNameCharsNotAllowed).Name), tplUserNew, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_chars_not_allowed", err.(db.ErrNameCharsNotAllowed).Name), tplUserNew, &form)
|
||||
default:
|
||||
ctx.ServerError("CreateUser", err)
|
||||
}
|
||||
@@ -345,23 +345,23 @@ func EditUserPost(ctx *context.Context) {
|
||||
}
|
||||
|
||||
if form.UserName != "" {
|
||||
if err := user_service.RenameUser(ctx, u, form.UserName); err != nil {
|
||||
if err := user_service.RenameUser(ctx, u, form.UserName, ctx.Doer); err != nil {
|
||||
switch {
|
||||
case user_model.IsErrUserIsNotLocal(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.username_change_not_local_user"), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("form.username_change_not_local_user"), tplUserEdit, &form)
|
||||
case user_model.IsErrUserAlreadyExist(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("form.username_been_taken"), tplUserEdit, &form)
|
||||
case db.IsErrNameReserved(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", form.UserName), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_reserved", form.UserName), tplUserEdit, &form)
|
||||
case db.IsErrNamePatternNotAllowed(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", form.UserName), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_pattern_not_allowed", form.UserName), tplUserEdit, &form)
|
||||
case db.IsErrNameCharsNotAllowed(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("user.form.name_chars_not_allowed", form.UserName), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_chars_not_allowed", form.UserName), tplUserEdit, &form)
|
||||
default:
|
||||
ctx.ServerError("RenameUser", err)
|
||||
}
|
||||
@@ -392,16 +392,16 @@ func EditUserPost(ctx *context.Context) {
|
||||
switch {
|
||||
case errors.Is(err, password.ErrMinLength):
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserEdit, &form)
|
||||
case errors.Is(err, password.ErrComplexity):
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(password.BuildComplexityError(ctx.Locale), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(password.BuildComplexityError(ctx.Locale), tplUserEdit, &form)
|
||||
case errors.Is(err, password.ErrIsPwned):
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("auth.password_pwned", "https://haveibeenpwned.com/Passwords"), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_pwned", "https://haveibeenpwned.com/Passwords"), tplUserEdit, &form)
|
||||
case password.IsErrIsPwnedRequest(err):
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_pwned_err"), tplUserEdit, &form)
|
||||
default:
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
}
|
||||
@@ -413,10 +413,10 @@ func EditUserPost(ctx *context.Context) {
|
||||
switch {
|
||||
case user_model.IsErrEmailCharIsNotSupported(err), user_model.IsErrEmailInvalid(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("form.email_invalid"), tplUserEdit, &form)
|
||||
case user_model.IsErrEmailAlreadyUsed(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("form.email_been_used"), tplUserEdit, &form)
|
||||
default:
|
||||
ctx.ServerError("AddOrSetPrimaryEmailAddress", err)
|
||||
}
|
||||
@@ -444,7 +444,7 @@ func EditUserPost(ctx *context.Context) {
|
||||
|
||||
if err := user_service.UpdateUser(ctx, u, opts); err != nil {
|
||||
if user_model.IsErrDeleteLastAdminUser(err) {
|
||||
ctx.RenderWithErr(ctx.Tr("auth.last_admin"), tplUserEdit, &form)
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("auth.last_admin"), tplUserEdit, &form)
|
||||
} else {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user