From eb7a2f5170f50fd40bb4637e4b4f217fbef75d37 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 21 Dec 2023 19:49:05 +0100 Subject: [PATCH 01/12] Added Filter by Role to user search --- api/users.go | 4 +++- web/template/admin/admin_tabs/users.gohtml | 9 +++++++++ web/ts/admin.ts | 21 +++++++++++++++------ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/api/users.go b/api/users.go index aed805dd8..cd9a0b7bb 100644 --- a/api/users.go +++ b/api/users.go @@ -125,9 +125,11 @@ func (r usersRoutes) updateUser(c *gin.Context) { func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err error) { q := c.Query("q") + rQ := c.Query("r") reg, _ := regexp.Compile("[^a-zA-Z0-9 ]+") q = reg.ReplaceAllString(q, "") - if len(q) < 3 { + // Removed in order to make the search work with empty query but selected role + if len(q) < 3 && rQ == "-1" { _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "query too short (minimum length is 3)", diff --git a/web/template/admin/admin_tabs/users.gohtml b/web/template/admin/admin_tabs/users.gohtml index 7460d2344..68bdf4bbd 100644 --- a/web/template/admin/admin_tabs/users.gohtml +++ b/web/template/admin/admin_tabs/users.gohtml @@ -6,6 +6,15 @@

Search

+
+ + +
diff --git a/web/ts/admin.ts b/web/ts/admin.ts index 3a63cbc8a..48d128d79 100755 --- a/web/ts/admin.ts +++ b/web/ts/admin.ts @@ -15,34 +15,43 @@ export class AdminUserList { showSearchResults: boolean; searchLoading: boolean; searchInput: string; + roles: number; constructor(usersAsJson: object[]) { this.list = usersAsJson; this.rowsPerPage = 10; this.showSearchResults = false; this.currentIndex = 0; + this.searchInput = ""; + this.roles = -1; this.numberOfPages = Math.ceil(this.list.length / this.rowsPerPage); this.updateVisibleRows(); } async search() { - if (this.searchInput.length < 3) { + if (this.searchInput.length < 3 && this.roles == -1) { this.showSearchResults = false; this.updateVisibleRows(); return; - } - if (this.searchInput.length > 2) { + } else { this.searchLoading = true; - fetch("/api/searchUser?q=" + this.searchInput) + fetch("/api/searchUser?q=" + this.searchInput + "&r=" + this.roles) .then((response) => { this.searchLoading = false; if (!response.ok) { throw new Error(response.statusText); } - return response.json(); + return response.json() }) .then((r) => { - this.currentPage = r; // show all results on page one. + console.log(r) + if(this.roles != -1) { + this.currentPage = r.filter((obj : any) => { + return obj.role == this.roles; + }); // show all results on page one. + } else { + this.currentPage = r; + } this.showSearchResults = true; }) .catch((err) => { From 820a2b90fa025a3d07d82ea6b8a7ff7ed9d3447a Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 21 Dec 2023 19:53:36 +0100 Subject: [PATCH 02/12] Lint fix --- web/ts/admin.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/ts/admin.ts b/web/ts/admin.ts index 48d128d79..7de60f2c1 100755 --- a/web/ts/admin.ts +++ b/web/ts/admin.ts @@ -41,12 +41,12 @@ export class AdminUserList { if (!response.ok) { throw new Error(response.statusText); } - return response.json() + return response.json(); }) .then((r) => { - console.log(r) - if(this.roles != -1) { - this.currentPage = r.filter((obj : any) => { + console.log(r); + if (this.roles != -1) { + this.currentPage = r.filter((obj) => { return obj.role == this.roles; }); // show all results on page one. } else { From 03c8c1216fdb02e1cd6e72606cbef3555acf5251 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 21 Dec 2023 20:03:28 +0100 Subject: [PATCH 03/12] Removed debug print --- web/ts/admin.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/web/ts/admin.ts b/web/ts/admin.ts index 7de60f2c1..e8b5f01d3 100755 --- a/web/ts/admin.ts +++ b/web/ts/admin.ts @@ -44,7 +44,6 @@ export class AdminUserList { return response.json(); }) .then((r) => { - console.log(r); if (this.roles != -1) { this.currentPage = r.filter((obj) => { return obj.role == this.roles; From aa458e0f1e7dc4c40d8d9f4ea68cf3bc1d23e2c7 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 28 Dec 2023 14:25:29 +0100 Subject: [PATCH 04/12] Fixed issue --- api/users.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/users.go b/api/users.go index cd9a0b7bb..fd18551ad 100644 --- a/api/users.go +++ b/api/users.go @@ -129,7 +129,7 @@ func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err reg, _ := regexp.Compile("[^a-zA-Z0-9 ]+") q = reg.ReplaceAllString(q, "") // Removed in order to make the search work with empty query but selected role - if len(q) < 3 && rQ == "-1" { + if len(q) < 3 && (rQ == "-1" || rQ == "") { _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "query too short (minimum length is 3)", From 1ba8123deefa4fccdafdcf5b62759c7aac3b0510 Mon Sep 17 00:00:00 2001 From: johanneskarrer Date: Thu, 21 Nov 2024 11:09:24 +0100 Subject: [PATCH 05/12] moved filtering from client to api --- api/users.go | 8 +++++++- dao/users.go | 7 +++++++ web/ts/admin.ts | 8 +------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/api/users.go b/api/users.go index fd18551ad..04861db9d 100644 --- a/api/users.go +++ b/api/users.go @@ -8,6 +8,7 @@ import ( "fmt" "net/http" "regexp" + "strconv" "strings" "time" @@ -136,7 +137,12 @@ func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err }) return nil, errors.New("query too short (minimum length is 3)") } - users, err = r.UsersDao.SearchUser(q) + role, err := strconv.ParseUint(rQ, 10, 64) + if err != nil { + users, err = r.UsersDao.SearchUser(q) + } else { + users, err = r.UsersDao.SearchUserWithRole(q, role) + } if err != nil && err != gorm.ErrRecordNotFound { _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, diff --git a/dao/users.go b/dao/users.go index aabbea98b..1e038e378 100644 --- a/dao/users.go +++ b/dao/users.go @@ -18,6 +18,7 @@ type UsersDao interface { CreateUser(ctx context.Context, user *model.User) (err error) DeleteUser(ctx context.Context, uid uint) (err error) SearchUser(query string) (users []model.User, err error) + SearchUserWithRole(query string, role uint64) (users []model.User, err error) IsUserAdmin(ctx context.Context, uid uint) (res bool, err error) GetUserByEmail(ctx context.Context, email string) (user model.User, err error) GetAllAdminsAndLecturers(users *[]model.User) (err error) @@ -69,6 +70,12 @@ func (d usersDao) SearchUser(query string) (users []model.User, err error) { return users, res.Error } +func (d usersDao) SearchUserWithRole(query string, role uint64) (users []model.User, err error) { + q := "%" + query + "%" + res := DB.Where("role = ? AND (UPPER(lrz_id) LIKE UPPER(?) OR UPPER(email) LIKE UPPER(?) OR UPPER(name) LIKE UPPER(?))", role, q, q, q).Limit(10).Preload("Settings").Find(&users) + return users, res.Error +} + func (d usersDao) IsUserAdmin(ctx context.Context, uid uint) (res bool, err error) { var user model.User err = DB.Find(&user, "id = ?", uid).Error diff --git a/web/ts/admin.ts b/web/ts/admin.ts index e8b5f01d3..11c1558a2 100755 --- a/web/ts/admin.ts +++ b/web/ts/admin.ts @@ -44,13 +44,7 @@ export class AdminUserList { return response.json(); }) .then((r) => { - if (this.roles != -1) { - this.currentPage = r.filter((obj) => { - return obj.role == this.roles; - }); // show all results on page one. - } else { - this.currentPage = r; - } + this.currentPage = r; this.showSearchResults = true; }) .catch((err) => { From 8beb49b67ab81ac06b8becbe64198b1e77475c87 Mon Sep 17 00:00:00 2001 From: johanneskarrer Date: Thu, 21 Nov 2024 11:23:40 +0100 Subject: [PATCH 06/12] updated users mock --- mock_dao/users.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/mock_dao/users.go b/mock_dao/users.go index fb97525b3..6c21480df 100644 --- a/mock_dao/users.go +++ b/mock_dao/users.go @@ -8,8 +8,8 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" model "github.com/TUM-Dev/gocast/model" + gomock "github.com/golang/mock/gomock" ) // MockUsersDao is a mock of UsersDao interface. @@ -251,6 +251,21 @@ func (mr *MockUsersDaoMockRecorder) SearchUser(query interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchUser", reflect.TypeOf((*MockUsersDao)(nil).SearchUser), query) } +// SearchUserWithRole mocks base method. +func (m *MockUsersDao) SearchUserWithRole(query string, role uint64) ([]model.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchUserWithRole", query, role) + ret0, _ := ret[0].([]model.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchUserWithRole indicates an expected call of SearchUserWithRole. +func (mr *MockUsersDaoMockRecorder) SearchUserWithRole(query, role interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchUserWithRole", reflect.TypeOf((*MockUsersDao)(nil).SearchUserWithRole), query, role) +} + // UpdateUser mocks base method. func (m *MockUsersDao) UpdateUser(user model.User) error { m.ctrl.T.Helper() From 4ac7fcae6252b001d883c3e3638df3f2230825a9 Mon Sep 17 00:00:00 2001 From: johanneskarrer Date: Thu, 21 Nov 2024 11:44:04 +0100 Subject: [PATCH 07/12] linter fix and made it clearer what is happening --- api/users.go | 4 ++-- web/ts/admin.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/users.go b/api/users.go index 04861db9d..19c2d7841 100644 --- a/api/users.go +++ b/api/users.go @@ -127,7 +127,7 @@ func (r usersRoutes) updateUser(c *gin.Context) { func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err error) { q := c.Query("q") rQ := c.Query("r") - reg, _ := regexp.Compile("[^a-zA-Z0-9 ]+") + reg := regexp.MustCompile("[^a-zA-Z0-9 ]+") q = reg.ReplaceAllString(q, "") // Removed in order to make the search work with empty query but selected role if len(q) < 3 && (rQ == "-1" || rQ == "") { @@ -138,7 +138,7 @@ func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err return nil, errors.New("query too short (minimum length is 3)") } role, err := strconv.ParseUint(rQ, 10, 64) - if err != nil { + if rQ == "" || rQ == "-1" || err != nil { users, err = r.UsersDao.SearchUser(q) } else { users, err = r.UsersDao.SearchUserWithRole(q, role) diff --git a/web/ts/admin.ts b/web/ts/admin.ts index 11c1558a2..50d09047c 100755 --- a/web/ts/admin.ts +++ b/web/ts/admin.ts @@ -44,7 +44,7 @@ export class AdminUserList { return response.json(); }) .then((r) => { - this.currentPage = r; + this.currentPage = r; // show all results on page one. this.showSearchResults = true; }) .catch((err) => { From 33cdabcf7f0440171e7b86e8874f8ec6df8774d9 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 24 Nov 2024 13:35:04 +0100 Subject: [PATCH 08/12] Update api/users.go Co-authored-by: Joscha Henningsen <44805696+joschahenningsen@users.noreply.github.com> --- api/users.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/users.go b/api/users.go index 19c2d7841..827d1cc44 100644 --- a/api/users.go +++ b/api/users.go @@ -129,7 +129,7 @@ func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err rQ := c.Query("r") reg := regexp.MustCompile("[^a-zA-Z0-9 ]+") q = reg.ReplaceAllString(q, "") - // Removed in order to make the search work with empty query but selected role + // make the search work with empty query but selected role if len(q) < 3 && (rQ == "-1" || rQ == "") { _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, From 8f7a6445867c1a360981160f912fb34cb7049fac Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 24 Nov 2024 13:41:37 +0100 Subject: [PATCH 09/12] Added separate error handling for not being able to parse role ID --- api/users.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/users.go b/api/users.go index 827d1cc44..3fb6f2697 100644 --- a/api/users.go +++ b/api/users.go @@ -138,7 +138,11 @@ func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err return nil, errors.New("query too short (minimum length is 3)") } role, err := strconv.ParseUint(rQ, 10, 64) - if rQ == "" || rQ == "-1" || err != nil { + if err != nil { + tools.RenderErrorPage(c, http.StatusBadRequest, "invalid role") + return nil, err + } + if rQ == "" || rQ == "-1" { users, err = r.UsersDao.SearchUser(q) } else { users, err = r.UsersDao.SearchUserWithRole(q, role) From a62d6f7d0427e159ba9acb54ae93d23b4f01613c Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 24 Nov 2024 14:09:42 +0100 Subject: [PATCH 10/12] Fixed code to pass test --- api/users.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/users.go b/api/users.go index 3fb6f2697..054894a40 100644 --- a/api/users.go +++ b/api/users.go @@ -138,7 +138,7 @@ func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err return nil, errors.New("query too short (minimum length is 3)") } role, err := strconv.ParseUint(rQ, 10, 64) - if err != nil { + if err != nil && rQ != "" && rQ != "-1" { tools.RenderErrorPage(c, http.StatusBadRequest, "invalid role") return nil, err } From 869703ea5d950e596ea28995446d612a3c51c9cd Mon Sep 17 00:00:00 2001 From: johanneskarrer Date: Fri, 29 Nov 2024 13:39:17 +0100 Subject: [PATCH 11/12] resolved conversations --- api/users.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/api/users.go b/api/users.go index 054894a40..d289b42d2 100644 --- a/api/users.go +++ b/api/users.go @@ -137,14 +137,18 @@ func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err }) return nil, errors.New("query too short (minimum length is 3)") } - role, err := strconv.ParseUint(rQ, 10, 64) - if err != nil && rQ != "" && rQ != "-1" { - tools.RenderErrorPage(c, http.StatusBadRequest, "invalid role") - return nil, err - } if rQ == "" || rQ == "-1" { users, err = r.UsersDao.SearchUser(q) } else { + role, err := strconv.ParseUint(rQ, 10, 64) + if err != nil { + _ = c.Error(tools.RequestError{ + Status: http.StatusBadRequest, + CustomMessage: "could not parse role", + Err: err, + }) + return nil, err + } users, err = r.UsersDao.SearchUserWithRole(q, role) } if err != nil && err != gorm.ErrRecordNotFound { From 6d0c3cc740995f7205a6d312bb9cab42d7305be0 Mon Sep 17 00:00:00 2001 From: Kordian Bruck Date: Fri, 10 Jan 2025 17:36:49 +0100 Subject: [PATCH 12/12] Update users.go --- api/users.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/api/users.go b/api/users.go index d289b42d2..f47fbc366 100644 --- a/api/users.go +++ b/api/users.go @@ -125,22 +125,22 @@ func (r usersRoutes) updateUser(c *gin.Context) { } func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err error) { - q := c.Query("q") - rQ := c.Query("r") + query := c.Query("q") + roleQuery := c.Query("r") reg := regexp.MustCompile("[^a-zA-Z0-9 ]+") - q = reg.ReplaceAllString(q, "") + query = reg.ReplaceAllString(query, "") // make the search work with empty query but selected role - if len(q) < 3 && (rQ == "-1" || rQ == "") { + if len(query) < 3 && (roleQuery == "-1" || roleQuery == "") { _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "query too short (minimum length is 3)", }) return nil, errors.New("query too short (minimum length is 3)") } - if rQ == "" || rQ == "-1" { - users, err = r.UsersDao.SearchUser(q) + if roleQuery == "" || roleQuery == "-1" { + users, err = r.UsersDao.SearchUser(query) } else { - role, err := strconv.ParseUint(rQ, 10, 64) + role, err := strconv.ParseUint(roleQuery, 10, 64) if err != nil { _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, @@ -149,12 +149,12 @@ func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err }) return nil, err } - users, err = r.UsersDao.SearchUserWithRole(q, role) + users, err = r.UsersDao.SearchUserWithRole(query, role) } if err != nil && err != gorm.ErrRecordNotFound { _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, - CustomMessage: "can not search user", + CustomMessage: "cannot search for user's", Err: err, }) return nil, err