Use the username instead of a user when adding a user to a team or giving it rights (#76)
This commit is contained in:
@ -22,8 +22,10 @@ import "code.vikunja.io/web"
|
||||
type ListUser struct {
|
||||
// The unique, numeric id of this list <-> user relation.
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"namespace"`
|
||||
// The user id.
|
||||
UserID int64 `xorm:"int(11) not null INDEX" json:"userID" param:"user"`
|
||||
// The username.
|
||||
Username string `xorm:"-" json:"username" param:"user"`
|
||||
// Used internally to reference the user
|
||||
UserID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||
// The list id.
|
||||
ListID int64 `xorm:"int(11) not null INDEX" json:"-" param:"list"`
|
||||
// The right this user has. 0 = Read only, 1 = Read & Write, 2 = Admin. See the docs for more details.
|
||||
|
@ -47,9 +47,11 @@ func (lu *ListUser) Create(a web.Auth) (err error) {
|
||||
}
|
||||
|
||||
// Check if the user exists
|
||||
if _, err = GetUserByID(lu.UserID); err != nil {
|
||||
user, err := GetUserByUsername(lu.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lu.UserID = user.ID
|
||||
|
||||
// Check if the user already has access or is owner of that list
|
||||
// We explicitly DONT check for teams here
|
||||
|
@ -34,10 +34,11 @@ import _ "code.vikunja.io/web" // For swaggerdocs generation
|
||||
func (lu *ListUser) Delete() (err error) {
|
||||
|
||||
// Check if the user exists
|
||||
_, err = GetUserByID(lu.UserID)
|
||||
user, err := GetUserByUsername(lu.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
lu.UserID = user.ID
|
||||
|
||||
// Check if the user has access to the list
|
||||
has, err := x.Where("user_id = ? AND list_id = ?", lu.UserID, lu.ListID).
|
||||
|
@ -29,6 +29,7 @@ func TestListUser_Create(t *testing.T) {
|
||||
type fields struct {
|
||||
ID int64
|
||||
UserID int64
|
||||
Username string
|
||||
ListID int64
|
||||
Right Right
|
||||
Created int64
|
||||
@ -49,15 +50,15 @@ func TestListUser_Create(t *testing.T) {
|
||||
{
|
||||
name: "ListUsers Create normally",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
ListID: 2,
|
||||
Username: "user1",
|
||||
ListID: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ListUsers Create for duplicate",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
ListID: 2,
|
||||
Username: "user1",
|
||||
ListID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserAlreadyHasAccess,
|
||||
@ -65,9 +66,9 @@ func TestListUser_Create(t *testing.T) {
|
||||
{
|
||||
name: "ListUsers Create with invalid right",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
ListID: 2,
|
||||
Right: 500,
|
||||
Username: "user1",
|
||||
ListID: 2,
|
||||
Right: 500,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrInvalidRight,
|
||||
@ -75,8 +76,8 @@ func TestListUser_Create(t *testing.T) {
|
||||
{
|
||||
name: "ListUsers Create with inexisting list",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
ListID: 2000,
|
||||
Username: "user1",
|
||||
ListID: 2000,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrListDoesNotExist,
|
||||
@ -84,8 +85,8 @@ func TestListUser_Create(t *testing.T) {
|
||||
{
|
||||
name: "ListUsers Create with inexisting user",
|
||||
fields: fields{
|
||||
UserID: 500,
|
||||
ListID: 2,
|
||||
Username: "user500",
|
||||
ListID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotExist,
|
||||
@ -93,8 +94,8 @@ func TestListUser_Create(t *testing.T) {
|
||||
{
|
||||
name: "ListUsers Create with the owner as shared user",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
ListID: 1,
|
||||
Username: "user1",
|
||||
ListID: 1,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserAlreadyHasAccess,
|
||||
@ -105,6 +106,7 @@ func TestListUser_Create(t *testing.T) {
|
||||
ul := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
Username: tt.fields.Username,
|
||||
ListID: tt.fields.ListID,
|
||||
Right: tt.fields.Right,
|
||||
Created: tt.fields.Created,
|
||||
@ -291,7 +293,7 @@ func TestListUser_Update(t *testing.T) {
|
||||
func TestListUser_Delete(t *testing.T) {
|
||||
type fields struct {
|
||||
ID int64
|
||||
UserID int64
|
||||
Username string
|
||||
ListID int64
|
||||
Right Right
|
||||
Created int64
|
||||
@ -308,8 +310,8 @@ func TestListUser_Delete(t *testing.T) {
|
||||
{
|
||||
name: "Try deleting some unexistant user",
|
||||
fields: fields{
|
||||
UserID: 1000,
|
||||
ListID: 2,
|
||||
Username: "user1000",
|
||||
ListID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotExist,
|
||||
@ -317,8 +319,8 @@ func TestListUser_Delete(t *testing.T) {
|
||||
{
|
||||
name: "Try deleting a user which does not has access but exists",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
ListID: 4,
|
||||
Username: "user1",
|
||||
ListID: 4,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotHaveAccessToList,
|
||||
@ -326,8 +328,8 @@ func TestListUser_Delete(t *testing.T) {
|
||||
{
|
||||
name: "Try deleting normally",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
ListID: 3,
|
||||
Username: "user1",
|
||||
ListID: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -335,7 +337,7 @@ func TestListUser_Delete(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
lu := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
Username: tt.fields.Username,
|
||||
ListID: tt.fields.ListID,
|
||||
Right: tt.fields.Right,
|
||||
Created: tt.fields.Created,
|
||||
|
@ -22,8 +22,9 @@ import "code.vikunja.io/web"
|
||||
type NamespaceUser struct {
|
||||
// The unique, numeric id of this namespace <-> user relation.
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"namespace"`
|
||||
// The user id.
|
||||
UserID int64 `xorm:"int(11) not null INDEX" json:"userID" param:"user"`
|
||||
// The username.
|
||||
Username string `xorm:"-" json:"userID" param:"user"`
|
||||
UserID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||
// The namespace id
|
||||
NamespaceID int64 `xorm:"int(11) not null INDEX" json:"-" param:"namespace"`
|
||||
// The right this user has. 0 = Read only, 1 = Read & Write, 2 = Admin. See the docs for more details.
|
||||
|
@ -49,9 +49,11 @@ func (nu *NamespaceUser) Create(a web.Auth) (err error) {
|
||||
}
|
||||
|
||||
// Check if the user exists
|
||||
if _, err = GetUserByID(nu.UserID); err != nil {
|
||||
user, err := GetUserByUsername(nu.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nu.UserID = user.ID
|
||||
|
||||
// Check if the user already has access or is owner of that namespace
|
||||
// We explicitly DO NOT check for teams here
|
||||
|
@ -34,10 +34,11 @@ import _ "code.vikunja.io/web" // For swaggerdocs generation
|
||||
func (nu *NamespaceUser) Delete() (err error) {
|
||||
|
||||
// Check if the user exists
|
||||
_, err = GetUserByID(nu.UserID)
|
||||
user, err := GetUserByUsername(nu.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nu.UserID = user.ID
|
||||
|
||||
// Check if the user has access to the namespace
|
||||
has, err := x.Where("user_id = ? AND namespace_id = ?", nu.UserID, nu.NamespaceID).
|
||||
|
@ -29,7 +29,7 @@ import (
|
||||
func TestNamespaceUser_Create(t *testing.T) {
|
||||
type fields struct {
|
||||
ID int64
|
||||
UserID int64
|
||||
Username string
|
||||
NamespaceID int64
|
||||
Right Right
|
||||
Created int64
|
||||
@ -50,14 +50,14 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||
{
|
||||
name: "NamespaceUsers Create normally",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
Username: "user1",
|
||||
NamespaceID: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NamespaceUsers Create for duplicate",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
Username: "user1",
|
||||
NamespaceID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
@ -66,7 +66,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||
{
|
||||
name: "NamespaceUsers Create with invalid right",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
Username: "user1",
|
||||
NamespaceID: 2,
|
||||
Right: 500,
|
||||
},
|
||||
@ -76,7 +76,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||
{
|
||||
name: "NamespaceUsers Create with inexisting list",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
Username: "user1",
|
||||
NamespaceID: 2000,
|
||||
},
|
||||
wantErr: true,
|
||||
@ -85,7 +85,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||
{
|
||||
name: "NamespaceUsers Create with inexisting user",
|
||||
fields: fields{
|
||||
UserID: 500,
|
||||
Username: "user500",
|
||||
NamespaceID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
@ -94,7 +94,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||
{
|
||||
name: "NamespaceUsers Create with the owner as shared user",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
Username: "user1",
|
||||
NamespaceID: 1,
|
||||
},
|
||||
wantErr: true,
|
||||
@ -105,7 +105,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
un := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
Username: tt.fields.Username,
|
||||
NamespaceID: tt.fields.NamespaceID,
|
||||
Right: tt.fields.Right,
|
||||
Created: tt.fields.Created,
|
||||
@ -293,7 +293,7 @@ func TestNamespaceUser_Update(t *testing.T) {
|
||||
func TestNamespaceUser_Delete(t *testing.T) {
|
||||
type fields struct {
|
||||
ID int64
|
||||
UserID int64
|
||||
Username string
|
||||
NamespaceID int64
|
||||
Right Right
|
||||
Created int64
|
||||
@ -310,7 +310,7 @@ func TestNamespaceUser_Delete(t *testing.T) {
|
||||
{
|
||||
name: "Try deleting some unexistant user",
|
||||
fields: fields{
|
||||
UserID: 1000,
|
||||
Username: "user1000",
|
||||
NamespaceID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
@ -319,7 +319,7 @@ func TestNamespaceUser_Delete(t *testing.T) {
|
||||
{
|
||||
name: "Try deleting a user which does not has access but exists",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
Username: "user1",
|
||||
NamespaceID: 4,
|
||||
},
|
||||
wantErr: true,
|
||||
@ -328,7 +328,7 @@ func TestNamespaceUser_Delete(t *testing.T) {
|
||||
{
|
||||
name: "Try deleting normally",
|
||||
fields: fields{
|
||||
UserID: 1,
|
||||
Username: "user1",
|
||||
NamespaceID: 3,
|
||||
},
|
||||
},
|
||||
@ -337,7 +337,7 @@ func TestNamespaceUser_Delete(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
nu := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
Username: tt.fields.Username,
|
||||
NamespaceID: tt.fields.NamespaceID,
|
||||
Right: tt.fields.Right,
|
||||
Created: tt.fields.Created,
|
||||
|
@ -41,10 +41,11 @@ func (tm *TeamMember) Create(a web.Auth) (err error) {
|
||||
}
|
||||
|
||||
// Check if the user exists
|
||||
_, err = GetUserByID(tm.UserID)
|
||||
user, err := GetUserByUsername(tm.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tm.UserID = user.ID
|
||||
|
||||
// Check if that user is already part of the team
|
||||
exists, err := x.Where("team_id = ? AND user_id = ?", tm.TeamID, tm.UserID).
|
||||
|
@ -37,6 +37,13 @@ func (tm *TeamMember) Delete() (err error) {
|
||||
return ErrCannotDeleteLastTeamMember{tm.TeamID, tm.UserID}
|
||||
}
|
||||
|
||||
// Find the numeric user id
|
||||
user, err := GetUserByUsername(tm.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tm.UserID = user.ID
|
||||
|
||||
_, err = x.Where("team_id = ? AND user_id = ?", tm.TeamID, tm.UserID).Delete(&TeamMember{})
|
||||
return
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ func TestTeamMember_Create(t *testing.T) {
|
||||
|
||||
// Dummy team member
|
||||
dummyteammember := TeamMember{
|
||||
TeamID: 1,
|
||||
UserID: 3,
|
||||
TeamID: 1,
|
||||
Username: "user3",
|
||||
}
|
||||
|
||||
// Doer
|
||||
@ -57,24 +57,24 @@ func TestTeamMember_Create(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Delete the other one
|
||||
tm := TeamMember{TeamID: 1, UserID: 2}
|
||||
tm := TeamMember{TeamID: 1, Username: "user2"}
|
||||
err = tm.Delete()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Try deleting the last one
|
||||
tm = TeamMember{TeamID: 1, UserID: 1}
|
||||
tm = TeamMember{TeamID: 1, Username: "user1"}
|
||||
err = tm.Delete()
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrCannotDeleteLastTeamMember(err))
|
||||
|
||||
// Try inserting a user which does not exist
|
||||
dummyteammember.UserID = 9484
|
||||
dummyteammember.Username = "user9484"
|
||||
err = dummyteammember.Create(&doer)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
|
||||
// Try adding a user to a team which does not exist
|
||||
tm = TeamMember{TeamID: 94824, UserID: 1}
|
||||
tm = TeamMember{TeamID: 94824, Username: "user1"}
|
||||
err = tm.Create(&doer)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrTeamDoesNotExist(err))
|
||||
|
@ -66,8 +66,10 @@ type TeamMember struct {
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id"`
|
||||
// The team id.
|
||||
TeamID int64 `xorm:"int(11) not null INDEX" json:"-" param:"team"`
|
||||
// The id of the member.
|
||||
UserID int64 `xorm:"int(11) not null INDEX" json:"userID" param:"user"`
|
||||
// The username of the member. We use this to prevent automated user id entering.
|
||||
Username string `xorm:"-" json:"username" param:"user"`
|
||||
// Used under the hood to manage team members
|
||||
UserID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||
// Whether or not the member is an admin of the team. See the docs for more about what a team admin can do
|
||||
Admin bool `xorm:"tinyint(1) INDEX null" json:"admin"`
|
||||
|
||||
|
@ -53,7 +53,7 @@ func (t *Team) Create(a web.Auth) (err error) {
|
||||
}
|
||||
|
||||
// Insert the current user as member and admin
|
||||
tm := TeamMember{TeamID: t.ID, UserID: doer.ID, Admin: true}
|
||||
tm := TeamMember{TeamID: t.ID, Username: doer.Username, Admin: true}
|
||||
if err = tm.Create(doer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -119,6 +119,15 @@ func GetUserByID(id int64) (user User, err error) {
|
||||
return GetUser(User{ID: id})
|
||||
}
|
||||
|
||||
// GetUserByUsername gets a user from its user name. This is an extra function to be able to add an extra error check.
|
||||
func GetUserByUsername(username string) (user User, err error) {
|
||||
if username == "" {
|
||||
return User{}, ErrUserDoesNotExist{}
|
||||
}
|
||||
|
||||
return GetUser(User{Username: username})
|
||||
}
|
||||
|
||||
// GetUser gets a user object
|
||||
func GetUser(user User) (userOut User, err error) {
|
||||
userOut = user
|
||||
@ -139,7 +148,7 @@ func CheckUserCredentials(u *UserLogin) (User, error) {
|
||||
}
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUser(User{Username: u.Username})
|
||||
user, err := GetUserByUsername(u.Username)
|
||||
if err != nil {
|
||||
// hashing the password takes a long time, so we hash something to not make it clear if the username was wrong
|
||||
bcrypt.GenerateFromPassword([]byte(u.Username), 14)
|
||||
|
@ -36,7 +36,7 @@ func CreateUser(user User) (newUser User, err error) {
|
||||
|
||||
// Check if the user already existst with that username
|
||||
exists := true
|
||||
existingUser, err := GetUser(User{Username: newUser.Username})
|
||||
existingUser, err := GetUserByUsername(newUser.Username)
|
||||
if err != nil {
|
||||
if IsErrUserDoesNotExist(err) {
|
||||
exists = false
|
||||
|
Reference in New Issue
Block a user