From 11e98b2368087578a6e3ab56c220a3435fc2fe91 Mon Sep 17 00:00:00 2001 From: handlerug Date: Tue, 29 Jun 2021 22:10:48 +0700 Subject: [PATCH] Working user panel See https://mycorrhiza.wiki/hypha/idea/user_panel It's not pretty, but it works. The next step is to make it look good. --- user/files.go | 4 ++ user/net.go | 2 +- user/user.go | 17 +++++ user/users.go | 8 +-- views/admin.qtpl | 35 ++++++++-- views/admin.qtpl.go | 156 +++++++++++++++++++++++++++++++++++++------- web/admin.go | 83 ++++++++++++++++++----- 7 files changed, 255 insertions(+), 50 deletions(-) diff --git a/user/files.go b/user/files.go index 08b3a0d..43ff75e 100644 --- a/user/files.go +++ b/user/files.go @@ -124,6 +124,10 @@ func readTokensToUsers() { log.Println("Found", len(tmp), "active sessions") } +func SaveUserDatabase() error { + return dumpRegistrationCredentials() +} + func dumpRegistrationCredentials() error { tmp := []*User{} diff --git a/user/net.go b/user/net.go index 09dd883..2748f93 100644 --- a/user/net.go +++ b/user/net.go @@ -23,7 +23,7 @@ func FromRequest(rq *http.Request) *User { if err != nil { return EmptyUser() } - return userByToken(cookie.Value) + return UserByToken(cookie.Value) } // LogoutFromRequest logs the user in `rq` out and rewrites the cookie in `w`. diff --git a/user/user.go b/user/user.go index 0ce6103..a1d6db5 100644 --- a/user/user.go +++ b/user/user.go @@ -51,6 +51,14 @@ var minimalRights = map[string]int{ "admin/shutdown": 4, } +var groups = []string{ + "anon", + "editor", + "trusted", + "moderator", + "admin", +} + // Group — Right var groupRight = map[string]int{ "anon": 0, @@ -60,6 +68,15 @@ var groupRight = map[string]int{ "admin": 4, } +func ValidGroup(group string) bool { + for _, grp := range groups { + if grp == group { + return true + } + } + return false +} + func EmptyUser() *User { return &User{ Name: "anon", diff --git a/user/users.go b/user/users.go index adf883d..8aaa4bb 100644 --- a/user/users.go +++ b/user/users.go @@ -56,18 +56,18 @@ func HasUsername(username string) bool { } func CredentialsOK(username, password string) bool { - return userByName(username).isCorrectPassword(password) + return UserByName(username).isCorrectPassword(password) } -func userByToken(token string) *User { +func UserByToken(token string) *User { if usernameUntyped, ok := tokens.Load(token); ok { username := usernameUntyped.(string) - return userByName(username) + return UserByName(username) } return EmptyUser() } -func userByName(username string) *User { +func UserByName(username string) *User { if userUntyped, ok := users.Load(username); ok { user := userUntyped.(*User) return user diff --git a/views/admin.qtpl b/views/admin.qtpl index 8be7499..93e22bf 100644 --- a/views/admin.qtpl +++ b/views/admin.qtpl @@ -5,7 +5,7 @@

Manage users

-
+
@@ -17,14 +17,18 @@ Name Group Registered at + {% for _, u := range userList %} - {%s= u.Name %} - {%s= u.Group %} - {%s= u.RegisteredAt.Format("2006-01-02 15:04:05-0700") %} + {%s u.Name %} + {%s u.Group %} + {%s u.RegisteredAt.Format("2006-01-02 15:04:05-0700") %} + + Edit + {% endfor %} @@ -32,3 +36,26 @@
{% endfunc %} + +{% func AdminUsersUserHTML(u *user.User) %} +
+
+

{%s u.Name %}

+ +
+ + +
+
+ + +
+
+
+{% endfunc %} diff --git a/views/admin.qtpl.go b/views/admin.qtpl.go index 0dfc69c..320bf11 100644 --- a/views/admin.qtpl.go +++ b/views/admin.qtpl.go @@ -28,7 +28,7 @@ func StreamAdminUsersPanelHTML(qw422016 *qt422016.Writer, userList []*user.User)

Manage users

-
+
@@ -40,66 +40,172 @@ func StreamAdminUsersPanelHTML(qw422016 *qt422016.Writer, userList []*user.User) Name Group Registered at + `) -//line views/admin.qtpl:23 +//line views/admin.qtpl:24 for _, u := range userList { -//line views/admin.qtpl:23 +//line views/admin.qtpl:24 qw422016.N().S(` `) -//line views/admin.qtpl:25 - qw422016.N().S(u.Name) -//line views/admin.qtpl:25 - qw422016.N().S(` - `) //line views/admin.qtpl:26 - qw422016.N().S(u.Group) + qw422016.E().S(u.Name) //line views/admin.qtpl:26 qw422016.N().S(` `) //line views/admin.qtpl:27 - qw422016.N().S(u.RegisteredAt.Format("2006-01-02 15:04:05-0700")) + qw422016.E().S(u.Group) //line views/admin.qtpl:27 qw422016.N().S(` + `) +//line views/admin.qtpl:28 + qw422016.E().S(u.RegisteredAt.Format("2006-01-02 15:04:05-0700")) +//line views/admin.qtpl:28 + qw422016.N().S(` + + Edit + `) -//line views/admin.qtpl:29 +//line views/admin.qtpl:33 } -//line views/admin.qtpl:29 +//line views/admin.qtpl:33 qw422016.N().S(`
`) -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 } -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 func WriteAdminUsersPanelHTML(qq422016 qtio422016.Writer, userList []*user.User) { -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 StreamAdminUsersPanelHTML(qw422016, userList) -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 qt422016.ReleaseWriter(qw422016) -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 } -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 func AdminUsersPanelHTML(userList []*user.User) string { -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 qb422016 := qt422016.AcquireByteBuffer() -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 WriteAdminUsersPanelHTML(qb422016, userList) -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 qs422016 := string(qb422016.B) -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 qt422016.ReleaseByteBuffer(qb422016) -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 return qs422016 -//line views/admin.qtpl:34 +//line views/admin.qtpl:38 +} + +//line views/admin.qtpl:40 +func StreamAdminUsersUserHTML(qw422016 *qt422016.Writer, u *user.User) { +//line views/admin.qtpl:40 + qw422016.N().S(` +
+
+

