Compare commits
4 Commits
main
...
devel/chri
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a77602574 | |||
| 2be92ca3e5 | |||
| 40741e4477 | |||
| 0e20ab95a7 |
@ -1 +0,0 @@
|
|||||||
de
|
|
||||||
16
PO/POTFILES
@ -1,16 +0,0 @@
|
|||||||
../src/Constants/const.php
|
|
||||||
../src/Controller/MainController.php
|
|
||||||
../src/Controller/SecurityController.php
|
|
||||||
../src/Controller/SetupController.php
|
|
||||||
../src/Controller/WebrootController.php
|
|
||||||
../src/Controller/WebrootSetupController.php
|
|
||||||
../src/Entity/WebrootFile.php
|
|
||||||
../src/Entity/WebrootFilePermission.php
|
|
||||||
../src/Entity/WebrootRole.php
|
|
||||||
../src/Entity/WebrootUser.php
|
|
||||||
../src/Kernel.php
|
|
||||||
../src/Repository/WebrootFilePermissionRepository.php
|
|
||||||
../src/Repository/WebrootFileRepository.php
|
|
||||||
../src/Repository/WebrootRoleRepository.php
|
|
||||||
../src/Repository/WebrootUserRepository.php
|
|
||||||
../src/Utility/i18n.php
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
../src/MyDevel/Webroot/Controller/WebrootController.php
|
|
||||||
../src/MyDevel/Webroot/Controller/WebrootSetupController.php
|
|
||||||
../src/MyDevel/Webroot/Entity/WebrootFile.php
|
|
||||||
../src/MyDevel/Webroot/Entity/WebrootFilePermission.php
|
|
||||||
../src/MyDevel/Webroot/Entity/WebrootRole.php
|
|
||||||
../src/MyDevel/Webroot/Entity/WebrootUser.php
|
|
||||||
../src/MyDevel/Webroot/Repository/WebrootFilePermissionRepository.php
|
|
||||||
../src/MyDevel/Webroot/Repository/WebrootFileRepository.php
|
|
||||||
../src/MyDevel/Webroot/Repository/WebrootRoleRepository.php
|
|
||||||
../src/MyDevel/Webroot/Repository/WebrootUserRepository.php
|
|
||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
SELF="$(realpath "$0")"
|
|
||||||
PO_DIR="$(dirname "$SELF")"
|
|
||||||
PROJECT_ROOT="$(dirname "$PO_DIR")"
|
|
||||||
|
|
||||||
cd "$PO_DIR"
|
|
||||||
|
|
||||||
for i in `cat LINGUAS`; do
|
|
||||||
msgdir="$PROJECT_ROOT/translations/$i/LC_MESSAGES";
|
|
||||||
if [ ! -d "$msgdir" ]; then
|
|
||||||
mkdir -p "$msgdir"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f $i.po ]; then
|
|
||||||
msgfmt -o "$msgdir/mydevel-webroot.mo" $i.po
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
151
PO/de.po
@ -1,151 +0,0 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
||||||
#
|
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: \n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2024-11-27 19:03+0100\n"
|
|
||||||
"PO-Revision-Date: 2024-11-27 19:12+0100\n"
|
|
||||||
"Last-Translator: Christian Moser <christian@cmoser.eu>\n"
|
|
||||||
"Language-Team: \n"
|
|
||||||
"Language: de\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"X-Generator: Poedit 3.5\n"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:45
|
|
||||||
msgid "Email Settings"
|
|
||||||
msgstr "Email Einstellungen"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:46
|
|
||||||
msgid "Site Settings"
|
|
||||||
msgstr "Site Einstellungen"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:47
|
|
||||||
msgid "Database Settings"
|
|
||||||
msgstr "Datenbank Einstellungen"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:48
|
|
||||||
msgid "User Settings"
|
|
||||||
msgstr "Nutzer Einstellungen"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:56
|
|
||||||
msgid "Enter the site name that should be displayed in titles."
|
|
||||||
msgstr "Gib den Setiennamen and, der in Titeln angezeigt werden soll."
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:57
|
|
||||||
msgid "Site name"
|
|
||||||
msgstr "Name der Site"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:61
|
|
||||||
msgid "Site root directory"
|
|
||||||
msgstr "Wurzelverzeichnis"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:65
|
|
||||||
msgid "Contact email"
|
|
||||||
msgstr "Kontakt Email"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:69
|
|
||||||
msgid "Username"
|
|
||||||
msgstr "Nutzername"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:73
|
|
||||||
msgid "Email"
|
|
||||||
msgstr "Email"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:77
|
|
||||||
#: ../src/Controller/SetupController.php:117
|
|
||||||
#: ../src/Controller/SetupController.php:144
|
|
||||||
msgid "Password"
|
|
||||||
msgstr "Passwort"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:81
|
|
||||||
msgid "Confirm Password"
|
|
||||||
msgstr "Passwort bestätigen"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:84
|
|
||||||
msgid "Run Migrations?"
|
|
||||||
msgstr "Migrationen anwenden?"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:93
|
|
||||||
msgid "SQLite3"
|
|
||||||
msgstr "SQLite3"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:94
|
|
||||||
msgid "MySQL/MariaDB"
|
|
||||||
msgstr "MySQL/MariaDB"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:95
|
|
||||||
msgid "PostgreSQL"
|
|
||||||
msgstr "PostgreSQL"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:96
|
|
||||||
#: ../src/Controller/SetupController.php:120
|
|
||||||
msgid "Database URL"
|
|
||||||
msgstr "Datenbank URL"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:101
|
|
||||||
msgid "Database"
|
|
||||||
msgstr "Datenbank"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:105
|
|
||||||
msgid "Host"
|
|
||||||
msgstr "Host"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:109
|
|
||||||
msgid "Port"
|
|
||||||
msgstr "Port"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:113
|
|
||||||
#: ../src/Controller/SetupController.php:140
|
|
||||||
msgid "User"
|
|
||||||
msgstr "Nutzer"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:124
|
|
||||||
msgid "Backend"
|
|
||||||
msgstr "Backend"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:127
|
|
||||||
msgid "No email support"
|
|
||||||
msgstr "Keine Emailunterstützung"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:128
|
|
||||||
msgid "SMTP"
|
|
||||||
msgstr "SMTP"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:129
|
|
||||||
msgid "Sendmail"
|
|
||||||
msgstr "Sendmail"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:130
|
|
||||||
msgid "Naitve"
|
|
||||||
msgstr "Nativ"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:131
|
|
||||||
msgid "User DSN"
|
|
||||||
msgstr "Nutzer DSN"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:136
|
|
||||||
msgid "Email Path"
|
|
||||||
msgstr "Email-Pfad"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:148
|
|
||||||
msgid "SMTP Host"
|
|
||||||
msgstr "SMTP Host"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:152
|
|
||||||
msgid "SMTP Port"
|
|
||||||
msgstr "SMTP Port"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:156
|
|
||||||
msgid "DSN"
|
|
||||||
msgstr "DSN"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:160
|
|
||||||
msgid "Sender address"
|
|
||||||
msgstr "Adresse des Senders"
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
SELF="$(realpath "$0")"
|
|
||||||
PODIR="$(dirname "$SELF")"
|
|
||||||
PROJECT_ROOT="$(dirname "$PODIR")"
|
|
||||||
|
|
||||||
cd "$PODIR"
|
|
||||||
|
|
||||||
echo "Creating POTFILES"
|
|
||||||
rm -v POTFILES
|
|
||||||
|
|
||||||
for i in $(find ../src | grep '\.*php$'); do
|
|
||||||
echo $i >> POTFILES
|
|
||||||
done
|
|
||||||
if [ -f messages.pot ]; then
|
|
||||||
JOIN="--join-existing"
|
|
||||||
else
|
|
||||||
JOIN=""
|
|
||||||
fi
|
|
||||||
echo "extracting messages"
|
|
||||||
|
|
||||||
xgettext -f POTFILES -d mydevel.webroot -L PHP $JOIN --force-po -o messages.pot
|
|
||||||
if [ -z "$JOIN" ]; then
|
|
||||||
sed -i s/charset=CHARSET/charset=UTF-8/g messages.pot
|
|
||||||
fi
|
|
||||||
|
|
||||||
for i in `cat LINGUAS`; do
|
|
||||||
if [ ! -f $i.po ]; then
|
|
||||||
cp messages.pot $i.po
|
|
||||||
else
|
|
||||||
msgmerge $i.po messages.pot
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
150
PO/messages.pot
@ -1,150 +0,0 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
||||||
#
|
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2024-11-27 19:03+0100\n"
|
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
||||||
"Language: \n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:45
|
|
||||||
msgid "Email Settings"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:46
|
|
||||||
msgid "Site Settings"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:47
|
|
||||||
msgid "Database Settings"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:48
|
|
||||||
msgid "User Settings"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:56
|
|
||||||
msgid "Enter the site name that should be displayed in titles."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:57
|
|
||||||
msgid "Site name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:61
|
|
||||||
msgid "Site root directory"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:65
|
|
||||||
msgid "Contact email"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:69
|
|
||||||
msgid "Username"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:73
|
|
||||||
msgid "Email"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:77
|
|
||||||
#: ../src/Controller/SetupController.php:117
|
|
||||||
#: ../src/Controller/SetupController.php:144
|
|
||||||
msgid "Password"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:81
|
|
||||||
msgid "Confirm Password"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:84
|
|
||||||
msgid "Run Migrations?"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:93
|
|
||||||
msgid "SQLite3"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:94
|
|
||||||
msgid "MySQL/MariaDB"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:95
|
|
||||||
msgid "PostgreSQL"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:96
|
|
||||||
#: ../src/Controller/SetupController.php:120
|
|
||||||
msgid "Database URL"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:101
|
|
||||||
msgid "Database"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:105
|
|
||||||
msgid "Host"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:109
|
|
||||||
msgid "Port"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:113
|
|
||||||
#: ../src/Controller/SetupController.php:140
|
|
||||||
msgid "User"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:124
|
|
||||||
msgid "Backend"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:127
|
|
||||||
msgid "No email support"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:128
|
|
||||||
msgid "SMTP"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:129
|
|
||||||
msgid "Sendmail"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:130
|
|
||||||
msgid "Naitve"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:131
|
|
||||||
msgid "User DSN"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:136
|
|
||||||
msgid "Email Path"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:148
|
|
||||||
msgid "SMTP Host"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:152
|
|
||||||
msgid "SMTP Port"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:156
|
|
||||||
msgid "DSN"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../src/Controller/SetupController.php:160
|
|
||||||
msgid "Sender address"
|
|
||||||
msgstr ""
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
||||||
#
|
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2024-11-26 20:44+0100\n"
|
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
||||||
"Language: \n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|
||||||
#
|
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2024-11-26 20:44+0100\n"
|
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
||||||
"Language: \n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
39
assets/icons/back.svg
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="16px"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="16px"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="back.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#505050"
|
||||||
|
inkscape:zoom="73.3125"
|
||||||
|
inkscape:cx="7.9931799"
|
||||||
|
inkscape:cy="8"
|
||||||
|
inkscape:window-width="3440"
|
||||||
|
inkscape:window-height="1369"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg1" />
|
||||||
|
<path
|
||||||
|
d="m 1 11 c 0 -0.265625 0.105469 -0.519531 0.292969 -0.707031 l 6 -6 c 0.390625 -0.390625 1.023437 -0.390625 1.414062 0 l 6 6 c 0.1875 0.1875 0.292969 0.441406 0.292969 0.707031 s -0.105469 0.519531 -0.292969 0.707031 c -0.390625 0.390625 -1.023437 0.390625 -1.414062 0 l -5.292969 -5.292969 l -5.292969 5.292969 c -0.390625 0.390625 -1.023437 0.390625 -1.414062 0 c -0.1875 -0.1875 -0.292969 -0.441406 -0.292969 -0.707031 z m 0 0"
|
||||||
|
fill="#2e3436"
|
||||||
|
id="path1"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
39
assets/icons/delete.svg
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="16px"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="16px"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="delete.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#505050"
|
||||||
|
inkscape:zoom="73.3125"
|
||||||
|
inkscape:cx="8"
|
||||||
|
inkscape:cy="8"
|
||||||
|
inkscape:window-width="2339"
|
||||||
|
inkscape:window-height="1353"
|
||||||
|
inkscape:window-x="-16"
|
||||||
|
inkscape:window-y="71"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg1" />
|
||||||
|
<path
|
||||||
|
d="m 8 0 c -4.410156 0 -8 3.589844 -8 8 s 3.589844 8 8 8 s 8 -3.589844 8 -8 s -3.589844 -8 -8 -8 z m 0 2 c 3.332031 0 6 2.667969 6 6 s -2.667969 6 -6 6 s -6 -2.667969 -6 -6 s 2.667969 -6 6 -6 z m -2.03125 2.96875 c -0.265625 0 -0.519531 0.105469 -0.707031 0.292969 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 l 1.292969 1.292969 l -1.292969 1.292969 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 s 1.023437 0.390625 1.414062 0 l 1.292969 -1.292969 l 1.292969 1.292969 c 0.390625 0.390625 1.023437 0.390625 1.414062 0 s 0.390625 -1.023437 0 -1.414062 l -1.292969 -1.292969 l 1.292969 -1.292969 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 s -0.519531 0.105469 -0.707031 0.292969 l -1.292969 1.292969 l -1.292969 -1.292969 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 z m 0 0"
|
||||||
|
fill="#2e3436"
|
||||||
|
id="path1"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
39
assets/icons/directory-new.svg
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="16px"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="16px"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="directory-new.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#505050"
|
||||||
|
inkscape:zoom="73.3125"
|
||||||
|
inkscape:cx="7.9931799"
|
||||||
|
inkscape:cy="8"
|
||||||
|
inkscape:window-width="3440"
|
||||||
|
inkscape:window-height="1369"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg1" />
|
||||||
|
<path
|
||||||
|
d="m 3 1 c -1.644531 0 -3 1.355469 -3 3 v 8 c 0 1.644531 1.355469 3 3 3 h 3 c 0.550781 0 1 -0.449219 1 -1 s -0.449219 -1 -1 -1 h -3 c -0.5625 0 -1 -0.4375 -1 -1 v -7 h 11 c 0.5625 0 1 0.4375 1 1 v 1 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 v -1 c 0 -1.644531 -1.355469 -3 -3 -3 h -3.585938 l -1.707031 -1.707031 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 z m 0 2 h 3.585938 l 1 1 h -5.585938 c 0 -0.5625 0.4375 -1 1 -1 z m 8 5 v 3 h -3 v 2 h 3 v 3 h 2 v -3 h 3 v -2 h -3 v -3 z m 0 0"
|
||||||
|
fill="#2e3436"
|
||||||
|
id="path1"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
60
assets/icons/directory.svg
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="16px"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="16px"
|
||||||
|
version="1.1"
|
||||||
|
id="svg2"
|
||||||
|
sodipodi:docname="folder.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview2"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#505050"
|
||||||
|
inkscape:zoom="73.3125"
|
||||||
|
inkscape:cx="7.9931799"
|
||||||
|
inkscape:cy="8"
|
||||||
|
inkscape:window-width="3440"
|
||||||
|
inkscape:window-height="1369"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg2" />
|
||||||
|
<g
|
||||||
|
fill="#2e3436"
|
||||||
|
id="g2"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1">
|
||||||
|
<path
|
||||||
|
d="m 1 4 v 1 h 8 v -1 z m 0 0"
|
||||||
|
id="path1"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1" />
|
||||||
|
<path
|
||||||
|
d="m 3 1 c -1.644531 0 -3 1.355469 -3 3 v 8 c 0 1.644531 1.355469 3 3 3 h 10 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -1.644531 -1.355469 -3 -3 -3 h -3.585938 l -1.707031 -1.707031 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 z m 0 2 h 3.585938 l 1.707031 1.707031 c 0.1875 0.1875 0.441406 0.292969 0.707031 0.292969 h 4 c 0.5625 0 1 0.4375 1 1 v 6 c 0 0.566406 -0.4375 1 -1 1 h -10 c -0.5625 0 -1 -0.433594 -1 -1 v -8 c 0 -0.5625 0.4375 -1 1 -1 z m 0 0"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
fill="#2e3436"
|
||||||
|
id="g4"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1">
|
||||||
|
<path
|
||||||
|
d="m 1 4 v 1 h 8 v -1 z m 0 0"
|
||||||
|
id="path3"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1" />
|
||||||
|
<path
|
||||||
|
d="m 3 1 c -1.644531 0 -3 1.355469 -3 3 v 8 c 0 1.644531 1.355469 3 3 3 h 10 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -1.644531 -1.355469 -3 -3 -3 h -3.585938 l -1.707031 -1.707031 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 z m 0 2 h 3.585938 l 1.707031 1.707031 c 0.1875 0.1875 0.441406 0.292969 0.707031 0.292969 h 4 c 0.5625 0 1 0.4375 1 1 v 6 c 0 0.566406 -0.4375 1 -1 1 h -10 c -0.5625 0 -1 -0.433594 -1 -1 v -8 c 0 -0.5625 0.4375 -1 1 -1 z m 0 0"
|
||||||
|
id="path4"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
41
assets/icons/empty.svg
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
viewBox="0 0 32 32"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||||
|
sodipodi:docname="emptysvg.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#505050"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:zoom="36.65625"
|
||||||
|
inkscape:cx="15.98636"
|
||||||
|
inkscape:cy="16"
|
||||||
|
inkscape:window-width="3440"
|
||||||
|
inkscape:window-height="1369"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
39
assets/icons/file.svg
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="16px"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="16px"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="file.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#505050"
|
||||||
|
inkscape:zoom="73.3125"
|
||||||
|
inkscape:cx="7.9931799"
|
||||||
|
inkscape:cy="8"
|
||||||
|
inkscape:window-width="3440"
|
||||||
|
inkscape:window-height="1369"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg1" />
|
||||||
|
<path
|
||||||
|
d="m 5 1 c -1.644531 0 -3 1.355469 -3 3 v 9 c 0 1.644531 1.355469 3 3 3 h 6 c 1.644531 0 3 -1.355469 3 -3 v -7.5 c 0 -0.265625 -0.105469 -0.519531 -0.292969 -0.707031 l -3.5 -3.5 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 z m 0 2 h 4 v 1.5 c 0 1 0.5 1.5 1.5 1.5 h 1.5 v 7 c 0 0.570312 -0.429688 1 -1 1 h -6 c -0.570312 0 -1 -0.429688 -1 -1 v -9 c 0 -0.570312 0.429688 -1 1 -1 z m 0 0"
|
||||||
|
fill="#2e3436"
|
||||||
|
id="path1"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
40
assets/icons/upload.svg
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="16px"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="16px"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="upload.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#505050"
|
||||||
|
inkscape:zoom="73.3125"
|
||||||
|
inkscape:cx="7.9931799"
|
||||||
|
inkscape:cy="8"
|
||||||
|
inkscape:window-width="3440"
|
||||||
|
inkscape:window-height="1369"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg1" />
|
||||||
|
<path
|
||||||
|
d="m 4 0 c -1.644531 0 -3 1.355469 -3 3 v 10 c 0 1.644531 1.355469 3 3 3 h 1 c 0.550781 0 1 -0.449219 1 -1 s -0.449219 -1 -1 -1 h -1 c -0.570312 0 -1 -0.429688 -1 -1 v -10 c 0 -0.570312 0.429688 -1 1 -1 h 5.585938 l 3.414062 3.414062 v 7.585938 c 0 0.570312 -0.429688 1 -1 1 h -1 c -0.550781 0 -1 0.449219 -1 1 s 0.449219 1 1 1 h 1 c 1.644531 0 3 -1.355469 3 -3 v -8 c 0 -0.265625 -0.105469 -0.519531 -0.292969 -0.707031 l -4 -4 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 z m 4 6 c -0.265625 0 -0.519531 0.105469 -0.707031 0.292969 l -3 3 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 s 1.023437 0.390625 1.414062 0 l 1.292969 -1.292969 v 6.585938 h 2 v -6.585938 l 1.292969 1.292969 c 0.390625 0.390625 1.023437 0.390625 1.414062 0 s 0.390625 -1.023437 0 -1.414062 l -3 -3 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 z m 0 0"
|
||||||
|
fill="#2e3436"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
id="path1"
|
||||||
|
style="fill:#e0d4a4;fill-opacity:1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
@ -2,8 +2,8 @@
|
|||||||
font-family: "JetBrains";
|
font-family: "JetBrains";
|
||||||
src:
|
src:
|
||||||
local("JetBrainsMono-Medium.ttf"),
|
local("JetBrainsMono-Medium.ttf"),
|
||||||
url("./fonts/JetBrainsMono/JetBrainsMono-Regular.woff2") format("woff2"),
|
url("../fonts/JetBrainsMono/JetBrainsMono-Regular.woff2") format("woff2"),
|
||||||
url("./fonts/JetBrainsMono/JetBrainsMono-Medium.woff2") format("woff2");
|
url("../fonts/JetBrainsMono/JetBrainsMono-Medium.woff2") format("woff2");
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
@ -12,7 +12,7 @@
|
|||||||
font-family: "JetBrains";
|
font-family: "JetBrains";
|
||||||
src:
|
src:
|
||||||
local("JetBrainsMono-MediumItalic.ttf"),
|
local("JetBrainsMono-MediumItalic.ttf"),
|
||||||
url("./fonts/JetBrainsMono/JetBrainsMono-Italic.woff2") format("woff2");
|
url("../fonts/JetBrainsMono/JetBrainsMono-Italic.woff2") format("woff2");
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@
|
|||||||
font-family: "JetBrains";
|
font-family: "JetBrains";
|
||||||
src:
|
src:
|
||||||
local("JetBrainsMono-Bold.ttf"),
|
local("JetBrainsMono-Bold.ttf"),
|
||||||
url("./fonts/JetBrainsMono/JetBrainsMono-Bold.woff2") format("woff2");
|
url("../fonts/JetBrainsMono/JetBrainsMono-Bold.woff2") format("woff2");
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@
|
|||||||
font-family: "JetBrains";
|
font-family: "JetBrains";
|
||||||
src:
|
src:
|
||||||
local("JetBrainsMono-BoldItalic.ttf"),
|
local("JetBrainsMono-BoldItalic.ttf"),
|
||||||
url("./fonts/JetBrainsMono/JetBrainsMono-BoldItalic.woff2") format("woff2");
|
url("../fonts/JetBrainsMono/JetBrainsMono-BoldItalic.woff2") format("woff2");
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@
|
|||||||
font-family: "JetBrains";
|
font-family: "JetBrains";
|
||||||
src:
|
src:
|
||||||
local("JetBrainsMono-ExtraBold.ttf"),
|
local("JetBrainsMono-ExtraBold.ttf"),
|
||||||
url("./fonts/JetBrainsMono/JetBrainsMono-ExtraBold.woff2") format("woff2");
|
url("../fonts/JetBrainsMono/JetBrainsMono-ExtraBold.woff2") format("woff2");
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@
|
|||||||
font-family: "JetBrains";
|
font-family: "JetBrains";
|
||||||
src:
|
src:
|
||||||
local("JetBrainsMono-ExtraBoldItalic.ttf"),
|
local("JetBrainsMono-ExtraBoldItalic.ttf"),
|
||||||
url("./fonts/JetBrainsMono/JetBrainsMono-ExtraBoldItalic.woff2") format("woff2");
|
url("../fonts/JetBrainsMono/JetBrainsMono-ExtraBoldItalic.woff2") format("woff2");
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@
|
|||||||
font-family: "JetBrains";
|
font-family: "JetBrains";
|
||||||
src:
|
src:
|
||||||
local("JetBrainsMono-Light.ttf"),
|
local("JetBrainsMono-Light.ttf"),
|
||||||
url("./fonts/JetBrainsMono/JetBrainsMono-Light.woff2") format("woff2");
|
url("../fonts/JetBrainsMono/JetBrainsMono-Light.woff2") format("woff2");
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@
|
|||||||
font-family: "JetBrains";
|
font-family: "JetBrains";
|
||||||
src:
|
src:
|
||||||
local("JetBrainsMono-LightItalic.ttf"),
|
local("JetBrainsMono-LightItalic.ttf"),
|
||||||
url("./fonts/JetBrainsMono/JetBrainsMono-LightItalic.woff2") format("woff2");
|
url("../fonts/JetBrainsMono/JetBrainsMono-LightItalic.woff2") format("woff2");
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
}
|
}
|
||||||
@ -191,6 +191,8 @@ th {
|
|||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
font-size: var(--font-size-th);
|
font-size: var(--font-size-th);
|
||||||
font-weight: var(--font-weight-th);
|
font-weight: var(--font-weight-th);
|
||||||
|
border-color:var(--color-th-background);
|
||||||
|
border-width:0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -199,6 +201,8 @@ td {
|
|||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
|
margin:0px;
|
||||||
|
border-width:0px;
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
font-size: var(--font-size-td);
|
font-size: var(--font-size-td);
|
||||||
}
|
}
|
||||||
@ -222,54 +226,6 @@ a:visited {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.left {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.center {
|
|
||||||
text-align: center;
|
|
||||||
align-self: center;
|
|
||||||
align-items:center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
color: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.frame {
|
|
||||||
border-width: 2px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: var(--color-text);
|
|
||||||
}
|
|
||||||
|
|
||||||
.frame-table th,
|
|
||||||
.frame-table td {
|
|
||||||
padding: 5px;
|
|
||||||
border-width: 0px;
|
|
||||||
}
|
|
||||||
.center-box {
|
|
||||||
align-content:center;
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-box {
|
|
||||||
min-width: 400px;
|
|
||||||
max-width: 600px;
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-width {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
label {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@ -321,15 +277,30 @@ select {
|
|||||||
border-width: 0px;
|
border-width: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.optional-input {
|
|
||||||
background-color: var(--color-optional-input);
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
code {
|
||||||
background-color: var(--color-code-background);
|
background-color: var(--color-code-background);
|
||||||
color: var(--color-code);
|
color: var(--color-code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: 3px solid var(--color-text);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog {
|
||||||
|
background-color: var(--color-background);
|
||||||
|
color: var(--color-text);
|
||||||
|
border: 2px, solid, white;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.optional-input {
|
||||||
|
background-color: var(--color-optional-input);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.td-color {
|
.td-color {
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
@ -340,16 +311,59 @@ code {
|
|||||||
white-space:nowrap;
|
white-space:nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
align-self: center;
|
||||||
|
align-items:center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame {
|
||||||
|
border-width: 2px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame-table th,
|
||||||
|
.frame-table td {
|
||||||
|
padding: 5px;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
.center-box {
|
||||||
|
align-content:center;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-box {
|
||||||
|
min-width: 400px;
|
||||||
|
max-width: 600px;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.standard-background {
|
.standard-background {
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset {
|
|
||||||
border: 3px solid var(--color-text);
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-top: 5px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.margin-5 {
|
.margin-5 {
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
@ -366,3 +380,54 @@ fieldset {
|
|||||||
background-color:var(--color-code-background);
|
background-color:var(--color-code-background);
|
||||||
color:white;
|
color:white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.icon-back {
|
||||||
|
content:url('../icons/back.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-delete {
|
||||||
|
content:url('../icons/delete.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-directory {
|
||||||
|
content:url('../icons/directory.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-empty {
|
||||||
|
content: url('../icons/empty.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-file {
|
||||||
|
content: url('../icons/file.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-upload {
|
||||||
|
content: url('../icons/upload.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-directory-new {
|
||||||
|
content: url('../icons/directory-new.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-icon {
|
||||||
|
width: 24;
|
||||||
|
height: 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-button {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
border: 0px hidden var(--color-text);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-item {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-collapse {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.tr-border-bottom {
|
||||||
|
border-bottom: 1px solid var(--color-text);
|
||||||
|
}
|
||||||
|
|||||||
@ -7,44 +7,45 @@
|
|||||||
"php": ">=8.1",
|
"php": ">=8.1",
|
||||||
"ext-ctype": "*",
|
"ext-ctype": "*",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
"doctrine/dbal": "^3",
|
"doctrine/dbal": "^3.9.3",
|
||||||
"doctrine/doctrine-bundle": "^2.13",
|
"doctrine/doctrine-bundle": "^2.13.1",
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.3",
|
"doctrine/doctrine-migrations-bundle": "^3.3.1",
|
||||||
"doctrine/orm": "^3.3",
|
"doctrine/orm": "^3.3",
|
||||||
"easycorp/easyadmin-bundle": "^4.18",
|
"easycorp/easyadmin-bundle": "4.x-dev",
|
||||||
"phpdocumentor/reflection-docblock": "^5.6",
|
"phpdocumentor/reflection-docblock": "^5.6",
|
||||||
"phpstan/phpdoc-parser": "^2.0",
|
"phpstan/phpdoc-parser": "^2.0",
|
||||||
"symfony/asset": "6.4.*",
|
"symfony/asset": "7.2.*",
|
||||||
"symfony/asset-mapper": "6.4.*",
|
"symfony/asset-mapper": "7.2.*",
|
||||||
"symfony/console": "6.4.*",
|
"symfony/console": "7.2.*",
|
||||||
"symfony/doctrine-messenger": "6.4.*",
|
"symfony/doctrine-messenger": "7.2.*",
|
||||||
"symfony/dotenv": "6.4.*",
|
"symfony/dotenv": "7.2.*",
|
||||||
"symfony/expression-language": "6.4.*",
|
"symfony/expression-language": "7.2.*",
|
||||||
"symfony/flex": "^2",
|
"symfony/flex": "^2.4",
|
||||||
"symfony/form": "6.4.*",
|
"symfony/form": "7.2.*",
|
||||||
"symfony/framework-bundle": "6.4.*",
|
"symfony/framework-bundle": "7.2.*",
|
||||||
"symfony/http-client": "6.4.*",
|
"symfony/http-client": "7.2.*",
|
||||||
"symfony/intl": "6.4.*",
|
"symfony/intl": "7.2.*",
|
||||||
"symfony/mailer": "6.4.*",
|
"symfony/mailer": "7.2.*",
|
||||||
"symfony/mime": "6.4.*",
|
"symfony/mime": "7.2.*",
|
||||||
"symfony/monolog-bundle": "^3.10",
|
"symfony/monolog-bundle": "^3.10",
|
||||||
"symfony/notifier": "6.4.*",
|
"symfony/notifier": "7.2.*",
|
||||||
"symfony/process": "6.4.*",
|
"symfony/process": "7.2.*",
|
||||||
"symfony/property-access": "6.4.*",
|
"symfony/property-access": "7.2.*",
|
||||||
"symfony/property-info": "6.4.*",
|
"symfony/property-info": "7.2.*",
|
||||||
"symfony/runtime": "6.4.*",
|
"symfony/runtime": "^7.2",
|
||||||
"symfony/security-bundle": "6.4.*",
|
"symfony/security-bundle": "7.2.*",
|
||||||
"symfony/serializer": "6.4.*",
|
"symfony/serializer": "7.2.*",
|
||||||
"symfony/stimulus-bundle": "^2.21",
|
"symfony/stimulus-bundle": "^2.22",
|
||||||
"symfony/string": "6.4.*",
|
"symfony/string": "7.2.*",
|
||||||
"symfony/translation": "6.4.*",
|
"symfony/translation": "7.2.*",
|
||||||
"symfony/twig-bundle": "6.4.*",
|
"symfony/twig-bundle": "7.2.*",
|
||||||
"symfony/ux-turbo": "^2.21",
|
"symfony/ux-turbo": "^2.22",
|
||||||
"symfony/validator": "6.4.*",
|
"symfony/validator": "7.2.*",
|
||||||
"symfony/web-link": "6.4.*",
|
"symfony/web-link": "7.2.*",
|
||||||
"symfony/yaml": "6.4.*",
|
"symfony/yaml": "7.2.*",
|
||||||
"twig/extra-bundle": "^2.12|^3.0",
|
"symfonycasts/reset-password-bundle": "^1.23",
|
||||||
"twig/twig": "^2.12|^3.0"
|
"twig/extra-bundle": "^2.12|^3.16",
|
||||||
|
"twig/twig": "^2.12|^3.16"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"allow-plugins": {
|
"allow-plugins": {
|
||||||
@ -92,17 +93,17 @@
|
|||||||
"extra": {
|
"extra": {
|
||||||
"symfony": {
|
"symfony": {
|
||||||
"allow-contrib": false,
|
"allow-contrib": false,
|
||||||
"require": "6.4.*"
|
"require": "7.2.*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9.5",
|
"phpunit/phpunit": "^9.6.21",
|
||||||
"symfony/browser-kit": "6.4.*",
|
"symfony/browser-kit": "7.2.*",
|
||||||
"symfony/css-selector": "6.4.*",
|
"symfony/css-selector": "7.2.*",
|
||||||
"symfony/debug-bundle": "6.4.*",
|
"symfony/debug-bundle": "7.2.*",
|
||||||
"symfony/maker-bundle": "^1.0",
|
"symfony/maker-bundle": "^1.61",
|
||||||
"symfony/phpunit-bridge": "^7.1",
|
"symfony/phpunit-bridge": "^7.2",
|
||||||
"symfony/stopwatch": "6.4.*",
|
"symfony/stopwatch": "7.2.*",
|
||||||
"symfony/web-profiler-bundle": "6.4.*"
|
"symfony/web-profiler-bundle": "7.2.*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2133
composer.lock
generated
@ -15,4 +15,5 @@ return [
|
|||||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||||
Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true],
|
Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true],
|
||||||
EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true],
|
EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true],
|
||||||
|
SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
|||||||
11
config/packages/csrf.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Enable stateless CSRF protection for forms and logins/logouts
|
||||||
|
framework:
|
||||||
|
form:
|
||||||
|
csrf_protection:
|
||||||
|
token_id: submit
|
||||||
|
|
||||||
|
csrf_protection:
|
||||||
|
stateless_token_ids:
|
||||||
|
- submit
|
||||||
|
- authenticate
|
||||||
|
- logout
|
||||||
@ -1,3 +1,4 @@
|
|||||||
framework:
|
framework:
|
||||||
mailer:
|
mailer:
|
||||||
dsn: '%env(MAILER_DSN)%'
|
dsn: '%env(MAILER_DSN)%'
|
||||||
|
message_bus: false
|
||||||
|
|||||||
4
config/packages/reset_password.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
symfonycasts_reset_password:
|
||||||
|
request_password_repository: App\Repository\ResetPasswordRequestRepository
|
||||||
|
lifetime: 3600
|
||||||
|
throttle_limit: 3600
|
||||||
@ -19,6 +19,8 @@ security:
|
|||||||
form_login:
|
form_login:
|
||||||
login_path: app_login
|
login_path: app_login
|
||||||
check_path: app_login
|
check_path: app_login
|
||||||
|
default_target_path: app_index
|
||||||
|
always_use_default_target_path: false
|
||||||
enable_csrf: true
|
enable_csrf: true
|
||||||
logout:
|
logout:
|
||||||
path: app_logout
|
path: app_logout
|
||||||
|
|||||||
@ -4,4 +4,4 @@ framework:
|
|||||||
default_path: '%kernel.project_dir%/translations'
|
default_path: '%kernel.project_dir%/translations'
|
||||||
fallbacks:
|
fallbacks:
|
||||||
- en
|
- en
|
||||||
|
- de
|
||||||
@ -1,4 +0,0 @@
|
|||||||
framework:
|
|
||||||
uid:
|
|
||||||
default_uuid_version: 7
|
|
||||||
time_based_uuid_version: 7
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace DoctrineMigrations;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\Schema\Schema;
|
|
||||||
use Doctrine\Migrations\AbstractMigration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto-generated Migration: Please modify to your needs!
|
|
||||||
*/
|
|
||||||
final class Version20241201211313 extends AbstractMigration
|
|
||||||
{
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function up(Schema $schema): void
|
|
||||||
{
|
|
||||||
// this up() migration is auto-generated, please modify it to your needs
|
|
||||||
$this->addSql('CREATE TABLE rememberme_token (series VARCHAR(88) NOT NULL, value VARCHAR(88) NOT NULL, lastUsed DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
|
||||||
, class VARCHAR(100) NOT NULL, username VARCHAR(200) NOT NULL, PRIMARY KEY(series))');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
// this down() migration is auto-generated, please modify it to your needs
|
|
||||||
$this->addSql('DROP TABLE rememberme_token');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
|
|||||||
/**
|
/**
|
||||||
* Auto-generated Migration: Please modify to your needs!
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
*/
|
*/
|
||||||
final class Version20241201030110 extends AbstractMigration
|
final class Version20241204160251 extends AbstractMigration
|
||||||
{
|
{
|
||||||
public function getDescription(): string
|
public function getDescription(): string
|
||||||
{
|
{
|
||||||
@ -58,6 +58,18 @@ final class Version20241201030110 extends AbstractMigration
|
|||||||
)');
|
)');
|
||||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_A6BDD54BE7927C74 ON mydevel_webroot_user (email)');
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_A6BDD54BE7927C74 ON mydevel_webroot_user (email)');
|
||||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_USERNAME ON mydevel_webroot_user (username)');
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_USERNAME ON mydevel_webroot_user (username)');
|
||||||
|
$this->addSql('CREATE TABLE reset_password_request (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
selector VARCHAR(20) NOT NULL,
|
||||||
|
hashed_token VARCHAR(100) NOT NULL,
|
||||||
|
requested_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||||
|
,
|
||||||
|
expires_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||||
|
,
|
||||||
|
CONSTRAINT FK_7CE748AA76ED395 FOREIGN KEY (user_id) REFERENCES mydevel_webroot_user (id) NOT DEFERRABLE INITIALLY IMMEDIATE
|
||||||
|
)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_7CE748AA76ED395 ON reset_password_request (user_id)');
|
||||||
$this->addSql('CREATE TABLE messenger_messages (
|
$this->addSql('CREATE TABLE messenger_messages (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
body CLOB NOT NULL,
|
body CLOB NOT NULL,
|
||||||
@ -72,6 +84,15 @@ final class Version20241201030110 extends AbstractMigration
|
|||||||
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0 ON messenger_messages (queue_name)');
|
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0 ON messenger_messages (queue_name)');
|
||||||
$this->addSql('CREATE INDEX IDX_75EA56E0E3BD61CE ON messenger_messages (available_at)');
|
$this->addSql('CREATE INDEX IDX_75EA56E0E3BD61CE ON messenger_messages (available_at)');
|
||||||
$this->addSql('CREATE INDEX IDX_75EA56E016BA31DB ON messenger_messages (delivered_at)');
|
$this->addSql('CREATE INDEX IDX_75EA56E016BA31DB ON messenger_messages (delivered_at)');
|
||||||
|
$this->addSql('CREATE TABLE rememberme_token (
|
||||||
|
series VARCHAR(88) NOT NULL,
|
||||||
|
value VARCHAR(88) NOT NULL,
|
||||||
|
lastUsed DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||||
|
,
|
||||||
|
class VARCHAR(100) NOT NULL,
|
||||||
|
username VARCHAR(200) NOT NULL,
|
||||||
|
PRIMARY KEY(series)
|
||||||
|
)');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
public function down(Schema $schema): void
|
||||||
@ -81,6 +102,8 @@ final class Version20241201030110 extends AbstractMigration
|
|||||||
$this->addSql('DROP TABLE mydevel_webroot_file_permission');
|
$this->addSql('DROP TABLE mydevel_webroot_file_permission');
|
||||||
$this->addSql('DROP TABLE mydevel_webroot_role');
|
$this->addSql('DROP TABLE mydevel_webroot_role');
|
||||||
$this->addSql('DROP TABLE mydevel_webroot_user');
|
$this->addSql('DROP TABLE mydevel_webroot_user');
|
||||||
|
$this->addSql('DROP TABLE reset_password_request');
|
||||||
$this->addSql('DROP TABLE messenger_messages');
|
$this->addSql('DROP TABLE messenger_messages');
|
||||||
|
$this->addSql('DROP TABLE rememberme_token');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
41
migrations/Version20241206014353.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20241206014353 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TEMPORARY TABLE __temp__mydevel_webroot_file AS SELECT id, owner_id, url, abspath, description FROM mydevel_webroot_file');
|
||||||
|
$this->addSql('DROP TABLE mydevel_webroot_file');
|
||||||
|
$this->addSql('CREATE TABLE mydevel_webroot_file (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, owner_id INTEGER NOT NULL, url_path CLOB NOT NULL, abspath CLOB NOT NULL, description CLOB DEFAULT NULL, section VARCHAR(1024) DEFAULT \'webroot\' NOT NULL, CONSTRAINT FK_A7B135127E3C61F9 FOREIGN KEY (owner_id) REFERENCES mydevel_webroot_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||||
|
$this->addSql('INSERT INTO mydevel_webroot_file (id, owner_id, url_path, abspath, description) SELECT id, owner_id, url, abspath, description FROM __temp__mydevel_webroot_file');
|
||||||
|
$this->addSql('DROP TABLE __temp__mydevel_webroot_file');
|
||||||
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_A7B135127E3C61F9 ON mydevel_webroot_file (owner_id)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TEMPORARY TABLE __temp__mydevel_webroot_file AS SELECT id, owner_id, url_path, abspath, description FROM mydevel_webroot_file');
|
||||||
|
$this->addSql('DROP TABLE mydevel_webroot_file');
|
||||||
|
$this->addSql('CREATE TABLE mydevel_webroot_file (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, owner_id INTEGER NOT NULL, url CLOB NOT NULL, abspath CLOB NOT NULL, description CLOB DEFAULT NULL, CONSTRAINT FK_A7B135127E3C61F9 FOREIGN KEY (owner_id) REFERENCES mydevel_webroot_user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||||
|
$this->addSql('INSERT INTO mydevel_webroot_file (id, owner_id, url, abspath, description) SELECT id, owner_id, url_path, abspath, description FROM __temp__mydevel_webroot_file');
|
||||||
|
$this->addSql('DROP TABLE __temp__mydevel_webroot_file');
|
||||||
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_A7B135127E3C61F9 ON mydevel_webroot_file (owner_id)');
|
||||||
|
}
|
||||||
|
}
|
||||||
41
migrations/Version20241209075313.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20241209075313 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TEMPORARY TABLE __temp__mydevel_webroot_file AS SELECT id, owner_id, url_path, abspath, description FROM mydevel_webroot_file');
|
||||||
|
$this->addSql('DROP TABLE mydevel_webroot_file');
|
||||||
|
$this->addSql('CREATE TABLE mydevel_webroot_file (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, owner_id INTEGER NOT NULL, url CLOB NOT NULL, abspath CLOB NOT NULL, description CLOB DEFAULT NULL, CONSTRAINT FK_A7B135127E3C61F9 FOREIGN KEY (owner_id) REFERENCES mydevel_webroot_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||||
|
$this->addSql('INSERT INTO mydevel_webroot_file (id, owner_id, url, abspath, description) SELECT id, owner_id, url_path, abspath, description FROM __temp__mydevel_webroot_file');
|
||||||
|
$this->addSql('DROP TABLE __temp__mydevel_webroot_file');
|
||||||
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_A7B135127E3C61F9 ON mydevel_webroot_file (owner_id)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TEMPORARY TABLE __temp__mydevel_webroot_file AS SELECT id, owner_id, url, abspath, description FROM mydevel_webroot_file');
|
||||||
|
$this->addSql('DROP TABLE mydevel_webroot_file');
|
||||||
|
$this->addSql('CREATE TABLE mydevel_webroot_file (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, owner_id INTEGER NOT NULL, url_path CLOB NOT NULL, abspath CLOB NOT NULL, description CLOB DEFAULT NULL, section VARCHAR(1024) DEFAULT \'webroot\' NOT NULL, CONSTRAINT FK_A7B135127E3C61F9 FOREIGN KEY (owner_id) REFERENCES mydevel_webroot_user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||||
|
$this->addSql('INSERT INTO mydevel_webroot_file (id, owner_id, url_path, abspath, description) SELECT id, owner_id, url, abspath, description FROM __temp__mydevel_webroot_file');
|
||||||
|
$this->addSql('DROP TABLE __temp__mydevel_webroot_file');
|
||||||
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_A7B135127E3C61F9 ON mydevel_webroot_file (owner_id)');
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/Component/Sorter/FileSortType.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Component\Sorter;
|
||||||
|
|
||||||
|
enum FileSortType {
|
||||||
|
case TYPE_ASC;
|
||||||
|
case TYPE_DESC;
|
||||||
|
case NAME_ASC;
|
||||||
|
case NAME_DESC;
|
||||||
|
case SIZE_ASC;
|
||||||
|
case SIZE_DESC;
|
||||||
|
case DATE_ASC;
|
||||||
|
case DATE_DESC;
|
||||||
|
}
|
||||||
61
src/Component/Sorter/FileSorter.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Component\Sorter;
|
||||||
|
use App\Component\Sorter\FileSortType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of FileSorter
|
||||||
|
*
|
||||||
|
* @author c9mos
|
||||||
|
*/
|
||||||
|
class FileSorter {
|
||||||
|
static public function sortTypeAsc(array $element1,array $element2): int
|
||||||
|
{
|
||||||
|
if ($element1['dir'] === $element2['dir']) {
|
||||||
|
return strcmp($element1['name'], $element2['name']);
|
||||||
|
} elseif ($element1['dir']) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function sortTypeDesc(array $element1,array $element2): int
|
||||||
|
{
|
||||||
|
if ($element1['dir'] === $element2['dir']) {
|
||||||
|
return (strcmp($element2['name'],$element1['name']));
|
||||||
|
} elseif ($element1['dir']) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function sortNameAsc($element1,$element2): int
|
||||||
|
{
|
||||||
|
return strcmp($element1['name'],$element2['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function sortNameDesc($element1,$element2): int
|
||||||
|
{
|
||||||
|
return strcmp($element2['name'],$element1['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function sortSizeAsc($element1,$element2): int
|
||||||
|
{
|
||||||
|
return ($element1['size'] - $element2['size']);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function sortSizeDesc($element1,$element2): int
|
||||||
|
{
|
||||||
|
return ($element2['size'] - $element1['size']);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function sortDateAsc($element1,$element2): int
|
||||||
|
{
|
||||||
|
return ($element1['mtime'] - $element2['mtime']);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function sortDateDesc($element1,$element2): int
|
||||||
|
{
|
||||||
|
return ($element2['mtime'] - $element1['mtime']);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/Controller/Admin/DashboardController.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
|
class DashboardController extends AbstractDashboardController
|
||||||
|
{
|
||||||
|
#[Route('/admin', name: 'admin')]
|
||||||
|
public function index(): Response
|
||||||
|
{
|
||||||
|
return parent::index();
|
||||||
|
|
||||||
|
// Option 1. You can make your dashboard redirect to some common page of your backend
|
||||||
|
//
|
||||||
|
// $adminUrlGenerator = $this->container->get(AdminUrlGenerator::class);
|
||||||
|
// return $this->redirect($adminUrlGenerator->setController(OneOfYourCrudController::class)->generateUrl());
|
||||||
|
|
||||||
|
// Option 2. You can make your dashboard redirect to different pages depending on the user
|
||||||
|
//
|
||||||
|
// if ('jane' === $this->getUser()->getUsername()) {
|
||||||
|
// return $this->redirect('...');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Option 3. You can render some custom template to display a proper dashboard with widgets, etc.
|
||||||
|
// (tip: it's easier if your template extends from @EasyAdmin/page/content.html.twig)
|
||||||
|
//
|
||||||
|
// return $this->render('some/path/my-dashboard.html.twig');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureDashboard(): Dashboard
|
||||||
|
{
|
||||||
|
return Dashboard::new()
|
||||||
|
->setTitle('Webroot');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureMenuItems(): iterable
|
||||||
|
{
|
||||||
|
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
|
||||||
|
// yield MenuItem::linkToCrud('The Label', 'fas fa-list', EntityClass::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/Controller/Admin/WebrootFileCrudController.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
|
use App\Entity\WebrootFile;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
||||||
|
|
||||||
|
class WebrootFileCrudController extends AbstractCrudController
|
||||||
|
{
|
||||||
|
public static function getEntityFqcn(): string
|
||||||
|
{
|
||||||
|
return WebrootFile::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public function configureFields(string $pageName): iterable
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
IdField::new('id'),
|
||||||
|
TextField::new('title'),
|
||||||
|
TextEditorField::new('description'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
28
src/Controller/Admin/WebrootFilePermissionCrudController.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
|
use App\Entity\WebrootFilePermission;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
||||||
|
|
||||||
|
class WebrootFilePermissionCrudController extends AbstractCrudController
|
||||||
|
{
|
||||||
|
public static function getEntityFqcn(): string
|
||||||
|
{
|
||||||
|
return WebrootFilePermission::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public function configureFields(string $pageName): iterable
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
IdField::new('id'),
|
||||||
|
TextField::new('title'),
|
||||||
|
TextEditorField::new('description'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
28
src/Controller/Admin/WebrootRoleCrudController.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
|
use App\Entity\WebrootRole;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
||||||
|
|
||||||
|
class WebrootRoleCrudController extends AbstractCrudController
|
||||||
|
{
|
||||||
|
public static function getEntityFqcn(): string
|
||||||
|
{
|
||||||
|
return WebrootRole::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public function configureFields(string $pageName): iterable
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
IdField::new('id'),
|
||||||
|
TextField::new('title'),
|
||||||
|
TextEditorField::new('description'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
28
src/Controller/Admin/WebrootUserCrudController.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
|
use App\Entity\WebrootUser;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
|
||||||
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
||||||
|
|
||||||
|
class WebrootUserCrudController extends AbstractCrudController
|
||||||
|
{
|
||||||
|
public static function getEntityFqcn(): string
|
||||||
|
{
|
||||||
|
return WebrootUser::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public function configureFields(string $pageName): iterable
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
IdField::new('id'),
|
||||||
|
TextField::new('title'),
|
||||||
|
TextEditorField::new('description'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
@ -4,8 +4,11 @@ namespace App\Controller;
|
|||||||
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\HttpKernel\KernelInterface;
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
|
use App\Component\Sorter\FileSortType;
|
||||||
use App\Controller\WebrootController;
|
use App\Controller\WebrootController;
|
||||||
|
|
||||||
class MainController extends WebrootController
|
class MainController extends WebrootController
|
||||||
@ -29,4 +32,103 @@ class MainController extends WebrootController
|
|||||||
'user' => $user,
|
'user' => $user,
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[Route('/webroot',name:"app_webroot")]
|
||||||
|
public function webroot(): Response
|
||||||
|
{
|
||||||
|
$user = $this->getUser();
|
||||||
|
$url = $this->generateUrl("app_webroot");
|
||||||
|
$permissions = $this->getFilePermissions($url);
|
||||||
|
|
||||||
|
if (!$permissions['read']) {
|
||||||
|
throw new AccessDeniedHttpException("You are not allowd to visit \"$url\"!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getDirectoryResponse($url);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#[Route('/webroot/share',name:"app_webroot")]
|
||||||
|
#[Route('/webroot/share/{path}',name:"app_webroot_path", requirements:["path"=>".+"])]
|
||||||
|
public function webroot(Request $request,?string $path=null): Response
|
||||||
|
{
|
||||||
|
$is_allowed = false;
|
||||||
|
$user = $this->getUser();
|
||||||
|
|
||||||
|
|
||||||
|
$url = ($path ?
|
||||||
|
$this->generateUrl("app_webroot_path",['path'=>$path])
|
||||||
|
: $this->generateUrl("app_webroot"));
|
||||||
|
|
||||||
|
$routeconf = [
|
||||||
|
'path' => $path,
|
||||||
|
'parent_url' => ($path ? join('/',array_slice(explode('/',$url),0 ,-1)) : null),
|
||||||
|
'delete_route' => 'app_webroot_delete',
|
||||||
|
'mkdir_route' => 'app_webroot_mkdir',
|
||||||
|
'upload_route' => 'app_webroot_upload',
|
||||||
|
];
|
||||||
|
return $this->getUrlResponse($url, $routeconf, $this->parseSort($request->get('S')));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/webroot')]
|
||||||
|
public function webrootRedirect(): Response
|
||||||
|
{
|
||||||
|
return $this->redirectToRoute("app_webroot");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/webroot/upload',name: 'app_webroot_upload')]
|
||||||
|
#[Route('/webroot/upload/{path}',name: 'app_webroot_upload_path',requirements:["path"=>".+"])]
|
||||||
|
public function webrootUpload(?string $path=null): Response
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
return render('main/controller.html.twig',array_merge(
|
||||||
|
$this->getControllerVariables(),
|
||||||
|
[
|
||||||
|
"controller_name"=>"MainController",
|
||||||
|
"controller_class"=> __CLASS__,
|
||||||
|
"controller_function"=> __FUNCTION__
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/webroot/upload_archive',name:'upload_archive')]
|
||||||
|
#[Route('/webroot/upload_archive/{path}',name:'upload_archive_path',requirements:["path"=>".+"])]
|
||||||
|
public function uploadArchive(?string $path=null): Response
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
return render('main/controller.html.twig',array_merge(
|
||||||
|
$this->getControllerVariables(),
|
||||||
|
[
|
||||||
|
"controller_name"=>"MainController",
|
||||||
|
"controller_class"=> __CLASS__,
|
||||||
|
"controller_function"=> __FUNCTION__
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/webroot/delete/{path}',name: 'app_webroot_delete',requirements:["path"=>".+"])]
|
||||||
|
public function webrootDelete(string $path): Response
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
return render('main/controller.html.twig',array_merge(
|
||||||
|
$this->getControllerVariables(),
|
||||||
|
[
|
||||||
|
"controller_name"=>"MainController",
|
||||||
|
"controller_class"=> __CLASS__,
|
||||||
|
"controller_function"=> __FUNCTION__
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/webroot/mkdir/{path}',name: 'app_webroot_mkdir',requirements:["path"=>".+"])]
|
||||||
|
public function webrootMkdir(string $path): Response
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
return render('main/controller.html.twig',array_merge(
|
||||||
|
$this->getControllerVariables(),
|
||||||
|
[
|
||||||
|
"controller_name"=>"MainController",
|
||||||
|
"controller_class"=> __CLASS__,
|
||||||
|
"controller_function"=> __FUNCTION__
|
||||||
|
]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
181
src/Controller/ResetPasswordController.php
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\WebrootUser;
|
||||||
|
use App\Form\ChangePasswordFormType;
|
||||||
|
use App\Form\ResetPasswordRequestFormType;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Mailer\MailerInterface;
|
||||||
|
use Symfony\Component\Mime\Address;
|
||||||
|
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait;
|
||||||
|
use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface;
|
||||||
|
use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface;
|
||||||
|
|
||||||
|
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||||
|
|
||||||
|
#[Route('/reset-password')]
|
||||||
|
class ResetPasswordController extends AbstractController
|
||||||
|
{
|
||||||
|
use ResetPasswordControllerTrait;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private ResetPasswordHelperInterface $resetPasswordHelper,
|
||||||
|
private EntityManagerInterface $entityManager
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display & process form to request a password reset.
|
||||||
|
*/
|
||||||
|
#[Route('', name: 'app_forgot_password_request')]
|
||||||
|
public function request(Request $request, TransportInterface $mailer, TranslatorInterface $translator): Response
|
||||||
|
{
|
||||||
|
$form = $this->createForm(ResetPasswordRequestFormType::class);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
/** @var string $email */
|
||||||
|
$email = $form->get('email')->getData();
|
||||||
|
|
||||||
|
return $this->processSendingPasswordResetEmail($email, $mailer, $translator
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('reset_password/request.html.twig', [
|
||||||
|
'requestForm' => $form,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirmation page after a user has requested a password reset.
|
||||||
|
*/
|
||||||
|
#[Route('/check-email', name: 'app_check_email')]
|
||||||
|
public function checkEmail(): Response
|
||||||
|
{
|
||||||
|
// Generate a fake token if the user does not exist or someone hit this page directly.
|
||||||
|
// This prevents exposing whether or not a user was found with the given email address or not
|
||||||
|
if (null === ($resetToken = $this->getTokenObjectFromSession())) {
|
||||||
|
$resetToken = $this->resetPasswordHelper->generateFakeResetToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('reset_password/check_email.html.twig', [
|
||||||
|
'resetToken' => $resetToken,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates and process the reset URL that the user clicked in their email.
|
||||||
|
*/
|
||||||
|
#[Route('/reset/{token}', name: 'app_reset_password')]
|
||||||
|
public function reset(Request $request, UserPasswordHasherInterface $passwordHasher, TranslatorInterface $translator, ?string $token = null): Response
|
||||||
|
{
|
||||||
|
if ($token) {
|
||||||
|
// We store the token in session and remove it from the URL, to avoid the URL being
|
||||||
|
// loaded in a browser and potentially leaking the token to 3rd party JavaScript.
|
||||||
|
$this->storeTokenInSession($token);
|
||||||
|
|
||||||
|
return $this->redirectToRoute('app_reset_password');
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $this->getTokenFromSession();
|
||||||
|
|
||||||
|
if (null === $token) {
|
||||||
|
throw $this->createNotFoundException('No reset password token found in the URL or in the session.');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
/** @var WebrootUser $user */
|
||||||
|
$user = $this->resetPasswordHelper->validateTokenAndFetchUser($token);
|
||||||
|
} catch (ResetPasswordExceptionInterface $e) {
|
||||||
|
$this->addFlash('reset_password_error', sprintf(
|
||||||
|
'%s - %s',
|
||||||
|
$translator->trans(ResetPasswordExceptionInterface::MESSAGE_PROBLEM_VALIDATE, [], 'ResetPasswordBundle'),
|
||||||
|
$translator->trans($e->getReason(), [], 'ResetPasswordBundle')
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('app_forgot_password_request');
|
||||||
|
}
|
||||||
|
|
||||||
|
// The token is valid; allow the user to change their password.
|
||||||
|
$form = $this->createForm(ChangePasswordFormType::class);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
// A password reset token should be used only once, remove it.
|
||||||
|
$this->resetPasswordHelper->removeResetRequest($token);
|
||||||
|
|
||||||
|
/** @var string $plainPassword */
|
||||||
|
$plainPassword = $form->get('plainPassword')->getData();
|
||||||
|
|
||||||
|
// Encode(hash) the plain password, and set it.
|
||||||
|
$user->setPassword($passwordHasher->hashPassword($user, $plainPassword));
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
// The session is cleaned up after the password has been changed.
|
||||||
|
$this->cleanSessionAfterReset();
|
||||||
|
|
||||||
|
return $this->redirectToRoute('app_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('reset_password/reset.html.twig', [
|
||||||
|
'resetForm' => $form,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processSendingPasswordResetEmail(string $emailFormData, TransportInterface $mailer, TranslatorInterface $translator): RedirectResponse
|
||||||
|
{
|
||||||
|
$user = $this->entityManager->getRepository(WebrootUser::class)->findOneBy([
|
||||||
|
'email' => $emailFormData,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Do not reveal whether a user account was found or not.
|
||||||
|
if (!$user) {
|
||||||
|
return $this->redirectToRoute('app_check_email');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$resetToken = $this->resetPasswordHelper->generateResetToken($user);
|
||||||
|
} catch (ResetPasswordExceptionInterface $e) {
|
||||||
|
// If you want to tell the user why a reset email was not sent, uncomment
|
||||||
|
// the lines below and change the redirect to 'app_forgot_password_request'.
|
||||||
|
// Caution: This may reveal if a user is registered or not.
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
$this->addFlash('reset_password_error', sprintf(
|
||||||
|
'%s - %s',
|
||||||
|
$translator->trans(ResetPasswordExceptionInterface::MESSAGE_PROBLEM_HANDLE, [], 'ResetPasswordBundle'),
|
||||||
|
$translator->trans($e->getReason(), [], 'ResetPasswordBundle')
|
||||||
|
));
|
||||||
|
return $this->redirectToRoute('app_forgot_password_request');
|
||||||
|
*/
|
||||||
|
return $this->redirectToRoute('app_check_email');
|
||||||
|
}
|
||||||
|
|
||||||
|
$email = (new TemplatedEmail())
|
||||||
|
->from(new Address('noreply@mydevel.at',"MyDevel.at"))
|
||||||
|
->to((string) $user->getEmail())
|
||||||
|
->subject($translator->trans('Your password reset request',domain:'ResetPasswordBundle'))
|
||||||
|
->htmlTemplate($translator->trans('reset_password/email.html.twig',domain:'ResetPasswordBundle'))
|
||||||
|
->context([
|
||||||
|
'resetToken' => $resetToken,
|
||||||
|
'username' => $user->getUsername(),
|
||||||
|
])
|
||||||
|
;
|
||||||
|
|
||||||
|
$mailer->send($email);
|
||||||
|
|
||||||
|
// Store the token object in session for retrieval in check-email route.
|
||||||
|
$this->setTokenObjectInSession($resetToken);
|
||||||
|
|
||||||
|
return $this->redirectToRoute('app_check_email');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||||
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
|
|
||||||
use App\Controller\WebrootController;
|
use App\Controller\WebrootController;
|
||||||
|
|
||||||
@ -27,14 +28,20 @@ class SecurityController extends WebrootController
|
|||||||
'login_username' => $this->trans("login.username",domain:"security"),
|
'login_username' => $this->trans("login.username",domain:"security"),
|
||||||
'login_password' => $this->trans("login.password",domain:"security"),
|
'login_password' => $this->trans("login.password",domain:"security"),
|
||||||
'login_remember_me' => $this->trans("login.remember_me",domain:"security"),
|
'login_remember_me' => $this->trans("login.remember_me",domain:"security"),
|
||||||
|
'login_forgotten_password' => $this->trans("login.forgotten_password",domain:"security"),
|
||||||
'last_username' => $lastUsername,
|
'last_username' => $lastUsername,
|
||||||
'error' => $error,
|
'error' => $error,
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route(path: '/logout', name: 'app_logout')]
|
#[Route('/logout',name:'app_logout')]
|
||||||
public function logout(): void
|
public function logout(Security $security): Response
|
||||||
{
|
{
|
||||||
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
|
if ($this->getUser()) {
|
||||||
|
$response = $security->logout(false);
|
||||||
|
} else {
|
||||||
|
$response = $this->redirect("Login");
|
||||||
|
}
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,6 +122,7 @@ class SetupController extends WebrootSetupController
|
|||||||
|
|
||||||
$data= $this->getDataFromInitialSetupDataCookie($request);
|
$data= $this->getDataFromInitialSetupDataCookie($request);
|
||||||
$commands=$data["__commands__"];
|
$commands=$data["__commands__"];
|
||||||
|
$error=null;
|
||||||
|
|
||||||
if ($step >= count($commands)) {
|
if ($step >= count($commands)) {
|
||||||
return $this->redirectToRoute("app_login");
|
return $this->redirectToRoute("app_login");
|
||||||
@ -133,14 +134,26 @@ class SetupController extends WebrootSetupController
|
|||||||
$output = $this->trans("command.createdb",domain:"mydevel.webroot.setup");
|
$output = $this->trans("command.createdb",domain:"mydevel.webroot.setup");
|
||||||
try {
|
try {
|
||||||
$this->runCreateDatabase();
|
$this->runCreateDatabase();
|
||||||
|
$status="SUCCESS";
|
||||||
|
} catch (\Exception $ex) {
|
||||||
|
$status = "FAILED";
|
||||||
|
$status_message = $this->translate("command.failed",domain:"mydevel.webroot.setup");
|
||||||
|
$error = $ex->getMessage();
|
||||||
} catch (\Throwable $ex) {
|
} catch (\Throwable $ex) {
|
||||||
$status = "FAILED";
|
$status = "FAILED";
|
||||||
|
if (function_exists([$ex,'getMessage'])) {
|
||||||
|
$error=$ex->getMessage();
|
||||||
|
}
|
||||||
$status_message = $this->trans("command.failed",domain:"mydevel.webroot.setup");
|
$status_message = $this->trans("command.failed",domain:"mydevel.webroot.setup");
|
||||||
}
|
}
|
||||||
} elseif ($commands[$step] === "make-migrations") {
|
} elseif ($commands[$step] === "make-migrations") {
|
||||||
$output = $this->trans("command.makemigrations",domain:"mydevel.webroot.setup");
|
$output = $this->trans("command.makemigrations",domain:"mydevel.webroot.setup");
|
||||||
try {
|
try {
|
||||||
$this->runMakeMigration();
|
$this->runMakeMigration();
|
||||||
|
} catch (\Exception $ex) {
|
||||||
|
$status = "FAILED";
|
||||||
|
$status_message = $this->translate("command.failed",domain:"mydevel.webroot.setup");
|
||||||
|
$error = $ex->getMessage();
|
||||||
} catch (\Throwable $ex) {
|
} catch (\Throwable $ex) {
|
||||||
$status = "FAILED";
|
$status = "FAILED";
|
||||||
$status_message = $this->trans("command.success",domain:"mydevel.webroot.setup");
|
$status_message = $this->trans("command.success",domain:"mydevel.webroot.setup");
|
||||||
@ -149,6 +162,10 @@ class SetupController extends WebrootSetupController
|
|||||||
$output = $this->trans("command.migrate",domain:"mydevel.webroot.setup");
|
$output = $this->trans("command.migrate",domain:"mydevel.webroot.setup");
|
||||||
try {
|
try {
|
||||||
$this->runMigrate();
|
$this->runMigrate();
|
||||||
|
} catch (\Exception $ex) {
|
||||||
|
$status = "FAILED";
|
||||||
|
$status_message = $this->translate("command.failed",domain:"mydevel.webroot.setup");
|
||||||
|
$error = $ex->getMessage();
|
||||||
} catch (\Throwable $ex) {
|
} catch (\Throwable $ex) {
|
||||||
$status_message = $this->trans("command.failed",domain:"mydevel.webroot.setup");
|
$status_message = $this->trans("command.failed",domain:"mydevel.webroot.setup");
|
||||||
$status = "FAILED";
|
$status = "FAILED";
|
||||||
@ -161,9 +178,13 @@ class SetupController extends WebrootSetupController
|
|||||||
$this->addRootDir($data);
|
$this->addRootDir($data);
|
||||||
$status = "SUCCESS";
|
$status = "SUCCESS";
|
||||||
$status_message = $this->trans("command.success",domain:"mydevel.webroot.setup");
|
$status_message = $this->trans("command.success",domain:"mydevel.webroot.setup");
|
||||||
} catch (\Throwable $ex) {
|
} catch (\Exception $ex) {
|
||||||
$status = "FAILED";
|
$status = "FAILED";
|
||||||
$status_message = $this->translate("command.failed",domain:"mydevel.webroot.setup");
|
$status_message = $this->translate("command.failed",domain:"mydevel.webroot.setup");
|
||||||
|
$error = $ex->getMessage();
|
||||||
|
} catch (\throwable $ex) {
|
||||||
|
$status_message = $this->trans("command.failed");
|
||||||
|
$status = "FAILED";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$output = "Unknown command \"" . $commands[$step] . "\"";
|
$output = "Unknown command \"" . $commands[$step] . "\"";
|
||||||
@ -177,6 +198,7 @@ class SetupController extends WebrootSetupController
|
|||||||
'status' => $status,
|
'status' => $status,
|
||||||
'status_message' => $status_message,
|
'status_message' => $status_message,
|
||||||
'output' => $output,
|
'output' => $output,
|
||||||
|
'error' => $error,
|
||||||
'failed_button' => $this->trans("button.return-setup",domain:"mydevel.webroot.setup"),
|
'failed_button' => $this->trans("button.return-setup",domain:"mydevel.webroot.setup"),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,24 +4,34 @@ namespace App\Controller;
|
|||||||
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
use Symfony\Component\HttpKernel\KernelInterface;
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use App\Entity\WebrootFile;
|
||||||
use App\Utility\NullTranslator;
|
use App\Utility\NullTranslator;
|
||||||
|
use App\Component\Sorter\FileSortType;
|
||||||
|
use App\Component\Sorter\FileSorter;
|
||||||
|
|
||||||
abstract class WebrootController extends AbstractController
|
abstract class WebrootController extends AbstractController
|
||||||
{
|
{
|
||||||
private ?string $project_dir = null;
|
private ?string $project_dir = null;
|
||||||
private ?TranslatorInterface $tranlsator = null;
|
private ?TranslatorInterface $tranlsator = null;
|
||||||
|
private ?EntityManagerInterface $entitymanager = null;
|
||||||
protected ?NullTranslator $nulltranslator = null;
|
protected ?NullTranslator $nulltranslator = null;
|
||||||
|
|
||||||
|
|
||||||
public function __construct(KernelInterface $kernel,TranslatorInterface $translator)
|
public function __construct(KernelInterface $kernel,TranslatorInterface $translator,EntityManagerInterface $entitymanager)
|
||||||
{
|
{
|
||||||
|
$this->entity_manager = $entitymanager;
|
||||||
$this->project_dir = $kernel->getProjectDir();
|
$this->project_dir = $kernel->getProjectDir();
|
||||||
$this->translator = $translator;
|
$this->translator = $translator;
|
||||||
$this->nulltranslator = new NullTranslator();
|
$this->nulltranslator = new NullTranslator();
|
||||||
|
$this->entitymanager = $entitymanager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHeaderTitleFiglet(): ?string
|
public function getHeaderTitleFiglet(): ?string
|
||||||
@ -51,4 +61,306 @@ abstract class WebrootController extends AbstractController
|
|||||||
{
|
{
|
||||||
return $this->translator->trans($message,$args,domain:$domain,locale:$locale);
|
return $this->translator->trans($message,$args,domain:$domain,locale:$locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getFilePermissions(string $url): array
|
||||||
|
{
|
||||||
|
return $this->entitymanager->getRepository(WebrootFile::class)
|
||||||
|
->findFilePermissionsByUrl($this->getUser(),$url);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getFileResponse($abspath): Response
|
||||||
|
{
|
||||||
|
if (!is_file($abspath)) {
|
||||||
|
throw new FileException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = new BinaryFileResponse($abspath);
|
||||||
|
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_INLINE);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getAbspathByUrl(string $url): ?string
|
||||||
|
{
|
||||||
|
return $this->entitymanager
|
||||||
|
->getRepository(WebrootFile::class)
|
||||||
|
->findAbspathByUrl($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayFileSize(int $size): string
|
||||||
|
{
|
||||||
|
$display_size = "";
|
||||||
|
if ($size > 1073741824) {
|
||||||
|
$size_type = "GB";
|
||||||
|
|
||||||
|
$display_size .= ((int) ($size / 1073741824))
|
||||||
|
. "."
|
||||||
|
. ((int) ((($size % 1073741824) * 10) / 1073741824))
|
||||||
|
. " GiB";
|
||||||
|
} elseif ($size > 1048576) {
|
||||||
|
$display_size .= ((int) ($size / 1048576))
|
||||||
|
. "."
|
||||||
|
. ((int) ((($size % 1048576) * 10) / 1048576))
|
||||||
|
. " MiB";
|
||||||
|
} elseif ($size > 1024) {
|
||||||
|
$display_size .= ((int) ($size / 1024))
|
||||||
|
. "."
|
||||||
|
. ((int) ((($size % 1024) * 10) / 1024))
|
||||||
|
. " KiB";
|
||||||
|
} else {
|
||||||
|
$display_size .= $size . " B";
|
||||||
|
}
|
||||||
|
return $display_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayMtime(int $mtime): string
|
||||||
|
{
|
||||||
|
$dt = new \DateTime();
|
||||||
|
$dt->setTimestamp($mtime);
|
||||||
|
return $dt->format($this->trans("directory.timefmt",domain:'mydevel.webroot.app'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDirectoryList(string $url): array
|
||||||
|
{
|
||||||
|
$abspath = $this->getAbspathByUrl($url);
|
||||||
|
|
||||||
|
if (!$abspath || !is_dir($abspath)) {
|
||||||
|
throw new FileException();
|
||||||
|
}
|
||||||
|
$file_repos = $this->entitymanager->getRepository(WebrootFile::class);
|
||||||
|
$user = $this->getUser();
|
||||||
|
$roles = $user->getRoles();
|
||||||
|
if (in_array('ROLE_SUPERADMIN', $roles) || in_array('ROLE_ADMIN',$roles)) {
|
||||||
|
$show_dotfiles = true;
|
||||||
|
} else {
|
||||||
|
$show_dotfiles = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dirlist = [];
|
||||||
|
|
||||||
|
foreach (scandir($abspath) as $dirent) {
|
||||||
|
if ($dirent === '.' || $dirent === '..') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($dirent[0] === '.' && ! $show_dotfiles) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileurl = $url . '/' . urlencode($dirent);
|
||||||
|
$file_abspath = $abspath . DIRECTORY_SEPARATOR . $dirent;
|
||||||
|
$fileperm = $file_repos->findFilePermissionsByUrl($user,$fileurl);
|
||||||
|
|
||||||
|
if (!$fileperm['read']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$mtime = filemtime($file_abspath);
|
||||||
|
if (is_file($file_abspath)) {
|
||||||
|
$filesize = filesize($file_abspath);
|
||||||
|
|
||||||
|
$dirlist[] = [
|
||||||
|
"name" => $dirent,
|
||||||
|
"icon" => "icon-file",
|
||||||
|
"href" => $fileurl,
|
||||||
|
"size" => $filesize,
|
||||||
|
"display_size" => $this->getDisplayFileSize($filesize),
|
||||||
|
"delete" => $fileperm['delete'],
|
||||||
|
"write" => $fileperm['write'],
|
||||||
|
"mtime" => $mtime,
|
||||||
|
"display_mtime" => $this->getDisplayMtime($mtime),
|
||||||
|
"read" => true,
|
||||||
|
"dir" => false,
|
||||||
|
];
|
||||||
|
} elseif (is_dir($file_abspath)) {
|
||||||
|
$dirlist[] = [
|
||||||
|
"name" => $dirent,
|
||||||
|
"icon"=>"icon-directory",
|
||||||
|
"href" => $fileurl,
|
||||||
|
"size" => "0",
|
||||||
|
"display_size" => "-",
|
||||||
|
"delete" => $fileperm['delete'],
|
||||||
|
"write" => $fileperm['write'],
|
||||||
|
"mtime" => $mtime,
|
||||||
|
"display_mtime" => $this->getDisplayMtime($mtime),
|
||||||
|
"read" => true,
|
||||||
|
"dir" => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $dirlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDirectoryResponse(string $url,array $routeconf, FileSortType $sort=FileSortType::TYPE_ASC) : Response
|
||||||
|
{
|
||||||
|
$dirlist = $this->getDirectoryList($url);
|
||||||
|
$dirperm = $this->getFilePermissions($url);
|
||||||
|
if (!$dirperm['read']) {
|
||||||
|
throw AccessDeniedHttpException("You are not allowed to accesss this resource!");
|
||||||
|
}
|
||||||
|
|
||||||
|
$sort_url = [
|
||||||
|
"type" => $url . "?S=T;0=A",
|
||||||
|
"name" => $url . "?S=N;T=A",
|
||||||
|
"size" => $url . "?S=S;T=A",
|
||||||
|
"date" => $url . "?S=D;T=A",
|
||||||
|
];
|
||||||
|
|
||||||
|
$sorter = FileSorter::class;
|
||||||
|
switch ($sort) {
|
||||||
|
case FileSortType::TYPE_ASC:
|
||||||
|
uasort($dirlist,[$sorter,'sortTypeAsc']);
|
||||||
|
$sort_url["type"] = $url . "?S=T;O=D";
|
||||||
|
breaK;
|
||||||
|
case FileSortType::TYPE_DESC:
|
||||||
|
uasort($dirlist,[$sorter,'sortTypeDesc']);
|
||||||
|
break;
|
||||||
|
case FileSortType::NAME_ASC:
|
||||||
|
uasort($dirlist,[$sorter,'sortNameAsc']);
|
||||||
|
$sort_url["name"] = $url . "?S=N;O=D";
|
||||||
|
break;
|
||||||
|
case FileSortType::NAME_DESC:
|
||||||
|
uasort($dirlist,[$sorter,'sortNameDesc']);
|
||||||
|
break;
|
||||||
|
case FileSortType::SIZE_ASC:
|
||||||
|
uasort($dirlist,[$sorter,'sortSizeAsc']);
|
||||||
|
$sort_url["size"] = $url ."?S=S;O=D";
|
||||||
|
break;
|
||||||
|
case FileSortType::SIZE_DESC:
|
||||||
|
uasort($dirlist,[$sorter,'sortSizeDesc']);
|
||||||
|
break;
|
||||||
|
case FileSortType::DATE_ASC:
|
||||||
|
uasort($dirlist,[$sorter,'sortDateAsc']);
|
||||||
|
$sort_url["date"] = $url . "?S=D;O=D";
|
||||||
|
break;
|
||||||
|
case FileSortType::DATE_DESC:
|
||||||
|
uasort($dirlist,[$sorter,'sortDateDesc']);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('webroot/directory.html.twig', array_merge(
|
||||||
|
$this->getControllerVariables(), [
|
||||||
|
"msg"=> [
|
||||||
|
'filename' => $this->trans("directory.filename",domain:'mydevel.webroot.app'),
|
||||||
|
'mtime' => $this->trans("directory.mtime",domain:'mydevel.webroot.app'),
|
||||||
|
'filesize' => $this->trans("directory.filesize",domain:'mydevel.webroot.app'),
|
||||||
|
'title' => $this->trans("directory.title",["url"=>$url],domain:'mydevel.webroot.app'),
|
||||||
|
'deletedialog' => [
|
||||||
|
'title' => $this->trans("directory.delete-dialog.title",domain:'mydevel.webroot.app'),
|
||||||
|
'message' => $this->trans("directory.delete-dialog.message",domain:'mydevel.webroot.app'),
|
||||||
|
'button_delete' => $this->trans("button.delete",domain:'mydevel.webroot.app'),
|
||||||
|
'button_close' => $this->trans("button.cancel",domain:'mydevel.webroot.app'),
|
||||||
|
],
|
||||||
|
'mkdirdialog' => [
|
||||||
|
'title' => $this->trans('directory.mkdir.title',domain:'mydevel.webroot.app'),
|
||||||
|
'message' => $this->trans('directory.mkdir.message',domain:'mydevel.webroot.app'),
|
||||||
|
'button_create' => $this->trans('button.cancel',domain:'mydevel.webroot.app'),
|
||||||
|
'button_close' => $this->trans('button.create',domain:'mydevel.webroot.app'),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"parent_url"=>$routeconf['parent_url'],
|
||||||
|
"url"=>$url,
|
||||||
|
"read"=>$dirperm['read'],
|
||||||
|
"write"=>$dirperm['write'],
|
||||||
|
"delete"=>$dirperm['delete'],
|
||||||
|
"upload_url"=>($routeconf['path']
|
||||||
|
? $this->generateUrl($routeconf['upload_route'],["path"=>$routeconf['path']]) . "/"
|
||||||
|
: substr($this->generateUrl($routeconf['upload_route'],['path'=>"."]),0,-1)),
|
||||||
|
"mkdir_url"=>($routeconf['path']
|
||||||
|
? $this->generateUrl($routeconf['mkdir_route'],["path"=>$routeconf['path']]) . "/"
|
||||||
|
: substr($this->generateUrl($routeconf['mkdir_route'],['path'=>"."]),0,-1)),
|
||||||
|
"dir_entries"=>$dirlist,
|
||||||
|
"sort_url" => $sort_url,
|
||||||
|
]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseSort(?string $sort): FileSortType
|
||||||
|
{
|
||||||
|
if (!$sort) {
|
||||||
|
return FileSortType::TYPE_ASC;
|
||||||
|
}
|
||||||
|
$sa = explode(";",$sort);
|
||||||
|
$s0 = $sa[0];
|
||||||
|
if (sizeof($sa) > 1) {
|
||||||
|
$s1 = explode("=",$sa[1]);
|
||||||
|
if (sizeof($s1) !== 2) {
|
||||||
|
$s1 = ['O','A'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$s1 = ['O','A'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$ret = FileSortType::TYPE_ASC;
|
||||||
|
switch ($s0) {
|
||||||
|
case 'T':
|
||||||
|
switch ($s1[1]) {
|
||||||
|
case 'D':
|
||||||
|
$ret = FileSortType::TYPE_DESC;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
default:
|
||||||
|
$ret = FileSortType::TYPE_ASC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
switch ($s1[1]) {
|
||||||
|
case 'D':
|
||||||
|
$ret = FileSortType::NAME_DESC;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
default:
|
||||||
|
$ret = FileSortType::NAME_ASC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
switch ($s1[1]) {
|
||||||
|
case 'D':
|
||||||
|
$ret = FileSortType::SIZE_DESC;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
default:
|
||||||
|
$ret = FileSortType::SIZE_ASC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
switch ($s1[1]) {
|
||||||
|
case 'D':
|
||||||
|
$ret = FileSortType::DATE_DESC;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
default:
|
||||||
|
$ret = FileSortType::DATE_ASC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getUrlResponse(string $url,array $routeconf,FileSortType $sort= FileSortType::TYPE_ASC): Response
|
||||||
|
{
|
||||||
|
if (!$this->getFilePermissions($url)['read']) {
|
||||||
|
return $this->redirectToRoute("app_login",['_target_path'=> $url]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$abspath = $this->getAbspathByUrl($url);
|
||||||
|
|
||||||
|
if (!file_exists($abspath)) {
|
||||||
|
throw new NotFoundHttpException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_file($abspath)) {
|
||||||
|
return $this->getFileResponse($abspath);
|
||||||
|
}
|
||||||
|
if (is_dir($abspath)) {
|
||||||
|
return $this->getDirectoryResponse($url,$routeconf,$sort);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw FileException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -208,6 +208,54 @@ abstract class WebrootSetupController extends AbstractController
|
|||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function runCacheClear(): string
|
||||||
|
{
|
||||||
|
$application = new Application($this->kernel);
|
||||||
|
$application->setAutoExit(false);
|
||||||
|
|
||||||
|
$input = new ArrayInput([
|
||||||
|
"command" => "cache:clear",
|
||||||
|
"--no-interaction" => true,
|
||||||
|
"--quiet" => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$output = new BufferedOutput();
|
||||||
|
$errcode = $application->run($input,$output);
|
||||||
|
if ($errcode) {
|
||||||
|
throw new \Exception("runMigrate failed!\n". $output->fetch());
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $output->fetch();
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function runDatabaseUpdate(): string
|
||||||
|
{
|
||||||
|
$application = new Application($this->kernel);
|
||||||
|
$application->setAutoExit(false);
|
||||||
|
|
||||||
|
$input = new ArrayInput([
|
||||||
|
"command" => "doctrine:schema:update",
|
||||||
|
"--no-interaction" => true,
|
||||||
|
"--quiet" => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$output = new BufferedOutput();
|
||||||
|
$errcode = $application->run($input,$output);
|
||||||
|
if ($errcode) {
|
||||||
|
throw new \Exception("runMigrate failed!\n". $output->fetch());
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $output->fetch();
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getInitialRoles(bool $translated=true): array
|
public function getInitialRoles(bool $translated=true): array
|
||||||
{
|
{
|
||||||
@ -543,8 +591,9 @@ abstract class WebrootSetupController extends AbstractController
|
|||||||
|
|
||||||
public function getDataFromSetupForm(Form $form) : array
|
public function getDataFromSetupForm(Form $form) : array
|
||||||
{
|
{
|
||||||
$data=[];
|
$data=[
|
||||||
$data['env'] = $form->get('env')->getNormData();
|
'env' => $form->get('env')->getNormData()
|
||||||
|
];
|
||||||
|
|
||||||
$locale = $form->get('locale')->getNormData();
|
$locale = $form->get('locale')->getNormData();
|
||||||
if ($locale && strlen($locale)) {
|
if ($locale && strlen($locale)) {
|
||||||
@ -632,22 +681,23 @@ abstract class WebrootSetupController extends AbstractController
|
|||||||
if ($email_path && strlen($email_path)) {
|
if ($email_path && strlen($email_path)) {
|
||||||
$email["path"] = $email_path;
|
$email["path"] = $email_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
$email_user = $form->get("email_user")->getNormData();
|
$email_user = $form->get("email_user")->getNormData();
|
||||||
if ($email_user && strlen($email_user)) {
|
if ($email_user && strlen($email_user)) {
|
||||||
$email["user"] = $email_user;
|
$email["user"] = $email_user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$email_password = $form->get("email_password")->getNormData();
|
||||||
|
if ($email_password && strlen($email_password)) {
|
||||||
|
$email["password"] = $email_password;
|
||||||
|
}
|
||||||
$email_host = $form->get('email_host')->getNormData();
|
$email_host = $form->get('email_host')->getNormData();
|
||||||
if ($email_host && strlen($email_host)) {
|
if ($email_host && strlen($email_host)) {
|
||||||
$email["host"] = $email_host;
|
$email["host"] = $email_host;
|
||||||
}
|
}
|
||||||
|
|
||||||
$email_port = $form->get('email_port')->getNormData();
|
$email_port = $form->get('email_port')->getNormData();
|
||||||
if ($email_port && (int) $email_port) {
|
if ($email_port && (int) $email_port) {
|
||||||
$email["port"] = $email_port;
|
$email["port"] = $email_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
$email_dsn = $form->get('email_dsn')->getNormData();
|
$email_dsn = $form->get('email_dsn')->getNormData();
|
||||||
if ($email_dsn && strlen($email_dsn)) {
|
if ($email_dsn && strlen($email_dsn)) {
|
||||||
$email["dsn"] = $email_dsn;
|
$email["dsn"] = $email_dsn;
|
||||||
@ -749,7 +799,14 @@ abstract class WebrootSetupController extends AbstractController
|
|||||||
$response->headers->removeCookie(WebrootSetupController::INITIAL_SETUP_COOKIE,"/setup/");
|
$response->headers->removeCookie(WebrootSetupController::INITIAL_SETUP_COOKIE,"/setup/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function envencode(string $str): string
|
||||||
|
{
|
||||||
|
return preg_replace('/%/','%%',urlencode($str));
|
||||||
|
}
|
||||||
|
|
||||||
public function writeDotEnvLocal(array $data,bool $generate_app_secret=true) {
|
public function writeDotEnvLocal(array $data,bool $generate_app_secret=true) {
|
||||||
|
|
||||||
|
|
||||||
$file = fopen(join(DIRECTORY_SEPARATOR,[$this->project_dir,".env.local"]),"w");
|
$file = fopen(join(DIRECTORY_SEPARATOR,[$this->project_dir,".env.local"]),"w");
|
||||||
fwrite($file,"APP_ENV=" . $data["env"] . "\n");
|
fwrite($file,"APP_ENV=" . $data["env"] . "\n");
|
||||||
|
|
||||||
@ -764,7 +821,7 @@ abstract class WebrootSetupController extends AbstractController
|
|||||||
|
|
||||||
$db_backend=$data['database']['backend'];
|
$db_backend=$data['database']['backend'];
|
||||||
if ($db_backend === "sqlite") {
|
if ($db_backend === "sqlite") {
|
||||||
fwrite($file,"DATABASE_URL=\"sqlite://" . $data['database']['database'] . "\"\n");
|
fwrite($file,"DATABASE_URL=\"sqlite:///" . $data['database']['database'] . "\"\n");
|
||||||
} elseif ($db_backend === "mysql") {
|
} elseif ($db_backend === "mysql") {
|
||||||
fwrite($file,"DATABASE_URL=\"msysql://"
|
fwrite($file,"DATABASE_URL=\"msysql://"
|
||||||
. urlencode($data['database']['user'])
|
. urlencode($data['database']['user'])
|
||||||
@ -784,7 +841,29 @@ abstract class WebrootSetupController extends AbstractController
|
|||||||
} elseif ($db_backend === "url") {
|
} elseif ($db_backend === "url") {
|
||||||
fwrite($file,"DATABASE_URL=\"" . $data["database"]["url"] . "\"\n");
|
fwrite($file,"DATABASE_URL=\"" . $data["database"]["url"] . "\"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$mail_backend = $data["email"]["backend"];
|
||||||
|
if ($mail_backend === "none") {
|
||||||
|
$MAILER_DSN="null://null";
|
||||||
|
} elseif ($mail_backend === "smtp") {
|
||||||
|
$MAILER_DSN="smtp://"
|
||||||
|
. urlencode($data['email']['user'])
|
||||||
|
. ':' . urlencode($data['email']['password'])
|
||||||
|
. '@' . urlencode($data['email']['host'])
|
||||||
|
. ':' . $data['email']['port'];
|
||||||
|
} elseif ($mail_backend === "sendmail") {
|
||||||
|
$MAILER_DSN="sendmail://default";
|
||||||
|
} elseif ($mail_backend === "native") {
|
||||||
|
$MAILER_DSN="native://default";
|
||||||
|
} elseif ($mail_backend === "dsn") {
|
||||||
|
$MAILER_DSN=$data['email']['dsn'];
|
||||||
}
|
}
|
||||||
|
fwrite($file,"MAILER_DSN=\"" . $MAILER_DSN . "\"\n");
|
||||||
|
|
||||||
|
fclose($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected function addRoles()
|
protected function addRoles()
|
||||||
{
|
{
|
||||||
@ -804,6 +883,7 @@ abstract class WebrootSetupController extends AbstractController
|
|||||||
$user->setUsername($setup_data["user"]["username"]);
|
$user->setUsername($setup_data["user"]["username"]);
|
||||||
$user->setEmail($setup_data["user"]["email"]);
|
$user->setEmail($setup_data["user"]["email"]);
|
||||||
$user->setAdmin(true);
|
$user->setAdmin(true);
|
||||||
|
$user->setRoles(["ROLE_SUPERADMIN","ROLE_ADMIN","ROLE_USER"]);
|
||||||
$user->setPassword($setup_data["user"]["password"]);
|
$user->setPassword($setup_data["user"]["password"]);
|
||||||
$this->entitymanager->persist($user);
|
$this->entitymanager->persist($user);
|
||||||
$this->entitymanager->flush();
|
$this->entitymanager->flush();
|
||||||
@ -814,7 +894,7 @@ abstract class WebrootSetupController extends AbstractController
|
|||||||
->getRepository(WebrootUser::class)
|
->getRepository(WebrootUser::class)
|
||||||
->findByUsername($setup_data['user']['username']);
|
->findByUsername($setup_data['user']['username']);
|
||||||
$wrf = new WebrootFile();
|
$wrf = new WebrootFile();
|
||||||
$wrf->setUrl('/root');
|
$wrf->setUrl($this->generateUrl("app_webroot"));
|
||||||
$wrf->setAbspath($setup_data["site"]["rootdir"]);
|
$wrf->setAbspath($setup_data["site"]["rootdir"]);
|
||||||
$wrf->setOwner($admin);
|
$wrf->setOwner($admin);
|
||||||
$this->entitymanager->persist($wrf);
|
$this->entitymanager->persist($wrf);
|
||||||
@ -822,14 +902,26 @@ abstract class WebrootSetupController extends AbstractController
|
|||||||
$superadmin_role = $this->entitymanager
|
$superadmin_role = $this->entitymanager
|
||||||
->getRepository(WebrootRole::class)
|
->getRepository(WebrootRole::class)
|
||||||
->findByRolename("ROLE_SUPERADMIN");
|
->findByRolename("ROLE_SUPERADMIN");
|
||||||
|
|
||||||
$rootperm = new WebrootFilePermission();
|
$rootperm = new WebrootFilePermission();
|
||||||
$rootperm->setWebrootFile($wrf);
|
$rootperm->setWebrootFile($wrf);
|
||||||
$rootperm->setRole($superadmin_role);
|
$rootperm->setRole($superadmin_role);
|
||||||
$rootperm->setDeleteable(true);
|
$rootperm->setDeleteable(true);
|
||||||
$rootperm->setReadable(true);
|
$rootperm->setReadable(true);
|
||||||
$rootperm->setWriteable(false);
|
$rootperm->setWriteable(true);
|
||||||
|
|
||||||
$this->entitymanager->persist($rootperm);
|
$this->entitymanager->persist($rootperm);
|
||||||
|
|
||||||
|
$admin_role = $this->entitymanager
|
||||||
|
->getRepository(WebrootRole::class)
|
||||||
|
->findByRolename("ROLE_ADMIN");
|
||||||
|
$adminperm = new WebrootFilePermission();
|
||||||
|
$adminperm->setWebrootFile($wrf);
|
||||||
|
$adminperm->setRole($admin_role);
|
||||||
|
$adminperm->setReadable(true);
|
||||||
|
$adminperm->setWriteable(false);
|
||||||
|
$adminperm->setDeleteable(false);
|
||||||
|
$this->entitymanager->persist($adminperm);
|
||||||
|
|
||||||
$this->entitymanager->flush();
|
$this->entitymanager->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/Entity/ResetPasswordRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\ResetPasswordRequestRepository;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use SymfonyCasts\Bundle\ResetPassword\Model\ResetPasswordRequestInterface;
|
||||||
|
use SymfonyCasts\Bundle\ResetPassword\Model\ResetPasswordRequestTrait;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: ResetPasswordRequestRepository::class)]
|
||||||
|
class ResetPasswordRequest implements ResetPasswordRequestInterface
|
||||||
|
{
|
||||||
|
use ResetPasswordRequestTrait;
|
||||||
|
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[ORM\ManyToOne]
|
||||||
|
#[ORM\JoinColumn(nullable: false)]
|
||||||
|
private ?WebrootUser $user = null;
|
||||||
|
|
||||||
|
public function __construct(WebrootUser $user, \DateTimeInterface $expiresAt, string $selector, string $hashedToken)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->initialize($expiresAt, $selector, $hashedToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUser(): WebrootUser
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,6 +19,7 @@ class WebrootFile
|
|||||||
#[ORM\Column(length: 65535,nullable:false)]
|
#[ORM\Column(length: 65535,nullable:false)]
|
||||||
private ?string $url = null;
|
private ?string $url = null;
|
||||||
|
|
||||||
|
|
||||||
#[ORM\Column(length: 65535,nullable:false)]
|
#[ORM\Column(length: 65535,nullable:false)]
|
||||||
private ?string $abspath = null;
|
private ?string $abspath = null;
|
||||||
|
|
||||||
@ -46,12 +47,12 @@ class WebrootFile
|
|||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrl(): ?string
|
public function getUrlPath(): ?string
|
||||||
{
|
{
|
||||||
return $this->url;
|
return $this->url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUrl(string $url): static
|
public function setUrlPath(string $url): static
|
||||||
{
|
{
|
||||||
$this->url = $url;
|
$this->url = $url;
|
||||||
|
|
||||||
|
|||||||
@ -75,6 +75,7 @@ class WebrootUser implements UserInterface, PasswordAuthenticatedUserInterface
|
|||||||
$roles = $this->roles;
|
$roles = $this->roles;
|
||||||
// guarantee every user at least has ROLE_USER
|
// guarantee every user at least has ROLE_USER
|
||||||
$roles[] = 'ROLE_USER';
|
$roles[] = 'ROLE_USER';
|
||||||
|
$roles[] = 'ROLE_PUBLIC';
|
||||||
|
|
||||||
return array_unique($roles);
|
return array_unique($roles);
|
||||||
}
|
}
|
||||||
|
|||||||
58
src/Form/ChangePasswordFormType.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Form;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints\Length;
|
||||||
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
|
use Symfony\Component\Validator\Constraints\NotCompromisedPassword;
|
||||||
|
use Symfony\Component\Validator\Constraints\PasswordStrength;
|
||||||
|
|
||||||
|
class ChangePasswordFormType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('plainPassword', RepeatedType::class, [
|
||||||
|
'type' => PasswordType::class,
|
||||||
|
'options' => [
|
||||||
|
'attr' => [
|
||||||
|
'autocomplete' => 'new-password',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'first_options' => [
|
||||||
|
'constraints' => [
|
||||||
|
new NotBlank([
|
||||||
|
'message' => 'Please enter a password',
|
||||||
|
]),
|
||||||
|
new Length([
|
||||||
|
'min' => 12,
|
||||||
|
'minMessage' => 'Your password should be at least {{ limit }} characters',
|
||||||
|
// max length allowed by Symfony for security reasons
|
||||||
|
'max' => 4096,
|
||||||
|
]),
|
||||||
|
new PasswordStrength(),
|
||||||
|
new NotCompromisedPassword(),
|
||||||
|
],
|
||||||
|
'label' => 'New password',
|
||||||
|
],
|
||||||
|
'second_options' => [
|
||||||
|
'label' => 'Repeat Password',
|
||||||
|
],
|
||||||
|
'invalid_message' => 'The password fields must match.',
|
||||||
|
// Instead of being set onto the object directly,
|
||||||
|
// this is read and encoded in the controller
|
||||||
|
'mapped' => false,
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/Form/ResetPasswordRequestFormType.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Form;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
|
|
||||||
|
class ResetPasswordRequestFormType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('email', EmailType::class, [
|
||||||
|
'attr' => ['autocomplete' => 'email'],
|
||||||
|
'constraints' => [
|
||||||
|
new NotBlank([
|
||||||
|
'message' => 'Please enter your email',
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/Repository/ResetPasswordRequestRepository.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\ResetPasswordRequest;
|
||||||
|
use App\Entity\WebrootUser;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
use SymfonyCasts\Bundle\ResetPassword\Model\ResetPasswordRequestInterface;
|
||||||
|
use SymfonyCasts\Bundle\ResetPassword\Persistence\Repository\ResetPasswordRequestRepositoryTrait;
|
||||||
|
use SymfonyCasts\Bundle\ResetPassword\Persistence\ResetPasswordRequestRepositoryInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<ResetPasswordRequest>
|
||||||
|
*/
|
||||||
|
class ResetPasswordRequestRepository extends ServiceEntityRepository implements ResetPasswordRequestRepositoryInterface
|
||||||
|
{
|
||||||
|
use ResetPasswordRequestRepositoryTrait;
|
||||||
|
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, ResetPasswordRequest::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param WebrootUser $user
|
||||||
|
*/
|
||||||
|
public function createResetPasswordRequest(object $user, \DateTimeInterface $expiresAt, string $selector, string $hashedToken): ResetPasswordRequestInterface
|
||||||
|
{
|
||||||
|
return new ResetPasswordRequest($user, $expiresAt, $selector, $hashedToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,9 +3,11 @@
|
|||||||
namespace App\Repository;
|
namespace App\Repository;
|
||||||
|
|
||||||
use App\Entity\WebrootFile;
|
use App\Entity\WebrootFile;
|
||||||
|
use App\Entity\WebrootUser;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends ServiceEntityRepository<WebrootFile>
|
* @extends ServiceEntityRepository<WebrootFile>
|
||||||
*/
|
*/
|
||||||
@ -16,28 +18,102 @@ class WebrootFileRepository extends ServiceEntityRepository
|
|||||||
parent::__construct($registry, WebrootFile::class);
|
parent::__construct($registry, WebrootFile::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
public function findFilePermissionsByUrl(?WebrootUser $user,string $url): array
|
||||||
// * @return WebrootFile[] Returns an array of WebrootFile objects
|
{
|
||||||
// */
|
$paths_array= explode('/', $url);
|
||||||
// public function findByExampleField($value): array
|
$query_builder = $this->createQueryBuilder('f')
|
||||||
// {
|
->andWhere('f.url = :url');
|
||||||
// return $this->createQueryBuilder('w')
|
|
||||||
// ->andWhere('w.exampleField = :val')
|
|
||||||
// ->setParameter('val', $value)
|
|
||||||
// ->orderBy('w.id', 'ASC')
|
|
||||||
// ->setMaxResults(10)
|
|
||||||
// ->getQuery()
|
|
||||||
// ->getResult()
|
|
||||||
// ;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public function findOneBySomeField($value): ?WebrootFile
|
$ret = [
|
||||||
// {
|
'read'=>false,
|
||||||
// return $this->createQueryBuilder('w')
|
'write'=>false,
|
||||||
// ->andWhere('w.exampleField = :val')
|
'delete'=>false,
|
||||||
// ->setParameter('val', $value)
|
];
|
||||||
// ->getQuery()
|
|
||||||
// ->getOneOrNullResult()
|
if ($user) {
|
||||||
// ;
|
$roles = $user->getRoles();
|
||||||
// }
|
if (in_array('ROLE_SUPERADMIN',$roles)) {
|
||||||
|
return ['read'=>true,'write'=>true,'delete'=>true];
|
||||||
|
}
|
||||||
|
if (in_array('ROLE_ADMIN',$roles)) {
|
||||||
|
$ret['read'] = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$roles = ["ROLE_PUBLIC"];
|
||||||
|
}
|
||||||
|
|
||||||
|
while (sizeof($paths_array) > 1) {
|
||||||
|
$result = $query_builder->setParameter('url',join(DIRECTORY_SEPARATOR,$paths_array))
|
||||||
|
->getQuery()
|
||||||
|
->getOneOrNullResult();
|
||||||
|
if ($result) {
|
||||||
|
if ($user && $result->getOwner()->getId() === $user->getId()) {
|
||||||
|
return [['read'=>true,'write'=>true,'delete'=>true]];
|
||||||
|
}
|
||||||
|
foreach($result->getPermissions() as $perm) {
|
||||||
|
if (in_array($perm->getRole()->getRole(),$roles)) {
|
||||||
|
if ($perm->isReadable()) {
|
||||||
|
$ret['read'] = true;
|
||||||
|
}
|
||||||
|
if ($perm->isWriteable()) {
|
||||||
|
$ret['write'] = true;
|
||||||
|
}
|
||||||
|
if ($perm->isDeleteable()) {
|
||||||
|
$ret['delete'] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$paths_array = array_slice($paths_array,0,-1);
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findByUrl(string $url): ?WebrootFile
|
||||||
|
{
|
||||||
|
return $this->createQueryBuilder('f')
|
||||||
|
->andWhere('f.section = :sect')
|
||||||
|
->andWhere('f.url := url')
|
||||||
|
->setParameter('url', $url)
|
||||||
|
->getQuery()
|
||||||
|
->getOneOrNullResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findAbspathByUrl(string $url): ?string
|
||||||
|
{
|
||||||
|
$query_builder = $this->createQueryBuilder('f')
|
||||||
|
->andWhere('f.url = :url');
|
||||||
|
|
||||||
|
|
||||||
|
$url_array = explode('/',$url);
|
||||||
|
$path_extend=[];
|
||||||
|
while (sizeof($url_array) > 1) {
|
||||||
|
$result = $query_builder->setParameter('url',join('/',$url_array))
|
||||||
|
->getQuery()
|
||||||
|
->getOneOrNullResult();
|
||||||
|
if ($result) {
|
||||||
|
if (!sizeof($path_extend)) {
|
||||||
|
return $result->getAbspath();
|
||||||
|
} else {
|
||||||
|
$join_path = [$result->getAbspath()];
|
||||||
|
foreach (array_reverse($path_extend) as $xpath) {
|
||||||
|
$join_path[] = $xpath;
|
||||||
|
}
|
||||||
|
return join(DIRECTORY_SEPARATOR,$join_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$path_extend[] = array_pop($url_array);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findByAbspath(string $abspath): array
|
||||||
|
{
|
||||||
|
return $this->createQueryBuilder('f')
|
||||||
|
->andWhere('f.abspath = :val')
|
||||||
|
->setParameter('val', $abspath)
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
symfony.lock
@ -27,7 +27,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"easycorp/easyadmin-bundle": {
|
"easycorp/easyadmin-bundle": {
|
||||||
"version": "4.18",
|
"version": "4.9999999",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
"repo": "github.com/symfony/recipes",
|
"repo": "github.com/symfony/recipes",
|
||||||
"branch": "main",
|
"branch": "main",
|
||||||
@ -100,6 +100,18 @@
|
|||||||
"./.env"
|
"./.env"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"symfony/form": {
|
||||||
|
"version": "7.2",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "7.2",
|
||||||
|
"ref": "7d86a6723f4a623f59e2bf966b6aad2fc461d36b"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"./config/packages/csrf.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
"symfony/framework-bundle": {
|
"symfony/framework-bundle": {
|
||||||
"version": "6.4",
|
"version": "6.4",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
@ -258,16 +270,13 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"symfony/uid": {
|
"symfony/uid": {
|
||||||
"version": "6.4",
|
"version": "7.2",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
"repo": "github.com/symfony/recipes",
|
"repo": "github.com/symfony/recipes",
|
||||||
"branch": "main",
|
"branch": "main",
|
||||||
"version": "6.2",
|
"version": "7.0",
|
||||||
"ref": "d294ad4add3e15d7eb1bae0221588ca89b38e558"
|
"ref": "0df5844274d871b37fc3816c57a768ffc60a43a5"
|
||||||
},
|
}
|
||||||
"files": [
|
|
||||||
"./config/packages/uid.yaml"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"symfony/ux-turbo": {
|
"symfony/ux-turbo": {
|
||||||
"version": "2.21",
|
"version": "2.21",
|
||||||
@ -279,7 +288,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"symfony/ux-twig-component": {
|
"symfony/ux-twig-component": {
|
||||||
"version": "2.21",
|
"version": "2.22",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
"repo": "github.com/symfony/recipes",
|
"repo": "github.com/symfony/recipes",
|
||||||
"branch": "main",
|
"branch": "main",
|
||||||
@ -315,6 +324,18 @@
|
|||||||
"./config/routes/web_profiler.yaml"
|
"./config/routes/web_profiler.yaml"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"symfonycasts/reset-password-bundle": {
|
||||||
|
"version": "1.23",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "1.0",
|
||||||
|
"ref": "97c1627c0384534997ae1047b93be517ca16de43"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"./config/packages/reset_password.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
"twig/extra-bundle": {
|
"twig/extra-bundle": {
|
||||||
"version": "v3.15.0"
|
"version": "v3.15.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
{% block javascripts %}
|
{% block javascripts %}
|
||||||
{% block importmap %}{{ importmap('app') }}{% endblock %}
|
{% block importmap %}{{ importmap('app') }}{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block headscript %}{%endblock%}
|
||||||
</head>
|
</head>
|
||||||
<body style="margin:0px;padding:0px;">
|
<body style="margin:0px;padding:0px;">
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|||||||
@ -3,4 +3,11 @@
|
|||||||
<p>
|
<p>
|
||||||
You are logged in as <em>{{ user.username }}</em>.
|
You are logged in as <em>{{ user.username }}</em>.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
{% for role in user.roles %}
|
||||||
|
<li>{{ role }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
11
templates/reset_password/check_email.html.twig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Password Reset Email Sent{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<p>
|
||||||
|
If an account matching your email exists, then an email was just sent that contains a link that you can use to reset your password.
|
||||||
|
This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}.
|
||||||
|
</p>
|
||||||
|
<p>If you don't receive an email please check your spam folder or <a href="{{ path('app_forgot_password_request') }}">try again</a>.</p>
|
||||||
|
{% endblock %}
|
||||||
9
templates/reset_password/de.email.html.twig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<h1>Hi!</h1>
|
||||||
|
|
||||||
|
<p>Um Dein Passwort zurückzusetzen, besuche folgenden Link</p>
|
||||||
|
|
||||||
|
<a href="{{ url('app_reset_password', {token: resetToken.token}) }}">{{ url('app_reset_password', {token: resetToken.token}) }}</a>
|
||||||
|
|
||||||
|
<p>Der Link läuft in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }} ab.</p>
|
||||||
|
<p>Dein Nutzername falls du ihn vergessen hast: <em>{{ username }}</em></p>
|
||||||
|
<p>Mit freundlichen Grüßen das <em>{{ app.request.server.get('SITE_NAME') }} Team</em>!</p>
|
||||||
9
templates/reset_password/email.html.twig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<h1>Hi!</h1>
|
||||||
|
|
||||||
|
<p>To reset your password, please visit the following link</p>
|
||||||
|
|
||||||
|
<a href="{{ url('app_reset_password', {token: resetToken.token}) }}">{{ url('app_reset_password', {token: resetToken.token}) }}</a>
|
||||||
|
|
||||||
|
<p>This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}.</p>
|
||||||
|
<p> Your username in case you have forgotten it: <em>{{ username }}</em></p>
|
||||||
|
<p>Cheers! Your <em>{{ app.request.server.get("SITE_NAME")}} team</em>.</p>
|
||||||
22
templates/reset_password/request.html.twig
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Reset your password{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{% for flash_error in app.flashes('reset_password_error') %}
|
||||||
|
<div class="alert alert-danger" role="alert">{{ flash_error }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
<h1>Reset your password</h1>
|
||||||
|
|
||||||
|
{{ form_start(requestForm) }}
|
||||||
|
{{ form_row(requestForm.email) }}
|
||||||
|
<div>
|
||||||
|
<small>
|
||||||
|
Enter your email address, and we will send you a
|
||||||
|
link to reset your password.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn btn-primary">Send password reset email</button>
|
||||||
|
{{ form_end(requestForm) }}
|
||||||
|
{% endblock %}
|
||||||
12
templates/reset_password/reset.html.twig
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Reset your password{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<h1>Reset your password</h1>
|
||||||
|
|
||||||
|
{{ form_start(resetForm) }}
|
||||||
|
{{ form_row(resetForm.plainPassword) }}
|
||||||
|
<button class="btn btn-primary">Reset password</button>
|
||||||
|
{{ form_end(resetForm) }}
|
||||||
|
{% endblock %}
|
||||||
@ -41,9 +41,14 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
||||||
|
<p class="right"><a href="{{ path('app_forgot_password_request') }}">{{ login_forgotten_password }}</a></p>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<div class="full-width right">
|
||||||
<button class="btn btn-lg btn-primary" type="submit" class="right">{{ login_button }}</button>
|
<button class="btn btn-lg btn-primary" type="submit" class="right">{{ login_button }}</button>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -12,9 +12,9 @@ function initializeSetup() {
|
|||||||
let a = document.createElement("a");
|
let a = document.createElement("a");
|
||||||
a.setAttribute('href',"{{ setup_url }}");
|
a.setAttribute('href',"{{ setup_url }}");
|
||||||
a.setAttribute('class','button');
|
a.setAttribute('class','button');
|
||||||
a.innerText = "{{ failed_button }}"
|
a.innerText = "{{ failed_button }}";
|
||||||
elem.appendChild(a);
|
elem.appendChild(a);
|
||||||
console.log("LOADED")
|
console.log("LOADED");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -24,5 +24,8 @@ function initializeSetup() {
|
|||||||
<h1>Running Setup</h1>
|
<h1>Running Setup</h1>
|
||||||
<p>{{ output }} ... {{ status_message }}</p>
|
<p>{{ output }} ... {{ status_message }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
{% if error %}
|
||||||
|
<p class="error-message"><pre>{{ error }}</pre></p>
|
||||||
|
{% endif %}
|
||||||
<script>initializeSetup();</script>
|
<script>initializeSetup();</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
20
templates/webroot/controller.html.twig
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Hello MainController!{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<style>
|
||||||
|
.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
|
||||||
|
.example-wrapper code {var(--color-code-background); padding: 2px 6px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="example-wrapper">
|
||||||
|
<h1>Hello {{ controller_name }}! ✅</h1>
|
||||||
|
|
||||||
|
This friendly message is coming from:
|
||||||
|
<ul>
|
||||||
|
<li>Your controller at <code>{{ controller_class }}::{{ controller_function }}</code></li>
|
||||||
|
<li>Your template at <code>C:/msys64/home/c9mos/www/webroot/templates/webroot/controller.html.twig</code></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@ -3,16 +3,14 @@
|
|||||||
{% block body %}
|
{% block body %}
|
||||||
<h3>Index für <em>{{ url_path }}</em></h3>
|
<h3>Index für <em>{{ url_path }}</em></h3>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
{% if create_dir %}
|
{% if write %}
|
||||||
<span class="toolbar-item">
|
<span class="toolbar-item">
|
||||||
<a class="coolbar-button" href="{{ create_dir }}">
|
<a class="coolbar-button" href="{#{ create_dir }#}">
|
||||||
<img />
|
<img src="{{ asset('icon/create') }}"/>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
|
||||||
{% if upload_file %}
|
|
||||||
<span class="toolbar-item">
|
<span class="toolbar-item">
|
||||||
<a class="toolbar-button" href="{{ upload_file }}">
|
<a class="toolbar-button" href="{#{ upload_file }#}">
|
||||||
<img />
|
<img />
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
@ -20,17 +18,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<table><!-- Directory Index -->
|
<table><!-- Directory Index -->
|
||||||
<tr>
|
<tr>
|
||||||
<th class="td-color"><a href="{{ sort_standard_href }}"><img class="list-icon" alt="[icon]" width="32" height="32" src="/static/icons/empty.svg" /></a></th>
|
<th class="td-color"><a href="{#{ sort_standard_href }#}"><img class="list-icon" alt="[icon]" width="32" height="32" src="/static/icons/empty.svg" /></a></th>
|
||||||
<th class="td-color"><a href="{{ sort_name_href }}">Name</a></th>
|
<th class="td-color"><a href="{#{ sort_name_href }#}">Name</a></th>
|
||||||
<th class="td-color"><a href="{{ sort_size_href }}">Größe</a></th>
|
<th class="td-color"><a href="{#{ sort_size_href }#}">Größe</a></th>
|
||||||
<th class="td-color"><a href="{{ sort_time_href }}">Zuletzt geändert</a></th>
|
<th class="td-color"><a href="{#{ sort_time_href }#}">Zuletzt geändert</a></th>
|
||||||
<th class="td-color">Beschreibung</th>
|
<th class="td-color">Beschreibung</th>
|
||||||
<th class="td-color"></th>
|
<th class="td-color"></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td colspan="6"><strong><hr></strong></td></tr>
|
<tr><td colspan="6"><strong><hr></strong></td></tr>
|
||||||
{% if parent_url %}
|
{% if parent_url %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><img class="list-icom" width="24" height="24" alt="[icon]" src="/static/icons/back.svg" /></td>
|
<td><img class="list-icom" width="24" height="24" alt="[icon]" src="{{ '' }}/static/icons/back.svg" /></td>
|
||||||
<td><a href="{{ parent_url }}">Zurück</a></td>
|
<td><a href="{{ parent_url }}">Zurück</a></td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
|
|||||||
@ -1,59 +1,130 @@
|
|||||||
{% extends 'base.html.twig' %}
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
{% block body %}
|
{% block headscript %}
|
||||||
<h3>Index for <em>{{ url_path }}</em></h3>
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<h3>{{ msg.title }}</em></h3>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
{% if create_dir %}
|
{% if write %}
|
||||||
<span class="toolbar-item">
|
<span class="toolbar-item">
|
||||||
<a class="coolbar-button" href="{{ create_dir }}">
|
<button class="toolbar-button" onclick="dirCreateDialog('{{ url }}');">
|
||||||
<img />
|
<img class="icon-directory-new" width="32" height="32" alt="create-icon"/>
|
||||||
</a>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
|
||||||
{% if upload_file %}
|
|
||||||
<span class="toolbar-item">
|
<span class="toolbar-item">
|
||||||
<a class="toolbar-button" href="{{ upload_file }}">
|
<button class="toolbar-button" {# href="dirUploadDialog('{{ url }}');" #}>
|
||||||
<img />
|
<img class="icon-upload" alt="icon-upload" width="32" height="32"/>
|
||||||
</a>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<table><!-- Directory Index -->
|
<table class="full-width border-collapse"><!-- Directory Index -->
|
||||||
<tr>
|
<tr style="background-color:white;">
|
||||||
<th class="td-color"><a href="{{ sort_standard_href }}"><img class="list-icon" alt="[icon]" width="32" height="32" src="/static/icons/empty.svg" /></a></th>
|
<th class="shrink-to-fit"><a href="{{ sort_url.type }}"><img class="list-icon icon-empty" alt="[icon]" /></a></th>
|
||||||
<th class="td-color"><a href="{{ sort_name_href }}">Size</a></th>
|
<th class="fullwidth left"><a href="{{ sort_url.name }}">{{ msg.filename }}</a></th>
|
||||||
<th class="td-color"><a href="{{ sort_time_href }}">Last changed</a></th>
|
<th class="shrink-to-fit left"></th>
|
||||||
<th class="td-color">Description</th>
|
<th class="left"><a href="{{ sort_url.size }}">{{ msg.filesize }}</a></th>
|
||||||
<th class="td-color"></th>
|
<th class="left"><a href="{{ sort_url.date }}">{{ msg.mtime }}</a></th>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td colspan="6"><strong><hr></strong></td></tr>
|
|
||||||
{% if parent_url %}
|
{% if parent_url %}
|
||||||
<tr>
|
<tr class="tr-border-bottom">
|
||||||
<td><img class="list-icom" width="24" height="24" alt="[icon]" src="/static/icons/back.svg" /></td>
|
<td><a href="{{ parent_url }}"><img class="list-icon icon-back" alt="[icon]"/></a></td>
|
||||||
<td><a href="{{ parent_url }}">Zurück</a></td>
|
<td><a href="{{ parent_url }}">Back</a></td>
|
||||||
|
<td><img class="list-icon icon-empty" alt="[icon]"/></td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
<td>-</td>
|
|
||||||
<td><img class="list-icon" alt="icon" width="24" height="24" src="/static/icons/empty.svg" /></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for entry in dir_entries %}
|
{% for entry in dir_entries %}
|
||||||
<tr>
|
<tr class="tr-border-bottom">
|
||||||
<td>{% if entry.icon %}<img class="list-icon" alt="{{ entry.icon_alt }}" src="{{ entry.icon }}" width="24" height="24" />{% endif %}</td>
|
<td><img class="list-icon {{ entry.icon }}" alt="[icon]" width="20" height="20" /></td>
|
||||||
<td><a href="{{ entry.href }}">{{ entry.name }}</a></td>
|
<td><a href="{{ entry.href }}">{{ entry.name }}</a></td>
|
||||||
<td>{{ entry.display_size }}</td>
|
|
||||||
<td>{{ entry.last_modified }}</td>
|
|
||||||
<td>{{ entry.description }}</td>
|
|
||||||
<td>
|
<td>
|
||||||
{% if entry.delete %}
|
{% if entry.delete %}
|
||||||
<a href="{{ entry.delete }}"<img class="list-icon" alt="[delete]" width="24" height="24" src="/static/icons/delete.svg" /></a>
|
<button class="toolbar-button" onclick="fileDeleteDialog('{{ url }}','{{ entry.name }}');"><img class="list-icon icon-delete" alt="[icon]" /></button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<img class="list-icon" alt="" width="24" height="24" src="/static/icons/empty.svg">
|
<img class="list-icon icon-empty" alt="[icon]" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
<td class="shrink-to-fit">{{ entry.display_size }}</td>
|
||||||
|
<td class="shrink-to-fit">{{ entry.display_mtime }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr><td colspan="6"><strong><hr></strong></td></tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<dialog id="dir-create-dialog" style="width:420;position:fixed;left:calc(30%-220px);top:30%;">
|
||||||
|
<h4>{{ msg.mkdirdialog.title }}</h4>
|
||||||
|
<p>{{ msg.mkdirdialog.message }}</p>
|
||||||
|
<form>
|
||||||
|
<p>
|
||||||
|
<input id="dir-create-input" class="full-width" type="text" required />
|
||||||
|
</p>
|
||||||
|
<p class="right">
|
||||||
|
<button onclick="dirCreateDialogApply();">{{ msg.mkdirdialog.button_create }}</button>
|
||||||
|
<button onclick="dirCreateDialogClose();">{{ msg.mkdirdialog.button_close }}</button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog id="file-delete-dialog" style="width:420px;position:fixed;left:calc(50%-220px);top:30%;">
|
||||||
|
<h4>{{ msg.deletedialog.title }}</h4>
|
||||||
|
<p>{{ msg.deletedialog.message|raw }}</p>
|
||||||
|
<form>
|
||||||
|
<p>
|
||||||
|
<input id="file-delete-input" class="full-width" type="text" required />
|
||||||
|
</p>
|
||||||
|
<p class="right">
|
||||||
|
<button onclick="fileDeleteDialogApply();">{{ msg.deletedialog.button_delete }}</button>
|
||||||
|
<button onclick="fileDeleteDialogClose();">{{ msg.deletedialog.button_close }}</button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var dir_create_url='';
|
||||||
|
var file_delete_basename='';
|
||||||
|
var file_delete_url='';
|
||||||
|
|
||||||
|
|
||||||
|
function fileDeleteDialog(url,basename)
|
||||||
|
{
|
||||||
|
file_delete_basename=basename;
|
||||||
|
var dialog = document.getElementById("file-delete-dialog");
|
||||||
|
document.getElementById("file-delete-name").textContent=basename;
|
||||||
|
dialog.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileDeleteDialogClose()
|
||||||
|
{
|
||||||
|
let dialog = document.getElementById("file-delete-dialog");
|
||||||
|
dialog.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileDeleteDialogApply(event)
|
||||||
|
{
|
||||||
|
let dialog = document.getElementById('file-delete-dialog');
|
||||||
|
let input = document.getElementById('file-delete-input')
|
||||||
|
let input_value = input.value;
|
||||||
|
|
||||||
|
if (input_value === file_delete_basename) {
|
||||||
|
console.log("basename matches");
|
||||||
|
dialog.close();
|
||||||
|
} else {
|
||||||
|
console.log("No match");
|
||||||
|
input.value="";
|
||||||
|
dialog.showModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dirCreateDialog(url) {
|
||||||
|
dir_create_url = url;
|
||||||
|
let dialog = document.getElementById('dir-create-dialog');
|
||||||
|
dialog.showModal();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
13
translations/ResetPasswordBundle.de.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'%count% year|%count% years': '%count% Jahr|%count% Jahren'
|
||||||
|
'%count% month|%count% months': '%count% Monat|%count% Monaten'
|
||||||
|
'%count% day|%count% days': '%count% Tag|%count% Tagen'
|
||||||
|
'%count% hour|%count% hours': '%count% Stunde|%count% Stunden'
|
||||||
|
'%count% minute|%count% minutes': '%count% Minute|%count% Minuten'
|
||||||
|
'There was a problem validating your password reset request': 'Es gab ein Problem bei der Validierung Ihrer Anfrage zum Zurücksetzen des Passworts'
|
||||||
|
'There was a problem handling your password reset request': 'Es gab ein Problem bei der Bearbeitung Ihrer Anfrage zum Zurücksetzen des Passworts'
|
||||||
|
'The link in your email is expired. Please try to reset your password again.': 'Der Link in Ihrer E-Mail ist abgelaufen. Bitte versuchen Sie erneut, Ihr Passwort zurückzusetzen.'
|
||||||
|
'Please update the request_password_repository configuration in config/packages/reset_password.yaml to point to your "request password repository" service.': 'Bitte aktualisieren Sie die request_password_repository-Konfiguration in config/packages/reset_password.yaml, um auf Ihren "request password repository"-Dienst zu verweisen.'
|
||||||
|
'The reset password link is invalid. Please try to reset your password again.': 'Der Link zum Zurücksetzen des Passworts ist ungültig. Bitte versuchen Sie erneut, Ihr Passwort zurückzusetzen.'
|
||||||
|
'You have already requested a reset password email. Please check your email or try again soon.': 'Sie haben bereits eine E-Mail mit einem neuen Passwort angefordert. Bitte überprüfen Sie Ihre E-Mail oder versuchen Sie es später erneut.'
|
||||||
|
'Your password reset request': 'Dein Passwort zurücksetzen Anfrage'
|
||||||
|
reset_password/email.html.twig: reset_password/de.email.html.twig
|
||||||
13
translations/ResetPasswordBundle.en.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'%count% year|%count% years': '%count% year|%count% years'
|
||||||
|
'%count% month|%count% months': '%count% month|%count% months'
|
||||||
|
'%count% day|%count% days': '%count% day|%count% days'
|
||||||
|
'%count% hour|%count% hours': '%count% hour|%count% hours'
|
||||||
|
'%count% minute|%count% minutes': '%count% minute|%count% minutes'
|
||||||
|
'There was a problem validating your password reset request': 'There was a problem validating your password reset request'
|
||||||
|
'There was a problem handling your password reset request': 'There was a problem handling your password reset request'
|
||||||
|
'The link in your email is expired. Please try to reset your password again.': 'The link in your email is expired. Please try to reset your password again.'
|
||||||
|
'Please update the request_password_repository configuration in config/packages/reset_password.yaml to point to your "request password repository" service.': 'Please update the request_password_repository configuration in config/packages/reset_password.yaml to point to your "request password repository" service.'
|
||||||
|
'The reset password link is invalid. Please try to reset your password again.': 'The reset password link is invalid. Please try to reset your password again.'
|
||||||
|
'You have already requested a reset password email. Please check your email or try again soon.': 'You have already requested a reset password email. Please check your email or try again soon.'
|
||||||
|
'Your password reset request': 'Your password reset request'
|
||||||
|
reset_password/email.html.twig: reset_password/email.html.twig
|
||||||
12
translations/mydevel.webroot.app+intl-icu.de.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
directory:
|
||||||
|
timefmt: 'd.m.Y H:i:s'
|
||||||
|
filename: Dateiname
|
||||||
|
mtime: 'Zuletzt geändert'
|
||||||
|
filesize: Größe
|
||||||
|
title: 'Index für {url}'
|
||||||
|
delete-dialog:
|
||||||
|
title: "Datei löschen"
|
||||||
|
message: 'Wenn du wirklich die asugewählte Datei löschen willst, gib <em id="file-delete-name"></em> in das untere Feld ein.'
|
||||||
|
button:
|
||||||
|
delete: Löschen
|
||||||
|
close: Abbrechen
|
||||||
12
translations/mydevel.webroot.app+intl-icu.en.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
directory:
|
||||||
|
timefmt: 'Y.d.m H.i.s'
|
||||||
|
filename: Filename
|
||||||
|
mtime: 'Last changed'
|
||||||
|
filesize: Size
|
||||||
|
title: 'Index for {url}'
|
||||||
|
delete-dialog:
|
||||||
|
title: 'Delete file'
|
||||||
|
message: 'If you really want to delete the file or directory, type <em id=f"ile-delete-name"></em> into the field below!'
|
||||||
|
button:
|
||||||
|
delete: Delete
|
||||||
|
close: Close
|
||||||
@ -1,13 +0,0 @@
|
|||||||
role:
|
|
||||||
superadmin:
|
|
||||||
name: __role.superadmin.name
|
|
||||||
descr: __role.superadmin.descr
|
|
||||||
admin:
|
|
||||||
name: __role.admin.name
|
|
||||||
descr: __role.admin.descr
|
|
||||||
user:
|
|
||||||
name: __role.user.name
|
|
||||||
descr: __role.user.descr
|
|
||||||
public:
|
|
||||||
name: __role.public.name
|
|
||||||
descr: __role.public.descr
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
role:
|
|
||||||
superadmin:
|
|
||||||
name: __role.superadmin.name
|
|
||||||
descr: __role.superadmin.descr
|
|
||||||
admin:
|
|
||||||
name: __role.admin.name
|
|
||||||
descr: __role.admin.descr
|
|
||||||
user:
|
|
||||||
name: __role.user.name
|
|
||||||
descr: __role.user.descr
|
|
||||||
public:
|
|
||||||
name: __role.public.name
|
|
||||||
descr: __role.public.descr
|
|
||||||
@ -18,8 +18,9 @@
|
|||||||
'Too many failed login attempts, please try again in %minutes% minute.': 'Zu viele fehlgeschlagene Anmeldeversuche, bitte versuchen Sie es in einer Minute noch einmal.'
|
'Too many failed login attempts, please try again in %minutes% minute.': 'Zu viele fehlgeschlagene Anmeldeversuche, bitte versuchen Sie es in einer Minute noch einmal.'
|
||||||
'Too many failed login attempts, please try again in %minutes% minutes.': 'Zu viele fehlgeschlagene Anmeldeversuche, bitte versuchen Sie es in %minutes% Minuten noch einmal.'
|
'Too many failed login attempts, please try again in %minutes% minutes.': 'Zu viele fehlgeschlagene Anmeldeversuche, bitte versuchen Sie es in %minutes% Minuten noch einmal.'
|
||||||
login:
|
login:
|
||||||
title: "Bitte melde dich an"
|
title: 'Bitte melde dich an'
|
||||||
button: "Anmelden"
|
button: Anmelden
|
||||||
username: "Nutzername"
|
username: Nutzername
|
||||||
password: "Passwort"
|
password: Passwort
|
||||||
remember_me: "An mich erinnern"
|
remember_me: 'An mich erinnern'
|
||||||
|
forgotten_password: 'Passwort vergessen?'
|
||||||
|
|||||||
@ -18,8 +18,9 @@
|
|||||||
'Too many failed login attempts, please try again in %minutes% minute.': 'Too many failed login attempts, please try again in %minutes% minute.'
|
'Too many failed login attempts, please try again in %minutes% minute.': 'Too many failed login attempts, please try again in %minutes% minute.'
|
||||||
'Too many failed login attempts, please try again in %minutes% minutes.': 'Too many failed login attempts, please try again in %minutes% minutes.'
|
'Too many failed login attempts, please try again in %minutes% minutes.': 'Too many failed login attempts, please try again in %minutes% minutes.'
|
||||||
login:
|
login:
|
||||||
title: "Please sign in"
|
title: 'Please sign in'
|
||||||
button: "Log me in"
|
button: 'Log me in'
|
||||||
username: "Username"
|
username: Username
|
||||||
password: "Password"
|
password: Password
|
||||||
remember_me: "Remember me"
|
remember_me: 'Remember me'
|
||||||
|
forgotten_password: "Password forgotten?"
|
||||||
|
|||||||