package main
import (
"bytes"
"html/template"
"net/http"
"git.neuromancer.ovh/bastien-mrq/gitfed/internal/i18n"
"git.neuromancer.ovh/bastien-mrq/gitfed/internal/store"
)
var adminUsersTpl = newTpl("admin-users", `
{{.Flash}}
<p><a href="/admin">← {{t .Lang "nav.admin"}}</a></p>
<h1>{{t .Lang "admin.users_title"}}</h1>
<table>
<tr><th>{{t .Lang "admin.users_col_username"}}</th><th>{{t .Lang "admin.users_col_keys"}}</th><th>{{t .Lang "nav.admin"}}</th><th></th></tr>
{{range .Users}}
<tr>
<td>{{.Username}}</td>
<td>{{len .PubKeys}}</td>
<td>
<form class="inline" method="post" action="/admin/users/set-admin">
<input type="hidden" name="username" value="{{.Username}}">
<input type="hidden" name="is_admin" value="{{if .IsAdmin}}0{{else}}1{{end}}">
<button type="submit">{{if .IsAdmin}}{{t $.Lang "admin.revoke_admin"}}{{else}}{{t $.Lang "admin.make_admin"}}{{end}}</button>
</form>
</td>
<td>
<form class="inline" method="post" action="/admin/users/delete" data-confirm="{{t $.Lang "admin.confirm_delete_user"}} {{.Username}}?">
<input type="hidden" name="username" value="{{.Username}}">
<button class="danger" type="submit">{{t $.Lang "settings.remove"}}</button>
</form>
</td>
</tr>
{{else}}
<tr><td colspan="4" class="muted">{{t .Lang "admin.users_empty"}}</td></tr>
{{end}}
</table>
<form class="card" method="post" action="/admin/users">
<strong>{{t .Lang "admin.add_user"}}</strong>
<label>{{t .Lang "admin.users_col_username"}}</label>
<input name="username" required placeholder="alice">
<label>{{t .Lang "settings.pubkey_label"}}</label>
<input name="pubkey" required placeholder="ssh-ed25519 AAAA... comment">
<label>{{t .Lang "admin.initial_password"}}</label>
<input name="password" type="password" required minlength="8">
<label><input type="checkbox" name="is_admin" value="1" style="width:auto; display:inline-block;"> {{t .Lang "admin.grant_admin"}}</label>
<button type="submit">{{t .Lang "dashboard.create"}}</button>
</form>
`)
func (s *server) handleAdminUsersList(w http.ResponseWriter, r *http.Request) {
lang := s.lang(r)
users, err := s.ops.ListUsers()
if err != nil {
s.serverError(w, r, err)
return
}
var buf bytes.Buffer
_ = adminUsersTpl.Execute(&buf, struct {
Users []store.User
Lang string
Flash template.HTML
}{users, string(lang), flash(r)})
s.render(w, r, i18n.T(lang, "admin.users_title"), "admin", template.HTML(buf.String()))
}
func (s *server) handleAdminUsersCreate(w http.ResponseWriter, r *http.Request) {
lang := s.lang(r)
username := r.FormValue("username")
pubkey := r.FormValue("pubkey")
password := r.FormValue("password")
if err := s.ops.CreateUser(username, pubkey); err != nil {
redirectWithMsg(w, r, "/admin/users", err.Error(), true)
return
}
if err := s.ops.SetPassword(username, password); err != nil {
redirectWithMsg(w, r, "/admin/users", err.Error(), true)
return
}
if r.FormValue("is_admin") == "1" {
if err := s.ops.SetUserAdmin(username, true); err != nil {
redirectWithMsg(w, r, "/admin/users", err.Error(), true)
return
}
}
redirectWithMsg(w, r, "/admin/users", i18n.T(lang, "admin.msg_user_created", username), false)
}
func (s *server) handleAdminUsersDelete(w http.ResponseWriter, r *http.Request) {
lang := s.lang(r)
username := r.FormValue("username")
if err := s.ops.DeleteUser(username); err != nil {
redirectWithMsg(w, r, "/admin/users", err.Error(), true)
return
}
redirectWithMsg(w, r, "/admin/users", i18n.T(lang, "admin.msg_user_deleted", username), false)
}
func (s *server) handleAdminUsersSetAdmin(w http.ResponseWriter, r *http.Request) {
lang := s.lang(r)
username := r.FormValue("username")
isAdmin := r.FormValue("is_admin") == "1"
if err := s.ops.SetUserAdmin(username, isAdmin); err != nil {
redirectWithMsg(w, r, "/admin/users", err.Error(), true)
return
}
redirectWithMsg(w, r, "/admin/users", i18n.T(lang, "admin.msg_user_updated", username), false)
}