Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added user language setting #3875

Merged
merged 20 commits into from
May 5, 2018
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
14 changes: 8 additions & 6 deletions integrations/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ func TestRenameUsername(t *testing.T) {

session := loginUser(t, "user2")
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
"_csrf": GetCSRF(t, session, "/user/settings"),
"name": "newUsername",
"email": "user2@example.com",
"_csrf": GetCSRF(t, session, "/user/settings"),
"name": "newUsername",
"email": "user2@example.com",
"language": "en-us",
})
session.MakeRequest(t, req, http.StatusFound)

Expand Down Expand Up @@ -81,9 +82,10 @@ func TestRenameReservedUsername(t *testing.T) {
for _, reservedUsername := range reservedUsernames {
t.Logf("Testing username %s", reservedUsername)
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
"_csrf": GetCSRF(t, session, "/user/settings"),
"name": reservedUsername,
"email": "user2@example.com",
"_csrf": GetCSRF(t, session, "/user/settings"),
"name": reservedUsername,
"email": "user2@example.com",
"language": "en-us",
})
resp := session.MakeRequest(t, req, http.StatusFound)

Expand Down
1 change: 1 addition & 0 deletions integrations/xss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestXSSUserFullName(t *testing.T) {
"name": user.Name,
"full_name": fullName,
"email": user.Email,
"language": "en-us",
})
session.MakeRequest(t, req, http.StatusFound)

Expand Down
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ var migrations = []Migration{
NewMigration("add size column for attachments", addSizeToAttachment),
// v62 -> v63
NewMigration("add last used passcode column for TOTP", addLastUsedPasscodeTOTP),
// v63 -> v64
NewMigration("add language column for user setting", addLanguageSetting),
}

// Migrate database to current version
Expand Down
23 changes: 23 additions & 0 deletions models/migrations/v63.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package migrations

import (
"fmt"

"github.com/go-xorm/xorm"
)

func addLanguageSetting(x *xorm.Engine) error {
type User struct {
Language string `xorm:"VARCHAR(5)"`
}

if err := x.Sync2(new(User)); err != nil {
return fmt.Errorf("Sync2: %v", err)
}

return nil
}
2 changes: 2 additions & 0 deletions models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ type User struct {
Website string
Rands string `xorm:"VARCHAR(10)"`
Salt string `xorm:"VARCHAR(10)"`
Language string `xorm:"VARCHAR(5)"`

CreatedUnix util.TimeStamp `xorm:"INDEX created"`
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
Expand Down Expand Up @@ -185,6 +186,7 @@ func (u *User) APIFormat() *api.User {
FullName: u.FullName,
Email: u.getEmail(),
AvatarURL: u.AvatarLink(),
Language: u.Language,
}
}

Expand Down
1 change: 1 addition & 0 deletions modules/auth/user_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ type UpdateProfileForm struct {
KeepEmailPrivate bool
Website string `binding:"ValidUrl;MaxSize(255)"`
Location string `binding:"MaxSize(50)"`
Language string `binding:"Size(5)"`
}

// Validate validates the fields
Expand Down
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ change_username = Your username has been changed.
change_username_prompt = Note: username changes also change your account URL.
continue = Continue
cancel = Cancel
language = Language

lookup_avatar_by_mail = Look Up Avatar by Email Address
federated_avatar_lookup = Federated Avatar Lookup
Expand Down
5 changes: 5 additions & 0 deletions public/swagger.v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -7318,6 +7318,11 @@
"format": "int64",
"x-go-name": "ID"
},
"language": {
"description": "User locale",
"type": "string",
"x-go-name": "Language"
},
"login": {
"description": "the user's username",
"type": "string",
Expand Down
13 changes: 13 additions & 0 deletions routers/user/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,18 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
ctx.Session.Set("uid", u.ID)
ctx.Session.Set("uname", u.Name)

// Language setting of the user overwrites the one previously set
// If the user does not have a locale set, we save the current one.
if len(u.Language) == 0 {
u.Language = ctx.Locale.Language()
if err := models.UpdateUser(u); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should only update language column but not all the columns.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed that.

log.Error(4, fmt.Sprintf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language))
return
}
}

