fix: make sure to use user discoverability settings when searching list users

Resolves https://kolaente.dev/vikunja/frontend/issues/2196
This commit is contained in:
kolaente 2022-08-02 13:26:42 +02:00
parent cd345b62c2
commit 382a7884be
No known key found for this signature in database
GPG key ID: F40E70337AB24C9B
4 changed files with 59 additions and 41 deletions

View file

@ -96,28 +96,12 @@ func ListUsersFromList(s *xorm.Session, l *List, search string) (users []*user.U
uids = append(uids, id) uids = append(uids, id)
} }
var cond builder.Cond = builder.Like{"username", "%" + search + "%"} var cond builder.Cond
if len(uids) > 0 { if len(uids) > 0 {
cond = builder.And( cond = builder.In("id", uids)
builder.In("id", uids),
cond,
)
}
// Get all users
err = s.
Table("users").
Select("*").
Where(cond).
GroupBy("id").
OrderBy("id").
Find(&users)
// Obfuscate all user emails
for _, u := range users {
u.Email = ""
} }
users, err = user.ListUsers(s, search, cond)
return return
} }

View file

@ -47,7 +47,7 @@ func UserList(c echo.Context) error {
s := db.NewSession() s := db.NewSession()
defer s.Close() defer s.Close()
users, err := user.ListUsers(s, search) users, err := user.ListUsers(s, search, nil)
if err != nil { if err != nil {
_ = s.Rollback() _ = s.Rollback()
return handler.HandleHTTPError(err, c) return handler.HandleHTTPError(err, c)

View file

@ -18,6 +18,7 @@ package user
import ( import (
"testing" "testing"
"xorm.io/builder"
"code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/db"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -362,7 +363,7 @@ func TestListUsers(t *testing.T) {
s := db.NewSession() s := db.NewSession()
defer s.Close() defer s.Close()
all, err := ListUsers(s, "user1") all, err := ListUsers(s, "user1", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, len(all) > 0) assert.True(t, len(all) > 0)
assert.Equal(t, all[0].Username, "user1") assert.Equal(t, all[0].Username, "user1")
@ -381,7 +382,7 @@ func TestListUsers(t *testing.T) {
s := db.NewSession() s := db.NewSession()
defer s.Close() defer s.Close()
all, err := ListUsers(s, "") all, err := ListUsers(s, "", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, all, 0) assert.Len(t, all, 0)
}) })
@ -390,11 +391,12 @@ func TestListUsers(t *testing.T) {
s := db.NewSession() s := db.NewSession()
defer s.Close() defer s.Close()
all, err := ListUsers(s, "user1@example.com") all, err := ListUsers(s, "user1@example.com", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, all, 0) assert.Len(t, all, 0)
db.AssertExists(t, "users", map[string]interface{}{ db.AssertExists(t, "users", map[string]interface{}{
"email": "user1@example.com", "email": "user1@example.com",
"discoverable_by_email": false,
}, false) }, false)
}) })
t.Run("not discoverable by name", func(t *testing.T) { t.Run("not discoverable by name", func(t *testing.T) {
@ -402,11 +404,12 @@ func TestListUsers(t *testing.T) {
s := db.NewSession() s := db.NewSession()
defer s.Close() defer s.Close()
all, err := ListUsers(s, "one else") all, err := ListUsers(s, "one else", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, all, 0) assert.Len(t, all, 0)
db.AssertExists(t, "users", map[string]interface{}{ db.AssertExists(t, "users", map[string]interface{}{
"name": "Some one else", "name": "Some one else",
"discoverable_by_name": false,
}, false) }, false)
}) })
t.Run("discoverable by email", func(t *testing.T) { t.Run("discoverable by email", func(t *testing.T) {
@ -414,20 +417,42 @@ func TestListUsers(t *testing.T) {
s := db.NewSession() s := db.NewSession()
defer s.Close() defer s.Close()
all, err := ListUsers(s, "user7@example.com") all, err := ListUsers(s, "user7@example.com", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, all, 1) assert.Len(t, all, 1)
assert.Equal(t, int64(7), all[0].ID) 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) { t.Run("discoverable by partial name", func(t *testing.T) {
db.LoadAndAssertFixtures(t) db.LoadAndAssertFixtures(t)
s := db.NewSession() s := db.NewSession()
defer s.Close() defer s.Close()
all, err := ListUsers(s, "with space") all, err := ListUsers(s, "with space", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, all, 1) assert.Len(t, all, 1)
assert.Equal(t, int64(12), all[0].ID) 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", builder.In("id", 7))
assert.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)
}) })
} }

View file

@ -23,8 +23,8 @@ import (
"xorm.io/xorm" "xorm.io/xorm"
) )
// ListUsers returns a list with all users, filtered by an optional searchstring // ListUsers returns a list with all users, filtered by an optional search string
func ListUsers(s *xorm.Session, search string) (users []*User, err error) { func ListUsers(s *xorm.Session, search string, additionalCond builder.Cond) (users []*User, err error) {
// Prevent searching for placeholders // Prevent searching for placeholders
search = strings.ReplaceAll(search, "%", "") search = strings.ReplaceAll(search, "%", "")
@ -33,18 +33,27 @@ func ListUsers(s *xorm.Session, search string) (users []*User, err error) {
return return
} }
cond := builder.Or(
builder.Like{"username", "%" + search + "%"},
builder.And(
builder.Eq{"email": search},
builder.Eq{"discoverable_by_email": true},
),
builder.And(
builder.Like{"name", "%" + search + "%"},
builder.Eq{"discoverable_by_name": true},
),
)
if additionalCond != nil {
cond = builder.And(
cond,
additionalCond,
)
}
err = s. err = s.
Where(builder.Or( Where(cond).
builder.Like{"username", "%" + search + "%"},
builder.And(
builder.Eq{"email": search},
builder.Eq{"discoverable_by_email": true},
),
builder.And(
builder.Like{"name", "%" + search + "%"},
builder.Eq{"discoverable_by_name": true},
),
)).
Find(&users) Find(&users)
return return
} }