. * * @package phpservermon * @author Pepijn Over * @copyright Copyright (c) 2008-2017 Pepijn Over * @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3 * @version Release: @package_version@ * @link http://www.phpservermonitor.org/ **/ namespace psm\Module\User\Controller; use psm\Module\AbstractController; use psm\Service\Database; /** * User module. Add, edit and delete users, or assign * servers to users. */ class UserController extends AbstractController { public $servers = array(); public function __construct(Database $db, \Twig_Environment $twig) { parent::__construct($db, $twig); $this->setMinUserLevelRequired(PSM_USER_ADMIN); $this->setCSRFKey('user'); $this->setActions(array( 'index', 'edit', 'delete', 'save', ), 'index'); $this->twig->addGlobal('subtitle', psm_get_lang('menu', 'user')); } public function run($action = null) { $servers = $this->db->select( PSM_DB_PREFIX . 'servers', null, array('server_id', 'label'), '', "ORDER BY `label` ASC" ); // change the indexes to reflect their server ids foreach ($servers as $server) { $this->servers[$server['server_id']] = $server; } return parent::run($action); } /** * Create HTML to show a list of all users * * @return string */ protected function executeIndex() { $sidebar = new \psm\Util\Module\Sidebar($this->twig); $this->setSidebar($sidebar); $sidebar->addButton( 'add_new', psm_get_lang('system', 'add_new'), psm_build_url(array('mod' => 'user', 'action' => 'edit')), 'plus icon-white', 'success', psm_get_lang('system', 'add_new') ); $modal = new \psm\Util\Module\Modal($this->twig, 'delete', \psm\Util\Module\Modal::MODAL_TYPE_DANGER); $this->addModal($modal); $modal->setTitle(psm_get_lang('users', 'delete_title')); $modal->setMessage(psm_get_lang('users', 'delete_message')); $modal->setOKButtonLabel(psm_get_lang('system', 'delete')); // build label array for the next loop $servers_labels = array(); foreach ($this->servers as $server) { $servers_labels[$server['server_id']] = $server['label']; } $users = $this->db->select( PSM_DB_PREFIX . 'users', null, array('user_id', 'user_name', 'level', 'name', 'mobile', 'email'), null, array('name') ); foreach ($users as $x => &$user) { $user_servers = $this->getUserServers($user['user_id']); $user['class'] = ($x & 1) ? 'odd' : 'even'; $user['level_text'] = psm_get_lang('users', 'level_' . $user['level']); $user['emp_servers'] = array(); // fix server list foreach ($user_servers as $server_id) { if (!isset($servers_labels[$server_id])) { continue; } $user['emp_servers'][] = array( 'label' => $servers_labels[$server_id], 'url' => psm_build_url( array('mod' => 'server', 'action' => 'view', 'id' => $server_id, 'back_to' => 'user') ) ); } sort($user['emp_servers']); $user['url_delete'] = psm_build_url(array( 'mod' => 'user', 'action' => 'delete', 'id' => $user['user_id'], )); $user['url_edit'] = psm_build_url(array( 'mod' => 'user', 'action' => 'edit', 'id' => $user['user_id'], )); } $tpl_data = $this->getLabels(); $tpl_data['users'] = $users; return $this->twig->render('module/user/user/list.tpl.html', $tpl_data); } /** * Crate HTML for the update screen for a user * * @return string */ protected function executeEdit() { $user_id = isset($_GET['id']) ? intval($_GET['id']) : 0; $fields_prefill = array( 'name', 'user_name', 'mobile', 'pushover_key', 'pushover_device', 'telegram_id', 'jabber', 'email' ); if ($user_id == 0) { // insert mode $title = psm_get_lang('system', 'insert'); $placeholder_password = ''; $lvl_selected = PSM_USER_USER; // default level is regular user // attempt to prefill previously posted fields $edit_user = new \stdClass(); foreach ($fields_prefill as $field) { $edit_user->$field = (isset($_POST[$field])) ? $_POST[$field] : ''; } // add inactive class to all servers foreach ($this->servers as &$server) { $server['class'] = 'inactive'; } } else { // edit mode try { $this->container->get('util.user.validator')->userId($user_id); } catch (\InvalidArgumentException $e) { $this->addMessage(psm_get_lang('users', 'error_' . $e->getMessage()), 'error'); return $this->executeIndex(); } $edit_user = $this->getUser()->getUser($user_id); $title = psm_get_lang('system', 'edit') . ' ' . $edit_user->name; $placeholder_password = psm_get_lang('users', 'password_leave_blank'); $lvl_selected = $edit_user->level; // select servers for this user $user_servers = $this->getUserServers($user_id); foreach ($this->servers as &$server) { $this->servers[$server['server_id']]['id'] = $server['server_id']; if (in_array($server['server_id'], $user_servers)) { $server['edit_selected'] = 'selected="selected"'; $server['class'] = 'active'; } } } $tpl_data = array( 'titlemode' => $title, 'placeholder_password' => $placeholder_password, 'edit_user_id' => $user_id, 'url_save' => psm_build_url(array( 'mod' => 'user', 'action' => 'save', 'id' => $user_id, )), 'servers' => $this->servers, 'user_level' => $lvl_selected, ); foreach ($fields_prefill as $field) { if (isset($edit_user->$field)) { $tpl_data['edit_value_' . $field] = $edit_user->$field; } } $tpl_data['levels'] = array(); foreach ($this->container->get('util.user.validator')->getUserLevels() as $lvl) { $tpl_data['levels'][] = array( 'value' => $lvl, 'label' => psm_get_lang('users', 'level_' . $lvl), ); } $tpl_data = array_merge($this->getLabels(), $tpl_data); return $this->twig->render('module/user/user/update.tpl.html', $tpl_data); } /** * Executes the saving of a user */ protected function executeSave() { if (empty($_POST)) { // dont process anything if no data has been posted return $this->executeIndex(); } $user_id = (isset($_GET['id'])) ? intval($_GET['id']) : 0; $fields = array( 'name', 'user_name', 'password', 'password_repeat', 'level', 'mobile', 'pushover_key', 'pushover_device', 'telegram_id', 'jabber', 'email' ); $clean = array(); foreach ($fields as $field) { if (isset($_POST[$field])) { $clean[$field] = trim(strip_tags($_POST[$field])); } else { $clean[$field] = ''; } } $user_validator = $this->container->get('util.user.validator'); try { $user_validator->username($clean['user_name'], $user_id); $user_validator->email($clean['email']); $user_validator->level($clean['level']); // always validate password for new users, // but only validate it for existing users when they change it. if ($user_id == 0 || ($user_id > 0 && $clean['password'] != '')) { $user_validator->password($clean['password'], $clean['password_repeat']); } if ($user_id > 0) { $user_validator->userId($user_id); } } catch (\InvalidArgumentException $e) { $this->addMessage(psm_get_lang('users', 'error_' . $e->getMessage()), 'error'); return $this->executeEdit(); } if (!empty($clean['password'])) { $password = $clean['password']; } unset($clean['password_repeat']); if ($user_id > 0) { // edit user unset($clean['password']); // password update is executed separately $admins = $this->db->select(PSM_DB_PREFIX . 'users', array('level' => PSM_USER_ADMIN)); if ( (int) count($admins) === (int) 1 && (int) $admins[0]['user_id'] === (int) $user_id && (int) $clean['level'] === (int) PSM_USER_USER ) { $this->addMessage(psm_get_lang('users', 'error_user_admin_cant_be_deleted'), 'warning'); $clean['level'] = PSM_USER_ADMIN; } $this->db->save(PSM_DB_PREFIX . 'users', $clean, array('user_id' => $user_id)); $this->addMessage(psm_get_lang('users', 'updated'), 'success'); $event = \psm\Module\User\UserEvents::USER_EDIT; } else { // add user $clean['password'] = ''; // password update is executed separately $user_id = $this->db->save(PSM_DB_PREFIX . 'users', $clean); $this->addMessage(psm_get_lang('users', 'inserted'), 'success'); $event = \psm\Module\User\UserEvents::USER_ADD; } $this->container->get('event')->dispatch( $event, new \psm\Module\User\Event\UserEvent($user_id, $this->getUser()->getUserId()) ); if (isset($password)) { $this->getUser()->changePassword($user_id, $password); } // update servers $server_idc = psm_POST('server_id', array()); $server_idc_save = array(); foreach ($server_idc as $server_id) { $server_idc_save[] = array( 'user_id' => $user_id, 'server_id' => intval($server_id), ); } // delete all existing records $this->db->delete(PSM_DB_PREFIX . 'users_servers', array('user_id' => $user_id)); if (!empty($server_idc_save)) { // add all new servers $this->db->insertMultiple(PSM_DB_PREFIX . 'users_servers', $server_idc_save); } return $this->executeIndex(); } /** * Executes the deletion of a user */ protected function executeDelete() { $id = (isset($_GET['id'])) ? intval($_GET['id']) : 0; try { $this->container->get('util.user.validator')->userId($id); $admins = $this->db->select(PSM_DB_PREFIX . 'users', array('level' => PSM_USER_ADMIN)); if ( (int) count($admins) === (int) 1 && (int) $admins[0]['user_id'] === (int) $id ) { $this->addMessage(psm_get_lang('users', 'error_user_admin_cant_be_deleted'), 'error'); } else { $this->db->delete(PSM_DB_PREFIX . 'users', array('user_id' => $id,)); $this->db->delete(PSM_DB_PREFIX . 'users_servers', array('user_id' => $id)); $this->container->get('event')->dispatch( \psm\Module\User\UserEvents::USER_DELETE, new \psm\Module\User\Event\UserEvent($id, $this->getUser()->getUserId()) ); $this->addMessage(psm_get_lang('users', 'deleted'), 'success'); } } catch (\InvalidArgumentException $e) { $this->addMessage(psm_get_lang('users', 'error_' . $e->getMessage()), 'error'); } return $this->executeIndex(); } protected function getLabels() { return array( 'label_users' => psm_get_lang('menu', 'user'), 'label_user' => psm_get_lang('users', 'user'), 'label_name' => psm_get_lang('users', 'name'), 'label_user_name' => psm_get_lang('users', 'user_name'), 'label_password' => psm_get_lang('users', 'password'), 'label_password_repeat' => psm_get_lang('users', 'password_repeat'), 'label_level' => psm_get_lang('users', 'level'), 'label_level_description' => psm_get_lang('users', 'level_description'), 'label_mobile' => psm_get_lang('users', 'mobile'), 'label_pushover' => psm_get_lang('users', 'pushover'), 'label_pushover_description' => psm_get_lang('users', 'pushover_description'), 'label_pushover_key' => psm_get_lang('users', 'pushover_key'), 'label_pushover_device' => psm_get_lang('users', 'pushover_device'), 'label_pushover_device_description' => psm_get_lang('users', 'pushover_device_description'), 'label_telegram' => psm_get_lang('users', 'telegram'), 'label_telegram_id' => psm_get_lang('users', 'telegram_chat_id'), 'label_telegram_id_description' => psm_get_lang('users', 'telegram_chat_id_description'), 'label_jabber' => psm_get_lang('users', 'jabber'), 'label_jabber_description' => psm_get_lang('users', 'jabber_description'), 'label_email' => psm_get_lang('users', 'email'), 'label_servers' => psm_get_lang('menu', 'server'), 'label_save' => psm_get_lang('system', 'save'), 'label_go_back' => psm_get_lang('system', 'go_back'), 'label_edit' => psm_get_lang('system', 'edit'), 'label_delete' => psm_get_lang('system', 'delete'), 'label_add_new' => psm_get_lang('system', 'add_new'), 'label_search' => psm_get_lang('system', 'search'), ); } /** * Get all server ids for a user * @param int $user_id * @return array with ids only * @todo we should probably find a central place for this kind of stuff */ protected function getUserServers($user_id) { $servers = $this->db->select( PSM_DB_PREFIX . 'users_servers', array('user_id' => $user_id), array('server_id') ); $result = array(); foreach ($servers as $server) { $result[] = $server['server_id']; } return $result; } }