Skip to content

Commit b4f39e4

Browse files
committed
Update
1 parent 1a9edf7 commit b4f39e4

File tree

10 files changed

+368
-99
lines changed

10 files changed

+368
-99
lines changed

custom/conf/app.example.ini

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,71 +1258,91 @@ LEVEL = Info
12581258
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12591259
;;
12601260
;; Number of repositories that are displayed on one explore page
1261+
;; Deprecated in v1.24
12611262
;EXPLORE_PAGING_NUM = 20
12621263
;;
12631264
;; Number of issues that are displayed on one page
1265+
;; Deprecated in v1.24
12641266
;ISSUE_PAGING_NUM = 20
12651267
;;
12661268
;; Number of maximum commits displayed in one activity feed
1269+
;; Deprecated in v1.24
12671270
;FEED_MAX_COMMIT_NUM = 5
12681271
;;
12691272
;; Number of items that are displayed in home feed
1273+
;; Deprecated in v1.24
12701274
;FEED_PAGING_NUM = 20
12711275
;;
12721276
;; Number of items that are displayed in a single subsitemap
1277+
;; Deprecated in v1.24
12731278
;SITEMAP_PAGING_NUM = 20
12741279
;;
12751280
;; Number of maximum commits displayed in commit graph.
1281+
;; Deprecated in v1.24
12761282
;GRAPH_MAX_COMMIT_NUM = 100
12771283
;;
12781284
;; Number of line of codes shown for a code comment
1285+
;; Deprecated in v1.24
12791286
;CODE_COMMENT_LINES = 4
12801287
;;
12811288
;; Max size of files to be displayed (default is 8MiB)
1289+
;; Deprecated in v1.24
12821290
;MAX_DISPLAY_FILE_SIZE = 8388608
12831291
;;
12841292
;; Detect ambiguous unicode characters in file contents and show warnings on the UI
1293+
;; Deprecated in v1.24
12851294
;AMBIGUOUS_UNICODE_DETECTION = true
12861295
;;
12871296
;; Whether the email of the user should be shown in the Explore Users page
1297+
;; Deprecated in v1.24
12881298
;SHOW_USER_EMAIL = true
12891299
;;
12901300
;; Set the default theme for the Gitea install
1301+
;; Deprecated in v1.24
12911302
;DEFAULT_THEME = gitea-auto
12921303
;;
12931304
;; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`.
12941305
;; Leave it empty to allow users to select any theme from "{CustomPath}/public/assets/css/theme-*.css"
1306+
;; Deprecated in v1.24
12951307
;THEMES =
12961308
;;
12971309
;; All available reactions users can choose on issues/prs and comments.
12981310
;; Values can be emoji alias (:smile:) or a unicode emoji.
12991311
;; For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png
1312+
;; Deprecated in v1.24
13001313
;REACTIONS = +1, -1, laugh, hooray, confused, heart, rocket, eyes
13011314
;;
13021315
;; Change the number of users that are displayed in reactions tooltip (triggered by mouse hover).
1316+
;; Deprecated in v1.24
13031317
;REACTION_MAX_USER_NUM = 10
13041318
;;
13051319
;; Additional Emojis not defined in the utf8 standard
13061320
;; By default we support gitea (:gitea:), to add more copy them to public/assets/img/emoji/emoji_name.png and add it to this config.
13071321
;; Dont mistake it for Reactions.
1322+
;; Deprecated in v1.24
13081323
;CUSTOM_EMOJIS = gitea, codeberg, gitlab, git, github, gogs
13091324
;;
13101325
;; Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
1326+
;; Deprecated in v1.24
13111327
;DEFAULT_SHOW_FULL_NAME = false
13121328
;;
13131329
;; Whether to search within description at repository search on explore page.
1330+
;; Deprecated in v1.24
13141331
;SEARCH_REPO_DESCRIPTION = true
13151332
;;
13161333
;; Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
13171334
;; A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
1335+
;; Deprecated in v1.24
13181336
;ONLY_SHOW_RELEVANT_REPOS = false
13191337
;;
13201338
;; Change the sort type of the explore pages.
13211339
;; Default is "recentupdate", but you also have "alphabetically", "reverselastlogin", "newest", "oldest".
1340+
;; Deprecated in v1.24
13221341
;EXPLORE_PAGING_DEFAULT_SORT = recentupdate
13231342
;;
13241343
;; The tense all timestamps should be rendered in. Possible values are `absolute` time (i.e. 1970-01-01, 11:59) and `mixed`.
13251344
;; `mixed` means most timestamps are rendered in relative time (i.e. 2 days ago).
1345+
;; Deprecated in v1.24
13261346
;PREFERRED_TIMESTAMP_TENSE = mixed
13271347

13281348
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

models/migrations/migrations.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ func prepareMigrationTasks() []*migration {
374374
// Gitea 1.23.0-rc0 ends at migration ID number 311 (database version 312)
375375
newMigration(312, "Add DeleteBranchAfterMerge to AutoMerge", v1_24.AddDeleteBranchAfterMergeForAutoMerge),
376376
newMigration(313, "Move PinOrder from issue table to a new table issue_pin", v1_24.MovePinOrderToTableIssuePin),
377+
newMigration(314, "Migrate the configuration of the ui section of the ini configuration file to the system setting table.", v1_24.MigrateIniToDatabase),
377378
}
378379
return preparedMigrations
379380
}

models/migrations/v1_24/v314.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_24 //nolint
5+
6+
import (
7+
"math"
8+
9+
system_model "code.gitea.io/gitea/models/system"
10+
"code.gitea.io/gitea/modules/setting"
11+
"code.gitea.io/gitea/modules/timeutil"
12+
"code.gitea.io/gitea/modules/util"
13+
14+
"xorm.io/xorm"
15+
)
16+
17+
const keyRevision = "revision"
18+
19+
type Setting struct {
20+
ID int64 `xorm:"pk autoincr"`
21+
SettingKey string `xorm:"varchar(255) unique"` // key should be lowercase
22+
SettingValue string `xorm:"text"`
23+
Version int `xorm:"version"`
24+
Created timeutil.TimeStamp `xorm:"created"`
25+
Updated timeutil.TimeStamp `xorm:"updated"`
26+
}
27+
28+
// TableName sets the table name for the settings struct
29+
func (s *Setting) TableName() string {
30+
return "system_setting"
31+
}
32+
33+
func MigrateIniToDatabase(x *xorm.Engine) error {
34+
uiMap, err := util.ConfigSectionToMap(setting.UI, "ui")
35+
if err != nil {
36+
return err
37+
}
38+
39+
sess := x.NewSession()
40+
defer sess.Close()
41+
42+
if err = sess.Begin(); err != nil {
43+
return err
44+
}
45+
46+
_ = GetRevision(sess) // prepare the "revision" key ahead
47+
48+
_, err = sess.Exec("UPDATE system_setting SET version=version+1 WHERE setting_key=?", keyRevision)
49+
if err != nil {
50+
return err
51+
}
52+
for k, v := range uiMap {
53+
res, err := sess.Exec("UPDATE system_setting SET version=version+1, setting_value=? WHERE setting_key=?", v, k)
54+
if err != nil {
55+
return err
56+
}
57+
rows, _ := res.RowsAffected()
58+
if rows == 0 { // if no existing row, insert a new row
59+
if _, err = sess.Insert(&system_model.Setting{SettingKey: k, SettingValue: v}); err != nil {
60+
return err
61+
}
62+
}
63+
}
64+
65+
return sess.Commit()
66+
}
67+
68+
func GetRevision(sess *xorm.Session) int {
69+
revision := &Setting{}
70+
exist, err := sess.Where("setting_key = ?", keyRevision).Get(revision)
71+
if err != nil {
72+
return 0
73+
} else if !exist {
74+
_, err = sess.Insert(&Setting{SettingKey: keyRevision, Version: 1})
75+
if err != nil {
76+
return 0
77+
}
78+
return 1
79+
}
80+
81+
if revision.Version <= 0 || revision.Version >= math.MaxInt-1 {
82+
_, err = sess.Exec("UPDATE system_setting SET version=1 WHERE setting_key=?", keyRevision)
83+
if err != nil {
84+
return 0
85+
}
86+
return 1
87+
}
88+
return revision.Version
89+
}

modules/util/util.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ package util
66
import (
77
"bytes"
88
"crypto/rand"
9+
"encoding/json"
910
"fmt"
1011
"math/big"
12+
"reflect"
1113
"strconv"
1214
"strings"
1315

@@ -257,3 +259,38 @@ func ReserveLineBreakForTextarea(input string) string {
257259
// Other than this, we should respect the original content, even leading or trailing spaces.
258260
return strings.ReplaceAll(input, "\r\n", "\n")
259261
}
262+
263+
func ConfigSectionToMap(in any, keyPrefix string) (map[string]string, error) {
264+
if keyPrefix == "" {
265+
return nil, fmt.Errorf("keyPrefix is empty")
266+
}
267+
out := map[string]string{}
268+
269+
v := reflect.ValueOf(in)
270+
if v.Kind() == reflect.Ptr {
271+
v = v.Elem()
272+
}
273+
if v.Kind() != reflect.Struct {
274+
return nil, fmt.Errorf("in is not a struct")
275+
}
276+
277+
t := v.Type()
278+
for i := 0; i < v.NumField(); i++ {
279+
fi := t.Field(i)
280+
if tagValue := fi.Tag.Get("ini"); tagValue == "-" {
281+
continue
282+
}
283+
switch v.FieldByName(fi.Name).Kind() {
284+
case reflect.Bool,
285+
reflect.String,
286+
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
287+
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
288+
out[fmt.Sprintf("%s.%s", keyPrefix, ToSnakeCase(fi.Name))] = fmt.Sprintf("%v", v.FieldByName(fi.Name).Interface())
289+
case reflect.Slice, reflect.Array:
290+
str, _ := json.Marshal(v.FieldByName(fi.Name))
291+
out[fmt.Sprintf("%s.%s", keyPrefix, ToSnakeCase(fi.Name))] = string(str)
292+
}
293+
}
294+
295+
return out, nil
296+
}

options/locale/locale_en-US.ini

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3360,6 +3360,26 @@ config.picture_service = Picture Service
33603360
config.disable_gravatar = Disable Gravatar
33613361
config.enable_federated_avatar = Enable Federated Avatars
33623362
config.open_with_editor_app_help = The "Open with" editors for the clone menu. If left empty, the default will be used. Expand to see the default.
3363+
config.ui.explore_paging_num = Explore Paging Number
3364+
config.ui.issue_paging_num = Issue Paging Number
3365+
config.ui.feed_max_commit_numb = Feed Max Commit Number
3366+
config.ui.feed_paging_num = Feed Paging Number
3367+
config.ui.sitemap_paging_num = Sitemap Paging Number
3368+
config.ui.graph_max_commit_num = Graph Max Commit Number
3369+
config.ui.code_comment_lines = Code Comment Lines
3370+
config.ui.max_display_file_size = Max Display File Size
3371+
config.ui.default_theme = Default Theme
3372+
config.ui.themes = Themes
3373+
config.ui.reactions = Reactions
3374+
config.ui.reaction_max_user_num = Reaction Max User Number
3375+
config.ui.custom_emojis = Custom Emojis
3376+
config.ui.explore_paging_default_sort = Explore Paging Default Sort
3377+
config.ui.ambiguous_unicode_detection = Ambiguous Unicode Detection
3378+
config.ui.show_user_email = Show User Email
3379+
config.ui.default_show_full_name = Default Show Full Name
3380+
config.ui.search_repo_description = Search Repo Description
3381+
config.ui.only_show_relevant_repos = Only Show Relevant Repos
3382+
config.ui.preferred_timestamp_tense = Preferred Timestamp Tense
33633383
33643384
config.git_config = Git Configuration
33653385
config.git_disable_diff_highlight = Disable Diff Syntax Highlight

routers/web/admin/config.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ import (
1919
"code.gitea.io/gitea/modules/setting/config"
2020
"code.gitea.io/gitea/modules/templates"
2121
"code.gitea.io/gitea/modules/util"
22+
"code.gitea.io/gitea/modules/web"
2223
"code.gitea.io/gitea/services/context"
24+
"code.gitea.io/gitea/services/forms"
2325
"code.gitea.io/gitea/services/mailer"
2426

2527
"gitea.com/go-chi/session"
@@ -191,6 +193,7 @@ func ConfigSettings(ctx *context.Context) {
191193
ctx.Data["Title"] = ctx.Tr("admin.config_settings")
192194
ctx.Data["PageIsAdminConfig"] = true
193195
ctx.Data["PageIsAdminConfigSettings"] = true
196+
ctx.Data["UI"] = setting.UI
194197
ctx.Data["DefaultOpenWithEditorAppsString"] = setting.DefaultOpenWithEditorApps().ToTextareaString()
195198
ctx.HTML(http.StatusOK, tplConfigSettings)
196199
}
@@ -253,3 +256,22 @@ func ChangeConfig(ctx *context.Context) {
253256
config.GetDynGetter().InvalidateCache()
254257
ctx.JSONOK()
255258
}
259+
260+
func ChangeUIConfig(ctx *context.Context) {
261+
form := web.GetForm(ctx).(*forms.UIForm)
262+
formMap, err := util.ConfigSectionToMap(form, "ui")
263+
if err != nil {
264+
ctx.ServerError("unable convert struct to map[string]string", err)
265+
return
266+
}
267+
268+
log.Debug("ChangeUIConfig form: %+v", formMap)
269+
270+
if err = system_model.SetSettings(ctx, formMap); err != nil {
271+
log.Error("set ui configuration failed: %v", err)
272+
ctx.ServerError("SetSettings", err)
273+
return
274+
}
275+
276+
ctx.Redirect(setting.AppSubURL + "/-/admin/config/settings")
277+
}

routers/web/web.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ func registerRoutes(m *web.Router) {
720720
m.Group("/config", func() {
721721
m.Get("", admin.Config)
722722
m.Post("", admin.ChangeConfig)
723+
m.Post("/ui", web.Bind(forms.UIForm{}), admin.ChangeUIConfig)
723724
m.Post("/test_mail", admin.SendTestMail)
724725
m.Post("/test_cache", admin.TestCache)
725726
m.Get("/settings", admin.ConfigSettings)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package forms
2+
3+
import (
4+
"net/http"
5+
6+
"code.gitea.io/gitea/modules/web/middleware"
7+
"code.gitea.io/gitea/services/context"
8+
"gitea.com/go-chi/binding"
9+
)
10+
11+
type UIForm struct {
12+
ExplorePagingNum int
13+
SitemapPagingNum int
14+
IssuePagingNum int
15+
RepoSearchPagingNum int
16+
MembersPagingNum int
17+
FeedMaxCommitNum int
18+
FeedPagingNum int
19+
PackagesPagingNum int
20+
GraphMaxCommitNum int
21+
CodeCommentLines int
22+
ReactionMaxUserNum int
23+
MaxDisplayFileSize int64
24+
ShowUserEmail bool
25+
DefaultShowFullName bool
26+
DefaultTheme string
27+
Themes []string
28+
Reactions []string
29+
CustomEmojis []string
30+
SearchRepoDescription bool
31+
OnlyShowRelevantRepos bool
32+
ExploreDefaultSort string `binding:"In(recentupdate,alphabetically,reverselastlogin,newest,oldest)"`
33+
PreferredTimestampTense string `binding:"In(mixed,absolute)"`
34+
35+
AmbiguousUnicodeDetection bool
36+
}
37+
38+
// Validate validates fields
39+
func (f *UIForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
40+
ctx := context.GetValidateContext(req)
41+
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
42+
}

0 commit comments

Comments
 (0)