Skip to content

Commit

Permalink
Added Filter by Role to user search (#1278)
Browse files Browse the repository at this point in the history
* Added Filter by Role to user search

* Lint fix

* Removed debug print

* Fixed issue

* moved filtering from client to api

* updated users mock

* linter fix and made it clearer what is happening

* Update api/users.go

Co-authored-by: Joscha Henningsen <[email protected]>

* Added separate error handling for not being able to parse role ID

* Fixed code to pass test

* resolved conversations

* Update users.go

---------

Co-authored-by: johanneskarrer <[email protected]>
Co-authored-by: Joscha Henningsen <[email protected]>
Co-authored-by: Kordian Bruck <[email protected]>
  • Loading branch information
4 people authored Feb 26, 2025
1 parent 2d278d7 commit 78445dc
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 10 deletions.
28 changes: 22 additions & 6 deletions api/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"net/http"
"regexp"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -127,21 +128,36 @@ func (r usersRoutes) updateUser(c *gin.Context) {
}

func (r usersRoutes) prepareUserSearch(c *gin.Context) (users []model.User, err error) {
q := c.Query("q")
reg, _ := regexp.Compile("[^a-zA-Z0-9 ]+")
q = reg.ReplaceAllString(q, "")
if len(q) < 3 {
query := c.Query("q")
roleQuery := c.Query("r")
reg := regexp.MustCompile("[^a-zA-Z0-9 ]+")
query = reg.ReplaceAllString(query, "")
// make the search work with empty query but selected role
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)")
}
users, err = r.UsersDao.SearchUser(q)
if roleQuery == "" || roleQuery == "-1" {
users, err = r.UsersDao.SearchUser(query)
} else {
role, err := strconv.ParseUint(roleQuery, 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(query, role)

Check failure on line 155 in api/users.go

View workflow job for this annotation

GitHub Actions / lint (./worker)

ineffectual assignment to err (ineffassign)
}
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
Expand Down
7 changes: 7 additions & 0 deletions dao/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,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)
Expand Down Expand Up @@ -70,6 +71,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
Expand Down
15 changes: 15 additions & 0 deletions mock_dao/users.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions web/template/admin/admin_tabs/users.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
<h2>Search</h2>
<input class="tl-input" placeholder="Search for users" type="text" x-model="userlist.searchInput"
@keyup="userlist.search()">
<div class="bg-transparent text-gray-800 dark:text-gray-200">
<label for="role">Role:</label>
<select id="role" class="bg-transparent dark:text-gray-300 text-gray-800" x-model="userlist.roles" @change="userlist.search()">
<option value="-1">All</option>
<option value="1">Admin</option>
<option value="2">Lecturer</option>
<option value="4">Student</option>
</select>
</div>
<div class="w-4 m-auto">
<i class="fas fa-circle-notch text-4 m-auto animate-spin" x-show="userlist.searchLoading"></i>
</div>
Expand Down
10 changes: 6 additions & 4 deletions web/ts/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,27 @@ 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) {
Expand Down

0 comments on commit 78445dc

Please sign in to comment.