mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2025-10-29 09:15:33 +00:00
started overview
This commit is contained in:
@@ -41,4 +41,6 @@ const (
|
|||||||
P_USER_CREATE_NAME = "user_create"
|
P_USER_CREATE_NAME = "user_create"
|
||||||
|
|
||||||
P_USER_EDIT_NAME = "user_edit"
|
P_USER_EDIT_NAME = "user_edit"
|
||||||
|
|
||||||
|
P_USER_MGMT_NAME = "user_management"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ func (p *LoginPage) GET(engine *templating.Engine, app core.App) HandleFunc {
|
|||||||
|
|
||||||
Logout(e, &app)
|
Logout(e, &app)
|
||||||
|
|
||||||
|
SetRedirect(data, e)
|
||||||
|
|
||||||
return engine.Response200(e, p.Template, data, p.Layout)
|
return engine.Response200(e, p.Template, data, p.Layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,6 +86,8 @@ func Unauthorized(
|
|||||||
data["csrf_token"] = token
|
data["csrf_token"] = token
|
||||||
data["error"] = error.Error()
|
data["error"] = error.Error()
|
||||||
|
|
||||||
|
SetRedirect(data, e)
|
||||||
|
|
||||||
htm, err := engine.RenderToString(e, data, TEMPLATE_LOGIN, "blank")
|
htm, err := engine.RenderToString(e, data, TEMPLATE_LOGIN, "blank")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return engine.Response500(e, err, data)
|
return engine.Response500(e, err, data)
|
||||||
@@ -160,6 +164,8 @@ func (p *LoginPage) POST(engine *templating.Engine, app core.App) HandleFunc {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetRedirect(data, e)
|
||||||
|
|
||||||
return RedirectTo(e)
|
return RedirectTo(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ func (p *UserCreatePage) GET(engine *templating.Engine, app core.App) HandleFunc
|
|||||||
data["csrf_nonce"] = nonce
|
data["csrf_nonce"] = nonce
|
||||||
data["csrf_token"] = token
|
data["csrf_token"] = token
|
||||||
|
|
||||||
|
SetRedirect(data, e)
|
||||||
|
|
||||||
return engine.Response200(e, p.Template, data, p.Layout)
|
return engine.Response200(e, p.Template, data, p.Layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,6 +135,8 @@ func (p *UserCreatePage) POST(engine *templating.Engine, app core.App) HandleFun
|
|||||||
return InvalidSignupResponse(engine, e, fmt.Sprintf("Fehler beim Erstellen des Benutzers: %s", err.Error()))
|
return InvalidSignupResponse(engine, e, fmt.Sprintf("Fehler beim Erstellen des Benutzers: %s", err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetRedirect(data, e)
|
||||||
|
|
||||||
data["user"] = user
|
data["user"] = user
|
||||||
return engine.Response200(e, p.Template, data, p.Layout)
|
return engine.Response200(e, p.Template, data, p.Layout)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func init() {
|
|||||||
ump := &UserEditPage{
|
ump := &UserEditPage{
|
||||||
StaticPage: pagemodels.StaticPage{
|
StaticPage: pagemodels.StaticPage{
|
||||||
Name: pagemodels.P_USER_EDIT_NAME,
|
Name: pagemodels.P_USER_EDIT_NAME,
|
||||||
Layout: "blank",
|
Layout: "blankfooter",
|
||||||
Template: TEMPLATE_USER_EDIT,
|
Template: TEMPLATE_USER_EDIT,
|
||||||
URL: URL_USER_EDIT,
|
URL: URL_USER_EDIT,
|
||||||
},
|
},
|
||||||
|
|||||||
78
pages/user_management.go
Normal file
78
pages/user_management.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package pages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/musenalm/app"
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels"
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/musenalm/middleware"
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels"
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/musenalm/templating"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
URL_USER_MANAGEMENT = "/user/management"
|
||||||
|
TEMPLATE_USER_MANAGEMENT = "/user/management/"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ump := &UserManagementPage{
|
||||||
|
StaticPage: pagemodels.StaticPage{
|
||||||
|
Name: pagemodels.P_USER_MGMT_NAME,
|
||||||
|
Layout: "blankfooter",
|
||||||
|
Template: TEMPLATE_USER_MANAGEMENT,
|
||||||
|
URL: URL_USER_MANAGEMENT,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
app.Register(ump)
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserManagementPage struct {
|
||||||
|
pagemodels.StaticPage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *UserManagementPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error {
|
||||||
|
rg := router.Group(URL_USER_MANAGEMENT)
|
||||||
|
rg.BindFunc(middleware.IsAdmin())
|
||||||
|
rg.GET("", p.GET(engine, app))
|
||||||
|
rg.POST("", p.POST(engine, app))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *UserManagementPage) GET(engine *templating.Engine, app core.App) HandleFunc {
|
||||||
|
return func(e *core.RequestEvent) error {
|
||||||
|
records := []*core.Record{}
|
||||||
|
err := app.RecordQuery(dbmodels.USERS_TABLE).OrderBy(dbmodels.USERS_NAME_FIELD).All(&records)
|
||||||
|
if err != nil {
|
||||||
|
return engine.Response500(e, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
users := make([]*dbmodels.User, 0, len(records))
|
||||||
|
for _, record := range records {
|
||||||
|
users = append(users, dbmodels.NewUser(record))
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make(map[string]any)
|
||||||
|
data["users"] = users
|
||||||
|
data["len"] = len(users)
|
||||||
|
|
||||||
|
nonce, token, err := CSRF_CACHE.GenerateTokenBundle()
|
||||||
|
if err != nil {
|
||||||
|
return engine.Response500(e, err, data)
|
||||||
|
}
|
||||||
|
data["csrf_nonce"] = nonce
|
||||||
|
data["csrf_token"] = token
|
||||||
|
|
||||||
|
SetRedirect(data, e)
|
||||||
|
|
||||||
|
return engine.Response200(e, p.Template, data, p.Layout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *UserManagementPage) POST(engine *templating.Engine, app core.App) HandleFunc {
|
||||||
|
return func(e *core.RequestEvent) error {
|
||||||
|
return fmt.Errorf("not implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ func init() {
|
|||||||
ump := &UserManagementAccessPage{
|
ump := &UserManagementAccessPage{
|
||||||
StaticPage: pagemodels.StaticPage{
|
StaticPage: pagemodels.StaticPage{
|
||||||
Name: pagemodels.P_USER_MGMT_ACCESS_NAME,
|
Name: pagemodels.P_USER_MGMT_ACCESS_NAME,
|
||||||
Layout: "blank",
|
Layout: "blankfooter",
|
||||||
Template: TEMPLATE_USER_MANAGEMENT_ACCESS,
|
Template: TEMPLATE_USER_MANAGEMENT_ACCESS,
|
||||||
URL: URL_USER_MANAGEMENT_ACCESS,
|
URL: URL_USER_MANAGEMENT_ACCESS,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,34 +1,3 @@
|
|||||||
Vorteile PocketBase
|
|
||||||
- Log-Datenbank
|
|
||||||
- User-Management
|
|
||||||
- Kurze Übernahme neuer Features
|
|
||||||
- Backup
|
|
||||||
- Email
|
|
||||||
|
|
||||||
- Hooks
|
|
||||||
|
|
||||||
|
|
||||||
Nachteile PocketBase
|
|
||||||
- Alles muss über Hooks gemacht werden
|
|
||||||
- Eigener HTTP-Server
|
|
||||||
- Eigene Cache-Implemtation
|
|
||||||
- Eigene Cookies on Auth
|
|
||||||
|
|
||||||
- Eine weitere Abhängigkeit
|
|
||||||
|
|
||||||
|
|
||||||
Für einen Umzug:
|
|
||||||
Alle PB-Abfragen die Record benutzen, nach sql-Abfragen umwandeln.
|
|
||||||
Eigene DB-Connection
|
|
||||||
Modelle umwandeln (zzt RecordProxy)
|
|
||||||
|
|
||||||
|
|
||||||
- Abfragen Personen
|
|
||||||
- Abfragen Person
|
|
||||||
- Ersellen & Abfragen FTS5-Tabellen
|
|
||||||
- Erstellen Textseiten
|
|
||||||
|
|
||||||
|
|
||||||
TODO danach:
|
TODO danach:
|
||||||
- Error Pages prüfen & error-Verhalten von HTMX
|
- Error Pages prüfen & error-Verhalten von HTMX
|
||||||
- Weißraum in den Antworten
|
- Weißraum in den Antworten
|
||||||
@@ -36,8 +5,10 @@ TODO danach:
|
|||||||
- Cache?
|
- Cache?
|
||||||
|
|
||||||
|
|
||||||
|
Ideen:
|
||||||
- Personen: related
|
- Personen: related
|
||||||
- Inhaltsliste: Personen sehen komisch aus
|
- Inhaltsliste: Personen sehen komisch aus
|
||||||
- Sammlungen neuer versuch
|
- Sammlungen neuer versuch
|
||||||
- Inhaltsliste Personen
|
|
||||||
- Sortierung nach Band A-Z?
|
- User: eigene Rolle ändern erlaubt?
|
||||||
|
- User: Session-Token CACHE wird invalidiert
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
97
views/layouts/blankfooter/root.gohtml
Normal file
97
views/layouts/blankfooter/root.gohtml
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html class="w-full h-full" {{ if .lang }}lang="{{ .lang }}"{{ end }}>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta
|
||||||
|
name="htmx-config"
|
||||||
|
content='{"defaultSwapStyle":"outerHTML", "scrollBehavior": "instant"}' />
|
||||||
|
|
||||||
|
{{ block "head" . }}
|
||||||
|
<!-- Default Head elements -->
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if .isDev }}
|
||||||
|
<link rel="icon" href="/assets/logo/dev_favicon.png" />
|
||||||
|
<meta name="robots" content="noindex" />
|
||||||
|
{{ else }}
|
||||||
|
{{ if .url }}
|
||||||
|
<link rel="canonical" href="{{ .url }}" />
|
||||||
|
{{ end }}
|
||||||
|
<link rel="icon" href="/assets/logo/favicon.png" />
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
|
<script src="/assets/js/alpine.min.js" defer></script>
|
||||||
|
<script src="/assets/js/htmx.min.js" defer></script>
|
||||||
|
<script src="/assets/js/htmx-response-targets.js" defer></script>
|
||||||
|
<script src="/assets/js/mark.min.js" defer></script>
|
||||||
|
|
||||||
|
<script type="module" src="/assets/scripts.js"></script>
|
||||||
|
<link href="/assets/css/remixicon.css" rel="stylesheet" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="/assets/css/fonts.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
document.body.addEventListener("htmx:responseError", function (event) {
|
||||||
|
const config = event.detail.requestConfig;
|
||||||
|
if (config.boosted) {
|
||||||
|
document.body.innerHTML = event.detail.xhr.responseText;
|
||||||
|
const newUrl = event.detail.xhr.responseURL || config.url;
|
||||||
|
window.history.pushState(null, "", newUrl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="w-full min-h-full" hx-ext="response-targets" hx-boost="true">
|
||||||
|
<div class="flex flex-col min-h-screen w-full">
|
||||||
|
<header class="container-normal py-0 px-0" id="header">
|
||||||
|
<div id="mainmenu" class="pb-1.5 bg-slate-100 px-8 py-6">
|
||||||
|
<div class="flex flex-row justify-between">
|
||||||
|
<div class="flex flex-row gap-x-3">
|
||||||
|
<div class="grow-0">
|
||||||
|
<a href="/" class="no-underline"
|
||||||
|
><img class="h-14 w-14 border" src="/assets/favicon.png"
|
||||||
|
/></a>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<h1 class="font-bold text-2xl tracking-wide">
|
||||||
|
<a href="/" class="no-underline text-slate-800">{{ .site.title }}</a>
|
||||||
|
</h1>
|
||||||
|
<h2 class="italic text-slate-800">{{ .site.desc }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="">
|
||||||
|
{{ block "body" . }}
|
||||||
|
<!-- Default app body... -->
|
||||||
|
{{ end }}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{{ block "_footer" . }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
|
<scroll-button></scroll-button>
|
||||||
|
|
||||||
|
{{ block "scripts" . }}
|
||||||
|
<!-- Default scripts... -->
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
const hash = window.location.hash;
|
||||||
|
if (hash) {
|
||||||
|
const stripped = hash.slice(1);
|
||||||
|
const element = document.getElementById(stripped);
|
||||||
|
if (element) {
|
||||||
|
element.setAttribute("aria-current", "location");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -17,7 +17,11 @@
|
|||||||
{{ if and .request.user (eq .request.user.Role "Admin") }}
|
{{ if and .request.user (eq .request.user.Role "Admin") }}
|
||||||
<a href="/user/management/access/User?redirectTo={{ .request.fullpath }}" class="">
|
<a href="/user/management/access/User?redirectTo={{ .request.fullpath }}" class="">
|
||||||
<i class="ri-group-3-line"></i>
|
<i class="ri-group-3-line"></i>
|
||||||
Benutzer einladen
|
Nutzer einladen
|
||||||
|
</a>
|
||||||
|
<a href="/user/management?redirectTo={{ .request.fullpath }}" class="">
|
||||||
|
<i class="ri-group-2-line"></i>
|
||||||
|
Benuzterverwaltung
|
||||||
</a>
|
</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<a href="/logout?redirectTo={{ .request.fullpath }}" class="">
|
<a href="/logout?redirectTo={{ .request.fullpath }}" class="">
|
||||||
@@ -49,8 +53,10 @@
|
|||||||
<span>·</span>
|
<span>·</span>
|
||||||
{{ if .request.user }}
|
{{ if .request.user }}
|
||||||
<button
|
<button
|
||||||
class="inline-block cursor-pointer hover:shadow-lg hover:bg-gray-100 px-1"
|
class="inline-block cursor-pointer hover:shadow-lg hover:bg-gray-100 px-1.5
|
||||||
@click="openusermenu = !openusermenu">
|
py-0.5 rounded-xs"
|
||||||
|
@click="openusermenu = !openusermenu"
|
||||||
|
x-bind:class="openusermenu ? 'bg-gray-100 shadow-lg' : ''">
|
||||||
<i class="ri-user-3-line"></i>
|
<i class="ri-user-3-line"></i>
|
||||||
{{ if .request.user.Name }}
|
{{ if .request.user.Name }}
|
||||||
<b>{{ .request.user.Name }}</b>
|
<b>{{ .request.user.Name }}</b>
|
||||||
|
|||||||
@@ -3,15 +3,21 @@
|
|||||||
|
|
||||||
<div class="flex max-w-md mx-auto !pt-44">
|
<div class="flex max-w-md mx-auto !pt-44">
|
||||||
<div class="flex-col w-full">
|
<div class="flex-col w-full">
|
||||||
|
{{- if not $model.redirect_url -}}
|
||||||
<a href="/" class="text-gray-700 hover:text-slate-950">
|
<a href="/" class="text-gray-700 hover:text-slate-950">
|
||||||
<i class="ri-arrow-left-s-line"></i> Startseite
|
<i class="ri-arrow-left-s-line"></i> Startseite
|
||||||
</a>
|
</a>
|
||||||
|
{{- else -}}
|
||||||
|
<a href="{{ $model.redirect_url }}" class="text-gray-700 hover:text-slate-950">
|
||||||
|
<i class="ri-arrow-left-s-line"></i> Zurück
|
||||||
|
</a>
|
||||||
|
{{- end -}}
|
||||||
<div class="flex justify-center mt-8 items-baseline">
|
<div class="flex justify-center mt-8 items-baseline">
|
||||||
<div>
|
<div>
|
||||||
<img class="h-20 w-20 border" src="/assets/favicon.png" />
|
<img class="h-18 w-18 border" src="/assets/favicon.png" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="text-4xl self-baseline text-center w-full my-6">Musenalm | Login</h1>
|
<h1 class="text-2xl self-baseline text-center w-full my-6 text-slate-900">Musenalm | Login</h1>
|
||||||
{{ if $model.error }}
|
{{ if $model.error }}
|
||||||
<div
|
<div
|
||||||
class="text-red-800 text-sm mt-2 rounded bg-red-200 p-2 font-bold border-red-700
|
class="text-red-800 text-sm mt-2 rounded bg-red-200 p-2 font-bold border-red-700
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{{ $model := . }}
|
{{ $model := . }}
|
||||||
|
|
||||||
|
|
||||||
<div class="flex max-w-lg mx-auto !pt-44">
|
<div class="flex container-normal bg-slate-100 mx-auto !pt-36 px-8">
|
||||||
<div class="flex-col w-full">
|
<div class="flex-col w-full">
|
||||||
{{ if $model.redirect_url }}
|
{{ if $model.redirect_url }}
|
||||||
<a href="{{ $model.redirect_url }}" class="text-gray-700 hover:text-slate-950">
|
<a href="{{ $model.redirect_url }}" class="text-gray-700 hover:text-slate-950">
|
||||||
@@ -12,7 +12,11 @@
|
|||||||
<i class="ri-arrow-left-s-line"></i> Startseite
|
<i class="ri-arrow-left-s-line"></i> Startseite
|
||||||
</a>
|
</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<h1 class="text-2xl self-baseline w-full my-6 font-bold">Benutzer bearbeiten</h1>
|
<h1 class="text-2xl self-baseline w-full my-6 font-bold text-slate-900">Profil bearbeiten</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex container-normal mx-auto px-8 mt-4">
|
||||||
|
<div class="flex-col max-w-2xl w-full">
|
||||||
{{ if $model.success }}
|
{{ if $model.success }}
|
||||||
<div
|
<div
|
||||||
class="text-green-800 text-sm mt-2 rounded bg-green-200 p-2 font-bold border-green-700
|
class="text-green-800 text-sm mt-2 rounded bg-green-200 p-2 font-bold border-green-700
|
||||||
@@ -29,8 +33,9 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
<form class="w-full grid grid-cols-3 gap-4" method="POST" x-data="{ openpw: false }">
|
<form class="w-full grid grid-cols-3 gap-4" method="POST" x-data="{ openpw: false }">
|
||||||
<div
|
<div
|
||||||
class="col-span-3 border-2 border-transparent focus-within:border-slate-600 px-2 py-1 pb-1.5
|
class="col-span-3 border-2 border-transparent px-2
|
||||||
bg-slate-200 focus-within:bg-slate-50 rounded-md transition-all duration-100">
|
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||||
|
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||||
<label for="username" class="text-sm text-gray-700 font-bold">
|
<label for="username" class="text-sm text-gray-700 font-bold">
|
||||||
Name <i class="ri-text"></i>
|
Name <i class="ri-text"></i>
|
||||||
</label>
|
</label>
|
||||||
@@ -46,8 +51,9 @@
|
|||||||
autofocus />
|
autofocus />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="col-span-3 border-2 border-transparent focus-within:border-slate-600 px-2 py-1 pb-1.5
|
class="col-span-3 border-2 border-transparent px-2
|
||||||
bg-slate-200 focus-within:bg-slate-50 rounded-md transition-all duration-100">
|
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||||
|
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||||
<label for="username" class="text-sm text-gray-700 font-bold">
|
<label for="username" class="text-sm text-gray-700 font-bold">
|
||||||
E-Mail <i class="ri-at-line"></i>
|
E-Mail <i class="ri-at-line"></i>
|
||||||
</label>
|
</label>
|
||||||
@@ -62,8 +68,9 @@
|
|||||||
value="{{ $model.user.Email }}" />
|
value="{{ $model.user.Email }}" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="col-span-3 border-2 border-transparent focus-within:border-slate-600 px-2 py-1
|
class="col-span-3 border-2 border-transparent px-2
|
||||||
pb-1.5 bg-slate-200 focus-within:bg-slate-50 rounded-md transition-all duration-100">
|
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||||
|
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||||
<label for="role" class="text-sm text-gray-700 font-bold">
|
<label for="role" class="text-sm text-gray-700 font-bold">
|
||||||
Rolle <i class="ri-user-3-line"></i>
|
Rolle <i class="ri-user-3-line"></i>
|
||||||
</label>
|
</label>
|
||||||
@@ -98,12 +105,12 @@
|
|||||||
{{- if not (eq $model.request.user.Role "Admin") -}}
|
{{- if not (eq $model.request.user.Role "Admin") -}}
|
||||||
<div
|
<div
|
||||||
x-bind:style="!openpw ? 'display:none' : ''"
|
x-bind:style="!openpw ? 'display:none' : ''"
|
||||||
class="col-span-3 border-2 border-transparent focus-within:border-slate-600 px-2 py-1 pb-1.5
|
class="col-span-3 border-2 border-transparent px-2
|
||||||
bg-slate-200 focus-within:bg-slate-50 rounded-md transition-all duration-100">
|
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||||
|
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||||
<label for="password_old" class="text-sm text-gray-700 font-bold"> Altes Passwort </label>
|
<label for="password_old" class="text-sm text-gray-700 font-bold"> Altes Passwort </label>
|
||||||
<input
|
<input
|
||||||
x-bind:type="openpw ? 'password' : 'hidden'"
|
x-bind:type="openpw ? 'password' : 'hidden'"
|
||||||
minlength="10"
|
|
||||||
name="password_old"
|
name="password_old"
|
||||||
id="password_old"
|
id="password_old"
|
||||||
class="mt-1 block w-full rounded-md focus:border-none focus:outline-none"
|
class="mt-1 block w-full rounded-md focus:border-none focus:outline-none"
|
||||||
@@ -113,8 +120,9 @@
|
|||||||
{{- end -}}
|
{{- end -}}
|
||||||
<div
|
<div
|
||||||
x-bind:style="!openpw ? 'display:none' : ''"
|
x-bind:style="!openpw ? 'display:none' : ''"
|
||||||
class="col-span-3 border-2 border-transparent focus-within:border-slate-600 px-2 py-1 pb-1.5
|
class="col-span-3 border-2 border-transparent px-2
|
||||||
bg-slate-200 focus-within:bg-slate-50 rounded-md transition-all duration-100">
|
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||||
|
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||||
<label for="password" class="text-sm text-gray-700 font-bold"> Neues Passwort </label>
|
<label for="password" class="text-sm text-gray-700 font-bold"> Neues Passwort </label>
|
||||||
<input
|
<input
|
||||||
x-bind:type="openpw ? 'password' : 'hidden'"
|
x-bind:type="openpw ? 'password' : 'hidden'"
|
||||||
@@ -127,8 +135,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
x-bind:style="!openpw ? 'display:none' : ''"
|
x-bind:style="!openpw ? 'display:none' : ''"
|
||||||
class="col-span-3 border-2 border-transparent focus-within:border-slate-600 px-2 py-1 pb-1.5
|
class="col-span-3 border-2 border-transparent px-2
|
||||||
bg-slate-200 focus-within:bg-slate-50 rounded-md transition-all duration-100">
|
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
|
||||||
|
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
|
||||||
<label for="password_repeat" class="text-sm text-gray-700 font-bold">
|
<label for="password_repeat" class="text-sm text-gray-700 font-bold">
|
||||||
Passwort wiederholen
|
Passwort wiederholen
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -52,28 +52,46 @@
|
|||||||
|
|
||||||
genQRCode();
|
genQRCode();
|
||||||
if (tokenElement) {
|
if (tokenElement) {
|
||||||
tokenElement.addEventListener('focus', () => tokenElement.select());
|
tokenElement.addEventListener('focus', (ev) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
tokenElement.select();
|
||||||
|
});
|
||||||
|
tokenElement.addEventListener('mousedown', (ev) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
tokenElement.select();
|
||||||
|
});
|
||||||
|
tokenElement.addEventListener('mouseup', (ev) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
tokenElement.select();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex max-w-md mx-auto !pt-44 user-invites">
|
<div class="flex container-normal bg-slate-100 mx-auto !pt-36 px-8">
|
||||||
<div class="flex-col w-full">
|
<div class="flex-col w-full">
|
||||||
{{- if not $model.redirect_url -}}
|
{{ if $model.redirect_url }}
|
||||||
<a href="/" class="text-gray-700 hover:text-slate-950 mb-9 block">
|
<a href="{{ $model.redirect_url }}" class="text-gray-700 hover:text-slate-950">
|
||||||
<i class="ri-arrow-left-s-line"></i> Startseite
|
|
||||||
</a>
|
|
||||||
{{- else -}}
|
|
||||||
<a href="{{ $model.redirect_url }}" class="text-gray-700 hover:text-slate-950 mb-9 block">
|
|
||||||
<i class="ri-arrow-left-s-line"></i> Zurück
|
<i class="ri-arrow-left-s-line"></i> Zurück
|
||||||
</a>
|
</a>
|
||||||
{{- end -}}
|
{{ else }}
|
||||||
<!--
|
<a href="/" class="text-gray-700 hover:text-slate-950">
|
||||||
<div class="mb-6">
|
<i class="ri-arrow-left-s-line"></i> Startseite
|
||||||
<h1 class="text-2xl font-bold text-slate-900 text-center">Benutzer einladen</h1>
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
<h1 class="text-2xl self-baseline w-full mt-6 mb-2 font-bold text-slate-900">
|
||||||
|
Nutzer einladen
|
||||||
|
</h1>
|
||||||
|
<div class="text-sm text-slate-600 !hyphens-auto mb-6 max-w-[60ch]">
|
||||||
|
<i class="ri-question-line"></i>
|
||||||
|
Mit diesem Link können neue Accounts des jeweiligen Typs registriert werden. Geben Sie den
|
||||||
|
Link an Personen weiter, die Sie einladen möchten.
|
||||||
</div>
|
</div>
|
||||||
-->
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="user-invites flex container-normal mx-auto px-8 mt-4">
|
||||||
|
<div class="flex-col max-w-xl w-full">
|
||||||
<div
|
<div
|
||||||
class="col-span-9 grid grid-cols-3 justify-between mb-4 py-1 px-1 border rounded-md gap-x-2
|
class="col-span-9 grid grid-cols-3 justify-between mb-4 py-1 px-1 border rounded-xs gap-x-2
|
||||||
bg-slate-200 user-chooser">
|
bg-slate-200 user-chooser">
|
||||||
<a
|
<a
|
||||||
href="/user/management/access/User?redirectTo={{ $model.redirect_url }}"
|
href="/user/management/access/User?redirectTo={{ $model.redirect_url }}"
|
||||||
@@ -101,21 +119,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
<div class="col-span-7 col-start-2 mb-4 p-4 border rounded-lg shadow hidden" id="qr"></div>
|
<div class="col-span-7 col-start-2 mb-4 p-4 border rounded-xs hidden" id="qr"></div>
|
||||||
<div class="col-span-9 mb-6 flex flex-col">
|
<div class="col-span-9 mb-6 flex flex-col">
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="token"
|
name="token"
|
||||||
id="token"
|
id="token"
|
||||||
class="w-full text-center border border-slate-300 rounded-md shadow-sm
|
class="w-full text-center border border-slate-300 rounded-xs
|
||||||
focus:border-slate-500 focus:ring-slate-500 p-1 px-2 overflow-ellipsis"
|
focus:border-slate-500 focus:ring-slate-500 p-1 px-2 overflow-ellipsis"
|
||||||
value="{{ $model.access_url }}"
|
value="{{ $model.access_url }}"
|
||||||
deactive
|
deactive
|
||||||
readonly />
|
readonly />
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="ml-2 inline-flex justify-center py-2 px-3 border border-transparent rounded-md
|
class="ml-2 inline-flex justify-center py-2 px-3 border border-transparent
|
||||||
|
rounded-xs
|
||||||
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer
|
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer
|
||||||
focus:outline-none no-underline
|
focus:outline-none no-underline
|
||||||
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500"
|
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500"
|
||||||
@@ -125,53 +144,14 @@
|
|||||||
<a
|
<a
|
||||||
href="{{ $model.relative_url }}"
|
href="{{ $model.relative_url }}"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="ml-2 inline-flex justify-center py-2 px-3 border border-transparent rounded-md
|
class="ml-2 inline-flex justify-center py-2 px-3 border border-transparent
|
||||||
|
rounded-xs
|
||||||
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer
|
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer
|
||||||
focus:outline-none no-underline
|
focus:outline-none no-underline
|
||||||
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
|
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
|
||||||
<i class="ri-external-link-line"></i>
|
<i class="ri-external-link-line"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
<form class="" method="POST">
|
||||||
<div class="col-span-9 text-center text-slate-400 mb-1 mt-3">
|
|
||||||
Gültig bis zum
|
|
||||||
{{ $model.validUntil }}
|
|
||||||
</div>
|
|
||||||
<div class="mt-2 text-sm text-slate-600 flex flex-row gap-x-2">
|
|
||||||
<div>
|
|
||||||
<i class="ri-information-line"></i>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
Unter diesem Link können neue Accounts registriert werden. Geben Sie diesen Link an neue
|
|
||||||
Nutzer der Datenbank weiter.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ if eq $model.role "User" }}
|
|
||||||
<div class="mt-1 text-sm text-blue-600 flex flex-row gap-x-2">
|
|
||||||
<div>
|
|
||||||
<i class="ri-information-line"></i>
|
|
||||||
</div>
|
|
||||||
<div>Benutzer können private Felder und Daten einsehen, aber nicht bearbeiten.</div>
|
|
||||||
</div>
|
|
||||||
{{ else if eq $model.role "Admin" }}
|
|
||||||
<div class="mt-1 text-sm text-red-600 flex flex-row gap-x-2">
|
|
||||||
<div>
|
|
||||||
<i class="ri-information-line"></i>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
Administratoren können alle Felder und Daten einsehen und bearbeiten. Administratoren
|
|
||||||
können Nutzer einladen und löschen.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ else if eq $model.role "Editor" }}
|
|
||||||
<div class="mt-1 text-sm text-orange-600 flex flex-row gap-x-2">
|
|
||||||
<div>
|
|
||||||
<i class="ri-information-line"></i>
|
|
||||||
</div>
|
|
||||||
<div>Redakteure können alle Felder und Daten der Datenbank einsehen und bearbeiten.</div>
|
|
||||||
</div>
|
|
||||||
{{- end -}}
|
|
||||||
</div>
|
|
||||||
<form class="w-full grid grid-cols-9 gap-4" method="POST">
|
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
name="csrf_nonce"
|
name="csrf_nonce"
|
||||||
@@ -188,20 +168,51 @@
|
|||||||
<div class="col-span-9 flex flex-row items-center justify-center">
|
<div class="col-span-9 flex flex-row items-center justify-center">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="inline-flex justify-center py-2 px-3 border border-transparent rounded-full
|
class="ml-2 inline-flex justify-center py-2 px-3 border border-transparent
|
||||||
|
rounded-xs
|
||||||
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer
|
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer
|
||||||
focus:outline-none no-underline
|
focus:outline-none no-underline
|
||||||
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
|
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
|
||||||
<i class="ri-loop-left-line"></i>
|
<i class="ri-loop-left-line"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<!--
|
|
||||||
<div class="col-span-3">
|
|
||||||
<a href="/forgot-password" class="text-sm text-slate-600 hover:text-slate-900">
|
|
||||||
Passwort vergessen?
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-span-9 text-right text-slate-400 mb-1 mt-3">
|
||||||
|
Gültig bis
|
||||||
|
{{ $model.validUntil }}
|
||||||
|
</div>
|
||||||
|
{{ if eq $model.role "User" }}
|
||||||
|
<div class="max-w-[60ch] mt-1 text-sm text-blue-600 flex flex-row gap-x-2 hyphens-auto">
|
||||||
|
<div>
|
||||||
|
<i class="ri-error-warning-line"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Benutzer können private Felder und Datensätze einsehen, aber nicht bearbeiten oder
|
||||||
|
löschen.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ else if eq $model.role "Admin" }}
|
||||||
|
<div class="max-w-[60ch] mt-1 text-sm text-red-600 flex flex-row gap-x-2 hyphens-auto">
|
||||||
|
<div>
|
||||||
|
<i class="ri-error-warning-line"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Administratoren können alle Felder und Datensätze einsehen, bearbeiten und löschen.
|
||||||
|
Administratoren können Passwörter setzen, Nutzer einladen und deaktivieren.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ else if eq $model.role "Editor" }}
|
||||||
|
<div class="max-w-[60ch] mt-1 text-sm text-orange-600 flex flex-row gap-x-2 hyphens-auto">
|
||||||
|
<div>
|
||||||
|
<i class="ri-error-warning-line"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Redakteure können alle Felder und Datensätze der Datenbank einsehen, bearbeiten und
|
||||||
|
löschen.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
{{ $model := . }}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex container-normal bg-slate-100 mx-auto !pt-36 px-8">
|
||||||
|
<div class="flex-col w-full">
|
||||||
|
{{ if $model.redirect_url }}
|
||||||
|
<a href="{{ $model.redirect_url }}" class="text-gray-700 hover:text-slate-950">
|
||||||
|
<i class="ri-arrow-left-s-line"></i> Zurück
|
||||||
|
</a>
|
||||||
|
{{ else }}
|
||||||
|
<a href="/" class="text-gray-700 hover:text-slate-950">
|
||||||
|
<i class="ri-arrow-left-s-line"></i> Startseite
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
<h1
|
||||||
|
class="text-2xl self-baseline w-full my-6 font-bold
|
||||||
|
text-slate-900">
|
||||||
|
Benutzerverwaltung
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex container-normal mx-auto px-8 mt-4">
|
||||||
|
<div class="flex-col max-w-2xl w-full">
|
||||||
|
{{ if $model.success }}
|
||||||
|
<div
|
||||||
|
class="text-green-800 text-sm mt-2 rounded bg-green-200 p-2 font-bold border-green-700
|
||||||
|
border-2 mb-3">
|
||||||
|
{{ $model.success }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
{{ if $model.error }}
|
||||||
|
<div
|
||||||
|
class="text-red-800 text-sm mt-2 rounded bg-red-200 p-2 font-bold border-red-700
|
||||||
|
border-2 mb-3">
|
||||||
|
{{ $model.error }}
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>E-Mail</th>
|
||||||
|
<th>Rolle</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{ range $u := $model.users }}
|
||||||
|
<tr>
|
||||||
|
<td>{{ $u.Name }}</td>
|
||||||
|
<td>{{ $u.Email }}</td>
|
||||||
|
<td>{{ $u.Role }}</td>
|
||||||
|
<td>
|
||||||
|
<a
|
||||||
|
href="/user/{{ $u.Id }}/edit?redirectTo={{ $model.request.fullpath }}"
|
||||||
|
class="text-blue-500 hover:text-blue-700">
|
||||||
|
<i class="ri-edit-line"></i> Bearbeiten
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -3,17 +3,22 @@
|
|||||||
|
|
||||||
<div class="flex max-w-md mx-auto !pt-44">
|
<div class="flex max-w-md mx-auto !pt-44">
|
||||||
<div class="flex-col w-full">
|
<div class="flex-col w-full">
|
||||||
|
{{- if $model.redirect_url -}}
|
||||||
|
<a href="{{ $model.redirect_url }}" class="text-gray-700 hover:text-slate-950">
|
||||||
|
<i class="ri-arrow-left-s-line"></i> Zurück
|
||||||
|
</a>
|
||||||
|
{{- else -}}
|
||||||
<a href="/" class="text-gray-700 hover:text-slate-950">
|
<a href="/" class="text-gray-700 hover:text-slate-950">
|
||||||
<i class="ri-arrow-left-s-line"></i> Startseite
|
<i class="ri-arrow-left-s-line"></i> Startseite
|
||||||
</a>
|
</a>
|
||||||
|
{{- end -}}
|
||||||
<div class="flex justify-center mt-8 items-baseline">
|
<div class="flex justify-center mt-8 items-baseline">
|
||||||
<div>
|
<div>
|
||||||
<img class="h-20 w-20 border" src="/assets/favicon.png" />
|
<img class="h-18 w-18 border" src="/assets/favicon.png" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="text-4xl self-baseline text-center w-full my-6">
|
<h1 class="text-2xl self-baseline text-center w-full my-6 text-slate-900">
|
||||||
Musenalm<br class="mb-3" />
|
Musenalm | Neuer
|
||||||
Neuer
|
|
||||||
{{ if eq $model.role "User" -}}
|
{{ if eq $model.role "User" -}}
|
||||||
Nutzer
|
Nutzer
|
||||||
{{ else if eq $model.role "Admin" -}}
|
{{ else if eq $model.role "Admin" -}}
|
||||||
|
|||||||
@@ -513,7 +513,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.user-invites .user-chooser a {
|
.user-invites .user-chooser a {
|
||||||
@apply py-1 rounded no-underline;
|
@apply py-1 rounded-xs no-underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-invites .user-chooser a[aria-current="page"] {
|
.user-invites .user-chooser a[aria-current="page"] {
|
||||||
|
|||||||
Reference in New Issue
Block a user