diff --git a/assets/styles/app.css b/assets/styles/app.css index b10a881..1d84a8d 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -12,7 +12,7 @@ font-family: "JetBrains"; src: local("JetBrainsMono-MediumItalic.ttf"), - url(".fonts/JetBrainsMono/JetBrainsMono-Italic.woff2") format("woff2"); + url("./fonts/JetBrainsMono/JetBrainsMono-Italic.woff2") format("woff2"); font-style: italic; font-weight: normal; } diff --git a/composer.json b/composer.json index c3ee750..0316fbf 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,9 @@ }, "autoload": { "psr-4": { + "MyDevel\\": "src/MyDevel/", "App\\": "src/" + } }, "autoload-dev": { diff --git a/config/services.yaml b/config/services.yaml index 2d6a76f..8d6e92e 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -13,12 +13,35 @@ services: # makes classes in src/ available to be used as services # this creates a service per class whose id is the fully-qualified class name + + + MyDevel\: + resource: '../src/MyDevel/' + + #exclude: + #- '../src/MyDevel/Webroot/Entity/' + #MyDevel\Webroot\Controller\WebrootSetupController: + # abstract: true + # class: WebrootSetupController + # autowire: true + # arguments: ['%kernel.project_dir%'] + + App\: resource: '../src/' exclude: - '../src/DependencyInjection/' - '../src/Entity/' - '../src/Kernel.php' + - '../src/MyDevel/' + + + App\Controller\: + resource: '../src/Controller' + tags: ['controller.service_arguments'] + + + # add more service definitions when explicit configuration is needed # please note that last definitions always *replace* previous ones diff --git a/migrations/Version20241126043446.php b/migrations/Version20241126043446.php new file mode 100644 index 0000000..27ce3c7 --- /dev/null +++ b/migrations/Version20241126043446.php @@ -0,0 +1,43 @@ +addSql('DROP TABLE mydevel_webroot_file'); + $this->addSql('DROP TABLE mydevel_webroot_file_permission'); + $this->addSql('DROP TABLE mydevel_webroot_role'); + $this->addSql('DROP TABLE mydevel_webroot_user'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE TABLE mydevel_webroot_file (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, owner_id INTEGER NOT NULL, url CLOB NOT NULL COLLATE "BINARY", abspath CLOB NOT NULL COLLATE "BINARY", CONSTRAINT FK_A7B135127E3C61F9 FOREIGN KEY (owner_id) REFERENCES mydevel_webroot_user (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_A7B135127E3C61F9 ON mydevel_webroot_file (owner_id)'); + $this->addSql('CREATE TABLE mydevel_webroot_file_permission (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, role_id INTEGER NOT NULL, webroot_file_id INTEGER NOT NULL, is_readable BOOLEAN DEFAULT 1 NOT NULL, is_writeable BOOLEAN DEFAULT 0 NOT NULL, is_deleteable BOOLEAN DEFAULT 0 NOT NULL, CONSTRAINT FK_4D56CEFD60322AC FOREIGN KEY (role_id) REFERENCES mydevel_webroot_role (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_4D56CEF2800AFC9 FOREIGN KEY (webroot_file_id) REFERENCES mydevel_webroot_file (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('CREATE INDEX IDX_4D56CEF2800AFC9 ON mydevel_webroot_file_permission (webroot_file_id)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_4D56CEFD60322AC ON mydevel_webroot_file_permission (role_id)'); + $this->addSql('CREATE TABLE mydevel_webroot_role (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, role VARCHAR(255) NOT NULL COLLATE "BINARY", name VARCHAR(255) NOT NULL COLLATE "BINARY", description VARCHAR(1023) DEFAULT NULL COLLATE "BINARY")'); + $this->addSql('CREATE TABLE mydevel_webroot_user (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, username VARCHAR(180) NOT NULL COLLATE "BINARY", roles CLOB NOT NULL COLLATE "BINARY" --(DC2Type:json) + , password VARCHAR(255) NOT NULL COLLATE "BINARY", email VARCHAR(255) NOT NULL COLLATE "BINARY")'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_USERNAME ON mydevel_webroot_user (username)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_A6BDD54BE7927C74 ON mydevel_webroot_user (email)'); + } +} diff --git a/src/Controller/MainController.php b/src/Controller/MainController.php index dad4eaa..809708c 100644 --- a/src/Controller/MainController.php +++ b/src/Controller/MainController.php @@ -6,17 +6,18 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\HttpKernel\KernelInterface; +//use MyDevel\Webroot\Controller\WebrootMainController; -class MainController extends AbstractController +class MainController extends AbstractController //WebrootMainController { #[Route('/', name: 'app_main')] public function index(KernelInterface $kernel): Response { - //$project_root = $kernel->getProjectDir(); + $project_root = $kernel->getProjectDir(); - //if (!file_exists(join(DIRECTORY_SEPARATOR,[$project_root,'.env.local']))) { - //return $this->redirect('/setup'); - //} + if (!file_exists(join(DIRECTORY_SEPARATOR,[$project_root,'.env.local']))) { + return $this->redirect('/setup'); + } return $this->render('main/index.html.twig', [ 'controller_name' => $kernel->getProjectDir(), diff --git a/src/Controller/SetupController.php b/src/Controller/SetupController.php index 41ed251..e41b5f2 100644 --- a/src/Controller/SetupController.php +++ b/src/Controller/SetupController.php @@ -6,13 +6,26 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; -class SetupController extends AbstractController +use MyDevel\Webroot\Controller\WebrootSetupController; + +class SetupController extends WebrootSetupController { - #[Route('/setup', name: 'app_setup')] + #[Route('/setup', name: 'webroot.setup')] public function index(): Response { - return $this->render('setup/index.html.twig', [ - 'controller_name' => 'SetupController', + return $this->render('setup/controller.html.twig', [ + 'controller_name' => "WebrootController", + 'function' => __FUNCTION__, + ]); + } + + + #[Route('/setup/login',name:'webroot.setup.login')] + public function login() + { + return $this->render('setup/controller.html.twig', [ + 'controller_name' => "WebrootController", + 'function' => __FUNCTION__, ]); } } diff --git a/src/MyDevel/Utility/i18n-lib/i18n-lib.php b/src/MyDevel/Utility/i18n-lib/i18n-lib.php new file mode 100644 index 0000000..4bbd6fb --- /dev/null +++ b/src/MyDevel/Utility/i18n-lib/i18n-lib.php @@ -0,0 +1,16 @@ +false])] + private ?bool $is_admin = null; public function getId(): ?int { @@ -121,4 +124,16 @@ class WebrootUser implements UserInterface, PasswordAuthenticatedUserInterface return $this; } + + public function isAdmin(): ?bool + { + return $this->is_admin; + } + + public function setAdmin(bool $admin): static + { + $this->is_admin = $admin; + + return $this; + } } diff --git a/src/Repository/WebrootFilePermissionRepository.php b/src/MyDevel/Webroot/Repository/WebrootFilePermissionRepository.php similarity index 97% rename from src/Repository/WebrootFilePermissionRepository.php rename to src/MyDevel/Webroot/Repository/WebrootFilePermissionRepository.php index 752fe98..68dbda5 100644 --- a/src/Repository/WebrootFilePermissionRepository.php +++ b/src/MyDevel/Webroot/Repository/WebrootFilePermissionRepository.php @@ -1,6 +1,6 @@ getEntityManager()->flush(); } - // /** - // * @return WebrootUser[] Returns an array of WebrootUser objects - // */ - // public function findByExampleField($value): array - // { - // return $this->createQueryBuilder('w') - // ->andWhere('w.exampleField = :val') - // ->setParameter('val', $value) - // ->orderBy('w.id', 'ASC') - // ->setMaxResults(10) - // ->getQuery() - // ->getResult() - // ; - // } - + public function getAdministrators(): array + { + return $this->createQueryBuilder('w') + ->andWhere('w.is_admin = :val') + ->setParameter('val', true) + ->orderBy('w.name','ASC') + ->getQuery() + ->getResult(); + } + + public function hasAdministrator(): array + { + return (count( + $this->createQueryBuilder('w') + ->andWhere('w.is_admin = :val') + ->setParameter('val', true) + ->setMaxResults(1) + ->getQuery() + ->getResult() + ) > 0); + } + + // public function findOneBySomeField($value): ?WebrootUser // { // return $this->createQueryBuilder('w') diff --git a/src/mydevel/Webroot/Controller/WebrootMainController.php b/src/mydevel/Webroot/Controller/WebrootMainController.php deleted file mode 100644 index 63499a3..0000000 --- a/src/mydevel/Webroot/Controller/WebrootMainController.php +++ /dev/null @@ -1,18 +0,0 @@ -render('webroot_main/index.html.twig', [ - 'controller_name' => 'WebrootMainController', - ]); - } -} diff --git a/src/mydevel/Webroot/Controller/WebrootSetupController.php b/src/mydevel/Webroot/Controller/WebrootSetupController.php index c7d1daa..1f0fd21 100644 --- a/src/mydevel/Webroot/Controller/WebrootSetupController.php +++ b/src/mydevel/Webroot/Controller/WebrootSetupController.php @@ -1,18 +1,205 @@ kernel = $kernel; + $this->project_dir = $kernel->getProjectDir(); + } + + /** + * @brief Get the root directory of the Project. + * + * This method gets the root directory of the project as an absolute path + * as returned by the Kernel->getProjectDir(); + * + * @return string|null The root directory of the prject or null if the + * Kernel cannot determine it. + */ + public function getProjectDir(): ?string { - return $this->render('webroot_setup/index.html.twig', [ - 'controller_name' => 'WebrootSetupController', + return $this->project_dir; + } + + /** + * @brief Check if there is an Administrator account existing. + * @return bool `true` if an Administrator is existent in the database. + */ + protected function hasAdministrator(): bool + { + $repos = $this->getRpository(WebrootUser::class); + return $repos->hasAdministrator(); + } + + /** + * @brief Check if there is a *.setupkey*-file in the project root. + * + * @note This file will be deleted after the initial setup! + * + * @return bool `true` if there is a *.setupkey* file int the project + * root directory. + */ + protected function hasSetupKey(): bool + { + return file_exists(join(DIRECTORY_SEPARATOR,[$this->project_dir,".setupkey"])); + } + + /** + * @Brief Get the actual setup key from file. + * @return string|null Returns `null` when there is no `.setupkey` file + * located in prject root else the first line of the file. + */ + protected function getSetupKey(): ?string + { + if (!$this->hasSetupKey()) { + return null; + } + $file = fopen($this->project_dir,".setupkey"); + $str = fread($file, 4096); + fclose($file); + $pos = strpos($str,"\r\n",0); + if (!$pos) { + $pos = strpos($str,"\n",0); + } + if ($pos) { + $key=substr(string,0,pos); + } else { + $key=$str; + } + return key; + } + + /** + * @brief Check if user is logged in for setup. + * @return bool Returns `true` if user is logged in and is allowed to view + * the setup pages. + */ + public function isLoggedIn(): bool + { + $user = $this->getUser(); + if ($user && $user->isAdmin()) { + return true; + } + + $has_setup_key = $this->hasSetupKey(); + $has_administrator = $this->hasAdministrator(); + if (!$has_administrator && !$has_setup_key) { + return true; + } + + if ($has_setup_key && isset($_COOKIE["mydevel_webroot_sk"])) { + return (filter_input(INPUT_COOKIE, "mydevel_webroot_sk") === $this->getSetupKey()); + } + + return false; + } + + /** + * @brief Check if we are already set up. + * + * This method checks if there is an .env.local file installed in the + * system and returns ture if the .env.local file is found. + * + * @return bool `true` if we are already installed. + */ + public function isInstalled(): bool + { + return (file_exists(join(DIRECTORY_SEPARATOR,[$this->project_dir,".env"])) + && file_exists(join(DIRECTORY_SEPARATOR,[$this->project_dir,".env.local"]))); + } + + /** + * @brief Check if the key marches the one from file. + * + * @param string $key The key to check. + * + * @return bool|null Returns `null` if there is no *.setupkey* file present, + * `true` on match and false if the key does not match. + */ + protected function checkSetupKey(string $key): ?bool + { + if (!$this->hasSetupKey()) { + return null; + } + + $file_key = $this->getSetupKey(); + if ($key === $file_key) { + $cookie_domain = getenv("WEBROOT_HOST"); + if (!$cookie_domain || !strlen("WEBROOT_HOST")) { + $request = $this->getRequest(); + $cookie_domain = $request->getHost(); + setcookie("mydevel_webroot_sk",$file_key,0,"/",$cookie_domain,1,0); + return true; + } + } + return false; + } + + /** + * + * @return string + */ + protected function runMakeMigration(): string + { + $application = new Application($this->kernel); + $application->setAutoExit(false); + + $input = new ArrayInput([ + "command" => "make:migration", + "--formatted" => true, + "--no-interaction" => true, ]); + + $output = new BufferedOutput(); + $application->run($input,$output); + + $content=$output->fetch(); + + return $content; + } + + /** + * + * @return string + */ + protected function runMigrate(): string + { + $application = new Application($this->kernel); + $application->setAutoExit(false); + + $input = new ArrayInput([ + "command" => "doctrine:migrations:migrate", + "--no-interaction" => true, + ]); + $output = new BufferedOutput(); + $application->run($input,$output); + + $content = $output->fetch(); + + return $content; } } diff --git a/templates/setup/controller.html.twig b/templates/setup/controller.html.twig new file mode 100644 index 0000000..798e1dc --- /dev/null +++ b/templates/setup/controller.html.twig @@ -0,0 +1,16 @@ +{% extends 'base.html.twig' %} + +{% block title %}Hello SetupController!{% endblock %} + +{% block body %} + +
src/MyDevel/Controller/SetupController.phptemplates/setup/controller.html.twigC:/msys64/home/c9mos/www/webroot/src/Controller/SetupController.phpC:/msys64/home/c9mos/www/webroot/templates/setup/index.html.twigC:/msys64/home/c9mos/www/webroot/src/Controller/WebrootMainController.phpC:/msys64/home/c9mos/www/webroot/templates/webroot_main/index.html.twigC:/msys64/home/c9mos/www/webroot/src/Controller/WebrootSetupController.phpC:/msys64/home/c9mos/www/webroot/templates/webroot_setup/index.html.twig