diff --git a/common/pages.go b/common/pages.go index 54a7f668..d05b5777 100644 --- a/common/pages.go +++ b/common/pages.go @@ -154,6 +154,13 @@ type Paginator struct { LastPage int } +type PaginatorMod struct { + Params template.URL + PageList []int + Page int + LastPage int +} + type CustomPagePage struct { *Header Page *CustomPage @@ -604,10 +611,15 @@ type PanelMenuItemPage struct { Item MenuItem } +type PanelUserPageSearch struct { + Name string + Email string +} type PanelUserPage struct { *BasePanelPage ItemList []*User - Paginator + Search PanelUserPageSearch + PaginatorMod } type PanelGroupPage struct { diff --git a/common/user_store.go b/common/user_store.go index 74f9f586..1e696865 100644 --- a/common/user_store.go +++ b/common/user_store.go @@ -21,6 +21,7 @@ type UserStore interface { Getn(id int) *User GetByName(name string) (*User, error) Exists(id int) bool + SearchOffset(name, email string, offset, perPage int) (users []*User, err error) GetOffset(offset, perPage int) ([]*User, error) Each(f func(*User) error) error //BulkGet(ids []int) ([]*User, error) @@ -29,6 +30,7 @@ type UserStore interface { Create(name, password, email string, group int, active bool) (int, error) Reload(id int) error Count() int + CountSearch(name, email string) int SetCache(cache UserCache) GetCache() UserCache @@ -37,14 +39,17 @@ type UserStore interface { type DefaultUserStore struct { cache UserCache - get *sql.Stmt - getByName *sql.Stmt - getOffset *sql.Stmt - getAll *sql.Stmt - exists *sql.Stmt - register *sql.Stmt - nameExists *sql.Stmt - count *sql.Stmt + get *sql.Stmt + getByName *sql.Stmt + searchOffset *sql.Stmt + getOffset *sql.Stmt + getAll *sql.Stmt + exists *sql.Stmt + register *sql.Stmt + nameExists *sql.Stmt + + count *sql.Stmt + countSearch *sql.Stmt } // NewDefaultUserStore gives you a new instance of DefaultUserStore @@ -57,15 +62,20 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) { allCols := "uid,name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds,profile_comments,who_can_convo" // TODO: Add an admin version of registerStmt with more flexibility? return &DefaultUserStore{ - cache: cache, - get: acc.Select(u).Columns("name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds,profile_comments,who_can_convo").Where("uid=?").Prepare(), - getByName: acc.Select(u).Columns(allCols).Where("name=?").Prepare(), - getOffset: acc.Select(u).Columns(allCols).Orderby("uid ASC").Limit("?,?").Prepare(), - getAll: acc.Select(u).Columns(allCols).Prepare(), + cache: cache, + + get: acc.Select(u).Columns("name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds,profile_comments,who_can_convo").Where("uid=?").Prepare(), + getByName: acc.Select(u).Columns(allCols).Where("name=?").Prepare(), + searchOffset: acc.Select(u).Columns(allCols).Where("(name=? OR ?='') AND (email=? OR ?='')").Orderby("uid ASC").Limit("?,?").Prepare(), + getOffset: acc.Select(u).Columns(allCols).Orderby("uid ASC").Limit("?,?").Prepare(), + getAll: acc.Select(u).Columns(allCols).Prepare(), + exists: acc.Exists(u, "uid").Prepare(), register: acc.Insert(u).Columns("name,email,password,salt,group,is_super_admin,session,active,message,createdAt,lastActiveAt,lastLiked,oldestItemLikedCreatedAt").Fields("?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), // TODO: Implement user_count on users_groups here nameExists: acc.Exists(u, "name").Prepare(), - count: acc.Count(u).Prepare(), + + count: acc.Count(u).Prepare(), + countSearch: acc.Count(u).Where("(name=? OR ?='') AND (email=? OR ?='')").Prepare(), }, acc.FirstError() } @@ -170,6 +180,30 @@ func (s *DefaultUserStore) GetOffset(offset, perPage int) (users []*User, err er } return users, rows.Err() } +func (s *DefaultUserStore) SearchOffset(name, email string, offset, perPage int) (users []*User, err error) { + rows, err := s.searchOffset.Query(name, name, email, email, offset, perPage) + if err != nil { + return users, err + } + defer rows.Close() + + var embeds int + for rows.Next() { + u := &User{Loggedin: true} + err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage) + if err != nil { + return nil, err + } + if embeds != -1 { + u.ParseSettings = DefaultParseSettings.CopyPtr() + u.ParseSettings.NoEmbed = embeds == 0 + } + u.Init() + s.cache.Set(u) + users = append(users, u) + } + return users, rows.Err() +} func (s *DefaultUserStore) Each(f func(*User) error) error { rows, e := s.getAll.Query() if e != nil { @@ -350,6 +384,10 @@ func (s *DefaultUserStore) Count() (count int) { return Countf(s.count) } +func (s *DefaultUserStore) CountSearch(name, email string) (count int) { + return Countf(s.countSearch, name, name, email, email) +} + func (s *DefaultUserStore) SetCache(cache UserCache) { s.cache = cache } diff --git a/langs/english.json b/langs/english.json index 1d8af8f5..bc53e955 100644 --- a/langs/english.json +++ b/langs/english.json @@ -895,6 +895,13 @@ "panel_users_ban":"Ban", "panel_users_activate":"Activate", + "panel_users_search_head":"Search", + "panel_users_search_name":"Name", + "panel_users_search_name_placeholder":"John Doe", + "panel_users_search_email":"Email", + "panel_users_search_email_placeholder":"john.doe@example.com", + "panel_users_search_button":"Search", + "panel_user_head":"User Editor", "panel_user_avatar":"Avatar", "panel_user_avatar_select":"Select", diff --git a/routes/panel/users.go b/routes/panel/users.go index c4e21964..6b49ec16 100644 --- a/routes/panel/users.go +++ b/routes/panel/users.go @@ -2,7 +2,9 @@ package panel import ( "database/sql" + "html/template" "net/http" + "net/url" "strconv" c "github.com/Azareal/Gosora/common" @@ -13,17 +15,45 @@ func Users(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError { if ferr != nil { return ferr } + + name := r.FormValue("s-name") + email := r.FormValue("s-email") + hasParam := name != "" || email != "" + page, _ := strconv.Atoi(r.FormValue("page")) perPage := 15 - offset, page, lastPage := c.PageOffset(basePage.Stats.Users, page, perPage) + userCount := basePage.Stats.Users + if hasParam { + userCount = c.Users.CountSearch(name, email) + } + offset, page, lastPage := c.PageOffset(userCount, page, perPage) - users, err := c.Users.GetOffset(offset, perPage) - if err != nil { - return c.InternalError(err, w, r) + var users []*c.User + var e error + if hasParam { + users, e = c.Users.SearchOffset(name, email, offset, perPage) + } else { + users, e = c.Users.GetOffset(offset, perPage) + } + if e != nil { + return c.InternalError(e, w, r) } + name = url.QueryEscape(name) + email = url.QueryEscape(email) + search := c.PanelUserPageSearch{name, email} + + var params string + if hasParam { + if name != "" { + params += "s-name=" + name + "&" + } + if email != "" { + params += "s-email=" + email + "&" + } + } pageList := c.Paginate(page, lastPage, 5) - pi := c.PanelUserPage{basePage, users, c.Paginator{pageList, page, lastPage}} + pi := c.PanelUserPage{basePage, users, search, c.PaginatorMod{template.URL(params), pageList, page, lastPage}} return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_users", &pi}) } diff --git a/templates/panel_themes.html b/templates/panel_themes.html index e7152245..a18176b4 100644 --- a/templates/panel_themes.html +++ b/templates/panel_themes.html @@ -1,17 +1,17 @@

{{lang "panel_themes_primary_themes"}}

-
+
{{range .PrimaryThemes}} -
+
- {{.FriendlyName}}
+ {{.FriendlyName}}
{{lang "panel_themes_author_prefix"}}{{.Creator}}
- {{if .MobileFriendly}}📱{{end}} + {{if .MobileFriendly}}📱{{end}} {{if .Tag}}{{.Tag}}{{end}} - {{if .Active}}{{lang "panel_themes_default"}}{{else}}{{lang "panel_themes_make_default"}}{{end}} + {{if .Active}}{{lang "panel_themes_default"}}{{else}}{{lang "panel_themes_make_default"}}{{end}}
{{end}} @@ -20,17 +20,17 @@

{{lang "panel_themes_variant_themes"}}

-
+
{{range .VariantThemes}} -
+
- {{.FriendlyName}}
- {{lang "panel_themes_author_prefix"}}{{.Creator}} + {{.FriendlyName}}
+ {{lang "panel_themes_author_prefix"}}{{.Creator}}
- {{if .MobileFriendly}}📱{{end}} + {{if .MobileFriendly}}📱{{end}} {{if .Tag}}{{.Tag}}{{end}} - {{if .Active}}{{lang "panel_themes_default"}}{{else}}{{lang "panel_themes_make_default"}}{{end}} + {{if .Active}}{{lang "panel_themes_default"}}{{else}}{{lang "panel_themes_make_default"}}{{end}}
{{end}} diff --git a/templates/panel_user_edit.html b/templates/panel_user_edit.html index fe6614dc..c1f6407f 100644 --- a/templates/panel_user_edit.html +++ b/templates/panel_user_edit.html @@ -19,7 +19,7 @@
{{if .CurrentUser.Perms.EditUserPassword}}
diff --git a/templates/panel_users.html b/templates/panel_users.html index e6bafc24..6a4003b8 100644 --- a/templates/panel_users.html +++ b/templates/panel_users.html @@ -1,20 +1,39 @@

{{lang "panel_users_head"}}

-
+
{{range .ItemList}} -
+
{{.Name}} - {{lang "panel_users_profile"}} + {{lang "panel_users_profile"}} {{if (.Tag) and (.IsSuperMod)}}{{.Tag}}{{end}} - {{if .IsBanned}}{{lang "panel_users_unban"}}{{else if not .IsSuperMod}}{{lang "panel_users_ban"}}{{end}} - {{if not .Active}}{{lang "panel_users_activate"}}{{end}} + {{if .IsBanned}}{{lang "panel_users_unban"}}{{else if not .IsSuperMod}}{{lang "panel_users_ban"}}{{end}} + {{if not .Active}}{{lang "panel_users_activate"}}{{end}}
{{end}}
-{{template "paginator.html" . }} \ No newline at end of file +{{template "paginator_mod.html" . }} + +
+

{{lang "panel_users_search_head"}}

+
+
+
+ + {{if .CurrentUser.Perms.EditUserEmail}}{{end}} +
+
+
+
+
\ No newline at end of file