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

Add option to change username to the admin panel #14229

Merged
merged 30 commits into from
Jan 10, 2021
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2c5edbd
Add option to change username to the admin panel
Bwko Jul 8, 2017
96b4ed2
Merge branch 'master' into change_username
techknowlogick Jul 21, 2018
571d6e9
Merge branch 'master' into change_username
techknowlogick Oct 29, 2018
8f44051
Merge branch 'master' into change_username
techknowlogick Dec 28, 2018
93076c0
Update year
techknowlogick Jan 30, 2019
de9c5ab
Merge branch 'master' into change_username
techknowlogick Jan 30, 2019
47aa7a5
Merge branch 'master' into change_username
zeripath Jul 1, 2019
d105721
Merge branch 'master' into Bwko/change_username
6543 Jan 3, 2021
16bc2b9
fix merge conflict relicts
6543 Jan 3, 2021
a8a44d0
fix
6543 Jan 3, 2021
f6926ae
Same limit on AdminEditUserForm as in AdminCreateUserForm
6543 Jan 3, 2021
e1db950
Impruve ChangeUserName
6543 Jan 3, 2021
e93e3ec
re-use HandleUsernameChange
6543 Jan 3, 2021
3524d0c
fix redirect url & return error if non local acount
6543 Jan 3, 2021
0bb5d69
Merge branch 'master' into Bwko/change_username
6543 Jan 3, 2021
d259210
fix lint
6543 Jan 3, 2021
cdf3ca8
Merge branch 'master' into Bwko/change_username
6543 Jan 3, 2021
ed4573b
it's 2021 😵
6543 Jan 4, 2021
f58fe15
Merge branch 'master' into Bwko/change_username
6543 Jan 4, 2021
f456600
Merge branch 'master' into Bwko/change_username
6543 Jan 4, 2021
a503f9f
Merge branch 'master' into Bwko/change_username
6543 Jan 5, 2021
f6de287
Merge branch 'master' into Bwko/change_username
6543 Jan 6, 2021
8f72728
Merge branch 'master' into Bwko/change_username
6543 Jan 6, 2021
dd9a3be
Merge branch 'master' into Bwko/change_username
6543 Jan 6, 2021
8360ac7
Merge branch 'master' into Bwko/change_username
6543 Jan 7, 2021
cef44d7
Merge branch 'master' into Bwko/change_username
6543 Jan 7, 2021
bd0b4b9
Merge branch 'master' into Bwko/change_username
6543 Jan 8, 2021
b622cba
Merge branch 'master' into Bwko/change_username
6543 Jan 9, 2021
cd2f5aa
Update integrations/admin_user_test.go
6543 Jan 9, 2021
951cf37
Merge branch 'master' into Bwko/change_username
6543 Jan 9, 2021
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
81 changes: 81 additions & 0 deletions integrations/admin_user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2021 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 integrations

import (
"net/http"
"strconv"
"testing"

"code.gitea.io/gitea/models"
"github.com/stretchr/testify/assert"
6543 marked this conversation as resolved.
Show resolved Hide resolved
6543 marked this conversation as resolved.
Show resolved Hide resolved
)

func TestAdminViewUsers(t *testing.T) {
prepareTestEnv(t)

session := loginUser(t, "user1")
req := NewRequest(t, "GET", "/admin/users")
session.MakeRequest(t, req, http.StatusOK)

session = loginUser(t, "user2")
req = NewRequest(t, "GET", "/admin/users")
session.MakeRequest(t, req, http.StatusForbidden)
}

func TestAdminViewUser(t *testing.T) {
prepareTestEnv(t)

session := loginUser(t, "user1")
req := NewRequest(t, "GET", "/admin/users/1")
session.MakeRequest(t, req, http.StatusOK)

session = loginUser(t, "user2")
req = NewRequest(t, "GET", "/admin/users/1")
session.MakeRequest(t, req, http.StatusForbidden)
}

func TestAdminEditUser(t *testing.T) {
prepareTestEnv(t)

testSuccessfullEdit(t, models.User{ID: 2, Name: "newusername", LoginName: "otherlogin", Email: "new@e-mail.gitea"})
}

func testSuccessfullEdit(t *testing.T, formData models.User) {
makeRequest(t, formData, http.StatusFound)
}

