diff --git a/assets/styles/app.css b/assets/styles/app.css index b8c6cf9..394f896 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -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; -} \ No newline at end of file +} + +.command-output { + padding:10px; + height:20em; + width:800px; + background-color:var(--color-code-background); + color:white; +} diff --git a/public/yaml_file b/public/yaml_file new file mode 100644 index 0000000..f0102e3 --- /dev/null +++ b/public/yaml_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' diff --git a/src/Controller/SetupController.php b/src/Controller/SetupController.php index d2c4bcf..9b5cacd 100644 --- a/src/Controller/SetupController.php +++ b/src/Controller/SetupController.php @@ -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"); } } diff --git a/src/Controller/WebrootSetupController.php b/src/Controller/WebrootSetupController.php index c22c012..fb5deb8 100644 --- a/src/Controller/WebrootSetupController.php +++ b/src/Controller/WebrootSetupController.php @@ -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(); + } } diff --git a/src/Repository/WebrootRoleRepository.php b/src/Repository/WebrootRoleRepository.php index c09b100..f0f7c35 100644 --- a/src/Repository/WebrootRoleRepository.php +++ b/src/Repository/WebrootRoleRepository.php @@ -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") diff --git a/src/Repository/WebrootUserRepository.php b/src/Repository/WebrootUserRepository.php index 077c908..b936a99 100644 --- a/src/Repository/WebrootUserRepository.php +++ b/src/Repository/WebrootUserRepository.php @@ -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 // { diff --git a/src/Utility/NullTranslator.php b/src/Utility/NullTranslator.php new file mode 100644 index 0000000..6c5f02b --- /dev/null +++ b/src/Utility/NullTranslator.php @@ -0,0 +1,10 @@ +{{ translations.db }} - - + diff --git a/templates/setup/initial-setup.run.html.twig b/templates/setup/initial-setup.run.html.twig index 30ab797..ee03cdf 100644 --- a/templates/setup/initial-setup.run.html.twig +++ b/templates/setup/initial-setup.run.html.twig @@ -2,71 +2,91 @@ {% block body %}

Running Setup

- +

Running commands...

- + + + + {% endblock %} diff --git a/translations/messages+intl-icu.en.yaml b/translations/messages+intl-icu.en.yaml deleted file mode 100644 index d2fbe14..0000000 --- a/translations/messages+intl-icu.en.yaml +++ /dev/null @@ -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 diff --git a/translations/mydevel.webroot.de.yaml b/translations/mydevel.webroot.de.yaml new file mode 100644 index 0000000..e07be7e --- /dev/null +++ b/translations/mydevel.webroot.de.yaml @@ -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 diff --git a/translations/mydevel.webroot.en.yaml b/translations/mydevel.webroot.en.yaml new file mode 100644 index 0000000..e07be7e --- /dev/null +++ b/translations/mydevel.webroot.en.yaml @@ -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 diff --git a/translations/mydevel.webroot.role.de.yaml b/translations/mydevel.webroot.role.de.yaml new file mode 100644 index 0000000..e8dfdab --- /dev/null +++ b/translations/mydevel.webroot.role.de.yaml @@ -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%.' diff --git a/translations/mydevel.webroot.role.en.yaml b/translations/mydevel.webroot.role.en.yaml new file mode 100644 index 0000000..c655453 --- /dev/null +++ b/translations/mydevel.webroot.role.en.yaml @@ -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%' diff --git a/translations/messages+intl-icu.de.yaml b/translations/mydevel.webroot.setup.de.yaml similarity index 86% rename from translations/messages+intl-icu.de.yaml rename to translations/mydevel.webroot.setup.de.yaml index 3f1da28..cbe0332 100644 --- a/translations/messages+intl-icu.de.yaml +++ b/translations/mydevel.webroot.setup.de.yaml @@ -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: diff --git a/translations/mydevel.webroot.setup.en.yaml b/translations/mydevel.webroot.setup.en.yaml new file mode 100644 index 0000000..25df329 --- /dev/null +++ b/translations/mydevel.webroot.setup.en.yaml @@ -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' diff --git a/translations/validators.de.yaml b/translations/validators.de.yaml deleted file mode 100644 index 01d7ce6..0000000 --- a/translations/validators.de.yaml +++ /dev/null @@ -1 +0,0 @@ -Error: Fehler diff --git a/translations/validators.en.yaml b/translations/validators.en.yaml deleted file mode 100644 index fd7233b..0000000 --- a/translations/validators.en.yaml +++ /dev/null @@ -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.'
{{ form_widget(form.db_migrate) }} {{ form_label(form.db_migrate) }}{{ form_widget(form.db_create) }} {{ form_label(form.db_create) }} + {{ form_widget(form.db_create) }}{{ form_label(form.db_create) }} + + {{ form_widget(form.db_mkmigrations) }}{{ form_label(form.db_mkmigrations) }} + + {{ form_widget(form.db_migrate) }}{{ form_label(form.db_migrate) }} + +
{{ form_label(form.db_backend) }} {{ form_widget(form.db_backend) }}