1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-10-30 03:36:16 +00:00

Admin: Isolate handlers and the list view

This commit is contained in:
Timur Ismagilov 2022-07-11 21:59:55 +05:00
parent 06caee907f
commit d6946b9e31
9 changed files with 424 additions and 561 deletions

View File

@ -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)
}
}
}

71
admin/view.go Normal file
View File

@ -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,
})
}

43
admin/view_user_list.html Normal file
View File

@ -0,0 +1,43 @@
{{define "manage users"}}Manage users{{end}}
{{define "title"}}{{template "manage users"}}{{end}}
{{define "body"}}
<main class="main-width">
<h1>{{template "manage users"}}</h1>
<form action="/admin/reindex-users" method="post">
<a class="btn" href="/admin/new-user">{{block "create user" .}}Create a new user{{end}}</a>
<button class="btn" type="submit">{{block "reindex users" .}}Reindex users{{end}}</button>
</form>
<table class="users-table">
<thead>
<tr>
<th>{{block "name" .}}Name{{end}}</th>
<th>{{block "group" .}}Group{{end}}</th>
<th>{{block "registered at" .}}Registered at{{end}}</th>
<th aria-label="{{block `actions` .}}Actions{{end}}"></th>
</tr>
</thead>
<tbody>{{$userHypha := .UserHypha}}
{{range .Users}}
<tr>
<td class="table-cell--fill">
<a href="/hypha/{{$userHypha}}/{{.Name}}">{{.Name}}</a>
</td>
<td>{{.Group}}</td>
<td>
{{if .RegisteredAt.IsZero}}
{{block "unknown registration time" .}}Unknown{{end}}
{{else}}
{{.RegisteredAt.UTC.Format "2006-01-02 15:04" }}
{{end}}
</td>
<td>
<a href="/admin/users/{{.Name}}/edit">{{block "edit" .}}Edit{{end}}</a>
</td>
</tr>
{{end}}
</tbody>
</table>
</main>
{{end}}

View File

@ -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;
}

View File

@ -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) %}
<main class="main-width">
<h1>{%s lc.Get("admin.users_title") %}</h1>
<form action="/admin/reindex-users" method="post">
<a class="btn" href="/admin/new-user">{%s lc.Get("admin.users_create") %}</a>
<button class="btn" type="submit">{%s lc.Get("admin.users_reindex") %}</button>
</form>
<br>
<table class="users-table">
<thead>
<tr>
<th>{%s lc.Get("admin.users_name") %}</th>
<th>{%s lc.Get("admin.users_group") %}</th>
<th>{%s lc.Get("admin.users_registered") %}</th>
<th aria-label="{%s lc.Get("admin.users_actions") %}"></th>
</tr>
</thead>
<tbody>
{% for _, u := range userList %}
<tr>
<td class="table-cell--fill">
<a href="/hypha/{%u cfg.UserHypha %}/{%u u.Name %}">{%s u.Name %}</a>
</td>
<td>{%s u.Group %}</td>
<td>
{% if u.RegisteredAt.IsZero() %}
{%s lc.Get("admin.users_notime") %}
{% else %}
{%s u.RegisteredAt.UTC().Format("2006-01-02 15:04") %}
{% endif %}
</td>
<td>
<a href="/admin/users/{%u u.Name %}/edit">{%s lc.Get("admin.users_edit") %}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</main>
{% endfunc %}
{% func AdminUserNew(f util.FormData, lc *l18n.Localizer) %}
<main class="main-width form-wrap">
<h1>{%s lc.Get("admin.newuser_title") %}</h1>

View File

@ -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(`
<main class="main-width">
<h1>`)
//line views/admin.qtpl:9
qw422016.E().S(lc.Get("admin.users_title"))
//line views/admin.qtpl:9
qw422016.N().S(`</h1>
<form action="/admin/reindex-users" method="post">
<a class="btn" href="/admin/new-user">`)
//line views/admin.qtpl:12
qw422016.E().S(lc.Get("admin.users_create"))
//line views/admin.qtpl:12
qw422016.N().S(`</a>
<button class="btn" type="submit">`)
//line views/admin.qtpl:13
qw422016.E().S(lc.Get("admin.users_reindex"))
//line views/admin.qtpl:13
qw422016.N().S(`</button>
</form>
<br>
<table class="users-table">
<thead>
<tr>
<th>`)
//line views/admin.qtpl:21
qw422016.E().S(lc.Get("admin.users_name"))
//line views/admin.qtpl:21
qw422016.N().S(`</th>
<th>`)
//line views/admin.qtpl:22
qw422016.E().S(lc.Get("admin.users_group"))
//line views/admin.qtpl:22
qw422016.N().S(`</th>
<th>`)
//line views/admin.qtpl:23
qw422016.E().S(lc.Get("admin.users_registered"))
//line views/admin.qtpl:23
qw422016.N().S(`</th>
<th aria-label="`)
//line views/admin.qtpl:24
qw422016.E().S(lc.Get("admin.users_actions"))
//line views/admin.qtpl:24
qw422016.N().S(`"></th>
</tr>
</thead>
<tbody>
`)
//line views/admin.qtpl:28
for _, u := range userList {
//line views/admin.qtpl:28
qw422016.N().S(`
<tr>
<td class="table-cell--fill">
<a href="/hypha/`)
//line views/admin.qtpl:31
qw422016.N().U(cfg.UserHypha)
//line views/admin.qtpl:31
qw422016.N().S(`/`)
//line views/admin.qtpl:31
qw422016.N().U(u.Name)
//line views/admin.qtpl:31
qw422016.N().S(`">`)
//line views/admin.qtpl:31
qw422016.E().S(u.Name)
//line views/admin.qtpl:31
qw422016.N().S(`</a>
</td>
<td>`)
//line views/admin.qtpl:33
qw422016.E().S(u.Group)
//line views/admin.qtpl:33
qw422016.N().S(`</td>
<td>
`)
//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(`
</td>
<td>
<a href="/admin/users/`)
//line views/admin.qtpl:42
qw422016.N().U(u.Name)
//line views/admin.qtpl:42
qw422016.N().S(`/edit">`)
//line views/admin.qtpl:42
qw422016.E().S(lc.Get("admin.users_edit"))
//line views/admin.qtpl:42
qw422016.N().S(`</a>
</td>
</tr>
`)
//line views/admin.qtpl:45
}
//line views/admin.qtpl:45
qw422016.N().S(`
</tbody>
</table>
</main>
`)
//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(`
<main class="main-width form-wrap">
<h1>`)
//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(`</h1>
`)
//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(`
<div class="notice notice--error">
<strong>`)
//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(`:</strong>
`)
//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(`
</div>
`)
//line views/admin.qtpl:60
//line views/admin.qtpl:15
}
//line views/admin.qtpl:60
//line views/admin.qtpl:15
qw422016.N().S(`
<form class="form--double" action="" method="post">
<div class="form-field">
<label for="name">`)
//line views/admin.qtpl:64
//line views/admin.qtpl:19
qw422016.E().S(lc.Get("admin.users_name"))
//line views/admin.qtpl:64
//line views/admin.qtpl:19
qw422016.N().S(`:</label>
<input type="text" name="name" id="name" value="`)
//line views/admin.qtpl:65
//line views/admin.qtpl:20
qw422016.E().S(f.Get("name"))
//line views/admin.qtpl:65
//line views/admin.qtpl:20
qw422016.N().S(`" autofocus>
</div>
<div class="form-field">
<label for="password">`)
//line views/admin.qtpl:69
//line views/admin.qtpl:24
qw422016.E().S(lc.Get("admin.users_password"))
//line views/admin.qtpl:69
//line views/admin.qtpl:24
qw422016.N().S(`:</label>
<input type="password" name="password" id="password" value="`)
//line views/admin.qtpl:70
//line views/admin.qtpl:25
qw422016.E().S(f.Get("password"))
//line views/admin.qtpl:70
//line views/admin.qtpl:25
qw422016.N().S(`">
</div>
<div class="form-field">
<label for="group">`)
//line views/admin.qtpl:74
//line views/admin.qtpl:29
qw422016.E().S(lc.Get("admin.users_group"))
//line views/admin.qtpl:74
//line views/admin.qtpl:29
qw422016.N().S(`:</label>
<select id="group" name="group">
<option`)
//line views/admin.qtpl:76
//line views/admin.qtpl:31
if f.Get("group") == "anon" {
//line views/admin.qtpl:76
//line views/admin.qtpl:31
qw422016.N().S(` selected`)
//line views/admin.qtpl:76
//line views/admin.qtpl:31
}
//line views/admin.qtpl:76
//line views/admin.qtpl:31
qw422016.N().S(`>anon</option>
<option`)
//line views/admin.qtpl:77
//line views/admin.qtpl:32
if f.Get("group") == "editor" {
//line views/admin.qtpl:77
//line views/admin.qtpl:32
qw422016.N().S(` selected`)
//line views/admin.qtpl:77
//line views/admin.qtpl:32
}
//line views/admin.qtpl:77
//line views/admin.qtpl:32
qw422016.N().S(`>editor</option>
<option`)
//line views/admin.qtpl:78
//line views/admin.qtpl:33
if f.Get("group") == "trusted" {
//line views/admin.qtpl:78
//line views/admin.qtpl:33
qw422016.N().S(` selected`)
//line views/admin.qtpl:78
//line views/admin.qtpl:33
}
//line views/admin.qtpl:78
//line views/admin.qtpl:33
qw422016.N().S(`>trusted</option>
<option`)
//line views/admin.qtpl:79
//line views/admin.qtpl:34
if f.Get("group") == "moderator" {
//line views/admin.qtpl:79
//line views/admin.qtpl:34
qw422016.N().S(` selected`)
//line views/admin.qtpl:79
//line views/admin.qtpl:34
}
//line views/admin.qtpl:79
//line views/admin.qtpl:34
qw422016.N().S(`>moderator</option>
<option`)
//line views/admin.qtpl:80
//line views/admin.qtpl:35
if f.Get("group") == "admin" {
//line views/admin.qtpl:80
//line views/admin.qtpl:35
qw422016.N().S(` selected`)
//line views/admin.qtpl:80
//line views/admin.qtpl:35
}
//line views/admin.qtpl:80
//line views/admin.qtpl:35
qw422016.N().S(`>admin</option>
</select>
</div>
@ -306,289 +148,289 @@ func StreamAdminUserNew(qw422016 *qt422016.Writer, f util.FormData, lc *l18n.Loc
<div class="form-field">
<div class="form-field__input">
<button class="btn" type="submit">`)
//line views/admin.qtpl:86
//line views/admin.qtpl:41
qw422016.E().S(lc.Get("admin.newuser_create"))
//line views/admin.qtpl:86
//line views/admin.qtpl:41
qw422016.N().S(`</button>
<a class="btn btn_weak" href="/admin/users/">`)
//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(`</a>
</div>
</div>
</form>
</main>
`)
//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(`
<main class="main-width form-wrap">
<h1>
<a href="/admin/users/">&larr;</a>
`)
//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(`
</h1>
<h2>`)
//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(`</h2>
`)
//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(`
<div class="notice notice--error">
<strong>`)
//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(`:</strong>
`)
//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(`
</div>
`)
//line views/admin.qtpl:108
//line views/admin.qtpl:63
}
//line views/admin.qtpl:108
//line views/admin.qtpl:63
qw422016.N().S(`
<form action="" method="post">
<div class="form-field">
<select id="group" name="group" aria-label="`)
//line views/admin.qtpl:112
//line views/admin.qtpl:67
qw422016.E().S(lc.Get("admin.users_group"))
//line views/admin.qtpl:112
//line views/admin.qtpl:67
qw422016.N().S(`">
<option`)
//line views/admin.qtpl:113
//line views/admin.qtpl:68
if f.Get("group") == "anon" {
//line views/admin.qtpl:113
//line views/admin.qtpl:68
qw422016.N().S(` selected`)
//line views/admin.qtpl:113
//line views/admin.qtpl:68
}
//line views/admin.qtpl:113
//line views/admin.qtpl:68
qw422016.N().S(`>anon</option>
<option`)
//line views/admin.qtpl:114
//line views/admin.qtpl:69
if f.Get("group") == "editor" {
//line views/admin.qtpl:114
//line views/admin.qtpl:69
qw422016.N().S(` selected`)
//line views/admin.qtpl:114
//line views/admin.qtpl:69
}
//line views/admin.qtpl:114
//line views/admin.qtpl:69
qw422016.N().S(`>editor</option>
<option`)
//line views/admin.qtpl:115
//line views/admin.qtpl:70
if f.Get("group") == "trusted" {
//line views/admin.qtpl:115
//line views/admin.qtpl:70
qw422016.N().S(` selected`)
//line views/admin.qtpl:115
//line views/admin.qtpl:70
}
//line views/admin.qtpl:115
//line views/admin.qtpl:70
qw422016.N().S(`>trusted</option>
<option`)
//line views/admin.qtpl:116
//line views/admin.qtpl:71
if f.Get("group") == "moderator" {
//line views/admin.qtpl:116
//line views/admin.qtpl:71
qw422016.N().S(` selected`)
//line views/admin.qtpl:116
//line views/admin.qtpl:71
}
//line views/admin.qtpl:116
//line views/admin.qtpl:71
qw422016.N().S(`>moderator</option>
<option`)
//line views/admin.qtpl:117
//line views/admin.qtpl:72
if f.Get("group") == "admin" {
//line views/admin.qtpl:117
//line views/admin.qtpl:72
qw422016.N().S(` selected`)
//line views/admin.qtpl:117
//line views/admin.qtpl:72
}
//line views/admin.qtpl:117
//line views/admin.qtpl:72
qw422016.N().S(`>admin</option>
</select>
</div>
<div class="form-field">
<button class="btn" type="submit">`)
//line views/admin.qtpl:122
//line views/admin.qtpl:77
qw422016.E().S(lc.Get("admin.user_update"))
//line views/admin.qtpl:122
//line views/admin.qtpl:77
qw422016.N().S(`</button>
</div>
</form>
<h2>`)
//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(`</h2>
<p>`)
//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(`</p>
<a class="btn btn_destructive" href="/admin/users/`)
//line views/admin.qtpl:128
//line views/admin.qtpl:83
qw422016.N().U(u.Name)
//line views/admin.qtpl:128
//line views/admin.qtpl:83
qw422016.N().S(`/delete">`)
//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(`</a>
</main>
`)
//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(`
<main class="main-width form-wrap">
<h1>`)
//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(`</h1>
`)
//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(`
<div class="notice notice--error">
<strong>`)
//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(`:</strong>
`)
//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(`
</div>
`)
//line views/admin.qtpl:141
//line views/admin.qtpl:96
}
//line views/admin.qtpl:141
//line views/admin.qtpl:96
qw422016.N().S(`
<p>`)
//line views/admin.qtpl:143
//line views/admin.qtpl:98
qw422016.N().S(lc.Get("admin.user_delete_warn", &l18n.Replacements{"name": fmt.Sprintf("<strong>%s</strong>", u.Name)}))
//line views/admin.qtpl:143
//line views/admin.qtpl:98
qw422016.N().S(`</p>
<form action="" method="post">
<button class="btn btn_destructive" type="submit">`)
//line views/admin.qtpl:146
//line views/admin.qtpl:101
qw422016.E().S(lc.Get("admin.user_delete"))
//line views/admin.qtpl:146
//line views/admin.qtpl:101
qw422016.N().S(`</button>
<a class="btn btn_weak" href="/admin/users/`)
//line views/admin.qtpl:147
//line views/admin.qtpl:102
qw422016.N().U(u.Name)
//line views/admin.qtpl:147
//line views/admin.qtpl:102
qw422016.N().S(`/edit">`)
//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(`</a>
</form>
</main>
`)
//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
}

View File

@ -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)
}
}
}

View File

@ -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)
}