func makeRequest(t *testing.T, formData models.User, headerCode int) {
session := loginUser(t, "user1")
csrf := GetCSRF(t, session, "/admin/users/"+strconv.Itoa(int(formData.ID)))
req := NewRequestWithValues(t, "POST", "/admin/users/"+strconv.Itoa(int(formData.ID)), map[string]string{
"_csrf": csrf,
"user_name": formData.Name,
"login_name": formData.LoginName,
"login_type": "0-0",
"email": formData.Email,
})

session.MakeRequest(t, req, headerCode)
user := models.AssertExistsAndLoadBean(t, &models.User{ID: formData.ID}).(*models.User)
assert.Equal(t, formData.Name, user.Name)
assert.Equal(t, formData.LoginName, user.LoginName)
assert.Equal(t, formData.Email, user.Email)
}

func TestAdminDeleteUser(t *testing.T) {
defer prepareTestEnv(t)()

session := loginUser(t, "user1")

csrf := GetCSRF(t, session, "/admin/users/8")
req := NewRequestWithValues(t, "POST", "/admin/users/8/delete", map[string]string{
"_csrf": csrf,
})
session.MakeRequest(t, req, http.StatusOK)

assertUserDeleted(t, 8)
models.CheckConsistencyFor(t, &models.User{})
}
15 changes: 0 additions & 15 deletions integrations/delete_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,6 @@ func assertUserDeleted(t *testing.T, userID int64) {
models.AssertNotExistsBean(t, &models.Star{UID: userID})
}

func TestAdminDeleteUser(t *testing.T) {
defer prepareTestEnv(t)()

session := loginUser(t, "user1")

csrf := GetCSRF(t, session, "/admin/users/8")
req := NewRequestWithValues(t, "POST", "/admin/users/8/delete", map[string]string{
"_csrf": csrf,
})
session.MakeRequest(t, req, http.StatusOK)

assertUserDeleted(t, 8)
models.CheckConsistencyFor(t, &models.User{})
}

func TestUserDeleteAccount(t *testing.T) {
defer prepareTestEnv(t)()

Expand Down
14 changes: 7 additions & 7 deletions models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -913,19 +913,19 @@ func ChangeUserName(u *User, newUserName string) (err error) {
return err
}

isExist, err := IsUserExist(0, newUserName)
if err != nil {
return err
} else if isExist {
return ErrUserAlreadyExist{newUserName}
}

sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}

isExist, err := isUserExist(sess, 0, newUserName)
if err != nil {
return err
} else if isExist {
return ErrUserAlreadyExist{newUserName}
}

