mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-04-30 08:56:59 +00:00
This adds a feature where you can enable users to only find members of teams they're part of. This makes the user search when sharing projects less confusing, because users only see other users they already know. It is still possible to add users to teams with their email address, if they have that enabled in the user settings.
574 lines
15 KiB
Go
574 lines
15 KiB
Go
// Vikunja is a to-do list application to facilitate your life.
|
|
// Copyright 2018-present Vikunja and contributors. All rights reserved.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public Licensee as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public Licensee for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public Licensee
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package user
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"code.vikunja.io/api/pkg/db"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"xorm.io/builder"
|
|
)
|
|
|
|
func TestCreateUser(t *testing.T) {
|
|
// Our dummy user for testing
|
|
dummyuser := &User{
|
|
Username: "testuser",
|
|
Password: "12345678",
|
|
Email: "noone@example.com",
|
|
}
|
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
createdUser, err := CreateUser(s, dummyuser)
|
|
require.NoError(t, err)
|
|
assert.NotZero(t, createdUser.Created)
|
|
})
|
|
t.Run("already existing", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CreateUser(s, &User{
|
|
Username: "user1",
|
|
Password: "12345",
|
|
Email: "email@example.com",
|
|
})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrUsernameExists(err))
|
|
})
|
|
t.Run("same email", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CreateUser(s, &User{
|
|
Username: "testuser",
|
|
Password: "12345",
|
|
Email: "user1@example.com",
|
|
})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrUserEmailExists(err))
|
|
})
|
|
t.Run("no username", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CreateUser(s, &User{
|
|
Username: "",
|
|
Password: "12345",
|
|
Email: "user1@example.com",
|
|
})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrNoUsernamePassword(err))
|
|
})
|
|
t.Run("no password", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CreateUser(s, &User{
|
|
Username: "testuser",
|
|
Password: "",
|
|
Email: "user1@example.com",
|
|
})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrNoUsernamePassword(err))
|
|
})
|
|
t.Run("no email", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CreateUser(s, &User{
|
|
Username: "testuser",
|
|
Password: "12345",
|
|
Email: "",
|
|
})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrNoUsernamePassword(err))
|
|
})
|
|
t.Run("same email but different issuer", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CreateUser(s, &User{
|
|
Username: "somenewuser",
|
|
Email: "user1@example.com",
|
|
Issuer: "https://some.site",
|
|
Subject: "12345",
|
|
})
|
|
require.NoError(t, err)
|
|
})
|
|
t.Run("same subject but different issuer", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CreateUser(s, &User{
|
|
Username: "somenewuser",
|
|
Email: "somenewuser@example.com",
|
|
Issuer: "https://some.site",
|
|
Subject: "12345",
|
|
})
|
|
require.NoError(t, err)
|
|
})
|
|
t.Run("space in username", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CreateUser(s, &User{
|
|
Username: "user name",
|
|
Password: "12345",
|
|
Email: "user1@example.com",
|
|
})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrUsernameMustNotContainSpaces(err))
|
|
})
|
|
}
|
|
|
|
func TestGetUser(t *testing.T) {
|
|
t.Run("by name", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
theuser, err := getUser(
|
|
s,
|
|
&User{
|
|
Username: "user1",
|
|
},
|
|
false,
|
|
)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(1), theuser.ID)
|
|
assert.Empty(t, theuser.Email)
|
|
})
|
|
t.Run("by email", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
theuser, err := getUser(
|
|
s,
|
|
&User{
|
|
Email: "user1@example.com",
|
|
},
|
|
false)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(1), theuser.ID)
|
|
assert.Empty(t, theuser.Email)
|
|
})
|
|
t.Run("by id", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
theuser, err := GetUserByID(s, 1)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(1), theuser.ID)
|
|
assert.Equal(t, "user1", theuser.Username)
|
|
assert.Empty(t, theuser.Email)
|
|
})
|
|
t.Run("invalid id", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := GetUserByID(s, 99999)
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrUserDoesNotExist(err))
|
|
})
|
|
t.Run("nonexistant", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := GetUserByID(s, 0)
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrUserDoesNotExist(err))
|
|
})
|
|
t.Run("empty name", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := GetUserByUsername(s, "")
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrUserDoesNotExist(err))
|
|
})
|
|
t.Run("with email", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
theuser, err := GetUserWithEmail(s, &User{ID: 1})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(1), theuser.ID)
|
|
assert.Equal(t, "user1", theuser.Username)
|
|
assert.NotEmpty(t, theuser.Email)
|
|
})
|
|
}
|
|
|
|
func TestCheckUserCredentials(t *testing.T) {
|
|
t.Run("normal", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CheckUserCredentials(s, &Login{Username: "user1", Password: "12345678"})
|
|
require.NoError(t, err)
|
|
})
|
|
t.Run("unverified email", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CheckUserCredentials(s, &Login{Username: "user5", Password: "12345678"})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrEmailNotConfirmed(err))
|
|
})
|
|
t.Run("wrong password", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CheckUserCredentials(s, &Login{Username: "user1", Password: "12345"})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrWrongUsernameOrPassword(err))
|
|
})
|
|
t.Run("nonexistant user", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CheckUserCredentials(s, &Login{Username: "dfstestuu", Password: "12345678"})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrWrongUsernameOrPassword(err))
|
|
})
|
|
t.Run("empty password", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CheckUserCredentials(s, &Login{Username: "user1"})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrNoUsernamePassword(err))
|
|
})
|
|
t.Run("empty username", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CheckUserCredentials(s, &Login{Password: "12345678"})
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrNoUsernamePassword(err))
|
|
})
|
|
t.Run("email", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := CheckUserCredentials(s, &Login{Username: "user1@example.com", Password: "12345678"})
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestUpdateUser(t *testing.T) {
|
|
t.Run("normal", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
uuser, err := UpdateUser(s, &User{
|
|
ID: 1,
|
|
Password: "LoremIpsum",
|
|
Email: "testing@example.com",
|
|
}, false)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "$2a$04$X4aRMEt0ytgPwMIgv36cI..7X9.nhY/.tYwxpqSi0ykRHx2CwQ0S6", uuser.Password) // Password should not change
|
|
assert.Equal(t, "user1", uuser.Username) // Username should not change either
|
|
})
|
|
t.Run("change username", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
uuser, err := UpdateUser(s, &User{
|
|
ID: 1,
|
|
Username: "changedname",
|
|
}, false)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "$2a$04$X4aRMEt0ytgPwMIgv36cI..7X9.nhY/.tYwxpqSi0ykRHx2CwQ0S6", uuser.Password) // Password should not change
|
|
assert.Equal(t, "changedname", uuser.Username)
|
|
})
|
|
t.Run("nonexistant", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
_, err := UpdateUser(s, &User{
|
|
ID: 99999,
|
|
}, false)
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrUserDoesNotExist(err))
|
|
})
|
|
}
|
|
|
|
func TestUpdateUserPassword(t *testing.T) {
|
|
t.Run("normal", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
err := UpdateUserPassword(s, &User{
|
|
ID: 1,
|
|
}, "12345")
|
|
require.NoError(t, err)
|
|
})
|
|
t.Run("nonexistant user", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
err := UpdateUserPassword(s, &User{
|
|
ID: 9999,
|
|
}, "12345")
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrUserDoesNotExist(err))
|
|
})
|
|
t.Run("empty password", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
err := UpdateUserPassword(s, &User{
|
|
ID: 1,
|
|
}, "")
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrEmptyNewPassword(err))
|
|
})
|
|
}
|
|
|
|
func TestListUsers(t *testing.T) {
|
|
user1 := &User{ID: 1}
|
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "user1", user1, nil)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, all)
|
|
assert.Equal(t, "user1", all[0].Username)
|
|
})
|
|
t.Run("case insensitive", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "uSEr1", user1, nil)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, all)
|
|
assert.Equal(t, "user1", all[0].Username)
|
|
})
|
|
t.Run("all users", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListAllUsers(s)
|
|
require.NoError(t, err)
|
|
assert.Len(t, all, 16)
|
|
})
|
|
t.Run("no search term", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "", user1, nil)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, all)
|
|
})
|
|
t.Run("not discoverable by email", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "user1@example.com", user1, nil)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, all)
|
|
db.AssertExists(t, "users", map[string]interface{}{
|
|
"email": "user1@example.com",
|
|
"discoverable_by_email": false,
|
|
}, false)
|
|
})
|
|
t.Run("not discoverable by name", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "one else", user1, nil)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, all)
|
|
db.AssertExists(t, "users", map[string]interface{}{
|
|
"name": "Some one else",
|
|
"discoverable_by_name": false,
|
|
}, false)
|
|
})
|
|
t.Run("discoverable by email", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "user7@example.com", user1, nil)
|
|
require.NoError(t, err)
|
|
assert.Len(t, all, 1)
|
|
assert.Equal(t, int64(7), all[0].ID)
|
|
db.AssertExists(t, "users", map[string]interface{}{
|
|
"email": "user7@example.com",
|
|
"discoverable_by_email": true,
|
|
}, false)
|
|
})
|
|
t.Run("discoverable by partial name", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "with space", user1, nil)
|
|
require.NoError(t, err)
|
|
assert.Len(t, all, 1)
|
|
assert.Equal(t, int64(12), all[0].ID)
|
|
db.AssertExists(t, "users", map[string]interface{}{
|
|
"name": "Name with spaces",
|
|
"discoverable_by_name": true,
|
|
}, false)
|
|
})
|
|
t.Run("discoverable by email with extra condition", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "user7@example.com", user1, &ProjectUserOpts{AdditionalCond: builder.In("id", 7)})
|
|
require.NoError(t, err)
|
|
assert.Len(t, all, 1)
|
|
assert.Equal(t, int64(7), all[0].ID)
|
|
db.AssertExists(t, "users", map[string]interface{}{
|
|
"email": "user7@example.com",
|
|
"discoverable_by_email": true,
|
|
}, false)
|
|
})
|
|
t.Run("discoverable by exact username", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "user7", user1, nil)
|
|
require.NoError(t, err)
|
|
assert.Len(t, all, 1)
|
|
assert.Equal(t, int64(7), all[0].ID)
|
|
db.AssertExists(t, "users", map[string]interface{}{
|
|
"username": "user7",
|
|
}, false)
|
|
})
|
|
t.Run("not discoverable by partial username", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "user", user1, nil)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, all)
|
|
db.AssertExists(t, "users", map[string]interface{}{
|
|
"username": "user7",
|
|
}, false)
|
|
})
|
|
t.Run("discoverable by partial username, email and name when matching fuzzily", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
all, err := ListUsers(s, "user", user1, &ProjectUserOpts{
|
|
MatchFuzzily: true,
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Len(t, all, 16)
|
|
})
|
|
}
|
|
|
|
func TestUserPasswordReset(t *testing.T) {
|
|
t.Run("normal", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
reset := &PasswordReset{
|
|
Token: "passwordresettesttoken",
|
|
NewPassword: "12345",
|
|
}
|
|
err := ResetPassword(s, reset)
|
|
require.NoError(t, err)
|
|
})
|
|
t.Run("without password", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
reset := &PasswordReset{
|
|
Token: "passwordresettesttoken",
|
|
}
|
|
err := ResetPassword(s, reset)
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrNoUsernamePassword(err))
|
|
})
|
|
t.Run("empty token", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
reset := &PasswordReset{
|
|
Token: "",
|
|
NewPassword: "12345",
|
|
}
|
|
err := ResetPassword(s, reset)
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrNoPasswordResetToken(err))
|
|
})
|
|
t.Run("wrong token", func(t *testing.T) {
|
|
db.LoadAndAssertFixtures(t)
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
|
|
reset := &PasswordReset{
|
|
Token: "somethingsomething",
|
|
NewPassword: "12345",
|
|
}
|
|
err := ResetPassword(s, reset)
|
|
require.Error(t, err)
|
|
assert.True(t, IsErrInvalidPasswordResetToken(err))
|
|
})
|
|
}
|