From 38cb5a21d2a41caba5b7ef4694321870c8acd955 Mon Sep 17 00:00:00 2001 From: Llewellyn van der Merwe Date: Tue, 19 Apr 2022 05:49:18 +0200 Subject: [PATCH] Week 4: Content Management of Items/Menus/Users --- .../project/administrator/includes/app.php | 5 +- week-04/project/composer.json | 1 + week-04/project/composer.lock | 5 +- week-04/project/includes/app.php | 3 +- .../src/Application/AdminApplication.php | 2 +- .../src/Controller/AccessInterface.php | 28 + .../libraries/src/Controller/AccessTrait.php | 111 ++++ .../src/Controller/CheckTokenInterface.php | 26 + .../src/Controller/CheckTokenTrait.php | 36 ++ .../src/Controller/DashboardController.php | 63 +-- .../src/Controller/HomepageController.php | 21 +- .../src/Controller/ItemController.php | 211 ++++++++ .../src/Controller/ItemsController.php | 76 +++ .../src/Controller/LoginController.php | 32 +- .../src/Controller/MenuController.php | 193 +++++++ .../src/Controller/MenusController.php | 77 +++ .../src/Controller/PageController.php | 7 +- .../src/Controller/UserController.php | 268 ++++++++++ .../src/Controller/UsersController.php | 76 +++ .../src/Controller/WrongCmsController.php | 2 +- week-04/project/libraries/src/Factory.php | 1 + .../libraries/src/Model/HomepageModel.php | 67 +++ .../project/libraries/src/Model/ItemModel.php | 285 ++++++++++ .../libraries/src/Model/ItemsModel.php | 55 ++ .../libraries/src/Model/MenuInterface.php | 28 + .../project/libraries/src/Model/MenuModel.php | 338 ++++++++++++ .../libraries/src/Model/MenusModel.php | 62 +++ .../libraries/src/Model/PageInterface.php | 41 ++ .../project/libraries/src/Model/PageModel.php | 58 +-- .../libraries/src/Model/SiteMenuTrait.php | 70 +++ .../libraries/src/Model/SitePageTrait.php | 96 ++++ .../project/libraries/src/Model/UserModel.php | 226 ++++++++ .../libraries/src/Model/UsersModel.php | 55 ++ .../src/Renderer/FrameworkExtension.php | 4 +- .../src/Renderer/FrameworkTwigRuntime.php | 78 ++- .../src/Service/AdminApplicationProvider.php | 167 ------ .../src/Service/AdminMVCProvider.php | 485 ++++++++++++++++++ .../src/Service/AdminRouterProvider.php | 98 ++++ .../src/Service/AdminTemplatingProvider.php | 314 ++++++++++++ .../src/Service/ConfigurationProvider.php | 17 +- .../libraries/src/Service/InputProvider.php | 47 ++ .../libraries/src/Service/SessionProvider.php | 1 - .../src/Service/SiteApplicationProvider.php | 45 +- ...rovider.php => SiteTemplatingProvider.php} | 3 +- .../libraries/src/User/UserFactory.php | 140 ++++- .../src/View/Admin/DashboardHtmlView.php | 14 +- .../libraries/src/View/Admin/ItemHtmlView.php | 84 +++ .../src/View/Admin/ItemsHtmlView.php | 64 +++ .../libraries/src/View/Admin/MenuHtmlView.php | 87 ++++ .../src/View/Admin/MenusHtmlView.php | 64 +++ .../libraries/src/View/Admin/UserHtmlView.php | 83 +++ .../src/View/Admin/UsersHtmlView.php | 64 +++ .../src/View/Page/HomepageHtmlView.php | 133 +++++ .../libraries/src/View/Page/PageHtmlView.php | 63 ++- .../project/templates/admin/dashboard.twig | 7 +- week-04/project/templates/admin/header.twig | 8 +- week-04/project/templates/admin/index.twig | 2 +- week-04/project/templates/admin/item.twig | 111 ++++ week-04/project/templates/admin/items.twig | 79 +-- week-04/project/templates/admin/login.twig | 6 +- week-04/project/templates/admin/menu.twig | 111 ++++ week-04/project/templates/admin/menus.twig | 97 ++-- .../templates/admin/message_queue.twig | 20 + week-04/project/templates/admin/nav.twig | 15 +- week-04/project/templates/admin/signup.twig | 6 +- week-04/project/templates/admin/user.twig | 70 +++ week-04/project/templates/admin/users.twig | 73 ++- week-04/project/templates/site/header.twig | 6 +- week-04/project/templates/site/homepage.twig | 4 +- week-04/project/templates/site/index.twig | 2 +- week-04/project/templates/site/nav.twig | 48 +- week-04/project/templates/site/page.twig | 18 +- 72 files changed, 4845 insertions(+), 518 deletions(-) create mode 100644 week-04/project/libraries/src/Controller/AccessInterface.php create mode 100644 week-04/project/libraries/src/Controller/AccessTrait.php create mode 100644 week-04/project/libraries/src/Controller/CheckTokenInterface.php create mode 100644 week-04/project/libraries/src/Controller/CheckTokenTrait.php create mode 100644 week-04/project/libraries/src/Controller/ItemController.php create mode 100644 week-04/project/libraries/src/Controller/ItemsController.php create mode 100644 week-04/project/libraries/src/Controller/MenuController.php create mode 100644 week-04/project/libraries/src/Controller/MenusController.php create mode 100644 week-04/project/libraries/src/Controller/UserController.php create mode 100644 week-04/project/libraries/src/Controller/UsersController.php create mode 100644 week-04/project/libraries/src/Model/HomepageModel.php create mode 100644 week-04/project/libraries/src/Model/ItemModel.php create mode 100644 week-04/project/libraries/src/Model/ItemsModel.php create mode 100644 week-04/project/libraries/src/Model/MenuInterface.php create mode 100644 week-04/project/libraries/src/Model/MenuModel.php create mode 100644 week-04/project/libraries/src/Model/MenusModel.php create mode 100644 week-04/project/libraries/src/Model/PageInterface.php create mode 100644 week-04/project/libraries/src/Model/SiteMenuTrait.php create mode 100644 week-04/project/libraries/src/Model/SitePageTrait.php create mode 100644 week-04/project/libraries/src/Model/UserModel.php create mode 100644 week-04/project/libraries/src/Model/UsersModel.php create mode 100644 week-04/project/libraries/src/Service/AdminMVCProvider.php create mode 100644 week-04/project/libraries/src/Service/AdminRouterProvider.php create mode 100644 week-04/project/libraries/src/Service/AdminTemplatingProvider.php create mode 100644 week-04/project/libraries/src/Service/InputProvider.php rename week-04/project/libraries/src/Service/{TemplatingProvider.php => SiteTemplatingProvider.php} (98%) create mode 100644 week-04/project/libraries/src/View/Admin/ItemHtmlView.php create mode 100644 week-04/project/libraries/src/View/Admin/ItemsHtmlView.php create mode 100644 week-04/project/libraries/src/View/Admin/MenuHtmlView.php create mode 100644 week-04/project/libraries/src/View/Admin/MenusHtmlView.php create mode 100644 week-04/project/libraries/src/View/Admin/UserHtmlView.php create mode 100644 week-04/project/libraries/src/View/Admin/UsersHtmlView.php create mode 100644 week-04/project/libraries/src/View/Page/HomepageHtmlView.php create mode 100644 week-04/project/templates/admin/item.twig create mode 100644 week-04/project/templates/admin/menu.twig create mode 100644 week-04/project/templates/admin/message_queue.twig create mode 100644 week-04/project/templates/admin/user.twig diff --git a/week-04/project/administrator/includes/app.php b/week-04/project/administrator/includes/app.php index 0f10dc1..9c303d2 100644 --- a/week-04/project/administrator/includes/app.php +++ b/week-04/project/administrator/includes/app.php @@ -45,13 +45,16 @@ try ->registerServiceProvider(new Octoleo\CMS\Service\ConfigurationProvider(LPATH_CONFIGURATION . '/octoconfig.php')) ->registerServiceProvider(new Octoleo\CMS\Service\SessionProvider) ->registerServiceProvider(new Octoleo\CMS\Service\UserProvider) + ->registerServiceProvider(new Octoleo\CMS\Service\InputProvider) ->registerServiceProvider(new Octoleo\CMS\Service\AdminApplicationProvider) + ->registerServiceProvider(new Octoleo\CMS\Service\AdminRouterProvider) + ->registerServiceProvider(new Octoleo\CMS\Service\AdminMVCProvider) ->registerServiceProvider(new Joomla\Database\Service\DatabaseProvider) ->registerServiceProvider(new Octoleo\CMS\Service\EventProvider) ->registerServiceProvider(new Octoleo\CMS\Service\HttpProvider) ->registerServiceProvider(new Octoleo\CMS\Service\LoggingProvider) ->registerServiceProvider(new Joomla\Preload\Service\PreloadProvider) - ->registerServiceProvider(new Octoleo\CMS\Service\TemplatingProvider); + ->registerServiceProvider(new Octoleo\CMS\Service\AdminTemplatingProvider); // Alias the web application to Octoleo's base application class as this is the primary application for the environment $container->alias(Joomla\Application\AbstractApplication::class, Joomla\Application\AbstractWebApplication::class); diff --git a/week-04/project/composer.json b/week-04/project/composer.json index 7f3b12b..24f9394 100644 --- a/week-04/project/composer.json +++ b/week-04/project/composer.json @@ -26,6 +26,7 @@ }, "require": { "php": "^7.2.5", + "ext-json": "*", "joomla/application": "~2.0", "joomla/archive": "~2.0", "joomla/authentication": "~2.0", diff --git a/week-04/project/composer.lock b/week-04/project/composer.lock index ed50632..1b167e1 100644 --- a/week-04/project/composer.lock +++ b/week-04/project/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3442722df6289914de45ee254d28bada", + "content-hash": "ce1103508736357f7992f4e8b00f7bc6", "packages": [ { "name": "algo26-matthias/idna-convert", @@ -5382,7 +5382,8 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.2.5" + "php": "^7.2.5", + "ext-json": "*" }, "platform-dev": [], "platform-overrides": { diff --git a/week-04/project/includes/app.php b/week-04/project/includes/app.php index 603becf..88d3892 100644 --- a/week-04/project/includes/app.php +++ b/week-04/project/includes/app.php @@ -44,12 +44,13 @@ try $container = (new Joomla\DI\Container) ->registerServiceProvider(new Octoleo\CMS\Service\SiteApplicationProvider) ->registerServiceProvider(new Octoleo\CMS\Service\ConfigurationProvider(LPATH_CONFIGURATION . '/octoconfig.php')) + ->registerServiceProvider(new Octoleo\CMS\Service\InputProvider) ->registerServiceProvider(new Joomla\Database\Service\DatabaseProvider) ->registerServiceProvider(new Octoleo\CMS\Service\EventProvider) ->registerServiceProvider(new Octoleo\CMS\Service\HttpProvider) ->registerServiceProvider(new Octoleo\CMS\Service\LoggingProvider) ->registerServiceProvider(new Joomla\Preload\Service\PreloadProvider) - ->registerServiceProvider(new Octoleo\CMS\Service\TemplatingProvider); + ->registerServiceProvider(new Octoleo\CMS\Service\SiteTemplatingProvider); // Alias the web application to Octoleo's base application class as this is the primary application for the environment $container->alias(Joomla\Application\AbstractApplication::class, Joomla\Application\AbstractWebApplication::class); diff --git a/week-04/project/libraries/src/Application/AdminApplication.php b/week-04/project/libraries/src/Application/AdminApplication.php index b1aaa64..4049569 100644 --- a/week-04/project/libraries/src/Application/AdminApplication.php +++ b/week-04/project/libraries/src/Application/AdminApplication.php @@ -87,4 +87,4 @@ class AdminApplication extends AbstractWebApplication implements SessionAwareWeb \call_user_func($this->controllerResolver->resolve($route)); } -} \ No newline at end of file +} diff --git a/week-04/project/libraries/src/Controller/AccessInterface.php b/week-04/project/libraries/src/Controller/AccessInterface.php new file mode 100644 index 0000000..de6dcdc --- /dev/null +++ b/week-04/project/libraries/src/Controller/AccessInterface.php @@ -0,0 +1,28 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Controller; + +/** + * Class for checking the user access + * + * @since 1.0.0 + */ +interface AccessInterface +{ + /** + * @param string $task + * @param string $default + * + * @return bool + * @throws \Exception + */ + public function allow(string $task, string $default = ''): bool; +} diff --git a/week-04/project/libraries/src/Controller/AccessTrait.php b/week-04/project/libraries/src/Controller/AccessTrait.php new file mode 100644 index 0000000..347dfbb --- /dev/null +++ b/week-04/project/libraries/src/Controller/AccessTrait.php @@ -0,0 +1,111 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Controller; + +use Joomla\Uri\Uri; + +/** + * Trait for checking the user access + * + * @since 1.0.0 + */ +trait AccessTrait +{ + /** + * When access not allowed this is the path to redirect to + * + * @var string + */ + private $noAccessRedirect = ''; + + /** + * Check if user is allowed to access this area + * + * @param string $task + * @param string $default + * + * @return bool + * @throws \Exception + */ + public function allow(string $task = 'post', string $default = ''): bool + { + // our little access controller TODO: we can do better + $has_access = false; + + /** @var \Octoleo\CMS\Application\AdminApplication $app */ + $app = $this->getApplication(); + + /** @var \Octoleo\CMS\User\UserFactory $userFactory */ + $userFactory = $app->getUserFactory(); + + // user actions [logout] + if ('logout' === $task) + { + if ($userFactory->logout()) + { + $this->noAccessRedirect = '/'; + // clear the message queue + $app->getMessageQueue(true); + } + } + // check if this is a user valid + elseif ($userFactory->active()) + { + $has_access = true; + } + // user actions [access, signup] + elseif ('access' === $task || 'signup' === $task) + { + if ('access' === $task) + { + if ($userFactory->login()) + { + $has_access = true; + } + } + else + { + if ($userFactory->create()) + { + $has_access = true; + } + else + { + $this->noAccessRedirect = '/?account=signup'; + } + } + + // we by default always load the dashboard + $this->view->setActiveDashboard($default); + } + + return $has_access; + } + + /** + * @param string|null $target + * + * @return void + */ + private function _redirect(string $target = null) + { + // get uri request to get host + $uri = new Uri($this->getApplication()->get('uri.request')); + + // get redirect path + $redirect = (!empty($target)) ? $target : $this->noAccessRedirect; + // fix the path + $path = $uri->getPath(); + $path = substr($path, 0, strripos($path, '/')) . '/' . $redirect; + // redirect to the set area + $this->getApplication()->redirect($uri->getScheme() . '://' . $uri->getHost() . $path ); + } +} diff --git a/week-04/project/libraries/src/Controller/CheckTokenInterface.php b/week-04/project/libraries/src/Controller/CheckTokenInterface.php new file mode 100644 index 0000000..ba83510 --- /dev/null +++ b/week-04/project/libraries/src/Controller/CheckTokenInterface.php @@ -0,0 +1,26 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Controller; + +/** + * Class for checking the form had a token + * + * @since 1.0.0 + */ +interface CheckTokenInterface +{ + /** + * Check the token of the form + * + * @return bool + */ + public function checkToken(): bool; +} diff --git a/week-04/project/libraries/src/Controller/CheckTokenTrait.php b/week-04/project/libraries/src/Controller/CheckTokenTrait.php new file mode 100644 index 0000000..5fd0df5 --- /dev/null +++ b/week-04/project/libraries/src/Controller/CheckTokenTrait.php @@ -0,0 +1,36 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Controller; + +/** + * Class for checking the form had a token + * + * @since 1.0.0 + */ +trait CheckTokenTrait +{ + /** + * Check the token of the form + * + * @return bool + */ + public function checkToken(): bool + { + $token = $this->getApplication()->getSession()->getToken(); + $form_token = $this->getInput()->getString($token, 0); + + if ($form_token == 0) + { + exit('Invalid form token'); + } + return true; + } +} diff --git a/week-04/project/libraries/src/Controller/DashboardController.php b/week-04/project/libraries/src/Controller/DashboardController.php index c324ad9..2f36c39 100644 --- a/week-04/project/libraries/src/Controller/DashboardController.php +++ b/week-04/project/libraries/src/Controller/DashboardController.php @@ -14,18 +14,19 @@ use Joomla\Application\AbstractApplication; use Joomla\Controller\AbstractController; use Joomla\Input\Input; use Joomla\Uri\Uri; -use Laminas\Diactoros\Response\RedirectResponse; use Octoleo\CMS\View\Admin\DashboardHtmlView; use Laminas\Diactoros\Response\HtmlResponse; /** - * Controller handling the site's homepage + * Controller handling the site's dashboard * * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object */ -class DashboardController extends AbstractController +class DashboardController extends AbstractController implements AccessInterface, CheckTokenInterface { + use AccessTrait, CheckTokenTrait; + /** * The view object. * @@ -36,10 +37,10 @@ class DashboardController extends AbstractController /** * Constructor. * - * @param DashboardHtmlView $view The view object. - * @param Input $user The user object. - * @param Input $input The input object. - * @param AbstractApplication $app The application object. + * @param DashboardHtmlView $view The view object. + * @param Input $user The user object. + * @param Input $input The input object. + * @param AbstractApplication $app The application object. */ public function __construct(DashboardHtmlView $view, Input $input = null, AbstractApplication $app = null) { @@ -56,56 +57,30 @@ class DashboardController extends AbstractController */ public function execute(): bool { - // our little access controller TODO: we can do better - $has_access = false; + // Do not Enable browser caching + $this->getApplication()->allowCache(false); - // Enable browser caching - $this->getApplication()->allowCache(true); - - $dashboard = $this->getInput()->getString('dashboard', ''); + $task = $this->getInput()->getString('task', ''); $id = $this->getInput()->getInt('id', 0); - $this->view->setActiveDashboard($dashboard); + $this->view->setActiveDashboard($task); $this->view->setActiveId($id); - /** @var \Octoleo\CMS\User\UserFactory $userFactory */ - $userFactory = $this->getApplication()->getUserFactory(); - - // user actions [access, signup] - if ('access' === $dashboard || 'signup' === $dashboard || 'logout' === $dashboard) + // validate form token + if ('access' === $task || 'signup' === $task) { - if ('access' === $dashboard && $userFactory->login()) - { - $has_access = true; - } - elseif ('signup' === $dashboard && $userFactory->create()) - { - $has_access = true; - } - elseif ('logout' === $dashboard && $userFactory->logout()) - { - $has_access = false; - } - - // we by default always load the dashboard - $this->view->setActiveDashboard('dashboard'); - } - elseif ($userFactory->active()) - { - $has_access = true; + $this->checkToken(); } - if ($has_access) + // check if user is allowed to access + if ($this->allow($task)) { $this->getApplication()->setResponse(new HtmlResponse($this->view->render())); } else { - // get uri request to get host - $uri = new Uri($this->getApplication()->get('uri.request')); - - // Redirect to the administrator area - $this->getApplication()->redirect($uri->getScheme() . '://' . $uri->getHost() . '/administrator/'); + // go to set page + $this->_redirect(); } return true; diff --git a/week-04/project/libraries/src/Controller/HomepageController.php b/week-04/project/libraries/src/Controller/HomepageController.php index fc90113..7fd0296 100644 --- a/week-04/project/libraries/src/Controller/HomepageController.php +++ b/week-04/project/libraries/src/Controller/HomepageController.php @@ -13,8 +13,8 @@ namespace Octoleo\CMS\Controller; use Joomla\Application\AbstractApplication; use Joomla\Controller\AbstractController; use Joomla\Input\Input; -use Joomla\Renderer\RendererInterface; use Laminas\Diactoros\Response\HtmlResponse; +use Octoleo\CMS\View\Page\HomepageHtmlView; /** * Controller handling the site's homepage @@ -25,24 +25,24 @@ use Laminas\Diactoros\Response\HtmlResponse; class HomepageController extends AbstractController { /** - * The template renderer. + * The view object. * - * @var RendererInterface + * @var HomepageHtmlView */ - private $renderer; + private $view; /** * Constructor. * - * @param RendererInterface $renderer The template renderer. + * @param HomepageHtmlView $view The view object. * @param Input $input The input object. * @param AbstractApplication $app The application object. */ - public function __construct(RendererInterface $renderer, Input $input = null, AbstractApplication $app = null) + public function __construct(HomepageHtmlView $view, Input $input = null, AbstractApplication $app = null) { parent::__construct($input, $app); - $this->renderer = $renderer; + $this->view = $view; } /** @@ -52,10 +52,11 @@ class HomepageController extends AbstractController */ public function execute(): bool { - // Enable browser caching - $this->getApplication()->allowCache(true); + // Disable all cache for now + $this->getApplication()->allowCache(false); - $this->getApplication()->setResponse(new HtmlResponse($this->renderer->render('homepage.twig'))); + // check if there is a home page + $this->getApplication()->setResponse(new HtmlResponse($this->view->render())); return true; } diff --git a/week-04/project/libraries/src/Controller/ItemController.php b/week-04/project/libraries/src/Controller/ItemController.php new file mode 100644 index 0000000..089de29 --- /dev/null +++ b/week-04/project/libraries/src/Controller/ItemController.php @@ -0,0 +1,211 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Controller; + +use Joomla\Application\AbstractApplication; +use Joomla\Controller\AbstractController; +use Joomla\Filter\InputFilter as InputFilterAlias; +use Joomla\Input\Input; +use Octoleo\CMS\Date\Date; +use Octoleo\CMS\Factory; +use Octoleo\CMS\Filter\InputFilter; +use Octoleo\CMS\Model\ItemModel; +use Octoleo\CMS\User\UserFactoryInterface; +use Octoleo\CMS\View\Admin\ItemHtmlView; +use Laminas\Diactoros\Response\HtmlResponse; + +/** + * Controller handling the site's dashboard + * + * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. + * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object + */ +class ItemController extends AbstractController implements AccessInterface, CheckTokenInterface +{ + use AccessTrait, CheckTokenTrait; + + /** + * The view object. + * + * @var ItemHtmlView + */ + private $view; + + /** + * The model object. + * + * @var ItemModel + */ + private $model; + + /** + * @var InputFilter + */ + private $inputFilter; + + /** + * Constructor. + * + * @param ItemModel $model The model object. + * @param ItemHtmlView $view The view object. + * @param Input $input The input object. + * @param AbstractApplication $app The application object. + */ + public function __construct(ItemModel $model, $view, Input $input = null, AbstractApplication $app = null) + { + parent::__construct($input, $app); + + $this->model = $model; + $this->view = $view; + $this->inputFilter = InputFilter::getInstance( + [], + [], + InputFilterAlias::ONLY_BLOCK_DEFINED_TAGS, + InputFilterAlias::ONLY_BLOCK_DEFINED_ATTRIBUTES + ); + } + + /** + * Execute the controller. + * + * @return boolean + * @throws \Exception + */ + public function execute(): bool + { + // Do not Enable browser caching + $this->getApplication()->allowCache(false); + + $method = $this->getInput()->getMethod(); + $task = $this->getInput()->getString('task', ''); + $id = $this->getInput()->getInt('id', 0); + + // if task is delete + if ('delete' === $task) + { + if ($id > 0 && $this->model->linked($id)) + { + $this->getApplication()->enqueueMessage('This item is still linked to a menu, first remove it from the menu.', 'error'); + } + elseif ($id > 0 && $this->model->delete($id)) + { + $this->getApplication()->enqueueMessage('Item was deleted!', 'success'); + } + else + { + $this->getApplication()->enqueueMessage('Item could not be deleted!', 'error'); + } + // go to set page + $this->_redirect('items'); + + return true; + } + + if ('POST' === $method) + { + $id = $this->setItem(); + } + + $this->view->setActiveId($id); + $this->view->setActiveView('item'); + + // check if user is allowed to access + if ($this->allow('item')) + { + $this->getApplication()->setResponse(new HtmlResponse($this->view->render())); + } + else + { + // go to set page + $this->_redirect(); + } + + return true; + } + + /** + * Set an item + * + * + * @return int + * @throws \Exception + */ + protected function setItem(): int + { + // always check the post token + $this->checkToken(); + // get the post + $post = $this->getInput()->getInputForRequestMethod(); + + // we get all the needed items + $tempItem = []; + $tempItem['id'] = $post->getInt('item_id', 0); + $tempItem['title'] = $post->getString('title', ''); + $tempItem['fulltext'] = $this->inputFilter->clean($post->getRaw('fulltext', ''), 'html'); + $tempItem['created_by_alias'] = $post->getString('created_by_alias', ''); + $tempItem['state'] = $post->getInt('state', 1); + $tempItem['metakey'] = $post->getString('metakey', ''); + $tempItem['metadesc'] = $post->getString('metadesc', ''); + $tempItem['metadata'] = $post->getString('metadata', ''); + $tempItem['publish_up'] = $post->getString('publish_up', ''); + $tempItem['publish_down'] = $post->getString('publish_down', ''); + $tempItem['featured'] = $post->getInt('featured', 0); + + // check that we have a Title + $can_save = true; + if (empty($tempItem['title'])) + { + // we show a warning message + $tempItem['title'] = ''; + $this->getApplication()->enqueueMessage('Title field is required.', 'error'); + $can_save = false; + } + // we actually can also not continue if we don't have content + if (empty($tempItem['fulltext'])) + { + // we show a warning message + $tempItem['fulltext'] = ''; + $this->getApplication()->enqueueMessage('Content field is required.', 'error'); + $can_save = false; + } + // can we save the item + if ($can_save) + { + /** @var \Octoleo\CMS\User\User $user */ + $user = Factory::getContainer()->get(UserFactoryInterface::class)->getUser(); + + $user_id = (int) $user->get('id', 0); + $today = (new Date())->toSql(); + + return $this->model->setItem( + $tempItem['id'], + $tempItem['title'], + $tempItem['fulltext'], + $tempItem['state'], + $today, + $user_id, + $tempItem['created_by_alias'], + $today, + $user_id, + $tempItem['publish_up'], + $tempItem['publish_down'], + $tempItem['metakey'], + $tempItem['metadesc'], + $tempItem['metadata'], + $tempItem['featured']); + } + + // add to model the post values + $this->model->tempItem = $tempItem; + + return $tempItem['id']; + } +} diff --git a/week-04/project/libraries/src/Controller/ItemsController.php b/week-04/project/libraries/src/Controller/ItemsController.php new file mode 100644 index 0000000..7205934 --- /dev/null +++ b/week-04/project/libraries/src/Controller/ItemsController.php @@ -0,0 +1,76 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Controller; + +use Joomla\Application\AbstractApplication; +use Joomla\Controller\AbstractController; +use Joomla\Input\Input; +use Octoleo\CMS\View\Admin\ItemsHtmlView; +use Laminas\Diactoros\Response\HtmlResponse; + +/** + * Controller handling the site's dashboard + * + * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. + * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object + */ +class ItemsController extends AbstractController implements AccessInterface, CheckTokenInterface +{ + use AccessTrait, CheckTokenTrait; + + /** + * The view object. + * + * @var ItemsHtmlView + */ + private $view; + + /** + * Constructor. + * + * @param ItemsHtmlView $view The view object. + * @param Input $input The input object. + * @param AbstractApplication $app The application object. + */ + public function __construct(ItemsHtmlView $view, Input $input = null, AbstractApplication $app = null) + { + parent::__construct($input, $app); + + $this->view = $view; + } + + /** + * Execute the controller. + * + * @return boolean + * @throws \Exception + */ + public function execute(): bool + { + // Do not Enable browser caching + $this->getApplication()->allowCache(false); + + $this->view->setActiveView('items'); + + // check if user is allowed to access + if ($this->allow('items')) + { + $this->getApplication()->setResponse(new HtmlResponse($this->view->render())); + } + else + { + // go to set page + $this->_redirect(); + } + + return true; + } +} diff --git a/week-04/project/libraries/src/Controller/LoginController.php b/week-04/project/libraries/src/Controller/LoginController.php index 5745503..2d94c07 100644 --- a/week-04/project/libraries/src/Controller/LoginController.php +++ b/week-04/project/libraries/src/Controller/LoginController.php @@ -15,6 +15,7 @@ use Joomla\Controller\AbstractController; use Joomla\Input\Input; use Joomla\Renderer\RendererInterface; use Laminas\Diactoros\Response\HtmlResponse; +use Octoleo\CMS\View\Admin\DashboardHtmlView; /** * Controller handling the site's homepage @@ -31,17 +32,26 @@ class LoginController extends AbstractController */ private $renderer; + /** + * The view object. + * + * @var DashboardHtmlView + */ + private $view; + /** * Constructor. * + * @param DashboardHtmlView $view The view object. * @param RendererInterface $renderer The template renderer. * @param Input $input The input object. * @param AbstractApplication $app The application object. */ - public function __construct(RendererInterface $renderer, Input $input = null, AbstractApplication $app = null) + public function __construct(DashboardHtmlView $view, RendererInterface $renderer, Input $input = null, AbstractApplication $app = null) { parent::__construct($input, $app); + $this->view = $view; $this->renderer = $renderer; } @@ -49,15 +59,29 @@ class LoginController extends AbstractController * Execute the controller. * * @return boolean + * @throws \Exception */ public function execute(): bool { - // Enable browser caching - $this->getApplication()->allowCache(true); + // Do not Enable browser caching + $this->getApplication()->allowCache(false); $task = $this->getInput()->getString('account', null); - if ('signup' === $task) + /** @var \Octoleo\CMS\Application\AdminApplication $app */ + $app = $this->getApplication(); + + /** @var \Octoleo\CMS\User\UserFactory $userFactory */ + $userFactory = $app->getUserFactory(); + + // if the user is logged in we go to dashboard + if ($userFactory->active(false)) + { + $this->view->setActiveDashboard('dashboard'); + $this->view->setActiveId(0); + $this->getApplication()->setResponse(new HtmlResponse($this->view->render())); + } + elseif ('signup' === $task) { $this->getApplication()->setResponse(new HtmlResponse($this->renderer->render('signup.twig'))); } diff --git a/week-04/project/libraries/src/Controller/MenuController.php b/week-04/project/libraries/src/Controller/MenuController.php new file mode 100644 index 0000000..2134604 --- /dev/null +++ b/week-04/project/libraries/src/Controller/MenuController.php @@ -0,0 +1,193 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Controller; + +use Joomla\Application\AbstractApplication; +use Joomla\Controller\AbstractController; +use Joomla\Filter\InputFilter as InputFilterAlias; +use Joomla\Input\Input; +use Octoleo\CMS\Filter\InputFilter; +use Octoleo\CMS\Model\MenuModel; +use Laminas\Diactoros\Response\HtmlResponse; +use Octoleo\CMS\View\Admin\MenuHtmlView; + +/** + * Controller handling the site's dashboard + * + * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. + * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object + */ +class MenuController extends AbstractController implements AccessInterface, CheckTokenInterface +{ + use AccessTrait, CheckTokenTrait; + + /** + * The view object. + * + * @var MenuHtmlView + */ + private $view; + + /** + * The model object. + * + * @var MenuModel + */ + private $model; + + /** + * @var InputFilter + */ + private $inputFilter; + + /** + * Constructor. + * + * @param MenuModel $model The model object. + * @param MenuHtmlView $view The view object. + * @param Input $input The input object. + * @param AbstractApplication $app The application object. + */ + public function __construct(MenuModel $model, MenuHtmlView $view, Input $input = null, AbstractApplication $app = null) + { + parent::__construct($input, $app); + + $this->model = $model; + $this->view = $view; + $this->inputFilter = InputFilter::getInstance( + [], + [], + InputFilterAlias::ONLY_BLOCK_DEFINED_TAGS, + InputFilterAlias::ONLY_BLOCK_DEFINED_ATTRIBUTES + ); + } + + /** + * Execute the controller. + * + * @return boolean + * @throws \Exception + */ + public function execute(): bool + { + // Do not Enable browser caching + $this->getApplication()->allowCache(false); + + $method = $this->getInput()->getMethod(); + $task = $this->getInput()->getString('task', ''); + $id = $this->getInput()->getInt('id', 0); + + // if task is delete + if ('delete' === $task) + { + if ($this->model->delete($id)) + { + $this->getApplication()->enqueueMessage('Menu was deleted!', 'success'); + } + else + { + $this->getApplication()->enqueueMessage('Menu could not be deleted!', 'error'); + } + // go to set page + $this->_redirect('menus'); + + return true; + } + + if ('POST' === $method) + { + $id = $this->setItem(); + } + + $this->view->setActiveId($id); + $this->view->setActiveView('menu'); + + // check if user is allowed to access + if ($this->allow('menu')) + { + $this->getApplication()->setResponse(new HtmlResponse($this->view->render())); + } + else + { + // go to set page + $this->_redirect(); + } + + return true; + } + + /** + * Set an item + * + * + * @return int + * @throws \Exception + */ + protected function setItem(): int + { + // always check the post token + $this->checkToken(); + // get the post + $post = $this->getInput()->getInputForRequestMethod(); + + // we get all the needed items + $tempItem = []; + $tempItem['id'] = $post->getInt('menu_id', 0); + $tempItem['title'] = $post->getString('title', ''); + $tempItem['alias'] = $post->getString('alias', ''); + $tempItem['path'] = $post->getString('path', ''); + $tempItem['item_id'] = $post->getInt('item_id', 0); + $tempItem['published'] = $post->getInt('published', 1); + $tempItem['publish_up'] = $post->getString('publish_up', ''); + $tempItem['publish_down'] = $post->getString('publish_down', ''); + $tempItem['position'] = $post->getString('position', 'center'); + $tempItem['home'] = $post->getInt('home', 0); + + // check that we have a Title + $can_save = true; + if (empty($tempItem['title'])) + { + // we show a warning message + $tempItem['title'] = ''; + $this->getApplication()->enqueueMessage('Title field is required.', 'error'); + $can_save = false; + } + // we actually can also not continue if we don't have content + if (empty($tempItem['item_id']) || $tempItem['item_id'] == 0) + { + // we show a warning message + $tempItem['item_id'] = 0; + $this->getApplication()->enqueueMessage('Item field is required.', 'error'); + $can_save = false; + } + + // can we save the item + if ($can_save) + { + return $this->model->setItem( + $tempItem['id'], + $tempItem['title'], + $tempItem['alias'], + $tempItem['item_id'], + $tempItem['path'], + $tempItem['published'], + $tempItem['publish_up'], + $tempItem['publish_down'], + $tempItem['position'], + $tempItem['home']); + } + + // add to model the post values + $this->model->tempItem = $tempItem; + + return $tempItem['id']; + } +} diff --git a/week-04/project/libraries/src/Controller/MenusController.php b/week-04/project/libraries/src/Controller/MenusController.php new file mode 100644 index 0000000..d468af8 --- /dev/null +++ b/week-04/project/libraries/src/Controller/MenusController.php @@ -0,0 +1,77 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Controller; + +use Joomla\Application\AbstractApplication; +use Joomla\Controller\AbstractController; +use Joomla\Input\Input; +use Octoleo\CMS\View\Admin\MenusHtmlView; +use Laminas\Diactoros\Response\HtmlResponse; + +/** + * Controller handling the site's dashboard + * + * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. + * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object + */ +class MenusController extends AbstractController implements AccessInterface, CheckTokenInterface +{ + use AccessTrait, CheckTokenTrait; + + /** + * The view object. + * + * @var MenusHtmlView + */ + private $view; + + /** + * Constructor. + * + * @param MenusHtmlView $view The view object. + * @param Input $user The user object. + * @param Input $input The input object. + * @param AbstractApplication $app The application object. + */ + public function __construct(MenusHtmlView $view, Input $input = null, AbstractApplication $app = null) + { + parent::__construct($input, $app); + + $this->view = $view; + } + + /** + * Execute the controller. + * + * @return boolean + * @throws \Exception + */ + public function execute(): bool + { + // Do not Enable browser caching + $this->getApplication()->allowCache(false); + + $this->view->setActiveView('menus'); + + // check if user is allowed to access + if ($this->allow('menus')) + { + $this->getApplication()->setResponse(new HtmlResponse($this->view->render())); + } + else + { + // go to set page + $this->_redirect(); + } + + return true; + } +} diff --git a/week-04/project/libraries/src/Controller/PageController.php b/week-04/project/libraries/src/Controller/PageController.php index ad246d3..70e1ef7 100644 --- a/week-04/project/libraries/src/Controller/PageController.php +++ b/week-04/project/libraries/src/Controller/PageController.php @@ -36,7 +36,7 @@ class PageController extends AbstractController /** * Constructor. * - * @param PageHtmlView $view The view object. + * @param PageHtmlView $view The view object. * @param Input $input The input object. * @param AbstractApplication $app The application object. */ @@ -54,8 +54,8 @@ class PageController extends AbstractController */ public function execute(): bool { - // Enable browser caching - $this->getApplication()->allowCache(true); + // Disable all cache for now + $this->getApplication()->allowCache(false); $page = $this->getInput()->getString('view', ''); $details = $this->getInput()->getString('details', ''); @@ -72,7 +72,6 @@ class PageController extends AbstractController else { $this->view->setPage($page); - $this->view->setDetails($details); $this->getApplication()->setResponse(new HtmlResponse($this->view->render())); } diff --git a/week-04/project/libraries/src/Controller/UserController.php b/week-04/project/libraries/src/Controller/UserController.php new file mode 100644 index 0000000..9ad6c22 --- /dev/null +++ b/week-04/project/libraries/src/Controller/UserController.php @@ -0,0 +1,268 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Controller; + +use Joomla\Application\AbstractApplication; +use Joomla\Controller\AbstractController; +use Joomla\Filter\InputFilter as InputFilterAlias; +use Joomla\Input\Input; +use Octoleo\CMS\Date\Date; +use Joomla\Authentication\Password\BCryptHandler; +use Octoleo\CMS\Factory; +use Octoleo\CMS\Filter\InputFilter; +use Octoleo\CMS\Model\UserModel; +use Octoleo\CMS\User\UserFactoryInterface; +use Octoleo\CMS\View\Admin\UserHtmlView; +use Laminas\Diactoros\Response\HtmlResponse; + +/** + * Controller handling the site's dashboard + * + * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. + * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object + */ +class UserController extends AbstractController implements AccessInterface, CheckTokenInterface +{ + use AccessTrait, CheckTokenTrait; + + /** + * The view object. + * + * @var UserHtmlView + */ + private $view; + + /** + * The model object. + * + * @var UserModel + */ + private $model; + + /** + * @var InputFilter + */ + private $inputFilter; + + /** + * @var BCryptHandler + */ + private $secure; + + /** + * Constructor. + * + * @param UserModel $model The model object. + * @param UserHtmlView $view The view object. + * @param Input|null $input The input object. + * @param AbstractApplication|null $app The application object. + */ + public function __construct(UserModel $model, UserHtmlView $view, Input $input = null, AbstractApplication $app = null, BCryptHandler $secure = null) + { + parent::__construct($input, $app); + + $this->model = $model; + $this->view = $view; + $this->inputFilter = InputFilter::getInstance( + [], + [], + InputFilterAlias::ONLY_BLOCK_DEFINED_TAGS, + InputFilterAlias::ONLY_BLOCK_DEFINED_ATTRIBUTES + ); + $this->secure = ($secure) ?: new BCryptHandler(); + } + + /** + * Execute the controller. + * + * @return boolean + * @throws \Exception + */ + public function execute(): bool + { + // Do not Enable browser caching + $this->getApplication()->allowCache(false); + + $method = $this->getInput()->getMethod(); + $task = $this->getInput()->getString('task', ''); + $id = $this->getInput()->getInt('id', 0); + + // if task is delete + if ('delete' === $task) + { + /** @var \Octoleo\CMS\User\User $user */ + $user = Factory::getContainer()->get(UserFactoryInterface::class)->getUser(); + // check that the user does not delete him/her self + $user_id = $user->get('id', -1); + if ($user_id == $id) + { + $this->getApplication()->enqueueMessage('You can not delete your own account!', 'warning'); + } + elseif ($this->model->delete($id)) + { + $this->getApplication()->enqueueMessage('User was deleted!', 'success'); + } + else + { + $this->getApplication()->enqueueMessage('User could not be deleted!', 'error'); + } + // go to set page + $this->_redirect('users'); + + return true; + } + + if ('POST' === $method) + { + $id = $this->setItem(); + } + + $this->view->setActiveId($id); + $this->view->setActiveView('user'); + + // check if user is allowed to access + if ($this->allow('user')) + { + $this->getApplication()->setResponse(new HtmlResponse($this->view->render())); + } + else + { + // go to set page + $this->_redirect(); + } + + return true; + } + + /** + * Set an item + * + * @return int + * @throws \Exception + */ + protected function setItem(): int + { + // always check the post token + $this->checkToken(); + // get the post + $post = $this->getInput()->getInputForRequestMethod(); + + // we get all the needed items + $tempItem = []; + $tempItem['id'] = $post->getInt('user_id', 0); + $tempItem['name'] = $post->getString('name', ''); + $tempItem['username'] = $post->getUsername('username', ''); + $tempItem['password'] = $post->getString('password', ''); + $tempItem['password2'] = $post->getString('password2', ''); + $tempItem['email'] = $post->getString('email', ''); + $tempItem['block'] = $post->getInt('block', 1); + $tempItem['sendEmail'] = $post->getInt('sendEmail', 1); + $tempItem['activation'] = $post->getInt('activation', 0); + + $can_save = true; + // check that we have a name + if (empty($tempItem['name'])) + { + // we show a warning message + $tempItem['name'] = ''; + $this->getApplication()->enqueueMessage('Name field is required.', 'error'); + $can_save = false; + } + // check that we have a username + if (empty($tempItem['username'])) + { + // we show a warning message + $tempItem['username'] = ''; + $this->getApplication()->enqueueMessage('Username field is required.', 'error'); + $can_save = false; + } + // check that we have an email TODO: check that we have a valid email + if (empty($tempItem['email'])) + { + // we show a warning message + $tempItem['email'] = ''; + $this->getApplication()->enqueueMessage('Email field is required.', 'error'); + $can_save = false; + } + // check passwords + if (isset($tempItem['password2']) && $tempItem['password'] != $tempItem['password2']) + { + // we show a warning message + $tempItem['password'] = 'xxxxxxxxxx'; + $tempItem['password2'] = 'xxxxxxxxxx'; + $this->getApplication()->enqueueMessage('Passwords do not match.', 'error'); + $can_save = false; + } + unset ($tempItem['password2']); + // do not set password that has not changed + if ($tempItem['password'] === 'xxxxxxxxxx') + { + if ($tempItem['id'] == 0) + { + // we show a warning message + $tempItem['password'] = 'xxxxxxxxxx'; + $tempItem['password2'] = 'xxxxxxxxxx'; + $this->getApplication()->enqueueMessage('Passwords not set.', 'error'); + $can_save = false; + } + else + { + $tempItem['password'] = ''; + } + } + elseif (strlen($tempItem['password']) < 7) + { + // we show a warning message + $tempItem['password'] = 'xxxxxxxxxx'; + $tempItem['password2'] = 'xxxxxxxxxx'; + $this->getApplication()->enqueueMessage('Passwords must be longer than 6 characters.', 'error'); + $can_save = false; + } + else + { + // hash the password + $tempItem['password'] = $this->secure->hashPassword($tempItem['password']); + } + + // can we save the item + if ($can_save) + { + /** @var \Octoleo\CMS\User\User $user */ + $user = Factory::getContainer()->get(UserFactoryInterface::class)->getUser(); + $today = (new Date())->toSql(); + + // check that the user does not block him/her self + $user_id = $user->get('id', -1); + if ($user_id == $tempItem['id'] && $tempItem['block'] == 1) + { + // don't allow user to block self + $this->getApplication()->enqueueMessage('You can not block yourself!', 'warning'); + $tempItem['block'] = 0; + } + + return $this->model->setItem( + $tempItem['id'], + $tempItem['name'], + $tempItem['username'], + $tempItem['email'], + $tempItem['password'], + $tempItem['block'], + $tempItem['sendEmail'], + $today, + $tempItem['activation']); + } + + // add to model the post values + $this->model->tempItem = $tempItem; + + return $tempItem['id']; + } +} diff --git a/week-04/project/libraries/src/Controller/UsersController.php b/week-04/project/libraries/src/Controller/UsersController.php new file mode 100644 index 0000000..628d58e --- /dev/null +++ b/week-04/project/libraries/src/Controller/UsersController.php @@ -0,0 +1,76 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Controller; + +use Joomla\Application\AbstractApplication; +use Joomla\Controller\AbstractController; +use Joomla\Input\Input; +use Octoleo\CMS\View\Admin\UsersHtmlView; +use Laminas\Diactoros\Response\HtmlResponse; + +/** + * Controller handling the site's dashboard + * + * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. + * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object + */ +class UsersController extends AbstractController implements AccessInterface, CheckTokenInterface +{ + use AccessTrait, CheckTokenTrait; + + /** + * The view object. + * + * @var UsersHtmlView + */ + private $view; + + /** + * Constructor. + * + * @param UsersHtmlView $view The view object. + * @param Input $input The input object. + * @param AbstractApplication $app The application object. + */ + public function __construct(UsersHtmlView $view, Input $input = null, AbstractApplication $app = null) + { + parent::__construct($input, $app); + + $this->view = $view; + } + + /** + * Execute the controller. + * + * @return boolean + * @throws \Exception + */ + public function execute(): bool + { + // Do not Enable browser caching + $this->getApplication()->allowCache(false); + + $this->view->setActiveView('users'); + + // check if user is allowed to access + if ($this->allow('users')) + { + $this->getApplication()->setResponse(new HtmlResponse($this->view->render())); + } + else + { + // go to set page + $this->_redirect(); + } + + return true; + } +} diff --git a/week-04/project/libraries/src/Controller/WrongCmsController.php b/week-04/project/libraries/src/Controller/WrongCmsController.php index 701e222..6755b27 100644 --- a/week-04/project/libraries/src/Controller/WrongCmsController.php +++ b/week-04/project/libraries/src/Controller/WrongCmsController.php @@ -31,7 +31,7 @@ class WrongCmsController extends AbstractController // Enable browser caching $this->getApplication()->allowCache(true); - $response = new TextResponse("This isn't the CMS you're looking for.", 404); + $response = new TextResponse("This isn't the what you're looking for.", 404); $this->getApplication()->setResponse($response); diff --git a/week-04/project/libraries/src/Factory.php b/week-04/project/libraries/src/Factory.php index 042209d..6ae8c63 100644 --- a/week-04/project/libraries/src/Factory.php +++ b/week-04/project/libraries/src/Factory.php @@ -147,6 +147,7 @@ abstract class Factory ->registerServiceProvider(new Service\ConfigurationProvider(LPATH_CONFIGURATION . '/octoconfig.php')) ->registerServiceProvider(new Service\SessionProvider) ->registerServiceProvider(new Service\UserProvider) + ->registerServiceProvider(new Service\InputProvider) ->registerServiceProvider(new DatabaseProvider) ->registerServiceProvider(new Service\EventProvider) ->registerServiceProvider(new Service\HttpProvider) diff --git a/week-04/project/libraries/src/Model/HomepageModel.php b/week-04/project/libraries/src/Model/HomepageModel.php new file mode 100644 index 0000000..232ef8e --- /dev/null +++ b/week-04/project/libraries/src/Model/HomepageModel.php @@ -0,0 +1,67 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +use Joomla\Database\DatabaseDriver; +use Joomla\Database\ParameterType; +use Joomla\Model\DatabaseModelInterface; +use Joomla\Model\DatabaseModelTrait; + +/** + * Model class for pages + * source: https://github.com/joomla/framework.joomla.org/blob/master/src/Model/PackageModel.php + */ +class HomepageModel implements DatabaseModelInterface, MenuInterface, PageInterface +{ + use DatabaseModelTrait, SiteMenuTrait, SitePageTrait; + + /** + * Instantiate the model. + * + * @param DatabaseDriver $db The database adapter. + */ + public function __construct(DatabaseDriver $db) + { + $this->setDb($db); + } + + /** + * @return \stdClass + */ + public function getHomePage(): \stdClass + { + $db = $this->getDb(); + + $query = $db->getQuery(true) + ->select('a.*') + ->from($db->quoteName('#__menu', 'a')) + ->where($db->quoteName('a.parent_id') . ' = 0') + ->where($db->quoteName('a.published') . ' = 1') + ->where($db->quoteName('a.home') . ' = 1') + ->setLimit(1); + + try + { + $home = $db->setQuery($query)->loadObject(); + } + catch (\RuntimeException $e) + { + return new \stdClass(); + } + + if ($home) + { + return $home; + } + + return new \stdClass(); + } +} diff --git a/week-04/project/libraries/src/Model/ItemModel.php b/week-04/project/libraries/src/Model/ItemModel.php new file mode 100644 index 0000000..a7c5622 --- /dev/null +++ b/week-04/project/libraries/src/Model/ItemModel.php @@ -0,0 +1,285 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +use Joomla\Database\DatabaseDriver; +use Joomla\Database\ParameterType; +use Joomla\Model\DatabaseModelInterface; +use Joomla\Model\DatabaseModelTrait; +use Octoleo\CMS\Date\Date; + +/** + * Model class for items + */ +class ItemModel implements DatabaseModelInterface +{ + use DatabaseModelTrait; + + /** + * @var array + */ + public $tempItem; + + /** + * Instantiate the model. + * + * @param DatabaseDriver $db The database adapter. + */ + public function __construct(DatabaseDriver $db) + { + $this->setDb($db); + } + + /** + * Add an item + * + * @param int $id + * @param string $title + * @param string $introtext + * @param string $fulltext + * @param int $state + * @param string $created + * @param int $createdBy + * @param string $createdByAlias + * @param string $modified + * @param int $modifiedBy + * @param string $publishUp + * @param string $publishDown + * @param string $metakey + * @param string $metadesc + * @param string $metadata + * @param int $featured + * + * @return int + * @throws \Exception + */ + public function setItem( + int $id, + string $title, + string $fulltext, + int $state, + string $created, + int $createdBy, + string $createdByAlias, + string $modified, + int $modifiedBy, + string $publishUp, + string $publishDown, + string $metakey, + string $metadesc, + string $metadata, + int $featured): int + { + $db = $this->getDb(); + + // extract the intro text + $introtext = ''; + if (strpos($fulltext, '