if _, err = sess.Exec("UPDATE `repository` SET owner_name=? WHERE owner_name=?", newUserName, u.Name); err != nil {
return fmt.Errorf("Change repo owner name: %v", err)
}
Expand Down
1 change: 1 addition & 0 deletions modules/auth/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func (f *AdminCreateUserForm) Validate(ctx *macaron.Context, errs binding.Errors
// AdminEditUserForm form for admin to create user
type AdminEditUserForm struct {
LoginType string `binding:"Required"`
UserName string `binding:"AlphaDashDot;MaxSize(40)"`
LoginName string
FullName string `binding:"MaxSize(100)"`
Email string `binding:"Required;Email;MaxSize(254)"`
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 @@ -359,6 +359,7 @@ password_not_match = The passwords do not match.
lang_select_error = Select a language from the list.

username_been_taken = The username is already taken.
username_change_not_local_user = Non-local users are not allowed to change their username.
repo_name_been_taken = The repository name is already used.
repository_files_already_exist = Files already exist for this repository. Contact the system administrator.
repository_files_already_exist.adopt = Files already exist for this repository and can only be Adopted.
Expand Down
10 changes: 10 additions & 0 deletions routers/admin/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/password"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers"
router_user_setting "code.gitea.io/gitea/routers/user/setting"
"code.gitea.io/gitea/services/mailer"
)

Expand Down Expand Up @@ -269,6 +270,15 @@ func EditUserPost(ctx *context.Context, form auth.AdminEditUserForm) {
u.HashPassword(form.Password)
}

if len(form.UserName) != 0 && u.Name != form.UserName {
if err := router_user_setting.HandleUsernameChange(ctx, u, form.UserName); err != nil {
ctx.Redirect(setting.AppSubURL + "/admin/users")
return
}
u.Name = form.UserName
u.LowerName = strings.ToLower(form.UserName)
}

if form.Reset2FA {
tf, err := models.GetTwoFactorByUID(u.ID)
if err != nil && !models.IsErrTwoFactorNotEnrolled(err) {
Expand Down
36 changes: 17 additions & 19 deletions routers/user/setting/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,42 +38,36 @@ func Profile(ctx *context.Context) {
ctx.HTML(200, tplSettingsProfile)
}

func handleUsernameChange(ctx *context.Context, newName string) {
// HandleUsernameChange handle username changes from user settings and admin interface
func HandleUsernameChange(ctx *context.Context, user *models.User, newName string) error {
// Non-local users are not allowed to change their username.
if len(newName) == 0 || !ctx.User.IsLocal() {
return
if !user.IsLocal() {
ctx.Flash.Error(ctx.Tr("form.username_change_not_local_user"))
return fmt.Errorf(ctx.Tr("form.username_change_not_local_user"))
}

// Check if user name has been changed
if ctx.User.LowerName != strings.ToLower(newName) {
if err := models.ChangeUserName(ctx.User, newName); err != nil {
if user.LowerName != strings.ToLower(newName) {
if err := models.ChangeUserName(user, newName); err != nil {
switch {
case models.IsErrUserAlreadyExist(err):
ctx.Flash.Error(ctx.Tr("form.username_been_taken"))
ctx.Redirect(setting.AppSubURL + "/user/settings")
case models.IsErrEmailAlreadyUsed(err):
ctx.Flash.Error(ctx.Tr("form.email_been_used"))
ctx.Redirect(setting.AppSubURL + "/user/settings")
case models.IsErrNameReserved(err):
ctx.Flash.Error(ctx.Tr("user.form.name_reserved", newName))
ctx.Redirect(setting.AppSubURL + "/user/settings")
case models.IsErrNamePatternNotAllowed(err):
ctx.Flash.Error(ctx.Tr("user.form.name_pattern_not_allowed", newName))
ctx.Redirect(setting.AppSubURL + "/user/settings")
case models.IsErrNameCharsNotAllowed(err):
ctx.Flash.Error(ctx.Tr("user.form.name_chars_not_allowed", newName))
ctx.Redirect(setting.AppSubURL + "/user/settings")
default:
ctx.ServerError("ChangeUserName", err)
}
return
return err
}
log.Trace("User name changed: %s -> %s", ctx.User.Name, newName)
log.Trace("User name changed: %s -> %s", user.Name, newName)
}

// In case it's just a case change
ctx.User.Name = newName
ctx.User.LowerName = strings.ToLower(newName)
return nil
}

// ProfilePost response for change user's profile
Expand All @@ -86,9 +80,13 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) {
return
}

handleUsernameChange(ctx, form.Name)
if ctx.Written() {
return
if len(form.Name) != 0 && ctx.User.Name != form.Name {
if err := HandleUsernameChange(ctx, ctx.User, form.Name); err != nil {
ctx.Redirect(setting.AppSubURL + "/user/settings")
return
}
ctx.User.Name = form.Name
ctx.User.LowerName = strings.ToLower(form.Name)
}

ctx.User.FullName = form.FullName
Expand Down
4 changes: 2 additions & 2 deletions templates/admin/user/edit.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
<div class="ui attached segment">
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<div class="inline field {{if .Err_UserName}}error{{end}}">
<div class="field {{if .Err_UserName}}error{{end}}">
<label for="user_name">{{.i18n.Tr "username"}}</label>
<span>{{.User.Name}}</span>
<input id="user_name" name="user_name" value="{{.User.Name}}" autofocus {{if not .User.IsLocal }}disabled{{end}}>
</div>
<!-- Types and name -->
<div class="inline required field {{if .Err_LoginType}}error{{end}}">
Expand Down
2 changes: 2 additions & 0 deletions web_src/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1796,6 +1796,7 @@ function initAdmin() {
if ($('.admin.new.user').length > 0 || $('.admin.edit.user').length > 0) {
$('#login_type').on('change', function () {
if ($(this).val().substring(0, 1) === '0') {
$('#user_name').removeAttr('disabled');
$('#login_name').removeAttr('required');
$('.non-local').hide();
$('.local').show();
Expand All @@ -1805,6 +1806,7 @@ function initAdmin() {
$('#password').attr('required', 'required');
}
} else {
$('#user_name').attr('disabled', 'disabled');
$('#login_name').attr('required', 'required');
$('.non-local').show();
$('.local').hide();
Expand Down