`) +//line views/admin.qtpl:43 + qw422016.E().S(u.Name) +//line views/admin.qtpl:43 + qw422016.N().S(`

+ +
+ + +
+
+ + +
+
+
+`) +//line views/admin.qtpl:61 +} + +//line views/admin.qtpl:61 +func WriteAdminUsersUserHTML(qq422016 qtio422016.Writer, u *user.User) { +//line views/admin.qtpl:61 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/admin.qtpl:61 + StreamAdminUsersUserHTML(qw422016, u) +//line views/admin.qtpl:61 + qt422016.ReleaseWriter(qw422016) +//line views/admin.qtpl:61 +} + +//line views/admin.qtpl:61 +func AdminUsersUserHTML(u *user.User) string { +//line views/admin.qtpl:61 + qb422016 := qt422016.AcquireByteBuffer() +//line views/admin.qtpl:61 + WriteAdminUsersUserHTML(qb422016, u) +//line views/admin.qtpl:61 + qs422016 := string(qb422016.B) +//line views/admin.qtpl:61 + qt422016.ReleaseByteBuffer(qb422016) +//line views/admin.qtpl:61 + return qs422016 +//line views/admin.qtpl:61 } diff --git a/web/admin.go b/web/admin.go index 5f05719..c8345cb 100644 --- a/web/admin.go +++ b/web/admin.go @@ -1,10 +1,13 @@ package web import ( + "fmt" + "mime" "io" "log" "net/http" "sort" + "strings" "github.com/bouncepaw/mycorrhiza/cfg" "github.com/bouncepaw/mycorrhiza/user" @@ -19,7 +22,7 @@ func initAdmin() { http.HandleFunc("/admin/shutdown", handlerAdminShutdown) http.HandleFunc("/admin/reindex-users", handlerAdminReindexUsers) - http.HandleFunc("/admin/users", handlerAdminUsers) + http.HandleFunc("/admin/users/", handlerAdminUsers) } } @@ -49,31 +52,79 @@ func handlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) if user.CanProceed(rq, "admin") && rq.Method == "POST" { user.ReadUsersFromFilesystem() - http.Redirect(w, rq, "/hypha/"+cfg.UserHypha, http.StatusSeeOther) + redirectTo := rq.Referer() + if redirectTo == "" { + redirectTo = "/hypha/"+cfg.UserHypha + } + http.Redirect(w, rq, redirectTo, http.StatusSeeOther) } } func handlerAdminUsers(w http.ResponseWriter, r *http.Request) { util.PrepareRq(r) if user.CanProceed(r, "admin") { - // Get a sorted list of users - var userList []*user.User - for u := range user.YieldUsers() { - userList = append(userList, u) + path := strings.TrimPrefix(r.URL.Path, "/admin/users") + parts := strings.Split(path, "/")[1:] + + // Users dashboard + if len(parts) == 0 { + // Get a sorted list of users + var userList []*user.User + for u := range user.YieldUsers() { + userList = append(userList, u) + } + + sort.Slice(userList, func(i, j int) bool { + less := userList[i].RegisteredAt.Before(userList[j].RegisteredAt) + return less + }) + + html := views.AdminUsersPanelHTML(userList) + html = views.BaseHTML("Manage users", html, user.FromRequest(r)) + + w.Header().Set("Content-Type", mime.TypeByExtension(".html")) + if _, err := io.WriteString(w, html); err != nil { + log.Println(err) + } + return } - sort.Slice(userList, func(i, j int) bool { - less := userList[i].RegisteredAt.Before(userList[j].RegisteredAt) - return less - }) + // User edit page + if len(parts) == 2 && parts[1] == "edit" { + u := user.UserByName(parts[0]) - html := views.AdminUsersPanelHTML(userList) - html = views.BaseHTML("Manage users", html, user.FromRequest(r)) + if u != nil && u.Name != "anon" { + if r.Method == http.MethodGet { + html := views.AdminUsersUserHTML(u) + html = views.BaseHTML(fmt.Sprintf("User %s", u.Name), html, user.FromRequest(r)) - w.Header().Set("Content-Type", "text/html; charset=utf-8") - _, err := io.WriteString(w, html) - if err != nil { - log.Println(err) + w.Header().Set("Content-Type", mime.TypeByExtension(".html")) + if _, err := io.WriteString(w, html); err != nil { + log.Println(err) + } + return + } else if r.Method == http.MethodPost { + oldGroup := u.Group + newGroup := r.PostFormValue("group") + if user.ValidGroup(newGroup) { + u.Group = newGroup + if err := user.SaveUserDatabase(); err != nil { + u.Group = oldGroup + log.Println(err) + w.WriteHeader(http.StatusInternalServerError) + io.WriteString(w, err.Error()) + } else { + http.Redirect(w, r, "/admin/users/", http.StatusSeeOther) + } + } else { + w.WriteHeader(http.StatusBadRequest) + io.WriteString(w, "invalid group") + } + return + } + } } + + util.HTTP404Page(w, "404 page not found") } }