2568 lines
90 KiB
PHP
2568 lines
90 KiB
PHP
|
|
<?php
|
||
|
|
/*
|
||
|
|
* Copyright (C) 2025 Xibo Signage Ltd
|
||
|
|
*
|
||
|
|
* Xibo - Digital Signage - https://xibosignage.com
|
||
|
|
*
|
||
|
|
* This file is part of Xibo.
|
||
|
|
*
|
||
|
|
* Xibo is free software: you can redistribute it and/or modify
|
||
|
|
* it under the terms of the GNU Affero General Public License as published by
|
||
|
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
|
* any later version.
|
||
|
|
*
|
||
|
|
* Xibo is distributed in the hope that it will be useful,
|
||
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
* GNU Affero General Public License for more details.
|
||
|
|
*
|
||
|
|
* You should have received a copy of the GNU Affero General Public License
|
||
|
|
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
*/
|
||
|
|
namespace Xibo\Controller;
|
||
|
|
|
||
|
|
use RobThree\Auth\TwoFactorAuth;
|
||
|
|
use Slim\Http\Response as Response;
|
||
|
|
use Slim\Http\ServerRequest as Request;
|
||
|
|
use Xibo\Entity\Permission;
|
||
|
|
use Xibo\Event\LayoutOwnerChangeEvent;
|
||
|
|
use Xibo\Event\LayoutSharingChangeEvent;
|
||
|
|
use Xibo\Event\ParsePermissionEntityEvent;
|
||
|
|
use Xibo\Event\UserDeleteEvent;
|
||
|
|
use Xibo\Factory\ApplicationFactory;
|
||
|
|
use Xibo\Factory\PermissionFactory;
|
||
|
|
use Xibo\Factory\SessionFactory;
|
||
|
|
use Xibo\Factory\UserFactory;
|
||
|
|
use Xibo\Factory\UserGroupFactory;
|
||
|
|
use Xibo\Factory\UserTypeFactory;
|
||
|
|
use Xibo\Helper\ByteFormatter;
|
||
|
|
use Xibo\Helper\QuickChartQRProvider;
|
||
|
|
use Xibo\Helper\Random;
|
||
|
|
use Xibo\Service\MediaService;
|
||
|
|
use Xibo\Support\Exception\AccessDeniedException;
|
||
|
|
use Xibo\Support\Exception\ConfigurationException;
|
||
|
|
use Xibo\Support\Exception\GeneralException;
|
||
|
|
use Xibo\Support\Exception\InvalidArgumentException;
|
||
|
|
use Xibo\Support\Exception\NotFoundException;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Class User
|
||
|
|
* @package Xibo\Controller
|
||
|
|
*/
|
||
|
|
class User extends Base
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* @var UserFactory
|
||
|
|
*/
|
||
|
|
private $userFactory;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @var UserTypeFactory
|
||
|
|
*/
|
||
|
|
private $userTypeFactory;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @var UserGroupFactory
|
||
|
|
*/
|
||
|
|
private $userGroupFactory;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @var PermissionFactory
|
||
|
|
*/
|
||
|
|
private $permissionFactory;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @var ApplicationFactory
|
||
|
|
*/
|
||
|
|
private $applicationFactory;
|
||
|
|
|
||
|
|
/** @var SessionFactory */
|
||
|
|
private $sessionFactory;
|
||
|
|
|
||
|
|
/** @var MediaService */
|
||
|
|
private $mediaService;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set common dependencies.
|
||
|
|
* @param UserFactory $userFactory
|
||
|
|
* @param UserTypeFactory $userTypeFactory
|
||
|
|
* @param UserGroupFactory $userGroupFactory
|
||
|
|
* @param PermissionFactory $permissionFactory
|
||
|
|
* @param ApplicationFactory $applicationFactory
|
||
|
|
* @param SessionFactory $sessionFactory
|
||
|
|
* @param MediaService $mediaService
|
||
|
|
*/
|
||
|
|
public function __construct(
|
||
|
|
$userFactory,
|
||
|
|
$userTypeFactory,
|
||
|
|
$userGroupFactory,
|
||
|
|
$permissionFactory,
|
||
|
|
$applicationFactory,
|
||
|
|
$sessionFactory,
|
||
|
|
MediaService $mediaService
|
||
|
|
) {
|
||
|
|
$this->userFactory = $userFactory;
|
||
|
|
$this->userTypeFactory = $userTypeFactory;
|
||
|
|
$this->userGroupFactory = $userGroupFactory;
|
||
|
|
$this->permissionFactory = $permissionFactory;
|
||
|
|
$this->applicationFactory = $applicationFactory;
|
||
|
|
$this->sessionFactory = $sessionFactory;
|
||
|
|
$this->mediaService = $mediaService;
|
||
|
|
}
|
||
|
|
|
||
|
|
private function getMediaService(\Xibo\Entity\User $user): MediaService
|
||
|
|
{
|
||
|
|
$this->mediaService->setUser($user);
|
||
|
|
return $this->mediaService;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Home Page
|
||
|
|
* this redirects to the appropriate page for this user.
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws \Xibo\Support\Exception\GeneralException
|
||
|
|
*/
|
||
|
|
public function home(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
// Should we show this user the welcome page?
|
||
|
|
if ($this->getUser()->newUserWizard == 0) {
|
||
|
|
return $response->withRedirect($this->urlFor($request, 'welcome.view'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// User wizard seen, go to home page
|
||
|
|
$this->getLog()->debug('Showing the homepage: ' . $this->getUser()->homePageId);
|
||
|
|
|
||
|
|
try {
|
||
|
|
$homepage = $this->userGroupFactory->getHomepageByName($this->getUser()->homePageId);
|
||
|
|
} catch (NotFoundException $exception) {
|
||
|
|
return $response->withRedirect($this->urlFor($request, 'icondashboard.view'));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!$this->getUser()->featureEnabled($homepage->feature)) {
|
||
|
|
return $response->withRedirect($this->urlFor($request, 'icondashboard.view'));
|
||
|
|
} else {
|
||
|
|
return $response->withRedirect($this->urlFor($request, $homepage->homepage));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Welcome Page
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
*/
|
||
|
|
public function welcome(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$this->getState()->template = 'welcome-page';
|
||
|
|
|
||
|
|
// Mark the page as seen
|
||
|
|
if ($this->getUser()->newUserWizard == 0) {
|
||
|
|
$this->getUser()->newUserWizard = 1;
|
||
|
|
$this->getUser()->save(['validate' => false]);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Controls which pages are to be displayed
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
function displayPage(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$this->getState()->template = 'user-page';
|
||
|
|
$this->getState()->setData([
|
||
|
|
'userTypes' => $this->userTypeFactory->query()
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Me
|
||
|
|
*
|
||
|
|
* @SWG\Get(
|
||
|
|
* path="/user/me",
|
||
|
|
* operationId="userMe",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="Get Me",
|
||
|
|
* description="Get my details",
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=200,
|
||
|
|
* description="successful operation",
|
||
|
|
* @SWG\Schema(ref="#/definitions/User")
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
*/
|
||
|
|
public function myDetails(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'httpStatus' => 200,
|
||
|
|
'data' => $this->getUser()
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Prints the user information in a table based on a check box selection
|
||
|
|
*
|
||
|
|
* @SWG\Get(
|
||
|
|
* path="/user",
|
||
|
|
* operationId="userSearch",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="User Search",
|
||
|
|
* description="Search users",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="userId",
|
||
|
|
* in="query",
|
||
|
|
* description="Filter by User Id",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="userName",
|
||
|
|
* in="query",
|
||
|
|
* description="Filter by User Name",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="userTypeId",
|
||
|
|
* in="query",
|
||
|
|
* description="Filter by UserType Id",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="retired",
|
||
|
|
* in="query",
|
||
|
|
* description="Filter by Retired",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=200,
|
||
|
|
* description="successful operation",
|
||
|
|
* @SWG\Schema(
|
||
|
|
* type="array",
|
||
|
|
* @SWG\Items(ref="#/definitions/User")
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
*/
|
||
|
|
function grid(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getQueryParams());
|
||
|
|
|
||
|
|
// Filter our users?
|
||
|
|
$filterBy = [
|
||
|
|
'userId' => $sanitizedParams->getInt('userId'),
|
||
|
|
'userTypeId' => $sanitizedParams->getInt('userTypeId'),
|
||
|
|
'userName' => $sanitizedParams->getString('userName'),
|
||
|
|
'firstName' => $sanitizedParams->getString('firstName'),
|
||
|
|
'lastName' => $sanitizedParams->getString('lastName'),
|
||
|
|
'useRegexForName' => $sanitizedParams->getCheckbox('useRegexForName'),
|
||
|
|
'retired' => $sanitizedParams->getInt('retired'),
|
||
|
|
'logicalOperatorName' => $sanitizedParams->getString('logicalOperatorName'),
|
||
|
|
'userGroupIdMembers' => $sanitizedParams->getInt('userGroupIdMembers'),
|
||
|
|
];
|
||
|
|
|
||
|
|
// Load results into an array
|
||
|
|
$users = $this->userFactory->query($this->gridRenderSort($sanitizedParams), $this->gridRenderFilter($filterBy, $sanitizedParams));
|
||
|
|
|
||
|
|
foreach ($users as $user) {
|
||
|
|
/* @var \Xibo\Entity\User $user */
|
||
|
|
|
||
|
|
$user->setUnmatchedProperty('libraryQuotaFormatted', ByteFormatter::format($user->libraryQuota * 1024));
|
||
|
|
|
||
|
|
$user->loggedIn = $this->sessionFactory->getActiveSessionsForUser($user->userId);
|
||
|
|
$this->getLog()->debug('Logged in status for user ID ' . $user->userId . ' with name ' . $user->userName . ' is ' . $user->loggedIn);
|
||
|
|
|
||
|
|
// Set some text for the display status
|
||
|
|
$user->setUnmatchedProperty('twoFactorDescription', match ($user->twoFactorTypeId) {
|
||
|
|
1 => __('Email'),
|
||
|
|
2 => __('Google Authenticator'),
|
||
|
|
default => __('Disabled'),
|
||
|
|
});
|
||
|
|
|
||
|
|
if ($this->isApi($request)) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$user->includeProperty('buttons');
|
||
|
|
|
||
|
|
// Deal with the home page
|
||
|
|
try {
|
||
|
|
$user->setUnmatchedProperty(
|
||
|
|
'homePage',
|
||
|
|
$this->userGroupFactory->getHomepageByName($user->homePageId)->title
|
||
|
|
);
|
||
|
|
} catch (NotFoundException $exception) {
|
||
|
|
$this->getLog()->error('User has homepage which does not exist. userId: ' . $user->userId . ', homepage: ' . $user->homePageId);
|
||
|
|
$user->setUnmatchedProperty('homePage', __('Unknown homepage, please edit to update.'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set the home folder
|
||
|
|
$user->setUnmatchedProperty('homeFolder', $user->getUnmatchedProperty('homeFolder', '/'));
|
||
|
|
|
||
|
|
// Super admins have some buttons
|
||
|
|
if ($this->getUser()->featureEnabled('users.modify')
|
||
|
|
&& $this->getUser()->checkEditable($user)
|
||
|
|
) {
|
||
|
|
// Edit
|
||
|
|
$user->buttons[] = [
|
||
|
|
'id' => 'user_button_edit',
|
||
|
|
'url' => $this->urlFor($request,'user.edit.form', ['id' => $user->userId]),
|
||
|
|
'text' => __('Edit')
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($this->getUser()->featureEnabled('users.modify')
|
||
|
|
&& $this->getUser()->checkDeleteable($user)
|
||
|
|
&& $user->userId != $this->getConfig()->getSetting('SYSTEM_USER')
|
||
|
|
&& $this->getUser()->userId !== $user->userId
|
||
|
|
&& ( ($this->getUser()->isGroupAdmin() && $user->userTypeId == 3) || $this->getUser()->isSuperAdmin() )
|
||
|
|
) {
|
||
|
|
// Delete
|
||
|
|
$user->buttons[] = [
|
||
|
|
'id' => 'user_button_delete',
|
||
|
|
'url' => $this->urlFor($request,'user.delete.form', ['id' => $user->userId]),
|
||
|
|
'text' => __('Delete')
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($this->getUser()->featureEnabled('folder.userHome')) {
|
||
|
|
$user->buttons[] = [
|
||
|
|
'id' => 'user_button_set_home',
|
||
|
|
'url' => $this->urlFor($request, 'user.homeFolder.form', ['id' => $user->userId]),
|
||
|
|
'text' => __('Set Home Folder'),
|
||
|
|
'multi-select' => true,
|
||
|
|
'dataAttributes' => [
|
||
|
|
['name' => 'commit-url', 'value' => $this->urlFor($request, 'user.homeFolder', ['id' => $user->userId])],
|
||
|
|
['name' => 'commit-method', 'value' => 'post'],
|
||
|
|
['name' => 'id', 'value' => 'user_button_set_home'],
|
||
|
|
['name' => 'text', 'value' => __('Set home folder')],
|
||
|
|
['name' => 'rowtitle', 'value' => $user->userName],
|
||
|
|
['name' => 'form-callback', 'value' => 'userHomeFolderMultiselectFormOpen']
|
||
|
|
],
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($this->getUser()->featureEnabled('users.modify')
|
||
|
|
&& $this->getUser()->checkPermissionsModifyable($user)
|
||
|
|
) {
|
||
|
|
$user->buttons[] = ['divider' => true];
|
||
|
|
|
||
|
|
// User Groups
|
||
|
|
$user->buttons[] = array(
|
||
|
|
'id' => 'user_button_group_membership',
|
||
|
|
'url' => $this->urlFor($request,'user.membership.form', ['id' => $user->userId]),
|
||
|
|
'text' => __('User Groups')
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($this->getUser()->isSuperAdmin()) {
|
||
|
|
$user->buttons[] = ['divider' => true];
|
||
|
|
|
||
|
|
// Features
|
||
|
|
$user->buttons[] = [
|
||
|
|
'id' => 'user_button_page_security',
|
||
|
|
'url' => $this->urlFor($request,'group.acl.form', ['id' => $user->groupId, 'userId' => $user->userId]),
|
||
|
|
'text' => __('Features'),
|
||
|
|
'title' => __('Turn Features on/off for this User')
|
||
|
|
];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getState()->template = 'grid';
|
||
|
|
$this->getState()->recordsTotal = $this->userFactory->countLast();
|
||
|
|
$this->getState()->setData($users);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds a user
|
||
|
|
*
|
||
|
|
* @SWG\Post(
|
||
|
|
* path="/user",
|
||
|
|
* operationId="userAdd",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="Add User",
|
||
|
|
* description="Add a new User",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="userName",
|
||
|
|
* in="formData",
|
||
|
|
* description="The User Name",
|
||
|
|
* type="string",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="email",
|
||
|
|
* in="formData",
|
||
|
|
* description="The user email address",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="userTypeId",
|
||
|
|
* in="formData",
|
||
|
|
* description="The user type ID",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="homePageId",
|
||
|
|
* in="formData",
|
||
|
|
* description="The homepage to use for this User",
|
||
|
|
* type="string",
|
||
|
|
* enum={"statusdashboard.view", "icondashboard.view", "mediamanager.view", "playlistdashboard.view"},
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="libraryQuota",
|
||
|
|
* in="formData",
|
||
|
|
* description="The users library quota in kilobytes",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="password",
|
||
|
|
* in="formData",
|
||
|
|
* description="The users password",
|
||
|
|
* type="string",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="groupId",
|
||
|
|
* in="formData",
|
||
|
|
* description="The inital user group for this User",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="firstName",
|
||
|
|
* in="formData",
|
||
|
|
* description="The users first name",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="lastName",
|
||
|
|
* in="formData",
|
||
|
|
* description="The users last name",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="phone",
|
||
|
|
* in="formData",
|
||
|
|
* description="The users phone number",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ref1",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reference 1",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ref2",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reference 2",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ref3",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reference 3",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ref4",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reference 4",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ref5",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reference 5",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="newUserWizard",
|
||
|
|
* in="formData",
|
||
|
|
* description="Flag indicating whether to show the new user guide",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="hideNavigation",
|
||
|
|
* in="formData",
|
||
|
|
* description="Flag indicating whether to hide the navigation",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="isPasswordChangeRequired",
|
||
|
|
* in="formData",
|
||
|
|
* description="A flag indicating whether password change should be forced for this user",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=201,
|
||
|
|
* description="successful operation",
|
||
|
|
* @SWG\Schema(ref="#/definitions/User"),
|
||
|
|
* @SWG\Header(
|
||
|
|
* header="Location",
|
||
|
|
* description="Location of the new record",
|
||
|
|
* type="string"
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function add(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
// Only group admins or super admins can create Users.
|
||
|
|
if (!$this->getUser()->isSuperAdmin() && !$this->getUser()->isGroupAdmin()) {
|
||
|
|
throw new AccessDeniedException(__('Only super and group admins can create users'));
|
||
|
|
}
|
||
|
|
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
// Build a user entity and save it
|
||
|
|
$user = $this->userFactory->create();
|
||
|
|
$user->setChildAclDependencies($this->userGroupFactory);
|
||
|
|
|
||
|
|
$user->userName = $sanitizedParams->getString('userName');
|
||
|
|
$user->email = $sanitizedParams->getString('email');
|
||
|
|
$user->homePageId = $sanitizedParams->getString('homePageId');
|
||
|
|
$user->libraryQuota = $sanitizedParams->getInt('libraryQuota', ['default' => 0]);
|
||
|
|
$user->setNewPassword($sanitizedParams->getString('password'));
|
||
|
|
|
||
|
|
// Are user home folders enabled? If not, use the default.
|
||
|
|
if ($this->getUser()->featureEnabled('folder.userHome')) {
|
||
|
|
$user->homeFolderId = $sanitizedParams->getInt('homeFolderId', ['default' => 1]);
|
||
|
|
} else {
|
||
|
|
$user->homeFolderId = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($this->getUser()->isSuperAdmin()) {
|
||
|
|
$user->userTypeId = $sanitizedParams->getInt('userTypeId');
|
||
|
|
$user->isSystemNotification = $sanitizedParams->getCheckbox('isSystemNotification');
|
||
|
|
$user->isDisplayNotification = $sanitizedParams->getCheckbox('isDisplayNotification');
|
||
|
|
} else {
|
||
|
|
$user->userTypeId = 3;
|
||
|
|
$user->isSystemNotification = 0;
|
||
|
|
$user->isDisplayNotification = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
$user->firstName = $sanitizedParams->getString('firstName');
|
||
|
|
$user->lastName = $sanitizedParams->getString('lastName');
|
||
|
|
$user->phone = $sanitizedParams->getString('phone');
|
||
|
|
$user->ref1 = $sanitizedParams->getString('ref1');
|
||
|
|
$user->ref2 = $sanitizedParams->getString('ref2');
|
||
|
|
$user->ref3 = $sanitizedParams->getString('ref3');
|
||
|
|
$user->ref4 = $sanitizedParams->getString('ref4');
|
||
|
|
$user->ref5 = $sanitizedParams->getString('ref5');
|
||
|
|
|
||
|
|
// Options
|
||
|
|
$user->newUserWizard = $sanitizedParams->getCheckbox('newUserWizard');
|
||
|
|
$user->setOptionValue('hideNavigation', $sanitizedParams->getCheckbox('hideNavigation'));
|
||
|
|
$user->isPasswordChangeRequired = $sanitizedParams->getCheckbox('isPasswordChangeRequired');
|
||
|
|
|
||
|
|
// Initial user group
|
||
|
|
$group = $this->userGroupFactory->getById($sanitizedParams->getInt('groupId'));
|
||
|
|
|
||
|
|
if ($group->isUserSpecific == 1) {
|
||
|
|
throw new InvalidArgumentException(__('Invalid user group selected'), 'groupId');
|
||
|
|
}
|
||
|
|
|
||
|
|
// Save the user
|
||
|
|
$user->save();
|
||
|
|
|
||
|
|
// Assign the initial group
|
||
|
|
$group->assignUser($user);
|
||
|
|
$group->save(['validate' => false]);
|
||
|
|
|
||
|
|
// Handle enabled features for the homepage.
|
||
|
|
if (!empty($user->homePageId)) {
|
||
|
|
$homepage = $this->userGroupFactory->getHomepageByName($user->homePageId);
|
||
|
|
if (!empty($homepage->feature) && !$user->featureEnabled($homepage->feature)) {
|
||
|
|
throw new InvalidArgumentException(__('User does not have the enabled Feature for this Dashboard'), 'homePageId');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'httpStatus' => 201,
|
||
|
|
'message' => sprintf(__('Added %s'), $user->userName),
|
||
|
|
'id' => $user->userId,
|
||
|
|
'data' => $user
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Edit a user
|
||
|
|
*
|
||
|
|
* @SWG\Put(
|
||
|
|
* path="/user/{userId}",
|
||
|
|
* operationId="userEdit",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="Edit User",
|
||
|
|
* description="Edit existing User",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="userId",
|
||
|
|
* in="path",
|
||
|
|
* description="The user ID to edit",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="userName",
|
||
|
|
* in="formData",
|
||
|
|
* description="The User Name",
|
||
|
|
* type="string",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="email",
|
||
|
|
* in="formData",
|
||
|
|
* description="The user email address",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="userTypeId",
|
||
|
|
* in="formData",
|
||
|
|
* description="The user type ID",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="homePageId",
|
||
|
|
* in="formData",
|
||
|
|
* description="The homepage to use for this User",
|
||
|
|
* type="string",
|
||
|
|
* enum={"statusdashboard.view", "icondashboard.view", "mediamanager.view", "playlistdashboard.view"},
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="libraryQuota",
|
||
|
|
* in="formData",
|
||
|
|
* description="The users library quota in kilobytes",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="newPassword",
|
||
|
|
* in="formData",
|
||
|
|
* description="New User password",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="retypeNewPassword",
|
||
|
|
* in="formData",
|
||
|
|
* description="Repeat the new User password",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="retired",
|
||
|
|
* in="formData",
|
||
|
|
* description="Flag indicating whether to retire this user",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="firstName",
|
||
|
|
* in="formData",
|
||
|
|
* description="The users first name",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="lastName",
|
||
|
|
* in="formData",
|
||
|
|
* description="The users last name",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="phone",
|
||
|
|
* in="formData",
|
||
|
|
* description="The users phone number",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ref1",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reference 1",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ref2",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reference 2",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ref3",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reference 3",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ref4",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reference 4",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ref5",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reference 5",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="newUserWizard",
|
||
|
|
* in="formData",
|
||
|
|
* description="Flag indicating whether to show the new user guide",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="hideNavigation",
|
||
|
|
* in="formData",
|
||
|
|
* description="Flag indicating whether to hide the navigation",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="isPasswordChangeRequired",
|
||
|
|
* in="formData",
|
||
|
|
* description="A flag indicating whether password change should be forced for this user",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=201,
|
||
|
|
* description="successful operation",
|
||
|
|
* @SWG\Schema(ref="#/definitions/User"),
|
||
|
|
* @SWG\Header(
|
||
|
|
* header="Location",
|
||
|
|
* description="Location of the new record",
|
||
|
|
* type="string"
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function edit(Request $request, Response $response, $id)
|
||
|
|
{
|
||
|
|
$user = $this->userFactory->getById($id);
|
||
|
|
|
||
|
|
if (!$this->getUser()->checkEditable($user)) {
|
||
|
|
throw new AccessDeniedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getLog()->debug('User Edit process started.');
|
||
|
|
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
// Build a user entity and save it
|
||
|
|
$user->setChildAclDependencies($this->userGroupFactory);
|
||
|
|
$user->load();
|
||
|
|
$user->userName = $sanitizedParams->getString('userName');
|
||
|
|
$user->email = $sanitizedParams->getString('email');
|
||
|
|
$user->homePageId = $sanitizedParams->getString('homePageId');
|
||
|
|
$user->libraryQuota = $sanitizedParams->getInt('libraryQuota');
|
||
|
|
$user->retired = $sanitizedParams->getCheckbox('retired');
|
||
|
|
|
||
|
|
// Are user home folders enabled? Don't change unless they are.
|
||
|
|
if ($this->getUser()->featureEnabled('folder.userHome')) {
|
||
|
|
$user->homeFolderId = $sanitizedParams->getInt('homeFolderId', ['default' => 1]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Some configuration is only avaialble to super admins.
|
||
|
|
if ($this->getUser()->isSuperAdmin()) {
|
||
|
|
$user->userTypeId = $sanitizedParams->getInt('userTypeId');
|
||
|
|
if ($user->retired === 1) {
|
||
|
|
$user->isSystemNotification = 0;
|
||
|
|
$user->isDisplayNotification = 0;
|
||
|
|
$user->isDataSetNotification = 0;
|
||
|
|
$user->isCustomNotification = 0;
|
||
|
|
$user->isLayoutNotification = 0;
|
||
|
|
$user->isLibraryNotification = 0;
|
||
|
|
$user->isReportNotification = 0;
|
||
|
|
$user->isScheduleNotification = 0;
|
||
|
|
} else {
|
||
|
|
$user->isSystemNotification = $sanitizedParams->getCheckbox('isSystemNotification');
|
||
|
|
$user->isDisplayNotification = $sanitizedParams->getCheckbox('isDisplayNotification');
|
||
|
|
$user->isDataSetNotification = $sanitizedParams->getCheckbox('isDataSetNotification');
|
||
|
|
$user->isCustomNotification = $sanitizedParams->getCheckbox('isCustomNotification');
|
||
|
|
$user->isLayoutNotification = $sanitizedParams->getCheckbox('isLayoutNotification');
|
||
|
|
$user->isLibraryNotification = $sanitizedParams->getCheckbox('isLibraryNotification');
|
||
|
|
$user->isReportNotification = $sanitizedParams->getCheckbox('isReportNotification');
|
||
|
|
$user->isScheduleNotification = $sanitizedParams->getCheckbox('isScheduleNotification');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$user->firstName = $sanitizedParams->getString('firstName');
|
||
|
|
$user->lastName = $sanitizedParams->getString('lastName');
|
||
|
|
$user->phone = $sanitizedParams->getString('phone');
|
||
|
|
$user->ref1 = $sanitizedParams->getString('ref1');
|
||
|
|
$user->ref2 = $sanitizedParams->getString('ref2');
|
||
|
|
$user->ref3 = $sanitizedParams->getString('ref3');
|
||
|
|
$user->ref4 = $sanitizedParams->getString('ref4');
|
||
|
|
$user->ref5 = $sanitizedParams->getString('ref5');
|
||
|
|
|
||
|
|
// Options
|
||
|
|
$user->newUserWizard = $sanitizedParams->getCheckbox('newUserWizard');
|
||
|
|
$user->setOptionValue('hideNavigation', $sanitizedParams->getCheckbox('hideNavigation'));
|
||
|
|
$user->isPasswordChangeRequired = $sanitizedParams->getCheckbox('isPasswordChangeRequired');
|
||
|
|
|
||
|
|
$this->getLog()->debug('Params read');
|
||
|
|
|
||
|
|
// Handle enabled features for the homepage.
|
||
|
|
$homepage = $this->userGroupFactory->getHomepageByName($user->homePageId);
|
||
|
|
if (!empty($homepage->feature) && !$user->featureEnabled($homepage->feature)) {
|
||
|
|
throw new InvalidArgumentException(
|
||
|
|
__('User does not have the enabled Feature for this Dashboard'),
|
||
|
|
'homePageId'
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getLog()->debug('Homepage validated.');
|
||
|
|
|
||
|
|
// If we are a super admin
|
||
|
|
if ($this->getUser()->userTypeId == 1) {
|
||
|
|
$newPassword = $sanitizedParams->getString('newPassword');
|
||
|
|
$retypeNewPassword = $sanitizedParams->getString('retypeNewPassword');
|
||
|
|
$disableTwoFactor = $sanitizedParams->getCheckbox('disableTwoFactor');
|
||
|
|
|
||
|
|
if ($newPassword != null && $newPassword != '') {
|
||
|
|
$this->getLog()->debug('New password provided, checking.');
|
||
|
|
|
||
|
|
// Make sure they are the same
|
||
|
|
if ($newPassword != $retypeNewPassword) {
|
||
|
|
throw new InvalidArgumentException(__('Passwords do not match'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set the new password
|
||
|
|
$user->setNewPassword($newPassword);
|
||
|
|
}
|
||
|
|
|
||
|
|
// super admin can clear the twoFactorTypeId and secret for the user.
|
||
|
|
if ($disableTwoFactor) {
|
||
|
|
$user->clearTwoFactor();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getLog()->debug('About to save.');
|
||
|
|
|
||
|
|
// Save the user
|
||
|
|
$user->save();
|
||
|
|
|
||
|
|
$this->getLog()->debug('User saved, about to return.');
|
||
|
|
|
||
|
|
// Re-fetch the user before returning to ensure all fields are populated,
|
||
|
|
// especially those omitted in the edit request.
|
||
|
|
$user = $this->userFactory->getById($id);
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'message' => sprintf(__('Edited %s'), $user->userName),
|
||
|
|
'id' => $user->userId,
|
||
|
|
'data' => $user
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Deletes a User
|
||
|
|
*
|
||
|
|
* @SWG\Delete(
|
||
|
|
* path="/user/{userId}",
|
||
|
|
* operationId="userDelete",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="User Delete",
|
||
|
|
* description="Delete user",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="userId",
|
||
|
|
* in="path",
|
||
|
|
* description="Id of the user to delete",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="deleteAllItems",
|
||
|
|
* in="formData",
|
||
|
|
* description="Flag indicating whether to delete all items owned by that user",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="reassignUserId",
|
||
|
|
* in="formData",
|
||
|
|
* description="Reassign all items owned by this user to the specified user ID",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=204,
|
||
|
|
* description="successful operation",
|
||
|
|
* @SWG\Schema(
|
||
|
|
* type="array",
|
||
|
|
* @SWG\Items(ref="#/definitions/User")
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws ConfigurationException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function delete(Request $request, Response $response, $id)
|
||
|
|
{
|
||
|
|
$user = $this->userFactory->getById($id);
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
// System User
|
||
|
|
if ($user->userId == $this->getConfig()->getSetting('SYSTEM_USER')) {
|
||
|
|
throw new InvalidArgumentException(__('This User is set as System User and cannot be deleted.'), 'userId');
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!$this->getUser()->checkDeleteable($user)) {
|
||
|
|
throw new AccessDeniedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($this->getUser()->userId === $user->userId) {
|
||
|
|
throw new InvalidArgumentException(__('Cannot delete your own User from the CMS.'));
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($this->getUser()->isGroupAdmin() && $user->userTypeId !== 3) {
|
||
|
|
throw new InvalidArgumentException(__('Group Admin cannot remove Super Admins or other Group Admins.'));
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($sanitizedParams->getCheckbox('deleteAllItems') && $user->isSuperAdmin()) {
|
||
|
|
throw new InvalidArgumentException(__('Cannot delete all items owned by a Super Admin, please reassign to a different User.'));
|
||
|
|
}
|
||
|
|
|
||
|
|
$user->setChildAclDependencies($this->userGroupFactory);
|
||
|
|
|
||
|
|
if ($sanitizedParams->getCheckbox('deleteAllItems') != 1) {
|
||
|
|
// Do we have a userId to reassign content to?
|
||
|
|
if ($sanitizedParams->getInt('reassignUserId') != null) {
|
||
|
|
// Reassign all content owned by this user to the provided user
|
||
|
|
$this->getLog()->debug(sprintf('Reassigning content to new userId: %d', $sanitizedParams->getInt('reassignUserId')));
|
||
|
|
$this->getDispatcher()->dispatch(
|
||
|
|
UserDeleteEvent::$NAME,
|
||
|
|
new UserDeleteEvent(
|
||
|
|
$user,
|
||
|
|
'reassignAll',
|
||
|
|
$this->userFactory->getSystemUser(),
|
||
|
|
$this->userFactory->getById($sanitizedParams->getInt('reassignUserId'))
|
||
|
|
)
|
||
|
|
);
|
||
|
|
} else {
|
||
|
|
// Check to see if we have any child data that would prevent us from deleting
|
||
|
|
/** @var UserDeleteEvent $countChildren */
|
||
|
|
$countChildren = $this->getDispatcher()->dispatch(UserDeleteEvent::$NAME, new UserDeleteEvent($user, 'countChildren', $this->userFactory->getSystemUser()));
|
||
|
|
|
||
|
|
if ($countChildren->getReturnValue() > 0) {
|
||
|
|
throw new InvalidArgumentException(sprintf(__('This user cannot be deleted as it has %d child items'), $countChildren->getReturnValue()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getDispatcher()->dispatch(UserDeleteEvent::$NAME, new UserDeleteEvent($user, 'delete', $this->userFactory->getSystemUser()));
|
||
|
|
// Delete the user
|
||
|
|
$user->delete();
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'message' => sprintf(__('Deleted %s'), $user->userName),
|
||
|
|
'id' => $user->userId
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param \Slim\Http\ServerRequest $request
|
||
|
|
* @param \Slim\Http\Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|\Slim\Http\Response
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\GeneralException
|
||
|
|
*/
|
||
|
|
public function homepages(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
// Only group admins or super admins can create Users.
|
||
|
|
if (!$this->getUser()->isSuperAdmin() && !$this->getUser()->isGroupAdmin()) {
|
||
|
|
throw new AccessDeniedException(__('Only super and group admins can create users'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get all homepages accessible for a user group
|
||
|
|
$params = $this->getSanitizer($request->getParams());
|
||
|
|
$userId = $params->getInt('userId');
|
||
|
|
|
||
|
|
if ($userId !== null) {
|
||
|
|
$homepages = [];
|
||
|
|
$user = $this->userFactory->getById($userId)
|
||
|
|
->setChildAclDependencies($this->userGroupFactory);
|
||
|
|
|
||
|
|
foreach ($this->userGroupFactory->getHomepages() as $homepage) {
|
||
|
|
if (empty($homepage->feature) || $user->featureEnabled($homepage->feature)) {
|
||
|
|
$homepages[] = $homepage;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$userTypeId = $params->getInt('userTypeId', [
|
||
|
|
'throw' => function () {
|
||
|
|
throw new NotFoundException();
|
||
|
|
}
|
||
|
|
]);
|
||
|
|
|
||
|
|
if ($userTypeId == 1) {
|
||
|
|
$homepages = $this->userGroupFactory->getHomepages();
|
||
|
|
} else {
|
||
|
|
$groupId = $params->getInt('groupId', [
|
||
|
|
'throw' => function () {
|
||
|
|
throw new NotFoundException();
|
||
|
|
}
|
||
|
|
]);
|
||
|
|
$group = $this->userGroupFactory->getById($groupId);
|
||
|
|
|
||
|
|
$homepages = [];
|
||
|
|
foreach ($this->userGroupFactory->getHomepages() as $homepage) {
|
||
|
|
if (empty($homepage->feature) || in_array($homepage->feature, $group->features)) {
|
||
|
|
$homepages[] = $homepage;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Prepare output
|
||
|
|
$this->getState()->template = 'grid';
|
||
|
|
|
||
|
|
// Have we asked for a specific homepage?
|
||
|
|
$homepageFilter = $params->getString('homepage');
|
||
|
|
if ($homepageFilter !== null) {
|
||
|
|
if (array_key_exists($homepageFilter, $homepages)) {
|
||
|
|
$this->getState()->recordsTotal = 1;
|
||
|
|
$this->getState()->setData([$homepages[$homepageFilter]]);
|
||
|
|
return $this->render($request, $response);
|
||
|
|
} else {
|
||
|
|
throw new NotFoundException(__('Homepage not found'));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getState()->recordsTotal = count($homepages);
|
||
|
|
$this->getState()->setData(array_values($homepages));
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* User Add Form
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function addForm(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
// Only group admins or super admins can create Users.
|
||
|
|
if (!$this->getUser()->isSuperAdmin() && !$this->getUser()->isGroupAdmin()) {
|
||
|
|
throw new AccessDeniedException(__('Only super and group admins can create users'));
|
||
|
|
}
|
||
|
|
|
||
|
|
$defaultUserTypeId = 3;
|
||
|
|
foreach ($this->userTypeFactory->query(null, [
|
||
|
|
'userType' => $this->getConfig()->getSetting('defaultUsertype')
|
||
|
|
]) as $defaultUserType) {
|
||
|
|
$defaultUserTypeId = $defaultUserType->userTypeId;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getState()->template = 'user-form-add';
|
||
|
|
$this->getState()->setData([
|
||
|
|
'options' => [
|
||
|
|
'userTypes' => ($this->getUser()->isSuperAdmin()) ? $this->userTypeFactory->getAllRoles() : $this->userTypeFactory->getNonAdminRoles(),
|
||
|
|
'defaultGroupId' => $this->getConfig()->getSetting('DEFAULT_USERGROUP'),
|
||
|
|
'defaultUserType' => $defaultUserTypeId
|
||
|
|
],
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* User Edit Form
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function editForm(Request $request, Response $response, $id)
|
||
|
|
{
|
||
|
|
$user = $this->userFactory->getById($id);
|
||
|
|
$user->setChildAclDependencies($this->userGroupFactory);
|
||
|
|
|
||
|
|
if (!$this->getUser()->checkEditable($user)) {
|
||
|
|
throw new AccessDeniedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
$homepage = [];
|
||
|
|
try {
|
||
|
|
$homepage = $this->userGroupFactory->getHomepageByName($user->homePageId);
|
||
|
|
} catch (NotFoundException $notFoundException) {
|
||
|
|
$this->getLog()->error(sprintf('User %d has non existing homepage %s', $user->userId, $user->homePageId));
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getState()->template = 'user-form-edit';
|
||
|
|
$this->getState()->setData([
|
||
|
|
'user' => $user,
|
||
|
|
'options' => [
|
||
|
|
'homepage' => $homepage,
|
||
|
|
'userTypes' => ($this->getUser()->isSuperAdmin()) ? $this->userTypeFactory->getAllRoles() : $this->userTypeFactory->getNonAdminRoles()
|
||
|
|
],
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* User Delete Form
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function deleteForm(Request $request, Response $response, $id)
|
||
|
|
{
|
||
|
|
$user = $this->userFactory->getById($id);
|
||
|
|
|
||
|
|
if (!$this->getUser()->checkDeleteable($user)) {
|
||
|
|
throw new AccessDeniedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getState()->template = 'user-form-delete';
|
||
|
|
$this->getState()->setData([
|
||
|
|
'user' => $user,
|
||
|
|
'users' => $this->userFactory->query(null, ['notUserId' => $id]),
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Change my password form
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
*/
|
||
|
|
public function editProfileForm(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$user = $this->getUser();
|
||
|
|
|
||
|
|
$this->getState()->template = 'user-form-edit-profile';
|
||
|
|
$this->getState()->setData([
|
||
|
|
'user' => $user,
|
||
|
|
'data' => [
|
||
|
|
'setup' => $this->urlFor($request,'user.setup.profile'),
|
||
|
|
'generate' => $this->urlFor($request,'user.recovery.generate.profile'),
|
||
|
|
'show' => $this->urlFor($request,'user.recovery.show.profile'),
|
||
|
|
]
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Change my Password
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \QRException
|
||
|
|
* @throws \RobThree\Auth\TwoFactorAuthException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
*/
|
||
|
|
public function editProfile(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$user = $this->getUser();
|
||
|
|
|
||
|
|
// get all other values from the form
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
$oldPassword = $sanitizedParams->getString('password');
|
||
|
|
$newPassword = $sanitizedParams->getString('newPassword');
|
||
|
|
$retypeNewPassword = $sanitizedParams->getString('retypeNewPassword');
|
||
|
|
$user->email = $sanitizedParams->getString('email');
|
||
|
|
$user->twoFactorTypeId = $sanitizedParams->getInt('twoFactorTypeId');
|
||
|
|
$code = $sanitizedParams->getString('code');
|
||
|
|
$recoveryCodes = $sanitizedParams->getString('twoFactorRecoveryCodes');
|
||
|
|
|
||
|
|
if ($recoveryCodes != null) {
|
||
|
|
$user->twoFactorRecoveryCodes = json_decode($recoveryCodes);
|
||
|
|
}
|
||
|
|
|
||
|
|
// What situations do we need to check the old password is correct?
|
||
|
|
if ($user->hasPropertyChanged('twoFactorTypeId')
|
||
|
|
|| ($user->hasPropertyChanged('email') && $user->twoFactorTypeId === 1)
|
||
|
|
|| ($user->hasPropertyChanged('email') && $user->getOriginalValue('twoFactorTypeId') === 1)
|
||
|
|
|| $newPassword != null
|
||
|
|
) {
|
||
|
|
try {
|
||
|
|
$user->checkPassword($oldPassword);
|
||
|
|
} catch (AccessDeniedException $exception) {
|
||
|
|
throw new InvalidArgumentException(__('Please enter your password'), 'password');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// check if we have a new password provided, if so check if it was correctly entered
|
||
|
|
if ($newPassword != $retypeNewPassword) {
|
||
|
|
throw new InvalidArgumentException(__('Passwords do not match'), 'newPassword');
|
||
|
|
}
|
||
|
|
|
||
|
|
// check if we have saved secret, for google auth that is done on jQuery side
|
||
|
|
if (!isset($user->twoFactorSecret) && $user->twoFactorTypeId === 1) {
|
||
|
|
$this->tfaSetup($request, $response);
|
||
|
|
$user->twoFactorSecret = $_SESSION['tfaSecret'];
|
||
|
|
unset($_SESSION['tfaSecret']);
|
||
|
|
}
|
||
|
|
|
||
|
|
// if we are setting up email two factor auth, check if the email is entered on the form as well
|
||
|
|
if ($user->twoFactorTypeId === 1 && $user->email == '') {
|
||
|
|
throw new InvalidArgumentException(__('Please provide valid email address'), 'email');
|
||
|
|
}
|
||
|
|
|
||
|
|
// if we are setting up email two factor auth, check if the sending email address is entered in CMS Settings.
|
||
|
|
if ($user->twoFactorTypeId === 1 && $this->getConfig()->getSetting('mail_from') == '') {
|
||
|
|
throw new InvalidArgumentException(__('Please provide valid sending email address in CMS Settings on Network tab'), 'mail_from');
|
||
|
|
}
|
||
|
|
|
||
|
|
// if we have a new password provided, update the user record
|
||
|
|
if ($newPassword != null && $newPassword == $retypeNewPassword) {
|
||
|
|
$user->setNewPassword($newPassword, $oldPassword);
|
||
|
|
$user->isPasswordChangeRequired = 0;
|
||
|
|
$user->save([
|
||
|
|
'passwordUpdate' => true
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// if we are setting up Google auth, we are expecting a code from the form, validate the code here
|
||
|
|
// we want to show QR code and validate the access code also with the previous auth method was set to email
|
||
|
|
if ($user->twoFactorTypeId === 2
|
||
|
|
&& ($user->twoFactorSecret === null || $user->getOriginalValue('twoFactorTypeId') === 1)
|
||
|
|
) {
|
||
|
|
if (!isset($code)) {
|
||
|
|
throw new InvalidArgumentException(__('Access Code is empty'), 'code');
|
||
|
|
}
|
||
|
|
|
||
|
|
$validation = $this->tfaValidate($code, $user);
|
||
|
|
|
||
|
|
if (!$validation) {
|
||
|
|
unset($_SESSION['tfaSecret']);
|
||
|
|
throw new InvalidArgumentException(__('Access Code is incorrect'), 'code');
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($validation) {
|
||
|
|
// if access code is correct, we want to set the secret to our user - either from session for new 2FA setup or leave it as it is for user changing from email to google auth
|
||
|
|
if (!isset($user->twoFactorSecret)) {
|
||
|
|
$secret = $_SESSION['tfaSecret'];
|
||
|
|
} else {
|
||
|
|
$secret = $user->twoFactorSecret;
|
||
|
|
}
|
||
|
|
|
||
|
|
$user->twoFactorSecret = $secret;
|
||
|
|
unset($_SESSION['tfaSecret']);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// if the two factor type is set to Off, clear any saved secrets and set the twoFactorTypeId to 0 in database.
|
||
|
|
if ($user->twoFactorTypeId == 0) {
|
||
|
|
$user->clearTwoFactor();
|
||
|
|
}
|
||
|
|
|
||
|
|
$user->save();
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'message' => __('User Profile Saved'),
|
||
|
|
'id' => $user->userId,
|
||
|
|
'data' => $user
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \QRException
|
||
|
|
* @throws \RobThree\Auth\TwoFactorAuthException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
*/
|
||
|
|
public function tfaSetup(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$user = $this->getUser();
|
||
|
|
|
||
|
|
$issuerSettings = $this->getConfig()->getSetting('TWOFACTOR_ISSUER');
|
||
|
|
$appName = $this->getConfig()->getThemeConfig('app_name');
|
||
|
|
$quickChartUrl = $this->getConfig()->getSetting('QUICK_CHART_URL', 'https://quickchart.io');
|
||
|
|
|
||
|
|
if ($issuerSettings !== '') {
|
||
|
|
$issuer = $issuerSettings;
|
||
|
|
} else {
|
||
|
|
$issuer = $appName;
|
||
|
|
}
|
||
|
|
|
||
|
|
$tfa = new TwoFactorAuth($issuer, 6, 30, 'sha1', new QuickChartQRProvider($quickChartUrl));
|
||
|
|
|
||
|
|
// create two factor secret and store it in user record
|
||
|
|
if (!isset($user->twoFactorSecret)) {
|
||
|
|
$secret = $tfa->createSecret();
|
||
|
|
$_SESSION['tfaSecret'] = $secret;
|
||
|
|
} else {
|
||
|
|
$secret = $user->twoFactorSecret;
|
||
|
|
}
|
||
|
|
|
||
|
|
// generate the QR code to scan, we only show it at first set up and only for Google auth
|
||
|
|
$qRUrl = $tfa->getQRCodeImageAsDataUri($user->userName, $secret, 150);
|
||
|
|
|
||
|
|
$this->getState()->setData([
|
||
|
|
'qRUrl' => $qRUrl
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param string $code The Code to validate
|
||
|
|
* @param $user
|
||
|
|
* @return bool
|
||
|
|
* @throws \RobThree\Auth\TwoFactorAuthException
|
||
|
|
*/
|
||
|
|
public function tfaValidate($code, $user)
|
||
|
|
{
|
||
|
|
$issuerSettings = $this->getConfig()->getSetting('TWOFACTOR_ISSUER');
|
||
|
|
$appName = $this->getConfig()->getThemeConfig('app_name');
|
||
|
|
|
||
|
|
if ($issuerSettings !== '') {
|
||
|
|
$issuer = $issuerSettings;
|
||
|
|
} else {
|
||
|
|
$issuer = $appName;
|
||
|
|
}
|
||
|
|
|
||
|
|
$tfa = new TwoFactorAuth($issuer);
|
||
|
|
|
||
|
|
if (isset($_SESSION['tfaSecret'])) {
|
||
|
|
// validate the provided two factor code with secret for this user
|
||
|
|
$result = $tfa->verifyCode($_SESSION['tfaSecret'], $code, 3);
|
||
|
|
} elseif (isset($user->twoFactorSecret)) {
|
||
|
|
$result = $tfa->verifyCode($user->twoFactorSecret, $code, 3);
|
||
|
|
} else {
|
||
|
|
$result = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
*/
|
||
|
|
public function tfaRecoveryGenerate(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$user = $this->getUser();
|
||
|
|
|
||
|
|
// clear any existing codes when we generate new ones
|
||
|
|
$user->twoFactorRecoveryCodes = [];
|
||
|
|
|
||
|
|
$count = 4;
|
||
|
|
$codes = [];
|
||
|
|
|
||
|
|
for ($i = 0; $i < $count; $i++) {
|
||
|
|
$codes[] = Random::generateString(50);
|
||
|
|
}
|
||
|
|
|
||
|
|
$user->twoFactorRecoveryCodes = $codes;
|
||
|
|
|
||
|
|
$this->getState()->setData([
|
||
|
|
'codes' => json_encode($codes, JSON_PRETTY_PRINT)
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
*/
|
||
|
|
public function tfaRecoveryShow(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$user = $this->getUser();
|
||
|
|
|
||
|
|
$user->twoFactorRecoveryCodes = json_decode($user->twoFactorRecoveryCodes);
|
||
|
|
|
||
|
|
if (isset($_GET["generatedCodes"]) && !empty($_GET["generatedCodes"])) {
|
||
|
|
$generatedCodes = $_GET["generatedCodes"];
|
||
|
|
$user->twoFactorRecoveryCodes = json_encode($generatedCodes);
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getState()->setData([
|
||
|
|
'codes' => $user->twoFactorRecoveryCodes
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Force User Password Change
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Slim\Http\Response
|
||
|
|
* @throws \Xibo\Support\Exception\GeneralException
|
||
|
|
*/
|
||
|
|
public function forceChangePasswordPage(Request $request, Response $response): Response
|
||
|
|
{
|
||
|
|
$user = $this->getUser();
|
||
|
|
|
||
|
|
// if the flag to force change password is not set to 1 then redirect to the Homepage
|
||
|
|
if ($user->isPasswordChangeRequired != 1) {
|
||
|
|
return $response->withRedirect($this->urlFor($request, 'home'));
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getState()->template = 'user-force-change-password-page';
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Force change my Password
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Slim\Http\Response
|
||
|
|
* @throws \Xibo\Support\Exception\GeneralException
|
||
|
|
*/
|
||
|
|
public function forceChangePassword(Request $request, Response $response): Response
|
||
|
|
{
|
||
|
|
$user = $this->getUser();
|
||
|
|
|
||
|
|
// This is only valid if the user has that option set on their account
|
||
|
|
if ($user->isPasswordChangeRequired != 1) {
|
||
|
|
throw new AccessDeniedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Save the user
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
$newPassword = $sanitizedParams->getString('newPassword');
|
||
|
|
$retypeNewPassword = $sanitizedParams->getString('retypeNewPassword');
|
||
|
|
|
||
|
|
if ($newPassword == null || $retypeNewPassword == '') {
|
||
|
|
throw new InvalidArgumentException(__('Please enter the password'), 'password');
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($newPassword != $retypeNewPassword) {
|
||
|
|
throw new InvalidArgumentException(__('Passwords do not match'), 'password');
|
||
|
|
}
|
||
|
|
|
||
|
|
// Make sure that the new password doesn't verify against the existing hash
|
||
|
|
try {
|
||
|
|
$user->checkPassword($newPassword);
|
||
|
|
throw new InvalidArgumentException(__('Please choose a new password'), 'password');
|
||
|
|
} catch (AccessDeniedException) {
|
||
|
|
// This is good, they don't match.
|
||
|
|
}
|
||
|
|
|
||
|
|
$user->setNewPassword($newPassword);
|
||
|
|
$user->save([
|
||
|
|
'passwordUpdate' => true
|
||
|
|
]);
|
||
|
|
|
||
|
|
$user->isPasswordChangeRequired = 0;
|
||
|
|
$user->save();
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'message' => __('Password Changed'),
|
||
|
|
'id' => $user->userId,
|
||
|
|
'data' => $user
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @SWG\Get(
|
||
|
|
* path="/user/permissions/{entity}/{objectId}",
|
||
|
|
* operationId="userPermissionsSearch",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="Permission Data",
|
||
|
|
* description="Permission data for the Entity and Object Provided.",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="entity",
|
||
|
|
* in="path",
|
||
|
|
* description="The Entity",
|
||
|
|
* type="string",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="objectId",
|
||
|
|
* in="path",
|
||
|
|
* description="The ID of the Object to return permissions for",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=200,
|
||
|
|
* description="successful operation",
|
||
|
|
* @SWG\Schema(
|
||
|
|
* type="array",
|
||
|
|
* @SWG\Items(ref="#/definitions/Permission")
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
*
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param string $entity
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function permissionsGrid(Request $request, Response $response, $entity, $id)
|
||
|
|
{
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
|
||
|
|
// Load our object
|
||
|
|
$object = $this->parsePermissionsEntity($entity, $id);
|
||
|
|
|
||
|
|
// Does this user have permission to edit the permissions?!
|
||
|
|
if (!$this->getUser()->checkPermissionsModifyable($object)) {
|
||
|
|
throw new AccessDeniedException(__('You do not have permission to edit these permissions.'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// List of all Groups with a view / edit / delete check box
|
||
|
|
$permissions = $this->permissionFactory->getAllByObjectId($this->getUser(), $object->permissionsClass(), $id, $this->gridRenderSort($sanitizedParams), $this->gridRenderFilter(['name' => $sanitizedParams->getString('name')], $sanitizedParams));
|
||
|
|
|
||
|
|
$this->getState()->template = 'grid';
|
||
|
|
$this->getState()->setData($permissions);
|
||
|
|
$this->getState()->recordsTotal = $this->permissionFactory->countLast();
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @SWG\Get(
|
||
|
|
* path="/user/permissions/{entity}",
|
||
|
|
* operationId="userPermissionsMultiSearch",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="Permission Data",
|
||
|
|
* description="Permission data for the multiple Entities and Objects Provided.",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="entity",
|
||
|
|
* in="path",
|
||
|
|
* description="The Entity",
|
||
|
|
* type="string",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ids",
|
||
|
|
* in="query",
|
||
|
|
* description="The IDs of the Objects to return permissions for",
|
||
|
|
* type="string",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=200,
|
||
|
|
* description="successful operation",
|
||
|
|
* @SWG\Schema(
|
||
|
|
* type="array",
|
||
|
|
* @SWG\Items(ref="#/definitions/Permission")
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
*
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param string $entities
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function permissionsMultiGrid(Request $request, Response $response, $entity)
|
||
|
|
{
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
|
||
|
|
// Check if the array of ids is passed
|
||
|
|
if($sanitizedParams->getString('ids') == '') {
|
||
|
|
throw new InvalidArgumentException(__('The array of ids is empty!'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get array of ids
|
||
|
|
$ids = explode(',', $sanitizedParams->getString('ids'));
|
||
|
|
|
||
|
|
// Array of all the permissions
|
||
|
|
$permissions = [];
|
||
|
|
$newPermissions = [];
|
||
|
|
$objects = [];
|
||
|
|
|
||
|
|
// Load our objects
|
||
|
|
for ($i=0; $i < count($ids); $i++) {
|
||
|
|
$objectId = $ids[$i];
|
||
|
|
|
||
|
|
$objects[$i] = $this->parsePermissionsEntity($entity, $objectId);
|
||
|
|
|
||
|
|
// Does this user have permission to edit the permissions?!
|
||
|
|
if (!$this->getUser()->checkPermissionsModifyable($objects[$i])) {
|
||
|
|
throw new AccessDeniedException(__('You do not have permission to edit all the entities permissions.'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// List of all Groups with a view / edit / delete check box
|
||
|
|
$permissions = array_merge_recursive($permissions, $this->permissionFactory->getAllByObjectId($this->getUser(), $objects[$i]->permissionsClass(), $objectId, $this->gridRenderSort($sanitizedParams), $this->gridRenderFilter(['name' => $sanitizedParams->getString('name')], $sanitizedParams)));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Change permissions structure to be grouped by user group
|
||
|
|
foreach ($permissions as $permission) {
|
||
|
|
|
||
|
|
if(!array_key_exists($permission->groupId, $newPermissions)) {
|
||
|
|
$newPermissions[$permission->groupId] = [
|
||
|
|
"groupId" => $permission->groupId,
|
||
|
|
"group" => $permission->group,
|
||
|
|
"isUser" => $permission->isUser,
|
||
|
|
"entity" => $permission->entity,
|
||
|
|
"permissions" => [
|
||
|
|
$permission->objectId => [
|
||
|
|
"permissionId" => $permission->permissionId,
|
||
|
|
"view" => $permission->view,
|
||
|
|
"edit" => $permission->edit,
|
||
|
|
"delete" => $permission->delete
|
||
|
|
]
|
||
|
|
]
|
||
|
|
];
|
||
|
|
} else {
|
||
|
|
$newPermissions[$permission->groupId]["permissions"][] = [
|
||
|
|
"permissionId" => $permission->permissionId,
|
||
|
|
"view" => $permission->view,
|
||
|
|
"edit" => $permission->edit,
|
||
|
|
"delete" => $permission->delete
|
||
|
|
];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getState()->template = 'grid';
|
||
|
|
$this->getState()->setData($newPermissions);
|
||
|
|
$this->getState()->recordsTotal = $this->permissionFactory->countLast();
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Permissions to users for the provided entity
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param $entity
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function permissionsForm(Request $request, Response $response, $entity, $id)
|
||
|
|
{
|
||
|
|
$requestEntity = $entity;
|
||
|
|
|
||
|
|
// Load our object
|
||
|
|
$object = $this->parsePermissionsEntity($entity, $id);
|
||
|
|
|
||
|
|
// Does this user have permission to edit the permissions?!
|
||
|
|
if (!$this->getUser()->checkPermissionsModifyable($object)) {
|
||
|
|
throw new AccessDeniedException(__('You do not have permission to edit these permissions.'));
|
||
|
|
}
|
||
|
|
|
||
|
|
$currentPermissions = [];
|
||
|
|
foreach ($this->permissionFactory->getAllByObjectId($this->getUser(), $object->permissionsClass(), $id, ['groupId'], ['setOnly' => 1]) as $permission) {
|
||
|
|
/* @var Permission $permission */
|
||
|
|
$currentPermissions[$permission->groupId] = [
|
||
|
|
'view' => ($permission->view == null) ? 0 : $permission->view,
|
||
|
|
'edit' => ($permission->edit == null) ? 0 : $permission->edit,
|
||
|
|
'delete' => ($permission->delete == null) ? 0 : $permission->delete
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
$data = [
|
||
|
|
'entity' => $requestEntity,
|
||
|
|
'objectId' => $id,
|
||
|
|
'permissions' => $currentPermissions,
|
||
|
|
'canSetOwner' => $object->canChangeOwner(),
|
||
|
|
'object' => $object,
|
||
|
|
'objectNameOverride' => $this->getSanitizer($request->getParams())->getString('nameOverride'),
|
||
|
|
];
|
||
|
|
|
||
|
|
$this->getState()->template = 'user-form-permissions';
|
||
|
|
$this->getState()->setData($data);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Permissions to users for the provided entity
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param $entity
|
||
|
|
* @param $ids
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function permissionsMultiForm(Request $request, Response $response, $entity)
|
||
|
|
{
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
|
||
|
|
// Check if the array of ids is passed
|
||
|
|
if($sanitizedParams->getString('ids') == '') {
|
||
|
|
throw new InvalidArgumentException(__('The array of ids is empty!'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get array of ids
|
||
|
|
$ids = $sanitizedParams->getString('ids');
|
||
|
|
|
||
|
|
$data = [
|
||
|
|
'entity' => $entity,
|
||
|
|
'objectIds' => $ids,
|
||
|
|
];
|
||
|
|
|
||
|
|
$this->getState()->template = 'user-form-multiple-permissions';
|
||
|
|
$this->getState()->setData($data);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @SWG\Post(
|
||
|
|
* path="/user/permissions/{entity}/{objectId}",
|
||
|
|
* operationId="userPermissionsSet",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="Permission Set",
|
||
|
|
* description="Set Permissions to users/groups for the provided entity.",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="entity",
|
||
|
|
* in="path",
|
||
|
|
* description="The Entity",
|
||
|
|
* type="string",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="objectId",
|
||
|
|
* in="path",
|
||
|
|
* description="The ID of the Object to set permissions on",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="groupIds",
|
||
|
|
* in="formData",
|
||
|
|
* description="Array of permissions with groupId as the key",
|
||
|
|
* type="array",
|
||
|
|
* required=true,
|
||
|
|
* @SWG\Items(type="string")
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ownerId",
|
||
|
|
* in="formData",
|
||
|
|
* description="Change the owner of this item. Leave empty to keep the current owner",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=204,
|
||
|
|
* description="successful operation"
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
*
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param string $entity
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws ConfigurationException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function permissions(Request $request, Response $response, $entity, $id)
|
||
|
|
{
|
||
|
|
// Load our object
|
||
|
|
$object = $this->parsePermissionsEntity($entity, $id);
|
||
|
|
|
||
|
|
// Does this user have permission to edit the permissions?!
|
||
|
|
if (!$this->getUser()->checkPermissionsModifyable($object)) {
|
||
|
|
throw new AccessDeniedException(__('This object is not shared with you with edit permission'));
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($object->permissionsClass() === 'Xibo\Entity\Folder' && $object->getId() === 1) {
|
||
|
|
throw new InvalidArgumentException(__('You cannot share the root folder'), 'id');
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($object->permissionsClass() === 'Xibo\Entity\Region' && $object->type === 'canvas') {
|
||
|
|
throw new InvalidArgumentException(
|
||
|
|
__('You cannot share the Canvas on a Layout, share the layout instead.'),
|
||
|
|
'type',
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
|
||
|
|
// Get all current permissions
|
||
|
|
$permissions = $this->permissionFactory->getAllByObjectId($this->getUser(), $object->permissionsClass(), $id);
|
||
|
|
|
||
|
|
// Get the provided permissions
|
||
|
|
$groupIds = $sanitizedParams->getArray('groupIds');
|
||
|
|
|
||
|
|
// Run the update
|
||
|
|
$this->updatePermissions($permissions, $groupIds);
|
||
|
|
|
||
|
|
// Should we update the owner?
|
||
|
|
if ($sanitizedParams->getInt('ownerId') != 0) {
|
||
|
|
$ownerId = $sanitizedParams->getInt('ownerId');
|
||
|
|
|
||
|
|
$this->getLog()->debug('Requesting update to a new Owner - id = ' . $ownerId);
|
||
|
|
|
||
|
|
if ($object->canChangeOwner()) {
|
||
|
|
$object->setOwner($ownerId);
|
||
|
|
$object->save([
|
||
|
|
'notify' => false,
|
||
|
|
'manageDynamicDisplayLinks' => false,
|
||
|
|
'validate' => false,
|
||
|
|
'recalculateHash' => false
|
||
|
|
]);
|
||
|
|
} else {
|
||
|
|
throw new ConfigurationException(__('Cannot change owner on this Object'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Nasty handling for ownerId on the Layout
|
||
|
|
// ideally we'd remove that column and rely on the campaign ownerId in 1.9 onward
|
||
|
|
if ($object->permissionsClass() == 'Xibo\Entity\Campaign') {
|
||
|
|
$this->getLog()->debug('Changing owner on child Layout');
|
||
|
|
|
||
|
|
$this->getDispatcher()->dispatch(
|
||
|
|
new LayoutOwnerChangeEvent($object->getId(), $ownerId),
|
||
|
|
LayoutOwnerChangeEvent::$NAME,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($object->permissionsClass() === 'Xibo\Entity\Folder') {
|
||
|
|
/** @var $object \Xibo\Entity\Folder */
|
||
|
|
$object->managePermissions();
|
||
|
|
} else if ($object->permissionsClass() === 'Xibo\Entity\Campaign') {
|
||
|
|
// Update any Canvas Regions to have the same permissions.
|
||
|
|
$event = new LayoutSharingChangeEvent($object->getId());
|
||
|
|
$this->getDispatcher()->dispatch($event, LayoutSharingChangeEvent::$NAME);
|
||
|
|
|
||
|
|
foreach ($event->getCanvasRegionIds() as $canvasRegionId) {
|
||
|
|
$this->getLog()->debug('permissions: canvas region detected, cascading permissions');
|
||
|
|
$permissions = $this->permissionFactory->getAllByObjectId(
|
||
|
|
$this->getUser(),
|
||
|
|
'Xibo\Entity\Region',
|
||
|
|
$canvasRegionId,
|
||
|
|
);
|
||
|
|
$this->updatePermissions($permissions, $groupIds);
|
||
|
|
}
|
||
|
|
} else if ($object->permissionsClass() === 'Xibo\Entity\Region') {
|
||
|
|
/** @var $object \Xibo\Entity\Region */
|
||
|
|
// The regions own playlist should always have the same permissions.
|
||
|
|
$permissions = $this->permissionFactory->getAllByObjectId(
|
||
|
|
$this->getUser(),
|
||
|
|
'Xibo\Entity\Playlist',
|
||
|
|
$object->getPlaylist()->playlistId
|
||
|
|
);
|
||
|
|
|
||
|
|
$this->updatePermissions($permissions, $groupIds);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'httpCode' => 204,
|
||
|
|
'message' => __('Share option Updated')
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @SWG\Post(
|
||
|
|
* path="/user/permissions/{entity}/multiple",
|
||
|
|
* operationId="userPermissionsMultiSet",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="Multiple Permission Set",
|
||
|
|
* description="Set Permissions to users/groups for multiple provided entities.",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="entity",
|
||
|
|
* in="path",
|
||
|
|
* description="The Entity type",
|
||
|
|
* type="string",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ids",
|
||
|
|
* in="formData",
|
||
|
|
* description="Array of object IDs",
|
||
|
|
* type="integer",
|
||
|
|
* required=true
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="groupIds",
|
||
|
|
* in="formData",
|
||
|
|
* description="Array of permissions with groupId as the key",
|
||
|
|
* type="array",
|
||
|
|
* required=true,
|
||
|
|
* @SWG\Items(type="string")
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="ownerId",
|
||
|
|
* in="formData",
|
||
|
|
* description="Change the owner of this item. Leave empty to keep the current owner",
|
||
|
|
* type="integer",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=204,
|
||
|
|
* description="successful operation"
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
*
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param string $entity
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws ConfigurationException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function permissionsMulti(Request $request, Response $response, $entity)
|
||
|
|
{
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
|
||
|
|
// Get array of ids
|
||
|
|
$ids = ($sanitizedParams->getString('ids') != '') ? explode(',', $sanitizedParams->getString('ids')) : [];
|
||
|
|
|
||
|
|
// Check if the array of ids is passed
|
||
|
|
if (count($ids) == 0) {
|
||
|
|
throw new InvalidArgumentException(__('The array of ids is empty!'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set permissions for all the object ids, one by one
|
||
|
|
foreach ($ids as $id) {
|
||
|
|
$this->permissions($request, $response, $entity, $id);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'httpCode' => 204,
|
||
|
|
'message' => __('Share option Updated')
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Parse the Permissions Entity
|
||
|
|
* @param string $entity
|
||
|
|
* @param int $objectId
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
*/
|
||
|
|
private function parsePermissionsEntity($entity, $objectId)
|
||
|
|
{
|
||
|
|
if ($entity == '') {
|
||
|
|
throw new InvalidArgumentException(__('Sharing requested without an entity'));
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($objectId == 0) {
|
||
|
|
throw new InvalidArgumentException(__('Sharing form requested without an object'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @var ParsePermissionEntityEvent $event */
|
||
|
|
$event = $this->getDispatcher()->dispatch(
|
||
|
|
new ParsePermissionEntityEvent($entity, $objectId),
|
||
|
|
ParsePermissionEntityEvent::$NAME . lcfirst($entity)
|
||
|
|
);
|
||
|
|
|
||
|
|
return $event->getObject();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Updates a set of permissions from a set of groupIds
|
||
|
|
* @param Permission[] $permissions
|
||
|
|
* @param array $groupIds
|
||
|
|
*/
|
||
|
|
private function updatePermissions($permissions, $groupIds)
|
||
|
|
{
|
||
|
|
$this->getLog()->debug(sprintf('Received Permissions Array to update: %s', var_export($groupIds, true)));
|
||
|
|
|
||
|
|
// List of groupIds with view, edit and del assignments
|
||
|
|
foreach ($permissions as $row) {
|
||
|
|
// Check and see what permissions we have been provided for this selection
|
||
|
|
// If all permissions are 0, then the record is deleted
|
||
|
|
if (is_array($groupIds)) {
|
||
|
|
if (array_key_exists($row->groupId, $groupIds)) {
|
||
|
|
if(array_key_exists('view', $groupIds[$row->groupId])) {
|
||
|
|
$row->view = $groupIds[$row->groupId]['view'];
|
||
|
|
}
|
||
|
|
|
||
|
|
if(array_key_exists('edit', $groupIds[$row->groupId])) {
|
||
|
|
$row->edit = $groupIds[$row->groupId]['edit'];
|
||
|
|
}
|
||
|
|
|
||
|
|
if(array_key_exists('delete', $groupIds[$row->groupId])) {
|
||
|
|
$row->delete = $groupIds[$row->groupId]['delete'];
|
||
|
|
}
|
||
|
|
|
||
|
|
$row->save();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* User Applications
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
*/
|
||
|
|
public function myApplications(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$this->getState()->template = 'user-applications-form';
|
||
|
|
$this->getState()->setData([
|
||
|
|
'applications' => $this->applicationFactory->getAuthorisedByUserId($this->getUser()->userId),
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @SWG\Get(
|
||
|
|
* path="/user/pref",
|
||
|
|
* operationId="userPrefGet",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="Retrieve User Preferences",
|
||
|
|
* description="User preferences for non-state information, such as Layout designer zoom levels",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="preference",
|
||
|
|
* in="query",
|
||
|
|
* description="An optional preference",
|
||
|
|
* type="string",
|
||
|
|
* required=false
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=200,
|
||
|
|
* description="successful response",
|
||
|
|
* @SWG\Schema(
|
||
|
|
* type="array",
|
||
|
|
* @SWG\Items(ref="#/definitions/UserOption")
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function pref(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$requestedPreference = $request->getQueryParam('preference');
|
||
|
|
|
||
|
|
if (!empty($requestedPreference)) {
|
||
|
|
try {
|
||
|
|
$option = $this->getUser()->getOption($requestedPreference);
|
||
|
|
} catch (NotFoundException $exception) {
|
||
|
|
$option = [];
|
||
|
|
}
|
||
|
|
$this->getState()->setData($option);
|
||
|
|
} else {
|
||
|
|
$this->getState()->setData($this->getUser()->getUserOptions());
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @SWG\Post(
|
||
|
|
* path="/user/pref",
|
||
|
|
* operationId="userPrefEdit",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="Save User Preferences",
|
||
|
|
* description="Save User preferences for non-state information, such as Layout designer zoom levels",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="preference",
|
||
|
|
* in="body",
|
||
|
|
* required=true,
|
||
|
|
* @SWG\Schema(
|
||
|
|
* type="array",
|
||
|
|
* @SWG\Items(ref="#/definitions/UserOption")
|
||
|
|
* )
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=204,
|
||
|
|
* description="successful operation"
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
*/
|
||
|
|
public function prefEdit(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$parsedRequest = $this->getSanitizer($request->getParsedBody());
|
||
|
|
|
||
|
|
// Update this user preference with the preference array
|
||
|
|
$i = 0;
|
||
|
|
foreach ($parsedRequest->getArray('preference') as $pref) {
|
||
|
|
$i++;
|
||
|
|
|
||
|
|
$sanitizedPref = $this->getSanitizer($pref);
|
||
|
|
|
||
|
|
$option = $sanitizedPref->getString('option');
|
||
|
|
$value = $sanitizedPref->getString('value');
|
||
|
|
|
||
|
|
$this->getUser()->setOptionValue($option, $value);
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($i > 0) {
|
||
|
|
$this->getUser()->save();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'httpStatus' => 204,
|
||
|
|
'message' => ($i == 1) ? __('Updated Preference') : __('Updated Preferences')
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function membershipForm(Request $request, Response $response, $id)
|
||
|
|
{
|
||
|
|
$user = $this->userFactory->getById($id);
|
||
|
|
|
||
|
|
if (!$this->getUser()->checkEditable($user)) {
|
||
|
|
throw new AccessDeniedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Groups we are assigned to
|
||
|
|
$groupsAssigned = $this->userGroupFactory->getByUserId($user->userId);
|
||
|
|
|
||
|
|
$this->getState()->template = 'user-form-membership';
|
||
|
|
$this->getState()->setData([
|
||
|
|
'user' => $user,
|
||
|
|
'extra' => [
|
||
|
|
'userGroupsAssigned' => $groupsAssigned
|
||
|
|
],
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
||
|
|
*/
|
||
|
|
public function assignUserGroup(Request $request, Response $response, $id)
|
||
|
|
{
|
||
|
|
$user = $this->userFactory->getById($id);
|
||
|
|
|
||
|
|
if (!$this->getUser()->checkEditable($user)) {
|
||
|
|
throw new AccessDeniedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
// Go through each ID to assign
|
||
|
|
foreach ($sanitizedParams->getIntArray('userGroupId', ['default' => []]) as $userGroupId) {
|
||
|
|
$userGroup = $this->userGroupFactory->getById($userGroupId);
|
||
|
|
|
||
|
|
if (!$this->getUser()->checkEditable($userGroup)) {
|
||
|
|
throw new AccessDeniedException(__('Access Denied to UserGroup'));
|
||
|
|
}
|
||
|
|
|
||
|
|
$userGroup->assignUser($user);
|
||
|
|
$userGroup->save(['validate' => false]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Have we been provided with unassign id's as well?
|
||
|
|
foreach ($sanitizedParams->getIntArray('unassignUserGroupId', ['default' => []]) as $userGroupId) {
|
||
|
|
$userGroup = $this->userGroupFactory->getById($userGroupId);
|
||
|
|
|
||
|
|
if (!$this->getUser()->checkEditable($userGroup)) {
|
||
|
|
throw new AccessDeniedException(__('Access Denied to UserGroup'));
|
||
|
|
}
|
||
|
|
|
||
|
|
$userGroup->unassignUser($user);
|
||
|
|
$userGroup->save(['validate' => false]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'httpStatus' => 204,
|
||
|
|
'message' => sprintf(__('%s assigned to User Groups'), $user->userName),
|
||
|
|
'id' => $user->userId
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Update the User Welcome Tutorial to Seen
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
*/
|
||
|
|
public function userWelcomeSetUnSeen(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$this->getUser()->newUserWizard = 0;
|
||
|
|
$this->getUser()->save(['validate' => false]);
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'httpStatus' => 204,
|
||
|
|
'message' => sprintf(__('%s has started the welcome tutorial'), $this->getUser()->userName)
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Update the User Welcome Tutorial to Seen
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
*/
|
||
|
|
public function userWelcomeSetSeen(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$this->getUser()->newUserWizard = 1;
|
||
|
|
$this->getUser()->save(['validate' => false]);
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'httpStatus' => 204,
|
||
|
|
'message' => sprintf(__('%s has seen the welcome tutorial'), $this->getUser()->userName)
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Preferences Form
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
*/
|
||
|
|
public function preferencesForm(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$this->getState()->template = 'user-form-preferences';
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @SWG\Put(
|
||
|
|
* path="/user/pref",
|
||
|
|
* operationId="userPrefEditFromForm",
|
||
|
|
* tags={"user"},
|
||
|
|
* summary="Save User Preferences",
|
||
|
|
* description="Save User preferences from the Preferences form.",
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="navigationMenuPosition",
|
||
|
|
* in="formData",
|
||
|
|
* required=true,
|
||
|
|
* type="string"
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="useLibraryDuration",
|
||
|
|
* in="formData",
|
||
|
|
* required=false,
|
||
|
|
* type="integer"
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="showThumbnailColumn",
|
||
|
|
* in="formData",
|
||
|
|
* required=false,
|
||
|
|
* type="integer"
|
||
|
|
* ),
|
||
|
|
* @SWG\Parameter(
|
||
|
|
* name="rememberFolderTreeStateGlobally",
|
||
|
|
* in="formData",
|
||
|
|
* required=false,
|
||
|
|
* type="integer"
|
||
|
|
* ),
|
||
|
|
* @SWG\Response(
|
||
|
|
* response=204,
|
||
|
|
* description="successful operation"
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws InvalidArgumentException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
* @throws \Xibo\Support\Exception\DuplicateEntityException
|
||
|
|
*/
|
||
|
|
public function prefEditFromForm(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
$parsedParams = $this->getSanitizer($request->getParams());
|
||
|
|
|
||
|
|
$this->getUser()->setOptionValue('navigationMenuPosition', $parsedParams->getString('navigationMenuPosition', ['defaultOnEmptyString' => true]));
|
||
|
|
$this->getUser()->setOptionValue('useLibraryDuration', $parsedParams->getCheckbox('useLibraryDuration'));
|
||
|
|
$this->getUser()->setOptionValue('showThumbnailColumn', $parsedParams->getCheckbox('showThumbnailColumn'));
|
||
|
|
$this->getUser()->setOptionValue('isAlwaysUseManualAddUserForm', $parsedParams->getCheckbox('isAlwaysUseManualAddUserForm'));
|
||
|
|
$this->getUser()->setOptionValue('rememberFolderTreeStateGlobally', $parsedParams->getCheckbox('rememberFolderTreeStateGlobally'));
|
||
|
|
|
||
|
|
// Clear auto submits?
|
||
|
|
if ($parsedParams->getCheckbox('autoSubmitClearAll', ['checkboxReturnInteger' => false])) {
|
||
|
|
$this->getUser()->removeOptionByPrefix('autoSubmit.');
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getUser()->save();
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'httpStatus' => 204,
|
||
|
|
'message' => __('Updated Preferences')
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* User Onboarding Form
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws AccessDeniedException
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\ControllerNotImplemented
|
||
|
|
*/
|
||
|
|
public function onboardingForm(Request $request, Response $response)
|
||
|
|
{
|
||
|
|
// Only group admins or super admins can create Users.
|
||
|
|
if (!$this->getUser()->isSuperAdmin() && !$this->getUser()->isGroupAdmin()) {
|
||
|
|
throw new AccessDeniedException(__('Only super and group admins can create users'));
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getState()->template = 'user-form-onboarding';
|
||
|
|
$this->getState()->setData([
|
||
|
|
'groups' => $this->userGroupFactory->query(null, [
|
||
|
|
'isShownForAddUser' => 1
|
||
|
|
])
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set home folder form
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\GeneralException
|
||
|
|
*/
|
||
|
|
public function setHomeFolderForm(Request $request, Response $response, $id)
|
||
|
|
{
|
||
|
|
$user = $this->userFactory->getById($id);
|
||
|
|
$user->setChildAclDependencies($this->userGroupFactory);
|
||
|
|
|
||
|
|
if (!$this->getUser()->checkEditable($user)) {
|
||
|
|
throw new AccessDeniedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->getState()->template = 'user-form-home-folder';
|
||
|
|
$this->getState()->setData([
|
||
|
|
'user' => $user
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set home folder form
|
||
|
|
* @param Request $request
|
||
|
|
* @param Response $response
|
||
|
|
* @param $id
|
||
|
|
* @return \Psr\Http\Message\ResponseInterface|Response
|
||
|
|
* @throws GeneralException
|
||
|
|
* @throws \Xibo\Support\Exception\GeneralException
|
||
|
|
*/
|
||
|
|
public function setHomeFolder(Request $request, Response $response, $id)
|
||
|
|
{
|
||
|
|
$user = $this->userFactory->getById($id);
|
||
|
|
$user->setChildAclDependencies($this->userGroupFactory);
|
||
|
|
|
||
|
|
if (!$this->getUser()->checkEditable($user)) {
|
||
|
|
throw new AccessDeniedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!$this->getUser()->featureEnabled('folder.userHome')) {
|
||
|
|
throw new AccessDeniedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
$sanitizedParams = $this->getSanitizer($request->getParams());
|
||
|
|
|
||
|
|
// Build a user entity and save it
|
||
|
|
$user->setChildAclDependencies($this->userGroupFactory);
|
||
|
|
$user->load();
|
||
|
|
$user->homeFolderId = $sanitizedParams->getInt('homeFolderId');
|
||
|
|
$user->save();
|
||
|
|
|
||
|
|
// Return
|
||
|
|
$this->getState()->hydrate([
|
||
|
|
'message' => sprintf(__('Edited %s'), $user->userName),
|
||
|
|
'id' => $user->userId,
|
||
|
|
'data' => $user
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->render($request, $response);
|
||
|
|
}
|
||
|
|
}
|