Week 6: Adding a User and Logging Out

This commit is contained in:
Llewellyn van der Merwe 2022-04-25 04:19:51 +02:00
parent 3a395967f1
commit dcd75b5004
Signed by: Llewellyn
GPG Key ID: EFC0C720A240551C
80 changed files with 3986 additions and 1016 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
week-06/project/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -14,11 +14,15 @@ use Joomla\Application\AbstractApplication;
use Joomla\Controller\AbstractController; use Joomla\Controller\AbstractController;
use Joomla\Input\Input; use Joomla\Input\Input;
use Joomla\Uri\Uri; use Joomla\Uri\Uri;
use Octoleo\CMS\Controller\Util\AccessInterface;
use Octoleo\CMS\Controller\Util\AccessTrait;
use Octoleo\CMS\Controller\Util\CheckTokenInterface;
use Octoleo\CMS\Controller\Util\CheckTokenTrait;
use Octoleo\CMS\View\Admin\DashboardHtmlView; use Octoleo\CMS\View\Admin\DashboardHtmlView;
use Laminas\Diactoros\Response\HtmlResponse; use Laminas\Diactoros\Response\HtmlResponse;
/** /**
* Controller handling the site's dashboard * Controller handling the requests
* *
* @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\AdminApplication $app Application object * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object
@ -37,10 +41,9 @@ class DashboardController extends AbstractController implements AccessInterface,
/** /**
* Constructor. * Constructor.
* *
* @param DashboardHtmlView $view The view object. * @param DashboardHtmlView $view The view object.
* @param Input $user The user object. * @param Input|null $input The input object.
* @param Input $input The input object. * @param AbstractApplication|null $app The application object.
* @param AbstractApplication $app The application object.
*/ */
public function __construct(DashboardHtmlView $view, Input $input = null, AbstractApplication $app = null) public function __construct(DashboardHtmlView $view, Input $input = null, AbstractApplication $app = null)
{ {

View File

@ -1,63 +0,0 @@
<?php
/**
* @package Octoleo CMS
*
* @created 9th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/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 Laminas\Diactoros\Response\HtmlResponse;
use Octoleo\CMS\View\Page\HomepageHtmlView;
/**
* Controller handling the site's homepage
*
* @method \Octoleo\CMS\Application\SiteApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\SiteApplication $app Application object
*/
class HomepageController extends AbstractController
{
/**
* The view object.
*
* @var HomepageHtmlView
*/
private $view;
/**
* Constructor.
*
* @param HomepageHtmlView $view The view object.
* @param Input $input The input object.
* @param AbstractApplication $app The application object.
*/
public function __construct(HomepageHtmlView $view, Input $input = null, AbstractApplication $app = null)
{
parent::__construct($input, $app);
$this->view = $view;
}
/**
* Execute the controller.
*
* @return boolean
*/
public function execute(): bool
{
// Disable all cache for now
$this->getApplication()->allowCache(false);
// check if there is a home page
$this->getApplication()->setResponse(new HtmlResponse($this->view->render()));
return true;
}
}

View File

@ -14,19 +14,24 @@ use Joomla\Application\AbstractApplication;
use Joomla\Controller\AbstractController; use Joomla\Controller\AbstractController;
use Joomla\Filter\InputFilter as InputFilterAlias; use Joomla\Filter\InputFilter as InputFilterAlias;
use Joomla\Input\Input; use Joomla\Input\Input;
use Octoleo\CMS\Controller\Util\AccessInterface;
use Octoleo\CMS\Controller\Util\AccessTrait;
use Octoleo\CMS\Controller\Util\CheckTokenInterface;
use Octoleo\CMS\Controller\Util\CheckTokenTrait;
use Octoleo\CMS\Date\Date; use Octoleo\CMS\Date\Date;
use Octoleo\CMS\Factory; use Octoleo\CMS\Factory;
use Octoleo\CMS\Filter\InputFilter; use Octoleo\CMS\Filter\InputFilter;
use Octoleo\CMS\Model\ItemModel; use Octoleo\CMS\Model\ItemModel;
use Octoleo\CMS\User\User;
use Octoleo\CMS\User\UserFactoryInterface; use Octoleo\CMS\User\UserFactoryInterface;
use Octoleo\CMS\View\Admin\ItemHtmlView; use Octoleo\CMS\View\Admin\ItemHtmlView;
use Laminas\Diactoros\Response\HtmlResponse; use Laminas\Diactoros\Response\HtmlResponse;
/** /**
* Controller handling the site's dashboard * Controller handling the requests
* *
* @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\AdminApplication $app Application object * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object
*/ */
class ItemController extends AbstractController implements AccessInterface, CheckTokenInterface class ItemController extends AbstractController implements AccessInterface, CheckTokenInterface
{ {
@ -51,20 +56,32 @@ class ItemController extends AbstractController implements AccessInterface, Chec
*/ */
private $inputFilter; private $inputFilter;
/**
* @var User
*/
private $user;
/** /**
* Constructor. * Constructor.
* *
* @param ItemModel $model The model object. * @param ItemModel $model The model object.
* @param ItemHtmlView $view The view object. * @param ItemHtmlView $view The view object.
* @param Input $input The input object. * @param Input|null $input The input object.
* @param AbstractApplication $app The application object. * @param AbstractApplication|null $app The application object.
* @param User|null $user
*/ */
public function __construct(ItemModel $model, $view, Input $input = null, AbstractApplication $app = null) public function __construct(
ItemModel $model,
$view,
Input $input = null,
AbstractApplication $app = null,
User $user = null)
{ {
parent::__construct($input, $app); parent::__construct($input, $app);
$this->model = $model; $this->model = $model;
$this->view = $view; $this->view = $view;
$this->user = ($user) ?: Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
$this->inputFilter = InputFilter::getInstance( $this->inputFilter = InputFilter::getInstance(
[], [],
[], [],
@ -85,23 +102,31 @@ class ItemController extends AbstractController implements AccessInterface, Chec
$this->getApplication()->allowCache(false); $this->getApplication()->allowCache(false);
$method = $this->getInput()->getMethod(); $method = $this->getInput()->getMethod();
$task = $this->getInput()->getString('task', ''); $task = $this->getInput()->getString('task', '');
$id = $this->getInput()->getInt('id', 0); $id = $this->getInput()->getInt('id', 0);
// if task is delete // if task is delete
if ('delete' === $task) if ('delete' === $task)
{ {
if ($id > 0 && $this->model->linked($id)) // check that the user does not delete him/her self
if ($this->allow('item') && $this->user->get('access.item.delete', false))
{ {
$this->getApplication()->enqueueMessage('This item is still linked to a menu, first remove it from the menu.', 'error'); if ($id > 0 && $this->model->linked($id))
} {
elseif ($id > 0 && $this->model->delete($id)) $this->getApplication()->enqueueMessage('This item is still linked to a menu, first remove it from the menu.', 'error');
{ }
$this->getApplication()->enqueueMessage('Item was deleted!', 'success'); elseif ($id > 0 && $this->model->delete($id))
{
$this->getApplication()->enqueueMessage('Item was deleted!', 'success');
}
else
{
$this->getApplication()->enqueueMessage('Item could not be deleted!', 'error');
}
} }
else else
{ {
$this->getApplication()->enqueueMessage('Item could not be deleted!', 'error'); $this->getApplication()->enqueueMessage('You do not have permission to delete this item!', 'error');
} }
// go to set page // go to set page
$this->_redirect('items'); $this->_redirect('items');
@ -111,21 +136,57 @@ class ItemController extends AbstractController implements AccessInterface, Chec
if ('POST' === $method) if ('POST' === $method)
{ {
$id = $this->setItem(); // check permissions
$update = ($id > 0 && $this->user->get('access.item.update', false));
$create = ($id == 0 && $this->user->get('access.item.create', false));
if ( $create || $update )
{
$id = $this->setItem();
}
else
{
// not allowed creating item
if ($id == 0)
{
$this->getApplication()->enqueueMessage('You do not have permission to create items!', 'error');
}
// not allowed updating item
if ($id > 0)
{
$this->getApplication()->enqueueMessage('You do not have permission to update the item details!', 'error');
}
}
} }
$this->view->setActiveId($id); // check permissions
$this->view->setActiveView('item'); $read = ($id > 0 && $this->user->get('access.item.read', false));
$create = ($id == 0 && $this->user->get('access.item.create', false));
// check if user is allowed to access // check if user is allowed to access
if ($this->allow('item')) if ($this->allow('item') && ( $read || $create ))
{ {
// set values for view
$this->view->setActiveId($id);
$this->view->setActiveView('item');
$this->getApplication()->setResponse(new HtmlResponse($this->view->render())); $this->getApplication()->setResponse(new HtmlResponse($this->view->render()));
} }
else else
{ {
// not allowed creating item
if ($id == 0 && !$create)
{
$this->getApplication()->enqueueMessage('You do not have permission to create items!', 'error');
}
// not allowed read item
if ($id > 0 && !$read)
{
$this->getApplication()->enqueueMessage('You do not have permission to read the item details!', 'error');
}
// go to set page // go to set page
$this->_redirect(); $this->_redirect('items');
} }
return true; return true;
@ -146,18 +207,18 @@ class ItemController extends AbstractController implements AccessInterface, Chec
$post = $this->getInput()->getInputForRequestMethod(); $post = $this->getInput()->getInputForRequestMethod();
// we get all the needed items // we get all the needed items
$tempItem = []; $tempItem = [];
$tempItem['id'] = $post->getInt('item_id', 0); $tempItem['id'] = $post->getInt('item_id', 0);
$tempItem['title'] = $post->getString('title', ''); $tempItem['title'] = $post->getString('title', '');
$tempItem['fulltext'] = $this->inputFilter->clean($post->getRaw('fulltext', ''), 'html'); $tempItem['fulltext'] = $this->inputFilter->clean($post->getRaw('fulltext', ''), 'html');
$tempItem['created_by_alias'] = $post->getString('created_by_alias', ''); $tempItem['created_by_alias'] = $post->getString('created_by_alias', '');
$tempItem['state'] = $post->getInt('state', 1); $tempItem['state'] = $post->getInt('state', 1);
$tempItem['metakey'] = $post->getString('metakey', ''); $tempItem['metakey'] = $post->getString('metakey', '');
$tempItem['metadesc'] = $post->getString('metadesc', ''); $tempItem['metadesc'] = $post->getString('metadesc', '');
$tempItem['metadata'] = $post->getString('metadata', ''); $tempItem['metadata'] = $post->getString('metadata', '');
$tempItem['publish_up'] = $post->getString('publish_up', ''); $tempItem['publish_up'] = $post->getString('publish_up', '');
$tempItem['publish_down'] = $post->getString('publish_down', ''); $tempItem['publish_down'] = $post->getString('publish_down', '');
$tempItem['featured'] = $post->getInt('featured', 0); $tempItem['featured'] = $post->getInt('featured', 0);
// check that we have a Title // check that we have a Title
$can_save = true; $can_save = true;
@ -183,7 +244,7 @@ class ItemController extends AbstractController implements AccessInterface, Chec
$user = Factory::getContainer()->get(UserFactoryInterface::class)->getUser(); $user = Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
$user_id = (int) $user->get('id', 0); $user_id = (int) $user->get('id', 0);
$today = (new Date())->toSql(); $today = (new Date())->toSql();
return $this->model->setItem( return $this->model->setItem(
$tempItem['id'], $tempItem['id'],

View File

@ -13,14 +13,21 @@ namespace Octoleo\CMS\Controller;
use Joomla\Application\AbstractApplication; use Joomla\Application\AbstractApplication;
use Joomla\Controller\AbstractController; use Joomla\Controller\AbstractController;
use Joomla\Input\Input; use Joomla\Input\Input;
use Octoleo\CMS\View\Admin\ItemsHtmlView;
use Laminas\Diactoros\Response\HtmlResponse; use Laminas\Diactoros\Response\HtmlResponse;
use Octoleo\CMS\Controller\Util\AccessInterface;
use Octoleo\CMS\Controller\Util\AccessTrait;
use Octoleo\CMS\Controller\Util\CheckTokenInterface;
use Octoleo\CMS\Controller\Util\CheckTokenTrait;
use Octoleo\CMS\Factory;
use Octoleo\CMS\User\User;
use Octoleo\CMS\User\UserFactoryInterface;
use Octoleo\CMS\View\Admin\ItemsHtmlView;
/** /**
* Controller handling the site's dashboard * Controller handling the requests
* *
* @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\AdminApplication $app Application object * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object
*/ */
class ItemsController extends AbstractController implements AccessInterface, CheckTokenInterface class ItemsController extends AbstractController implements AccessInterface, CheckTokenInterface
{ {
@ -33,18 +40,29 @@ class ItemsController extends AbstractController implements AccessInterface, Che
*/ */
private $view; private $view;
/**
* @var User
*/
private $user;
/** /**
* Constructor. * Constructor.
* *
* @param ItemsHtmlView $view The view object. * @param ItemsHtmlView $view The view object.
* @param Input $input The input object. * @param Input|null $input The input object.
* @param AbstractApplication $app The application object. * @param AbstractApplication|null $app The application object.
* @param User|null $user
*/ */
public function __construct(ItemsHtmlView $view, Input $input = null, AbstractApplication $app = null) public function __construct(
ItemsHtmlView $view,
Input $input = null,
AbstractApplication $app = null,
User $user = null)
{ {
parent::__construct($input, $app); parent::__construct($input, $app);
$this->view = $view; $this->view = $view;
$this->user = ($user) ?: Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
} }
/** /**
@ -61,7 +79,7 @@ class ItemsController extends AbstractController implements AccessInterface, Che
$this->view->setActiveView('items'); $this->view->setActiveView('items');
// check if user is allowed to access // check if user is allowed to access
if ($this->allow('items')) if ($this->allow('items') && $this->user->get('access.item.read', false))
{ {
$this->getApplication()->setResponse(new HtmlResponse($this->view->render())); $this->getApplication()->setResponse(new HtmlResponse($this->view->render()));
} }

View File

@ -18,7 +18,7 @@ use Laminas\Diactoros\Response\HtmlResponse;
use Octoleo\CMS\View\Admin\DashboardHtmlView; use Octoleo\CMS\View\Admin\DashboardHtmlView;
/** /**
* Controller handling the site's homepage * Controller handling the requests
* *
* @method \Octoleo\CMS\Application\SiteApplication getApplication() Get the application object. * @method \Octoleo\CMS\Application\SiteApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\SiteApplication $app Application object * @property-read \Octoleo\CMS\Application\SiteApplication $app Application object
@ -75,7 +75,7 @@ class LoginController extends AbstractController
$userFactory = $app->getUserFactory(); $userFactory = $app->getUserFactory();
// if the user is logged in we go to dashboard // if the user is logged in we go to dashboard
if ($userFactory->active(false)) if ($userFactory->active())
{ {
$this->view->setActiveDashboard('dashboard'); $this->view->setActiveDashboard('dashboard');
$this->view->setActiveId(0); $this->view->setActiveId(0);

View File

@ -12,18 +12,24 @@ namespace Octoleo\CMS\Controller;
use Joomla\Application\AbstractApplication; use Joomla\Application\AbstractApplication;
use Joomla\Controller\AbstractController; use Joomla\Controller\AbstractController;
use Joomla\Filter\InputFilter as InputFilterAlias;
use Joomla\Input\Input; use Joomla\Input\Input;
use Laminas\Diactoros\Response\HtmlResponse;
use Octoleo\CMS\Controller\Util\AccessInterface;
use Octoleo\CMS\Controller\Util\AccessTrait;
use Octoleo\CMS\Controller\Util\CheckTokenInterface;
use Octoleo\CMS\Controller\Util\CheckTokenTrait;
use Octoleo\CMS\Factory;
use Octoleo\CMS\Filter\InputFilter; use Octoleo\CMS\Filter\InputFilter;
use Octoleo\CMS\Model\MenuModel; use Octoleo\CMS\Model\MenuModel;
use Laminas\Diactoros\Response\HtmlResponse; use Octoleo\CMS\User\User;
use Octoleo\CMS\User\UserFactoryInterface;
use Octoleo\CMS\View\Admin\MenuHtmlView; use Octoleo\CMS\View\Admin\MenuHtmlView;
/** /**
* Controller handling the site's dashboard * Controller handling the requests
* *
* @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\AdminApplication $app Application object * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object
*/ */
class MenuController extends AbstractController implements AccessInterface, CheckTokenInterface class MenuController extends AbstractController implements AccessInterface, CheckTokenInterface
{ {
@ -48,26 +54,31 @@ class MenuController extends AbstractController implements AccessInterface, Chec
*/ */
private $inputFilter; private $inputFilter;
/**
* @var User
*/
private $user;
/** /**
* Constructor. * Constructor.
* *
* @param MenuModel $model The model object. * @param MenuModel $model The model object.
* @param MenuHtmlView $view The view object. * @param MenuHtmlView $view The view object.
* @param Input $input The input object. * @param Input|null $input The input object.
* @param AbstractApplication $app The application object. * @param AbstractApplication|null $app The application object.
*/ */
public function __construct(MenuModel $model, MenuHtmlView $view, Input $input = null, AbstractApplication $app = null) public function __construct(
MenuModel $model,
MenuHtmlView $view,
Input $input = null,
AbstractApplication $app = null,
User $user = null)
{ {
parent::__construct($input, $app); parent::__construct($input, $app);
$this->model = $model; $this->model = $model;
$this->view = $view; $this->view = $view;
$this->inputFilter = InputFilter::getInstance( $this->user = ($user) ?: Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
[],
[],
InputFilterAlias::ONLY_BLOCK_DEFINED_TAGS,
InputFilterAlias::ONLY_BLOCK_DEFINED_ATTRIBUTES
);
} }
/** /**
@ -82,19 +93,26 @@ class MenuController extends AbstractController implements AccessInterface, Chec
$this->getApplication()->allowCache(false); $this->getApplication()->allowCache(false);
$method = $this->getInput()->getMethod(); $method = $this->getInput()->getMethod();
$task = $this->getInput()->getString('task', ''); $task = $this->getInput()->getString('task', '');
$id = $this->getInput()->getInt('id', 0); $id = $this->getInput()->getInt('id', 0);
// if task is delete // if task is delete
if ('delete' === $task) if ('delete' === $task)
{ {
if ($this->model->delete($id)) if ($this->allow('menu') && $this->user->get('access.menu.delete', false))
{ {
$this->getApplication()->enqueueMessage('Menu was deleted!', 'success'); if ($this->model->delete($id))
{
$this->getApplication()->enqueueMessage('Menu was deleted!', 'success');
}
else
{
$this->getApplication()->enqueueMessage('Menu could not be deleted!', 'error');
}
} }
else else
{ {
$this->getApplication()->enqueueMessage('Menu could not be deleted!', 'error'); $this->getApplication()->enqueueMessage('You do not have permission to delete this menu!', 'error');
} }
// go to set page // go to set page
$this->_redirect('menus'); $this->_redirect('menus');
@ -104,21 +122,57 @@ class MenuController extends AbstractController implements AccessInterface, Chec
if ('POST' === $method) if ('POST' === $method)
{ {
$id = $this->setItem(); // check permissions
$update = ($id > 0 && $this->user->get('access.menu.update', false));
$create = ($id == 0 && $this->user->get('access.menu.create', false));
if ( $create || $update )
{
$id = $this->setItem();
}
else
{
// not allowed creating menu
if ($id == 0)
{
$this->getApplication()->enqueueMessage('You do not have permission to create menus!', 'error');
}
// not allowed updating menu
if ($id > 0)
{
$this->getApplication()->enqueueMessage('You do not have permission to update the menu details!', 'error');
}
}
} }
$this->view->setActiveId($id); // check permissions
$this->view->setActiveView('menu'); $read = ($id > 0 && $this->user->get('access.menu.read', false));
$create = ($id == 0 && $this->user->get('access.menu.create', false));
// check if user is allowed to access // check if user is allowed to access
if ($this->allow('menu')) if ($this->allow('menu') && ( $read || $create ))
{ {
// set values for view
$this->view->setActiveId($id);
$this->view->setActiveView('menu');
$this->getApplication()->setResponse(new HtmlResponse($this->view->render())); $this->getApplication()->setResponse(new HtmlResponse($this->view->render()));
} }
else else
{ {
// not allowed creating menu
if ($id == 0 && !$create)
{
$this->getApplication()->enqueueMessage('You do not have permission to create menus!', 'error');
}
// not allowed read menu
if ($id > 0 && !$read)
{
$this->getApplication()->enqueueMessage('You do not have permission to read the menu details!', 'error');
}
// go to set page // go to set page
$this->_redirect(); $this->_redirect('menus');
} }
return true; return true;
@ -139,17 +193,18 @@ class MenuController extends AbstractController implements AccessInterface, Chec
$post = $this->getInput()->getInputForRequestMethod(); $post = $this->getInput()->getInputForRequestMethod();
// we get all the needed items // we get all the needed items
$tempItem = []; $tempItem = [];
$tempItem['id'] = $post->getInt('menu_id', 0); $tempItem['id'] = $post->getInt('menu_id', 0);
$tempItem['title'] = $post->getString('title', ''); $tempItem['title'] = $post->getString('title', '');
$tempItem['alias'] = $post->getString('alias', ''); $tempItem['alias'] = $post->getString('alias', '');
$tempItem['path'] = $post->getString('path', ''); $tempItem['path'] = $post->getString('path', '');
$tempItem['item_id'] = $post->getInt('item_id', 0); $tempItem['item_id'] = $post->getInt('item_id', 0);
$tempItem['published'] = $post->getInt('published', 1); $tempItem['published'] = $post->getInt('published', 1);
$tempItem['publish_up'] = $post->getString('publish_up', ''); $tempItem['publish_up'] = $post->getString('publish_up', '');
$tempItem['publish_down'] = $post->getString('publish_down', ''); $tempItem['publish_down'] = $post->getString('publish_down', '');
$tempItem['position'] = $post->getString('position', 'center'); $tempItem['position'] = $post->getString('position', 'center');
$tempItem['home'] = $post->getInt('home', 0); $tempItem['home'] = $post->getInt('home', 0);
$tempItem['parent_id'] = $post->getInt('parent_id', 0);
// check that we have a Title // check that we have a Title
$can_save = true; $can_save = true;
@ -182,7 +237,8 @@ class MenuController extends AbstractController implements AccessInterface, Chec
$tempItem['publish_up'], $tempItem['publish_up'],
$tempItem['publish_down'], $tempItem['publish_down'],
$tempItem['position'], $tempItem['position'],
$tempItem['home']); $tempItem['home'],
$tempItem['parent_id']);
} }
// add to model the post values // add to model the post values

View File

@ -13,14 +13,21 @@ namespace Octoleo\CMS\Controller;
use Joomla\Application\AbstractApplication; use Joomla\Application\AbstractApplication;
use Joomla\Controller\AbstractController; use Joomla\Controller\AbstractController;
use Joomla\Input\Input; use Joomla\Input\Input;
use Octoleo\CMS\View\Admin\MenusHtmlView;
use Laminas\Diactoros\Response\HtmlResponse; use Laminas\Diactoros\Response\HtmlResponse;
use Octoleo\CMS\Controller\Util\AccessInterface;
use Octoleo\CMS\Controller\Util\AccessTrait;
use Octoleo\CMS\Controller\Util\CheckTokenInterface;
use Octoleo\CMS\Controller\Util\CheckTokenTrait;
use Octoleo\CMS\Factory;
use Octoleo\CMS\User\User;
use Octoleo\CMS\User\UserFactoryInterface;
use Octoleo\CMS\View\Admin\MenusHtmlView;
/** /**
* Controller handling the site's dashboard * Controller handling the requests
* *
* @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\AdminApplication $app Application object * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object
*/ */
class MenusController extends AbstractController implements AccessInterface, CheckTokenInterface class MenusController extends AbstractController implements AccessInterface, CheckTokenInterface
{ {
@ -33,19 +40,29 @@ class MenusController extends AbstractController implements AccessInterface, Che
*/ */
private $view; private $view;
/**
* @var User
*/
private $user;
/** /**
* Constructor. * Constructor.
* *
* @param MenusHtmlView $view The view object. * @param MenusHtmlView $view The view object.
* @param Input $user The user object. * @param Input|null $input The input object.
* @param Input $input The input object. * @param AbstractApplication|null $app The application object.
* @param AbstractApplication $app The application object. * @param User|null $user The user object.
*/ */
public function __construct(MenusHtmlView $view, Input $input = null, AbstractApplication $app = null) public function __construct(
MenusHtmlView $view,
Input $input = null,
AbstractApplication $app = null,
User $user = null)
{ {
parent::__construct($input, $app); parent::__construct($input, $app);
$this->view = $view; $this->view = $view;
$this->user = ($user) ?: Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
} }
/** /**
@ -62,7 +79,7 @@ class MenusController extends AbstractController implements AccessInterface, Che
$this->view->setActiveView('menus'); $this->view->setActiveView('menus');
// check if user is allowed to access // check if user is allowed to access
if ($this->allow('menus')) if ($this->allow('menus') && $this->user->get('access.menu.read', false))
{ {
$this->getApplication()->setResponse(new HtmlResponse($this->view->render())); $this->getApplication()->setResponse(new HtmlResponse($this->view->render()));
} }

View File

@ -14,12 +14,13 @@ use Joomla\Application\AbstractApplication;
use Joomla\Controller\AbstractController; use Joomla\Controller\AbstractController;
use Joomla\Input\Input; use Joomla\Input\Input;
use Joomla\Uri\Uri; use Joomla\Uri\Uri;
use Octoleo\CMS\View\Page\PageHtmlView; use Octoleo\CMS\Utilities\StringHelper;
use Octoleo\CMS\View\Site\PageHtmlView;
use Laminas\Diactoros\Response\HtmlResponse; use Laminas\Diactoros\Response\HtmlResponse;
use Laminas\Diactoros\Response\RedirectResponse; use Laminas\Diactoros\Response\RedirectResponse;
/** /**
* Controller handling the site's simple text pages * Controller handling the requests
* *
* @method \Octoleo\CMS\Application\SiteApplication getApplication() Get the application object. * @method \Octoleo\CMS\Application\SiteApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\SiteApplication $app Application object * @property-read \Octoleo\CMS\Application\SiteApplication $app Application object
@ -36,9 +37,9 @@ class PageController extends AbstractController
/** /**
* Constructor. * Constructor.
* *
* @param PageHtmlView $view The view object. * @param PageHtmlView $view The view object.
* @param Input $input The input object. * @param Input|null $input The input object.
* @param AbstractApplication $app The application object. * @param AbstractApplication|null $app The application object.
*/ */
public function __construct(PageHtmlView $view, Input $input = null, AbstractApplication $app = null) public function __construct(PageHtmlView $view, Input $input = null, AbstractApplication $app = null)
{ {
@ -57,11 +58,34 @@ class PageController extends AbstractController
// Disable all cache for now // Disable all cache for now
$this->getApplication()->allowCache(false); $this->getApplication()->allowCache(false);
$page = $this->getInput()->getString('view', ''); // get the root name
$details = $this->getInput()->getString('details', ''); $root = $this->getInput()->getString('root', '');
// start building the full path
$path = [];
$path[] = $root;
// set a mad depth TODO: we should limit the menu depth to 6 or something
$depth = range(1,20);
// load the whole path
foreach ($depth as $page)
{
$page = StringHelper::numbers($page);
// check if there is a value
$result = $this->getInput()->getString($page, false);
if ($result)
{
$path[] = $result;
}
else
{
// first false means we are at the end of the line
break;
}
}
// set the final path
$path = implode('/', $path);
// if for some reason the view value is administrator // if for some reason the view value is administrator
if ('administrator' === $page) if ('administrator' === $root)
{ {
// get uri request to get host // get uri request to get host
$uri = new Uri($this->getApplication()->get('uri.request')); $uri = new Uri($this->getApplication()->get('uri.request'));
@ -71,7 +95,7 @@ class PageController extends AbstractController
} }
else else
{ {
$this->view->setPage($page); $this->view->setPage($path);
$this->getApplication()->setResponse(new HtmlResponse($this->view->render())); $this->getApplication()->setResponse(new HtmlResponse($this->view->render()));
} }

View File

@ -10,21 +10,25 @@
namespace Octoleo\CMS\Controller; namespace Octoleo\CMS\Controller;
use Exception;
use Joomla\Application\AbstractApplication; use Joomla\Application\AbstractApplication;
use Joomla\Controller\AbstractController; use Joomla\Controller\AbstractController;
use Joomla\Filter\InputFilter as InputFilterAlias;
use Joomla\Input\Input; use Joomla\Input\Input;
use Octoleo\CMS\Date\Date;
use Joomla\Authentication\Password\BCryptHandler; use Joomla\Authentication\Password\BCryptHandler;
use Laminas\Diactoros\Response\HtmlResponse;
use Octoleo\CMS\Controller\Util\AccessInterface;
use Octoleo\CMS\Controller\Util\AccessTrait;
use Octoleo\CMS\Controller\Util\CheckTokenInterface;
use Octoleo\CMS\Controller\Util\CheckTokenTrait;
use Octoleo\CMS\Date\Date;
use Octoleo\CMS\Factory; use Octoleo\CMS\Factory;
use Octoleo\CMS\Filter\InputFilter;
use Octoleo\CMS\Model\UserModel; use Octoleo\CMS\Model\UserModel;
use Octoleo\CMS\User\User;
use Octoleo\CMS\User\UserFactoryInterface; use Octoleo\CMS\User\UserFactoryInterface;
use Octoleo\CMS\View\Admin\UserHtmlView; use Octoleo\CMS\View\Admin\UserHtmlView;
use Laminas\Diactoros\Response\HtmlResponse;
/** /**
* Controller handling the site's dashboard * Controller handling the requests
* *
* @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\AdminApplication $app Application object * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object
@ -47,44 +51,46 @@ class UserController extends AbstractController implements AccessInterface, Chec
*/ */
private $model; private $model;
/**
* @var InputFilter
*/
private $inputFilter;
/** /**
* @var BCryptHandler * @var BCryptHandler
*/ */
private $secure; private $secure;
/**
* @var User
*/
private $user;
/** /**
* Constructor. * Constructor.
* *
* @param UserModel $model The model object. * @param UserModel $model The model object.
* @param UserHtmlView $view The view object. * @param UserHtmlView $view The view object.
* @param Input|null $input The input object. * @param Input|null $input The input object.
* @param User|null $user The current user.
* @param AbstractApplication|null $app The application object. * @param AbstractApplication|null $app The application object.
*/ */
public function __construct(UserModel $model, UserHtmlView $view, Input $input = null, AbstractApplication $app = null, BCryptHandler $secure = null) public function __construct(
UserModel $model,
UserHtmlView $view,
Input $input = null,
AbstractApplication $app = null,
User $user = null,
BCryptHandler $secure = null)
{ {
parent::__construct($input, $app); parent::__construct($input, $app);
$this->model = $model; $this->model = $model;
$this->view = $view; $this->view = $view;
$this->inputFilter = InputFilter::getInstance( $this->user = ($user) ?: Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
[], $this->secure = ($secure) ?: new BCryptHandler();
[],
InputFilterAlias::ONLY_BLOCK_DEFINED_TAGS,
InputFilterAlias::ONLY_BLOCK_DEFINED_ATTRIBUTES
);
$this->secure = ($secure) ?: new BCryptHandler();
} }
/** /**
* Execute the controller. * Execute the controller.
* *
* @return boolean * @return boolean
* @throws \Exception * @throws Exception
*/ */
public function execute(): bool public function execute(): bool
{ {
@ -98,21 +104,35 @@ class UserController extends AbstractController implements AccessInterface, Chec
// if task is delete // if task is delete
if ('delete' === $task) 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 // check that the user does not delete him/her self
$user_id = $user->get('id', -1); if ($this->allow('user') && $this->user->get('access.user.delete', false))
if ($user_id == $id)
{ {
$this->getApplication()->enqueueMessage('You can not delete your own account!', 'warning'); // get the current user being deleted
} /** @var \Octoleo\CMS\User\User $userBeingDeleted */
elseif ($this->model->delete($id)) $userBeingDeleted = Factory::getContainer()->get(UserFactoryInterface::class)->getUser($id);
{ // get the current active user ID
$this->getApplication()->enqueueMessage('User was deleted!', 'success'); $user_id = $this->user->get('id', -1);
// is this the same user account as the active user
if ($user_id == $id)
{
$this->getApplication()->enqueueMessage('You can not delete your own account!', 'warning');
}
elseif ($userBeingDeleted->get('is_admin', false) && !$this->user->get('is_admin', false))
{
$this->getApplication()->enqueueMessage('You dont have the permission to delete an administrator account!', 'error');
}
elseif ($this->model->delete($id))
{
$this->getApplication()->enqueueMessage('User was deleted!', 'success');
}
else
{
$this->getApplication()->enqueueMessage('User could not be deleted!', 'error');
}
} }
else else
{ {
$this->getApplication()->enqueueMessage('User could not be deleted!', 'error'); $this->getApplication()->enqueueMessage('You do not have permission to delete this user!', 'error');
} }
// go to set page // go to set page
$this->_redirect('users'); $this->_redirect('users');
@ -120,23 +140,81 @@ class UserController extends AbstractController implements AccessInterface, Chec
return true; return true;
} }
// set the current user ID
$user_id = $this->user->get('id', -1);
if ('POST' === $method) if ('POST' === $method)
{ {
$id = $this->setItem(); // always check the post token
$this->checkToken();
// get the post
$post = $this->getInput()->getInputForRequestMethod();
// we get all the needed items
$tempItem = $post->getArray(['groups' => 'INT']);
$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);
// check permissions
$update = ($tempItem['id'] > 0 && $this->user->get('access.user.update', false));
$create = ($tempItem['id'] == 0 && $this->user->get('access.user.create', false));
$selfUpdate = ($tempItem['id'] > 0 && $tempItem['id'] == $user_id);
if ($create || $update || $selfUpdate)
{
$id = $this->setItem($tempItem);
}
else
{
// not allowed creating user
if ($id == 0)
{
$this->getApplication()->enqueueMessage('You do not have permission to create users!', 'error');
}
// not allowed updating user
if ($id > 0)
{
$this->getApplication()->enqueueMessage('You do not have permission to update the user details!', 'error');
}
}
} }
$this->view->setActiveId($id); // check permissions
$this->view->setActiveView('user'); $read = ($id > 0 && $this->user->get('access.user.read', false));
$create = ($id == 0 && $this->user->get('access.user.create', false));
$selfUpdate = ($id > 0 && $id == $user_id);
// check if user is allowed to access // check if user is allowed to access
if ($this->allow('user')) if ($this->allow('user') && ($read || $create || $selfUpdate))
{ {
// set values for view
$this->view->setActiveId($id);
$this->view->setActiveView('user');
$this->getApplication()->setResponse(new HtmlResponse($this->view->render())); $this->getApplication()->setResponse(new HtmlResponse($this->view->render()));
} }
else else
{ {
// not allowed creating user
if ($id == 0 && !$create)
{
$this->getApplication()->enqueueMessage('You do not have permission to create users!', 'error');
}
// not allowed updating user
if ($id > 0 && !$read)
{
$this->getApplication()->enqueueMessage('You do not have permission to read the user details!', 'error');
}
// go to set page // go to set page
$this->_redirect(); $this->_redirect('users');
} }
return true; return true;
@ -145,33 +223,18 @@ class UserController extends AbstractController implements AccessInterface, Chec
/** /**
* Set an item * Set an item
* *
* @param array $tempItem
*
* @return int * @return int
* @throws \Exception * @throws Exception
*/ */
protected function setItem(): int protected function setItem(array $tempItem): 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; $can_save = true;
// check that we have a name // check that we have a name
if (empty($tempItem['name'])) if (empty($tempItem['name']))
{ {
// we show a warning message // we show an error message
$tempItem['name'] = ''; $tempItem['name'] = '';
$this->getApplication()->enqueueMessage('Name field is required.', 'error'); $this->getApplication()->enqueueMessage('Name field is required.', 'error');
$can_save = false; $can_save = false;
@ -179,7 +242,7 @@ class UserController extends AbstractController implements AccessInterface, Chec
// check that we have a username // check that we have a username
if (empty($tempItem['username'])) if (empty($tempItem['username']))
{ {
// we show a warning message // we show an error message
$tempItem['username'] = ''; $tempItem['username'] = '';
$this->getApplication()->enqueueMessage('Username field is required.', 'error'); $this->getApplication()->enqueueMessage('Username field is required.', 'error');
$can_save = false; $can_save = false;
@ -187,7 +250,7 @@ class UserController extends AbstractController implements AccessInterface, Chec
// check that we have an email TODO: check that we have a valid email // check that we have an email TODO: check that we have a valid email
if (empty($tempItem['email'])) if (empty($tempItem['email']))
{ {
// we show a warning message // we show an error message
$tempItem['email'] = ''; $tempItem['email'] = '';
$this->getApplication()->enqueueMessage('Email field is required.', 'error'); $this->getApplication()->enqueueMessage('Email field is required.', 'error');
$can_save = false; $can_save = false;
@ -195,8 +258,8 @@ class UserController extends AbstractController implements AccessInterface, Chec
// check passwords // check passwords
if (isset($tempItem['password2']) && $tempItem['password'] != $tempItem['password2']) if (isset($tempItem['password2']) && $tempItem['password'] != $tempItem['password2'])
{ {
// we show a warning message // we show an error message
$tempItem['password'] = 'xxxxxxxxxx'; $tempItem['password'] = 'xxxxxxxxxx';
$tempItem['password2'] = 'xxxxxxxxxx'; $tempItem['password2'] = 'xxxxxxxxxx';
$this->getApplication()->enqueueMessage('Passwords do not match.', 'error'); $this->getApplication()->enqueueMessage('Passwords do not match.', 'error');
$can_save = false; $can_save = false;
@ -207,8 +270,8 @@ class UserController extends AbstractController implements AccessInterface, Chec
{ {
if ($tempItem['id'] == 0) if ($tempItem['id'] == 0)
{ {
// we show a warning message // we show an error message
$tempItem['password'] = 'xxxxxxxxxx'; $tempItem['password'] = 'xxxxxxxxxx';
$tempItem['password2'] = 'xxxxxxxxxx'; $tempItem['password2'] = 'xxxxxxxxxx';
$this->getApplication()->enqueueMessage('Passwords not set.', 'error'); $this->getApplication()->enqueueMessage('Passwords not set.', 'error');
$can_save = false; $can_save = false;
@ -220,8 +283,8 @@ class UserController extends AbstractController implements AccessInterface, Chec
} }
elseif (strlen($tempItem['password']) < 7) elseif (strlen($tempItem['password']) < 7)
{ {
// we show a warning message // we show an error message
$tempItem['password'] = 'xxxxxxxxxx'; $tempItem['password'] = 'xxxxxxxxxx';
$tempItem['password2'] = 'xxxxxxxxxx'; $tempItem['password2'] = 'xxxxxxxxxx';
$this->getApplication()->enqueueMessage('Passwords must be longer than 6 characters.', 'error'); $this->getApplication()->enqueueMessage('Passwords must be longer than 6 characters.', 'error');
$can_save = false; $can_save = false;
@ -235,29 +298,150 @@ class UserController extends AbstractController implements AccessInterface, Chec
// can we save the item // can we save the item
if ($can_save) 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 // check that the user does not block him/her self
$user_id = $user->get('id', -1); $user_id = $this->user->get('id', -1);
if ($user_id == $tempItem['id'] && $tempItem['block'] == 1) $block_status = $tempItem['block'];
// this user is the current user
if ($user_id == $tempItem['id'])
{ {
// don't allow user to block self // don't allow user to block self
$this->getApplication()->enqueueMessage('You can not block yourself!', 'warning'); if ($tempItem['block'] != 0)
$tempItem['block'] = 0; {
// we show a warning message
$this->getApplication()->enqueueMessage('You can not block yourself!', 'warning');
$tempItem['block'] = 0;
}
// don't allow user remove self from admin groups
if ($this->user->get('is_admin', false))
{
$admin_groups = $this->user->get('is_admin_groups', []);
if (is_array($admin_groups) && count($admin_groups) > 0)
{
$notice_set_groups = true;
foreach ($admin_groups as $admin_group)
{
if (!is_array($tempItem['groups']) || !in_array($admin_group, $tempItem['groups']))
{
if ($notice_set_groups)
{
// we show a warning message
$this->getApplication()->enqueueMessage('You can not remove yourself from the administrator group!', 'warning');
$notice_set_groups = false;
}
$tempItem['groups'][] = $admin_group;
}
}
}
else
{
// we show an error message
$this->getApplication()->enqueueMessage('There is a problem with the admin user groups, we can not save the user details.', 'error');
$can_save = false;
}
}
} }
return $this->model->setItem( // can we save the item
$tempItem['id'], if ($can_save)
$tempItem['name'], {
$tempItem['username'], // check that the user will have some groups left
$tempItem['email'], if (!is_array($tempItem['groups']) || count($tempItem['groups']) == 0)
$tempItem['password'], {
$tempItem['block'], // we show a warning message
$tempItem['sendEmail'], $this->getApplication()->enqueueMessage('You must select at least one group.', 'warning');
$today, // this user is the current user
$tempItem['activation']); if ($user_id == $tempItem['id'])
{
$tempItem['groups'] = $this->user->get('groups_ids', []);
// check if we still have no groups
if (count($tempItem['groups']) == 0)
{
$can_save = false;
}
}
else
{
$can_save = false;
}
}
}
// can we save the item
if ($can_save)
{
// none admin restrictions TODO would like to move this to the database and not hard code it
if (!$this->user->get('is_admin', false))
{
// with existing users
if ($tempItem['id'] > 0)
{
// get the current user being saved
/** @var \Octoleo\CMS\User\User $userBeingSaved */
$userBeingSaved = Factory::getContainer()->get(UserFactoryInterface::class)->getUser($tempItem['id']);
// don't allow block status change by none admin users
$block = $userBeingSaved->get('block', 1);
$current_posted_block = $tempItem['block'];
// if the status changed we revert and give message
// we allow block but not un-block
if ($block != $current_posted_block && $current_posted_block == 0)
{
// we show a warning message
$this->getApplication()->enqueueMessage('Only the administrator can update user access to system.', 'warning');
$tempItem['block'] = 1;
}
// get current group to see if we must give a notice
$groups = $userBeingSaved->get('groups_ids', []);
$current_posted_groups = $tempItem['groups'];
sort($groups);
sort($current_posted_groups);
// if the groups changes we give a message
if ($groups !== $current_posted_groups)
{
// we show a warning message
$this->getApplication()->enqueueMessage('Only the administrator can update user group selection.', 'warning');
}
// if the current user being saved is an admin account
// we don't allow the following changes
if ($userBeingSaved->get('is_admin', false))
{
// we do not allow password changes of admin accounts
$tempItem['password'] = '';
// we don't allow username changes
$tempItem['username'] = $userBeingSaved->get('username', $tempItem['username']);
// we don't allow change of status
if ($block != $current_posted_block)
{
// we show an error message
$this->getApplication()->enqueueMessage('Only the administrator can update another administrator account access to system.', 'error');
$tempItem['block'] = $block;
}
}
}
else
{
// new users created by none admin must be blocked by default
// since only admin can unblock any users
$tempItem['block'] = 1;
}
// only admin can change groups
// empty groups will not get updated
$tempItem['groups'] = [];
}
$today = (new Date())->toSql();
return $this->model->setItem(
$tempItem['id'],
$tempItem['name'],
$tempItem['username'],
$tempItem['groups'],
$tempItem['email'],
$tempItem['password'],
$tempItem['block'],
$tempItem['sendEmail'],
$today,
$tempItem['activation']);
}
} }
// add to model the post values // add to model the post values

View File

@ -0,0 +1,262 @@
<?php
/**
* @package Octoleo CMS
*
* @created 20th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/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\Controller\Util\AccessInterface;
use Octoleo\CMS\Controller\Util\AccessTrait;
use Octoleo\CMS\Controller\Util\CheckTokenInterface;
use Octoleo\CMS\Controller\Util\CheckTokenTrait;
use Octoleo\CMS\Factory;
use Octoleo\CMS\Model\UsergroupModel;
use Octoleo\CMS\User\User;
use Octoleo\CMS\User\UserFactoryInterface;
use Octoleo\CMS\View\Admin\UsergroupHtmlView;
use Laminas\Diactoros\Response\HtmlResponse;
/**
* Controller handling the requests
*
* @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\AdminApplication $app Application object
*/
class UserGroupController extends AbstractController implements AccessInterface, CheckTokenInterface
{
use AccessTrait, CheckTokenTrait;
/**
* The view object.
*
* @var UsergroupHtmlView
*/
private $view;
/**
* The model object.
*
* @var UsergroupModel
*/
private $model;
/**
* @var User
*/
private $user;
/**
* Constructor.
*
* @param UsergroupModel $model The model object.
* @param UsergroupHtmlView $view The view object.
* @param Input|null $input The input object.
* @param AbstractApplication|null $app The application object.
*/
public function __construct(
UsergroupModel $model,
UsergroupHtmlView $view,
Input $input = null,
AbstractApplication $app = null,
User $user = null)
{
parent::__construct($input, $app);
$this->model = $model;
$this->view = $view;
$this->user = ($user) ?: Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
}
/**
* 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->allow('usergroup') && $this->user->get('access.usergroup.delete', false))
{
// TODO not ideal to hard code any ID
if ($id == 1)
{
$this->getApplication()->enqueueMessage('This is the administrator user group that can not be deleted.', 'error');
}
elseif ($id > 0 && $this->model->linked($id))
{
$this->getApplication()->enqueueMessage('This user group is still in use and can therefore no be deleted.', 'error');
}
elseif ($this->model->delete($id))
{
$this->getApplication()->enqueueMessage('User group was deleted!', 'success');
}
else
{
$this->getApplication()->enqueueMessage('User group could not be deleted!', 'error');
}
}
else
{
$this->getApplication()->enqueueMessage('You do not have permission to delete this user group!', 'error');
}
// go to set page
$this->_redirect('usergroups');
return true;
}
if ('POST' === $method)
{
// check permissions
$update = ($id > 0 && $this->user->get('access.usergroup.update', false));
$create = ($id == 0 && $this->user->get('access.usergroup.create', false));
// TODO not ideal to hard code any ID
if ($id == 1 && $update)
{
$this->getApplication()->enqueueMessage('This is the administrator user group that can not change.', 'error');
}
elseif ( $create || $update )
{
$id = $this->setItem();
}
else
{
// not allowed creating user group
if ($id == 0)
{
$this->getApplication()->enqueueMessage('You do not have permission to create user groups!', 'error');
}
// not allowed updating user group
if ($id > 0)
{
$this->getApplication()->enqueueMessage('You do not have permission to update the user group details!', 'error');
}
}
}
// check permissions
$read = ($id > 0 && $this->user->get('access.usergroup.read', false));
$create = ($id == 0 && $this->user->get('access.usergroup.create', false));
// check if user is allowed to access
if ($this->allow('usergroup') && ( $read || $create ))
{
// set values for view
$this->view->setActiveId($id);
$this->view->setActiveView('usergroup');
$this->getApplication()->setResponse(new HtmlResponse($this->view->render()));
}
else
{
// not allowed creating user group
if ($id == 0 && !$create)
{
$this->getApplication()->enqueueMessage('You do not have permission to create user groups!', 'error');
}
// not allowed read user group
if ($id > 0 && !$read)
{
$this->getApplication()->enqueueMessage('You do not have permission to read the user group details!', 'error');
}
// go to set page
$this->_redirect('items');
}
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 = $post->getArray(['params' => 'STRING']);;
$tempItem['id'] = $post->getInt('usergroup_id', 0);
$tempItem['title'] = $post->getString('title', '');
$can_save = true;
// check that we have a name
if (empty($tempItem['title']))
{
// we show a warning message
$tempItem['name'] = '';
$this->getApplication()->enqueueMessage('User group name field is required.', 'error');
$can_save = false;
}
// set the params
$build_params = $this->model->getGroupDefaultsAccess();
if (isset($tempItem['params']) && is_array($tempItem['params']) && count($tempItem['params']))
{
$only = 'CRUD';
foreach ($build_params as $n => &$item)
{
if (isset($tempItem['params'][$item->area]) && strlen($tempItem['params'][$item->area]))
{
$array_of_access = str_split(strtoupper($tempItem['params'][$item->area]));
$access_keeper = [];
if ($array_of_access)
{
foreach ($array_of_access as $char)
{
if (strpos($only, $char) === false)
{
$this->getApplication()->enqueueMessage("User group access in ({$item->area} area) had a wrong key ({$char}) so we removed it. Please only use the keys prescribed.", 'warning');
}
else
{
$access_keeper[] = $char;
}
}
}
$item->access = implode($access_keeper);
}
}
}
// update the params
$tempItem['params'] = $build_params;
// can we save the item
if ($can_save)
{
return $this->model->setItem(
$tempItem['id'],
$tempItem['title'],
$tempItem['params']);
}
// add to model the post values
$this->model->tempItem = $tempItem;
return $tempItem['id'];
}
}

View File

@ -0,0 +1,94 @@
<?php
/**
* @package Octoleo CMS
*
* @created 20th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/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\Controller\Util\AccessInterface;
use Octoleo\CMS\Controller\Util\AccessTrait;
use Octoleo\CMS\Controller\Util\CheckTokenInterface;
use Octoleo\CMS\Controller\Util\CheckTokenTrait;
use Octoleo\CMS\Factory;
use Octoleo\CMS\User\User;
use Octoleo\CMS\User\UserFactoryInterface;
use Octoleo\CMS\View\Admin\UsergroupsHtmlView;
use Laminas\Diactoros\Response\HtmlResponse;
/**
* Controller handling the requests
*
* @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\AdminApplication $app Application object
*/
class UsergroupsController extends AbstractController implements AccessInterface, CheckTokenInterface
{
use AccessTrait, CheckTokenTrait;
/**
* The view object.
*
* @var UsergroupsHtmlView
*/
private $view;
/**
* @var User
*/
private $user;
/**
* Constructor.
*
* @param UsergroupsHtmlView $view The view object.
* @param Input|null $input The input object.
* @param AbstractApplication|null $app The application object.
* @param User|null $user
*/
public function __construct(
UsergroupsHtmlView $view,
Input $input = null,
AbstractApplication $app = null,
User $user = null)
{
parent::__construct($input, $app);
$this->view = $view;
$this->user = ($user) ?: Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
}
/**
* Execute the controller.
*
* @return boolean
* @throws \Exception
*/
public function execute(): bool
{
// Do not Enable browser caching
$this->getApplication()->allowCache(false);
$this->view->setActiveView('usergroups');
// check if user is allowed to access
if ($this->allow('usergroups') && $this->user->get('access.usergroup.read', false))
{
$this->getApplication()->setResponse(new HtmlResponse($this->view->render()));
}
else
{
// go to set page
$this->_redirect();
}
return true;
}
}

View File

@ -13,14 +13,21 @@ namespace Octoleo\CMS\Controller;
use Joomla\Application\AbstractApplication; use Joomla\Application\AbstractApplication;
use Joomla\Controller\AbstractController; use Joomla\Controller\AbstractController;
use Joomla\Input\Input; use Joomla\Input\Input;
use Octoleo\CMS\Controller\Util\AccessInterface;
use Octoleo\CMS\Controller\Util\AccessTrait;
use Octoleo\CMS\Controller\Util\CheckTokenInterface;
use Octoleo\CMS\Controller\Util\CheckTokenTrait;
use Octoleo\CMS\Factory;
use Octoleo\CMS\User\User;
use Octoleo\CMS\User\UserFactoryInterface;
use Octoleo\CMS\View\Admin\UsersHtmlView; use Octoleo\CMS\View\Admin\UsersHtmlView;
use Laminas\Diactoros\Response\HtmlResponse; use Laminas\Diactoros\Response\HtmlResponse;
/** /**
* Controller handling the site's dashboard * Controller handling the requests
* *
* @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object. * @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object.
* @property-read \Octoleo\CMS\Application\AdminApplication $app Application object * @property-read \Octoleo\CMS\Application\AdminApplication $app Application object
*/ */
class UsersController extends AbstractController implements AccessInterface, CheckTokenInterface class UsersController extends AbstractController implements AccessInterface, CheckTokenInterface
{ {
@ -33,6 +40,11 @@ class UsersController extends AbstractController implements AccessInterface, Che
*/ */
private $view; private $view;
/**
* @var User
*/
private $user;
/** /**
* Constructor. * Constructor.
* *
@ -40,11 +52,16 @@ class UsersController extends AbstractController implements AccessInterface, Che
* @param Input $input The input object. * @param Input $input The input object.
* @param AbstractApplication $app The application object. * @param AbstractApplication $app The application object.
*/ */
public function __construct(UsersHtmlView $view, Input $input = null, AbstractApplication $app = null) public function __construct(
UsersHtmlView $view,
Input $input = null,
AbstractApplication $app = null,
User $user = null)
{ {
parent::__construct($input, $app); parent::__construct($input, $app);
$this->view = $view; $this->view = $view;
$this->user = ($user) ?: Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
} }
/** /**
@ -61,7 +78,7 @@ class UsersController extends AbstractController implements AccessInterface, Che
$this->view->setActiveView('users'); $this->view->setActiveView('users');
// check if user is allowed to access // check if user is allowed to access
if ($this->allow('users')) if ($this->allow('users') && $this->user->get('access.user.read', false))
{ {
$this->getApplication()->setResponse(new HtmlResponse($this->view->render())); $this->getApplication()->setResponse(new HtmlResponse($this->view->render()));
} }

View File

@ -8,7 +8,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\Controller; namespace Octoleo\CMS\Controller\Util;
/** /**
* Class for checking the user access * Class for checking the user access

View File

@ -8,7 +8,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\Controller; namespace Octoleo\CMS\Controller\Util;
use Joomla\Uri\Uri; use Joomla\Uri\Uri;

View File

@ -8,7 +8,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\Controller; namespace Octoleo\CMS\Controller\Util;
/** /**
* Class for checking the form had a token * Class for checking the form had a token

View File

@ -8,7 +8,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\Controller; namespace Octoleo\CMS\Controller\Util;
/** /**
* Class for checking the form had a token * Class for checking the form had a token

View File

@ -11,32 +11,17 @@
namespace Octoleo\CMS\Model; namespace Octoleo\CMS\Model;
use Joomla\Database\DatabaseDriver; use Joomla\Database\DatabaseDriver;
use Joomla\Database\ParameterType;
use Joomla\Model\DatabaseModelInterface; use Joomla\Model\DatabaseModelInterface;
use Joomla\Model\DatabaseModelTrait; use Joomla\Model\DatabaseModelTrait;
/** /**
* Model class for pages * Model class
* source: https://github.com/joomla/framework.joomla.org/blob/master/src/Model/PackageModel.php * source: https://github.com/joomla/framework.joomla.org/blob/master/src/Model/PackageModel.php
*/ */
class DashboardModel implements DatabaseModelInterface class DashboardModel implements DatabaseModelInterface
{ {
use DatabaseModelTrait; use DatabaseModelTrait;
/**
* Array of legal dashboards
*
* @var array
*/
private $legalDashboards = [
'items' => 'items.twig',
'item' => 'edit.twig',
'menus' => 'menus.twig',
'menu' => 'edit.twig',
'users' => 'users.twig',
'user' => 'edit.twig'
];
/** /**
* Instantiate the model. * Instantiate the model.
* *
@ -48,7 +33,7 @@ class DashboardModel implements DatabaseModelInterface
} }
/** /**
* Get a active dashboard template name * Get an active dashboard template name
* *
* @param string $dashboardName The dashboard to lookup * @param string $dashboardName The dashboard to lookup
* *
@ -57,11 +42,6 @@ class DashboardModel implements DatabaseModelInterface
*/ */
public function getDashboard(string $dashboardName): string public function getDashboard(string $dashboardName): string
{ {
if (!isset($this->legalDashboards[$dashboardName])) return 'dashboard.twig'; // only one at this time
{
return 'dashboard.twig';
}
return $this->legalDashboards[$dashboardName];
} }
} }

View File

@ -17,7 +17,7 @@ use Joomla\Model\DatabaseModelTrait;
use Octoleo\CMS\Date\Date; use Octoleo\CMS\Date\Date;
/** /**
* Model class for items * Model class
*/ */
class ItemModel implements DatabaseModelInterface class ItemModel implements DatabaseModelInterface
{ {
@ -134,6 +134,8 @@ class ItemModel implements DatabaseModelInterface
// remove what can not now be set // remove what can not now be set
$data['modified'] = '0000-00-00 00:00:00'; $data['modified'] = '0000-00-00 00:00:00';
$data['modified_by'] = 0; $data['modified_by'] = 0;
// we don't have any params for now
$data['params'] = '';
// change to object // change to object
$data = (object) $data; $data = (object) $data;

View File

@ -11,12 +11,11 @@
namespace Octoleo\CMS\Model; namespace Octoleo\CMS\Model;
use Joomla\Database\DatabaseDriver; use Joomla\Database\DatabaseDriver;
use Joomla\Database\ParameterType;
use Joomla\Model\DatabaseModelInterface; use Joomla\Model\DatabaseModelInterface;
use Joomla\Model\DatabaseModelTrait; use Joomla\Model\DatabaseModelTrait;
/** /**
* Model class for items * Model class
*/ */
class ItemsModel implements DatabaseModelInterface class ItemsModel implements DatabaseModelInterface
{ {

View File

@ -14,15 +14,25 @@ use Joomla\Database\DatabaseDriver;
use Joomla\Database\ParameterType; use Joomla\Database\ParameterType;
use Joomla\Model\DatabaseModelInterface; use Joomla\Model\DatabaseModelInterface;
use Joomla\Model\DatabaseModelTrait; use Joomla\Model\DatabaseModelTrait;
use Joomla\String\StringHelper;
use Octoleo\CMS\Date\Date; use Octoleo\CMS\Date\Date;
use Octoleo\CMS\Model\Util\MenuInterface;
use Octoleo\CMS\Model\Util\SelectMenuTrait;
use Octoleo\CMS\Model\Util\UniqueInterface;
use Octoleo\CMS\Model\Util\UniqueMenuAliasTrait;
/** /**
* Model class for menu item * Model class
*/ */
class MenuModel implements DatabaseModelInterface class MenuModel implements DatabaseModelInterface, UniqueInterface, MenuInterface
{ {
use DatabaseModelTrait; use DatabaseModelTrait, UniqueMenuAliasTrait, SelectMenuTrait;
/**
* Active id
*
* @var int
*/
public $id = 0;
/** /**
* @var array * @var array
@ -52,6 +62,7 @@ class MenuModel implements DatabaseModelInterface
* @param string $publishDown * @param string $publishDown
* @param string $position * @param string $position
* @param int $home * @param int $home
* @param int $parent
* *
* @return int * @return int
* @throws \Exception * @throws \Exception
@ -66,12 +77,16 @@ class MenuModel implements DatabaseModelInterface
string $publishUp, string $publishUp,
string $publishDown, string $publishDown,
string $position, string $position,
int $home): int int $home,
int $parent): int
{ {
$db = $this->getDb(); $db = $this->getDb();
// set the path if not set // set the alias if not set
$this->setPathAlias($id, $title, $path, $alias); $alias = (empty($alias)) ? $title : $alias;
$alias = $this->unique($id, $alias, $parent);
// set the path
$path = $this->getPath($alias, $parent);
$data = [ $data = [
'title' => (string) $title, 'title' => (string) $title,
@ -82,7 +97,7 @@ class MenuModel implements DatabaseModelInterface
'publish_up' => (string) (empty($publishUp)) ? '0000-00-00 00:00:00' : (new Date($publishUp))->toSql(), '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(), 'publish_down' => (string) (empty($publishDown)) ? '0000-00-00 00:00:00' : (new Date($publishDown))->toSql(),
'home' => (int) $home, 'home' => (int) $home,
'parent_id' => 0 // only root items for now 'parent_id' => (int) $parent
]; ];
// we set position in params // we set position in params
@ -91,7 +106,9 @@ class MenuModel implements DatabaseModelInterface
// if we have ID update // if we have ID update
if ($id > 0) if ($id > 0)
{ {
// set active ID
$data['id'] = (int) $id; $data['id'] = (int) $id;
$this->id = (int) $id;
// change to object // change to object
$data = (object) $data; $data = (object) $data;
@ -272,67 +289,65 @@ class MenuModel implements DatabaseModelInterface
} }
/** /**
* @param int $id * get path
* @param string $title *
* @param string $path
* @param string $alias * @param string $alias
* @param int $parent
*
* @return string
*/ */
private function setPathAlias(int $id, string $title, string &$path, string &$alias) private function getPath(string $alias, int $parent): string
{ {
$alias = (empty($alias)) ? $title : $alias; // alias bucket
$alias = preg_replace('/\s+/', '-', strtolower(preg_replace("/[^A-Za-z0-9\- ]/", '', $alias))); $bucket = [];
// TODO: we will only have root menus for now, no sub-menus $bucket[] = $alias;
$seeker = $alias; $parent = $this->getParent($parent);
$pointer = 2; // make sure to get all path aliases TODO: we should limit the menu depth to 6 or something
while ($this->exist($id, $seeker)) while (isset($parent->alias))
{ {
$seeker = $alias . '-' . $pointer; // load the alias
$pointer++; $bucket[] = $parent->alias;
// get the next parent
$parent = $this->getParent($parent->parent_id);
} }
// update the path // now return the path
$alias = $seeker; return implode('/', array_reverse($bucket));
$path = $seeker;
} }
/** /**
* Check if an alias exist * get parent
* *
* @param int $id * @param int $id
* @param string $alias
* *
* @return bool * @return \stdClass
*/ */
private function exist(int $id, string $alias): bool private function getParent(int $id): \stdClass
{ {
$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) if ($id > 0)
{ {
$query $db = $this->getDb();
->where($db->quoteName('id') . ' != :id') $query = $db->getQuery(true)
->bind(':id', $id, ParameterType::INTEGER); ->select('*')
} ->from($db->quoteName('#__menu'))
->where($db->quoteName('id') . ' = :id')
->bind(':id', $id)
->setLimit(1);
try try
{ {
$id = $db->setQuery($query)->loadResult(); $parent = $db->setQuery($query)->loadObject();
} }
catch (\RuntimeException $e) catch (\RuntimeException $e)
{ {
// we ignore this and just return an empty object // we ignore this and just return an empty object
} }
if (isset($id) && $id > 0) // return only if found
{ if (isset($parent) && $parent instanceof \stdClass)
return true; {
return $parent;
}
} }
return false; return new \stdClass();
} }
} }

View File

@ -16,7 +16,7 @@ use Joomla\Model\DatabaseModelInterface;
use Joomla\Model\DatabaseModelTrait; use Joomla\Model\DatabaseModelTrait;
/** /**
* Model class for menus * Model class
*/ */
class MenusModel implements DatabaseModelInterface class MenusModel implements DatabaseModelInterface
{ {

View File

@ -13,13 +13,19 @@ namespace Octoleo\CMS\Model;
use Joomla\Database\DatabaseDriver; use Joomla\Database\DatabaseDriver;
use Joomla\Model\DatabaseModelInterface; use Joomla\Model\DatabaseModelInterface;
use Joomla\Model\DatabaseModelTrait; use Joomla\Model\DatabaseModelTrait;
use Octoleo\CMS\Model\Util\MenuInterface;
use Octoleo\CMS\Model\Util\PageInterface;
use Octoleo\CMS\Model\Util\HomeMenuInterface;
use Octoleo\CMS\Model\Util\HomeMenuTrait;
use Octoleo\CMS\Model\Util\SiteMenuTrait;
use Octoleo\CMS\Model\Util\SitePageTrait;
/** /**
* Model class for pages * Model class
*/ */
class PageModel implements DatabaseModelInterface, MenuInterface, PageInterface class PageModel implements DatabaseModelInterface, MenuInterface, PageInterface, HomeMenuInterface
{ {
use DatabaseModelTrait, SiteMenuTrait, SitePageTrait; use DatabaseModelTrait, HomeMenuTrait, SiteMenuTrait, SitePageTrait;
/** /**
* Instantiate the model. * Instantiate the model.

View File

@ -15,13 +15,18 @@ use Joomla\Database\ParameterType;
use Joomla\Model\DatabaseModelInterface; use Joomla\Model\DatabaseModelInterface;
use Joomla\Model\DatabaseModelTrait; use Joomla\Model\DatabaseModelTrait;
use Octoleo\CMS\Date\Date; use Octoleo\CMS\Date\Date;
use Octoleo\CMS\Model\Util\GetUsergroupsInterface;
use Octoleo\CMS\Model\Util\GetUsergroupsTrait;
use Exception;
use RuntimeException;
use stdClass;
/** /**
* Model class for items * Model class
*/ */
class UserModel implements DatabaseModelInterface class UserModel implements DatabaseModelInterface, GetUsergroupsInterface
{ {
use DatabaseModelTrait; use DatabaseModelTrait, GetUsergroupsTrait;
/** /**
* @var array * @var array
@ -31,9 +36,9 @@ class UserModel implements DatabaseModelInterface
/** /**
* Instantiate the model. * Instantiate the model.
* *
* @param DatabaseDriver $db The database adapter. * @param DatabaseDriver|null $db The database adapter.
*/ */
public function __construct(DatabaseDriver $db) public function __construct(DatabaseDriver $db = null)
{ {
$this->setDb($db); $this->setDb($db);
} }
@ -44,6 +49,7 @@ class UserModel implements DatabaseModelInterface
* @param int $id * @param int $id
* @param string $name * @param string $name
* @param string $username * @param string $username
* @param array $groups
* @param string $email * @param string $email
* @param string $password * @param string $password
* @param int $block * @param int $block
@ -52,12 +58,13 @@ class UserModel implements DatabaseModelInterface
* @param int $activation * @param int $activation
* *
* @return int * @return int
* @throws \Exception * @throws Exception
*/ */
public function setItem( public function setItem(
int $id, int $id,
string $name, string $name,
string $username, string $username,
array $groups,
string $email, string $email,
string $password, string $password,
int $block, int $block,
@ -96,16 +103,15 @@ class UserModel implements DatabaseModelInterface
{ {
$db->updateObject('#__users', $data, 'id'); $db->updateObject('#__users', $data, 'id');
} }
catch (\RuntimeException $exception) catch (RuntimeException $exception)
{ {
throw new \RuntimeException($exception->getMessage(), 404); throw new RuntimeException($exception->getMessage(), 404);
} }
return $id;
} }
else else
{ {
// we don't have any params for now
$data['params'] = '';
// change to object // change to object
$data = (object) $data; $data = (object) $data;
@ -113,13 +119,68 @@ class UserModel implements DatabaseModelInterface
{ {
$db->insertObject('#__users', $data); $db->insertObject('#__users', $data);
} }
catch (\RuntimeException $exception) catch (RuntimeException $exception)
{ {
throw new \RuntimeException($exception->getMessage(), 404); throw new RuntimeException($exception->getMessage(), 404);
} }
return $db->insertid(); $id = $db->insertid();
} }
// update the group linked to this user
// only if there are groups
if (count($groups) > 0)
{
try
{
$this->setGroups($id, $groups);
}
catch (RuntimeException $exception)
{
throw new RuntimeException($exception->getMessage(), 404);
}
}
return $id;
}
/**
* Add groups for this user
*
* @param int $id
* @param array $groups
*
* @return bool
* @throws Exception
*/
private function setGroups(int $id, array $groups): bool
{
$db = $this->getDb();
// add the new groups
$query = $db->getQuery(true)
->insert($db->quoteName('#__user_usergroup_map'))
->columns($db->quoteName(['user_id', 'group_id']));
// Insert values.
foreach ($groups as $group)
{
$query->values(implode(',', [(int) $id, (int) $group]));
}
// execute the update/change
try
{
// delete link to groups
if ($this->deleteGroups($id))
{
// add the new groups
$db->setQuery($query)->execute();
}
}
catch (RuntimeException $e)
{
throw new RuntimeException($e->getMessage(), 404);
}
return true;
} }
/** /**
@ -127,10 +188,10 @@ class UserModel implements DatabaseModelInterface
* *
* @param int|null $id * @param int|null $id
* *
* @return \stdClass * @return stdClass
* @throws \Exception * @throws Exception
*/ */
public function getItem(?int $id): \stdClass public function getItem(?int $id): stdClass
{ {
$db = $this->getDb(); $db = $this->getDb();
// default object (use posted values if set) // default object (use posted values if set)
@ -140,7 +201,7 @@ class UserModel implements DatabaseModelInterface
} }
else else
{ {
$default = new \stdClass(); $default = new stdClass();
} }
// to be sure ;) // to be sure ;)
$default->today_date = (new Date())->toSql(); $default->today_date = (new Date())->toSql();
@ -169,12 +230,12 @@ class UserModel implements DatabaseModelInterface
{ {
$result = $db->setQuery($query)->loadObject(); $result = $db->setQuery($query)->loadObject();
} }
catch (\RuntimeException $e) catch (RuntimeException $e)
{ {
// we ignore this and just return an empty object // we ignore this and just return an empty object
} }
if (isset($result) && $result instanceof \stdClass) if (isset($result) && $result instanceof stdClass && isset($result->id))
{ {
$result->post_key = "?id=$id&task=edit"; $result->post_key = "?id=$id&task=edit";
$result->today_date = $default->today_date; $result->today_date = $default->today_date;
@ -182,6 +243,23 @@ class UserModel implements DatabaseModelInterface
$result->password = $default->password; $result->password = $default->password;
$result->password2 = $default->password2; $result->password2 = $default->password2;
// Initialise some variables
$query = $db->getQuery(true)
->select('m.group_id')
->from($db->quoteName('#__user_usergroup_map', 'm'))
->where($db->quoteName('m.user_id') . ' = :user_id')
->bind(':user_id', $result->id, ParameterType::INTEGER);
try
{
// we just load the ID's
$result->groups = $db->setQuery($query)->loadColumn();
}
catch (RuntimeException $e)
{
// we ignore this and just return result
}
return $result; return $result;
} }
@ -202,23 +280,56 @@ class UserModel implements DatabaseModelInterface
* @param int $id * @param int $id
* *
* @return bool * @return bool
* @throws Exception
*/ */
public function delete(int $id): bool public function delete(int $id): bool
{ {
$db = $this->getDb(); $db = $this->getDb();
// Purge the session // Delete the user from the database
$query = $db->getQuery(true) $query = $db->getQuery(true)
->delete($db->quoteName('#__users')) ->delete($db->quoteName('#__users'))
->where($db->quoteName('id') . ' = :id') ->where($db->quoteName('id') . ' = :id')
->bind(':id', $id, ParameterType::INTEGER); ->bind(':id', $id, ParameterType::INTEGER);
try try
{
// delete link to groups
if ($this->deleteGroups($id))
{
// delete user
$db->setQuery($query)->execute();
}
}
catch (RuntimeException $e)
{
throw new RuntimeException($e->getMessage(), 404);
}
return true;
}
/**
* delete all groups form this user
*
* @param int $id
*
* @return bool
* @throws Exception
*/
private function deleteGroups(int $id): bool
{
$db = $this->getDb();
// Delete the user from the database
$query = $db->getQuery(true)
->delete($db->quoteName('#__user_usergroup_map'))
->where($db->quoteName('user_id') . ' = :user_id')
->bind(':user_id', $id, ParameterType::INTEGER);
try
{ {
$db->setQuery($query)->execute(); $db->setQuery($query)->execute();
} }
catch (\RuntimeException $e) catch (RuntimeException $e)
{ {
// delete failed throw new RuntimeException($e->getMessage(), 404);
return false;
} }
return true; return true;

View File

@ -0,0 +1,239 @@
<?php
/**
* @package Octoleo CMS
*
* @created 21th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/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\Model\Util\GetUsergroupsInterface;
use Octoleo\CMS\Model\Util\GetUsergroupsTrait;
/**
* Model class
*/
class UsergroupModel implements DatabaseModelInterface, GetUsergroupsInterface
{
use DatabaseModelTrait, GetUsergroupsTrait;
/**
* @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 array $params
*
* @return int
*/
public function setItem(
int $id,
string $title,
array $params): int
{
$db = $this->getDb();
if (count($params) > 0)
{
$params = json_encode($params);
}
else
{
$params = '';
}
$data = [
'title' => (string) $title,
'params' => (string) $params
];
// if we have ID update
if ($id > 0)
{
$data['id'] = (int) $id;
// change to object
$data = (object) $data;
try
{
$db->updateObject('#__usergroups', $data, 'id');
}
catch (\RuntimeException $exception)
{
throw new \RuntimeException($exception->getMessage(), 404);
}
return $id;
}
else
{
// change to object
$data = (object) $data;
try
{
$db->insertObject('#__usergroups', $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();
$default->params = $this->getGroupDefaultsAccess();
}
// we return the default if id not correct
if (!is_numeric($id))
{
return $default;
}
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__usergroups'))
->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";
// make sure to set the params
$result->params = json_decode($result->params);
// We set an empty default
if (!is_array($result->params))
{
$result->params = $this->getGroupDefaultsAccess();
}
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('#__usergroups'))
->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
*
* @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('user_id'))
->from($db->quoteName('#__user_usergroup_map'))
->where($db->quoteName('group_id') . ' = :id')
->bind(':id', $id, ParameterType::INTEGER);
try
{
$users = $db->setQuery($query)->loadColumn();
}
catch (\RuntimeException $e)
{
// not linked... or something
return false;
}
if ($users)
{
return true;
}
return false;
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* @package Octoleo CMS
*
* @created 21th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/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\Model\DatabaseModelInterface;
use Joomla\Model\DatabaseModelTrait;
use Octoleo\CMS\Model\Util\GetUsergroupsInterface;
use Octoleo\CMS\Model\Util\GetUsergroupsTrait;
/**
* Model class
*/
class UsergroupsModel implements DatabaseModelInterface, GetUsergroupsInterface
{
use DatabaseModelTrait, GetUsergroupsTrait;
/**
* 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
{
return $this->getUsergroups();
}
public function setLayout(string $name): string
{
return $name . '.twig';
}
}

View File

@ -11,16 +11,17 @@
namespace Octoleo\CMS\Model; namespace Octoleo\CMS\Model;
use Joomla\Database\DatabaseDriver; use Joomla\Database\DatabaseDriver;
use Joomla\Database\ParameterType;
use Joomla\Model\DatabaseModelInterface; use Joomla\Model\DatabaseModelInterface;
use Joomla\Model\DatabaseModelTrait; use Joomla\Model\DatabaseModelTrait;
use Octoleo\CMS\Model\Util\GetUsergroupsInterface;
use Octoleo\CMS\Model\Util\GetUsergroupsTrait;
/** /**
* Model class for users * Model class
*/ */
class UsersModel implements DatabaseModelInterface class UsersModel implements DatabaseModelInterface, GetUsergroupsInterface
{ {
use DatabaseModelTrait; use DatabaseModelTrait, GetUsergroupsTrait;
/** /**
* Instantiate the model. * Instantiate the model.
@ -45,7 +46,18 @@ class UsersModel implements DatabaseModelInterface
->select('*') ->select('*')
->from($db->quoteName('#__users')); ->from($db->quoteName('#__users'));
return $db->setQuery($query)->loadObjectList('id'); $users = $db->setQuery($query)->loadObjectList('id');
// add groups
if ($users)
{
foreach ($users as $id => &$user)
{
$user->groups = $this->getUsergroups($id);
}
}
return $users;
} }
public function setLayout(string $name): string public function setLayout(string $name): string

View File

@ -0,0 +1,37 @@
<?php
/**
* @package Octoleo CMS
*
* @created 23th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Octoleo\CMS\Model\Util;
/**
* Class for all user groups
*
* @since 1.0.0
*/
interface GetUsergroupsInterface
{
/**
* Get all user groups
*
* @param int|null $id
*
* @return array
*/
public function getUsergroups(?int $id = null): array;
/**
* Get the group default full access values
*
* @param string $access
*
* @return array
*/
public function getGroupDefaultsAccess(string $access = 'CRUD'): array;
}

View File

@ -0,0 +1,103 @@
<?php
/**
* @package Octoleo CMS
*
* @created 23th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Octoleo\CMS\Model\Util;
use Joomla\Database\ParameterType;
use Octoleo\CMS\Utilities\StringHelper;
use RuntimeException;
use stdClass;
/**
* Class for all user groups
*
* @since 1.0.0
* @method getDb()
*/
trait GetUsergroupsTrait
{
/**
* Get all user groups
*
* @param int|null $id user ID
*
* @return array
*/
public function getUsergroups(?int $id = null): array
{
$db = $this->getDb();
$query = $db->getQuery(true)
->select('g.*')
->from($db->quoteName('#__usergroups', 'g'));
if ($id > 0)
{
$query
->join('INNER', $db->quoteName('#__user_usergroup_map', 'm'), 'g.id = m.group_id')
->where($db->quoteName('m.user_id') . ' = :user_id')
->bind(':user_id', $id, ParameterType::INTEGER);
}
try
{
$groups = $db->setQuery($query)->loadObjectList('id');
}
catch (RuntimeException $e)
{
throw new RuntimeException($e->getMessage(), 404);
}
if (is_array($groups) && count($groups) > 0)
{
foreach ($groups as $n => &$group)
{
$group->params = json_decode($group->params);
// We set an empty default
if (!is_array($group->params))
{
$group->params = $this->getGroupDefaultsAccess();
}
}
return $groups;
}
return [];
}
/**
* Get the group default full access values
*
* @param string $access
*
* @return array
*/
public function getGroupDefaultsAccess(string $access = ''): array
{
return [
(object) [
'area' => 'user',
'access' => $access
],
(object) [
'area' => 'usergroup',
'access' => $access
],
(object) [
'area' => 'menu',
'access' => $access
],
(object) [
'area' => 'item',
'access' => $access
],
];
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @package Octoleo CMS
*
* @created 21th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Octoleo\CMS\Model\Util;
/**
* Class for getting the home page
*
* @since 1.0.0
*/
interface HomeMenuInterface
{
/**
* @return \stdClass
*/
public function getHomePage(): \stdClass;
}

View File

@ -2,37 +2,21 @@
/** /**
* @package Octoleo CMS * @package Octoleo CMS
* *
* @created 9th April 2022 * @created 21th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn> * @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45> * @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45>
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\Model; namespace Octoleo\CMS\Model\Util;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\ParameterType;
use Joomla\Model\DatabaseModelInterface;
use Joomla\Model\DatabaseModelTrait;
/** /**
* Model class for pages * Trait for getting home menu
* source: https://github.com/joomla/framework.joomla.org/blob/master/src/Model/PackageModel.php *
* @since 1.0.0
*/ */
class HomepageModel implements DatabaseModelInterface, MenuInterface, PageInterface trait HomeMenuTrait
{ {
use DatabaseModelTrait, SiteMenuTrait, SitePageTrait;
/**
* Instantiate the model.
*
* @param DatabaseDriver $db The database adapter.
*/
public function __construct(DatabaseDriver $db)
{
$this->setDb($db);
}
/** /**
* @return \stdClass * @return \stdClass
*/ */

View File

@ -8,7 +8,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\Model; namespace Octoleo\CMS\Model\Util;
/** /**
* Class for getting menu items * Class for getting menu items
@ -20,9 +20,9 @@ interface MenuInterface
/** /**
* Get all menu items * Get all menu items
* *
* @param string|null $active * @param int $active
* *
* @return array * @return array
*/ */
public function getMenus(string $active = null): array; public function getMenus(int $active = 0): array;
} }

View File

@ -8,7 +8,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\Model; namespace Octoleo\CMS\Model\Util;
/** /**
* Class for getting page data * Class for getting page data

View File

@ -0,0 +1,54 @@
<?php
/**
* @package Octoleo CMS
*
* @created 21th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Octoleo\CMS\Model\Util;
use Joomla\Database\ParameterType;
/**
* Trait for getting menu items
*
* @since 1.0.0
*/
trait SelectMenuTrait
{
/**
* Get all menu items
*
* @param int $active
*
* @return array
*/
public function getMenus(int $active = 0): array
{
$db = $this->getDb();
if (empty($active) && !empty($this->id))
{
$active = $this->id;
}
$query = $db->getQuery(true)
->select($db->quoteName(array('id', 'title')))
->from($db->quoteName('#__menu'))
->where('published = 1')
->where('home = 0');
// we need to remove the active menu
if ($active > 0)
{
$query
->where($db->quoteName('id') . ' != :id')
->bind(':id', $active, ParameterType::INTEGER);
}
return $db->setQuery($query)->loadObjectList('id');
}
}

View File

@ -8,7 +8,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\Model; namespace Octoleo\CMS\Model\Util;
/** /**
* Trait for getting menu items * Trait for getting menu items
@ -20,18 +20,17 @@ trait SiteMenuTrait
/** /**
* Get all menu items that are root and published and not home page * Get all menu items that are root and published and not home page
* *
* @param string|null $active * @param int $active
* *
* @return array * @return array
*/ */
public function getMenus($active = null): array public function getMenus(int $active = 0): array
{ {
$db = $this->getDb(); $db = $this->getDb();
$query = $db->getQuery(true) $query = $db->getQuery(true)
->select('a.*') ->select('a.*')
->from($db->quoteName('#__menu', 'a')) ->from($db->quoteName('#__menu', 'a'))
->where($db->quoteName('a.parent_id') . ' = 0')
->where($db->quoteName('a.published') . ' = 1') ->where($db->quoteName('a.published') . ' = 1')
->where($db->quoteName('a.home') . ' = 0'); ->where($db->quoteName('a.home') . ' = 0');
@ -51,9 +50,10 @@ trait SiteMenuTrait
{ {
$row = []; $row = [];
// set the details // set the details
$row['id'] = $menu->id;
$row['title'] = $menu->title; $row['title'] = $menu->title;
$row['path'] = $menu->path; $row['path'] = $menu->path;
$row['root'] = true; $row['parent'] = $menu->parent_id;
// set position // set position
$params = (isset($menu->params) && strpos($menu->params, 'position') !== false) ? json_decode($menu->params) : null; $params = (isset($menu->params) && strpos($menu->params, 'position') !== false) ? json_decode($menu->params) : null;
// default is center // default is center

View File

@ -8,7 +8,7 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\Model; namespace Octoleo\CMS\Model\Util;
use Joomla\Database\ParameterType; use Joomla\Database\ParameterType;
@ -33,10 +33,13 @@ trait SitePageTrait
$db = $this->getDb(); $db = $this->getDb();
$query = $db->getQuery(true) $query = $db->getQuery(true)
->select('t.*') ->select('i.*')
->from($db->quoteName('#__menu', 'a')) ->select($db->quoteName(array('m.id'), array('menu_id')))
->join('INNER', $db->quoteName('#__item', 't'), 'a.item_id = t.id') ->from($db->quoteName('#__menu', 'm'))
->where($db->quoteName('path') . ' = :path') ->join('INNER', $db->quoteName('#__item', 'i'), 'm.item_id = i.id')
->where($db->quoteName('i.state') . ' >= 1')
->where($db->quoteName('m.published') . ' = 1')
->where($db->quoteName('m.path') . ' = :path')
->bind(':path', $path) ->bind(':path', $path)
->setLimit(1); ->setLimit(1);
@ -71,9 +74,13 @@ trait SitePageTrait
$db = $this->getDb(); $db = $this->getDb();
$query = $db->getQuery(true) $query = $db->getQuery(true)
->select('a.*') ->select('i.*')
->from($db->quoteName('#__item', 'a')) ->select($db->quoteName(array('m.id'), array('menu_id')))
->where($db->quoteName('id') . ' = :id') ->from($db->quoteName('#__item', 'i'))
->join('INNER', $db->quoteName('#__menu', 'm'), 'i.id = m.item_id')
->where($db->quoteName('m.published') . ' = 1')
->where($db->quoteName('i.state') . ' >= 1')
->where($db->quoteName('i.id') . ' = :id')
->bind(':id', $item, ParameterType::INTEGER) ->bind(':id', $item, ParameterType::INTEGER)
->setLimit(1); ->setLimit(1);

View File

@ -0,0 +1,44 @@
<?php
/**
* @package Octoleo CMS
*
* @created 21th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Octoleo\CMS\Model\Util;
/**
* Class for getting unique string
*
* @since 1.0.0
*/
interface UniqueInterface
{
/**
* Get a unique string
*
* @param int $id
* @param string $value
* @param int $parent
* @param string $key
* @param string $spacer
*
* @return string
*/
public function unique(int $id, string $value, int $parent = -1, string $key = 'alias', string $spacer = '-'): string;
/**
* Check if an any key exist with same parent
*
* @param int $id
* @param string $value
* @param string $key
* @param int $parent
*
* @return bool
*/
public function exist(int $id, string $value, string $key = 'alias', int $parent = -1): bool;
}

View File

@ -0,0 +1,103 @@
<?php
/**
* @package Octoleo CMS
*
* @created 21th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Octoleo\CMS\Model\Util;
use Joomla\Database\ParameterType;
/**
* Trait for getting unique string
*
* @since 1.0.0
*/
trait UniqueMenuAliasTrait
{
/**
* Get a unique string
*
* @param int $id
* @param string $value
* @param int $parent
* @param string $key
* @param string $spacer
*
* @return string
*/
public function unique(int $id, string $value, int $parent = -1, string $key = 'alias', string $spacer = '-'): string
{
// start building the value
$value = str_replace($spacer, ' ', $value);
$value = preg_replace('/\s+/', $spacer, strtolower(preg_replace("/[^A-Za-z0-9\- ]/", '', $value)));
// set a counter
$counter = 2;
// set original tracker
$original = $value;
// check if we found any with the same alias
while ($this->exist($id, $value, $key, $parent))
{
$value = $original . '-' . $counter;
$counter++;
}
// return the unique value (on this parent layer)
return $value;
}
/**
* Check if an any key exist with same parent
*
* @param int $id
* @param string $value
* @param string $key
* @param int $parent
*
* @return bool
*/
public function exist(int $id, string $value, string $key = 'alias', int $parent = -1): bool
{
$db = $this->getDb();
$query = $db->getQuery(true)
->select('id')
->from($db->quoteName('#__menu'))
->where($db->quoteName($key) . " = :$key")
->bind(":$key", $value)
->setLimit(1);
// only add the id item exist
if ($parent >= 0)
{
$query
->where($db->quoteName('parent_id') . ' = :parent_id')
->bind(':parent_id', $parent, ParameterType::INTEGER);
}
// only add the id item exist
if ($id > 0)
{
$query
->where($db->quoteName('id') . ' != :id')
->bind(':id', $id, ParameterType::INTEGER);
}
try
{
$result = $db->setQuery($query)->loadResult();
}
catch (\RuntimeException $e)
{
// we ignore this and just return an empty object
}
if (isset($result) && $result > 0)
{
return true;
}
return false;
}
}

View File

@ -46,6 +46,8 @@ class FrameworkExtension extends AbstractExtension
new TwigFunction('route', [FrameworkTwigRuntime::class, 'getRouteUri']), new TwigFunction('route', [FrameworkTwigRuntime::class, 'getRouteUri']),
new TwigFunction('sri', [FrameworkTwigRuntime::class, 'getSriAttributes'], ['is_safe' => ['html']]), new TwigFunction('sri', [FrameworkTwigRuntime::class, 'getSriAttributes'], ['is_safe' => ['html']]),
new TwigFunction('message_queue', [FrameworkTwigRuntime::class, 'getMessageQueue']), new TwigFunction('message_queue', [FrameworkTwigRuntime::class, 'getMessageQueue']),
new TwigFunction('user_array', [FrameworkTwigRuntime::class, 'getUserArray']),
new TwigFunction('user', [FrameworkTwigRuntime::class, 'getUser']),
new TwigFunction('token', [FrameworkTwigRuntime::class, 'getToken']), new TwigFunction('token', [FrameworkTwigRuntime::class, 'getToken']),
new TwigFunction('shorten_string', [FrameworkTwigRuntime::class, 'shortenString']), new TwigFunction('shorten_string', [FrameworkTwigRuntime::class, 'shortenString']),
]; ];

View File

@ -11,6 +11,9 @@ namespace Octoleo\CMS\Renderer;
use Joomla\Application\AbstractApplication; use Joomla\Application\AbstractApplication;
use Joomla\Preload\PreloadManager; use Joomla\Preload\PreloadManager;
use Joomla\Session\SessionInterface; use Joomla\Session\SessionInterface;
use Octoleo\CMS\Factory;
use Octoleo\CMS\User\User;
use Octoleo\CMS\User\UserFactoryInterface;
/** /**
* Twig runtime class * Twig runtime class
@ -47,10 +50,15 @@ class FrameworkTwigRuntime
private $sriManifestPath; private $sriManifestPath;
/** /**
* @var SessionInterface * @var SessionInterface|null
*/ */
private $session; private $session;
/**
* @var User|null
*/
private $user;
/** /**
* Constructor * Constructor
* *
@ -59,12 +67,16 @@ class FrameworkTwigRuntime
* @param string $sriManifestPath The path to the SRI manifest data * @param string $sriManifestPath The path to the SRI manifest data
* @param SessionInterface|null $session The session object * @param SessionInterface|null $session The session object
*/ */
public function __construct(AbstractApplication $app, PreloadManager $preloadManager, string $sriManifestPath, $session = null) public function __construct(
AbstractApplication $app,
PreloadManager $preloadManager,
string $sriManifestPath,
SessionInterface $session = null)
{ {
$this->session = $session;
$this->app = $app; $this->app = $app;
$this->preloadManager = $preloadManager; $this->preloadManager = $preloadManager;
$this->sriManifestPath = $sriManifestPath; $this->sriManifestPath = $sriManifestPath;
$this->session = $session;
} }
/** /**
@ -149,6 +161,41 @@ class FrameworkTwigRuntime
return $string; return $string;
} }
/**
* Get current user as array
*
* @return array
*/
public function getUserArray(): array
{
if (!$this->user instanceof User)
{
/** @var \Octoleo\CMS\User\User $user */
$this->user = Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
}
// check again
if ($this->user instanceof User && method_exists($this->user, 'toArray'))
{
return $this->user->toArray();
}
return [];
}
public function getUser(string $key = 'name', $default = '')
{
if (!$this->user instanceof User)
{
/** @var \Octoleo\CMS\User\User $user */
$this->user = Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
}
// check again
if ($this->user instanceof User)
{
return $this->user->get($key, $default);
}
return '';
}
/** /**
* Get any messages in the queue * Get any messages in the queue
* *

View File

@ -26,7 +26,7 @@ use Joomla\Router\RouterInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
* Application service provider * Admin Application service provider
* source: https://github.com/joomla/framework.joomla.org/blob/master/src/Service/ApplicationProvider.php * source: https://github.com/joomla/framework.joomla.org/blob/master/src/Service/ApplicationProvider.php
*/ */
class AdminApplicationProvider implements ServiceProviderInterface class AdminApplicationProvider implements ServiceProviderInterface

View File

@ -24,6 +24,8 @@ use Octoleo\CMS\Controller\MenuController;
use Octoleo\CMS\Controller\MenusController; use Octoleo\CMS\Controller\MenusController;
use Octoleo\CMS\Controller\UserController; use Octoleo\CMS\Controller\UserController;
use Octoleo\CMS\Controller\UsersController; use Octoleo\CMS\Controller\UsersController;
use Octoleo\CMS\Controller\UserGroupController;
use Octoleo\CMS\Controller\UsergroupsController;
use Octoleo\CMS\Controller\WrongCmsController; use Octoleo\CMS\Controller\WrongCmsController;
use Octoleo\CMS\Model\DashboardModel; use Octoleo\CMS\Model\DashboardModel;
use Octoleo\CMS\Model\ItemsModel; use Octoleo\CMS\Model\ItemsModel;
@ -32,6 +34,9 @@ use Octoleo\CMS\Model\MenusModel;
use Octoleo\CMS\Model\MenuModel; use Octoleo\CMS\Model\MenuModel;
use Octoleo\CMS\Model\UserModel; use Octoleo\CMS\Model\UserModel;
use Octoleo\CMS\Model\UsersModel; use Octoleo\CMS\Model\UsersModel;
use Octoleo\CMS\Model\UsergroupModel;
use Octoleo\CMS\Model\UsergroupsModel;
use Octoleo\CMS\User\UserFactoryInterface;
use Octoleo\CMS\View\Admin\DashboardHtmlView; use Octoleo\CMS\View\Admin\DashboardHtmlView;
use Octoleo\CMS\View\Admin\ItemsHtmlView; use Octoleo\CMS\View\Admin\ItemsHtmlView;
use Octoleo\CMS\View\Admin\ItemHtmlView; use Octoleo\CMS\View\Admin\ItemHtmlView;
@ -39,6 +44,8 @@ use Octoleo\CMS\View\Admin\MenuHtmlView;
use Octoleo\CMS\View\Admin\MenusHtmlView; use Octoleo\CMS\View\Admin\MenusHtmlView;
use Octoleo\CMS\View\Admin\UserHtmlView; use Octoleo\CMS\View\Admin\UserHtmlView;
use Octoleo\CMS\View\Admin\UsersHtmlView; use Octoleo\CMS\View\Admin\UsersHtmlView;
use Octoleo\CMS\View\Admin\UsergroupHtmlView;
use Octoleo\CMS\View\Admin\UsergroupsHtmlView;
use Octoleo\CMS\Application\AdminApplication; use Octoleo\CMS\Application\AdminApplication;
use Joomla\Input\Input; use Joomla\Input\Input;
@ -72,6 +79,12 @@ class AdminMVCProvider implements ServiceProviderInterface
$container->alias(UserController::class, 'controller.user') $container->alias(UserController::class, 'controller.user')
->share('controller.user', [$this, 'getControllerUserService'], true); ->share('controller.user', [$this, 'getControllerUserService'], true);
$container->alias(UsergroupsController::class, 'controller.usergroups')
->share('controller.usergroups', [$this, 'getControllerUsergroupsService'], true);
$container->alias(UsergroupController::class, 'controller.usergroup')
->share('controller.usergroup', [$this, 'getControllerUsergroupService'], true);
$container->alias(MenusController::class, 'controller.menus') $container->alias(MenusController::class, 'controller.menus')
->share('controller.menus', [$this, 'getControllerMenusService'], true); ->share('controller.menus', [$this, 'getControllerMenusService'], true);
@ -100,6 +113,12 @@ class AdminMVCProvider implements ServiceProviderInterface
$container->alias(UserModel::class, 'model.user') $container->alias(UserModel::class, 'model.user')
->share('model.user', [$this, 'getModelUserService'], true); ->share('model.user', [$this, 'getModelUserService'], true);
$container->alias(UsergroupsModel::class, 'model.usergroups')
->share('model.usergroups', [$this, 'getModelUsergroupsService'], true);
$container->alias(UsergroupModel::class, 'model.usergroup')
->share('model.usergroup', [$this, 'getModelUsergroupService'], true);
$container->alias(MenusModel::class, 'model.menus') $container->alias(MenusModel::class, 'model.menus')
->share('model.menus', [$this, 'getModelMenusService'], true); ->share('model.menus', [$this, 'getModelMenusService'], true);
@ -122,6 +141,12 @@ class AdminMVCProvider implements ServiceProviderInterface
$container->alias(UserHtmlView::class, 'view.user.html') $container->alias(UserHtmlView::class, 'view.user.html')
->share('view.user.html', [$this, 'getViewUserHtmlService'], true); ->share('view.user.html', [$this, 'getViewUserHtmlService'], true);
$container->alias(UsergroupsHtmlView::class, 'view.usergroups.html')
->share('view.usergroups.html', [$this, 'getViewUsergroupsHtmlService'], true);
$container->alias(UsergroupHtmlView::class, 'view.usergroup.html')
->share('view.usergroup.html', [$this, 'getViewUsergroupHtmlService'], true);
$container->alias(MenusHtmlView::class, 'view.menus.html') $container->alias(MenusHtmlView::class, 'view.menus.html')
->share('view.menus.html', [$this, 'getViewMenusHtmlService'], true); ->share('view.menus.html', [$this, 'getViewMenusHtmlService'], true);
@ -234,7 +259,8 @@ class AdminMVCProvider implements ServiceProviderInterface
return new UsersController( return new UsersController(
$container->get(UsersHtmlView::class), $container->get(UsersHtmlView::class),
$container->get(Input::class), $container->get(Input::class),
$container->get(AdminApplication::class) $container->get(AdminApplication::class),
$container->get(UserFactoryInterface::class)->getUser()
); );
} }
@ -278,7 +304,8 @@ class AdminMVCProvider implements ServiceProviderInterface
$container->get(UserModel::class), $container->get(UserModel::class),
$container->get(UserHtmlView::class), $container->get(UserHtmlView::class),
$container->get(Input::class), $container->get(Input::class),
$container->get(AdminApplication::class) $container->get(AdminApplication::class),
$container->get(UserFactoryInterface::class)->getUser()
); );
} }
@ -309,6 +336,95 @@ class AdminMVCProvider implements ServiceProviderInterface
); );
} }
/**
* Get the `controller.usergroups` service
*
* @param Container $container The DI container.
*
* @return UsergroupsController
*/
public function getControllerUsergroupsService(Container $container): UsergroupsController
{
return new UsergroupsController(
$container->get(UsergroupsHtmlView::class),
$container->get(Input::class),
$container->get(AdminApplication::class),
$container->get(UserFactoryInterface::class)->getUser()
);
}
/**
* Get the `model.usergroups` service
*
* @param Container $container The DI container.
*
* @return UsergroupsModel
*/
public function getModelUsergroupsService(Container $container): UsergroupsModel
{
return new UsergroupsModel($container->get(DatabaseInterface::class));
}
/**
* Get the `view.usergroups.html` service
*
* @param Container $container The DI container.
*
* @return UsergroupsHtmlView
*/
public function getViewUsergroupsHtmlService(Container $container): UsergroupsHtmlView
{
return new UsergroupsHtmlView(
$container->get('model.usergroups'),
$container->get('renderer')
);
}
/**
* Get the `controller.usergroup` service
*
* @param Container $container The DI container.
*
* @return UsergroupController
*/
public function getControllerUsergroupService(Container $container): UsergroupController
{
return new UsergroupController(
$container->get(UsergroupModel::class),
$container->get(UsergroupHtmlView::class),
$container->get(Input::class),
$container->get(AdminApplication::class),
$container->get(UserFactoryInterface::class)->getUser()
);
}
/**
* Get the `model.usergroup` service
*
* @param Container $container The DI container.
*
* @return UsergroupModel
*/
public function getModelUsergroupService(Container $container): UsergroupModel
{
return new UsergroupModel($container->get(DatabaseInterface::class));
}
/**
* Get the `view.usergroup.html` service
*
* @param Container $container The DI container.
*
* @return UsergroupHtmlView
*/
public function getViewUsergroupHtmlService(Container $container): UsergroupHtmlView
{
return new UsergroupHtmlView(
$container->get('model.usergroup'),
$container->get('renderer')
);
}
/** /**
* Get the `controller.menus` service * Get the `controller.menus` service
* *
@ -321,7 +437,8 @@ class AdminMVCProvider implements ServiceProviderInterface
return new MenusController( return new MenusController(
$container->get(MenusHtmlView::class), $container->get(MenusHtmlView::class),
$container->get(Input::class), $container->get(Input::class),
$container->get(AdminApplication::class) $container->get(AdminApplication::class),
$container->get(UserFactoryInterface::class)->getUser()
); );
} }
@ -365,7 +482,8 @@ class AdminMVCProvider implements ServiceProviderInterface
$container->get(MenuModel::class), $container->get(MenuModel::class),
$container->get(MenuHtmlView::class), $container->get(MenuHtmlView::class),
$container->get(Input::class), $container->get(Input::class),
$container->get(AdminApplication::class) $container->get(AdminApplication::class),
$container->get(UserFactoryInterface::class)->getUser()
); );
} }
@ -408,7 +526,8 @@ class AdminMVCProvider implements ServiceProviderInterface
return new ItemsController( return new ItemsController(
$container->get(ItemsHtmlView::class), $container->get(ItemsHtmlView::class),
$container->get(Input::class), $container->get(Input::class),
$container->get(AdminApplication::class) $container->get(AdminApplication::class),
$container->get(UserFactoryInterface::class)->getUser()
); );
} }
@ -452,7 +571,8 @@ class AdminMVCProvider implements ServiceProviderInterface
$container->get(ItemModel::class), $container->get(ItemModel::class),
$container->get(ItemHtmlView::class), $container->get(ItemHtmlView::class),
$container->get(Input::class), $container->get(Input::class),
$container->get(AdminApplication::class) $container->get(AdminApplication::class),
$container->get(UserFactoryInterface::class)->getUser()
); );
} }

View File

@ -21,6 +21,8 @@ use Octoleo\CMS\Controller\MenuController;
use Octoleo\CMS\Controller\MenusController; use Octoleo\CMS\Controller\MenusController;
use Octoleo\CMS\Controller\UserController; use Octoleo\CMS\Controller\UserController;
use Octoleo\CMS\Controller\UsersController; use Octoleo\CMS\Controller\UsersController;
use Octoleo\CMS\Controller\UserGroupController;
use Octoleo\CMS\Controller\UsergroupsController;
use Joomla\Router\Router; use Joomla\Router\Router;
use Joomla\Router\RouterInterface; use Joomla\Router\RouterInterface;
@ -72,6 +74,14 @@ class AdminRouterProvider implements ServiceProviderInterface
'/index.php/user', '/index.php/user',
UserController::class UserController::class
); );
$router->get(
'/index.php/usergroups',
UsergroupsController::class
);
$router->all(
'/index.php/usergroup',
UsergroupController::class
);
$router->get( $router->get(
'/index.php/menus', '/index.php/menus',
MenusController::class MenusController::class

View File

@ -14,6 +14,9 @@ use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface; use Joomla\DI\ServiceProviderInterface;
use Joomla\Registry\Registry; use Joomla\Registry\Registry;
/**
* Configuration service provider
*/
class ConfigurationProvider implements ServiceProviderInterface class ConfigurationProvider implements ServiceProviderInterface
{ {
/** /**

View File

@ -16,8 +16,7 @@ use Joomla\DI\ServiceProviderInterface;
use Joomla\Input\Input; use Joomla\Input\Input;
/** /**
* Application service provider * Input service provider
* source: https://github.com/joomla/framework.joomla.org/blob/master/src/Service/ApplicationProvider.php
*/ */
class InputProvider implements ServiceProviderInterface class InputProvider implements ServiceProviderInterface
{ {

View File

@ -36,7 +36,6 @@ class SessionProvider implements ServiceProviderInterface
*/ */
public function register(Container $container): void public function register(Container $container): void
{ {
$container->alias(SessionDatabaseHandler::class, HandlerInterface::class) $container->alias(SessionDatabaseHandler::class, HandlerInterface::class)
->share(HandlerInterface::class, [$this, 'getSessionDatabaseHandlerClassService'], true); ->share(HandlerInterface::class, [$this, 'getSessionDatabaseHandlerClassService'], true);

View File

@ -19,24 +19,21 @@ use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface; use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface; use Joomla\Event\DispatcherInterface;
use Octoleo\CMS\Controller\HomepageController;
use Octoleo\CMS\Controller\WrongCmsController; use Octoleo\CMS\Controller\WrongCmsController;
use Octoleo\CMS\Controller\PageController; use Octoleo\CMS\Controller\PageController;
use Octoleo\CMS\Model\HomepageModel;
use Octoleo\CMS\Model\PageModel; use Octoleo\CMS\Model\PageModel;
use Octoleo\CMS\View\Page\HomepageHtmlView; use Octoleo\CMS\Utilities\StringHelper;
use Octoleo\CMS\View\Page\PageHtmlView; use Octoleo\CMS\View\Site\PageHtmlView;
use Octoleo\CMS\Application\SiteApplication; use Octoleo\CMS\Application\SiteApplication;
use Joomla\Input\Input; use Joomla\Input\Input;
use Joomla\Renderer\RendererInterface;
use Joomla\Router\Route; use Joomla\Router\Route;
use Joomla\Router\Router; use Joomla\Router\Router;
use Joomla\Router\RouterInterface; use Joomla\Router\RouterInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
* Application service provider * Site Application service provider
* source: https://github.com/joomla/framework.joomla.org/blob/master/src/Service/ApplicationProvider.php * source: https://github.com/joomla/framework.joomla.org/blob/master/src/Service/ApplicationProvider.php
*/ */
class SiteApplicationProvider implements ServiceProviderInterface class SiteApplicationProvider implements ServiceProviderInterface
@ -78,9 +75,6 @@ class SiteApplicationProvider implements ServiceProviderInterface
*/ */
// Controllers // Controllers
$container->alias(HomepageController::class, 'controller.homepage')
->share('controller.homepage', [$this, 'getControllerHomepageService'], true);
$container->alias(PageController::class, 'controller.page') $container->alias(PageController::class, 'controller.page')
->share('controller.page', [$this, 'getControllerPageService'], true); ->share('controller.page', [$this, 'getControllerPageService'], true);
@ -88,16 +82,10 @@ class SiteApplicationProvider implements ServiceProviderInterface
->share('controller.wrong.cms', [$this, 'getControllerWrongCmsService'], true); ->share('controller.wrong.cms', [$this, 'getControllerWrongCmsService'], true);
// Models // Models
$container->alias(HomepageModel::class, 'model.homepage')
->share('model.homepage', [$this, 'getModelHomepageService'], true);
$container->alias(PageModel::class, 'model.page') $container->alias(PageModel::class, 'model.page')
->share('model.page', [$this, 'getModelPageService'], true); ->share('model.page', [$this, 'getModelPageService'], true);
// Views // Views
$container->alias(HomepageHtmlView::class, 'view.homepage.html')
->share('view.homepage.html', [$this, 'getViewHomepageHtmlService'], true);
$container->alias(PageHtmlView::class, 'view.page.html') $container->alias(PageHtmlView::class, 'view.page.html')
->share('view.page.html', [$this, 'getViewPageHtmlService'], true); ->share('view.page.html', [$this, 'getViewPageHtmlService'], true);
} }
@ -134,32 +122,29 @@ class SiteApplicationProvider implements ServiceProviderInterface
/* /*
* Web routes * Web routes
*/ */
$router->addRoute(new Route(['GET', 'HEAD'], '/', HomepageController::class)); $router->addRoute(new Route(['GET', 'HEAD'], '/', PageController::class));
// dynamic pages
$pages = '/:root';
$router->get( $router->get(
'/:view', $pages,
PageController::class PageController::class
); );
// set a mad depth TODO: we should limit the menu depth to 6 or something
$depth = range(1,20);
foreach ($depth as $page)
{
$page = StringHelper::numbers($page);
$pages .= "/:$page";
$router->get(
$pages,
PageController::class
);
}
return $router; return $router;
} }
/**
* Get the `controller.homepage` service
*
* @param Container $container The DI container.
*
* @return HomepageController
*/
public function getControllerHomepageService(Container $container): HomepageController
{
return new HomepageController(
$container->get(HomepageHtmlView::class),
$container->get(Input::class),
$container->get(SiteApplication::class)
);
}
/** /**
* Get the `controller.page` service * Get the `controller.page` service
* *
@ -191,18 +176,6 @@ class SiteApplicationProvider implements ServiceProviderInterface
); );
} }
/**
* Get the `model.homepage` service
*
* @param Container $container The DI container.
*
* @return HomepageModel
*/
public function getModelHomepageService(Container $container): HomepageModel
{
return new HomepageModel($container->get(DatabaseInterface::class));
}
/** /**
* Get the `model.page` service * Get the `model.page` service
* *
@ -253,21 +226,6 @@ class SiteApplicationProvider implements ServiceProviderInterface
return new ContainerControllerResolver($container); 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 * Get the `view.page.html` service
* *

View File

@ -13,6 +13,7 @@ namespace Octoleo\CMS\Service;
use Joomla\Authentication\AuthenticationStrategyInterface; use Joomla\Authentication\AuthenticationStrategyInterface;
use Joomla\Authentication\Strategies\DatabaseStrategy; use Joomla\Authentication\Strategies\DatabaseStrategy;
use Joomla\Input\Input; use Joomla\Input\Input;
use Octoleo\CMS\Session\MetadataManager;
use Octoleo\CMS\User\UserFactory; use Octoleo\CMS\User\UserFactory;
use Octoleo\CMS\User\UserFactoryInterface; use Octoleo\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseInterface; use Joomla\Database\DatabaseInterface;
@ -58,7 +59,8 @@ class UserProvider implements ServiceProviderInterface
{ {
return new UserFactory( return new UserFactory(
$container->get(DatabaseInterface::class), $container->get(DatabaseInterface::class),
$container->get(AuthenticationStrategyInterface::class) $container->get(AuthenticationStrategyInterface::class),
$container->get(MetadataManager::class)
); );
} }

View File

@ -12,7 +12,11 @@ namespace Octoleo\CMS\User;
use Joomla\Registry\Registry; use Joomla\Registry\Registry;
use Joomla\Database\DatabaseInterface; use Joomla\Database\DatabaseInterface;
use Joomla\Database\ParameterType;
use Octoleo\CMS\Factory; use Octoleo\CMS\Factory;
use Octoleo\CMS\Utilities\StringHelper;
use stdClass;
use Exception;
/** /**
* User class. Handles all application interaction with a user * User class. Handles all application interaction with a user
@ -26,7 +30,7 @@ class User extends Registry
* *
* @param integer $identifier The primary key of the user to load (optional). * @param integer $identifier The primary key of the user to load (optional).
* *
* @throws \Exception * @throws Exception
* @since 1.1.0 * @since 1.1.0
*/ */
public function __construct($identifier = 0) public function __construct($identifier = 0)
@ -41,7 +45,7 @@ class User extends Registry
else else
{ {
// Initialise guest // Initialise guest
$data = (object) ['id' => 0, 'sendEmail' => 0, 'aid' => 0, 'guest' => 1]; $data = (object) ['id' => 0, 'sendEmail' => 0, 'block' => 1, 'aid' => 0, 'guest' => 1, 'groups' => []];
} }
// set the data // set the data
parent::__construct($data); parent::__construct($data);
@ -52,25 +56,124 @@ class User extends Registry
* *
* @param int $id The user id of the user to load * @param int $id The user id of the user to load
* *
* @return Object on success * @return stdClass on success
* *
* @throws \Exception * @throws Exception
* @since 1.0.0 * @since 1.0.0
*/ */
protected function load( int $id): object protected function load(int $id): stdClass
{ {
// Get the database // Get the database
$db = Factory::getContainer()->get(DatabaseInterface::class); $db = Factory::getContainer()->get(DatabaseInterface::class);
// Initialise some variables // Initialise some variables
$query = $db->getQuery(true) $query = $db->getQuery(true)
->select('*') ->select('u.*')
->from($db->quoteName('#__users')) ->from($db->quoteName('#__users', 'u'))
->where($db->quoteName('id') . ' = :id') ->where($db->quoteName('u.id') . ' = :id')
->bind(':id', $id) ->bind(':id', $id, ParameterType::INTEGER)
->setLimit(1); ->setLimit(1);
$db->setQuery($query); $db->setQuery($query);
return $db->loadObject(); $user = $db->loadObject();
if ($user instanceof stdClass && isset($user->id))
{
// start admin details
$user->is_admin = false;
$user->is_admin_groups = [];
// start access
$user->access = new stdClass();
// Initialise some variables
$query = $db->getQuery(true)
->select($db->quoteName(array('g.id', 'g.title', 'g.params')))
->from($db->quoteName('#__user_usergroup_map', 'm'))
->join('INNER', $db->quoteName('#__usergroups', 'g'), 'g.id = m.group_id')
->where($db->quoteName('m.user_id') . ' = :user_id')
->bind(':user_id', $user->id, ParameterType::INTEGER);
$db->setQuery($query);
$groups = $db->loadObjectList();
if (is_array($groups) && count($groups) > 0)
{
// group bucket of id's
$groups_ids = [];
foreach ($groups as $group)
{
// add group ID
$groups_ids[] = $group->id;
// convert params to object
$params = json_decode($group->params);
// set the access
if (is_array($params) && count($params) > 0)
{
$counter = 0;
$checker = 0;
foreach ($params as $param)
{
// prep the area string
$area = StringHelper::safe($param->area);
// only tart object if not already set
if(empty($user->access->{$area}))
{
// start object
$user->access->{$area} = new stdClass();
}
// make sure we have upper case
$param->access = strtoupper($param->access);
// full access to area
if ($param->access === 'CRUD')
{
$checker++;
// add the full permissions
$user->access->{$area}->create = true;
$user->access->{$area}->read = true;
$user->access->{$area}->update = true;
$user->access->{$area}->delete = true;
}
else
{
// this user has fewer permissions
// set them one at a time
if (strpos($param->access, 'C') !== false)
{
$user->access->{$area}->create = true;
}
if (strpos($param->access, 'R') !== false)
{
$user->access->{$area}->read = true;
}
if (strpos($param->access, 'U') !== false)
{
$user->access->{$area}->update = true;
}
if (strpos($param->access, 'D') !== false)
{
$user->access->{$area}->delete = true;
}
}
$counter++;
}
// if this group has full access
if ($counter == $checker)
{
// we need to know when this is an admin user
$user->is_admin = true;
// we load the ids to use in user update, so we can prevent
// admin users from removing themselves from the admin group
$user->is_admin_groups[] = $group->id;
}
}
unset($group->params);
}
// keep the group details
$user->groups = $groups;
$user->groups_ids = $groups_ids;
}
return $user;
}
return (object) ['id' => 0, 'sendEmail' => 0, 'block' => 1, 'aid' => 0, 'guest' => 1, 'groups' => []];
} }
} }

View File

@ -20,6 +20,8 @@ use Octoleo\CMS\Date\Date;
use Octoleo\CMS\Factory; use Octoleo\CMS\Factory;
use Octoleo\CMS\Filter\InputFilter; use Octoleo\CMS\Filter\InputFilter;
use Octoleo\CMS\Session\MetadataManager; use Octoleo\CMS\Session\MetadataManager;
use Exception;
use RuntimeException;
/** /**
* Default factory for creating User objects * Default factory for creating User objects
@ -41,6 +43,25 @@ class UserFactory implements UserFactoryInterface
*/ */
private $authentication; private $authentication;
/**
* @var MetadataManager
*/
private $manager;
/**
* The Admin Application
*
* @var AdminApplication
*/
private $app;
/**
* The user objects.
*
* @var User[]
*/
private $users = [];
/** /**
* @var InputFilter * @var InputFilter
*/ */
@ -56,6 +77,7 @@ class UserFactory implements UserFactoryInterface
'password' => 'RAW', 'password' => 'RAW',
'password2' => 'RAW' 'password2' => 'RAW'
]; ];
/** /**
* @var BCryptHandler * @var BCryptHandler
*/ */
@ -67,52 +89,37 @@ class UserFactory implements UserFactoryInterface
* @param DatabaseInterface|null $db The database * @param DatabaseInterface|null $db The database
* @param AuthenticationStrategyInterface|null $authentication * @param AuthenticationStrategyInterface|null $authentication
* *
* @throws \Exception * @throws Exception
*/ */
public function __construct( public function __construct(
DatabaseInterface $db = null, DatabaseInterface $db = null,
AuthenticationStrategyInterface $authentication = null, AuthenticationStrategyInterface $authentication = null,
MetadataManager $manager = null,
BCryptHandler $secure = null) BCryptHandler $secure = null)
{ {
$this->db = ($db) ?: Factory::getApplication()->get(DatabaseInterface::class); $this->db = ($db) ?: Factory::getApplication()->get(DatabaseInterface::class);
$this->authentication = ($authentication) ?: Factory::getApplication()->get(AuthenticationStrategyInterface::class); $this->authentication = ($authentication) ?: Factory::getApplication()->get(AuthenticationStrategyInterface::class);
$this->manager = ($manager) ?: Factory::getApplication()->get(MetadataManager::class);
$this->secure = ($secure) ?: new BCryptHandler(); $this->secure = ($secure) ?: new BCryptHandler();
} }
/** /**
* Method to get an instance of a user for the given id or session. * Method to get an instance of a user for the given id or user in session.
* *
* @param int|null $id The id * @param int|null $id The user id
* *
* @return User * @return User
* *
* @throws \Exception * @throws Exception
* @since 1.0.0 * @since 1.0.0
*/ */
public function getUser(?int $id = null): User public function getUser(?int $id = null): User
{ {
// load the user
if (empty($id)) if (empty($id))
{ {
/** @var \Octoleo\CMS\Application\AdminApplication $application */ return $this->loadUserBySession();
$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); return $this->loadUserById($id);
} }
@ -123,12 +130,49 @@ class UserFactory implements UserFactoryInterface
* *
* @return User * @return User
* *
* @throws \Exception * @throws Exception
* @since 1.0.0 * @since 1.0.0
*/ */
public function loadUserById(int $id): User public function loadUserById(int $id): User
{ {
return new User($id); // check if we already called for this user
if (isset($this->users[$id]))
{
return $this->users[$id];
}
$this->users[$id] = new User($id);
return $this->users[$id];
}
/**
* Method to get an instance of a user for the session.
*
* @return User
*
* @throws Exception
* @since 1.0.0
*/
public function loadUserBySession(): User
{
if (!$this->app instanceof AdminApplication)
{
$this->app = Factory::getApplication();
}
// Grab the current session ID
$sessionId = $this->app->getSession()->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);
return $this->loadUserById((int) $this->db->loadResult());
} }
/** /**
@ -138,7 +182,7 @@ class UserFactory implements UserFactoryInterface
* *
* @return User * @return User
* *
* @throws \Exception * @throws Exception
* @since 1.0.0 * @since 1.0.0
*/ */
public function loadUserByUsername(string $username): User public function loadUserByUsername(string $username): User
@ -158,47 +202,37 @@ class UserFactory implements UserFactoryInterface
/** /**
* Check if user is active * Check if user is active
* *
* @param bool $purge
*
* @return bool * @return bool
* @throws \Exception * @throws Exception
*/ */
public function active(?bool $purge = true): bool public function active(): bool
{ {
/** @var \Octoleo\CMS\Application\AdminApplication $application */ // get the user in the session
$application = Factory::getApplication(); $user = $this->loadUserBySession();
$session = $application->getSession(); // get the user ID
$user_id = $user->get('id', 0);
// Grab the current session ID // check if we have a user (and it's not blocked)
$sessionId = $session->getId(); if ($user_id > 0)
/** @var \Octoleo\CMS\Session\MetadataManager $manager */
$manager = Factory::getContainer()->get(MetadataManager::class);
$active = $manager->getSessionRecord($sessionId);
// if no active session is found...
if (!$active)
{ {
return false; // 1 == blocked
}
// if user above 0 the active
if ($active->guest == 0 && $active->userid > 0)
{
// get user
$user = $this->loadUserById($active->userid);
// check if user has access
$blocked = $user->get('block', 1); $blocked = $user->get('block', 1);
// 0 == not blocked
if ($blocked == 0) if ($blocked == 0)
{ {
return true; return true;
} }
} // check if we have the application
if (!$this->app instanceof AdminApplication)
{
$this->app = Factory::getApplication();
}
// Get the session
$session = $this->app->getSession();
// Grab the current session ID (to purge the session)
$sessionId = $session->getId();
if ($purge)
{
// Purge the session // Purge the session
$query = $this->db->getQuery(true) $query = $this->db->getQuery(true)
->delete($this->db->quoteName('#__session')) ->delete($this->db->quoteName('#__session'))
@ -208,7 +242,7 @@ class UserFactory implements UserFactoryInterface
{ {
$this->db->setQuery($query)->execute(); $this->db->setQuery($query)->execute();
} }
catch (\RuntimeException $e) catch (RuntimeException $e)
{ {
// The old session is already invalidated, don't let this block logging in // The old session is already invalidated, don't let this block logging in
} }
@ -237,7 +271,7 @@ class UserFactory implements UserFactoryInterface
->setLimit(1) ->setLimit(1)
)->loadResult(); )->loadResult();
} }
catch (\RuntimeException $exception) catch (RuntimeException $exception)
{ {
return false; return false;
} }
@ -269,7 +303,7 @@ class UserFactory implements UserFactoryInterface
->bind(1, $value) ->bind(1, $value)
)->loadResult(); )->loadResult();
} }
catch (\RuntimeException $exception) catch (RuntimeException $exception)
{ {
return false; return false;
} }
@ -281,56 +315,49 @@ class UserFactory implements UserFactoryInterface
return false; return false;
} }
/**
* Attempt to authenticate the username and password pair.
*
* @return string|boolean A string containing a username if authentication is successful, false otherwise.
*
* @since 1.1.0
*/
public function authenticate()
{
return $this->authentication->authenticate();
}
/** /**
* Attempt to login user * Attempt to login user
* *
* @return boolean true on success * @return boolean true on success
* *
* @throws \Exception * @throws Exception
* @since 1.0.0 * @since 1.0.0
*/ */
public function login(): bool public function login(): bool
{ {
/** @var \Octoleo\CMS\Application\AdminApplication $application */ // check if we have the application
$application = Factory::getApplication(); if (!$this->app instanceof AdminApplication)
{
$this->app = Factory::getApplication();
}
if (($username = $this->authenticate()) !== false) if (($username = $this->authenticate()) !== false)
{ {
// If loadUserByUsername returned an error, then pass it back.
$user = $this->loadUserByUsername($username); $user = $this->loadUserByUsername($username);
// If loadUserByUsername returned an error, then pass it back. // If loadUserByUsername returned an error, then pass it back.
if ($user instanceof \Exception) if ($user instanceof Exception)
{ {
$application->enqueueMessage('Login failure', 'Error'); $this->app->enqueueMessage('Login failure', 'Error');
return false; return false;
} }
// If loadUserByUsername returned an error, then pass it back. // check if this user is active
// 1 = blocked
// 0 = active (un blocked)
$blocked = $user->get('block', 1); $blocked = $user->get('block', 1);
if ($blocked == 1) if ($blocked == 1)
{ {
$application->enqueueMessage('Login failure, user is blocked. Contact your system administrator.', 'Warning'); $this->app->enqueueMessage('Login failure, user is blocked. Contact your system administrator.', 'Warning');
return false; return false;
} }
return $this->setUserSession($application, $user->toArray()); return $this->setUserSession($user->toArray());
} }
// set authentication failure message // set authentication failure message
$application->enqueueMessage('Login failure, please try again.', 'Warning'); $this->app->enqueueMessage('Login failure, please try again.', 'Warning');
return false; return false;
} }
@ -339,15 +366,17 @@ class UserFactory implements UserFactoryInterface
* Logout user * Logout user
* *
* @return bool * @return bool
* @throws \Exception * @throws Exception
*/ */
public function logout(): bool public function logout(): bool
{ {
/** @var \Octoleo\CMS\Application\AdminApplication $application */ // check if we have the application
$application = Factory::getApplication(); if (!$this->app instanceof AdminApplication)
{
$session = $application->getSession(); $this->app = Factory::getApplication();
}
// Get the session
$session = $this->app->getSession();
// Grab the current session ID // Grab the current session ID
$sessionId = $session->getId(); $sessionId = $session->getId();
@ -360,7 +389,7 @@ class UserFactory implements UserFactoryInterface
{ {
$this->db->setQuery($query)->execute(); $this->db->setQuery($query)->execute();
} }
catch (\RuntimeException $e) catch (RuntimeException $e)
{ {
// The old session is already invalidated, don't let this block logging in // The old session is already invalidated, don't let this block logging in
} }
@ -383,7 +412,7 @@ class UserFactory implements UserFactoryInterface
* *
* @return boolean true on success * @return boolean true on success
* *
* @throws \Exception * @throws Exception
* @since 1.0.0 * @since 1.0.0
*/ */
public function create( public function create(
@ -393,11 +422,12 @@ class UserFactory implements UserFactoryInterface
string $password = null, string $password = null,
string $password2 = null): bool string $password2 = null): bool
{ {
/** @var \Octoleo\CMS\Application\AdminApplication $application */ // check if we have the application
$application = Factory::getApplication(); if (!$this->app instanceof AdminApplication)
{
/** @var \Joomla\Input\Input $input */ $this->app = Factory::getApplication();
$input = $application->getInput(); }
$input = $this->app->getInput();
$user = []; $user = [];
$user['name'] = ($name) ?: $input->getString('name', ''); $user['name'] = ($name) ?: $input->getString('name', '');
@ -405,18 +435,20 @@ class UserFactory implements UserFactoryInterface
$user['email'] = ($email) ?: $input->getString('email', ''); $user['email'] = ($email) ?: $input->getString('email', '');
$user['password'] = ($password) ?: $input->getString('password', ''); $user['password'] = ($password) ?: $input->getString('password', '');
$user['password2'] = ($password2) ?: $input->getString('password2', ''); $user['password2'] = ($password2) ?: $input->getString('password2', '');
// normally we don't add newly registered users to the admin group
$add_to_admin_group = false;
// check if username exist // check if username exist
if (!empty($user['username']) && $this->exist($user['username'])) if (!empty($user['username']) && $this->exist($user['username']))
{ {
$application->enqueueMessage('Username already exist, try another username.', 'Warning'); $this->app->enqueueMessage('Username already exist, try another username.', 'Warning');
return false; return false;
} }
// check if email exist // check if email exist
if (!empty($user['email']) && $this->exist($user['email'], 'email')) if (!empty($user['email']) && $this->exist($user['email'], 'email'))
{ {
$application->enqueueMessage('Email already exist, try another email.', 'Warning'); $this->app->enqueueMessage('Email already exist, try another email.', 'Warning');
return false; return false;
} }
@ -437,13 +469,13 @@ class UserFactory implements UserFactoryInterface
if (empty($detail)) if (empty($detail))
{ {
$valid = false; $valid = false;
$application->enqueueMessage($key . ' is required', 'error'); $this->app->enqueueMessage($key . ' is required', 'error');
} }
// check if its valid // check if its valid
if (!$this->valid($key, $detail)) elseif (!$this->valid($key, $detail))
{ {
$valid = false; $valid = false;
$application->enqueueMessage($key . ' is not valid', 'error'); $this->app->enqueueMessage($key . ' is not valid', 'error');
} }
} }
@ -451,7 +483,7 @@ class UserFactory implements UserFactoryInterface
if (isset($user['password2']) && $user['password'] != $user['password2']) if (isset($user['password2']) && $user['password'] != $user['password2'])
{ {
$valid = false; $valid = false;
$application->enqueueMessage('Passwords do not match', 'error'); $this->app->enqueueMessage('Passwords do not match', 'error');
} }
unset ($user['password2']); unset ($user['password2']);
@ -473,7 +505,10 @@ class UserFactory implements UserFactoryInterface
} }
else else
{ {
// this is the first account (so it's an admin account)
$user['block'] = 0; $user['block'] = 0;
// we must add this user to the admin group
$add_to_admin_group = true;
} }
// there are no params at this stage // there are no params at this stage
$user['params'] = ''; $user['params'] = '';
@ -485,27 +520,58 @@ class UserFactory implements UserFactoryInterface
// Insert the user // Insert the user
$result = $this->db->insertObject('#__users', $insert, 'id'); $result = $this->db->insertObject('#__users', $insert, 'id');
} }
catch (\RuntimeException $exception) catch (RuntimeException $exception)
{ {
throw new \RuntimeException($exception->getMessage(), 404); throw new RuntimeException($exception->getMessage(), 404);
return false;
} }
// only set session if success and not blocked // only set session if success and not blocked
if ($result && $user['block'] == 0) if ($result && $user['block'] == 0)
{ {
// get the user ID
$user['id'] = $this->db->insertid(); $user['id'] = $this->db->insertid();
return $this->setUserSession($application, $user); // add to admin
if ($add_to_admin_group)
{
// build the mapped group link to admin
$group = [];
$group['user_id'] = $user['id'];
$group['group_id'] = 1; // admin group ID is normally 1 see /sq/install.sql (line 110)
$insert = (object) $group;
try
{
// Insert the user group link
$this->db->insertObject('#__user_usergroup_map', $insert);
}
catch (RuntimeException $exception)
{
// we ignore this... at this point
}
}
return $this->setUserSession($user);
} }
elseif ($result) elseif ($result)
{ {
$application->enqueueMessage('You account has been created, an administrator will active it shortly.', 'success'); $this->app->enqueueMessage('You account has been created, an administrator will active it shortly.', 'success');
} }
} }
return false; return false;
} }
/**
* Attempt to authenticate the username and password pair.
*
* @return string|boolean A string containing a username if authentication is successful, false otherwise.
*
* @since 1.1.0
*/
private function authenticate()
{
return $this->authentication->authenticate();
}
/** /**
* Attempt validate user input (BASIC) * Attempt validate user input (BASIC)
* *
@ -529,16 +595,22 @@ class UserFactory implements UserFactoryInterface
} }
/** /**
* @param AdminApplication $application * Method to add the user to the session
* @param array $user *
* @param array $user
* *
* @return bool * @return bool
* @throws \Exception * @throws Exception
*/ */
private function setUserSession(AdminApplication $application, array $user): bool private function setUserSession(array $user): bool
{ {
$session = $application->getSession(); // check if we have the application
if (!$this->app instanceof AdminApplication)
{
$this->app = Factory::getApplication();
}
// Get the session
$session = $this->app->getSession();
// Grab the current session ID // Grab the current session ID
$oldSessionId = $session->getId(); $oldSessionId = $session->getId();
@ -557,18 +629,16 @@ class UserFactory implements UserFactoryInterface
{ {
$this->db->setQuery($query)->execute(); $this->db->setQuery($query)->execute();
} }
catch (\RuntimeException $e) catch (RuntimeException $e)
{ {
// The old session is already invalidated, don't let this block logging in // The old session is already invalidated, don't let this block logging in
} }
/** @var \Octoleo\CMS\Session\MetadataManager $manager */ // creat or update the record for this user session
$manager = Factory::getContainer()->get(MetadataManager::class); $this->manager->createOrUpdateRecord($session, $this->loadUserById($user['id']));
$manager->createOrUpdateRecord($session, $this->loadUserById($user['id']));
// show a success message // show a success message
$application->enqueueMessage('Welcome ' . $user['name'] . ', you have successfully lodged in!', 'Success'); $this->app->enqueueMessage('Welcome ' . $user['name'] . ', you have successfully lodged in!', 'Success');
return true; return true;
} }

View File

@ -1,13 +1,17 @@
<?php <?php
/** /**
* Joomla! Content Management System * @package Octoleo CMS
* *
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @created 21th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45>
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\User; namespace Octoleo\CMS\User;
use Exception;
/** /**
* Interface defining a factory which can create User objects * Interface defining a factory which can create User objects
* *
@ -15,6 +19,18 @@ namespace Octoleo\CMS\User;
*/ */
interface UserFactoryInterface interface UserFactoryInterface
{ {
/**
* 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;
/** /**
* Method to get an instance of a user for the given id. * Method to get an instance of a user for the given id.
* *
@ -38,11 +54,76 @@ interface UserFactoryInterface
public function loadUserByUsername(string $username): User; public function loadUserByUsername(string $username): User;
/** /**
* Attempt to authenticate the username and password pair. * Method to get an instance of a user for the session.
* *
* @return string|boolean A string containing a username if authentication is successful, false otherwise. * @return User
* *
* @since 1.1.0 * @throws Exception
* @since 1.0.0
*/ */
public function authenticate(); public function loadUserBySession(): User;
/**
* Check if user is active
*
* @return bool
* @throws Exception
*/
public function active(): bool;
/**
* Check if we have users
*
* @return bool true if we have
*/
public function has(): bool;
/**
* Check if a user exist based on give key value pair
*
* @param string $value
* @param string $key
*
* @return false|mixed on success return user ID
*/
public function exist(string $value, string $key = 'username');
/**
* Attempt to login user
*
* @return boolean true on success
*
* @throws Exception
* @since 1.0.0
*/
public function login(): bool;
/**
* Logout user
*
* @return bool
* @throws Exception
*/
public function logout(): bool;
/**
* Attempt to great user
*
* @param string|null $name
* @param string|null $username
* @param string|null $email
* @param string|null $password
* @param string|null $password2
*
* @return boolean true on success
*
* @throws Exception
* @since 1.0.0
*/
public function create(
string $name = null,
string $username = null,
string $email = null,
string $password = null,
string $password2 = null): bool;
} }

View File

@ -0,0 +1,79 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 30th April, 2015
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder-Pro>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Octoleo\CMS\Utilities;
/**
* Some array tricks helper
*
* @since 3.0.9
*/
abstract class ArrayHelper
{
/**
* Check if have an array with a length
*
* @input array The array to check
*
* @returns bool/int number of items in array on success
*
* @since 3.0.9
*/
public static function check($array, $removeEmptyString = false)
{
if (is_array($array) && ($nr = count((array)$array)) > 0)
{
// also make sure the empty strings are removed
if ($removeEmptyString)
{
foreach ($array as $key => $string)
{
if (empty($string))
{
unset($array[$key]);
}
}
return self::check($array, false);
}
return $nr;
}
return false;
}
/**
* Merge an array of array's
*
* @input array The arrays you would like to merge
*
* @returns array on success
*
* @since 3.0.9
*/
public static function merge($arrays)
{
if(self::check($arrays))
{
$arrayBuket = array();
foreach ($arrays as $array)
{
if (self::check($array))
{
$arrayBuket = array_merge($arrayBuket, $array);
}
}
return $arrayBuket;
}
return false;
}
}

View File

@ -0,0 +1,322 @@
<?php
/**
* @package Joomla.Component.Builder
*
* @created 30th April, 2015
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder-Pro>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Octoleo\CMS\Utilities;
/**
* Some string tricks
*
* @since 3.0.9
*/
abstract class StringHelper
{
/**
* Check if we have a string with a length
*
* @input string $string The string to check
*
* @returns bool true on success
*
* @since 3.0.9
*/
public static function check($string): bool
{
if (is_string($string) && strlen($string) > 0)
{
return true;
}
return false;
}
/**
* Shorten a string
*
* @input string The you would like to shorten
*
* @returns string on success
*
* @since 3.0.9
*/
public static function shorten($string, $length = 40, $addTip = true)
{
if (self::check($string))
{
$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));
$final = strlen($newString);
if ($initial != $final && $addTip)
{
$title = self::shorten($string, 400 , false);
return '<span class="hasTip" title="' . $title . '" style="cursor:help">' . trim($newString) . '...</span>';
}
elseif ($initial != $final && !$addTip)
{
return trim($newString) . '...';
}
}
return $string;
}
/**
* Making strings safe (various ways)
*
* @input string The you would like to make safe
*
* @returns string on success
*
* @since 3.0.9
*/
public static function safe($string, $type = 'L', $spacer = '_', $replaceNumbers = true, $keepOnlyCharacters = true)
{
if ($replaceNumbers === true)
{
// remove all numbers and replace with english text version (works well only up to millions)
$string = self::numbers($string);
}
// 0nly continue if we have a string
if (self::check($string))
{
// create file name without the extension that is safe
if ($type === 'filename')
{
// make sure VDM is not in the string
$string = str_replace('VDM', 'vDm', $string);
// Remove anything which isn't a word, whitespace, number
// or any of the following caracters -_()
// If you don't need to handle multi-byte characters
// you can use preg_replace rather than mb_ereg_replace
// Thanks @Łukasz Rysiak!
// $string = mb_ereg_replace("([^\w\s\d\-_\(\)])", '', $string);
$string = preg_replace("([^\w\s\d\-_\(\)])", '', $string);
// http://stackoverflow.com/a/2021729/1429677
return preg_replace('/\s+/', ' ', $string);
}
// remove all other characters
$string = trim($string);
$string = preg_replace('/'.$spacer.'+/', ' ', $string);
$string = preg_replace('/\s+/', ' ', $string);
// remove all and keep only characters
if ($keepOnlyCharacters)
{
$string = preg_replace("/[^A-Za-z ]/", '', $string);
}
// keep both numbers and characters
else
{
$string = preg_replace("/[^A-Za-z0-9 ]/", '', $string);
}
// select final adaptations
if ($type === 'L' || $type === 'strtolower')
{
// replace white space with underscore
$string = preg_replace('/\s+/', $spacer, $string);
// default is to return lower
return strtolower($string);
}
elseif ($type === 'W')
{
// return a string with all first letter of each word uppercase(no underscore)
return ucwords(strtolower($string));
}
elseif ($type === 'w' || $type === 'word')
{
// return a string with all lowercase(no underscore)
return strtolower($string);
}
elseif ($type === 'Ww' || $type === 'Word')
{
// return a string with first letter of the first word uppercase and all the rest lowercase(no underscore)
return ucfirst(strtolower($string));
}
elseif ($type === 'WW' || $type === 'WORD')
{
// return a string with all the uppercase(no underscore)
return strtoupper($string);
}
elseif ($type === 'U' || $type === 'strtoupper')
{
// replace white space with underscore
$string = preg_replace('/\s+/', $spacer, $string);
// return all upper
return strtoupper($string);
}
elseif ($type === 'F' || $type === 'ucfirst')
{
// replace white space with underscore
$string = preg_replace('/\s+/', $spacer, $string);
// return with first character to upper
return ucfirst(strtolower($string));
}
elseif ($type === 'cA' || $type === 'cAmel' || $type === 'camelcase')
{
// convert all words to first letter uppercase
$string = ucwords(strtolower($string));
// remove white space
$string = preg_replace('/\s+/', '', $string);
// now return first letter lowercase
return lcfirst($string);
}
// return string
return $string;
}
// not a string
return '';
}
/**
* Convert all int in a string to an English word string
*
* @input an string with numbers
*
* @returns a string
*
* @since 3.0.9
*/
public static function numbers($string)
{
// set numbers array
$numbers = array();
// first get all numbers
preg_match_all('!\d+!', $string, $numbers);
// check if we have any numbers
if (isset($numbers[0]) && ArrayHelper::check($numbers[0]))
{
foreach ($numbers[0] as $number)
{
$searchReplace[$number] = self::number((int)$number);
}
// now replace numbers in string
$string = str_replace(array_keys($searchReplace), array_values($searchReplace), $string);
// check if we missed any, strange if we did.
return self::numbers($string);
}
// return the string with no numbers remaining.
return $string;
}
/**
* Convert an integer into an English word string
* Thanks to Tom Nicholson <http://php.net/manual/en/function.strval.php#41988>
*
* @input an int
* @returns a string
*
* @since 3.0.9
*/
public static function number($x)
{
$nwords = array( "zero", "one", "two", "three", "four", "five", "six", "seven",
"eight", "nine", "ten", "eleven", "twelve", "thirteen",
"fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
"nineteen", "twenty", 30 => "thirty", 40 => "forty",
50 => "fifty", 60 => "sixty", 70 => "seventy", 80 => "eighty",
90 => "ninety" );
if(!is_numeric($x))
{
$w = $x;
}
elseif(fmod($x, 1) != 0)
{
$w = $x;
}
else
{
if($x < 0)
{
$w = 'minus ';
$x = -$x;
}
else
{
$w = '';
// ... now $x is a non-negative integer.
}
if($x < 21) // 0 to 20
{
$w .= $nwords[$x];
}
elseif($x < 100) // 21 to 99
{
$w .= $nwords[10 * floor($x/10)];
$r = fmod($x, 10);
if($r > 0)
{
$w .= ' ' . $nwords[$r];
}
}
elseif($x < 1000) // 100 to 999
{
$w .= $nwords[floor($x/100)] .' hundred';
$r = fmod($x, 100);
if($r > 0)
{
$w .= ' and '. self::number($r);
}
}
elseif($x < 1000000) // 1000 to 999999
{
$w .= self::number(floor($x/1000)) .' thousand';
$r = fmod($x, 1000);
if($r > 0)
{
$w .= ' ';
if($r < 100)
{
$w .= 'and ';
}
$w .= self::number($r);
}
}
else // millions
{
$w .= self::number(floor($x/1000000)) .' million';
$r = fmod($x, 1000000);
if($r > 0)
{
$w .= ' ';
if($r < 100)
{
$w .= 'and ';
}
$w .= self::number($r);
}
}
}
return $w;
}
}

View File

@ -15,12 +15,12 @@ use Joomla\Renderer\RendererInterface;
use Joomla\View\HtmlView; use Joomla\View\HtmlView;
/** /**
* Dashboard HTML view class for the application * HTML view class for the application
*/ */
class DashboardHtmlView extends HtmlView class DashboardHtmlView extends HtmlView
{ {
/** /**
* The id of item/user/menu * The id
* *
* @var int * @var int
*/ */
@ -36,7 +36,7 @@ class DashboardHtmlView extends HtmlView
/** /**
* Instantiate the view. * Instantiate the view.
* *
* @param DashboardModel $model The page model object. * @param DashboardModel $model The model object.
* @param RendererInterface $renderer The renderer object. * @param RendererInterface $renderer The renderer object.
*/ */
public function __construct(DashboardModel $model, RendererInterface $renderer) public function __construct(DashboardModel $model, RendererInterface $renderer)
@ -58,7 +58,7 @@ class DashboardHtmlView extends HtmlView
} }
/** /**
* Set the active dashboard * Set the active view
* *
* @param string $name The active page name * @param string $name The active page name
* *
@ -70,9 +70,9 @@ class DashboardHtmlView extends HtmlView
} }
/** /**
* Set the active page details * Set the active id
* *
* @param int $id The selected item/user/menu * @param int $id The active id
* *
* @return void * @return void
*/ */

View File

@ -15,19 +15,19 @@ use Joomla\Renderer\RendererInterface;
use Joomla\View\HtmlView; use Joomla\View\HtmlView;
/** /**
* Dashboard HTML view class for the application * HTML view class for the application
*/ */
class ItemHtmlView extends HtmlView class ItemHtmlView extends HtmlView
{ {
/** /**
* The id of item/user/menu * The id
* *
* @var int * @var int
*/ */
private $id; private $id;
/** /**
* The item model object. * The model object.
* *
* @var ItemModel * @var ItemModel
*/ */
@ -36,7 +36,7 @@ class ItemHtmlView extends HtmlView
/** /**
* Instantiate the view. * Instantiate the view.
* *
* @param ItemModel $model The page model object. * @param ItemModel $model The model object.
* @param RendererInterface $renderer The renderer object. * @param RendererInterface $renderer The renderer object.
*/ */
public function __construct(ItemModel $model, RendererInterface $renderer) public function __construct(ItemModel $model, RendererInterface $renderer)
@ -71,9 +71,9 @@ class ItemHtmlView extends HtmlView
} }
/** /**
* Set the active page details * Set the active id
* *
* @param int $id The selected item * @param int $id The active id
* *
* @return void * @return void
*/ */

View File

@ -15,12 +15,12 @@ use Joomla\Renderer\RendererInterface;
use Joomla\View\HtmlView; use Joomla\View\HtmlView;
/** /**
* Dashboard HTML view class for the application * HTML view class for the application
*/ */
class ItemsHtmlView extends HtmlView class ItemsHtmlView extends HtmlView
{ {
/** /**
* The item model object. * The model object.
* *
* @var ItemsModel * @var ItemsModel
*/ */
@ -29,7 +29,7 @@ class ItemsHtmlView extends HtmlView
/** /**
* Instantiate the view. * Instantiate the view.
* *
* @param ItemsModel $model The page model object. * @param ItemsModel $model The model object.
* @param RendererInterface $renderer The renderer object. * @param RendererInterface $renderer The renderer object.
*/ */
public function __construct(ItemsModel $model, RendererInterface $renderer) public function __construct(ItemsModel $model, RendererInterface $renderer)

View File

@ -13,21 +13,22 @@ namespace Octoleo\CMS\View\Admin;
use Octoleo\CMS\Model\MenuModel; use Octoleo\CMS\Model\MenuModel;
use Joomla\Renderer\RendererInterface; use Joomla\Renderer\RendererInterface;
use Joomla\View\HtmlView; use Joomla\View\HtmlView;
use Octoleo\CMS\Model\Util\MenuInterface;
/** /**
* Dashboard HTML view class for the application * HTML view class for the application
*/ */
class MenuHtmlView extends HtmlView class MenuHtmlView extends HtmlView
{ {
/** /**
* The id of item/user/menu * The id
* *
* @var int * @var int
*/ */
private $id; private $id;
/** /**
* The item model object. * The model object.
* *
* @var MenuModel * @var MenuModel
*/ */
@ -36,7 +37,7 @@ class MenuHtmlView extends HtmlView
/** /**
* Instantiate the view. * Instantiate the view.
* *
* @param MenuModel $model The page model object. * @param MenuModel $model The model object.
* @param RendererInterface $renderer The renderer object. * @param RendererInterface $renderer The renderer object.
*/ */
public function __construct(MenuModel $model, RendererInterface $renderer) public function __construct(MenuModel $model, RendererInterface $renderer)
@ -54,9 +55,16 @@ class MenuHtmlView extends HtmlView
*/ */
public function render(): string public function render(): string
{ {
// set the active menus if possible
$menus = [];
if ($this->model instanceof MenuInterface)
{
$menus = $this->model->getMenus($this->id);
}
$this->setData([ $this->setData([
'form' => $this->model->getItem($this->id), 'form' => $this->model->getItem($this->id),
'items' => $this->model->getItems() 'items' => $this->model->getItems(),
'menus' => $menus
]); ]);
return parent::render(); return parent::render();
} }
@ -74,9 +82,9 @@ class MenuHtmlView extends HtmlView
} }
/** /**
* Set the active page details * Set the active id
* *
* @param int $id The selected item/user/menu * @param int $id The active id
* *
* @return void * @return void
*/ */

View File

@ -15,12 +15,12 @@ use Joomla\Renderer\RendererInterface;
use Joomla\View\HtmlView; use Joomla\View\HtmlView;
/** /**
* Dashboard HTML view class for the application * HTML view class for the application
*/ */
class MenusHtmlView extends HtmlView class MenusHtmlView extends HtmlView
{ {
/** /**
* The item model object. * The model object.
* *
* @var MenusModel * @var MenusModel
*/ */
@ -29,7 +29,7 @@ class MenusHtmlView extends HtmlView
/** /**
* Instantiate the view. * Instantiate the view.
* *
* @param MenusModel $model The page model object. * @param MenusModel $model The model object.
* @param RendererInterface $renderer The renderer object. * @param RendererInterface $renderer The renderer object.
*/ */
public function __construct(MenusModel $model, RendererInterface $renderer) public function __construct(MenusModel $model, RendererInterface $renderer)
@ -51,9 +51,9 @@ class MenusHtmlView extends HtmlView
} }
/** /**
* Set the active view * Set the active id
* *
* @param string $name The active view name * @param string $name The active id
* *
* @return void * @return void
*/ */

View File

@ -15,19 +15,19 @@ use Joomla\Renderer\RendererInterface;
use Joomla\View\HtmlView; use Joomla\View\HtmlView;
/** /**
* Dashboard HTML view class for the application * HTML view class for the application
*/ */
class UserHtmlView extends HtmlView class UserHtmlView extends HtmlView
{ {
/** /**
* The id of user * The id
* *
* @var int * @var int
*/ */
private $id; private $id;
/** /**
* The User model object. * The model object.
* *
* @var UserModel * @var UserModel
*/ */
@ -36,7 +36,7 @@ class UserHtmlView extends HtmlView
/** /**
* Instantiate the view. * Instantiate the view.
* *
* @param UserModel $model The page model object. * @param UserModel $model The model object.
* @param RendererInterface $renderer The renderer object. * @param RendererInterface $renderer The renderer object.
*/ */
public function __construct(UserModel $model, RendererInterface $renderer) public function __construct(UserModel $model, RendererInterface $renderer)
@ -50,10 +50,14 @@ class UserHtmlView extends HtmlView
* Method to render the view * Method to render the view
* *
* @return string The rendered view * @return string The rendered view
* @throws \Exception
*/ */
public function render(): string public function render(): string
{ {
$this->setData(['form' => $this->model->getItem($this->id)]); $this->setData([
'form' => $this->model->getItem($this->id),
'groups' => $this->model->getUsergroups()
]);
return parent::render(); return parent::render();
} }
@ -70,9 +74,9 @@ class UserHtmlView extends HtmlView
} }
/** /**
* Set the active page details * Set the active id
* *
* @param int $id The selected user * @param int $id The active id
* *
* @return void * @return void
*/ */

View File

@ -0,0 +1,85 @@
<?php
/**
* @package Octoleo CMS
*
* @created 20th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Octoleo\CMS\View\Admin;
use Octoleo\CMS\Model\UsergroupModel;
use Joomla\Renderer\RendererInterface;
use Joomla\View\HtmlView;
/**
* HTML view class for the application
*/
class UsergroupHtmlView extends HtmlView
{
/**
* The id
*
* @var int
*/
private $id;
/**
* The model object.
*
* @var UsergroupModel
*/
private $model;
/**
* Instantiate the view.
*
* @param UsergroupModel $model The model object.
* @param RendererInterface $renderer The renderer object.
*/
public function __construct(UsergroupModel $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 id
*
* @param int $id The active id
*
* @return void
*/
public function setActiveId(int $id): void
{
$this->id = $id;
}
}

View File

@ -0,0 +1,64 @@
<?php
/**
* @package Octoleo CMS
*
* @created 20th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/WEBD-325-45>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Octoleo\CMS\View\Admin;
use Octoleo\CMS\Model\UsergroupsModel;
use Joomla\Renderer\RendererInterface;
use Joomla\View\HtmlView;
/**
* HTML view class for the application
*/
class UsergroupsHtmlView extends HtmlView
{
/**
* The model object.
*
* @var UsergroupsModel
*/
private $model;
/**
* Instantiate the view.
*
* @param UsergroupsModel $model The model object.
* @param RendererInterface $renderer The renderer object.
*/
public function __construct(UsergroupsModel $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));
}
}

View File

@ -15,12 +15,12 @@ use Joomla\Renderer\RendererInterface;
use Joomla\View\HtmlView; use Joomla\View\HtmlView;
/** /**
* Dashboard HTML view class for the application * HTML view class for the application
*/ */
class UsersHtmlView extends HtmlView class UsersHtmlView extends HtmlView
{ {
/** /**
* The item model object. * The model object.
* *
* @var UsersModel * @var UsersModel
*/ */
@ -29,8 +29,8 @@ class UsersHtmlView extends HtmlView
/** /**
* Instantiate the view. * Instantiate the view.
* *
* @param UsersModel $model The page model object. * @param UsersModel $model The model object.
* @param RendererInterface $renderer The renderer object. * @param RendererInterface $renderer The renderer object.
*/ */
public function __construct(UsersModel $model, RendererInterface $renderer) public function __construct(UsersModel $model, RendererInterface $renderer)
{ {

View File

@ -1,133 +0,0 @@
<?php
/**
* @package Octoleo CMS
*
* @created 18th April 2022
* @author Llewellyn van der Merwe <https://git.vdm.dev/Llewellyn>
* @git WEBD-325-45 <https://git.vdm.dev/Llewellyn/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;
}
}

View File

@ -8,16 +8,17 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt * @license GNU General Public License version 2 or later; see LICENSE.txt
*/ */
namespace Octoleo\CMS\View\Page; namespace Octoleo\CMS\View\Site;
use Octoleo\CMS\Model\MenuInterface;
use Octoleo\CMS\Model\PageInterface;
use Octoleo\CMS\Model\PageModel; use Octoleo\CMS\Model\PageModel;
use Joomla\Renderer\RendererInterface; use Joomla\Renderer\RendererInterface;
use Joomla\View\HtmlView; use Joomla\View\HtmlView;
use Octoleo\CMS\Model\Util\MenuInterface;
use Octoleo\CMS\Model\Util\PageInterface;
use Octoleo\CMS\Model\Util\HomeMenuInterface;
/** /**
* Page HTML view class for the application * HTML view class for the application
*/ */
class PageHtmlView extends HtmlView class PageHtmlView extends HtmlView
{ {
@ -29,14 +30,7 @@ class PageHtmlView extends HtmlView
private $page = ''; private $page = '';
/** /**
* The active page details * The model object.
*
* @var string
*/
private $details;
/**
* The page model object.
* *
* @var PageModel * @var PageModel
*/ */
@ -45,7 +39,7 @@ class PageHtmlView extends HtmlView
/** /**
* Instantiate the view. * Instantiate the view.
* *
* @param PageModel $model The page model object. * @param PageModel $model The model object.
* @param RendererInterface $renderer The renderer object. * @param RendererInterface $renderer The renderer object.
*/ */
public function __construct(PageModel $model, RendererInterface $renderer) public function __construct(PageModel $model, RendererInterface $renderer)
@ -66,13 +60,39 @@ class PageHtmlView extends HtmlView
$title = 'Error'; $title = 'Error';
$body = ''; $body = '';
$menus = []; $menus = [];
// menu ID
$menu_id = 0;
$menu_home = false;
// set home menu title (not ideal)
$home_menu_title = 'Home';
// we check if we have a home page
if ($this->model instanceof HomeMenuInterface)
{
$home_page = $this->model->getHomePage();
if (isset($home_page->title))
{
$home_menu_title = $home_page->title;
}
}
// get the page data // get the page data
if ($this->model instanceof PageInterface) if ($this->model instanceof PageInterface)
{ {
// get the page data // get the page data
$data = $this->model->getPageItemByPath($this->page); if (empty($this->page) && isset($home_page->item_id) && $home_page->item_id > 0)
{
// this is the home menu
$data = $this->model->getPageItemById($home_page->item_id);
$menu_home = true;
}
else
{
$data = $this->model->getPageItemByPath($this->page);
}
// check if we found any data
if (isset($data->id)) if (isset($data->id))
{ {
// set the menu ID
$menu_id = $data->menu_id;
// set the title // set the title
$title = $data->title; $title = $data->title;
// check if we have intro text we add it to full text // check if we have intro text we add it to full text
@ -93,13 +113,16 @@ class PageHtmlView extends HtmlView
// set the menus if possible // set the menus if possible
if ($this->model instanceof MenuInterface) if ($this->model instanceof MenuInterface)
{ {
$menus = $this->model->getMenus(); $menus = $this->model->getMenus($menu_id);
} }
$this->setData( $this->setData(
[ [
'main_menu' => $menus, 'menus' => $menus,
'home' => $menu_home,
'menu_active' => $menu_id,
'title' => $title, 'title' => $title,
'home_menu_title' => $home_menu_title,
'body' => $body 'body' => $body
] ]
); );

View File

@ -1,141 +1,249 @@
-- phpMyAdmin SQL Dump
-- version 5.1.1
-- https://www.phpmyadmin.net/
-- --
-- DATABASE STRUCTURE FOR GENERIC CMS (Adapted from Joomla!) -- Host: mariadb_cms:3306
-- -- subject to change -- -- Generation Time: Apr 22, 2022 at 03:25 PM
-- -- Server version: 10.6.5-MariaDB-1:10.6.5+maria~focal
-- PHP Version: 7.4.20
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET
SET time_zone = "+00:00"; SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET
time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
-- --
-- Table structure for table `llewellyn_menu` -- Database: `vdm_io`
-- --
CREATE TABLE IF NOT EXISTS `llewellyn_menu` ( -- --------------------------------------------------------
`id` int NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL COMMENT 'The display title of the menu item.',
`alias` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'The SEF alias of the menu item.',
`path` varchar(1024) NOT NULL COMMENT 'The computed path of the menu item based on the alias field.',
`published` tinyint NOT NULL DEFAULT 0 COMMENT 'The published state of the menu link.',
`parent_id` int unsigned NOT NULL DEFAULT 1 COMMENT 'The parent menu item in the menu tree.',
`level` int unsigned NOT NULL DEFAULT 0 COMMENT 'The relative level in the tree.',
`item_id` int unsigned NOT NULL DEFAULT 0 COMMENT 'FK to llewellyn_item.id',
`checked_out` int unsigned COMMENT 'FK to llewellyn_users.id',
`checked_out_time` datetime COMMENT 'The time the menu item was checked out.',
`params` text NOT NULL COMMENT 'JSON encoded data for the menu item.',
`lft` int NOT NULL DEFAULT 0 COMMENT 'Nested set lft.',
`rgt` int NOT NULL DEFAULT 0 COMMENT 'Nested set rgt.',
`home` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Indicates if this menu item is the home or default page.',
`publish_up` datetime,
`publish_down` datetime,
PRIMARY KEY (`id`),
KEY `idx_item` (`item_id`),
KEY `idx_left_right` (`lft`,`rgt`),
KEY `idx_alias` (`alias`(100)),
KEY `idx_path` (`path`(100))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=102;
--
-- Table structure for table `llewellyn_session`
--
CREATE TABLE IF NOT EXISTS `llewellyn_session` (
`session_id` varbinary(192) NOT NULL,
`guest` tinyint unsigned DEFAULT 1,
`time` int NOT NULL DEFAULT 0,
`data` mediumtext,
`userid` int DEFAULT 0,
`username` varchar(150) DEFAULT '',
PRIMARY KEY (`session_id`),
KEY `userid` (`userid`),
KEY `time` (`time`),
KEY `guest` (`guest`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `llewellyn_users`
--
CREATE TABLE IF NOT EXISTS `llewellyn_users` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(400) NOT NULL DEFAULT '',
`username` varchar(150) NOT NULL DEFAULT '',
`email` varchar(100) NOT NULL DEFAULT '',
`password` varchar(100) NOT NULL DEFAULT '',
`block` tinyint NOT NULL DEFAULT 0,
`sendEmail` tinyint DEFAULT 0,
`registerDate` datetime NOT NULL,
`lastvisitDate` datetime,
`activation` varchar(100) NOT NULL DEFAULT '',
`params` text NOT NULL,
`lastResetTime` datetime COMMENT 'Date of last password reset',
`resetCount` int NOT NULL DEFAULT 0 COMMENT 'Count of password resets since lastResetTime',
`requireReset` tinyint NOT NULL DEFAULT 0 COMMENT 'Require user to reset password on next login',
PRIMARY KEY (`id`),
KEY `idx_name` (`name`(100)),
KEY `idx_block` (`block`),
UNIQUE KEY `idx_username` (`username`),
KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `llewellyn_usergroups`
--
CREATE TABLE IF NOT EXISTS `llewellyn_usergroups` (
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
`parent_id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Adjacency List Reference Id',
`lft` int NOT NULL DEFAULT 0 COMMENT 'Nested set lft.',
`rgt` int NOT NULL DEFAULT 0 COMMENT 'Nested set rgt.',
`title` varchar(100) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_usergroup_parent_title_lookup` (`parent_id`,`title`),
KEY `idx_usergroup_title_lookup` (`title`),
KEY `idx_usergroup_adjacency_lookup` (`parent_id`),
KEY `idx_usergroup_nested_set_lookup` (`lft`,`rgt`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `llewellyn_user_usergroup_map`
--
CREATE TABLE IF NOT EXISTS `llewellyn_user_usergroup_map` (
`user_id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Foreign Key to llewellyn_users.id',
`group_id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Foreign Key to llewellyn_usergroups.id',
PRIMARY KEY (`user_id`,`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci;
-- --
-- Table structure for table `llewellyn_item` -- Table structure for table `llewellyn_item`
-- --
CREATE TABLE IF NOT EXISTS `llewellyn_item` ( CREATE TABLE `llewellyn_item`
`id` int unsigned NOT NULL AUTO_INCREMENT, (
`title` varchar(255) NOT NULL DEFAULT '', `id` int(10) UNSIGNED NOT NULL,
`alias` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '', `title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`introtext` mediumtext NOT NULL, `alias` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '',
`fulltext` mediumtext NOT NULL, `introtext` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
`state` tinyint NOT NULL DEFAULT 0, `fulltext` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
`created` datetime NOT NULL, `state` tinyint(4) NOT NULL DEFAULT 0,
`created_by` int unsigned NOT NULL DEFAULT 0, `created` datetime NOT NULL,
`created_by_alias` varchar(255) NOT NULL DEFAULT '', `created_by` int(10) UNSIGNED NOT NULL DEFAULT 0,
`modified` datetime NOT NULL, `created_by_alias` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`modified_by` int unsigned NOT NULL DEFAULT 0, `modified` datetime NOT NULL,
`checked_out` int unsigned, `modified_by` int(10) UNSIGNED NOT NULL DEFAULT 0,
`checked_out_time` datetime NULL DEFAULT NULL, `checked_out` int(10) UNSIGNED DEFAULT NULL,
`publish_up` datetime NULL DEFAULT NULL, `checked_out_time` datetime DEFAULT NULL,
`publish_down` datetime NULL DEFAULT NULL, `publish_up` datetime DEFAULT NULL,
`version` int unsigned NOT NULL DEFAULT 1, `publish_down` datetime DEFAULT NULL,
`ordering` int NOT NULL DEFAULT 0, `version` int(10) UNSIGNED NOT NULL DEFAULT 1,
`metakey` text, `ordering` int(11) NOT NULL DEFAULT 0,
`metadesc` text NOT NULL, `metakey` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`hits` int unsigned NOT NULL DEFAULT 0, `metadesc` text COLLATE utf8mb4_unicode_ci NOT NULL,
`metadata` text NOT NULL, `hits` int(10) UNSIGNED NOT NULL DEFAULT 0,
`featured` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Set if article is featured.', `metadata` text COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`), `params` text COLLATE utf8mb4_unicode_ci NOT NULL,
KEY `idx_checkout` (`checked_out`), `featured` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Set if article is featured.'
KEY `idx_state` (`state`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
KEY `idx_createdby` (`created_by`),
KEY `idx_alias` (`alias`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `llewellyn_menu`
--
CREATE TABLE `llewellyn_menu`
(
`id` int(11) NOT NULL,
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'The display title of the menu item.',
`alias` varchar(400) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'The SEF alias of the menu item.',
`path` varchar(1024) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'The computed path of the menu item based on the alias field.',
`published` tinyint(4) NOT NULL DEFAULT 0 COMMENT 'The published state of the menu link.',
`parent_id` int(10) UNSIGNED NOT NULL DEFAULT 1 COMMENT 'The parent menu item in the menu tree.',
`level` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'The relative level in the tree.',
`item_id` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'FK to llewellyn_item.id',
`checked_out` int(10) UNSIGNED DEFAULT NULL COMMENT 'FK to llewellyn_users.id',
`checked_out_time` datetime DEFAULT NULL COMMENT 'The time the menu item was checked out.',
`params` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'JSON encoded data for the menu item.',
`lft` int(11) NOT NULL DEFAULT 0 COMMENT 'Nested set lft.',
`rgt` int(11) NOT NULL DEFAULT 0 COMMENT 'Nested set rgt.',
`home` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Indicates if this menu item is the home or default page.',
`publish_up` datetime DEFAULT NULL,
`publish_down` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `llewellyn_session`
--
CREATE TABLE `llewellyn_session`
(
`session_id` varbinary(192) NOT NULL,
`guest` tinyint(3) UNSIGNED DEFAULT 1,
`time` int(11) NOT NULL DEFAULT 0,
`data` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`userid` int(11) DEFAULT 0,
`username` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `llewellyn_usergroups`
--
CREATE TABLE `llewellyn_usergroups`
(
`id` int(10) UNSIGNED NOT NULL COMMENT 'Primary Key',
`title` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`params` text COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `llewellyn_usergroups`
--
INSERT INTO `llewellyn_usergroups` (`id`, `title`, `params`)
VALUES (1, 'Administrator',
'[{\"area\":\"user\",\"access\":\"CRUD\"},{\"area\":\"usergroup\",\"access\":\"CRUD\"},{\"area\":\"menu\",\"access\":\"CRUD\"},{\"area\":\"item\",\"access\":\"CRUD\"}]'),
(2, 'Manager',
'[{\"area\":\"user\",\"access\":\"CR\"},{\"area\":\"usergroup\",\"access\":\"\"},{\"area\":\"menu\",\"access\":\"CRU\"},{\"area\":\"item\",\"access\":\"CRU\"}]'),
(3, 'Editor',
'[{\"area\":\"user\",\"access\":\"\"},{\"area\":\"usergroup\",\"access\":\"\"},{\"area\":\"menu\",\"access\":\"\"},{\"area\":\"item\",\"access\":\"CRU\"}]');
-- --------------------------------------------------------
--
-- Table structure for table `llewellyn_users`
--
CREATE TABLE `llewellyn_users`
(
`id` int(11) NOT NULL,
`name` varchar(400) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`username` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`email` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`password` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`block` tinyint(4) NOT NULL DEFAULT 0,
`sendEmail` tinyint(4) DEFAULT 0,
`registerDate` datetime NOT NULL,
`lastvisitDate` datetime DEFAULT NULL,
`activation` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`params` text COLLATE utf8mb4_unicode_ci NOT NULL,
`lastResetTime` datetime DEFAULT NULL COMMENT 'Date of last password reset',
`resetCount` int(11) NOT NULL DEFAULT 0 COMMENT 'Count of password resets since lastResetTime',
`requireReset` tinyint(4) NOT NULL DEFAULT 0 COMMENT 'Require user to reset password on next login'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `llewellyn_user_usergroup_map`
--
CREATE TABLE `llewellyn_user_usergroup_map`
(
`user_id` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Foreign Key to llewellyn_users.id',
`group_id` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Foreign Key to llewellyn_usergroups.id'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Indexes for dumped tables
--
--
-- Indexes for table `llewellyn_item`
--
ALTER TABLE `llewellyn_item`
ADD PRIMARY KEY (`id`),
ADD KEY `idx_checkout` (`checked_out`),
ADD KEY `idx_state` (`state`),
ADD KEY `idx_createdby` (`created_by`),
ADD KEY `idx_alias` (`alias`(191));
--
-- Indexes for table `llewellyn_menu`
--
ALTER TABLE `llewellyn_menu`
ADD PRIMARY KEY (`id`),
ADD KEY `idx_item` (`item_id`),
ADD KEY `idx_left_right` (`lft`,`rgt`),
ADD KEY `idx_alias` (`alias`(100)),
ADD KEY `idx_path` (`path`(100));
--
-- Indexes for table `llewellyn_session`
--
ALTER TABLE `llewellyn_session`
ADD PRIMARY KEY (`session_id`),
ADD KEY `userid` (`userid`),
ADD KEY `time` (`time`),
ADD KEY `guest` (`guest`);
--
-- Indexes for table `llewellyn_usergroups`
--
ALTER TABLE `llewellyn_usergroups`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `idx_usergroup_title_lookup` (`title`);
--
-- Indexes for table `llewellyn_users`
--
ALTER TABLE `llewellyn_users`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `idx_username` (`username`),
ADD KEY `idx_name` (`name`(100)),
ADD KEY `idx_block` (`block`),
ADD KEY `email` (`email`);
--
-- Indexes for table `llewellyn_user_usergroup_map`
--
ALTER TABLE `llewellyn_user_usergroup_map`
ADD PRIMARY KEY (`user_id`, `group_id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `llewellyn_item`
--
ALTER TABLE `llewellyn_item`
MODIFY `id` int (10) UNSIGNED NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `llewellyn_menu`
--
ALTER TABLE `llewellyn_menu`
MODIFY `id` int (11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=102;
--
-- AUTO_INCREMENT for table `llewellyn_usergroups`
--
ALTER TABLE `llewellyn_usergroups`
MODIFY `id` int (10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', AUTO_INCREMENT=3;
--
-- AUTO_INCREMENT for table `llewellyn_users`
--
ALTER TABLE `llewellyn_users`
MODIFY `id` int (11) NOT NULL AUTO_INCREMENT;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

View File

@ -7,15 +7,51 @@
<h1 class="uk-article-title">Octoleo CMS Dashboard</h1> <h1 class="uk-article-title">Octoleo CMS Dashboard</h1>
{{ block("messages_queue", "message_queue.twig") }} {{ block("messages_queue", "message_queue.twig") }}
<div class="uk-grid-small uk-child-width-expand@s uk-text-center" uk-grid> <div class="uk-grid-small uk-child-width-expand@s uk-text-center" uk-grid>
<div> {% set no_access = true %}
<div class="uk-card uk-card-default uk-card-body"><a href="{{ route() }}index.php/users">Users</a></div> {% if user('access.user.read', false) %}
</div> {% set no_access = false %}
<div> <div>
<div class="uk-card uk-card-default uk-card-body"><a href="{{ route() }}index.php/menus">Menus</a></div> <div class="uk-card uk-card-default uk-card-body">
</div> <a href="{{ route() }}index.php/users" uk-icon="icon: user; ratio: 7"></a><br />
<div> <a href="{{ route() }}index.php/users">Users</a>
<div class="uk-card uk-card-default uk-card-body"><a href="{{ route() }}index.php/items">Items</a></div> </div>
</div> </div>
{% endif %}
{% if user('access.usergroup.read', false) %}
{% set no_access = false %}
<div>
<div class="uk-card uk-card-default uk-card-body">
<a href="{{ route() }}index.php/usergroups" uk-icon="icon: users; ratio: 7"></a><br />
<a href="{{ route() }}index.php/usergroups">User Groups</a>
</div>
</div>
{% endif %}
{% if user('access.menu.read', false) %}
{% set no_access = false %}
<div>
<div class="uk-card uk-card-default uk-card-body">
<a href="{{ route() }}index.php/menus" uk-icon="icon: menu; ratio: 7"></a><br />
<a href="{{ route() }}index.php/menus">Menus</a>
</div>
</div>
{% endif %}
{% if user('access.item.read', false) %}
{% set no_access = false %}
<div>
<div class="uk-card uk-card-default uk-card-body">
<a href="{{ route() }}index.php/items" uk-icon="icon: pencil; ratio: 7"></a><br />
<a href="{{ route() }}index.php/items">Items</a>
</div>
</div>
{% endif %}
{% if no_access %}
<div>
<div class="uk-card uk-card-default uk-card-body">
<span uk-icon="icon: ban; ratio: 7"></span><br />
No access found to any area, please contact your system administrator!
</div>
</div>
{% endif %}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,5 +1,5 @@
{% extends "header.twig" %} {% extends "header.twig" %}
{% set user = user_array() %}
{% block body %} {% block body %}
<body id="go"> <body id="go">
{% block bodyNavigation %}{{ block("bodyNavigation", "nav.twig") }}{% endblock %} {% block bodyNavigation %}{{ block("bodyNavigation", "nav.twig") }}{% endblock %}

View File

@ -1,6 +1,6 @@
{% extends "index.twig" %} {% extends "index.twig" %}
{% block title %}Edit Item{% endblock %} {% block title %}{% if form.id == 0 %}Create{% else %}Edit{% endif %} Item {{ form.title|default('') }}{% endblock %}
{% block headJavaScriptLinks %} {% block headJavaScriptLinks %}
<script src="https://cdn.ckeditor.com/ckeditor5/34.0.0/classic/ckeditor.js"></script> <script src="https://cdn.ckeditor.com/ckeditor5/34.0.0/classic/ckeditor.js"></script>
@ -9,11 +9,20 @@
{% block content %} {% block content %}
<div class="uk-container uk-margin"> <div class="uk-container uk-margin">
{{ block("messages_queue", "message_queue.twig") }} {{ block("messages_queue", "message_queue.twig") }}
{% if form.id == 0 %}
<h3><span uk-icon="icon: pencil; ratio: 1"></span> Create Item</h3>
{% else %}
<h3><span uk-icon="icon: pencil; ratio: 1"></span> Edit Item {{ form.title|default('') }}</h3>
{% endif %}
<form class="uk-form-stacked" action="{{ route() }}index.php/item{{ form.post_key|default('') }}" method="post"> <form class="uk-form-stacked" action="{{ route() }}index.php/item{{ form.post_key|default('') }}" method="post">
<div class="uk-button-group uk-width-1-1 uk-margin"> {% if user('access.item.update', false) %}
<input type="submit" class="uk-button uk-button-primary uk-width-1-2" value="Save"/> <div class="uk-button-group uk-width-1-1 uk-margin">
<a href="{{ route() }}index.php/items" type="button" class="uk-button uk-button-danger uk-width-1-2">Close</a> <input type="submit" class="uk-button uk-button-primary uk-width-1-2" value="Save"/>
</div> <a href="{{ route() }}index.php/items" type="button" class="uk-button uk-button-danger uk-width-1-2">Close</a>
</div>
{% else %}
<a href="{{ route() }}index.php/items" type="button" class="uk-button uk-button-danger uk-width-1-1">Close</a>
{% endif %}
<div> <div>
<label class="uk-form-label">Title</label> <label class="uk-form-label">Title</label>
<div class="uk-form-controls"> <div class="uk-form-controls">

View File

@ -4,9 +4,11 @@
{% block content %} {% block content %}
<div class="uk-container uk-margin"> <div class="uk-container uk-margin">
<h1 class="uk-article-title">Items</h1> <h1 class="uk-article-title"><span uk-icon="icon: pencil; ratio: 2"></span> Items</h1>
{{ block("messages_queue", "message_queue.twig") }} {{ block("messages_queue", "message_queue.twig") }}
<a class="uk-button uk-button-default" href="{{ route() }}index.php/item?task=create">Create</a> {% if user('access.item.create', false) %}
<a class="uk-button uk-button-default" href="{{ route() }}index.php/item?task=create">Create</a>
{% endif %}
{% if list %} {% if list %}
<table class="uk-table uk-table-justify uk-table-divider"> <table class="uk-table uk-table-justify uk-table-divider">
<thead> <thead>
@ -23,11 +25,17 @@
<tr> <tr>
<td> <td>
<div class="uk-button-group uk-width-1-1"> <div class="uk-button-group uk-width-1-1">
<a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/item?id={{ item.id }}&task=edit">Edit</a> {% if user('access.item.update', false) %}
<button class="uk-button uk-button-default uk-button-small" onclick="confirmDeletion('{{ item.title }}', {{ item.id }});">Delete</button> <a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/item?id={{ item.id }}&task=edit">Edit</a>
{% else %}
<a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/item?id={{ item.id }}&task=edit">Read</a>
{% endif %}
{% if user('access.item.delete', false) %}
<button class="uk-button uk-button-default uk-button-small" onclick="confirmDeletion('{{ item.title|escape('js') }}', {{ item.id }});">Delete</button>
{% endif %}
</div> </div>
</td> </td>
<td>{{ item.title }}</td> <td>{{ item.title|escape('html') }}</td>
<td>{% if item.introtext %}{{ shorten_string(item.introtext|striptags) }} {% endif %}{{ shorten_string(item.fulltext|striptags) }}</td> <td>{% if item.introtext %}{{ shorten_string(item.introtext|striptags) }} {% endif %}{{ shorten_string(item.fulltext|striptags) }}</td>
<td> <td>
{% if item.state == 1 %} {% if item.state == 1 %}
@ -49,10 +57,15 @@
</table> </table>
{% else %} {% else %}
<div class="uk-alert-primary" uk-alert> <div class="uk-alert-primary" uk-alert>
<p>There has no items been found, click create to add some.</p> {% if user('access.item.create', false) %}
<p>There has no items been found, click create to add some.</p>
{% else %}
<p>There has no items been found.</p>
{% endif %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% if user('access.item.delete', false) %}
<script> <script>
function confirmDeletion(title, id){ function confirmDeletion(title, id){
UIkit.modal.confirm('You are about to permanently delete <b>' + title + '</b>?').then(function () { UIkit.modal.confirm('You are about to permanently delete <b>' + title + '</b>?').then(function () {
@ -62,4 +75,5 @@
}); });
} }
</script> </script>
{% endif %}
{% endblock %} {% endblock %}

View File

@ -1,16 +1,25 @@
{% extends "index.twig" %} {% extends "index.twig" %}
{% block title %}Edit Menu{% endblock %} {% block title %}{% if form.id == 0 %}Create{% else %}Edit{% endif %} Menu {{ form.title|default('') }}{% endblock %}
{% block content %} {% block content %}
<div class="uk-container uk-margin"> <div class="uk-container uk-margin">
{{ block("messages_queue", "message_queue.twig") }} {{ block("messages_queue", "message_queue.twig") }}
{% if form.id == 0 %}
<h3><span uk-icon="icon: menu; ratio: 1"></span> Create Menu</h3>
{% else %}
<h3><span uk-icon="icon: menu; ratio: 1"></span> Edit Menu {{ form.title|default('') }}</h3>
{% endif %}
{% if items %} {% if items %}
<form class="uk-form-stacked" action="{{ route() }}index.php/menu{{ form.post_key|default('') }}" method="post"> <form id="menu-admin" class="uk-form-stacked" action="{{ route() }}index.php/menu{{ form.post_key|default('') }}" method="post">
<div class="uk-button-group uk-width-1-1 uk-margin"> {% if user('access.menu.update', false) %}
<input type="submit" class="uk-button uk-button-primary uk-width-1-2" value="Save"/> <div class="uk-button-group uk-width-1-1 uk-margin">
<a href="{{ route() }}index.php/menus" type="button" class="uk-button uk-button-danger uk-width-1-2">Close</a> <input type="submit" class="uk-button uk-button-primary uk-width-1-2" value="Save"/>
</div> <a href="{{ route() }}index.php/menus" type="button" class="uk-button uk-button-danger uk-width-1-2">Close</a>
</div>
{% else %}
<a href="{{ route() }}index.php/menus" type="button" class="uk-button uk-button-danger uk-width-1-1">Close</a>
{% endif %}
<div class="uk-child-width-1-2 uk-margin" uk-grid> <div class="uk-child-width-1-2 uk-margin" uk-grid>
<div> <div>
<label class="uk-form-label">Name (title)</label> <label class="uk-form-label">Name (title)</label>
@ -43,21 +52,35 @@
<div class="uk-form-controls"> <div class="uk-form-controls">
<select name="item_id" class="uk-select"> <select name="item_id" class="uk-select">
{% for item in items %} {% for item in items %}
<option value="{{ item.id }}" {% if item.id == form.id|default(0) %}selected{% endif %}>{{ item.title }}</option> <option value="{{ item.id }}" {% if item.id == form.item_id|default(0) %}selected{% endif %}>{{ item.title }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<a class="uk-button uk-button-default uk-width-1-1" href="{{ route() }}index.php/item?task=create">Create More Items</a>
</div> </div>
<div> <div>
<label class="uk-form-label">Parent</label>
<div class="uk-form-controls">
<select id="parent_id" name="parent_id" class="uk-select" onchange="updatePosition();">
<option value="0" {% if form.parent_id == 0 %}selected{% endif %}>Root</option>
{% if menus %}
{% for menu in menus %}
<option value="{{ menu.id }}" {% if menu.id == form.parent_id|default(0) %}selected{% endif %}>{{ menu.title }}</option>
{% endfor %}
{% endif %}
</select>
</div>
</div>
<div id="home-block">
<label class="uk-form-label">Is this your home page menu item?</label> <label class="uk-form-label">Is this your home page menu item?</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
<select name="home" class="uk-select"> <select id="home" name="home" class="uk-select" onchange="updatePosition();">
<option value="1">Yes</option> <option value="1">Yes</option>
<option value="0" {% if form.home == 0 %}selected{% endif %}>No</option> <option value="0" {% if form.home == 0 %}selected{% endif %}>No</option>
</select> </select>
</div> </div>
</div> </div>
<div> <div id="position-block">
<label class="uk-form-label">Position of this menu item?</label> <label class="uk-form-label">Position of this menu item?</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
<select name="position" class="uk-select"> <select name="position" class="uk-select">
@ -101,6 +124,26 @@
<input type="hidden" name="menu_id" value="{{ form.id|default(0) }}"> <input type="hidden" name="menu_id" value="{{ form.id|default(0) }}">
<input type="hidden" name="{{ token() }}" value="1"> <input type="hidden" name="{{ token() }}" value="1">
</form> </form>
<script type="text/javascript">
function updatePosition(){
// based on the parent selection we hide the position and home option
let parent = document.getElementById('parent_id').value;
if (parent > 0) {
document.getElementById('position-block').style.visibility = 'hidden';
document.getElementById('home-block').style.visibility = 'hidden';
document.getElementById('home').value = 0;
} else {
document.getElementById('position-block').style.visibility = 'visible';
document.getElementById('home-block').style.visibility = 'visible';
// based on the home selection we hide the position
let home = document.getElementById('home').value;
if (home == 1) {
document.getElementById('position-block').style.visibility = 'hidden';
}
}
}
updatePosition();
</script>
{% else %} {% else %}
<a class="uk-button uk-button-default" href="{{ route() }}index.php/item?task=create">Create</a> <a class="uk-button uk-button-default" href="{{ route() }}index.php/item?task=create">Create</a>
<div class="uk-alert-primary" uk-alert> <div class="uk-alert-primary" uk-alert>

View File

@ -4,9 +4,11 @@
{% block content %} {% block content %}
<div class="uk-container uk-margin"> <div class="uk-container uk-margin">
<h1 class="uk-article-title">Menus</h1> <h1 class="uk-article-title"><span uk-icon="icon: menu; ratio: 2"></span> Menus</h1>
{{ block("messages_queue", "message_queue.twig") }} {{ block("messages_queue", "message_queue.twig") }}
<a class="uk-button uk-button-default" href="{{ route() }}index.php/menu?task=create">Create</a> {% if user('access.menu.create', false) %}
<a class="uk-button uk-button-default" href="{{ route() }}index.php/menu?task=create">Create</a>
{% endif %}
{% if list %} {% if list %}
<table class="uk-table uk-table-justify uk-table-divider"> <table class="uk-table uk-table-justify uk-table-divider">
<thead> <thead>
@ -24,17 +26,27 @@
<tr> <tr>
<td> <td>
<div class="uk-button-group uk-width-1-1"> <div class="uk-button-group uk-width-1-1">
<a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/menu?id={{ item.id }}&task=edit">Edit</a> {% if user('access.menu.update', false) %}
<button class="uk-button uk-button-default uk-button-small" onclick="confirmDeletion('{{ item.title }}', {{ item.id }});">Delete</button> <a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/menu?id={{ item.id }}&task=edit">Edit</a>
{% else %}
<a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/menu?id={{ item.id }}&task=edit">Read</a>
{% endif %}
{% if user('access.menu.delete', false) %}
<button class="uk-button uk-button-default uk-button-small" onclick="confirmDeletion('{{ item.title|escape('js') }}', {{ item.id }});">Delete</button>
{% endif %}
</div> </div>
</td> </td>
<td>{% if item.home == 1 %}<span uk-icon="icon: home"></span> {% endif %}{{ item.title }}</td> <td>{% if item.home == 1 %}<span uk-icon="icon: home"></span> {% endif %}{{ item.title|escape('html') }}</td>
<td> <td>
<a class="uk-button uk-button-default uk-button-small uk-width-1-1" href="{{ route() }}index.php/item?id={{ item.item_id }}&task=edit"> {% if user('access.item.update', user('access.item.read', false)) %}
<a class="uk-button uk-button-default uk-button-small uk-width-1-1" href="{{ route() }}index.php/item?id={{ item.item_id }}&task=edit">
{{ shorten_string(item.item_title, 10) }}
</a>
{% else %}
{{ shorten_string(item.item_title, 10) }} {{ shorten_string(item.item_title, 10) }}
</a> {% endif %}
</td> </td>
<td>{{ item.path }}</td> <td>{{ item.path|escape('html') }}</td>
<td> <td>
{% if item.published == 1 %} {% if item.published == 1 %}
<button class="uk-button uk-button-primary uk-button-small uk-width-1-1">Published</button> <button class="uk-button uk-button-primary uk-button-small uk-width-1-1">Published</button>
@ -55,12 +67,18 @@
</table> </table>
{% else %} {% else %}
<div class="uk-alert-primary" uk-alert> <div class="uk-alert-primary" uk-alert>
<p>There has no menus been found, click create to add some.</p> {% if user('access.menu.create', false) %}
<p>There has no menus been found, click create to add some.</p>
{% else %}
<p>There has no menus been found.</p>
{% endif %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% if user('access.menu.delete', false) %}
<script> <script>
function confirmDeletion(title, id){ function confirmDeletion(title, id){
console.log(title);
UIkit.modal.confirm('You are about to permanently delete <b>' + title + '</b>?').then(function () { UIkit.modal.confirm('You are about to permanently delete <b>' + title + '</b>?').then(function () {
window.open("{{ route() }}index.php/menu?id=" + id + "&task=delete", "_self") window.open("{{ route() }}index.php/menu?id=" + id + "&task=delete", "_self")
}, function () { }, function () {
@ -68,4 +86,5 @@
}); });
} }
</script> </script>
{% endif %}
{% endblock %} {% endblock %}

View File

@ -3,13 +3,25 @@
<div class="uk-navbar-left"> <div class="uk-navbar-left">
<ul class="uk-navbar-nav"> <ul class="uk-navbar-nav">
<li><a href="{{ route() }}index.php/dashboard">Dashboard</a></li> <li><a href="{{ route() }}index.php/dashboard">Dashboard</a></li>
<li><a href="{{ route() }}index.php/users">Users</a></li> {% if user('access.user.read', false) %}
<li><a href="{{ route() }}index.php/menus">Menus</a></li> <li><a href="{{ route() }}index.php/users">Users</a></li>
<li><a href="{{ route() }}index.php/items">Items</a></li> {% endif %}
{% if user('access.usergroup.read', false) %}
<li><a href="{{ route() }}index.php/usergroups">User Groups</a></li>
{% endif %}
{% if user('access.menu.read', false) %}
<li><a href="{{ route() }}index.php/menus">Menus</a></li>
{% endif %}
{% if user('access.item.read', false) %}
<li><a href="{{ route() }}index.php/items">Items</a></li>
{% endif %}
</ul> </ul>
</div> </div>
<div class="uk-navbar-right"> <div class="uk-navbar-right">
<ul class="uk-navbar-nav"> <ul class="uk-navbar-nav">
{% if user.id %}
<li class="uk-active"><a href="{{ route() }}index.php/user?id={{ user.id }}">{{ user.name }}</a></li>
{% endif %}
<li class="uk-active"><a href="{{ route() }}index.php/dashboard?task=logout">Logout</a></li> <li class="uk-active"><a href="{{ route() }}index.php/dashboard?task=logout">Logout</a></li>
<li class="uk-active"><a href="/">Site</a></li> <li class="uk-active"><a href="/">Site</a></li>
</ul> </ul>

View File

@ -1,15 +1,24 @@
{% extends "index.twig" %} {% extends "index.twig" %}
{% block title %}Edit User{% endblock %} {% block title %}{% if form.id == 0 %}Create{% else %}Edit{% endif %} User {{ form.name|default('') }}{% endblock %}
{% block content %} {% block content %}
<div class="uk-container uk-margin"> <div class="uk-container uk-margin">
{{ block("messages_queue", "message_queue.twig") }} {{ block("messages_queue", "message_queue.twig") }}
{% if form.id == 0 %}
<h3><span uk-icon="icon: user; ratio: 1"></span> Create User</h3>
{% else %}
<h3><span uk-icon="icon: user; ratio: 1"></span> Edit User {{ form.name|default('') }}</h3>
{% endif %}
<form class="uk-form-stacked" action="{{ route() }}index.php/user{{ form.post_key|default('') }}" method="post"> <form class="uk-form-stacked" action="{{ route() }}index.php/user{{ form.post_key|default('') }}" method="post">
<div class="uk-button-group uk-width-1-1 uk-margin"> {% if user('access.user.update', false) %}
<input type="submit" class="uk-button uk-button-primary uk-width-1-2" value="Save"/> <div class="uk-button-group uk-width-1-1 uk-margin">
<a href="{{ route() }}index.php/users" type="button" class="uk-button uk-button-danger uk-width-1-2">Close</a> <input type="submit" class="uk-button uk-button-primary uk-width-1-2" value="Save"/>
</div> <a href="{{ route() }}index.php/users" type="button" class="uk-button uk-button-danger uk-width-1-2">Close</a>
</div>
{% else %}
<a href="{{ route() }}index.php/users" type="button" class="uk-button uk-button-danger uk-width-1-1">Close</a>
{% endif %}
<div> <div>
<label class="uk-form-label">Name</label> <label class="uk-form-label">Name</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
@ -18,7 +27,7 @@
</div> </div>
<ul class="uk-flex-center" uk-switcher="connect: .switcher-container; animation: uk-animation-slide-left-medium, uk-animation-slide-right-medium" uk-tab> <ul class="uk-flex-center" uk-switcher="connect: .switcher-container; animation: uk-animation-slide-left-medium, uk-animation-slide-right-medium" uk-tab>
<li class="uk-active"><a href="#">Details</a></li> <li class="uk-active"><a href="#">Details</a></li>
<li><a href="#">Activate</a></li> <li><a href="#">Access</a></li>
</ul> </ul>
<ul class="uk-switcher switcher-container uk-margin"> <ul class="uk-switcher switcher-container uk-margin">
<li> <li>
@ -50,8 +59,8 @@
</div> </div>
</li> </li>
<li> <li>
<div> <div class="uk-child-width-1-2 uk-margin" uk-grid>
<div class="uk-width-1-1 uk-margin"> <div>
<label class="uk-form-label">Activation of User Access to System</label> <label class="uk-form-label">Activation of User Access to System</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
<select name="block" class="uk-select"> <select name="block" class="uk-select">
@ -60,6 +69,43 @@
</select> </select>
</div> </div>
</div> </div>
<div>
<label class="uk-form-label">Select the Access Groups</label>
<div class="uk-form-controls">
{% if groups %}
{% for group in groups %}
<label><input class="uk-checkbox" name="groups[]" value="{{ group.id }}" type="checkbox" {% if group.id in form.groups %}checked{% endif %}>
<a href="#modal-{{ item.id }}-{{ group.title|spaceless }}" uk-toggle>{{ group.title|escape('html') }}</a></label><br />
<div id="modal-{{ item.id }}-{{ group.title|spaceless }}" uk-modal>
<div class="uk-modal-dialog uk-modal-body">
<button class="uk-modal-close-default" type="button" uk-close></button>
<div class="uk-modal-header">
<h2 class="uk-modal-title">{{ group.title|escape('html') }} Group</h2>
</div>
<div class="uk-child-width-1-2 uk-margin" uk-grid>
<div>
<b>Area access of this group</b>
<ul class="uk-list uk-list-striped">
<li>{{ group.params|map( param => "<b>#{param.area|upper}</b>: #{param.access|default('N')}" )|join('</li><li>')|raw }}</li>
</ul>
</div>
<div>
<b>Access key map</b>
<ul class="uk-list">
<li>C = Create</li>
<li>R = Read</li>
<li>U = Update</li>
<li>D = Delete</li>
<li>N = No-Access</li>
</ul>
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>
</div> </div>
</li> </li>
</ul> </ul>

View File

@ -0,0 +1,46 @@
{% extends "index.twig" %}
{% block title %}{% if form.id == 0 %}Create{% else %}Edit {% endif %}{{ form.title|default('') }} User Group{% endblock %}
{% block content %}
<div class="uk-container uk-margin">
{{ block("messages_queue", "message_queue.twig") }}
{% if form.id == 0 %}
<h3><span uk-icon="icon: users; ratio: 1"></span> Create User Group</h3>
{% else %}
<h3><span uk-icon="icon: users; ratio: 1"></span> Edit {{ form.title|default('') }} User Group</h3>
{% endif %}
<form class="uk-form-stacked" action="{{ route() }}index.php/usergroup{{ form.post_key|default('') }}" method="post">
{% if user('access.usergroup.update', false) %}
<div class="uk-button-group uk-width-1-1 uk-margin">
<input type="submit" class="uk-button uk-button-primary uk-width-1-2" value="Save"/>
<a href="{{ route() }}index.php/usergroups" type="button" class="uk-button uk-button-danger uk-width-1-2">Close</a>
</div>
{% else %}
<a href="{{ route() }}index.php/usergroups" type="button" class="uk-button uk-button-danger uk-width-1-1">Close</a>
{% endif %}
<div>
<label class="uk-form-label">User Group Name</label>
<div class="uk-form-controls">
<input name="title" class="uk-input uk-width-1-1" type="text" placeholder="Add Group Name" value="{{ form.title|default('') }}">
</div>
</div>
<h3>C = Create | R = Read | U = Update | D = Delete</h3>
<small>Use these keys in this order, or <b>empty</b> for no access, or <b>CRUD</b> for full access, or <b>C</b> for just create, or <b>RU</b> for just read and update. Select any pre/area, have fun!</small>
<div class="uk-child-width-1-2 uk-margin" uk-grid>
{% if form.params %}
{% for params in form.params %}
<div>
<label class="uk-form-label">{{ params.area|escape('html')|upper }} AREA</label>
<div class="uk-form-controls">
<input name="params[{{ params.area }}]" class="uk-input uk-width-1-1" type="text" placeholder="CRUD" value="{{ params.access|default('')|upper }}">
</div>
</div>
{% endfor %}
{% endif %}
</div>
<input type="hidden" name="usergroup_id" value="{{ form.id|default(0) }}">
<input type="hidden" name="{{ token() }}" value="1">
</form>
</div>
{% endblock %}

View File

@ -0,0 +1,82 @@
{% extends "index.twig" %}
{% block title %}User Groups{% endblock %}
{% block content %}
<div class="uk-container uk-margin">
<h1 class="uk-article-title"><span uk-icon="icon: users; ratio: 2"></span> User Groups</h1>
{{ block("messages_queue", "message_queue.twig") }}
{% if user('access.usergroup.create', false) %}
<a class="uk-button uk-button-default" href="{{ route() }}index.php/usergroup?task=create">Create</a>
{% endif %}
{% if list %}
<table class="uk-table uk-table-justify uk-table-divider">
<thead>
<tr>
<th class="uk-width-small">Action</th>
<th>Group Name</th>
<th>ID</th>
</tr>
</thead>
<tbody>
{% for item in list %}
<tr>
<td>
<div class="uk-button-group uk-width-1-1">
{% if user('access.usergroup.update', false) %}
<a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/usergroup?id={{ item.id }}&task=edit">{% if item.id == 1 %}Read{% else %}Edit{% endif %}</a>
{% else %}
<a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/usergroup?id={{ item.id }}&task=edit">Read</a>
{% endif %}
{% if user('access.usergroup.delete', false) %}
{% if item.id != 1 %}
<button class="uk-button uk-button-default uk-button-small" onclick="confirmDeletion('{{ item.title|escape('js') }}', {{ item.id }});">Delete</button>
{% endif %}
{% endif %}
</div>
</td>
<td>
{% if item.params %}
<ul uk-accordion>
<li>
<a class="uk-accordion-title" href="#">{{ item.title|escape('html') }}</a>
<div class="uk-accordion-content">
<ul class="uk-list">
{% for areas in item.params %}
<li><span uk-icon="icon: chevron-double-right"></span> {{ areas.area|upper }}: <b>{{ areas.access|default('N') }}</b></li>
{% endfor %}
</ul>
</div>
</li>
</ul>
{% else %}
{{ item.title|escape('html') }}
{% endif %}
</td>
<td>{{ item.id }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="uk-alert-primary" uk-alert>
{% if user('access.usergroup.create', false) %}
<p>There has no user groups been found, click create to add some.</p>
{% else %}
<p>There has no user groups been found.</p>
{% endif %}
</div>
{% endif %}
</div>
{% if user('access.usergroup.delete', false) %}
<script>
function confirmDeletion(name, id){
UIkit.modal.confirm('You are about to permanently delete <b>' + name + '</b>?').then(function () {
window.open("{{ route() }}index.php/usergroup?id=" + id + "&task=delete", "_self")
}, function () {
// we do nothing ;)
});
}
</script>
{% endif %}
{% endblock %}

View File

@ -4,9 +4,11 @@
{% block content %} {% block content %}
<div class="uk-container uk-margin"> <div class="uk-container uk-margin">
<h1 class="uk-article-title">Users</h1> <h1 class="uk-article-title"><span uk-icon="icon: user; ratio: 2"></span> Users</h1>
{{ block("messages_queue", "message_queue.twig") }} {{ block("messages_queue", "message_queue.twig") }}
<a class="uk-button uk-button-default" href="{{ route() }}index.php/user?task=create">Create</a> {% if user('access.user.create', false) %}
<a class="uk-button uk-button-default" href="{{ route() }}index.php/user?task=create">Create</a>
{% endif %}
{% if list %} {% if list %}
<table class="uk-table uk-table-justify uk-table-divider"> <table class="uk-table uk-table-justify uk-table-divider">
<thead> <thead>
@ -14,6 +16,7 @@
<th class="uk-width-small">Action</th> <th class="uk-width-small">Action</th>
<th>Name</th> <th>Name</th>
<th class="uk-width-small">Email</th> <th class="uk-width-small">Email</th>
<th>Groups</th>
<th class="uk-width-small">State</th> <th class="uk-width-small">State</th>
<th>ID</th> <th>ID</th>
</tr> </tr>
@ -23,12 +26,56 @@
<tr> <tr>
<td> <td>
<div class="uk-button-group uk-width-1-1"> <div class="uk-button-group uk-width-1-1">
<a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/user?id={{ item.id }}&task=edit">Edit</a> {% if user('access.user.update', false) %}
<button class="uk-button uk-button-default uk-button-small" onclick="confirmDeletion('{{ item.name }}', {{ item.id }});">Delete</button> <a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/user?id={{ item.id }}&task=edit">Edit</a>
{% else %}
<a class="uk-button uk-button-default uk-button-small" href="{{ route() }}index.php/user?id={{ item.id }}&task=edit">Read</a>
{% endif %}
{% if user('access.user.delete', false) %}
<button class="uk-button uk-button-default uk-button-small" onclick="confirmDeletion('{{ item.name|escape('js') }}', {{ item.id }});">Delete</button>
{% endif %}
</div> </div>
</td> </td>
<td>{{ item.name }}</td> <td>{{ item.name|escape('html') }}<br /><small>username: {{ item.username|escape('html') }}</small></td>
<td>{{ item.email }}</td> <td>{{ item.email|escape('html') }}</td>
<td>{% if item.groups %}
<ul class="uk-list uk-list-collapse">
{% for group in item.groups %}
<li>
<a href="#modal-{{ item.id }}-{{ group.title|spaceless }}" uk-toggle>{{ group.title|escape('html') }}</a>
<div id="modal-{{ item.id }}-{{ group.title|spaceless }}" uk-modal>
<div class="uk-modal-dialog uk-modal-body">
<button class="uk-modal-close-default" type="button" uk-close></button>
<div class="uk-modal-header">
<h2 class="uk-modal-title">{{ group.title|escape('html') }} Group</h2>
</div>
<div class="uk-child-width-1-2 uk-margin" uk-grid>
<div>
<b>Area access of this group</b>
<ul class="uk-list uk-list-striped">
<li>{{ group.params|map( param => "<b>#{param.area|upper}</b>: #{param.access|default('N')}" )|join('</li><li>')|raw }}</li>
</ul>
</div>
<div>
<b>Access key map</b>
<ul class="uk-list">
<li>C = Create</li>
<li>R = Read</li>
<li>U = Update</li>
<li>D = Delete</li>
<li>N = No-Access</li>
</ul>
</div>
</div>
</div>
</div>
</li>
{% endfor %}
</ul>
{% else %}
None set
{% endif %}
</td>
<td> <td>
{% if item.block == 0 %} {% if item.block == 0 %}
<button class="uk-button uk-button-primary uk-button-small uk-width-1-1">Active</button> <button class="uk-button uk-button-primary uk-button-small uk-width-1-1">Active</button>
@ -43,10 +90,15 @@
</table> </table>
{% else %} {% else %}
<div class="uk-alert-primary" uk-alert> <div class="uk-alert-primary" uk-alert>
<p>There has no items been found, click create to add some.</p> {% if user('access.user.create', false) %}
<p>There has no users been found, click create to add some. (this should never happen!!!)</p>
{% else %}
<p>There has no users been found. (this should never happen!!!)</p>
{% endif %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% if user('access.user.delete', false) %}
<script> <script>
function confirmDeletion(name, id){ function confirmDeletion(name, id){
UIkit.modal.confirm('You are about to permanently delete <b>' + name + '</b>?').then(function () { UIkit.modal.confirm('You are about to permanently delete <b>' + name + '</b>?').then(function () {
@ -56,4 +108,5 @@
}); });
} }
</script> </script>
{% endif %}
{% endblock %} {% endblock %}

View File

@ -1,10 +0,0 @@
{% extends "index.twig" %}
{% block content %}
<div class="uk-margin-remove-top uk-height-large uk-background-cover uk-overflow-hidden uk-flex" style="background-image: url('https://source.unsplash.com/random/1920x500/?yachts');">
<div class="uk-width-1-2@m uk-text-center uk-margin-auto uk-margin-auto-vertical uk-overlay uk-overlay-default">
<h1>Octoleo CMS</h1>
<p>There has no home page been created for this CMS. Please come again soon...</p>
</div>
</div>
{% endblock %}

View File

@ -1,23 +1,132 @@
{% block bodyNavigation %} {% block bodyNavigation %}
{% set center = false %} {% set center = false %}
{% set right = false %} {% set right = false %}
{% if main_menu %} {% if menus %}
{% for menu in main_menu %} {% for menu in menus %}
{% if menu.root and menu.position == 'center' %} {% if menu.parent == 0 and menu.position == 'center' %}
{% set center = true %} {% set center = true %}
{% elseif menu.root and menu.position == 'right' %} {% elseif menu.parent == 0 and menu.position == 'right' %}
{% set right = true %} {% set right = true %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
<nav class="uk-navbar-container" uk-navbar> {% if center and right %}
<div class="uk-position-relative">
{% endif %}
<nav class="uk-navbar-container" uk-navbar{% if center and right %}="dropbar: true"{% endif %}>
<div class="uk-navbar-center"> <div class="uk-navbar-center">
<ul class="uk-navbar-nav"> <ul class="uk-navbar-nav">
<li class="uk-active"><a href="{{ route() }}">Home</a></li> <li{% if home %} class="uk-active"{% endif %}><a href="{{ route() }}">{{ home_menu_title|default('Home') }}</a></li>
{% if center %} {% if center %}
{% for menu in main_menu %} {% for menu in menus %}
{% if menu.root and menu.position == 'center' %} {% if menu.parent == 0 and menu.position == 'center' %}
<li><a href="{{ route() }}{{ menu.path }}">{{ menu.title }}</a></li> <li{% if menu_active == menu.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu.path }}">{{ menu.title|escape('html') }}</a>
{% set load_menu_one = false %}
{% for menu_one in menus %}
{% if menu_one.parent == menu.id %}
{% set load_menu_one = true %}
{% endif %}
{% endfor %}
{% if load_menu_one %}
<div class="uk-navbar-dropdown">
<ul class="uk-nav uk-navbar-dropdown-nav">
{% for menu_one in menus %}
{% if menu_one.parent == menu.id %}
<li{% if menu_active == menu_one.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_one.path }}">{{ menu_one.title|escape('html') }}</a>
{% set load_menu_two = false %}
{% for menu_two in menus %}
{% if menu_two.parent == menu_one.id %}
{% set load_menu_two = true %}
{% endif %}
{% endfor %}
{% if load_menu_two %}
<ul class="uk-nav-sub">
{% for menu_two in menus %}
{% if menu_two.parent == menu_one.id %}
<li{% if menu_active == menu_two.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_two.path }}">{{ menu_two.title|escape('html') }}</a>
{% set load_menu_three = false %}
{% for menu_three in menus %}
{% if menu_three.parent == menu_two.id %}
{% set load_menu_three = true %}
{% endif %}
{% endfor %}
{% if load_menu_three %}
<ul class="uk-nav-sub">
{% for menu_three in menus %}
{% if menu_three.parent == menu_two.id %}
<li{% if menu_active == menu_three.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_three.path }}">{{ menu_three.title|escape('html') }}</a>
{% set load_menu_four = false %}
{% for menu_four in menus %}
{% if menu_four.parent == menu_three.id %}
{% set load_menu_four = true %}
{% endif %}
{% endfor %}
{% if load_menu_four %}
<ul class="uk-nav-sub">
{% for menu_four in menus %}
{% if menu_four.parent == menu_three.id %}
<li{% if menu_active == menu_four.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_four.path }}">{{ menu_four.title|escape('html') }}</a>
{% set load_menu_five = false %}
{% for menu_five in menus %}
{% if menu_five.parent == menu_four.id %}
{% set load_menu_five = true %}
{% endif %}
{% endfor %}
{% if load_menu_five %}
<ul class="uk-nav-sub">
{% for menu_five in menus %}
{% if menu_five.parent == menu_four.id %}
<li{% if menu_active == menu_five.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_five.path }}">{{ menu_five.title|escape('html') }}</a>
{% set load_menu_six = false %}
{% for menu_six in menus %}
{% if menu_six.parent == menu_five.id %}
{% set load_menu_six = true %}
{% endif %}
{% endfor %}
{% if load_menu_six %}
<ul class="uk-nav-sub">
{% for menu_six in menus %}
{% if menu_six.parent == menu_five.id %}
<li{% if menu_active == menu_six.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_six.path }}">{{ menu_six.title|escape('html') }}</a>
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endif %}
</li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
@ -27,9 +136,115 @@
<div class="uk-navbar-right"> <div class="uk-navbar-right">
<ul class="uk-navbar-nav"> <ul class="uk-navbar-nav">
{% if right %} {% if right %}
{% for menu in main_menu %} {% for menu in menus %}
{% if menu.root and menu.position == 'right' %} {% if menu.parent == 0 and menu.position == 'right' %}
<li><a href="{{ route() }}{{ menu.path }}">{{ menu.title }}</a></li> <li{% if menu_active == menu.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu.path }}">{{ menu.title|escape('html') }}</a>
{% set load_menu_one = false %}
{% for menu_one in menus %}
{% if menu_one.parent == menu.id %}
{% set load_menu_one = true %}
{% endif %}
{% endfor %}
{% if load_menu_one %}
<div class="uk-navbar-dropdown">
<ul class="uk-nav uk-navbar-dropdown-nav">
{% for menu_one in menus %}
{% if menu_one.parent == menu.id %}
<li{% if menu_active == menu_one.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_one.path }}">{{ menu_one.title|escape('html') }}</a>
{% set load_menu_two = false %}
{% for menu_two in menus %}
{% if menu_two.parent == menu_one.id %}
{% set load_menu_two = true %}
{% endif %}
{% endfor %}
{% if load_menu_two %}
<ul class="uk-nav-sub">
{% for menu_two in menus %}
{% if menu_two.parent == menu_one.id %}
<li{% if menu_active == menu_two.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_two.path }}">{{ menu_two.title|escape('html') }}</a>
{% set load_menu_three = false %}
{% for menu_three in menus %}
{% if menu_three.parent == menu_two.id %}
{% set load_menu_three = true %}
{% endif %}
{% endfor %}
{% if load_menu_three %}
<ul class="uk-nav-sub">
{% for menu_three in menus %}
{% if menu_three.parent == menu_two.id %}
<li{% if menu_active == menu_three.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_three.path }}">{{ menu_three.title|escape('html') }}</a>
{% set load_menu_four = false %}
{% for menu_four in menus %}
{% if menu_four.parent == menu_three.id %}
{% set load_menu_four = true %}
{% endif %}
{% endfor %}
{% if load_menu_four %}
<ul class="uk-nav-sub">
{% for menu_four in menus %}
{% if menu_four.parent == menu_three.id %}
<li{% if menu_active == menu_four.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_four.path }}">{{ menu_four.title|escape('html') }}</a>
{% set load_menu_five = false %}
{% for menu_five in menus %}
{% if menu_five.parent == menu_four.id %}
{% set load_menu_five = true %}
{% endif %}
{% endfor %}
{% if load_menu_five %}
<ul class="uk-nav-sub">
{% for menu_five in menus %}
{% if menu_five.parent == menu_four.id %}
<li{% if menu_active == menu_five.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_five.path }}">{{ menu_five.title|escape('html') }}</a>
{% set load_menu_six = false %}
{% for menu_six in menus %}
{% if menu_six.parent == menu_five.id %}
{% set load_menu_six = true %}
{% endif %}
{% endfor %}
{% if load_menu_six %}
<ul class="uk-nav-sub">
{% for menu_six in menus %}
{% if menu_six.parent == menu_five.id %}
<li{% if menu_active == menu_six.id %} class="uk-active"{% endif %}>
<a href="{{ route() }}{{ menu_six.path }}">{{ menu_six.title|escape('html') }}</a>
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endif %}
</li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
@ -37,4 +252,7 @@
</div> </div>
{% endif %} {% endif %}
</nav> </nav>
{% if center and right %}
</div>
{% endif %}
{% endblock %} {% endblock %}

View File

@ -1,14 +1,19 @@
{% extends "index.twig" %} {% extends "index.twig" %}
{% block title %}{{ title|escape('html') }}{% endblock %}
{% block content %} {% block content %}
{% if body == '' %}
<div class="uk-container uk-margin">
<h2>We Couldn't Find It</h2>
<p class="lead">Sorry, we couldn't find the page matching your request. Try using the navigation to find what you were looking for?</p>
</div>
{% else %}
<div class="uk-margin-remove-top uk-background-cover uk-flex" style="background-image: url('https://source.unsplash.com/random/1920x500/?yachts');"> <div class="uk-margin-remove-top uk-background-cover uk-flex" style="background-image: url('https://source.unsplash.com/random/1920x500/?yachts');">
<div class="uk-width-1-2@m uk-text-center uk-margin-auto uk-margin-auto-vertical uk-overlay uk-overlay-default"> <div class="uk-width-1-2@m uk-text-center uk-margin-auto uk-margin-auto-vertical uk-overlay uk-overlay-default">
<h1>{{ title }}</h1> <h1>{{ title|escape('html') }}</h1>
{% if body == '' %}
<p>We have an error!</p>
{% else %}
{{ body|raw }} {{ body|raw }}
{% endif %}
</div> </div>
</div> </div>
{% endif %}
{% endblock %} {% endblock %}