Skip to content

Commit 0c547f0

Browse files
committed
Merge remote-tracking branch 'origin/main' into fix-9691-configure-ssl-cipher-suites
2 parents 94500d5 + 01fc24c commit 0c547f0

File tree

18 files changed

+241
-104
lines changed

18 files changed

+241
-104
lines changed

Dockerfile.rootless

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ RUN chown git:git /var/lib/gitea /etc/gitea
5555
COPY docker/rootless /
5656
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /usr/local/bin/gitea
5757
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
58-
RUN chmod 755 /usr/local/bin/docker-entrypoint.sh /app/gitea/gitea /usr/local/bin/environment-to-ini /usr/local/bin/docker-setup.sh
58+
RUN chmod 755 /usr/local/bin/docker-entrypoint.sh /usr/local/bin/docker-setup.sh /usr/local/bin/gitea /usr/local/bin/environment-to-ini
5959

6060
#git:git
6161
USER 1000:1000

modules/csv/csv.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ var quoteRegexp = regexp.MustCompile(`["'][\s\S]+?["']`)
2222
func CreateReader(input io.Reader, delimiter rune) *stdcsv.Reader {
2323
rd := stdcsv.NewReader(input)
2424
rd.Comma = delimiter
25-
rd.TrimLeadingSpace = true
25+
if delimiter != '\t' && delimiter != ' ' {
26+
// TrimLeadingSpace can't be true when delimiter is a tab or a space as the value for a column might be empty,
27+
// thus would change `\t\t` to just `\t` or ` ` (two spaces) to just ` ` (single space)
28+
rd.TrimLeadingSpace = true
29+
}
2630
return rd
2731
}
2832

modules/csv/csv_test.go

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,57 @@ func TestCreateReader(t *testing.T) {
1717
assert.Equal(t, ',', rd.Comma)
1818
}
1919

20+
//nolint
2021
func TestCreateReaderAndGuessDelimiter(t *testing.T) {
21-
input := "a;b;c\n1;2;3\n4;5;6"
22+
var csvToRowsMap = map[string][][]string{
23+
`a;b;c
24+
1;2;3
25+
4;5;6`: {{"a", "b", "c"}, {"1", "2", "3"}, {"4", "5", "6"}},
26+
`col1 col2 col3
27+
a b c
28+
e f
29+
g h i
30+
j l
31+
m n
32+
p q r
33+
u
34+
v w x
35+
y
36+
`: {{"col1", "col2", "col3"},
37+
{"a", "b", "c"},
38+
{"", "e", "f"},
39+
{"g", "h", "i"},
40+
{"j", "", "l"},
41+
{"m", "n", ""},
42+
{"p", "q", "r"},
43+
{"", "", "u"},
44+
{"v", "w", "x"},
45+
{"y", "", ""},
46+
{"", "", ""}},
47+
` col1,col2,col3
48+
a, b, c
49+
d,e,f
50+
,h, i
51+
j, ,
52+
, , `: {{"col1", "col2", "col3"},
53+
{"a", "b", "c"},
54+
{"d", "e", "f"},
55+
{"", "h", "i"},
56+
{"j", "", ""},
57+
{"", "", ""}},
58+
}
2259

23-
rd, err := CreateReaderAndGuessDelimiter(strings.NewReader(input))
24-
assert.NoError(t, err)
25-
assert.Equal(t, ';', rd.Comma)
60+
for csv, expectedRows := range csvToRowsMap {
61+
rd, err := CreateReaderAndGuessDelimiter(strings.NewReader(csv))
62+
assert.NoError(t, err)
63+
rows, err := rd.ReadAll()
64+
assert.NoError(t, err)
65+
assert.EqualValues(t, rows, expectedRows)
66+
}
2667
}
2768

