dir = $dir; $this->name = $name; parent :: __construct($uriData); $this->module = new cmsPubUsersModule(); $this->oView->setTemplateDir($this->dir . "/tmpl/"); if(!$this->oView->cacheUsed()){ $this->oView->setJs(getCurrentFolder($this->dir) . '/js/' . $this->name . '.js'); $this->oView->setCss(getCurrentFolder($this->dir) . '/css/' . $this->name . '.css'); } // Set JS module init title $this->oView->setAsJSON(cCore::JS_MOD, ucfirst($name)); $this->session = new cSession('appUsers'); // TODO Shiro: Do we need this? } public function run($initEditMode = false){ $this->oView->TABLE = true; $this->oView->setAsJSON('initEdit', $initEditMode); $this->oView->setAsJSON('baseUrl', $this->gL()); $this->oView->setAsJSON('gM', $this->getTranslations()); $this->oView->setAsJSON('vcfg', $this->getUserValCfg()); $this->oView->display(); } /** * Function to create cms table & return for direct & ajax input * * @author Mareks Keišs * @category cmsPubUsers Controller * @param int $page - page to display * @param string $filter_json - (optional) filter json string * @param bool $headers - flag whether to send header data or not * @return array of data * @version 1.1 */ public function createCmsTable($page = 1, $filter_json = '', $headers = false) { $pages = 0; $filter = []; if ($filter_json) { $filter = cJSON::decode($filter_json, true); } $this->oView->MODULE_TITLE = $this->gM("User Management"); if (!!$filter && is_array($filter)) $this->oView->DEFAULT_SEARCH_VALUES = prepForDisplayHtml($filter); $this->oView->LIST_HEADER = reOrderTableFields( $this->getTableFields(), $this->oUser->oCfg->getTableProperty($this->name), ); $this->oView->LIST_DATA = $this->getModuleData($page, $filter, $pages); $this->oView->LIST_ACTIONS = $this->getTableActions(); $data = [ 'data' => $this->oView->genHelperView('cmsc/table/data-table'), 'pcount' => $pages, 'rlimit' => $this->cmsTableRecordsPerPage, ]; // Send data to client if($headers) $data['header'] = $this->oView->genHelperView('cmsc/table/data-table-search'); return $data; } /** * Function to get module data * * @author Mareks Keišs * @category cmsPubUsers Controller * @param int $page * @param array $filter * @param int $pages * @return array of data * @version 1.1 */ public function getModuleData($page = 1, $filter = array(), &$pages) { $where = "AND 1"; $sort = "id DESC"; $offset = (($page?:1)-1) * $this->cmsTableRecordsPerPage; $tFields = $this->getTableFields(); // Create sort by if(getP('sortBy')) $sort = $this->module->db->genOrderByQuery(getP('sortBy'), getP('sortWay'), $tFields); // Create where clause if(count($filter)) $where = $this->module->db->genSearchFieldQuery($filter, $tFields); $subWhere = ""; // Fetch data $data = $this->module->getModuleRecords($where . $subWhere, $sort, $offset, $this->cmsTableRecordsPerPage); if(count($data)){ // Switch if permission to see auto login button $_SESSION['autologin'] = cNumbers::getRandomChString(); foreach($data as &$v){ if($v['user_last_login']){ // Activity indicators $bIndicator = ($v['user_last_login'] > strtotime("-1 month") ? '' : ''); if(date('d-m-Y', $v['user_last_login']) == date('d-m-Y')){ $v['sclass'] = 'bggreen'; $v['user_last_login'] = date('H:i', $v['user_last_login']) . $bIndicator; }else{ $v['user_last_login'] = date('d/m/Y', $v['user_last_login']) . $bIndicator; } }else{ $v['user_last_login'] = '-'; } if(!$v['user_last_ip']){ $v['user_last_ip'] = '-'; } //$v['tfa'] = ($v['tfa'] ? '✓' : ''); if(date('d-m-Y', $v['user_created']) == date('d-m-Y')){ $v['user_created'] = date('H:i', $v['user_created']); }else{ $v['user_created'] = date('d/m/Y', $v['user_created']); } $v['user_in'] = '-'; $v['user_name'] = $v['user_title']; } } $this->oView->ROWS = $rows = $this->module->db->getSelectedRecordsCount(); $pages = floor($rows / $this->cmsTableRecordsPerPage) + ($rows%$this->cmsTableRecordsPerPage?1:0); return $data; } /** * Function to disable / enable enum records marked in table * * @author Mareks Keišs * @category cmsPubUsers Controller * @param array $baseField - basefield to handle * @param string $rows - passed user ids in JSON string * @return array of data */ public function changeEnumFields($baseField, $rows) { if($baseField && $rows = cJSON::decode($rows, true)){ $baseField = substr($baseField, 2); $fields = $this->getTableFields(); if(isset($fields[$baseField]['db_field'])){ if($this->module->changeRecordsStatus($this->module->db->prepData($rows), $fields[$baseField]['db_field'])){ return true; } } } cJSON::sendError(); } /** * Function to delete records marked in table * * @author Mareks Keišs * @category cmsPubUsers Controller * @param string $rows - passed user ids in JSON string * @return bool|array of data */ public function delete($rows) { if($rows = cJSON::decode($rows, true)){ if($this->module->deleteRecords($this->module->db->prepData($rows))){ return true; }else{ cJSON::sendError(); } } return false; } /** * Function to get randomly generated password * * @author Mareks Keišs * @category cmsPubUsers Controller * @return array of data */ public function genTempPWD() { $this->oView->TPASSWD = $this->session->TPASSWD = cNumbers::getRandomChString(16, true); return array('key' => $this->session->TPASSWD); } /** * Function to get table record data for edit mode * * @author Mareks Keišs * @category cmsPubUsers Controller * @param int $id - record id * @return array of data */ public function editCmsTableRecord($id): array { if ($id) { $vData = $this->module->getRecordDataById((int)$id); $isToday = date('d-m-Y') == date('d-m-Y', $vData['user_created']); $dateFormat = $isToday ? $this->timeDateFormat : $this->CMSDateFormat; // Update dates using date format $vData['user_created'] = date($dateFormat, $vData['user_created']); $vData['user_modified'] = date($dateFormat, $vData['user_modified']); if ($vData['user_last_login']) { $vData['user_last_login'] = date($dateFormat, $vData['user_last_login']); } // Check if user is subscribed to newsletters $this->oView->SUB = (new indexModule())->chkUserSubscription($vData['user_email']); // Set data to view $this->oView->USER = $vData; } $this->oView->TPASSWD = $this->session->TPASSWD = cNumbers::getRandomChString(16, true); $data = [ 'groups' => [], 'permissions' => [], ]; // Load user permissions if ($gr = $this->module->getUserPermissionsByUserId($id)) { foreach ($gr as $v) { $v['p_name'] = ucfirst(strtolower(str_replace('_', ' ', $v['p_name']))); $data['permissions'][] = $v; } } // Load user groups if ($gr = $this->module->getUserPermissionGroupsByUserId($id)) { if (count($gr)) { foreach ($gr as $v) { $v['group_name'] = ucfirst(strtolower(str_replace('_', ' ', $v['group_name']))); $data['groups'][] = $v; } } } $this->oView->P = $data; return [ 'show' => ['buttons_top' => false, 'buttons_bottom' => true], 'btn' => $this->getFormButtons(), 'html' => $this->oView->genTemplate('users'), ]; } /** * Function to save Record data * * @author Mareks Keišs * @category cmsPubUsers Controller * @param int $userId - record id * @param string $fields - param JSON string */ public function saveRecordData($userId, $fields): void { $fields = $this->getSubmittedDataAsArray($fields ?? ''); if (empty($fields)) { cJSON::sendError($this->gM('No data submitted!')); } // Validate fields $valid = new cValidator($this); $errors = $valid->checkArray($fields, $this->getUserValCfg()); if ($errors !== true) { cJSON::sendError(['data' => $errors]); } // Check user exists by login name if ($this->module->getUserDataByLogin($userId, $fields['pbase']['user_login'])) { $text = 'User login already exists - please choose another!'; cJSON::sendError(['data' => ['user_login' => $this->gM($text)]]); } // Base data update $update = [ 'user_name' => $fields['pbase']['user_name'], 'user_surname' => $fields['pbase']['user_surname'], 'user_email' => $fields['pbase']['user_email'], 'user_login' => $fields['pbase']['user_login'], 'user_phone' => $fields['pbase']['user_phone'], 'user_admin' => (!empty($fields['psettings']['user_admin']) ? 1 : 0), 'user_blocked' => ($fields['psettings']['user_blocked'] ? 1 : 0), 'user_fchange' => ($fields['psettings']['user_pass_change'] ? 1 : 0), 'user_modified' => time(), 'user_modified_by' => -$this->oUser->getUser(), ]; if (!$userId) { $update['user_created'] = time(); $update['user_created_by'] = -$this->oUser->getUser(); $update['user_cfg'] = ""; } // Drop 2FA key if ($fields['psettings']['user_2fa_reset']) $update['user_2fa_secret_enabled'] = ''; // Check pass change if (isset($fields['ppasschange']) && isset($fields['ppasschange']['user_newpass'])) { $oPwdMaster = new cPasswordMaster(); $update['user_password'] = $oPwdMaster->password_hash($fields['ppasschange']['user_newpass']); $isSame = $this->session->TPASSWD == $fields['ppasschange']['user_newpass']; if ($fields['psettings']['user_passgen'] && $isSame) { $update['user_fchange'] = 1; } } // Update user permission data $insert = array(); if (isset($fields['user_permissions'])) { foreach ($fields['user_permissions'] as $k => $v) { if ($v == "1") { $insert[] = [ 'user_id' => &$userId, 'groups_id' => 0, 'permissions_id' => substr($k, 1), ]; } } } // Update user groups data if (isset($fields['user_groups'])) { foreach ($fields['user_groups'] as $k => $v) { if ($v == "1") { $insert[] = [ 'user_id' => &$userId, 'groups_id' => substr($k, 1), 'permissions_id' => 0, ]; } } } // Save record data $oldId = $userId; if (!($userId = $this->module->saveRecordDataById($userId, $update))) { cJSON::sendError($this->gM('Something went wrong while saving user data!')); } // ADD TO SUBSCRIPTION LIST $oIndexModule = new indexModule(); if ($oIndexModule->chkEmailExists($update['user_email'])) { if (!empty($fields['psettings']['user_subscription'])) { $oIndexModule->enableEmail($update['user_email']); } else { $oIndexModule->disableEmail($update['user_email']); } } else { $oIndexModule->saveEmail( [ 'email' => $update['user_email'], 'email_sub' => (!empty($fields['psettings']['user_subscription']) ? 1 : 0), 'email_sub_ip' => $_SERVER['REMOTE_ADDR'], 'email_reg_user_agent' => $_SERVER['HTTP_USER_AGENT'], 'email_added' => time(), 'email_modified' => time(), ], ); } // Send inserts & delete old permissions $this->module->updateUserPermissions($userId, $insert); // Drop apc keys containing user id $this->oApc->setExpiredContaining(cApc::STORE_USER_KEY . $userId); cJSON::sendOk($oldId ? "" : ['newid' => $userId]); } public function getUserValCfg(): array { $compWarn = $this->gM('Please fill in the field!'); return [ 'user_name' => [ cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => [cValidator::CHK_STR], 'comp-warning' => $compWarn, ], 'user_surname' => [ cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => [cValidator::CHK_STR], 'comp-warning' => $compWarn, ], 'user_login' => [ cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => [cValidator::CHK_STR], 'comp-warning' => $compWarn, ], 'user_email' => [ cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => [cValidator::CHK_EMAIL], 'comp-warning' => $compWarn, ], 'user_phone' => [ cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 0, cValidator::P_TEST => [cValidator::CHK_PHONE], 'comp-warning' => $compWarn, ], 'user_og' => [ // TODO Shiro: Unused? cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => [cValidator::CHK_STR], cValidator::P_EVENT => 'change', ], 'user_newpass' => [ cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => [ cValidator::CHK_LEN => $this->gM('Min password lenght is 6 symbols!'), cValidator::CHK_EQUAL => $this->gM('Passwords must match!'), ], 'comp-warning' => $compWarn, cValidator::P_LINK => 'user_newpassre', cValidator::P_ADDS => ['min' => 6], ], 'user_newpassre' => [ cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => [ cValidator::CHK_LEN => $this->gM('Min password lenght is 6 symbols!'), cValidator::CHK_EQUAL => $this->gM('Passwords must match!'), ], 'comp-warning' => $compWarn, cValidator::P_LINK => 'user_newpass', cValidator::P_ADDS => ['min' => 6], ], ]; } public function getTableFields() { if (!$this->chkP('CMS_APP_USER_SHOW_MANAGEMENT')) { return false; } $statusData = [ '' => [ 'title' => $this->gM("Select"), ], 0 => [ 'title' => $this->gM("Active"), ], 1 => [ 'title' => $this->gM("Inactive"), ], ]; $tFields = [ "checkbox" => [ 'sort' => false, 'title' => '', 'class' => 'w4 center rchk', ], "id" => [ 'sort' => true, 'search' => true, 'title' => $this->gM("ID"), 'class' => 'w8 center sortDesc sort', 'db_field' => 'mu.id', 'type' => 'input', ], "user_login" => [ 'sort' => true, 'search' => true, 'title' => $this->gM("Login"), 'class' => 'w14', 'db_field' => 'mu.user_login', 'type' => 'input', ], "user_name" => [ 'sort' => true, 'search' => true, 'title' => $this->gM("Name"), 'class' => 'w14', 'db_field' => 'mu.user_name', 'type' => 'input', ], "user_email" => [ 'sort' => true, 'search' => true, 'title' => $this->gM("Email"), 'class' => 'w26', 'db_field' => 'mu.user_email', 'type' => 'input', ], "user_phone" => [ 'sort' => true, 'search' => false, 'title' => $this->gM("Phone"), 'class' => 'w12', 'db_field' => 'mu.user_phone', 'type' => 'input', ], "user_last_ip" => [ 'sort' => true, 'search' => true, 'title' => $this->gM("IP"), 'class' => 'w12', 'db_field' => 'mu.user_last_ip', 'type' => 'input', ], "user_last_login" => [ 'sort' => true, 'search' => false, 'title' => $this->gM("Last login"), 'class' => 'w12 center', 'db_field' => 'mu.user_last_login', 'type' => 'input', ], "user_created" => [ 'sort' => true, 'search' => false, 'title' => $this->gM("Created"), 'class' => 'w12 center', 'db_field' => 'mu.user_created', 'type' => 'input', ], "status" => [ 'sort' => false, 'search' => false, 'title' => $this->gM("Blocked"), 'class' => 'w9 center', 'field' => 'user_blocked', 'db_field' => 'mu.user_blocked', 'type' => 'dropBox', 'data' => $statusData, 'default' => '', ], "buttons" => [ 'sort' => false, 'title' => $this->gM("Actions"), 'class' => 'w20', 'btnset' => [ 'ledit' => [ 'edit' => true, 'title' => $this->gM("Edit"), ], 'ldelete' => [ 'title' => $this->gM("Delete"), ], ], ], ]; if (!$this->oUser->chkPermission('PUB_USER_AUTOLOGIN', false, false)) { unset($tFields['user_in']); } if (!$this->oUser->chkPermission('CMS_APP_USER_EDIT', false, false)) { unset($tFields['user_news'], $tFields['status']); unset($tFields['buttons']['btnset']['qedit']); } if (!$this->chkP('SYS_SHOW_TABLE_IDS')) { unset($tFields['id']); } return $tFields; } public function getTranslations(): array { $delMessage = 'Selected users will be permanently deleted and cannot be recovered. Confirm delete?'; return [ 'yes' => $this->gM('Yes'), 'no' => $this->gM('No'), 'delTitle' => $this->gM('Delete users?'), 'delMessage' => $this->gM($delMessage), 'buttonYes' => $this->gM('Delete selected users'), 'buttonCancel' => $this->gM('Cancel operation'), ]; } public function getTableActions(): array { $actions = [ 'inew' => [ 'lbl' => $this->gM("Add new"), 'icon' => 'nico-add', ], 'iclone' => [ 'lbl' => $this->gM("Clone user"), 'icon' => 'nico-add', ], 'istatus' => [ 'lbl' => $this->gM("Change item status"), ], 'sepline', 'idelete' => [ 'lbl' => $this->gM("Delete selected"), 'icon' => 'nico-delete', ], ]; // Reformat drop down reformatDropDown($actions, false); return $actions; } public function getFormButtons(): array { return [ 1 => [ 'id' => 'fsave', 'lbl' => $this->gM('Save'), ], 2 => [ 'id' => 'fcancel', 'lbl' => $this->gM('Cancel'), ], ]; } }