modx =& $modx; $corePath = $this->modx->getOption('admintools_core_path', $config, $this->modx->getOption('core_path') . 'components/admintools/'); $assetsUrl = $this->modx->getOption('admintools_assets_url', $config, $this->modx->getOption('assets_url') . 'components/admintools/'); $connectorUrl = $assetsUrl . 'connector.php'; $this->config = array_merge([ 'assetsUrl' => $assetsUrl, 'cssUrl' => $assetsUrl . 'css/', 'jsUrl' => $assetsUrl . 'js/', 'connectorUrl' => $connectorUrl, 'corePath' => $corePath, 'modelPath' => $corePath . 'model/', 'templatesPath' => $corePath . 'elements/templates/', 'processorsPath' => $corePath . 'processors/', 'unlockCode' => $this->modx->getOption('admintools_unlock_code', null, ''), 'lockTimeout' => $this->modx->getOption('admintools_lock_timeout', null, 0) * 60 * 1000, 'show_lockmenu' => $this->modx->getOption('admintools_show_lockmenu', null, true), ], $config); if (!$this->modx->addPackage('admintools', $this->config['modelPath'])) { $this->modx->log(modX::LOG_LEVEL_ERROR, '[adminTools] Can\'t load the package.'); } $this->modx->lexicon->load('admintools:default'); } public function initialize($ctx = 'mgr') { switch ($ctx) { case 'mgr': if (empty($this->initialized[$ctx])) { $this->modx->controller->addLexiconTopic('admintools:default'); $this->modx->controller->addCss($this->config['cssUrl'] . 'mgr/main.css'); $theme = $this->modx->getOption('admintools_theme', null, ''); $theme = trim($theme) == 'default' ? '' : trim($theme); if (!empty($theme)) { $themeCssFile = 'mgr/themes/' . $theme . '.css'; $this->modx->controller->addCss($this->config['cssUrl'] . $themeCssFile); $theme .= '-theme'; } // Custom style files if ($customCSS = $this->modx->getOption('admintools_custom_css')) { $customCSS = explode(',', $customCSS); foreach ($customCSS as $cssFile) { $cssFile = str_replace('{adminToolsCss}', $this->config['cssUrl'] . 'mgr/', $cssFile); $this->modx->controller->addCss($cssFile); } } $this->modx->controller->addJavascript($this->config['jsUrl'] . 'mgr/admintools.js'); /** @var bool $pElementTree Permission for the element tree */ $pElementTree = $this->modx->hasPermission('element_tree'); // favorite elements if ($pElementTree && $this->modx->getOption('admintools_enable_favorite_elements', null, true)) { $this->modx->controller->addLastJavascript($this->config['jsUrl'] . 'mgr/favorites.js'); // View "All/Favorites" $states = $this->getFromProfile('adminToolsStates'); if (empty($states)) { $_SESSION['admintools']['favoriteElements']['states'] = ['template' => false, 'chunk' => false, 'tv' => false, 'plugin' => false, 'snippet' => false]; $this->saveToProfile($_SESSION['admintools']['favoriteElements']['states'], 'adminToolsStates'); //$this->saveToCache($_SESSION['admintools']['favoriteElements']['states'], 'states', 'favorite_elements/' . $this->modx->user->id); } else { $_SESSION['admintools']['favoriteElements']['states'] = $states; } // Get favorites elements $elements = $this->getFromProfile('adminToolsElements'); if (empty($elements)) { $_SESSION['admintools']['favoriteElements']['elements'] = [ 'templates' => [], 'tvs' => [], 'chunks' => [], 'plugins' => [], 'snippets' => [], ]; $this->saveToProfile($_SESSION['admintools']['favoriteElements']['elements'], 'adminToolsElements'); } else { $_SESSION['admintools']['favoriteElements']['elements'] = $elements; } $_SESSION['admintools']['favoriteElements']['icon'] = $this->modx->getOption('admintools_favorites_icon') ? 'icon ' . $this->modx->getOption('admintools_favorites_icon') : ''; } // system settings if ($this->modx->hasPermission('settings') && $this->modx->getOption('admintools_remember_system_settings', null, true)) { $this->modx->controller->addLastJavascript($this->config['jsUrl'] . 'mgr/systemsettings.js'); $settings = $this->getFromProfile('systemSettings'); if (empty($settings)) { $_SESSION['admintools']['systemSettings'] = ['namespace' => 'core', 'area' => '']; $this->saveToProfile($_SESSION['admintools']['systemSettings'], 'systemSettings'); } else { $_SESSION['admintools']['systemSettings'] = $settings; } if (empty($_SESSION['admintools']['systemSettings']['namespace'])) { $_SESSION['admintools']['systemSettings']['namespace'] = 'core'; } } // edited elements log if ($pElementTree && $this->modx->getOption('admintools_enable_elements_log', null, true)) { $this->modx->controller->addLastJavascript($this->config['jsUrl'] . 'mgr/elementlog.js'); $this->modx->controller->addLexiconTopic('manager_log'); } // admin notes if ($this->modx->getOption('admintools_enable_notes', null, true)) { $this->modx->controller->addLastJavascript($this->config['jsUrl'] . 'mgr/notes.js'); } // Hide components description $_css = ''; if ($this->modx->getOption('admintools_hide_component_description', null, true)) { $_css .= "\t#limenu-components ul.modx-subnav li a span.description {display: none;}\n"; } // Animate the main menu if ($this->modx->getOption('admintools_animate_menu', null, true)) { $_css .= "\t#modx-navbar ul.modx-subnav, #modx-navbar ul.modx-subsubnav {transition: all .2s ease-in .2s;} \n"; $_css .= "\t#modx-navbar ul.modx-subsubnav {display:block !important;opacity: 0; visibility: hidden;} \n"; $_css .= "\t#modx-navbar ul.modx-subnav li:hover ul.modx-subsubnav {opacity: 1; visibility: visible;} \n"; } if ($_css) { $this->modx->controller->addHtml(""); } // Plugins if ($pElementTree && $this->modx->getOption('admintools_plugins_events', null, true)) { $this->modx->controller->addLastJavascript($this->config['jsUrl'] . 'mgr/plugins.js'); } // taskpanel /* if ($this->modx->getOption('admintools_enable_taskpanel',null,false)) { $this->modx->controller->addLastJavascript($this->config['jsUrl'] . 'mgr/taskpanel.js'); } */ // config $region = $this->modx->getOption('admintools_modx_tree_position', null, 'left', true) == 'right' ? 'east' : 'west'; if ($region == 'east') { $scripts = "\n"; $scripts .= $this->modx->smarty->get_template_vars('maincssjs'); $layout_src = $this->getOption('jsUrl') . 'mgr/core/modx.layout.js'; $scripts .= ""; $this->modx->smarty->assign('maincssjs', $scripts); } // Messages $messageNumber = $this->modx->getOption('admintools_messages', null, true) ? $this->modx->getCount('modUserMessage', ['recipient' => $this->modx->user->id, 'read' => 0]) : -1; // Lock $_SESSION['admintools']['locked'] = isset($_SESSION['admintools']['locked']) ? $_SESSION['admintools']['locked'] : false; $_SESSION['admintools']['config'] = [ 'connector_url' => $this->config['assetsUrl'] . 'connector.php', 'theme' => $theme, 'region' => $region, 'lock_timeout' => $this->config['lockTimeout'], 'show_lockmenu' => $this->config['show_lockmenu'], 'messages' => $messageNumber, ]; $scripts = ""; $this->modx->controller->addHtml($scripts); // Custom javascript files if ($customJS = $this->modx->getOption('admintools_custom_js')) { $customJS = explode(',', $customJS); foreach ($customJS as $jsFile) { $jsFile = str_replace('{adminToolsJs}', $this->config['jsUrl'] . 'mgr/', $jsFile); $this->modx->controller->addLastJavascript($jsFile); } } $this->initialized[$ctx] = true; } break; case 'web': break; } return true; } /** * @param $key * @param mixed $value * @internal param $property */ public function setOption($key, $value) { if (!empty($key)) { $this->config[$key] = $value; } } /** * @param $property * @param string $default * @return mixed */ public function getOption($property, $default = '') { return isset($this->config[$property]) ? $this->config[$property] : $default; } /** * @return array */ public function getOptions() { return $this->config; } public function getFromProfile($key) { if ($this->modx->user->isAuthenticated('mgr')) { $profile = $this->modx->user->getOne('Profile'); $fields = $profile->get('extended'); if (isset($fields[$key])) { return $fields[$key]; } else { return false; } } else { return false; } } /** * @param array $data * @param string $key */ public function saveToProfile($data, $key) { if ($this->modx->user->isAuthenticated('mgr')) { $profile = $this->modx->user->getOne('Profile'); $fields = $profile->get('extended'); $fields[$key] = $data; $profile->set('extended', $fields); if (!$profile->save()) { $this->modx->log(modX::LOG_LEVEL_ERROR, '[' . __METHOD__ . '] Could not save extended fields = ' . print_r($fields, 1)); } } } /** * @param array $object * @deprecated */ public function updateElementLog(array $object) { $type = explode('/', $object['action']); $elementData = [ 'type' => $type[1], 'eid' => $object['id'], 'name' => $type[1] == 'template' ? $object['templatename'] : $object['name'], 'editedon' => date('Y-m-d H:i:s'), 'user' => $this->modx->user->get('username'), ]; $key = $elementData['type'] . '-' . $elementData['eid']; $data[$key] = $elementData; $elements = $this->getFromCache('element_log', 'elementlog/'); if (is_array($elements)) { if (isset($elements[$key])) { unset($elements[$key]); } $elements = array_merge($data, $elements); } else { $elements = $data; } $this->saveToCache($elements, 'element_log', 'elementlog/'); } /** * @deprecated * @return mixed */ public function getElementLog() { return $this->getFromCache('element_log', 'elementlog/'); } /** * @param modResource $resource */ public function clearResourceCache(&$resource) { // $resource->clearCache(); $resource->_contextKey = $resource->context_key; /** @var modCacheManager $cache */ $cache = $this->modx->cacheManager->getCacheProvider($this->modx->getOption('cache_resource_key', null, 'resource')); $key = $resource->getCacheKey(); $cache->delete($key, ['deleteTop' => true]); $cache->delete($key); $this->modx->_clearResourceCache = true; $this->modx->cacheManager = new atCacheManager($this->modx); } public function sendLoginLink($data) { $c = $this->modx->newQuery('modUser'); $c->select(['modUser.*', 'Profile.email', 'Profile.fullname']); $c->innerJoin('modUserProfile', 'Profile'); $c->where([ 'modUser.username' => $data['userdata'], 'OR:Profile.email:=' => $data['userdata'], ]); $c->where([ 'modUser.active' => 1, 'Profile.blocked' => 0, ]); $message = ''; /** @var modUser $user */ $user = $this->modx->getObject('modUser', $c); if ($user) { $this->modx->user = $user; if (!$this->modx->hasPermission('frames')) { $message = $this->modx->lexicon('admintools_user_not_found'); $this->modx->user = null; $this->modx->user = $this->modx->getUser(); return $message; } $hash = $this->addLoginState($user); if (!empty($hash)) { $key = md5($_SERVER['REMOTE_ADDR'] . '/' . $_SERVER['HTTP_USER_AGENT'] . $user->id); $args = ['a' => 'login', 'id' => $key, 'hash' => $hash]; $url = $this->modx->makeUrl($this->modx->resource->id, '', $args, 'full'); $options['email_body'] = $this->modx->lexicon('admintools_authorization_email_body', ['url' => $url]); $this->sendEmail($user->get('email'), $options); } else { $message = $this->modx->lexicon('admintools_link_already_sent'); } } else { $message = $this->modx->lexicon('admintools_user_not_found'); } return $message; } /** * @param modUser $user * @return bool */ public function addLoginState($user) { $hash = ''; $key = md5($_SERVER['REMOTE_ADDR'] . '/' . $_SERVER['HTTP_USER_AGENT'] . $user->id); $state = $this->getLoginState($key); if (empty($state)) { $ttl = $this->modx->getOption('admintools_authorization_ttl', null, 200); $hash = md5(uniqid(md5($user->get('email') . '/' . $key), true)); $this->modx->registry->user->subscribe('/admintools/login/'); $this->modx->registry->user->send('/admintools/login/', [ $key => [ 'hash' => $hash, 'uid' => $user->get('id'), ], ], ['ttl' => $ttl]); } return $hash; } public function getLoginState($key) { $data = ''; if ($this->modx->getService('registry', 'registry.modRegistry')) { $this->modx->registry->addRegister('user', 'registry.modDbRegister'); $this->modx->registry->user->connect(); $this->modx->registry->user->subscribe('/admintools/login/' . $key); if ($msgs = $this->modx->registry->user->read(['remove_read' => false, 'poll_limit' => 1])) { $data = reset($msgs); } } return $data; } public function deleteLoginState($key) { $deleted = false; if ($this->modx->getService('registry', 'registry.modRegistry')) { $this->modx->registry->addRegister('user', 'registry.modDbRegister'); $this->modx->registry->user->connect(); $this->modx->registry->user->subscribe('/admintools/login/' . $key); $this->modx->registry->user->read(['remove_read' => true, 'poll_limit' => 1]); $deleted = true; } return $deleted; } /** * Sends email with authorization link * * @param $email * @param array $options * * @return string|bool */ public function sendEmail($email, array $options = []) { /** @var modPHPMailer $mail */ $mail = $this->modx->getService('mail', 'mail.modPHPMailer'); $mail->set(modMail::MAIL_SUBJECT, $this->modx->getOption('email_subject', $options, $this->modx->lexicon('admintools_authorization_email_subject'))); $mail->set(modMail::MAIL_BODY, $this->modx->getOption('email_body', $options, '')); $mail->set(modMail::MAIL_SENDER, $this->modx->getOption('email_from', $options, $this->modx->getOption('emailsender'), true)); $mail->set(modMail::MAIL_FROM, $this->modx->getOption('email_from', $options, $this->modx->getOption('emailsender'), true)); $mail->set(modMail::MAIL_FROM_NAME, $this->modx->getOption('email_from_name', $options, $this->modx->getOption('site_name'), true)); $mail->address('to', $email); $mail->address('reply-to', $this->modx->getOption('email_from', $options, $this->modx->getOption('emailsender'), true)); $mail->setHTML(true); $response = !$mail->send() ? $mail->mailer->errorInfo : true; $mail->reset(); return $response; } public function loginUser($userId) { $error_message = ''; /** @var modUser $user */ if ($user = $this->modx->getObject('modUser', $userId)) { $data['username'] = $user->get('username'); $data['password'] = 'password'; $data['login_context'] = 'mgr'; $data['addContexts'] = []; $data['rememberme'] = (int)$this->modx->getOption('admintools_rememberme', null, 0); } else { return 'Error when try to login.'; } $query = $this->modx->newQuery('modPlugin', [ 'name' => 'AdminTools', ]); $query->select('id'); $id = $this->modx->getValue($query->prepare()); if (!empty($id)) { // $this->modx->addEventListener('OnManagerPageBeforeRender', $id); // $this->modx->addEventListener('OnManagerAuthentication', $id); $this->modx->eventMap['OnManagerPageBeforeRender'][$id] = $id; $this->modx->eventMap['OnManagerAuthentication'][$id] = $id; } else { $error_message = $this->modx->lexicon('admintools_plugin_not_found'); return $error_message; } $this->modx->setOption('admintools_user_can_login', true); /** @var modProcessorResponse $response */ $response = $this->modx->runProcessor('security/login', $data); if (($response instanceof modProcessorResponse) && !$response->isError()) { $key = md5($_SERVER['REMOTE_ADDR'] . '/' . $_SERVER['HTTP_USER_AGENT'] . $userId); $this->deleteLoginState($key); $url = $this->modx->getOption('manager_url', null, MODX_MANAGER_URL); $url = $this->modx->getOption('url_scheme', null, MODX_URL_SCHEME) . $this->modx->getOption('http_host', null, MODX_HTTP_HOST) . rtrim($url, '/'); $this->modx->sendRedirect($url); } else { $errors = $response->getAllErrors(); $error_message = implode("\n", $errors); } return $error_message; } /** * @param int $rid Resource id * @return bool */ public function hasPermissions($rid = 0) { //TODO-sergant Сделать map файл. if ($rid == 0) { $rid = $this->modx->resource->get('id'); } $user = $this->modx->user; $userId = $this->modx->user->get('id'); $q = $this->modx->newQuery('adminToolsPermissions'); $q->setClassAlias('Permissions'); // $q->leftJoin('modUserProfile','User', 'Permissions.principal = User.internalKey AND Permissions.principal_type = "usr"'); $q->leftJoin('modUserGroup', 'Group', 'Permissions.principal = Group.id AND Permissions.principal_type = "grp"'); $q->select('Permissions.*, Group.name as groupname'); $q->where([ 'Permissions.rid' => $rid, ]); $q->sortby('Permissions.weight', 'ASC'); $q->sortby('Permissions.priority', 'ASC'); $tstart = microtime(true); if ($q->prepare() && $q->stmt->execute()) { $this->modx->queryTime += microtime(true) - $tstart; $this->modx->executedQueries++; $permissions = $q->stmt->fetchAll(PDO::FETCH_ASSOC); } $allow = true; if (!empty($permissions)) { foreach ($permissions as $permission) { switch ($permission['principal_type']) { case 'all': $allow = (bool)$permission['status']; break; case 'gst': if ($userId == 0) { $allow = (bool)$permission['status']; } break; case 'grp': if ($userId && $user->isMember($permission['groupname'])) { $allow = (bool)$permission['status']; } break; case 'usr': if ($userId == $permission['principal']) { $allow = (bool)$permission['status']; } break; } } } return $allow; } public function createResourceCache($uri = '/') { $siteUrl = $this->modx->getOption('site_url'); /** @var modRestCurlClient $client */ $client = $this->modx->getService('rest.modRestCurlClient'); $result = $client->request($siteUrl, $uri, 'POST'); } public function isLocked() { return !empty($_SESSION['admintools']['locked']); } public function unlock($unlockCode) { if (!empty($unlockCode)) { $_SESSION['admintools']['locked'] = empty($this->config['unlockCode']) ? !$this->modx->user->passwordMatches($unlockCode) : $this->config['unlockCode'] !== $unlockCode; } return !$_SESSION['admintools']['locked']; } public function getInputPlaceholder() { return empty($this->config['unlockCode']) ? $this->modx->lexicon('admintools_enter_password') : $this->modx->lexicon('admintools_enter_unlockcode'); } } /** * Cache manager class for adminTools. */ require_once MODX_CORE_PATH . 'model/modx/modcachemanager.class.php'; class atCacheManager extends modCacheManager { public function refresh(array $providers = [], array &$results = []) { if ($this->modx->getOption('admintools_clear_only_resource_cache', null, false) && !empty($this->modx->_clearResourceCache)) { $this->modx->_clearResourceCache = false; unset($providers['resource']); $this->modx->cacheManager = null; $this->modx->getCacheManager(); } return parent::refresh($providers, $results); } }