2024.11.30 20:47:04

This commit is contained in:
Christian Moser 2024-11-30 20:47:04 +01:00
parent 6d540a6c71
commit c59655e513
18 changed files with 497 additions and 500 deletions

View File

@ -75,11 +75,11 @@
:root {
--color-black: #000000;
--color-white: #ffffff;
--color-background: #17150E;
--color-background: #191921;
--color-text: #E0D4A4;
--error-color: #FF2A1E;
--color-code-background: #383838;
--color-th-background: #383838;
--color-code-background: #3D3D3D;
--color-th-background: #3D3D3D;
--color-code: white;
--color-link-visited: #E496E7;
--color-link-normal: #4880E7;
@ -185,7 +185,7 @@ tr {
padding: 0px;
}
hr,vr {
hr {
color: var(--color-text);
}
@ -335,4 +335,12 @@ fieldset {
.margin-10 {
margin: 10px;
}
}
.command-output {
padding:10px;
height:20em;
width:800px;
background-color:var(--color-code-background);
color:white;
}

14
public/yaml_file Normal file
View File

@ -0,0 +1,14 @@
locale: de_AT
tempdir: \xampp\tmp\webroot
site:
name: webroot.cmoser.eu
email: webroot.cmoser.eu
rootdir: 'c:/msys64/home/c9mos/www/webroot'
user:
username: c9mos
email: christian@cmoser.eu
password: $2y$13$N2WGRMc/oEoaE5jdXBiYUejZjefjVTQwGNmdRCpIM5KT1Pv8kt.ku
email:
backend: dsn
address: christian@cmoser.eu
dsn: 'null://null'

View File

@ -6,6 +6,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Form\Extension\Core\Type as FormType;
@ -22,7 +23,7 @@ use App\Entity\WebrootFilePermission;
class SetupController extends WebrootSetupController
{
#[Route('/setup',name:'webroot.setup.initial')]
#[Route('/setup/initial',name:'webroot.initial-setup')]
public function initialSetup(Request $request,
EntityManagerInterface $em,
UserPasswordHasherInterface $passwd_hasher): Response
@ -30,21 +31,18 @@ class SetupController extends WebrootSetupController
$lang= getenv("LANG");
$dotenv_file = join(DIRECTORY_SEPARATOR,[$this->getProjectDir(),".env"]);
$dotenvlocal_file = join(DIRECTORY_SEPARATOR,[$this->getProjectDir(),".env.local"]);
$errors = array();
$errors = [];
if (!file_exists($dotenv_file)) {
$file = fopen($dotenv_file, "w", false);
fclose($file);
}
$command_output=['migration'=>"",'migrate'=>""];
$have_migration_output=false;
$translations=[
'email'=>$this->trans("setupform.section.email"),
'site' => $this->trans("setupform.section.site"),
'db' => $this->trans("setupform.section.database"),
'user' => $this->trans("setupform.section.user"),
'title' => $this->trans("setupform.title"),
'email'=>$this->trans("setupform.section.email",domain:"mydevel.webroot.setup"),
'site' => $this->trans("setupform.section.site",domain:"mydevel.webroot.setup"),
'db' => $this->trans("setupform.section.database",domain:"mydevel.webroot.setup"),
'user' => $this->trans("setupform.section.user",domain:"mydevel.webroot.setup"),
'title' => $this->trans("setupform.title",domain:"mydevel.webroot.setup"),
];
$form = $this->createSetupForm();
@ -69,81 +67,21 @@ class SetupController extends WebrootSetupController
"form" => $form,
"translations" => $translations,
"have_migration_output"=>false,
"command_output"=>$command_output]);
]);
}
$this->setSetupDataCookie($form);
$response = $this->redirectToRoute("webroot.initial-setup.run");
$this->setInitialSetupDataCookie($request,$form,$response);
(new Dotenv())->loadEnv(join(DIRECTORY_SEPARATOR,[$this->getProjectDir(),".env"]));
$this->redirectToRoute("webroot.setup.run");
/*
try {
$have_migration_output=true;
$command_output["migration"] = $this->runMakeMigration();
$create_database = $form->get('db_create')->getNormData();
if ($create_database) {
$command_output["create_database"] = $this->runCreateDatabase();
}
$command_output["migrate"] = $this->runMigrate();
$user = new WebrootUser();
$user->setAdmin(true);
$user->setUsername($form->get('user_username')->getNormData());
$user->setRoles(["ROLE_SUPERADMIN","ROLE_ADMIN","ROLE_USER"]);
$user->setEmail($form->get("user_email")->getNormData());
$user->setPassword($passwd_hasher->hashPassword($user, $password0));
$em->persist($user);
$em->flush();
foreach($this->getInitialRoles() as $roledata) {
$role = new WebrootRole();
$role->setRole($roledata["role"]);
$role->setName($roledata["name"]);
$role->setDescription($roledata["description"]);
$em->persist($role);
}
$em->flush();
$rootdir = $form->get("site_rootdir")->getNormData();
$db_rootdir = new WebrootFile();
$db_rootdir->setUrl("/weboot");
$db_rootdir->setPath($rootdir);
$db_rootdir->setDescription($webroot);
$em->persist($db_rootdir);
$em->flush();
$db_file_repos = $em->getRespository(WebrootFile::class);
$db_role_repos = $em->getRepository(WebroorRole::class);
$role = findByRoleName("ROLE_SUPERADMIN");
$perm = new App\Entity\WebrootFilePermission();
$perm->setWebrootFile($db_rootdir);
$perm->setReadable(true);
$perm->setWriteable(true);
$perm->setDeleteable(true);
$perm->setRole($role);
$rm->persist($perm);
$rm->flush();
return redirectToRoute("app_login");
} catch (\Exception $ex) {
array_push($errors,$ex->getMessage());
unlink($dotevnlocal);
throw $ex;
} finally {
}*/
return $response;
}
foreach ($form->getErrors() as $error) {
$errors[] = $error;
}
return $this->render('setup/initial-setup.html.twig', [
"form" => $form,
"errors" => $errors,
"translations" => $translations,
"have_migration_output"=>true,
"command_output"=>$command_output,
]);
}
@ -151,11 +89,11 @@ class SetupController extends WebrootSetupController
public function setup(): Response
{
if (!$this->isInstalled()) {
return redirectToRoute('webroot.setup.initial');
return $this->redirectToRoute('webroot.initial-setup');
}
if (!$this->userIsLoggedInAsAdmin()) {
return redirectToRoute("app_login");
return $this->redirectToRoute("app_login");
}
return $this->render('setup/controller.html.twig', [
@ -164,16 +102,31 @@ class SetupController extends WebrootSetupController
]);
}
#[ROUTE('/setup/inital/run',name:'setup.initial.run')]
#[ROUTE('/setup/inital/run',name:'webroot.initial-setup.run')]
public function setupInitialRun() : Response
{
return $this->render('setup/controller.html.twig', [
'controller_name' => "WebrootController",
'function' => __FUNCTION__,
//if (!$this->hasInitialSetupDataCookie()) {
// return new AccessDeniedHttpException();
//}
return $this->render('setup/initial-setup.run.html.twig', [
'setup_commands'=>[],
'extra' => print_r($_COOKIE),
'setup_url' => $this->generateUrl("webroot.initial-setup"),
'success_url' => $this->generateUrl("app_login"),
]);
}
#[Route('/setup/run/make-migration',name:'setup.initial.run.mkmigrations')]
#[ROUTE('/setup/initial/reste',name:'webroot.initial-setup.reset')]
public function setupInitialReset(): Response
{
if (!$this->hasInitialSetupDataCookie()) {
throw new AccessDeniedHttpException();
}
unlink(join(DIRECTORY_SEPARATOR,[$this->getProjectDir(),'.env.local']));
$this->redirectToRoute('webroot.initial-setup');
}
#[Route('/setup/run/make-migration',name:'webroot.setup.run.make-migrations')]
public function setupInitialRunMakeMigrations(): Response
{
if ($this->hasAdministrator()) {
@ -181,7 +134,7 @@ class SetupController extends WebrootSetupController
if (!$user.isAdmin()) {
return redirectToRoute("app_login");
}
} elseif (!isset($_COOKIE["--webroot-setup--"])) {
} elseif (!$this->hasInitialSetupDataCookie()) {
throw AccessDeniedException("You do not seem to be the Administrator");
}
@ -212,7 +165,7 @@ class SetupController extends WebrootSetupController
if (!$user.isAdmin()) {
return redirectToRoute("app_login");
}
} elseif (!isset($_COOKIE["--webroot-setup--"])) {
} elseif ($this->hasInitialSetupDataCookie()) {
throw AccessDeniedException("You do not seem to be the Administrator");
}
@ -235,7 +188,7 @@ class SetupController extends WebrootSetupController
return new Response($ret);
}
#[Route('/setup/run/createdb',name:'webroot.setup.run.createdb')]
#[Route('/setup/run/createdb',name:'webroot.initial-setup.run.createdb')]
public function createDatabase(): Response
{
if ($this->hasAdministrator()) {
@ -243,8 +196,9 @@ class SetupController extends WebrootSetupController
if (!$user.isAdmin()) {
return redirectToRoute("app_login");
}
} elseif (!isset($_COOKIE["--webroot-setup--"])) {
throw AccessDeniedException("You do not seem to be the Administrator");
}
if (!$this->hasInitialSetupDataCookie()) {
throw new AccessDeniedHttpException();
}
try {
@ -269,9 +223,6 @@ class SetupController extends WebrootSetupController
#[Route('/setup/login',name:'webroot.setup.login')]
public function login(): Response
{
return $this->render('setup/controller.html.twig', [
'controller_name' => "WebrootController",
'function' => __F0UNCTION__,
]);
return $this->redirectToRoute("app_login");
}
}

View File

@ -4,6 +4,8 @@ namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
@ -17,9 +19,14 @@ use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\Extension\Core\Type as FormType;
use Symfony\Component\Yaml\Yaml;
use Doctrine\ORM\EntityManagerInterface;
use App\Utility\NullTranslator;
use App\Utility;
use App\Entity\WebrootUser;
use App\Entity\WebrootRole;
use App\Entity\WebrootFilePermission;
use App\Entity\WebrootFile;
abstract class WebrootSetupController extends AbstractController
{
@ -29,22 +36,23 @@ abstract class WebrootSetupController extends AbstractController
*/
private ?KernelInterface $kernel = null;
private ?string $project_dir = null;
private ?UserPasswordHasherInterface $password_hasher;
private ?TranslatorInterface $translator;
private ?UserPasswordHasherInterface $password_hasher=null;
private ?TranslatorInterface $translator=null;
private ?EntityManagerInterface $entitymanager=null;
private ?NullTranslator $nulltranslator=null;
public function __construct(KernelInterface $kernel,
UserPasswordHasherInterface $password_hasher,
TranslatorInterface $translator) {
TranslatorInterface $translator,
EntityManagerInterface $entytymanager) {
$this->kernel = $kernel;
$this->project_dir = $kernel->getProjectDir();
$this->password_hasher = $password_hasher;
$this->translator = $translator;
Utility\gettext_lib_init(
WEBROOT_GETTEXT_DOMAIN,
join(DIRECTORY_SEPARATOR,[$this->project_dir,"translations"]),
getenv("LANG"));
$this->nulltranslator = new NullTranslator();
$this->entitymanager = $entytymanager;
}
/**
@ -198,191 +206,215 @@ abstract class WebrootSetupController extends AbstractController
}
public function getInitialRoles(): array
public function getInitialRoles(bool $translated=true): array
{
return [
[
"role"=>"ROLE_SUPERADMIN",
"name"=>$this->trans("role.superadmin.name",locale:'en'),
"description"=>$this->trans("role.superadmin.descr",locale:'en'),
],[
"role"=>"ROLE_ADMIN",
"name"=>$this->trans("role.admin.name",locale:'en'),
"description"=>$this->trans("role.admin.descr"),
],[
"role"=>"ROLE_USER",
"name"=>$this->trans("role.user.name",locale:'en'),
"description"=>$this->trans("role.user.descr",locale:'en'),
],[
"role"=>"ROLE_PUBLIC",
"name"=>$this->trans("role.public.name",locale:'en'),
"description"=>$this->trans("role.public.descr",locale:'en'),
],
];
$domain="mydevel.webroot";
if (0) {
//should never be executed just here to be able to tranlsate
$this->nulltrans->trans("webroot-user.name",domain:"mydevel.webroot.role");
$this->nulltrans->trans("webroot-user.decr",domain:"mydevel.webroot.role");
}
$roles = [
[
"role"=>"ROLE_SUPERADMIN",
"name"=>$this->nulltranslator->trans("superadmin.name",domain:"mydevel.webroot.role"),
"description"=>$this->nulltranslator->trans("superadmin.descr",domain:"mydevel.webroot.role"),
],[
"role"=>"ROLE_ADMIN",
"name"=>$this->nulltranslator->trans("admin.name",domain:"mydevel.webroot.role"),
"description"=>$this->nulltranslator->trans("admin.descr",domain:"mydevel.webroot.role"),
],[
"role"=>"ROLE_USER",
"name"=>$this->nulltranslator->trans("user.name",domain:"mydevel.webroot.role"),
"description"=>$this->nulltranslator->trans("user.descr",domain:"mydevel.webroot.role"),
],[
"role"=>"ROLE_PUBLIC",
"name"=>$this->nulltranslator->trans("public.name",domain:"mydevel.webroot.role"),
"description"=>$this->nulltranslator->trans("public.descr",domain:"mydevel.webroot.role"),
],
];
if (!$translated) {
return $roles;
}
$ret = [];
foreach ($roles as $role) {
$ret[] = [
"role" => $role["role"],
"name" => $this->trans($role["name"],domain:$domain),
"description" => $this->trans($role["description"],domain:$domain),
];
}
return $ret;
}
public function createSetupForm(): Form
{
return $this->createFormBuilder()
->add('env', FormType\ChoiceType::class,[
"label"=>$this->translator->trans("setupform.env.label"),
"label"=>$this->translator->trans("setupform.env.label",domain:"mydevel.webroot.setup"),
"mapped"=>false,
"required"=>true,
"help"=>$this->trans("setupform.env.help"),
"help"=>$this->trans("setupform.env.help",domain:"mydevel.webroot.setup"),
"choices"=>[
$this->translator->trans("setupform.env.choices.prod") => "prod",
$this->translator->trans("setupform.env.choices.dev") => "dev",
$this->translator->trans("setupform.env.choices.prod",domain:"mydevel.webroot.setup") => "prod",
$this->translator->trans("setupform.env.choices.dev",domain:"mydevel.webroot.setup") => "dev",
],
"attr"=>["class"=>"full-width"],
"data" => "prod"])
->add('locale',FormType\TextType::class,[
"mapped"=>false,
"label"=>$this->trans("setupform.locale.label"),
"help"=>$this->trans("setupform.locale.help"),
"label"=>$this->trans("setupform.locale.label",domain:"mydevel.webroot.setup"),
"help"=>$this->trans("setupform.locale.help",domain:"mydevel.webroot.setup"),
"required"=>false,
"attr"=>["class"=>"full-width"]])
->add('tempdir',FormType\TextType::class,[
"mapped"=>false,
"label"=>$this->trans("setupform.tempdir.label"),
"label"=>$this->trans("setupform.tempdir.label",domain:"mydevel.webroot.setup"),
"required"=>false,
"attr"=>["class"=>"full-width"]])
->add('site_name',FormType\TextType::class,[
"mapped"=>false,
"required"=>true,
"help"=>$this->trans("setupform.site.name.help"),
"label" => $this->trans("setupform.site.name.label"),
"help"=>$this->trans("setupform.site.name.help",domain:"mydevel.webroot.setup"),
"label" => $this->trans("setupform.site.name.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('site_rootdir',FormType\TextType::class,[
"mapped"=>false,
"required"=>true,
"help"=>$this->trans("setupform.site.root.help"),
"label" => $this->trans("setupform.site.root.label"),
"help"=>$this->trans("setupform.site.root.help",domain:"mydevel.webroot.setup"),
"label" => $this->trans("setupform.site.root.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('site_email',FormType\EmailType::class,[
"mapped"=>false,
"required"=>false,
"label" => $this->trans("setupform.site.email.label"),
"label" => $this->trans("setupform.site.email.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('user_username',FormType\TextType::class,[
"mapped"=>false,
"required"=>true,
"label"=>$this->trans("setupform.user.username.label"),
"label"=>$this->trans("setupform.user.username.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('user_email',FormType\EmailType::class,[
"mapped"=>false,
"required"=>true,
"label"=> $this->trans("setupform.user.email.label"),
"label"=> $this->trans("setupform.user.email.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add("user_password0", FormType\PasswordType::class,[
"mapped"=>false,
"required"=>true,
"label"=>$this->trans("setupform.user.password.label"),
"label"=>$this->trans("setupform.user.password.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add("user_password1",FormType\PasswordType::class,[
"mapped"=>false,
"required"=>true,
"label"=>$this->trans("setupform.user.confpasswd.label"),
"label"=>$this->trans("setupform.user.confpasswd.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('db_migrate', FormType\CheckboxType::class,[
"mapped"=>false,
"label"=>$this->trans("setupform.db.migrate.label"),
"label"=>$this->trans("setupform.db.migrate.label",domain:"mydevel.webroot.setup"),
"attr"=>["checked"=>true],
"required"=>false])
->add('db_create', FormType\CheckboxType::class,[
"mapped"=>false,
"label"=>$this->trans("setupform.db.create.label"),
"label"=>$this->trans("setupform.db.create.label",domain:"mydevel.webroot.setup"),
"required"=>false,
"attr"=>["checked"=>false]])
->add("db_mkmigrations", FormType\CheckboxType::class,[
"mapped"=>false,
"label"=>$this->trans("setupform.db.mkmigrations.label",domain:"mydevel.webroot.setup"),
"required"=>false,
"attr"=>["checked"=>false]])
->add('db_backend',FormType\ChoiceType::class,[
"mapped" => false,
"label" => $this->trans("setupform.db.backend.label"),
"label" => $this->trans("setupform.db.backend.label",domain:"mydevel.webroot.setup"),
"required" => true,
"choices" => [
$this->trans("setupform.db.backend.choices.sqlite")=>"sqlite",
$this->trans("setupform.db.backend.choices.mysql")=>"mysql",
$this->trans("setupform.db.backend.choices.portgesql")=>"postgresql",
$this->trans("setupform.db.backend.choices.url")=>"url",
$this->trans("setupform.db.backend.choices.sqlite",domain:"mydevel.webroot.setup")=>"sqlite",
$this->trans("setupform.db.backend.choices.mysql",domain:"mydevel.webroot.setup")=>"mysql",
$this->trans("setupform.db.backend.choices.portgesql",domain:"mydevel.webroot.setup")=>"postgresql",
$this->trans("setupform.db.backend.choices.url",domain:"mydevel.webroot.setup")=>"url",
],
"attr"=>["class"=>"full-width"]])
->add('db_database',FormType\TextType::class,[
"mapped"=>false,
"required"=>true,
"label"=>$this->trans("setupform.db.database.label"),
"label"=>$this->trans("setupform.db.database.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('db_host', FormType\TextType::class,[
"mapped"=>false,
"required"=>false,
"label"=>$this->trans("setupform.db.host.label"),
"label"=>$this->trans("setupform.db.host.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('db_port', FormType\IntegerType::class,[
"mapped"=>false,
"required"=>false,
"label"=>$this->trans("setupform.db.port.label"),
"label"=>$this->trans("setupform.db.port.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('db_user',FormType\TextType::class,[
"mapped"=>false,
"required"=>false,
"label"=>$this->trans("setupform.db.user.label"),
"label"=>$this->trans("setupform.db.user.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('db_password',FormType\TextType::class,[
"mapped"=>false,
"required"=>false,
"label"=>$this->trans("setupform.db.password.label"),
"label"=>$this->trans("setupform.db.password.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('db_url',FormType\TextType::class,[
"mapped"=>false,
"label"=>$this->trans("setupform.db.url.label"),
"label"=>$this->trans("setupform.db.url.label",domain:"mydevel.webroot.setup"),
"required"=>false,
"attr"=>["class"=>"full-width"]])
->add('email_backend', FormType\ChoiceType::class, [
"mapped"=>false,
"label" => $this->trans("setupform.email.backend.label"),
"label" => $this->trans("setupform.email.backend.label",domain:"mydevel.webroot.setup"),
"required"=>true,
"choices"=> [
$this->trans("setupform.email.backend.choices.none")=>"none",
$this->trans("setupform.email.backend.choices.smtp")=>"smtp",
$this->trans("setupform.email.backend.choices.sendmail")=>"sendmail",
$this->trans("setupform.email.backend.choices.native")=>"native",
$this->trans("setupform.email.backend.choices.dsn")=>"dsn",
$this->trans("setupform.email.backend.choices.none",domain:"mydevel.webroot.setup")=>"none",
$this->trans("setupform.email.backend.choices.smtp",domain:"mydevel.webroot.setup")=>"smtp",
$this->trans("setupform.email.backend.choices.sendmail",domain:"mydevel.webroot.setup")=>"sendmail",
$this->trans("setupform.email.backend.choices.native",domain:"mydevel.webroot.setup")=>"native",
$this->trans("setupform.email.backend.choices.dsn",domain:"mydevel.webroot.setup")=>"dsn",
],
"attr"=>["class"=>"full-width"]])
->add('email_path',FormType\TextType::class,[
"mapped"=>false,
"required"=>false,
"label"=>$this->trans("setupform.email.path.label"),
"label"=>$this->trans("setupform.email.path.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('email_user',FormType\TextType::class,[
"mapped"=>false,
"required"=>false,
"label"=>$this->trans("setupform.email.user.label"),
"label"=>$this->trans("setupform.email.user.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('email_password', FormType\PasswordType::class,[
"mapped"=>false,
"required"=>false,
"label"=> $this->trans("setupform.email.password.label"),
"label"=> $this->trans("setupform.email.password.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('email_host',FormType\TextType::class,[
"mapped"=>false,
"required"=>false,
"label"=>$this->trans("setupform.email.host.label"),
"label"=>$this->trans("setupform.email.host.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('email_port',FormType\TextType::class,[
"mapped"=>false,
"required"=>false,
"label"=>$this->trans("setupform.email.smtp-port.label"),
"label"=>$this->trans("setupform.email.smtp-port.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('email_dsn',FormType\TextType::class,[
"mapped"=>false,
"required"=>false,
"label"=>$this->trans("setupform.email.dsn.label"),
"label"=>$this->trans("setupform.email.dsn.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('email_address', FormType\EmailType::class,[
"mapped"=>false,
"required"=>true,
"label"=>$this->trans("setupform.email.sender.label"),
"label"=>$this->trans("setupform.email.sender.label",domain:"mydevel.webroot.setup"),
"attr"=>["class"=>"full-width"]])
->add('submit', FormType\SubmitType::class,[
"label"=>$this->trans("setupform.submit")])
"label"=>$this->trans("setupform.submit",domain:"mydevel.webroot.setup")])
->getForm();
}
@ -516,7 +548,8 @@ abstract class WebrootSetupController extends AbstractController
$site=[
"name" => $form->get("site_name")->getNormData(),
"email" => $form->get("site_name")->getNormData()
"email" => $form->get("site_name")->getNormData(),
"rootdir" => $form->get("site_rootdir")->getNormData(),
];
$data["site"] = $site;
@ -524,11 +557,11 @@ abstract class WebrootSetupController extends AbstractController
$tmp_user = new WebrootUser();
$user_username = $form->get('user_username')->getNormData();
if (!$username) {
$username="";
if (!$user_username) {
$user_username="";
}
$tmp_user->setUsername($username);
$user['username']=username;
$tmp_user->setUsername($user_username);
$user['username']=$user_username;
$user_email = $form->get('user_email')->getNormData();
if (!$user_email) {
@ -537,8 +570,8 @@ abstract class WebrootSetupController extends AbstractController
$tmp_user->setEmail($user_email);
$user['email'] = $user_email;
$password0 = $form->get('user_password0')->get('user_password0');
$password1 = $form->get('user_password1')->get('user_password1');
$password0 = $form->get('user_password0')->getData();
$password1 = $form->get('user_password1')->getData();
if ((strlen($password0) >= 8) && ($password0 == $password1)) {
$passwd = $this->password_hasher->hashPassword($tmp_user,$password0);
}
@ -550,11 +583,14 @@ abstract class WebrootSetupController extends AbstractController
$db = array();
$db["backend"] = $form->get("db_backend")->getNormData();
$db["make_migrations"] = $form->get("db_mkmigrations")->getNormData();
$db["migrate"] = $form->get("db_migrate")->getNormData();
$db["create"] = $form->get("db_create")->getNormData();
$db_url = $form->get('db_url')->getNormData();
if ($db_url && strlen($db_url)) {
$db['url'] = $db_url;
}
$db_database = $form->get('db_database')->getNormData();
if ($db_database && strlen($db_database)) {
$db["database"] = $db_database;
@ -575,7 +611,7 @@ abstract class WebrootSetupController extends AbstractController
if ($db_password && strlen($db_password)) {
$db['password'] = $db_password;
}
$data["user"] = user;
$data["user"] = $user;
$email = [
"backend" => $form->get("email_backend")->getNormData(),
@ -616,12 +652,12 @@ abstract class WebrootSetupController extends AbstractController
$data = (new Yaml())->dump($this->getDataFromSetupForm($form));
$file = fopen("yaml_file","w");
fwrite($file, $data);
$fclose($file);
fclose($file);
}
function generateRandomString($length = 10) : string
{
$x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_,;.:()[]{}!$&/=?+*<>|@';
$x_len=strlen($x);
$ret="";
@ -631,20 +667,56 @@ abstract class WebrootSetupController extends AbstractController
return ret;
}
public function setSetupFormFromFile(Form $form,string $yaml_file)
{
$this->setSetupFormFromData($form,(new Yaml())->parseFile($yaml_file));
protected function getDataFromFile(string $filename) {
}
public function setSetupDataCookie(Form $form): string
protected function setInitialSetupDataCookie(Request $request,Form $form,Response $response)
{
$old_file = filter_input($_COOKIE["--webroot-setup--"], FILTER_DEFAULT);
if ($old_file && strlen($old_file)) {
unlink($old_file);
if ($this->hasInitialSetupDataCookie()) {
$old_file = filter_input($_COOKIE["webroot-inital-setup"], FILTER_DEFAULT);
if ($old_file && strlen($old_file)) {
unlink($old_file);
}
}
$filename = tempnam($form->get("tempdir")->getNormData(),"wrsetup-");
$tempdir = $form->get("tempdir")->getNormData();
if (!file_exists($tempdir)) {
mkdir($tempdir);
}
$filename = tempnam($tempdir,"wis");
$cookie = new Cookie(
"webroot-initial-setup",
$filename,
0,
"/setup/",
$_SERVER["SERVER_NAME"],
$request->getScheme() === "https",
false,
true,
'Strict');
$this->exportSetupFormToFile($form, $filename);
setcookie("--webroot-setup--", $filename);
$response->headers->setCookie($cookie);
}
protected function getDataFromInitialSetupDataCookie(): ?array
{
if (!$this->hasInitialSetupDataCookie()) {
return null;
}
$data_cookie = filter_input($_COOKIE["webroot-initial-setup"],FILTER_DEFAULT);
if (!$data_cookie || !strlen($data_cookie)) {
return null;
}
return (new Yaml)->parseFile($data_cookie);
}
protected function hasInitialSetupDataCookie(): bool
{
if (key_exists("webroot-initial-setup", $_COOKIE)) {
$data_cookie = filter_input($_COOKIE["--webroot-initial-setup--"],FILTER_DEFAULT);
return ($data_cookie && strlen($data_cookie));
}
return false;
}
public function writePrivEnv(array $data,bool $generate_app_secret=true) {
@ -658,6 +730,7 @@ abstract class WebrootSetupController extends AbstractController
}
fwrite($file,"SITE_NAME=\"" . $data['site']['site_name'] . "\"\n");
fwrite($file,"SITE_EMAIL=\"". $data['site']['email'] . "\"\n");
fwrite($file,"SITE_ROOTDIR=\"" .$data['site']['rootdir'] ."\"\n");
$db_backend=$data['database']['backend'];
if ($db_backend === "sqlite") {
@ -682,4 +755,51 @@ abstract class WebrootSetupController extends AbstractController
fwrite($file,"DATABASE_URL=\"" . $data["database"]["url"] . "\"\n");
}
}
protected function addRoles()
{
foreach ($this->getInitialRoles(false) as $roledata) {
$role = new WebrootRole();
$role->setRole($roledata["role"]);
$role->setName($roledata["name"]);
$role->setDescription($roledata["description"]);
$this->entitymanager->persist($role);
}
$this->entitymanager->flush();
}
protected function addAdministrator(array $setup_data)
{
$user = new WebrootUser();
$user->setUsername($setup_data["user"]["username"]);
$user->setEmail($setup_data["user"]["email"]);
$user->setAdmin(true);
$user->setPassword($setup_data["user"]["password"]);
$this->entitymanager->persist($user);
$this->entitymanager->flush();
}
protected function addRootDir(array $setup_data) {
$admin = $this->entitymanager
->getRepository(WebrootUser::class)
->findByUsername($setup_data['user']['username']);
$wrf = new WebrootFile();
$wrf->setUrl('/root');
$wrf->setPath($setup_data["site"]["rootdir"]);
$wrf->setOwner($admin);
$this->entitymanager->persist($wrf);
$superadmin_role = $this->entitymanager
->getRepository(WebrootRole::class)
->findByRolename("ROLE_SUPERADMIN");
$rootperm = new WebrootFilePermission();
$rootperm->setWebrootFile($wrf);
$rootperm->setRole($superadmin_role);
$rootperm->setDeleteable(true);
$rootperm->setReadable(true);
$rootperm->setWriteable(false);
$this->entitymanager->persist($rootperm);
$this->entitymanager->flush();
}
}

View File

@ -16,7 +16,7 @@ class WebrootRoleRepository extends ServiceEntityRepository
parent::__construct($registry, WebrootRole::class);
}
public function findByRoleName(string $rolename): ?WebrootRole
public function findByRolename(string $rolename): ?WebrootRole
{
return $this->createQueryBuilder("wr")
->andWhere("wr.role = :val")

View File

@ -55,6 +55,23 @@ class WebrootUserRepository extends ServiceEntityRepository implements PasswordU
) > 0);
}
public function findByUsername($username): ?WebrootUser
{
return $this->createQueryBuilder("w")
->andWhere('w.username = :val')
->setParameter('val', $username)
->getQuery()
->getOneOrNullResult();
}
public function findByEmail($email): ?WebrootUser
{
return $this->createQueryBuilder("w")
->andWhere('w.email = :val')
->setParameter('val', $email)
->getQuery()
->getOneOrNullResult();
}
// public function findOneBySomeField($value): ?WebrootUser
// {

View File

@ -0,0 +1,10 @@
<?php
namespace App\Utility;
class NullTranslator
{
public function trans(string $message,array $args=[],?string $locale=null, ?string $domain=null): string
{
return message;
}
}

View File

@ -62,8 +62,14 @@
<legend><strong>{{ translations.db }}</strong></legend>
<table class="full-width">
<tr>
<td colspan="2" class="left">{{ form_widget(form.db_migrate) }} {{ form_label(form.db_migrate) }}</td>
<td colspan="2" class="left">{{ form_widget(form.db_create) }} {{ form_label(form.db_create) }}</td>
<td colspan="4" class="left">
<span>{{ form_widget(form.db_create) }}{{ form_label(form.db_create) }}</span>
<span style="height:16px;margin:15px;width:1px;border-left:2px solid;" />
<span style="margin-left:15px;">{{ form_widget(form.db_mkmigrations) }}{{ form_label(form.db_mkmigrations) }}</span>
<span style="height:16px;margin-left:12px;border-left:2px solid;" />
<span style="margin-left:15px;">{{ form_widget(form.db_migrate) }}{{ form_label(form.db_migrate) }}
</td>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.db_backend) }}</th>
<td>{{ form_widget(form.db_backend) }}</td>

View File

@ -2,71 +2,91 @@
{% block body %}
<script>
const setup_commands = [
for {{ cmd in setup_commands }}; do
{% for cmd in setup_commands %}
{ "url":{{ cmd.url }}, "output": {{ cmd.output }} },
{{ endfor }}
{% endfor %}
];
redirect_error="{{ setup_url }}";
let command_n = 0;
function endCommands(success) {
element = document.getElementById("setup-command");
let button = document.getElementById("commands-finished-button");
element = document.getElementById("command-code");
p = document.createElement("p");
if (success) {
p.innerText = "Commands executed successfully!";
button.onclick = onCommandsSuccess;
} else {
p.innerText = "Executing commands failed!";
button.onclick = onCommandsFailed;
button.innerText = "Return to setup";
}
element.appendChild(p);
console.log("Button Settings");
button.disabled=false;
}
function appendCommand(n) {
element = document.getElementById("setup-command");
element = document.getElementById("command-code");
p = document.createElement("p");
span = document.createElement("span");
span.innerText = setup_commands[n]["output"];
iframe = document.createElement("iframe");
iframe.setAttribute("id","setup-command-" + n);
iframe.setAttribute("onload","onCommandLoaded(n);");
iframe.setAttribute("onload","onCommandLoaded");
iframe.setAttribute("src",setup_commands[n]["url"]);
p.appendChild(span);
p.appendChild(iframe);
command_n = n;
}
function onCommandLoaded(n) {
let element = document.getElementById("setup-command");
function onCommandLoaded() {
let element = document.getElementById("command-code");
let cmd_iframe = document.getElementById("setup-command-" + n);
let cmd_result = iframe.contentWindow.document.getElementById("command-result");
if (cmd_result === "SUCCESS") {
next = n + 1;
next = command_n + 1;
if (n < setup_commands.length) {
appendCommand(next);
} else {
endCommands(true);
document.getElementById("commands-finished-button").removeAttribute("disabled");
}
} else {
endCommands(false);
let button = document.getElementById("commands-finished-button");
button.innerText("Return to setup");
button.removeAttribute("disabled");
}
}
function onCommandsSuccess()
{
location.replace('{{ success_url }}');
}
function onCommandsFailed()
{
location.replace('{{ setup_url }}');
}
function onCommandInit()
{
if (setup_commands.length > 0) {
appendCommand(0);
} else {
document.getElementById('commands-finished-button').disabled=true;
endCommands(true);
}
}
</script>
<h1>Running Setup</h1>
<div class="command-output">
<code id="setup-commands" onload="">
<code id="command-code" onload="">
<p id="null-command">Running commands...</p>
</code>
</div>
<button id="commands-finished-button" onclick="window.replace(\"{{ success_url }}\")" disabled>Finish</button>
<button id="commands-finished-button" onclick="onCommandsSuccess;">Finish</button>
<script>onCommandInit();</script>
{% endblock %}

View File

@ -1,92 +0,0 @@
'Email Settings': '__Email Settings'
'Site Settings': '__Site Settings'
'Database Settings': '__Database Settings'
'User Settings': '__User Settings'
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
setupform:
env:
label: __setupform.env.label
help: __setupform.env.help
choices:
prod: __setupform.env.choices.prod
dev: __setupform.env.choices.dev
locale:
label: __setupform.locale.label
help: __setupform.locale.help
tempdir:
label: __setupform.tempdir.label
site:
name:
help: __setupform.site.name.help
label: __setupform.site.name.label
root:
help: __setupform.site.root.help
label: __setupform.site.root.label
email:
label: __setupform.site.email.label
user:
username:
label: __setupform.user.username.label
email:
label: __setupform.user.email.label
password:
label: __setupform.user.password.label
confpasswd:
label: __setupform.user.confpasswd.label
db:
migrate:
label: __setupform.db.migrate.label
backend:
choices:
sqlite: __setupform.db.backend.choices.sqlite
mysql: __setupform.db.backend.choices.mysql
portgesql: __setupform.db.backend.choices.portgesql
url: __setupform.db.backend.choices.url
database:
label: __setupform.db.database.label
host:
label: __setupform.db.host.label
port:
label: __setupform.db.port.label
user:
label: __setupform.db.user.label
password:
label: __setupform.db.password.label
url:
label: __setupform.db.url.label
email:
backend:
choices:
none: __setupform.email.backend.choices.none
smtp: __setupform.email.backend.choices.smtp
sendmail: __setupform.email.backend.choices.sendmail
native: __setupform.email.backend.choices.native
dsn: __setupform.email.backend.choices.dsn
path:
label: __setupform.email.path.label
user:
label: __setupform.email.user.label
password:
label: __setupform.email.password.label
host:
label: __setupform.email.host.label
smtp-port:
label: __setupform.email.smtp-port.label
sender:
label: __setupform.email.sender.label
stupform:
db:
create:
label: __stupform.db.create.label

View File

@ -0,0 +1,13 @@
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

View File

@ -0,0 +1,13 @@
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

View File

@ -0,0 +1,15 @@
superadmin:
name: Superadministrator
descr: 'Superadministratoren sollen alle Rechte haben. (Um /setup/-Seiten aufrufen zu können ist allerdings der admin-Schalter im UserEntity zu setzen!)'
admin:
name: Administrator
descr: 'Role mit administrativen Rechten'
user:
name: Nutzer
descr: 'Gewöhnlicher Nutzer'
public:
name: Öffentlich
descr: 'Für öffentlich Zugangsrechte'
webroot-user:
name: 'Nutzer %username%'
decr: 'Rechte für Nutzer %username%.'

View File

@ -0,0 +1,15 @@
superadmin:
name: Superadministrator
descr: 'Superadministrator should have all rights. (For running Setup functions, the admin flag has to be set in the UserEntity!)'
admin:
name: Administrator
descr: 'Role with administrator rights'
user:
name: User
descr: 'An ordinary user'
public:
name: Public
descr: 'Role for public access rights'
webroot-user:
name: 'User-%username%'
decr: 'Rights für Nutzer %username%'

View File

@ -1,16 +1,3 @@
role:
superadmin:
name: Superadministrator
descr: 'Superadministrator hat alle Rechte.'
admin:
name: Administrator
descr: 'Rolle für Administrator rechte.'
user:
name: 'Common User'
descr: 'Standardnutzer Role'
public:
name: Public
descr: 'Role für öffentlichen Zugang'
setupform:
env:
label: Umgebung
@ -65,6 +52,8 @@ setupform:
label: URL/DSN
create:
label: 'Erstelle Datenbank'
mkmigrations:
label: 'Erstelle Migrationen'
email:
backend:
choices:

View File

@ -0,0 +1,86 @@
setupform:
env:
label: Environment
help: 'The Environment. Developent should only be used for development!'
choices:
prod: Production
dev: Development
locale:
label: Locale
help: 'The language the site is using'
tempdir:
label: Tempdir
site:
name:
help: 'The Site name to be displayed in titles'
label: 'Site name'
root:
help: 'The site root directory.'
label: Rootdir
email:
label: 'Contact email'
user:
username:
label: Username
email:
label: Email
password:
label: Password
confpasswd:
label: 'Confirm Password'
db:
migrate:
label: Migrate
backend:
choices:
sqlite: SQLite3
mysql: MySQL/MariaDB
portgesql: PostgreSQL
url: URL/DSN
label: Backend
database:
label: Database
host:
label: Host
port:
label: Port
user:
label: User
password:
label: Password
url:
label: URL/DSN
create:
label: 'Create database'
mkmigrations:
label: 'Make migrations'
email:
backend:
choices:
none: 'No email support'
smtp: SMTP
sendmail: Sendmail
native: Native
dsn: DSN
label: Backend
path:
label: Path
user:
label: User
password:
label: Password
host:
label: Host
smtp-port:
label: 'SMTP port'
sender:
label: 'Sender email'
dsn:
label: DSN
section:
email: 'Email support'
site: 'Site settings'
database: Database
user: 'New Adminitrator'
title: 'Setup Webroot'
submit: 'Run setup'

View File

@ -1 +0,0 @@
Error: Fehler

View File

@ -1,187 +0,0 @@
'This value should be false.': 'This value should be false.'
'This value should be true.': 'This value should be true.'
'This value should be of type {{ type }}.': 'This value should be of type {{ type }}.'
'This value should be blank.': 'This value should be blank.'
'The value you selected is not a valid choice.': 'The value you selected is not a valid choice.'
'You must select at least {{ limit }} choice':
'|You must select at least {{ limit }} choices.': 'You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.'
'You must select at most {{ limit }} choice':
'|You must select at most {{ limit }} choices.': 'You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices.'
'One or more of the given values is invalid.': 'One or more of the given values is invalid.'
'This field was not expected.': 'This field was not expected.'
'This field is missing.': 'This field is missing.'
'This value is not a valid date.': 'This value is not a valid date.'
'This value is not a valid datetime.': 'This value is not a valid datetime.'
'This value is not a valid email address.': 'This value is not a valid email address.'
'The file could not be found.': 'The file could not be found.'
'The file is not readable.': 'The file is not readable.'
'The file is too large ({{ size }} {{ suffix }})':
' Allowed maximum size is {{ limit }} {{ suffix }}.': 'The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}.'
'The mime type of the file is invalid ({{ type }})':
' Allowed mime types are {{ types }}.': 'The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}.'
'This value should be {{ limit }} or less.': 'This value should be {{ limit }} or less.'
'This value is too long':
' It should have {{ limit }} character or less':
'|This value is too long':
' It should have {{ limit }} characters or less.': 'This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.'
' It should contain one word':
'|This value is too long':
' It should contain {{ max }} words or less.': 'This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less.'
'This value should be {{ limit }} or more.': 'This value should be {{ limit }} or more.'
'This value is too short':
' It should have {{ limit }} character or more':
'|This value is too short':
' It should have {{ limit }} characters or more.': 'This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.'
' It should contain at least one word':
'|This value is too short':
' It should contain at least {{ min }} words.': 'This value is too short. It should contain at least one word.|This value is too short. It should contain at least {{ min }} words.'
'This value should not be blank.': 'This value should not be blank.'
'This value should not be null.': 'This value should not be null.'
'This value should be null.': 'This value should be null.'
'This value is not valid.': 'This value is not valid.'
'This value is not a valid time.': 'This value is not a valid time.'
'This value is not a valid URL.': 'This value is not a valid URL.'
'The two values should be equal.': 'The two values should be equal.'
'The file is too large':
' Allowed maximum size is {{ limit }} {{ suffix }}.': 'The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.'
'The file is too large.': 'The file is too large.'
'The file could not be uploaded.': 'The file could not be uploaded.'
'This value should be a valid number.': 'This value should be a valid number.'
'This file is not a valid image.': 'This file is not a valid image.'
'This is not a valid IP address.': 'This value is not a valid IP address.'
'This value is not a valid language.': 'This value is not a valid language.'
'This value is not a valid locale.': 'This value is not a valid locale.'
'This value is not a valid country.': 'This value is not a valid country.'
'This value is already used.': 'This value is already used.'
'The size of the image could not be detected.': 'The size of the image could not be detected.'
'The image width is too big ({{ width }}px)':
' Allowed maximum width is {{ max_width }}px.': 'The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px.'
'The image width is too small ({{ width }}px)':
' Minimum width expected is {{ min_width }}px.': 'The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px.'
'The image height is too big ({{ height }}px)':
' Allowed maximum height is {{ max_height }}px.': 'The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px.'
'The image height is too small ({{ height }}px)':
' Minimum height expected is {{ min_height }}px.': 'The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px.'
"This value should be the user's current password.": "This value should be the user's current password."
'This value should have exactly {{ limit }} character':
'|This value should have exactly {{ limit }} characters.': 'This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.'
'The file was only partially uploaded.': 'The file was only partially uploaded.'
'No file was uploaded.': 'No file was uploaded.'
'No temporary folder was configured in php':
ini.: 'No temporary folder was configured in php.ini, or the configured folder does not exist.'
'Cannot write temporary file to disk.': 'Cannot write temporary file to disk.'
'A PHP extension caused the upload to fail.': 'A PHP extension caused the upload to fail.'
'This collection should contain {{ limit }} element or more':
'|This collection should contain {{ limit }} elements or more.': 'This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.'
'This collection should contain {{ limit }} element or less':
'|This collection should contain {{ limit }} elements or less.': 'This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.'
'This collection should contain exactly {{ limit }} element':
'|This collection should contain exactly {{ limit }} elements.': 'This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.'
'Invalid card number.': 'Invalid card number.'
'Unsupported card type or invalid card number.': 'Unsupported card type or invalid card number.'
'This is not a valid International Bank Account Number (IBAN).': 'This value is not a valid International Bank Account Number (IBAN).'
'This value is not a valid ISBN-10.': 'This value is not a valid ISBN-10.'
'This value is not a valid ISBN-13.': 'This value is not a valid ISBN-13.'
'This value is neither a valid ISBN-10 nor a valid ISBN-13.': 'This value is neither a valid ISBN-10 nor a valid ISBN-13.'
'This value is not a valid ISSN.': 'This value is not a valid ISSN.'
'This value is not a valid currency.': 'This value is not a valid currency.'
'This value should be equal to {{ compared_value }}.': 'This value should be equal to {{ compared_value }}.'
'This value should be greater than {{ compared_value }}.': 'This value should be greater than {{ compared_value }}.'
'This value should be greater than or equal to {{ compared_value }}.': 'This value should be greater than or equal to {{ compared_value }}.'
'This value should be identical to {{ compared_value_type }} {{ compared_value }}.': 'This value should be identical to {{ compared_value_type }} {{ compared_value }}.'
'This value should be less than {{ compared_value }}.': 'This value should be less than {{ compared_value }}.'
'This value should be less than or equal to {{ compared_value }}.': 'This value should be less than or equal to {{ compared_value }}.'
'This value should not be equal to {{ compared_value }}.': 'This value should not be equal to {{ compared_value }}.'
'This value should not be identical to {{ compared_value_type }} {{ compared_value }}.': 'This value should not be identical to {{ compared_value_type }} {{ compared_value }}.'
'The image ratio is too big ({{ ratio }})':
' Allowed maximum ratio is {{ max_ratio }}.': 'The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}.'
'The image ratio is too small ({{ ratio }})':
' Minimum ratio expected is {{ min_ratio }}.': 'The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}.'
'The image is square ({{ width }}x{{ height }}px)':
' Square images are not allowed.': 'The image is square ({{ width }}x{{ height }}px). Square images are not allowed.'
'The image is landscape oriented ({{ width }}x{{ height }}px)':
' Landscape oriented images are not allowed.': 'The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed.'
'The image is portrait oriented ({{ width }}x{{ height }}px)':
' Portrait oriented images are not allowed.': 'The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed.'
'An empty file is not allowed.': 'An empty file is not allowed.'
'The host could not be resolved.': 'The host could not be resolved.'
'This value does not match the expected {{ charset }} charset.': 'This value does not match the expected {{ charset }} charset.'
'This is not a valid Business Identifier Code (BIC).': 'This value is not a valid Business Identifier Code (BIC).'
Error: Error
'This is not a valid UUID.': 'This value is not a valid UUID.'
'This value should be a multiple of {{ compared_value }}.': 'This value should be a multiple of {{ compared_value }}.'
'This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.': 'This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.'
'This value should be valid JSON.': 'This value should be valid JSON.'
'This collection should contain only unique elements.': 'This collection should contain only unique elements.'
'This value should be positive.': 'This value should be positive.'
'This value should be either positive or zero.': 'This value should be either positive or zero.'
'This value should be negative.': 'This value should be negative.'
'This value should be either negative or zero.': 'This value should be either negative or zero.'
'This value is not a valid timezone.': 'This value is not a valid timezone.'
'This password has been leaked in a data breach, it must not be used':
' Please use another password.': 'This password has been leaked in a data breach, it must not be used. Please use another password.'
'This value should be between {{ min }} and {{ max }}.': 'This value should be between {{ min }} and {{ max }}.'
'This value is not a valid hostname.': 'This value is not a valid hostname.'
'The number of elements in this collection should be a multiple of {{ compared_value }}.': 'The number of elements in this collection should be a multiple of {{ compared_value }}.'
'This value should satisfy at least one of the following constraints:': 'This value should satisfy at least one of the following constraints:'
'Each element of this collection should satisfy its own set of constraints.': 'Each element of this collection should satisfy its own set of constraints.'
'This value is not a valid International Securities Identification Number (ISIN).': 'This value is not a valid International Securities Identification Number (ISIN).'
'This value should be a valid expression.': 'This value should be a valid expression.'
'This value is not a valid CSS color.': 'This value is not a valid CSS color.'
'This value is not a valid CIDR notation.': 'This value is not a valid CIDR notation.'
'The value of the netmask should be between {{ min }} and {{ max }}.': 'The value of the netmask should be between {{ min }} and {{ max }}.'
'The filename is too long':
' It should have {{ filename_max_length }} character or less':
'|The filename is too long':
' It should have {{ filename_max_length }} characters or less.': 'The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less.'
'The password strength is too low':
' Please use a stronger password.': 'The password strength is too low. Please use a stronger password.'
'This value contains characters that are not allowed by the current restriction-level.': 'This value contains characters that are not allowed by the current restriction-level.'
'Using invisible characters is not allowed.': 'Using invisible characters is not allowed.'
'Mixing numbers from different scripts is not allowed.': 'Mixing numbers from different scripts is not allowed.'
'Using hidden overlay characters is not allowed.': 'Using hidden overlay characters is not allowed.'
'The extension of the file is invalid ({{ extension }})':
' Allowed extensions are {{ extensions }}.': 'The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}.'
'The detected character encoding is invalid ({{ detected }})':
' Allowed encodings are {{ encodings }}.': 'The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}.'
'This value is not a valid MAC address.': 'This value is not a valid MAC address.'
'This URL is missing a top-level domain.': 'This URL is missing a top-level domain.'
'This value does not represent a valid week in the ISO 8601 format.': 'This value does not represent a valid week in the ISO 8601 format.'
'This value is not a valid week.': 'This value is not a valid week.'
'This value should not be before week "{{ min }}".': 'This value should not be before week "{{ min }}".'
'This value should not be after week "{{ max }}".': 'This value should not be after week "{{ max }}".'
'This form should not contain extra fields.': 'This form should not contain extra fields.'
'The uploaded file was too large':
' Please try to upload a smaller file.': 'The uploaded file was too large. Please try to upload a smaller file.'
'The CSRF token is invalid':
' Please try to resubmit the form.': 'The CSRF token is invalid. Please try to resubmit the form.'
'This value is not a valid HTML5 color.': 'This value is not a valid HTML5 color.'
'Please enter a valid birthdate.': 'Please enter a valid birthdate.'
'The selected choice is invalid.': 'The selected choice is invalid.'
'The collection is invalid.': 'The collection is invalid.'
'Please select a valid color.': 'Please select a valid color.'
'Please select a valid country.': 'Please select a valid country.'
'Please select a valid currency.': 'Please select a valid currency.'
'Please choose a valid date interval.': 'Please choose a valid date interval.'
'Please enter a valid date and time.': 'Please enter a valid date and time.'
'Please enter a valid date.': 'Please enter a valid date.'
'Please select a valid file.': 'Please select a valid file.'
'The hidden field is invalid.': 'The hidden field is invalid.'
'Please enter an integer.': 'Please enter an integer.'
'Please select a valid language.': 'Please select a valid language.'
'Please select a valid locale.': 'Please select a valid locale.'
'Please enter a valid money amount.': 'Please enter a valid money amount.'
'Please enter a number.': 'Please enter a number.'
'The password is invalid.': 'The password is invalid.'
'Please enter a percentage value.': 'Please enter a percentage value.'
'The values do not match.': 'The values do not match.'
'Please enter a valid time.': 'Please enter a valid time.'
'Please select a valid timezone.': 'Please select a valid timezone.'
'Please enter a valid URL.': 'Please enter a valid URL.'
'Please enter a valid search term.': 'Please enter a valid search term.'
'Please provide a valid phone number.': 'Please provide a valid phone number.'
'The checkbox has an invalid value.': 'The checkbox has an invalid value.'
'Please enter a valid email address.': 'Please enter a valid email address.'
'Please select a valid option.': 'Please select a valid option.'
'Please select a valid range.': 'Please select a valid range.'
'Please enter a valid week.': 'Please enter a valid week.'