diff --git a/admin/admin.go b/admin/admin.go index 2d09b01..14ff6a6 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -1,33 +1,158 @@ package admin import ( - "embed" + "fmt" "github.com/bouncepaw/mycorrhiza/viewutil" "github.com/gorilla/mux" + "io" + "log" + "mime" + "net/http" + "os" + "sort" + + "github.com/bouncepaw/mycorrhiza/cfg" + "github.com/bouncepaw/mycorrhiza/l18n" + "github.com/bouncepaw/mycorrhiza/user" + "github.com/bouncepaw/mycorrhiza/util" + "github.com/bouncepaw/mycorrhiza/views" ) -const adminTranslationRu = ` -{{define "panel title"}}Панель админстратора{{end}} -{{define "panel safe section title"}}Безопасная секция{{end}} -{{define "panel link about"}}Об этой вики{{end}} -{{define "panel update header"}}Обновить ссылки в верхней панели{{end}} -{{define "panel link user list"}}Список пользователей{{end}} -{{define "panel users"}}Управление пользователями{{end}} -{{define "panel unsafe section title"}}Опасная секция{{end}} -{{define "panel shutdown"}}Выключить вики{{end}} -{{define "panel reindex hyphae"}}Переиндексировать гифы{{end}} -` - -var ( - //go:embed *.html - fs embed.FS - panelChain viewutil.Chain -) - -func Init(rtr *mux.Router) { - panelChain = viewutil.CopyEnRuWith(fs, "admin.html", adminTranslationRu) +// handlerAdmin provides the admin panel. +func handlerAdmin(w http.ResponseWriter, rq *http.Request) { + w.Header().Set("Content-Type", "text/html;charset=utf-8") + w.WriteHeader(http.StatusOK) + viewPanel(viewutil.MetaFrom(w, rq)) } -func AdminPanel(meta viewutil.Meta) { - viewutil.ExecutePage(meta, panelChain, &viewutil.BaseData{}) +// handlerAdminShutdown kills the wiki. +func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { + if user.CanProceed(rq, "admin/shutdown") { + log.Println("An admin commanded the wiki to shutdown") + os.Exit(0) + } +} + +// handlerAdminReindexUsers reinitialises the user system. +func handlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) { + user.ReadUsersFromFilesystem() + redirectTo := rq.Referer() + if redirectTo == "" { + redirectTo = "/hypha/" + cfg.UserHypha + } + http.Redirect(w, rq, redirectTo, http.StatusSeeOther) +} + +func handlerAdminUsers(w http.ResponseWriter, rq *http.Request) { + // Get a sorted list of users + var users []*user.User + for u := range user.YieldUsers() { + users = append(users, u) + } + + sort.Slice(users, func(i, j int) bool { + less := users[i].RegisteredAt.Before(users[j].RegisteredAt) + return less + }) + viewList(viewutil.MetaFrom(w, rq), users) +} + +func handlerAdminUserEdit(w http.ResponseWriter, rq *http.Request) { + vars := mux.Vars(rq) + u := user.ByName(vars["username"]) + if u == nil { + util.HTTP404Page(w, "404 page not found") + return + } + + f := util.FormDataFromRequest(rq, []string{"group"}) + + if rq.Method == http.MethodPost { + oldGroup := u.Group + newGroup := f.Get("group") + + if user.ValidGroup(newGroup) { + u.Group = newGroup + if err := user.SaveUserDatabase(); err != nil { + u.Group = oldGroup + log.Println(err) + f = f.WithError(err) + } else { + http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther) + return + } + } else { + f = f.WithError(fmt.Errorf("invalid group ‘%s’", newGroup)) + } + } + + f.Put("group", u.Group) + + var lc = l18n.FromRequest(rq) + html := views.AdminUserEdit(u, f, lc) + html = views.Base(viewutil.MetaFrom(w, rq), fmt.Sprintf(lc.Get("admin.user_title"), u.Name), html) + + if f.HasError() { + w.WriteHeader(http.StatusBadRequest) + } + w.Header().Set("Content-Type", mime.TypeByExtension(".html")) + io.WriteString(w, html) +} + +func handlerAdminUserDelete(w http.ResponseWriter, rq *http.Request) { + vars := mux.Vars(rq) + u := user.ByName(vars["username"]) + if u == nil { + util.HTTP404Page(w, "404 page not found") + return + } + + f := util.NewFormData() + + if rq.Method == http.MethodPost { + f = f.WithError(user.DeleteUser(u.Name)) + if !f.HasError() { + http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther) + } else { + log.Println(f.Error()) + } + } + + var lc = l18n.FromRequest(rq) + html := views.AdminUserDelete(u, util.NewFormData(), lc) + html = views.Base(viewutil.MetaFrom(w, rq), fmt.Sprintf(lc.Get("admin.user_title"), u.Name), html) + + if f.HasError() { + w.WriteHeader(http.StatusBadRequest) + } + w.Header().Set("Content-Type", mime.TypeByExtension(".html")) + io.WriteString(w, html) +} + +func handlerAdminUserNew(w http.ResponseWriter, rq *http.Request) { + var lc = l18n.FromRequest(rq) + if rq.Method == http.MethodGet { + // New user form + html := views.AdminUserNew(util.NewFormData(), lc) + html = views.Base(viewutil.MetaFrom(w, rq), lc.Get("admin.newuser_title"), html) + + w.Header().Set("Content-Type", mime.TypeByExtension(".html")) + io.WriteString(w, html) + } else if rq.Method == http.MethodPost { + // Create a user + f := util.FormDataFromRequest(rq, []string{"name", "password", "group"}) + + err := user.Register(f.Get("name"), f.Get("password"), f.Get("group"), "local", true) + + if err != nil { + html := views.AdminUserNew(f.WithError(err), lc) + html = views.Base(viewutil.MetaFrom(w, rq), lc.Get("admin.newuser_title"), html) + + w.WriteHeader(http.StatusBadRequest) + w.Header().Set("Content-Type", mime.TypeByExtension(".html")) + io.WriteString(w, html) + } else { + http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther) + } + } } diff --git a/admin/view.go b/admin/view.go new file mode 100644 index 0000000..ec22ae2 --- /dev/null +++ b/admin/view.go @@ -0,0 +1,71 @@ +package admin + +import ( + "embed" + "github.com/bouncepaw/mycorrhiza/cfg" + "github.com/bouncepaw/mycorrhiza/user" + "github.com/bouncepaw/mycorrhiza/viewutil" + "github.com/gorilla/mux" + "net/http" +) + +const adminTranslationRu = ` +{{define "panel title"}}Панель админстратора{{end}} +{{define "panel safe section title"}}Безопасная секция{{end}} +{{define "panel link about"}}Об этой вики{{end}} +{{define "panel update header"}}Обновить ссылки в верхней панели{{end}} +{{define "panel link user list"}}Список пользователей{{end}} +{{define "panel users"}}Управление пользователями{{end}} +{{define "panel unsafe section title"}}Опасная секция{{end}} +{{define "panel shutdown"}}Выключить вики{{end}} +{{define "panel reindex hyphae"}}Переиндексировать гифы{{end}} + +{{define "manage users"}}Управление пользователями{{end}} +{{define "create user"}}Создать пользователя{{end}} +{{define "reindex users"}}Переиндексировать пользователей{{end}} +{{define "name"}}Имя{{end}} +{{define "group"}}Группа{{end}} +{{define "registered at"}}Зарегистрирован{{end}} +{{define "actions"}}Действия{{end}} +{{define "edit"}}Изменить{{end}} +` + +var ( + //go:embed *.html + fs embed.FS + panelChain viewutil.Chain + listChain viewutil.Chain +) + +func Init(rtr *mux.Router) { + rtr.HandleFunc("/shutdown", handlerAdminShutdown).Methods(http.MethodPost) + rtr.HandleFunc("/reindex-users", handlerAdminReindexUsers).Methods(http.MethodPost) + + rtr.HandleFunc("/new-user", handlerAdminUserNew).Methods(http.MethodGet, http.MethodPost) + rtr.HandleFunc("/users/{username}/edit", handlerAdminUserEdit).Methods(http.MethodGet, http.MethodPost) + rtr.HandleFunc("/users/{username}/delete", handlerAdminUserDelete).Methods(http.MethodGet, http.MethodPost) + rtr.HandleFunc("/users", handlerAdminUsers) + + rtr.HandleFunc("/", handlerAdmin) + + panelChain = viewutil.CopyEnRuWith(fs, "view_panel.html", adminTranslationRu) + listChain = viewutil.CopyEnRuWith(fs, "view_user_list.html", adminTranslationRu) +} + +func viewPanel(meta viewutil.Meta) { + viewutil.ExecutePage(meta, panelChain, &viewutil.BaseData{}) +} + +type listData struct { + *viewutil.BaseData + UserHypha string + Users []*user.User +} + +func viewList(meta viewutil.Meta, users []*user.User) { + viewutil.ExecutePage(meta, listChain, listData{ + BaseData: &viewutil.BaseData{}, + UserHypha: cfg.UserHypha, + Users: users, + }) +} diff --git a/admin/admin.html b/admin/view_panel.html similarity index 100% rename from admin/admin.html rename to admin/view_panel.html diff --git a/admin/view_user_list.html b/admin/view_user_list.html new file mode 100644 index 0000000..7eb762c --- /dev/null +++ b/admin/view_user_list.html @@ -0,0 +1,43 @@ +{{define "manage users"}}Manage users{{end}} +{{define "title"}}{{template "manage users"}}{{end}} +{{define "body"}} +
+

{{template "manage users"}}

+ +
+ {{block "create user" .}}Create a new user{{end}} + +
+ + + + + + + + + + + {{$userHypha := .UserHypha}} + {{range .Users}} + + + + + + + {{end}} + +
{{block "name" .}}Name{{end}}{{block "group" .}}Group{{end}}{{block "registered at" .}}Registered at{{end}}
+ {{.Name}} + {{.Group}} + {{if .RegisteredAt.IsZero}} + {{block "unknown registration time" .}}Unknown{{end}} + {{else}} + {{.RegisteredAt.UTC.Format "2006-01-02 15:04" }} + {{end}} + + {{block "edit" .}}Edit{{end}} +
+
+{{end}} \ No newline at end of file diff --git a/static/default.css b/static/default.css index bf17b66..feddd69 100644 --- a/static/default.css +++ b/static/default.css @@ -891,4 +891,11 @@ body[data-rrh-addr^="/interwiki"] main form + form { color: red; content: "*"; margin-left: .25rem; +} + +/* + * Admin pages + */ +.users-table { + margin-top: 1rem; } \ No newline at end of file diff --git a/views/admin.qtpl b/views/admin.qtpl index e972fcf..368eeaf 100644 --- a/views/admin.qtpl +++ b/views/admin.qtpl @@ -1,53 +1,8 @@ {% import "fmt" %} -{% import "github.com/bouncepaw/mycorrhiza/cfg" %} {% import "github.com/bouncepaw/mycorrhiza/l18n" %} {% import "github.com/bouncepaw/mycorrhiza/user" %} {% import "github.com/bouncepaw/mycorrhiza/util" %} -{% func AdminUsersPanel(userList []*user.User, lc *l18n.Localizer) %} -
-

{%s lc.Get("admin.users_title") %}

- -
- {%s lc.Get("admin.users_create") %} - -
- -
- - - - - - - - - - - - {% for _, u := range userList %} - - - - - - - {% endfor %} - -
{%s lc.Get("admin.users_name") %}{%s lc.Get("admin.users_group") %}{%s lc.Get("admin.users_registered") %}
- {%s u.Name %} - {%s u.Group %} - {% if u.RegisteredAt.IsZero() %} - {%s lc.Get("admin.users_notime") %} - {% else %} - {%s u.RegisteredAt.UTC().Format("2006-01-02 15:04") %} - {% endif %} - - {%s lc.Get("admin.users_edit") %} -
-
-{% endfunc %} - {% func AdminUserNew(f util.FormData, lc *l18n.Localizer) %}

{%s lc.Get("admin.newuser_title") %}

diff --git a/views/admin.qtpl.go b/views/admin.qtpl.go index a16d298..f674ca7 100644 --- a/views/admin.qtpl.go +++ b/views/admin.qtpl.go @@ -8,297 +8,139 @@ package views import "fmt" //line views/admin.qtpl:2 -import "github.com/bouncepaw/mycorrhiza/cfg" - -//line views/admin.qtpl:3 import "github.com/bouncepaw/mycorrhiza/l18n" -//line views/admin.qtpl:4 +//line views/admin.qtpl:3 import "github.com/bouncepaw/mycorrhiza/user" -//line views/admin.qtpl:5 +//line views/admin.qtpl:4 import "github.com/bouncepaw/mycorrhiza/util" -//line views/admin.qtpl:7 +//line views/admin.qtpl:6 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/admin.qtpl:7 +//line views/admin.qtpl:6 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/admin.qtpl:7 -func StreamAdminUsersPanel(qw422016 *qt422016.Writer, userList []*user.User, lc *l18n.Localizer) { -//line views/admin.qtpl:7 - qw422016.N().S(` -
-

`) -//line views/admin.qtpl:9 - qw422016.E().S(lc.Get("admin.users_title")) -//line views/admin.qtpl:9 - qw422016.N().S(`

- -
- `) -//line views/admin.qtpl:12 - qw422016.E().S(lc.Get("admin.users_create")) -//line views/admin.qtpl:12 - qw422016.N().S(` - -
- -
- - - - - - - - - - - - `) -//line views/admin.qtpl:28 - for _, u := range userList { -//line views/admin.qtpl:28 - qw422016.N().S(` - - - - - - - `) -//line views/admin.qtpl:45 - } -//line views/admin.qtpl:45 - qw422016.N().S(` - -
`) -//line views/admin.qtpl:21 - qw422016.E().S(lc.Get("admin.users_name")) -//line views/admin.qtpl:21 - qw422016.N().S(``) -//line views/admin.qtpl:22 - qw422016.E().S(lc.Get("admin.users_group")) -//line views/admin.qtpl:22 - qw422016.N().S(``) -//line views/admin.qtpl:23 - qw422016.E().S(lc.Get("admin.users_registered")) -//line views/admin.qtpl:23 - qw422016.N().S(`
- `) -//line views/admin.qtpl:31 - qw422016.E().S(u.Name) -//line views/admin.qtpl:31 - qw422016.N().S(` - `) -//line views/admin.qtpl:33 - qw422016.E().S(u.Group) -//line views/admin.qtpl:33 - qw422016.N().S(` - `) -//line views/admin.qtpl:35 - if u.RegisteredAt.IsZero() { -//line views/admin.qtpl:35 - qw422016.N().S(` - `) -//line views/admin.qtpl:36 - qw422016.E().S(lc.Get("admin.users_notime")) -//line views/admin.qtpl:36 - qw422016.N().S(` - `) -//line views/admin.qtpl:37 - } else { -//line views/admin.qtpl:37 - qw422016.N().S(` - `) -//line views/admin.qtpl:38 - qw422016.E().S(u.RegisteredAt.UTC().Format("2006-01-02 15:04")) -//line views/admin.qtpl:38 - qw422016.N().S(` - `) -//line views/admin.qtpl:39 - } -//line views/admin.qtpl:39 - qw422016.N().S(` - - `) -//line views/admin.qtpl:42 - qw422016.E().S(lc.Get("admin.users_edit")) -//line views/admin.qtpl:42 - qw422016.N().S(` -
-
-`) -//line views/admin.qtpl:49 -} - -//line views/admin.qtpl:49 -func WriteAdminUsersPanel(qq422016 qtio422016.Writer, userList []*user.User, lc *l18n.Localizer) { -//line views/admin.qtpl:49 - qw422016 := qt422016.AcquireWriter(qq422016) -//line views/admin.qtpl:49 - StreamAdminUsersPanel(qw422016, userList, lc) -//line views/admin.qtpl:49 - qt422016.ReleaseWriter(qw422016) -//line views/admin.qtpl:49 -} - -//line views/admin.qtpl:49 -func AdminUsersPanel(userList []*user.User, lc *l18n.Localizer) string { -//line views/admin.qtpl:49 - qb422016 := qt422016.AcquireByteBuffer() -//line views/admin.qtpl:49 - WriteAdminUsersPanel(qb422016, userList, lc) -//line views/admin.qtpl:49 - qs422016 := string(qb422016.B) -//line views/admin.qtpl:49 - qt422016.ReleaseByteBuffer(qb422016) -//line views/admin.qtpl:49 - return qs422016 -//line views/admin.qtpl:49 -} - -//line views/admin.qtpl:51 +//line views/admin.qtpl:6 func StreamAdminUserNew(qw422016 *qt422016.Writer, f util.FormData, lc *l18n.Localizer) { -//line views/admin.qtpl:51 +//line views/admin.qtpl:6 qw422016.N().S(`

`) -//line views/admin.qtpl:53 +//line views/admin.qtpl:8 qw422016.E().S(lc.Get("admin.newuser_title")) -//line views/admin.qtpl:53 +//line views/admin.qtpl:8 qw422016.N().S(`

`) -//line views/admin.qtpl:55 +//line views/admin.qtpl:10 if f.HasError() { -//line views/admin.qtpl:55 +//line views/admin.qtpl:10 qw422016.N().S(`
`) -//line views/admin.qtpl:57 +//line views/admin.qtpl:12 qw422016.E().S(lc.Get("ui.error")) -//line views/admin.qtpl:57 +//line views/admin.qtpl:12 qw422016.N().S(`: `) -//line views/admin.qtpl:58 +//line views/admin.qtpl:13 qw422016.E().S(f.Error()) -//line views/admin.qtpl:58 +//line views/admin.qtpl:13 qw422016.N().S(`
`) -//line views/admin.qtpl:60 +//line views/admin.qtpl:15 } -//line views/admin.qtpl:60 +//line views/admin.qtpl:15 qw422016.N().S(`
@@ -306,289 +148,289 @@ func StreamAdminUserNew(qw422016 *qt422016.Writer, f util.FormData, lc *l18n.Loc
`) -//line views/admin.qtpl:87 +//line views/admin.qtpl:42 qw422016.E().S(lc.Get("ui.cancel")) -//line views/admin.qtpl:87 +//line views/admin.qtpl:42 qw422016.N().S(`
`) -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 } -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 func WriteAdminUserNew(qq422016 qtio422016.Writer, f util.FormData, lc *l18n.Localizer) { -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 StreamAdminUserNew(qw422016, f, lc) -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 qt422016.ReleaseWriter(qw422016) -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 } -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 func AdminUserNew(f util.FormData, lc *l18n.Localizer) string { -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 qb422016 := qt422016.AcquireByteBuffer() -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 WriteAdminUserNew(qb422016, f, lc) -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 qs422016 := string(qb422016.B) -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 qt422016.ReleaseByteBuffer(qb422016) -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 return qs422016 -//line views/admin.qtpl:92 +//line views/admin.qtpl:47 } -//line views/admin.qtpl:94 +//line views/admin.qtpl:49 func StreamAdminUserEdit(qw422016 *qt422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) { -//line views/admin.qtpl:94 +//line views/admin.qtpl:49 qw422016.N().S(`

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

`) -//line views/admin.qtpl:101 +//line views/admin.qtpl:56 qw422016.E().S(lc.Get("admin.user_group_heading")) -//line views/admin.qtpl:101 +//line views/admin.qtpl:56 qw422016.N().S(`

`) -//line views/admin.qtpl:103 +//line views/admin.qtpl:58 if f.HasError() { -//line views/admin.qtpl:103 +//line views/admin.qtpl:58 qw422016.N().S(`
`) -//line views/admin.qtpl:105 +//line views/admin.qtpl:60 qw422016.E().S(lc.Get("ui.error")) -//line views/admin.qtpl:105 +//line views/admin.qtpl:60 qw422016.N().S(`: `) -//line views/admin.qtpl:106 +//line views/admin.qtpl:61 qw422016.E().S(f.Error()) -//line views/admin.qtpl:106 +//line views/admin.qtpl:61 qw422016.N().S(`
`) -//line views/admin.qtpl:108 +//line views/admin.qtpl:63 } -//line views/admin.qtpl:108 +//line views/admin.qtpl:63 qw422016.N().S(`

`) -//line views/admin.qtpl:126 +//line views/admin.qtpl:81 qw422016.E().S(lc.Get("admin.user_delete_heading")) -//line views/admin.qtpl:126 +//line views/admin.qtpl:81 qw422016.N().S(`

`) -//line views/admin.qtpl:127 +//line views/admin.qtpl:82 qw422016.E().S(lc.Get("admin.user_delete_tip")) -//line views/admin.qtpl:127 +//line views/admin.qtpl:82 qw422016.N().S(`

`) -//line views/admin.qtpl:128 +//line views/admin.qtpl:83 qw422016.E().S(lc.Get("admin.user_delete")) -//line views/admin.qtpl:128 +//line views/admin.qtpl:83 qw422016.N().S(`
`) -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 } -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 func WriteAdminUserEdit(qq422016 qtio422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) { -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 StreamAdminUserEdit(qw422016, u, f, lc) -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 qt422016.ReleaseWriter(qw422016) -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 } -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 func AdminUserEdit(u *user.User, f util.FormData, lc *l18n.Localizer) string { -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 qb422016 := qt422016.AcquireByteBuffer() -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 WriteAdminUserEdit(qb422016, u, f, lc) -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 qs422016 := string(qb422016.B) -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 qt422016.ReleaseByteBuffer(qb422016) -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 return qs422016 -//line views/admin.qtpl:130 +//line views/admin.qtpl:85 } -//line views/admin.qtpl:132 +//line views/admin.qtpl:87 func StreamAdminUserDelete(qw422016 *qt422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) { -//line views/admin.qtpl:132 +//line views/admin.qtpl:87 qw422016.N().S(`

`) -//line views/admin.qtpl:134 +//line views/admin.qtpl:89 qw422016.E().S(lc.Get("admin.user_delete_heading")) -//line views/admin.qtpl:134 +//line views/admin.qtpl:89 qw422016.N().S(`

`) -//line views/admin.qtpl:136 +//line views/admin.qtpl:91 if f.HasError() { -//line views/admin.qtpl:136 +//line views/admin.qtpl:91 qw422016.N().S(`
`) -//line views/admin.qtpl:138 +//line views/admin.qtpl:93 qw422016.E().S(lc.Get("ui.error")) -//line views/admin.qtpl:138 +//line views/admin.qtpl:93 qw422016.N().S(`: `) -//line views/admin.qtpl:139 +//line views/admin.qtpl:94 qw422016.E().S(f.Error()) -//line views/admin.qtpl:139 +//line views/admin.qtpl:94 qw422016.N().S(`
`) -//line views/admin.qtpl:141 +//line views/admin.qtpl:96 } -//line views/admin.qtpl:141 +//line views/admin.qtpl:96 qw422016.N().S(`

`) -//line views/admin.qtpl:143 +//line views/admin.qtpl:98 qw422016.N().S(lc.Get("admin.user_delete_warn", &l18n.Replacements{"name": fmt.Sprintf("%s", u.Name)})) -//line views/admin.qtpl:143 +//line views/admin.qtpl:98 qw422016.N().S(`

`) -//line views/admin.qtpl:147 +//line views/admin.qtpl:102 qw422016.E().S(lc.Get("ui.cancel")) -//line views/admin.qtpl:147 +//line views/admin.qtpl:102 qw422016.N().S(`
`) -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 } -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 func WriteAdminUserDelete(qq422016 qtio422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) { -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 StreamAdminUserDelete(qw422016, u, f, lc) -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 qt422016.ReleaseWriter(qw422016) -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 } -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 func AdminUserDelete(u *user.User, f util.FormData, lc *l18n.Localizer) string { -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 qb422016 := qt422016.AcquireByteBuffer() -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 WriteAdminUserDelete(qb422016, u, f, lc) -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 qs422016 := string(qb422016.B) -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 qt422016.ReleaseByteBuffer(qb422016) -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 return qs422016 -//line views/admin.qtpl:150 +//line views/admin.qtpl:105 } diff --git a/web/admin.go b/web/admin.go deleted file mode 100644 index 4843f4c..0000000 --- a/web/admin.go +++ /dev/null @@ -1,179 +0,0 @@ -package web - -import ( - "fmt" - "github.com/bouncepaw/mycorrhiza/admin" - "github.com/bouncepaw/mycorrhiza/viewutil" - "io" - "log" - "mime" - "net/http" - "os" - "sort" - - "github.com/gorilla/mux" - - "github.com/bouncepaw/mycorrhiza/cfg" - "github.com/bouncepaw/mycorrhiza/l18n" - "github.com/bouncepaw/mycorrhiza/user" - "github.com/bouncepaw/mycorrhiza/util" - "github.com/bouncepaw/mycorrhiza/views" -) - -// initAdmin sets up /admin routes if auth is used. Call it after you have decided if you want to use auth. -func initAdmin(rtr *mux.Router) { - rtr.HandleFunc("/shutdown", handlerAdminShutdown).Methods(http.MethodPost) - rtr.HandleFunc("/reindex-users", handlerAdminReindexUsers).Methods(http.MethodPost) - - rtr.HandleFunc("/new-user", handlerAdminUserNew).Methods(http.MethodGet, http.MethodPost) - rtr.HandleFunc("/users/{username}/edit", handlerAdminUserEdit).Methods(http.MethodGet, http.MethodPost) - rtr.HandleFunc("/users/{username}/delete", handlerAdminUserDelete).Methods(http.MethodGet, http.MethodPost) - rtr.HandleFunc("/users", handlerAdminUsers) - - rtr.HandleFunc("/", handlerAdmin) -} - -// handlerAdmin provides the admin panel. -func handlerAdmin(w http.ResponseWriter, rq *http.Request) { - w.Header().Set("Content-Type", "text/html;charset=utf-8") - w.WriteHeader(http.StatusOK) - admin.AdminPanel(viewutil.MetaFrom(w, rq)) -} - -// handlerAdminShutdown kills the wiki. -func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) { - if user.CanProceed(rq, "admin/shutdown") { - log.Println("An admin commanded the wiki to shutdown") - os.Exit(0) - } -} - -// handlerAdminReindexUsers reinitialises the user system. -func handlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) { - user.ReadUsersFromFilesystem() - redirectTo := rq.Referer() - if redirectTo == "" { - redirectTo = "/hypha/" + cfg.UserHypha - } - http.Redirect(w, rq, redirectTo, http.StatusSeeOther) -} - -func handlerAdminUsers(w http.ResponseWriter, rq *http.Request) { - // 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 - }) - - var lc = l18n.FromRequest(rq) - html := views.AdminUsersPanel(userList, lc) - html = views.Base(viewutil.MetaFrom(w, rq), lc.Get("admin.users_title"), html) - - w.Header().Set("Content-Type", mime.TypeByExtension(".html")) - io.WriteString(w, html) -} - -func handlerAdminUserEdit(w http.ResponseWriter, rq *http.Request) { - vars := mux.Vars(rq) - u := user.ByName(vars["username"]) - if u == nil { - util.HTTP404Page(w, "404 page not found") - return - } - - f := util.FormDataFromRequest(rq, []string{"group"}) - - if rq.Method == http.MethodPost { - oldGroup := u.Group - newGroup := f.Get("group") - - if user.ValidGroup(newGroup) { - u.Group = newGroup - if err := user.SaveUserDatabase(); err != nil { - u.Group = oldGroup - log.Println(err) - f = f.WithError(err) - } else { - http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther) - return - } - } else { - f = f.WithError(fmt.Errorf("invalid group ‘%s’", newGroup)) - } - } - - f.Put("group", u.Group) - - var lc = l18n.FromRequest(rq) - html := views.AdminUserEdit(u, f, lc) - html = views.Base(viewutil.MetaFrom(w, rq), fmt.Sprintf(lc.Get("admin.user_title"), u.Name), html) - - if f.HasError() { - w.WriteHeader(http.StatusBadRequest) - } - w.Header().Set("Content-Type", mime.TypeByExtension(".html")) - io.WriteString(w, html) -} - -func handlerAdminUserDelete(w http.ResponseWriter, rq *http.Request) { - vars := mux.Vars(rq) - u := user.ByName(vars["username"]) - if u == nil { - util.HTTP404Page(w, "404 page not found") - return - } - - f := util.NewFormData() - - if rq.Method == http.MethodPost { - f = f.WithError(user.DeleteUser(u.Name)) - if !f.HasError() { - http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther) - } else { - log.Println(f.Error()) - } - } - - var lc = l18n.FromRequest(rq) - html := views.AdminUserDelete(u, util.NewFormData(), lc) - html = views.Base(viewutil.MetaFrom(w, rq), fmt.Sprintf(lc.Get("admin.user_title"), u.Name), html) - - if f.HasError() { - w.WriteHeader(http.StatusBadRequest) - } - w.Header().Set("Content-Type", mime.TypeByExtension(".html")) - io.WriteString(w, html) -} - -func handlerAdminUserNew(w http.ResponseWriter, rq *http.Request) { - var lc = l18n.FromRequest(rq) - if rq.Method == http.MethodGet { - // New user form - html := views.AdminUserNew(util.NewFormData(), lc) - html = views.Base(viewutil.MetaFrom(w, rq), lc.Get("admin.newuser_title"), html) - - w.Header().Set("Content-Type", mime.TypeByExtension(".html")) - io.WriteString(w, html) - } else if rq.Method == http.MethodPost { - // Create a user - f := util.FormDataFromRequest(rq, []string{"name", "password", "group"}) - - err := user.Register(f.Get("name"), f.Get("password"), f.Get("group"), "local", true) - - if err != nil { - html := views.AdminUserNew(f.WithError(err), lc) - html = views.Base(viewutil.MetaFrom(w, rq), lc.Get("admin.newuser_title"), html) - - w.WriteHeader(http.StatusBadRequest) - w.Header().Set("Content-Type", mime.TypeByExtension(".html")) - io.WriteString(w, html) - } else { - http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther) - } - } -} diff --git a/web/web.go b/web/web.go index ad6d585..ba57aa8 100644 --- a/web/web.go +++ b/web/web.go @@ -63,7 +63,6 @@ func Handler() http.Handler { if cfg.UseAuth { adminRouter := wikiRouter.PathPrefix("/admin").Subrouter() adminRouter.Use(groupMiddleware("admin")) - initAdmin(adminRouter) admin.Init(adminRouter) }