467 lines
17 KiB
PHP
467 lines
17 KiB
PHP
<?php
|
|
|
|
/**
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; under version 2
|
|
* of the License (non-upgradable).
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Copyright (c) 2002-2008 (original work) Public Research Centre Henri Tudor & University of Luxembourg (under the project TAO & TAO2);
|
|
* 2008-2010 (update and modification) Deutsche Institut für Internationale Pädagogische Forschung (under the project TAO-TRANSFER);
|
|
* 2009-2012 (update and modification) Public Research Centre Henri Tudor (under the project TAO-SUSTAIN & TAO-DEV);
|
|
* 2013-2018 (update and modification) Open Assessment Technologies SA;
|
|
*
|
|
*/
|
|
|
|
use oat\generis\model\user\UserRdf;
|
|
use oat\generis\Helper\UserHashForEncryption;
|
|
use oat\generis\model\GenerisRdf;
|
|
use oat\generis\model\OntologyAwareTrait;
|
|
use oat\oatbox\event\EventManager;
|
|
use oat\tao\helpers\ApplicationHelper;
|
|
use oat\tao\helpers\UserHelper;
|
|
use oat\tao\model\TaoOntology;
|
|
use oat\tao\model\user\UserLocks;
|
|
use oat\oatbox\user\UserLanguageServiceInterface;
|
|
use oat\oatbox\log\LoggerAwareTrait;
|
|
use tao_helpers_form_FormContainer as FormContainer;
|
|
use tao_helpers_Display as DisplayHelper;
|
|
|
|
/**
|
|
* This controller provide the actions to manage the application users (list/add/edit/delete)
|
|
*
|
|
* @author CRP Henri Tudor - TAO Team - {@link http://www.tao.lu}
|
|
* @license GPLv2 http://www.opensource.org/licenses/gpl-2.0.php
|
|
* @package tao
|
|
*
|
|
*/
|
|
class tao_actions_Users extends tao_actions_CommonModule
|
|
{
|
|
use OntologyAwareTrait;
|
|
use LoggerAwareTrait;
|
|
|
|
/**
|
|
* @return EventManager
|
|
*/
|
|
protected function getEventManager()
|
|
{
|
|
return $this->getServiceLocator()->get(EventManager::SERVICE_ID);
|
|
}
|
|
|
|
/**
|
|
* Show the list of users
|
|
* @return void
|
|
*/
|
|
public function index()
|
|
{
|
|
$this->defaultData();
|
|
$userLangService = $this->getServiceLocator()->get(UserLanguageServiceInterface::class);
|
|
$this->setData('user-data-lang-enabled', $userLangService->isDataLanguageEnabled());
|
|
$this->setView('user/list.tpl');
|
|
}
|
|
|
|
/**
|
|
* Provide the user list data via json
|
|
* @return string|json
|
|
* @throws Exception
|
|
* @throws common_exception_InvalidArgumentType
|
|
*/
|
|
public function data()
|
|
{
|
|
$userService = $this->getServiceLocator()->get(tao_models_classes_UserService::class);
|
|
$userLangService = $this->getServiceLocator()->get(UserLanguageServiceInterface::class);
|
|
$page = $this->getRequestParameter('page');
|
|
$limit = $this->getRequestParameter('rows');
|
|
$sortBy = $this->getRequestParameter('sortby');
|
|
$sortOrder = $this->getRequestParameter('sortorder');
|
|
$filterQuery = $this->getRequestParameter('filterquery');
|
|
$filterColumns = $this->getRequestParameter('filtercolumns');
|
|
$start = $limit * $page - $limit;
|
|
|
|
$fieldsMap = [
|
|
'login' => GenerisRdf::PROPERTY_USER_LOGIN,
|
|
'firstname' => GenerisRdf::PROPERTY_USER_FIRSTNAME,
|
|
'lastname' => GenerisRdf::PROPERTY_USER_LASTNAME,
|
|
'email' => GenerisRdf::PROPERTY_USER_MAIL,
|
|
'guiLg' => GenerisRdf::PROPERTY_USER_UILG,
|
|
'roles' => GenerisRdf::PROPERTY_USER_ROLES
|
|
];
|
|
if ($userLangService->isDataLanguageEnabled()) {
|
|
$fieldsMap['dataLg'] = GenerisRdf::PROPERTY_USER_DEFLG;
|
|
}
|
|
|
|
// sorting
|
|
$order = array_key_exists($sortBy, $fieldsMap) ? $fieldsMap[$sortBy] : $fieldsMap['login'];
|
|
|
|
// filtering
|
|
$filters = [
|
|
GenerisRdf::PROPERTY_USER_LOGIN => '*',
|
|
];
|
|
|
|
if ($filterQuery) {
|
|
if (!$filterColumns) {
|
|
// if filter columns not set, search by all columns
|
|
$filterColumns = array_keys($fieldsMap);
|
|
}
|
|
$filters = array_flip(array_intersect_key($fieldsMap, array_flip($filterColumns)));
|
|
array_walk($filters, function (&$row, $key) use ($filterQuery) {
|
|
$row = $filterQuery;
|
|
});
|
|
}
|
|
|
|
$options = [
|
|
'recursive' => true,
|
|
'like' => true,
|
|
'chaining' => count($filters) > 1 ? 'or' : 'and',
|
|
'order' => $order,
|
|
'orderdir' => strtoupper($sortOrder),
|
|
];
|
|
|
|
// get total user count...
|
|
$total = $userService->getCountUsers($options, $filters);
|
|
|
|
// get the users using requested paging...
|
|
$users = $userService->getAllUsers(array_merge($options, [
|
|
'offset' => $start,
|
|
'limit' => $limit
|
|
]), $filters);
|
|
|
|
$rolesProperty = $this->getProperty(GenerisRdf::PROPERTY_USER_ROLES);
|
|
|
|
$response = new stdClass();
|
|
$readonly = [];
|
|
$index = 0;
|
|
|
|
/** @var core_kernel_classes_Resource $user */
|
|
foreach ($users as $user) {
|
|
$propValues = $user->getPropertiesValues(array_values($fieldsMap));
|
|
|
|
$roles = $user->getPropertyValues($rolesProperty);
|
|
$labels = [];
|
|
|
|
foreach ($roles as $uri) {
|
|
$labels[] = $this->getResource($uri)->getLabel();
|
|
}
|
|
|
|
$id = tao_helpers_Uri::encode($user->getUri());
|
|
$login = (string)current($propValues[GenerisRdf::PROPERTY_USER_LOGIN]);
|
|
$firstName = empty($propValues[GenerisRdf::PROPERTY_USER_FIRSTNAME]) ? '' : (string)current($propValues[GenerisRdf::PROPERTY_USER_FIRSTNAME]);
|
|
$lastName = empty($propValues[GenerisRdf::PROPERTY_USER_LASTNAME]) ? '' : (string)current($propValues[GenerisRdf::PROPERTY_USER_LASTNAME]);
|
|
$uiRes = empty($propValues[GenerisRdf::PROPERTY_USER_UILG]) ? null : current($propValues[GenerisRdf::PROPERTY_USER_UILG]);
|
|
if ($userLangService->isDataLanguageEnabled()) {
|
|
$dataRes = empty($propValues[GenerisRdf::PROPERTY_USER_DEFLG]) ? null : current($propValues[GenerisRdf::PROPERTY_USER_DEFLG]);
|
|
$response->data[$index]['dataLg'] = is_null($dataRes) ? '' : $dataRes->getLabel();
|
|
}
|
|
|
|
$email = (string)current($propValues[GenerisRdf::PROPERTY_USER_MAIL]);
|
|
$response->data[$index]['id'] = $id;
|
|
$response->data[$index]['login'] = DisplayHelper::htmlEscape($login);
|
|
$response->data[$index]['firstname'] = DisplayHelper::htmlEscape($firstName);
|
|
$response->data[$index]['lastname'] = DisplayHelper::htmlEscape($lastName);
|
|
$response->data[$index]['email'] = DisplayHelper::htmlEscape($email);
|
|
$response->data[$index]['roles'] = implode(', ', $labels);
|
|
$response->data[$index]['guiLg'] = is_null($uiRes) ? '' : $uiRes->getLabel();
|
|
|
|
$statusInfo = $this->getUserLocksService()->getStatusDetails($login);
|
|
$response->data[$index]['lockable'] = $statusInfo['lockable'];
|
|
$response->data[$index]['locked'] = $statusInfo['locked'];
|
|
$response->data[$index]['status'] = $statusInfo['status'];
|
|
|
|
if ($user->getUri() == LOCAL_NAMESPACE . TaoOntology::DEFAULT_USER_URI_SUFFIX) {
|
|
$readonly[$id] = true;
|
|
}
|
|
|
|
$index++;
|
|
}
|
|
|
|
$response->page = floor($start / $limit) + 1;
|
|
$response->total = ceil($total / $limit);
|
|
$response->records = count($users);
|
|
$response->readonly = $readonly;
|
|
|
|
$this->returnJson($response, 200);
|
|
}
|
|
|
|
/**
|
|
* Remove a user
|
|
* The request must contains the user's login to remove
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws common_exception_Error
|
|
*/
|
|
public function delete()
|
|
{
|
|
try {
|
|
$this->validateCsrf();
|
|
} catch (common_exception_Unauthorized $e) {
|
|
$this->response = $this->getPsrResponse()->withStatus(403, __('Unable to process your request'));
|
|
return;
|
|
}
|
|
|
|
$userService = $this->getServiceLocator()->get(tao_models_classes_UserService::class);
|
|
|
|
$deleted = false;
|
|
$message = __('An error occurred during user deletion');
|
|
if (ApplicationHelper::isDemo()) {
|
|
$message = __('User deletion not permitted on a demo instance');
|
|
} elseif ($this->hasRequestParameter('uri')) {
|
|
$user = $this->getResource(tao_helpers_Uri::decode($this->getRequestParameter('uri')));
|
|
$this->checkUser($user->getUri());
|
|
|
|
if ($userService->removeUser($user)) {
|
|
$deleted = true;
|
|
$message = __('User deleted successfully');
|
|
}
|
|
}
|
|
$this->returnJson([
|
|
'success' => $deleted,
|
|
'message' => $message
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* form to add a user
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws \oat\generis\model\user\PasswordConstraintsException
|
|
* @throws tao_models_classes_dataBinding_GenerisFormDataBindingException
|
|
*/
|
|
public function add()
|
|
{
|
|
$this->defaultData();
|
|
$container = new tao_actions_form_Users(
|
|
$this->getClass(TaoOntology::CLASS_URI_TAO_USER),
|
|
null,
|
|
false,
|
|
[FormContainer::CSRF_PROTECTION_OPTION => true]
|
|
);
|
|
$form = $container->getForm();
|
|
|
|
if ($form->isSubmited() && $form->isValid()) {
|
|
$values = $form->getValues();
|
|
$plainPassword = $values['password1'];
|
|
unset($values['password1'], $values['password2']);
|
|
|
|
$values[UserRdf::PROPERTY_PASSWORD] = core_kernel_users_Service::getPasswordHash()
|
|
->encrypt($plainPassword);
|
|
$hashForKey = UserHashForEncryption::hash($plainPassword);
|
|
|
|
/** @var tao_models_classes_UserService $userService */
|
|
$userService = $this->getServiceLocator()->get(tao_models_classes_UserService::SERVICE_ID);
|
|
|
|
if ($userService->triggerUpdatedEvent($container->getUser(), $values, $hashForKey)) {
|
|
$this->setData('message', __('User added'));
|
|
$this->setData('exit', true);
|
|
}
|
|
}
|
|
|
|
$this->setData('loginUri', tao_helpers_Uri::encode(GenerisRdf::PROPERTY_USER_LOGIN));
|
|
$this->setData('formTitle', __('Add a user'));
|
|
$this->setData('myForm', $form->render());
|
|
$this->setView('user/form.tpl');
|
|
}
|
|
|
|
/**
|
|
* @throws Exception
|
|
* @throws common_exception_BadRequest
|
|
*/
|
|
public function addInstanceForm()
|
|
{
|
|
$this->defaultData();
|
|
if (!$this->isXmlHttpRequest()) {
|
|
throw new common_exception_BadRequest('wrong request mode');
|
|
}
|
|
|
|
$clazz = $this->getClass(TaoOntology::CLASS_URI_TAO_USER);
|
|
$formContainer = new tao_actions_form_CreateInstance([$clazz], [FormContainer::CSRF_PROTECTION_OPTION => true]);
|
|
$form = $formContainer->getForm();
|
|
|
|
if ($form->isSubmited() && $form->isValid()) {
|
|
$properties = $form->getValues();
|
|
$instance = $this->createInstance([$clazz], $properties);
|
|
|
|
$this->setData('message', __('%s created', $instance->getLabel()));
|
|
$this->setData('selectTreeNode', $instance->getUri());
|
|
}
|
|
|
|
$this->setData('formTitle', __('Create instance of ') . $clazz->getLabel());
|
|
$this->setData('myForm', $form->render());
|
|
|
|
$this->setView('form.tpl', 'tao');
|
|
}
|
|
|
|
/**
|
|
* action used to check if a login can be used
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws common_exception_BadRequest
|
|
*/
|
|
public function checkLogin()
|
|
{
|
|
$this->defaultData();
|
|
$userService = $this->getServiceLocator()->get(tao_models_classes_UserService::class);
|
|
if (!$this->isXmlHttpRequest()) {
|
|
throw new common_exception_BadRequest('wrong request mode');
|
|
}
|
|
|
|
$data = ['available' => false];
|
|
if ($this->hasRequestParameter('login')) {
|
|
$data['available'] = $userService->loginAvailable($this->getRequestParameter('login'));
|
|
}
|
|
|
|
$this->returnJson($data);
|
|
}
|
|
|
|
/**
|
|
* Form to edit a user
|
|
* User login must be set in parameter
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws \oat\generis\model\user\PasswordConstraintsException
|
|
* @throws common_exception_Error
|
|
* @throws tao_models_classes_dataBinding_GenerisFormDataBindingException
|
|
*/
|
|
public function edit()
|
|
{
|
|
$this->defaultData();
|
|
$user = $this->getUserResource();
|
|
|
|
$types = $user->getTypes();
|
|
$myFormContainer = new tao_actions_form_Users(
|
|
reset($types),
|
|
$user,
|
|
false,
|
|
[FormContainer::CSRF_PROTECTION_OPTION => true]
|
|
);
|
|
$myForm = $myFormContainer->getForm();
|
|
|
|
if ($myForm->isSubmited() && $myForm->isValid()) {
|
|
$values = $myForm->getValues();
|
|
$hashForKey = null;
|
|
|
|
if (!empty($values['password2']) && !empty($values['password3'])) {
|
|
$plainPassword = $values['password2'];
|
|
$values[UserRdf::PROPERTY_PASSWORD] = core_kernel_users_Service::getPasswordHash()
|
|
->encrypt($plainPassword);
|
|
$hashForKey = UserHashForEncryption::hash($plainPassword);
|
|
}
|
|
|
|
unset($values['password2'], $values['password3']);
|
|
|
|
if (!preg_match('/[A-Z]{2,4}$/', trim($values[GenerisRdf::PROPERTY_USER_UILG]))) {
|
|
unset($values[GenerisRdf::PROPERTY_USER_UILG]);
|
|
}
|
|
if (!preg_match('/[A-Z]{2,4}$/', trim($values[GenerisRdf::PROPERTY_USER_DEFLG]))) {
|
|
unset($values[GenerisRdf::PROPERTY_USER_DEFLG]);
|
|
}
|
|
|
|
/** @var tao_models_classes_UserService $userService */
|
|
$userService = $this->getServiceLocator()->get(tao_models_classes_UserService::SERVICE_ID);
|
|
$userService->checkCurrentUserAccess($values[GenerisRdf::PROPERTY_USER_ROLES]);
|
|
|
|
// leave roles which are not in the allowed list for current user
|
|
$oldRoles = $userService->getUserRoles($user);
|
|
$allowedRoles = $userService->getPermittedRoles($userService->getCurrentUser(), $oldRoles, false);
|
|
$staticRoles = array_diff($oldRoles, $allowedRoles);
|
|
$values[GenerisRdf::PROPERTY_USER_ROLES] = array_merge($values[GenerisRdf::PROPERTY_USER_ROLES], $staticRoles);
|
|
|
|
if ($userService->triggerUpdatedEvent($user, $values, $hashForKey)) {
|
|
$this->setData('message', __('User saved'));
|
|
}
|
|
}
|
|
|
|
$this->setData('formTitle', __('Edit a user'));
|
|
$this->setData('myForm', $myForm->render());
|
|
$this->setView('user/form.tpl');
|
|
}
|
|
|
|
/**
|
|
* Removes all locks from user account
|
|
* @throws Exception
|
|
*/
|
|
public function unlock()
|
|
{
|
|
try {
|
|
$this->validateCsrf();
|
|
} catch (common_exception_Unauthorized $e) {
|
|
$this->response = $this->getPsrResponse()->withStatus(403, __('Unable to process your request'));
|
|
return;
|
|
}
|
|
$user = UserHelper::getUser($this->getUserResource());
|
|
|
|
if ($this->getUserLocksService()->unlockUser($user)) {
|
|
$this->returnJson(['success' => true, 'message' => __('User %s successfully unlocked', UserHelper::getUserLogin(UserHelper::getUser($user)))]);
|
|
} else {
|
|
$this->returnJson(['success' => false, 'message' => __('User %s can not be unlocked', UserHelper::getUserLogin(UserHelper::getUser($user)))]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Locks user account, he can not login in to the system anymore
|
|
* @throws Exception
|
|
*/
|
|
public function lock()
|
|
{
|
|
try {
|
|
$this->validateCsrf();
|
|
} catch (common_exception_Unauthorized $e) {
|
|
$this->response = $this->getPsrResponse()->withStatus(403, __('Unable to process your request'));
|
|
return;
|
|
}
|
|
|
|
$user = UserHelper::getUser($this->getUserResource());
|
|
|
|
if ($this->getUserLocksService()->lockUser($user)) {
|
|
$this->returnJson(['success' => true, 'message' => __('User %s successfully locked', UserHelper::getUserLogin(UserHelper::getUser($user)))]);
|
|
} else {
|
|
$this->returnJson(['success' => false, 'message' => __('User %s can not be locked', UserHelper::getUserLogin(UserHelper::getUser($user)))]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @throws common_exception_MissingParameter
|
|
* @throws Exception
|
|
* @return core_kernel_classes_Resource
|
|
*/
|
|
private function getUserResource()
|
|
{
|
|
if (!$this->hasRequestParameter('uri')) {
|
|
throw new common_exception_MissingParameter('uri');
|
|
}
|
|
|
|
$userUri = tao_helpers_Uri::decode($this->getRequestParameter('uri'));
|
|
$this->checkUser($userUri);
|
|
|
|
return $this->getResource($userUri);
|
|
}
|
|
|
|
/**
|
|
* Check whether user user data can be changed
|
|
* @param $uri
|
|
* @throws Exception
|
|
*/
|
|
private function checkUser($uri)
|
|
{
|
|
if ($uri === LOCAL_NAMESPACE . TaoOntology::DEFAULT_USER_URI_SUFFIX) {
|
|
throw new Exception('Default user data cannot be changed');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return UserLocks
|
|
*/
|
|
protected function getUserLocksService()
|
|
{
|
|
return $this->getServiceLocator()->get(UserLocks::SERVICE_ID);
|
|
}
|
|
}
|