453 lines
14 KiB
PHP
453 lines
14 KiB
PHP
<?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 Exception;
|
|
use Joomla\Application\AbstractApplication;
|
|
use Joomla\Controller\AbstractController;
|
|
use Joomla\Input\Input;
|
|
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\Model\UserModel;
|
|
use Octoleo\CMS\User\User;
|
|
use Octoleo\CMS\User\UserFactoryInterface;
|
|
use Octoleo\CMS\View\Admin\UserHtmlView;
|
|
|
|
/**
|
|
* Controller handling the requests
|
|
*
|
|
* @method \Octoleo\CMS\Application\AdminApplication getApplication() Get the application object.
|
|
* @property-read \Octoleo\CMS\Application\AdminApplication $app Application object
|
|
*/
|
|
class UserController extends AbstractController implements AccessInterface, CheckTokenInterface
|
|
{
|
|
use AccessTrait, CheckTokenTrait;
|
|
|
|
/**
|
|
* The view object.
|
|
*
|
|
* @var UserHtmlView
|
|
*/
|
|
private $view;
|
|
|
|
/**
|
|
* The model object.
|
|
*
|
|
* @var UserModel
|
|
*/
|
|
private $model;
|
|
|
|
/**
|
|
* @var BCryptHandler
|
|
*/
|
|
private $secure;
|
|
|
|
/**
|
|
* @var User
|
|
*/
|
|
private $user;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param UserModel $model The model object.
|
|
* @param UserHtmlView $view The view object.
|
|
* @param Input|null $input The input object.
|
|
* @param User|null $user The current user.
|
|
* @param AbstractApplication|null $app The application object.
|
|
*/
|
|
public function __construct(
|
|
UserModel $model,
|
|
UserHtmlView $view,
|
|
Input $input = null,
|
|
AbstractApplication $app = null,
|
|
User $user = null,
|
|
BCryptHandler $secure = null)
|
|
{
|
|
parent::__construct($input, $app);
|
|
|
|
$this->model = $model;
|
|
$this->view = $view;
|
|
$this->user = ($user) ?: Factory::getContainer()->get(UserFactoryInterface::class)->getUser();
|
|
$this->secure = ($secure) ?: new BCryptHandler();
|
|
}
|
|
|
|
/**
|
|
* Execute the controller.
|
|
*
|
|
* @return boolean
|
|
* @throws Exception
|
|
*/
|
|
public function execute(): bool
|
|
{
|
|
// Do not Enable browser caching
|
|
$this->getApplication()->allowCache(false);
|
|
|
|
$method = $this->getInput()->getMethod();
|
|
$task = $this->getInput()->getString('task', '');
|
|
$id = $this->getInput()->getInt('id', 0);
|
|
|
|
// if task is delete
|
|
if ('delete' === $task)
|
|
{
|
|
// check that the user does not delete him/her self
|
|
if ($this->allow('user') && $this->user->get('access.user.delete', false))
|
|
{
|
|
// get the current user being deleted
|
|
/** @var \Octoleo\CMS\User\User $userBeingDeleted */
|
|
$userBeingDeleted = Factory::getContainer()->get(UserFactoryInterface::class)->getUser($id);
|
|
// get the current active user ID
|
|
$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
|
|
{
|
|
$this->getApplication()->enqueueMessage('You do not have permission to delete this user!', 'error');
|
|
}
|
|
// go to set page
|
|
$this->_redirect('users');
|
|
|
|
return true;
|
|
}
|
|
|
|
// set the current user ID
|
|
$user_id = $this->user->get('id', -1);
|
|
|
|
if ('POST' === $method)
|
|
{
|
|
// 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');
|
|
}
|
|
}
|
|
}
|
|
|
|
// check permissions
|
|
$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
|
|
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()));
|
|
}
|
|
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
|
|
$this->_redirect('users');
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Set an item
|
|
*
|
|
* @param array $tempItem
|
|
*
|
|
* @return int
|
|
* @throws Exception
|
|
*/
|
|
protected function setItem(array $tempItem): int
|
|
{
|
|
$can_save = true;
|
|
// check that we have a name
|
|
if (empty($tempItem['name']))
|
|
{
|
|
// we show an error message
|
|
$tempItem['name'] = '';
|
|
$this->getApplication()->enqueueMessage('Name field is required.', 'error');
|
|
$can_save = false;
|
|
}
|
|
// check that we have a username
|
|
if (empty($tempItem['username']))
|
|
{
|
|
// we show an error message
|
|
$tempItem['username'] = '';
|
|
$this->getApplication()->enqueueMessage('Username field is required.', 'error');
|
|
$can_save = false;
|
|
}
|
|
// check that we have an email TODO: check that we have a valid email
|
|
if (empty($tempItem['email']))
|
|
{
|
|
// we show an error message
|
|
$tempItem['email'] = '';
|
|
$this->getApplication()->enqueueMessage('Email field is required.', 'error');
|
|
$can_save = false;
|
|
}
|
|
// check passwords
|
|
if (isset($tempItem['password2']) && $tempItem['password'] != $tempItem['password2'])
|
|
{
|
|
// we show an error message
|
|
$tempItem['password'] = 'xxxxxxxxxx';
|
|
$tempItem['password2'] = 'xxxxxxxxxx';
|
|
$this->getApplication()->enqueueMessage('Passwords do not match.', 'error');
|
|
$can_save = false;
|
|
}
|
|
unset ($tempItem['password2']);
|
|
// do not set password that has not changed
|
|
if ($tempItem['password'] === 'xxxxxxxxxx')
|
|
{
|
|
if ($tempItem['id'] == 0)
|
|
{
|
|
// we show an error message
|
|
$tempItem['password'] = 'xxxxxxxxxx';
|
|
$tempItem['password2'] = 'xxxxxxxxxx';
|
|
$this->getApplication()->enqueueMessage('Passwords not set.', 'error');
|
|
$can_save = false;
|
|
}
|
|
else
|
|
{
|
|
$tempItem['password'] = '';
|
|
}
|
|
}
|
|
elseif (strlen($tempItem['password']) < 7)
|
|
{
|
|
// we show an error message
|
|
$tempItem['password'] = 'xxxxxxxxxx';
|
|
$tempItem['password2'] = 'xxxxxxxxxx';
|
|
$this->getApplication()->enqueueMessage('Passwords must be longer than 6 characters.', 'error');
|
|
$can_save = false;
|
|
}
|
|
else
|
|
{
|
|
// hash the password
|
|
$tempItem['password'] = $this->secure->hashPassword($tempItem['password']);
|
|
}
|
|
|
|
// can we save the item
|
|
if ($can_save)
|
|
{
|
|
// check that the user does not block him/her self
|
|
$user_id = $this->user->get('id', -1);
|
|
$block_status = $tempItem['block'];
|
|
// this user is the current user
|
|
if ($user_id == $tempItem['id'])
|
|
{
|
|
// don't allow user to block self
|
|
if ($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;
|
|
}
|
|
}
|
|
}
|
|
|
|
// can we save the item
|
|
if ($can_save)
|
|
{
|
|
// check that the user will have some groups left
|
|
if (!is_array($tempItem['groups']) || count($tempItem['groups']) == 0)
|
|
{
|
|
// we show a warning message
|
|
$this->getApplication()->enqueueMessage('You must select at least one group.', 'warning');
|
|
// this user is the current user
|
|
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
|
|
$this->model->tempItem = $tempItem;
|
|
|
|
return $tempItem['id'];
|
|
}
|
|
}
|