intro-text

')) + { + $bucket = explode('

intro-text

', $fulltext); + $introtext = array_shift($bucket); + $fulltext = implode('', $bucket); + } + + $data = [ + 'title' => (string) $title, + 'introtext' => (string) $introtext, + 'fulltext' => (string) $fulltext, + 'state' => (int) $state, + 'created' => (string) $created, + 'created_by' => (int) $createdBy, + 'created_by_alias' => (string) $createdByAlias, + 'modified' => (string) $modified, + 'modified_by' => (int) $modifiedBy, + 'publish_up' => (string) (empty($publishUp)) ? '0000-00-00 00:00:00' : (new Date($publishUp))->toSql(), + 'publish_down' => (string) (empty($publishDown)) ? '0000-00-00 00:00:00' : (new Date($publishDown))->toSql(), + 'metakey' => (string) $metakey, + 'metadesc' => (string) $metadesc, + 'metadata' => (string) $metadata, + 'featured' => (int) $featured + ]; + + // if we have ID update + if ($id > 0) + { + $data['id'] = (int) $id; + // remove what can not now be set + unset($data['created']); + unset($data['created_by']); + // change to object + $data = (object) $data; + + try + { + $db->updateObject('#__item', $data, 'id'); + } + catch (\RuntimeException $exception) + { + throw new \RuntimeException($exception->getMessage(), 404); + } + + return $id; + + } + else + { + // remove what can not now be set + $data['modified'] = '0000-00-00 00:00:00'; + $data['modified_by'] = 0; + // change to object + $data = (object) $data; + + try + { + $db->insertObject('#__item', $data); + } + catch (\RuntimeException $exception) + { + throw new \RuntimeException($exception->getMessage(), 404); + } + + return $db->insertid(); + } + } + + /** + * Get an item + * + * @param int|null $id + * + * @return \stdClass + * @throws \Exception + */ + public function getItem(?int $id): \stdClass + { + $db = $this->getDb(); + // default object (use posted values if set) + if (is_array($this->tempItem)) + { + $default = (object) $this->tempItem; + } + else + { + $default = new \stdClass(); + } + // to be sure ;) + $default->today_date = (new Date())->toSql(); + $default->post_key = "?task=create"; + $default->state = 1; + + // we return the default if id not correct + if (!is_numeric($id)) + { + return $default; + } + + $query = $db->getQuery(true) + ->select('*') + ->from($db->quoteName('#__item')) + ->where($db->quoteName('id') . ' = :id') + ->bind(':id', $id, ParameterType::INTEGER) + ->setLimit(1); + + try + { + $result = $db->setQuery($query)->loadObject(); + } + catch (\RuntimeException $e) + { + // we ignore this and just return an empty object + } + + if (isset($result) && $result instanceof \stdClass) + { + $result->post_key = "?id=$id&task=edit"; + $result->today_date = $default->today_date; + // check if we have intro text we add it to full text + if (!empty($result->introtext)) + { + $result->fulltext = $result->introtext . '

