<?php
/**
* SeekQuarry/Yioop --
* Open Source Pure PHP Search Engine, Crawler, and Indexer
*
* Copyright (C) 2009 - 2026 Chris Pollett chris@pollett.org
*
* LICENSE:
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <https://www.gnu.org/licenses/>.
*
* END LICENSE
*
* @author Chris Pollett chris@pollett.org
* @license https://www.gnu.org/licenses/ GPL3
* @link https://www.seekquarry.com/
* @copyright 2009 - 2026
* @filesource
*/
namespace seekquarry\yioop\controllers\components;
use seekquarry\yioop\configs as C;
use seekquarry\yioop\library as L;
use seekquarry\yioop\library\mail as ML;
/**
* Component of the Yioop control panel used to handle activitys for
* managing accounts, users, roles, and groups. i.e., Settings of users
* and groups, what roles and groups a user has, what roles and users
* a group has, and what activities make up a role. It is used by
* AdminController
*
* @author Chris Pollett
*/
class AccountaccessComponent extends Component
{
/**
* Used to handle the change current user password admin activity
*
* @return array $data SCRIPT field contains success or failure message
*/
public function manageAccount()
{
$parent = $this->parent;
$signin_model = $parent->model("signin");
$group_model = $parent->model("group");
$user_model = $parent->model("user");
$impression_model = $parent->model("impression");
$crawl_model = $parent->model("crawl");
$role_model = $parent->model("role");
$profile_model = $parent->model("profile");
$locale_model = $parent->model("locale");
$cron_model = $parent->model("cron");
$credit_model = $parent->model("credit");
$profile = $profile_model->getProfile(C\WORK_DIRECTORY);
$data["ELEMENT"] = "manageaccount";
$data['SCRIPT'] = "";
$data["INCLUDE_SCRIPTS"] ??= [];
$data["INCLUDE_SCRIPTS"][] = "register_validator";
$data['MESSAGE'] = "";
$changed_settings_flag = false;
$changed_locale_flag = true;
$changed_user = false;
$data['yioop_bot_configuration'] = $profile['CONFIGURE_BOT'];
if ($profile['CONFIGURE_BOT'] == 'enable_bot_users') {
$data['yioop_bot_configuration'] = true;
} else {
$data['yioop_bot_configuration'] = false;
}
$user_id = $_SESSION['USER_ID'];
if (isset($_REQUEST['arg']) &&
$_REQUEST['arg'] == "stopactingas" &&
!empty($_SESSION['IMPERSONATOR_RETURN_ID'])) {
$return_id = $_SESSION['IMPERSONATOR_RETURN_ID'];
$return_name = $signin_model->getUserName($return_id);
$supplied_password =
$_REQUEST['impersonator_password'] ?? "";
$check_name = $return_name;
$reauth = $signin_model->checkValidSignin($check_name,
$supplied_password);
if (!$reauth) {
return $parent->redirectWithMessage(
tl('accountaccess_component_reauth_failed'),
false, false, true);
}
$acting_as = $_SESSION['USER_NAME'] ?? '';
unset($_SESSION['IMPERSONATOR_RETURN_ID']);
unset($_SESSION['IMPERSONATOR_RETURN_NAME']);
$_SESSION['USER_ID'] = $return_id;
$_SESSION['USER_NAME'] = $return_name;
$_REQUEST[C\p('CSRF_TOKEN')] =
$parent->generateCSRFToken($return_id);
L\crawlLog("ACT AS: user " . $return_name .
" (id $return_id) stopped acting as user " .
$acting_as);
unset($_REQUEST['route']['c'], $_REQUEST['route']['a']);
$_REQUEST['c'] = 'admin';
$_REQUEST['a'] = 'manageUsers';
return $parent->redirectWithMessage(
tl('accountaccess_component_stopped_acting'),
false, false, true);
}
/**
* Preparing data for recommending users with threads and groups
*/
$cron_timestamp =
$cron_model->getCronTime("item_group_recommendations");
$data['THREAD_RECOMMENDATIONS'] =
$user_model->getRecommendations($cron_timestamp,
$user_id, C\THREAD_RECOMMENDATION);
$data['GROUP_RECOMMENDATIONS'] =
$user_model->getRecommendations($cron_timestamp,
$user_id, C\GROUP_RECOMMENDATION);
$data['RESOURCE_RECOMMENDATIONS'] =
$user_model->getResourceRecommendations($user_id);
$username = $signin_model->getUserName($user_id);
$data["USER"] = $user_model->getUser($username);
$data["CRAWL_MANAGER"] = false;
if ($user_model->isAllowedUserActivity($user_id, "manageCrawls")) {
$data['NO_TOPMARGIN'] = true;
$this->initCrawlBadges($user_id, $data);
}
if (isset($_REQUEST['edit']) && $_REQUEST['edit'] == "true") {
$data['EDIT_USER'] = true;
}
if (isset($_REQUEST['edit_pass'])) {
if ($_REQUEST['edit_pass'] == "true") {
$data['EDIT_USER'] = true;
$data['EDIT_PASSWORD'] = true;
} else {
$data['EDIT_USER'] = true;
}
}
if (isset($_REQUEST['edit_recovery'])) {
if ($_REQUEST['edit_recovery'] == "true") {
$data['EDIT_USER'] = true;
$data['EDIT_RECOVERY'] = true;
} else {
$data['EDIT_USER'] = true;
}
}
if (isset($_REQUEST['edit_purchase']) &&
$_REQUEST['edit_purchase'] == "true") {
$data['EDIT_USER'] = true;
}
if (!empty($data['EDIT_USER'])) {
$user_session = $user_model->getUserSession($user_id);
if (C\p('RECOVERY_MODE') == C\QUESTIONS_RECOVERY &&
!empty($data['EDIT_RECOVERY'])) {
$recovery_user = $user_model->getUserById($user_id);
$data['RECOVERY_QUESTION'] =
empty($recovery_user['RECOVERY_QUESTION']) ? "" :
$parent->clean($recovery_user['RECOVERY_QUESTION'],
"string");
$data['RECOVERY_ANSWER'] =
empty($recovery_user['RECOVERY_ANSWER']) ? "" :
C\RECOVERY_ANSWER_PLACEHOLDER;
}
}
$data['USERNAME'] = $username;
$data['NUM_SHOWN'] = 5;
$personal_group_name = C\PERSONAL_GROUP_PREFIX . $user_id;
if (($personal_group_id =
$group_model->getGroupId($personal_group_name)) < 0) {
$personal_group_id = $group_model->addGroup($personal_group_name,
$user_id, C\INVITE_ONLY_JOIN, C\ACTIVE_STATUS,
C\NON_VOTING_GROUP, C\FOREVER, 0);
}
$this->initSocialBadges($user_id, $data);
$groups = $group_model->getUserGroups($user_id, "", [], 0,
min($data['NUM_GROUPS'], 100));
$data['GROUPS'] = [];
$i = 0;
$len = strlen(C\PERSONAL_GROUP_PREFIX);
$group_ids = [];
foreach ($groups as $group) {
$group_ids[] = $group['GROUP_ID'];
}
$most_recent_views = $impression_model->mostRecentGroupViews($user_id,
$group_ids);
foreach ($groups as $group) {
$group_id = $group['GROUP_ID'];
$data['GROUPS'][$i] = $group;
$data['GROUPS'][$i]['MEMBER_STATUS'] =
$data['GROUPS'][$i]['STATUS'];
$data['GROUPS'][$i]["MOST_RECENT_VIEW"] =
$most_recent_views[$group_id] ?? 0;
$item = $group_model->getMostRecentGroupPost($group_id);
$data['GROUPS'][$i]['NUM_POSTS'] =
$group_model->getGroupPostCount($group_id);
$data['GROUPS'][$i]['NEW_POSTS'] =
$group_model->getGroupPostCount($group_id,
$data['GROUPS'][$i]["MOST_RECENT_VIEW"]);
$data['GROUPS'][$i]['NUM_THREADS'] =
$group_model->getGroupThreadCount($group_id);
$data['GROUPS'][$i]['NUM_PAGES'] =
$group_model->getGroupPageCount($group_id);
if (isset($item['TITLE'])) {
$data['GROUPS'][$i]["ITEM_TITLE"] = $item['TITLE'];
$data['GROUPS'][$i]["THREAD_ID"] = $item['PARENT_ID'];
} else {
$data['GROUPS'][$i]["ITEM_TITLE"] =
tl('accountaccess_component_no_posts_yet');
$data['GROUPS'][$i]["THREAD_ID"] = -1;
}
$i++;
}
usort($data['GROUPS'], function($group1, $group2) {
if ($group1["MOST_RECENT_VIEW"] == $group2["MOST_RECENT_VIEW"]) {
return 0;
}
return ($group1["MOST_RECENT_VIEW"] > $group2["MOST_RECENT_VIEW"]) ?
-1 : 1;
});
$data['GROUPS'] = array_slice($data['GROUPS'], 0, $data['NUM_SHOWN']);
$data['NUM_SHOWN'] = count($data['GROUPS']);
$languages = $locale_model->getLocaleList();
foreach ($languages as $language) {
$data['LANGUAGES'][$language['LOCALE_TAG']] =
$language['LOCALE_NAME'];
}
if (isset($_REQUEST['lang']) &&
in_array($_REQUEST['lang'],
array_keys($data['LANGUAGES']))) {
$old_value = isset($_SESSION['l']) ?
$_SESSION['l'] : L\getLocaleTag();
$_SESSION['l'] = $_REQUEST['lang'];
L\setLocaleObject($_SESSION['l']);
if ($old_value != $_SESSION['l'] || empty($user_session['l'])
|| $user_session['l'] != $_SESSION['l']) {
$changed_locale_flag = true;
$user_session['l'] = $_SESSION['l'];
}
}
$data['LANGUAGES_TO_SHOW'] = 1;
$data['LOCALE_TAG'] = L\getLocaleTag();
$data['NUM_MIXES'] = count($crawl_model->getMixList($user_id));
$arg = (isset($_REQUEST['arg'])) ? $_REQUEST['arg'] : "";
switch ($arg) {
case "updateuser":
if (isset($data['EDIT_PASSWORD'])) {
if (isset($_REQUEST['new_password']) ) {
$pass_len = strlen($_REQUEST['new_password']);
if ($pass_len > C\LONG_NAME_LEN) {
return $parent->redirectWithMessage(
tl('accountaccess_component_passwords_too_long'),
["edit", "edit_pass"]);
}
}
if (!isset($_REQUEST['retype_password']) ||
!isset($_REQUEST['new_password']) ||
$_REQUEST['retype_password'] !=
$_REQUEST['new_password']) {
return $parent->redirectWithMessage(
tl('accountaccess_component_passwords_dont_match'),
["edit", "edit_pass"]);
}
if (!empty(L\passwordPolicyViolations(
$_REQUEST['new_password']))) {
return $parent->redirectWithMessage(
tl('accountaccess_component_password_requirements'),
["edit", "edit_pass"]);
}
$result = $signin_model->checkValidSignin($username,
$parent->clean($_REQUEST['password'], "password") );
if (!$result) {
return $parent->redirectWithMessage(
tl('accountaccess_component_invalid_password'),
["edit", "edit_pass"]);
}
$signin_model->changePassword($username,
$parent->clean($_REQUEST['new_password'],
"password"));
if ($changed_settings_flag) {
$user_model->setUserSession($user_id, $user_session);
}
$_REQUEST['edit'] = "true";
return $parent->redirectWithMessage(
tl('accountaccess_component_password_updated'),
["edit"]);
}
if (!empty($data['EDIT_RECOVERY']) &&
C\p('RECOVERY_MODE') == C\QUESTIONS_RECOVERY &&
!empty($_REQUEST['recovery_question']) &&
!empty($_REQUEST['recovery_answer'])) {
$result = $signin_model->checkValidSignin($username,
$parent->clean($_REQUEST['password'] ?? "",
"password") );
if (!$result) {
$_REQUEST['edit_recovery'] = "true";
return $parent->redirectWithMessage(
tl('accountaccess_component_invalid_password'),
["edit", "edit_recovery"]);
}
$question = mb_substr($_REQUEST['recovery_question'], 0,
C\RECOVERY_QUESTION_LEN);
$answer = $_REQUEST['recovery_answer'];
if ($answer === C\RECOVERY_ANSWER_PLACEHOLDER) {
$answer = null;
}
$user_model->setRecoveryQuestion($user_id, $question,
$answer);
$_REQUEST['edit'] = "true";
return $parent->redirectWithMessage(
tl('accountaccess_component_answers_updated'),
["edit"]);
}
$user = [];
$user['USER_ID'] = $user_id;
$fields = ["EMAIL" => C\LONG_NAME_LEN,
"FIRST_NAME" => C\NAME_LEN, "LAST_NAME" => C\NAME_LEN];
foreach ($fields as $field => $len) {
if (isset($_REQUEST[$field])) {
$user[$field] = substr($parent->clean(
$_REQUEST[$field], "string"), 0, $len);
if ($data["USER"][$field] != $user[$field]) {
$data['USER'][$field] = $user[$field];
$changed_user = true;
}
}
}
if (isset($user['EMAIL']) &&
ML\MailSiteFactory::isForbiddenAccountEmail(
$user['EMAIL'])) {
return $parent->redirectWithMessage(
tl('accountaccess_component_email_system_address'),
["edit"]);
}
$is_bot_updated = false;
$is_bot_toggle = false;
$bot_role_id = $role_model->getRoleId('Bot User');
if (isset($_REQUEST['IS_BOT_USER']) && $bot_role_id) {
$is_bot_toggle = 1;
$is_bot_updated = true;
} else if ($bot_role_id) {
$is_bot_toggle = 0;
}
if (isset($_REQUEST['BOT_TOKEN'])) {
$user['BOT_TOKEN'] = $_REQUEST['BOT_TOKEN'];
$data['USER']['BOT_TOKEN'] = $user['BOT_TOKEN'];
$is_bot_updated = true;
}
if (isset($_REQUEST['BOT_CALLBACK_URL'])){
$user['CALLBACK_URL'] = $_REQUEST['BOT_CALLBACK_URL'];
$data['USER']['CALLBACK_URL'] = $user['CALLBACK_URL'];
$is_bot_updated = true;
}
if (isset($_FILES['user_icon']['name']) &&
$_FILES['user_icon']['name'] != "") {
if (!in_array($_FILES['user_icon']['type'],
['image/png', 'image/gif', 'image/jpeg',
'image/webp', 'image/x-icon'])) {
return $parent->redirectWithMessage(
tl('accountaccess_component_unknown_imagetype'),
["edit", "edit_pass"]);
}
if ($_FILES['user_icon']['size'] > C\THUMB_SIZE) {
return $parent->redirectWithMessage(
tl('accountaccess_component_icon_too_big'),
["edit", "edit_pass"]);
}
if (empty($_FILES['user_icon']['data'])) {
$user['IMAGE_STRING'] = file_get_contents(
$_FILES['user_icon']['tmp_name']);
$changed_user = true;
} else {
$user['IMAGE_STRING'] = $_FILES['user_icon']['data'];
$changed_user = true;
}
$folder = $user_model->getUserIconFolder(
$user['USER_ID']);
if (!$folder) {
return $parent->redirectWithMessage(
tl('accountaccess_component_no_user_folder'),
["edit", "edit_pass"]);
}
}
if ($changed_user || $is_bot_updated) {
$result = $signin_model->checkValidSignin($username,
$parent->clean($_REQUEST['password'] ?? "",
"password") );
if (!$result) {
return $parent->redirectWithMessage(
tl('accountaccess_component_valid_password_required'),
["edit"]);
}
}
if ($changed_user) {
$user_model->updateUser($user);
}
if ($changed_settings_flag || $changed_locale_flag) {
$user_model->setUserSession($user_id, $user_session);
}
if ($is_bot_updated) {
if ($is_bot_toggle === 1) {
$data['USER']['IS_BOT_USER'] = 1;
$role_model->addUserRole($user_id, $bot_role_id);
} else if ($is_bot_toggle === 0) {
$data['USER']['IS_BOT_USER'] = 0;
$role_model->deleteUserRole($user_id, $bot_role_id);
}
$user_model->updateBot($user);
}
$data['USER']['USER_ICON'] = $user_model->getUserIconUrl(
$user['USER_ID']);
unset($user['IMAGE_STRING']);
return $parent->redirectWithMessage(
tl('accountaccess_component_user_updated'),
["edit", "edit_pass"]);
case "purchaserole":
$message = $this->purchaseRole($role_model,
$credit_model, $user_id,
intval($_REQUEST['purchase_role_id'] ?? 0));
return $parent->redirectWithMessage($message,
["edit", "edit_purchase"]);
case "unsubscriberole":
$message = $this->unsubscribeRole($role_model, $user_id,
intval($_REQUEST['unsubscribe_role_id'] ?? 0));
return $parent->redirectWithMessage($message, ["edit"]);
}
$this->renewExpiredRoleSubscriptions($role_model, $credit_model,
$user_id);
$sellable_roles = $role_model->getSellableRoles();
$data['SELLABLE_ROLES_EXIST'] = !empty($sellable_roles);
if ($data['SELLABLE_ROLES_EXIST']) {
$data['USER_ROLE_LIST'] =
$role_model->getUserRoles($user_id, "");
$data['USER_SELLABLE_ROLES'] =
$role_model->getUserSellableRoles($user_id);
$data['CREDIT_BALANCE'] =
$credit_model->getCreditBalance($user_id);
$held_ids = [];
foreach ($data['USER_ROLE_LIST'] as $role) {
$held_ids[(int)$role['ROLE_ID']] = true;
}
$purchasable = [];
foreach ($sellable_roles as $role) {
if (empty($held_ids[(int)$role['ROLE_ID']])) {
$purchasable[] = $role;
}
}
$data['PURCHASABLE_ROLES'] = $purchasable;
if (isset($_REQUEST['edit_purchase']) &&
$_REQUEST['edit_purchase'] == "true") {
$data['EDIT_PURCHASE'] = true;
}
}
return $data;
}
/**
* Converts a role's charge frequency into the number of seconds a
* purchase of it lasts. A one-time ("once") purchase never lapses and
* returns the FOREVER sentinel; the recurring frequencies return
* their length in seconds, so a grant's expiry can be advanced by
* that amount.
*
* @param string $frequency one of the CHARGE_FREQUENCY values
* @return int seconds the purchase lasts, or FOREVER when permanent
*/
private function chargeFrequency($frequency)
{
$months_per_semi_annual = 6;
$seconds = [
'once' => C\FOREVER,
'monthly' => C\ONE_MONTH,
'semi_annual' => $months_per_semi_annual * C\ONE_MONTH,
'yearly' => C\ONE_YEAR,
'test_minute' => C\ONE_MINUTE];
return $seconds[$frequency] ?? C\FOREVER;
}
/**
* Buys a sellable role for a user, or resumes one they cancelled.
* If the user still holds the role and it has not lapsed, buying it
* again only turns renewing back on and charges nothing until the
* current paid period ends. Otherwise it checks the role is on sale
* and the balance covers the cost, then debits the cost and grants
* (or re-dates) the role with an expiry one billing period out, or a
* never-lapsing grant for a one-time purchase.
*
* @param object $role_model model used to read and grant roles
* @param object $credit_model model used to read and debit credits
* @param int $user_id id of the buyer
* @param int $role_id id of the role to buy
* @return string the status message to show the buyer
*/
private function purchaseRole($role_model, $credit_model, $user_id,
$role_id)
{
$for_sale = null;
foreach ($role_model->getSellableRoles() as $role) {
if ((int)$role['ROLE_ID'] === (int)$role_id) {
$for_sale = $role;
break;
}
}
if (empty($for_sale)) {
return tl('accountaccess_component_role_not_for_sale');
}
$now = time();
$held = null;
foreach ($role_model->getUserSellableRoles($user_id) as $row) {
if ((int)$row['ROLE_ID'] === (int)$role_id) {
$held = $row;
break;
}
}
if ($held !== null) {
$held_expires = (int)$held['EXPIRES'];
if ($held_expires === C\FOREVER || $held_expires > $now) {
if ((int)$held['WILL_RENEW'] === 1) {
return tl('accountaccess_component_role_already_held');
}
$role_model->setUserRoleRenew($user_id, $role_id, 1);
return tl('accountaccess_component_role_resubscribed');
}
}
$cost = (int)$for_sale['ROLE_COST'];
if ($credit_model->getCreditBalance($user_id) < $cost) {
return tl('accountaccess_component_role_no_credits');
}
$period = $this->chargeFrequency($for_sale['CHARGE_FREQUENCY']);
$expires = ($period === C\FOREVER) ? C\FOREVER : $now + $period;
$credit_model->updateCredits($user_id, -$cost,
'accountaccess_component_role_purchase');
if ($held !== null) {
$role_model->updateUserRoleExpires($user_id, $role_id,
$expires);
$role_model->setUserRoleRenew($user_id, $role_id, 1);
} else {
$role_model->addUserRole($user_id, $role_id, $expires, 1);
}
return tl('accountaccess_component_role_purchased');
}
/**
* Cancels a user's subscription to a sellable role. If the grant is
* still within its paid period it is kept but stops renewing, so the
* user keeps the role until it lapses and it is removed then; the
* account page shows the expiry date meanwhile. A grant that has
* already lapsed, or a one-time permanent grant, is removed at once.
*
* @param object $role_model model used to read and update grants
* @param int $user_id id of the user cancelling
* @param int $role_id id of the role to cancel
* @return string the status message to show the user
*/
private function unsubscribeRole($role_model, $user_id, $role_id)
{
$held = null;
foreach ($role_model->getUserSellableRoles($user_id) as $row) {
if ((int)$row['ROLE_ID'] === (int)$role_id) {
$held = $row;
break;
}
}
if ($held === null) {
return tl('accountaccess_component_role_unsubscribed');
}
$expires = (int)$held['EXPIRES'];
if ($expires !== C\FOREVER && $expires > time()) {
$role_model->setUserRoleRenew($user_id, $role_id, 0);
return tl('accountaccess_component_role_cancelled');
}
$role_model->deleteUserRole($user_id, $role_id);
return tl('accountaccess_component_role_unsubscribed');
}
/**
* Settles a user's lapsed sellable roles when the account page is
* viewed. A grant the user cancelled is removed once it lapses. A
* grant still set to renew has its expiry moved forward one billing
* period at a time, spending credits, for as many periods as the
* balance can cover. A one-time ("once") grant never lapses and is
* left alone.
*
* @param object $role_model model used to read and update grants
* @param object $credit_model model used to read and debit credits
* @param int $user_id id of the user whose subscriptions to settle
*/
private function renewExpiredRoleSubscriptions($role_model,
$credit_model, $user_id)
{
$balance = $credit_model->getCreditBalance($user_id);
$now = time();
foreach ($role_model->getUserSellableRoles($user_id) as $role) {
$expires = (int)$role['EXPIRES'];
if ($expires === C\FOREVER || $expires > $now) {
continue;
}
if ((int)$role['WILL_RENEW'] === 0) {
$role_model->deleteUserRole($user_id, $role['ROLE_ID']);
continue;
}
$period = $this->chargeFrequency($role['CHARGE_FREQUENCY']);
$cost = (int)$role['ROLE_COST'];
if ($period === C\FOREVER || $cost <= 0) {
continue;
}
$new_expires = $expires;
while ($new_expires <= $now && $balance >= $cost) {
$credit_model->updateCredits($user_id, -$cost,
'accountaccess_component_role_renewal');
$balance -= $cost;
$new_expires += $period;
}
if ($new_expires !== $expires) {
$role_model->updateUserRoleExpires($user_id,
$role['ROLE_ID'], $new_expires);
}
}
}
/**
* Used to handle the manage user activity.
*
* This activity allows new users to be added, old users to be
* deleted and allows roles to be added to/deleted from a user
*
* @return array $data infomartion about users of the system, roles, etc.
* as well as status messages on performing a given sub activity
*/
public function manageUsers()
{
$parent = $this->parent;
$request_fields = ['start_row', 'num_show', 'end_row',
'visible_roles', 'visible_groups', 'role_filter', 'role_sorts',
'group_filter', 'group_sorts', 'role_limit', 'group_limit',
'context'];
$signin_model = $parent->model("signin");
$user_model = $parent->model("user");
$group_model = $parent->model("group");
$role_model = $parent->model("role");
$possible_arguments = ["adduser", 'edituser', 'search',
"deleteuser", "adduserrole", "deleteuserrole",
"addusergroup", "deleteusergroup", "updatestatus",
"actasuser"];
$data["ELEMENT"] = "manageusers";
$data['SCRIPT'] = "";
$data["INCLUDE_SCRIPTS"] ??= [];
$data["INCLUDE_SCRIPTS"][] = "register_validator";
$data['STATUS_CODES'] = [
C\ACTIVE_STATUS => tl('accountaccess_component_active_status'),
C\INACTIVE_STATUS => tl('accountaccess_component_inactive_status'),
C\EDITOR_STATUS => tl('accountaccess_component_editor_status'),
C\SUSPENDED_STATUS =>
tl('accountaccess_component_suspended_status'),
];
$data['MEMBERSHIP_CODES'] = [
C\INACTIVE_STATUS => tl('accountaccess_component_request_join'),
C\INVITED_STATUS => tl('accountaccess_component_invited'),
C\ACTIVE_STATUS => tl('accountaccess_component_active_status'),
C\EDITOR_STATUS => tl('accountaccess_component_editor_status'),
C\SUSPENDED_STATUS =>
tl('accountaccess_component_suspended_status')
];
$data['FORM_TYPE'] = "adduser";
$search_array = [];
$username = "";
if (isset($_REQUEST['user_name'])) {
$username = substr($parent->clean($_REQUEST['user_name'], "string"),
0, C\NAME_LEN);
}
if ($username == "" && isset($_REQUEST['arg']) && $_REQUEST['arg']
!= "search") {
unset($_REQUEST['arg']);
}
$select_group = isset($_REQUEST['selectgroup']) ?
$parent->clean($_REQUEST['selectgroup'],"string") : "";
$select_role = isset($_REQUEST['selectrole']) ?
$parent->clean($_REQUEST['selectrole'],"string") : "";
if (isset($_REQUEST['arg']) && $_REQUEST['arg'] == 'edituser') {
if ($select_role != "") {
$_REQUEST['arg'] = "adduserrole";
} else if ($select_group != ""){
$_REQUEST['arg'] = "addusergroup";
}
}
$user_id = -1;
$data['visible_roles'] = 'false';
$data['visible_groups'] = 'false';
if ($username != "") {
$user_id = $signin_model->getUserId($username);
if ($user_id) {
$this->getUserRolesData($data, $user_id);
$this->getUserGroupsData($data, $user_id);
}
}
$data['CURRENT_USER'] = ["user_name" => "", "first_name" => "",
"last_name" => "", "email" => "", "status" => "", "password" => "",
"repassword" => ""];
$data['CAN_SET_PASSWORD'] = true;
$data['PAGING'] = "";
if (isset($_REQUEST['arg']) &&
in_array($_REQUEST['arg'], $possible_arguments)) {
$arg = $_REQUEST['arg'];
$pass_len = (isset($_REQUEST['new_password'])) ?
strlen($_REQUEST['new_password']) : 0;
switch ($arg) {
case "adduser":
if ($pass_len > C\LONG_NAME_LEN ) {
return $parent->redirectWithMessage(
tl('accountaccess_component_passwords_too_long'),
$request_fields);
} else if ($_REQUEST['retypepassword'] !=
$_REQUEST['password']) {
return $parent->redirectWithMessage(
tl('accountaccess_component_passwords_dont_match'),
$request_fields);
} else if (!empty(L\passwordPolicyViolations(
$_REQUEST['password']))) {
return $parent->redirectWithMessage(tl(
'accountaccess_component_password_requirements'),
$request_fields);
} else if (trim($username) == "") {
return $parent->redirectWithMessage(
tl('accountaccess_component_invalid_username'),
$request_fields);
} else if ($signin_model->getUserId($username) > 0) {
return $parent->redirectWithMessage(
tl('accountaccess_component_user_exists'),
$request_fields);
} else if (!empty($_REQUEST['email']) &&
ML\MailSiteFactory::isForbiddenAccountEmail(
substr(trim($parent->clean($_REQUEST['email'],
"string")), 0, C\LONG_NAME_LEN))) {
return $parent->redirectWithMessage(
tl('accountaccess_component_email_system_address'),
$request_fields);
} else if (!isset($data['STATUS_CODES'][
$_REQUEST['status']])) {
$_REQUEST['status'] = C\INACTIVE_STATUS;
} else {
$norm_password =
substr($parent->clean($_REQUEST['password'],
"password"), 0, C\LONG_NAME_LEN);
$username = trim($username);
$user_id = $user_model->addUser($username,
$norm_password,
substr(trim($parent->clean($_REQUEST['first_name'],
"string")), 0, C\NAME_LEN),
substr(trim($parent->clean($_REQUEST['last_name'],
"string")), 0, C\NAME_LEN),
substr(trim($parent->clean($_REQUEST['email'],
"string")), 0, C\LONG_NAME_LEN),
$_REQUEST['status']
);
$data['USER_NAMES'][$username] = $username;
$personal_group_name = C\PERSONAL_GROUP_PREFIX .
$user_id;
if ($group_model->getGroupId($personal_group_name) < 0){
$group_model->addGroup($personal_group_name,
$user_id, C\INVITE_ONLY_JOIN, C\ACTIVE_STATUS,
C\NON_VOTING_GROUP, C\FOREVER, 0);
}
return $parent->redirectWithMessage(
tl('accountaccess_component_user_added'),
$request_fields);
}
break;
case "edituser":
$data['FORM_TYPE'] = "edituser";
if (!empty($_REQUEST['context'])) {
$data['context'] = "search";
}
$user = $user_model->getUser($username);
if (!$user) {
return $parent->redirectWithMessage(
tl('accountaccess_component_user_doesnt_exist'),
$request_fields);
}
$update = false;
$error = false;
if ($user["USER_ID"] == C\PUBLIC_USER_ID) {
return $parent->redirectWithMessage(
tl('accountaccess_component_cant_edit_public_user'),
$request_fields);
}
$editing_root = ($user["USER_ID"] == C\ROOT_ID);
$actor_is_root =
($_SESSION['USER_ID'] == C\ROOT_ID);
$can_set_password =
(!$editing_root || $actor_is_root);
$data['CAN_SET_PASSWORD'] = $can_set_password;
if (!$can_set_password) {
unset($_REQUEST['password']);
unset($_REQUEST['retypepassword']);
}
foreach ($data['CURRENT_USER'] as $field => $value) {
$upper_field = strtoupper($field);
if (isset($_REQUEST[$field]) && $field != 'user_name') {
if ($field != "password" || ($_REQUEST["password"]
!= md5("password") && $_REQUEST["password"] ==
$_REQUEST["retypepassword"])) {
if ($field == "password" && !empty(
L\passwordPolicyViolations(
$_REQUEST["password"]))) {
return $parent->redirectWithMessage(tl(
'accountaccess_component_password_requirements'
), array_merge(array('arg', 'user_name'),
$request_fields));
}
$clean_type =
(!str_contains($field, 'password')) ?
"string" : "password";
$tmp = $parent->clean(
$_REQUEST[$field], $clean_type);
if ($tmp != $user[$upper_field]) {
$user[$upper_field] = $tmp;
if (!isset($_REQUEST['change_filter'])) {
$update = true;
}
}
$data['CURRENT_USER'][$field] =
$user[$upper_field];
} else if ($_REQUEST["password"] !=
$_REQUEST["retypepassword"]) {
$error = true;
break;
}
} else if (isset($user[$upper_field])){
if ($field != "password" &&
$field != "retypepassword") {
$data['CURRENT_USER'][$field] =
$user[$upper_field];
}
}
}
$data['CURRENT_USER']['password'] = md5("password");
$data['CURRENT_USER']['retypepassword'] = md5("password");
if ($error) {
return $parent->redirectWithMessage(
tl('accountaccess_component_passwords_dont_match'),
array_merge(array('arg', 'user_name'),
$request_fields));
} else if (isset($user['EMAIL']) &&
ML\MailSiteFactory::isForbiddenAccountEmail(
$user['EMAIL'])) {
return $parent->redirectWithMessage(
tl('accountaccess_component_email_system_address'),
array_merge(array('arg', 'user_name'),
$request_fields));
} else if ($update) {
$user_model->updateUser($user);
return $parent->redirectWithMessage(
tl('accountaccess_component_user_updated'),
array_merge(array('arg', 'user_name'),
$request_fields));
} else if (isset($_REQUEST['change_filter'])) {
if ($_REQUEST['change_filter'] == "group") {
$data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
tl('accountaccess_component_user_filter_group').
"</h1>');";
} else {
$data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
tl('accountaccess_component_user_filter_role').
"</h1>');";
}
}
$data['CURRENT_USER']['id'] = $user_id;
$actor_may_act_as = $user_model->
isAllowedUserActivity($_SESSION['USER_ID'],
'manageUsers');
$data['CAN_ACT_AS_USER'] = ($actor_may_act_as &&
!$editing_root &&
$user["USER_ID"] != C\PUBLIC_USER_ID &&
empty($_SESSION['IMPERSONATOR_RETURN_ID']));
$data['SCRIPT'] .= "elt('focus-button').focus();";
break;
case "actasuser":
$target_id = $signin_model->getUserId($username);
$actor_may_act_as = $user_model->
isAllowedUserActivity($_SESSION['USER_ID'],
'manageUsers');
if (!$actor_may_act_as ||
!empty($_SESSION['IMPERSONATOR_RETURN_ID']) ||
$target_id <= 0 || in_array($target_id,
[C\ROOT_ID, C\PUBLIC_USER_ID])) {
return $parent->redirectWithMessage(
tl('accountaccess_component_no_act_as'),
$request_fields);
}
$_SESSION['IMPERSONATOR_RETURN_ID'] =
$_SESSION['USER_ID'];
$_SESSION['IMPERSONATOR_RETURN_NAME'] =
$_SESSION['USER_NAME'] ?? '';
L\crawlLog("ACT AS: user " .
($_SESSION['USER_NAME'] ?? '') .
" (id " . $_SESSION['IMPERSONATOR_RETURN_ID'] .
") began acting as user " . $username);
$_SESSION['USER_ID'] = $target_id;
$_SESSION['USER_NAME'] = $username;
$_REQUEST[C\p('CSRF_TOKEN')] =
$parent->generateCSRFToken($target_id);
unset($_REQUEST['route']['c'],
$_REQUEST['route']['a']);
$_REQUEST['c'] = 'admin';
$_REQUEST['a'] = 'manageAccount';
return $parent->redirectWithMessage(
tl('accountaccess_component_now_acting_as',
$username), false, false, true);
break;
case "deleteuser":
if (!empty($_REQUEST['context'])) {
$_REQUEST['arg'] = 'search';
$request_fields[] = 'arg';
}
$user_id =
$signin_model->getUserId($username);
if ($user_id <= 0) {
return $parent->redirectWithMessage(
tl('accountaccess_component_username_doesnt_exists'
), $request_fields);
} else if (in_array(
$user_id, [C\ROOT_ID, C\PUBLIC_USER_ID])) {
return $parent->redirectWithMessage(
tl('accountaccess_component_cant_delete_builtin'),
$request_fields);
} else {
$user_model->deleteUser($username);
return $parent->redirectWithMessage(
tl('accountaccess_component_user_deleted'),
$request_fields);
}
break;
case "adduserrole":
$_REQUEST['arg'] = 'edituser';
if ($user_id <= 0 ) {
$_REQUEST['arg'] = 'adduser';
return $parent->redirectWithMessage(
tl('accountaccess_component_username_doesnt_exists'),
array_merge(['arg'], $request_fields));
} else if (!($role_id = $role_model->getRoleId(
$select_role))) {
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_doesnt_exists'
), array_merge(['arg', 'user_name'],
$request_fields));
} else if ($role_model->checkUserRole($user_id,
$role_id)) {
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_already_added'
), array_merge(['arg', 'user_name'],
$request_fields));
} else {
$role_model->addUserRole($user_id, $role_id);
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_added'),
array_merge(['arg', 'user_name'],
$request_fields));
}
break;
case "addusergroup":
$_REQUEST['arg'] = 'edituser';
if ( $user_id <= 0 ) {
$_REQUEST['arg'] = 'adduser';
return $parent->redirectWithMessage(
tl('accountaccess_component_username_doesnt_exists'),
array_merge(['arg'], $request_fields));
} else if (!($group_id = $group_model->getGroupId(
$select_group))) {
return $parent->redirectWithMessage(
tl('accountaccess_component_groupname_doesnt_exists'
), array_merge(['arg', 'user_name'],
$request_fields));
} else if ($group_model->checkUserGroup($user_id,
$group_id)){
return $parent->redirectWithMessage(
tl('accountaccess_component_groupname_already_added'
), array_merge(['arg', 'user_name'],
$request_fields));
} else {
$group_model->addUserGroup($user_id,
$group_id);
$this->getUserGroupsData($data, $user_id);
return $parent->redirectWithMessage(
tl('accountaccess_component_groupname_added'),
array_merge(['arg', 'user_name'],
$request_fields));
}
break;
case "deleteuserrole":
$_REQUEST['arg'] = 'edituser';
if ($user_id <= 0) {
$_REQUEST['arg'] = 'adduser';
return $parent->redirectWithMessage(
tl('accountaccess_component_username_doesnt_exists'),
array_merge(['arg'],
$request_fields));
}
$deleted = 0;
if (!empty($_REQUEST['role_ids'])) {
$role_ids = $_REQUEST['role_ids'];
$ids = explode("*", $role_ids);
foreach ($ids as $role_id) {
$role_id = (!empty($role_id)) ?
$parent->clean($role_id, 'int'): 0;
if ($role_model->checkUserRole($user_id,
$role_id)) {
$role_model->deleteUserRole(
$user_id, $role_id);
$deleted++;
}
}
}
if ($deleted == 1) {
$this->getUserRolesData($data, $user_id);
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_deleted'
), array_merge(['arg', 'user_name'],
$request_fields));
} else if ($deleted > 1) {
$this->getUserRolesData($data, $user_id);
return $parent->redirectWithMessage(
tl('accountaccess_component_rolenames_deleted'
), array_merge(['arg', 'user_name'],
$request_fields));
}
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_doesnt_exists'
), array_merge(['arg', 'user_name'],
$request_fields));
case "deleteusergroup":
$_REQUEST['arg'] = 'edituser';
if (!empty($_REQUEST['context'])) {
$_REQUEST['c'] = 'search';
$request_fields[] = 'arg';
}
if ($user_id <= 0) {
$_REQUEST['arg'] = 'adduser';
return $parent->redirectWithMessage(
tl('accountaccess_component_username_doesnt_exists'),
$request_fields);
}
$deleted = 0;
if (!empty($_REQUEST['group_ids'])) {
$group_ids = $_REQUEST['group_ids'];
$ids = explode("*", $group_ids);
foreach ($ids as $group_id) {
$group_id = (!empty($group_id)) ?
$parent->clean($group_id, 'int'): 0;
if ($group_model->checkUserGroup($user_id,
$group_id)) {
$group_model->deleteUserGroup(
$user_id, $group_id);
$deleted++;
}
}
}
if ($deleted == 1) {
$this->getUserGroupsData($data, $user_id);
return $parent->redirectWithMessage(
tl('accountaccess_component_group_deleted'
), array_merge(['arg', 'user_name'],
$request_fields));
} else if ($deleted > 1) {
$this->getUserGroupsData($data, $user_id);
return $parent->redirectWithMessage(
tl('accountaccess_component_groups_deleted'
), array_merge(['arg', 'user_name'],
$request_fields));
}
return $parent->redirectWithMessage(
tl('accountaccess_component_groupname_doesnt_exists'
), array_merge(['arg', 'user_name'],
$request_fields));
case "search":
$data["FORM_TYPE"] = "search";
$search_array =
$parent->tableSearchRequestHandler($data,
"manageUsers",
['ALL_FIELDS' =>
['user', 'first', 'last', 'email', 'status'],
'EQUAL_COMPARISON_TYPES' => ['status']], "_name");
if (empty($_SESSION['LAST_SEARCH']['manageUsers_name']) ||
(!empty($_SESSION['LAST_SEARCH']['manageUsers_name']) &&
isset($_REQUEST['user_name'])) ) {
$_SESSION['LAST_SEARCH']['manageUsers_name'] =
$_SESSION['SEARCH']['manageUsers_name'];
unset($_SESSION['SEARCH']['manageUsers_name']);
} else {
$default_search = true;
}
break;
case "updatestatus":
if (!empty($_REQUEST['context'])) {
$_REQUEST['arg'] = 'search';
$request_fields[] = 'arg';
}
$user_id = $signin_model->getUserId($username);
if (!isset($data['STATUS_CODES'][$_REQUEST['userstatus']])||
$user_id == 1) {
return $parent->redirectWithMessage(
tl('accountaccess_component_username_doesnt_exists'
), $request_fields);
} else {
$user_model->updateUserStatus($user_id,
$_REQUEST['userstatus']);
return $parent->redirectWithMessage(
tl('accountaccess_component_userstatus_updated'),
$request_fields);
}
break;
}
}
if ($search_array == [] || !empty($default_search)) {
if (!empty($_SESSION['LAST_SEARCH']['manageUsers_name'])) {
if (!empty($_REQUEST['arg']) && $_REQUEST['arg'] == 'search') {
$search_array =
$parent->restoreLastSearchFromSession($data,
'manageUsers_name');
} else if (!empty($_REQUEST['context'])) {
$search_array = $_SESSION['LAST_SEARCH'][
'manageUsers_name']['SEARCH_ARRAY'];
$data['PAGING'] =
$_SESSION['LAST_SEARCH']['manageUsers_name']['PAGING'];
}
}
if ($search_array == []) {
$search_array[] = ["user", "", "", "ASC"];
}
}
$parent->pagingLogic($data, $user_model, "USERS",
C\DEFAULT_ADMIN_PAGING_NUM, $search_array, "");
$num_users = count($data['USERS']);
for ($i = 0; $i < $num_users; $i++) {
$data['USERS'][$i]['NUM_GROUPS'] =
$group_model->countUserGroups($data['USERS'][$i]['USER_ID']);
}
if ($data['FORM_TYPE'] == 'adduser') {
$data['SCRIPT'] .= "setDisplay('admin-form-row', false);";
}
return $data;
}
/**
* Uses $_REQUEST and $user_id to look up all the roles that a user
* has subject to $_REQUEST['role_limit'], $_REQUEST['role_filter'],
* and $_REQUEST['role_sorts']. Information about these roles is added as
* fields to $data[NUM_USER_ROLES'] and $data['USER_ROLES']
*
* @param array &$data data for the manageUsers view.
* @param int $user_id user to look up roles for
*/
public function getUserRolesData(&$data, $user_id)
{
$parent = $this->parent;
$role_model = $parent->model("role");
$data['visible_roles'] = (isset($_REQUEST['visible_roles']) &&
$_REQUEST['visible_roles']=='true') ? 'true' : 'false';
if ($data['visible_roles'] == 'false') {
unset($_REQUEST['role_filter']);
unset($_REQUEST['role_limit']);
}
if (isset($_REQUEST['role_filter'])) {
$role_filter = substr($parent->clean(
$_REQUEST['role_filter'], 'string'), 0, C\NAME_LEN);
} else {
$role_filter = "";
}
$data['ROLE_FILTER'] = $role_filter;
$data['ROLE_SORTS'] = (empty($_REQUEST['role_sorts'])) ? [] :
json_decode(urldecode($_REQUEST['role_sorts']), true);
if ($data['ROLE_SORTS'] === null) {
$data['ROLE_SORTS'] = json_decode(html_entity_decode(
urldecode($_REQUEST['role_sorts'])), true);
$data['ROLE_SORTS'] = ($data['ROLE_SORTS']) ? $data['ROLE_SORTS'] :
[];
}
$data['NUM_USER_ROLES'] =
$role_model->countUserRoles($user_id, $role_filter);
if (isset($_REQUEST['role_limit'])) {
$role_limit = min($parent->clean(
$_REQUEST['role_limit'], 'int'),
$data['NUM_USER_ROLES']);
if ($role_limit == $data['NUM_USER_ROLES']) {
$role_limit = $data['NUM_USER_ROLES']- C\NUM_RESULTS_PER_PAGE;
}
$role_limit = max($role_limit, 0);
} else {
$role_limit = 0;
}
$data['ROLE_LIMIT'] = $role_limit;
$data['USER_ROLES'] =
$role_model->getUserRoles($user_id, $role_filter,
$data['ROLE_SORTS'], $role_limit);
$data['SCRIPT'] .= "listenAll('input.role-id', 'click',".
" function(event){ updateCheckedIds(role_ids, event.target); });";
}
/**
* Uses $_REQUEST and $user_id to look up all the groups that a user
* belongs to subject to $_REQUEST['group_limit'],
* $_REQUEST['group_filter'], and $_REQUEST['group_sorts']. Information
* about these roles is added as
* fields to $data[NUM_USER_GROUPS'] and $data['USER_GROUPS']
*
* @param array &$data data for the manageUsers view.
* @param int $user_id user to look up roles for
*/
public function getUserGroupsData(&$data, $user_id)
{
$parent = $this->parent;
$group_model = $parent->model("group");
$data['visible_groups'] = (isset($_REQUEST['visible_groups']) &&
$_REQUEST['visible_groups']=='true') ? 'true' : 'false';
if ($data['visible_groups'] == 'false') {
unset($_REQUEST['group_filter']);
unset($_REQUEST['group_limit']);
}
if (isset($_REQUEST['group_filter'])) {
$group_filter = substr($parent->clean(
$_REQUEST['group_filter'], 'string'), 0, C\SHORT_TITLE_LEN);
} else {
$group_filter = "";
}
$data['GROUP_FILTER'] = $group_filter;
$data['GROUP_SORTS'] = (empty($_REQUEST['group_sorts'])) ? [] :
json_decode(urldecode($_REQUEST['group_sorts']), true);
if ($data['GROUP_SORTS'] === null) {
$data['GROUP_SORTS'] = json_decode(html_entity_decode(
urldecode($_REQUEST['group_sorts'])), true);
$data['GROUP_SORTS'] = ($data['GROUP_SORTS']) ?
$data['GROUP_SORTS'] : [];
}
$data['NUM_USER_GROUPS'] =
$group_model->countUserGroups($user_id, $group_filter);
if (isset($_REQUEST['group_limit'])) {
$group_limit = min($parent->clean(
$_REQUEST['group_limit'], 'int'),
$data['NUM_USER_GROUPS']);
$group_limit = max($group_limit, 0);
} else {
$group_limit = 0;
}
$data['GROUP_LIMIT'] = $group_limit;
$data['USER_GROUPS'] =
$group_model->getUserGroups($user_id, $group_filter,
$data['GROUP_SORTS'], $group_limit);
$data['SCRIPT'] .= "listenAll('input.group-id', 'click',".
" function(event){ updateCheckedIds(group_ids, event.target); });";
}
/**
* Used to handle the manage role activity.
*
* This activity allows new roles to be added, old roles to be
* deleted and allows activities to be added to/deleted from a role
*
* @return array $data information about roles in the system, activities,
* etc. as well as status messages on performing a given sub activity
*/
public function manageRoles()
{
$parent = $this->parent;
$role_model = $parent->model("role");
$possible_arguments = ["addactivity", "addmodifier", "addrole",
"deleteactivity", "deletemodifier", "deleterole", "editrole",
"search"];
$data["ELEMENT"] = "manageroles";
$data['SCRIPT'] = "";
$data['FORM_TYPE'] = "addrole";
$search_array = [];
$data['CURRENT_ROLE'] = ["name" => ""];
$data['PAGING'] = "";
$modifier_activity_id = -1;
if (isset($_REQUEST['arg']) && $_REQUEST['arg'] == 'editrole') {
if (isset($_REQUEST['selectactivity']) &&
$_REQUEST['selectactivity'] >= 0) {
$_REQUEST['arg'] = "addactivity";
}
if (!empty($_REQUEST['selectmodifier']) &&
is_array($_REQUEST['selectmodifier']) &&
!in_array("-1", $_REQUEST['selectmodifier'])) {
$modifier_activity_id =
array_keys($_REQUEST['selectmodifier'])[0];
if ($modifier_activity_id > 0) {
$_REQUEST['arg'] = "addmodifier";
}
}
}
if (isset($_REQUEST['name'])) {
$name = substr($parent->clean($_REQUEST['name'], "string"),
0, C\NAME_LEN);
$data['CURRENT_ROLE']['name'] = $name;
} else {
$name = "";
}
if ($name != "") {
$role_id = $role_model->getRoleId($name);
$data['ROLE_ACTIVITIES'] =
$role_model->getRoleActivities($role_id);
$all_activities = $parent->model("activity")->getActivityList();
$activity_ids = [];
$activity_names = [];
$data['AVAILABLE_MODIFIERS'] = [];
foreach ($all_activities as $activity) {
$activity_ids[] = $activity['ACTIVITY_ID'];
$activity_names[$activity['ACTIVITY_ID']] =
$activity['ACTIVITY_NAME'];
$data['AVAILABLE_MODIFIERS'][$activity['ACTIVITY_ID']] =
$parent->getAccessModifiers($activity['METHOD_NAME']);
}
$available_activities = [];
$role_activity_ids = [];
$activities_by_id = [];
foreach ($data['ROLE_ACTIVITIES'] as $activity) {
$role_activity_ids[] = $activity["ACTIVITY_ID"];
$activities_by_id[$activity["ACTIVITY_ID"]] = $activity;
}
$tmp = [];
foreach ($all_activities as $activity) {
if (!in_array($activity["ACTIVITY_ID"], $role_activity_ids) &&
!isset($tmp[$activity["ACTIVITY_ID"]])) {
$tmp[$activity["ACTIVITY_ID"]] = true;
$available_activities[] = $activity;
}
}
$data['AVAILABLE_ACTIVITIES'][-1] =
tl('accountaccess_component_add_roleactivity');
foreach ($available_activities as $activity) {
$data['AVAILABLE_ACTIVITIES'][$activity['ACTIVITY_ID']] =
$activity['ACTIVITY_NAME'];
}
if (isset($_REQUEST['selectactivity'])) {
$select_activity =
$parent->clean($_REQUEST['selectactivity'], "int" );
} else {
$select_activity = "";
}
if ($select_activity != "") {
$data['SELECT_ACTIVITY'] = $select_activity;
} else {
$data['SELECT_ACTIVITY'] = -1;
}
}
if (isset($_REQUEST['arg']) &&
in_array($_REQUEST['arg'], $possible_arguments)) {
switch ($_REQUEST['arg']) {
case "addactivity":
$_REQUEST['arg'] = "editrole";
if (($role_id = $role_model->getRoleId($name)) <= 0) {
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_doesnt_exists'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
} else if (!in_array($select_activity, $activity_ids)) {
return $parent->redirectWithMessage(
tl(
'accountaccess_component_activityname_doesnt_exists'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
} else {
$role_model->addActivityRole(
$role_id, $select_activity);
unset($data['AVAILABLE_ACTIVITIES'][$select_activity]);
$data['ROLE_ACTIVITIES'] =
$role_model->getRoleActivities($role_id);
return $parent->redirectWithMessage(
tl('accountaccess_component_activity_added'),
["arg", "start_row", "end_row", "num_show", "name",
"context"]);
}
break;
case "addmodifier":
$_REQUEST['arg'] = "editrole";
$modifier =
$_REQUEST['selectmodifier'][$modifier_activity_id] ??
"none";
$available_modifiers = $data['AVAILABLE_MODIFIERS'][
$modifier_activity_id] ?? [];
if (($role_id = $role_model->getRoleId($name)) <= 0) {
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_doesnt_exists'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
} else if (!in_array($modifier_activity_id,
$activity_ids)) {
return $parent->redirectWithMessage(
tl(
'accountaccess_component_activityname_doesnt_exists'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
} else if (!isset($available_modifiers[$modifier])) {
return $parent->redirectWithMessage(
tl(
'accountaccess_component_modifier_doesnt_exists'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
} else {
$activity =
$activities_by_id[$modifier_activity_id];
$allowed_arguments = $activity["ALLOWED_ARGUMENTS"];
if ($modifier == "all") {
$allowed_arguments = "all";
} else {
if ($allowed_arguments == "all") {
$allowed_arguments = "";
}
$comma = (trim($allowed_arguments)) ?
"," : "";
if (!str_contains($allowed_arguments, $modifier)) {
$allowed_arguments .= $comma . $modifier;
} else {
return $parent->redirectWithMessage(
tl('accountaccess_component_modifier_exists'
), ["arg", "start_row", "end_row",
"num_show","name", "context"]);
}
}
$role_model->updateActivityRoleArguments($role_id,
$modifier_activity_id,
$allowed_arguments);
return $parent->redirectWithMessage(
tl('accountaccess_component_modifier_added'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
}
break;
case "addrole":
$name = trim($name);
if ($name != "" && $role_model->getRoleId($name) > 0) {
$data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
tl('accountaccess_component_rolename_exists').
"</h1>');";
} else if ($name != "") {
$role_model->addRole($name);
$data['CURRENT_ROLE']['name'] = "";
$data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
tl('accountaccess_component_rolename_added').
"</h1>');";
} else {
$data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
tl('accountaccess_component_rolename_blank').
"</h1>');";
}
$data['CURRENT_ROLE']['name'] = "";
break;
case "deleteactivity":
$_REQUEST['arg'] = "editrole";
if (($role_id = $role_model->getRoleId($name)) <= 0) {
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_doesnt_exists'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
} else if (!in_array($select_activity, $activity_ids)) {
return $parent->redirectWithMessage(
tl(
'accountaccess_component_activityname_doesnt_exists'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
} else {
$role_model->deleteActivityRole(
$role_id, $select_activity);
$data['ROLE_ACTIVITIES'] =
$role_model->getRoleActivities($role_id);
$data['AVAILABLE_ACTIVITIES'][$select_activity] =
$activity_names[$select_activity];
$data['SELECT_ACTIVITY'] = -1;
return $parent->redirectWithMessage(
tl('accountaccess_component_activity_deleted'),
["arg", "start_row", "end_row", "num_show",
"name", "context"]);
}
break;
case "deletemodifier":
$_REQUEST['arg'] = "editrole";
$modifier = $parent->clean($_REQUEST['modifier'], "string")
?? "none";
$available_modifiers = $data['AVAILABLE_MODIFIERS'][
$select_activity] ?? [];
if (!isset($available_modifiers[$modifier])) {
return $parent->redirectWithMessage(
tl('accountaccess_component_invalid_modifier'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
} else if (($role_id = $role_model->getRoleId($name)) <= 0){
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_doesnt_exists'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
} else if (!in_array($select_activity, $activity_ids)) {
return $parent->redirectWithMessage(
tl(
'accountaccess_component_activityname_doesnt_exists'
), ["arg", "start_row", "end_row", "num_show",
"name", "context"]);
} else {
$activity =
$activities_by_id[$select_activity];
$allowed_arguments = $activity["ALLOWED_ARGUMENTS"];
if (!str_contains($allowed_arguments, $modifier)) {
return $parent->redirectWithMessage(
tl('accountaccess_component_mod_doesnt_exists'
), ["arg", "start_row", "end_row",
"num_show","name", "context"]);
}
$allowed_arguments = preg_replace(
"/".preg_quote($modifier)."\s*\,?\s*/", "",
$allowed_arguments);
if (empty($allowed_arguments)) {
$allowed_arguments = "all";
}
$role_model->updateActivityRoleArguments($role_id,
$select_activity,
$allowed_arguments);
return $parent->redirectWithMessage(
tl('accountaccess_component_modifier_deleted'
), ["arg", "start_row", "end_row",
"num_show","name", "context"]);
}
break;
case "deleterole":
$preserve = [];
if (!empty($_REQUEST['context'])) {
$_REQUEST['arg'] = 'search';
$preserve[] = 'arg';
}
if (($role_id = $role_model->getRoleId($name)) <= 0) {
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_doesnt_exists'
),array_merge($preserve, ["start_row", "end_row",
"num_show"]));
} else {
$role_model->deleteRole($role_id);
return $parent->redirectWithMessage(
tl('accountaccess_component_rolename_deleted'),
array_merge($preserve, ["start_row", "end_row",
"num_show"]));
}
break;
case "editrole":
$data['FORM_TYPE'] = "editrole";
$role = false;
if ($name) {
$role = $role_model->getRole($name);
}
if ($role === false) {
$data['FORM_TYPE'] = "addrole";
break;
}
if (!empty($_REQUEST['context'])) {
$data['context'] = 'search';
}
$num_activities = count($data['ROLE_ACTIVITIES']);
$update_activities = $_REQUEST['activities'] ?? [];
if (!$update_activities) {
break;
}
$update = false;
for ($i = 0; $i < $num_activities; $i++) {
$role_activity = $data['ROLE_ACTIVITIES'][$i];
$activity_id = $role_activity['ACTIVITY_ID'];
if (isset($update_activities[$activity_id]) &&
$update_activities[$activity_id] !=
$role_activity['ALLOWED_ARGUMENTS']) {
$role_model->updateActivityRoleArguments($role_id,
$activity_id, $update_activities[$activity_id]);
$update = true;
}
}
if ($update) {
return $parent->redirectWithMessage(
tl('accountaccess_component_role_updated'),
["arg", "name", "start_row", "end_row", "num_show",
"context"]);
}
break;
case "search":
$search_array = $parent->tableSearchRequestHandler($data,
"manageRoles", ['ALL_FIELDS' => ['name']]);
if (empty($_SESSION['LAST_SEARCH']['manageRoles']) ||
isset($_REQUEST['name'])) {
$_SESSION['LAST_SEARCH']['manageRoles'] =
$_SESSION['SEARCH']['manageRoles'];
unset($_SESSION['SEARCH']['manageRoles']);
} else {
$default_search = true;
}
break;
}
}
if ($search_array == [] || !empty($default_search)) {
if (!empty($_SESSION['LAST_SEARCH']['manageRoles'])) {
if (!empty($_REQUEST['arg']) && $_REQUEST['arg'] == 'search') {
$search_array =
$parent->restoreLastSearchFromSession($data,
'manageRoles');
} else if (!empty($_REQUEST['context'])) {
$search_array =
$_SESSION['LAST_SEARCH']['manageRoles']['SEARCH_ARRAY'];
$data['PAGING'] =
$_SESSION['LAST_SEARCH']['manageRoles']['PAGING'];
}
}
if ($search_array == []) {
$search_array[] = ["name", "", "", "ASC"];
}
}
if ($data['FORM_TYPE'] == 'addrole') {
$data['SCRIPT'] .= "setDisplay('admin-form-row', false);";
}
$parent->pagingLogic($data, $role_model, "ROLES",
C\DEFAULT_ADMIN_PAGING_NUM, $search_array, "");
return $data;
}
}