ctx.SetCookie("lang", u.Language, nil, setting.AppSubURL)

// Clear whatever CSRF has right now, force to generate a new one
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL)

Expand Down Expand Up @@ -704,6 +716,7 @@ func SignOut(ctx *context.Context) {
ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL)
ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL)
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL)
ctx.SetCookie("lang", "", -1, setting.AppSubURL) // Setting the lang cookie will trigger the middleware to reset the language ot previous state.
ctx.Redirect(setting.AppSubURL + "/")
}

Expand Down
7 changes: 6 additions & 1 deletion routers/user/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"strings"

"github.com/Unknwon/com"
"github.com/Unknwon/i18n"
"github.com/pquerna/otp"
"github.com/pquerna/otp/totp"

Expand Down Expand Up @@ -105,6 +106,7 @@ func SettingsPost(ctx *context.Context, form auth.UpdateProfileForm) {
ctx.User.KeepEmailPrivate = form.KeepEmailPrivate
ctx.User.Website = form.Website
ctx.User.Location = form.Location
ctx.User.Language = form.Language
if err := models.UpdateUserSetting(ctx.User); err != nil {
if _, ok := err.(models.ErrEmailAlreadyUsed); ok {
ctx.Flash.Error(ctx.Tr("form.email_been_used"))
Expand All @@ -115,8 +117,11 @@ func SettingsPost(ctx *context.Context, form auth.UpdateProfileForm) {
return
}

// Update the language to the one we just set
ctx.SetCookie("lang", ctx.User.Language, nil, setting.AppSubURL)

log.Trace("User settings updated: %s", ctx.User.Name)
ctx.Flash.Success(ctx.Tr("settings.update_profile_success"))
ctx.Flash.Success(i18n.Tr(ctx.User.Language, "settings.update_profile_success"))
ctx.Redirect(setting.AppSubURL + "/user/settings")
}

Expand Down
14 changes: 14 additions & 0 deletions templates/user/settings/profile.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@
<input id="location" name="location" value="{{.SignedUser.Location}}">
</div>

<div class="field">
<label for="language">{{.i18n.Tr "settings.language"}}</label>
<div class="ui language selection dropdown" id="language">
<input name="language" type="hidden">
<i class="dropdown icon"></i>
<div class="text">{{range .AllLangs}}{{if eq $.SignedUser.Language .Lang}}{{.Name}}{{end}}{{end}}</div>
<div class="menu">
{{range .AllLangs}}
<div class="item{{if eq $.SignedUser.Language .Lang}} active selected{{end}}" data-value="{{.Lang}}">{{.Name}}</div>
{{end}}
</div>
</div>
</div>

<div class="field">
<button class="ui green button">{{$.i18n.Tr "settings.update_profile"}}</button>
</div>
Expand Down
2 changes: 2 additions & 0 deletions vendor/code.gitea.io/sdk/gitea/user.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions vendor/vendor.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
"revisionTime": "2018-04-21T01:08:19Z"
},
{
"checksumSHA1": "xXzi8Xx7HA3M0z3lR/1wr1Vz1fc=",
"checksumSHA1": "WMD6+Qh2+5hd9uiq910pF/Ihylw=",
"path": "code.gitea.io/sdk/gitea",
"revision": "142acef5ce79f78585afcce31748af46c72a3dea",
"revisionTime": "2018-04-17T00:54:29Z"
"revision": "1c8d12f79a51605ed91587aa6b86cf38fc0f987f",
"revisionTime": "2018-05-01T11:15:19Z"
},
{
"checksumSHA1": "bOODD4Gbw3GfcuQPU2dI40crxxk=",
Expand Down