intro-text

' . $result->fulltext; + } + + return $result; + } + + return $default; + } + + /** + * @param string $name + * + * @return string + */ + public function setLayout(string $name): string + { + return $name . '.twig'; + } + + /** + * @param int $id + * + * @return bool + */ + public function linked(int $id): bool + { + $db = $this->getDb(); + // first check if this item is linked to menu + $query = $db->getQuery(true) + ->select($db->quoteName('title')) + ->from($db->quoteName('#__menu')) + ->where($db->quoteName('item_id') . ' = :id') + ->bind(':id', $id, ParameterType::INTEGER); + + try + { + $menu = $db->setQuery($query)->loadResult(); + } + catch (\RuntimeException $e) + { + // not linked... or something + return false; + } + + if ($menu) + { + return true; + } + + return false; + } + + /** + * @param int $id + * + * @return bool + */ + public function delete(int $id): bool + { + $db = $this->getDb(); + + // Purge the session + $query = $db->getQuery(true) + ->delete($db->quoteName('#__item')) + ->where($db->quoteName('id') . ' = :id') + ->bind(':id', $id, ParameterType::INTEGER); + try + { + $db->setQuery($query)->execute(); + } + catch (\RuntimeException $e) + { + // delete failed + return false; + } + + return true; + } +} diff --git a/week-04/project/libraries/src/Model/ItemsModel.php b/week-04/project/libraries/src/Model/ItemsModel.php new file mode 100644 index 0000000..30cc63e --- /dev/null +++ b/week-04/project/libraries/src/Model/ItemsModel.php @@ -0,0 +1,55 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +use Joomla\Database\DatabaseDriver; +use Joomla\Database\ParameterType; +use Joomla\Model\DatabaseModelInterface; +use Joomla\Model\DatabaseModelTrait; + +/** + * Model class for items + */ +class ItemsModel implements DatabaseModelInterface +{ + use DatabaseModelTrait; + + /** + * Instantiate the model. + * + * @param DatabaseDriver $db The database adapter. + */ + public function __construct(DatabaseDriver $db) + { + $this->setDb($db); + } + + /** + * Get all items + * + * @return array + */ + public function getItems(): array + { + $db = $this->getDb(); + + $query = $db->getQuery(true) + ->select('*') + ->from($db->quoteName('#__item')); + + return $db->setQuery($query)->loadObjectList('id'); + } + + public function setLayout(string $name): string + { + return $name . '.twig'; + } +} diff --git a/week-04/project/libraries/src/Model/MenuInterface.php b/week-04/project/libraries/src/Model/MenuInterface.php new file mode 100644 index 0000000..3e6c5eb --- /dev/null +++ b/week-04/project/libraries/src/Model/MenuInterface.php @@ -0,0 +1,28 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +/** + * Class for getting menu items + * + * @since 1.0.0 + */ +interface MenuInterface +{ + /** + * Get all menu items + * + * @param string|null $active + * + * @return array + */ + public function getMenus(string $active = null): array; +} diff --git a/week-04/project/libraries/src/Model/MenuModel.php b/week-04/project/libraries/src/Model/MenuModel.php new file mode 100644 index 0000000..0bc23b3 --- /dev/null +++ b/week-04/project/libraries/src/Model/MenuModel.php @@ -0,0 +1,338 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +use Joomla\Database\DatabaseDriver; +use Joomla\Database\ParameterType; +use Joomla\Model\DatabaseModelInterface; +use Joomla\Model\DatabaseModelTrait; +use Joomla\String\StringHelper; +use Octoleo\CMS\Date\Date; + +/** + * Model class for menu item + */ +class MenuModel implements DatabaseModelInterface +{ + use DatabaseModelTrait; + + /** + * @var array + */ + public $tempItem; + + /** + * Instantiate the model. + * + * @param DatabaseDriver $db The database adapter. + */ + public function __construct(DatabaseDriver $db) + { + $this->setDb($db); + } + + /** + * Add an item + * + * @param int $id + * @param string $title + * @param string $alias + * @param int $itemId + * @param string $path + * @param int $published + * @param string $publishUp + * @param string $publishDown + * @param string $position + * @param int $home + * + * @return int + * @throws \Exception + */ + public function setItem( + int $id, + string $title, + string $alias, + int $itemId, + string $path, + int $published, + string $publishUp, + string $publishDown, + string $position, + int $home): int + { + $db = $this->getDb(); + + // set the path if not set + $this->setPathAlias($id, $title, $path, $alias); + + $data = [ + 'title' => (string) $title, + 'alias' => (string) $alias, + 'path' => (string) $path, + 'item_id' => (int) $itemId, + 'published' => (int) $published, + 'publish_up' => (string) (empty($publishUp)) ? '0000-00-00 00:00:00' : (new Date($publishUp))->toSql(), + 'publish_down' => (string) (empty($publishDown)) ? '0000-00-00 00:00:00' : (new Date($publishDown))->toSql(), + 'home' => (int) $home, + 'parent_id' => 0 // only root items for now + ]; + + // we set position in params + $data['params'] = json_encode(['position' => $position]); + + // if we have ID update + if ($id > 0) + { + $data['id'] = (int) $id; + // change to object + $data = (object) $data; + + try + { + $db->updateObject('#__menu', $data, 'id'); + } + catch (\RuntimeException $exception) + { + throw new \RuntimeException($exception->getMessage(), 404); + } + } + else + { + // change to object + $data = (object) $data; + + try + { + $db->insertObject('#__menu', $data); + } + catch (\RuntimeException $exception) + { + throw new \RuntimeException($exception->getMessage(), 404); + } + + $id = $db->insertid(); + } + + // check if we have another home set + if ($data->home == 1) + { + $this->setHome($id); + } + + return $id; + } + + /** + * Get all published items + * + * @return array + */ + public function getItems(): array + { + $db = $this->getDb(); + + $query = $db->getQuery(true) + ->select($db->quoteName(array('id', 'title'))) + ->from($db->quoteName('#__item')) + ->where('state = 1'); + + return $db->setQuery($query)->loadObjectList('id'); + } + + /** + * Get an item + * + * @param int|null $id + * + * @return \stdClass + * @throws \Exception + */ + public function getItem(?int $id): \stdClass + { + $db = $this->getDb(); + // default object (use posted values if set) + if (is_array($this->tempItem)) + { + $default = (object) $this->tempItem; + } + else + { + $default = new \stdClass(); + } + // to be sure ;) + $default->today_date = (new Date())->toSql(); + $default->post_key = "?task=create"; + $default->published = 1; + $default->home = 0; + + // we return the default if id not correct + if (!is_numeric($id)) + { + return $default; + } + + $query = $db->getQuery(true) + ->select('*') + ->from($db->quoteName('#__menu')) + ->where($db->quoteName('id') . ' = :id') + ->bind(':id', $id, ParameterType::INTEGER) + ->setLimit(1); + + try + { + $result = $db->setQuery($query)->loadObject(); + } + catch (\RuntimeException $e) + { + // we ignore this and just return an empty object + } + + if (isset($result) && $result instanceof \stdClass) + { + $result->post_key = "?id=$id&task=edit"; + $result->today_date = $default->today_date; + // set the position + $result->params = json_decode($result->params); + + return $result; + } + + return $default; + } + + /** + * @param string $name + * + * @return string + */ + public function setLayout(string $name): string + { + return $name . '.twig'; + } + + /** + * @param int $id + * + * @return bool + */ + public function delete(int $id): bool + { + $db = $this->getDb(); + // Purge the session + $query = $db->getQuery(true) + ->delete($db->quoteName('#__menu')) + ->where($db->quoteName('id') . ' = :id') + ->bind(':id', $id, ParameterType::INTEGER); + try + { + $db->setQuery($query)->execute(); + } + catch (\RuntimeException $e) + { + // delete failed + return false; + } + return true; + } + + /** + * Make sure that we have only one home + * + * @param $id + * + * @return bool + */ + private function setHome($id): bool + { + $db = $this->getDb(); + // Purge the session + $query = $db->getQuery(true) + ->update($db->quoteName('#__menu')) + ->set($db->quoteName('home') . ' = 0') + ->where($db->quoteName('id') . ' != :id') + ->bind(':id', $id, ParameterType::INTEGER); + try + { + $db->setQuery($query)->execute(); + } + catch (\RuntimeException $e) + { + // delete failed + return false; + } + return true; + } + + /** + * @param int $id + * @param string $title + * @param string $path + * @param string $alias + */ + private function setPathAlias(int $id, string $title, string &$path, string &$alias) + { + $alias = (empty($alias)) ? $title : $alias; + $alias = preg_replace('/\s+/', '-', strtolower(preg_replace("/[^A-Za-z0-9\- ]/", '', $alias))); + // TODO: we will only have root menus for now, no sub-menus + $seeker = $alias; + $pointer = 2; + while ($this->exist($id, $seeker)) + { + $seeker = $alias . '-' . $pointer; + $pointer++; + } + // update the path + $alias = $seeker; + $path = $seeker; + } + + /** + * Check if an alias exist + * + * @param int $id + * @param string $alias + * + * @return bool + */ + private function exist(int $id, string $alias): bool + { + $db = $this->getDb(); + $query = $db->getQuery(true) + ->select('id') + ->from($db->quoteName('#__menu')) + ->where($db->quoteName('alias') . ' = :alias') + ->bind(':alias', $alias) + ->setLimit(1); + + // only add the id item exist + if ($id > 0) + { + $query + ->where($db->quoteName('id') . ' != :id') + ->bind(':id', $id, ParameterType::INTEGER); + } + + try + { + $id = $db->setQuery($query)->loadResult(); + } + catch (\RuntimeException $e) + { + // we ignore this and just return an empty object + } + + if (isset($id) && $id > 0) + { + return true; + } + return false; + } +} diff --git a/week-04/project/libraries/src/Model/MenusModel.php b/week-04/project/libraries/src/Model/MenusModel.php new file mode 100644 index 0000000..41bd3dc --- /dev/null +++ b/week-04/project/libraries/src/Model/MenusModel.php @@ -0,0 +1,62 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +use Joomla\Database\DatabaseDriver; +use Joomla\Database\ParameterType; +use Joomla\Model\DatabaseModelInterface; +use Joomla\Model\DatabaseModelTrait; + +/** + * Model class for menus + */ +class MenusModel implements DatabaseModelInterface +{ + use DatabaseModelTrait; + + /** + * Instantiate the model. + * + * @param DatabaseDriver $db The database adapter. + */ + public function __construct(DatabaseDriver $db) + { + $this->setDb($db); + } + + /** + * Get all items + * + * @return array + */ + public function getItems(): array + { + $db = $this->getDb(); + + $query = $db->getQuery(true) + ->select('a.*') + ->select($db->quoteName(array('t.title'), array('item_title'))) + ->from($db->quoteName('#__menu', 'a')) + ->join('INNER', $db->quoteName('#__item', 't'), 'a.item_id = t.id'); + + return $db->setQuery($query)->loadObjectList('id'); + } + + /** + * @param string $name + * + * @return string + */ + public function setLayout(string $name): string + { + return $name . '.twig'; + } +} diff --git a/week-04/project/libraries/src/Model/PageInterface.php b/week-04/project/libraries/src/Model/PageInterface.php new file mode 100644 index 0000000..91233d4 --- /dev/null +++ b/week-04/project/libraries/src/Model/PageInterface.php @@ -0,0 +1,41 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +/** + * Class for getting page data + * + * @since 1.0.0 + */ +interface PageInterface +{ + /** + * Get page data + * + * @param string $path The page path + * + * @return \stdClass + * + * @throws \RuntimeException + */ + public function getPageItemByPath(string $path): \stdClass; + + /** + * Get page data + * + * @param int $item The item id + * + * @return \stdClass + * + * @throws \RuntimeException + */ + public function getPageItemById(int $item): \stdClass; +} diff --git a/week-04/project/libraries/src/Model/PageModel.php b/week-04/project/libraries/src/Model/PageModel.php index 69eccbd..cfb6ac5 100644 --- a/week-04/project/libraries/src/Model/PageModel.php +++ b/week-04/project/libraries/src/Model/PageModel.php @@ -11,31 +11,15 @@ namespace Octoleo\CMS\Model; use Joomla\Database\DatabaseDriver; -use Joomla\Database\ParameterType; use Joomla\Model\DatabaseModelInterface; use Joomla\Model\DatabaseModelTrait; /** * Model class for pages - * source: https://github.com/joomla/framework.joomla.org/blob/master/src/Model/PackageModel.php */ -class PageModel implements DatabaseModelInterface +class PageModel implements DatabaseModelInterface, MenuInterface, PageInterface { - use DatabaseModelTrait; - - /** - * Array of legal pages - * - * @var array - */ - private $legalPages = ['products', 'blog', 'about-us', 'location', 'contact-us']; - - /** - * Array of legal details pages - * - * @var array - */ - private $legalDetailsPages = ['yachts', 'ski-boats', 'drones']; + use DatabaseModelTrait, SiteMenuTrait, SitePageTrait; /** * Instantiate the model. @@ -46,42 +30,4 @@ class PageModel implements DatabaseModelInterface { $this->setDb($db); } - - /** - * Get a page's data - * - * @param string $pageName The page to lookup - * - * @return string - * - * @throws \RuntimeException - */ - public function getPage(string $pageName): string - { - if (!in_array($pageName, $this->legalPages)) - { - throw new \RuntimeException(sprintf('Unable to find page data for the `%s`', $pageName), 404); - } - - return $pageName; - } - - /** - * Get a page's details data - * - * @param string $detailsName The page details to lookup - * - * @return string - * - * @throws \RuntimeException - */ - public function getDetails(string $detailsName): string - { - if (strlen($detailsName) && !in_array($detailsName, $this->legalDetailsPages)) - { - throw new \RuntimeException(sprintf('Unable to find page details data for the `%s`', $detailsName), 404); - } - - return $detailsName; - } } diff --git a/week-04/project/libraries/src/Model/SiteMenuTrait.php b/week-04/project/libraries/src/Model/SiteMenuTrait.php new file mode 100644 index 0000000..41d7af1 --- /dev/null +++ b/week-04/project/libraries/src/Model/SiteMenuTrait.php @@ -0,0 +1,70 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +/** + * Trait for getting menu items + * + * @since 1.0.0 + */ +trait SiteMenuTrait +{ + /** + * Get all menu items that are root and published and not home page + * + * @param string|null $active + * + * @return array + */ + public function getMenus($active = null): array + { + $db = $this->getDb(); + + $query = $db->getQuery(true) + ->select('a.*') + ->from($db->quoteName('#__menu', 'a')) + ->where($db->quoteName('a.parent_id') . ' = 0') + ->where($db->quoteName('a.published') . ' = 1') + ->where($db->quoteName('a.home') . ' = 0'); + + try + { + $menus = $db->setQuery($query)->loadObjectList(); + } + catch (\RuntimeException $e) + { + return []; + } + + if ($menus) + { + $bucket = []; + foreach ($menus as $menu) + { + $row = []; + // set the details + $row['title'] = $menu->title; + $row['path'] = $menu->path; + $row['root'] = true; + // set position + $params = (isset($menu->params) && strpos($menu->params, 'position') !== false) ? json_decode($menu->params) : null; + // default is center + $row['position'] = (is_object($params) && isset($params->position)) ? $params->position : 'center'; + + // add to our bucket + $bucket[] = $row; + } + return $bucket; + } + + return []; + } +} diff --git a/week-04/project/libraries/src/Model/SitePageTrait.php b/week-04/project/libraries/src/Model/SitePageTrait.php new file mode 100644 index 0000000..da9b0db --- /dev/null +++ b/week-04/project/libraries/src/Model/SitePageTrait.php @@ -0,0 +1,96 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +use Joomla\Database\ParameterType; + +/** + * Trait for getting page data + * + * @since 1.0.0 + */ +trait SitePageTrait +{ + /** + * Get page data + * + * @param string $path The page path + * + * @return \stdClass + * + * @throws \RuntimeException + */ + public function getPageItemByPath(string $path): \stdClass + { + $db = $this->getDb(); + + $query = $db->getQuery(true) + ->select('t.*') + ->from($db->quoteName('#__menu', 'a')) + ->join('INNER', $db->quoteName('#__item', 't'), 'a.item_id = t.id') + ->where($db->quoteName('path') . ' = :path') + ->bind(':path', $path) + ->setLimit(1); + + try + { + $page = $db->setQuery($query)->loadObject(); + } + catch (\RuntimeException $e) + { + return new \stdClass(); + } + + if ($page) + { + return $page; + } + + return new \stdClass(); + } + + /** + * Get page data + * + * @param int $item The item id + * + * @return \stdClass + * + * @throws \RuntimeException + */ + public function getPageItemById(int $item): \stdClass + { + $db = $this->getDb(); + + $query = $db->getQuery(true) + ->select('a.*') + ->from($db->quoteName('#__item', 'a')) + ->where($db->quoteName('id') . ' = :id') + ->bind(':id', $item, ParameterType::INTEGER) + ->setLimit(1); + + try + { + $page = $db->setQuery($query)->loadObject(); + } + catch (\RuntimeException $e) + { + return new \stdClass(); + } + + if ($page) + { + return $page; + } + + return new \stdClass(); + } +} diff --git a/week-04/project/libraries/src/Model/UserModel.php b/week-04/project/libraries/src/Model/UserModel.php new file mode 100644 index 0000000..cc1cf65 --- /dev/null +++ b/week-04/project/libraries/src/Model/UserModel.php @@ -0,0 +1,226 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +use Joomla\Database\DatabaseDriver; +use Joomla\Database\ParameterType; +use Joomla\Model\DatabaseModelInterface; +use Joomla\Model\DatabaseModelTrait; +use Octoleo\CMS\Date\Date; + +/** + * Model class for items + */ +class UserModel implements DatabaseModelInterface +{ + use DatabaseModelTrait; + + /** + * @var array + */ + public $tempItem; + + /** + * Instantiate the model. + * + * @param DatabaseDriver $db The database adapter. + */ + public function __construct(DatabaseDriver $db) + { + $this->setDb($db); + } + + /** + * Add an item + * + * @param int $id + * @param string $name + * @param string $username + * @param string $email + * @param string $password + * @param int $block + * @param int $sendEmail + * @param string $registerDate + * @param int $activation + * + * @return int + * @throws \Exception + */ + public function setItem( + int $id, + string $name, + string $username, + string $email, + string $password, + int $block, + int $sendEmail, + string $registerDate, + int $activation): int + { + $db = $this->getDb(); + + $data = [ + 'name' => (string) $name, + 'username' => (string) $username, + 'email' => (string) $email, + 'block' => (int) $block, + 'sendEmail' => (int) $sendEmail, + 'registerDate' => (string) (empty($registerDate)) ? (new Date())->toSql() : (new Date($registerDate))->toSql(), + 'activation' => (int) $activation + ]; + + // only update password if set + if (!empty($password) && strlen($password) > 6) + { + $data['password'] = (string) $password; + } + + // if we have ID update + if ($id > 0) + { + $data['id'] = (int) $id; + // we remove registration date when we update the user + unset($data['registerDate']); + // change to object + $data = (object) $data; + + try + { + $db->updateObject('#__users', $data, 'id'); + } + catch (\RuntimeException $exception) + { + throw new \RuntimeException($exception->getMessage(), 404); + } + + return $id; + + } + else + { + // change to object + $data = (object) $data; + + try + { + $db->insertObject('#__users', $data); + } + catch (\RuntimeException $exception) + { + throw new \RuntimeException($exception->getMessage(), 404); + } + + return $db->insertid(); + } + } + + /** + * Get an item + * + * @param int|null $id + * + * @return \stdClass + * @throws \Exception + */ + public function getItem(?int $id): \stdClass + { + $db = $this->getDb(); + // default object (use posted values if set) + if (is_array($this->tempItem)) + { + $default = (object) $this->tempItem; + } + else + { + $default = new \stdClass(); + } + // to be sure ;) + $default->today_date = (new Date())->toSql(); + $default->post_key = "?task=create"; + $default->block = 0; + $default->activation = 1; + $default->sendEmail = 1; + // always remove password + $default->password = 'xxxxxxxxxx'; + $default->password2 = 'xxxxxxxxxx'; + + // we return the default if id not correct + if (!is_numeric($id)) + { + return $default; + } + + $query = $db->getQuery(true) + ->select('*') + ->from($db->quoteName('#__users')) + ->where($db->quoteName('id') . ' = :id') + ->bind(':id', $id, ParameterType::INTEGER) + ->setLimit(1); + + try + { + $result = $db->setQuery($query)->loadObject(); + } + catch (\RuntimeException $e) + { + // we ignore this and just return an empty object + } + + if (isset($result) && $result instanceof \stdClass) + { + $result->post_key = "?id=$id&task=edit"; + $result->today_date = $default->today_date; + // always remove password + $result->password = $default->password; + $result->password2 = $default->password2; + + return $result; + } + + return $default; + } + + /** + * @param string $name + * + * @return string + */ + public function setLayout(string $name): string + { + return $name . '.twig'; + } + + /** + * @param int $id + * + * @return bool + */ + public function delete(int $id): bool + { + $db = $this->getDb(); + // Purge the session + $query = $db->getQuery(true) + ->delete($db->quoteName('#__users')) + ->where($db->quoteName('id') . ' = :id') + ->bind(':id', $id, ParameterType::INTEGER); + try + { + $db->setQuery($query)->execute(); + } + catch (\RuntimeException $e) + { + // delete failed + return false; + } + + return true; + } +} diff --git a/week-04/project/libraries/src/Model/UsersModel.php b/week-04/project/libraries/src/Model/UsersModel.php new file mode 100644 index 0000000..dcd16cf --- /dev/null +++ b/week-04/project/libraries/src/Model/UsersModel.php @@ -0,0 +1,55 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Model; + +use Joomla\Database\DatabaseDriver; +use Joomla\Database\ParameterType; +use Joomla\Model\DatabaseModelInterface; +use Joomla\Model\DatabaseModelTrait; + +/** + * Model class for users + */ +class UsersModel implements DatabaseModelInterface +{ + use DatabaseModelTrait; + + /** + * Instantiate the model. + * + * @param DatabaseDriver $db The database adapter. + */ + public function __construct(DatabaseDriver $db) + { + $this->setDb($db); + } + + /** + * Get all items + * + * @return array + */ + public function getItems(): array + { + $db = $this->getDb(); + + $query = $db->getQuery(true) + ->select('*') + ->from($db->quoteName('#__users')); + + return $db->setQuery($query)->loadObjectList('id'); + } + + public function setLayout(string $name): string + { + return $name . '.twig'; + } +} diff --git a/week-04/project/libraries/src/Renderer/FrameworkExtension.php b/week-04/project/libraries/src/Renderer/FrameworkExtension.php index 33c612e..f5d0e5f 100644 --- a/week-04/project/libraries/src/Renderer/FrameworkExtension.php +++ b/week-04/project/libraries/src/Renderer/FrameworkExtension.php @@ -45,7 +45,9 @@ class FrameworkExtension extends AbstractExtension new TwigFunction('request_uri', [FrameworkTwigRuntime::class, 'getRequestUri']), new TwigFunction('route', [FrameworkTwigRuntime::class, 'getRouteUri']), new TwigFunction('sri', [FrameworkTwigRuntime::class, 'getSriAttributes'], ['is_safe' => ['html']]), - new TwigFunction('url', [FrameworkTwigRuntime::class, 'getRouteUrl']), + new TwigFunction('message_queue', [FrameworkTwigRuntime::class, 'getMessageQueue']), + new TwigFunction('token', [FrameworkTwigRuntime::class, 'getToken']), + new TwigFunction('shorten_string', [FrameworkTwigRuntime::class, 'shortenString']), ]; } diff --git a/week-04/project/libraries/src/Renderer/FrameworkTwigRuntime.php b/week-04/project/libraries/src/Renderer/FrameworkTwigRuntime.php index 3db62bb..b9c89f2 100644 --- a/week-04/project/libraries/src/Renderer/FrameworkTwigRuntime.php +++ b/week-04/project/libraries/src/Renderer/FrameworkTwigRuntime.php @@ -10,6 +10,7 @@ namespace Octoleo\CMS\Renderer; use Joomla\Application\AbstractApplication; use Joomla\Preload\PreloadManager; +use Joomla\Session\SessionInterface; /** * Twig runtime class @@ -45,15 +46,22 @@ class FrameworkTwigRuntime */ private $sriManifestPath; + /** + * @var SessionInterface + */ + private $session; + /** * Constructor * - * @param AbstractApplication $app The application object - * @param PreloadManager $preloadManager The HTTP/2 preload manager - * @param string $sriManifestPath The path to the SRI manifest data + * @param AbstractApplication $app The application object + * @param PreloadManager $preloadManager The HTTP/2 preload manager + * @param string $sriManifestPath The path to the SRI manifest data + * @param SessionInterface|null $session The session object */ - public function __construct(AbstractApplication $app, PreloadManager $preloadManager, string $sriManifestPath) + public function __construct(AbstractApplication $app, PreloadManager $preloadManager, string $sriManifestPath, $session = null) { + $this->session = $session; $this->app = $app; $this->preloadManager = $preloadManager; $this->sriManifestPath = $sriManifestPath; @@ -93,6 +101,68 @@ class FrameworkTwigRuntime return $this->app->get('uri.base.host') . $this->getRouteUri($route); } + /** + * Get form Token + * + * @return string + */ + public function getToken(): string + { + if ($this->session instanceof SessionInterface) + { + return $this->session->getToken(); + } + return ''; + } + + /** + * Shorten a string + * + * @input string The you would like to shorten + * + * @returns string on success + * + * @since 1.0.0 + */ + public function shortenString($string, $length = 100) + { + if (is_string($string) && strlen($string) > $length) + { + $initial = strlen($string); + $words = preg_split('/([\s\n\r]+)/', $string, null, PREG_SPLIT_DELIM_CAPTURE); + $words_count = count((array)$words); + + $word_length = 0; + $last_word = 0; + for (; $last_word < $words_count; ++$last_word) + { + $word_length += strlen($words[$last_word]); + if ($word_length > $length) + { + break; + } + } + + $newString = implode(array_slice($words, 0, $last_word)); + return trim($newString) . '...'; + } + return $string; + } + + /** + * Get any messages in the queue + * + * @return array + */ + public function getMessageQueue(): array + { + if (method_exists($this->app, 'getMessageQueue')) + { + return $this->app->getMessageQueue(true); + } + return []; + } + /** * Get the SRI attributes for an asset * diff --git a/week-04/project/libraries/src/Service/AdminApplicationProvider.php b/week-04/project/libraries/src/Service/AdminApplicationProvider.php index b4202c0..1daf534 100644 --- a/week-04/project/libraries/src/Service/AdminApplicationProvider.php +++ b/week-04/project/libraries/src/Service/AdminApplicationProvider.php @@ -11,26 +11,17 @@ namespace Octoleo\CMS\Service; use Joomla\Application\AbstractWebApplication; -use Joomla\Application\Controller\ContainerControllerResolver; use Joomla\Application\Controller\ControllerResolverInterface; use Joomla\Application\Web\WebClient; -use Joomla\Database\DatabaseInterface; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; use Joomla\Event\DispatcherInterface; use Joomla\Session\SessionInterface; -use Octoleo\CMS\Controller\DashboardController; -use Octoleo\CMS\Controller\LoginController; -use Octoleo\CMS\Controller\WrongCmsController; -use Octoleo\CMS\Model\DashboardModel; use Octoleo\CMS\User\UserFactoryInterface; -use Octoleo\CMS\View\Admin\DashboardHtmlView; use Octoleo\CMS\Application\AdminApplication; use Joomla\Input\Input; -use Joomla\Renderer\RendererInterface; -use Joomla\Router\Router; use Joomla\Router\RouterInterface; use Psr\Log\LoggerInterface; @@ -60,138 +51,7 @@ class AdminApplicationProvider implements ServiceProviderInterface /* * Application Helpers and Dependencies */ - - // This service cannot be protected as it is decorated when the debug bar is available - $container->alias(ContainerControllerResolver::class, ControllerResolverInterface::class) - ->share(ControllerResolverInterface::class, [$this, 'getControllerResolverService']); - $container->share(WebClient::class, [$this, 'getWebClientService'], true); - - // This service cannot be protected as it is decorated when the debug bar is available - $container->alias(RouterInterface::class, 'application.router') - ->alias(Router::class, 'application.router') - ->share('application.router', [$this, 'getApplicationRouterService']); - - $container->share(Input::class, [$this, 'getInputClassService'], true); - - /* - * MVC Layer - */ - - // Controllers - $container->alias(DashboardController::class, 'controller.dashboard') - ->share('controller.dashboard', [$this, 'getControllerDashboardService'], true); - - $container->alias(LoginController::class, 'controller.login') - ->share('controller.login', [$this, 'getControllerLoginService'], true); - - $container->alias(WrongCmsController::class, 'controller.wrong.cms') - ->share('controller.wrong.cms', [$this, 'getControllerWrongCmsService'], true); - - // Models - $container->alias(DashboardModel::class, 'model.dashboard') - ->share('model.dashboard', [$this, 'getModelDashboardService'], true); - - // Views - $container->alias(DashboardHtmlView::class, 'view.dashboard.html') - ->share('view.dashboard.html', [$this, 'getViewDashboardHtmlService'], true); - } - - /** - * Get the `application.router` service - * - * @param Container $container The DI container. - * - * @return RouterInterface - */ - public function getApplicationRouterService(Container $container): RouterInterface - { - $router = new Router; - - /* - * CMS Admin Panels - */ - $router->all( - '/index.php?dashboard=*', - DashboardController::class - ); - $router->get( - '/*', - LoginController::class - ); - - return $router; - } - - /** - * Get the `controller.login` service - * - * @param Container $container The DI container. - * - * @return LoginController - */ - public function getControllerLoginService(Container $container): LoginController - { - return new LoginController( - $container->get(RendererInterface::class), - $container->get(Input::class), - $container->get(AdminApplication::class) - ); - } - - /** - * Get the `controller.dashboard` service - * - * @param Container $container The DI container. - * - * @return DashboardController - */ - public function getControllerDashboardService(Container $container): DashboardController - { - return new DashboardController( - $container->get(DashboardHtmlView::class), - $container->get(Input::class), - $container->get(AdminApplication::class) - ); - } - - /** - * Get the `controller.wrong.cms` service - * - * @param Container $container The DI container. - * - * @return WrongCmsController - */ - public function getControllerWrongCmsService(Container $container): WrongCmsController - { - return new WrongCmsController( - $container->get(Input::class), - $container->get(AdminApplication::class) - ); - } - - /** - * Get the Input class service - * - * @param Container $container The DI container. - * - * @return Input - */ - public function getInputClassService(Container $container): Input - { - return new Input($_REQUEST); - } - - /** - * Get the `model.dashboard` service - * - * @param Container $container The DI container. - * - * @return DashboardModel - */ - public function getModelDashboardService(Container $container): DashboardModel - { - return new DashboardModel($container->get(DatabaseInterface::class)); } /** @@ -223,33 +83,6 @@ class AdminApplicationProvider implements ServiceProviderInterface return $application; } - /** - * Get the controller resolver service - * - * @param Container $container The DI container. - * - * @return ControllerResolverInterface - */ - public function getControllerResolverService(Container $container): ControllerResolverInterface - { - return new ContainerControllerResolver($container); - } - - /** - * Get the `view.page.html` service - * - * @param Container $container The DI container. - * - * @return DashboardHtmlView - */ - public function getViewDashboardHtmlService(Container $container): DashboardHtmlView - { - return new DashboardHtmlView( - $container->get('model.dashboard'), - $container->get('renderer') - ); - } - /** * Get the web client service * diff --git a/week-04/project/libraries/src/Service/AdminMVCProvider.php b/week-04/project/libraries/src/Service/AdminMVCProvider.php new file mode 100644 index 0000000..d572893 --- /dev/null +++ b/week-04/project/libraries/src/Service/AdminMVCProvider.php @@ -0,0 +1,485 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Service; + +use Joomla\Application\Controller\ContainerControllerResolver; +use Joomla\Application\Controller\ControllerResolverInterface; +use Joomla\Database\DatabaseInterface; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +use Octoleo\CMS\Controller\DashboardController; +use Octoleo\CMS\Controller\ItemsController; +use Octoleo\CMS\Controller\ItemController; +use Octoleo\CMS\Controller\LoginController; +use Octoleo\CMS\Controller\MenuController; +use Octoleo\CMS\Controller\MenusController; +use Octoleo\CMS\Controller\UserController; +use Octoleo\CMS\Controller\UsersController; +use Octoleo\CMS\Controller\WrongCmsController; +use Octoleo\CMS\Model\DashboardModel; +use Octoleo\CMS\Model\ItemsModel; +use Octoleo\CMS\Model\ItemModel; +use Octoleo\CMS\Model\MenusModel; +use Octoleo\CMS\Model\MenuModel; +use Octoleo\CMS\Model\UserModel; +use Octoleo\CMS\Model\UsersModel; +use Octoleo\CMS\View\Admin\DashboardHtmlView; +use Octoleo\CMS\View\Admin\ItemsHtmlView; +use Octoleo\CMS\View\Admin\ItemHtmlView; +use Octoleo\CMS\View\Admin\MenuHtmlView; +use Octoleo\CMS\View\Admin\MenusHtmlView; +use Octoleo\CMS\View\Admin\UserHtmlView; +use Octoleo\CMS\View\Admin\UsersHtmlView; +use Octoleo\CMS\Application\AdminApplication; + +use Joomla\Input\Input; +use Joomla\Renderer\RendererInterface; + +/** + * Model View Controller service provider + */ +class AdminMVCProvider implements ServiceProviderInterface +{ + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + */ + public function register(Container $container): void + { + // This service cannot be protected as it is decorated when the debug bar is available + $container->alias(ContainerControllerResolver::class, ControllerResolverInterface::class) + ->share(ControllerResolverInterface::class, [$this, 'getControllerResolverService']); + + // Controllers + $container->alias(DashboardController::class, 'controller.dashboard') + ->share('controller.dashboard', [$this, 'getControllerDashboardService'], true); + + $container->alias(UsersController::class, 'controller.users') + ->share('controller.users', [$this, 'getControllerUsersService'], true); + + $container->alias(UserController::class, 'controller.user') + ->share('controller.user', [$this, 'getControllerUserService'], true); + + $container->alias(MenusController::class, 'controller.menus') + ->share('controller.menus', [$this, 'getControllerMenusService'], true); + + $container->alias(MenuController::class, 'controller.menu') + ->share('controller.menu', [$this, 'getControllerMenuService'], true); + + $container->alias(ItemsController::class, 'controller.items') + ->share('controller.items', [$this, 'getControllerItemsService'], true); + + $container->alias(ItemController::class, 'controller.item') + ->share('controller.item', [$this, 'getControllerItemService'], true); + + $container->alias(LoginController::class, 'controller.login') + ->share('controller.login', [$this, 'getControllerLoginService'], true); + + $container->alias(WrongCmsController::class, 'controller.wrong.cms') + ->share('controller.wrong.cms', [$this, 'getControllerWrongCmsService'], true); + + // Models + $container->alias(DashboardModel::class, 'model.dashboard') + ->share('model.dashboard', [$this, 'getModelDashboardService'], true); + + $container->alias(UsersModel::class, 'model.users') + ->share('model.users', [$this, 'getModelUsersService'], true); + + $container->alias(UserModel::class, 'model.user') + ->share('model.user', [$this, 'getModelUserService'], true); + + $container->alias(MenusModel::class, 'model.menus') + ->share('model.menus', [$this, 'getModelMenusService'], true); + + $container->alias(MenuModel::class, 'model.menu') + ->share('model.menu', [$this, 'getModelMenuService'], true); + + $container->alias(ItemsModel::class, 'model.items') + ->share('model.items', [$this, 'getModelItemsService'], true); + + $container->alias(ItemModel::class, 'model.item') + ->share('model.item', [$this, 'getModelItemService'], true); + + // Views + $container->alias(DashboardHtmlView::class, 'view.dashboard.html') + ->share('view.dashboard.html', [$this, 'getViewDashboardHtmlService'], true); + + $container->alias(UsersHtmlView::class, 'view.users.html') + ->share('view.users.html', [$this, 'getViewUsersHtmlService'], true); + + $container->alias(UserHtmlView::class, 'view.user.html') + ->share('view.user.html', [$this, 'getViewUserHtmlService'], true); + + $container->alias(MenusHtmlView::class, 'view.menus.html') + ->share('view.menus.html', [$this, 'getViewMenusHtmlService'], true); + + $container->alias(MenuHtmlView::class, 'view.menu.html') + ->share('view.menu.html', [$this, 'getViewMenuHtmlService'], true); + + $container->alias(ItemsHtmlView::class, 'view.items.html') + ->share('view.items.html', [$this, 'getViewItemsHtmlService'], true); + + $container->alias(ItemHtmlView::class, 'view.item.html') + ->share('view.item.html', [$this, 'getViewItemHtmlService'], true); + } + + /** + * Get the controller resolver service + * + * @param Container $container The DI container. + * + * @return ControllerResolverInterface + */ + public function getControllerResolverService(Container $container): ControllerResolverInterface + { + return new ContainerControllerResolver($container); + } + + /** + * Get the `controller.login` service + * + * @param Container $container The DI container. + * + * @return LoginController + */ + public function getControllerLoginService(Container $container): LoginController + { + return new LoginController( + $container->get(DashboardHtmlView::class), + $container->get(RendererInterface::class), + $container->get(Input::class), + $container->get(AdminApplication::class) + ); + } + + /** + * Get the `controller.wrong.cms` service + * + * @param Container $container The DI container. + * + * @return WrongCmsController + */ + public function getControllerWrongCmsService(Container $container): WrongCmsController + { + return new WrongCmsController( + $container->get(Input::class), + $container->get(AdminApplication::class) + ); + } + + /** + * Get the `controller.dashboard` service + * + * @param Container $container The DI container. + * + * @return DashboardController + */ + public function getControllerDashboardService(Container $container): DashboardController + { + return new DashboardController( + $container->get(DashboardHtmlView::class), + $container->get(Input::class), + $container->get(AdminApplication::class) + ); + } + + /** + * Get the `model.dashboard` service + * + * @param Container $container The DI container. + * + * @return DashboardModel + */ + public function getModelDashboardService(Container $container): DashboardModel + { + return new DashboardModel($container->get(DatabaseInterface::class)); + } + + /** + * Get the `view.dashboard.html` service + * + * @param Container $container The DI container. + * + * @return DashboardHtmlView + */ + public function getViewDashboardHtmlService(Container $container): DashboardHtmlView + { + return new DashboardHtmlView( + $container->get('model.dashboard'), + $container->get('renderer') + ); + } + + /** + * Get the `controller.users` service + * + * @param Container $container The DI container. + * + * @return UsersController + */ + public function getControllerUsersService(Container $container): UsersController + { + return new UsersController( + $container->get(UsersHtmlView::class), + $container->get(Input::class), + $container->get(AdminApplication::class) + ); + } + + /** + * Get the `model.users` service + * + * @param Container $container The DI container. + * + * @return UsersModel + */ + public function getModelUsersService(Container $container): UsersModel + { + return new UsersModel($container->get(DatabaseInterface::class)); + } + + /** + * Get the `view.users.html` service + * + * @param Container $container The DI container. + * + * @return UsersHtmlView + */ + public function getViewUsersHtmlService(Container $container): UsersHtmlView + { + return new UsersHtmlView( + $container->get('model.users'), + $container->get('renderer') + ); + } + + /** + * Get the `controller.user` service + * + * @param Container $container The DI container. + * + * @return UserController + */ + public function getControllerUserService(Container $container): UserController + { + return new UserController( + $container->get(UserModel::class), + $container->get(UserHtmlView::class), + $container->get(Input::class), + $container->get(AdminApplication::class) + ); + } + + /** + * Get the `model.user` service + * + * @param Container $container The DI container. + * + * @return UserModel + */ + public function getModelUserService(Container $container): UserModel + { + return new UserModel($container->get(DatabaseInterface::class)); + } + + /** + * Get the `view.user.html` service + * + * @param Container $container The DI container. + * + * @return UserHtmlView + */ + public function getViewUserHtmlService(Container $container): UserHtmlView + { + return new UserHtmlView( + $container->get('model.user'), + $container->get('renderer') + ); + } + + /** + * Get the `controller.menus` service + * + * @param Container $container The DI container. + * + * @return MenusController + */ + public function getControllerMenusService(Container $container): MenusController + { + return new MenusController( + $container->get(MenusHtmlView::class), + $container->get(Input::class), + $container->get(AdminApplication::class) + ); + } + + /** + * Get the `model.menus` service + * + * @param Container $container The DI container. + * + * @return MenusModel + */ + public function getModelMenusService(Container $container): MenusModel + { + return new MenusModel($container->get(DatabaseInterface::class)); + } + + /** + * Get the `view.menus.html` service + * + * @param Container $container The DI container. + * + * @return MenusHtmlView + */ + public function getViewMenusHtmlService(Container $container): MenusHtmlView + { + return new MenusHtmlView( + $container->get('model.menus'), + $container->get('renderer') + ); + } + + /** + * Get the `controller.menu` service + * + * @param Container $container The DI container. + * + * @return MenuController + */ + public function getControllerMenuService(Container $container): MenuController + { + return new MenuController( + $container->get(MenuModel::class), + $container->get(MenuHtmlView::class), + $container->get(Input::class), + $container->get(AdminApplication::class) + ); + } + + /** + * Get the `model.menu` service + * + * @param Container $container The DI container. + * + * @return MenuModel + */ + public function getModelMenuService(Container $container): MenuModel + { + return new MenuModel($container->get(DatabaseInterface::class)); + } + + /** + * Get the `view.menu.html` service + * + * @param Container $container The DI container. + * + * @return MenuHtmlView + */ + public function getViewMenuHtmlService(Container $container): MenuHtmlView + { + return new MenuHtmlView( + $container->get('model.menu'), + $container->get('renderer') + ); + } + + /** + * Get the `controller.items` service + * + * @param Container $container The DI container. + * + * @return ItemsController + */ + public function getControllerItemsService(Container $container): ItemsController + { + return new ItemsController( + $container->get(ItemsHtmlView::class), + $container->get(Input::class), + $container->get(AdminApplication::class) + ); + } + + /** + * Get the `model.items` service + * + * @param Container $container The DI container. + * + * @return ItemsModel + */ + public function getModelItemsService(Container $container): ItemsModel + { + return new ItemsModel($container->get(DatabaseInterface::class)); + } + + /** + * Get the `view.items.html` service + * + * @param Container $container The DI container. + * + * @return ItemsHtmlView + */ + public function getViewItemsHtmlService(Container $container): ItemsHtmlView + { + return new ItemsHtmlView( + $container->get('model.items'), + $container->get('renderer') + ); + } + + /** + * Get the `controller.item` service + * + * @param Container $container The DI container. + * + * @return ItemController + */ + public function getControllerItemService(Container $container): ItemController + { + return new ItemController( + $container->get(ItemModel::class), + $container->get(ItemHtmlView::class), + $container->get(Input::class), + $container->get(AdminApplication::class) + ); + } + + /** + * Get the `model.item` service + * + * @param Container $container The DI container. + * + * @return ItemModel + */ + public function getModelItemService(Container $container): ItemModel + { + return new ItemModel($container->get(DatabaseInterface::class)); + } + + /** + * Get the `view.item.html` service + * + * @param Container $container The DI container. + * + * @return ItemHtmlView + */ + public function getViewItemHtmlService(Container $container): ItemHtmlView + { + return new ItemHtmlView( + $container->get('model.item'), + $container->get('renderer') + ); + } +} diff --git a/week-04/project/libraries/src/Service/AdminRouterProvider.php b/week-04/project/libraries/src/Service/AdminRouterProvider.php new file mode 100644 index 0000000..5ec5e29 --- /dev/null +++ b/week-04/project/libraries/src/Service/AdminRouterProvider.php @@ -0,0 +1,98 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Service; + +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +use Octoleo\CMS\Controller\DashboardController; +use Octoleo\CMS\Controller\LoginController; +use Octoleo\CMS\Controller\ItemsController; +use Octoleo\CMS\Controller\ItemController; +use Octoleo\CMS\Controller\MenuController; +use Octoleo\CMS\Controller\MenusController; +use Octoleo\CMS\Controller\UserController; +use Octoleo\CMS\Controller\UsersController; + +use Joomla\Router\Router; +use Joomla\Router\RouterInterface; + +/** + * Application service provider + * source: https://github.com/joomla/framework.joomla.org/blob/master/src/Service/ApplicationProvider.php + */ +class AdminRouterProvider implements ServiceProviderInterface +{ + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + */ + public function register(Container $container): void + { + // This service cannot be protected as it is decorated when the debug bar is available + $container->alias(RouterInterface::class, 'application.router') + ->alias(Router::class, 'application.router') + ->share('application.router', [$this, 'getApplicationRouterService']); + } + + /** + * Get the `application.router` service + * + * @param Container $container The DI container. + * + * @return RouterInterface + */ + public function getApplicationRouterService(Container $container): RouterInterface + { + $router = new Router; + + /** + * CMS Admin Panels + **/ + $router->all( + '/index.php/dashboard', + DashboardController::class + ); + $router->get( + '/index.php/users', + UsersController::class + ); + $router->all( + '/index.php/user', + UserController::class + ); + $router->get( + '/index.php/menus', + MenusController::class + ); + $router->all( + '/index.php/menu', + MenuController::class + ); + $router->get( + '/index.php/items', + ItemsController::class + ); + $router->all( + '/index.php/item', + ItemController::class + ); + $router->get( + '/*', + LoginController::class + ); + + return $router; + } +} diff --git a/week-04/project/libraries/src/Service/AdminTemplatingProvider.php b/week-04/project/libraries/src/Service/AdminTemplatingProvider.php new file mode 100644 index 0000000..84f5900 --- /dev/null +++ b/week-04/project/libraries/src/Service/AdminTemplatingProvider.php @@ -0,0 +1,314 @@ +alias(Packages::class, 'asset.packages') + ->share('asset.packages', [$this, 'getAssetPackagesService'], true); + + $container->alias(RendererInterface::class, 'renderer') + ->alias(TwigRenderer::class, 'renderer') + ->share('renderer', [$this, 'getRendererService'], true); + + $container->alias(CacheInterface::class, 'twig.cache') + ->alias(\Twig_CacheInterface::class, 'twig.cache') + ->share('twig.cache', [$this, 'getTwigCacheService'], true); + + $container->alias(Environment::class, 'twig.environment') + ->alias(\Twig_Environment::class, 'twig.environment') + ->share('twig.environment', [$this, 'getTwigEnvironmentService'], true); + + $container->alias(DebugExtension::class, 'twig.extension.debug') + ->alias(\Twig_Extension_Debug::class, 'twig.extension.debug') + ->share('twig.extension.debug', [$this, 'getTwigExtensionDebugService'], true); + + $container->alias(FrameworkExtension::class, 'twig.extension.framework') + ->share('twig.extension.framework', [$this, 'getTwigExtensionFrameworkService'], true); + + // This service cannot be protected as it is decorated when the debug bar is available + $container->alias(ProfilerExtension::class, 'twig.extension.profiler') + ->alias(\Twig_Extension_Profiler::class, 'twig.extension.profiler') + ->share('twig.extension.profiler', [$this, 'getTwigExtensionProfilerService']); + + $container->alias(LoaderInterface::class, 'twig.loader') + ->alias(\Twig_LoaderInterface::class, 'twig.loader') + ->share('twig.loader', [$this, 'getTwigLoaderService'], true); + + $container->alias(Profile::class, 'twig.profiler.profile') + ->alias(\Twig_Profiler_Profile::class, 'twig.profiler.profile') + ->share('twig.profiler.profile', [$this, 'getTwigProfilerProfileService'], true); + + $container->alias(FrameworkTwigRuntime::class, 'twig.runtime.framework') + ->share('twig.runtime.framework', [$this, 'getTwigRuntimeFrameworkService'], true); + + $container->alias(ContainerRuntimeLoader::class, 'twig.runtime.loader') + ->alias(\Twig_ContainerRuntimeLoader::class, 'twig.runtime.loader') + ->share('twig.runtime.loader', [$this, 'getTwigRuntimeLoaderService'], true); + + $this->tagTwigExtensions($container); + } + + /** + * Get the `asset.packages` service + * + * @param Container $container The DI container. + * + * @return Packages + */ + public function getAssetPackagesService(Container $container): Packages + { + /** @var AbstractApplication $app */ + $app = $container->get(AbstractApplication::class); + + $context = new ApplicationContext($app); + + $mediaPath = $app->get('uri.media.path', '/media/'); + + $defaultPackage = new PathPackage($mediaPath, new EmptyVersionStrategy, $context); + + $mixStrategy = new MixPathPackage( + $defaultPackage, + $mediaPath, + new JsonManifestVersionStrategy(LPATH_ROOT . '/media/mix-manifest.json'), + $context + ); + + return new Packages( + $defaultPackage, + [ + 'mix' => $mixStrategy, + ] + ); + } + + /** + * Get the `renderer` service + * + * @param Container $container The DI container. + * + * @return RendererInterface + */ + public function getRendererService(Container $container): RendererInterface + { + return new TwigRenderer($container->get('twig.environment')); + } + + /** + * Get the `twig.cache` service + * + * @param Container $container The DI container. + * + * @return \Twig_CacheInterface + */ + public function getTwigCacheService(Container $container): \Twig_CacheInterface + { + /** @var \Joomla\Registry\Registry $config */ + $config = $container->get('config'); + + // Pull down the renderer config + $cacheEnabled = $config->get('template.cache.enabled', false); + $cachePath = $config->get('template.cache.path', 'cache/twig'); + $debug = $config->get('template.debug', false); + + if ($debug === false && $cacheEnabled !== false) + { + return new FilesystemCache(LPATH_ROOT . '/' . $cachePath); + } + + return new NullCache; + } + + /** + * Get the `twig.environment` service + * + * @param Container $container The DI container. + * + * @return Environment + */ + public function getTwigEnvironmentService(Container $container): Environment + { + /** @var \Joomla\Registry\Registry $config */ + $config = $container->get('config'); + + $debug = $config->get('template.debug', false); + + $environment = new Environment( + $container->get('twig.loader'), + ['debug' => $debug] + ); + + // Add the runtime loader + $environment->addRuntimeLoader($container->get('twig.runtime.loader')); + + // Set up the environment's caching service + $environment->setCache($container->get('twig.cache')); + + // Add the Twig extensions + $environment->setExtensions($container->getTagged('twig.extension')); + + // Add a global tracking the debug states + $environment->addGlobal('appDebug', $config->get('debug', false)); + $environment->addGlobal('fwDebug', $debug); + + return $environment; + } + + /** + * Get the `twig.extension.debug` service + * + * @param Container $container The DI container. + * + * @return DebugExtension + */ + public function getTwigExtensionDebugService(Container $container): DebugExtension + { + return new DebugExtension; + } + + /** + * Get the `twig.extension.framework` service + * + * @param Container $container The DI container. + * + * @return FrameworkExtension + */ + public function getTwigExtensionFrameworkService(Container $container): FrameworkExtension + { + return new FrameworkExtension; + } + + /** + * Get the `twig.extension.profiler` service + * + * @param Container $container The DI container. + * + * @return ProfilerExtension + */ + public function getTwigExtensionProfilerService(Container $container): ProfilerExtension + { + return new ProfilerExtension($container->get('twig.profiler.profile')); + } + + /** + * Get the `twig.loader` service + * + * @param Container $container The DI container. + * + * @return \Twig_LoaderInterface + */ + public function getTwigLoaderService(Container $container): \Twig_LoaderInterface + { + return new FilesystemLoader([LPATH_TEMPLATES]); + } + + /** + * Get the `twig.profiler.profile` service + * + * @param Container $container The DI container. + * + * @return Profile + */ + public function getTwigProfilerProfileService(Container $container): Profile + { + return new Profile; + } + + /** + * Get the `twig.runtime.framework` service + * + * @param Container $container The DI container. + * + * @return FrameworkTwigRuntime + */ + public function getTwigRuntimeFrameworkService(Container $container): FrameworkTwigRuntime + { + return new FrameworkTwigRuntime( + $container->get(AbstractApplication::class), + $container->get(PreloadManager::class), + LPATH_ROOT . '/media/sri-manifest.json', + $container->get(SessionInterface::class) + ); + } + + /** + * Get the `twig.runtime.loader` service + * + * @param Container $container The DI container. + * + * @return ContainerRuntimeLoader + */ + public function getTwigRuntimeLoaderService(Container $container): ContainerRuntimeLoader + { + return new ContainerRuntimeLoader($container); + } + + /** + * Tag services which are Twig extensions + * + * @param Container $container The DI container. + * + * @return void + */ + private function tagTwigExtensions(Container $container): void + { + /** @var \Joomla\Registry\Registry $config */ + $config = $container->get('config'); + + $debug = $config->get('template.debug', false); + + $twigExtensions = ['twig.extension.framework']; + + if ($debug) + { + $twigExtensions[] = 'twig.extension.debug'; + } + + $container->tag('twig.extension', $twigExtensions); + } +} \ No newline at end of file diff --git a/week-04/project/libraries/src/Service/ConfigurationProvider.php b/week-04/project/libraries/src/Service/ConfigurationProvider.php index f655f82..64c0bb0 100644 --- a/week-04/project/libraries/src/Service/ConfigurationProvider.php +++ b/week-04/project/libraries/src/Service/ConfigurationProvider.php @@ -43,14 +43,15 @@ class ConfigurationProvider implements ServiceProviderInterface $this->config = new Registry(new \LConfig()); // Set database values based on config values - $this->config->loadObject( (object) ['database' => [ - 'driver' => 'mysql', - 'host' => $this->config->get('host'), - 'port' => $this->config->get('port', ''), - 'user' => $this->config->get('user'), - 'password' => $this->config->get('password'), - 'database' => $this->config->get('db'), - 'prefix' => $this->config->get('dbprefix') + $this->config->loadObject( (object) [ + 'database' => [ + 'driver' => $this->config->get('dbdriver'), + 'host' => $this->config->get('host'), + 'port' => $this->config->get('port', ''), + 'user' => $this->config->get('user'), + 'password' => $this->config->get('password'), + 'database' => $this->config->get('db'), + 'prefix' => $this->config->get('dbprefix') ] ]); } diff --git a/week-04/project/libraries/src/Service/InputProvider.php b/week-04/project/libraries/src/Service/InputProvider.php new file mode 100644 index 0000000..03cf6c4 --- /dev/null +++ b/week-04/project/libraries/src/Service/InputProvider.php @@ -0,0 +1,47 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\Service; + +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +use Joomla\Input\Input; + +/** + * Application service provider + * source: https://github.com/joomla/framework.joomla.org/blob/master/src/Service/ApplicationProvider.php + */ +class InputProvider implements ServiceProviderInterface +{ + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + */ + public function register(Container $container): void + { + $container->share(Input::class, [$this, 'getInputClassService'], true); + } + + /** + * Get the Input class service + * + * @param Container $container The DI container. + * + * @return Input + */ + public function getInputClassService(Container $container): Input + { + return new Input($_REQUEST); + } +} diff --git a/week-04/project/libraries/src/Service/SessionProvider.php b/week-04/project/libraries/src/Service/SessionProvider.php index 4ee6fda..9553030 100644 --- a/week-04/project/libraries/src/Service/SessionProvider.php +++ b/week-04/project/libraries/src/Service/SessionProvider.php @@ -10,7 +10,6 @@ namespace Octoleo\CMS\Service; -use Joomla\Application\AbstractWebApplication; use Joomla\Database\DatabaseInterface; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; diff --git a/week-04/project/libraries/src/Service/SiteApplicationProvider.php b/week-04/project/libraries/src/Service/SiteApplicationProvider.php index 01008e6..48f7dad 100644 --- a/week-04/project/libraries/src/Service/SiteApplicationProvider.php +++ b/week-04/project/libraries/src/Service/SiteApplicationProvider.php @@ -22,7 +22,9 @@ use Joomla\Event\DispatcherInterface; use Octoleo\CMS\Controller\HomepageController; use Octoleo\CMS\Controller\WrongCmsController; use Octoleo\CMS\Controller\PageController; +use Octoleo\CMS\Model\HomepageModel; use Octoleo\CMS\Model\PageModel; +use Octoleo\CMS\View\Page\HomepageHtmlView; use Octoleo\CMS\View\Page\PageHtmlView; use Octoleo\CMS\Application\SiteApplication; @@ -71,8 +73,6 @@ class SiteApplicationProvider implements ServiceProviderInterface ->alias(Router::class, 'application.router') ->share('application.router', [$this, 'getApplicationRouterService']); - $container->share(Input::class, [$this, 'getInputClassService'], true); - /* * MVC Layer */ @@ -88,10 +88,16 @@ class SiteApplicationProvider implements ServiceProviderInterface ->share('controller.wrong.cms', [$this, 'getControllerWrongCmsService'], true); // Models + $container->alias(HomepageModel::class, 'model.homepage') + ->share('model.homepage', [$this, 'getModelHomepageService'], true); + $container->alias(PageModel::class, 'model.page') ->share('model.page', [$this, 'getModelPageService'], true); // Views + $container->alias(HomepageHtmlView::class, 'view.homepage.html') + ->share('view.homepage.html', [$this, 'getViewHomepageHtmlService'], true); + $container->alias(PageHtmlView::class, 'view.page.html') ->share('view.page.html', [$this, 'getViewPageHtmlService'], true); } @@ -135,16 +141,6 @@ class SiteApplicationProvider implements ServiceProviderInterface PageController::class ); - $router->get( - '/:view', - PageController::class - ); - - $router->get( - '/:view/:details', - PageController::class - ); - return $router; } @@ -158,7 +154,7 @@ class SiteApplicationProvider implements ServiceProviderInterface public function getControllerHomepageService(Container $container): HomepageController { return new HomepageController( - $container->get(RendererInterface::class), + $container->get(HomepageHtmlView::class), $container->get(Input::class), $container->get(SiteApplication::class) ); @@ -196,15 +192,15 @@ class SiteApplicationProvider implements ServiceProviderInterface } /** - * Get the Input class service + * Get the `model.homepage` service * * @param Container $container The DI container. * - * @return Input + * @return HomepageModel */ - public function getInputClassService(Container $container): Input + public function getModelHomepageService(Container $container): HomepageModel { - return new Input($_REQUEST); + return new HomepageModel($container->get(DatabaseInterface::class)); } /** @@ -257,6 +253,21 @@ class SiteApplicationProvider implements ServiceProviderInterface return new ContainerControllerResolver($container); } + /** + * Get the `view.homepage.html` service + * + * @param Container $container The DI container. + * + * @return HomepageHtmlView + */ + public function getViewHomepageHtmlService(Container $container): HomepageHtmlView + { + return new HomepageHtmlView( + $container->get('model.homepage'), + $container->get('renderer') + ); + } + /** * Get the `view.page.html` service * diff --git a/week-04/project/libraries/src/Service/TemplatingProvider.php b/week-04/project/libraries/src/Service/SiteTemplatingProvider.php similarity index 98% rename from week-04/project/libraries/src/Service/TemplatingProvider.php rename to week-04/project/libraries/src/Service/SiteTemplatingProvider.php index 608681c..e12433d 100644 --- a/week-04/project/libraries/src/Service/TemplatingProvider.php +++ b/week-04/project/libraries/src/Service/SiteTemplatingProvider.php @@ -11,6 +11,7 @@ namespace Octoleo\CMS\Service; use Joomla\Application\AbstractApplication; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; +use Joomla\Session\SessionInterface; use Octoleo\CMS\Asset\MixPathPackage; use Octoleo\CMS\Renderer\ApplicationContext; use Octoleo\CMS\Renderer\FrameworkExtension; @@ -37,7 +38,7 @@ use Twig\RuntimeLoader\ContainerRuntimeLoader; * Templating service provider * source: https://github.com/joomla/framework.joomla.org/blob/master/src/Service/TemplatingProvider.php */ -class TemplatingProvider implements ServiceProviderInterface +class SiteTemplatingProvider implements ServiceProviderInterface { /** * Registers the service provider with a DI container. diff --git a/week-04/project/libraries/src/User/UserFactory.php b/week-04/project/libraries/src/User/UserFactory.php index 63043e8..72d5ea3 100644 --- a/week-04/project/libraries/src/User/UserFactory.php +++ b/week-04/project/libraries/src/User/UserFactory.php @@ -79,6 +79,43 @@ class UserFactory implements UserFactoryInterface $this->secure = ($secure) ?: new BCryptHandler(); } + /** + * Method to get an instance of a user for the given id or session. + * + * @param int|null $id The id + * + * @return User + * + * @throws \Exception + * @since 1.0.0 + */ + public function getUser(?int $id = null): User + { + if (empty($id)) + { + /** @var \Octoleo\CMS\Application\AdminApplication $application */ + $application = Factory::getApplication(); + + $session = $application->getSession(); + + // Grab the current session ID + $sessionId = $session->getId(); + + // Get the session user ID + $query = $this->db->getQuery(true) + ->select($this->db->quoteName('userid')) + ->from($this->db->quoteName('#__session')) + ->where($this->db->quoteName('session_id') . ' = :sessionid') + ->bind(':sessionid', $sessionId) + ->setLimit(1); + $this->db->setQuery($query); + + $id = (int) $this->db->loadResult(); + } + + return $this->loadUserById($id); + } + /** * Method to get an instance of a user for the given id. * @@ -121,10 +158,12 @@ class UserFactory implements UserFactoryInterface /** * Check if user is active * + * @param bool $purge + * * @return bool * @throws \Exception */ - public function active(): bool + public function active(?bool $purge = true): bool { /** @var \Octoleo\CMS\Application\AdminApplication $application */ $application = Factory::getApplication(); @@ -148,30 +187,68 @@ class UserFactory implements UserFactoryInterface // if user above 0 the active if ($active->guest == 0 && $active->userid > 0) { - return true; + // get user + $user = $this->loadUserById($active->userid); + // check if user has access + $blocked = $user->get('block', 1); + if ($blocked == 0) + { + return true; + } } - // Purge the session - $query = $this->db->getQuery(true) - ->delete($this->db->quoteName('#__session')) - ->where($this->db->quoteName('session_id') . ' = :sessionid') - ->bind(':sessionid', $sessionId); - try + if ($purge) { - $this->db->setQuery($query)->execute(); - } - catch (\RuntimeException $e) - { - // The old session is already invalidated, don't let this block logging in - } + // Purge the session + $query = $this->db->getQuery(true) + ->delete($this->db->quoteName('#__session')) + ->where($this->db->quoteName('session_id') . ' = :sessionid') + ->bind(':sessionid', $sessionId); + try + { + $this->db->setQuery($query)->execute(); + } + catch (\RuntimeException $e) + { + // The old session is already invalidated, don't let this block logging in + } - // destroy session - $session->destroy(); + // destroy session + $session->destroy(); + } // very basic for now.... return false; } + /** + * Check if we have users + * + * @return bool true if we have + */ + public function has(): bool + { + try + { + $found = $this->db->setQuery( + $this->db->getQuery(true) + ->select($this->db->quoteName('id')) + ->from($this->db->quoteName('#__users')) + ->setLimit(1) + )->loadResult(); + } + catch (\RuntimeException $exception) + { + return false; + } + + if ($found > 0) + { + return true; + } + return false; + } + /** * Check if a user exist based on give key value pair * @@ -242,9 +319,10 @@ class UserFactory implements UserFactoryInterface } // If loadUserByUsername returned an error, then pass it back. - if ($user->get('block', true)) + $blocked = $user->get('block', 1); + if ($blocked == 1) { - $application->enqueueMessage('Login failure, user is blocked.', 'Warning'); + $application->enqueueMessage('Login failure, user is blocked. Contact your system administrator.', 'Warning'); return false; } @@ -287,8 +365,8 @@ class UserFactory implements UserFactoryInterface // The old session is already invalidated, don't let this block logging in } - // destroy session - $session->destroy(); + // close session + $session->close(); // very basic for now.... return true; @@ -388,7 +466,16 @@ class UserFactory implements UserFactoryInterface // set other defaults for now $user['sendEmail'] = 1; - $user['block'] = 0; + // all auto created accounts are blocked (and require admin activation) except for first account + if ($this->has()) + { + $user['block'] = 1; + } + else + { + $user['block'] = 0; + } + // there are no params at this stage $user['params'] = ''; $insert = (object) $user; @@ -405,12 +492,16 @@ class UserFactory implements UserFactoryInterface return false; } - // only set session if success - if ($result) + // only set session if success and not blocked + if ($result && $user['block'] == 0) { $user['id'] = $this->db->insertid(); return $this->setUserSession($application, $user); } + elseif ($result) + { + $application->enqueueMessage('You account has been created, an administrator will active it shortly.', 'success'); + } } return false; } @@ -476,6 +567,9 @@ class UserFactory implements UserFactoryInterface $manager->createOrUpdateRecord($session, $this->loadUserById($user['id'])); + // show a success message + $application->enqueueMessage('Welcome ' . $user['name'] . ', you have successfully lodged in!', 'Success'); + return true; } } diff --git a/week-04/project/libraries/src/View/Admin/DashboardHtmlView.php b/week-04/project/libraries/src/View/Admin/DashboardHtmlView.php index 89ddb30..1fab3a6 100644 --- a/week-04/project/libraries/src/View/Admin/DashboardHtmlView.php +++ b/week-04/project/libraries/src/View/Admin/DashboardHtmlView.php @@ -31,19 +31,19 @@ class DashboardHtmlView extends HtmlView * * @var DashboardModel */ - private $dashboardModel; + private $model; /** * Instantiate the view. * - * @param DashboardModel $dashboardModel The page model object. - * @param RendererInterface $renderer The renderer object. + * @param DashboardModel $model The page model object. + * @param RendererInterface $renderer The renderer object. */ - public function __construct(DashboardModel $dashboardModel, RendererInterface $renderer) + public function __construct(DashboardModel $model, RendererInterface $renderer) { parent::__construct($renderer); - $this->dashboardModel = $dashboardModel; + $this->model = $model; } /** @@ -51,7 +51,7 @@ class DashboardHtmlView extends HtmlView * * @return string The rendered view */ - public function render() + public function render(): string { $this->setData(['page' => $this->id]); return parent::render(); @@ -66,7 +66,7 @@ class DashboardHtmlView extends HtmlView */ public function setActiveDashboard(string $name): void { - $this->setLayout($this->dashboardModel->getDashboard($name)); + $this->setLayout($this->model->getDashboard($name)); } /** diff --git a/week-04/project/libraries/src/View/Admin/ItemHtmlView.php b/week-04/project/libraries/src/View/Admin/ItemHtmlView.php new file mode 100644 index 0000000..80287bc --- /dev/null +++ b/week-04/project/libraries/src/View/Admin/ItemHtmlView.php @@ -0,0 +1,84 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\View\Admin; + +use Octoleo\CMS\Model\ItemModel; +use Joomla\Renderer\RendererInterface; +use Joomla\View\HtmlView; + +/** + * Dashboard HTML view class for the application + */ +class ItemHtmlView extends HtmlView +{ + /** + * The id of item/user/menu + * + * @var int + */ + private $id; + + /** + * The item model object. + * + * @var ItemModel + */ + private $model; + + /** + * Instantiate the view. + * + * @param ItemModel $model The page model object. + * @param RendererInterface $renderer The renderer object. + */ + public function __construct(ItemModel $model, RendererInterface $renderer) + { + parent::__construct($renderer); + + $this->model = $model; + } + + /** + * Method to render the view + * + * @return string The rendered view + * @throws \Exception + */ + public function render(): string + { + $this->setData(['form' => $this->model->getItem($this->id)]); + return parent::render(); + } + + /** + * Set the active view + * + * @param string $name The active view name + * + * @return void + */ + public function setActiveView(string $name): void + { + $this->setLayout($this->model->setLayout($name)); + } + + /** + * Set the active page details + * + * @param int $id The selected item + * + * @return void + */ + public function setActiveId(int $id): void + { + $this->id = $id; + } +} diff --git a/week-04/project/libraries/src/View/Admin/ItemsHtmlView.php b/week-04/project/libraries/src/View/Admin/ItemsHtmlView.php new file mode 100644 index 0000000..368399d --- /dev/null +++ b/week-04/project/libraries/src/View/Admin/ItemsHtmlView.php @@ -0,0 +1,64 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\View\Admin; + +use Octoleo\CMS\Model\ItemsModel; +use Joomla\Renderer\RendererInterface; +use Joomla\View\HtmlView; + +/** + * Dashboard HTML view class for the application + */ +class ItemsHtmlView extends HtmlView +{ + /** + * The item model object. + * + * @var ItemsModel + */ + private $model; + + /** + * Instantiate the view. + * + * @param ItemsModel $model The page model object. + * @param RendererInterface $renderer The renderer object. + */ + public function __construct(ItemsModel $model, RendererInterface $renderer) + { + parent::__construct($renderer); + + $this->model = $model; + } + + /** + * Method to render the view + * + * @return string The rendered view + */ + public function render(): string + { + $this->setData(['list' => $this->model->getItems()]); + return parent::render(); + } + + /** + * Set the active view + * + * @param string $name The active view name + * + * @return void + */ + public function setActiveView(string $name): void + { + $this->setLayout($this->model->setLayout($name)); + } +} diff --git a/week-04/project/libraries/src/View/Admin/MenuHtmlView.php b/week-04/project/libraries/src/View/Admin/MenuHtmlView.php new file mode 100644 index 0000000..663e5b2 --- /dev/null +++ b/week-04/project/libraries/src/View/Admin/MenuHtmlView.php @@ -0,0 +1,87 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\View\Admin; + +use Octoleo\CMS\Model\MenuModel; +use Joomla\Renderer\RendererInterface; +use Joomla\View\HtmlView; + +/** + * Dashboard HTML view class for the application + */ +class MenuHtmlView extends HtmlView +{ + /** + * The id of item/user/menu + * + * @var int + */ + private $id; + + /** + * The item model object. + * + * @var MenuModel + */ + private $model; + + /** + * Instantiate the view. + * + * @param MenuModel $model The page model object. + * @param RendererInterface $renderer The renderer object. + */ + public function __construct(MenuModel $model, RendererInterface $renderer) + { + parent::__construct($renderer); + + $this->model = $model; + } + + /** + * Method to render the view + * + * @return string The rendered view + * @throws \Exception + */ + public function render(): string + { + $this->setData([ + 'form' => $this->model->getItem($this->id), + 'items' => $this->model->getItems() + ]); + return parent::render(); + } + + /** + * Set the active view + * + * @param string $name The active view name + * + * @return void + */ + public function setActiveView(string $name): void + { + $this->setLayout($this->model->setLayout($name)); + } + + /** + * Set the active page details + * + * @param int $id The selected item/user/menu + * + * @return void + */ + public function setActiveId(int $id): void + { + $this->id = $id; + } +} diff --git a/week-04/project/libraries/src/View/Admin/MenusHtmlView.php b/week-04/project/libraries/src/View/Admin/MenusHtmlView.php new file mode 100644 index 0000000..79a51d1 --- /dev/null +++ b/week-04/project/libraries/src/View/Admin/MenusHtmlView.php @@ -0,0 +1,64 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\View\Admin; + +use Octoleo\CMS\Model\MenusModel; +use Joomla\Renderer\RendererInterface; +use Joomla\View\HtmlView; + +/** + * Dashboard HTML view class for the application + */ +class MenusHtmlView extends HtmlView +{ + /** + * The item model object. + * + * @var MenusModel + */ + private $model; + + /** + * Instantiate the view. + * + * @param MenusModel $model The page model object. + * @param RendererInterface $renderer The renderer object. + */ + public function __construct(MenusModel $model, RendererInterface $renderer) + { + parent::__construct($renderer); + + $this->model = $model; + } + + /** + * Method to render the view + * + * @return string The rendered view + */ + public function render(): string + { + $this->setData(['list' => $this->model->getItems()]); + return parent::render(); + } + + /** + * Set the active view + * + * @param string $name The active view name + * + * @return void + */ + public function setActiveView(string $name): void + { + $this->setLayout($this->model->setLayout($name)); + } +} diff --git a/week-04/project/libraries/src/View/Admin/UserHtmlView.php b/week-04/project/libraries/src/View/Admin/UserHtmlView.php new file mode 100644 index 0000000..7104759 --- /dev/null +++ b/week-04/project/libraries/src/View/Admin/UserHtmlView.php @@ -0,0 +1,83 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\View\Admin; + +use Octoleo\CMS\Model\UserModel; +use Joomla\Renderer\RendererInterface; +use Joomla\View\HtmlView; + +/** + * Dashboard HTML view class for the application + */ +class UserHtmlView extends HtmlView +{ + /** + * The id of user + * + * @var int + */ + private $id; + + /** + * The User model object. + * + * @var UserModel + */ + private $model; + + /** + * Instantiate the view. + * + * @param UserModel $model The page model object. + * @param RendererInterface $renderer The renderer object. + */ + public function __construct(UserModel $model, RendererInterface $renderer) + { + parent::__construct($renderer); + + $this->model = $model; + } + + /** + * Method to render the view + * + * @return string The rendered view + */ + public function render(): string + { + $this->setData(['form' => $this->model->getItem($this->id)]); + return parent::render(); + } + + /** + * Set the active view + * + * @param string $name The active view name + * + * @return void + */ + public function setActiveView(string $name): void + { + $this->setLayout($this->model->setLayout($name)); + } + + /** + * Set the active page details + * + * @param int $id The selected user + * + * @return void + */ + public function setActiveId(int $id): void + { + $this->id = $id; + } +} diff --git a/week-04/project/libraries/src/View/Admin/UsersHtmlView.php b/week-04/project/libraries/src/View/Admin/UsersHtmlView.php new file mode 100644 index 0000000..2014369 --- /dev/null +++ b/week-04/project/libraries/src/View/Admin/UsersHtmlView.php @@ -0,0 +1,64 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\View\Admin; + +use Octoleo\CMS\Model\UsersModel; +use Joomla\Renderer\RendererInterface; +use Joomla\View\HtmlView; + +/** + * Dashboard HTML view class for the application + */ +class UsersHtmlView extends HtmlView +{ + /** + * The item model object. + * + * @var UsersModel + */ + private $model; + + /** + * Instantiate the view. + * + * @param UsersModel $model The page model object. + * @param RendererInterface $renderer The renderer object. + */ + public function __construct(UsersModel $model, RendererInterface $renderer) + { + parent::__construct($renderer); + + $this->model = $model; + } + + /** + * Method to render the view + * + * @return string The rendered view + */ + public function render(): string + { + $this->setData(['list' => $this->model->getItems()]); + return parent::render(); + } + + /** + * Set the active view + * + * @param string $name The active view name + * + * @return void + */ + public function setActiveView(string $name): void + { + $this->setLayout($this->model->setLayout($name)); + } +} diff --git a/week-04/project/libraries/src/View/Page/HomepageHtmlView.php b/week-04/project/libraries/src/View/Page/HomepageHtmlView.php new file mode 100644 index 0000000..492b1ac --- /dev/null +++ b/week-04/project/libraries/src/View/Page/HomepageHtmlView.php @@ -0,0 +1,133 @@ + + * @git WEBD-325-45 + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Octoleo\CMS\View\Page; + +use Octoleo\CMS\Model\MenuInterface; +use Octoleo\CMS\Model\HomepageModel; +use Joomla\Renderer\RendererInterface; +use Joomla\View\HtmlView; +use Octoleo\CMS\Model\PageInterface; + +/** + * Page HTML view class for the application + */ +class HomepageHtmlView extends HtmlView +{ + /** + * The active page + * + * @var string + */ + private $page = ''; + + /** + * The active page details + * + * @var string + */ + private $details; + + /** + * The page model object. + * + * @var HomepageModel + */ + private $model; + + /** + * Instantiate the view. + * + * @param HomepageModel $model The page model object. + * @param RendererInterface $renderer The renderer object. + */ + public function __construct(HomepageModel $model, RendererInterface $renderer) + { + parent::__construct($renderer); + + $this->model = $model; + } + + /** + * Method to render the view + * + * @return string The rendered view + */ + public function render() + { + // set the defaults + $title = 'Home'; + $body = ''; + $menus = []; + // set the home page default template + $this->setLayout('homepage.twig'); + // we check if we have a home page + $home_page = $this->model->getHomePage(); + if ($this->model instanceof PageInterface && isset($home_page->item_id) && $home_page->item_id > 0) + { + // get the page data + $data = $this->model->getPageItemById($home_page->item_id); + if ($data->id) + { + // set the title + $title = $data->title; + // check if we have intro text we add it to full text + if (!empty($data->introtext)) + { + // TODO: for now we just merge these + $data->fulltext = $data->introtext . $data->fulltext; + } + // set the title + $body = $data->fulltext; + // set the page template + $this->setLayout('page.twig'); + } + } + + // set the menus if possible + if ($this->model instanceof MenuInterface) + { + $menus = $this->model->getMenus(); + } + + $this->setData( + [ + 'main_menu' => $menus, + 'title' => $title, + 'body' => $body + ] + ); + return parent::render(); + } + + /** + * Set the active page + * + * @param string $page The active page name + * + * @return void + */ + public function setPage(string $page): void + { + $this->page = $page; + } + + /** + * Set the active page details + * + * @param string $page The active page name + * + * @return void + */ + public function setDetails(string $details): void + { + $this->details = $details; + } +} diff --git a/week-04/project/libraries/src/View/Page/PageHtmlView.php b/week-04/project/libraries/src/View/Page/PageHtmlView.php index 78dd647..46b7745 100644 --- a/week-04/project/libraries/src/View/Page/PageHtmlView.php +++ b/week-04/project/libraries/src/View/Page/PageHtmlView.php @@ -10,6 +10,8 @@ namespace Octoleo\CMS\View\Page; +use Octoleo\CMS\Model\MenuInterface; +use Octoleo\CMS\Model\PageInterface; use Octoleo\CMS\Model\PageModel; use Joomla\Renderer\RendererInterface; use Joomla\View\HtmlView; @@ -38,19 +40,19 @@ class PageHtmlView extends HtmlView * * @var PageModel */ - private $pageModel; + private $model; /** * Instantiate the view. * - * @param PageModel $pageModel The page model object. - * @param RendererInterface $renderer The renderer object. + * @param PageModel $model The page model object. + * @param RendererInterface $renderer The renderer object. */ - public function __construct(PageModel $pageModel, RendererInterface $renderer) + public function __construct(PageModel $model, RendererInterface $renderer) { parent::__construct($renderer); - $this->pageModel = $pageModel; + $this->model = $model; } /** @@ -60,10 +62,45 @@ class PageHtmlView extends HtmlView */ public function render() { + // set the defaults + $title = 'Error'; + $body = ''; + $menus = []; + // get the page data + if ($this->model instanceof PageInterface) + { + // get the page data + $data = $this->model->getPageItemByPath($this->page); + if (isset($data->id)) + { + // set the title + $title = $data->title; + // check if we have intro text we add it to full text + if (!empty($data->introtext)) + { + // TODO: for now we just merge these + $data->fulltext = $data->introtext . $data->fulltext; + } + // set the title + $body = $data->fulltext; + } + else + { + throw new \RuntimeException('Trying to access a page that does not exit (' . $this->page . ')', 404); + } + } + + // set the menus if possible + if ($this->model instanceof MenuInterface) + { + $menus = $this->model->getMenus(); + } + $this->setData( [ - 'page' => $this->pageModel->getPage($this->page), - 'details' => $this->pageModel->getDetails($this->details) + 'main_menu' => $menus, + 'title' => $title, + 'body' => $body ] ); @@ -81,16 +118,4 @@ class PageHtmlView extends HtmlView { $this->page = $page; } - - /** - * Set the active page details - * - * @param string $page The active page name - * - * @return void - */ - public function setDetails(string $details): void - { - $this->details = $details; - } } diff --git a/week-04/project/templates/admin/dashboard.twig b/week-04/project/templates/admin/dashboard.twig index e88e51c..efe818e 100644 --- a/week-04/project/templates/admin/dashboard.twig +++ b/week-04/project/templates/admin/dashboard.twig @@ -5,15 +5,16 @@ {% block content %}

