feat(web): add admin settings and vault detail
This commit is contained in:
parent
5ca030e5f9
commit
6ca174b2d9
|
|
@ -116,6 +116,10 @@ var _translations = map[string]map[string]string{
|
||||||
"admin.runCleanup": "Запустить безопасную очистку",
|
"admin.runCleanup": "Запустить безопасную очистку",
|
||||||
"admin.downloadDiagnostics": "Скачать диагностику",
|
"admin.downloadDiagnostics": "Скачать диагностику",
|
||||||
"admin.vaultPrivacy": "Содержимое файлов и операции не отображаются в диагностике.",
|
"admin.vaultPrivacy": "Содержимое файлов и операции не отображаются в диагностике.",
|
||||||
|
"admin.general": "Общие настройки",
|
||||||
|
"admin.serverName": "Название сервера",
|
||||||
|
"admin.allowRegistration": "Разрешить публичную регистрацию",
|
||||||
|
"admin.smtpConfigured": "SMTP настраивается отдельно и пароль никогда не возвращается в форму.",
|
||||||
"user.account": "Моя учётная запись",
|
"user.account": "Моя учётная запись",
|
||||||
"user.devices": "Подключённые устройства",
|
"user.devices": "Подключённые устройства",
|
||||||
"user.noDevices": "Устройств пока нет",
|
"user.noDevices": "Устройств пока нет",
|
||||||
|
|
@ -355,6 +359,10 @@ var _translations = map[string]map[string]string{
|
||||||
"admin.runCleanup": "Run safe cleanup",
|
"admin.runCleanup": "Run safe cleanup",
|
||||||
"admin.downloadDiagnostics": "Download diagnostics",
|
"admin.downloadDiagnostics": "Download diagnostics",
|
||||||
"admin.vaultPrivacy": "File contents and operations are not displayed in diagnostics.",
|
"admin.vaultPrivacy": "File contents and operations are not displayed in diagnostics.",
|
||||||
|
"admin.general": "General settings",
|
||||||
|
"admin.serverName": "Server name",
|
||||||
|
"admin.allowRegistration": "Allow public registration",
|
||||||
|
"admin.smtpConfigured": "SMTP is configured separately and its password is never returned to a form.",
|
||||||
"user.account": "My account",
|
"user.account": "My account",
|
||||||
"user.devices": "Connected devices",
|
"user.devices": "Connected devices",
|
||||||
"user.noDevices": "No devices yet",
|
"user.noDevices": "No devices yet",
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ func NewServer(dbPath, dataDir string, cfg *Config) (*Server, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
cfg = DefaultConfig()
|
cfg = DefaultConfig()
|
||||||
}
|
}
|
||||||
|
if cfg.path == "" {
|
||||||
|
cfg.path = filepath.Join(dataDir, "config.yml")
|
||||||
|
}
|
||||||
if err := cfg.normalize(); err != nil {
|
if err := cfg.normalize(); err != nil {
|
||||||
return nil, fmt.Errorf("config: %w", err)
|
return nil, fmt.Errorf("config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
{{define "admin_settings"}}{{template "layout" .}}{{end}}
|
||||||
|
{{define "content"}}<section class="admin-shell"><div class="admin-content"><p class="eyebrow">{{t .Locale "admin.settings"}}</p><h1>{{t .Locale "admin.settings"}}</h1><section class="card panel"><h2>{{t .Locale "admin.general"}}</h2><form method="post" action="/admin/action" class="stack"><input type="hidden" name="csrf_token" value="{{.CSRF}}"><input type="hidden" name="action" value="web-settings"><label>{{t .Locale "admin.serverName"}}<input name="server_name" value="{{.ServerName}}"></label><label>{{t .Locale "locale.label"}}<select name="default_locale"><option value="en" {{if eq .DefaultLocale "en"}}selected{{end}}>English</option><option value="ru" {{if eq .DefaultLocale "ru"}}selected{{end}}>Русский</option></select></label><label><input name="allow_registration" type="checkbox" {{if .AllowRegistration}}checked{{end}}>{{t .Locale "admin.allowRegistration"}}</label><label>{{t .Locale "field.password"}}<input name="password" type="password" required></label><button class="button primary">{{t .Locale "admin.saveUser"}}</button></form></section><section class="card panel"><h2>{{t .Locale "admin.smtpTitle"}}</h2><p class="muted">{{t .Locale "admin.smtpConfigured"}}</p><a class="button secondary" href="/admin/dashboard">{{t .Locale "common.back"}}</a></section></div></section>{{end}}
|
||||||
|
|
@ -141,6 +141,10 @@ func (s *Server) handleAdminWeb(w http.ResponseWriter, r *http.Request) {
|
||||||
s.renderWebError(w, r, http.StatusInternalServerError, "error.internal", "/admin/dashboard")
|
s.renderWebError(w, r, http.StatusInternalServerError, "error.internal", "/admin/dashboard")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if page == "settings" {
|
||||||
|
s.renderPage(w, r, "admin_settings", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
s.renderPage(w, r, "admin", data)
|
s.renderPage(w, r, "admin", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,6 +334,27 @@ func (s *Server) handleAdminWebAction(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
action := r.FormValue("action")
|
action := r.FormValue("action")
|
||||||
switch action {
|
switch action {
|
||||||
|
case "web-settings":
|
||||||
|
if !s.adminReauth(r, session.SubjectID) {
|
||||||
|
s.renderWebError(w, r, http.StatusForbidden, "error.invalidCredentials", "/admin/settings")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
locale := r.FormValue("default_locale")
|
||||||
|
if locale != "ru" && locale != "en" {
|
||||||
|
locale = "en"
|
||||||
|
}
|
||||||
|
s.cfg.mu.Lock()
|
||||||
|
s.cfg.Web.DefaultLocale = locale
|
||||||
|
s.cfg.Web.AllowRegistration = r.FormValue("allow_registration") == "on"
|
||||||
|
s.cfg.Web.ServerName = strings.TrimSpace(r.FormValue("server_name"))
|
||||||
|
err := s.cfg.saveLocked()
|
||||||
|
s.cfg.mu.Unlock()
|
||||||
|
if err != nil {
|
||||||
|
jsonInternalError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.auditLog("web_settings_updated", "", "", s.clientIP(r), "updated by administrator")
|
||||||
|
http.Redirect(w, r, "/admin/settings", http.StatusSeeOther)
|
||||||
case "toggle-user":
|
case "toggle-user":
|
||||||
if !s.adminReauth(r, session.SubjectID) {
|
if !s.adminReauth(r, session.SubjectID) {
|
||||||
s.renderWebError(w, r, http.StatusForbidden, "error.invalidCredentials", "/admin/users")
|
s.renderWebError(w, r, http.StatusForbidden, "error.invalidCredentials", "/admin/users")
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ type webRenderer struct {
|
||||||
type webPage struct {
|
type webPage struct {
|
||||||
Locale string
|
Locale string
|
||||||
LocalePreference string
|
LocalePreference string
|
||||||
|
DefaultLocale string
|
||||||
Title string
|
Title string
|
||||||
ServerName string
|
ServerName string
|
||||||
CurrentPath string
|
CurrentPath string
|
||||||
|
|
@ -111,7 +112,7 @@ func newWebRenderer() (*webRenderer, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
renderer := &webRenderer{templates: make(map[string]*template.Template)}
|
renderer := &webRenderer{templates: make(map[string]*template.Template)}
|
||||||
for _, page := range []string{"home", "login", "register", "forgot", "reset", "confirm", "message", "error", "admin_login", "dashboard", "admin", "admin_create_user", "vault_detail"} {
|
for _, page := range []string{"home", "login", "register", "forgot", "reset", "confirm", "message", "error", "admin_login", "dashboard", "admin", "admin_create_user", "vault_detail", "admin_settings"} {
|
||||||
clone, err := layout.Clone()
|
clone, err := layout.Clone()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -139,6 +140,7 @@ func (s *Server) renderPageStatus(w http.ResponseWriter, r *http.Request, page s
|
||||||
}
|
}
|
||||||
data.Locale = s.webLocale(r)
|
data.Locale = s.webLocale(r)
|
||||||
data.LocalePreference = s.webLocalePreference(r)
|
data.LocalePreference = s.webLocalePreference(r)
|
||||||
|
data.DefaultLocale = s.cfg.Web.DefaultLocale
|
||||||
data.ServerName = s.cfg.Web.ServerName
|
data.ServerName = s.cfg.Web.ServerName
|
||||||
data.CurrentPath = r.URL.Path
|
data.CurrentPath = r.URL.Path
|
||||||
data.CurrentURL = r.URL.RequestURI()
|
data.CurrentURL = r.URL.RequestURI()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue