Add pager to admin user list
This enables paging through the entire list of users. Ref T553
This commit is contained in:
parent
3d301c97e9
commit
bf7d422039
23
admin.go
23
admin.go
|
@ -29,6 +29,8 @@ var (
|
||||||
sysStatus systemStatus
|
sysStatus systemStatus
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const adminUsersPerPage = 30
|
||||||
|
|
||||||
type systemStatus struct {
|
type systemStatus struct {
|
||||||
Uptime string
|
Uptime string
|
||||||
NumGoroutine int
|
NumGoroutine int
|
||||||
|
@ -116,15 +118,32 @@ func handleViewAdminUsers(app *app, u *User, w http.ResponseWriter, r *http.Requ
|
||||||
Config config.AppCfg
|
Config config.AppCfg
|
||||||
Message string
|
Message string
|
||||||
|
|
||||||
Users *[]User
|
Users *[]User
|
||||||
|
CurPage int
|
||||||
|
TotalUsers int64
|
||||||
|
TotalPages []int
|
||||||
}{
|
}{
|
||||||
UserPage: NewUserPage(app, r, u, "Users", nil),
|
UserPage: NewUserPage(app, r, u, "Users", nil),
|
||||||
Config: app.cfg.App,
|
Config: app.cfg.App,
|
||||||
Message: r.FormValue("m"),
|
Message: r.FormValue("m"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.TotalUsers = app.db.GetAllUsersCount()
|
||||||
|
ttlPages := p.TotalUsers / adminUsersPerPage
|
||||||
|
p.TotalPages = []int{}
|
||||||
|
for i := 1; i <= int(ttlPages); i++ {
|
||||||
|
p.TotalPages = append(p.TotalPages, i)
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
p.Users, err = app.db.GetAllUsers(1)
|
p.CurPage, err = strconv.Atoi(r.FormValue("p"))
|
||||||
|
if err != nil || p.CurPage < 1 {
|
||||||
|
p.CurPage = 1
|
||||||
|
} else if p.CurPage > int(ttlPages) {
|
||||||
|
p.CurPage = int(ttlPages)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Users, err = app.db.GetAllUsers(uint(p.CurPage))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not get users: %v", err)}
|
return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not get users: %v", err)}
|
||||||
}
|
}
|
||||||
|
|
20
database.go
20
database.go
|
@ -113,6 +113,7 @@ type writestore interface {
|
||||||
GetDynamicContent(id string) (string, *time.Time, error)
|
GetDynamicContent(id string) (string, *time.Time, error)
|
||||||
UpdateDynamicContent(id, content string) error
|
UpdateDynamicContent(id, content string) error
|
||||||
GetAllUsers(page uint) (*[]User, error)
|
GetAllUsers(page uint) (*[]User, error)
|
||||||
|
GetAllUsersCount() int64
|
||||||
GetUserLastPostTime(id int64) (*time.Time, error)
|
GetUserLastPostTime(id int64) (*time.Time, error)
|
||||||
GetCollectionLastPostTime(id int64) (*time.Time, error)
|
GetCollectionLastPostTime(id int64) (*time.Time, error)
|
||||||
}
|
}
|
||||||
|
@ -2220,10 +2221,9 @@ func (db *datastore) UpdateDynamicContent(id, content string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *datastore) GetAllUsers(page uint) (*[]User, error) {
|
func (db *datastore) GetAllUsers(page uint) (*[]User, error) {
|
||||||
const usersPerPage = 30
|
limitStr := fmt.Sprintf("0, %d", adminUsersPerPage)
|
||||||
limitStr := fmt.Sprintf("0, %d", usersPerPage)
|
|
||||||
if page > 1 {
|
if page > 1 {
|
||||||
limitStr = fmt.Sprintf("%d, %d", (page-1)*usersPerPage, usersPerPage)
|
limitStr = fmt.Sprintf("%d, %d", (page-1)*adminUsersPerPage, adminUsersPerPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := db.Query("SELECT id, username, created FROM users ORDER BY created DESC LIMIT " + limitStr)
|
rows, err := db.Query("SELECT id, username, created FROM users ORDER BY created DESC LIMIT " + limitStr)
|
||||||
|
@ -2246,6 +2246,20 @@ func (db *datastore) GetAllUsers(page uint) (*[]User, error) {
|
||||||
return &users, nil
|
return &users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *datastore) GetAllUsersCount() int64 {
|
||||||
|
var count int64
|
||||||
|
err := db.QueryRow("SELECT COUNT(*) FROM users").Scan(&count)
|
||||||
|
switch {
|
||||||
|
case err == sql.ErrNoRows:
|
||||||
|
return 0
|
||||||
|
case err != nil:
|
||||||
|
log.Error("Failed selecting all users count: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
func (db *datastore) GetUserLastPostTime(id int64) (*time.Time, error) {
|
func (db *datastore) GetUserLastPostTime(id int64) (*time.Time, error) {
|
||||||
var t time.Time
|
var t time.Time
|
||||||
err := db.QueryRow("SELECT created FROM posts WHERE owner_id = ? ORDER BY created DESC LIMIT 1", id).Scan(&t)
|
err := db.QueryRow("SELECT created FROM posts WHERE owner_id = ? ORDER BY created DESC LIMIT 1", id).Scan(&t)
|
||||||
|
|
|
@ -9,3 +9,23 @@ header.admin {
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.pager {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #333;
|
||||||
|
font-family: @sansFont;
|
||||||
|
font-size: 0.86em;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
background: #efefef;
|
||||||
|
}
|
||||||
|
&.selected {
|
||||||
|
cursor: default;
|
||||||
|
background: #ccc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
<div class="snug content-container">
|
<div class="snug content-container">
|
||||||
{{template "admin-header" .}}
|
{{template "admin-header" .}}
|
||||||
|
|
||||||
<h2 id="posts-header">Users</h2>
|
<h2 id="posts-header" style="display: flex; justify-content: space-between;">Users <span style="font-style: italic; font-size: 0.75em;">{{.TotalUsers}} total</strong></h2>
|
||||||
|
|
||||||
<table class="classy export">
|
<table class="classy export" style="width:100%">
|
||||||
<tr>
|
<tr>
|
||||||
<th>User</th>
|
<th>User</th>
|
||||||
<th>Joined</th>
|
<th>Joined</th>
|
||||||
|
@ -21,6 +21,10 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<nav class="pager">
|
||||||
|
{{range $n := .TotalPages}}<a href="/admin/users{{if ne $n 1}}?p={{$n}}{{end}}" {{if eq $.CurPage $n}}class="selected"{{end}}>{{$n}}</a>{{end}}
|
||||||
|
</nav>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{template "footer" .}}
|
{{template "footer" .}}
|
||||||
|
|
Loading…
Reference in New Issue