2869
func TestGuessDelimiter(t *testing.T) {
29-
var kases = map[string]rune{
70+
var csvToDelimiterMap = map[string]rune{
3071
"a": ',',
3172
"1,2": ',',
3273
"1;2": ';',
@@ -37,7 +78,7 @@ func TestGuessDelimiter(t *testing.T) {
3778
"<br/>": ',',
3879
}
3980

40-
for k, v := range kases {
41-
assert.EqualValues(t, guessDelimiter([]byte(k)), v)
81+
for csv, expectedDelimiter := range csvToDelimiterMap {
82+
assert.EqualValues(t, guessDelimiter([]byte(csv)), expectedDelimiter)
4283
}
4384
}

options/locale/locale_en-US.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ form.name_chars_not_allowed = User name '%s' contains invalid characters.
490490
[settings]
491491
profile = Profile
492492
account = Account
493+
appearance = Appearance
493494
password = Password
494495
security = Security
495496
avatar = Avatar
@@ -514,7 +515,9 @@ website = Website
514515
location = Location
515516
update_theme = Update Theme
516517
update_profile = Update Profile
518+
update_language = Update Language
517519
update_language_not_found = Language '%s' is not available.
520+
update_language_success = Language has been updated.
518521
update_profile_success = Your profile has been updated.
519522
change_username = Your username has been changed.
520523
change_username_prompt = Note: username changes also change your account URL.

routers/web/user/setting/account.go

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -257,34 +257,6 @@ func DeleteAccount(ctx *context.Context) {
257257
}
258258
}
259259

260-
// UpdateUIThemePost is used to update users' specific theme
261-
func UpdateUIThemePost(ctx *context.Context) {
262-
form := web.GetForm(ctx).(*forms.UpdateThemeForm)
263-
ctx.Data["Title"] = ctx.Tr("settings")
264-
ctx.Data["PageIsSettingsAccount"] = true
265-
266-
if ctx.HasError() {
267-
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
268-
return
269-
}
270-
271-
if !form.IsThemeExists() {
272-
ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
273-
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
274-
return
275-
}
276-
277-
if err := ctx.User.UpdateTheme(form.Theme); err != nil {
278-
ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
279-
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
280-
return
281-
}
282-
283-
log.Trace("Update user theme: %s", ctx.User.Name)
284-
ctx.Flash.Success(ctx.Tr("settings.theme_update_success"))
285-
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
286-
}
287-
288260
func loadAccountData(ctx *context.Context) {
289261
emlist, err := models.GetEmailAddresses(ctx.User.ID)
290262
if err != nil {

routers/web/user/setting/profile.go

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232

3333
const (
3434
tplSettingsProfile base.TplName = "user/settings/profile"
35+
tplSettingsAppearance base.TplName = "user/settings/appearance"
3536
tplSettingsOrganization base.TplName = "user/settings/organization"
3637
tplSettingsRepositories base.TplName = "user/settings/repos"
3738
)
@@ -115,14 +116,6 @@ func ProfilePost(ctx *context.Context) {
115116
ctx.User.KeepEmailPrivate = form.KeepEmailPrivate
116117
ctx.User.Website = form.Website
117118
ctx.User.Location = form.Location
118-
if len(form.Language) != 0 {
119-
if !util.IsStringInSlice(form.Language, setting.Langs) {
120-
ctx.Flash.Error(ctx.Tr("settings.update_language_not_found", form.Language))
121-
ctx.Redirect(setting.AppSubURL + "/user/settings")
122-
return
123-
}
124-
ctx.User.Language = form.Language
125-
}
126119
ctx.User.Description = form.Description
127120
ctx.User.KeepActivityPrivate = form.KeepActivityPrivate
128121
ctx.User.Visibility = form.Visibility
@@ -329,3 +322,68 @@ func Repos(ctx *context.Context) {
329322
ctx.Data["Page"] = pager
330323
ctx.HTML(http.StatusOK, tplSettingsRepositories)
331324
}
325+
326+
// Appearance render user's appearance settings
327+
func Appearance(ctx *context.Context) {
328+
ctx.Data["Title"] = ctx.Tr("settings")
329+
ctx.Data["PageIsSettingsAppearance"] = true
330+
331+
ctx.HTML(http.StatusOK, tplSettingsAppearance)
332+
}
333+
334+
// UpdateUIThemePost is used to update users' specific theme
335+
func UpdateUIThemePost(ctx *context.Context) {
336+
form := web.GetForm(ctx).(*forms.UpdateThemeForm)
337+
ctx.Data["Title"] = ctx.Tr("settings")
338+
ctx.Data["PageIsSettingsAppearance"] = true
339+
340+
if ctx.HasError() {
341+
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
342+
return
343+
}
344+
345+
if !form.IsThemeExists() {
346+
ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
347+
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
348+
return
349+
}
350+
351+
if err := ctx.User.UpdateTheme(form.Theme); err != nil {
352+
ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
353+
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
354+
return
355+
}
356+
357+
log.Trace("Update user theme: %s", ctx.User.Name)
358+
ctx.Flash.Success(ctx.Tr("settings.theme_update_success"))
359+
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
360+
}
361+
362+
// UpdateUserLang update a user's language
363+
func UpdateUserLang(ctx *context.Context) {
364+
form := web.GetForm(ctx).(*forms.UpdateLanguageForm)
365+
ctx.Data["Title"] = ctx.Tr("settings")
366+
ctx.Data["PageIsSettingsAppearance"] = true
367+
368+
if len(form.Language) != 0 {
369+
if !util.IsStringInSlice(form.Language, setting.Langs) {
370+
ctx.Flash.Error(ctx.Tr("settings.update_language_not_found", form.Language))
371+
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
372+
return
373+
}
374+
ctx.User.Language = form.Language
375+
}
376+
377+
if err := models.UpdateUserSetting(ctx.User); err != nil {
378+
ctx.ServerError("UpdateUserSetting", err)
379+
return
380+
}
381+
382+
// Update the language to the one we just set
383+
middleware.SetLocaleCookie(ctx.Resp, ctx.User.Language, 0)
384+
385+
log.Trace("User settings updated: %s", ctx.User.Name)
386+
ctx.Flash.Success(i18n.Tr(ctx.User.Language, "settings.update_language_success"))
387+
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
388+
389+
}

routers/web/web.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ func RegisterRoutes(m *web.Route) {
317317
m.Post("/email", bindIgnErr(forms.AddEmailForm{}), userSetting.EmailPost)
318318
m.Post("/email/delete", userSetting.DeleteEmail)
319319
m.Post("/delete", userSetting.DeleteAccount)
320+
})
321+
m.Group("/appearance", func() {
322+
m.Get("", userSetting.Appearance)
323+
m.Post("/language", bindIgnErr(forms.UpdateLanguageForm{}), userSetting.UpdateUserLang)
320324
m.Post("/theme", bindIgnErr(forms.UpdateThemeForm{}), userSetting.UpdateUIThemePost)
321325
})
322326
m.Group("/security", func() {

services/forms/user_form.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,6 @@ type UpdateProfileForm struct {
240240
KeepEmailPrivate bool
241241
Website string `binding:"ValidSiteUrl;MaxSize(255)"`
242242
Location string `binding:"MaxSize(50)"`
243-
Language string
244243
Description string `binding:"MaxSize(255)"`
245244
Visibility structs.VisibleType
246245
KeepActivityPrivate bool
@@ -252,6 +251,17 @@ func (f *UpdateProfileForm) Validate(req *http.Request, errs binding.Errors) bin
252251
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
253252
}
254253

254+
// UpdateLanguageForm form for updating profile
255+
type UpdateLanguageForm struct {
256+
Language string
257+
}
258+
259+
// Validate validates the fields
260+
func (f *UpdateLanguageForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
261+
ctx := context.GetContext(req)
262+
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
263+
}
264+
255265
// Avatar types
256266
const (
257267
AvatarLocal string = "local"

templates/repo/diff/box.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
{{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}}
6060
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} mt-3" id="diff-{{.Index}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if $file.IsGenerated}}data-folded="true"{{end}}>
6161
<h4 class="diff-file-header sticky-2nd-row ui top attached normal header df ac sb">
62-
<div class="fold-file df ac">
62+
<div class="df ac">
6363
<a role="button" class="fold-file muted mr-2">
6464
{{if $file.IsGenerated}}
6565
{{svg "octicon-chevron-right" 18}}

templates/repo/wiki/new.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
</div>
2323
<div class="field content" data-loading="{{.i18n.Tr "loading"}}">
2424
<div class="ui bottom active tab" data-tab="write">
25-
<textarea class="js-quick-submit" id="edit_area" name="content" data-id="wiki-{{.title}}" data-url="{{.Repository.APIURL}}/markdown" data-context="{{.RepoLink}}" required>{{if .PageIsUncycloEdit}}{{.content}}{{else}}{{.i18n.Tr "repo.wiki.welcome"}}{{end}}</textarea>
25+
<textarea class="js-quick-submit" id="edit_area" name="content" data-id="wiki-{{.title}}" data-url="{{.Repository.APIURL}}/markdown" data-context="{{.RepoLink}}">{{if .PageIsUncycloEdit}}{{.content}}{{else}}{{.i18n.Tr "repo.wiki.welcome"}}{{end}}</textarea>
2626
</div>
2727
</div>
2828
<div class="field">

templates/user/settings/account.tmpl

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -130,44 +130,6 @@
130130
</form>
131131
</div>
132132

133-
<h4 class="ui top attached header">
134-
{{.i18n.Tr "settings.manage_themes"}}
135-
</h4>
136-
<div class="ui attached segment">
137-
<div class="ui email list">
138-
<div class="item">
139-
{{.i18n.Tr "settings.theme_desc"}}
140-
</div>
141-
142-
<form class="ui form" action="{{.Link}}/theme" method="post">
143-
{{.CsrfTokenHtml}}
144-
<div class="field">
145-
<label for="ui">{{.i18n.Tr "settings.ui"}}</label>
146-
<div class="ui selection dropdown" id="ui">
147-
<input name="theme" type="hidden" value="{{.SignedUser.Theme}}">
148-
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
149-
<div class="text">
150-
{{range $i,$a := .AllThemes}}
151-
{{if eq $.SignedUser.Theme $a}}{{$a}}{{end}}
152-
{{end}}
153-
</div>
154-
155-
<div class="menu">
156-
{{range $i,$a := .AllThemes}}
157-
<div class="item{{if eq $.SignedUser.Theme $a}} active selected{{end}}" data-value="{{$a}}">
158-
{{$a}}
159-
</div>
160-
{{end}}
161-
</div>
162-
</div>
163-
</div>
164-
165-
<div class="field">
166-
<button class="ui green button">{{$.i18n.Tr "settings.update_theme"}}</button>
167-
</div>
168-
</form>
169-
</div>
170-
</div>
171133
<h4 class="ui top attached error header">
172134
{{.i18n.Tr "settings.delete_account"}}
173135
</h4>

0 commit comments

Comments
 (0)