Octoleo CMS Dashboard

+ {{ block("messages_queue", "message_queue.twig") }}
diff --git a/week-04/project/templates/admin/header.twig b/week-04/project/templates/admin/header.twig index 6761f39..9caaa47 100644 --- a/week-04/project/templates/admin/header.twig +++ b/week-04/project/templates/admin/header.twig @@ -8,10 +8,12 @@ - + + {% block headCSSLinks %}{% endblock %} - - + + + {% block headJavaScriptLinks %}{% endblock %} diff --git a/week-04/project/templates/admin/index.twig b/week-04/project/templates/admin/index.twig index e43c158..43bb7a7 100644 --- a/week-04/project/templates/admin/index.twig +++ b/week-04/project/templates/admin/index.twig @@ -2,7 +2,7 @@ {% block body %} -{% block bodyNavigation %}{% import 'nav.twig' as macros %}{{ macros.load_admin_navbar() }}{% endblock %} +{% block bodyNavigation %}{{ block("bodyNavigation", "nav.twig") }}{% endblock %}
{% block content %}{% endblock %}
diff --git a/week-04/project/templates/admin/item.twig b/week-04/project/templates/admin/item.twig new file mode 100644 index 0000000..d9a9fcc --- /dev/null +++ b/week-04/project/templates/admin/item.twig @@ -0,0 +1,111 @@ +{% extends "index.twig" %} + +{% block title %}Edit Item{% endblock %} + +{% block headJavaScriptLinks %} + +{% endblock %} + +{% block content %} +
+ {{ block("messages_queue", "message_queue.twig") }} +
+
+ + Close +
+
+ +
+ +
+
+ +
    +
  • +
    + +
    + +
    +
    +
  • +
  • +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + +
    + +
    +
    +
  • +
  • +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
  • +
+ + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/admin/items.twig b/week-04/project/templates/admin/items.twig index 3a35f38..be663e0 100644 --- a/week-04/project/templates/admin/items.twig +++ b/week-04/project/templates/admin/items.twig @@ -5,48 +5,61 @@ {% block content %}

Items

- Create + {{ block("messages_queue", "message_queue.twig") }} + Create + {% if list %} - - - + + + + + + {% for item in list %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + {% endfor %}
Table HeadingTable HeadingTable HeadingActionTitleContentStateID
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit +
+ Edit + +
+
{{ item.title }}{% if item.introtext %}{{ shorten_string(item.introtext|striptags) }} {% endif %}{{ shorten_string(item.fulltext|striptags) }} + {% if item.state == 1 %} + + {% elseif item.state == 2 %} + + {% elseif item.state == -1 %} + + {% elseif item.state == 0 %} + + {% else %} + Error + {% endif %} + {{ item.id }}
+ {% else %} +
+

There has no items been found, click create to add some.

+
+ {% endif %}
- + {% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/admin/login.twig b/week-04/project/templates/admin/login.twig index ef797cc..55b1dbf 100644 --- a/week-04/project/templates/admin/login.twig +++ b/week-04/project/templates/admin/login.twig @@ -6,13 +6,15 @@
+ {{ block("messages_queue", "message_queue.twig") }}

Login Here

-
+ - Create Account +
+ Create Account
{% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/admin/menu.twig b/week-04/project/templates/admin/menu.twig new file mode 100644 index 0000000..d53e0e7 --- /dev/null +++ b/week-04/project/templates/admin/menu.twig @@ -0,0 +1,111 @@ +{% extends "index.twig" %} + +{% block title %}Edit Menu{% endblock %} + +{% block content %} +
+ {{ block("messages_queue", "message_queue.twig") }} + {% if items %} +
+
+ + Close +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+ +
    +
  • +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
  • +
  • +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + +
    + +
    +
    +
  • +
+ + +
+ {% else %} + Create +
+

There has no items been found, click create to add items.

+
+ {% endif %} +
+{% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/admin/menus.twig b/week-04/project/templates/admin/menus.twig index 360699a..9374616 100644 --- a/week-04/project/templates/admin/menus.twig +++ b/week-04/project/templates/admin/menus.twig @@ -1,50 +1,71 @@ {% extends "index.twig" %} +{% block title %}Menus{% endblock %} + {% block content %} -
-

Menus

- Create +
+

Menus

+ {{ block("messages_queue", "message_queue.twig") }} + Create + {% if list %} - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + {% for item in list %} + + + + + + + + + {% endfor %}
Table HeadingTable HeadingTable HeadingActionTitleItemPathStateID
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
+
+ Edit + +
+
{% if item.home == 1 %} {% endif %}{{ item.title }} + + {{ shorten_string(item.item_title, 10) }} + + {{ item.path }} + {% if item.published == 1 %} + + {% elseif item.published == 2 %} + + {% elseif item.published == -1 %} + + {% elseif item.published == 0 %} + + {% else %} + Error + {% endif %} + {{ item.id }}
-
- + {% else %} +
+

There has no menus been found, click create to add some.

+
+ {% endif %} +
+ {% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/admin/message_queue.twig b/week-04/project/templates/admin/message_queue.twig new file mode 100644 index 0000000..9d89bab --- /dev/null +++ b/week-04/project/templates/admin/message_queue.twig @@ -0,0 +1,20 @@ +{% block messages_queue %} +{% set message_queue = message_queue() %} +{% if message_queue|length > 0 %} + {% for messages in message_queue|sort %} + {% if messages.type == 'error' %} + {% set messages_type = 'uk-alert-danger' %} + {% elseif messages.type == 'success' %} + {% set messages_type = 'uk-alert-success' %} + {% elseif messages.type == 'warning' %} + {% set messages_type = 'uk-alert-warning' %} + {% else %} + {% set messages_type = 'uk-alert-primary' %} + {% endif %} +
+ +

{{ messages.message }}

+
+ {% endfor %} +{% endif %} +{% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/admin/nav.twig b/week-04/project/templates/admin/nav.twig index c5f4609..ab2f26b 100644 --- a/week-04/project/templates/admin/nav.twig +++ b/week-04/project/templates/admin/nav.twig @@ -1,19 +1,18 @@ -{% macro load_admin_navbar() %} +{% block bodyNavigation %} -{% endmacro %} - \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/admin/signup.twig b/week-04/project/templates/admin/signup.twig index 11cff72..85bccde 100644 --- a/week-04/project/templates/admin/signup.twig +++ b/week-04/project/templates/admin/signup.twig @@ -6,16 +6,18 @@
+ {{ block("messages_queue", "message_queue.twig") }}

Create Account

-
+ + - Login
+ Login
{% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/admin/user.twig b/week-04/project/templates/admin/user.twig new file mode 100644 index 0000000..c4c4d00 --- /dev/null +++ b/week-04/project/templates/admin/user.twig @@ -0,0 +1,70 @@ +{% extends "index.twig" %} + +{% block title %}Edit User{% endblock %} + +{% block content %} +
+ {{ block("messages_queue", "message_queue.twig") }} +
+
+ + Close +
+
+ +
+ +
+
+ +
    +
  • +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
  • +
  • +
    +
    + +
    + +
    +
    +
    +
  • +
+ + +
+
+{% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/admin/users.twig b/week-04/project/templates/admin/users.twig index 770f5d5..90b764b 100644 --- a/week-04/project/templates/admin/users.twig +++ b/week-04/project/templates/admin/users.twig @@ -5,28 +5,55 @@ {% block content %}

Users

- Create - - - - - - - - - - - - - - - - - - - - -
Table HeadingTable HeadingTable Heading
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
Table DataLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Edit
+ {{ block("messages_queue", "message_queue.twig") }} + Create + {% if list %} + + + + + + + + + + + + {% for item in list %} + + + + + + + + {% endfor %} + +
ActionNameEmailStateID
+
+ Edit + +
+
{{ item.name }}{{ item.email }} + {% if item.block == 0 %} + + {% else %} + + {% endif %} + {{ item.id }}
+ {% else %} +
+

There has no items been found, click create to add some.

+
+ {% endif %}
- + {% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/site/header.twig b/week-04/project/templates/site/header.twig index 6761f39..349cb8c 100644 --- a/week-04/project/templates/site/header.twig +++ b/week-04/project/templates/site/header.twig @@ -8,10 +8,10 @@ - + - - + + diff --git a/week-04/project/templates/site/homepage.twig b/week-04/project/templates/site/homepage.twig index 153f13c..097d8ed 100644 --- a/week-04/project/templates/site/homepage.twig +++ b/week-04/project/templates/site/homepage.twig @@ -3,8 +3,8 @@ {% block content %}
-

Welcome

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+

Octoleo CMS

+

There has no home page been created for this CMS. Please come again soon...

{% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/site/index.twig b/week-04/project/templates/site/index.twig index 207d374..b844748 100644 --- a/week-04/project/templates/site/index.twig +++ b/week-04/project/templates/site/index.twig @@ -2,7 +2,7 @@ {% block body %} -{% block bodyNavigation %}{% import 'nav.twig' as macros %}{{ macros.load_site_navbar() }}{% endblock %} +{% block bodyNavigation %}{{ block("bodyNavigation", "nav.twig") }}{% endblock %}
{% block content %}{% endblock %}
diff --git a/week-04/project/templates/site/nav.twig b/week-04/project/templates/site/nav.twig index 38bee15..89554ac 100644 --- a/week-04/project/templates/site/nav.twig +++ b/week-04/project/templates/site/nav.twig @@ -1,28 +1,40 @@ -{% macro load_site_navbar() %} +{% block bodyNavigation %} +{% set center = false %} +{% set right = false %} +{% if main_menu %} + {% for menu in main_menu %} + {% if menu.root and menu.position == 'center' %} + {% set center = true %} + {% elseif menu.root and menu.position == 'right' %} + {% set right = true %} + {% endif %} + {% endfor %} +{% endif %} -{% endmacro %} - \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/week-04/project/templates/site/page.twig b/week-04/project/templates/site/page.twig index 92f6759..ef68620 100644 --- a/week-04/project/templates/site/page.twig +++ b/week-04/project/templates/site/page.twig @@ -1,14 +1,14 @@ {% extends "index.twig" %} {% block content %} -
-
-

{{ page }}

- {% if details == '' %} -

YOU ARE IN PAGES

- {% else %} -

You are into {{ details }}

- {% endif %} -
+
+
+

{{ title }}

+ {% if body == '' %} +

We have an error!

+ {% else %} + {{ body|raw }} + {% endif %}
+
{% endblock %} \ No newline at end of file