mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2025-10-29 01:05:32 +00:00
Registration form for new users
This commit is contained in:
1
views/assets/js/qrcode.min.js
vendored
Normal file
1
views/assets/js/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,5 +1,31 @@
|
||||
{{- $date := Today -}}
|
||||
<footer class="container-normal pb-1.5 text-base text-gray-800">
|
||||
<footer
|
||||
class="container-normal pb-1.5 text-base text-gray-800 relative"
|
||||
x-data="{ openusermenu: false }">
|
||||
<div class="" x-show="openusermenu">
|
||||
<div
|
||||
class="absolute right-0 bottom-10 bg-white border border-gray-300 rounded-md shadow mt-2
|
||||
[&>a]:no-underline [&>a]:text-gray-700 [&>a]:hover:bg-gray-100 [&>a]:hover:text-gray-900
|
||||
[&>a]:block [&>a]:px-3 [&>a]:py-2 [&>a]:text-sm [&>a]:rounded-md [&>a]:w-full [&>a]:text-left
|
||||
[&>a]:whitespace-nowrap [&>a]:transition-all [&>a]:duration-200 [&>a]:border-b
|
||||
[&>a]:last:border-b-0">
|
||||
<a href="/user/edit" class="">
|
||||
<i class="ri-user-3-line"></i>
|
||||
Profil bearbeiten
|
||||
</a>
|
||||
{{ if and .request.user (eq .request.user.Role "Admin") }}
|
||||
<a href="/user/management/access/User?redirectTo={{ .request.fullpath }}" class="">
|
||||
<i class="ri-group-3-line"></i>
|
||||
Benutzer einladen
|
||||
</a>
|
||||
{{ end }}
|
||||
<a href="/logout?redirectTo={{ .request.fullpath }}" class="">
|
||||
<i class="ri-logout-box-line"></i>
|
||||
Ausloggen
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-12 pt-3 flex flex-row justify-between">
|
||||
<div>
|
||||
<i class="ri-creative-commons-line"></i>
|
||||
@@ -19,15 +45,20 @@
|
||||
<a href="https://github.com/Theodor-Springmann-Stiftung/musenalm">Code</a>
|
||||
<span>·</span>
|
||||
{{ if .request.user }}
|
||||
<i class="ri-user-3-line"></i>
|
||||
{{ if .request.user.Name }}
|
||||
<b>{{ .request.user.Name }}</b>
|
||||
{{ else }}
|
||||
<b>{{ .request.user.Email }}</b>
|
||||
{{ end }}
|
||||
<button class="inline-block cursor-pointer" @click="openusermenu = !openusermenu">
|
||||
<i class="ri-user-3-line"></i>
|
||||
{{ if .request.user.Name }}
|
||||
<b>{{ .request.user.Name }}</b>
|
||||
{{ else }}
|
||||
<b>{{ .request.user.Email }}</b>
|
||||
{{ end }}
|
||||
<i class="ri-arrow-up-s-fill"></i>
|
||||
</button>
|
||||
<!--
|
||||
|
|
||||
<i class="ri-logout-box-line"></i>
|
||||
<a href="/logout?redirectTo={{ .request.fullpath }}">Logout</a>
|
||||
-->
|
||||
{{ else }}
|
||||
<i class="ri-login-box-line"></i>
|
||||
<a href="/login?redirectTo={{ .request.fullpath }}">Login</a>
|
||||
|
||||
1
views/public/js/qrcode.min.js
vendored
Normal file
1
views/public/js/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
0
views/routes/user/edit/body.gohtml
Normal file
0
views/routes/user/edit/body.gohtml
Normal file
0
views/routes/user/edit/head.hohtml
Normal file
0
views/routes/user/edit/head.hohtml
Normal file
207
views/routes/user/management/access/body.gohtml
Normal file
207
views/routes/user/management/access/body.gohtml
Normal file
@@ -0,0 +1,207 @@
|
||||
{{ $model := . }}
|
||||
|
||||
|
||||
<script src="/assets/js/qrcode.min.js"></script>
|
||||
|
||||
<script type="module">
|
||||
const qrElement = document.getElementById('qr');
|
||||
const tokenElement = document.getElementById('token');
|
||||
const accessUrl = "{{ $model.access_url }}";
|
||||
|
||||
/**
|
||||
* @param {number} timeout - Maximum time to wait in milliseconds.
|
||||
* @param {number} interval - How often to check in milliseconds.
|
||||
* @returns {Promise<Function>} Resolves with the QRCode constructor when available.
|
||||
*/
|
||||
function getQRCodeWhenAvailable(timeout = 5000, interval = 100) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let elapsedTime = 0;
|
||||
const checkInterval = setInterval(() => {
|
||||
if (typeof window.QRCode === 'function') {
|
||||
clearInterval(checkInterval);
|
||||
resolve(window.QRCode); // Resolve with the QRCode object/function
|
||||
} else {
|
||||
elapsedTime += interval;
|
||||
if (elapsedTime >= timeout) {
|
||||
clearInterval(checkInterval);
|
||||
console.error('Timed out waiting for QRCode to become available.');
|
||||
reject(new Error('QRCode not available after ' + timeout + 'ms. Check if qrcode.min.js is loaded correctly and sets window.QRCode.'));
|
||||
}
|
||||
}
|
||||
}, interval);
|
||||
});
|
||||
}
|
||||
|
||||
// INFO: We have to wait for the QRCode object to be available. It's messy.
|
||||
async function genQRCode() {
|
||||
const QRCode = await getQRCodeWhenAvailable();
|
||||
if (qrElement && accessUrl && qrElement.innerHTML.trim() === '') {
|
||||
new QRCode(qrElement, {
|
||||
text: accessUrl,
|
||||
width: 1280,
|
||||
height: 1280,
|
||||
colorDark: "#000000",
|
||||
colorLight: "#ffffff",
|
||||
correctLevel: QRCode.CorrectLevel.H
|
||||
});
|
||||
setTimeout(() => {
|
||||
qrElement.classList.remove('hidden');
|
||||
}, 20);
|
||||
}
|
||||
}
|
||||
|
||||
genQRCode();
|
||||
if (tokenElement) {
|
||||
tokenElement.addEventListener('focus', () => tokenElement.select());
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex max-w-md mx-auto !pt-44 user-invites">
|
||||
<div class="flex-col w-full">
|
||||
{{- if not $model.redirect_url -}}
|
||||
<a href="/" class="text-gray-700 hover:text-slate-950 mb-9 block">
|
||||
<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
|
||||
</a>
|
||||
{{- end -}}
|
||||
<!--
|
||||
<div class="mb-6">
|
||||
<h1 class="text-2xl font-bold text-slate-900 text-center">Benutzer einladen</h1>
|
||||
</div>
|
||||
-->
|
||||
<div
|
||||
class="col-span-9 grid grid-cols-3 justify-between mb-4 py-1 px-1 border rounded-md gap-x-2
|
||||
bg-slate-200 user-chooser">
|
||||
<a
|
||||
href="/user/management/access/User?redirectTo={{ $model.redirect_url }}"
|
||||
class="text-center px-4 text-gray-700 hover:text-slate-950 block"
|
||||
{{ if eq $model.role "User" }}aria-current="page"{{ end }}>
|
||||
Benutzer
|
||||
</a>
|
||||
<a
|
||||
href="/user/management/access/Editor?redirectTo={{ $model.redirect_url }}"
|
||||
class="text-gray-700 hover:text-slate-950 block px-4 text-center"
|
||||
{{ if eq $model.role "Editor" }}aria-current="page"{{ end }}>
|
||||
Redakteur
|
||||
</a>
|
||||
<a
|
||||
href="/user/management/access/Admin?redirectTo={{ $model.redirect_url }}"
|
||||
class="text-gray-700 hover:text-slate-950 text-center px-4 block"
|
||||
{{ if eq $model.role "Admin" }}aria-current="page"{{ end }}>
|
||||
Admin
|
||||
</a>
|
||||
</div>
|
||||
<!--
|
||||
<div class="flex justify-center mt-8 items-baseline">
|
||||
<div>
|
||||
<img class="h-20 w-20 border" src="/assets/favicon.png" />
|
||||
</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-9 mb-6 flex flex-col">
|
||||
<div class="flex flex-row">
|
||||
<input
|
||||
type="text"
|
||||
name="token"
|
||||
id="token"
|
||||
class="w-full text-center border border-slate-300 rounded-md shadow-sm
|
||||
focus:border-slate-500 focus:ring-slate-500 p-1 px-2 overflow-ellipsis"
|
||||
value="{{ $model.access_url }}"
|
||||
deactive
|
||||
readonly />
|
||||
<button
|
||||
type="button"
|
||||
class="ml-2 inline-flex justify-center py-2 px-3 border border-transparent rounded-md
|
||||
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer
|
||||
focus:outline-none no-underline
|
||||
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500"
|
||||
onclick="navigator.clipboard.writeText('{{ $model.access_url }}')">
|
||||
<i class="ri-file-copy-line"></i>
|
||||
</button>
|
||||
<a
|
||||
href="{{ $model.relative_url }}"
|
||||
target="_blank"
|
||||
class="ml-2 inline-flex justify-center py-2 px-3 border border-transparent rounded-md
|
||||
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer
|
||||
focus:outline-none no-underline
|
||||
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
|
||||
<i class="ri-external-link-line"></i>
|
||||
</a>
|
||||
</div>
|
||||
<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
|
||||
type="hidden"
|
||||
name="csrf_nonce"
|
||||
id="csrf_nonce"
|
||||
required
|
||||
value="{{ $model.csrf_nonce }}" />
|
||||
<input
|
||||
type="hidden"
|
||||
name="csrf_token"
|
||||
id="csrf_token"
|
||||
required
|
||||
value="{{ $model.csrf_token }}" />
|
||||
|
||||
<div class="col-span-9 flex flex-row items-center justify-center">
|
||||
<button
|
||||
type="submit"
|
||||
class="inline-flex justify-center py-2 px-3 border border-transparent rounded-full
|
||||
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer
|
||||
focus:outline-none no-underline
|
||||
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
|
||||
<i class="ri-loop-left-line"></i>
|
||||
</button>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
0
views/routes/user/management/access/head.gohtml
Normal file
0
views/routes/user/management/access/head.gohtml
Normal file
0
views/routes/user/management/body.gohtml
Normal file
0
views/routes/user/management/body.gohtml
Normal file
0
views/routes/user/management/head.gohtml
Normal file
0
views/routes/user/management/head.gohtml
Normal file
143
views/routes/user/new/body.gohtml
Normal file
143
views/routes/user/new/body.gohtml
Normal file
@@ -0,0 +1,143 @@
|
||||
{{ $model := . }}
|
||||
|
||||
|
||||
<div class="flex max-w-md mx-auto !pt-44">
|
||||
<div class="flex-col w-full">
|
||||
<a href="/" class="text-gray-700 hover:text-slate-950">
|
||||
<i class="ri-arrow-left-s-line"></i> Startseite
|
||||
</a>
|
||||
<div class="flex justify-center mt-8 items-baseline">
|
||||
<div>
|
||||
<img class="h-20 w-20 border" src="/assets/favicon.png" />
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="text-4xl self-baseline text-center w-full my-6">
|
||||
Musenalm<br class="mb-3" />
|
||||
Neuer
|
||||
{{ if eq $model.role "User" -}}
|
||||
Nutzer
|
||||
{{ else if eq $model.role "Admin" -}}
|
||||
Administrator
|
||||
{{ else -}}
|
||||
Redakteur
|
||||
{{- end -}}
|
||||
</h1>
|
||||
{{ 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 }}
|
||||
{{ if not $model.user }}
|
||||
<form class="w-full grid grid-cols-3 gap-4" method="POST">
|
||||
<div
|
||||
class="col-span-3 border-2 border-transparent focus-within:border-slate-600 px-2 py-1 pb-1.5
|
||||
bg-slate-200 focus-within:bg-slate-50 rounded-md transition-all duration-100">
|
||||
<label for="username" class="text-sm text-gray-700 font-bold">
|
||||
Name <i class="ri-text"></i>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
class="mt-1 block w-full rounded-md focus:border-none focus:outline-none"
|
||||
placeholder=""
|
||||
required
|
||||
autocomplete="name"
|
||||
value=""
|
||||
autofocus />
|
||||
</div>
|
||||
<div
|
||||
class="col-span-3 border-2 border-transparent focus-within:border-slate-600 px-2 py-1 pb-1.5
|
||||
bg-slate-200 focus-within:bg-slate-50 rounded-md transition-all duration-100">
|
||||
<label for="username" class="text-sm text-gray-700 font-bold">
|
||||
E-Mail <i class="ri-at-line"></i>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name="username"
|
||||
id="username"
|
||||
class="mt-1 block w-full rounded-md focus:border-none focus:outline-none"
|
||||
placeholder=""
|
||||
required
|
||||
value=""
|
||||
autofocus />
|
||||
</div>
|
||||
<div
|
||||
class="col-span-3 border-2 border-transparent focus-within:border-slate-600 px-2 py-1 pb-1.5
|
||||
bg-slate-200 focus-within:bg-slate-50 rounded-md transition-all duration-100">
|
||||
<label for="password" class="text-sm text-gray-700 font-bold">
|
||||
Passwort <i class="ri-key-2-line"></i>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
minlength="10"
|
||||
name="password"
|
||||
id="password"
|
||||
class="mt-1 block w-full rounded-md focus:border-none focus:outline-none"
|
||||
placeholder=""
|
||||
required />
|
||||
</div>
|
||||
<div
|
||||
class="col-span-3 border-2 border-transparent focus-within:border-slate-600 px-2 py-1 pb-1.5
|
||||
bg-slate-200 focus-within:bg-slate-50 rounded-md transition-all duration-100">
|
||||
<label for="password" class="text-sm text-gray-700 font-bold">
|
||||
Passwort wiederholen <i class="ri-key-2-line"></i>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
minlength="10"
|
||||
name="password_repeat"
|
||||
id="password_repeat"
|
||||
class="mt-1 block w-full rounded-md focus:border-none focus:outline-none"
|
||||
placeholder=""
|
||||
required />
|
||||
</div>
|
||||
<div class="col-span-3">
|
||||
<input
|
||||
type="hidden"
|
||||
name="csrf_nonce"
|
||||
id="csrf_nonce"
|
||||
required
|
||||
value="{{ $model.csrf_nonce }}" />
|
||||
<input
|
||||
type="hidden"
|
||||
name="csrf_token"
|
||||
id="csrf_token"
|
||||
required
|
||||
value="{{ $model.csrf_token }}" />
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full inline-flex justify-center py-2 px-4 border border-transparent rounded-md
|
||||
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer focus:outline-none
|
||||
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
|
||||
Registrieren
|
||||
</button>
|
||||
</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>
|
||||
{{- else -}}
|
||||
<div
|
||||
class="text-green-800 text-sm mt-2 rounded bg-green-200 p-2 font-bold border-green-700
|
||||
border-2 mb-3">
|
||||
Benutzer {{ $model.user.Name }} erfolgreich angelegt.
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href="/login"
|
||||
class="w-full inline-flex justify-center py-2 px-4 border border-transparent rounded-md
|
||||
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer focus:outline-none
|
||||
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
|
||||
Login
|
||||
</a>
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</div>
|
||||
0
views/routes/user/new/head.gohtml
Normal file
0
views/routes/user/new/head.gohtml
Normal file
@@ -512,6 +512,14 @@
|
||||
@apply !text-slate-900 bg-stone-50;
|
||||
}
|
||||
|
||||
.user-invites .user-chooser a {
|
||||
@apply py-1 rounded no-underline;
|
||||
}
|
||||
|
||||
.user-invites .user-chooser a[aria-current="page"] {
|
||||
@apply font-bold !bg-stone-50 relative border-b z-20 shadow;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
|
||||
Reference in New Issue
Block a user