Index: branches/5.3.x/core/kernel/session/session.php =================================================================== --- branches/5.3.x/core/kernel/session/session.php (revision 16599) +++ branches/5.3.x/core/kernel/session/session.php (revision 16600) @@ -1,1132 +1,1134 @@ SetCookieDomain('my.domain.com'); $session->SetCookiePath('/myscript'); $session->SetCookieName('my_sid_cookie'); $session->SetGETName('sid'); $session->InitSession(); ... //link output: echo "NeedQueryString() ? 'sid='.$session->SID : '' ) .">My Link"; */ class BaseSession extends kBase { const smAUTO = 1; const smCOOKIES_ONLY = 2; const smGET_ONLY = 3; const smCOOKIES_AND_GET = 4; var $Checkers; var $Mode; var $OriginalMode = null; var $GETName = 'sid'; var $CookiesEnabled = true; var $CookieName = 'sid'; var $CookieDomain; var $CookiePath; var $CookieSecure = 0; var $SessionTimeout = 3600; var $Expiration; var $SID; var $CachedSID; var $SessionSet = false; /** * Session ID is used from GET * * @var bool */ var $_fromGet = false; /** * Enter description here... * * @var BaseSessionStorage * @access protected */ protected $Storage; var $CachedNeedQueryString = null; /** * Session Data array * * @var Params */ var $Data; /** * Names of optional session keys with their optional values (which does not need to be always stored) * * @var Array */ var $OptionalData = Array (); /** * Session expiration mark * * @var bool */ var $expired = false; /** * Creates session * * @param int $mode * @access public */ public function __construct($mode = self::smAUTO) { parent::__construct(); $this->SetMode($mode); } function SetMode($mode) { $this->Mode = $mode; $this->CachedNeedQueryString = null; $this->CachedSID = null; } function SetCookiePath($path) { $this->CookiePath = str_replace(' ', '%20', $path); } /** * Setting cookie domain. Set false for local domains, because they don't contain dots in their names. * * @param string $domain */ function SetCookieDomain($domain) { // 1. localhost or other like it without "." in domain name if (!substr_count($domain, '.')) { // don't use cookie domain at all $this->CookieDomain = false; return ; } // 2. match using predefined cookie domains from configuration $cookie_domains = $this->Application->ConfigValue('SessionCookieDomains'); if ($cookie_domains) { $cookie_domains = array_map('trim', explode("\n", $cookie_domains)); foreach ($cookie_domains as $cookie_domain) { if (ltrim($cookie_domain, '.') == $domain) { $this->CookieDomain = $cookie_domain; // as defined in configuration return ; } } } // 3. only will execute, when none of domains were matched at previous step $this->CookieDomain = $this->_autoGuessDomain($domain); } /** * Auto-guess cookie domain based on $_SERVER['HTTP_HOST'] * * @param $domain * @return string */ function _autoGuessDomain($domain) { static $cache = Array (); if (!array_key_exists($domain, $cache)) { switch ( substr_count($domain, '.') ) { case 2: // 3rd level domain (3 parts) $cache[$domain] = substr($domain, strpos($domain, '.')); // with leading "." break; case 1: // 2rd level domain (2 parts) $cache[$domain] = '.' . $domain; // with leading "." break; default: // more then 3rd level $cache[$domain] = ltrim($domain, '.'); // without leading "." break; } } return $cache[$domain]; } function SetGETName($get_name) { $this->GETName = $get_name; } function SetCookieName($cookie_name) { $this->CookieName = $cookie_name; } function InitStorage($special) { $this->Storage = $this->Application->recallObject('SessionStorage.'.$special); $this->Storage->setSession($this); } public function Init($prefix, $special) { parent::Init($prefix, $special); if ( php_sapi_name() == 'cli' ) { $this->SetMode(self::smGET_ONLY); } $this->CheckIfCookiesAreOn(); $this->Checkers = Array(); $this->InitStorage($special); $this->Data = new Params(); $tmp_sid = $this->GetPassedSIDValue(); $check = $this->Check(); if ($this->Application->isAdmin) { // 1. Front-End session may not be created (SID is present, but no data in database). // Check expiration LATER from kApplication::Init, because template, used in session // expiration redirect should be retrieved from mod-rewrite url first. // 2. Admin sessions are always created, so case when SID is present, // but session in database isn't is 100% session expired. Check expiration // HERE because Session::SetSession will create missing session in database // and when Session::ValidateExpired will be called later from kApplication::Init // it won't consider such session as expired !!! $this->ValidateExpired(); } if ($check) { $this->SID = $this->GetPassedSIDValue(); $this->Refresh(); $this->LoadData(); } else { $this->SetSession(); } if (!is_null($this->OriginalMode)) $this->SetMode($this->OriginalMode); } function ValidateExpired() { if (defined('IS_INSTALL') && IS_INSTALL) { return ; } // $this->DeleteExpired(); // called from u:OnDeleteExpiredSessions scheduled task now if ($this->expired || ($this->CachedSID && !$this->_fromGet && !$this->SessionSet)) { $this->RemoveSessionCookie(); // true was here to force new session creation, but I (kostja) used // RemoveCookie a line above, to avoid redirect loop with expired sid // not being removed setSession with true was used before, to set NEW // session cookie $this->SetSession(); // case #1: I've OR other site visitor expired my session // case #2: I have no session in database, but SID is present $this->expired = false; $this->Application->HandleEvent(new kEvent('u:OnSessionExpire')); } } /** * Helper method for detecting cookie availability * * @return bool */ function _checkCookieReferer() { // removing /admin for compatability with in-portal (in-link/admin/add_link.php) $path = preg_replace('/admin[\/]{0,1}$/', '', $this->CookiePath); $reg = '#^'.preg_quote(PROTOCOL.ltrim($this->CookieDomain, '.').$path).'#'; return preg_match($reg, getArrayValue($_SERVER, 'HTTP_REFERER') ); } function CheckIfCookiesAreOn() { if ( $this->Mode == self::smGET_ONLY ) { //we don't need to bother checking if we would not use it $this->CookiesEnabled = false; return false; } /** @var kHTTPQuery $http_query */ $http_query = $this->Application->recallObject('kHTTPQuery'); $cookies_on = array_key_exists('cookies_on', $http_query->Cookie); // not good here $get_sid = getArrayValue($http_query->Get, $this->GETName); if ( ($this->Application->HttpQuery->IsHTTPSRedirect() && $get_sid) || $this->getFlashSID() ) { // Redirect from http to https on different domain OR flash uploader $this->OriginalMode = $this->Mode; $this->SetMode(self::smGET_ONLY); } if ( !$cookies_on || $this->Application->HttpQuery->IsHTTPSRedirect() || $this->getFlashSID() ) { //If referer is our server, but we don't have our cookies_on, it's definetly off $is_install = defined('IS_INSTALL') && IS_INSTALL; if ( !$is_install && $this->_checkCookieReferer() && !$this->Application->GetVar('admin') && !$this->Application->HttpQuery->IsHTTPSRedirect() ) { $this->CookiesEnabled = false; } else { //Otherwise we still suppose cookies are on, because may be it's the first time user visits the site //So we send cookies on to get it next time (when referal will tell us if they are realy off $this->SetCookie('cookies_on', 1, time() + 31104000); //one year should be enough } } else { $this->CookiesEnabled = true; } return $this->CookiesEnabled; } /** * Sets cookie for current site using path and domain * * @param string $name * @param mixed $value * @param int $expires */ function SetCookie($name, $value, $expires = null) { if (isset($expires) && $expires < time()) { unset($this->Application->HttpQuery->Cookie[$name]); } else { $this->Application->HttpQuery->Cookie[$name] = $value; } $old_style_domains = Array ( // domain like in pre 5.1.0 versions '.' . SERVER_NAME, // auto-guessed domain (when user specified other domain in configuration variable) $this->_autoGuessDomain(SERVER_NAME) ); $cookie_hasher = $this->Application->makeClass('kCookieHasher'); /* @var $cookie_hasher kCookieHasher */ $encrypted_value = $cookie_hasher->encrypt($name, $value); foreach ($old_style_domains as $old_style_domain) { if ($this->CookieDomain != $old_style_domain) { // new style cookie domain -> delete old style cookie to prevent infinite redirect setcookie($name, $encrypted_value, time() - 3600, $this->CookiePath, $old_style_domain, $this->CookieSecure, true); } } setcookie($name, $encrypted_value, $expires, $this->CookiePath, $this->CookieDomain, $this->CookieSecure, true); } function Check() { // don't check referer here, because it doesn't provide any security option and can be easily falsified $sid = $this->GetPassedSIDValue(); if (empty($sid)) { return false; } //try to load session by sid, if everything is fine $result = $this->LoadSession($sid); $this->SessionSet = $result; // fake front-end session will given "false" here return $result; } function LoadSession($sid) { if( $this->Storage->LocateSession($sid) ) { // if we have session with such SID - get its expiration $this->Expiration = $this->Storage->GetExpiration(); // If session has expired if ($this->Expiration < time()) { // when expired session is loaded, then SID is // not assigned, but used in Destroy method $this->SID = $sid; $this->Destroy(); $this->expired = true; // when Destory methods calls SetSession inside and new session get created return $this->SessionSet; } // Otherwise it's ok return true; } else { // fake or deleted due to expiration SID if (!$this->_fromGet) { $this->expired = true; } return false; } } function getFlashSID() { /** @var kHTTPQuery $http_query */ $http_query = $this->Application->recallObject('kHTTPQuery'); return getArrayValue($http_query->Post, 'flashsid'); } function GetPassedSIDValue($use_cache = 1) { if (!empty($this->CachedSID) && $use_cache) { return $this->CachedSID; } // flash sid overrides regular sid $get_sid = $this->getFlashSID(); if (!$get_sid) { /** @var kHTTPQuery $http_query */ $http_query = $this->Application->recallObject('kHTTPQuery'); $get_sid = getArrayValue($http_query->Get, $this->GETName); } $sid_from_get = $get_sid ? true : false; if ($this->Application->GetVar('admin') == 1 && $get_sid) { $sid = $get_sid; } else { switch ($this->Mode) { case self::smAUTO: //Cookies has the priority - we ignore everything else $sid = $this->CookiesEnabled ? $this->GetSessionCookie() : $get_sid; if ($this->CookiesEnabled) { $sid_from_get = false; } break; case self::smCOOKIES_ONLY: $sid = $this->GetSessionCookie(); break; case self::smGET_ONLY: $sid = $get_sid; break; case self::smCOOKIES_AND_GET: $cookie_sid = $this->GetSessionCookie(); //both sids should match if cookies are enabled if (!$this->CookiesEnabled || ($cookie_sid == $get_sid)) { $sid = $get_sid; //we use get here just in case cookies are disabled } else { $sid = ''; $sid_from_get = false; } break; } } $this->CachedSID = $sid; $this->_fromGet = $sid_from_get; return $this->CachedSID; } /** * Returns session id * * @return int * @access public */ function GetID() { return $this->SID; } /** * Generates new session id * * @return int * @access private */ function GenerateSID() { $this->setSID(kUtil::generateId()); return $this->SID; } /** * Set's new session id * * @param int $new_sid * @access private */ function setSID($new_sid) { $this->SID /*= $this->CachedSID*/ = $new_sid; // don't set cached sid here $this->Application->SetVar($this->GETName,$new_sid); } function NeedSession() { $data = $this->Data->GetParams(); $data_keys = array_keys($data); $optional_keys = array_keys($this->OptionalData); $real_keys = array_diff($data_keys, $optional_keys); return $real_keys ? true : false; } function SetSession($force = false) { if ( $this->SessionSet && !$force ) { return true; } $this->Expiration = time() + $this->SessionTimeout; if ( !$force && /*!$this->Application->isAdmin &&*/ !$this->Application->GetVar('admin') && !$this->NeedSession() ) { // don't create session (in db) on Front-End, when sid is present (GPC), but data in db isn't if ( $this->_fromGet ) { // set sid, that was given in GET $this->setSID($this->GetPassedSIDValue()); } else { // re-generate sid only, when cookies are used $this->GenerateSID(); } $this->Storage->StoreSession(false); return false; } if ( !$this->SID || $force ) { $this->GenerateSID(); } switch ( $this->Mode ) { case self::smAUTO: if ( $this->CookiesEnabled ) { $this->SetSessionCookie(); } break; case self::smGET_ONLY: break; case self::smCOOKIES_ONLY: case self::smCOOKIES_AND_GET: $this->SetSessionCookie(); break; } $this->Storage->StoreSession(); if ( $this->Application->isAdmin || $this->Special == 'admin' ) { $this->StoreVar('admin', 1); } $this->SessionSet = true; // should be called before SaveData, because SaveData will try to SetSession again if ( $this->Special != '' ) { // front-session called from admin or otherwise, then save it's data $this->SaveData(); } $this->Application->resetCounters('UserSessions'); return true; } /** * Returns SID from cookie. * * Use 2 cookies to have 2 expiration: * - 1. for normal expiration when browser is not closed (30 minutes by default), configurable * - 2. for advanced expiration when browser is closed * * @return int */ function GetSessionCookie() { $keep_session_on_browser_close = $this->Application->ConfigValue('KeepSessionOnBrowserClose'); if (isset($this->Application->HttpQuery->Cookie[$this->CookieName]) && ( $keep_session_on_browser_close || ( !$keep_session_on_browser_close && isset($this->Application->HttpQuery->Cookie[$this->CookieName.'_live']) && $this->Application->HttpQuery->Cookie[$this->CookieName] == $this->Application->HttpQuery->Cookie[$this->CookieName.'_live'] ) ) ) { return $this->Application->HttpQuery->Cookie[$this->CookieName]; } return false; } /** * Updates SID in cookie with new value * */ function SetSessionCookie() { $this->SetCookie($this->CookieName, $this->SID, $this->Expiration); $this->SetCookie($this->CookieName.'_live', $this->SID); } function RemoveSessionCookie() { $this->SetCookie($this->CookieName, ''); $this->SetCookie($this->CookieName.'_live', ''); } /** * Refreshes session expiration time * * @access private */ function Refresh() { if ($this->Application->GetVar('skip_session_refresh')) { return ; } if ($this->CookiesEnabled) { // we need to refresh the cookie $this->SetSessionCookie(); } $this->Storage->UpdateSession(); } function Destroy() { $this->Storage->DeleteSession(); $this->Data = new Params(); $this->SID = $this->CachedSID = ''; $this->SessionSet = false; if ($this->CookiesEnabled) { $this->SetSessionCookie(); //will remove the cookie due to value (sid) is empty } $this->SetSession(true); //will create a new session, true to force } function NeedQueryString($use_cache = 1) { - if ($this->CachedNeedQueryString != null && $use_cache) { + if ( $this->CachedNeedQueryString !== null && $use_cache ) { return $this->CachedNeedQueryString; } $result = false; switch ($this->Mode) { case self::smAUTO: - if (!$this->CookiesEnabled) { + if ( !$this->CookiesEnabled && PHP_SAPI !== 'cli' ) { $result = true; } break; /*case self::smCOOKIES_ONLY: break;*/ case self::smGET_ONLY: case self::smCOOKIES_AND_GET: - $result = true; + if ( PHP_SAPI !== 'cli' ) { + $result = true; + } break; } $this->CachedNeedQueryString = $result; return $result; } function LoadData() { $this->Data->AddParams( $this->Storage->LoadData() ); } /** * Returns information about session contents * * @param bool $include_optional * @return array * @access public */ public function getSessionData($include_optional = true) { $session_data = $this->Data->GetParams(); ksort($session_data); foreach ($session_data as $session_key => $session_value) { if ( kUtil::IsSerialized($session_value) ) { $session_data[$session_key] = unserialize($session_value); } } if ( !$include_optional ) { $optional_keys = array_keys($this->OptionalData); foreach ($session_data as $session_key => $session_value) { if ( in_array($session_key, $optional_keys) ) { unset($session_data[$session_key]); } } } return $session_data; } /** * Returns real session data, that was saved * * @param Array $session_data * @return Array * @access protected */ protected function _getRealSessionData($session_data) { $data_keys = array_keys($session_data); $optional_keys = array_keys($this->OptionalData); $real_keys = array_diff($data_keys, $optional_keys); if ( !$real_keys ) { return Array (); } $ret = Array (); foreach ($real_keys as $real_key) { $ret[$real_key] = $session_data[$real_key]; } return $ret; } function PrintSession($comment = '') { if ( defined('DEBUG_MODE') && $this->Application->isDebugMode() && kUtil::constOn('DBG_SHOW_SESSIONDATA') ) { // dump session data $this->Application->Debugger->appendHTML('SessionStorage [' . ($this->RecallVar('admin') == 1 ? 'Admin' : 'Front-End') . '] (' . $comment . '):'); $session_data = $this->getSessionData(); $this->Application->Debugger->dumpVars($session_data); if ( !$this->RecallVar('admin') ) { // dump real keys (only for front-end) $real_session_data = $this->_getRealSessionData($session_data); if ( $real_session_data ) { $this->Application->Debugger->appendHTML('Real Keys:'); $this->Application->Debugger->dumpVars($real_session_data); } } } if ( defined('DEBUG_MODE') && $this->Application->isDebugMode() && kUtil::constOn('DBG_SHOW_PERSISTENTDATA') ) { // dump persistent session data if ( $this->Storage->PersistentVars ) { $this->Application->Debugger->appendHTML('Persistant Session:'); $session_data = $this->Storage->PersistentVars; ksort($session_data); foreach ($session_data as $session_key => $session_value) { if ( kUtil::IsSerialized($session_value) ) { $session_data[$session_key] = unserialize($session_value); } } $this->Application->Debugger->dumpVars($session_data); } } } function SaveData($params = Array ()) { if (!$this->SetSession()) { // call it here - it may be not set before, because there was no need; if there is a need, it will be set here return; } if (!$this->Application->GetVar('skip_last_template') && $this->Application->GetVar('ajax') != 'yes') { $this->SaveLastTemplate( $this->Application->GetVar('t'), $params ); } $this->PrintSession('after save'); $this->Storage->SaveData(); } /** * Save last template * * @param string $t * @param Array $params */ function SaveLastTemplate($t, $params = Array ()) { $wid = $this->Application->GetVar('m_wid'); $last_env = $this->getLastTemplateENV($t, array('m_opener' => 'u')); $last_template = basename($_SERVER['PHP_SELF']) . '|' . $last_env; $this->StoreVar(rtrim('last_template_' . $wid, '_'), $last_template); // prepare last_template for opener stack, module & session could be added later $last_env = $this->getLastTemplateENV($t); $last_template = basename($_SERVER['PHP_SELF']) . '|' . $last_env; // save last_template in persistent session if (!$wid) { if ($this->Application->isAdmin) { // only for main window, not popups, not login template, not temp mode (used in adm:MainFrameLink tag) $temp_mode = false; $passed = explode(',', $this->Application->GetVar('passed')); foreach ($passed as $passed_prefix) { if ($this->Application->GetVar($passed_prefix.'_mode')) { $temp_mode = true; break; } } if (!$temp_mode) { if ( $this->Application->GetVarDirect('section', 'Get') !== false ) { // check directly in GET, because LinkVar (session -> request) used on these vars $last_template .= '§ion='.$this->Application->GetVar('section').'&module='.$this->Application->GetVar('module'); } $this->StorePersistentVar('last_template_popup', $last_template); } } elseif ($this->Application->GetVar('admin')) { // admin checking by session data to prevent recursive session save static $admin_saved = null; if (!$this->RecallVar('admin') && !isset($admin_saved)) { // bug: we get recursion in this place, when cookies are disabled in browser and we are browsing // front-end in admin's frame (front-end session is initialized using admin's sid and they are // mixed together) $admin_saved = true; /** @var Session $admin_session */ $admin_session = $this->Application->recallObject('Session.admin'); // save to admin last_template too, because when F5 is pressed in frameset Front-End frame should reload as well $admin_session->StoreVar('last_template_popup', '../' . $last_template); $admin_session->StorePersistentVar('last_template_popup', '../' . $last_template); $admin_session->SaveData( Array ('save_last_template' => false) ); } else { // don't allow admin=1 & editing_mode=* to get in admin last_template $last_template = preg_replace('/&(admin|editing_mode)=[\d]/', '', $last_template); } } } // save other last... variables for mystical purposes (customizations may be) $this->StoreVar('last_url', $_SERVER['REQUEST_URI']); // needed by ord:StoreContinueShoppingLink $this->StoreVar('last_env', $last_env); $save_last_template = array_key_exists('save_last_template', $params) ? $params['save_last_template'] : true; if ($save_last_template) { // save last template here, because section & module could be added before $this->StoreVar(rtrim('last_template_popup_'.$wid, '_'), $last_template); } } protected function getLastTemplateENV($t, $params = null) { if (!isset($params)) { $params = Array (); } if ($this->Application->GetVar('admin') && !array_key_exists('admin', $params) && !defined('EDITING_MODE')) { $params['editing_mode'] = ''; // used in kApplication::Run } $params = array_merge($this->Application->getPassThroughVariables($params), $params); return $this->Application->BuildEnv($t, $params, 'all', false, false); } /** * Stores variable $val in session under name $var * * Use this method to store variable in session. Later this variable could be recalled. * * @param string $name Variable name * @param mixed $value Variable value * @param bool $optional * @return void * @access public * @see Session::RecallVar() */ public function StoreVar($name, $value, $optional = false) { $this->Data->Set($name, $value); if ( $optional ) { // make variable optional, also remember optional value $this->OptionalData[$name] = $value; } elseif ( !$optional && array_key_exists($name, $this->OptionalData) ) { if ( $this->OptionalData[$name] == $value ) { // same value as optional -> don't remove optional mark return; } // make variable non-optional unset($this->OptionalData[$name]); } } /** * Stores variable to persistent session * * @param string $name * @param mixed $value * @param bool $optional * @return void * @access public */ public function StorePersistentVar($name, $value, $optional = false) { $this->Storage->StorePersistentVar($name, $value, $optional); } function LoadPersistentVars() { $this->Storage->LoadPersistentVars(); } /** * Stores default value for session variable * * @param string $name * @param string $value * @param bool $optional * @return void * @access public * @see Session::RecallVar() * @see Session::StoreVar() */ public function StoreVarDefault($name, $value, $optional = false) { $tmp = $this->RecallVar($name); if ( $tmp === false || $tmp == '' ) { $this->StoreVar($name, $value, $optional); } } /** * Returns session variable value * * Return value of $var variable stored in Session. An optional default value could be passed as second parameter. * * @param string $name Variable name * @param mixed $default Default value to return if no $var variable found in session * @return mixed * @access public */ public function RecallVar($name, $default = false) { $ret = $this->Data->Get($name); return ($ret === false) ? $default : $ret; } /** * Returns variable value from persistent session * * @param string $name * @param mixed $default * @return mixed * @access public */ public function RecallPersistentVar($name, $default = false) { return $this->Storage->RecallPersistentVar($name, $default); } /** * Deletes Session variable * * @param string $var * @return void * @access public */ public function RemoveVar($name) { $this->Storage->RemoveFromData($name); $this->Data->Remove($name); } /** * Removes variable from persistent session * * @param string $name * @return void * @access public */ public function RemovePersistentVar($name) { $this->Storage->RemovePersistentVar($name); } /** * Ignores session variable value set before * * @param string $name * @return void * @access public */ public function RestoreVar($name) { $value = $this->Storage->GetFromData($name, '__missing__'); if ( $value === '__missing__' ) { // there is nothing to restore (maybe session was not saved), look in optional variable values $value = array_key_exists($name, $this->OptionalData) ? $this->OptionalData[$name] : false; } $this->StoreVar($name, $value); } function GetField($var_name, $default = false) { return $this->Storage->GetField($var_name, $default); } function SetField($var_name, $value) { $this->Storage->SetField($var_name, $value); } /** * Deletes expired sessions * * @return Array expired sids if any * @access private */ function DeleteExpired() { return $this->Storage->DeleteExpired(); } /** * Deletes given sessions * * @param $session_ids * @param int $delete_reason * @return void */ function DeleteSessions($session_ids, $delete_reason = SESSION_LOG_EXPIRED) { $this->Storage->DeleteSessions($session_ids, $delete_reason); } /** * Allows to check if user in this session is logged in or not * * @return bool */ function LoggedIn() { $user_id = $this->RecallVar('user_id'); $ret = $user_id > 0; if (($this->RecallVar('admin') == 1 || defined('ADMIN')) && ($user_id == USER_ROOT)) { $ret = true; } return $ret; } } Index: branches/5.3.x/core/kernel/db/db_tag_processor.php =================================================================== --- branches/5.3.x/core/kernel/db/db_tag_processor.php (revision 16599) +++ branches/5.3.x/core/kernel/db/db_tag_processor.php (revision 16600) @@ -1,3128 +1,3187 @@ getObject($params); return $object->GetID() <= 0; } /** * Returns view menu name for current prefix * * @param Array $params * @return string */ function GetItemName($params) { $item_name = $this->getUnitConfig()->getViewMenuPhrase(); return $this->Application->Phrase($item_name); } function ViewMenu($params) { $block_params = $params; unset($block_params['block']); $block_params['name'] = $params['block']; $list =& $this->GetList($params); $block_params['PrefixSpecial'] = $list->getPrefixSpecial(); return $this->Application->ParseBlock($block_params); } function SearchKeyword($params) { $list =& $this->GetList($params); return $this->Application->RecallVar($list->getPrefixSpecial() . '_search_keyword'); } /** * Draw filter menu content (for ViewMenu) based on filters defined in config * * @param Array $params * @return string */ function DrawFilterMenu($params) { $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['spearator_block']; $separator = $this->Application->ParseBlock($block_params); $filter_menu = $this->getUnitConfig()->getFilterMenu(); if ( !$filter_menu ) { trigger_error('no filters defined for prefix ' . $this->Prefix . ', but DrawFilterMenu tag used', E_USER_NOTICE); return ''; } // Params: label, filter_action, filter_status $block_params['name'] = $params['item_block']; $view_filter = $this->Application->RecallVar($this->getPrefixSpecial() . '_view_filter'); if ( $view_filter === false ) { $this->Application->HandleEvent(new kEvent($this->getPrefixSpecial() . ':OnRemoveFilters')); $view_filter = $this->Application->RecallVar($this->getPrefixSpecial() . '_view_filter'); } $view_filter = unserialize($view_filter); $filters = Array (); $prefix_special = $this->getPrefixSpecial(); foreach ($filter_menu['Filters'] as $filter_key => $filter_params) { $group_params = isset($filter_params['group_id']) ? $filter_menu['Groups'][$filter_params['group_id']] : Array (); if ( !isset($group_params['element_type']) ) { $group_params['element_type'] = 'checkbox'; } if ( !$filter_params ) { $filters[] = $separator; continue; } $block_params['label'] = $filter_params['label']; if ( getArrayValue($view_filter, $filter_key) ) { $submit = 0; if ( isset($params['old_style']) ) { $status = $group_params['element_type'] == 'checkbox' ? 1 : 2; } else { $status = $group_params['element_type'] == 'checkbox' ? '[\'img/check_on.gif\']' : '[\'img/menu_dot.gif\']'; } } else { $submit = 1; $status = 'null'; } $block_params['filter_action'] = 'set_filter("' . $prefix_special . '","' . $filter_key . '","' . $submit . '",' . $params['ajax'] . ');'; $block_params['filter_status'] = $status; // 1 - checkbox, 2 - radio, 0 - no image $filters[] = $this->Application->ParseBlock($block_params); } return implode('', $filters); } /** * Draws auto-refresh submenu in View Menu. * * @param Array $params * @return string */ function DrawAutoRefreshMenu($params) { $refresh_intervals = $this->Application->ConfigValue('AutoRefreshIntervals'); if (!$refresh_intervals) { trigger_error('no refresh intervals defined for prefix '.$this->Prefix.', but DrawAutoRefreshMenu tag used', E_USER_NOTICE); return ''; } $refresh_intervals = explode(',', $refresh_intervals); $view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view'); $current_refresh_interval = $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_refresh_interval.'.$view_name); if ($current_refresh_interval === false) { // if no interval was selected before, then choose 1st interval $current_refresh_interval = $refresh_intervals[0]; } $ret = ''; $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['render_as']; foreach ($refresh_intervals as $refresh_interval) { $block_params['label'] = $this->_formatInterval($refresh_interval); $block_params['refresh_interval'] = $refresh_interval; $block_params['selected'] = $current_refresh_interval == $refresh_interval; $ret .= $this->Application->ParseBlock($block_params); } return $ret; } /** * Tells, that current grid is using auto refresh * * @param Array $params * @return bool */ function UseAutoRefresh($params) { $view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view'); return $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_auto_refresh.'.$view_name); } /** * Returns current grid refresh interval * * @param Array $params * @return bool */ function AutoRefreshInterval($params) { $view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view'); return $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_refresh_interval.'.$view_name); } /** * Formats time interval using given text for hours and minutes * * @param int $interval minutes * @param string $hour_text Text for hours * @param string $min_text Text for minutes * @return string */ function _formatInterval($interval, $hour_text = 'h', $min_text = 'min') { // 65 $minutes = $interval % 60; $hours = ($interval - $minutes) / 60; $ret = ''; if ($hours) { $ret .= $hours.$hour_text.' '; } if ($minutes) { $ret .= $minutes.$min_text; } return $ret; } function IterateGridFields($params) { $mode = $params['mode']; $def_block = isset($params['block']) ? $params['block'] : ''; $force_block = isset($params['force_block']) ? $params['force_block'] : false; $grid = $this->getUnitConfig()->getGridByName($params['grid']); $grid_config = $grid['Fields']; $picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']); $grid_config = $picker_helper->apply($grid_config); if ( $mode == 'fields' ) { return "'" . join("','", array_keys($grid_config)) . "'"; } $object =& $this->GetList($params); $o = ''; $i = 0; foreach ($grid_config as $field => $options) { $i++; $block_params = $this->prepareTagParams($params); $block_params = array_merge($block_params, $options); $block_params['block_name'] = array_key_exists($mode . '_block', $block_params) ? $block_params[$mode . '_block'] : $def_block; $block_params['name'] = $force_block ? $force_block : $block_params['block_name']; $block_params['field'] = $field; $block_params['sort_field'] = isset($options['sort_field']) ? $options['sort_field'] : $field; $block_params['filter_field'] = isset($options['filter_field']) ? $options['filter_field'] : $field; $w = $picker_helper->getWidth($field); if ( $w ) { // column picker width overrides width from unit config $block_params['width'] = $w; } $field_options = $object->GetFieldOptions($field); if ( array_key_exists('use_phrases', $field_options) ) { $block_params['use_phrases'] = $field_options['use_phrases']; } $block_params['is_last'] = ($i == count($grid_config)); $o .= $this->Application->ParseBlock($block_params, 1); } return $o; } function PickerCRC($params) { $picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']); return $picker_helper->getData()->getChecksum(); } function FreezerPosition($params) { $picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']); $data = $picker_helper->getData(); $freezer_pos = $data->getOrder('__FREEZER__'); return $freezer_pos === false || $data->isHidden('__FREEZER__') ? 1 : ++$freezer_pos; } function GridFieldsCount($params) { $grid = $this->getUnitConfig()->getGridByName($params['grid']); return count($grid['Fields']); } /** * Prints list content using block specified * * @param Array $params * @return string * @access public */ function PrintList($params) { $params['no_table'] = 1; return $this->PrintList2($params); } function InitList($params) { $list_name = isset($params['list_name']) ? $params['list_name'] : ''; if ( getArrayValue($this->nameToSpecialMapping, $list_name) === false ) { $list =& $this->GetList($params); } } function BuildListSpecial($params) { return $this->Special; } /** * Returns key, that identifies each list on template (used internally, not tag) * * @param Array $params * @return string */ function getUniqueListKey($params) { $types = array_key_exists('types', $params) ? $params['types'] : ''; $except = array_key_exists('except', $params) ? $params['except'] : ''; $list_name = array_key_exists('list_name', $params) ? $params['list_name'] : ''; if (!$list_name) { $list_name = $this->Application->Parser->GetParam('list_name'); } return $types . $except . $list_name; } /** * Enter description here... * * @param Array $params * @return kDBList */ function &GetList($params) { $list_name = array_key_exists('list_name', $params) ? $params['list_name'] : ''; if ( !$list_name ) { $list_name = $this->Application->Parser->GetParam('list_name'); } $requery = isset($params['requery']) && $params['requery']; $main_list = array_key_exists('main_list', $params) && $params['main_list']; if ( $list_name && !$requery ) { // list with "list_name" parameter if ( !array_key_exists($list_name, $this->nameToSpecialMapping) ) { // special missing -> generate one $special = $main_list ? $this->Special : $this->BuildListSpecial($params); } else { // get special, formed during list initialization $special = $this->nameToSpecialMapping[$list_name]; } } else { // list without "list_name" parameter $special = $main_list ? $this->Special : $this->BuildListSpecial($params); } $prefix_special = rtrim($this->Prefix . '.' . $special, '.'); $params['skip_counting'] = true; /** @var kDBList $list */ $list = $this->Application->recallObject($prefix_special, $this->Prefix . '_List', $params); if ( !array_key_exists('skip_quering', $params) || !$params['skip_quering'] ) { if ( $requery ) { $this->Application->HandleEvent(new kEvent($prefix_special . ':OnListBuild', $params)); } if ( array_key_exists('offset', $params) ) { $list->SetOffset($list->GetOffset() + $params['offset']); // apply custom offset } $list->Query($requery); if ( array_key_exists('offset', $params) ) { $list->SetOffset($list->GetOffset() - $params['offset']); // remove custom offset } } $this->Init($this->Prefix, $special); if ( $list_name ) { $this->nameToSpecialMapping[$list_name] = $special; } return $list; } function ListMarker($params) { $list =& $this->GetList($params); $ret = $list->getPrefixSpecial(); if (array_key_exists('as_preg', $params) && $params['as_preg']) { $ret = preg_quote($ret, '/'); } return $ret; } function CombinedSortingDropDownName($params) { $list =& $this->GetList($params); return $list->getPrefixSpecial() . '_CombinedSorting'; } /** * Prepares name for field with event in it (used only on front-end) * * @param Array $params * @return string */ function SubmitName($params) { $list =& $this->GetList($params); $prefix_special = $list->getPrefixSpecial(); return 'events[' . $prefix_special . '][' . $params['event'] . ']'; } /** * Prints list content using block specified * * @param Array $params * @return string * @access public */ function PrintList2($params) { $per_page = $this->SelectParam($params, 'per_page,max_items'); if ( $per_page !== false ) { $params['per_page'] = $per_page; } $list =& $this->GetList($params); $o = ''; $direction = (isset($params['direction']) && $params['direction'] == "H") ? "H" : "V"; $columns = (isset($params['columns'])) ? $params['columns'] : 1; $config = $this->getUnitConfig(); $id_field = (isset($params['id_field'])) ? $params['id_field'] : $config->getIDField(); if ( $columns > 1 && $direction == 'V' ) { $records_left = array_splice($list->Records, $list->GetSelectedCount()); // because we have 1 more record for "More..." link detection (don't need to sort it) $list->Records = $this->LinearToVertical($list->Records, $columns, $list->GetPerPage()); $list->Records = array_merge($list->Records, $records_left); } $list->GoFirst(); $block_params = $this->prepareTagParams($params); $block_params['name'] = $this->SelectParam($params, 'render_as,block'); $block_params['pass_params'] = 'true'; $block_params['column_width'] = $params['column_width'] = 100 / $columns; $block_start_row_params = $this->prepareTagParams($params); $block_start_row_params['name'] = $this->SelectParam($params, 'row_start_render_as,block_row_start,row_start_block'); $block_end_row_params = $this->prepareTagParams($params); $block_end_row_params['name'] = $this->SelectParam($params, 'row_end_render_as,block_row_end,row_end_block'); $block_empty_cell_params = $this->prepareTagParams($params); $block_empty_cell_params['name'] = $this->SelectParam($params, 'empty_cell_render_as,block_empty_cell,empty_cell_block'); $i = 0; $backup_id = $this->Application->GetVar($this->Prefix . '_id'); $displayed = Array (); $column_number = 1; $cache_mod_rw = $config->getCacheModRewrite() && $this->Application->RewriteURLs() && !$this->Application->isCachingType(CACHING_TYPE_MEMORY); $limit = isset($params['limit']) ? $params['limit'] : false; while (!$list->EOL() && (!$limit || $i<$limit)) { $this->Application->SetVar($this->getPrefixSpecial() . '_id', $list->GetDBField($id_field)); // for edit/delete links using GET $this->Application->SetVar($this->Prefix . '_id', $list->GetDBField($id_field)); $block_params['is_last'] = ($i == $list->GetSelectedCount() - 1); $block_params['last_row'] = ($i + (($i + 1) % $columns) >= $list->GetSelectedCount() - 1); $block_params['not_last'] = !$block_params['is_last']; // for front-end if ( $cache_mod_rw ) { $serial_name = $this->Application->incrementCacheSerial($this->Prefix, $list->GetDBField($id_field), false); if ( $this->Prefix == 'c' ) { // for listing subcategories in category $this->Application->setCache('filenames[%' . $serial_name . '%]', $list->GetDBField('NamedParentPath')); $this->Application->setCache('category_tree[%CIDSerial:' . $list->GetDBField($id_field) . '%]', $list->GetDBField('TreeLeft') . ';' . $list->GetDBField('TreeRight')); } else { // for listing items in category $this->Application->setCache('filenames[%' . $serial_name . '%]', $list->GetDBField('Filename')); $serial_name = $this->Application->incrementCacheSerial('c', $list->GetDBField('CategoryId'), false); $this->Application->setCache('filenames[%' . $serial_name . '%]', $list->GetDBField('CategoryFilename')); } } if ( $i % $columns == 0 ) { // record in this iteration is first in row, then open row $column_number = 1; $o .= $block_start_row_params['name'] ? $this->Application->ParseBlock($block_start_row_params) : (!isset($params['no_table']) ? '' : ''); } else { $column_number++; } $block_params['first_col'] = $column_number == 1 ? 1 : 0; $block_params['last_col'] = $column_number == $columns ? 1 : 0; $block_params['column_number'] = $column_number; $block_params['num'] = ($i + 1); $this->PrepareListElementParams($list, $block_params); // new, no need to rewrite PrintList $o .= $this->Application->ParseBlock($block_params); array_push($displayed, $list->GetDBField($id_field)); if ( $direction == 'V' && $list->GetSelectedCount() % $columns > 0 && $column_number == ($columns - 1) && ceil(($i + 1) / $columns) > $list->GetSelectedCount() % ceil($list->GetSelectedCount() / $columns) ) { // if vertical output, then draw empty cells vertically, not horizontally $o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params) : ' '; $i++; } if ( ($i + 1) % $columns == 0 ) { // record in next iteration is first in row too, then close this row $o .= $block_end_row_params['name'] ? $this->Application->ParseBlock($block_end_row_params) : (!isset($params['no_table']) ? '' : ''); } if ( $this->Special && $this->Application->hasObject($this->Prefix) ) { // object, produced by "kDBList::linkToParent" method, that otherwise would keep it's id /** @var kDBBase $item */ $item = $this->Application->recallObject($this->Prefix); if ( $item instanceof kDBItem ) { $this->Application->removeObject($this->Prefix); } } $list->GoNext(); $i++; } // append empty cells in place of missing cells in last row while ($i % $columns != 0) { // until next cell will be in new row append empty cells $o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params) : ' '; if ( ($i + 1) % $columns == 0 ) { // record in next iteration is first in row too, then close this row $o .= $block_end_row_params['name'] ? $this->Application->ParseBlock($block_end_row_params) : ''; } $i++; } $cur_displayed = $this->Application->GetVar($this->Prefix . '_displayed_ids'); if ( !$cur_displayed ) { $cur_displayed = Array (); } else { $cur_displayed = explode(',', $cur_displayed); } $displayed = array_unique(array_merge($displayed, $cur_displayed)); $this->Application->SetVar($this->Prefix . '_displayed_ids', implode(',', $displayed)); $this->Application->SetVar($this->Prefix . '_id', $backup_id); $this->Application->SetVar($this->getPrefixSpecial() . '_id', ''); if ( isset($params['more_link_render_as']) ) { $block_params = $params; $params['render_as'] = $params['more_link_render_as']; $o .= $this->MoreLink($params); } return $o; } /** * Returns ID of previous record (related to current) in list. * Use only on item detail pages. * * @param Array $params * @return int * @access protected */ protected function PreviousResource($params) { /** @var kDBItem $object */ $object = $this->getObject($params); /** @var ListHelper $list_helper */ $list_helper = $this->Application->recallObject('ListHelper'); $select_clause = $object->getUnitConfig()->getNavigationSelectClause(null); return $list_helper->getNavigationResource($object, $params['list'], false, $select_clause); } /** * Returns ID of next record (related to current) in list. * Use only on item detail pages. * * @param Array $params * @return int * @access protected */ protected function NextResource($params) { /** @var kDBItem $object */ $object = $this->getObject($params); /** @var ListHelper $list_helper */ $list_helper = $this->Application->recallObject('ListHelper'); $select_clause = $object->getUnitConfig()->getNavigationSelectClause(null); return $list_helper->getNavigationResource($object, $params['list'], true, $select_clause); } /** * Allows to modify block params & current list record before PrintList parses record * * @param kDBList $object * @param Array $block_params * @return void * @access protected */ protected function PrepareListElementParams(&$object, &$block_params) { // $fields_hash =& $object->getCurrentRecord(); } /** * Renders given block name, when there there is more data in list, then are displayed right now * * @param Array $params * @return string * @access protected */ protected function MoreLink($params) { $per_page = $this->SelectParam($params, 'per_page,max_items'); if ( $per_page !== false ) { $params['per_page'] = $per_page; } $list =& $this->GetList($params); if ( $list->isCounted() ) { $has_next_page = $list->GetPage() < $list->GetTotalPages(); } else { // selected more, then on the page -> has more $has_next_page = $list->GetPerPage() < $list->GetRecordsCount(); } if ( $has_next_page ) { $block_params = Array ('name' => $this->SelectParam($params, 'render_as,block')); return $this->Application->ParseBlock($block_params); } return ''; } function PageLink($params) { static $default_per_page = Array (); /** @var kDBList $object */ $object =& $this->GetList($params); // process sorting if ($object->isMainList()) { if (!array_key_exists('sort_by', $params)) { $sort_by = $this->Application->GetVar('sort_by'); if ($sort_by !== false) { $params['sort_by'] = $sort_by; } } } $prefix_special = $this->getPrefixSpecial(); // process page $page = array_key_exists('page', $params) ? $params['page'] : $this->Application->GetVar($prefix_special . '_Page'); if (!$page) { // ensure, that page is always present if ($object->isMainList()) { $params[$prefix_special . '_Page'] = $this->Application->GetVar('page', 1); } else { $params[$prefix_special . '_Page'] = 1; } } if (array_key_exists('page', $params)) { $params[$prefix_special . '_Page'] = $params['page']; unset($params['page']); } // process per-page $per_page = array_key_exists('per_page', $params) ? $params['per_page'] : $this->Application->GetVar($prefix_special . '_PerPage'); if (!$per_page) { // ensure, that per-page is always present list ($prefix, ) = explode('.', $prefix_special); if (!array_key_exists($prefix, $default_per_page)) { /** @var ListHelper $list_helper */ $list_helper = $this->Application->recallObject('ListHelper'); $default_per_page[$prefix] = $list_helper->getDefaultPerPage($prefix); } if ($object->isMainList()) { $params[$prefix_special . '_PerPage'] = $this->Application->GetVar('per_page', $default_per_page[$prefix]); } else { $params[$prefix_special . '_PerPage'] = $default_per_page[$prefix]; } } if (array_key_exists('per_page', $params)) { $params[$prefix_special . '_PerPage'] = $params['per_page']; unset($params['per_page']); } if (!array_key_exists('pass', $params)) { $params['pass'] = 'm,' . $prefix_special; } // process template $t = array_key_exists('template', $params) ? $params['template'] : ''; unset($params['template']); if (!$t) { $t = $this->Application->GetVar('t'); } return $this->Application->HREF($t, '', $params); } /** * Deprecated * * @param array $params * @return int * @deprecated Parameter "column_width" of "PrintList" tag does that */ function ColumnWidth($params) { $columns = $this->Application->Parser->GetParam('columns'); return round(100/$columns).'%'; } /** * Append prefix and special to tag * params (get them from tagname) like * they were really passed as params * * @param Array $tag_params * @return Array * @access protected */ function prepareTagParams($tag_params = Array()) { $ret = $tag_params; $ret['Prefix'] = $this->Prefix; $ret['Special'] = $this->Special; $ret['PrefixSpecial'] = $this->getPrefixSpecial(); return $ret; } function GetISO($currency, $field_currency = '') { if ( $currency == 'selected' ) { return $this->Application->RecallVar('curr_iso'); } if ( $currency == 'primary' || $currency == '' ) { return $this->Application->GetPrimaryCurrency(); } // explicit currency return $currency == 'field' && $field_currency ? $field_currency : $currency; } /** * Convert primary currency to selected (if they are the same, converter will just return) * * @param float $value * @param string $target_iso * @param string $source_iso * @return float */ function ConvertCurrency($value, $target_iso, $source_iso = 'PRIMARY') { /** @var CurrencyRates $converter */ $converter = $this->Application->recallObject('CurrencyRates'); return $converter->Convert($value, $source_iso, $target_iso); } function AddCurrencySymbol($value, $iso, $decimal_tag = '') { /** @var CurrencyRates $converter */ $converter = $this->Application->recallObject('CurrencyRates'); return $converter->AddCurrencySymbol($value, $iso, $decimal_tag); } /** * Get's requested field value * * @param Array $params * @return string * @access public */ function Field($params) { $field = $this->SelectParam($params, 'name,field'); if (!$this->Application->isAdmin) { // don't apply kUtil::escape() on any field value on Front-End $params['no_special'] = 'no_special'; } /** @var kDBItem $object */ $object = $this->getObject($params); if (array_key_exists('db', $params) && $params['db']) { $value = $object->GetDBField($field); } else { if (array_key_exists('currency', $params) && $params['currency']) { $source_iso = isset($params['currency_field']) ? $object->GetDBField($params['currency_field']) : 'PRIMARY'; $target_iso = $this->GetISO($params['currency'], $source_iso); $original = $object->GetDBField($field); $value = $this->ConvertCurrency($original, $target_iso, $source_iso); $object->SetDBField($field, $value); $object->SetFieldOption($field, 'converted', true); } $format = array_key_exists('format', $params) ? $params['format'] : false; if (!$format || $format == '$format') { $format = NULL; } $value = $object->GetField($field, $format); if (array_key_exists('negative', $params) && $params['negative']) { if (strpos($value, '-') === 0) { $value = substr($value, 1); } else { $value = '-' . $value; } } if (array_key_exists('currency', $params) && $params['currency']) { $decimal_tag = isset($params['decimal_tag']) ? $params['decimal_tag'] : ''; $value = $this->AddCurrencySymbol($value, $target_iso, $decimal_tag); $params['no_special'] = 1; } } if (!array_key_exists('no_special', $params) || !$params['no_special']) { $value = kUtil::escape($value); } if (array_key_exists('checked', $params) && $params['checked']) { $value = ($value == ( isset($params['value']) ? $params['value'] : 1)) ? 'checked' : ''; } if (array_key_exists('plus_or_as_label', $params) && $params['plus_or_as_label']) { $value = substr($value, 0,1) == '+' ? substr($value, 1) : $this->Application->Phrase($value); } elseif (array_key_exists('as_label', $params) && $params['as_label']) { $value = $this->Application->Phrase($value); } $first_chars = $this->SelectParam($params,'first_chars,cut_first'); if ($first_chars) { $stripped_value = strip_tags($value, $this->SelectParam($params, 'allowed_tags')); if ( mb_strlen($stripped_value) > $first_chars ) { $value = preg_replace('/\s+?(\S+)?$/', '', mb_substr($stripped_value, 0, $first_chars + 1)) . ' ...'; } } if (array_key_exists('nl2br', $params) && $params['nl2br']) { $value = nl2br($value); } if ($value != '') { $this->Application->Parser->DataExists = true; } if (array_key_exists('currency', $params) && $params['currency']) { // restoring value in original currency, for other Field tags to work properly $object->SetDBField($field, $original); } return $value; } function FieldHintLabel($params) { if ( isset($params['direct_label']) && $params['direct_label'] ) { $label = $params['direct_label']; $hint = $this->Application->Phrase($label, false); } else { $label = $params['title_label']; $hint = $this->Application->Phrase('hint:' . $label, false); } return $hint != strtoupper('!' . $label . '!') ? $hint : ''; // $hint } /** * Returns formatted date + time on current language * * @param $params */ function DateField($params) { $field = $this->SelectParam($params, 'name,field'); if ($field) { /** @var kDBItem $object */ $object = $this->getObject($params); $timestamp = $object->GetDBField($field); } else { $timestamp = $params['value']; } $date = $timestamp; // prepare phrase replacements $replacements = Array ( 'l' => 'la_WeekDay', 'D' => 'la_WeekDay', 'M' => 'la_Month', 'F' => 'la_Month', ); // cases allow to append phrase suffix based on requested case (e.g. Genitive) $case_suffixes = array_key_exists('case_suffixes', $params) ? $params['case_suffixes'] : false; if ($case_suffixes) { // apply case suffixes (for russian language only) $case_suffixes = explode(',', $case_suffixes); foreach ($case_suffixes as $case_suffux) { list ($replacement_name, $case_suffix_value) = explode('=', $case_suffux, 2); $replacements[$replacement_name] .= $case_suffix_value; } } $format = array_key_exists('format', $params) ? $params['format'] : false; if (preg_match('/_regional_(.*)/', $format, $regs)) { /** @var kDBItem $language */ $language = $this->Application->recallObject('lang.current'); $format = $language->GetDBField($regs[1]); } elseif (!$format) { $format = null; } // escape formats, that are resolved to words by `date` foreach ($replacements as $format_char => $phrase_prefix) { if (strpos($format, $format_char) === false) { unset($replacements[$format_char]); continue; } $replacements[$format_char] = $this->Application->Phrase($phrase_prefix . date($format_char, $date)); $format = str_replace($format_char, '#' . ord($format_char) . '#', $format); } $date_formatted = date($format, $date); // unescape formats, that are resolved to words by `date` foreach ($replacements as $format_char => $format_replacement) { $date_formatted = str_replace('#' . ord($format_char) . '#', $format_replacement, $date_formatted); } return $date_formatted; } function SetField($params) { // /** @var kDBItem $object */ $object = $this->getObject($params); $dst_field = $this->SelectParam($params, 'name,field'); list($prefix_special, $src_field) = explode(':', $params['src']); /** @var kDBItem $src_object */ $src_object = $this->Application->recallObject($prefix_special); $object->SetDBField($dst_field, $src_object->GetDBField($src_field)); } /** * Depricated * * @param Array $params * @return string * @deprecated parameter "as_label" of "Field" tag does the same */ function PhraseField($params) { $field_label = $this->Field($params); $translation = $this->Application->Phrase( $field_label ); return $translation; } function Error($params) { /** @var kDBItem $object */ $object = $this->getObject($params); $field = $this->SelectParam($params, 'name,field'); return $object->GetErrorMsg($field, false); } function HasError($params) { if ($params['field'] == 'any') { /** @var kDBItem $object */ $object = $this->getObject($params); $skip_fields = array_key_exists('except', $params) ? $params['except'] : false; $skip_fields = $skip_fields ? explode(',', $skip_fields) : Array(); return $object->HasErrors($skip_fields); } else { $res = false; $fields = explode(',', $this->SelectParam($params, 'field,fields')); foreach ($fields as $field) { // call kDBTagProcessor::Error instead of kDBItem::GetErrorPseudo to have ability to override Error tag $params['field'] = $field; $res = $res || ($this->Error($params) != ''); } return $res; } } /** * Renders error message block, when there are errors on a form * * @param Array $params * @return string * @access protected */ protected function ErrorWarning($params) { if ( !isset($params['field']) ) { $params['field'] = 'any'; } if ( $this->HasError($params) ) { $params['prefix'] = $this->getPrefixSpecial(); return $this->Application->ParseBlock($params); } return ''; } function IsRequired($params) { /** @var kDBItem $object */ $object = $this->getObject($params); $field = $params['field']; $formatter_class = $object->GetFieldOption($field, 'formatter'); if ( $formatter_class == 'kMultiLanguage' ) { /** @var kMultiLanguage $formatter */ $formatter = $this->Application->recallObject($formatter_class); $field = $formatter->LangFieldName($field); } return $object->isRequired($field); } function FieldOption($params) { $object = $this->getObject($params);; $options = $object->GetFieldOptions($params['field']); $ret = isset($options[$params['option']]) ? $options[$params['option']] : ''; if (isset($params['as_label']) && $params['as_label']) $ret = $this->Application->ReplaceLanguageTags($ret); return $ret; } /** * Prints list a all possible field options * * @param Array $params * @return string * @access protected */ protected function PredefinedOptions($params) { /** @var kDBList $object */ $object = $this->getObject($params); $field = $params['field']; $value = array_key_exists('value', $params) ? $params['value'] : $object->GetDBField($field); $field_options = $object->GetFieldOptions($field); if (!array_key_exists('options', $field_options) || !is_array($field_options['options'])) { trigger_error('Options not defined for '.$object->Prefix.' field '.$field.'', E_USER_WARNING); return ''; } $options = $field_options['options']; if ( array_key_exists('has_empty', $params) && $params['has_empty'] ) { $empty_value = array_key_exists('empty_value', $params) ? $params['empty_value'] : ''; $empty_label = isset($params['empty_label']) ? $params['empty_label'] : ''; if ( $empty_label ) { if ( mb_substr($empty_label, 0, 1) == '+' ) { // using plain text instead of phrase label $empty_label = mb_substr($empty_label, 1); } else { $empty_label = $this->Application->Phrase($empty_label, false); } } // don't use other array merge function, because they will reset keys !!! $options = kUtil::array_merge_recursive(Array ($empty_value => $empty_label), $options); } $block_params = $this->prepareTagParams($params); $block_params['name'] = $this->SelectParam($params, 'render_as,block'); $block_params['pass_params'] = 'true'; if (method_exists($object, 'EOL') && count($object->Records) == 0) { // for drawing grid column filter $block_params['field_name'] = ''; } else { // deprecated (produces warning when used as grid filter), but used in Front-End (submission create), admin (submission view) $block_params['field_name'] = $this->InputName($params); } $selected_html = isset($params['selected']) ? $params['selected'] : 'selected'; $selected_param_name = array_key_exists('selected_param', $params) ? $params['selected_param'] : false; if (!$selected_param_name) { $selected_param_name = $selected_html; } $o = ''; if (array_key_exists('no_empty', $params) && $params['no_empty'] && !getArrayValue($options, '')) { // removes empty option, when present (needed?) array_shift($options); } $selected_option_keys = $this->getSelectedOptionKeys($value); if ( isset($params['selected_only']) && $params['selected_only'] ) { $options = $this->getSelectedOptions($options, $selected_option_keys); } $column_changed = false; $option_number = $column_number = 1; $option_count = count($options); $column_count = isset($params['columns']) ? $params['columns'] : 1; $options_per_column = ceil($option_count / $column_count); $block_params['option_count'] = $option_count; foreach ( $options as $option_key => $option_title ) { $block_params['key'] = $option_key; $block_params['option'] = $option_title; $block_params[$selected_param_name] = $this->isOptionSelected($option_key, $selected_option_keys) ? ' ' . $selected_html : ''; $block_params['column_number'] = $column_number; $block_params['column_changed'] = $column_changed; $block_params['option_number'] = $option_number; $block_params['is_last'] = $option_number == $option_count; $o .= $this->Application->ParseBlock($block_params); $column_changed = false; $option_number++; if ( $option_number > $column_number * $options_per_column ) { $column_number++; $column_changed = true; } } return $o; } /** * Returns unified representation of selected options based on field value. * * @param mixed $field_value Field value. * * @return array */ protected function getSelectedOptionKeys($field_value) { if ( strpos($field_value, '|') !== false ) { // multiple checkboxes OR multiselect return explode('|', trim($field_value, '|')); } // single selection radio OR checkboxes OR dropdown return array("$field_value"); } /** * Returns only options, that have been selected. * * @param array $options All options. * @param array $selected_option_keys Selected options. * * @return array */ protected function getSelectedOptions(array $options, array $selected_option_keys) { $ret = array(); foreach ( $options as $option_key => $option_title ) { if ( $this->isOptionSelected($option_key, $selected_option_keys) ) { $ret[$option_key] = $option_title; } } return $ret; } /** * Determines if given option is among selected ones. * * @param mixed $option_key Option key. * @param array $selected_option_keys Selected options. * * @return boolean */ protected function isOptionSelected($option_key, array $selected_option_keys) { return in_array("$option_key", $selected_option_keys, true); } function PredefinedSearchOptions($params) { /** @var kDBList $object */ $object =& $this->GetList($params); $params['value'] = $this->SearchField($params); return $this->PredefinedOptions($params); } function Format($params, $object = null) { $field = $this->SelectParam($params, 'name,field'); if ( !isset($object) ) { /** @var kDBItem $object */ $object = $this->getObject($params); } $options = $object->GetFieldOptions($field); $format = $options[$this->SelectParam($params, 'input_format') ? 'input_format' : 'format']; $formatter_class = array_key_exists('formatter', $options) ? $options['formatter'] : false; if ( $formatter_class ) { /** @var kFormatter $formatter */ $formatter = $this->Application->recallObject($formatter_class); $human_format = array_key_exists('human', $params) ? $params['human'] : false; $edit_size = array_key_exists('edit_size', $params) ? $params['edit_size'] : false; $sample = array_key_exists('sample', $params) ? $params['sample'] : false; if ( $sample ) { return $formatter->GetSample($field, $options, $object); } elseif ( $human_format || $edit_size ) { $format = $formatter->HumanFormat($format); return $edit_size ? strlen($format) : $format; } } return $format; } /** * Returns grid padination information * Can return links to pages * * @param Array $params * @return mixed */ function PageInfo($params) { /** @var kDBList $object */ $object =& $this->GetList($params); $type = $params['type']; unset($params['type']); // remove parameters used only by current tag $ret = ''; switch ($type) { case 'current': $ret = $object->GetPage(); break; case 'total': $ret = $object->GetTotalPages(); break; case 'prev': $ret = $object->GetPage() > 1 ? $object->GetPage() - 1 : false; break; case 'next': $ret = $object->GetPage() < $object->GetTotalPages() ? $object->GetPage() + 1 : false; break; } if ($ret && isset($params['as_link']) && $params['as_link']) { unset($params['as_link']); // remove parameters used only by current tag $params['page'] = $ret; $current_page = $object->GetPage(); // backup current page $ret = $this->PageLink($params); $this->Application->SetVar($object->getPrefixSpecial().'_Page', $current_page); // restore page } return $ret; } /** * Print grid pagination using * block names specified * * @param Array $params * @return string * @access public */ function PrintPages($params) { $list =& $this->GetList($params); $prefix_special = $list->getPrefixSpecial(); $total_pages = $list->GetTotalPages(); if ( $total_pages > 1 ) { $this->Application->Parser->DataExists = true; } if ( $total_pages == 0 ) { // display 1st page as selected in case if we have no pages at all $total_pages = 1; } $o = ''; // what are these 2 lines for? $this->Application->SetVar($prefix_special . '_event', ''); $this->Application->SetVar($prefix_special . '_id', ''); $current_page = $list->GetPage(); // $this->Application->RecallVar($prefix_special.'_Page'); $block_params = $this->prepareTagParams($params); $split = (isset($params['split']) ? $params['split'] : 10); $split_start = $current_page - ceil($split / 2); if ( $split_start < 1 ) { $split_start = 1; } $split_end = $split_start + $split - 1; if ( $split_end > $total_pages ) { $split_end = $total_pages; $split_start = max($split_end - $split + 1, 1); } if ( $current_page > 1 ) { $prev_block_params = $this->prepareTagParams($params); if ( $total_pages > $split ) { $prev_block_params['page'] = max($current_page - $split, 1); $prev_block_params['name'] = $this->SelectParam($params, 'prev_page_split_render_as,prev_page_split_block'); if ( $prev_block_params['name'] ) { $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $prev_block_params['page']); $o .= $this->Application->ParseBlock($prev_block_params); } } $prev_block_params['name'] = 'page'; $prev_block_params['page'] = $current_page - 1; $prev_block_params['name'] = $this->SelectParam($params, 'prev_page_render_as,block_prev_page,prev_page_block'); if ( $prev_block_params['name'] ) { $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $prev_block_params['page']); $o .= $this->Application->ParseBlock($prev_block_params); } } else { $no_prev_page_block = $this->SelectParam($params, 'no_prev_page_render_as,block_no_prev_page'); if ( $no_prev_page_block ) { $block_params['name'] = $no_prev_page_block; $o .= $this->Application->ParseBlock($block_params); } } $total_records = $list->GetRecordsCount(); $separator_params['name'] = $this->SelectParam($params, 'separator_render_as,block_separator'); for ($i = $split_start; $i <= $split_end; $i++) { $from_record = ($i - 1) * $list->GetPerPage(); $to_record = $from_record + $list->GetPerPage(); if ( $to_record > $total_records ) { $to_record = $total_records; } $block_params['from_record'] = $from_record + 1; $block_params['to_record'] = $to_record; if ( $i == $current_page ) { $block = $this->SelectParam($params, 'current_render_as,active_render_as,block_current,active_block'); } else { $block = $this->SelectParam($params, 'link_render_as,inactive_render_as,block_link,inactive_block'); } $block_params['name'] = $block; $block_params['page'] = $i; $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $block_params['page']); $o .= $this->Application->ParseBlock($block_params); if ( $this->SelectParam($params, 'separator_render_as,block_separator') && $i < $split_end ) { $o .= $this->Application->ParseBlock($separator_params); } } if ( $current_page < $total_pages ) { $next_block_params = $this->prepareTagParams($params); $next_block_params['page'] = $current_page + 1; $next_block_params['name'] = $this->SelectParam($params, 'next_page_render_as,block_next_page,next_page_block'); if ( $next_block_params['name'] ) { $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $next_block_params['page']); $o .= $this->Application->ParseBlock($next_block_params); } if ( $total_pages > $split ) { $next_block_params['page'] = min($current_page + $split, $total_pages); $next_block_params['name'] = $this->SelectParam($params, 'next_page_split_render_as,next_page_split_block'); if ( $next_block_params['name'] ) { $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $next_block_params['page']); $o .= $this->Application->ParseBlock($next_block_params); } } } else { $no_next_page_block = $this->SelectParam($params, 'no_next_page_render_as,block_no_next_page'); if ( $no_next_page_block ) { $block_params['name'] = $no_next_page_block; $o .= $this->Application->ParseBlock($block_params); } } $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $current_page); return $o; } /** * Print grid pagination using * block names specified * * @param Array $params * @return string * @access public */ function PaginationBar($params) { return $this->PrintPages($params); } function PerPageBar($params) { $object =& $this->GetList($params); $ret = ''; $per_pages = explode(';', $params['per_pages']); $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['render_as']; foreach ($per_pages as $per_page) { $block_params['per_page'] = $per_page; $this->Application->SetVar($this->getPrefixSpecial() . '_PerPage', $per_page); $block_params['selected'] = $per_page == $object->GetPerPage(); $ret .= $this->Application->ParseBlock($block_params, 1); } $this->Application->SetVar($this->getPrefixSpecial() . '_PerPage', $object->GetPerPage()); return $ret; } /** * Returns field name (processed by kMultiLanguage formatter * if required) and item's id from it's IDField or field required * * @param Array $params * @return Array (id,field) * @access private */ function prepareInputName($params) { /** @var kDBItem $object */ $object = $this->getObject($params); $field = $this->SelectParam($params, 'name,field'); $formatter_class = $object->GetFieldOption($field, 'formatter'); if ($formatter_class == 'kMultiLanguage') { /** @var kMultiLanguage $formatter */ $formatter = $this->Application->recallObject($formatter_class); $force_primary = $object->GetFieldOption($field, 'force_primary'); $field = $formatter->LangFieldName($field, $force_primary); } if (array_key_exists('force_id', $params)) { $id = $params['force_id']; } else { $id_field = array_key_exists('IdField', $params) ? $params['IdField'] : false; $id = $id_field ? $object->GetDBField($id_field) : $object->GetID(); } return Array($id, $field); } /** * Returns input field name to * be placed on form (for correct * event processing) * * @param Array $params * @return string * @access public */ function InputName($params) { list($id, $field) = $this->prepareInputName($params); $ret = $this->getPrefixSpecial().'['.$id.']['.$field.']'; if (array_key_exists('as_preg', $params) && $params['as_preg']) { $ret = preg_quote($ret, '/'); } return $ret; } /** * Allows to override various field options through hidden fields with specific names in submit. * This tag generates this special names * * @param Array $params * @return string * @author Alex */ function FieldModifier($params) { list($id, $field) = $this->prepareInputName($params); $ret = 'field_modifiers['.$this->getPrefixSpecial().']['.$field.']['.$params['type'].']'; if (array_key_exists('as_preg', $params) && $params['as_preg']) { $ret = preg_quote($ret, '/'); } if (isset($params['value'])) { $object = $this->getObject($params); $field_modifiers[$field][$params['type']] = $params['value']; $object->ApplyFieldModifiers($field_modifiers); } return $ret; } /** * Returns index where 1st changeable sorting field begins * * @return int * @access private */ function getUserSortIndex() { $list_sortings = $this->getUnitConfig()->getListSortingsBySpecial($this, Array ()); $user_sorting_start = 0; $forced_sorting = getArrayValue($list_sortings, 'ForcedSorting'); return $forced_sorting ? count($forced_sorting) : $user_sorting_start; } /** * Returns order direction for given field * * * * @param Array $params * @return string * @access public */ function Order($params) { $field = $params['field']; $user_sorting_start = $this->getUserSortIndex(); $list =& $this->GetList($params); if ($list->GetOrderField($user_sorting_start) == $field) { return strtolower($list->GetOrderDirection($user_sorting_start)); } elseif($this->Application->ConfigValue('UseDoubleSorting') && $list->GetOrderField($user_sorting_start+1) == $field) { return '2_'.strtolower($list->GetOrderDirection($user_sorting_start+1)); } else { return 'no'; } } /** * Detects, that current sorting is not default * * @param Array $params * @return bool */ function OrderChanged($params) { $list =& $this->GetList($params); /** @var ListHelper $list_helper */ $list_helper = $this->Application->recallObject('ListHelper'); return $list_helper->hasUserSorting($list); } /** * Gets information of sorting field at "pos" position, * like sorting field name (type="field") or sorting direction (type="direction") * * @param Array $params * @return string * @access protected */ protected function OrderInfo($params) { $user_sorting_start = $this->getUserSortIndex() + --$params['pos']; $list =& $this->GetList($params); if ( $params['type'] == 'field' ) { return $list->GetOrderField($user_sorting_start); } if ( $params['type'] == 'direction' ) { return $list->GetOrderDirection($user_sorting_start); } return ''; } /** * Checks if sorting field/direction matches passed field/direction parameter * * @param Array $params * @return bool * @access protected */ protected function IsOrder($params) { $params['type'] = isset($params['field']) ? 'field' : 'direction'; $value = $this->OrderInfo($params); if ( isset($params['field']) ) { return $params['field'] == $value; } elseif ( isset($params['direction']) ) { return $params['direction'] == $value; } return false; } /** * Returns list per-page * * @param Array $params * @return int */ function PerPage($params) { $object =& $this->GetList($params); return $object->GetPerPage(); } /** * Checks if list perpage matches value specified * * @param Array $params * @return bool */ function PerPageEquals($params) { $object =& $this->GetList($params); return $object->GetPerPage() == $params['value']; } function SaveEvent($params) { // SaveEvent is set during OnItemBuild, but we may need it before any other tag calls OnItemBuild $object = $this->getObject($params); return $this->Application->GetVar($this->getPrefixSpecial().'_SaveEvent'); } function NextId($params) { $object = $this->getObject($params); $wid = $this->Application->GetTopmostWid($this->Prefix); $session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_'); $ids = explode(',', $this->Application->RecallVar($session_name)); $cur_id = $object->GetID(); $i = array_search($cur_id, $ids); if ($i !== false) { return $i < count($ids) - 1 ? $ids[$i + 1] : ''; } return ''; } function PrevId($params) { $object = $this->getObject($params); $wid = $this->Application->GetTopmostWid($this->Prefix); $session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_'); $ids = explode(',', $this->Application->RecallVar($session_name)); $cur_id = $object->GetID(); $i = array_search($cur_id, $ids); if ($i !== false) { return $i > 0 ? $ids[$i - 1] : ''; } return ''; } function IsSingle($params) { return ($this->NextId($params) === '' && $this->PrevId($params) === ''); } function IsLast($params) { return ($this->NextId($params) === ''); } function IsFirst($params) { return ($this->PrevId($params) === ''); } /** * Checks if field value is equal to proposed one * * @param Array $params * @return bool * @deprecated */ function FieldEquals($params) { /** @var kDBItem $object */ $object = $this->getObject($params); return $object->GetDBField( $this->SelectParam($params, 'name,field') ) == $params['value']; } /** * Checks, that grid has icons defined and they should be shown * * @param Array $params * @return bool */ function UseItemIcons($params) { return array_key_exists('Icons', $this->getUnitConfig()->getGridByName($params['grid'])); } /** * Returns corresponding to grid layout selector column width * * @param Array $params * @return int */ function GridSelectorColumnWidth($params) { $width = 0; if ($params['selector']) { $width += $params['selector_width']; } if ($this->UseItemIcons($params)) { $width += $params['icon_width']; } return $width; } /** * Returns grids item selection mode (checkbox, radio, ) * * @param Array $params * @return string */ function GridSelector($params) { $grid = $this->getUnitConfig()->getGridByName($params['grid']); return array_key_exists('Selector', $grid) ? $grid['Selector'] : $params['default']; } function ItemIcon($params) { $config = $this->getUnitConfig(); $grid = $config->getGridByName($params['grid']); if ( !isset($grid['Icons']) ) { return ''; } $icons = $grid['Icons']; if ( isset($params['name']) ) { $icon_name = $params['name']; return isset($icons[$icon_name]) ? $icons[$icon_name] : ''; } $status_fields = $config->getStatusField(false, Array ()); if ( !$status_fields ) { return $icons['default']; } /** @var kDBList $object */ $object = $this->getObject($params); $icon = ''; foreach ($status_fields as $status_field) { $icon .= $object->GetDBField($status_field) . '_'; } $icon = rtrim($icon, '_'); return isset($icons[$icon]) ? $icons[$icon] : $icons['default']; } /** * Generates bluebar title + initializes prefixes used on page * * @param Array $params * @return string */ function SectionTitle($params) { $config = $this->getUnitConfig(); $preset_name = kUtil::replaceModuleSection($params['title_preset']); $title_info = $config->getTitlePresetByName($preset_name); if ( $title_info === false ) { $title = str_replace('#preset_name#', $preset_name, $params['title']); if ( $this->Application->ConfigValue('UseSmallHeader') && isset($params['group_title']) && $params['group_title'] ) { $title .= ' - ' . $params['group_title']; } return $title; } $default_title_preset = $config->getTitlePresetByName('default'); if ( $default_title_preset ) { // use default labels + custom labels specified in preset used $title_info = kUtil::array_merge_recursive($default_title_preset, $title_info); } $title = $title_info['format']; // 1. get objects in use for title construction $objects = Array (); $object_status = Array (); $status_labels = Array (); $prefixes = array_key_exists('prefixes', $title_info) ? $title_info['prefixes'] : false; $all_tag_params = array_key_exists('tag_params', $title_info) ? $title_info['tag_params'] : false; /** @var Array $prefixes */ if ( $prefixes ) { // extract tag_params passed directly to SectionTitle tag for specific prefix foreach ($params as $tp_name => $tp_value) { if ( preg_match('/(.*)\[(.*)\]/', $tp_name, $regs) ) { $all_tag_params[$regs[1]][$regs[2]] = $tp_value; unset($params[$tp_name]); } } $tag_params = Array (); foreach ($prefixes as $prefix_special) { $prefix_data = $this->Application->processPrefix($prefix_special); $prefix_data['prefix_special'] = rtrim($prefix_data['prefix_special'], '.'); if ( $all_tag_params ) { $tag_params = getArrayValue($all_tag_params, $prefix_data['prefix_special']); if ( !$tag_params ) { $tag_params = Array (); } } $tag_params = array_merge($params, $tag_params); $objects[$prefix_data['prefix_special']] = $this->Application->recallObject($prefix_data['prefix_special'], $prefix_data['prefix'], $tag_params); $object_status[$prefix_data['prefix_special']] = $objects[$prefix_data['prefix_special']]->IsNewItem() ? 'new' : 'edit'; // a. set object's status field (adding item/editing item) for each object in title if ( getArrayValue($title_info[$object_status[$prefix_data['prefix_special']] . '_status_labels'], $prefix_data['prefix_special']) ) { $status_labels[$prefix_data['prefix_special']] = $title_info[$object_status[$prefix_data['prefix_special']] . '_status_labels'][$prefix_data['prefix_special']]; $title = str_replace('#' . $prefix_data['prefix_special'] . '_status#', $status_labels[$prefix_data['prefix_special']], $title); } // b. setting object's titlefield value (in titlebar ONLY) to default in case if object beeing created with no titlefield filled in if ( $object_status[$prefix_data['prefix_special']] == 'new' ) { $new_value = $this->getInfo($objects[$prefix_data['prefix_special']], 'titlefield'); if ( !$new_value && getArrayValue($title_info['new_titlefield'], $prefix_data['prefix_special']) ) { $new_value = $this->Application->Phrase($title_info['new_titlefield'][$prefix_data['prefix_special']]); } $title = str_replace('#' . $prefix_data['prefix_special'] . '_titlefield#', $new_value, $title); } } } // replace to section title $section = array_key_exists('section', $params) ? $params['section'] : false; if ( $section ) { /** @var kSectionsHelper $sections_helper */ $sections_helper = $this->Application->recallObject('SectionsHelper'); $section_data =& $sections_helper->getSectionData($section); $title = str_replace('#section_label#', '!' . $section_data['label'] . '!', $title); } // 2. replace phrases if any found in format string $title = $this->Application->ReplaceLanguageTags($title, false); // 3. find and replace any replacement vars preg_match_all('/#(.*_.*)#/Uis', $title, $rets); if ( $rets[1] ) { $replacement_vars = array_keys(array_flip($rets[1])); foreach ($replacement_vars as $replacement_var) { $var_info = explode('_', $replacement_var, 2); $object =& $objects[$var_info[0]]; $new_value = $this->getInfo($object, $var_info[1]); $title = str_replace('#' . $replacement_var . '#', $new_value, $title); } } // replace trailing spaces inside title preset + '' occurrences into single space $title = preg_replace('/[ ]*\'\'[ ]*/', ' ', $title); if ( $this->Application->ConfigValue('UseSmallHeader') && isset($params['group_title']) && $params['group_title'] ) { $title .= ' - ' . $params['group_title']; } $first_chars = $this->SelectParam($params, 'first_chars,cut_first'); if ( $first_chars && !preg_match('/(.*)<\/a>/', $title) ) { // don't cut titles, that contain phrase translation links $stripped_title = strip_tags($title, $this->SelectParam($params, 'allowed_tags')); if ( mb_strlen($stripped_title) > $first_chars ) { $title = mb_substr($stripped_title, 0, $first_chars) . ' ...'; } } return $title; } /** * Returns information about list * * @param kDBList $object * @param string $info_type * @return string * @access protected */ protected function getInfo(&$object, $info_type) { switch ( $info_type ) { case 'titlefield': $field = $object->getUnitConfig()->getTitleField(); return $field !== false ? $object->GetField($field) : 'TitleField Missing'; break; case 'recordcount': if ( $object->GetRecordsCount(false) != $object->GetRecordsCount() ) { $of_phrase = $this->Application->Phrase('lc_of'); return $object->GetRecordsCount() . ' ' . $of_phrase . ' ' . $object->GetRecordsCount(false); } return $object->GetRecordsCount(); break; } return $object->GetField($info_type); } function GridInfo($params) { /** @var kDBList $object */ $object =& $this->GetList($params); switch ( $params['type'] ) { case 'filtered': return $object->GetRecordsCount(); case 'total': return $object->GetRecordsCount(false); case 'selected': return $object->GetSelectedCount(); case 'from': return $object->GetRecordsCount() ? $object->GetOffset() + 1 : 0; //0-based case 'to': $record_count = $object->GetRecordsCount(); return $object->GetPerPage(true) != -1 ? min($object->GetOffset() + $object->GetPerPage(), $record_count) : $record_count; case 'total_pages': return $object->GetTotalPages(); case 'needs_pagination': return ($object->GetPerPage(true) != -1) && (($object->GetRecordsCount() > $object->GetPerPage()) || ($object->GetPage() > 1)); } return false; } /** * Parses block depending on its element type. * For radio and select elements values are taken from 'value_list_field' in key1=value1,key2=value2 * format. key=value can be substituted by SELECT f1 AS OptionName, f2 AS OptionValue... FROM TableName * where prefix is TABLE_PREFIX * * @param Array $params * @return string */ function ConfigFormElement($params) { /** @var kDBItem $object */ $object = $this->getObject($params); $field = $params['field']; /** @var InpCustomFieldsHelper $helper */ $helper = $this->Application->recallObject('InpCustomFieldsHelper'); $element_type = $object->GetDBField($params['element_type_field']); if ($element_type == 'label') { $element_type = 'text'; } $formatter_class = $object->GetFieldOption($field, 'formatter'); switch ($element_type) { case 'select': case 'multiselect': case 'radio': if ($object->GetDBField('DirectOptions')) { // used for custom fields $options = $object->GetDBField('DirectOptions'); } else { // used for configuration $options = $helper->GetValuesHash( $object->GetDBField($params['value_list_field']) ); } $object->SetFieldOption($field, 'formatter', 'kOptionsFormatter'); $object->SetFieldOption($field, 'options', $options); break; case 'text': case 'textarea': case 'upload': $params['field_params'] = $helper->ParseConfigSQL($object->GetDBField($params['value_list_field'])); break; case 'password': case 'checkbox': default: break; } if (!$element_type) { throw new Exception('Element type missing for "' . $object->GetDBField('VariableName') . '" configuration variable'); } $params['name'] = $params['blocks_prefix'] . $element_type; // use $pass_params to pass 'SourcePrefix' parameter from PrintList to CustomInputName tag $ret = $this->Application->ParseBlock($params, 1); $object->SetFieldOption($field, 'formatter', $formatter_class); return $ret; } /** * Get's requested custom field value * * @param Array $params * @return string * @access public */ function CustomField($params) { $params['name'] = 'cust_'.$this->SelectParam($params, 'name,field'); return $this->Field($params); } function CustomFieldLabel($params) { $object = $this->getObject($params); $field = $this->SelectParam($params, 'name,field'); $sql = 'SELECT FieldLabel FROM ' . $this->Application->getUnitConfig('cf')->getTableName() . ' WHERE FieldName = ' . $this->Conn->qstr($field); return $this->Application->Phrase($this->Conn->GetOne($sql)); } /** * transposes 1-dimensional array elements for vertical alignment according to given columns and per_page parameters * * @param array $arr * @param int $columns * @param int $per_page * @return array */ function LinearToVertical(&$arr, $columns, $per_page) { $rows = $columns; // in case if after applying per_page limit record count less then // can fill requrested column count, then fill as much as we can $cols = min(ceil($per_page / $columns), ceil(count($arr) / $columns)); $imatrix = array(); for ($row = 0; $row < $rows; $row++) { for ($col = 0; $col < $cols; $col++) { $source_index = $row * $cols + $col; if (!isset($arr[$source_index])) { // in case if source array element count is less then element count in one row continue; } $imatrix[$col * $rows + $row] = $arr[$source_index]; } } ksort($imatrix); return array_values($imatrix); } /** * If data was modified & is in TempTables mode, then parse block with name passed; * remove modification mark if not in TempTables mode * * @param Array $params * @return string * @access protected */ protected function SaveWarning($params) { $main_prefix = array_key_exists('main_prefix', $params) ? $params['main_prefix'] : false; if ( $main_prefix ) { $top_prefix = $main_prefix; } else { $top_prefix = $this->Application->GetTopmostPrefix($this->Prefix); } $temp_tables = substr($this->Application->GetVar($top_prefix . '_mode'), 0, 1) == 't'; $modified = $this->Application->RecallVar($top_prefix . '_modified'); if ( $temp_tables && $modified ) { $block_params = $this->prepareTagParams($params); $block_params['name'] = $this->SelectParam($params, 'render_as,name'); $block_params['edit_mode'] = $temp_tables ? 1 : 0; return $this->Application->ParseBlock($block_params); } $this->Application->RemoveVar($top_prefix . '_modified'); return ''; } /** * Returns list record count queries (on all pages) * * @param Array $params * @return int */ function TotalRecords($params) { $list =& $this->GetList($params); return $list->GetRecordsCount(); } /** * Returns selected records count. * * @param array $params Tag params. * * @return string */ protected function SelectedRecords(array $params) { $list =& $this->GetList($params); return $list->GetSelectedCount(); } /** * Range filter field name * * @param Array $params * @return string */ function SearchInputName($params) { $field = $this->SelectParam($params, 'field,name'); $ret = 'custom_filters['.$this->getPrefixSpecial().']['.$params['grid'].']['.$field.']['.$params['filter_type'].']'; if (isset($params['type'])) { $ret .= '['.$params['type'].']'; } if (array_key_exists('as_preg', $params) && $params['as_preg']) { $ret = preg_quote($ret, '/'); } return $ret; } /** * Return range filter field value * * @param Array $params * @return string * @access protected */ protected function SearchField($params) // RangeValue { $field = $this->SelectParam($params, 'field,name'); $view_name = $this->Application->RecallVar($this->getPrefixSpecial() . '_current_view'); $custom_filter = $this->Application->RecallPersistentVar($this->getPrefixSpecial() . '_custom_filter.' . $view_name /*, ALLOW_DEFAULT_SETTINGS*/); $custom_filter = $custom_filter ? unserialize($custom_filter) : Array (); if ( isset($custom_filter[$params['grid']][$field]) ) { $ret = $custom_filter[$params['grid']][$field][$params['filter_type']]['submit_value']; if ( isset($params['type']) ) { $ret = $ret[$params['type']]; } if ( array_key_exists('formatted', $params) && $params['formatted'] ) { $object =& $this->GetList($params); $formatter_class = $object->GetFieldOption($field, 'formatter'); if ( $formatter_class ) { /** @var kFormatter $formatter */ $formatter = $this->Application->recallObject($formatter_class); $ret = $formatter->Format($ret, $field, $object); } } if ( !array_key_exists('no_special', $params) || !$params['no_special'] ) { $ret = kUtil::escape($ret); } return $ret; } return ''; } /** * Tells, that at least one of search filters is used by now * * @param Array $params * @return bool */ function SearchActive($params) { if ($this->Application->RecallVar($this->getPrefixSpecial() . '_search_keyword')) { // simple search filter is used return true; } $view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view'); $custom_filter = $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_custom_filter.'.$view_name/*, ALLOW_DEFAULT_SETTINGS*/); $custom_filter = $custom_filter ? unserialize($custom_filter) : Array(); return array_key_exists($params['grid'], $custom_filter); } function SearchFormat($params) { $object =& $this->GetList($params); return $this->Format($params, $object); } /** * Returns error of range field * * @param Array $params * @return string * @access protected */ protected function SearchError($params) { $field = $this->SelectParam($params, 'field,name'); $error_var_name = $this->getPrefixSpecial() . '_' . $field . '_error'; $pseudo = $this->Application->RecallVar($error_var_name); if ( $pseudo ) { $this->Application->RemoveVar($error_var_name); } /** @var kDBItem $object */ $object = $this->Application->recallObject($this->Prefix . '.' . $this->Special . '-item', null, Array ('skip_autoload' => true)); $object->SetError($field, $pseudo); return $object->GetErrorMsg($field, false); } /** * Returns object used in tag processor * * @param Array $params * @access public * @return kDBItem|kDBList */ function getObject($params = Array()) { /** @var kDBItem $object */ $object = $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix, $params); if ( isset($params['requery']) && $params['requery'] ) { $this->Application->HandleEvent(new kEvent($this->getPrefixSpecial() . ':LoadItem', $params)); } return $object; } /** * Checks if object propery value matches value passed * * @param Array $params * @return bool */ function PropertyEquals($params) { $object = $this->getObject($params); $property_name = $this->SelectParam($params, 'name,var,property'); return $object->$property_name == $params['value']; } function DisplayOriginal($params) { return false; } /*function MultipleEditing($params) { $wid = $this->Application->GetTopmostWid($this->Prefix); $session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_'); $selected_ids = explode(',', $this->Application->RecallVar($session_name)); $ret = ''; if ($selected_ids) { $selected_ids = explode(',', $selected_ids); $object = $this->getObject( kUtil::array_merge_recursive($params, Array('skip_autoload' => true)) ); $params['name'] = $params['render_as']; foreach ($selected_ids as $id) { $object->Load($id); $ret .= $this->Application->ParseBlock($params); } } return $ret; }*/ /** * Returns import/export process percent * * @param Array $params * @return int * @deprecated Please convert to event-model, not tag based */ function ExportStatus($params) { /** @var kCatDBItemExportHelper $export_object */ $export_object = $this->Application->recallObject('CatItemExportHelper'); $event = new kEvent($this->getPrefixSpecial().':OnDummy'); $action_method = 'perform'.ucfirst($this->Special); $field_values = $export_object->$action_method($event); // finish code is done from JS now if ($field_values['start_from'] >= $field_values['total_records']) { if ($this->Special == 'import') { // this is used? $this->Application->StoreVar('PermCache_UpdateRequired', 1); $this->Application->Redirect('categories/cache_updater', Array('m_opener' => 'r', 'pass' => 'm', 'continue' => 1)); } elseif ($this->Special == 'export') { // used for orders export in In-Commerce $finish_t = $this->Application->RecallVar('export_finish_t'); $this->Application->Redirect($finish_t, Array('pass' => 'all')); $this->Application->RemoveVar('export_finish_t'); } } $export_options = $export_object->loadOptions($event); return $export_options['start_from'] * 100 / $export_options['total_records']; } /** * Returns path where exported category items should be saved * * @param Array $params * @return string * @access protected */ protected function ExportPath($params) { $export_options = unserialize($this->Application->RecallVar($this->getPrefixSpecial() . '_options')); $extension = $export_options['ExportFormat'] == 1 ? 'csv' : 'xml'; $filename = preg_replace('/(.*)\.' . $extension . '$/', '\1', $export_options['ExportFilename']) . '.' . $extension; $path = EXPORT_PATH . '/'; if ( array_key_exists('as_url', $params) && $params['as_url'] ) { $path = str_replace(FULL_PATH . '/', $this->Application->BaseURL(), $path); } return $path . $filename; } function FieldTotal($params) { $list =& $this->GetList($params); $field = $this->SelectParam($params, 'field,name'); $total_function = array_key_exists('function', $params) ? $params['function'] : $list->getTotalFunction($field); if (array_key_exists('function_only', $params) && $params['function_only']) { return $total_function; } if (array_key_exists('currency', $params) && $params['currency']) { $iso = $this->GetISO($params['currency']); $original = $list->getTotal($field, $total_function); $value = $this->ConvertCurrency($original, $iso); $list->setTotal($field, $total_function, $value); } $value = $list->GetFormattedTotal($field, $total_function); if (array_key_exists('currency', $params) && $params['currency']) { $value = $this->AddCurrencySymbol($value, $iso); } return $value; } function FCKEditor($params) { $editor_name = array_key_exists('name', $params) ? $params['name'] : $this->InputName($params); /** @var fckFCKHelper $fck_helper */ $fck_helper = $this->Application->recallObject('FCKHelper'); if ( isset($params['mode']) && $params['mode'] == 'inline' ) { return $fck_helper->CKEditorInlineTag($editor_name, $params); } return $fck_helper->CKEditorTag($editor_name, $this->CKEditorValue($params), $params); } /** * Returns value, used by FCKEditor tag * * @param array $params * * @return string */ protected function CKEditorValue($params) { $params['no_special'] = 1; $params['format'] = array_key_exists('format', $params) ? $params['format'] . ';fck_ready' : 'fck_ready'; return $this->Field($params); } function IsNewItem($params) { $object = $this->getObject($params); return $object->IsNewItem(); } /** * Creates link to an item including only it's id * * @param Array $params * @return string * @access protected */ protected function ItemLink($params) { /** @var kDBItem $object */ $object = $this->getObject($params); if ( !isset($params['pass']) ) { $params['pass'] = 'm'; } $params[ $object->getPrefixSpecial() . '_id' ] = $object->GetID(); return $this->Application->ProcessParsedTag('m', 'T', $params); } /** * Creates a button for editing item in Admin Console * * @param Array $params * @return string * @access protected * @throws InvalidArgumentException */ protected function AdminEditButton($params) { if ( EDITING_MODE != EDITING_MODE_CONTENT ) { return ''; } /** @var kDBItem $object */ $object = $this->getObject($params); $item_prefix = isset($params['item_prefix']) ? $params['item_prefix'] : $this->Prefix; if ( isset($params['template']) ) { $template = $params['template']; } else { $item_config = $this->Application->getUnitConfig($item_prefix); $admin_template_prefix = $item_config->getAdminTemplatePrefix(); $template = $item_config->getAdminTemplatePath() . '/' . $admin_template_prefix . 'edit'; if ( !$admin_template_prefix ) { throw new InvalidArgumentException('Automatic admin editing template detection failed because of missing "AdminTemplatePrefix" unit config option in "' . $this->Prefix . '" unit config'); } } $form_name = 'kf_' . str_replace('-', '_', $item_prefix) . '_' . $object->GetID(); $form_name .= '_' . kUtil::crc32(json_encode($params)); $button_icon = isset($params['button_icon']) ? $params['button_icon'] : 'content_mode.png'; $button_class = isset($params['button_class']) ? $params['button_class'] : 'admin-edit-btn'; $button_title = isset($params['button_title']) ? $params['button_title'] : 'la_btn_AdminEditItem'; if ( substr($button_title, 0, 1) == '+' ) { $button_title = substr($button_title, 1); } else { $button_title = $this->Application->Phrase($button_title, false, true); } + if ( !isset($params['pass']) ) { + $params['pass'] = 'm,' . $item_prefix; + } + + $edit_prefix = $item_prefix; + list($parent_prefix, $parent_id) = $this->getParentPrefixAndId($object); + + if ( $parent_prefix !== false ) { + $edit_prefix = $parent_prefix; + $params[$parent_prefix . '_id'] = $parent_id; + $params['pass'] = $parent_prefix . ',' . $params['pass']; + } + $icon_url = $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/' . $button_icon; - $button_onclick = '$form_name = ' . json_encode($form_name) . '; std_edit_item(' . json_encode($item_prefix) . ', ' . json_encode($template) . '); return false;'; + + if ( !isset($params['temp_mode']) || (isset($params['temp_mode']) && $params['temp_mode']) ) { + $edit_function = 'std_edit_item'; + } + else { + $edit_function = 'std_edit_temp_item'; + } + + $button_onclick = '$form_name = ' . json_encode($form_name) . '; ' . $edit_function . '(' . json_encode($edit_prefix) . ', ' . json_encode($template) . '); return false;'; $button_code = ''; - if ( !isset($params['pass']) ) { - $params['pass'] = 'm,' . $item_prefix; - } - $params['m_opener'] = 'd'; $params[$item_prefix . '_id'] = $object->GetID(); - - if ( !isset($params['temp_mode']) || (isset($params['temp_mode']) && $params['temp_mode']) ) { - $params[$item_prefix . '_mode'] = 't'; - $params[$item_prefix . '_event'] = 'OnEdit'; - } - $params['front'] = 1; // to make opener stack work properly $params['__NO_REWRITE__'] = 1; // since admin link unset($params['button_icon'], $params['button_class'], $params['button_title'], $params['template'], $params['item_prefix'], $params['temp_mode']); // link from Front-End to Admin, don't remove "index.php" $form_name_escaped = kUtil::escape($form_name, kUtil::ESCAPE_HTML); $edit_url = kUtil::escape($this->Application->HREF($template, ADMIN_DIRECTORY, $params, 'index.php'), kUtil::ESCAPE_HTML); $edit_form = '
'; if ( isset($params['forms_later']) && $params['forms_later'] ) { $all_forms = $this->Application->GetVar('all_forms'); $this->Application->SetVar('all_forms', $all_forms . $edit_form); } else { $button_code .= $edit_form; } return $button_code; } /** + * Returns parent record ID. + * + * @param kDBBase $object Object. + * + * @return array + */ + protected function getParentPrefixAndId(kDBBase $object) + { + static $parent_mapping = array(); + + $unit_config = $object->getUnitConfig(); + $parent_prefix = $unit_config->getParentPrefix(); + + if ( $parent_prefix === false ) { + return array(false, null); + } + + $foreign_key = $unit_config->getForeignKey($parent_prefix); + $parent_table_key = $unit_config->getParentTableKey($parent_prefix); + + $parent_unit_config = $this->Application->getUnitConfig($parent_prefix); + $parent_id_field = $parent_unit_config->getIDField(); + $parent_id = $object->GetDBField($foreign_key); + + if ( $parent_table_key != $parent_id_field ) { + $cache_key = $object->getPrefixSpecial(); + + if ( !isset($parent_mapping[$cache_key]) ) { + $foreign_key_values = array_unique($object->GetCol($foreign_key)); + + $sql = 'SELECT ' . $parent_id_field . ', ' . $parent_table_key . ' + FROM ' . $parent_unit_config->getTableName() . ' + WHERE ' . $parent_table_key . ' IN (' . implode(',', $foreign_key_values) . ')'; + $parent_mapping[$cache_key] = $this->Conn->GetCol($sql, $parent_table_key); + } + + // Parent record was deleted, but child record is still referencing it. + if ( !isset($parent_mapping[$cache_key][$parent_id]) ) { + return array(false, null); + } + + $parent_id = $parent_mapping[$cache_key][$parent_id]; + } + + return array($parent_prefix, $parent_id); + } + + /** * Calls OnNew event from template, when no other event submitted * * @param Array $params */ function PresetFormFields($params) { $prefix = $this->getPrefixSpecial(); if ( !$this->Application->GetVar($prefix . '_event') ) { $this->Application->HandleEvent(new kEvent($prefix . ':OnNew')); } } function PrintSerializedFields($params) { /** @var kDBItem $object */ $object = $this->getObject($params); $field = $this->SelectParam($params, 'field'); $data = unserialize($object->GetDBField($field)); $o = ''; $std_params['name'] = $params['render_as']; $std_params['field'] = $params['field']; $std_params['pass_params'] = true; foreach ($data as $key => $row) { $block_params = array_merge($std_params, $row, array('key'=>$key)); $o .= $this->Application->ParseBlock($block_params); } return $o; } /** * Checks if current prefix is main item * * @param Array $params * @return bool */ function IsTopmostPrefix($params) { return $this->Prefix == $this->Application->GetTopmostPrefix($this->Prefix); } function PermSection($params) { $section = $this->SelectParam($params, 'section,name'); return $this->getUnitConfig()->getPermSectionByName($section, ''); } function PerPageSelected($params) { $list =& $this->GetList($params); return $list->GetPerPage(true) == $params['per_page'] ? $params['selected'] : ''; } /** * Returns prefix + generated sepcial + any word * * @param Array $params * @return string */ function VarName($params) { $list =& $this->GetList($params); return $list->getPrefixSpecial() . '_' . $params['type']; } /** * Returns edit tabs by specified preset name or false in case of error * * @param string $preset_name * @return mixed */ function getEditTabs($preset_name) { $presets = $this->getUnitConfig()->getEditTabPresets(); if ( !$presets || !isset($presets[$preset_name]) || count($presets[$preset_name]) == 0 ) { return false; } return count($presets[$preset_name]) > 1 ? $presets[$preset_name] : false; } /** * Detects if specified preset has tabs in it * * @param Array $params * @return bool */ function HasEditTabs($params) { return $this->getEditTabs($params['preset_name']) ? true : false; } /** * Sorts edit tabs based on their priority * * @param Array $tab_a * @param Array $tab_b * @return int */ function sortEditTabs($tab_a, $tab_b) { if ($tab_a['priority'] == $tab_b['priority']) { return 0; } return $tab_a['priority'] < $tab_b['priority'] ? -1 : 1; } /** * Prints edit tabs based on preset name specified * * @param Array $params * @return string * @access protected */ protected function PrintEditTabs($params) { $edit_tabs = $this->getEditTabs($params['preset_name']); if ( !$edit_tabs ) { return ''; } usort($edit_tabs, Array (&$this, 'sortEditTabs')); $ret = ''; $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['render_as']; foreach ($edit_tabs as $tab_info) { $block_params['title'] = $tab_info['title']; $block_params['template'] = $tab_info['t']; $ret .= $this->Application->ParseBlock($block_params); } return $ret; } /** * Performs image resize to required dimensions and returns resulting url (cached resized image) * * @param Array $params * @return string */ function ImageSrc($params) { $max_width = isset($params['MaxWidth']) ? $params['MaxWidth'] : false; $max_height = isset($params['MaxHeight']) ? $params['MaxHeight'] : false; $logo_filename = isset($params['LogoFilename']) ? $params['LogoFilename'] : false; $logo_h_margin = isset($params['LogoHMargin']) ? $params['LogoHMargin'] : false; $logo_v_margin = isset($params['LogoVMargin']) ? $params['LogoVMargin'] : false; $object = $this->getObject($params); $field = $this->SelectParam($params, 'name,field'); return $object->GetField($field, 'resize:'.$max_width.'x'.$max_height.';wm:'.$logo_filename.'|'.$logo_h_margin.'|'.$logo_v_margin); } /** * Allows to retrieve given setting from unit config * * @param Array $params * @return mixed */ function UnitOption($params) { return $this->getUnitConfig()->getSetting($params['name']); } /** * Returns list of allowed toolbar buttons or false, when all is allowed * * @param Array $params * @return string */ function VisibleToolbarButtons($params) { $preset_name = kUtil::replaceModuleSection($params['title_preset']); $preset_info = $this->getUnitConfig()->getTitlePresetByName($preset_name); if ( !$preset_info ) { trigger_error('Title preset not specified or missing (in tag "' . $this->getPrefixSpecial() . ':' . __METHOD__ . '")', E_USER_NOTICE); return false; } if ( !array_key_exists('toolbar_buttons', $preset_info) || !is_array($preset_info['toolbar_buttons']) ) { return false; } // always add search buttons array_push($preset_info['toolbar_buttons'], 'search', 'search_reset_alt'); $toolbar_buttons = array_values($preset_info['toolbar_buttons']); // reset index return $toolbar_buttons ? trim(json_encode($toolbar_buttons), '[]') : 'false'; } /** * Checks, that "To" part of at least one of range filters is used * * @param Array $params * @return bool */ function RangeFiltersUsed($params) { /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); return $search_helper->rangeFiltersUsed($this->getPrefixSpecial(), $params['grid']); } /** * This is abstract tag, used to modify unit config data based on template, where it's used. * Tag is called from "combined_header" block in admin only. * * @param Array $params */ function ModifyUnitConfig($params) { } /** * Checks, that field is visible on edit form * * @param Array $params * @return bool */ function FieldVisible($params) { $check_field = $params['field']; $field_options = $this->_getFieldDefinition($check_field); if ( !$field_options ) { $params['field'] = 'Password'; return $check_field == 'VerifyPassword' ? $this->FieldVisible($params) : true; } $show_mode = array_key_exists('show_mode', $field_options) ? $field_options['show_mode'] : true; if ( $show_mode === smDEBUG ) { return defined('DEBUG_MODE') && DEBUG_MODE; } return $show_mode; } /** * Checks, that there area visible fields in given section on edit form * * @param Array $params * @return bool */ function FieldsVisible($params) { if ( !$params['fields'] ) { return true; } $check_fields = explode(',', $params['fields']); foreach ($check_fields as $check_field) { // when at least one field in subsection is visible, then subsection is visible too $field_options = $this->_getFieldDefinition($check_field); if ( $field_options ) { $show_mode = array_key_exists('show_mode', $field_options) ? $field_options['show_mode'] : true; } else { $show_mode = true; } if ( ($show_mode === true) || (($show_mode === smDEBUG) && (defined('DEBUG_MODE') && DEBUG_MODE)) ) { // field is visible return true; } } return false; } /** * Returns field definition * * @param string $field_name * @return Array * @access protected */ protected function _getFieldDefinition($field_name) { $config = $this->getUnitConfig(); $ret = $config->getFieldByName($field_name); if ( !$ret ) { $ret = $config->getVirtualFieldByName($field_name); } return $ret; } /** * Checks, that requested option is checked inside field value. * * @param array $params Tag params. * * @return boolean */ protected function Selected(array $params) { /** @var kDBItem $object */ $object = $this->getObject($params); $field = $this->SelectParam($params, 'name,field'); $value = $object->GetDBField($field); if ( strpos($value, '|') !== false ) { $selected_values = explode('|', substr($value, 1, -1)); } else { $selected_values = array((string)$value); } return in_array((string)$params['value'], $selected_values, true); } /** * Displays option name by it's value * * @param Array $params * @return string * @access protected */ protected function OptionValue($params) { /** @var kDBItem $object */ $object = $this->getObject($params); $value = $params['value']; $field = $this->SelectParam($params, 'name,field'); $field_options = $object->GetFieldOptions($field); if ( isset($field_options['options'][$value]) ) { $value = $field_options['options'][$value]; $use_phrases = isset($field_options['use_phrases']) ? $field_options['use_phrases'] : false; return $use_phrases ? $this->Application->Phrase($value) : $value; } return ''; } /** * Returns/sets form name for current object * * @param Array $params * @return string */ function FormName($params) { $form_name = $this->SelectParam($params, 'name,form,form_name'); if ( $form_name ) { $prefix = $this->getPrefixSpecial(); if ( $this->Application->hasObject( $this->getPrefixSpecial() ) ) { /** @var kDBItem $object */ $object = $this->getObject($params); if ( $object->getFormName() != $form_name ) { trigger_error('Setting form to "' . $form_name . '" failed, since object "' . $this->getPrefixSpecial() . '" is created before FormName tag (e.g. in event or another tag).', E_USER_WARNING); } } else { $forms = $this->Application->GetVar('forms', Array ()); $forms[ $this->getPrefixSpecial() ] = $form_name; $this->Application->SetVar('forms', $forms); } return ''; } /** @var kDBItem $object */ $object = $this->getObject($params); return $object->getFormName(); } /** * Just reloads the object using given parameters * * @param Array $params * @return string * @access protected */ protected function ReloadItem($params) { $params['requery'] = 1; /** @var kDBItem $object */ $object = $this->getObject($params); return ''; } } Index: branches/5.3.x/core/kernel/db/db_event_handler.php =================================================================== --- branches/5.3.x/core/kernel/db/db_event_handler.php (revision 16599) +++ branches/5.3.x/core/kernel/db/db_event_handler.php (revision 16600) @@ -1,3459 +1,3483 @@ getPrefixSpecial(true) instead of * $event->getPrefixSpecial() as usual. This is due PHP * is converting "." symbols in variable names during * submit info "_". $event->getPrefixSpecial optional * 1st parameter returns correct current Prefix_Special * for variables being submitted such way (e.g. variable * name that will be converted by PHP: "users.read_only_id" * will be submitted as "users_read_only_id". * * 2. When using $this->Application-LinkVar on variables submitted * from form which contain $Prefix_Special then note 1st item. Example: * LinkVar($event->getPrefixSpecial(true).'_varname',$event->getPrefixSpecial().'_varname') * */ /** * EventHandler that is used to process * any database related events * */ class kDBEventHandler extends kEventHandler { /** * Checks permissions of user * * @param kEvent $event * @return bool * @access public */ public function CheckPermission(kEvent $event) { $section = $event->getSection(); if ( !$this->Application->isAdmin ) { $allow_events = Array ('OnSearch', 'OnSearchReset', 'OnNew'); if ( in_array($event->Name, $allow_events) ) { // allow search on front return true; } } elseif ( ($event->Name == 'OnPreSaveAndChangeLanguage') && !$this->UseTempTables($event) ) { // allow changing language in grids, when not in editing mode return $this->Application->CheckPermission($section . '.view', 1); } if ( !preg_match('/^CATEGORY:(.*)/', $section) ) { // only if not category item events if ( (substr($event->Name, 0, 9) == 'OnPreSave') || ($event->Name == 'OnSave') ) { if ( $this->isNewItemCreate($event) ) { return $this->Application->CheckPermission($section . '.add', 1); } else { return $this->Application->CheckPermission($section . '.add', 1) || $this->Application->CheckPermission($section . '.edit', 1); } } } if ( $event->Name == 'OnPreCreate' ) { // save category_id before item create (for item category selector not to destroy permission checking category) $this->Application->LinkVar('m_cat_id'); } return parent::CheckPermission($event); } /** * Allows to override standard permission mapping * * @return void * @access protected * @see kEventHandler::$permMapping */ protected function mapPermissions() { parent::mapPermissions(); $permissions = Array ( 'OnLoad' => Array ('self' => 'view', 'subitem' => 'view'), 'OnItemBuild' => Array ('self' => 'view', 'subitem' => 'view'), 'OnSuggestValues' => Array ('self' => 'admin', 'subitem' => 'admin'), 'OnSuggestValuesJSON' => Array ('self' => 'admin', 'subitem' => 'admin'), 'OnBuild' => Array ('self' => true), 'OnNew' => Array ('self' => 'add', 'subitem' => 'add|edit'), 'OnCreate' => Array ('self' => 'add', 'subitem' => 'add|edit'), 'OnUpdate' => Array ('self' => 'edit', 'subitem' => 'add|edit'), 'OnSetPrimary' => Array ('self' => 'add|edit', 'subitem' => 'add|edit'), 'OnDelete' => Array ('self' => 'delete', 'subitem' => 'add|edit'), 'OnDeleteAll' => Array ('self' => 'delete', 'subitem' => 'add|edit'), 'OnMassDelete' => Array ('self' => 'delete', 'subitem' => 'add|edit'), 'OnMassClone' => Array ('self' => 'add', 'subitem' => 'add|edit'), 'OnCut' => Array ('self'=>'edit', 'subitem' => 'edit'), 'OnCopy' => Array ('self'=>'edit', 'subitem' => 'edit'), 'OnPaste' => Array ('self'=>'edit', 'subitem' => 'edit'), 'OnSelectItems' => Array ('self' => 'add|edit', 'subitem' => 'add|edit'), 'OnProcessSelected' => Array ('self' => 'add|edit', 'subitem' => 'add|edit'), 'OnStoreSelected' => Array ('self' => 'add|edit', 'subitem' => 'add|edit'), 'OnSelectUser' => Array ('self' => 'add|edit', 'subitem' => 'add|edit'), 'OnMassApprove' => Array ('self' => 'advanced:approve|edit', 'subitem' => 'advanced:approve|add|edit'), 'OnMassDecline' => Array ('self' => 'advanced:decline|edit', 'subitem' => 'advanced:decline|add|edit'), 'OnMassMoveUp' => Array ('self' => 'advanced:move_up|edit', 'subitem' => 'advanced:move_up|add|edit'), 'OnMassMoveDown' => Array ('self' => 'advanced:move_down|edit', 'subitem' => 'advanced:move_down|add|edit'), 'OnPreCreate' => Array ('self' => 'add|add.pending', 'subitem' => 'edit|edit.pending'), 'OnEdit' => Array ('self' => 'edit|edit.pending', 'subitem' => 'edit|edit.pending'), 'OnExport' => Array ('self' => 'view|advanced:export'), 'OnExportBegin' => Array ('self' => 'view|advanced:export'), 'OnExportProgress' => Array ('self' => 'view|advanced:export'), 'OnSetAutoRefreshInterval' => Array ('self' => true, 'subitem' => true), 'OnAutoRefreshToggle' => Array ('self' => true, 'subitem' => true), // theese event do not harm, but just in case check them too :) 'OnCancelEdit' => Array ('self' => true, 'subitem' => true), 'OnCancel' => Array ('self' => true, 'subitem' => true), 'OnReset' => Array ('self' => true, 'subitem' => true), 'OnSetSorting' => Array ('self' => true, 'subitem' => true), 'OnSetSortingDirect' => Array ('self' => true, 'subitem' => true), 'OnResetSorting' => Array ('self' => true, 'subitem' => true), 'OnSetFilter' => Array ('self' => true, 'subitem' => true), 'OnApplyFilters' => Array ('self' => true, 'subitem' => true), 'OnRemoveFilters' => Array ('self' => true, 'subitem' => true), 'OnSetFilterPattern' => Array ('self' => true, 'subitem' => true), 'OnSetPerPage' => Array ('self' => true, 'subitem' => true), 'OnSetPage' => Array ('self' => true, 'subitem' => true), 'OnSearch' => Array ('self' => true, 'subitem' => true), 'OnSearchReset' => Array ('self' => true, 'subitem' => true), 'OnGoBack' => Array ('self' => true, 'subitem' => true), // it checks permission itself since flash uploader does not send cookies 'OnUploadFile' => Array ('self' => true, 'subitem' => true), 'OnDeleteFile' => Array ('self' => true, 'subitem' => true), 'OnViewFile' => Array ('self' => true, 'subitem' => true), 'OnSaveWidths' => Array ('self' => 'admin', 'subitem' => 'admin'), 'OnValidateMInputFields' => Array ('self' => 'view'), 'OnValidateField' => Array ('self' => true, 'subitem' => true), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Define alternative event processing method names * * @return void * @see kEventHandler::$eventMethods * @access protected */ protected function mapEvents() { $events_map = Array ( 'OnRemoveFilters' => 'FilterAction', 'OnApplyFilters' => 'FilterAction', 'OnMassApprove' => 'iterateItems', 'OnMassDecline' => 'iterateItems', 'OnMassMoveUp' => 'iterateItems', 'OnMassMoveDown' => 'iterateItems', ); $this->eventMethods = array_merge($this->eventMethods, $events_map); } /** * Returns ID of current item to be edited * by checking ID passed in get/post as prefix_id * or by looking at first from selected ids, stored. * Returned id is also stored in Session in case * it was explicitly passed as get/post * * @param kEvent $event * @return int * @access public */ public function getPassedID(kEvent $event) { if ( $event->getEventParam('raise_warnings') === false ) { $event->setEventParam('raise_warnings', 1); } if ( $event->Special == 'previous' || $event->Special == 'next' ) { /** @var kDBItem $object */ $object = $this->Application->recallObject($event->getEventParam('item')); /** @var ListHelper $list_helper */ $list_helper = $this->Application->recallObject('ListHelper'); $select_clause = $object->getUnitConfig()->getNavigationSelectClause(NULL); return $list_helper->getNavigationResource($object, $event->getEventParam('list'), $event->Special == 'next', $select_clause); } elseif ( $event->Special == 'filter' ) { // temporary object, used to print filter options only return 0; } if ( preg_match('/^auto-(.*)/', $event->Special, $regs) && $this->Application->prefixRegistred($regs[1]) ) { // - returns field DateFormat value from language (LanguageId is extracted from current phrase object) /** @var kDBItem $main_object */ $main_object = $this->Application->recallObject($regs[1]); return $main_object->GetDBField($event->getUnitConfig()->getIDField()); } // 1. get id from post (used in admin) $ret = $this->Application->GetVar($event->getPrefixSpecial(true) . '_id'); if ( ($ret !== false) && ($ret != '') ) { $event->setEventParam(kEvent::FLAG_ID_FROM_REQUEST, true); return $ret; } // 2. get id from env (used in front) $ret = $this->Application->GetVar($event->getPrefixSpecial() . '_id'); if ( ($ret !== false) && ($ret != '') ) { $event->setEventParam(kEvent::FLAG_ID_FROM_REQUEST, true); return $ret; } // recall selected ids array and use the first one $ids = $this->Application->GetVar($event->getPrefixSpecial() . '_selected_ids'); if ( $ids != '' ) { $ids = explode(',', $ids); if ( $ids ) { $ret = array_shift($ids); $event->setEventParam(kEvent::FLAG_ID_FROM_REQUEST, true); } } else { // if selected ids are not yet stored $this->StoreSelectedIDs($event); // StoreSelectedIDs sets this variable. $ret = $this->Application->GetVar($event->getPrefixSpecial() . '_id'); if ( ($ret !== false) && ($ret != '') ) { $event->setEventParam(kEvent::FLAG_ID_FROM_REQUEST, true); return $ret; } } return $ret; } /** * Prepares and stores selected_ids string * in Session and Application Variables * by getting all checked ids from grid plus * id passed in get/post as prefix_id * * @param kEvent $event * @param Array $direct_ids * @return Array * @access protected */ protected function StoreSelectedIDs(kEvent $event, $direct_ids = NULL) { $wid = $this->Application->GetTopmostWid($event->Prefix); $session_name = rtrim($event->getPrefixSpecial() . '_selected_ids_' . $wid, '_'); $ids = $event->getEventParam('ids'); if ( isset($direct_ids) || ($ids !== false) ) { // save ids directly if they given + reset array indexes $resulting_ids = $direct_ids ? array_values($direct_ids) : ($ids ? array_values($ids) : false); if ( $resulting_ids ) { $this->Application->SetVar($event->getPrefixSpecial() . '_selected_ids', implode(',', $resulting_ids)); $this->Application->LinkVar($event->getPrefixSpecial() . '_selected_ids', $session_name, '', true); $this->Application->SetVar($event->getPrefixSpecial() . '_id', $resulting_ids[0]); return $resulting_ids; } return Array (); } $ret = Array (); // May be we don't need this part: ? $passed = $this->Application->GetVar($event->getPrefixSpecial(true) . '_id'); if ( $passed !== false && $passed != '' ) { array_push($ret, $passed); } $ids = Array (); // get selected ids from post & save them to session $items_info = $this->Application->GetVar($event->getPrefixSpecial(true)); if ( $items_info ) { $id_field = $event->getUnitConfig()->getIDField(); foreach ($items_info as $id => $field_values) { if ( getArrayValue($field_values, $id_field) ) { array_push($ids, $id); } } //$ids = array_keys($items_info); } $ret = array_unique(array_merge($ret, $ids)); $this->Application->SetVar($event->getPrefixSpecial() . '_selected_ids', implode(',', $ret)); $this->Application->LinkVar($event->getPrefixSpecial() . '_selected_ids', $session_name, '', !$ret); // optional when IDs are missing // This is critical - otherwise getPassedID will return last ID stored in session! (not exactly true) // this smells... needs to be refactored $first_id = getArrayValue($ret, 0); if ( ($first_id === false) && ($event->getEventParam('raise_warnings') == 1) ) { if ( $this->Application->isDebugMode() ) { $this->Application->Debugger->appendTrace(); } trigger_error('Requested ID for prefix ' . $event->getPrefixSpecial() . ' not passed', E_USER_NOTICE); } $this->Application->SetVar($event->getPrefixSpecial() . '_id', $first_id); return $ret; } /** * Returns stored selected ids as an array * * @param kEvent $event * @param bool $from_session return ids from session (written, when editing was started) * @return Array * @access protected */ protected function getSelectedIDs(kEvent $event, $from_session = false) { if ( $from_session ) { $wid = $this->Application->GetTopmostWid($event->Prefix); $var_name = rtrim($event->getPrefixSpecial() . '_selected_ids_' . $wid, '_'); $ret = $this->Application->RecallVar($var_name); } else { $ret = $this->Application->GetVar($event->getPrefixSpecial() . '_selected_ids'); } return explode(',', $ret); } /** * Stores IDs, selected in grid in session * * @param kEvent $event * @return void * @access protected */ protected function OnStoreSelected(kEvent $event) { $this->StoreSelectedIDs($event); $id = $this->Application->GetVar($event->getPrefixSpecial() . '_id'); if ( $id !== false ) { $event->SetRedirectParam($event->getPrefixSpecial() . '_id', $id); $event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial()); } } /** * Returns associative array of submitted fields for current item * Could be used while creating/editing single item - * meaning on any edit form, except grid edit * * @param kEvent $event * @return Array * @access protected */ protected function getSubmittedFields(kEvent $event) { $items_info = $this->Application->GetVar($event->getPrefixSpecial(true)); $field_values = $items_info ? array_shift($items_info) : Array (); return $field_values; } /** * Removes any information about current/selected ids * from Application variables and Session * * @param kEvent $event * @return void * @access protected */ protected function clearSelectedIDs(kEvent $event) { $prefix_special = $event->getPrefixSpecial(); $ids = implode(',', $this->getSelectedIDs($event, true)); $event->setEventParam('ids', $ids); $wid = $this->Application->GetTopmostWid($event->Prefix); $session_name = rtrim($prefix_special . '_selected_ids_' . $wid, '_'); $this->Application->RemoveVar($session_name); $this->Application->SetVar($prefix_special . '_selected_ids', ''); $this->Application->SetVar($prefix_special . '_id', ''); // $event->getPrefixSpecial(true) . '_id' too may be } /** * Common builder part for Item & List * * @param kDBBase|kDBItem|kDBList $object * @param kEvent $event * @return void * @access protected */ protected function dbBuild(&$object, kEvent $event) { // for permission checking inside item/list build events $event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true)); if ( $event->getEventParam('form_name') !== false ) { $form_name = $event->getEventParam('form_name'); } else { $request_forms = $this->Application->GetVar('forms', Array ()); $form_name = (string)getArrayValue($request_forms, $object->getPrefixSpecial()); } $object->Configure($event->getEventParam('populate_ml_fields') || $event->getUnitConfig()->getPopulateMlFields(), $form_name); $this->PrepareObject($object, $event); $parent_event = $event->getEventParam('parent_event'); if ( is_object($parent_event) ) { $object->setParentEvent($parent_event); } // force live table if specified or is original item $live_table = $event->getEventParam('live_table') || $event->Special == 'original'; if ( $this->UseTempTables($event) && !$live_table ) { $object->SwitchToTemp(); } $this->Application->setEvent($event->getPrefixSpecial(), ''); $save_event = $this->UseTempTables($event) && $this->Application->GetTopmostPrefix($event->Prefix) == $event->Prefix ? 'OnSave' : 'OnUpdate'; $this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', $save_event); } /** * Checks, that currently loaded item is allowed for viewing (non permission-based) * * @param kEvent $event * @return bool * @access protected */ protected function checkItemStatus(kEvent $event) { $status_field = $event->getUnitConfig()->getStatusField(true); if ( !$status_field ) { return true; } if ( $status_field == 'Status' || $status_field == 'Enabled' ) { /** @var kDBItem $object */ $object = $event->getObject(); if ( !$object->isLoaded() ) { return true; } return $object->GetDBField($status_field) == STATUS_ACTIVE; } return true; } /** * Shows not found template content * * @param kEvent $event * @return void * @access protected */ protected function _errorNotFound(kEvent $event) { if ( $event->getEventParam('raise_warnings') === 0 ) { // when it's possible, that autoload fails do nothing return; } if ( $this->Application->isDebugMode() ) { $this->Application->Debugger->appendTrace(); } trigger_error('ItemLoad Permission Failed for prefix [' . $event->getPrefixSpecial() . '] in checkItemStatus, leading to "404 Not Found"', E_USER_NOTICE); $this->Application->UrlManager->show404(); } /** * Builds item (loads if needed) * * Pattern: Prototype Manager * * @param kEvent $event * @access protected */ protected function OnItemBuild(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $this->dbBuild($object, $event); $sql = $this->ItemPrepareQuery($event); $sql = $this->Application->ReplaceLanguageTags($sql); $object->setSelectSQL($sql); // 2. loads if allowed $auto_load = $event->getUnitConfig()->getAutoLoad(); $skip_autoload = $event->getEventParam('skip_autoload'); if ( $auto_load && !$skip_autoload ) { $perm_status = true; $user_id = $this->Application->InitDone ? $this->Application->RecallVar('user_id') : USER_ROOT; $event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true)); $status_checked = false; - if ( $user_id == USER_ROOT || $this->CheckPermission($event) ) { - // don't autoload item, when user doesn't have view permission + if ( $this->Application->permissionCheckingDisabled($user_id) || $this->CheckPermission($event) ) { + // Don't autoload item, when user doesn't have view permission. $this->LoadItem($event); $status_checked = true; $editing_mode = defined('EDITING_MODE') ? EDITING_MODE : false; $id_from_request = $event->getEventParam(kEvent::FLAG_ID_FROM_REQUEST); - if ( $user_id != USER_ROOT + if ( !$this->Application->permissionCheckingDisabled($user_id) && !$this->Application->isAdmin && !($editing_mode || ($id_from_request ? $this->checkItemStatus($event) : true)) ) { - // non-root user AND on front-end AND (not editing mode || incorrect status) + // Permissions are being checked AND on Front-End AND (not editing mode || incorrect status). $perm_status = false; } } else { $perm_status = false; } if ( !$perm_status ) { // when no permission to view item -> redirect to no permission template $this->_processItemLoadingError($event, $status_checked); } } /** @var Params $actions */ $actions = $this->Application->recallObject('kActions'); $actions->Set($event->getPrefixSpecial() . '_GoTab', ''); $actions->Set($event->getPrefixSpecial() . '_GoId', ''); $actions->Set('forms[' . $event->getPrefixSpecial() . ']', $object->getFormName()); } /** * Processes case, when item wasn't loaded because of lack of permissions * * @param kEvent $event * @param bool $status_checked * @throws kNoPermissionException * @return void * @access protected */ protected function _processItemLoadingError($event, $status_checked) { $current_template = $this->Application->GetVar('t'); $redirect_template = $this->Application->isAdmin ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate'); $error_msg = 'ItemLoad Permission Failed for prefix [' . $event->getPrefixSpecial() . '] in ' . ($status_checked ? 'checkItemStatus' : 'CheckPermission') . ''; if ( $current_template == $redirect_template ) { // don't perform "no_permission" redirect if already on a "no_permission" template if ( $this->Application->isDebugMode() ) { $this->Application->Debugger->appendTrace(); } trigger_error($error_msg, E_USER_NOTICE); return; } if ( MOD_REWRITE ) { $redirect_params = Array ( 'm_cat_id' => 0, 'next_template' => 'external:' . $_SERVER['REQUEST_URI'], ); } else { $redirect_params = Array ( 'next_template' => $current_template, ); } $exception = new kNoPermissionException($error_msg); $exception->setup($redirect_template, $redirect_params); throw $exception; } /** * Build sub-tables array from configs * * @param kEvent $event * @return void * @access protected */ protected function OnTempHandlerBuild(kEvent $event) { /** @var kTempTablesHandler $object */ $object = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler'); /** @var kEvent $parent_event */ $parent_event = $event->getEventParam('parent_event'); if ( is_object($parent_event) ) { $object->setParentEvent($parent_event); } $object->BuildTables($event->Prefix, $this->getSelectedIDs($event)); } /** * Checks, that object used in event should use temp tables * * @param kEvent $event * @return bool * @access protected */ protected function UseTempTables(kEvent $event) { $top_prefix = $this->Application->GetTopmostPrefix($event->Prefix); // passed parent, not always actual $special = ($top_prefix == $event->Prefix) ? $event->Special : $this->getMainSpecial($event); return $this->Application->IsTempMode($event->Prefix, $special); } /** * Load item if id is available * * @param kEvent $event * @return void * @access protected */ protected function LoadItem(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $id = $this->getPassedID($event); if ( $object->isLoaded() && !is_array($id) && ($object->GetID() == $id) ) { // object is already loaded by same id return ; } if ( $object->Load($id) ) { /** @var Params $actions */ $actions = $this->Application->recallObject('kActions'); $actions->Set($event->getPrefixSpecial() . '_id', $object->GetID()); } else { $object->setID( is_array($id) ? false : $id ); } } /** * Builds list * * Pattern: Prototype Manager * * @param kEvent $event * @access protected */ protected function OnListBuild(kEvent $event) { /** @var kDBList $object */ $object = $event->getObject(); /*if ( $this->Application->isDebugMode() ) { $event_params = http_build_query($event->getEventParams()); $this->Application->Debugger->appendHTML('InitList "' . $event->getPrefixSpecial() . '" (' . $event_params . ')'); }*/ $this->dbBuild($object, $event); if ( !$object->isMainList() && $event->getEventParam('main_list') ) { // once list is set to main, then even "requery" parameter can't remove that /*$passed = $this->Application->GetVar('passed'); $this->Application->SetVar('passed', $passed . ',' . $event->Prefix);*/ $object->becameMain(); } $object->setGridName($event->getEventParam('grid')); $sql = $this->ListPrepareQuery($event); $sql = $this->Application->ReplaceLanguageTags($sql); $object->setSelectSQL($sql); $object->reset(); if ( $event->getEventParam('skip_parent_filter') === false ) { $object->linkToParent($this->getMainSpecial($event)); } $this->AddFilters($event); $this->SetCustomQuery($event); // new!, use this for dynamic queries based on specials for ex. $this->SetPagination($event); $this->SetSorting($event); /** @var Params $actions */ $actions = $this->Application->recallObject('kActions'); $actions->Set('remove_specials[' . $event->getPrefixSpecial() . ']', '0'); $actions->Set($event->getPrefixSpecial() . '_GoTab', ''); } /** * Returns special of main item for linking with sub-item * * @param kEvent $event * @return string * @access protected */ protected function getMainSpecial(kEvent $event) { $main_special = $event->getEventParam('main_special'); if ( $main_special === false ) { // main item's special not passed if ( substr($event->Special, -5) == '-item' ) { // temp handler added "-item" to given special -> process that here return substr($event->Special, 0, -5); } // by default subitem's special is used for main item searching return $event->Special; } return $main_special; } /** * Apply any custom changes to list's sql query * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetCustomQuery(kEvent $event) { } /** * Set's new per-page for grid * * @param kEvent $event * @return void * @access protected */ protected function OnSetPerPage(kEvent $event) { $per_page = $this->Application->GetVar($event->getPrefixSpecial(true) . '_PerPage'); $event->SetRedirectParam($event->getPrefixSpecial() . '_PerPage', $per_page); $event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial()); if ( !$this->Application->isAdminUser ) { /** @var ListHelper $list_helper */ $list_helper = $this->Application->recallObject('ListHelper'); $this->_passListParams($event, 'per_page'); } } /** * Occurs when page is changed (only for hooking) * * @param kEvent $event * @return void * @access protected */ protected function OnSetPage(kEvent $event) { $page = $this->Application->GetVar($event->getPrefixSpecial(true) . '_Page'); $event->SetRedirectParam($event->getPrefixSpecial() . '_Page', $page); $event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial()); if ( !$this->Application->isAdminUser ) { $this->_passListParams($event, 'page'); } } /** * Passes through main list pagination and sorting * * @param kEvent $event * @param string $skip_var * @return void * @access protected */ protected function _passListParams($event, $skip_var) { $param_names = array_diff(Array ('page', 'per_page', 'sort_by'), Array ($skip_var)); /** @var ListHelper $list_helper */ $list_helper = $this->Application->recallObject('ListHelper'); foreach ($param_names as $param_name) { $value = $this->Application->GetVar($param_name); switch ($param_name) { case 'page': if ( $value > 1 ) { $event->SetRedirectParam('page', $value); } break; case 'per_page': if ( $value > 0 ) { if ( $value != $list_helper->getDefaultPerPage($event->Prefix) ) { $event->SetRedirectParam('per_page', $value); } } break; case 'sort_by': $event->setPseudoClass('_List'); /** @var kDBList $object */ $object = $event->getObject(Array ('main_list' => 1)); if ( $list_helper->hasUserSorting($object) ) { $event->SetRedirectParam('sort_by', $value); } break; } } } /** * Set's correct page for list based on data provided with event * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetPagination(kEvent $event) { /** @var kDBList $object */ $object = $event->getObject(); // get PerPage (forced -> session -> config -> 10) $object->SetPerPage($this->getPerPage($event)); // main lists on Front-End have special get parameter for page $page = $object->isMainList() ? $this->Application->GetVar('page') : false; if ( !$page ) { // page is given in "env" variable for given prefix $page = $this->Application->GetVar($event->getPrefixSpecial() . '_Page'); } if ( !$page && $event->Special ) { // when not part of env, then variables like "prefix.special_Page" are // replaced (by PHP) with "prefix_special_Page", so check for that too $page = $this->Application->GetVar($event->getPrefixSpecial(true) . '_Page'); } if ( !$object->isMainList() ) { // main lists doesn't use session for page storing $this->Application->StoreVarDefault($event->getPrefixSpecial() . '_Page', 1, true); // true for optional if ( $page ) { // page found in request -> store in session $this->Application->StoreVar($event->getPrefixSpecial() . '_Page', $page, true); //true for optional } else { // page not found in request -> get from session $page = $this->Application->RecallVar($event->getPrefixSpecial() . '_Page'); } if ( !$event->getEventParam('skip_counting') ) { // when stored page is larger, then maximal list page number // (such case is also processed in kDBList::Query method) $pages = $object->GetTotalPages(); if ( $page > $pages ) { $page = 1; $this->Application->StoreVar($event->getPrefixSpecial() . '_Page', 1, true); } } } $object->SetPage($page); } /** * Returns current per-page setting for list * * @param kEvent $event * @return int * @access protected */ protected function getPerPage(kEvent $event) { /** @var kDBList $object */ $object = $event->getObject(); $per_page = $event->getEventParam('per_page'); if ( $per_page ) { // per-page is passed as tag parameter to PrintList, InitList, etc. $config_mapping = $event->getUnitConfig()->getConfigMapping(); // 2. per-page setting is stored in configuration variable if ( $config_mapping ) { // such pseudo per-pages are only defined in templates directly switch ($per_page) { case 'short_list': $per_page = $this->Application->ConfigValue($config_mapping['ShortListPerPage']); break; case 'default': $per_page = $this->Application->ConfigValue($config_mapping['PerPage']); break; } } return $per_page; } if ( !$per_page && $object->isMainList() ) { // main lists on Front-End have special get parameter for per-page $per_page = $this->Application->GetVar('per_page'); } if ( !$per_page ) { // per-page is given in "env" variable for given prefix $per_page = $this->Application->GetVar($event->getPrefixSpecial() . '_PerPage'); } if ( !$per_page && $event->Special ) { // when not part of env, then variables like "prefix.special_PerPage" are // replaced (by PHP) with "prefix_special_PerPage", so check for that too $per_page = $this->Application->GetVar($event->getPrefixSpecial(true) . '_PerPage'); } if ( !$object->isMainList() ) { // per-page given in env and not in main list $view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view'); if ( $per_page ) { // per-page found in request -> store in session and persistent session $this->setListSetting($event, 'PerPage', $per_page); } else { // per-page not found in request -> get from pesistent session (or session) $per_page = $this->getListSetting($event, 'PerPage'); } } if ( !$per_page ) { // per page wan't found in request/session/persistent session /** @var ListHelper $list_helper */ $list_helper = $this->Application->recallObject('ListHelper'); // allow to override default per-page value from tag $default_per_page = $event->getEventParam('default_per_page'); if ( !is_numeric($default_per_page) ) { $default_per_page = $this->Application->ConfigValue('DefaultGridPerPage'); } $per_page = $list_helper->getDefaultPerPage($event->Prefix, $default_per_page); } return $per_page; } /** * Set's correct sorting for list based on data provided with event * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetSorting(kEvent $event) { $event->setPseudoClass('_List'); /** @var kDBList $object */ $object = $event->getObject(); if ( $object->isMainList() ) { $sort_by = $this->Application->GetVar('sort_by'); $cur_sort1 = $cur_sort1_dir = $cur_sort2 = $cur_sort2_dir = false; if ( $sort_by ) { $sortings = explode('|', $sort_by); list ($cur_sort1, $cur_sort1_dir) = explode(',', $sortings[0]); if ( isset($sortings[1]) ) { list ($cur_sort2, $cur_sort2_dir) = explode(',', $sortings[1]); } } } else { $sorting_settings = $this->getListSetting($event, 'Sortings'); $cur_sort1 = getArrayValue($sorting_settings, 'Sort1'); $cur_sort1_dir = getArrayValue($sorting_settings, 'Sort1_Dir'); $cur_sort2 = getArrayValue($sorting_settings, 'Sort2'); $cur_sort2_dir = getArrayValue($sorting_settings, 'Sort2_Dir'); } $tag_sort_by = $event->getEventParam('sort_by'); if ( $tag_sort_by ) { if ( $tag_sort_by == 'random' ) { $object->AddOrderField('RAND()', ''); } else { // multiple sortings could be specified at once $tag_sort_by = explode('|', $tag_sort_by); foreach ($tag_sort_by as $sorting_element) { list ($by, $dir) = explode(',', $sorting_element); $object->AddOrderField($by, $dir); } } } $list_sortings = $this->_getDefaultSorting($event); // use default if not specified in session if ( !$cur_sort1 || !$cur_sort1_dir ) { $sorting = getArrayValue($list_sortings, 'Sorting'); if ( $sorting ) { reset($sorting); $cur_sort1 = key($sorting); $cur_sort1_dir = current($sorting); if ( next($sorting) ) { $cur_sort2 = key($sorting); $cur_sort2_dir = current($sorting); } } } // always add forced sorting before any user sorting fields /** @var Array $forced_sorting */ $forced_sorting = getArrayValue($list_sortings, 'ForcedSorting'); if ( $forced_sorting ) { foreach ($forced_sorting as $field => $dir) { $object->AddOrderField($field, $dir); } } // add user sorting fields if ( $cur_sort1 != '' && $cur_sort1_dir != '' ) { $object->AddOrderField($cur_sort1, $cur_sort1_dir); } if ( $cur_sort2 != '' && $cur_sort2_dir != '' ) { $object->AddOrderField($cur_sort2, $cur_sort2_dir); } } /** * Returns default list sortings * * @param kEvent $event * @return Array * @access protected */ protected function _getDefaultSorting(kEvent $event) { $config = $event->getUnitConfig(); $sorting_configs = $config->getConfigMapping(); $list_sortings = $config->getListSortingsBySpecial($event); if ( $sorting_configs && array_key_exists('DefaultSorting1Field', $sorting_configs) ) { // sorting defined in configuration variables overrides one from unit config $list_sortings['Sorting'] = Array ( $this->Application->ConfigValue($sorting_configs['DefaultSorting1Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting1Dir']), $this->Application->ConfigValue($sorting_configs['DefaultSorting2Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting2Dir']), ); // TODO: lowercase configuration variable values in db, instead of here $list_sortings['Sorting'] = array_map('strtolower', $list_sortings['Sorting']); } return $list_sortings ? $list_sortings : Array (); } /** * Gets list setting by name (persistent or real session) * * @param kEvent $event * @param string $variable_name * @return string|Array * @access protected */ protected function getListSetting(kEvent $event, $variable_name) { $view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view'); $storage_prefix = $event->getEventParam('same_special') ? $event->Prefix : $event->getPrefixSpecial(); // get sorting from persistent session $default_value = $this->Application->isAdmin ? ALLOW_DEFAULT_SETTINGS : false; $variable_value = $this->Application->RecallPersistentVar($storage_prefix . '_' . $variable_name . '.' . $view_name, $default_value); /*if ( !$variable_value ) { // get sorting from session $variable_value = $this->Application->RecallVar($storage_prefix . '_' . $variable_name); }*/ if ( kUtil::IsSerialized($variable_value) ) { $variable_value = unserialize($variable_value); } return $variable_value; } /** * Sets list setting by name (persistent and real session) * * @param kEvent $event * @param string $variable_name * @param string|Array $variable_value * @return void * @access protected */ protected function setListSetting(kEvent $event, $variable_name, $variable_value = NULL) { $view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view'); // $this->Application->StoreVar($event->getPrefixSpecial() . '_' . $variable_name, $variable_value, true); //true for optional if ( isset($variable_value) ) { if ( is_array($variable_value) ) { $variable_value = serialize($variable_value); } $this->Application->StorePersistentVar($event->getPrefixSpecial() . '_' . $variable_name . '.' . $view_name, $variable_value, true); //true for optional } else { $this->Application->RemovePersistentVar($event->getPrefixSpecial() . '_' . $variable_name . '.' . $view_name); } } /** * Add filters found in session * * @param kEvent $event * @return void * @access protected */ protected function AddFilters(kEvent $event) { /** @var kDBList $object */ $object = $event->getObject(); $edit_mark = rtrim($this->Application->GetSID() . '_' . $this->Application->GetTopmostWid($event->Prefix), '_'); // add search filter $filter_data = $this->Application->RecallVar($event->getPrefixSpecial() . '_search_filter'); if ( $filter_data ) { $filter_data = unserialize($filter_data); foreach ($filter_data as $filter_field => $filter_params) { $filter_type = ($filter_params['type'] == 'having') ? kDBList::HAVING_FILTER : kDBList::WHERE_FILTER; $filter_value = str_replace(EDIT_MARK, $edit_mark, $filter_params['value']); $object->addFilter($filter_field, $filter_value, $filter_type, kDBList::FLT_SEARCH); } } // add custom filter $view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view'); $custom_filters = $this->Application->RecallPersistentVar($event->getPrefixSpecial() . '_custom_filter.' . $view_name); if ( $custom_filters ) { $grid_name = $event->getEventParam('grid'); $custom_filters = unserialize($custom_filters); if ( isset($custom_filters[$grid_name]) ) { foreach ($custom_filters[$grid_name] as $field_name => $field_options) { list ($filter_type, $field_options) = each($field_options); if ( isset($field_options['value']) && $field_options['value'] ) { $filter_type = ($field_options['sql_filter_type'] == 'having') ? kDBList::HAVING_FILTER : kDBList::WHERE_FILTER; $filter_value = str_replace(EDIT_MARK, $edit_mark, $field_options['value']); $object->addFilter($field_name, $filter_value, $filter_type, kDBList::FLT_CUSTOM); } } } } // add view filter $view_filter = $this->Application->RecallVar($event->getPrefixSpecial() . '_view_filter'); if ( $view_filter ) { $view_filter = unserialize($view_filter); /** @var kMultipleFilter $temp_filter */ $temp_filter = $this->Application->makeClass('kMultipleFilter'); $filter_menu = $event->getUnitConfig()->getFilterMenu(); $group_key = 0; $group_count = count($filter_menu['Groups']); while ($group_key < $group_count) { $group_info = $filter_menu['Groups'][$group_key]; $temp_filter->setType(constant('kDBList::FLT_TYPE_' . $group_info['mode'])); $temp_filter->clearFilters(); foreach ($group_info['filters'] as $flt_id) { $sql_key = getArrayValue($view_filter, $flt_id) ? 'on_sql' : 'off_sql'; if ( $filter_menu['Filters'][$flt_id][$sql_key] != '' ) { $temp_filter->addFilter('view_filter_' . $flt_id, $filter_menu['Filters'][$flt_id][$sql_key]); } } $object->addFilter('view_group_' . $group_key, $temp_filter, $group_info['type'], kDBList::FLT_VIEW); $group_key++; } } // add item filter if ( $object->isMainList() ) { $this->applyItemFilters($event); } } /** * Applies item filters * * @param kEvent $event * @return void * @access protected */ protected function applyItemFilters($event) { $filter_values = $this->Application->GetVar('filters', Array ()); if ( !$filter_values ) { return; } /** @var kDBList $object */ $object = $event->getObject(); $where_clause = Array ( 'ItemPrefix = ' . $this->Conn->qstr($object->Prefix), 'FilterField IN (' . implode(',', $this->Conn->qstrArray(array_keys($filter_values))) . ')', 'Enabled = 1', ); $sql = 'SELECT * FROM ' . $this->Application->getUnitConfig('item-filter')->getTableName() . ' WHERE (' . implode(') AND (', $where_clause) . ')'; $filters = $this->Conn->Query($sql, 'FilterField'); foreach ($filters as $filter_field => $filter_data) { $filter_value = $filter_values[$filter_field]; if ( "$filter_value" === '' ) { // ListManager don't pass empty values, but check here just in case continue; } $table_name = $object->isVirtualField($filter_field) ? '' : '%1$s.'; switch ($filter_data['FilterType']) { case 'radio': $filter_value = $table_name . '`' . $filter_field . '` = ' . $this->Conn->qstr($filter_value); break; case 'checkbox': $filter_value = explode('|', substr($filter_value, 1, -1)); $filter_value = $this->Conn->qstrArray($filter_value, 'escape'); if ( $object->GetFieldOption($filter_field, 'multiple') ) { $filter_value = $table_name . '`' . $filter_field . '` LIKE "%|' . implode('|%" OR ' . $table_name . '`' . $filter_field . '` LIKE "%|', $filter_value) . '|%"'; } else { $filter_value = $table_name . '`' . $filter_field . '` IN (' . implode(',', $filter_value) . ')'; } break; case 'range': $filter_value = $this->Conn->qstrArray(explode('-', $filter_value)); $filter_value = $table_name . '`' . $filter_field . '` BETWEEN ' . $filter_value[0] . ' AND ' . $filter_value[1]; break; } $object->addFilter('item_filter_' . $filter_field, $filter_value, $object->isVirtualField($filter_field) ? kDBList::HAVING_FILTER : kDBList::WHERE_FILTER); } } /** * Set's new sorting for list * * @param kEvent $event * @return void * @access protected */ protected function OnSetSorting(kEvent $event) { $sorting_settings = $this->getListSetting($event, 'Sortings'); $cur_sort1 = getArrayValue($sorting_settings, 'Sort1'); $cur_sort1_dir = getArrayValue($sorting_settings, 'Sort1_Dir'); $use_double_sorting = $this->Application->ConfigValue('UseDoubleSorting'); if ( $use_double_sorting ) { $cur_sort2 = getArrayValue($sorting_settings, 'Sort2'); $cur_sort2_dir = getArrayValue($sorting_settings, 'Sort2_Dir'); } $passed_sort1 = $this->Application->GetVar($event->getPrefixSpecial(true) . '_Sort1'); if ( $cur_sort1 == $passed_sort1 ) { $cur_sort1_dir = $cur_sort1_dir == 'asc' ? 'desc' : 'asc'; } else { if ( $use_double_sorting ) { $cur_sort2 = $cur_sort1; $cur_sort2_dir = $cur_sort1_dir; } $cur_sort1 = $passed_sort1; $cur_sort1_dir = 'asc'; } $sorting_settings = Array ('Sort1' => $cur_sort1, 'Sort1_Dir' => $cur_sort1_dir); if ( $use_double_sorting ) { $sorting_settings['Sort2'] = $cur_sort2; $sorting_settings['Sort2_Dir'] = $cur_sort2_dir; } $this->setListSetting($event, 'Sortings', $sorting_settings); } /** * Set sorting directly to session (used for category item sorting (front-end), grid sorting (admin, view menu) * * @param kEvent $event * @return void * @access protected */ protected function OnSetSortingDirect(kEvent $event) { // used on Front-End in category item lists $prefix_special = $event->getPrefixSpecial(); $combined = $this->Application->GetVar($event->getPrefixSpecial(true) . '_CombinedSorting'); if ( $combined ) { list ($field, $dir) = explode('|', $combined); if ( $this->Application->isAdmin || !$this->Application->GetVar('main_list') ) { $this->setListSetting($event, 'Sortings', Array ('Sort1' => $field, 'Sort1_Dir' => $dir)); } else { $event->setPseudoClass('_List'); $this->Application->SetVar('sort_by', $field . ',' . $dir); /** @var kDBList $object */ $object = $event->getObject(Array ('main_list' => 1)); /** @var ListHelper $list_helper */ $list_helper = $this->Application->recallObject('ListHelper'); $this->_passListParams($event, 'sort_by'); if ( $list_helper->hasUserSorting($object) ) { $event->SetRedirectParam('sort_by', $field . ',' . strtolower($dir)); } $event->SetRedirectParam('pass', 'm'); } return; } // used in "View Menu -> Sort" menu in administrative console $field_pos = $this->Application->GetVar($event->getPrefixSpecial(true) . '_SortPos'); $this->Application->LinkVar($event->getPrefixSpecial(true) . '_Sort' . $field_pos, $prefix_special . '_Sort' . $field_pos); $this->Application->LinkVar($event->getPrefixSpecial(true) . '_Sort' . $field_pos . '_Dir', $prefix_special . '_Sort' . $field_pos . '_Dir'); } /** * Reset grid sorting to default (from config) * * @param kEvent $event * @return void * @access protected */ protected function OnResetSorting(kEvent $event) { $this->setListSetting($event, 'Sortings'); } /** * Sets grid refresh interval * * @param kEvent $event * @return void * @access protected */ protected function OnSetAutoRefreshInterval(kEvent $event) { $refresh_interval = $this->Application->GetVar('refresh_interval'); $view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view'); $this->Application->StorePersistentVar($event->getPrefixSpecial() . '_refresh_interval.' . $view_name, $refresh_interval); } /** * Changes auto-refresh state for grid * * @param kEvent $event * @return void * @access protected */ protected function OnAutoRefreshToggle(kEvent $event) { $refresh_intervals = $this->Application->ConfigValue('AutoRefreshIntervals'); if ( !$refresh_intervals ) { return; } $view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view'); $auto_refresh = $this->Application->RecallPersistentVar($event->getPrefixSpecial() . '_auto_refresh.' . $view_name); if ( $auto_refresh === false ) { $refresh_intervals = explode(',', $refresh_intervals); $this->Application->StorePersistentVar($event->getPrefixSpecial() . '_refresh_interval.' . $view_name, $refresh_intervals[0]); } $this->Application->StorePersistentVar($event->getPrefixSpecial() . '_auto_refresh.' . $view_name, $auto_refresh ? 0 : 1); } /** * Creates needed sql query to load item, * if no query is defined in config for * special requested, then use list query * * @param kEvent $event * @return string * @access protected */ protected function ItemPrepareQuery(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $sqls = $object->getFormOption('ItemSQLs', Array ()); $special = isset($sqls[$event->Special]) ? $event->Special : ''; // preferred special not found in ItemSQLs -> use analog from ListSQLs return isset($sqls[$special]) ? $sqls[$special] : $this->ListPrepareQuery($event); } /** * Creates needed sql query to load list, * if no query is defined in config for * special requested, then use default * query * * @param kEvent $event * @return string * @access protected */ protected function ListPrepareQuery(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $sqls = $object->getFormOption('ListSQLs', Array ()); return $sqls[array_key_exists($event->Special, $sqls) ? $event->Special : '']; } /** * Apply custom processing to item * * @param kEvent $event * @param string $type * @return void * @access protected */ protected function customProcessing(kEvent $event, $type) { } /* Edit Events mostly used in Admin */ /** * Creates new kDBItem * * @param kEvent $event * @return void * @access protected */ protected function OnCreate(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $items_info = $this->Application->GetVar($event->getPrefixSpecial(true)); if ( !$items_info ) { return; } list($id, $field_values) = each($items_info); $object->setID($id); $object->SetFieldsFromHash($field_values); $event->setEventParam('form_data', $field_values); $this->customProcessing($event, 'before'); // look at kDBItem' Create for ForceCreateId description, it's rarely used and is NOT set by default if ( $object->Create($event->getEventParam('ForceCreateId')) ) { $this->customProcessing($event, 'after'); $event->SetRedirectParam('opener', 'u'); return; } $event->redirect = false; $event->status = kEvent::erFAIL; $this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate'); } /** * Updates kDBItem * * @param kEvent $event * @return void * @access protected */ protected function OnUpdate(kEvent $event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } $this->_update($event); $event->SetRedirectParam('opener', 'u'); + + if ( $event->status == kEvent::erSUCCESS ) { + $this->saveChangesToLiveTable($event->Prefix); + } } /** * Updates data in database based on request * * @param kEvent $event * @return void * @access protected */ protected function _update(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); if ( $items_info ) { foreach ($items_info as $id => $field_values) { $object->Load($id); $object->SetFieldsFromHash($field_values); $event->setEventParam('form_data', $field_values); $this->customProcessing($event, 'before'); if ( $object->Update($id) ) { $this->customProcessing($event, 'after'); $event->status = kEvent::erSUCCESS; } else { $event->status = kEvent::erFAIL; $event->redirect = false; break; } } } } /** + * Automatically saves data to live table after sub-item was updated in Content Mode. + * + * @param string $prefix Prefix. + * + * @return void + */ + protected function saveChangesToLiveTable($prefix) + { + $parent_prefix = $this->Application->getUnitConfig($prefix)->getParentPrefix(); + + if ( $parent_prefix === false ) { + return; + } + + if ( $this->Application->GetVar('admin') && $this->Application->IsTempMode($parent_prefix) ) { + $this->Application->HandleEvent(new kEvent($parent_prefix . ':OnSave')); + } + } + + /** * Delete's kDBItem object * * @param kEvent $event * @return void * @access protected */ protected function OnDelete(kEvent $event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $temp_handler->DeleteItems($event->Prefix, $event->Special, Array ($this->getPassedID($event))); } /** * Deletes all records from table * * @param kEvent $event * @return void * @access protected */ protected function OnDeleteAll(kEvent $event) { $config = $event->getUnitConfig(); $sql = 'SELECT ' . $config->getIDField() . ' FROM ' . $config->getTableName(); $ids = $this->Conn->GetCol($sql); if ( $ids ) { /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $temp_handler->DeleteItems($event->Prefix, $event->Special, $ids); } } /** * Prepares new kDBItem object * * @param kEvent $event * @return void * @access protected */ protected function OnNew(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $object->Clear(0); $this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate'); if ( $event->getEventParam('top_prefix') != $event->Prefix ) { // this is subitem prefix, so use main item special $table_info = $object->getLinkedInfo($this->getMainSpecial($event)); } else { $table_info = $object->getLinkedInfo(); } $object->SetDBField($table_info['ForeignKey'], $table_info['ParentId']); $event->redirect = false; } /** * Cancels kDBItem Editing/Creation * * @param kEvent $event * @return void * @access protected */ protected function OnCancel(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $items_info = $this->Application->GetVar($event->getPrefixSpecial(true)); if ( $items_info ) { $delete_ids = Array (); /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); foreach ($items_info as $id => $field_values) { $object->Load($id); // record created for using with selector (e.g. Reviews->Select User), and not validated => Delete it if ( $object->isLoaded() && !$object->Validate() && ($id <= 0) ) { $delete_ids[] = $id; } } if ( $delete_ids ) { $temp_handler->DeleteItems($event->Prefix, $event->Special, $delete_ids); } } $event->SetRedirectParam('opener', 'u'); } /** * Deletes all selected items. * Automatically recurse into sub-items using temp handler, and deletes sub-items * by calling its Delete method if sub-item has AutoDelete set to true in its config file * * @param kEvent $event * @return void * @access protected */ protected function OnMassDelete(kEvent $event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return ; } /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $ids = $this->StoreSelectedIDs($event); $event->setEventParam('ids', $ids); $this->customProcessing($event, 'before'); $ids = $event->getEventParam('ids'); if ( $ids ) { $temp_handler->DeleteItems($event->Prefix, $event->Special, $ids); } $this->clearSelectedIDs($event); } /** * Sets window id (of first opened edit window) to temp mark in uls * * @param kEvent $event * @return void * @access protected */ protected function setTempWindowID(kEvent $event) { $prefixes = Array ($event->Prefix, $event->getPrefixSpecial(true)); foreach ($prefixes as $prefix) { $mode = $this->Application->GetVar($prefix . '_mode'); if ($mode == 't') { $wid = $this->Application->GetVar('m_wid'); $this->Application->SetVar(str_replace('_', '.', $prefix) . '_mode', 't' . $wid); break; } } } /** * Prepare temp tables and populate it * with items selected in the grid * * @param kEvent $event * @return void * @access protected */ protected function OnEdit(kEvent $event) { $this->setTempWindowID($event); $ids = $this->StoreSelectedIDs($event); /** @var kDBItem $object */ $object = $event->getObject(Array('skip_autoload' => true)); $object->setPendingActions(null, true); $changes_var_name = $this->Prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix); $this->Application->RemoveVar($changes_var_name); /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $temp_handler->PrepareEdit(); $event->SetRedirectParam('m_lang', $this->Application->GetDefaultLanguageId()); $event->SetRedirectParam($event->getPrefixSpecial() . '_id', array_shift($ids)); $event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial()); $pass_through = array('_simultaneous_edit_message', 'edit_field'); foreach ( $pass_through as $name ) { $value = $this->Application->GetVar($name); if ( strlen($value) ) { $event->SetRedirectParam($name, $value); } } } /** * Saves content of temp table into live and * redirects to event' default redirect (normally grid template) * * @param kEvent $event * @return void * @access protected */ protected function OnSave(kEvent $event) { $event->CallSubEvent('OnPreSave'); if ( $event->status != kEvent::erSUCCESS ) { return; } $skip_master = false; /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $changes_var_name = $this->Prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix); if ( !$this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $live_ids = $temp_handler->SaveEdit($event->getEventParam('master_ids') ? $event->getEventParam('master_ids') : Array ()); if ( $live_ids === false ) { // coping from table failed, because we have another coping process to same table, that wasn't finished $event->status = kEvent::erFAIL; return; } if ( $live_ids ) { // ensure, that newly created item ids are available as if they were selected from grid // NOTE: only works if main item has sub-items !!! $this->StoreSelectedIDs($event, $live_ids); } /** @var kDBItem $object */ $object = $event->getObject(); $this->SaveLoggedChanges($changes_var_name, $object->ShouldLogChanges()); } else { $event->status = kEvent::erFAIL; } $this->clearSelectedIDs($event); $event->SetRedirectParam('opener', 'u'); $this->Application->RemoveVar($event->getPrefixSpecial() . '_modified'); // all temp tables are deleted here => all after hooks should think, that it's live mode now $this->Application->SetVar($event->Prefix . '_mode', ''); } /** * Saves changes made in temporary table to log * * @param string $changes_var_name * @param bool $save * @return void * @access public */ public function SaveLoggedChanges($changes_var_name, $save = true) { // 1. get changes, that were made $changes = $this->Application->RecallVar($changes_var_name); $changes = $changes ? unserialize($changes) : Array (); $this->Application->RemoveVar($changes_var_name); if (!$changes) { // no changes, skip processing return ; } // TODO: 2. optimize change log records (replace multiple changes to same record with one change record) $to_increment = Array (); // 3. collect serials to reset based on foreign keys foreach ($changes as $index => $rec) { if (array_key_exists('DependentFields', $rec)) { foreach ($rec['DependentFields'] as $field_name => $field_value) { // will be "ci|ItemResourceId:345" $to_increment[] = $rec['Prefix'] . '|' . $field_name . ':' . $field_value; // also reset sub-item prefix general serial $to_increment[] = $rec['Prefix']; } unset($changes[$index]['DependentFields']); } unset($changes[$index]['ParentId'], $changes[$index]['ParentPrefix']); } // 4. collect serials to reset based on changed ids foreach ($changes as $change) { $to_increment[] = $change['MasterPrefix'] . '|' . $change['MasterId']; if ($change['MasterPrefix'] != $change['Prefix']) { // also reset sub-item prefix general serial $to_increment[] = $change['Prefix']; // will be "ci|ItemResourceId" $to_increment[] = $change['Prefix'] . '|' . $change['ItemId']; } } // 5. reset serials collected before $to_increment = array_unique($to_increment); $this->Application->incrementCacheSerial($this->Prefix); foreach ($to_increment as $to_increment_mixed) { if (strpos($to_increment_mixed, '|') !== false) { list ($to_increment_prefix, $to_increment_id) = explode('|', $to_increment_mixed, 2); $this->Application->incrementCacheSerial($to_increment_prefix, $to_increment_id); } else { $this->Application->incrementCacheSerial($to_increment_mixed); } } // save changes to database $session_log_id = $this->Application->RecallVar('_SessionLogId_'); if (!$save || !$session_log_id) { // saving changes to database disabled OR related session log missing return ; } $add_fields = Array ( 'PortalUserId' => $this->Application->RecallVar('user_id'), 'SessionLogId' => $session_log_id, ); $change_log_table = $this->Application->getUnitConfig('change-log')->getTableName(); foreach ($changes as $rec) { $this->Conn->doInsert(array_merge($rec, $add_fields), $change_log_table); } $this->Application->incrementCacheSerial('change-log'); $sql = 'UPDATE ' . $this->Application->getUnitConfig('session-log')->getTableName() . ' SET AffectedItems = AffectedItems + ' . count($changes) . ' WHERE SessionLogId = ' . $session_log_id; $this->Conn->Query($sql); $this->Application->incrementCacheSerial('session-log'); } /** * Cancels edit * Removes all temp tables and clears selected ids * * @param kEvent $event * @return void * @access protected */ protected function OnCancelEdit(kEvent $event) { /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $temp_handler->CancelEdit(); $this->clearSelectedIDs($event); $this->Application->RemoveVar($event->getPrefixSpecial() . '_modified'); $changes_var_name = $this->Prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix); $this->Application->RemoveVar($changes_var_name); $event->SetRedirectParam('opener', 'u'); } /** * Allows to determine if we are creating new item or editing already created item * * @param kEvent $event * @return bool * @access public */ public function isNewItemCreate(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject( Array ('raise_warnings' => 0) ); return !$object->isLoaded(); } /** * Saves edited item into temp table * If there is no id, new item is created in temp table * * @param kEvent $event * @return void * @access protected */ protected function OnPreSave(kEvent $event) { // if there is no id - it means we need to create an item if ( is_object($event->MasterEvent) ) { $event->MasterEvent->setEventParam('IsNew', false); } if ( $this->isNewItemCreate($event) ) { $event->CallSubEvent('OnPreSaveCreated'); if ( is_object($event->MasterEvent) ) { $event->MasterEvent->setEventParam('IsNew', true); } return ; } // don't just call OnUpdate event here, since it maybe overwritten to Front-End specific behavior $this->_update($event); } /** * Analog of OnPreSave event for usage in AJAX request * * @param kEvent $event * * @return void */ protected function OnPreSaveAjax(kEvent $event) { /** @var AjaxFormHelper $ajax_form_helper */ $ajax_form_helper = $this->Application->recallObject('AjaxFormHelper'); $ajax_form_helper->transitEvent($event, 'OnPreSave'); } /** * [HOOK] Saves sub-item * * @param kEvent $event * @return void * @access protected */ protected function OnPreSaveSubItem(kEvent $event) { $not_created = $this->isNewItemCreate($event); $event->CallSubEvent($not_created ? 'OnCreate' : 'OnUpdate'); if ( $event->status == kEvent::erSUCCESS ) { /** @var kDBItem $object */ $object = $event->getObject(); $this->Application->SetVar($event->getPrefixSpecial() . '_id', $object->GetID()); } else { $event->MasterEvent->status = $event->status; } $event->SetRedirectParam('opener', 's'); } /** * Saves edited item in temp table and loads * item with passed id in current template * Used in Prev/Next buttons * * @param kEvent $event * @return void * @access protected */ protected function OnPreSaveAndGo(kEvent $event) { $event->CallSubEvent('OnPreSave'); if ( $event->status == kEvent::erSUCCESS ) { $id = $this->Application->GetVar($event->getPrefixSpecial(true) . '_GoId'); $event->SetRedirectParam($event->getPrefixSpecial() . '_id', $id); } } /** * Saves edited item in temp table and goes * to passed tabs, by redirecting to it with OnPreSave event * * @param kEvent $event * @return void * @access protected */ protected function OnPreSaveAndGoToTab(kEvent $event) { $event->CallSubEvent('OnPreSave'); if ( $event->status == kEvent::erSUCCESS ) { $event->redirect = $this->Application->GetVar($event->getPrefixSpecial(true) . '_GoTab'); } } /** * Saves editable list and goes to passed tab, * by redirecting to it with empty event * * @param kEvent $event * @return void * @access protected */ protected function OnUpdateAndGoToTab(kEvent $event) { $event->setPseudoClass('_List'); $event->CallSubEvent('OnUpdate'); if ( $event->status == kEvent::erSUCCESS ) { $event->redirect = $this->Application->GetVar($event->getPrefixSpecial(true) . '_GoTab'); } } /** * Prepare temp tables for creating new item * but does not create it. Actual create is * done in OnPreSaveCreated * * @param kEvent $event * @return void * @access protected */ protected function OnPreCreate(kEvent $event) { $this->setTempWindowID($event); $this->clearSelectedIDs($event); $this->Application->SetVar('m_lang', $this->Application->GetDefaultLanguageId()); /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->Prefix . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $temp_handler->PrepareEdit(); $object->setID(0); $this->Application->SetVar($event->getPrefixSpecial() . '_id', 0); $this->Application->SetVar($event->getPrefixSpecial() . '_PreCreate', 1); $changes_var_name = $this->Prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix); $this->Application->RemoveVar($changes_var_name); $event->redirect = false; } /** * Creates a new item in temp table and * stores item id in App vars and Session on success * * @param kEvent $event * @return void * @access protected */ protected function OnPreSaveCreated(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject( Array('skip_autoload' => true) ); $object->setID(0); $field_values = $this->getSubmittedFields($event); $object->SetFieldsFromHash($field_values); $event->setEventParam('form_data', $field_values); $this->customProcessing($event, 'before'); if ( $object->Create() ) { $this->customProcessing($event, 'after'); $event->SetRedirectParam($event->getPrefixSpecial(true) . '_id', $object->GetID()); } else { $event->status = kEvent::erFAIL; $event->redirect = false; } } /** * Reloads form to loose all changes made during item editing * * @param kEvent $event * @return void * @access protected */ protected function OnReset(kEvent $event) { //do nothing - should reset :) if ( $this->isNewItemCreate($event) ) { // just reset id to 0 in case it was create /** @var kDBItem $object */ $object = $event->getObject( Array ('skip_autoload' => true) ); $object->setID(0); $this->Application->SetVar($event->getPrefixSpecial() . '_id', 0); } } /** * Apply same processing to each item being selected in grid * * @param kEvent $event * @return void * @access protected */ protected function iterateItems(kEvent $event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return ; } /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $ids = $this->StoreSelectedIDs($event); if ( $ids ) { $config = $event->getUnitConfig(); $status_field = $config->getStatusField(true); $order_field = $config->getOrderField(); if ( !$order_field ) { $order_field = 'Priority'; } foreach ($ids as $id) { $object->Load($id); switch ( $event->Name ) { case 'OnMassApprove': $object->SetDBField($status_field, 1); break; case 'OnMassDecline': $object->SetDBField($status_field, 0); break; case 'OnMassMoveUp': $object->SetDBField($order_field, $object->GetDBField($order_field) + 1); break; case 'OnMassMoveDown': $object->SetDBField($order_field, $object->GetDBField($order_field) - 1); break; } $object->Update(); } } $this->clearSelectedIDs($event); } /** * Clones selected items in list * * @param kEvent $event * @return void * @access protected */ protected function OnMassClone(kEvent $event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $ids = $this->StoreSelectedIDs($event); if ( $ids ) { $temp_handler->CloneItems($event->Prefix, $event->Special, $ids); } $this->clearSelectedIDs($event); } /** * Checks if given value is present in given array * * @param Array $records * @param string $field * @param mixed $value * @return bool * @access protected */ protected function check_array($records, $field, $value) { foreach ($records as $record) { if ($record[$field] == $value) { return true; } } return false; } /** * Saves data from editing form to database without checking required fields * * @param kEvent $event * @return void * @access protected */ protected function OnPreSavePopup(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $this->RemoveRequiredFields($object); $event->CallSubEvent('OnPreSave'); $event->SetRedirectParam('opener', 'u'); } /* End of Edit events */ // III. Events that allow to put some code before and after Update,Load,Create and Delete methods of item /** * Occurs before loading item, 'id' parameter * allows to get id of item being loaded * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemLoad(kEvent $event) { } /** * Occurs after loading item, 'id' parameter * allows to get id of item that was loaded * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemLoad(kEvent $event) { } /** * Occurs before creating item * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemCreate(kEvent $event) { } /** * Occurs after creating item * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemCreate(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); if ( !$object->IsTempTable() ) { $this->_processPendingActions($event); } } /** * Occurs before updating item * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemUpdate(kEvent $event) { } /** * Occurs after updating item * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemUpdate(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); if ( !$object->IsTempTable() ) { $this->_processPendingActions($event); } } /** * Occurs before deleting item, id of item being * deleted is stored as 'id' event param * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemDelete(kEvent $event) { } /** * Occurs after deleting item, id of deleted item * is stored as 'id' param of event * * Also deletes subscriptions to that particual item once it's deleted * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemDelete(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); // 1. delete direct subscriptions to item, that was deleted $this->_deleteSubscriptions($event->Prefix, 'ItemId', $object->GetID()); // 2. delete this item sub-items subscriptions, that reference item, that was deleted foreach ($event->getUnitConfig()->getSubItems(Array ()) as $sub_prefix) { $this->_deleteSubscriptions($sub_prefix, 'ParentItemId', $object->GetID()); } } /** * Deletes all subscriptions, associated with given item * * @param string $prefix * @param string $field * @param int $value * @return void * @access protected */ protected function _deleteSubscriptions($prefix, $field, $value) { $sql = 'SELECT TemplateId FROM ' . $this->Application->getUnitConfig('email-template')->getTableName() . ' WHERE BindToSystemEvent REGEXP "' . $this->Conn->escape($prefix) . '(\\\\.[^:]*:.*|:.*)"'; $email_template_ids = $this->Conn->GetCol($sql); if ( !$email_template_ids ) { return; } // e-mail events, connected to that unit prefix are found $sql = 'SELECT SubscriptionId FROM ' . TABLE_PREFIX . 'SystemEventSubscriptions WHERE ' . $field . ' = ' . $value . ' AND EmailTemplateId IN (' . implode(',', $email_template_ids) . ')'; $ids = $this->Conn->GetCol($sql); if ( !$ids ) { return; } /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject('system-event-subscription_TempHandler', 'kTempTablesHandler'); $temp_handler->DeleteItems('system-event-subscription', '', $ids); } /** * Occurs before validation attempt * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemValidate(kEvent $event) { } /** * Occurs after successful item validation * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemValidate(kEvent $event) { } /** * Occurs after an item has been copied to temp * Id of copied item is passed as event' 'id' param * * @param kEvent $event * @return void * @access protected */ protected function OnAfterCopyToTemp(kEvent $event) { } /** * Occurs before an item is deleted from live table when copying from temp * (temp handler deleted all items from live and then copy over all items from temp) * Id of item being deleted is passed as event' 'id' param * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeDeleteFromLive(kEvent $event) { } /** * Occurs before an item is copied to live table (after all foreign keys have been updated) * Id of item being copied is passed as event' 'id' param * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeCopyToLive(kEvent $event) { } /** * Occurs after an item has been copied to live table * Id of copied item is passed as event' 'id' param * * @param kEvent $event * @return void * @access protected */ protected function OnAfterCopyToLive(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(array('skip_autoload' => true)); $object->SwitchToLive(); $object->Load($event->getEventParam('id')); $this->_processPendingActions($event); } /** * Processing file pending actions (e.g. delete scheduled files) * * @param kEvent $event * @return void * @access protected */ protected function _processPendingActions(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $update_required = false; $temp_id = $event->getEventParam('temp_id'); $id = $temp_id !== false ? $temp_id : $object->GetID(); foreach ($object->getPendingActions($id) as $data) { switch ( $data['action'] ) { case 'delete': unlink($data['file']); break; case 'make_live': /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); if ( !file_exists($data['file']) ) { // file removal was requested too continue; } $old_name = basename($data['file']); $new_name = $file_helper->ensureUniqueFilename(dirname($data['file']), kUtil::removeTempExtension($old_name)); rename($data['file'], dirname($data['file']) . '/' . $new_name); $db_value = $object->GetDBField($data['field']); $object->SetDBField($data['field'], str_replace($old_name, $new_name, $db_value)); $update_required = true; break; default: trigger_error('Unsupported pending action "' . $data['action'] . '" for "' . $event->getPrefixSpecial() . '" unit', E_USER_WARNING); break; } } // remove pending actions before updating to prevent recursion $object->setPendingActions(); if ( $update_required ) { $object->Update(); } } /** * Occurs before an item has been cloned * Id of newly created item is passed as event' 'id' param * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeClone(kEvent $event) { } /** * Occurs after an item has been cloned * Id of newly created item is passed as event' 'id' param * * @param kEvent $event * @return void * @access protected */ protected function OnAfterClone(kEvent $event) { } /** * Occurs after list is queried * * @param kEvent $event * @return void * @access protected */ protected function OnAfterListQuery(kEvent $event) { } /** * Ensures that popup will be closed automatically * and parent window will be refreshed with template * passed * * @param kEvent $event * @return void * @access protected * @deprecated */ protected function finalizePopup(kEvent $event) { $event->SetRedirectParam('opener', 'u'); } /** * Create search filters based on search query * * @param kEvent $event * @return void * @access protected */ protected function OnSearch(kEvent $event) { $event->setPseudoClass('_List'); /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); $search_helper->performSearch($event); } /** * Clear search keywords * * @param kEvent $event * @return void * @access protected */ protected function OnSearchReset(kEvent $event) { /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); $search_helper->resetSearch($event); } /** * Set's new filter value (filter_id meaning from config) * * @param kEvent $event * @return void * @access protected * @deprecated */ protected function OnSetFilter(kEvent $event) { $filter_id = $this->Application->GetVar('filter_id'); $filter_value = $this->Application->GetVar('filter_value'); $view_filter = $this->Application->RecallVar($event->getPrefixSpecial() . '_view_filter'); $view_filter = $view_filter ? unserialize($view_filter) : Array (); $view_filter[$filter_id] = $filter_value; $this->Application->StoreVar($event->getPrefixSpecial() . '_view_filter', serialize($view_filter)); } /** * Sets view filter based on request * * @param kEvent $event * @return void * @access protected */ protected function OnSetFilterPattern(kEvent $event) { $filters = $this->Application->GetVar($event->getPrefixSpecial(true) . '_filters'); if ( !$filters ) { return; } $view_filter = $this->Application->RecallVar($event->getPrefixSpecial() . '_view_filter'); $view_filter = $view_filter ? unserialize($view_filter) : Array (); $filters = explode(',', $filters); foreach ($filters as $a_filter) { list($id, $value) = explode('=', $a_filter); $view_filter[$id] = $value; } $this->Application->StoreVar($event->getPrefixSpecial() . '_view_filter', serialize($view_filter)); $event->redirect = false; } /** * Add/Remove all filters applied to list from "View" menu * * @param kEvent $event * @return void * @access protected */ protected function FilterAction(kEvent $event) { $view_filter = Array (); $filter_menu = $event->getUnitConfig()->getFilterMenu(); switch ($event->Name) { case 'OnRemoveFilters': $filter_value = 1; break; case 'OnApplyFilters': $filter_value = 0; break; default: $filter_value = 0; break; } foreach ($filter_menu['Filters'] as $filter_key => $filter_params) { if ( !$filter_params ) { continue; } $view_filter[$filter_key] = $filter_value; } $this->Application->StoreVar($event->getPrefixSpecial() . '_view_filter', serialize($view_filter)); } /** * Enter description here... * * @param kEvent $event * @access protected */ protected function OnPreSaveAndOpenTranslator(kEvent $event) { $this->Application->SetVar('allow_translation', true); /** @var kDBItem $object */ $object = $event->getObject(); $this->RemoveRequiredFields($object); $event->CallSubEvent('OnPreSave'); if ( $event->status == kEvent::erSUCCESS ) { $resource_id = $this->Application->GetVar('translator_resource_id'); if ( $resource_id ) { $t_prefixes = explode(',', $this->Application->GetVar('translator_prefixes')); /** @var kDBItem $cdata */ $cdata = $this->Application->recallObject($t_prefixes[1], NULL, Array ('skip_autoload' => true)); $cdata->Load($resource_id, 'ResourceId'); if ( !$cdata->isLoaded() ) { $cdata->SetDBField('ResourceId', $resource_id); $cdata->Create(); } $this->Application->SetVar($cdata->getPrefixSpecial() . '_id', $cdata->GetID()); } $event->redirect = $this->Application->GetVar('translator_t'); $redirect_params = Array ( 'pass' => 'all,trans,' . $this->Application->GetVar('translator_prefixes'), 'opener' => 's', $event->getPrefixSpecial(true) . '_id' => $object->GetID(), 'trans_event' => 'OnLoad', 'trans_prefix' => $this->Application->GetVar('translator_prefixes'), 'trans_field' => $this->Application->GetVar('translator_field'), 'trans_multi_line' => $this->Application->GetVar('translator_multi_line'), ); $event->setRedirectParams($redirect_params); // 1. SAVE LAST TEMPLATE TO SESSION (really needed here, because of tweaky redirect) $last_template = $this->Application->RecallVar('last_template'); preg_match('/index4\.php\|' . $this->Application->GetSID() . '-(.*):/U', $last_template, $rets); $this->Application->StoreVar('return_template', $this->Application->GetVar('t')); } } /** * Makes all fields non-required * * @param kDBItem $object * @return void * @access protected */ protected function RemoveRequiredFields(&$object) { // making all field non-required to achieve successful presave $fields = array_keys( $object->getFields() ); foreach ($fields as $field) { if ( $object->isRequired($field) ) { $object->setRequired($field, false); } } } /** * Saves selected user in needed field * * @param kEvent $event * @return void * @access protected */ protected function OnSelectUser(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $items_info = $this->Application->GetVar('u'); if ( $items_info ) { list ($user_id, ) = each($items_info); $this->RemoveRequiredFields($object); $is_new = !$object->isLoaded(); $is_main = substr($this->Application->GetVar($event->Prefix . '_mode'), 0, 1) == 't'; if ( $is_new ) { $new_event = $is_main ? 'OnPreCreate' : 'OnNew'; $event->CallSubEvent($new_event); $event->redirect = true; } $object->SetDBField($this->Application->RecallVar('dst_field'), $user_id); if ( $is_new ) { $object->Create(); } else { $object->Update(); } } $event->SetRedirectParam($event->getPrefixSpecial() . '_id', $object->GetID()); $event->SetRedirectParam('opener', 'u'); } /** EXPORT RELATED **/ /** * Shows export dialog * * @param kEvent $event * @return void * @access protected */ protected function OnExport(kEvent $event) { $selected_ids = $this->StoreSelectedIDs($event); if ( implode(',', $selected_ids) == '' ) { // K4 fix when no ids found bad selected ids array is formed $selected_ids = false; } $this->Application->StoreVar($event->Prefix . '_export_ids', $selected_ids ? implode(',', $selected_ids) : ''); $this->Application->LinkVar('export_finish_t'); $this->Application->LinkVar('export_progress_t'); $this->Application->StoreVar('export_special', $event->Special); $this->Application->StoreVar('export_grid', $this->Application->GetVar('grid', 'Default')); $redirect_params = Array ( $this->Prefix . '.export_event' => 'OnNew', 'pass' => 'all,' . $this->Prefix . '.export' ); $event->setRedirectParams($redirect_params); } /** * Apply some special processing to object being * recalled before using it in other events that * call prepareObject * * @param kDBItem|kDBList $object * @param kEvent $event * @return void * @access protected */ protected function prepareObject(&$object, kEvent $event) { if ( $event->Special == 'export' || $event->Special == 'import' ) { /** @var kCatDBItemExportHelper $export_helper */ $export_helper = $this->Application->recallObject('CatItemExportHelper'); $export_helper->prepareExportColumns($event); } } /** * Returns specific to each item type columns only * * @param kEvent $event * @return Array * @access public */ public function getCustomExportColumns(kEvent $event) { return Array (); } /** * Export form validation & processing * * @param kEvent $event * @return void * @access protected */ protected function OnExportBegin(kEvent $event) { /** @var kCatDBItemExportHelper $export_helper */ $export_helper = $this->Application->recallObject('CatItemExportHelper'); $export_helper->OnExportBegin($event); } /** * Enter description here... * * @param kEvent $event * @return void * @access protected */ protected function OnExportCancel(kEvent $event) { $this->OnGoBack($event); } /** * Allows configuring export options * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeExportBegin(kEvent $event) { } /** * Deletes export preset * * @param kEvent $event * @return void * @access protected */ protected function OnDeleteExportPreset(kEvent $event) { $field_values = $this->getSubmittedFields($event); if ( !$field_values ) { return ; } $preset_key = $field_values['ExportPresets']; $export_settings = $this->Application->RecallPersistentVar('export_settings'); if ( !$export_settings ) { return ; } $export_settings = unserialize($export_settings); if ( !isset($export_settings[$event->Prefix]) ) { return ; } $to_delete = ''; foreach ($export_settings[$event->Prefix] as $key => $val) { if ( implode('|', $val['ExportColumns']) == $preset_key ) { $to_delete = $key; break; } } if ( $to_delete ) { unset($export_settings[$event->Prefix][$to_delete]); $this->Application->StorePersistentVar('export_settings', serialize($export_settings)); } } /** * Saves changes & changes language * * @param kEvent $event * @return void * @access protected */ protected function OnPreSaveAndChangeLanguage(kEvent $event) { if ( $this->UseTempTables($event) ) { $event->CallSubEvent('OnPreSave'); } if ( $event->status == kEvent::erSUCCESS ) { $this->Application->SetVar('m_lang', $this->Application->GetVar('language')); $data = $this->Application->GetVar('st_id'); if ( $data ) { $event->SetRedirectParam('st_id', $data); } } } /** * Used to save files uploaded via Plupload * * @param kEvent $event * @return void * @access protected */ protected function OnUploadFile(kEvent $event) { $event->status = kEvent::erSTOP; /** @var kUploadHelper $upload_helper */ $upload_helper = $this->Application->recallObject('kUploadHelper'); try { $filename = $upload_helper->handle($event); $response = array( 'jsonrpc' => '2.0', 'status' => 'success', 'result' => $filename, ); } catch ( kUploaderException $e ) { $response = array( 'jsonrpc' => '2.0', 'status' => 'error', 'error' => array('code' => $e->getCode(), 'message' => $e->getMessage()), ); } echo json_encode($response); } /** * Remembers, that file should be deleted on item's save from temp table * * @param kEvent $event * @return void * @access protected */ protected function OnDeleteFile(kEvent $event) { $event->status = kEvent::erSTOP; $field_id = $this->Application->GetVar('field_id'); if ( !preg_match_all('/\[([^\[\]]*)\]/', $field_id, $regs) ) { return; } $field = $regs[1][1]; $record_id = $regs[1][0]; /** @var kUploadHelper $upload_helper */ $upload_helper = $this->Application->recallObject('kUploadHelper'); $object = $upload_helper->prepareUploadedFile($event, $field); if ( !$object->GetDBField($field) ) { return; } $pending_actions = $object->getPendingActions($record_id); $pending_actions[] = Array ( 'action' => 'delete', 'id' => $record_id, 'field' => $field, 'file' => $object->GetField($field, 'full_path'), ); $object->setPendingActions($pending_actions, $record_id); } /** * Returns url for viewing uploaded file * * @param kEvent $event * @return void * @access protected */ protected function OnViewFile(kEvent $event) { $event->status = kEvent::erSTOP; $field = $this->Application->GetVar('field'); /** @var kUploadHelper $upload_helper */ $upload_helper = $this->Application->recallObject('kUploadHelper'); $object = $upload_helper->prepareUploadedFile($event, $field); if ( !$object->GetDBField($field) ) { return; } // get url to uploaded file if ( $this->Application->GetVar('thumb') ) { $url = $object->GetField($field, $object->GetFieldOption($field, 'thumb_format')); } else { $url = $object->GetField($field, 'raw_url'); } /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); $path = $file_helper->urlToPath($url); if ( !file_exists($path) ) { exit; } header('Content-Length: ' . filesize($path)); $this->Application->setContentType(kUtil::mimeContentType($path), false); header('Content-Disposition: inline; filename="' . kUtil::removeTempExtension($object->GetDBField($field)) . '"'); readfile($path); } /** * Validates MInput control fields * * @param kEvent $event * @return void * @access protected */ protected function OnValidateMInputFields(kEvent $event) { /** @var MInputHelper $minput_helper */ $minput_helper = $this->Application->recallObject('MInputHelper'); $minput_helper->OnValidateMInputFields($event); } /** * Validates individual object field and returns the result * * @param kEvent $event * @return void * @access protected */ protected function OnValidateField(kEvent $event) { $event->status = kEvent::erSTOP; $field = $this->Application->GetVar('field'); if ( ($this->Application->GetVar('ajax') != 'yes') || !$field ) { return; } /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $items_info = $this->Application->GetVar($event->getPrefixSpecial(true)); if ( !$items_info ) { return; } list ($id, $field_values) = each($items_info); $object->Load($id); $object->SetFieldsFromHash($field_values); $event->setEventParam('form_data', $field_values); $object->setID($id); $response = Array ('status' => 'OK'); $event->CallSubEvent($object->isLoaded() ? 'OnBeforeItemUpdate' : 'OnBeforeItemCreate'); // validate all fields, since "Password_plain" field sets error to "Password" field, which is passed here $error_field = $object->GetFieldOption($field, 'error_field', false, $field); if ( !$object->Validate() && $object->GetErrorPseudo($error_field) ) { $response['status'] = $object->GetErrorMsg($error_field, false); } /** @var AjaxFormHelper $ajax_form_helper */ $ajax_form_helper = $this->Application->recallObject('AjaxFormHelper'); $response['other_errors'] = $ajax_form_helper->getErrorMessages($object); $response['uploader_info'] = $ajax_form_helper->getUploaderInfo($object, array_keys($field_values)); $event->status = kEvent::erSTOP; // since event's OnBefore... events can change this event status echo json_encode($response); } /** * Returns auto-complete values for ajax-dropdown * * @param kEvent $event * @return void * @access protected */ protected function OnSuggestValues(kEvent $event) { $event->status = kEvent::erSTOP; $this->Application->XMLHeader(); $data = $this->getAutoCompleteSuggestions($event, $this->Application->GetVar('cur_value')); echo ''; if ( kUtil::isAssoc($data) ) { foreach ($data as $key => $title) { echo '' . kUtil::escape($title, kUtil::ESCAPE_HTML) . ''; } } else { foreach ($data as $title) { echo '' . kUtil::escape($title, kUtil::ESCAPE_HTML) . ''; } } echo ''; } /** * Returns auto-complete values for jQueryUI.AutoComplete * * @param kEvent $event * @return void * @access protected */ protected function OnSuggestValuesJSON(kEvent $event) { $event->status = kEvent::erSTOP; $data = $this->getAutoCompleteSuggestions($event, $this->Application->GetVar('term')); if ( kUtil::isAssoc($data) ) { $transformed_data = array(); foreach ($data as $key => $title) { $transformed_data[] = array('value' => $key, 'label' => $title); } $data = $transformed_data; } echo json_encode($data); } /** * Prepares a suggestion list based on a given term. * * @param kEvent $event Event. * @param string $term Term. * * @return Array * @access protected */ protected function getAutoCompleteSuggestions(kEvent $event, $term) { /** @var kDBItem $object */ $object = $event->getObject(); $field = $this->Application->GetVar('field'); if ( !$field || !$term || !$object->isField($field) ) { return array(); } $limit = $this->Application->GetVar('limit'); if ( !$limit ) { $limit = 20; } $sql = 'SELECT DISTINCT ' . $field . ' FROM ' . $event->getUnitConfig()->getTableName() . ' WHERE ' . $field . ' LIKE ' . $this->Conn->qstr($term . '%') . ' ORDER BY ' . $field . ' LIMIT 0,' . $limit; return $this->Conn->GetCol($sql); } /** * Enter description here... * * @param kEvent $event * @return void * @access protected */ protected function OnSaveWidths(kEvent $event) { $event->status = kEvent::erSTOP; // $this->Application->setContentType('text/xml'); $picker_helper = new kColumnPickerHelper( $event->getPrefixSpecial(), $this->Application->GetVar('grid_name') ); $picker_helper->saveWidths($this->Application->GetVar('widths')); echo 'OK'; } /** * Called from CSV import script after item fields * are set and validated, but before actual item create/update. * If event status is kEvent::erSUCCESS, line will be imported, * else it will not be imported but added to skipped lines * and displayed in the end of import. * Event status is preset from import script. * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeCSVLineImport(kEvent $event) { // abstract, for hooking } /** * [HOOK] Allows to add cloned subitem to given prefix * * @param kEvent $event * @return void * @access protected */ protected function OnCloneSubItem(kEvent $event) { $sub_item_prefix = $event->Prefix . '-' . preg_replace('/^#/', '', $event->MasterEvent->Prefix); $event->MasterEvent->getUnitConfig()->addClones(Array ( $sub_item_prefix => Array ('ParentPrefix' => $event->Prefix), )); } /** * Returns constrain for priority calculations * * @param kEvent $event * @return void * @see PriorityEventHandler * @access protected */ protected function OnGetConstrainInfo(kEvent $event) { $event->setEventParam('constrain_info', Array ('', '')); } } Index: branches/5.3.x/core/kernel/db/cat_event_handler.php =================================================================== --- branches/5.3.x/core/kernel/db/cat_event_handler.php (revision 16599) +++ branches/5.3.x/core/kernel/db/cat_event_handler.php (revision 16600) @@ -1,3100 +1,3100 @@ Array ('self' => 'add|edit|advanced:import'), 'OnResetSettings' => Array ('self' => 'add|edit|advanced:import'), 'OnBeforeDeleteOriginal' => Array ('self' => 'edit|advanced:approve'), 'OnAfterDeleteOriginal' => Array ('self' => 'edit|advanced:approve'), 'OnCopy' => Array ('self' => true), 'OnDownloadFile' => Array ('self' => 'view'), 'OnCancelAction' => Array ('self' => true), 'OnItemBuild' => Array ('self' => true), 'OnMakeVote' => Array ('self' => true), 'OnReviewHelpful' => Array ('self' => true), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Load item if id is available * * @param kEvent $event * @return void * @access protected */ protected function LoadItem(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $id = $this->getPassedID($event); if ( $object->Load($id) ) { /** @var Params $actions */ $actions = $this->Application->recallObject('kActions'); $actions->Set($event->getPrefixSpecial() . '_id', $object->GetID()); $use_pending_editing = $event->getUnitConfig()->getUsePendingEditing(); if ( $use_pending_editing && $event->Special != 'original' ) { $this->Application->SetVar($event->Prefix . '.original_id', $object->GetDBField('OrgId')); } } else { $object->setID($id); } } /** * Checks user permission to execute given $event * * @param kEvent $event * @return bool * @access public */ public function CheckPermission(kEvent $event) { if ( !$this->Application->isAdmin ) { if ( $event->Name == 'OnSetSortingDirect' ) { // allow sorting on front event without view permission return true; } } if ( $event->Name == 'OnExport' ) { // save category_id before doing export $this->Application->LinkVar('m_cat_id'); } if ( in_array($event->Name, $this->_getMassPermissionEvents()) ) { $items = $this->_getPermissionCheckInfo($event); /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); if ( ($event->Name == 'OnSave') && array_key_exists(0, $items) ) { // adding new item (ID = 0) $perm_value = $perm_helper->AddCheckPermission($items[0]['CategoryId'], $event->Prefix) > 0; } else { // leave only items, that can be edited $ids = Array (); $check_method = in_array($event->Name, Array ('OnMassDelete', 'OnCut')) ? 'DeleteCheckPermission' : 'ModifyCheckPermission'; foreach ($items as $item_id => $item_data) { if ( $perm_helper->$check_method($item_data['CreatedById'], $item_data['CategoryId'], $event->Prefix) > 0 ) { $ids[] = $item_id; } } if ( !$ids ) { // no items left for editing -> no permission return $perm_helper->finalizePermissionCheck($event, false); } $perm_value = true; $event->setEventParam('ids', $ids); // will be used later by "kDBEventHandler::StoreSelectedIDs" method } return $perm_helper->finalizePermissionCheck($event, $perm_value); } $export_events = array('OnSaveSettings', 'OnResetSettings', 'OnExportBegin'); if ( in_array($event->Name, $export_events) || ($event->Special == 'export' && $event->Name == 'OnNew') ) { /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); $perm_value = $this->Application->CheckPermission('in-portal:main_import.view'); return $perm_helper->finalizePermissionCheck($event, $perm_value); } if ( $event->Name == 'OnProcessSelected' ) { if ( $this->Application->RecallVar('dst_field') == 'ImportCategory' ) { // when selecting target import category return $this->Application->CheckPermission('in-portal:main_import.view'); } } return parent::CheckPermission($event); } /** * Returns events, that require item-based (not just event-name based) permission check * * @return Array */ function _getMassPermissionEvents() { - return Array ( - 'OnEdit', 'OnSave', 'OnMassDelete', 'OnMassApprove', + return array( + 'OnStoreSelected', 'OnEdit', 'OnSave', 'OnMassDelete', 'OnMassApprove', 'OnMassDecline', 'OnMassMoveUp', 'OnMassMoveDown', 'OnCut', ); } /** * Returns category item IDs, that require permission checking * * @param kEvent $event * @return string */ function _getPermissionCheckIDs($event) { if ($event->Name == 'OnSave') { $selected_ids = implode(',', $this->getSelectedIDs($event, true)); if (!$selected_ids) { $selected_ids = 0; // when saving newly created item (OnPreCreate -> OnPreSave -> OnSave) } } else { // OnEdit, OnMassDelete events, when items are checked in grid $selected_ids = implode(',', $this->StoreSelectedIDs($event)); } return $selected_ids; } /** * Returns information used in permission checking * * @param kEvent $event * @return Array */ function _getPermissionCheckInfo($event) { /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); // when saving data from temp table to live table check by data from temp table $item_ids = $this->_getPermissionCheckIDs($event); $items = $perm_helper->GetCategoryItemData($event->Prefix, $item_ids, $event->Name == 'OnSave'); if (!$items) { // when item not present in temp table, then permission is not checked, because there are no data in db to check $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); list ($id, $fields_hash) = each($items_info); if (array_key_exists('CategoryId', $fields_hash)) { $item_category = $fields_hash['CategoryId']; } else { $item_category = $this->Application->GetVar('m_cat_id'); } $items[$id] = Array ( 'CreatedById' => $this->Application->RecallVar('use_id'), 'CategoryId' => $item_category, ); } return $items; } /** * Add selected items to clipboard with mode = COPY (CLONE) * * @param kEvent $event * @return void * @access protected */ protected function OnCopy($event) { $this->Application->RemoveVar('clipboard'); /** @var kClipboardHelper $clipboard_helper */ $clipboard_helper = $this->Application->recallObject('ClipboardHelper'); $clipboard_helper->setClipboard($event, 'copy', $this->StoreSelectedIDs($event)); $this->clearSelectedIDs($event); } /** * Add selected items to clipboard with mode = CUT * * @param kEvent $event * @return void * @access protected */ protected function OnCut($event) { $this->Application->RemoveVar('clipboard'); /** @var kClipboardHelper $clipboard_helper */ $clipboard_helper = $this->Application->recallObject('ClipboardHelper'); $clipboard_helper->setClipboard($event, 'cut', $this->StoreSelectedIDs($event)); $this->clearSelectedIDs($event); } /** * Checks permission for OnPaste event * * @param kEvent $event * @return bool */ function _checkPastePermission($event) { /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); $category_id = $this->Application->GetVar('m_cat_id'); if ($perm_helper->AddCheckPermission($category_id, $event->Prefix) == 0) { // no items left for editing -> no permission return $perm_helper->finalizePermissionCheck($event, false); } return true; } /** * Performs category item paste * * @param kEvent $event * @return void * @access protected */ protected function OnPaste($event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) || !$this->_checkPastePermission($event) ) { $event->status = kEvent::erFAIL; return; } $clipboard_data = $event->getEventParam('clipboard_data'); if ( !$clipboard_data['cut'] && !$clipboard_data['copy'] ) { return; } if ( $clipboard_data['copy'] ) { /** @var kTempTablesHandler $temp */ $temp = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $this->Application->SetVar('ResetCatBeforeClone', 1); // used in "kCatDBEventHandler::OnBeforeClone" $temp->CloneItems($event->Prefix, $event->Special, $clipboard_data['copy']); } if ( $clipboard_data['cut'] ) { /** @var kCatDBItem $object */ $object = $this->Application->recallObject($event->getPrefixSpecial() . '.item', $event->Prefix, Array ('skip_autoload' => true)); foreach ($clipboard_data['cut'] as $id) { $object->Load($id); $object->MoveToCat(); } } } /** * Deletes all selected items. * Automatically recurse into sub-items using temp handler, and deletes sub-items * by calling its Delete method if sub-item has AutoDelete set to true in its config file * * @param kEvent $event * @return void * @access protected */ protected function OnMassDelete(kEvent $event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } $ids = $this->StoreSelectedIDs($event); $to_delete = Array (); $recycle_bin = $this->Application->ConfigValue('RecycleBinFolder'); if ( $recycle_bin ) { /** @var CategoriesItem $rb */ $rb = $this->Application->recallObject('c.recycle', NULL, array ('skip_autoload' => true)); $rb->Load($recycle_bin); /** @var kCatDBItem $object */ $object = $this->Application->recallObject($event->Prefix . '.recycleitem', NULL, Array ('skip_autoload' => true)); foreach ($ids as $id) { $object->Load($id); if ( preg_match('/^' . preg_quote($rb->GetDBField('ParentPath'), '/') . '/', $object->GetDBField('ParentPath')) ) { $to_delete[] = $id; continue; } $object->MoveToCat($recycle_bin); } $ids = $to_delete; } /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $event->setEventParam('ids', $ids); $this->customProcessing($event, 'before'); $ids = $event->getEventParam('ids'); if ( $ids ) { $temp_handler->DeleteItems($event->Prefix, $event->Special, $ids); } $this->clearSelectedIDs($event); } /** * Return type clauses for list bulding on front * * @param kEvent $event * @return Array */ function getTypeClauses($event) { $types = $event->getEventParam('types'); $types = $types ? explode(',', $types) : Array (); $except_types = $event->getEventParam('except'); $except_types = $except_types ? explode(',', $except_types) : Array (); $type_clauses = Array(); $user_id = $this->Application->RecallVar('user_id'); $owner_field = $this->getOwnerField($event->Prefix); $type_clauses['my_items']['include'] = '%1$s.'.$owner_field.' = '.$user_id; $type_clauses['my_items']['except'] = '%1$s.'.$owner_field.' <> '.$user_id; $type_clauses['my_items']['having_filter'] = false; $type_clauses['pick']['include'] = '%1$s.EditorsPick = 1 AND '.TABLE_PREFIX.'CategoryItems.PrimaryCat = 1'; $type_clauses['pick']['except'] = '%1$s.EditorsPick! = 1 AND '.TABLE_PREFIX.'CategoryItems.PrimaryCat = 1'; $type_clauses['pick']['having_filter'] = false; $type_clauses['hot']['include'] = '`IsHot` = 1 AND PrimaryCat = 1'; $type_clauses['hot']['except'] = '`IsHot`! = 1 AND PrimaryCat = 1'; $type_clauses['hot']['having_filter'] = true; $type_clauses['pop']['include'] = '`IsPop` = 1 AND PrimaryCat = 1'; $type_clauses['pop']['except'] = '`IsPop`! = 1 AND PrimaryCat = 1'; $type_clauses['pop']['having_filter'] = true; $type_clauses['new']['include'] = '`IsNew` = 1 AND PrimaryCat = 1'; $type_clauses['new']['except'] = '`IsNew`! = 1 AND PrimaryCat = 1'; $type_clauses['new']['having_filter'] = true; $type_clauses['displayed']['include'] = ''; $displayed = $this->Application->GetVar($event->Prefix.'_displayed_ids'); if ($displayed) { $id_field = $event->getUnitConfig()->getIDField(); $type_clauses['displayed']['except'] = '%1$s.'.$id_field.' NOT IN ('.$displayed.')'; } else { $type_clauses['displayed']['except'] = ''; } $type_clauses['displayed']['having_filter'] = false; if (in_array('search', $types) || in_array('search', $except_types)) { $event_mapping = Array ( 'simple' => 'OnSimpleSearch', 'subsearch' => 'OnSubSearch', 'advanced' => 'OnAdvancedSearch' ); $keywords = $event->getEventParam('keyword_string'); $type = $this->Application->GetVar('search_type', 'simple'); if ( $keywords ) { // processing keyword_string param of ListProducts tag $this->Application->SetVar('keywords', $keywords); $type = 'simple'; } $search_event = $event_mapping[$type]; $this->$search_event($event); /** @var kDBList $object */ $object = $event->getObject(); /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); $search_sql = ' FROM ' . $search_helper->getSearchTable() . ' search_result JOIN %1$s ON %1$s.ResourceId = search_result.ResourceId'; $sql = str_replace('FROM %1$s', $search_sql, $object->GetPlainSelectSQL()); $object->SetSelectSQL($sql); $object->addCalculatedField('Relevance', 'search_result.Relevance'); $type_clauses['search']['include'] = 'PrimaryCat = 1 AND ('.TABLE_PREFIX.'Categories.Status = '.STATUS_ACTIVE.')'; $type_clauses['search']['except'] = 'PrimaryCat = 1 AND ('.TABLE_PREFIX.'Categories.Status = '.STATUS_ACTIVE.')'; $type_clauses['search']['having_filter'] = false; } if (in_array('related', $types) || in_array('related', $except_types)) { $related_to = $event->getEventParam('related_to'); if (!$related_to) { $related_prefix = $event->Prefix; } else { $sql = 'SELECT Prefix FROM '.TABLE_PREFIX.'ItemTypes WHERE ItemName = '.$this->Conn->qstr($related_to); $related_prefix = $this->Conn->GetOne($sql); } $rel_table = $this->Application->getUnitConfig('rel')->getTableName(); $item_type = (int)$event->getUnitConfig()->getItemType(); if ($item_type == 0) { trigger_error('ItemType not defined for prefix ' . $event->Prefix . '', E_USER_WARNING); } // process case, then this list is called inside another list $prefix_special = $event->getEventParam('PrefixSpecial'); if (!$prefix_special) { $prefix_special = $this->Application->Parser->GetParam('PrefixSpecial'); } $id = false; if ($prefix_special !== false) { $processed_prefix = $this->Application->processPrefix($prefix_special); if ($processed_prefix['prefix'] == $related_prefix) { // printing related categories within list of items (not on details page) /** @var kDBList $list */ $list = $this->Application->recallObject($prefix_special); $id = $list->GetID(); } } if ($id === false) { // printing related categories for single item (possibly on details page) if ($related_prefix == 'c') { $id = $this->Application->GetVar('m_cat_id'); } else { $id = $this->Application->GetVar($related_prefix . '_id'); } } /** @var kCatDBItem $p_item */ $p_item = $this->Application->recallObject($related_prefix.'.current', NULL, Array('skip_autoload' => true)); $p_item->Load( (int)$id ); $p_resource_id = $p_item->GetDBField('ResourceId'); $sql = 'SELECT SourceId, TargetId FROM '.$rel_table.' WHERE (Enabled = 1) AND ( (Type = 0 AND SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.') OR (Type = 1 AND ( (SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.') OR (TargetId = '.$p_resource_id.' AND SourceType = '.$item_type.') ) ) )'; $related_ids_array = $this->Conn->Query($sql); $related_ids = Array(); foreach ($related_ids_array as $record) { $related_ids[] = $record[ $record['SourceId'] == $p_resource_id ? 'TargetId' : 'SourceId' ]; } if (count($related_ids) > 0) { $type_clauses['related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_ids).') AND PrimaryCat = 1'; $type_clauses['related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_ids).') AND PrimaryCat = 1'; } else { $type_clauses['related']['include'] = '0'; $type_clauses['related']['except'] = '1'; } $type_clauses['related']['having_filter'] = false; } if (in_array('favorites', $types) || in_array('favorites', $except_types)) { $sql = 'SELECT ResourceId FROM ' . $this->Application->getUnitConfig('fav')->getTableName() . ' WHERE PortalUserId = '.$this->Application->RecallVar('user_id'); $favorite_ids = $this->Conn->GetCol($sql); if ($favorite_ids) { $type_clauses['favorites']['include'] = '%1$s.ResourceId IN ('.implode(',', $favorite_ids).') AND PrimaryCat = 1'; $type_clauses['favorites']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $favorite_ids).') AND PrimaryCat = 1'; } else { $type_clauses['favorites']['include'] = 0; $type_clauses['favorites']['except'] = 1; } $type_clauses['favorites']['having_filter'] = false; } return $type_clauses; } /** * Returns SQL clause, that will help to select only data from specified category & it's children * * @param int $category_id * @return string */ function getCategoryLimitClause($category_id) { if (!$category_id) { return false; } $tree_indexes = $this->Application->getTreeIndex($category_id); if (!$tree_indexes) { // id of non-existing category was given return 'FALSE'; } return TABLE_PREFIX.'Categories.TreeLeft BETWEEN '.$tree_indexes['TreeLeft'].' AND '.$tree_indexes['TreeRight']; } /** * Apply any custom changes to list's sql query * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetCustomQuery(kEvent $event) { parent::SetCustomQuery($event); /** @var kCatDBList $object */ $object = $event->getObject(); // add category filter if needed if ($event->Special != 'showall' && $event->Special != 'user') { if ( (string)$event->getEventParam('parent_cat_id') !== '' ) { $parent_cat_id = $event->getEventParam('parent_cat_id'); } else { $parent_cat_id = $this->Application->GetVar('c_id'); if (!$parent_cat_id) { $parent_cat_id = $this->Application->GetVar('m_cat_id'); } if (!$parent_cat_id) { $parent_cat_id = 0; } } if ("$parent_cat_id" == '0') { // replace "0" category with "Content" category id (this way template $parent_cat_id = $this->Application->getBaseCategory(); } if ((string)$parent_cat_id != 'any') { if ($event->getEventParam('recursive')) { $filter_clause = $this->getCategoryLimitClause($parent_cat_id); if ($filter_clause !== false) { $object->addFilter('category_filter', $filter_clause); } $object->addFilter('primary_filter', 'PrimaryCat = 1'); } else { $object->addFilter('category_filter', TABLE_PREFIX.'CategoryItems.CategoryId = '.$parent_cat_id ); } } else { $object->addFilter('primary_filter', 'PrimaryCat = 1'); } } else { $object->addFilter('primary_filter', 'PrimaryCat = 1'); // if using recycle bin don't show items from there $recycle_bin = $this->Application->ConfigValue('RecycleBinFolder'); if ($recycle_bin) { $object->addFilter('recyclebin_filter', TABLE_PREFIX.'CategoryItems.CategoryId <> '.$recycle_bin); } } if ($event->Special == 'user') { $editable_user = $this->Application->GetVar('u_id'); $object->addFilter('owner_filter', '%1$s.'.$this->getOwnerField($event->Prefix).' = '.$editable_user); } $this->applyViewPermissionFilter($object); $types = $event->getEventParam('types'); $this->applyItemStatusFilter($object, $types); $except_types = $event->getEventParam('except'); $type_clauses = $this->getTypeClauses($event); /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); $search_helper->SetComplexFilter($event, $type_clauses, $types, $except_types); } /** * Adds filter, that uses *.VIEW permissions to determine if an item should be shown to a user. * * @param kCatDBList $object Object. * * @return void * @access protected */ protected function applyViewPermissionFilter(kCatDBList $object) { if ( !$this->Application->ConfigValue('CheckViewPermissionsInCatalog') ) { return; } if ( $this->Application->RecallVar('user_id') == USER_ROOT ) { // for "root" CATEGORY.VIEW permission is checked for items lists too $view_perm = 1; } else { // for any real user item list view permission is checked instead of CATEGORY.VIEW /** @var kCountHelper $count_helper */ $count_helper = $this->Application->recallObject('CountHelper'); list ($view_perm, $view_filter) = $count_helper->GetPermissionClause($object->Prefix, 'perm'); $object->addFilter('perm_filter2', $view_filter); } $object->addFilter('perm_filter', 'perm.PermId = ' . $view_perm); } /** * Adds filter that filters out items with non-required statuses * * @param kDBList $object * @param string $types */ function applyItemStatusFilter(&$object, $types) { // Link1 (before modifications) [Status = 1, OrgId = NULL], Link2 (after modifications) [Status = -2, OrgId = Link1_ID] $pending_editing = $object->getUnitConfig()->getUsePendingEditing(); if (!$this->Application->isAdminUser) { $types = explode(',', $types); if (in_array('my_items', $types)) { $allow_statuses = Array (STATUS_ACTIVE, STATUS_PENDING, STATUS_PENDING_EDITING); $object->addFilter('status_filter', '%1$s.Status IN ('.implode(',', $allow_statuses).')'); if ($pending_editing) { $user_id = $this->Application->RecallVar('user_id'); $this->applyPendingEditingFilter($object, $user_id); } } else { $object->addFilter('status_filter', '(%1$s.Status = ' . STATUS_ACTIVE . ') AND (' . TABLE_PREFIX . 'Categories.Status = ' . STATUS_ACTIVE . ')'); if ($pending_editing) { // if category item uses pending editing abilities, then in no cases show pending copies on front $object->addFilter('original_filter', '%1$s.OrgId = 0 OR %1$s.OrgId IS NULL'); } } } else { if ($pending_editing) { $this->applyPendingEditingFilter($object); } } } /** * Adds filter, that removes live items if they have pending editing copies * * @param kDBList $object * @param int $user_id */ function applyPendingEditingFilter(&$object, $user_id = NULL) { $sql = 'SELECT OrgId FROM '.$object->TableName.' WHERE Status = '.STATUS_PENDING_EDITING.' AND OrgId IS NOT NULL'; if (isset($user_id)) { $owner_field = $this->getOwnerField($object->Prefix); $sql .= ' AND '.$owner_field.' = '.$user_id; } $pending_ids = $this->Conn->GetCol($sql); if ($pending_ids) { $object->addFilter('no_original_filter', '%1$s.'.$object->IDField.' NOT IN ('.implode(',', $pending_ids).')'); } } /** * Adds calculates fields for item statuses * * @param kDBItem|kDBList $object * @param kEvent $event * @return void * @access protected */ protected function prepareObject(&$object, kEvent $event) { $this->prepareItemStatuses($event); $object->addCalculatedField('CachedNavbar', 'l' . $this->Application->GetVar('m_lang') . '_CachedNavbar'); if ( $event->Special == 'export' || $event->Special == 'import' ) { /** @var kCatDBItemExportHelper $export_helper */ $export_helper = $this->Application->recallObject('CatItemExportHelper'); $export_helper->prepareExportColumns($event); } } /** * Creates calculated fields for all item statuses based on config settings * * @param kEvent $event */ function prepareItemStatuses($event) { $object = $event->getObject( Array('skip_autoload' => true) ); $property_map = $event->getUnitConfig()->getItemPropertyMappings(); if (!$property_map) { return ; } // new items $object->addCalculatedField('IsNew', ' IF(%1$s.NewItem = 2, IF(%1$s.CreatedOn >= (UNIX_TIMESTAMP() - ' . $this->Application->ConfigValue($property_map['NewDays']) . '*3600*24), 1, 0), %1$s.NewItem )'); // hot items (cache updated every hour) if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $serial_name = $this->Application->incrementCacheSerial($event->Prefix, NULL, false); $hot_limit = $this->Application->getCache($property_map['HotLimit'] . '[%' . $serial_name . '%]'); } else { $hot_limit = $this->Application->getDBCache($property_map['HotLimit']); } if ($hot_limit === false) { $hot_limit = $this->CalculateHotLimit($event); } $object->addCalculatedField('IsHot', ' IF(%1$s.HotItem = 2, IF(%1$s.'.$property_map['ClickField'].' >= '.$hot_limit.', 1, 0), %1$s.HotItem )'); // popular items $object->addCalculatedField('IsPop', ' IF(%1$s.PopItem = 2, IF(%1$s.CachedVotesQty >= ' . $this->Application->ConfigValue($property_map['MinPopVotes']) . ' AND %1$s.CachedRating >= ' . $this->Application->ConfigValue($property_map['MinPopRating']) . ', 1, 0), %1$s.PopItem)'); } /** * Calculates hot limit for current item's table * * @param kEvent $event * @return float * @access protected */ protected function CalculateHotLimit($event) { $config = $event->getUnitConfig(); $property_map = $config->getItemPropertyMappings(); if ( !$property_map ) { return 0.00; } $click_field = $property_map['ClickField']; $last_hot = $this->Application->ConfigValue($property_map['MaxHotNumber']) - 1; $sql = 'SELECT ' . $click_field . ' FROM ' . $config->getTableName() . ' ORDER BY ' . $click_field . ' DESC LIMIT ' . $last_hot . ', 1'; $res = $this->Conn->GetCol($sql); $hot_limit = (double)array_shift($res); if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $serial_name = $this->Application->incrementCacheSerial($event->Prefix, NULL, false); $this->Application->setCache($property_map['HotLimit'] . '[%' . $serial_name . '%]', $hot_limit); } else { $this->Application->setDBCache($property_map['HotLimit'], $hot_limit, 3600); } return $hot_limit; } /** * Moves item to preferred category, updates item hits * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemUpdate(kEvent $event) { parent::OnBeforeItemUpdate($event); /** @var kCatDBItem $object */ $object = $event->getObject(); // update hits field $config = $event->getUnitConfig(); $property_map = $config->getUserProfileMapping(); if ( $property_map ) { $click_field = $property_map['ClickField']; if ( $this->Application->isAdminUser && ($this->Application->GetVar($click_field . '_original') !== false) && floor($this->Application->GetVar($click_field . '_original')) != $object->GetDBField($click_field) ) { $sql = 'SELECT MAX(' . $click_field . ') FROM ' . $config->getTableName() . ' WHERE FLOOR(' . $click_field . ') = ' . $object->GetDBField($click_field); $hits = ($res = $this->Conn->GetOne($sql)) ? $res + 0.000001 : $object->GetDBField($click_field); $object->SetDBField($click_field, $hits); } } // change category $target_category = $object->GetDBField('CategoryId'); if ( $object->GetOriginalField('CategoryId') != $target_category ) { $object->MoveToCat($target_category); } } /** * Occurs after loading item, 'id' parameter * allows to get id of item that was loaded * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemLoad(kEvent $event) { parent::OnAfterItemLoad($event); $special = substr($event->Special, -6); /** @var kCatDBItem $object */ $object = $event->getObject(); if ( $special == 'import' || $special == 'export' ) { $image_data = $object->getPrimaryImageData(); if ( $image_data ) { $thumbnail_image = $image_data[$image_data['LocalThumb'] ? 'ThumbPath' : 'ThumbUrl']; if ( $image_data['SameImages'] ) { $full_image = ''; } else { $full_image = $image_data[$image_data['LocalImage'] ? 'LocalPath' : 'Url']; } $object->SetDBField('ThumbnailImage', $thumbnail_image); $object->SetDBField('FullImage', $full_image); $object->SetDBField('ImageAlt', $image_data['AltName']); } } // substituting pending status value for pending editing if ( $object->HasField('OrgId') && $object->GetDBField('OrgId') > 0 && $object->GetDBField('Status') == -2 ) { $new_options = Array (); $options = $object->GetFieldOption('Status', 'options', false, Array ()); foreach ($options as $key => $val) { if ( $key == 2 ) { $key = -2; } $new_options[$key] = $val; } $object->SetFieldOption('Status', 'options', $new_options); } if ( !$this->Application->isAdmin ) { // linking existing images for item with virtual fields /** @var ImageHelper $image_helper */ $image_helper = $this->Application->recallObject('ImageHelper'); $image_helper->LoadItemImages($object); // linking existing files for item with virtual fields /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); $file_helper->LoadItemFiles($object); } if ( $object->isVirtualField('MoreCategories') ) { // set item's additional categories to virtual field (used in editing) $item_categories = $this->getItemCategories($object->GetDBField('ResourceId')); $object->SetDBField('MoreCategories', $item_categories ? '|' . implode('|', $item_categories) . '|' : ''); } } /** * Occurs after updating item * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemUpdate(kEvent $event) { parent::OnAfterItemUpdate($event); $this->CalculateHotLimit($event); if ( substr($event->Special, -6) == 'import' ) { $this->setCustomExportColumns($event); } /** @var kCatDBItem $object */ $object = $event->getObject(); if ( !$this->Application->isAdmin ) { /** @var ImageHelper $image_helper */ $image_helper = $this->Application->recallObject('ImageHelper'); // process image upload in virtual fields $image_helper->SaveItemImages($object); /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); // process file upload in virtual fields $file_helper->SaveItemFiles($object); if ( $event->Special != '-item' ) { // don't touch categories during cloning $this->processAdditionalCategories($object, 'update'); } } $recycle_bin = $this->Application->ConfigValue('RecycleBinFolder'); if ( $this->Application->isAdminUser && $recycle_bin ) { $sql = 'SELECT CategoryId FROM ' . $this->Application->getUnitConfig('ci')->getTableName() . ' WHERE ItemResourceId = ' . $object->GetDBField('ResourceId') . ' AND PrimaryCat = 1'; $primary_category = $this->Conn->GetOne($sql); if ( $primary_category == $recycle_bin ) { $event->CallSubEvent('OnAfterItemDelete'); } } if ( $object->GetChangedFields() ) { $now = time(); $object->SetDBField('Modified_date', $now); $object->SetDBField('Modified_time', $now); $object->SetDBField('ModifiedById', $this->Application->RecallVar('user_id')); } } /** * Sets values for import process * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemCreate(kEvent $event) { parent::OnAfterItemCreate($event); /** @var kCatDBItem $object */ $object = $event->getObject(); if ( substr($event->Special, -6) == 'import' ) { $this->setCustomExportColumns($event); } $object->assignPrimaryCategory(); if ( !$this->Application->isAdmin ) { /** @var ImageHelper $image_helper */ $image_helper = $this->Application->recallObject('ImageHelper'); // process image upload in virtual fields $image_helper->SaveItemImages($object); /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); // process file upload in virtual fields $file_helper->SaveItemFiles($object); if ( $event->Special != '-item' ) { // don't touch categories during cloning $this->processAdditionalCategories($object, 'create'); } } } /** * Make record to search log * * @param string $keywords * @param int $search_type 0 - simple search, 1 - advanced search */ function saveToSearchLog($keywords, $search_type = 0) { // don't save keywords for each module separately, just one time // static variable can't help here, because each module uses it's own class instance ! if (!$this->Application->GetVar('search_logged')) { $sql = 'UPDATE '.TABLE_PREFIX.'SearchLogs SET Indices = Indices + 1 WHERE Keyword = '.$this->Conn->qstr($keywords).' AND SearchType = '.$search_type; // 0 - simple search, 1 - advanced search $this->Conn->Query($sql); if ($this->Conn->getAffectedRows() == 0) { $fields_hash = Array('Keyword' => $keywords, 'Indices' => 1, 'SearchType' => $search_type); $this->Conn->doInsert($fields_hash, TABLE_PREFIX.'SearchLogs'); } $this->Application->SetVar('search_logged', 1); } } /** * Makes simple search for category items * based on keywords string * * @param kEvent $event */ function OnSimpleSearch($event) { $event->redirect = false; $keywords = $this->Application->unescapeRequestVariable(trim($this->Application->GetVar('keywords'))); /** @var kHTTPQuery $query_object */ $query_object = $this->Application->recallObject('kHTTPQuery'); /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); $search_table = $search_helper->getSearchTable(); $sql = 'SHOW TABLES LIKE "'.$search_table.'"'; if(!isset($query_object->Get['keywords']) && !isset($query_object->Post['keywords']) && $this->Conn->Query($sql)) { return; // used when navigating by pages or changing sorting in search results } if(!$keywords || strlen($keywords) < $this->Application->ConfigValue('Search_MinKeyword_Length')) { $search_helper->ensureEmptySearchTable(); $this->Application->SetVar('keywords_too_short', 1); return; // if no or too short keyword entered, doing nothing } $this->Application->StoreVar('keywords', $keywords); $this->saveToSearchLog($keywords, 0); // 0 - simple search, 1 - advanced search $event->setPseudoClass('_List'); /** @var kDBList $object */ $object = $event->getObject(); $config = $event->getUnitConfig(); $this->Application->SetVar($event->getPrefixSpecial().'_Page', 1); $lang = $this->Application->GetVar('m_lang'); $items_table = $config->getTableName(); $module_name = $this->Application->findModule('Var', $event->Prefix, 'Name'); $sql = 'SELECT * FROM ' . $this->Application->getUnitConfig('confs')->getTableName() . ' WHERE ModuleName = ' . $this->Conn->qstr($module_name) . ' AND SimpleSearch = 1'; $search_config = $this->Conn->Query($sql, 'FieldName'); $field_list = array_keys($search_config); $join_clauses = Array(); // field processing $weight_sum = 0; $alias_counter = 0; $custom_fields = $config->getCustomFields(); if ($custom_fields) { $custom_table = $this->Application->getUnitConfig($event->Prefix . '-cdata')->getTableName(); $join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$items_table.'.ResourceId = custom_data.ResourceId'; } // what field in search config becomes what field in sql (key - new field, value - old field (from searchconfig table)) $search_config_map = Array(); foreach ($field_list as $key => $field) { $local_table = TABLE_PREFIX.$search_config[$field]['TableName']; $weight_sum += $search_config[$field]['Priority']; // counting weight sum; used when making relevance clause // processing multilingual fields if ( !$search_config[$field]['CustomFieldId'] && $object->GetFieldOption($field, 'formatter') == 'kMultiLanguage' ) { $field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field; $field_list[$key] = 'l'.$lang.'_'.$field; if (!isset($search_config[$field]['ForeignField'])) { $field_list[$key.'_primary'] = $local_table.'.'.$field_list[$key.'_primary']; $search_config_map[ $field_list[$key.'_primary'] ] = $field; } } // processing fields from other tables $foreign_field = $search_config[$field]['ForeignField']; if ( $foreign_field ) { $exploded = explode(':', $foreign_field, 2); if ($exploded[0] == 'CALC') { // ignoring having type clauses in simple search unset($field_list[$key]); continue; } else { $multi_lingual = false; if ($exploded[0] == 'MULTI') { $multi_lingual = true; $foreign_field = $exploded[1]; } $exploded = explode('.', $foreign_field); // format: table.field_name $foreign_table = TABLE_PREFIX.$exploded[0]; $alias_counter++; $alias = 't'.$alias_counter; if ($multi_lingual) { $field_list[$key] = $alias.'.'.'l'.$lang.'_'.$exploded[1]; $field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field; $search_config_map[ $field_list[$key] ] = $field; $search_config_map[ $field_list[$key.'_primary'] ] = $field; } else { $field_list[$key] = $alias.'.'.$exploded[1]; $search_config_map[ $field_list[$key] ] = $field; } $join_clause = str_replace('{ForeignTable}', $alias, $search_config[$field]['JoinClause']); $join_clause = str_replace('{LocalTable}', $items_table, $join_clause); $join_clauses[] = ' LEFT JOIN '.$foreign_table.' '.$alias.' ON '.$join_clause; } } else { // processing fields from local table if ($search_config[$field]['CustomFieldId']) { $local_table = 'custom_data'; // search by custom field value on current language $custom_field_id = array_search($field_list[$key], $custom_fields); $field_list[$key] = 'l'.$lang.'_cust_'.$custom_field_id; // search by custom field value on primary language $field_list[$key.'_primary'] = $local_table.'.l'.$this->Application->GetDefaultLanguageId().'_cust_'.$custom_field_id; $search_config_map[ $field_list[$key.'_primary'] ] = $field; } $field_list[$key] = $local_table.'.'.$field_list[$key]; $search_config_map[ $field_list[$key] ] = $field; } } // Keyword string processing. $where_clause = Array (); foreach ($field_list as $field) { if (preg_match('/^' . preg_quote($items_table, '/') . '\.(.*)/', $field, $regs)) { // local real field $filter_data = $search_helper->getSearchClause($object, $regs[1], $keywords, false); if ($filter_data) { $where_clause[] = $filter_data['value']; } } elseif (preg_match('/^custom_data\.(.*)/', $field, $regs)) { $custom_field_name = 'cust_' . $search_config_map[$field]; $filter_data = $search_helper->getSearchClause($object, $custom_field_name, $keywords, false); if ($filter_data) { $where_clause[] = str_replace('`' . $custom_field_name . '`', $field, $filter_data['value']); } } else { $where_clause[] = $search_helper->buildWhereClause($keywords, Array ($field)); } } $where_clause = '((' . implode(') OR (', $where_clause) . '))'; // 2 braces for next clauses, see below! $search_scope = $this->Application->GetVar('search_scope'); if ($search_scope == 'category') { $category_id = $this->Application->GetVar('m_cat_id'); $category_filter = $this->getCategoryLimitClause($category_id); if ($category_filter !== false) { $join_clauses[] = ' LEFT JOIN '.TABLE_PREFIX.'CategoryItems ON '.TABLE_PREFIX.'CategoryItems.ItemResourceId = '.$items_table.'.ResourceId'; $join_clauses[] = ' LEFT JOIN '.TABLE_PREFIX.'Categories ON '.TABLE_PREFIX.'Categories.CategoryId = '.TABLE_PREFIX.'CategoryItems.CategoryId'; $where_clause = '('.$this->getCategoryLimitClause($category_id).') AND '.$where_clause; } } $where_clause = $where_clause . ' AND (' . $items_table . '.Status = ' . STATUS_ACTIVE . ')'; if ($event->MasterEvent && $event->MasterEvent->Name == 'OnListBuild') { $sub_search_ids = $event->MasterEvent->getEventParam('ResultIds'); if ( $sub_search_ids !== false ) { if ( $sub_search_ids ) { $where_clause .= 'AND (' . $items_table . '.ResourceId IN (' . implode(',', $sub_search_ids) . '))'; } else { $where_clause .= 'AND FALSE'; } } } // making relevance clause $positive_words = $search_helper->getPositiveKeywords($keywords); $this->Application->StoreVar('highlight_keywords', serialize($positive_words)); $relevance_parts = Array(); reset($search_config); foreach ($positive_words as $keyword_index => $positive_word) { $positive_word = $search_helper->transformWildcards($positive_word); $positive_words[$keyword_index] = $this->Conn->escape($positive_word); } foreach ($field_list as $field) { if (!array_key_exists($field, $search_config_map)) { $map_key = $search_config_map[$items_table . '.' . $field]; } else { $map_key = $search_config_map[$field]; } $config_elem = $search_config[ $map_key ]; $weight = $config_elem['Priority']; // search by whole words only ([[:<:]] - word boundary) /*$relevance_parts[] = 'IF('.$field.' REGEXP "[[:<:]]('.implode(' ', $positive_words).')[[:>:]]", '.$weight.', 0)'; foreach ($positive_words as $keyword) { $relevance_parts[] = 'IF('.$field.' REGEXP "[[:<:]]('.$keyword.')[[:>:]]", '.$weight.', 0)'; }*/ if ( count($positive_words) > 1 ) { $condition = $field . ' LIKE "%' . implode(' ', $positive_words) . '%"'; $relevance_parts[] = 'IF(' . $condition . ', ' . $weight_sum . ', 0)'; } // search by partial word matches too foreach ( $positive_words as $keyword ) { $relevance_parts[] = 'IF(' . $field . ' LIKE "%' . $keyword . '%", ' . $weight . ', 0)'; } } $relevance_parts = array_unique($relevance_parts); $conf_postfix = $config->getSearchConfigPostfix(); $rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_'.$conf_postfix) / 100; $rel_pop = $this->Application->ConfigValue('SearchRel_Pop_'.$conf_postfix) / 100; $rel_rating = $this->Application->ConfigValue('SearchRel_Rating_'.$conf_postfix) / 100; $relevance_clause = '('.implode(' + ', $relevance_parts).') / '.$weight_sum.' * '.$rel_keywords; if ($rel_pop && $object->isField('Hits')) { $relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop; } if ($rel_rating && $object->isField('CachedRating')) { $relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating; } // building final search query if (!$this->Application->GetVar('do_not_drop_search_table')) { $this->Conn->Query('DROP TABLE IF EXISTS '.$search_table); // erase old search table if clean k4 event $this->Application->SetVar('do_not_drop_search_table', true); } $search_table_exists = $this->Conn->Query('SHOW TABLES LIKE "'.$search_table.'"'); if ($search_table_exists) { $select_intro = 'INSERT INTO '.$search_table.' (Relevance, ItemId, ResourceId, ItemType, EdPick) '; } else { $select_intro = 'CREATE TABLE '.$search_table.' AS '; } $edpick_clause = $config->getFieldByName('EditorsPick') ? $items_table.'.EditorsPick' : '0'; $sql = $select_intro.' SELECT '.$relevance_clause.' AS Relevance, '.$items_table.'.'.$config->getIDField().' AS ItemId, '.$items_table.'.ResourceId, '.$config->getItemType().' AS ItemType, '.$edpick_clause.' AS EdPick FROM '.$object->TableName.' '.implode(' ', $join_clauses).' WHERE '.$where_clause.' GROUP BY '.$items_table.'.'.$config->getIDField().' ORDER BY Relevance DESC'; $this->Conn->Query($sql); if ( !$search_table_exists ) { $sql = 'ALTER TABLE ' . $search_table . ' ADD INDEX (ResourceId), ADD INDEX (Relevance)'; $this->Conn->Query($sql); } } /** * Enter description here... * * @param kEvent $event */ function OnSubSearch($event) { // keep search results from other items after doing a sub-search on current item type $this->Application->SetVar('do_not_drop_search_table', true); /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); $search_table = $search_helper->getSearchTable(); $sql = 'SHOW TABLES LIKE "' . $search_table . '"'; $ids = array(); if ( $this->Conn->Query($sql) ) { $item_type = $event->getUnitConfig()->getItemType(); // 1. get ids to be used as search bounds $sql = 'SELECT DISTINCT ResourceId FROM ' . $search_table . ' WHERE ItemType = ' . $item_type; $ids = $this->Conn->GetCol($sql); // 2. delete previously found ids $sql = 'DELETE FROM ' . $search_table . ' WHERE ItemType = ' . $item_type; $this->Conn->Query($sql); } $event->setEventParam('ResultIds', $ids); $event->CallSubEvent('OnSimpleSearch'); } /** * Enter description here... * * @param kEvent $event * @todo Change all hardcoded Products table & In-Commerce module usage to dynamic usage from item config !!! */ function OnAdvancedSearch($event) { /** @var kHTTPQuery $query_object */ $query_object = $this->Application->recallObject('kHTTPQuery'); if ( !isset($query_object->Post['andor']) ) { // used when navigating by pages or changing sorting in search results return; } $this->Application->RemoveVar('keywords'); $this->Application->RemoveVar('Search_Keywords'); $module_name = $this->Application->findModule('Var', $event->Prefix, 'Name'); $sql = 'SELECT * FROM '.$this->Application->getUnitConfig('confs')->getTableName().' WHERE (ModuleName = '.$this->Conn->qstr($module_name).') AND (AdvancedSearch = 1)'; $search_config = $this->Conn->Query($sql); $lang = $this->Application->GetVar('m_lang'); /** @var kDBList $object */ $object = $event->getObject(); $object->SetPage(1); $config = $event->getUnitConfig(); $items_table = $config->getTableName(); $search_keywords = $this->Application->GetVar('value'); // will not be changed $keywords = $this->Application->GetVar('value'); // will be changed down there $verbs = $this->Application->GetVar('verb'); $glues = $this->Application->GetVar('andor'); $and_conditions = Array(); $or_conditions = Array(); $and_having_conditions = Array(); $or_having_conditions = Array(); $join_clauses = Array(); $highlight_keywords = Array(); $relevance_parts = Array(); $alias_counter = 0; $custom_fields = $config->getCustomFields(); if ($custom_fields) { $custom_table = $this->Application->getUnitConfig($event->Prefix . '-cdata')->getTableName(); $join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$items_table.'.ResourceId = custom_data.ResourceId'; } $search_log = ''; $weight_sum = 0; // processing fields and preparing conditions foreach ($search_config as $record) { $field = $record['FieldName']; $join_clause = ''; $condition_mode = 'WHERE'; // field processing $local_table = TABLE_PREFIX.$record['TableName']; $weight_sum += $record['Priority']; // counting weight sum; used when making relevance clause // processing multilingual fields if ( $object->GetFieldOption($field, 'formatter') == 'kMultiLanguage' ) { $field_name = 'l'.$lang.'_'.$field; } else { $field_name = $field; } // processing fields from other tables $foreign_field = $record['ForeignField']; if ( $foreign_field ) { $exploded = explode(':', $foreign_field, 2); if($exploded[0] == 'CALC') { $user_groups = $this->Application->RecallVar('UserGroups'); $field_name = str_replace('{PREFIX}', TABLE_PREFIX, $exploded[1]); $join_clause = str_replace('{PREFIX}', TABLE_PREFIX, $record['JoinClause']); $join_clause = str_replace('{USER_GROUPS}', $user_groups, $join_clause); $join_clause = ' LEFT JOIN '.$join_clause; $condition_mode = 'HAVING'; } else { $exploded = explode('.', $foreign_field); $foreign_table = TABLE_PREFIX.$exploded[0]; if($record['CustomFieldId']) { $exploded[1] = 'l'.$lang.'_'.$exploded[1]; } $alias_counter++; $alias = 't'.$alias_counter; $field_name = $alias.'.'.$exploded[1]; $join_clause = str_replace('{ForeignTable}', $alias, $record['JoinClause']); $join_clause = str_replace('{LocalTable}', $items_table, $join_clause); if($record['CustomFieldId']) { $join_clause .= ' AND '.$alias.'.CustomFieldId='.$record['CustomFieldId']; } $join_clause = ' LEFT JOIN '.$foreign_table.' '.$alias.' ON '.$join_clause; } } else { // processing fields from local table if ($record['CustomFieldId']) { $local_table = 'custom_data'; $field_name = 'l'.$lang.'_cust_'.array_search($field_name, $custom_fields); } $field_name = $local_table.'.'.$field_name; } $condition = $this->getAdvancedSearchCondition($field_name, $record, $keywords, $verbs, $highlight_keywords); if ($record['CustomFieldId'] && strlen($condition)) { // search in primary value of custom field + value in current language $field_name = $local_table.'.'.'l'.$this->Application->GetDefaultLanguageId().'_cust_'.array_search($field, $custom_fields); $primary_condition = $this->getAdvancedSearchCondition($field_name, $record, $keywords, $verbs, $highlight_keywords); $condition = '('.$condition.' OR '.$primary_condition.')'; } if ($condition) { if ($join_clause) { $join_clauses[] = $join_clause; } $relevance_parts[] = 'IF('.$condition.', '.$record['Priority'].', 0)'; if ($glues[$field] == 1) { // and if ($condition_mode == 'WHERE') { $and_conditions[] = $condition; } else { $and_having_conditions[] = $condition; } } else { // or if ($condition_mode == 'WHERE') { $or_conditions[] = $condition; } else { $or_having_conditions[] = $condition; } } // create search log record $search_log_data = Array('search_config' => $record, 'verb' => getArrayValue($verbs, $field), 'value' => ($record['FieldType'] == 'range') ? $search_keywords[$field.'_from'].'|'.$search_keywords[$field.'_to'] : $search_keywords[$field]); $search_log[] = $this->Application->Phrase('la_Field').' "'.$this->getHuman('Field', $search_log_data).'" '.$this->getHuman('Verb', $search_log_data).' '.$this->Application->Phrase('la_Value').' '.$this->getHuman('Value', $search_log_data).' '.$this->Application->Phrase($glues[$field] == 1 ? 'lu_And' : 'lu_Or'); } } if ($search_log) { $search_log = implode('
', $search_log); $search_log = preg_replace('/(.*) '.preg_quote($this->Application->Phrase('lu_and'), '/').'|'.preg_quote($this->Application->Phrase('lu_or'), '/').'$/is', '\\1', $search_log); $this->saveToSearchLog($search_log, 1); // advanced search } $this->Application->StoreVar('highlight_keywords', serialize($highlight_keywords)); // making relevance clause if($relevance_parts) { $conf_postfix = $config->getSearchConfigPostfix(); $rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_'.$conf_postfix) / 100; $rel_pop = $this->Application->ConfigValue('SearchRel_Pop_'.$conf_postfix) / 100; $rel_rating = $this->Application->ConfigValue('SearchRel_Rating_'.$conf_postfix) / 100; $relevance_clause = '('.implode(' + ', $relevance_parts).') / '.$weight_sum.' * '.$rel_keywords; $relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop; $relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating; } else { $relevance_clause = '0'; } // building having clause if($or_having_conditions) { $and_having_conditions[] = '('.implode(' OR ', $or_having_conditions).')'; } $having_clause = implode(' AND ', $and_having_conditions); $having_clause = $having_clause ? ' HAVING '.$having_clause : ''; // building where clause if($or_conditions) { $and_conditions[] = '('.implode(' OR ', $or_conditions).')'; } // $and_conditions[] = $items_table.'.Status = 1'; $where_clause = implode(' AND ', $and_conditions); if(!$where_clause) { if($having_clause) { $where_clause = '1'; } else { $where_clause = '0'; $this->Application->SetVar('adv_search_error', 1); } } $where_clause .= ' AND '.$items_table.'.Status = 1'; /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); // Building final search query. $search_table = $search_helper->getSearchTable(); $this->Conn->Query('DROP TABLE IF EXISTS '.$search_table); $id_field = $config->getIDField(); $pick_field = $config->getFieldByName('EditorsPick') ? $items_table.'.EditorsPick' : '0'; $sql = ' CREATE TABLE '.$search_table.' SELECT '.$relevance_clause.' AS Relevance, '.$items_table.'.'.$id_field.' AS ItemId, '.$items_table.'.ResourceId AS ResourceId, 11 AS ItemType, '.$pick_field.' AS EdPick FROM '.$items_table.' '.implode(' ', $join_clauses).' WHERE '.$where_clause.' GROUP BY '.$items_table.'.'.$id_field. $having_clause; $this->Conn->Query($sql); } function getAdvancedSearchCondition($field_name, $record, $keywords, $verbs, &$highlight_keywords) { $field = $record['FieldName']; $condition_patterns = Array ( 'any' => '%s LIKE %s', 'contains' => '%s LIKE %s', 'notcontains' => '(NOT (%1$s LIKE %2$s) OR %1$s IS NULL)', 'is' => '%s = %s', 'isnot' => '(%1$s != %2$s OR %1$s IS NULL)' ); $condition = ''; switch ($record['FieldType']) { case 'select': $keywords[$field] = $this->Application->unescapeRequestVariable($keywords[$field]); if ($keywords[$field]) { $condition = sprintf($condition_patterns['is'], $field_name, $this->Conn->qstr( $keywords[$field] )); } break; case 'multiselect': $keywords[$field] = $this->Application->unescapeRequestVariable($keywords[$field]); if ($keywords[$field]) { $condition = Array (); $values = explode('|', substr($keywords[$field], 1, -1)); foreach ($values as $selected_value) { $condition[] = sprintf($condition_patterns['contains'], $field_name, $this->Conn->qstr('%|'.$selected_value.'|%')); } $condition = '('.implode(' OR ', $condition).')'; } break; case 'text': $keywords[$field] = $this->Application->unescapeRequestVariable($keywords[$field]); if (mb_strlen($keywords[$field]) >= $this->Application->ConfigValue('Search_MinKeyword_Length')) { $highlight_keywords[] = $keywords[$field]; if (in_array($verbs[$field], Array('any', 'contains', 'notcontains'))) { $keywords[$field] = '%'.strtr($keywords[$field], Array('%' => '\\%', '_' => '\\_')).'%'; } $condition = sprintf($condition_patterns[$verbs[$field]], $field_name, $this->Conn->qstr( $keywords[$field] )); } break; case 'boolean': if ($keywords[$field] != -1) { $config = $this->getUnitConfig(); $items_table = $config->getTableName(); $property_mappings = $config->getItemPropertyMappings(); switch ($field) { case 'HotItem': $hot_limit_var = getArrayValue($property_mappings, 'HotLimit'); if ($hot_limit_var) { $hot_limit = (int)$this->Application->getDBCache($hot_limit_var); $condition = 'IF('.$items_table.'.HotItem = 2, IF('.$items_table.'.Hits >= '. $hot_limit. ', 1, 0), '.$items_table.'.HotItem) = '.$keywords[$field]; } break; case 'PopItem': $votes2pop_var = getArrayValue($property_mappings, 'VotesToPop'); $rating2pop_var = getArrayValue($property_mappings, 'RatingToPop'); if ($votes2pop_var && $rating2pop_var) { $condition = 'IF('.$items_table.'.PopItem = 2, IF('.$items_table.'.CachedVotesQty >= '. $this->Application->ConfigValue($votes2pop_var). ' AND '.$items_table.'.CachedRating >= '. $this->Application->ConfigValue($rating2pop_var). ', 1, 0), '.$items_table.'.PopItem) = '.$keywords[$field]; } break; case 'NewItem': $new_days_var = getArrayValue($property_mappings, 'NewDays'); if ($new_days_var) { $condition = 'IF('.$items_table.'.NewItem = 2, IF('.$items_table.'.CreatedOn >= (UNIX_TIMESTAMP() - '. $this->Application->ConfigValue($new_days_var). '*3600*24), 1, 0), '.$items_table.'.NewItem) = '.$keywords[$field]; } break; case 'EditorsPick': $condition = $items_table.'.EditorsPick = '.$keywords[$field]; break; } } break; case 'range': $range_conditions = Array(); if ($keywords[$field.'_from'] && !preg_match("/[^0-9]/i", $keywords[$field.'_from'])) { $range_conditions[] = $field_name.' >= '.$keywords[$field.'_from']; } if ($keywords[$field.'_to'] && !preg_match("/[^0-9]/i", $keywords[$field.'_to'])) { $range_conditions[] = $field_name.' <= '.$keywords[$field.'_to']; } if ($range_conditions) { $condition = implode(' AND ', $range_conditions); } break; case 'date': if ($keywords[$field]) { if (in_array($keywords[$field], Array('today', 'yesterday'))) { $current_time = getdate(); $day_begin = mktime(0, 0, 0, $current_time['mon'], $current_time['mday'], $current_time['year']); $time_mapping = Array('today' => $day_begin, 'yesterday' => ($day_begin - 86400)); $min_time = $time_mapping[$keywords[$field]]; } else { $time_mapping = Array ( 'last_week' => 604800, 'last_month' => 2628000, 'last_3_months' => 7884000, 'last_6_months' => 15768000, 'last_year' => 31536000, ); $min_time = time() - $time_mapping[$keywords[$field]]; } $condition = $field_name.' > '.$min_time; } break; } return $condition; } /** * Returns human readable representation of searched data to be placed in search log * @param string $type * @param Array $search_data * @return string * @access protected */ protected function getHuman($type, $search_data) { // all 3 variables are retrieved from $search_data array /** @var Array $search_config */ /** @var string $verb */ /** @var string $value */ $type = ucfirst(strtolower($type)); extract($search_data, EXTR_SKIP); switch ($type) { case 'Field': return $this->Application->Phrase($search_config['DisplayName']); break; case 'Verb': return $verb ? $this->Application->Phrase('lu_advsearch_'.$verb) : ''; break; case 'Value': switch ($search_config['FieldType']) { case 'date': $values = Array(0 => 'lu_comm_Any', 'today' => 'lu_comm_Today', 'yesterday' => 'lu_comm_Yesterday', 'last_week' => 'lu_comm_LastWeek', 'last_month' => 'lu_comm_LastMonth', 'last_3_months' => 'lu_comm_Last3Months', 'last_6_months' => 'lu_comm_Last6Months', 'last_year' => 'lu_comm_LastYear'); $ret = $this->Application->Phrase($values[$value]); break; case 'range': $value = explode('|', $value); return $this->Application->Phrase('lu_comm_From').' "'.$value[0].'" '.$this->Application->Phrase('lu_comm_To').' "'.$value[1].'"'; break; case 'boolean': $values = Array(1 => 'lu_comm_Yes', 0 => 'lu_comm_No', -1 => 'lu_comm_Both'); $ret = $this->Application->Phrase($values[$value]); break; default: $ret = $value; break; } return '"'.$ret.'"'; break; } return ''; } /** * Set's correct page for list based on data provided with event * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetPagination(kEvent $event) { /** @var kDBList $object */ $object = $event->getObject(); // get PerPage (forced -> session -> config -> 10) $object->SetPerPage($this->getPerPage($event)); // main lists on Front-End have special get parameter for page $page = $object->isMainList() ? $this->Application->GetVar('page') : false; if ( !$page ) { // page is given in "env" variable for given prefix $page = $this->Application->GetVar($event->getPrefixSpecial() . '_Page'); } if ( !$page && $event->Special ) { // when not part of env, then variables like "prefix.special_Page" are // replaced (by PHP) with "prefix_special_Page", so check for that too $page = $this->Application->GetVar($event->getPrefixSpecial(true) . '_Page'); } if ( !$object->isMainList() ) { // main lists doesn't use session for page storing $this->Application->StoreVarDefault($event->getPrefixSpecial() . '_Page', 1, true); // true for optional if ( !$page ) { if ( $this->Application->RewriteURLs() ) { // when page not found by prefix+special, then try to search it without special at all $page = $this->Application->GetVar($event->Prefix . '_Page'); if ( !$page ) { // page not found in request -> get from session $page = $this->Application->RecallVar($event->Prefix . '_Page'); } if ( $page ) { // page found in request -> store in session $this->Application->StoreVar($event->getPrefixSpecial() . '_Page', $page, true); //true for optional } } else { // page not found in request -> get from session $page = $this->Application->RecallVar($event->getPrefixSpecial() . '_Page'); } } else { // page found in request -> store in session $this->Application->StoreVar($event->getPrefixSpecial() . '_Page', $page, true); //true for optional } if ( !$event->getEventParam('skip_counting') ) { // when stored page is larger, then maximal list page number // (such case is also processed in kDBList::Query method) $pages = $object->GetTotalPages(); if ( $page > $pages ) { $page = 1; $this->Application->StoreVar($event->getPrefixSpecial() . '_Page', 1, true); } } } $object->SetPage($page); } /* === RELATED TO IMPORT/EXPORT: BEGIN === */ /** * Shows export dialog * * @param kEvent $event * @return void * @access protected */ protected function OnExport(kEvent $event) { $selected_ids = $this->StoreSelectedIDs($event); if ( implode(',', $selected_ids) == '' ) { // K4 fix when no ids found bad selected ids array is formed $selected_ids = false; } $selected_cats_ids = $this->Application->GetVar('export_categories'); $this->Application->StoreVar($event->Prefix . '_export_ids', $selected_ids ? implode(',', $selected_ids) : ''); $this->Application->StoreVar($event->Prefix . '_export_cats_ids', $selected_cats_ids); /** @var kCatDBItemExportHelper $export_helper */ $export_helper = $this->Application->recallObject('CatItemExportHelper'); $redirect_params = Array ( $this->Prefix . '.export_event' => 'OnNew', 'pass' => 'all,' . $this->Prefix . '.export' ); $event->setRedirectParams($redirect_params); } /** * Performs each export step & displays progress percent * * @param kEvent $event */ function OnExportProgress($event) { /** @var kCatDBItemExportHelper $export_object */ $export_object = $this->Application->recallObject('CatItemExportHelper'); $action_method = 'perform'.ucfirst($event->Special); $field_values = $export_object->$action_method($event); // finish code is done from JS now if ($field_values['start_from'] == $field_values['total_records']) { if ($event->Special == 'import') { $this->Application->StoreVar('PermCache_UpdateRequired', 1); $event->SetRedirectParam('m_cat_id', $this->Application->RecallVar('ImportCategory')); $event->SetRedirectParam('anchor', 'tab-' . $event->Prefix); $event->redirect = 'catalog/catalog'; } elseif ($event->Special == 'export') { $event->redirect = $export_object->getModuleName($event) . '/' . $event->Special . '_finish'; $event->SetRedirectParam('pass', 'all'); } return ; } $export_options = $export_object->loadOptions($event); echo $export_options['start_from'] * 100 / $export_options['total_records']; $event->status = kEvent::erSTOP; } /** * Returns specific to each item type columns only * * @param kEvent $event * @return Array * @access protected */ public function getCustomExportColumns(kEvent $event) { return Array ( '__VIRTUAL__ThumbnailImage' => 'ThumbnailImage', '__VIRTUAL__FullImage' => 'FullImage', '__VIRTUAL__ImageAlt' => 'ImageAlt' ); } /** * Sets non standart virtual fields (e.g. to other tables) * * @param kEvent $event */ function setCustomExportColumns($event) { $this->restorePrimaryImage($event); } /** * Create/Update primary image record in info found in imported data * * @param kEvent $event * @return void * @access protected */ protected function restorePrimaryImage($event) { /** @var kCatDBItem $object */ $object = $event->getObject(); if ( !$object->GetDBField('ThumbnailImage') && !$object->GetDBField('FullImage') ) { return ; } $image_data = $object->getPrimaryImageData(); /** @var kDBItem $image */ $image = $this->Application->recallObject('img', NULL, Array ('skip_autoload' => true)); if ( $image_data ) { $image->Load($image_data['ImageId']); } else { $image->Clear(); $image->SetDBField('Name', 'main'); $image->SetDBField('DefaultImg', 1); $image->SetDBField('ResourceId', $object->GetDBField('ResourceId')); } if ( $object->GetDBField('ImageAlt') ) { $image->SetDBField('AltName', $object->GetDBField('ImageAlt')); } if ( $object->GetDBField('ThumbnailImage') ) { $thumbnail_field = $this->isURL($object->GetDBField('ThumbnailImage')) ? 'ThumbUrl' : 'ThumbPath'; $image->SetDBField($thumbnail_field, $object->GetDBField('ThumbnailImage')); $image->SetDBField('LocalThumb', $thumbnail_field == 'ThumbPath' ? 1 : 0); } if ( !$object->GetDBField('FullImage') ) { $image->SetDBField('SameImages', 1); } else { $image->SetDBField('SameImages', 0); $full_field = $this->isURL($object->GetDBField('FullImage')) ? 'Url' : 'LocalPath'; $image->SetDBField($full_field, $object->GetDBField('FullImage')); $image->SetDBField('LocalImage', $full_field == 'LocalPath' ? 1 : 0); } if ( $image->isLoaded() ) { $image->Update(); } else { $image->Create(); } } /** * Detects if image url is specified in a given path (instead of path on disk) * * @param string $path * @return bool * @access protected */ protected function isURL($path) { return preg_match('#(http|https)://(.*)#', $path); } /** * Prepares item for import/export operations * * @param kEvent $event * @return void * @access protected */ protected function OnNew(kEvent $event) { parent::OnNew($event); if ( $event->Special == 'import' || $event->Special == 'export' ) { /** @var kCatDBItemExportHelper $export_helper */ $export_helper = $this->Application->recallObject('CatItemExportHelper'); $export_helper->setRequiredFields($event); } } /** * Process items selected in item_selector * * @param kEvent $event */ function OnProcessSelected($event) { $dst_field = $this->Application->RecallVar('dst_field'); $selected_ids = $this->Application->GetVar('selected_ids'); if ( $dst_field == 'ItemCategory' ) { // Item Edit -> Categories Tab -> New Categories /** @var kCatDBItem $object */ $object = $event->getObject(); $category_ids = explode(',', $selected_ids['c']); foreach ($category_ids as $category_id) { $object->assignToCategory($category_id); } } if ($dst_field == 'ImportCategory') { // Tools -> Import -> Item Import -> Select Import Category $this->Application->StoreVar('ImportCategory', $selected_ids['c']); $event->SetRedirectParam($event->getPrefixSpecial() . '_id', 0); $event->SetRedirectParam($event->getPrefixSpecial() . '_event', 'OnExportBegin'); } $event->SetRedirectParam('opener', 'u'); } /** * Saves Import/Export settings to session * * @param kEvent $event */ function OnSaveSettings($event) { $event->redirect = false; $items_info = $this->Application->GetVar($event->getPrefixSpecial(true)); if ( $items_info ) { list($id, $field_values) = each($items_info); /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $object->setID($id); $object->SetFieldsFromHash($field_values); $event->setEventParam('form_data', $field_values); $field_values['ImportFilename'] = $object->GetDBField('ImportFilename'); //if upload formatter has renamed the file during moving !!! $field_values['ImportSource'] = 2; $field_values['ImportLocalFilename'] = $object->GetDBField('ImportFilename'); $items_info[$id] = $field_values; $this->Application->StoreVar($event->getPrefixSpecial() . '_ItemsInfo', serialize($items_info)); } } /** * Saves Import/Export settings to session * * @param kEvent $event */ function OnResetSettings($event) { $this->Application->StoreVar('ImportCategory', $this->Application->getBaseCategory()); } /** * Cancels item editing * @param kEvent $event * @return void * @todo Used? */ function OnCancelAction($event) { $event->redirect = $this->Application->GetVar('cancel_template'); $event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial()); } /* === RELATED TO IMPORT/EXPORT: END === */ /** * Stores item's owner login into separate field together with id * * @param kEvent $event * @param string $id_field * @param string $cached_field */ function cacheItemOwner($event, $id_field, $cached_field) { /** @var kDBItem $object */ $object = $event->getObject(); $object->SetDBField($cached_field, $object->GetField($id_field)); } /** * Saves edited item into temp table * If there is no id, new item is created in temp table * * @param kEvent $event * @return void * @access protected */ protected function OnPreSave(kEvent $event) { parent::OnPreSave($event); $use_pending_editing = $event->getUnitConfig()->getUsePendingEditing(); if ( $event->status == kEvent::erSUCCESS && $use_pending_editing ) { // decision: clone or not clone /** @var kCatDBItem $object */ $object = $event->getObject(); if ( $object->GetID() == 0 || $object->GetDBField('OrgId') > 0 ) { // new items or cloned items shouldn't be cloned again return ; } /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); $owner_field = $this->getOwnerField($event->Prefix); if ( $perm_helper->ModifyCheckPermission($object->GetDBField($owner_field), $object->GetDBField('CategoryId'), $event->Prefix) == 2 ) { // 1. clone original item /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $cloned_ids = $temp_handler->CloneItems($event->Prefix, $event->Special, Array ($object->GetID()), NULL, NULL, NULL, true); $ci_table = $this->Application->GetTempName(TABLE_PREFIX . 'CategoryItems'); // 2. delete record from CategoryItems (about cloned item) that was automatically created during call of Create method of kCatDBItem $sql = 'SELECT ResourceId FROM ' . $object->TableName . ' WHERE ' . $object->IDField . ' = ' . $cloned_ids[0]; $clone_resource_id = $this->Conn->GetOne($sql); $sql = 'DELETE FROM ' . $ci_table . ' WHERE ItemResourceId = ' . $clone_resource_id . ' AND PrimaryCat = 1'; $this->Conn->Query($sql); // 3. copy main item categoryitems to cloned item $sql = ' INSERT INTO ' . $ci_table . ' (CategoryId, ItemResourceId, PrimaryCat, ItemPrefix, Filename) SELECT CategoryId, ' . $clone_resource_id . ' AS ItemResourceId, PrimaryCat, ItemPrefix, Filename FROM ' . $ci_table . ' WHERE ItemResourceId = ' . $object->GetDBField('ResourceId'); $this->Conn->Query($sql); // 4. put cloned id to OrgId field of item being cloned $sql = 'UPDATE ' . $object->TableName . ' SET OrgId = ' . $object->GetID() . ' WHERE ' . $object->IDField . ' = ' . $cloned_ids[0]; $this->Conn->Query($sql); // 5. substitute id of item being cloned with clone id $this->Application->SetVar($event->getPrefixSpecial() . '_id', $cloned_ids[0]); $selected_ids = $this->getSelectedIDs($event, true); $selected_ids[ array_search($object->GetID(), $selected_ids) ] = $cloned_ids[0]; $this->StoreSelectedIDs($event, $selected_ids); // 6. delete original item from temp table $temp_handler->DeleteItems($event->Prefix, $event->Special, Array ($object->GetID())); } } } /** * Sets item's owner field * * @param kEvent $event * @return void * @access protected */ protected function OnPreCreate(kEvent $event) { parent::OnPreCreate($event); if ( $event->status != kEvent::erSUCCESS ) { return ; } /** @var kDBItem $object */ $object = $event->getObject(); $owner_field = $this->getOwnerField($event->Prefix); $object->SetDBField($owner_field, $this->Application->RecallVar('user_id')); } /** * Occurs before original item of item in pending editing got deleted (for hooking only) * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeDeleteOriginal(kEvent $event) { } /** * Occurs after original item of item in pending editing got deleted (for hooking only) * * @param kEvent $event * @return void * @access protected */ protected function OnAfterDeleteOriginal(kEvent $event) { } /** * Occurs before an item has been cloned * Id of newly created item is passed as event' 'id' param * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeClone(kEvent $event) { parent::OnBeforeClone($event); /** @var kDBItem $object */ $object = $event->getObject(); $object->SetDBField('ResourceId', 0); // this will reset it if ( $this->Application->GetVar('ResetCatBeforeClone') ) { $object->SetDBField('CategoryId', NULL); } } /** * Set status for new category item based on user permission in category * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemCreate(kEvent $event) { parent::OnBeforeItemCreate($event); /** @var kCatDBItem $object */ $object = $event->getObject(); $owner_field = $this->getOwnerField($event->Prefix); // Don't allow creating records on behalf of another user. if ( !$this->Application->isAdminUser && !defined('CRON') ) { $object->SetDBField($owner_field, $object->GetOriginalField($owner_field)); } // Auto-assign records to currently logged-in user. if ( !$object->GetDBField($owner_field) ) { $object->SetDBField($owner_field, $this->Application->RecallVar('user_id')); } if ( !$this->Application->isAdmin ) { $this->setItemStatusByPermission($event); } } /** * Sets category item status based on user permissions (only on Front-end) * * @param kEvent $event */ function setItemStatusByPermission($event) { $use_pending_editing = $event->getUnitConfig()->getUsePendingEditing(); if (!$use_pending_editing) { return ; } /** @var kCatDBItem $object */ $object = $event->getObject(); /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); $primary_category = $object->GetDBField('CategoryId') > 0 ? $object->GetDBField('CategoryId') : $this->Application->GetVar('m_cat_id'); $item_status = $perm_helper->AddCheckPermission($primary_category, $event->Prefix); if ($item_status == STATUS_DISABLED) { $event->status = kEvent::erFAIL; } else { $object->SetDBField('Status', $item_status); } } /** * Creates category item & redirects to confirmation template (front-end only) * * @param kEvent $event * @return void * @access protected */ protected function OnCreate(kEvent $event) { parent::OnCreate($event); $this->SetFrontRedirectTemplate($event, 'suggest'); } /** * Returns item's categories (allows to exclude primary category) * * @param int $resource_id * @param bool $with_primary * @return Array */ function getItemCategories($resource_id, $with_primary = false) { $sql = 'SELECT CategoryId FROM '.TABLE_PREFIX.'CategoryItems WHERE (ItemResourceId = '.$resource_id.')'; if (!$with_primary) { $sql .= ' AND (PrimaryCat = 0)'; } return $this->Conn->GetCol($sql); } /** * Adds new and removes old additional categories from category item * * @param kCatDBItem $object * @param int $mode */ function processAdditionalCategories(&$object, $mode) { if ( !$object->isVirtualField('MoreCategories') ) { // given category item doesn't require such type of processing return ; } $process_categories = $object->GetDBField('MoreCategories'); if ($process_categories === '') { // field was not in submit & have default value (when no categories submitted, then value is null) return ; } if ($mode == 'create') { // prevents first additional category to become primary $object->assignPrimaryCategory(); } $process_categories = $process_categories ? explode('|', substr($process_categories, 1, -1)) : Array (); $existing_categories = $this->getItemCategories($object->GetDBField('ResourceId')); $add_categories = array_diff($process_categories, $existing_categories); foreach ($add_categories as $category_id) { $object->assignToCategory($category_id); } $remove_categories = array_diff($existing_categories, $process_categories); foreach ($remove_categories as $category_id) { $object->removeFromCategory($category_id); } } /** * Creates category item & redirects to confirmation template (front-end only) * * @param kEvent $event * @return void * @access protected */ protected function OnUpdate(kEvent $event) { $use_pending = $event->getUnitConfig()->getUsePendingEditing(); if ($this->Application->isAdminUser || !$use_pending) { parent::OnUpdate($event); $this->SetFrontRedirectTemplate($event, 'modify'); return ; } /** @var kCatDBItem $object */ $object = $event->getObject(Array('skip_autoload' => true)); $items_info = $this->Application->GetVar($event->getPrefixSpecial(true)); if ($items_info) { /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); $owner_field = $this->getOwnerField($event->Prefix); /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); foreach ($items_info as $id => $field_values) { $object->Load($id); $edit_perm = $perm_helper->ModifyCheckPermission($object->GetDBField($owner_field), $object->GetDBField('CategoryId'), $event->Prefix); if ($use_pending && !$object->GetDBField('OrgId') && ($edit_perm == STATUS_PENDING)) { // pending editing enabled + not pending copy -> get/create pending copy & save changes to it $original_id = $object->GetID(); $original_resource_id = $object->GetDBField('ResourceId'); $file_helper->PreserveItemFiles($field_values); $object->Load($original_id, 'OrgId'); if (!$object->isLoaded()) { // 1. user has no pending copy of live item -> clone live item $cloned_ids = $temp_handler->CloneItems($event->Prefix, $event->Special, Array($original_id), NULL, NULL, NULL, true); $object->Load($cloned_ids[0]); $object->SetFieldsFromHash($field_values); $event->setEventParam('form_data', $field_values); // 1a. delete record from CategoryItems (about cloned item) that was automatically created during call of Create method of kCatDBItem $ci_table = $this->Application->getUnitConfig('ci')->getTableName(); $sql = 'DELETE FROM '.$ci_table.' WHERE ItemResourceId = '.$object->GetDBField('ResourceId').' AND PrimaryCat = 1'; $this->Conn->Query($sql); // 1b. copy main item categoryitems to cloned item $sql = 'INSERT INTO '.$ci_table.' (CategoryId, ItemResourceId, PrimaryCat, ItemPrefix, Filename) SELECT CategoryId, '.$object->GetDBField('ResourceId').' AS ItemResourceId, PrimaryCat, ItemPrefix, Filename FROM '.$ci_table.' WHERE ItemResourceId = '.$original_resource_id; $this->Conn->Query($sql); // 1c. put cloned id to OrgId field of item being cloned $object->SetDBField('Status', STATUS_PENDING_EDITING); $object->SetDBField('OrgId', $original_id); } else { // 2. user has pending copy of live item -> just update field values $object->SetFieldsFromHash($field_values); $event->setEventParam('form_data', $field_values); } // update id in request (used for redirect in mod-rewrite mode) $this->Application->SetVar($event->getPrefixSpecial().'_id', $object->GetID()); } else { // 3. already editing pending copy -> just update field values $object->SetFieldsFromHash($field_values); $event->setEventParam('form_data', $field_values); } if ($object->Update()) { $event->status = kEvent::erSUCCESS; } else { $event->status = kEvent::erFAIL; $event->redirect = false; break; } } } $this->SetFrontRedirectTemplate($event, 'modify'); } /** * Sets next template to one required for front-end after adding/modifying item * * @param kEvent $event * @param string $template_key - {suggest,modify} */ function SetFrontRedirectTemplate($event, $template_key) { if ( $this->Application->isAdmin || $event->status != kEvent::erSUCCESS ) { return; } // prepare redirect template /** @var kDBItem $object */ $object = $event->getObject(); $is_active = ($object->GetDBField('Status') == STATUS_ACTIVE); $next_template = $is_active ? 'confirm_template' : 'pending_confirm_template'; $event->redirect = $this->Application->GetVar($template_key . '_' . $next_template); $event->SetRedirectParam('opener', 's'); // send email events $perm_prefix = $event->getUnitConfig()->getPermItemPrefix(); $owner_field = $this->getOwnerField($event->Prefix); $owner_id = $object->GetDBField($owner_field); $send_params = $object->getEmailParams(); switch ( $event->Name ) { case 'OnCreate': $event_suffix = $is_active ? 'ADD' : 'ADD.PENDING'; $this->Application->emailUser($perm_prefix . '.' . $event_suffix, $owner_id, $send_params); $this->Application->emailAdmin($perm_prefix . '.' . $event_suffix, null, $send_params); // there are no ADD.PENDING event for admin :( break; case 'OnUpdate': $event_suffix = $is_active ? 'MODIFY' : 'MODIFY.PENDING'; $user_id = is_numeric($object->GetDBField('ModifiedById')) ? $object->GetDBField('ModifiedById') : $owner_id; $this->Application->emailUser($perm_prefix . '.' . $event_suffix, $user_id, $send_params); $this->Application->emailAdmin($perm_prefix . '.' . $event_suffix, null, $send_params); // there are no ADD.PENDING event for admin :( break; } } /** * Apply same processing to each item being selected in grid * * @param kEvent $event * @return void * @access protected */ protected function iterateItems(kEvent $event) { if ( $event->Name != 'OnMassApprove' && $event->Name != 'OnMassDecline' ) { parent::iterateItems($event); } if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return ; } /** @var kCatDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $ids = $this->StoreSelectedIDs($event); if ( $ids ) { foreach ($ids as $id) { $object->Load($id); switch ( $event->Name ) { case 'OnMassApprove': $object->ApproveChanges(); break; case 'OnMassDecline': $object->DeclineChanges(); break; } } } $this->clearSelectedIDs($event); } /** * Deletes items & preserves clean env * * @param kEvent $event * @return void * @access protected */ protected function OnDelete(kEvent $event) { parent::OnDelete($event); if ( $event->status == kEvent::erSUCCESS && !$this->Application->isAdmin ) { $event->SetRedirectParam('pass', 'm'); $event->SetRedirectParam('m_cat_id', 0); } } /** * Checks, that currently loaded item is allowed for viewing (non permission-based) * * @param kEvent $event * @return bool * @access protected */ protected function checkItemStatus(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); if ( !$object->isLoaded() ) { if ( $event->Special != 'previous' && $event->Special != 'next' ) { $this->_errorNotFound($event); } return true; } $status = $object->GetDBField('Status'); $user_id = $this->Application->RecallVar('user_id'); $owner_field = $this->getOwnerField($event->Prefix); if ( ($status == STATUS_PENDING_EDITING || $status == STATUS_PENDING) && ($object->GetDBField($owner_field) == $user_id) ) { return true; } return $status == STATUS_ACTIVE; } /** * Set's correct sorting for list based on data provided with event * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetSorting(kEvent $event) { if ( !$this->Application->isAdmin ) { $event->setEventParam('same_special', true); } $types = $event->getEventParam('types'); $types = $types ? explode(',', $types) : Array (); if ( in_array('search', $types) ) { $event->setPseudoClass('_List'); /** @var kDBList $object */ $object = $event->getObject(); // 1. no user sorting - sort by relevance $default_sortings = parent::_getDefaultSorting($event); $default_sorting = key($default_sortings['Sorting']) . ',' . current($default_sortings['Sorting']); if ( $object->isMainList() ) { $sort_by = $this->Application->GetVar('sort_by', ''); if ( !$sort_by ) { $this->Application->SetVar('sort_by', 'Relevance,desc|' . $default_sorting); } } else { $sorting_settings = $this->getListSetting($event, 'Sortings'); $sort_by = trim(getArrayValue($sorting_settings, 'Sort1') . ',' . getArrayValue($sorting_settings, 'Sort1_Dir'), ','); if ( !$sort_by ) { $event->setEventParam('sort_by', 'Relevance,desc|' . $default_sorting); } } $this->_removeForcedSortings($event); } parent::SetSorting($event); } /** * Removes forced sortings * * @param kEvent $event */ protected function _removeForcedSortings(kEvent $event) { $config = $event->getUnitConfig(); foreach ($config->getListSortingSpecials() as $special) { $list_sortings = $config->getListSortingsBySpecial($special); unset($list_sortings['ForcedSorting']); $config->setListSortingsBySpecial('', $list_sortings); } } /** * Default sorting in search results only comes from relevance field * * @param kEvent $event * @return Array * @access protected */ protected function _getDefaultSorting(kEvent $event) { $types = $event->getEventParam('types'); $types = $types ? explode(',', $types) : Array (); return in_array('search', $types) ? Array () : parent::_getDefaultSorting($event); } /** * Returns current per-page setting for list * * @param kEvent $event * @return int * @access protected */ protected function getPerPage(kEvent $event) { if ( !$this->Application->isAdmin ) { $event->setEventParam('same_special', true); } return parent::getPerPage($event); } /** * Returns owner field for given prefix * * @param $prefix * @return string * @access protected */ protected function getOwnerField($prefix) { return $this->Application->getUnitConfig($prefix)->getOwnerField('CreatedById'); } /** * Creates virtual image fields for item * * @param kEvent $event * @return void * @access protected */ protected function OnAfterConfigRead(kEvent $event) { parent::OnAfterConfigRead($event); if (defined('IS_INSTALL') && IS_INSTALL) { $this->addViewPermissionJoin($event); return ; } if ( !$this->Application->isAdmin ) { /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); $file_helper->createItemFiles($event->Prefix, true); // create image fields $file_helper->createItemFiles($event->Prefix, false); // create file fields } $this->changeSortings($event)->addViewPermissionJoin($event); // add grids for advanced view (with primary category column) $config = $event->getUnitConfig(); foreach (Array ('Default', 'Radio') as $process_grid) { $grid_data = $config->getGridByName($process_grid); $grid_data['Fields']['CachedNavbar'] = Array ('title' => 'la_col_Path', 'data_block' => 'grid_primary_category_td', 'filter_block' => 'grid_like_filter'); $config->addGrids($grid_data, $process_grid . 'ShowAll'); } // add options for CategoryId field (quick way to select item's primary category) /** @var CategoryHelper $category_helper */ $category_helper = $this->Application->recallObject('CategoryHelper'); $virtual_fields = $config->getVirtualFields(); $virtual_fields['CategoryId']['default'] = (int)$this->Application->GetVar('m_cat_id'); $virtual_fields['CategoryId']['options'] = $category_helper->getStructureTreeAsOptions(); $config->setVirtualFields($virtual_fields); } /** * Changes default sorting according to system settings. * * @param kEvent $event Event. * * @return self * @access protected */ protected function changeSortings(kEvent $event) { $remove_sortings = Array (); $config = $event->getUnitConfig(); if ( !$this->Application->isAdmin ) { // remove Pick sorting on Front-end, when not required $config_mapping = $config->getConfigMapping(Array ()); if ( !isset($config_mapping['ForceEditorPick']) || !$this->Application->ConfigValue($config_mapping['ForceEditorPick']) ) { $remove_sortings[] = 'EditorsPick'; } } else { // remove all forced sortings in Admin Console $remove_sortings = array_merge($remove_sortings, Array ('Priority', 'EditorsPick')); } if ( !$remove_sortings ) { return $this; } foreach ($config->getListSortingSpecials() as $special) { $list_sortings = $config->getListSortingsBySpecial($special); foreach ($remove_sortings as $sorting_field) { unset($list_sortings['ForcedSorting'][$sorting_field]); } $config->setListSortingsBySpecial('', $list_sortings); } return $this; } /** * Adds permission table table JOIN clause only, when advanced catalog view permissions enabled. * * @param kEvent $event Event. * * @return self * @access protected */ protected function addViewPermissionJoin(kEvent $event) { if ( $this->Application->ConfigValue('CheckViewPermissionsInCatalog') ) { $join_clause = 'LEFT JOIN ' . TABLE_PREFIX . 'CategoryPermissionsCache perm ON perm.CategoryId = ' . TABLE_PREFIX . '%3$sCategoryItems.CategoryId'; } else { $join_clause = ''; } $config = $event->getUnitConfig(); foreach ( $config->getListSQLSpecials() as $special ) { $list_sql = str_replace('{PERM_JOIN}', $join_clause, $config->getListSQLsBySpecial($special)); $config->setListSQLsBySpecial($special, $list_sql); } return $this; } /** * Returns file contents associated with item * * @param kEvent $event */ function OnDownloadFile($event) { /** @var kCatDBItem $object */ $object = $event->getObject(); $event->status = kEvent::erSTOP; $field = $this->Application->GetVar('field'); if (!preg_match('/^File([\d]+)/', $field)) { return ; } /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); $filename = $object->GetField($field, 'full_path'); $file_helper->DownloadFile($filename); } /** * Saves user's vote * * @param kEvent $event */ function OnMakeVote($event) { $event->status = kEvent::erSTOP; if ($this->Application->GetVar('ajax') != 'yes') { // this is supposed to call from AJAX only return ; } /** @var RatingHelper $rating_helper */ $rating_helper = $this->Application->recallObject('RatingHelper'); /** @var kCatDBItem $object */ $object = $event->getObject( Array ('skip_autoload' => true) ); $object->Load( $this->Application->GetVar('id') ); echo $rating_helper->makeVote($object); } /** * Marks review as useful * * @param kEvent $event * @return void * @access protected */ protected function OnReviewHelpful($event) { if ( $this->Application->GetVar('ajax') == 'yes' ) { $event->status = kEvent::erSTOP; } $review_id = (int)$this->Application->GetVar('review_id'); if ( !$review_id ) { return; } /** @var SpamHelper $spam_helper */ $spam_helper = $this->Application->recallObject('SpamHelper'); $spam_helper->InitHelper($review_id, 'ReviewHelpful', strtotime('+1 month') - strtotime('now')); $field = (int)$this->Application->GetVar('helpful') ? 'HelpfulCount' : 'NotHelpfulCount'; $review_config = $this->Application->getUnitConfig('rev'); $sql = 'SELECT ' . $field . ' FROM ' . $review_config->getTableName() . ' WHERE ' . $review_config->getIDField() . ' = ' . $review_id; $count = $this->Conn->GetOne($sql); if ( $spam_helper->InSpamControl() ) { if ( $this->Application->GetVar('ajax') == 'yes' ) { echo $count; } return; } $sql = 'UPDATE ' . $review_config->getTableName() . ' SET ' . $field . ' = ' . $field . ' + 1 WHERE ' . $review_config->getIDField() . ' = ' . $review_id; $this->Conn->Query($sql); if ( $this->Conn->getAffectedRows() ) { // db was changed -> review with such ID exists $spam_helper->AddToSpamControl(); } if ( $this->Application->GetVar('ajax') == 'yes' ) { echo $count + 1; } } /** * [HOOK] Allows to add cloned subitem to given prefix * * @param kEvent $event * @return void * @access protected */ protected function OnCloneSubItem(kEvent $event) { parent::OnCloneSubItem($event); if ( $event->MasterEvent->Prefix == 'fav' ) { $master_config = $event->MasterEvent->getUnitConfig(); $clones = $master_config->getClones(); $sub_item_prefix = $event->Prefix . '-' . $event->MasterEvent->Prefix; $clones[$sub_item_prefix]['ParentTableKey'] = 'ResourceId'; $clones[$sub_item_prefix]['ForeignKey'] = 'ResourceId'; $master_config->setClones($clones); } } /** * Set's new unique resource id to user * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemValidate(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $resource_id = $object->GetDBField('ResourceId'); if ( !$resource_id ) { $object->SetDBField('ResourceId', $this->Application->NextResourceId()); } } } Index: branches/5.3.x/core/kernel/application.php =================================================================== --- branches/5.3.x/core/kernel/application.php (revision 16599) +++ branches/5.3.x/core/kernel/application.php (revision 16600) @@ -1,3093 +1,3095 @@ * The class encapsulates the main run-cycle of the script, provide access to all other objects in the framework.
*
* The class is a singleton, which means that there could be only one instance of kApplication in the script.
* This could be guaranteed by NOT calling the class constructor directly, but rather calling kApplication::Instance() method, * which returns an instance of the application. The method guarantees that it will return exactly the same instance for any call.
* See singleton pattern by GOF. */ class kApplication implements kiCacheable { /** * Location of module helper class (used in installator too) */ const MODULE_HELPER_PATH = '/../units/helpers/modules_helper.php'; /** * Is true, when Init method was called already, prevents double initialization * * @var bool */ public $InitDone = false; /** * Holds internal NParser object * * @var NParser * @access public */ public $Parser; /** * Holds parser output buffer * * @var string * @access protected */ protected $HTML = ''; /** * The main Factory used to create * almost any class of kernel and * modules * * @var kFactory * @access protected */ protected $Factory; /** * Template names, that will be used instead of regular templates * * @var Array * @access public */ public $ReplacementTemplates = Array (); /** * Registered routers, that are used during url building and parsing. * * @var array */ public $routers = array(); /** * Reference to debugger * * @var Debugger * @access public */ public $Debugger = null; /** * Holds all phrases used * in code and template * * @var kPhraseCache * @access public */ public $Phrases; /** * Modules table content, key - module name * * @var Array * @access public */ public $ModuleInfo = Array (); /** * Holds DBConnection * * @var IDBConnection * @access public */ public $Conn = null; /** * Reference to event log * * @var Array|kLogger * @access public */ protected $_logger = Array (); // performance needs: /** * Holds a reference to httpquery * * @var kHttpQuery * @access public */ public $HttpQuery = null; /** * Holds a reference to UnitConfigReader * * @var kUnitConfigReader * @access public */ public $UnitConfigReader = null; /** * Holds a reference to Session * * @var Session * @access public */ public $Session = null; /** * Holds a ref to kEventManager * * @var kEventManager * @access public */ public $EventManager = null; /** * Holds a ref to kUrlManager * * @var kUrlManager * @access public */ public $UrlManager = null; /** * Ref for TemplatesCache * * @var TemplatesCache * @access public */ public $TemplatesCache = null; /** * Holds current NParser tag while parsing, can be used in error messages to display template file and line * * @var _BlockTag * @access public */ public $CurrentNTag = null; /** * Object of unit caching class * * @var kCacheManager * @access public */ public $cacheManager = null; /** * Tells, that administrator has authenticated in administrative console * Should be used to manipulate data change OR data restrictions! * * @var bool * @access public */ public $isAdminUser = false; /** * Tells, that admin version of "index.php" was used, nothing more! * Should be used to manipulate data display! * * @var bool * @access public */ public $isAdmin = false; /** * Instance of site domain object * * @var kDBItem * @access public * @todo move away into separate module */ public $siteDomain = null; /** * Prevent kApplication class to be created directly, only via Instance method * * @access private */ private function __construct() { } final private function __clone() {} /** * Returns kApplication instance anywhere in the script. * * This method should be used to get single kApplication object instance anywhere in the * Kernel-based application. The method is guaranteed to return the SAME instance of kApplication. * Anywhere in the script you could write: * * $application =& kApplication::Instance(); * * or in an object: * * $this->Application =& kApplication::Instance(); * * to get the instance of kApplication. Note that we call the Instance method as STATIC - directly from the class. * To use descendant of standard kApplication class in your project you would need to define APPLICATION_CLASS constant * BEFORE calling kApplication::Instance() for the first time. If APPLICATION_CLASS is not defined the method would * create and return default KernelApplication instance. * * Pattern: Singleton * * @static * @return kApplication * @access public */ public static function &Instance() { static $instance = false; if ( !$instance ) { $class = defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication'; $instance = new $class(); } return $instance; } /** * Initializes the Application * * @param string $factory_class * @return bool Was Init actually made now or before * @access public * @see kHTTPQuery * @see Session * @see TemplatesCache */ public function Init($factory_class = 'kFactory') { if ( $this->InitDone ) { return false; } if ( preg_match('/utf-8/i', CHARSET) ) { setlocale(LC_ALL, 'en_US.UTF-8'); mb_internal_encoding('UTF-8'); } $this->isAdmin = kUtil::constOn('ADMIN'); if ( !kUtil::constOn('SKIP_OUT_COMPRESSION') ) { ob_start(); // collect any output from method (other then tags) into buffer } if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) { $this->Debugger->appendMemoryUsage('Application before Init:'); } $this->_logger = new kLogger($this->_logger); $this->Factory = new $factory_class(); $this->registerDefaultClasses(); $system_config = new kSystemConfig(true); $vars = $system_config->getData(); $db_class = isset($vars['Databases']) ? 'kDBLoadBalancer' : ($this->isDebugMode() ? 'kDBConnectionDebug' : 'kDBConnection'); $this->Conn = $this->Factory->makeClass($db_class, Array (SQL_TYPE, Array ($this->_logger, 'handleSQLError'))); $this->Conn->setup($vars); $this->cacheManager = $this->makeClass('kCacheManager'); $this->cacheManager->InitCache(); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Before UnitConfigReader'); } // init config reader and all managers $this->UnitConfigReader = $this->makeClass('kUnitConfigReader'); $this->UnitConfigReader->scanModules(MODULES_PATH); // Will also set routers. $this->registerModuleConstants(); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('After UnitConfigReader'); } define('MOD_REWRITE', $this->ConfigValue('UseModRewrite') && !$this->isAdmin ? 1 : 0); // start processing request $this->HttpQuery = $this->recallObject('kHTTPQuery'); $this->HttpQuery->process(); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed HTTPQuery initial'); } $this->Session = $this->recallObject('Session'); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed Session'); } $this->Session->ValidateExpired(); // needs mod_rewrite url already parsed to keep user at proper template after session expiration if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed HTTPQuery AfterInit'); } $this->cacheManager->LoadApplicationCache(); $site_timezone = $this->ConfigValue('Config_Site_Time'); if ( $site_timezone ) { date_default_timezone_set($site_timezone); } if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Loaded cache and phrases'); } $this->ValidateLogin(); // must be called before AfterConfigRead, because current user should be available there $this->UnitConfigReader->AfterConfigRead(); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed AfterConfigRead'); } if ( $this->GetVar('m_cat_id') === false ) { $this->SetVar('m_cat_id', 0); } if ( !$this->RecallVar('curr_iso') && !(defined('IS_INSTALL') && IS_INSTALL) ) { $this->StoreVar('curr_iso', $this->GetPrimaryCurrency(), true); // true for optional } $visit_id = $this->RecallVar('visit_id'); if ( $visit_id !== false ) { $this->SetVar('visits_id', $visit_id); } if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->profileFinish('kernel4_startup'); } $this->InitDone = true; if ( PHP_SAPI !== 'cli' && !$this->isAdmin ) { $this->HandleEvent(new kEvent('adm:OnStartup')); } return true; } /** * Performs initialization of manager classes, that can be overridden from unit configs * * @return void * @access public * @throws Exception */ public function InitManagers() { if ( $this->InitDone ) { throw new Exception('Duplicate call of ' . __METHOD__, E_USER_ERROR); } $this->UrlManager = $this->makeClass('kUrlManager'); $this->EventManager = $this->makeClass('kEventManager'); $this->Phrases = $this->makeClass('kPhraseCache'); $this->RegisterDefaultBuildEvents(); } /** * Returns module information. Searches module by requested field * * @param string $field * @param mixed $value * @param string $return_field field value to returns, if not specified, then return all fields * @return Array */ public function findModule($field, $value, $return_field = null) { $found = $module_info = false; foreach ($this->ModuleInfo as $module_info) { if ( strtolower($module_info[$field]) == strtolower($value) ) { $found = true; break; } } if ( $found ) { return isset($return_field) ? $module_info[$return_field] : $module_info; } return false; } /** * Refreshes information about loaded modules * * @return void * @access public */ public function refreshModuleInfo() { if ( defined('IS_INSTALL') && IS_INSTALL && !$this->TableFound('Modules', true) ) { $this->registerModuleConstants(); $this->Factory->configureAutoloader(); return; } // use makeClass over recallObject, since used before kApplication initialization during installation /** @var kModulesHelper $modules_helper */ $modules_helper = $this->makeClass('kModulesHelper'); $this->Conn->nextQueryCachable = true; $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'Modules WHERE ' . $modules_helper->getWhereClause() . ' ORDER BY LoadOrder'; $this->ModuleInfo = $this->Conn->Query($sql, 'Name'); $this->registerModuleConstants(); $this->Factory->configureAutoloader(); } /** * Checks if passed language id if valid and sets it to primary otherwise * * @return void * @access public */ public function VerifyLanguageId() { /** @var LanguagesItem $lang */ $lang = $this->recallObject('lang.current'); if ( !$lang->isLoaded() || (!$this->isAdmin && !$lang->GetDBField('Enabled')) ) { if ( !defined('IS_INSTALL') ) { $this->ApplicationDie('Unknown or disabled language'); } } } /** * Checks if passed theme id if valid and sets it to primary otherwise * * @return void * @access public */ public function VerifyThemeId() { if ( $this->isAdmin ) { kUtil::safeDefine('THEMES_PATH', '/core/admin_templates'); return; } $path = $this->GetFrontThemePath(); if ( $path === false ) { $this->ApplicationDie('No Primary Theme Selected or Current Theme is Unknown or Disabled'); } kUtil::safeDefine('THEMES_PATH', $path); } /** * Returns relative path to current front-end theme * * @param bool $force * @return string * @access public */ public function GetFrontThemePath($force = false) { static $path = null; if ( !$force && isset($path) ) { return $path; } /** @var ThemeItem $theme */ $theme = $this->recallObject('theme.current'); if ( !$theme->isLoaded() || !$theme->GetDBField('Enabled') ) { return false; } // assign & then return, since it's static variable $path = '/themes/' . $theme->GetDBField('Name'); return $path; } /** * Returns primary front/admin language id * * @param bool $init * @return int * @access public */ public function GetDefaultLanguageId($init = false) { $cache_key = 'primary_language_info[%LangSerial%]'; $language_info = $this->getCache($cache_key); if ( $language_info === false ) { // cache primary language info first $language_config = $this->getUnitConfig('lang'); $table = $language_config->getTableName(); $id_field = $language_config->getIDField(); $this->Conn->nextQueryCachable = true; $sql = 'SELECT ' . $id_field . ', IF(AdminInterfaceLang, "Admin", "Front") AS LanguageKey FROM ' . $table . ' WHERE (AdminInterfaceLang = 1 OR PrimaryLang = 1) AND (Enabled = 1)'; $language_info = $this->Conn->GetCol($sql, 'LanguageKey'); if ( $language_info !== false ) { $this->setCache($cache_key, $language_info); } } $language_key = ($this->isAdmin && $init) || count($language_info) == 1 ? 'Admin' : 'Front'; if ( array_key_exists($language_key, $language_info) && $language_info[$language_key] > 0 ) { // get from cache return $language_info[$language_key]; } $language_id = $language_info && array_key_exists($language_key, $language_info) ? $language_info[$language_key] : false; if ( !$language_id && defined('IS_INSTALL') && IS_INSTALL ) { $language_id = 1; } return $language_id; } /** * Returns front-end primary theme id (even, when called from admin console) * * @param bool $force_front * @return int * @access public */ public function GetDefaultThemeId($force_front = false) { static $theme_id = 0; if ( $theme_id > 0 ) { return $theme_id; } if ( kUtil::constOn('DBG_FORCE_THEME') ) { $theme_id = DBG_FORCE_THEME; } elseif ( !$force_front && $this->isAdmin ) { $theme_id = 999; } else { $cache_key = 'primary_theme[%ThemeSerial%]'; $theme_id = $this->getCache($cache_key); if ( $theme_id === false ) { $this->Conn->nextQueryCachable = true; $theme_config = $this->getUnitConfig('theme'); $sql = 'SELECT ' . $theme_config->getIDField() . ' FROM ' . $theme_config->getTableName() . ' WHERE (PrimaryTheme = 1) AND (Enabled = 1)'; $theme_id = $this->Conn->GetOne($sql); if ( $theme_id !== false ) { $this->setCache($cache_key, $theme_id); } } } return $theme_id; } /** * Returns site primary currency ISO code * * @return string * @access public * @todo Move into In-Commerce */ public function GetPrimaryCurrency() { $cache_key = 'primary_currency[%CurrSerial%][%SiteDomainSerial%]:' . $this->siteDomainField('DomainId'); $currency_iso = $this->getCache($cache_key); if ( $currency_iso === false ) { if ( $this->prefixRegistred('curr') ) { $this->Conn->nextQueryCachable = true; $currency_id = $this->siteDomainField('PrimaryCurrencyId'); $sql = 'SELECT ISO FROM ' . $this->getUnitConfig('curr')->getTableName() . ' WHERE ' . ($currency_id > 0 ? 'CurrencyId = ' . $currency_id : 'IsPrimary = 1'); $currency_iso = $this->Conn->GetOne($sql); } else { $currency_iso = 'USD'; } $this->setCache($cache_key, $currency_iso); } return $currency_iso; } /** * Returns site domain field. When none of site domains are found false is returned. * * @param string $field * @param bool $formatted * @param string $format * @return mixed * @todo Move into separate module */ public function siteDomainField($field, $formatted = false, $format = null) { if ( $this->isAdmin ) { // don't apply any filtering in administrative console return false; } if ( !$this->siteDomain ) { $this->siteDomain = $this->recallObject('site-domain.current', null, Array ('live_table' => true)); /** @var kDBItem $site_domain */ } if ( $this->siteDomain->isLoaded() ) { return $formatted ? $this->siteDomain->GetField($field, $format) : $this->siteDomain->GetDBField($field); } return false; } /** * Registers classes, that are used before unit configs (where class registration usually is done) are read. * * Called automatically while initializing kApplication. * * @return void * @access public */ public function RegisterDefaultClasses() { // Database. $this->registerClass('IDBConnection', KERNEL_PATH . '/db/i_db_connection.php'); $this->registerClass('kDBConnection', KERNEL_PATH . '/db/db_connection.php'); $this->registerClass('kDBConnectionDebug', KERNEL_PATH . '/db/db_connection.php'); $this->registerClass('kDBLoadBalancer', KERNEL_PATH . '/db/db_load_balancer.php'); // Cache. $this->registerClass('kCacheManager', KERNEL_PATH . '/managers/cache_manager.php'); $this->registerClass('kCache', KERNEL_PATH . '/utility/cache.php'); $this->registerClass('kSubscriptionItem', KERNEL_PATH . '/managers/subscription_manager.php'); // Unit configs. $this->registerClass('kUnitConfigReader', KERNEL_PATH . '/utility/unit_config_reader.php'); $this->registerClass('kUnitConfigCloner', KERNEL_PATH . '/utility/unit_config_cloner.php'); // Urls. $this->registerClass('kUrlManager', KERNEL_PATH . '/managers/url_manager.php'); $this->registerClass('kUrlProcessor', KERNEL_PATH . '/managers/url_processor.php'); $this->registerClass('kPlainUrlProcessor', KERNEL_PATH . '/managers/plain_url_processor.php'); // $this->registerClass('kRewriteUrlProcessor', KERNEL_PATH . '/managers/rewrite_url_processor.php'); // Events. $this->registerClass('kEventManager', KERNEL_PATH . '/event_manager.php'); $this->registerClass('kHookManager', KERNEL_PATH . '/managers/hook_manager.php'); $this->registerClass('kScheduledTaskManager', KERNEL_PATH . '/managers/scheduled_task_manager.php'); $this->registerClass('kRequestManager', KERNEL_PATH . '/managers/request_manager.php'); // Misc. $this->registerClass('kPhraseCache', KERNEL_PATH . '/languages/phrases_cache.php'); $this->registerClass('kModulesHelper', KERNEL_PATH . self::MODULE_HELPER_PATH); $this->registerClass('CKEditor', FULL_PATH . '/core/ckeditor/ckeditor_php5.php'); // Aliased. $this->registerClass('Params', KERNEL_PATH . '/utility/params.php', 'kActions'); $this->registerClass('kMainTagProcessor', KERNEL_PATH . '/processors/main_processor.php', 'm_TagProcessor'); $this->registerClass('kEmailSendingHelper', KERNEL_PATH . '/utility/email_send.php', 'EmailSender'); } /** * Registers default build events * * @return void */ public function RegisterDefaultBuildEvents() { $this->EventManager->registerBuildEvent('kTempTablesHandler', 'OnTempHandlerBuild'); } /** * Returns cached category information by given cache name. All given category * information is recached, when at least one of 4 caches is missing. * * @param int $category_id * @param string $name cache name = {filenames, category_designs, category_tree} * @return string * @access public */ public function getCategoryCache($category_id, $name) { return $this->cacheManager->getCategoryCache($category_id, $name); } /** * Returns caching type (none, memory, temporary) * * @param int $caching_type * @return bool * @access public */ public function isCachingType($caching_type) { return $this->cacheManager->isCachingType($caching_type); } /** * Increments serial based on prefix and it's ID (optional) * * @param string $prefix * @param int $id ID (value of IDField) or ForeignKeyField:ID * @param bool $increment * @return string * @access public */ public function incrementCacheSerial($prefix, $id = null, $increment = true) { return $this->cacheManager->incrementCacheSerial($prefix, $id, $increment); } /** * Returns cached $key value from cache named $cache_name * * @param int $key key name from cache * @param bool $store_locally store data locally after retrieved * @param int $max_rebuild_seconds * @return mixed * @access public */ public function getCache($key, $store_locally = true, $max_rebuild_seconds = 0) { return $this->cacheManager->getCache($key, $store_locally, $max_rebuild_seconds); } /** * Stores new $value in cache with $key name * * @param int $key key name to add to cache * @param mixed $value value of cached record * @param int $expiration when value expires (0 - doesn't expire) * @return bool * @access public */ public function setCache($key, $value, $expiration = 0) { return $this->cacheManager->setCache($key, $value, $expiration); } /** * Stores new $value in cache with $key name (only if it's not there) * * @param int $key key name to add to cache * @param mixed $value value of cached record * @param int $expiration when value expires (0 - doesn't expire) * @return bool * @access public */ public function addCache($key, $value, $expiration = 0) { return $this->cacheManager->addCache($key, $value, $expiration); } /** * Sets rebuilding mode for given cache * * @param string $name * @param int $mode * @param int $max_rebuilding_time * @return bool * @access public */ public function rebuildCache($name, $mode = null, $max_rebuilding_time = 0) { return $this->cacheManager->rebuildCache($name, $mode, $max_rebuilding_time); } /** * Deletes key from cache * * @param string $key * @return void * @access public */ public function deleteCache($key) { $this->cacheManager->deleteCache($key); } /** * Reset's all memory cache at once * * @return void * @access public */ public function resetCache() { $this->cacheManager->resetCache(); } /** * Returns value from database cache * * @param string $name key name * @param int $max_rebuild_seconds * @return mixed * @access public */ public function getDBCache($name, $max_rebuild_seconds = 0) { return $this->cacheManager->getDBCache($name, $max_rebuild_seconds); } /** * Sets value to database cache * * @param string $name * @param mixed $value * @param int|bool $expiration * @return void * @access public */ public function setDBCache($name, $value, $expiration = false) { $this->cacheManager->setDBCache($name, $value, $expiration); } /** * Sets rebuilding mode for given cache * * @param string $name * @param int $mode * @param int $max_rebuilding_time * @return bool * @access public */ public function rebuildDBCache($name, $mode = null, $max_rebuilding_time = 0) { return $this->cacheManager->rebuildDBCache($name, $mode, $max_rebuilding_time); } /** * Deletes key from database cache * * @param string $name * @return void * @access public */ public function deleteDBCache($name) { $this->cacheManager->deleteDBCache($name); } /** * Registers each module specific constants if any found * * @return bool * @access protected */ protected function registerModuleConstants() { if ( file_exists(KERNEL_PATH . '/constants.php') ) { kUtil::includeOnce(KERNEL_PATH . '/constants.php'); } if ( !$this->ModuleInfo ) { return false; } foreach ($this->ModuleInfo as $module_info) { $constants_file = FULL_PATH . '/' . $module_info['Path'] . 'constants.php'; if ( file_exists($constants_file) ) { kUtil::includeOnce($constants_file); } } return true; } /** * Performs redirect to hard maintenance template * * @return void * @access public */ public function redirectToMaintenance() { $maintenance_page = WRITEBALE_BASE . '/maintenance.html'; $query_string = ''; // $this->isAdmin ? '' : '?next_template=' . kUtil::escape($_SERVER['REQUEST_URI'], kUtil::ESCAPE_URL); if ( file_exists(FULL_PATH . $maintenance_page) ) { header('Location: ' . BASE_PATH . $maintenance_page . $query_string); exit; } } /** * Actually runs the parser against current template and stores parsing result * * This method gets 't' variable passed to the script, loads the template given in 't' variable and * parses it. The result is store in {@link $this->HTML} property. * * @return void * @access public */ public function Run() { // process maintenance mode redirect: begin $maintenance_mode = $this->getMaintenanceMode(); if ( $maintenance_mode == MaintenanceMode::HARD ) { $this->redirectToMaintenance(); } elseif ( $maintenance_mode == MaintenanceMode::SOFT ) { $maintenance_template = $this->isAdmin ? 'login' : $this->ConfigValue('SoftMaintenanceTemplate'); if ( $this->GetVar('t') != $maintenance_template ) { $redirect_params = Array (); if ( !$this->isAdmin ) { $redirect_params['next_template'] = $_SERVER['REQUEST_URI']; } $this->Redirect($maintenance_template, $redirect_params); } } // process maintenance mode redirect: end if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) { $this->Debugger->appendMemoryUsage('Application before Run:'); } if ( $this->isAdminUser ) { // for permission checking in events & templates $this->LinkVar('module'); // for common configuration templates $this->LinkVar('module_key'); // for common search templates $this->LinkVar('section'); // for common configuration templates if ( $this->GetVar('m_opener') == 'p' ) { $this->LinkVar('main_prefix'); // window prefix, that opened selector $this->LinkVar('dst_field'); // field to set value choosed in selector } if ( $this->GetVar('ajax') == 'yes' && !$this->GetVar('debug_ajax') ) { // hide debug output from ajax requests automatically kUtil::safeDefine('DBG_SKIP_REPORTING', 1); // safeDefine, because debugger also defines it } } - elseif ( $this->GetVar('admin') ) { - /** @var Session $admin_session */ - $admin_session = $this->recallObject('Session.admin'); - // store Admin Console User's ID to Front-End's session for cross-session permission checks - $this->StoreVar('admin_user_id', (int)$admin_session->RecallVar('user_id')); - - if ( $this->CheckAdminPermission('CATEGORY.MODIFY', 0, $this->getBaseCategory()) ) { - // user can edit cms blocks (when viewing front-end through admin's frame) - $editing_mode = $this->GetVar('editing_mode'); - define('EDITING_MODE', $editing_mode ? $editing_mode : EDITING_MODE_BROWSE); - } - } - - kUtil::safeDefine('EDITING_MODE', ''); // user can't edit anything $this->Phrases->setPhraseEditing(); $this->EventManager->ProcessRequest(); $this->InitParser(); $t = $this->GetVar('render_template', $this->GetVar('t')); if ( !$this->TemplatesCache->TemplateExists($t) && !$this->isAdmin ) { /** @var CategoriesEventHandler $cms_handler */ $cms_handler = $this->recallObject('st_EventHandler'); $t = ltrim($cms_handler->GetDesignTemplate(), '/'); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendHTML('Design Template: ' . $t . '; CategoryID: ' . $this->GetVar('m_cat_id')); } } /*else { $cms_handler->SetCatByTemplate(); }*/ if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) { $this->Debugger->appendMemoryUsage('Application before Parsing:'); } $this->HTML = $this->Parser->Run($t); if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) { $this->Debugger->appendMemoryUsage('Application after Parsing:'); } } /** * Returns console application. * * @return ConsoleApplication */ public function getConsoleApplication() { return $this->makeClass('InPortal\Core\kernel\Console\ConsoleApplication'); } /** * Replaces current rendered template with given one. * * @param string|null $template Template. * * @return void */ public function QuickRun($template) { /** @var kThemesHelper $themes_helper */ $themes_helper = $this->recallObject('ThemesHelper'); // Set Web Request variables to affect link building on template itself. $this->SetVar('t', $template); $this->SetVar('m_cat_id', $themes_helper->getPageByTemplate($template)); $this->SetVar('passed', 'm'); // Replace current page content with given template. $this->InitParser(); $this->Parser->Clear(); $this->HTML = $this->Parser->Run($template); } /** * Performs template parser/cache initialization * * @param bool|string $theme_name * @return void * @access public */ public function InitParser($theme_name = false) { if ( !is_object($this->Parser) ) { $this->Parser = $this->recallObject('NParser'); $this->TemplatesCache = $this->recallObject('TemplatesCache'); } $this->TemplatesCache->forceThemeName = $theme_name; } /** * Send the parser results to browser * * Actually send everything stored in {@link $this->HTML}, to the browser by echoing it. * * @return void * @access public */ public function Done() { $this->HandleEvent(new kEvent('adm:OnBeforeShutdown')); $debug_mode = defined('DEBUG_MODE') && $this->isDebugMode(); if ( $debug_mode ) { if ( kUtil::constOn('DBG_PROFILE_MEMORY') ) { $this->Debugger->appendMemoryUsage('Application before Done:'); } $this->Session->SaveData(); // adds session data to debugger report $this->HTML = ob_get_clean() . $this->HTML . $this->Debugger->printReport(true); } else { // send "Set-Cookie" header before any output is made $this->Session->SetSession(); $this->HTML = ob_get_clean() . $this->HTML; } $this->_outputPage(); $this->cacheManager->UpdateApplicationCache(); if ( !$debug_mode ) { $this->Session->SaveData(); } $this->EventManager->runScheduledTasks(); if ( defined('DBG_CAPTURE_STATISTICS') && DBG_CAPTURE_STATISTICS && !$this->isAdmin ) { $this->_storeStatistics(); } } /** * Outputs generated page content to end-user * * @return void * @access protected */ protected function _outputPage() { $this->setContentType(); ob_start(); if ( $this->UseOutputCompression() ) { $compression_level = $this->ConfigValue('OutputCompressionLevel'); if ( !$compression_level || $compression_level < 0 || $compression_level > 9 ) { $compression_level = 7; } header('Content-Encoding: gzip'); echo gzencode($this->HTML, $compression_level); } else { // when gzip compression not used connection won't be closed early! echo $this->HTML; } // send headers to tell the browser to close the connection header('Content-Length: ' . ob_get_length()); header('Connection: close'); // flush all output ob_end_flush(); if ( ob_get_level() ) { ob_flush(); } flush(); // close current session if ( session_id() ) { session_write_close(); } } /** * Stores script execution statistics to database * * @return void * @access protected */ protected function _storeStatistics() { global $start; $script_time = microtime(true) - $start; $query_statistics = $this->Conn->getQueryStatistics(); // time & count $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'StatisticsCapture WHERE TemplateName = ' . $this->Conn->qstr($this->GetVar('t')); $data = $this->Conn->GetRow($sql); if ( $data ) { $this->_updateAverageStatistics($data, 'ScriptTime', $script_time); $this->_updateAverageStatistics($data, 'SqlTime', $query_statistics['time']); $this->_updateAverageStatistics($data, 'SqlCount', $query_statistics['count']); $data['Hits']++; $data['LastHit'] = time(); $this->Conn->doUpdate($data, TABLE_PREFIX . 'StatisticsCapture', 'StatisticsId = ' . $data['StatisticsId']); } else { $data['ScriptTimeMin'] = $data['ScriptTimeAvg'] = $data['ScriptTimeMax'] = $script_time; $data['SqlTimeMin'] = $data['SqlTimeAvg'] = $data['SqlTimeMax'] = $query_statistics['time']; $data['SqlCountMin'] = $data['SqlCountAvg'] = $data['SqlCountMax'] = $query_statistics['count']; $data['TemplateName'] = $this->GetVar('t'); $data['Hits'] = 1; $data['LastHit'] = time(); $this->Conn->doInsert($data, TABLE_PREFIX . 'StatisticsCapture'); } } /** * Calculates average time for statistics * * @param Array $data * @param string $field_prefix * @param float $current_value * @return void * @access protected */ protected function _updateAverageStatistics(&$data, $field_prefix, $current_value) { $data[$field_prefix . 'Avg'] = (($data['Hits'] * $data[$field_prefix . 'Avg']) + $current_value) / ($data['Hits'] + 1); if ( $current_value < $data[$field_prefix . 'Min'] ) { $data[$field_prefix . 'Min'] = $current_value; } if ( $current_value > $data[$field_prefix . 'Max'] ) { $data[$field_prefix . 'Max'] = $current_value; } } /** * Remembers slow query SQL and execution time into log * * @param string $slow_sql * @param int $time * @return void * @access public */ public function logSlowQuery($slow_sql, $time) { $query_crc = kUtil::crc32($slow_sql); $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'SlowSqlCapture WHERE QueryCrc = ' . $query_crc; $data = $this->Conn->Query($sql, null, true); if ( $data ) { $this->_updateAverageStatistics($data, 'Time', $time); $template_names = explode(',', $data['TemplateNames']); array_push($template_names, $this->GetVar('t')); $data['TemplateNames'] = implode(',', array_unique($template_names)); $data['Hits']++; $data['LastHit'] = time(); $this->Conn->doUpdate($data, TABLE_PREFIX . 'SlowSqlCapture', 'CaptureId = ' . $data['CaptureId']); } else { $data['TimeMin'] = $data['TimeAvg'] = $data['TimeMax'] = $time; $data['SqlQuery'] = $slow_sql; $data['QueryCrc'] = $query_crc; $data['TemplateNames'] = $this->GetVar('t'); $data['Hits'] = 1; $data['LastHit'] = time(); $this->Conn->doInsert($data, TABLE_PREFIX . 'SlowSqlCapture'); } } /** * Checks if output compression options is available * * @return bool * @access protected */ protected function UseOutputCompression() { if ( kUtil::constOn('IS_INSTALL') || kUtil::constOn('DBG_ZEND_PRESENT') || kUtil::constOn('SKIP_OUT_COMPRESSION') ) { return false; } $accept_encoding = isset($_SERVER['HTTP_ACCEPT_ENCODING']) ? $_SERVER['HTTP_ACCEPT_ENCODING'] : ''; return $this->ConfigValue('UseOutputCompression') && function_exists('gzencode') && strstr($accept_encoding, 'gzip'); } // Facade /** * Returns current session id (SID) * * @return int * @access public */ public function GetSID() { /** @var Session $session */ $session = $this->recallObject('Session'); return $session->GetID(); } /** * Destroys current session * * @return void * @access public * @see UserHelper::logoutUser() */ public function DestroySession() { /** @var Session $session */ $session = $this->recallObject('Session'); $session->Destroy(); } /** * Returns variable passed to the script as GET/POST/COOKIE * * @param string $name Name of variable to retrieve * @param mixed $default default value returned in case if variable not present * @return mixed * @access public */ public function GetVar($name, $default = false) { return isset($this->HttpQuery->_Params[$name]) ? $this->HttpQuery->_Params[$name] : $default; } /** * Removes forceful escaping done to the variable upon Front-End submission. * * @param string|array $value Value. * * @return string|array * @see kHttpQuery::StripSlashes * @todo Temporary method for marking problematic places to take care of, when forceful escaping will be removed. */ public function unescapeRequestVariable($value) { return $this->HttpQuery->unescapeRequestVariable($value); } /** * Returns variable passed to the script as $type * * @param string $name Name of variable to retrieve * @param string $type Get/Post/Cookie * @param mixed $default default value returned in case if variable not present * @return mixed * @access public */ public function GetVarDirect($name, $type, $default = false) { // $type = ucfirst($type); $array = $this->HttpQuery->$type; return isset($array[$name]) ? $array[$name] : $default; } /** * Returns ALL variables passed to the script as GET/POST/COOKIE * * @return Array * @access public * @deprecated */ public function GetVars() { return $this->HttpQuery->GetParams(); } /** * Set the variable 'as it was passed to the script through GET/POST/COOKIE' * * This could be useful to set the variable when you know that * other objects would relay on variable passed from GET/POST/COOKIE * or you could use SetVar() / GetVar() pairs to pass the values between different objects.
* * @param string $var Variable name to set * @param mixed $val Variable value * @return void * @access public */ public function SetVar($var,$val) { $this->HttpQuery->Set($var, $val); } /** * Deletes kHTTPQuery variable * * @param string $var * @return void * @todo Think about method name */ public function DeleteVar($var) { $this->HttpQuery->Remove($var); } /** * Deletes Session variable * * @param string $var * @return void * @access public */ public function RemoveVar($var) { $this->Session->RemoveVar($var); } /** * Removes variable from persistent session * * @param string $var * @return void * @access public */ public function RemovePersistentVar($var) { $this->Session->RemovePersistentVar($var); } /** * Restores Session variable to it's db version * * @param string $var * @return void * @access public */ public function RestoreVar($var) { $this->Session->RestoreVar($var); } /** * Returns session variable value * * Return value of $var variable stored in Session. An optional default value could be passed as second parameter. * * @param string $var Variable name * @param mixed $default Default value to return if no $var variable found in session * @return mixed * @access public * @see Session::RecallVar() */ public function RecallVar($var,$default=false) { return $this->Session->RecallVar($var,$default); } /** * Returns variable value from persistent session * * @param string $var * @param mixed $default * @return mixed * @access public * @see Session::RecallPersistentVar() */ public function RecallPersistentVar($var, $default = false) { return $this->Session->RecallPersistentVar($var, $default); } /** * Stores variable $val in session under name $var * * Use this method to store variable in session. Later this variable could be recalled. * * @param string $var Variable name * @param mixed $val Variable value * @param bool $optional * @return void * @access public * @see kApplication::RecallVar() */ public function StoreVar($var, $val, $optional = false) { /** @var Session $session */ $session = $this->recallObject('Session'); $this->Session->StoreVar($var, $val, $optional); } /** * Stores variable to persistent session * * @param string $var * @param mixed $val * @param bool $optional * @return void * @access public */ public function StorePersistentVar($var, $val, $optional = false) { $this->Session->StorePersistentVar($var, $val, $optional); } /** * Stores default value for session variable * * @param string $var * @param string $val * @param bool $optional * @return void * @access public * @see Session::RecallVar() * @see Session::StoreVar() */ public function StoreVarDefault($var, $val, $optional = false) { /** @var Session $session */ $session = $this->recallObject('Session'); $this->Session->StoreVarDefault($var, $val, $optional); } /** * Links HTTP Query variable with session variable * * If variable $var is passed in HTTP Query it is stored in session for later use. If it's not passed it's recalled from session. * This method could be used for making sure that GetVar will return query or session value for given * variable, when query variable should overwrite session (and be stored there for later use).
* This could be used for passing item's ID into popup with multiple tab - * in popup script you just need to call LinkVar('id', 'current_id') before first use of GetVar('id'). * After that you can be sure that GetVar('id') will return passed id or id passed earlier and stored in session * * @param string $var HTTP Query (GPC) variable name * @param mixed $ses_var Session variable name * @param mixed $default Default variable value * @param bool $optional * @return void * @access public */ public function LinkVar($var, $ses_var = null, $default = '', $optional = false) { if ( !isset($ses_var) ) { $ses_var = $var; } if ( $this->GetVar($var) !== false ) { $this->StoreVar($ses_var, $this->GetVar($var), $optional); } else { $this->SetVar($var, $this->RecallVar($ses_var, $default)); } } /** * Returns variable from HTTP Query, or from session if not passed in HTTP Query * * The same as LinkVar, but also returns the variable value taken from HTTP Query if passed, or from session if not passed. * Returns the default value if variable does not exist in session and was not passed in HTTP Query * * @param string $var HTTP Query (GPC) variable name * @param mixed $ses_var Session variable name * @param mixed $default Default variable value * @return mixed * @access public * @see LinkVar */ public function GetLinkedVar($var, $ses_var = null, $default = '') { $this->LinkVar($var, $ses_var, $default); return $this->GetVar($var); } /** * Renders given tag and returns it's output * * @param string $prefix * @param string $tag * @param Array $params * @return mixed * @access public * @see kApplication::InitParser() */ public function ProcessParsedTag($prefix, $tag, $params) { /** @var kDBTagProcessor $processor */ $processor = $this->Parser->GetProcessor($prefix); return $processor->ProcessParsedTag($tag, $params, $prefix); } /** * Return object of IDBConnection interface * * Return object of IDBConnection interface already connected to the project database, configurable in config.php * * @return IDBConnection * @access public */ public function &GetADODBConnection() { return $this->Conn; } /** * Allows to parse given block name or include template * * @param Array $params Parameters to pass to block. Reserved parameter "name" used to specify block name. * @param bool $pass_params Forces to pass current parser params to this block/template. Use with caution, because you can accidentally pass "block_no_data" parameter. * @param bool $as_template * @return string * @access public */ public function ParseBlock($params, $pass_params = false, $as_template = false) { if ( substr($params['name'], 0, 5) == 'html:' ) { return substr($params['name'], 5); } return $this->Parser->ParseBlock($params, $pass_params, $as_template); } /** * Checks, that we have given block defined * * @param string $name * @return bool * @access public */ public function ParserBlockFound($name) { return $this->Parser->blockFound($name); } /** * Allows to include template with a given name and given parameters * * @param Array $params Parameters to pass to template. Reserved parameter "name" used to specify template name. * @return string * @access public */ public function IncludeTemplate($params) { return $this->Parser->IncludeTemplate($params, isset($params['is_silent']) ? 1 : 0); } /** * Return href for template * * @param string $t Template path * @param string $prefix index.php prefix - could be blank, 'admin' * @param Array $params * @param string $index_file * @return string */ public function HREF($t, $prefix = '', $params = Array (), $index_file = null) { return $this->UrlManager->HREF($t, $prefix, $params, $index_file); } /** * Returns theme template filename and it's corresponding page_id based on given seo template * * @param string $seo_template * @return string * @access public */ public function getPhysicalTemplate($seo_template) { return $this->UrlManager->getPhysicalTemplate($seo_template); } /** * Returns seo template by physical template * * @param string $physical_template * @return string * @access public */ public function getSeoTemplate($physical_template) { return $this->UrlManager->getSeoTemplate($physical_template); } /** * Returns template name, that corresponds with given virtual (not physical) page id * * @param int $page_id * @return string|bool * @access public */ public function getVirtualPageTemplate($page_id) { return $this->UrlManager->getVirtualPageTemplate($page_id); } /** * Returns section template for given physical/virtual template * * @param string $template * @param int $theme_id * @return string * @access public */ public function getSectionTemplate($template, $theme_id = null) { return $this->UrlManager->getSectionTemplate($template, $theme_id); } /** * Returns variables with values that should be passed through with this link + variable list * * @param Array $params * @return Array * @access public */ public function getPassThroughVariables(&$params) { return $this->UrlManager->getPassThroughVariables($params); } /** * Builds url * * @param string $t * @param Array $params * @param string $pass * @param bool $pass_events * @param bool $env_var * @return string * @access public */ public function BuildEnv($t, $params, $pass = 'all', $pass_events = false, $env_var = true) { return $this->UrlManager->plain->build($t, $params, $pass, $pass_events, $env_var); } /** * Process QueryString only, create * events, ids, based on config * set template name and sid in * desired application variables. * * @param string $env_var environment string value * @param string $pass_name * @return Array * @access public */ public function processQueryString($env_var, $pass_name = 'passed') { return $this->UrlManager->plain->parse($env_var, $pass_name); } /** * Parses rewrite url and returns parsed variables * * @param string $url * @param string $pass_name * @return Array * @access public */ public function parseRewriteUrl($url, $pass_name = 'passed') { return $this->UrlManager->rewrite->parse($url, $pass_name); } /** * Returns base part of all urls, build on website * * @param string $domain Domain override. * @param boolean $ssl_redirect Redirect to/from SSL. * * @return string */ public function BaseURL($domain = '', $ssl_redirect = null) { if ( $ssl_redirect === null ) { // stay on same encryption level return PROTOCOL . ($domain ? $domain : SERVER_NAME) . (defined('PORT') ? ':' . PORT : '') . BASE_PATH . '/'; } if ( $ssl_redirect ) { // going from http:// to https:// $protocol = 'https://'; $domain = $this->getSecureDomain(); } else { // going from https:// to http:// $protocol = 'http://'; $domain = $this->siteDomainField('DomainName'); if ( $domain === false ) { $domain = DOMAIN; // not on site domain } } return $protocol . $domain . (defined('PORT') ? ':' . PORT : '') . BASE_PATH . '/'; } /** * Returns secure domain. * * @return string */ public function getSecureDomain() { $ret = $this->isAdmin ? $this->ConfigValue('AdminSSLDomain') : false; if ( !$ret ) { $ssl_domain = $this->siteDomainField('SSLDomainName'); return strlen($ssl_domain) ? $ssl_domain : $this->ConfigValue('SSLDomain'); } return $ret; } /** * Redirects user to url, that's build based on given parameters * * @param string $t * @param Array $params * @param string $prefix * @param string $index_file * @return void * @access public */ public function Redirect($t = '', $params = Array(), $prefix = '', $index_file = null) { $js_redirect = getArrayValue($params, 'js_redirect'); if ( $t == '' || $t === true ) { $t = $this->GetVar('t'); } // pass prefixes and special from previous url if ( array_key_exists('js_redirect', $params) ) { unset($params['js_redirect']); } // allows to send custom responce code along with redirect header if ( array_key_exists('response_code', $params) ) { $response_code = (int)$params['response_code']; unset($params['response_code']); } else { $response_code = 302; // Found } if ( !array_key_exists('pass', $params) ) { $params['pass'] = 'all'; } if ( $this->GetVar('ajax') == 'yes' && $t == $this->GetVar('t') ) { // redirects to the same template as current $params['ajax'] = 'yes'; } $location = $this->HREF($t, $prefix, $params, $index_file); if ( $this->isDebugMode() && (kUtil::constOn('DBG_REDIRECT') || (kUtil::constOn('DBG_RAISE_ON_WARNINGS') && $this->Debugger->WarningCount)) ) { $this->Debugger->appendTrace(); echo 'Debug output above !!!
' . "\n"; if ( array_key_exists('HTTP_REFERER', $_SERVER) ) { echo 'Referer: ' . kUtil::escape($_SERVER['HTTP_REFERER'], kUtil::ESCAPE_HTML) . '
' . "\n"; } echo "Proceed to redirect:
{$location}
\n"; } else { if ( $js_redirect ) { // show "redirect" template instead of redirecting, // because "Set-Cookie" header won't work, when "Location" // header is used later $this->SetVar('t', 'redirect'); $this->SetVar('redirect_to', $location); // make all additional parameters available on "redirect" template too foreach ($params as $name => $value) { $this->SetVar($name, $value); } return; } else { if ( $this->GetVar('ajax') == 'yes' && ($t != $this->GetVar('t') || !$this->isSOPSafe($location, $t)) ) { // redirection to other then current template during ajax request OR SOP violation kUtil::safeDefine('DBG_SKIP_REPORTING', 1); echo '#redirect#' . $location; } elseif ( headers_sent() != '' ) { // some output occurred -> redirect using javascript echo ''; } else { // no output before -> redirect using HTTP header // header('HTTP/1.1 302 Found'); header('Location: ' . $location, true, $response_code); } } } // session expiration is called from session initialization, // that's why $this->Session may be not defined here /** @var Session $session */ $session = $this->recallObject('Session'); if ( $this->InitDone ) { // if redirect happened in the middle of application initialization don't call event, // that presumes that application was successfully initialized $this->HandleEvent(new kEvent('adm:OnBeforeShutdown')); } $session->SaveData(); ob_end_flush(); exit; } /** * Determines if real redirect should be made within AJAX request. * * @param string $url Location. * @param string $template Template. * * @return boolean * @link http://en.wikipedia.org/wiki/Same-origin_policy */ protected function isSOPSafe($url, $template) { $parsed_url = parse_url($url); if ( $parsed_url['scheme'] . '://' != PROTOCOL ) { return false; } if ( $parsed_url['host'] != SERVER_NAME ) { return false; } if ( defined('PORT') && isset($parsed_url['port']) && $parsed_url['port'] != PORT ) { return false; } return true; } /** * Returns translation of given label * * @param string $label * @param bool $allow_editing return translation link, when translation is missing on current language * @param bool $use_admin use current Admin Console language to translate phrase * @return string * @access public */ public function Phrase($label, $allow_editing = true, $use_admin = false) { return $this->Phrases->GetPhrase($label, $allow_editing, $use_admin); } /** * Replace language tags in exclamation marks found in text * * @param string $text * @param bool $force_escape force escaping, not escaping of resulting string * @return string * @access public */ public function ReplaceLanguageTags($text, $force_escape = null) { return $this->Phrases->ReplaceLanguageTags($text, $force_escape); } /** * Checks if user is logged in, and creates * user object if so. User object can be recalled * later using "u.current" prefix_special. Also you may * get user id by getting "u.current_id" variable. * * @return void * @access protected */ protected function ValidateLogin() { /** @var Session $session */ $session = $this->recallObject('Session'); $user_id = $session->GetField('PortalUserId'); if ( !$user_id && $user_id != USER_ROOT ) { $user_id = USER_GUEST; } $this->SetVar('u.current_id', $user_id); if ( !$this->isAdmin ) { // needed for "profile edit", "registration" forms ON FRONT ONLY $this->SetVar('u_id', $user_id); } $this->StoreVar('user_id', $user_id, $user_id == USER_GUEST); // storing Guest user_id (-2) is optional $this->isAdminUser = $this->isAdmin && $this->LoggedIn(); if ( $this->GetVar('expired') == 1 ) { // this parameter is set only from admin /** @var UsersItem $user */ $user = $this->recallObject('u.login-admin', null, Array ('form_name' => 'login')); $user->SetError('UserLogin', 'session_expired', 'la_text_sess_expired'); } $this->HandleEvent(new kEvent('adm:OnLogHttpRequest')); if ( $user_id != USER_GUEST ) { // normal users + root $this->LoadPersistentVars(); } $user_timezone = $this->Session->GetField('TimeZone'); if ( $user_timezone ) { date_default_timezone_set($user_timezone); } } /** * Loads current user persistent session data * * @return void * @access public */ public function LoadPersistentVars() { $this->Session->LoadPersistentVars(); } /** * Returns configuration option value by name * * @param string $name * @return string * @access public */ public function ConfigValue($name) { return $this->cacheManager->ConfigValue($name); } /** * Changes value of individual configuration variable (+resets cache, when needed) * * @param string $name * @param string $value * @param bool $local_cache_only * @return string * @access public */ public function SetConfigValue($name, $value, $local_cache_only = false) { return $this->cacheManager->SetConfigValue($name, $value, $local_cache_only); } /** * Allows to process any type of event. * * @param kEvent $event Event. * * @return void */ public function HandleEvent(kEvent $event) { $this->EventManager->HandleEvent($event); } /** * Notifies event subscribers, that event has occured * * @param kEvent $event * @return void */ public function notifyEventSubscribers(kEvent $event) { $this->EventManager->notifySubscribers($event); } /** * Allows to process any type of event * * @param kEvent $event * @return bool * @access public */ public function eventImplemented(kEvent $event) { return $this->EventManager->eventImplemented($event); } /** * Registers new class in the factory * * @param string $real_class Real name of class as in class declaration * @param string $file Filename in what $real_class is declared * @param string $pseudo_class Name under this class object will be accessed using getObject method * @return void * @access public */ public function registerClass($real_class, $file, $pseudo_class = null) { $this->Factory->registerClass($real_class, $file, $pseudo_class); } /** * Unregisters existing class from factory * * @param string $real_class Real name of class as in class declaration * @param string $pseudo_class Name under this class object is accessed using getObject method * @return void * @access public */ public function unregisterClass($real_class, $pseudo_class = null) { $this->Factory->unregisterClass($real_class, $pseudo_class); } /** * Finds the absolute path to the file where the class is defined. * * @param string $class The name of the class. * * @return string|false */ public function findClassFile($class) { return $this->Factory->findClassFile($class); } /** * Add new scheduled task * * @param string $short_name name to be used to store last maintenance run info * @param string $event_string * @param int $run_schedule run schedule like for Cron * @param string $module * @param int $status * @access public */ public function registerScheduledTask($short_name, $event_string, $run_schedule, $module, $status = STATUS_ACTIVE) { $this->EventManager->registerScheduledTask($short_name, $event_string, $run_schedule, $module, $status); } /** * Registers Hook from subprefix event to master prefix event * * Pattern: Observer * * @param string $hook_event * @param string $do_event * @param int $mode * @param bool $conditional * @access public */ public function registerHook($hook_event, $do_event, $mode = hAFTER, $conditional = false) { $this->EventManager->registerHook($hook_event, $do_event, $mode, $conditional); } /** * Registers build event for given pseudo class * * @param string $pseudo_class * @param string $event_name * @access public */ public function registerBuildEvent($pseudo_class, $event_name) { $this->EventManager->registerBuildEvent($pseudo_class, $event_name); } /** * Allows one TagProcessor tag act as other TagProcessor tag * * @param Array $tag_info * @return void * @access public */ public function registerAggregateTag($tag_info) { /** @var kArray $aggregator */ $aggregator = $this->recallObject('TagsAggregator', 'kArray'); $tag_data = Array ( $tag_info['LocalPrefix'], $tag_info['LocalTagName'], getArrayValue($tag_info, 'LocalSpecial') ); $aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], $tag_data); } /** * Returns object using params specified, creates it if is required * * @param string $name * @param string $pseudo_class * @param Array $event_params * @param Array $arguments * @return kBase */ public function recallObject($name, $pseudo_class = null, array $event_params = array(), array $arguments = array()) { /*if ( !$this->hasObject($name) && $this->isDebugMode() && ($name == '_prefix_here_') ) { // first time, when object with "_prefix_here_" prefix is accessed $this->Debugger->appendTrace(); }*/ return $this->Factory->getObject($name, $pseudo_class, $event_params, $arguments); } /** * Returns tag processor for prefix specified * * @param string $prefix * @return kDBTagProcessor * @access public */ public function recallTagProcessor($prefix) { $this->InitParser(); // because kDBTagProcesor is in NParser dependencies return $this->recallObject($prefix . '_TagProcessor'); } /** * Checks if object with prefix passes was already created in factory * * @param string $name object pseudo_class, prefix * @return bool * @access public */ public function hasObject($name) { return $this->Factory->hasObject($name); } /** * Removes object from storage by given name * * @param string $name Object's name in the Storage * @return void * @access public */ public function removeObject($name) { $this->Factory->DestroyObject($name); } /** * Get's real class name for pseudo class, includes class file and creates class instance * * Pattern: Factory Method * * @param string $pseudo_class * @param Array $arguments * @return kBase * @access public */ public function makeClass($pseudo_class, array $arguments = array()) { return $this->Factory->makeClass($pseudo_class, $arguments); } /** * Returns sub-classes of given ancestor class. * * @param string $ancestor_class Ancestor class. * @param boolean $concrete_only Return only non-abstract classes. * * @return array */ public function getSubClasses($ancestor_class, $concrete_only = true) { return $this->Factory->getSubClasses($ancestor_class, $concrete_only); } /** * Checks if application is in debug mode * * @param bool $check_debugger check if kApplication debugger is initialized too, not only for defined DEBUG_MODE constant * @return bool * @author Alex * @access public */ public function isDebugMode($check_debugger = true) { $debug_mode = defined('DEBUG_MODE') && DEBUG_MODE; if ($check_debugger) { $debug_mode = $debug_mode && is_object($this->Debugger); } return $debug_mode; } /** * Apply url rewriting used by mod_rewrite or not * * @param bool|null $ssl Force ssl link to be build * @return bool * @access public */ public function RewriteURLs($ssl = false) { // case #1,#4: // we want to create https link from http mode // we want to create https link from https mode // conditions: ($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL') // case #2,#3: // we want to create http link from https mode // we want to create http link from http mode // conditions: !$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://') $allow_rewriting = (!$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://')) // always allow mod_rewrite for http || // or allow rewriting for redirect TO httpS or when already in httpS (($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL')); // but only if it's allowed in config! return kUtil::constOn('MOD_REWRITE') && $allow_rewriting; } /** * Returns unit config for given prefix * * @param string $prefix * @return kUnitConfig * @access public */ public function getUnitConfig($prefix) { return $this->UnitConfigReader->getUnitConfig($prefix); } /** * Returns true if config exists and is allowed for reading * * @param string $prefix * @return bool */ public function prefixRegistred($prefix) { return $this->UnitConfigReader->prefixRegistered($prefix); } /** * Splits any mixing of prefix and * special into correct ones * * @param string $prefix_special * @return Array * @access public */ public function processPrefix($prefix_special) { return $this->Factory->processPrefix($prefix_special); } /** * Set's new event for $prefix_special * passed * * @param string $prefix_special * @param string $event_name * @return void * @access public */ public function setEvent($prefix_special, $event_name) { $this->EventManager->setEvent($prefix_special, $event_name); } /** * SQL Error Handler * * @param int $code * @param string $msg * @param string $sql * @return bool * @access public * @throws Exception * @deprecated */ public function handleSQLError($code, $msg, $sql) { return $this->_logger->handleSQLError($code, $msg, $sql); } /** * Returns & blocks next ResourceId available in system * * @return int * @access public */ public function NextResourceId() { $table_name = TABLE_PREFIX . 'IdGenerator'; $this->Conn->Query('LOCK TABLES ' . $table_name . ' WRITE'); $this->Conn->Query('UPDATE ' . $table_name . ' SET lastid = lastid + 1'); $id = $this->Conn->GetOne('SELECT lastid FROM ' . $table_name); if ( $id === false ) { $this->Conn->Query('INSERT INTO ' . $table_name . ' (lastid) VALUES (2)'); $id = 2; } $this->Conn->Query('UNLOCK TABLES'); return $id - 1; } /** * Returns genealogical main prefix for sub-table prefix passes * OR prefix, that has been found in REQUEST and some how is parent of passed sub-table prefix * * @param string $current_prefix * @param bool $real_top if set to true will return real topmost prefix, regardless of its id is passed or not * @return string * @access public */ public function GetTopmostPrefix($current_prefix, $real_top = false) { // 1. get genealogical tree of $current_prefix $prefixes = Array ($current_prefix); while ($parent_prefix = $this->getUnitConfig($current_prefix)->getParentPrefix()) { if ( !$this->prefixRegistred($parent_prefix) ) { // stop searching, when parent prefix is not registered break; } $current_prefix = $parent_prefix; array_unshift($prefixes, $current_prefix); } if ( $real_top ) { return $current_prefix; } // 2. find what if parent is passed $passed = explode(',', $this->GetVar('all_passed')); foreach ($prefixes as $a_prefix) { if ( in_array($a_prefix, $passed) ) { return $a_prefix; } } return $current_prefix; } /** * Triggers email event of type Admin * * @param string $email_template_name * @param int $to_user_id * @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text * @return kEvent * @access public */ public function emailAdmin($email_template_name, $to_user_id = null, $send_params = Array ()) { return $this->_email($email_template_name, EmailTemplate::TEMPLATE_TYPE_ADMIN, $to_user_id, $send_params); } /** * Triggers email event of type User * * @param string $email_template_name * @param int $to_user_id * @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text * @return kEvent * @access public */ public function emailUser($email_template_name, $to_user_id = null, $send_params = Array ()) { return $this->_email($email_template_name, EmailTemplate::TEMPLATE_TYPE_FRONTEND, $to_user_id, $send_params); } /** * Triggers general email event * * @param string $email_template_name * @param int $email_template_type (0 for User, 1 for Admin) * @param int $to_user_id * @param array $send_params associative array of direct send params, * possible keys: to_email, to_name, from_email, from_name, message, message_text * @return kEvent * @access protected */ protected function _email($email_template_name, $email_template_type, $to_user_id = null, $send_params = Array ()) { /** @var kEmail $email */ $email = $this->makeClass('kEmail'); if ( !$email->findTemplate($email_template_name, $email_template_type) ) { return false; } $email->setParams($send_params); return $email->send($to_user_id); } /** * Allows to check if user in this session is logged in or not * * @return bool * @access public */ public function LoggedIn() { // no session during expiration process return is_null($this->Session) ? false : $this->Session->LoggedIn(); } /** + * Determines if access permissions should not be checked. + * + * @param integer|null $user_id User ID. + * + * @return boolean + */ + public function permissionCheckingDisabled($user_id = null) + { + if ( !isset($user_id) ) { + $user_id = $this->RecallVar('user_id'); + } + + return $user_id == USER_ROOT; + } + + /** * Check current user permissions based on it's group permissions in specified category * * @param string $name permission name * @param int $cat_id category id, current used if not specified * @param int $type permission type {1 - system, 0 - per category} * @return int * @access public */ public function CheckPermission($name, $type = 1, $cat_id = null) { /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->recallObject('PermissionsHelper'); return $perm_helper->CheckPermission($name, $type, $cat_id); } /** * Check current admin permissions based on it's group permissions in specified category * * @param string $name permission name * @param int $cat_id category id, current used if not specified * @param int $type permission type {1 - system, 0 - per category} * @return int * @access public */ public function CheckAdminPermission($name, $type = 1, $cat_id = null) { /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->recallObject('PermissionsHelper'); return $perm_helper->CheckAdminPermission($name, $type, $cat_id); } /** * Set's any field of current visit * * @param string $field * @param mixed $value * @return void * @access public * @todo move to separate module */ public function setVisitField($field, $value) { if ( $this->isAdmin || !$this->ConfigValue('UseVisitorTracking') ) { // admin logins are not registered in visits list return; } /** @var kDBItem $visit */ $visit = $this->recallObject('visits', null, Array ('raise_warnings' => 0)); if ( $visit->isLoaded() ) { $visit->SetDBField($field, $value); $visit->Update(); } } /** * Allows to check if in-portal is installed * * @return bool * @access public */ public function isInstalled() { return $this->InitDone && (count($this->ModuleInfo) > 0); } /** * Allows to determine if module is installed & enabled * * @param string $module_name * @return bool * @access public */ public function isModuleEnabled($module_name) { return $this->findModule('Name', $module_name) !== false; } /** * Returns Window ID of passed prefix main prefix (in edit mode) * * @param string $prefix * @return int * @access public */ public function GetTopmostWid($prefix) { $top_prefix = $this->GetTopmostPrefix($prefix); $mode = $this->GetVar($top_prefix . '_mode'); return $mode != '' ? substr($mode, 1) : ''; } /** * Get temp table name * * @param string $table * @param mixed $wid * @return string * @access public */ public function GetTempName($table, $wid = '') { return $this->GetTempTablePrefix($wid) . $table; } /** * Builds temporary table prefix based on given window id * * @param string $wid * @return string * @access public */ public function GetTempTablePrefix($wid = '') { if ( preg_match('/prefix:(.*)/', $wid, $regs) ) { $wid = $this->GetTopmostWid($regs[1]); } return TABLE_PREFIX . 'ses_' . $this->GetSID() . ($wid ? '_' . $wid : '') . '_edit_'; } /** * Checks if given table is a temporary table * * @param string $table * @return bool * @access public */ public function IsTempTable($table) { static $cache = Array (); if ( !array_key_exists($table, $cache) ) { $cache[$table] = preg_match('/' . TABLE_PREFIX . 'ses_' . $this->GetSID() . '(_[\d]+){0,1}_edit_(.*)/', $table); } return (bool)$cache[$table]; } /** * Checks, that given prefix is in temp mode * * @param string $prefix * @param string $special * @return bool * @access public */ public function IsTempMode($prefix, $special = '') { $top_prefix = $this->GetTopmostPrefix($prefix); $var_names = Array ( $top_prefix, rtrim($top_prefix . '_' . $special, '_'), // from post rtrim($top_prefix . '.' . $special, '.'), // assembled locally ); $var_names = array_unique($var_names); $temp_mode = false; foreach ($var_names as $var_name) { $value = $this->GetVar($var_name . '_mode'); if ( $value && (substr($value, 0, 1) == 't') ) { $temp_mode = true; break; } } return $temp_mode; } /** * Return live table name based on temp table name * * @param string $temp_table * @return string */ public function GetLiveName($temp_table) { if ( preg_match('/' . TABLE_PREFIX . 'ses_' . $this->GetSID() . '(_[\d]+){0,1}_edit_(.*)/', $temp_table, $rets) ) { // cut wid from table end if any return $rets[2]; } else { return $temp_table; } } /** * Stops processing of user request and displays given message * * @param string $message * @access public */ public function ApplicationDie($message = '') { while ( ob_get_level() ) { ob_end_clean(); } if ( $this->isDebugMode() ) { $message .= $this->Debugger->printReport(true); } $this->HTML = $message; $this->_outputPage(); } /** * Returns comma-separated list of groups from given user * * @param int $user_id * @return string */ public function getUserGroups($user_id) { switch ($user_id) { case USER_ROOT: $user_groups = $this->ConfigValue('User_LoggedInGroup'); break; case USER_GUEST: $user_groups = $this->ConfigValue('User_LoggedInGroup') . ',' . $this->ConfigValue('User_GuestGroup'); break; default: $sql = 'SELECT GroupId FROM ' . TABLE_PREFIX . 'UserGroupRelations WHERE PortalUserId = ' . (int)$user_id; $res = $this->Conn->GetCol($sql); $user_groups = Array ($this->ConfigValue('User_LoggedInGroup')); if ( $res ) { $user_groups = array_merge($user_groups, $res); } $user_groups = implode(',', $user_groups); } return $user_groups; } /** * Allows to detect if page is browsed by spider (293 scheduled_tasks supported) * * @return bool * @access public */ /*public function IsSpider() { static $is_spider = null; if ( !isset($is_spider) ) { $user_agent = trim($_SERVER['HTTP_USER_AGENT']); $robots = file(FULL_PATH . '/core/robots_list.txt'); foreach ($robots as $robot_info) { $robot_info = explode("\t", $robot_info, 3); if ( $user_agent == trim($robot_info[2]) ) { $is_spider = true; break; } } } return $is_spider; }*/ /** * Allows to detect table's presence in database * * @param string $table_name * @param bool $force * @return bool * @access public */ public function TableFound($table_name, $force = false) { return $this->Conn->TableFound($table_name, $force); } /** * Returns counter value * * @param string $name counter name * @param Array $params counter parameters * @param string $query_name specify query name directly (don't generate from parameters) * @param bool $multiple_results * @return mixed * @access public */ public function getCounter($name, $params = Array (), $query_name = null, $multiple_results = false) { /** @var kCountHelper $count_helper */ $count_helper = $this->recallObject('CountHelper'); return $count_helper->getCounter($name, $params, $query_name, $multiple_results); } /** * Resets counter, which are affected by one of specified tables * * @param string $tables comma separated tables list used in counting sqls * @return void * @access public */ public function resetCounters($tables) { if ( kUtil::constOn('IS_INSTALL') ) { return; } /** @var kCountHelper $count_helper */ $count_helper = $this->recallObject('CountHelper'); $count_helper->resetCounters($tables); } /** * Sends XML header + optionally displays xml heading * * @param string|bool $xml_version * @return string * @access public * @author Alex */ public function XMLHeader($xml_version = false) { $this->setContentType('text/xml'); return $xml_version ? '' : ''; } /** * Returns category tree * * @param int $category_id * @return Array * @access public */ public function getTreeIndex($category_id) { $tree_index = $this->getCategoryCache($category_id, 'category_tree'); if ( $tree_index ) { $ret = Array (); list ($ret['TreeLeft'], $ret['TreeRight']) = explode(';', $tree_index); return $ret; } return false; } /** * Base category of all categories * Usually replaced category, with ID = 0 in category-related operations. * * @return int * @access public */ public function getBaseCategory() { // same, what $this->findModule('Name', 'Core', 'RootCat') does // don't cache while IS_INSTALL, because of kInstallToolkit::createModuleCategory and upgrade return $this->ModuleInfo['Core']['RootCat']; } /** * Deletes all data, that was cached during unit config parsing (excluding unit config locations) * * @param Array $config_variables * @access public */ public function DeleteUnitCache($config_variables = null) { $this->cacheManager->DeleteUnitCache($config_variables); } /** * Deletes cached section tree, used during permission checking and admin console tree display * * @return void * @access public */ public function DeleteSectionCache() { $this->cacheManager->DeleteSectionCache(); } /** * Sets data from cache to object * * @param Array $data * @access public */ public function setFromCache(&$data) { $this->Factory->setFromCache($data); $this->UnitConfigReader->setFromCache($data); $this->EventManager->setFromCache($data); $this->ReplacementTemplates = $data['Application.ReplacementTemplates']; $this->routers = $data['Application.Routers']; $this->ModuleInfo = $data['Application.ModuleInfo']; } /** * Gets object data for caching * The following caches should be reset based on admin interaction (adjusting config, enabling modules etc) * * @access public * @return Array */ public function getToCache() { return array_merge( $this->Factory->getToCache(), $this->UnitConfigReader->getToCache(), $this->EventManager->getToCache(), Array ( 'Application.ReplacementTemplates' => $this->ReplacementTemplates, 'Application.Routers' => $this->routers, 'Application.ModuleInfo' => $this->ModuleInfo, ) ); } public function delayUnitProcessing($method, $params) { $this->cacheManager->delayUnitProcessing($method, $params); } /** * Returns current maintenance mode state * * @param bool $check_ips * @return int * @access public */ public function getMaintenanceMode($check_ips = true) { $exception_ips = defined('MAINTENANCE_MODE_IPS') ? MAINTENANCE_MODE_IPS : ''; $setting_name = $this->isAdmin ? 'MAINTENANCE_MODE_ADMIN' : 'MAINTENANCE_MODE_FRONT'; if ( defined($setting_name) && constant($setting_name) > MaintenanceMode::NONE ) { $exception_ip = $check_ips ? kUtil::ipMatch($exception_ips) : false; if ( !$exception_ip ) { return constant($setting_name); } } return MaintenanceMode::NONE; } /** * Sets content type of the page * * @param string $content_type * @param bool $include_charset * @return void * @access public */ public function setContentType($content_type = 'text/html', $include_charset = null) { static $already_set = false; if ( $already_set ) { return; } $header = 'Content-type: ' . $content_type; if ( !isset($include_charset) ) { $include_charset = $content_type = 'text/html' || $content_type == 'text/plain' || $content_type = 'text/xml'; } if ( $include_charset ) { $header .= '; charset=' . CHARSET; } $already_set = true; header($header); } /** * Posts message to event log * * @param string $message * @param int $code * @param bool $write_now Allows further customization of log record by returning kLog object * @return bool|int|kLogger * @access public */ public function log($message, $code = null, $write_now = false) { $log = $this->_logger->prepare($message, $code)->addSource($this->_logger->createTrace(null, 1)); if ( $write_now ) { return $log->write(); } return $log; } /** * Deletes log with given id from database or disk, when database isn't available * * @param int $unique_id * @param int $storage_medium * @return void * @access public * @throws InvalidArgumentException */ public function deleteLog($unique_id, $storage_medium = kLogger::LS_AUTOMATIC) { $this->_logger->delete($unique_id, $storage_medium); } /** * Returns the client IP address. * * @return string The client IP address * @access public */ public function getClientIp() { return $this->HttpQuery->getClientIp(); } } Index: branches/5.3.x/core/kernel/managers/request_manager.php =================================================================== --- branches/5.3.x/core/kernel/managers/request_manager.php (revision 16599) +++ branches/5.3.x/core/kernel/managers/request_manager.php (revision 16600) @@ -1,478 +1,478 @@ processed ) { return; } $this->dumpRequest(); $this->processOpener(); $events = $this->getEvents(); $all_passed = $this->getAllPassed($events); // set "all_passed" before kApplication::GetTopmostPrefix method call ! $this->Application->SetVar('all_passed', implode(',', $all_passed)); foreach ($events as $prefix_special => $event_name) { $event =& $this->runEvent($prefix_special, $event_name); if ( $event->status == kEvent::erSTOP ) { // event requested to stop processing at this point kUtil::safeDefine('DBG_SKIP_REPORTING', 1); $this->Application->Session->SaveData(); exit; } if ( $event->status == kEvent::erPERM_FAIL ) { $this->processPermissionError($event); } if ( ($event->status == kEvent::erSUCCESS || $event->status == kEvent::erPERM_FAIL) && $this->canRedirect($event) ) { $this->performRedirect($event); } } $this->Application->SetVar('events', $events); $this->Application->SetVar('passed', implode(',', $all_passed)); $this->processed = true; } /** * Dumps user request to debugger (only when enabled) * * @return void * @access protected */ protected function dumpRequest() { if ( defined('DEBUG_MODE') && $this->Application->isDebugMode() && kUtil::constOn('DBG_SHOW_HTTPQUERY') ) { $this->Application->Debugger->appendHTML('HTTPQuery:'); $this->Application->Debugger->dumpVars($this->Application->HttpQuery->_Params); } } /** * Returns event names, given in request (post, get) * * @return Array * @access protected */ protected function getEvents() { $post_events = $this->getEventsFromPost(); return $post_events ? $post_events : $this->getEventsFromGet(); } /** * Get all passed prefixes * * @param Array $events * @return Array * @access protected */ protected function getAllPassed($events) { $ret = explode(',', $this->Application->GetVar('passed')); foreach ($events as $prefix_special => $event_name) { if (!$event_name) { continue; } if ($this->Application->isAdmin) { array_push($ret, $prefix_special); } else { // don't add special on Front-end because of category item list special is autogenerated $prefix_special = explode('.', $prefix_special); array_push($ret, $prefix_special[0]); } } return $ret; } /** * Creates and runs event. Returns false, when prefix of given event isn't registered * * @param string $prefix_special * @param string $event_name * * @return kEvent|false * @access protected */ protected function &runEvent($prefix_special, $event_name) { $event = new kEvent($prefix_special . ':' . $event_name); if ( !$this->Application->EventManager->verifyEventPrefix($event, true) ) { $false = false; return $false; } $event->SetRedirectParam('opener', 's'); // stay on same page after event is called $event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true)); /** @var kEventHandler $event_handler */ $event_handler = $this->Application->recallObject($event->Prefix . '_EventHandler'); - if ( ($this->Application->RecallVar('user_id') == USER_ROOT) || $event_handler->CheckPermission($event) ) { + if ( $this->Application->permissionCheckingDisabled() || $event_handler->CheckPermission($event) ) { $this->Application->HandleEvent($event); $this->Application->notifyEventSubscribers($event); } return $event; } /** * Processes case, when event finished with permission error * * @param kEvent $event * @access protected */ protected function processPermissionError($event) { // should do redirect but to no_permissions template $event->redirect = $this->Application->isAdmin ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate'); $event->SetRedirectParam('pass', 'm'); /** @var kThemesHelper $themes_helper */ $themes_helper = $this->Application->recallObject('ThemesHelper'); $event->SetRedirectParam( 'm_cat_id', $themes_helper->getPageByTemplate($event->redirect) ); // restore stuff, that processOpener() changed $wid = $this->Application->GetVar('m_wid'); $this->Application->RestoreVar( rtrim('opener_stack_' . $wid, '_') ); // don't save last_template, because no_permission template does js history.back and could cause invalid opener_stack content $this->Application->SetVar('skip_last_template', 1); } /** * Performs redirect after event execution * * @param kEvent $event * @access protected */ protected function performRedirect($event) { // we need to pass category if the action was submitted to self-template, with the category passed // and it has not explicitly set redirect template or pass_category param if ( $this->samePageRedirect($event) && ($event->getEventParam('pass_category') === false) && $this->Application->GetVar('m_cat_id') ) { $event->SetRedirectParam('pass_category', 1); } $wid = $this->Application->GetVar('m_wid'); $redirect_params = $event->getRedirectParams(); if ( $wid && $event->getRedirectParam('opener') == 'u' ) { // update last element in current opener stack unset($redirect_params['opener']); $redirect_template = is_string($event->redirect) ? $event->redirect : null; $this->openerStackChange($redirect_template, $redirect_params); // reset opener, because kApplication::HREF will react differently when 'opener' => 'u' $event->SetRedirectParam('opener', 's'); $event->redirect = defined('CLOSE_POPUP_TPL') ? CLOSE_POPUP_TPL : 'incs/close_popup'; } if ( $event->getRedirectParam('pass') === false ) { // pass all discovered units to redirected page unless developer decided otherwise $event->SetRedirectParam('pass', 'all'); } $this->Application->Redirect($event->redirect, $event->getRedirectParams(), '', $event->redirectScript); } /** * Checks, if redirect can be made * * @param kEvent $event * @return bool * @access protected */ protected function canRedirect($event) { return $this->samePageRedirect($event) || strlen($event->redirect) > 0; } /** * Checks, that current template will be displayed after redirect * * @param kEvent $event * @return bool * @access protected */ protected function samePageRedirect($event) { return $event->redirect === true || $event->redirect == $this->Application->GetVar('t'); } /** * Returns event names given in GET * * @return Array * @access protected */ protected function getEventsFromGet() { $events = Array (); $discovered_units = $this->Application->HttpQuery->getDiscoveredUnits(false); foreach ($discovered_units as $prefix_special => $query_string) { $query_string = array_flip($query_string); if ( !isset($query_string['event']) ) { continue; } $event_name = $this->Application->GetVar($prefix_special . '_event'); // we need to check for pre 5.1.0 url format, because of "PerPage" // query string part (that was added in place of "event" query // string part) is available only since 5.1.0 version if ($event_name && !is_numeric($event_name)) { $events[$prefix_special] = $event_name; } } return $events; } /** * Returns event names given in POST * * @return Array * @access protected */ protected function getEventsFromPost() { $ret = Array (); $events = $this->Application->GetVar('events'); if (!$events) { return Array (); } foreach ($events as $prefix_special => $event_name) { if (!$event_name) { continue; } if ( is_array($event_name) ) { // HTML-input names like "events[prefix.special][event_name]", input value don't matter $event_name = key($event_name); $this->Application->SetVar($prefix_special . '_event', $event_name); } // HTML-input names like "events[prefix.special]", input value is event name $ret[$prefix_special] = $event_name; } return $ret; } /** * Processes window opener stack * * @access protected */ protected function processOpener() { /** @var kOpenerStack $opener_stack */ $opener_stack = $this->Application->makeClass('kOpenerStack'); switch ( $this->Application->GetVar('m_opener') ) { case 'r': $opener_stack->reset(); break; case 'd': // "down/push" new template to opener stack, deeplevel++ if ( $this->Application->GetVar('front') ) { /** @var Session $front_session */ $front_session = $this->Application->recallObject('Session.front'); $opener_stack->pushRaw( '../' . $front_session->RecallVar('last_template') ); } else { $opener_stack->pushRaw( $this->Application->RecallVar('last_template') ); } break; case 'u': // "up/pop" last template from opener stack, deeplevel-- $opener_stack->pop(); break; case 'p': // pop-up - generate new wid $parent_wid = $this->Application->GetVar('m_wid'); // window_id of popup's parent window $popup_wid = (int)$this->Application->RecallVar('last_wid') + 1; $this->Application->StoreVar('last_wid', $popup_wid); $this->Application->SetVar('m_wid', $popup_wid); /** @var kOpenerStack $popup_opener_stack */ $popup_opener_stack = $this->Application->makeClass('kOpenerStack', Array ($popup_wid)); $popup_opener_stack->pushRaw( $this->getLastTemplate($parent_wid) ); $popup_opener_stack->save(); $this->Application->SetVar('m_opener', 's'); /*// store window relations $window_relations = $this->Application->RecallVar('window_relations'); $window_relations = $window_relations ? unserialize($window_relations) : Array (); $window_relations[$popup_wid] = $parent_wid; $this->Application->StoreVar('window_relations', serialize($window_relations));*/ return; break; default: // "s/0," stay on same deep level break; } $this->Application->SetVar('m_opener', 's'); $opener_stack->save(); } /** * Returns last template from window with given id * * @param int $window_id * @return string * @access protected */ protected function getLastTemplate($window_id) { if ( $this->Application->GetVar('front') ) { /** @var Session $front_session */ $front_session = $this->Application->recallObject('Session.front'); return '../' . $front_session->RecallVar( rtrim('last_template_popup_' . $window_id, '_') ); } if ( $this->Application->GetVar('merge_opener_stack') ) { // get last template from parent (that was closed) window opener stack /** @var kOpenerStack $parent_opener_stack */ $parent_opener_stack = $this->Application->makeClass('kOpenerStack', Array ($window_id)); $last_template = $parent_opener_stack->pop(true); $parent_opener_stack->save(true); } else { $last_template = $this->Application->RecallVar( rtrim('last_template_popup_' . $window_id, '_') ); } return $last_template; } /** * Allows to add new element to opener stack * * @param string $template * @param Array $params * @param int $wid * @access public */ public function openerStackPush($template = '', $params = Array (), $wid = null) { if ( !isset($params['pass']) ) { $params['pass'] = 'all'; } /*// get parent window wid, when this was popup $window_relations = $this->Application->RecallVar('window_relations'); $window_relations = $window_relations ? unserialize($window_relations) : Array (); $wid = isset($window_relations[$wid]) ? $window_relations[$wid] : false;*/ /** @var kOpenerStack $opener_stack */ $opener_stack = $this->Application->makeClass('kOpenerStack', Array ($wid)); // change opener stack $default_params = Array ('m_opener' => 'u'); if ( !$this->Application->ConfigValue('UsePopups') && $opener_stack->getWindowID() ) { // remove wid to show combined header block in editing window $default_params['m_wid'] = ''; list ($last_template, $last_params, ) = $opener_stack->get(kOpenerStack::LAST_ELEMENT); // move last popup's opener stack element to main window's opener stack if ( $last_params ) { $last_params = array_merge($last_params, $default_params); $this->openerStackPush($last_template, $last_params, ''); } } $params = array_merge($default_params, $params); $opener_stack->push($template, $params, 'index.php'); $opener_stack->save(); } /** * Allows to change last element in opener stack * * @param string $new_template * @param Array $new_params * @access protected */ protected function openerStackChange($new_template = null, $new_params = null) { /** @var kOpenerStack $opener_stack */ $opener_stack = $this->Application->makeClass('kOpenerStack'); list ($template, $params, $index_file) = $opener_stack->pop(); if ( isset($new_template) ) { $template = $new_template; } if ( isset($new_params) ) { $params = array_merge($params, $new_params); } if ( !isset($params['pass_events']) ) { // don't pass events, unless requested $params['pass_events'] = false; } $opener_stack->push($template, $params, $index_file); $opener_stack->save(); } -} \ No newline at end of file +} Index: branches/5.3.x/core/kernel/processors/main_processor.php =================================================================== --- branches/5.3.x/core/kernel/processors/main_processor.php (revision 16599) +++ branches/5.3.x/core/kernel/processors/main_processor.php (revision 16600) @@ -1,1307 +1,1307 @@ Application->recallObject('kActions'); $actions->Set('t', $this->Application->GetVar('t')); $actions->Set('sid', $this->Application->GetSID()); $actions->Set('m_opener', $this->Application->GetVar('m_opener') ); } /** * Base folder for all template includes * * @param Array $params * @return string */ function TemplatesBase($params) { static $cached = Array (); $cache_key = crc32( serialize($params) ); if (!array_key_exists($cache_key, $cached)) { $module = array_key_exists('module', $params) ? $params['module'] : 'core'; if ($this->Application->isAdmin) { if ($module == 'in-portal') { $module = 'kernel'; } // remove leading slash + substitute module $module_path = $this->Application->findModule('Name', $module, 'Path'); if ($module_path !== false) { $path = $module_path . 'admin_templates'; } else { // remove leading slash + substitute module $path = preg_replace('/\/(.*?)\/(.*)/', $module . '/\\2', THEMES_PATH); } } else { $path = mb_substr(THEMES_PATH, 1); if (mb_strtolower($module) == 'in-portal') { $module_folder = 'platform'; } else { $module_folder = $this->Application->findModule('Name', $module, 'TemplatePath'); } $path .= rtrim('/' . trim($module_folder, '/'), '/') . '/'; } $cached[$cache_key] = $this->Application->BaseURL() . $path; } return $cached[$cache_key]; } /** * Creates HTML tag for all templates * affects future css, js files and href params of links * * @param Array $params * @return string * @access protected * @see kMainTagProcessor::TemplatesBase */ protected function Base_Ref($params) { // tag TemplatesBase adds trailing "/" but only on Front-End $base_href = rtrim($this->TemplatesBase($params), '/'); return ''; } /** * Returns base url for web-site * * @return string * @access public */ function BaseURL() { return $this->Application->BaseURL(); } //for compatability with K3 tags function Base($params) { return $this->TemplatesBase($params).'/'; } function ProjectBase($params) { return $this->Application->BaseURL(); } /*function Base($params) { return $this->Application->BaseURL().$params['add']; }*/ /** * Used to create link to any template. * use "pass" paramter if "t" tag to specify * prefix & special of object to be represented * in resulting url * * @param Array $params * @return string * @access public */ function T($params) { // by default link to current template $template = $this->SelectParam($params, 't,template'); $prefix = array_key_exists('prefix', $params) ? $params['prefix'] : ''; unset($params['t'], $params['template'], $params['prefix']); $no_html_escape = false; if ( isset($params['no_amp']) ) { $no_html_escape = $params['no_amp']; unset($params['no_amp']); } $ret = $this->Application->HREF($template, $prefix, $params); if ( !$no_html_escape ) { // most of the time links are placed into HTML document // TODO: in future always do escaping according to current "escape context" $ret = kUtil::escape($ret, kUtil::ESCAPE_HTML); } return $ret; } function Link($params) { // pass "m" prefix, instead of "all", that is by default on Front-End if (!array_key_exists('pass', $params)) { $params['pass'] = 'm'; } return $this->T($params); } /** * Performs redirect to provided template/url * * @param Array $params * @return string */ function Redirect($params) { // By default link to current template. $template = $this->SelectParam($params, 't,template'); $prefix = array_key_exists('prefix', $params) ? $params['prefix'] : ''; unset($params['t'], $params['template'], $params['prefix']); // Pass "m" prefix, instead of "all", that is by default on Front-End. if ( !array_key_exists('pass', $params) ) { $params['pass'] = 'm'; } $this->Application->Redirect($template, $params, $prefix); return ''; } /*function Env($params) { $t = $params['template']; unset($params['template']); return $this->Application->BuildEnv($t, $params, 'm', false, false); }*/ function FormAction($params) { if (!array_key_exists('pass', $params)) { $params['pass'] = 'all,m'; } $params['pass_category'] = 1; return $this->Application->HREF('', '', $params); } /*// NEEDS TEST function Config($params) { return $this->Application->ConfigOption($params['var']); } function Object($params) { $name = $params['name']; $method = $params['method']; $tmp = $this->Application->recallObject($name); if ($tmp != null) { if (method_exists($tmp, $method)) return $tmp->$method($params); else echo "Method $method does not exist in object ".get_class($tmp)." named $name
"; } else echo "Object $name does not exist in the appliaction
"; }*/ /** * Tag, that always returns true. * For parser testing purposes * * @param Array $params * @return bool * @access public */ function True($params) { return true; } /** * Tag, that always returns false. * For parser testing purposes * * @param Array $params * @return bool * @access public */ function False($params) { return false; } /** * Returns block parameter by name (used only as "check" parameter value for "m_if" tag!) * * @param Array $params * @return stirng * @access public */ function Param($params) { $name = $params['name']; if (array_key_exists($name, $this->Application->Parser->Captures)) { $capture_params = $params; $capture_params['name'] = '__capture_' . $name; $this->Application->Parser->SetParam($name, $this->Application->ParseBlock($capture_params)); } $res = $this->Application->Parser->GetParam($name); if ($res === false) { $res = ''; } if (array_key_exists('plus', $params)) { $res += $params['plus']; } return $res; } /** * Compares block parameter with value specified * * @param Array $params * @return bool * @access public */ function ParamEquals($params) { $name = $this->SelectParam($params, 'name,var,param'); $value = $params['value']; return ($this->Application->Parser->GetParam($name) == $value); } /*function PHP_Self($params) { return $HTTP_SERVER_VARS['PHP_SELF']; } */ /** * Returns session variable value by name * * @param Array $params * @return string * @access public */ function Recall($params) { $var_name = $this->SelectParam($params,'name,var,param'); if (isset($params['persistent']) && $params['persistent']) { $ret = $this->Application->RecallPersistentVar($var_name); } else { $ret = $this->Application->RecallVar($var_name); } $ret = ($ret === false && isset($params['no_null'])) ? '' : $ret; if (getArrayValue($params, 'special') || getArrayValue($params, 'htmlchars')) { $ret = kUtil::escape($ret, kUtil::ESCAPE_HTML); } if (getArrayValue($params, 'urlencode')) { $ret = kUtil::escape($ret, kUtil::ESCAPE_URL); } return $ret; } function RemoveVar($params) { $this->Application->RemoveVar( $this->SelectParam($params,'name,var,param') ); } // bad style to store something from template to session !!! (by Alex) // Used here only to test how session works, nothing more function Store($params) { //echo"Store $params[name]
"; $name = $params['name']; $value = $params['value']; $this->Application->StoreVar($name,$value); } /** * Links variable from request with variable from session * * @param Array $params * @return string * @access protected */ protected function LinkVar($params) { $var_name = $params['name']; $session_var_name = isset($params['session_name']) ? $params['session_name'] : $var_name; $default_value = isset($params['default']) ? $params['default'] : ''; $this->Application->LinkVar($var_name, $session_var_name, $default_value); return ''; } /** * Links variable from request with variable from session and returns it's value * * @param Array $params * @return string * @access protected */ protected function GetLinkedVar($params) { $this->LinkVar($params); return $this->Application->GetVar( $params['name'] ); } /** * Sets application variable value(-s) * * @param Array $params * @access public */ function Set($params) { foreach ($params as $param => $value) { $this->Application->SetVar($param, $value); } } /** * Increment application variable * specified by number specified * * @param Array $params * @access public */ function Inc($params) { $this->Application->SetVar($params['param'], $this->Application->GetVar($params['param']) + $params['by']); } /** * Retrieves application variable * value by name * * @param Array $params * @return string * @access public */ function Get($params) { $name = $this->SelectParam($params, 'name,var,param'); if ( strpos($name, '[') !== false ) { preg_match('/([^\[\]]+)\[(.*)\]/', $name, $regs); $function_params = explode('][', $regs[2]); $ret = $this->Application->GetVar($regs[1], array()); kUtil::array_unshift_ref($function_params, $ret); $ret = call_user_func_array('getArrayValue', $function_params); } else { $ret = $this->Application->GetVar($name, ''); } if ( array_key_exists('no_html_escape', $params) && $params['no_html_escape'] ) { return $this->Application->isAdmin ? $ret : kUtil::unescape($ret, kUtil::ESCAPE_HTML); } return kUtil::escape($ret, kUtil::ESCAPE_HTML); } /** * Retrieves application constant * value by name * * @param Array $params * @return string * @access public */ function GetConst($params) { $constant_name = $this->SelectParam($params, 'name,const'); return defined($constant_name) ? constant($constant_name) : ''; } /** * Retrieves configuration variable value by name * * @param Array $params * @return string * @access public */ function GetConfig($params) { $config_name = $this->SelectParam($params, 'name,var'); $ret = $this->Application->ConfigValue($config_name); if ( isset($params['formatted']) && $params['formatted'] ) { $sql = 'SELECT ValueList FROM ' . TABLE_PREFIX . 'SystemSettings WHERE VariableName = ' . $this->Conn->qstr($config_name) . ' AND ElementType IN ("select", "radio")'; $value_list = $this->Conn->GetOne($sql); if ( $value_list ) { /** @var InpCustomFieldsHelper $helper */ $helper = $this->Application->recallObject('InpCustomFieldsHelper'); $options = $helper->GetValuesHash($value_list); $ret = isset($options[$ret]) ? $options[$ret] : $ret; } } if ( isset($params['as_label']) && $params['as_label'] ) { $ret = $this->Application->Phrase($ret); } return $ret; } /** * Compares configuration variable to a given value * * @param Array $params * @return bool * @deprecated * @access protected */ protected function ConfigEquals($params) { $option = $this->SelectParam($params, 'name,option,var'); return $this->Application->ConfigValue($option) == $params['value']; } /** * Creates all hidden fields * needed for kernel_form * * @param Array $params * @return string * @access protected */ protected function DumpSystemInfo($params) { /** @var Params $actions */ $actions = $this->Application->recallObject('kActions'); $actions->Set('t', $this->Application->GetVar('t')); $o = ''; $params = $actions->GetParams(); foreach ($params AS $name => $val) { $o .= "\n"; } return $o; } /** * Used for search sidebox on front-end only * * @param Array $params * @return string * @access protected */ protected function GetFormHiddens($params) { $t = $this->SelectParam($params, 'template,t'); unset($params['template']); $form_fields = Array (); if ( $this->Application->RewriteURLs() ) { /** @var Session $session */ $session = $this->Application->recallObject('Session'); if ( $session->NeedQueryString() ) { $form_fields['sid'] = $this->Application->GetSID(); } } else { $form_fields['env'] = $this->Application->BuildEnv($t, $params, 'm', false, false); } if ( $this->Application->GetVar('admin') == 1 ) { $form_fields['admin'] = 1; } $ret = ''; $field_tpl = '' . "\n"; foreach ($form_fields as $form_field => $field_value) { $ret .= sprintf($field_tpl, $form_field, $field_value); } return $ret; } function Odd_Even($params) { $odd = $params['odd']; $even = $params['even']; if (!isset($params['var'])) { $var = 'odd_even'; } else { $var = $params['var']; } if ($this->Application->GetVar($var) == 'even') { if (!isset($params['readonly']) || !$params['readonly']) { $this->Application->SetVar($var, 'odd'); } return $even; } else { if (!isset($params['readonly']) || !$params['readonly']) { $this->Application->SetVar($var, 'even'); } return $odd; } } /** * Returns phrase translation by name * * @param Array $params * @return string * @access public */ function Phrase($params) { $phrase_name = $this->SelectParam($params, 'label,name,title'); $default_translation = $this->SelectParam($params, 'default'); $no_editing = isset($params['no_editing']) && $params['no_editing']; $translation = $this->Application->Phrase($phrase_name, !$no_editing); $phrase_key = mb_strtoupper($phrase_name); if ( $default_translation && strpos($translation, '!' . $phrase_key . '!') !== false ) { /** @var kDBItem $phrase */ $phrase = $this->Application->recallObject('phrases.autocreate', null, Array ('skip_autoload' => true)); if ( !$phrase->Load($phrase_key, 'PhraseKey') ) { $phrase->SetDBField('Phrase', $phrase_name); /** @var kMultiLanguageHelper $ml_helper */ $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); $languages = $ml_helper->getLanguages(); foreach ($languages AS $language_id) { $phrase->SetDBField('l' . $language_id . '_Translation', $default_translation); } if ( $phrase->Create() ) { $translation = $default_translation; } } } if ( isset($params['escape']) && $params['escape'] ) { // html escaping here is redundant $translation = kUtil::escape($translation, kUtil::ESCAPE_JS); } return $translation; } // for tabs function is_active($params) { $test_templ = $this->SelectParam($params, 'templ,template,t'); if ( !getArrayValue($params, 'allow_empty') ) { $if_true = getArrayValue($params, 'true') ? $params['true'] : 1; $if_false = getArrayValue($params, 'false') ? $params['false'] : 0; } else { $if_true = $params['true']; $if_false = $params['false']; } $physical_template = $this->Application->getPhysicalTemplate($this->Application->GetVar('t')); return preg_match('/^' . str_replace('/', '\/', $test_templ) . '/i', $physical_template) ? $if_true : $if_false; } function IsNotActive($params) { return !$this->is_active($params); } function IsActive($params) { return $this->is_active($params); } function is_t_active($params) { return $this->is_active($params); } function CurrentTemplate($params) { return $this->is_active($params); } /** * Checks if session variable * specified by name value match * value passed as parameter * * @param Array $params * @return string * @access public */ function RecallEquals($params) { $name = $this->SelectParam($params, 'name,var'); $value = $params['value']; if (isset($params['persistent']) && $params['persistent']) { return $this->Application->RecallPersistentVar($name) == $value; } return ($this->Application->RecallVar($name) == $value); } /** * Checks if application variable specified by name value match value passed as parameter * * @param Array $params * @return bool * @access protected * @deprecated */ protected function GetEquals($params) { $name = $this->SelectParam($params, 'var,name,param'); return $this->Application->GetVar($name) == $params['value']; } function ModuleInclude($params) { $ret = ''; $included = Array (); $block_params = array_merge($params, Array ('is_silent' => 2)); // don't make fatal errors in case if template is missing $current_template = $this->Application->GetVar('t'); $replace_main = isset($params['replace_m']) && $params['replace_m']; $skip_prefixes = isset($params['skip_prefixes']) ? explode(',', $params['skip_prefixes']) : Array (); $cms_mode = $this->Application->GetVar('admin'); foreach ($this->Application->ModuleInfo as $module_name => $module_data) { $module_key = mb_strtolower($module_name); if ( $module_name == 'In-Portal' ) { if ( !$cms_mode && $this->Application->isAdmin ) { // don't process In-Portal templates in admin continue; } // Front-End still relies on In-Portal module $module_prefix = $module_data['TemplatePath']; } elseif ( $this->Application->isAdmin && $module_data['Path'] != 'core/' ) { $module_prefix = $module_key . '/'; // was $module_data['Path']; } else { $module_prefix = $module_data['TemplatePath']; // always have trailing "/" } if ( in_array($module_prefix, $included) ) { // template by this path was already included by other module (e.g. in-portal used core's template) continue; } $block_params['t'] = $module_prefix . $this->SelectParam($params, $module_key . '_template,' . $module_key . '_t,template,t'); $check_prefix = $module_data['Var']; if ( $check_prefix == 'adm' && $replace_main ) { $check_prefix = 'c'; } if ( $block_params['t'] == $current_template || in_array($check_prefix, $skip_prefixes) ) { continue; } $no_data = $this->SelectParam($params, $module_key . '_block_no_data,block_no_data'); if ( $no_data ) { $block_params['block_no_data'] = $module_prefix . '/' . $no_data; } $ret .= $this->Application->IncludeTemplate($block_params); $included[] = $module_prefix; } return $ret; } function ModuleEnabled($params) { return $this->Application->isModuleEnabled( $params['module'] ); } /** * Checks if debug mode is on * * @param Array $params * @return bool * @access public */ function IsDebugMode($params) { return defined('DEBUG_MODE') && $this->Application->isDebugMode(); } /*function MassParse($params) { $qty = $params['qty']; $block = $params['block']; $mode = $params['mode']; $o = ''; if ($mode == 'func') { $func = create_function('$params', ' $o = \'\'; $o.= \'a\'.$params[\'param1\'].\'\'; $o.= \'a\'.$params[\'param2\'].\'\'; $o.= \'a\'.$params[\'param3\'].\'\'; $o.= \'a\'.$params[\'param4\'].\'\'; $o.= \'\'; return $o; '); for ($i=1; $i<$qty; $i++) { $block_params['param1'] = rand(1, 10000); $block_params['param2'] = rand(1, 10000); $block_params['param3'] = rand(1, 10000); $block_params['param4'] = rand(1, 10000); $o .= $func($block_params); } return $o; } $block_params['name'] = $block; for ($i=0; $i<$qty; $i++) { $block_params['param1'] = rand(1, 10000); $block_params['param2'] = rand(1, 10000); $block_params['param3'] = rand(1, 10000); $block_params['param4'] = rand(1, 10000); $block_params['passed'] = $params['passed']; $block_params['prefix'] = 'm'; $o.= $this->Application->ParseBlock($block_params); } return $o; }*/ function LoggedIn($params) { return $this->Application->LoggedIn(); } /** * Allows to check if permission exists directly in template and perform additional actions if required * * @param Array $params * @return bool */ function CheckPermission($params) { /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); return $perm_helper->TagPermissionCheck($params); } /** * Checks if user is logged in and if not redirects it to template passed * * @param Array $params */ function RequireLogin($params) { $t = $this->Application->GetVar('t'); $next_t = getArrayValue($params, 'next_template'); if ( $next_t ) { $t = $next_t; } // check by permissions: begin if ((isset($params['perm_event']) && $params['perm_event']) || (isset($params['perm_prefix']) && $params['perm_prefix']) || (isset($params['permissions']) && $params['permissions'])) { /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); $perm_status = $perm_helper->TagPermissionCheck($params); if (!$perm_status) { list($redirect_template, $redirect_params) = $perm_helper->getPermissionTemplate($params); $this->Application->Redirect($redirect_template, $redirect_params); } else { return ; } } // check by permissions: end // check by configuration value: begin $condition = getArrayValue($params, 'condition'); if (!$condition) { $condition = true; } else { if (substr($condition, 0, 1) == '!') { $condition = !$this->Application->ConfigValue(substr($condition, 1)); } else { $condition = $this->Application->ConfigValue($condition); } } // check by configuration value: end // check by belonging to group: begin $group = $this->SelectParam($params, 'group'); $group_access = true; if ($group) { $sql = 'SELECT GroupId FROM '.TABLE_PREFIX.'UserGroups WHERE Name = '.$this->Conn->qstr($group); $group_id = $this->Conn->GetOne($sql); if ($group_id) { $groups = explode(',', $this->Application->RecallVar('UserGroups')); $group_access = in_array($group_id, $groups); } } // check by belonging to group: end if ((!$this->Application->LoggedIn() || !$group_access) && $condition) { $redirect_params = $this->Application->HttpQuery->getRedirectParams(true); if (MOD_REWRITE) { // TODO: $next_t variable is ignored !!! (is anyone using m_RequireLogin tag with "next_template" parameter?) $redirect_params = Array ( 'm_cat_id' => 0, 'next_template' => 'external:' . $_SERVER['REQUEST_URI'], ); } else { $redirect_params['next_template'] = $t; } if (array_key_exists('pass_category', $params)) { $redirect_params['pass_category'] = $params['pass_category']; } if (array_key_exists('use_section', $params)) { $redirect_params['use_section'] = $params['use_section']; } if ( $this->Application->LoggedIn() && !$group_access) { $this->Application->Redirect($params['no_group_perm_template'], $redirect_params); } $this->Application->Redirect($params['login_template'], $redirect_params); } } /** * Checks, that user belongs to a group with a given name * * @param Array $params * @return bool */ protected function IsMember($params) { $sql = 'SELECT GroupId FROM ' . TABLE_PREFIX . 'UserGroups WHERE Name = ' . $this->Conn->qstr($params['group']); $group_id = $this->Conn->GetOne($sql); if ( $group_id ) { $groups = explode(',', $this->Application->RecallVar('UserGroups')); return in_array($group_id, $groups); } return false; } /** * Checks if SSL is enabled and redirects to SSL Domain if needed * If SSLDomain is not defined in config - the tag does not do anything * If for_logged_in_only="1" exits if user is not logged in. * If called without params forces https right away. If called with by_config="1" checks the * Require SSL setting from General Config and if it is ON forces https * * @param Array $params */ protected function CheckSSL($params) { $ssl_domain = $this->Application->getSecureDomain(); if ( !$ssl_domain || ($this->Application->TemplatesCache->forceThemeName !== false) ) { // SSL URL is not set - no way to require SSL // internal parsing (e.g. "TemplateParser::_parseTemplate") -> don't redirect return; } $require = false; if ( isset($params['mode']) && $params['mode'] == 'required' ) { $require = true; if ( isset($params['for_logged_in_only']) && $params['for_logged_in_only'] && !$this->Application->LoggedIn() ) { $require = false; } if ( isset($params['condition']) ) { if ( !$this->Application->ConfigValue($params['condition']) ) { $require = false; } } } - if ( EDITING_MODE ) { - // match SSL mode on front-end to one in administrative console, when browse modes are used + if ( defined('EDITING_MODE') && EDITING_MODE ) { + // Match SSL mode on front-end to one in administrative console, when browse modes are used. $require = $this->Application->ConfigValue('Require_AdminSSL'); } /** @var kHTTPQuery $http_query */ $http_query = $this->Application->recallObject('kHTTPQuery'); $pass = $http_query->getRedirectParams(); $pass['pass_events'] = 1; // to make sure all events are passed when redirect happens if ( $require ) { if ( PROTOCOL == 'https://' ) { $this->Application->SetVar('__KEEP_SSL__', 1); return; } $pass['__SSL__'] = 1; $this->Application->Redirect('', $pass); } else { if ( PROTOCOL == 'https://' && $this->Application->ConfigValue('Force_HTTP_When_SSL_Not_Required') ) { if ( $this->Application->GetVar('__KEEP_SSL__') ) { return; } // $pass_more = Array ('pass' => 'm', 'm_cat_id' => 0, '__SSL__' => 0); $pass['__SSL__'] = 0; $this->Application->Redirect('', $pass); // $pass_more } } } function ConstOn($params) { $name = $this->SelectParam($params,'name,const'); return kUtil::constOn($name); } function SetDefaultCategory($params) { $category_id = $this->Application->findModule('Name', $params['module'], 'RootCat'); $this->Application->SetVar('m_cat_id', $category_id); } function XMLTemplate($params) { $this->NoDebug($params); if ( isset($params['cache']) && $params['cache'] ) { $nextyear = intval(date('Y') + 1); $format = "D, d M Y H:i:s"; $expiration = gmdate($format, time() + $params['cache']) . ' GMT'; $last_modified = time(); header('Cache-Control: public, cache, max-age=' . $params['cache']); header("Expires: $expiration"); header('Pragma: public'); // Getting headers sent by the client. $headers = $this->Application->HttpQuery->getHeaders(); // Checking if the client is validating his cache and if it is current. if ( isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) > $last_modified - $params['cache']) ) { // Client's cache IS current, so we just respond '304 Not Modified'. header('Last-Modified: ' . date($format, strtotime($headers['If-Modified-Since'])) . ' GMT', true, 304); exit; } else { // Image not cached or cache outdated, we respond '200 OK' and output the image. header('Last-Modified: ' . gmdate($format, $last_modified) . ' GMT', true, 200); } } // xml documents are usually long kUtil::setResourceLimit(); if ( !$this->Application->GetVar('debug') ) { return $this->Application->XMLHeader(getArrayValue($params, 'xml_version')); } return ''; } function Header($params) { header($params['data']); } function NoDebug($params) { if ( !$this->Application->GetVar('debug') ) { kUtil::safeDefine('DBG_SKIP_REPORTING', 1); } } /** * Returns Home category name * * @param Array $params * @return string * @deprecated */ function RootCategoryName($params) { $no_editing = array_key_exists('no_editing', $params) && $params['no_editing']; return $this->Application->Phrase('la_rootcategory_name', !$no_editing); } /** * Allows to attach file directly from email event template * * @param Array $params */ function AttachFile($params) { $path = FULL_PATH . '/' . $params['path']; $pseudo = isset($params['special']) ? 'EmailSender.' . $params['special'] : 'EmailSender'; /** @var kEmailSendingHelper $esender */ $esender = $this->Application->recallObject($pseudo); if ( file_exists($path) && is_file($path) ) { $esender->AddAttachment($path); } } function CaptchaImage($params) { $this->NoDebug($params); $this->Application->SetVar('skip_last_template', 1); /** @var kCaptchaHelper $captcha_helper */ $captcha_helper = $this->Application->recallObject('CaptchaHelper'); // generate captcha code $code = $captcha_helper->prepareCode( $this->Application->GetVar('var') ); $captcha_helper->GenerateCaptchaImage($code, $this->Application->GetVar('w'), $this->Application->GetVar('h'), true); } function SID($params) { return $this->Application->GetSID(); } function ModuleInfo($params) { return $this->Application->findModule($params['key'], $params['value'], $params['return']); } function Random($params) { return rand(1, 100000000); } /** * Prints parser params, available at current deep level * * @param Array $params * @return string */ function PrintCurrentParams($params) { $current_params = $this->Application->Parser->Params; foreach ($current_params as $param_name => $param_value) { if ( is_object($param_value) && !method_exists($param_value, '__toString') ) { $param_value = 'ClassName: ' . get_class($param_value); } $current_params[$param_name] = $param_name . ' = "' . $param_value . '"'; } return '
' . implode("\n", $current_params) . '
'; } /** * Gets previously defined counter result * * @param Array $params * @return int */ function GetCounter($params) { return $this->Application->getCounter($params['name'], $params); } /** * Increments PageHit counter * * @param Array $params * @return int */ function RegisterPageHit($params) { if ($this->Application->ConfigValue('UsePageHitCounter')) { // get current counte $sql = 'SELECT VariableValue FROM '.TABLE_PREFIX.'SystemSettings WHERE VariableName = "PageHitCounter"'; $page_counter = (int)$this->Conn->GetOne($sql); $sql = 'UPDATE LOW_PRIORITY '.TABLE_PREFIX.'SystemSettings SET VariableValue = '.($page_counter + 1).' WHERE VariableName = "PageHitCounter"'; $this->Conn->Query($sql); } } function Timestamp($params) { $format = isset($params['format']) ? $params['format'] : 'd.m.Y H:i:s'; return date($format); } function GetUrlHiddenFileds($params) { $vars = Array ('page', 'per_page', 'sort_by'); $ret = ''; if (array_key_exists('skip', $params)) { $vars = array_diff($vars, $params['skip']); } foreach ($vars as $var_name) { $var_value = $this->Application->GetVar($var_name); if ($var_value) { $ret .= ''; } } return $ret; } /** * Returns current Page URL (without re-assembling it). * "skip_query" param is optional and will remove the ?QUERY part from the result. * * @param Array $params * @return string * @access protected */ protected function CurrentPageLink($params) { if ( isset($params['skip_query']) && $params['skip_query'] ) { return preg_replace('/\?' . preg_quote($_SERVER['QUERY_STRING'], '/') . '$/', '', $_SERVER['REQUEST_URI']); } return $_SERVER['REQUEST_URI']; } /** * Returns current maintenance mode state * * @param Array $params * @return int * @access protected */ protected function MaintenanceMode($params) { $check_ips = isset($params['check_ips']) ? $params['check_ips'] : true; return $this->Application->getMaintenanceMode($check_ips); } /** * Checks if element with given name is defined * * @param Array $params * @return int * @access protected */ protected function ElementDefined($params) { return $this->Application->Parser->blockFound($params['name']); } /** * Detects mobile browser. * * @param array $params * * @return string * @link http://detectmobilebrowsers.com/ */ protected function IsMobileBrowser($params) { $user_agent = $_SERVER['HTTP_USER_AGENT']; if ( preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i', $user_agent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i', substr($user_agent, 0, 4)) ) { return true; } return false; } } Index: branches/5.3.x/core/kernel/utility/formatters/date_formatter.php =================================================================== --- branches/5.3.x/core/kernel/utility/formatters/date_formatter.php (revision 16599) +++ branches/5.3.x/core/kernel/utility/formatters/date_formatter.php (revision 16600) @@ -1,524 +1,528 @@ language = $this->Application->recallObject('lang.current'); } /** * Sets mixed format (date + time) for field if not set directly * * @param Array $field_options options of field * @param Array $format separate formats for date & time * @param string $type destination key in field_options to store mixed format */ function SetMixedFormat(&$field_options, &$format, $type) { if (!isset($field_options[$type])) { // default value is date+separator+time $field_options[$type] = '_regional_DateTimeFormat'; } if ($field_options[$type] == '_regional_DateTimeFormat') { $field_options[$type] = $format['date'].$field_options['date_time_separator'].$format['time']; } else if(preg_match('/_regional_(.*)/', $field_options[$type], $regs)) { $field_options[$type] = $this->language->GetDBField($regs[1]); } $format['mixed'] = $field_options[$type]; } /** * Returns separate formats for date,time,combined for input & display formats * * @param Array $field_options options of field * @param string $type type of requested information = {mixed,date,time} * @return Array display & input formats */ function GetSeparateFormats(&$field_options, $type) { if ($type == 'mixed') { if (!isset($field_options['date_time_separator'])) $field_options['date_time_separator'] = ' '; $display_format = Array (); $input_format = Array (); list ($display_format['date'], $input_format['date']) = $this->GetSeparateFormats($field_options, 'date'); list ($display_format['time'], $input_format['time']) = $this->GetSeparateFormats($field_options, 'time'); $this->SetMixedFormat($field_options, $display_format, 'format'); $this->SetMixedFormat($field_options, $input_format, 'input_format'); return Array ($display_format, $input_format); } else { // 1. set display format if (isset($field_options[$type.'_format'])) { $format = $field_options[$type.'_format']; } else { $format = $this->language->GetDBField(ucfirst($type).'Format'); } // 2. set input format if (isset($field_options['input_'.$type.'_format'])) { $input_format = $field_options['input_'.$type.'_format']; } else { $input_format = $this->language->GetDBField('Input'.ucfirst($type).'Format'); } return Array ($format, $input_format); } } /** * The method is supposed to alter config options or configure object in some way based on its usage of formatters * The methods is called for every field with formatter defined when configuring item. * Could be used for adding additional VirtualFields to an object required by some special Formatter * * @param string $field_name * @param array $field_options * @param kDBBase $object */ function PrepareOptions($field_name, &$field_options, &$object) { list ($display_format, $input_format) = $this->GetSeparateFormats($field_options, 'mixed'); $field_options['sub_fields'] = Array('date' => $field_name.'_date', 'time' => $field_name.'_time'); if (!isset($field_options['use_timezone'])) { // apply timezone from server $field_options['use_timezone'] = true; } // 1. add field to indicate, that date is already combined into one field $add_fields = Array ( $field_name . '_combined' => Array ('type' => 'int', 'default' => 0), ); // 2. add DATE virtual field $opts = Array('master_field' => $field_name, 'formatter' => 'kDateFormatter', 'format' => $display_format['date'], 'input_format' => $input_format['date']); $copy_options = Array ('type', 'default', 'required', 'use_timezone', 'error_msgs'); foreach ($copy_options as $copy_option) { if ( array_key_exists($copy_option, $field_options) ) { $opts[$copy_option] = $field_options[$copy_option]; } } $add_fields[$field_name . '_date'] = $opts; // 3. add TIME virtual field $opts['format'] = $display_format['time']; $opts['input_format'] = $input_format['time']; $add_fields[$field_name . '_time'] = $opts; $filter_type = getArrayValue($field_options, 'filter_type'); if ( $filter_type == 'range' ) { $opts['format'] = $field_options['format']; $add_fields[$field_name . '_rangefrom'] = $opts; $add_fields[$field_name . '_rangeto'] = $opts; } if ( !$object->isVirtualField($field_name) ) { // adding calculated field to format date directly in the query $object->addCalculatedField($field_name . '_date', '%1$s.' . $field_name); $object->addCalculatedField($field_name . '_time', '%1$s.' . $field_name); } $virtual_fields = $object->getVirtualFields(); $add_fields = kUtil::array_merge_recursive($add_fields, $virtual_fields); $object->setVirtualFields($add_fields); } /** * Used for split fields like timestamp -> date, time * Called from DBItem to update sub fields values after loading item * * @param string $field * @param string $value * @param Array $options * @param kDBItem $object * @return void * @access public */ public function UpdateSubFields($field, $value, &$options, &$object) { $sub_fields = getArrayValue($options, 'sub_fields'); if ( !$sub_fields || !isset($value) || !$value ) { return ; } $object->SetDBField($sub_fields['date'], $value); $object->SetDBField($sub_fields['time'], $value); } /** * Used for split fields like timestamp -> date, time * Called from DBItem Validate (before validation) to get back master field value from its sub_fields * * @param string $field * @param mixed $value * @param Array $options * @param kDBItem $object */ function UpdateMasterFields($field, $value, &$options, &$object) { $sub_fields = getArrayValue($options, 'sub_fields'); $master_field = getArrayValue($options, 'master_field'); if ( $master_field ) { // when in one of sub_fields - call update for master_field to update its value from sub_fields [are you following ? :) ] $opt = $object->GetFieldOptions($master_field); $this->UpdateMasterFields($master_field, null, $opt, $object); } elseif ( $sub_fields && !$object->GetDBField($field . '_combined') ) { // when in master field - set own value from sub_fields if ( $object->GetDBField($sub_fields['date']) != '' && $object->GetDBField($sub_fields['time']) == '' ) { // when time is not supplied, then use "midnight" (or unit config override) $empty_time = getArrayValue($options, 'empty_time'); if ( $empty_time === false ) { $empty_time = mktime(0, 0, 0); } $object->SetDBField($sub_fields['time'], $empty_time); } elseif ( $object->GetDBField($sub_fields['time']) != '' && $object->GetDBField($sub_fields['date']) == '' ) { // when date is not supplied, then use "1970-01-01 00:00:00" instead (or unit config override) $empty_date = getArrayValue($options, 'empty_date'); if ( $empty_date === false ) { $empty_date = mktime(0, 0, 0, 1, 1, 1970); } $object->SetDBField($sub_fields['date'], $empty_date); } $input_format['date'] = $object->GetFieldOption($sub_fields['date'], 'input_format'); $input_format['time'] = $object->GetFieldOption($sub_fields['time'], 'input_format'); $object->SetField($field, $object->GetField($sub_fields['date'], $input_format['date']) . $options['date_time_separator'] . $object->GetField($sub_fields['time'], $input_format['time'])); } } /** * Formats value of a given field * * @param string $value Value. * @param string $field_name Field name. * @param kDBBase $object Object. * @param string $format Format. * * @return string */ public function Format($value, $field_name, &$object, $format = null) { $options = $object->GetFieldOptions($field_name); if ( is_null($value) ) { if ( $format != 'picker' || !isset($options['picker_default']) ) { return ''; } $value = strtotime($options['picker_default']); } if ( $format == 'picker' ) { $format = '_input_'; } if ( !is_numeric($value) ) { return $value; // for leaving badly formatted date on the form } settype($value, 'int'); if ( !is_int($value) ) { return $value; } if ( isset($format) ) { $options['format'] = $format; } if ( preg_match('/_regional_(.*)/', $options['format'], $regs) ) { // when such type of format is given directly to kDBBase::GetField $options['format'] = $this->language->GetDBField($regs[1]); } if ( $options['format'] == '_input_' ) { // use input format instead of output format $options['format'] = $options['input_format']; } if ( !$options['use_timezone'] ) { return gmdate($options['format'], $value); } $format = defined($options['format']) ? constant($options['format']) : $options['format']; $dt_separator = getArrayValue($options, 'date_time_separator'); if ( $dt_separator ) { $format = trim($format, $dt_separator); } return date($format, $value); } function HumanFormat($format) { $patterns = Array('/m/', '/n/', '/d/', '/j/', '/y/', '/Y/', '/h|H/', '/g|G/', '/i/', '/s/', '/a|A/'); $replace = Array( 'mm', 'm', 'dd', 'd', 'yy', 'yyyy', 'hh', 'h', 'mm', 'ss', 'AM'); $res = preg_replace($patterns, $replace, $format); return $res; } function SQLFormat($format) { $mapping = Array( '/%/' => '%%', '/(? '%p', // Lowercase Ante meridiem and Post meridiem => MySQL provides only uppercase '/(? '%p', // Uppercase Ante meridiem and Post meridiem '/(? '%d', // Day of the month, 2 digits with leading zeros '/(? '%a', // A textual representation of a day, three letters '/(? '%M', // A full textual representation of a month, such as January or March '/(? '%l', // 12-hour format of an hour without leading zeros '/(? '%k', // 24-hour format of an hour without leading zeros '/(? '%h', // 12-hour format of an hour with leading zeros '/(? '%H', // 24-hour format of an hour with leading zeros '/(? '%i', // Minutes with leading zeros '/(? 'N/A', // Whether or not the date is in daylights savings time '/(? 'N/A', // English ordinal suffix for the day of the month, 2 characters, see below '/jS/' => '%D', // MySQL can't return separate suffix, but could return date with suffix '/(? '%e', // Day of the month without leading zeros '/(? '%W', // A full textual representation of the day of the week '/(? 'N/A', // Whether it's a leap year '/(? '%m', // Numeric representation of a month, with leading zeros '/(? '%b', // A short textual representation of a month, three letters '/(? '%c', // Numeric representation of a month, without leading zeros '/(? 'N/A', // Difference to Greenwich time (GMT) in hours '/(? 'N/A', // RFC 2822 formatted date '/(? '%s', // Seconds, with leading zeros // S and jS moved before j - see above '/(? 'N/A', // Number of days in the given month '/(? 'N/A', // Timezone setting of this machine '/(? 'N/A', // Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) '/(? '%w', // Numeric representation of the day of the week '/(? '%v', // ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0) '/(? '%Y', // A full numeric representation of a year, 4 digits '/(? '%y', // A two digit representation of a year '/(? 'N/A', // The day of the year (starting from 0) => MySQL starts from 1 '/(? 'N/A', // Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive. ); $patterns = array_keys($mapping); $replacements = array_values($mapping); $res = preg_replace($patterns, $replacements, $format); return $res; } /** * Converts formatted date+time to timestamp and validates format * * @param mixed $value * @param string $field_name * @param kDBItem $object * @return mixed * @access public */ public function Parse($value, $field_name, &$object) { $options = $object->GetFieldOptions($field_name); $dt_separator = getArrayValue($options,'date_time_separator'); if($dt_separator) $value = trim($value, $dt_separator); if($value == '') return NULL; //return strtotime($value); $format = $options['input_format']; if ($dt_separator) $format = trim($format, $dt_separator); - $error_params = Array( $this->HumanFormat($format), date($format), 'value' => $value ); + $error_params = array( + 'format' => $this->HumanFormat($format), + 'sample' => date($format), + 'value' => $value, + ); $hour = 0; $minute = 0; $second = 0; $month = 1; $day = 1; $year = 1970; $patterns['n'] = '([0-9]{1,2})'; $patterns['m'] = '([0-9]{1,2})'; $patterns['d'] = '([0-9]{1,2})'; $patterns['j'] = '([0-9]{1,2})'; $patterns['Y'] = '([0-9]{4})'; $patterns['y'] = '([0-9]{2})'; $patterns['G'] = '([0-9]{1,2})'; $patterns['g'] = '([0-9]{1,2})'; $patterns['H'] = '([0-9]{2})'; $patterns['h'] = '([0-9]{2})'; $patterns['i'] = '([0-9]{2})'; $patterns['s'] = '([0-9]{2})'; $patterns['a'] = '(am|pm)'; $patterns['A'] = '(AM|PM)'; $holders_mask = '/' . preg_replace('/[a-zA-Z]{1}/i', '([a-zA-Z]{1})', preg_quote($format, '/')) . '/'; if (!preg_match($holders_mask, $format, $holders)) { $object->SetError($field_name, 'bad_date_format', null, $error_params); return $value; } $values_mask = '/^' . preg_quote($format, '/') . '$/'; foreach ($patterns as $key => $val) { $values_mask = str_replace($key, $val, $values_mask); } if (!preg_match($values_mask, $value, $values)) { $object->SetError($field_name, 'bad_date_format', null, $error_params); return $value; } for ($i = 1; $i < count($holders); $i++) { switch ($holders[$i]) { case 'n': case 'm': $month = $values[$i]; $month = preg_replace('/^0{1}/', '', $month); break; case 'd': $day = $values[$i]; $day = preg_replace('/^0{1}/', '', $day); break; case 'Y': $year = $values[$i]; break; case 'y': $year = $values[$i] >= 70 ? 1900 + $values[$i] : 2000 + $values[$i]; break; case 'H': case 'h': case 'G': case 'g': $hour = $values[$i]; $hour = preg_replace('/^0{1}/', '', $hour); break; case 'i': $minute = $values[$i]; $minute = preg_replace('/^0{1}/', '', $minute); break; case 's': $second = $values[$i]; $second = preg_replace('/^0{1}/', '', $second); break; case 'a': case 'A': if ($hour <= 12) { // if AM/PM used with 24-hour - could happen :) if ($values[$i] == 'pm' || $values[$i] == 'PM') { $hour += 12; if ($hour == 24) $hour = 12; } elseif ($values[$i] == 'am' || $values[$i] == 'AM') { if ($hour == 12) $hour = 0; } } break; } } //echo "day: $day, month: $month, year: $year, hour: $hour, minute: $minute
"; /*if (!($year >= 1970 && $year <= 2037)) { $object->SetError($field_name, 'bad_date_format', null, $error_params); return $value; }*/ if (!($month >= 1 && $month <= 12)) { $object->SetError($field_name, 'bad_date_format', null, $error_params); return $value; } $months_days = Array ( 1 => 31,2 => 28, 3 => 31, 4 => 30,5 => 31,6 => 30, 7 => 31, 8 => 31,9 => 30,10 => 31,11 => 30,12 => 31); if ($year % 4 == 0) $months_days[2] = 29; if (!($day >=1 && $day <= $months_days[$month])) { $object->SetError($field_name, 'bad_date_format', null, $error_params); return $value; } if (!($hour >=0 && $hour <= 23)) { $object->SetError($field_name, 'bad_date_format', null, $error_params); return $value; } if (!($minute >=0 && $minute <= 59)) { $object->SetError($field_name, 'bad_date_format', null, $error_params); return $value; } if (!($second >=0 && $second <= 59)) { $object->SetError($field_name, 'bad_date_format', null, $error_params); return $value; } if (!$options['use_timezone']) { return gmmktime($hour, $minute, $second, $month, $day, $year); } return mktime($hour, $minute, $second, $month, $day, $year); } function GetSample($field, &$options, &$object) { return $this->Format( time(), $field, $object, $options['input_format']); } } Index: branches/5.3.x/core/kernel/utility/formatters/formatter.php =================================================================== --- branches/5.3.x/core/kernel/utility/formatters/formatter.php (revision 16599) +++ branches/5.3.x/core/kernel/utility/formatters/formatter.php (revision 16600) @@ -1,309 +1,305 @@ _categoryHelper = $this->Application->recallObject('CategoryHelper'); } /** * Replace FCK links like "@@ID@@" to real page urls, when "using_fck" option is set. * * @param string $value * @param Array $options * @param string $format * @return string */ function _replaceFCKLinks(&$value, $options, $format = null) { if ((isset($format) && strpos($format, 'fck_ready') !== false) || (!array_key_exists('using_fck', $options) || !$options['using_fck'])) { // in textarea, where fck will be used OR not using fck return $value; } return $this->_categoryHelper->replacePageIds($value); } /** * Convert's value to match type from config * * @param mixed $value * @param Array $options * @return mixed * @access protected */ function TypeCast($value, $options) { - $ret = true; - if ( isset($options['type']) ) { $field_type = $options['type']; if ($field_type == 'numeric') { trigger_error('Invalid field type ' . $field_type . ' (in TypeCast method), please use float instead', E_USER_NOTICE); $field_type = 'float'; } elseif ( $field_type == 'string' ) { if ( isset($options['allow_html']) && $options['allow_html'] ) { $value = $this->Application->unescapeRequestVariable($value); } return $value; } $value = $this->formatNumber($value); - $type_ok = preg_match('#int|integer|double|float|real|numeric|string#', $field_type); + $is_numeric_type = preg_match('#int|integer|double|float|real#', $field_type); - if ( $value != '' && $type_ok ) { - $ret = is_numeric($value); + if ( $value != '' && $is_numeric_type ) { + $tc_value = $value; + settype($tc_value, $field_type); - if ($ret) { - $f = 'is_' . $field_type; - settype($value, $field_type); - $ret = $f($value); - } + // Type casing is considered a success only, when type casted value visually looks the same. + return (string)$value === (string)$tc_value ? $tc_value : false; } } - return $ret ? $value : false; + return $value; } /** * Formats number, according to regional settings * * @param string $number * @return float */ function formatNumber($number) { static $comma = null, $thousands = null; if ( !isset($comma) || !isset($thousands) ) { /** @var LanguagesItem $lang */ $lang = $this->Application->recallObject('lang.current'); $comma = $lang->GetDBField('DecimalPoint'); $thousands = $lang->GetDBField('ThousandSep'); } $number = str_replace($thousands, '', $number); $number = str_replace($comma, '.', $number); return $number; } /** * Applies type casting on each array element * @param Array $src * @param kDBItem|kDBList|kDBBase $object * @return Array * @access public */ public function TypeCastArray($src, &$object) { $dst = array (); foreach ($src as $id => $row) { $tmp_row = array (); foreach ($row as $fld => $value) { $field_options = $object->GetFieldOptions($fld); $tmp_row[$fld] = $this->TypeCast($value, $field_options); } $dst[$id] = $tmp_row; } return $dst; } /** * Formats value of a given field * * @param string $value * @param string $field_name * @param kDBItem|kDBList|kDBBase $object * @param string $format * @return string */ function Format($value, $field_name, &$object, $format = null) { if ( is_null($value) ) { return ''; } $options = $object->GetFieldOptions($field_name); if (!isset($format) && array_key_exists('format', $options)) { $format = $options['format']; } if ($value === false) { // used ? return $value; // for leaving badly formatted date on the form } $original_format = $format; if (isset($format)) { if (strpos($format, 'fck_ready') !== false) { $format = trim(str_replace('fck_ready', '', $format), ';'); } } if (isset($format) && $format) { if ( substr($format, -1) === 'f' ) { // High precision formats (e.g. '%01.20f') are not supported to keep code below as fast as possible. $value = round($value, substr($format, -2, 1)); } $value = sprintf($format, $value); if ( isset($options['cut_zeros']) && $options['cut_zeros'] ) { // Remove trailing zeros in decimal part (including "." if any left at the end). $value = preg_replace('/\.0+$/', '', $value); $value = preg_replace('/(\.\d+?)0+$/', '$1', $value); } } if (preg_match('#int|integer|double|float|real|numeric#', $options['type'])) { /** @var LanguagesItem $lang */ $lang = $this->Application->recallObject('lang.current'); return $lang->formatNumber($value); } elseif ($options['type'] == 'string') { $value = $this->_replaceFCKLinks($value, $options, $original_format); } return $value; } /** * Performs basic type validation on form field value * * @param mixed $value * @param string $field_name * @param kDBItem|kDBList|kDBBase $object * @return mixed * @access public */ public function Parse($value, $field_name, &$object) { $options = $object->GetFieldOptions($field_name); if ($value == '') { return $options['type'] == 'string' ? $value : null; } $tc_value = $this->TypeCast($value, $options); if ($tc_value === false) { return $value; // for leaving badly formatted date on the form } if(isset($options['type'])) { if (preg_match('#double|float|real|numeric#', $options['type'])) { $tc_value = str_replace(',', '.', $tc_value); } } if (isset($options['regexp'])) { if (!preg_match($options['regexp'], $value)) { $object->SetError($field_name, 'invalid_format'); } } return $tc_value; } function HumanFormat($format) { return $format; } /** * The method is supposed to alter config options or cofigure object in some way based on its usage of formatters * The methods is called for every field with formatter defined when configuring item. * Could be used for adding additional VirtualFields to an object required by some special Formatter * * @param string $field_name * @param array $field_options * @param kDBBase $object */ function PrepareOptions($field_name, &$field_options, &$object) { } /** * Used for split fields like timestamp -> date, time * Called from DBItem to update sub fields values after loading item * * @param string $field * @param string $value * @param Array $options * @param kDBItem|kDBList|kDBBase $object * @return void * @access public */ public function UpdateSubFields($field, $value, &$options, &$object) { } /** * Used for split fields like timestamp -> date, time * Called from DBItem Validate (before validation) to get back master field value from its sub_fields * * @param string $field * @param mixed $value * @param Array $options * @param kDBItem|kDBList|kDBBase $object */ function UpdateMasterFields($field, $value, &$options, &$object) { } /** * Return sample value, that can be entered in this field * * @param string $field * @param Array $options * @param kDBItem|kDBList|kDBBase $object * @return string * @access public */ public function GetSample($field, &$options, &$object) { return isset($options['sample_value']) ? $options['sample_value'] : ''; } } Index: branches/5.3.x/core/kernel/utility/formatters/upload_formatter.php =================================================================== --- branches/5.3.x/core/kernel/utility/formatters/upload_formatter.php (revision 16599) +++ branches/5.3.x/core/kernel/utility/formatters/upload_formatter.php (revision 16600) @@ -1,627 +1,647 @@ fileHelper = $this->Application->recallObject('FileHelper'); if ( $this->DestinationPath ) { $this->FullPath = FULL_PATH . $this->DestinationPath; } } /** + * Sets field option defaults. + * + * @param string $field_name Field nae. + * @param array $field_options Field options. + * @param kDBBase $object Object. + * + * @return void + */ + public function PrepareOptions($field_name, &$field_options, &$object) + { + if ( !$this->DestinationPath && !isset($field_options['upload_dir']) ) { + $base_path = $object->getUnitConfig()->getBasePath(); + $field_options['upload_dir'] = WRITEBALE_BASE . '/' . basename($base_path) . '/'; + } + + if ( !isset($field_options['max_size']) ) { + $field_options['max_size'] = MAX_UPLOAD_SIZE; + } + } + + /** * Processes file uploads from form * * @param mixed $value * @param string $field_name * @param kDBItem $object * @return mixed * @access public */ public function Parse($value, $field_name, &$object) { $value = $this->Application->HttpQuery->unescapeRequestVariable($value); $options = $object->GetFieldOptions($field_name); if ( getArrayValue($options, 'upload_dir') ) { $this->DestinationPath = $options['upload_dir']; $this->FullPath = FULL_PATH . $this->DestinationPath; } if ( is_array($value) && isset($value['tmp_ids']) ) { - // SWF Uploader - return $this->_processFlashUploader($value, $field_name, $object); + $ret = $this->_processFlashUploader($value, $field_name, $object); + } + else { + $ret = $this->_processRegularUploader($value, $field_name, $object); + } + + if ( getArrayValue($options, 'upload_dir') ) { + $this->DestinationPath = null; + $this->FullPath = null; } - return $this->_processRegularUploader($value, $field_name, $object); + return $ret; } /** * Handles uploaded files, provided by Flash uploader * * @param Array|string $value * @param string $field_name * @param kDBItem $object * @return string * @access protected */ protected function _processFlashUploader($value, $field_name, $object) { $options = $object->GetFieldOptions($field_name); $this->sorting = isset($value['order']) ? explode('|', $value['order']) : Array (); if ( $value['tmp_deleted'] ) { $n_upload = Array (); $deleted = explode('|', $value['tmp_deleted']); $upload = explode('|', $value['upload']); foreach ($upload as $name) { if ( in_array($name, $deleted) ) { continue; } $n_upload[] = $name; } $value['upload'] = implode('|', $n_upload); } if ( !$value['tmp_ids'] ) { // no pending files -> return already uploaded files return $this->_sortFiles($value['upload']); } $swf_uploaded_ids = explode('|', $value['tmp_ids']); $swf_uploaded_names = explode('|', $value['tmp_names']); $existing = $value['upload'] ? explode('|', $value['upload']) : Array (); $fret = Array (); $max_files = $this->_getMaxFiles($options); $pending_actions = $object->getPendingActions(); $files_to_delete = $this->_getFilesToDelete($object); for ($i = 0; $i < min($max_files, count($swf_uploaded_ids)); $i++) { // don't delete uploaded file, when it's name matches delete file name $real_name = $this->_getRealFilename($swf_uploaded_names[$i], $options, $object, $files_to_delete); $file_name = $this->FullPath . $real_name; $tmp_file = WRITEABLE . '/tmp/' . $swf_uploaded_ids[$i] . '_' . $swf_uploaded_names[$i]; rename($tmp_file, $file_name); @chmod($file_name, 0666); $fret[] = getArrayValue($options, 'upload_dir') ? $real_name : $this->DestinationPath . $real_name; $pending_actions[] = Array ( 'action' => 'make_live', 'id' => $object->GetID(), 'field' => $field_name, 'file' => $file_name ); $this->_renameFileInSorting($swf_uploaded_names[$i], $real_name); } $object->setPendingActions($pending_actions); return $this->_sortFiles(array_merge($existing, $fret)); } /** * Returns files, scheduled for deleting * * @param kDBItem $object * @return Array * @access protected */ protected function _getFilesToDelete($object) { $ret = Array (); foreach ($object->getPendingActions() as $data) { if ( $data['action'] == 'delete' ) { $ret[] = $data['file']; } } return $ret; } /** * Handles regular file upload * * @param string|Array $value * @param string $field_name * @param kDBItem $object * @return string * @access protected */ protected function _processRegularUploader($value, $field_name, $object) { $ret = !is_array($value) ? $value : ''; $options = $object->GetFieldOptions($field_name); if ( getArrayValue($value, 'upload') && getArrayValue($value, 'error') == UPLOAD_ERR_NO_FILE ) { // file was not uploaded this time, but was uploaded before, then use previously uploaded file (from db) return getArrayValue($value, 'upload'); } if ( is_array($value) && count($value) > 1 && $value['size'] ) { if ( is_array($value) && (int)$value['error'] === UPLOAD_ERR_OK ) { - $max_file_size = isset($options['max_size']) ? $options['max_size'] : MAX_UPLOAD_SIZE; - // we can get mime type based on file content and don't use one, provided by the client // $value['type'] = kUtil::mimeContentType($value['tmp_name']); if ( getArrayValue($options, 'file_types') && !$this->extensionMatch($value['name'], $options['file_types']) ) { // match by file extensions $error_params = Array ( 'file_name' => $value['name'], 'file_types' => $options['file_types'], ); $object->SetError($field_name, 'bad_file_format', 'la_error_InvalidFileFormat', $error_params); } elseif ( getArrayValue($options, 'allowed_types') && !in_array($value['type'], $options['allowed_types']) ) { // match by mime type provided by web-browser $error_params = Array ( 'file_type' => $value['type'], 'allowed_types' => $options['allowed_types'], ); $object->SetError($field_name, 'bad_file_format', 'la_error_InvalidFileFormat', $error_params); } - elseif ( $value['size'] > $max_file_size ) { + elseif ( $value['size'] > $options['max_size'] ) { $object->SetError($field_name, 'bad_file_size', 'la_error_FileTooLarge'); } elseif ( !is_writable($this->FullPath) ) { $object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file'); } else { $real_name = $this->_getRealFilename($value['name'], $options, $object); $file_name = $this->FullPath . $real_name; + $moved = move_uploaded_file($value['tmp_name'], $file_name); $storage_format = isset($options['storage_format']) ? $options['storage_format'] : false; if ( $storage_format ) { - /** @var ImageHelper $image_helper */ - $image_helper = $this->Application->recallObject('ImageHelper'); - - move_uploaded_file($value['tmp_name'], $value['tmp_name'] . '.jpg'); // add extension, so ResizeImage can work - $url = $image_helper->ResizeImage($value['tmp_name'] . '.jpg', $storage_format); - $tmp_name = preg_replace('/^' . preg_quote($this->Application->BaseURL(), '/') . '/', '/', $url); - $moved = rename($tmp_name, $file_name); - } - else { - $moved = move_uploaded_file($value['tmp_name'], $file_name); + /** @var kUploadHelper $upload_helper */ + $upload_helper = $this->Application->recallObject('kUploadHelper'); + $moved = $upload_helper->resizeUploadedFile($file_name, $storage_format); } if ( !$moved ) { $object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file'); } else { @chmod($file_name, 0666); if ( getArrayValue($options, 'size_field') ) { $object->SetDBField($options['size_field'], $value['size']); } if ( getArrayValue($options, 'orig_name_field') ) { $object->SetDBField($options['orig_name_field'], $value['name']); } if ( getArrayValue($options, 'content_type_field') ) { $object->SetDBField($options['content_type_field'], $value['type']); } $ret = getArrayValue($options, 'upload_dir') ? $real_name : $this->DestinationPath . $real_name; // delete previous file, when new file is uploaded under same field /*$previous_file = isset($value['upload']) ? $value['upload'] : false; if ( $previous_file && file_exists($this->FullPath . $previous_file) ) { unlink($this->FullPath . $previous_file); }*/ } } } else { $object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file'); } } if ( (count($value) > 1) && $value['error'] && ($value['error'] != UPLOAD_ERR_NO_FILE) ) { $object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file', $value); } return $ret; } /** * Checks, that given file name has on of provided file extensions * * @param string $filename * @param string $file_types * @return bool * @access protected */ protected function extensionMatch($filename, $file_types) { if ( preg_match_all('/\*\.(.*?)(;|$)/', $file_types, $regs) ) { $file_extension = mb_strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $file_extensions = array_map('mb_strtolower', $regs[1]); return in_array($file_extension, $file_extensions); } return true; } /** * Resorts uploaded files according to given file order * * @param Array|string $files * @return string * @access protected */ protected function _sortFiles($files) { if ( !is_array($files) ) { $files = explode('|', $files); } $sorted_files = array_intersect($this->sorting, $files); // removes deleted files from sorting $new_files = array_diff($files, $sorted_files); // files, that weren't sorted - add to the end return implode('|', array_merge($sorted_files, $new_files)); } /** * Returns maximal allowed file count per field * * @param Array $options * @return int * @access protected */ protected function _getMaxFiles($options) { if ( !isset($options['multiple']) ) { return 1; } return $options['multiple'] == false ? 1 : $options['multiple']; } /** * Returns final filename after applying storage-engine specific naming * * @param string $file_name * @param Array $options * @param kDBItem $object * @param Array $files_to_delete * @return string * @access protected */ protected function _getRealFilename($file_name, $options, $object, $files_to_delete = Array ()) { $real_name = $this->getStorageEngineFile($file_name, $options, $object->Prefix); $real_name = $this->getStorageEngineFolder($real_name, $options) . $real_name; return $this->fileHelper->ensureUniqueFilename($this->FullPath, $real_name, $files_to_delete); } /** * Renames file in sorting list * * @param string $old_name * @param string $new_name * @return void * @access protected */ protected function _renameFileInSorting($old_name, $new_name) { $index = array_search($old_name, $this->sorting); if ( $index !== false ) { $this->sorting[$index] = $new_name; } } function getSingleFormat($format) { $single_mapping = Array ( 'file_raw_urls' => 'raw_url', 'file_display_names' => 'display_name', 'file_urls' => 'full_url', 'file_paths' => 'full_path', 'file_sizes' => 'file_size', 'files_resized' => 'resize', 'img_sizes' => 'img_size', 'wms' => 'wm', ); return $single_mapping[$format]; } /** * Return formatted file url,path or size (or same for multiple files) * * @param string $value * @param string $field_name * @param kDBItem|kDBList $object * @param string $format * @return string */ function Format($value, $field_name, &$object, $format = NULL) { if ( is_null($value) ) { return ''; } $options = $object->GetFieldOptions($field_name); if ( !isset($format) ) { $format = isset($options['format']) ? $options['format'] : false; } if ( $format && preg_match('/(file_raw_urls|file_display_names|file_urls|file_paths|file_names|file_sizes|img_sizes|files_resized|wms)(.*)/', $format, $regs) ) { if ( !$value || $format == 'file_names' ) { // storage format matches display format OR no value return $value; } $ret = Array (); $files = explode('|', $value); $format = $this->getSingleFormat($regs[1]) . $regs[2]; foreach ($files as $a_file) { $ret[] = $this->GetFormatted($a_file, $field_name, $object, $format); } return implode('|', $ret); } $tc_value = $this->TypeCast($value, $options); if ( ($tc_value === false) || ($tc_value != $value) ) { // for leaving badly formatted date on the form return $value; } return $this->GetFormatted($tc_value, $field_name, $object, $format); } /** * Return formatted file url,path or size * * @param string $value * @param string $field_name * @param kDBItem $object * @param string $format * @return string */ function GetFormatted($value, $field_name, &$object, $format = NULL) { if ( !$format ) { return $value; } $options = $object->GetFieldOptions($field_name); $upload_dir = isset($options['include_path']) && $options['include_path'] ? '' : $this->getUploadDir($options); $file_path = strlen($value) ? FULL_PATH . str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . $value : ''; if ( preg_match('/resize:([\d]*)x([\d]*)/', $format, $regs) ) { /** @var ImageHelper $image_helper */ $image_helper = $this->Application->recallObject('ImageHelper'); try { return $image_helper->ResizeImage($file_path, $format); } catch ( RuntimeException $e ) { // error, during image resize -> return empty string return ''; } } elseif ( !strlen($file_path) || !file_exists($file_path) ) { // file doesn't exist OR not uploaded return ''; } switch ($format) { case 'display_name': return kUtil::removeTempExtension($value); break; case 'raw_url': return $this->fileHelper->pathToUrl($file_path); break; case 'full_url': $direct_links = isset($options['direct_links']) ? $options['direct_links'] : true; if ( $direct_links ) { return $this->fileHelper->pathToUrl($file_path); } else { $url_params = Array ( 'pass' => 'm,'.$object->Prefix, $object->Prefix . '_event' => 'OnViewFile', 'file' => $value, 'field' => $field_name ); return $this->Application->HREF('', '', $url_params); } break; case 'full_path': return $file_path; break; case 'file_size': return filesize($file_path); break; case 'img_size': /** @var ImageHelper $image_helper */ $image_helper = $this->Application->recallObject('ImageHelper'); $image_info = $image_helper->getImageInfo($file_path); return $image_info ? $image_info[3] : ''; break; } return sprintf($format, $value); } /** * Creates & returns folder, based on storage engine specified in field options * * @param string $file_name * @param array $options * @return string * @access protected * @throws Exception */ protected function getStorageEngineFolder($file_name, $options) { $storage_engine = (string)getArrayValue($options, 'storage_engine'); if ( !$storage_engine ) { return ''; } switch ($storage_engine) { case StorageEngine::HASH: $folder_path = kUtil::getHashPathForLevel($file_name); break; case StorageEngine::TIMESTAMP: $folder_path = date('Y-m/d/'); break; default: throw new Exception('Unknown storage engine "' . $storage_engine . '".'); break; } return $folder_path; } /** * Applies prefix & suffix to uploaded filename, based on storage engine in field options * * @param string $name * @param array $options * @param string $unit_prefix * @return string * @access protected */ protected function getStorageEngineFile($name, $options, $unit_prefix) { $prefix = $this->getStorageEngineFilePart(getArrayValue($options, 'filename_prefix'), $unit_prefix); $suffix = $this->getStorageEngineFilePart(getArrayValue($options, 'filename_suffix'), $unit_prefix); $parts = pathinfo($name); return ($prefix ? $prefix . '_' : '') . $parts['filename'] . ($suffix ? '_' . $suffix : '') . '.' . $parts['extension']; } /** * Creates prefix/suffix to join with uploaded file * * Added "u" before user_id to keep this value after FileHelper::ensureUniqueFilename method call * * @param string $option * @param string $unit_prefix * @return string * @access protected */ protected function getStorageEngineFilePart($option, $unit_prefix) { $replace_from = Array ( StorageEngine::PS_DATE_TIME, StorageEngine::PS_PREFIX, StorageEngine::PS_USER ); $replace_to = Array ( date('Ymd-His'), $unit_prefix, 'u' . $this->Application->RecallVar('user_id') ); return str_replace($replace_from, $replace_to, $option); } public function getUploadDir($options) { return isset($options['upload_dir']) ? $options['upload_dir'] : $this->DestinationPath; } } class kPictureFormatter extends kUploadFormatter { public function __construct() { $this->NakeLookupPath = IMAGES_PATH; // used ? $this->DestinationPath = kUtil::constOn('ADMIN') ? IMAGES_PENDING_PATH : IMAGES_PATH; parent::__construct(); } /** * Return formatted file url,path or size * * @param string $value * @param string $field_name * @param kDBItem $object * @param string $format * @return string */ function GetFormatted($value, $field_name, &$object, $format = NULL) { if ( $format == 'img_size' ) { $options = $object->GetFieldOptions($field_name); $img_path = FULL_PATH . '/' . $this->getUploadDir($options) . $value; $image_info = getimagesize($img_path); return ' ' . $image_info[3]; } return parent::GetFormatted($value, $field_name, $object, $format); } } Index: branches/5.3.x/core/kernel/utility/http_query.php =================================================================== --- branches/5.3.x/core/kernel/utility/http_query.php (revision 16599) +++ branches/5.3.x/core/kernel/utility/http_query.php (revision 16600) @@ -1,792 +1,806 @@ Order = $order; - if ( isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') { - // when AJAX request is made from jQuery, then create ajax variable, - // so any logic based in it (like redirects) will not break down + if ( isset($_SERVER['HTTP_PROXY']) && PHP_SAPI !== 'cli' ) { + throw new RuntimeException('Web Requests with "Proxy" header are forbidden.'); + } + + if ( isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ) { + // When AJAX request is made from jQuery, then create ajax variable, + // so any logic based in it (like redirects) will not break down. $_GET['ajax'] = 'yes'; } $this->_trustProxy = kUtil::getSystemConfig()->get('TrustProxy'); } /** * Discovers unit form request and returns it's QueryString option on success * * @param string $prefix_special * * @return Array|bool * @access public */ public function discoverUnit($prefix_special) { list($prefix) = explode('.', $prefix_special); $query_string = $this->getQueryString($prefix); if ($query_string) { // only units with QueryString option can be discovered $this->discoveredUnits[$prefix_special] = $query_string; return $query_string; } unset( $this->discoveredUnits[$prefix] ); return false; } /** * Returns units, passed in request * * @param bool $prefix_special_only * @return Array * @access protected */ public function getDiscoveredUnits($prefix_special_only = true) { return $prefix_special_only ? array_keys( $this->discoveredUnits ) : $this->discoveredUnits; } /** * Returns QueryMap for requested unit config. * In case if unit config is a clone, then get parent item's (from prefix) config to create clone * * @param string $prefix * @return Array * @access protected */ protected function getQueryString($prefix) { return $this->Application->getUnitConfig($prefix)->getQueryString(Array ()); } /** * Removes specials from request * * @param Array $array * @return Array * @access protected */ protected function _removeSpecials($array) { $ret = Array (); $removed = false; foreach ($this->specialsToRemove as $prefix_special => $flag) { if ( $flag ) { $removed = true; list ($prefix, $special) = explode('.', $prefix_special, 2); foreach ($array as $key => $val) { $new_key = preg_match("/^" . $prefix . "[._]{1}" . $special . "(.*)/", $key, $regs) ? $prefix . $regs[1] : $key; $ret[$new_key] = is_array($val) ? $this->_removeSpecials($val) : $val; } } } return $removed ? $ret : $array; } public function process() { $this->AddAllVars(); $this->removeSpecials(); ini_set('magic_quotes_gpc', 0); $this->Application->UrlManager->LoadStructureTemplateMapping(); $this->AfterInit(); } /** * All all requested vars to * common storage place * * @return void * @access protected */ protected function AddAllVars() { for ($i = 0; $i < strlen($this->Order); $i++) { switch ($this->Order[$i]) { case 'G': $this->Get = $this->AddVars($_GET); if ( array_key_exists('sid', $_GET) ) { $this->_sidInQueryString = true; } $vars = $this->Application->processQueryString($this->Get(ENV_VAR_NAME)); if ( array_key_exists('sid', $vars) ) { // used by Session::GetPassedSIDValue $this->Get['sid'] = $vars['sid']; } $this->AddParams($vars); break; case 'P': $this->Post = $this->AddVars($_POST); $this->convertPostEvents(); $this->_processPostEnvVariables(); break; case 'C': $cookie_hasher = $this->Application->makeClass('kCookieHasher'); /* @var $cookie_hasher kCookieHasher */ $parsed_cookies = Array (); foreach ($_COOKIE as $cookie_name => $encrypted_value) { $parsed_cookies[$cookie_name] = $cookie_hasher->decrypt($cookie_name, $encrypted_value); } $this->Cookie = $this->AddVars($parsed_cookies); break; /*case 'E'; $this->Env = $this->AddVars($_ENV, false); //do not strip slashes! break; case 'S'; $this->Server = $this->AddVars($_SERVER, false); //do not strip slashes! break;*/ case 'F'; $this->convertFiles(); $this->Files = $this->MergeVars($_FILES); // , false); //do not strip slashes! break; } } } /** * Allow POST variables, that names were transformed by PHP ("." replaced with "_") to * override variables, that were virtually created through environment variable parsing * */ function _processPostEnvVariables() { $passed = $this->Get('passed'); if ( !$passed ) { return; } $passed = explode(',', $passed); foreach ($passed as $prefix_special) { if ( strpos($prefix_special, '.') === false ) { continue; } list ($prefix, $special) = explode('.', $prefix_special); $query_map = $this->getQueryString($prefix); $post_prefix_special = $prefix . '_' . $special; foreach ($query_map as $var_name) { if ( array_key_exists($post_prefix_special . '_' . $var_name, $this->Post) ) { $this->Set($prefix_special . '_' . $var_name, $this->Post[$post_prefix_special . '_' . $var_name]); } } } } /** * Removes requested specials from all request variables * * @return void * @access protected */ protected function removeSpecials() { $this->specialsToRemove = $this->Get('remove_specials'); if ( $this->specialsToRemove ) { foreach ($this->specialsToRemove as $prefix_special => $flag) { if ( $flag && strpos($prefix_special, '.') === false ) { unset($this->specialsToRemove[$prefix_special]); trigger_error('Incorrect usage of "remove_specials[' . $prefix_special . ']" field (no special found)', E_USER_NOTICE); } } $this->_Params = $this->_removeSpecials($this->_Params); } } /** * Finishes initialization of kHTTPQuery class. * * @return void */ protected function AfterInit() { $rewrite_url = $this->Get('_mod_rw_url_'); if ( $this->Application->RewriteURLs() || $rewrite_url ) { // maybe call onafterconfigread here $this->Application->UrlManager->initRewrite(); if ( defined('DEBUG_MODE') && $this->Application->isDebugMode() ) { $this->Application->Debugger->profileStart('url_parsing', 'Parsing MOD_REWRITE url'); $this->Application->UrlManager->rewrite->parseRewriteURL(); $description = 'Parsing MOD_REWRITE url (template: ' . $this->Get('t') . ')'; $this->Application->Debugger->profileFinish('url_parsing', $description); } else { $this->Application->UrlManager->rewrite->parseRewriteURL(); } if ( !$rewrite_url && $this->rewriteRedirectRequired() ) { // rewrite url is missing (e.g. not a script from tools folder) $url_params = $this->getRedirectParams(); // no idea about how to check, that given template require category to be passed with it, so pass anyway $url_params['pass_category'] = 1; $url_params['response_code'] = 301; // Moved Permanently trigger_error('Non mod-rewrite url "' . $_SERVER['REQUEST_URI'] . '" used', E_USER_NOTICE); $this->Application->Redirect('', $url_params); } + + if ( $this->Application->GetVar('is_friendly_url') ) { + $url_params = $this->getRedirectParams(); + + // No idea about how to check, that given template + // require category to be passed with it, so pass anyway. + $url_params['pass_category'] = 1; + + $this->Application->Redirect('', $url_params); + } } else { $this->Application->VerifyThemeId(); $this->Application->VerifyLanguageId(); } $virtual_template = $this->Application->getVirtualPageTemplate($this->Get('m_cat_id')); if ( ($virtual_template !== false) && preg_match('/external:(.*)/', $virtual_template) ) { trigger_error('URL of page, that has "External URL" set was accessed: "' . $_SERVER['REQUEST_URI'] . '"', E_USER_NOTICE); $this->Application->Redirect($virtual_template); } if ( !$this->Application->isAdmin && $this->Application->ConfigValue('ForceCanonicalUrls') ) { $template = $this->Application->GetVar('t'); $seo_template = $this->Application->getSeoTemplate($template); if ( $seo_template && $seo_template != $template ) { $url_params = $this->getRedirectParams(); $url_params['response_code'] = 301; trigger_error('Request url "' . $_SERVER['REQUEST_URI'] . '" points directly to physical template', E_USER_NOTICE); $this->Application->Redirect($seo_template, $url_params); } } } /** * Checks, that non-rewrite url was visited and it's automatic rewrite is required * * @return bool */ function rewriteRedirectRequired() { $redirect_conditions = Array ( !$this->IsHTTPSRedirect(), // not https <-> http redirect !$this->refererIsOurSite(), // referer doesn't match ssl path or non-ssl domain (same for site domains) !defined('GW_NOTIFY'), // not in payment gateway notification script preg_match('/[\/]{0,1}index.php[\/]{0,1}/', $_SERVER['PHP_SELF']), // "index.php" was visited $this->Get('t') != 'index', // not on index page ); $perform_redirect = true; foreach ($redirect_conditions as $redirect_condition) { $perform_redirect = $perform_redirect && $redirect_condition; if (!$perform_redirect) { return false; } } return true; } /** * This is redirect from https to http or via versa * * @return bool */ function IsHTTPSRedirect() { $http_referer = array_key_exists('HTTP_REFERER', $_SERVER) ? $_SERVER['HTTP_REFERER'] : false; return ( ( PROTOCOL == 'https://' && preg_match('#http:\/\/#', $http_referer) ) || ( PROTOCOL == 'http://' && preg_match('#https:\/\/#', $http_referer) ) ); } /** * Checks, that referer is out site * * @return bool */ function refererIsOurSite() { if ( !array_key_exists('HTTP_REFERER', $_SERVER) ) { // no referer -> don't care what happens return false; } /** @var SiteHelper $site_helper */ $site_helper = $this->Application->recallObject('SiteHelper'); $parsed_url = parse_url($_SERVER['HTTP_REFERER']); if ( $parsed_url['scheme'] == 'https' ) { $found = $site_helper->compare($parsed_url['host'], 'SSLDomainName', $this->Application->ConfigValue('SSLDomain')); } else { $found = $site_helper->compare($parsed_url['host'], 'DomainName', DOMAIN); } return $found; } function convertFiles() { if ( !$_FILES ) { return ; } $tmp = Array (); $file_keys = Array ('error', 'name', 'size', 'tmp_name', 'type'); foreach ($_FILES as $file_name => $file_info) { if ( is_array($file_info['error']) ) { $tmp[$file_name] = $this->getArrayLevel($file_info['error'], $file_name); } else { $normal_files[$file_name] = $file_info; } } if ( !$tmp ) { return ; } $files = $_FILES; $_FILES = Array (); foreach ($tmp as $prefix => $prefix_files) { $anchor =& $_FILES; foreach ($prefix_files['keys'] as $key) { $anchor =& $anchor[$key]; } foreach ($prefix_files['value'] as $field_name) { unset($inner_anchor, $copy); $work_copy = $prefix_files['keys']; foreach ($file_keys as $file_key) { $inner_anchor =& $files[$prefix][$file_key]; if ( isset($copy) ) { $work_copy = $copy; } else { $copy = $work_copy; } array_shift($work_copy); foreach ($work_copy as $prefix_file_key) { $inner_anchor =& $inner_anchor[$prefix_file_key]; } $anchor[$field_name][$file_key] = $inner_anchor[$field_name]; } } } // keys: img_temp, 0, values: LocalPath, ThumbPath } function getArrayLevel(&$level, $prefix='') { $ret['keys'] = $prefix ? Array($prefix) : Array(); $ret['value'] = Array(); foreach($level as $level_key => $level_value) { if( is_array($level_value) ) { $ret['keys'][] = $level_key; $tmp = $this->getArrayLevel($level_value); $ret['keys'] = array_merge($ret['keys'], $tmp['keys']); $ret['value'] = array_merge($ret['value'], $tmp['value']); } else { $ret['value'][] = $level_key; } } return $ret; } /** * Overwrites GET events with POST events in case if they are set and not empty * * @return void * @access protected */ protected function convertPostEvents() { /** @var Array $events */ $events = $this->Get('events', Array ()); if ( is_array($events) ) { $events = array_filter($events); foreach ($events as $prefix_special => $event_name) { $this->Set($prefix_special . '_event', $event_name); } } } function finalizeParsing($passed = Array()) { if (!$passed) { return; } foreach ($passed as $passed_prefix) { $this->discoverUnit($passed_prefix); // from mod-rewrite url parsing } $this->Set('passed', implode(',', $this->getDiscoveredUnits())); } /** * Saves variables from array specified * into common variable storage place * * @param Array $array * @param bool $strip_slashes * @return Array * @access private */ function AddVars($array, $strip_slashes = true) { if ( $strip_slashes ) { $array = $this->StripSlashes($array); } foreach ($array as $key => $value) { $this->Set($key, $value); } return $array; } function MergeVars($array, $strip_slashes = true) { if ( $strip_slashes ) { $array = $this->StripSlashes($array); } foreach ($array as $key => $value_array) { // $value_array is an array too $this->_Params = kUtil::array_merge_recursive($this->_Params, Array ($key => $value_array)); } return $array; } function StripSlashes($array) { static $magic_quotes = null; if (!isset($magic_quotes)) { $magic_quotes = get_magic_quotes_gpc(); } foreach ($array as $key => $value) { if (is_array($value)) { $array[$key] = $this->StripSlashes($value); } else { if ($magic_quotes) { $value = stripslashes($value); } if (!$this->Application->isAdmin) { // TODO: always escape output instead of input $value = kUtil::escape($value, kUtil::ESCAPE_HTML); } $array[$key] = $value; } } return $array; } /** * Removes forceful escaping done to the variable upon Front-End submission. * * @param string|array $value Value. * * @return string|array * @see StripSlashes */ public function unescapeRequestVariable($value) { if ( $this->Application->isAdmin ) { return $value; } // This allows to revert kUtil::escape() call for each field submitted on front-end. if ( is_array($value) ) { foreach ( $value as $param_name => $param_value ) { $value[$param_name] = $this->unescapeRequestVariable($param_value); } return $value; } return kUtil::unescape($value, kUtil::ESCAPE_HTML); } /** * Returns all $_GET array excluding system parameters, that are not allowed to be passed through generated urls * * @param bool $access_error Method is called during no_permission, require login, session expiration link preparation * @return Array */ function getRedirectParams($access_error = false) { $vars = $this->Get; $unset_vars = Array (ENV_VAR_NAME, 'rewrite', '_mod_rw_url_', 'Action'); if (!$this->_sidInQueryString) { $unset_vars[] = 'sid'; } // remove system variables foreach ($unset_vars as $var_name) { if (array_key_exists($var_name, $vars)) { unset($vars[$var_name]); } } if ($access_error) { // place 1 of 2 (also in UsersEventHandler::OnSessionExpire) $vars = $this->_removePassThroughVariables($vars); } return $vars; } /** * Removes all pass_though variables from redirect params * * @param Array $url_params * @return Array */ function _removePassThroughVariables($url_params) { $pass_through = array_key_exists('pass_through', $url_params) ? $url_params['pass_through'] : ''; if (!$pass_through) { return $url_params; } $pass_through = explode(',', $pass_through . ',pass_through'); foreach ($pass_through as $pass_through_var) { unset($url_params[$pass_through_var]); } $url_params['no_pass_through'] = 1; // this way kApplication::HREF won't add them again return $url_params; } /** * Checks, that url is empty * * @return bool * @access public */ public function isEmptyUrl() { if ( $this->Application->RewriteURLs() ) { return !$this->Get('_mod_rw_url_'); } return !count($this->Get); } /** * Returns the client IP address. * * @return string The client IP address * @access public */ public function getClientIp() { if ( $this->_trustProxy ) { if ( array_key_exists('HTTP_CLIENT_IP', $_SERVER) ) { return $_SERVER['HTTP_CLIENT_IP']; } if ( array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER) ) { $client_ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); foreach ($client_ip as $ip_address) { $clean_ip_address = trim($ip_address); if ( false !== filter_var($clean_ip_address, FILTER_VALIDATE_IP) ) { return $clean_ip_address; } } return ''; } } return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''; } /** * Returns headers * * @return array * @access public */ public function getHeaders() { if ( function_exists('apache_request_headers') ) { // If apache_request_headers() exists... $headers = apache_request_headers(); if ( $headers ) { return $headers; // And works... Use it } } $headers = array(); foreach ( array_keys($_SERVER) as $server_key ) { if ( substr($server_key, 0, 5) == 'HTTP_' ) { $header_name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($server_key, 0, 5))))); $headers[$header_name] = $_SERVER[$server_key]; } } return $headers; } } Index: branches/5.3.x/core/kernel/utility/validator.php =================================================================== --- branches/5.3.x/core/kernel/utility/validator.php (revision 16599) +++ branches/5.3.x/core/kernel/utility/validator.php (revision 16600) @@ -1,527 +1,528 @@ '!la_err_required!', // Field is required 'unique' => '!la_err_unique!', // Field value must be unique 'value_out_of_range' => '!la_err_value_out_of_range!', // Field is out of range, possible values from %s to %s 'length_out_of_range' => '!la_err_length_out_of_range!', // Field is out of range 'bad_type' => '!la_err_bad_type!', // Incorrect data format, please use %s 'invalid_format' => '!la_err_invalid_format!', // Incorrect data format, please use %s 'bad_date_format' => '!la_err_bad_date_format!', // Incorrect date format, please use (%s) ex. (%s) 'primary_lang_required' => '!la_err_primary_lang_required!', // Primary Lang. value Required ); /** * Sets data source for validation * * @param kDBItem $object */ public function setDataSource(&$object) { if ( $object->getFormName() === $this->lastFormName && $object->getPrefixSpecial() === $this->lastPrefixSpecial ) { return ; } $this->reset(); $this->dataSource =& $object; $this->lastFormName = $object->getFormName(); $this->lastPrefixSpecial = $object->getPrefixSpecial(); } /** * Validate all item fields based on * constraints set in each field options * in config * * @return bool * @access private */ public function Validate() { // order is critical - should be called BEFORE checking errors $this->dataSource->UpdateFormattersMasterFields(); $global_res = true; $fields = array_keys( $this->dataSource->getFields() ); foreach ($fields as $field) { // call separately, otherwise 2+ validation errors will be ignored $res = $this->ValidateField($field); $global_res = $global_res && $res; } if ( !$global_res && $this->Application->isDebugMode() ) { $title_info = $this->dataSource->GetTitleField(); $item_info = Array ( $this->dataSource->IDField . ': ' . $this->dataSource->GetID() . '', ); if ( $title_info && reset($title_info) ) { $item_info[] = key($title_info) . ': ' . current($title_info) . ''; } $error_msg = ' Validation failed in prefix - ' . $this->dataSource->Prefix . ' (' . implode('; ', $item_info) . '), FieldErrors follow (look at items with "pseudo" key set)
You may ignore this notice if submitted data really has a validation error'; trigger_error(trim($error_msg), E_USER_NOTICE); $this->Application->Debugger->dumpVars($this->FieldErrors); } return $global_res; } /** * Validates given field * * @param string $field * @return bool * @access public */ public function ValidateField($field) { $options = $this->dataSource->GetFieldOptions($field); $error_field = isset($options['error_field']) ? $options['error_field'] : $field; $res = $this->GetErrorPseudo($error_field) == ''; $res = $res && $this->ValidateRequired($field, $options); $res = $res && $this->ValidateType($field, $options); $res = $res && $this->ValidateRange($field, $options); $res = $res && $this->ValidateUnique($field, $options); $res = $res && $this->CustomValidation($field, $options); return $res; } /** * Check if value is set for required field * * @param string $field field name * @param Array $params field options from config * @return bool * @access public */ public function ValidateRequired($field, $params) { if ( !isset($params['required']) || !$params['required'] ) { return true; } $value = $this->dataSource->GetDBField($field); if ( $this->Application->ConfigValue('TrimRequiredFields') ) { $value = trim($value); } if ( (string)$value == '' ) { $this->SetError($field, 'required'); return false; } return true; } /** * Check if value in field matches field type specified in config * * @param string $field field name * @param Array $params field options from config * @return bool */ protected function ValidateType($field, $params) { $val = $this->dataSource->GetDBField($field); $type_regex = "#int|integer|double|float|real|numeric|string#"; if ( $val == '' || !isset($params['type']) || !preg_match($type_regex, $params['type']) ) { return true; } if ( $params['type'] == 'numeric' ) { trigger_error('Invalid field type ' . $params['type'] . ' (in ValidateType method), please use float instead', E_USER_NOTICE); $params['type'] = 'float'; } $res = is_numeric($val); if ( $params['type'] == 'string' || $res ) { $f = 'is_' . $params['type']; settype($val, $params['type']); $res = $f($val) && ($val == $this->dataSource->GetDBField($field)); } if ( !$res ) { $this->SetError($field, 'bad_type', null, array('type' => $params['type'])); return false; } return true; } /** * Check if field value is in range specified in config * * @param string $field field name * @param Array $params field options from config * @return bool * @access private */ protected function ValidateRange($field, $params) { $res = true; $val = $this->dataSource->GetDBField($field); if ( isset($params['type']) && preg_match("#int|integer|double|float|real#", $params['type']) && strlen($val) > 0 ) { // validate number if ( isset($params['max_value_inc'])) { $res = $res && $val <= $params['max_value_inc']; $max_val = $params['max_value_inc'].' (inclusive)'; } if ( isset($params['min_value_inc'])) { $res = $res && $val >= $params['min_value_inc']; $min_val = $params['min_value_inc'].' (inclusive)'; } if ( isset($params['max_value_exc'])) { $res = $res && $val < $params['max_value_exc']; $max_val = $params['max_value_exc'].' (exclusive)'; } if ( isset($params['min_value_exc'])) { $res = $res && $val > $params['min_value_exc']; $min_val = $params['min_value_exc'].' (exclusive)'; } } if ( !$res ) { if ( !isset($min_val) ) $min_val = '-∞'; if ( !isset($max_val) ) $max_val = '∞'; $this->SetError($field, 'value_out_of_range', null, array( 'min_value' => $min_val, 'max_value' => $max_val )); return false; } if ( strlen($val) > 0 ) { // Validate string. if ( isset($params['max_len']) ) { $res = $res && mb_strlen($val) <= $params['max_len']; } if ( isset($params['min_len']) ) { $res = $res && mb_strlen($val) >= $params['min_len']; } } if ( !$res ) { $error_params = array( 'min_length' => (int)getArrayValue($params, 'min_len'), 'max_length' => (int)getArrayValue($params, 'max_len'), 'value' => mb_strlen($val) ); $this->SetError($field, 'length_out_of_range', null, $error_params); return false; } return true; } /** * Validates that current record has unique field combination among other table records * * @param string $field field name * @param Array $params field options from config * @return bool * @access private */ protected function ValidateUnique($field, $params) { $unique_fields = getArrayValue($params, 'unique'); if ( $unique_fields === false ) { return true; } $where = Array (); array_push($unique_fields, $field); foreach ($unique_fields as $unique_field) { // if field is not empty or if it is required - we add where condition $field_value = $this->dataSource->GetDBField($unique_field); if ( (string)$field_value != '' || $this->dataSource->isRequired($unique_field) ) { $where[] = '`' . $unique_field . '` = ' . $this->Conn->qstr($field_value); } else { // not good if we check by less fields than indicated return true; } } // This can ONLY happen if all unique fields are empty and not required. // In such case we return true, because if unique field is not required there may be numerous empty values // if (!$where) return true; $sql = 'SELECT COUNT(*) FROM %s WHERE (' . implode(') AND (', $where) . ') AND (' . $this->dataSource->IDField . ' <> ' . (int)$this->dataSource->GetID() . ')'; $res_temp = $this->Conn->GetOne( str_replace('%s', $this->dataSource->TableName, $sql) ); $current_table_only = getArrayValue($params, 'current_table_only'); // check unique record only in current table $res_live = $current_table_only ? 0 : $this->Conn->GetOne( str_replace('%s', $this->Application->GetLiveName($this->dataSource->TableName), $sql) ); $res = ($res_temp == 0) && ($res_live == 0); if ( !$res ) { $this->SetError($field, 'unique'); return false; } return true; } /** * Check field value by user-defined alghoritm * * @param string $field field name * @param Array $params field options from config * @return bool */ protected function CustomValidation($field, $params) { return true; } /** * Set's field error, if pseudo passed not found then create it with message text supplied. * Don't overwrite existing pseudo translation. * * @param string $field * @param string $pseudo * @param string $error_label * @param Array $error_params * * @return bool * @access public */ public function SetError($field, $pseudo, $error_label = null, $error_params = null) { $error_field = $this->dataSource->GetFieldOption($field, 'error_field', false, $field); if ( $this->GetErrorPseudo($error_field) ) { // don't set more then one error on field return false; } $this->FieldErrors[$error_field]['pseudo'] = $pseudo; if ( isset($error_params) ) { if ( array_key_exists('value', $error_params) ) { $this->FieldErrors[$error_field]['value'] = $error_params['value']; unset($error_params['value']); } // additional params, that helps to determine error sources $this->FieldErrors[$error_field]['params'] = $error_params; } if ( isset($error_label) && !isset($this->ErrorMsgs[$pseudo]) ) { // label for error (only when not already set) $this->ErrorMsgs[$pseudo] = (substr($error_label, 0, 1) == '+') ? substr($error_label, 1) : '!'.$error_label.'!'; } return true; } /** * Return error message for field * * @param string $field * @param bool $force_escape * @return string * @access public */ public function GetErrorMsg($field, $force_escape = null) { $error_pseudo = $this->GetErrorPseudo($field); if ( !$error_pseudo ) { return ''; } // if special error msg defined in config $error_msgs = $this->dataSource->GetFieldOption($field, 'error_msgs', false, Array ()); if ( isset($error_msgs[$error_pseudo]) ) { $msg = $error_msgs[$error_pseudo]; } else { // fallback to defaults if ( !isset($this->ErrorMsgs[$error_pseudo]) ) { trigger_error('No user message is defined for pseudo error ' . $error_pseudo . '', E_USER_WARNING); return $error_pseudo; //return the pseudo itself } $msg = $this->ErrorMsgs[$error_pseudo]; } $msg = $this->Application->ReplaceLanguageTags($msg, $force_escape); if ( isset($this->FieldErrors[$field]['params']) ) { $params = $this->FieldErrors[$field]['params']; } else { $params = array(); } - $field_phrase = $this->Application->isAdmin ? 'la_fld_' . $field : 'lu_fld_' . $field; - $params['field'] = $this->Application->Phrase($field_phrase); - - foreach ( $params as $param_name => $param_value ) { - $msg = str_replace('{' . $param_name . '}', $param_value, $msg, $replacement_count); + if ( $params && preg_match('/%[^\s]/', $msg) ) { + $msg = vsprintf($msg, array_values($params)); } + else { + $field_phrase = $this->Application->isAdmin ? 'la_fld_' . $field : 'lu_fld_' . $field; + $params['field'] = $this->Application->Phrase($field_phrase); - if ( strpos($msg, '%s') !== false ) { - trigger_error('Unexpected "%s" in field "' . $field . '" validation error message (pseudo: "' . $error_pseudo . '") in "' . $this->dataSource->Prefix . '" unit', E_USER_WARNING); + foreach ( $params as $param_name => $param_value ) { + $msg = str_replace('{' . $param_name . '}', $param_value, $msg); + } } return $msg; } /** * Returns error pseudo * * @param string $field * @return string * @access public * */ public function GetErrorPseudo($field) { if ( !isset($this->FieldErrors[$field]) ) { return ''; } return isset($this->FieldErrors[$field]['pseudo']) ? $this->FieldErrors[$field]['pseudo'] : ''; } /** * Removes error on field * * @param string $field * @access public */ public function RemoveError($field) { unset( $this->FieldErrors[$field] ); } /** * Returns field errors * * @return Array * @access public */ public function GetFieldErrors() { return $this->FieldErrors; } /** * Check if item has errors * * @param Array $skip_fields fields to skip during error checking * @return bool * @access public */ public function HasErrors( $skip_fields = Array () ) { $fields = array_keys( $this->dataSource->getFields() ); $fields = array_diff($fields, $skip_fields); foreach ($fields as $field) { // if Formatter has set some error messages during values parsing if ( $this->GetErrorPseudo($field) ) { return true; } } return false; } /** * Clears all validation errors * * @access public */ public function reset() { $this->FieldErrors = Array(); } } Index: branches/5.3.x/core/units/categories/categories_config.php =================================================================== --- branches/5.3.x/core/units/categories/categories_config.php (revision 16599) +++ branches/5.3.x/core/units/categories/categories_config.php (revision 16600) @@ -1,545 +1,561 @@ 'c', 'ItemClass' => Array ('class' => 'CategoriesItem', 'file' => 'categories_item.php', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'CategoriesEventHandler', 'file' => 'categories_event_handler.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'CategoriesTagProcessor', 'file' => 'categories_tag_processor.php', 'build_event' => 'OnBuild'), 'RegisterClasses' => Array ( Array ('pseudo' => 'clsCachedPermissions', 'class' => 'clsCachedPermissions', 'file' => 'cache_updater.php', 'build_event' => ''), Array ('pseudo' => 'clsRecursionStack', 'class' => 'clsRecursionStack', 'file' => 'cache_updater.php', 'build_event' => ''), Array ('pseudo' => 'kPermCacheUpdater', 'class' => 'kPermCacheUpdater', 'file' => 'cache_updater.php', 'build_event' => ''), ), 'ConfigPriority' => 0, 'Hooks' => Array ( Array ( 'Mode' => hAFTER, 'Conditional' => false, 'HookToPrefix' => 'adm', //self 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnRebuildThemes'), 'DoPrefix' => '', 'DoSpecial' => '', 'DoEvent' => 'OnAfterRebuildThemes', ), Array ( 'Mode' => hBEFORE, 'Conditional' => false, 'HookToPrefix' => '', 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnAfterConfigRead'), 'DoPrefix' => 'cdata', 'DoSpecial' => '*', 'DoEvent' => 'OnDefineCustomFields', ), Array ( 'Mode' => hBEFORE, 'Conditional' => false, 'HookToPrefix' => 'rel', 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnAfterConfigRead'), 'DoPrefix' => '', 'DoSpecial' => '*', 'DoEvent' => 'OnCloneSubItem', ), Array ( 'Mode' => hBEFORE, 'Conditional' => false, 'HookToPrefix' => 'img', 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnAfterConfigRead'), 'DoPrefix' => '', 'DoSpecial' => '*', 'DoEvent' => 'OnCloneSubItem', ), + + array( + 'Mode' => hAFTER, + 'Conditional' => false, + 'HookToPrefix' => 'adm', + 'HookToSpecial' => '', + 'HookToEvent' => array('OnStartup'), + 'DoPrefix' => '', + 'DoSpecial' => '', + 'DoEvent' => 'OnAfterStartupHook', + ), ), 'AutoLoad' => true, 'CatalogItem' => true, 'AdminTemplatePath' => 'categories', 'AdminTemplatePrefix' => 'categories_', 'SearchConfigPostfix' => 'category', 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'PerPage', 4 => 'event', 5 => 'mode', ), 'AggregateTags' => Array ( Array ( 'AggregateTo' => 'm', 'AggregatedTagName' => 'CategoryLink', 'LocalTagName' => 'CategoryLink', ), ), 'IDField' => 'CategoryId', 'StatusField' => Array ('Status'), // 'Status' 'TitleField' => 'Name', 'TitlePhrase' => 'la_Text_Category', 'ItemType' => 1, // used for custom fields only 'StatisticsInfo' => Array ( 'pending' => Array ( 'icon' => 'icon16_cat_pending.gif', 'label' => 'la_tab_Categories', 'js_url' => '#url#', 'url' => Array ('t' => 'catalog/advanced_view', 'SetTab' => 'c', 'pass' => 'm,c.showall', 'c.showall_event' => 'OnSetFilterPattern', 'c.showall_filters' => 'show_active=0,show_pending=1,show_disabled=0,show_new=1,show_pick=1'), 'status' => STATUS_PENDING, ), ), 'TableName' => TABLE_PREFIX.'Categories', 'CustomDataTableName' => TABLE_PREFIX . 'CategoryCustomData', 'ViewMenuPhrase' => 'la_text_Categories', 'CatalogTabIcon' => 'icon16_sections.png', 'TitlePresets' => Array ( 'default' => Array ( 'new_status_labels' => Array ('c' => '!la_title_Adding_Category!'), 'edit_status_labels' => Array ('c' => '!la_title_Editing_Category!'), 'new_titlefield' => Array ('c' => '!la_title_New_Category!'), ), 'category_list' => Array ('prefixes' => Array ('c_List'), 'format' => "!la_title_Categories! (#c_recordcount#)"), 'catalog' => Array ( 'prefixes' => Array (), 'format' => "!la_title_Categories!", 'toolbar_buttons' => Array ('select', 'cancel', 'upcat', 'homecat', 'new_cat', 'new_link', 'new_article', 'new_topic', 'new_product', 'edit', 'delete', 'new_listing', 'approve', 'decline', 'cut', 'copy', 'paste', 'move_up', 'move_down', 'tools', 'view', 'dbl-click') ), 'advanced_view' => Array ( 'prefixes' => Array (), 'format' => "!la_title_AdvancedView!", 'toolbar_buttons' => Array ('select', 'cancel', 'new_cat', 'new_link', 'new_article', 'new_topic', 'new_product', 'edit', 'delete', 'new_listing', 'approve', 'decline', 'export', 'view', 'dbl-click'), ), 'reviews' => Array ( 'prefixes' => Array (), 'format' => "!la_title_Reviews!", 'toolbar_buttons' => Array ('edit', 'delete', 'approve', 'decline', 'view', 'dbl-click',) ), 'review_edit' => Array ('prefixes' => Array (), 'format' => "!la_title_Editing_Review!"), 'categories_edit' => Array ( 'prefixes' => Array ('c'), 'format' => "#c_status# '#c_titlefield#' - !la_title_General!", ), 'categories_properties' => Array ( 'prefixes' => Array ('c'), 'format' => "#c_status# '#c_titlefield#' - !la_title_Properties!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'categories_relations' => Array ( 'prefixes' => Array ('c'), 'format' => "#c_status# '#c_titlefield#' - !la_title_Relations!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next', 'new_item', 'edit', 'delete', 'approve', 'decline', 'view', 'dbl-click'), ), 'categories_related_searches' => Array ( 'prefixes' => Array ('c'), 'format' => "#c_status# '#c_titlefield#' - !la_title_RelatedSearches!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next', 'new_item', 'edit', 'delete', 'move_up', 'move_down', 'approve', 'decline', 'view', 'dbl-click'), ), 'categories_images' => Array ( 'prefixes' => Array ('c'), 'format' => "#c_status# '#c_titlefield#' - !la_title_Images!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next', 'new_item', 'edit', 'delete', 'move_up', 'move_down', 'primary_image', 'view', 'dbl-click'), ), 'categories_permissions' => Array ( 'prefixes' => Array ('c'), 'format' => "#c_status# '#c_titlefield#' - !la_title_Permissions!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'categories_custom' => Array ('prefixes' => Array ('c'), 'format' => "#c_status# '#c_titlefield#' - !la_title_Custom!"), 'categories_update' => Array ('prefixes' => Array (), 'format' => "!la_title_UpdatingCategories!"), 'images_edit' => Array ( 'prefixes' => Array ('c', 'c-img'), 'new_status_labels' => Array ('c-img' => '!la_title_Adding_Image!'), 'edit_status_labels' => Array ('c-img' => '!la_title_Editing_Image!'), 'new_titlefield' => Array ('c-img' => ''), 'format' => "#c_status# '#c_titlefield#' - #c-img_status# '#c-img_titlefield#'", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'relations_edit' => Array ( 'prefixes' => Array ('c', 'c-rel'), 'new_status_labels' => Array ('c-rel' => "!la_title_Adding_Relationship! '!la_title_New_Relationship!'"), 'edit_status_labels' => Array ('c-rel' => '!la_title_Editing_Relationship!'), 'format' => "#c_status# '#c_titlefield#' - #c-rel_status#", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'related_searches_edit' => Array ( 'prefixes' => Array ('c', 'c-search'), 'new_status_labels' => Array ('c-search' => "!la_title_Adding_RelatedSearch_Keyword!"), 'edit_status_labels' => Array ('c-search' => '!la_title_Editing_RelatedSearch_Keyword!'), 'format' => "#c_status# '#c_titlefield#' - #c-search_status#", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'edit_content' => Array ('format' => '!la_EditingContent!'), 'tree_site' => Array ('format' => '!la_selecting_categories!'), ), 'EditTabPresets' => Array ( 'Default' => Array ( 'general' => Array ('title' => 'la_tab_General', 't' => 'categories/categories_edit', 'priority' => 1), 'properties' => Array ('title' => 'la_tab_Properties', 't' => 'categories/categories_edit_properties', 'priority' => 2), 'relations' => Array ('title' => 'la_tab_Relations', 't' => 'categories/categories_edit_relations', 'priority' => 3), 'related_searches' => Array ('title' => 'la_tab_Related_Searches', 't' => 'categories/categories_edit_related_searches', 'priority' => 4), 'images' => Array ('title' => 'la_tab_Images', 't' => 'categories/categories_edit_images', 'priority' => 5), 'permissions' => Array ('title' => 'la_tab_Permissions', 't' => 'categories/categories_edit_permissions', 'priority' => 6), 'custom' => Array ('title' => 'la_tab_Custom', 't' => 'categories/categories_edit_custom', 'priority' => 7), ), ), 'PermItemPrefix' => 'CATEGORY', 'PermSection' => Array ('main' => 'CATEGORY:in-portal:categories', /*'search' => 'in-portal:configuration_search',*/ 'custom' => 'in-portal:configuration_custom'), 'Sections' => Array ( 'in-portal:configure_categories' => Array ( 'parent' => 'in-portal:website_setting_folder', 'icon' => 'conf_output', 'label' => 'la_tab_ConfigOutput', 'url' => Array ('t' => 'config/config_universal', 'pass_section' => true, 'pass' => 'm'), 'permissions' => Array ('view', 'add', 'edit'), 'priority' => 11.1, 'type' => stTREE, ), 'in-portal:configuration_search' => Array ( 'parent' => 'in-portal:website_setting_folder', 'icon' => 'conf_search', 'label' => 'la_tab_ConfigSearch', 'url' => Array ('t' => 'config/config_search', 'module_key' => 'category', 'pass_section' => true, 'pass' => 'm'), 'permissions' => Array ('view', 'edit'), 'priority' => 11.2, 'type' => stTREE, ), 'in-portal:configuration_custom' => Array ( 'parent' => 'in-portal:website_setting_folder', 'icon' => 'conf_customfields', 'label' => 'la_tab_ConfigCustom', 'url' => Array ('t' => 'custom_fields/custom_fields_list', 'cf_type' => 1, 'pass_section' => true, 'pass' => 'm,cf'), 'permissions' => Array ('view', 'add', 'edit', 'delete'), 'priority' => 11.3, 'type' => stTREE, ), ), 'FilterMenu' => Array ( 'Groups' => Array ( Array ('mode' => 'AND', 'filters' => Array ('show_new'), 'type' => kDBList::HAVING_FILTER), Array ('mode' => 'AND', 'filters' => Array ('show_pick'), 'type' => kDBList::WHERE_FILTER), ), 'Filters' => Array ( 'show_new' => Array ('label' => 'la_Text_New', 'on_sql' => '', 'off_sql' => '`IsNew` != 1'), 'show_pick' => Array ('label' => 'la_prompt_EditorsPick', 'on_sql' => '', 'off_sql' => '`EditorsPick` != 1'), ) ), 'ListSQLs' => Array ( '' => ' SELECT %1$s.* %2$s FROM %1$s LEFT JOIN '.TABLE_PREFIX.'%3$sCatalogImages img ON img.ResourceId = %1$s.ResourceId AND img.DefaultImg = 1 {PERM_JOIN} LEFT JOIN '.TABLE_PREFIX.'%3$sCategoryCustomData cust ON %1$s.ResourceId = cust.ResourceId', '-virtual' => ' SELECT %1$s.* %2$s FROM %1$s', ), 'SubItems' => Array ('c-rel', 'c-search', 'c-img', 'c-cdata', 'c-perm', 'content', 'page-revision'), 'ListSortings' => Array ( '' => Array ( 'Sorting' => Array ('Priority' => 'desc', 'Name' => 'asc'), ) ), 'CalculatedFields' => Array ( '' => Array ( 'CurrentSort' => "REPLACE(ParentPath, CONCAT('|', ".'%1$s'.".CategoryId, '|'), '')", 'AltName' => 'img.AltName', 'SameImages' => 'img.SameImages', 'LocalThumb' => 'img.LocalThumb', 'ThumbPath' => 'img.ThumbPath', 'ThumbUrl' => 'img.ThumbUrl', 'LocalImage' => 'img.LocalImage', 'LocalPath' => 'img.LocalPath', 'FullUrl' => 'img.Url', ), '-virtual' => Array (), ), 'CacheModRewrite' => true, 'Fields' => Array ( 'CategoryId' => Array ('type' => 'int', 'not_null' => 1,'default' => 0), 'Type' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_Virtual', 2 => 'la_opt_Template'), 'use_phrases' => 1, 'not_null' => 1,'default' => 1 ), 'SymLinkCategoryId' => Array ('type' => 'int', 'default' => NULL), 'ParentId' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'not_null' => 1,'default' => 0, 'required' => 1), 'Name' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'not_null' => 1, 'required' => 1, 'default' => ''), 'Filename' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''), 'AutomaticFilename' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1, 'default' => 1, 'not_null' => 1, ), 'Description' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'using_fck' => 1, 'default' => null), 'CreatedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'required' => 1, 'default' => '#NOW#'), 'EditorsPick' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1, 'default' => 0, 'not_null' => 1, ), 'Status' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Active', 2 => 'la_Pending', 0 => 'la_Disabled' ), 'use_phrases' => 1, 'not_null' => 1,'default' => 1), 'Priority' => Array ('type' => 'int', 'not_null' => 1, 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'default' => 0), - 'MetaKeywords' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null), + 'MetaKeywords' => Array ('type' => 'string', 'default' => null), 'CachedDescendantCatsQty' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'CachedNavbar' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'default' => null), 'CreatedById' => Array ('type' => 'int', 'formatter' => 'kLEFTFormatter', 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'), 'options' => Array (USER_ROOT => 'root', USER_GUEST => 'Guest'),'left_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'Users WHERE %s', 'left_key_field' => 'PortalUserId', 'left_title_field' => USER_TITLE_FIELD, 'default' => NULL), 'ResourceId' => Array ('type' => 'int', 'default' => null), 'ParentPath' => Array ('type' => 'string', 'default' => null), 'TreeLeft' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'TreeRight' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'NamedParentPath' => Array ('type' => 'string', 'default' => null), 'NamedParentPathHash' => Array ('type' => 'string', 'not_null' => 1, 'default' => 0), - 'MetaDescription' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null), + 'MetaDescription' => Array ('type' => 'string', 'default' => null), 'HotItem' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 2), 'NewItem' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 2), 'PopItem' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 2), 'Modified' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'), 'ModifiedById' => Array ('type' => 'int', 'formatter' => 'kLEFTFormatter', 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'), 'options' => Array (USER_ROOT => 'root', USER_GUEST => 'Guest'),'left_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'Users WHERE %s', 'left_key_field' => 'PortalUserId', 'left_title_field' => USER_TITLE_FIELD, 'default' => NULL), 'CachedTemplate' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''), 'CachedTemplateHash' => Array ('type' => 'string', 'not_null' => 1, 'default' => 0), // fields from Pages 'Template' => Array ( 'type' => 'string', 'formatter' => 'kOptionsFormatter', 'options_sql' => ' SELECT CONCAT(tf.Description, " :: ", FilePath, "/", TRIM(TRAILING ".tpl" FROM FileName) ) AS Title, IF(tf.TemplateAlias <> "", tf.TemplateAlias, CONCAT(FilePath, "/", TRIM(TRAILING ".tpl" FROM FileName))) AS Value FROM ' . TABLE_PREFIX . 'ThemeFiles AS tf LEFT JOIN ' . TABLE_PREFIX . 'Themes AS t ON t.ThemeId = tf.ThemeId WHERE (t.Enabled = 1) AND (tf.FileName NOT LIKE "%%.elm.tpl") AND (tf.FileName NOT LIKE "%%.des.tpl") AND (tf.FilePath = "/designs") ORDER BY tf.Description ASC, tf.FileName ASC', 'option_key_field' => 'Value', 'option_title_field' => 'Title', 'error_msgs' => Array ( 'no_inherit' => '!la_error_NoInheritancePossible!', ), 'required' => 1, 'not_null' => 1, 'default' => CATEGORY_TEMPLATE_INHERIT ), 'UseExternalUrl' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0, ), 'ExternalUrl' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'UseMenuIconUrl' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0, ), 'MenuIconUrl' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'Title' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'default' => '', 'not_null'=>1), 'MenuTitle' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'not_null' => 1, 'default' => ''), 'MetaTitle' => Array ('type' => 'string', 'default' => null), - 'IndexTools' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null), + 'IndexTools' => Array ('type' => 'string', 'default' => null), 'IsMenu' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Show', 0 => 'la_Hide'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1), 'Protected' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0), 'FormId' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array ('' => ''), 'options_sql' => 'SELECT Title, FormId FROM '.TABLE_PREFIX.'Forms ORDER BY Title', 'option_key_field' => 'FormId', 'option_title_field' => 'Title', 'default' => NULL ), 'FormSubmittedTemplate' => Array ('type' => 'string', 'default' => null), - 'FriendlyURL' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''), + 'FriendlyURL' => Array ( + 'type' => 'string', + 'unique' => array(), + 'error_msgs' => array('unique' => '!la_error_FriendlyUrlIsNotUnique!'), + 'not_null' => 1, 'default' => '', + ), 'ThemeId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'EnablePageCache' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'OverridePageCacheKey' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'PageCacheKey' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'PageExpiration' => Array ('type' => 'int', 'default' => NULL), 'LiveRevisionNumber' => Array ('type' => 'int', 'not_null' => 1, 'default' => 1), 'DirectLinkEnabled' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1 ), 'DirectLinkAuthKey' => Array ('type' => 'string', 'max_len' => 20, 'not_null' => 1, 'default' => ''), 'PromoBlockGroupId' => Array ( 'type' => 'int', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'PromoBlockGroups ORDER BY Title', 'option_title_field' => 'Title', 'option_key_field' => 'PromoBlockGroupId', 'not_null' => 1, 'default' => 0, ), 'RequireSSL' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'RequireLogin' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), ), 'VirtualFields' => Array ( 'Relevance' => Array ('type' => 'float', 'default' => 0), 'CurrentSort' => Array ('type' => 'string', 'default' => ''), 'IsNew' => Array ('type' => 'int', 'default' => 0), 'OldPriority' => Array ('type' => 'int', 'default' => 0), // for primary image 'AltName' => Array ('type' => 'string', 'default' => ''), 'SameImages' => Array ('type' => 'string', 'default' => ''), 'LocalThumb' => Array ('type' => 'string', 'default' => ''), 'ThumbPath' => Array ('type' => 'string', 'default' => ''), 'ThumbUrl' => Array ('type' => 'string', 'default' => ''), 'LocalImage' => Array ('type' => 'string', 'default' => ''), 'LocalPath' => Array ('type' => 'string', 'default' => ''), 'FullUrl' => Array ('type' => 'string', 'default' => ''), ), 'Grids' => Array ( 'Default' => Array ( 'Icons' => Array ( // 'StatusField' => Array ('Type', 'Status', 'IsMenu'), // 'Status' 'default' => 'icon_section.png', '1_0_0' => 'icon16_section_system.png', // system '1_0_1' => 'icon16_section_system.png', // system '1_1_1' => 'icon16_section_system.png', // system '0_0_0' => 'icon16_section_disabled.png', // disabled '0_0_1' => 'icon16_section_disabled.png', // disabled '0_1_0' => 'icon16_section_menuhidden.png', // hidden from menu '0_2_0' => 'icon16_section_pending.png', // pending '0_2_1' => 'icon16_section_pending.png', // pending 'NEW' => 'icon16_section_new.png', // section is new ), 'Fields' => Array ( 'CategoryId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 55), 'Name' => Array ('title' => 'column:la_fld_PageTitle', 'data_block' => 'page_browse_td', 'filter_block' => 'grid_like_filter', 'width' => 250), 'Priority' => Array ('filter_block' => 'grid_options_filter', 'width' => 65), 'Modified' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 170), 'Template' => Array ('title' => 'column:la_fld_TemplateType', 'filter_block' => 'grid_options_filter', 'width' => 220), 'IsMenu' => Array ('title' => 'la_col_InMenu', 'filter_block' => 'grid_options_filter', 'width' => 70), 'Type' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'Protected' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'RequireSSL' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'RequireLogin' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), ), ), 'Radio' => Array ( 'Selector' => 'radio', 'Icons' => Array ( // 'StatusField' => Array ('Type', 'Status', 'IsMenu'), // 'Status' 'default' => 'icon_section.png', '1_0_0' => 'icon16_section_system.png', // system '1_0_1' => 'icon16_section_system.png', // system '1_1_1' => 'icon16_section_system.png', // system '0_0_0' => 'icon16_section_disabled.png', // disabled '0_0_1' => 'icon16_section_disabled.png', // disabled '0_1_0' => 'icon16_section_menuhidden.png', // hidden from menu '0_2_0' => 'icon16_section_pending.png', // pending '0_2_1' => 'icon16_section_pending.png', // pending 'NEW' => 'icon16_section_new.png', // section is new ), 'Fields' => Array ( 'CategoryId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_radio_td', 'filter_block' => 'grid_range_filter', 'width' => 55), 'Name' => Array ('title' => 'column:la_fld_PageTitle', 'data_block' => 'page_browse_td', 'filter_block' => 'grid_like_filter', 'width' => 250), 'Priority' => Array ('filter_block' => 'grid_options_filter', 'width' => 65), 'IsMenu' => Array ('title' => 'la_col_InMenu', 'filter_block' => 'grid_options_filter', 'width' => 70), 'Modified' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 170), 'Template' => Array ('title' => 'column:la_fld_TemplateType', 'filter_block' => 'grid_options_filter', 'width' => 220), 'Type' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'Protected' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'RequireSSL' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'RequireLogin' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), ), ), 'Structure' => Array ( 'Icons' => Array ( // 'StatusField' => Array ('Type', 'Status', 'IsMenu'), // 'Status' 'default' => 'icon_section.png', '1_0_0' => 'icon16_section_system.png', // system '1_0_1' => 'icon16_section_system.png', // system '1_1_1' => 'icon16_section_system.png', // system '0_0_0' => 'icon16_section_disabled.png', // disabled '0_0_1' => 'icon16_section_disabled.png', // disabled '0_1_0' => 'icon16_section_menuhidden.png', // hidden from menu '0_2_0' => 'icon16_section_pending.png', // pending '0_2_1' => 'icon16_section_pending.png', // pending 'NEW' => 'icon16_section_new.png', // section is new ), 'Fields' => Array ( 'CategoryId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 55), 'Name' => Array ('title' => 'column:la_fld_PageTitle', 'data_block' => 'page_browse_td', 'filter_block' => 'grid_like_filter', 'width' => 250), 'Priority' => Array ('filter_block' => 'grid_options_filter', 'width' => 65), 'IsMenu' => Array ('title' => 'la_col_InMenu', 'filter_block' => 'grid_options_filter', 'width' => 70), 'Modified' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 170), 'Template' => Array ('title' => 'column:la_fld_TemplateType', 'filter_block' => 'grid_options_filter', 'width' => 220), 'Type' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'Protected' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'RequireSSL' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'RequireLogin' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), ), ), ), 'ConfigMapping' => Array ( 'PerPage' => 'Perpage_Category', 'ShortListPerPage' => 'Perpage_Category_Short', 'DefaultSorting1Field' => 'Category_Sortfield', 'DefaultSorting2Field' => 'Category_Sortfield2', 'DefaultSorting1Dir' => 'Category_Sortorder', 'DefaultSorting2Dir' => 'Category_Sortorder2', ), ); Index: branches/5.3.x/core/units/categories/categories_event_handler.php =================================================================== --- branches/5.3.x/core/units/categories/categories_event_handler.php (revision 16599) +++ branches/5.3.x/core/units/categories/categories_event_handler.php (revision 16600) @@ -1,2905 +1,2986 @@ Array ('self' => 'add|edit'), 'OnCopy' => Array ('self' => true), 'OnCut' => Array ('self' => 'edit'), 'OnPasteClipboard' => Array ('self' => true), 'OnPaste' => Array ('self' => 'add|edit', 'subitem' => 'edit'), 'OnRecalculatePriorities' => Array ('self' => 'add|edit'), // category ordering 'OnItemBuild' => Array ('self' => true), // always allow to view individual categories (regardless of CATEGORY.VIEW right) 'OnUpdatePreviewBlock' => Array ('self' => true), // for FCKEditor integration ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Categories are sorted using special sorting event * */ function mapEvents() { parent::mapEvents(); $events_map = Array ( 'OnMassMoveUp' => 'OnChangePriority', 'OnMassMoveDown' => 'OnChangePriority', ); $this->eventMethods = array_merge($this->eventMethods, $events_map); } /** * Checks user permission to execute given $event * * @param kEvent $event * @return bool * @access public */ public function CheckPermission(kEvent $event) { if ( $event->Name == 'OnResetCMSMenuCache' ) { // events from "Tools -> System Tools" section are controlled via that section "edit" permission /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); $perm_value = $this->Application->CheckPermission('in-portal:service.edit'); return $perm_helper->finalizePermissionCheck($event, $perm_value); } if ( !$this->Application->isAdmin ) { if ( $event->Name == 'OnSetSortingDirect' ) { // allow sorting on front event without view permission return true; } if ( $event->Name == 'OnItemBuild' ) { $category_id = $this->getPassedID($event); if ( $category_id == 0 ) { return true; } } } if ( in_array($event->Name, $this->_getMassPermissionEvents()) ) { $items = $this->_getPermissionCheckInfo($event); /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); if ( ($event->Name == 'OnSave') && array_key_exists(0, $items) ) { // adding new item (ID = 0) $perm_value = $perm_helper->AddCheckPermission($items[0]['ParentId'], $event->Prefix) > 0; } else { // leave only items, that can be edited $ids = Array (); $check_method = in_array($event->Name, Array ('OnMassDelete', 'OnCut')) ? 'DeleteCheckPermission' : 'ModifyCheckPermission'; foreach ($items as $item_id => $item_data) { if ( $perm_helper->$check_method($item_data['CreatedById'], $item_data['ParentId'], $event->Prefix) > 0 ) { $ids[] = $item_id; } } if ( !$ids ) { // no items left for editing -> no permission return $perm_helper->finalizePermissionCheck($event, false); } $perm_value = true; $event->setEventParam('ids', $ids); // will be used later by "kDBEventHandler::StoreSelectedIDs" method } return $perm_helper->finalizePermissionCheck($event, $perm_value); } if ( $event->Name == 'OnRecalculatePriorities' ) { /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); $category_id = $this->Application->GetVar('m_cat_id'); return $perm_helper->AddCheckPermission($category_id, $event->Prefix) || $perm_helper->ModifyCheckPermission(0, $category_id, $event->Prefix); } if ( $event->Name == 'OnPasteClipboard' ) { // forces permission check to work by current category for "Paste In Category" operation $category_id = $this->Application->GetVar('m_cat_id'); $this->Application->SetVar('c_id', $category_id); } return parent::CheckPermission($event); } /** * Returns events, that require item-based (not just event-name based) permission check * * @return Array */ function _getMassPermissionEvents() { - return Array ( - 'OnEdit', 'OnSave', 'OnMassDelete', 'OnMassApprove', + return array( + 'OnStoreSelected', 'OnEdit', 'OnSave', 'OnMassDelete', 'OnMassApprove', 'OnMassDecline', 'OnMassMoveUp', 'OnMassMoveDown', 'OnCut', ); } /** * Returns category item IDs, that require permission checking * * @param kEvent $event * @return string */ function _getPermissionCheckIDs($event) { if ($event->Name == 'OnSave') { $selected_ids = implode(',', $this->getSelectedIDs($event, true)); if (!$selected_ids) { $selected_ids = 0; // when saving newly created item (OnPreCreate -> OnPreSave -> OnSave) } } else { // OnEdit, OnMassDelete events, when items are checked in grid $selected_ids = implode(',', $this->StoreSelectedIDs($event)); } return $selected_ids; } /** * Returns information used in permission checking * * @param kEvent $event * @return Array */ function _getPermissionCheckInfo($event) { // when saving data from temp table to live table check by data from temp table $config = $event->getUnitConfig(); $id_field = $config->getIDField(); $table_name = $config->getTableName(); if ($event->Name == 'OnSave') { $table_name = $this->Application->GetTempName($table_name, 'prefix:' . $event->Prefix); } $sql = 'SELECT ' . $id_field . ', CreatedById, ParentId FROM ' . $table_name . ' WHERE ' . $id_field . ' IN (' . $this->_getPermissionCheckIDs($event) . ')'; $items = $this->Conn->Query($sql, $id_field); if (!$items) { // when creating new category, then no IDs are stored in session $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); list ($id, $fields_hash) = each($items_info); if (array_key_exists('ParentId', $fields_hash)) { $item_category = $fields_hash['ParentId']; } else { $item_category = $this->Application->RecallVar('m_cat_id'); // saved in c:OnPreCreate event permission checking } $items[$id] = Array ( 'CreatedById' => $this->Application->RecallVar('user_id'), 'ParentId' => $item_category, ); } return $items; } /** + * Creates "EDITING_MODE" constant. + * + * @param kEvent $event Event. + * + * @return void + */ + protected function OnAfterStartupHook(kEvent $event) + { + if ( !$this->Application->GetVar('admin') ) { + // User can't edit anything. + kUtil::safeDefine('EDITING_MODE', ''); + + return; + } + + /** @var Session $admin_session */ + $admin_session = $this->Application->recallObject('Session.admin'); + + // Store Admin Console User's ID to Front-End's session for cross-session permission checks. + $this->Application->StoreVar('admin_user_id', (int)$admin_session->RecallVar('user_id')); + + $base_category = $this->Application->getBaseCategory(); + + if ( $this->Application->CheckAdminPermission('CATEGORY.MODIFY', 0, $base_category) ) { + // User can edit cms blocks (when viewing front-end through admin's frame). + $editing_mode = $this->Application->GetVar('editing_mode'); + define('EDITING_MODE', $editing_mode ? $editing_mode : EDITING_MODE_BROWSE); + } + + // User can't edit anything. + kUtil::safeDefine('EDITING_MODE', ''); + } + + /** * Set's mark, that root category is edited * * @param kEvent $event * @return void * @access protected */ protected function OnEdit(kEvent $event) { $category_id = $this->Application->GetVar($event->getPrefixSpecial() . '_id'); $home_category = $this->Application->getBaseCategory(); $this->Application->StoreVar('IsRootCategory_' . $this->Application->GetVar('m_wid'), ($category_id === '0') || ($category_id == $home_category)); parent::OnEdit($event); if ( $event->status == kEvent::erSUCCESS ) { // keep "Section Properties" link (in browse modes) clean $this->Application->DeleteVar('admin'); } } /** * Adds selected link to listing * * @param kEvent $event */ function OnProcessSelected($event) { /** @var kDBItem $object */ $object = $event->getObject(); $selected_ids = $this->Application->GetVar('selected_ids'); $this->RemoveRequiredFields($object); $object->SetDBField($this->Application->RecallVar('dst_field'), $selected_ids['c']); $object->Update(); $event->SetRedirectParam('opener', 'u'); } /** * Apply system filter to categories list * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetCustomQuery(kEvent $event) { parent::SetCustomQuery($event); /** @var kDBList $object */ $object = $event->getObject(); // don't show "Content" category in advanced view $object->addFilter('system_categories', '%1$s.Status <> 4'); // show system templates from current theme only + all virtual templates $object->addFilter('theme_filter', '%1$s.ThemeId = ' . $this->_getCurrentThemeId() . ' OR %1$s.ThemeId = 0'); if ($event->Special == 'showall') { // if using recycle bin don't show categories from there $recycle_bin = $this->Application->ConfigValue('RecycleBinFolder'); if ($recycle_bin) { $sql = 'SELECT TreeLeft, TreeRight FROM '.TABLE_PREFIX.'Categories WHERE CategoryId = '.$recycle_bin; $tree_indexes = $this->Conn->GetRow($sql); $object->addFilter('recyclebin_filter', '%1$s.TreeLeft < '.$tree_indexes['TreeLeft'].' OR %1$s.TreeLeft > '.$tree_indexes['TreeRight']); } } if ( (string)$event->getEventParam('parent_cat_id') !== '' ) { $parent_cat_id = $event->getEventParam('parent_cat_id'); if ("$parent_cat_id" == 'Root') { $module_name = $event->getEventParam('module') ? $event->getEventParam('module') : 'In-Commerce'; $parent_cat_id = $this->Application->findModule('Name', $module_name, 'RootCat'); } } else { $parent_cat_id = $this->Application->GetVar('c_id'); if (!$parent_cat_id) { $parent_cat_id = $this->Application->GetVar('m_cat_id'); } if (!$parent_cat_id) { $parent_cat_id = 0; } } if ("$parent_cat_id" == '0') { // replace "0" category with "Content" category id (this way template $parent_cat_id = $this->Application->getBaseCategory(); } if ("$parent_cat_id" != 'any') { if ($event->getEventParam('recursive')) { if ($parent_cat_id > 0) { // not "Home" category $tree_indexes = $this->Application->getTreeIndex($parent_cat_id); $object->addFilter('parent_filter', '%1$s.TreeLeft BETWEEN '.$tree_indexes['TreeLeft'].' AND '.$tree_indexes['TreeRight']); } } else { $object->addFilter('parent_filter', '%1$s.ParentId = '.$parent_cat_id); } } $this->applyViewPermissionFilter($object); if (!$this->Application->isAdminUser) { // apply status filter only on front $object->addFilter('status_filter', $object->TableName.'.Status = 1'); } // process "types" and "except" parameters $type_clauses = Array(); $types = $event->getEventParam('types'); $types = $types ? explode(',', $types) : Array (); $except_types = $event->getEventParam('except'); $except_types = $except_types ? explode(',', $except_types) : Array (); $config = $event->getUnitConfig(); if (in_array('related', $types) || in_array('related', $except_types)) { $related_to = $event->getEventParam('related_to'); if (!$related_to) { $related_prefix = $event->Prefix; } else { $sql = 'SELECT Prefix FROM '.TABLE_PREFIX.'ItemTypes WHERE ItemName = '.$this->Conn->qstr($related_to); $related_prefix = $this->Conn->GetOne($sql); } $rel_table = $this->Application->getUnitConfig('rel')->getTableName(); $item_type = (int)$config->getItemType(); if ($item_type == 0) { trigger_error('ItemType not defined for prefix ' . $event->Prefix . '', E_USER_WARNING); } // process case, then this list is called inside another list $prefix_special = $event->getEventParam('PrefixSpecial'); if (!$prefix_special) { $prefix_special = $this->Application->Parser->GetParam('PrefixSpecial'); } $id = false; if ($prefix_special !== false) { $processed_prefix = $this->Application->processPrefix($prefix_special); if ($processed_prefix['prefix'] == $related_prefix) { // printing related categories within list of items (not on details page) /** @var kDBList $list */ $list = $this->Application->recallObject($prefix_special); $id = $list->GetID(); } } if ($id === false) { // printing related categories for single item (possibly on details page) if ($related_prefix == 'c') { $id = $this->Application->GetVar('m_cat_id'); } else { $id = $this->Application->GetVar($related_prefix . '_id'); } } /** @var kCatDBItem $p_item */ $p_item = $this->Application->recallObject($related_prefix . '.current', null, Array('skip_autoload' => true)); $p_item->Load( (int)$id ); $p_resource_id = $p_item->GetDBField('ResourceId'); $sql = 'SELECT SourceId, TargetId FROM '.$rel_table.' WHERE (Enabled = 1) AND ( (Type = 0 AND SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.') OR (Type = 1 AND ( (SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.') OR (TargetId = '.$p_resource_id.' AND SourceType = '.$item_type.') ) ) )'; $related_ids_array = $this->Conn->Query($sql); $related_ids = Array(); foreach ($related_ids_array as $key => $record) { $related_ids[] = $record[ $record['SourceId'] == $p_resource_id ? 'TargetId' : 'SourceId' ]; } if (count($related_ids) > 0) { $type_clauses['related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_ids).')'; $type_clauses['related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_ids).')'; } else { $type_clauses['related']['include'] = '0'; $type_clauses['related']['except'] = '1'; } $type_clauses['related']['having_filter'] = false; } if (in_array('category_related', $type_clauses)) { $object->removeFilter('parent_filter'); $resource_id = $this->Conn->GetOne(' SELECT ResourceId FROM '.$config->getTableName().' WHERE CategoryId = '.$parent_cat_id ); $sql = 'SELECT DISTINCT(TargetId) FROM '.TABLE_PREFIX.'CatalogRelationships WHERE SourceId = '.$resource_id.' AND SourceType = 1'; $related_cats = $this->Conn->GetCol($sql); $related_cats = is_array($related_cats) ? $related_cats : Array(); $sql = 'SELECT DISTINCT(SourceId) FROM '.TABLE_PREFIX.'CatalogRelationships WHERE TargetId = '.$resource_id.' AND TargetType = 1 AND Type = 1'; $related_cats2 = $this->Conn->GetCol($sql); $related_cats2 = is_array($related_cats2) ? $related_cats2 : Array(); $related_cats = array_unique( array_merge( $related_cats2, $related_cats ) ); if ($related_cats) { $type_clauses['category_related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_cats).')'; $type_clauses['category_related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_cats).')'; } else { $type_clauses['category_related']['include'] = '0'; $type_clauses['category_related']['except'] = '1'; } $type_clauses['category_related']['having_filter'] = false; } if (in_array('product_related', $types)) { $object->removeFilter('parent_filter'); $product_id = $event->getEventParam('product_id') ? $event->getEventParam('product_id') : $this->Application->GetVar('p_id'); $sql = 'SELECT ResourceId FROM ' . $this->Application->getUnitConfig('p')->getTableName() . ' WHERE ProductId = ' . $product_id; $resource_id = $this->Conn->GetOne($sql); $sql = 'SELECT DISTINCT(TargetId) FROM ' . TABLE_PREFIX . 'CatalogRelationships WHERE SourceId = '.$resource_id.' AND TargetType = 1'; $related_cats = $this->Conn->GetCol($sql); $related_cats = is_array($related_cats) ? $related_cats : Array(); $sql = 'SELECT DISTINCT(SourceId) FROM ' . TABLE_PREFIX . 'CatalogRelationships WHERE TargetId = '.$resource_id.' AND SourceType = 1 AND Type = 1'; $related_cats2 = $this->Conn->GetCol($sql); $related_cats2 = is_array($related_cats2) ? $related_cats2 : Array(); $related_cats = array_unique( array_merge( $related_cats2, $related_cats ) ); if ($related_cats) { $type_clauses['product_related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_cats).')'; $type_clauses['product_related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_cats).')'; } else { $type_clauses['product_related']['include'] = '0'; $type_clauses['product_related']['except'] = '1'; } $type_clauses['product_related']['having_filter'] = false; } $type_clauses['menu']['include'] = '%1$s.IsMenu = 1'; $type_clauses['menu']['except'] = '%1$s.IsMenu = 0'; $type_clauses['menu']['having_filter'] = false; /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); if (in_array('search', $types) || in_array('search', $except_types)) { $event_mapping = Array ( 'simple' => 'OnSimpleSearch', 'subsearch' => 'OnSubSearch', 'advanced' => 'OnAdvancedSearch' ); $keywords = $event->getEventParam('keyword_string'); $type = $this->Application->GetVar('search_type', 'simple'); if ( $keywords ) { // processing keyword_string param of ListProducts tag $this->Application->SetVar('keywords', $keywords); $type = 'simple'; } $search_event = $event_mapping[$type]; $this->$search_event($event); /** @var kDBList $object */ $object = $event->getObject(); $search_sql = ' FROM ' . $search_helper->getSearchTable() . ' search_result JOIN %1$s ON %1$s.ResourceId = search_result.ResourceId'; $sql = str_replace('FROM %1$s', $search_sql, $object->GetPlainSelectSQL()); $object->SetSelectSQL($sql); $object->addCalculatedField('Relevance', 'search_result.Relevance'); $type_clauses['search']['include'] = '1'; $type_clauses['search']['except'] = '0'; $type_clauses['search']['having_filter'] = false; } $search_helper->SetComplexFilter($event, $type_clauses, implode(',', $types), implode(',', $except_types)); } /** * Adds filter, that uses *.VIEW permissions to determine if an item should be shown to a user. * * @param kDBList $object Object. * * @return void * @access protected */ protected function applyViewPermissionFilter(kDBList $object) { if ( !$this->Application->ConfigValue('CheckViewPermissionsInCatalog') ) { return; } if ( $this->Application->RecallVar('user_id') == USER_ROOT ) { // for "root" CATEGORY.VIEW permission is checked for items lists too $view_perm = 1; } else { /** @var kCountHelper $count_helper */ $count_helper = $this->Application->recallObject('CountHelper'); list ($view_perm, $view_filter) = $count_helper->GetPermissionClause($object->Prefix, 'perm'); $object->addFilter('perm_filter2', $view_filter); } $object->addFilter('perm_filter', 'perm.PermId = ' . $view_perm); // check for CATEGORY.VIEW permission } /** * Returns current theme id * * @return int */ function _getCurrentThemeId() { /** @var kThemesHelper $themes_helper */ $themes_helper = $this->Application->recallObject('ThemesHelper'); return (int)$themes_helper->getCurrentThemeId(); } /** * Returns ID of current item to be edited * by checking ID passed in get/post as prefix_id * or by looking at first from selected ids, stored. * Returned id is also stored in Session in case * it was explicitly passed as get/post * * @param kEvent $event * @return int * @access public */ public function getPassedID(kEvent $event) { if ( ($event->Special == 'page') || $this->_isVirtual($event) || ($event->Prefix == 'st') ) { return $this->_getPassedStructureID($event); } if ( $this->Application->isAdmin ) { return parent::getPassedID($event); } $event->setEventParam(kEvent::FLAG_ID_FROM_REQUEST, true); return $this->Application->GetVar('m_cat_id'); } /** * Enter description here... * * @param kEvent $event * @return int */ function _getPassedStructureID($event) { static $page_by_template = Array (); if ( $event->Special == 'current' ) { $event->setEventParam(kEvent::FLAG_ID_FROM_REQUEST, true); return $this->Application->GetVar('m_cat_id'); } $event->setEventParam('raise_warnings', 0); $page_id = parent::getPassedID($event); if ( $page_id === false ) { $template = $event->getEventParam('page'); if ( !$template ) { $template = $this->Application->GetVar('t'); } // bug: when template contains "-" symbols (or others, that stripDisallowed will replace) it's not found if ( !array_key_exists($template, $page_by_template) ) { $config = $event->getUnitConfig(); $template_crc = kUtil::crc32(mb_strtolower($template)); $sql = 'SELECT ' . $config->getIDField() . ' FROM ' . $config->getTableName() . ' WHERE ( (NamedParentPathHash = ' . $template_crc . ') OR (`Type` = ' . PAGE_TYPE_TEMPLATE . ' AND CachedTemplateHash = ' . $template_crc . ') ) AND (ThemeId = ' . $this->_getCurrentThemeId() . ' OR ThemeId = 0)'; $page_id = $this->Conn->GetOne($sql); } else { $page_id = $page_by_template[$template]; } if ( $page_id ) { $page_by_template[$template] = $page_id; } } if ( !$page_id && !$this->Application->isAdmin ) { $page_id = $this->Application->GetVar('m_cat_id'); $event->setEventParam(kEvent::FLAG_ID_FROM_REQUEST, true); } return $page_id; } function ParentGetPassedID($event) { return parent::getPassedID($event); } /** * Adds calculates fields for item statuses * * @param kCatDBItem $object * @param kEvent $event * @return void * @access protected */ protected function prepareObject(&$object, kEvent $event) { if ( $this->_isVirtual($event) ) { return; } /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $object->addCalculatedField( 'IsNew', ' IF(%1$s.NewItem = 2, IF(%1$s.CreatedOn >= (UNIX_TIMESTAMP() - '. $this->Application->ConfigValue('Category_DaysNew'). '*3600*24), 1, 0), %1$s.NewItem )'); } /** * Checks, that this is virtual page * * @param kEvent $event * @return int * @access protected */ protected function _isVirtual(kEvent $event) { return strpos($event->Special, '-virtual') !== false; } /** * Gets right special for configuring virtual page * * @param kEvent $event * @return string * @access protected */ protected function _getCategorySpecial(kEvent $event) { return $this->_isVirtual($event) ? '-virtual' : $event->Special; } /** * Set correct parent path for newly created categories * * @param kEvent $event * @return void * @access protected */ protected function OnAfterCopyToLive(kEvent $event) { parent::OnAfterCopyToLive($event); /** @var CategoriesItem $object */ $object = $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true, 'live_table' => true)); $parent_path = false; $object->Load($event->getEventParam('id')); if ( $event->getEventParam('temp_id') == 0 ) { if ( $object->isLoaded() ) { // update path only for real categories (not including "Home" root category) $fields_hash = $object->buildParentBasedFields(); $this->Conn->doUpdate($fields_hash, $object->TableName, 'CategoryId = ' . $object->GetID()); $parent_path = $fields_hash['ParentPath']; } } else { $parent_path = $object->GetDBField('ParentPath'); } if ( $parent_path ) { /** @var kPermCacheUpdater $cache_updater */ $cache_updater = $this->Application->makeClass('kPermCacheUpdater', Array (null, $parent_path)); $cache_updater->OneStepRun(); } } /** * Set cache modification mark if needed * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeDeleteFromLive(kEvent $event) { parent::OnBeforeDeleteFromLive($event); $id = $event->getEventParam('id'); // loading anyway, because this object is needed by "c-perm:OnBeforeDeleteFromLive" event /** @var CategoriesItem $temp_object */ $temp_object = $event->getObject(Array ('skip_autoload' => true)); $temp_object->Load($id); if ( $id == 0 ) { if ( $temp_object->isLoaded() ) { // new category -> update cache (not loaded when "Home" category) $this->Application->StoreVar('PermCache_UpdateRequired', 1); } return ; } // existing category was edited, check if in-cache fields are modified /** @var CategoriesItem $live_object */ $live_object = $this->Application->recallObject($event->Prefix . '.-item', null, Array ('live_table' => true, 'skip_autoload' => true)); $live_object->Load($id); $cached_fields = Array ('l' . $this->Application->GetDefaultLanguageId() . '_Name', 'Filename', 'Template', 'ParentId', 'Priority'); foreach ($cached_fields as $cached_field) { if ( $live_object->GetDBField($cached_field) != $temp_object->GetDBField($cached_field) ) { // use session instead of REQUEST because of permission editing in category can contain // multiple submits, that changes data before OnSave event occurs $this->Application->StoreVar('PermCache_UpdateRequired', 1); break; } } // remember category filename change between temp and live records if ( $temp_object->GetDBField('Filename') != $live_object->GetDBField('Filename') ) { $filename_changes = $this->Application->GetVar($event->Prefix . '_filename_changes', Array ()); $filename_changes[ $live_object->GetID() ] = Array ( 'from' => $live_object->GetDBField('Filename'), 'to' => $temp_object->GetDBField('Filename') ); $this->Application->SetVar($event->Prefix . '_filename_changes', $filename_changes); } } /** * Calls kDBEventHandler::OnSave original event * Used in proj-cms:StructureEventHandler->OnSave * * @param kEvent $event */ function parentOnSave($event) { parent::OnSave($event); } /** * Reset root-category flag when new category is created * * @param kEvent $event * @return void * @access protected */ protected function OnPreCreate(kEvent $event) { // 1. for permission editing of Home category $this->Application->RemoveVar('IsRootCategory_' . $this->Application->GetVar('m_wid')); parent::OnPreCreate($event); /** @var kDBItem $object */ $object = $event->getObject(); // 2. preset template $category_id = $this->Application->GetVar('m_cat_id'); $root_category = $this->Application->getBaseCategory(); if ( $category_id == $root_category ) { $object->SetDBField('Template', $this->_getDefaultDesign()); } // 3. set default owner $object->SetDBField('CreatedById', $this->Application->RecallVar('user_id')); } /** * Checks cache update mark and redirect to cache if needed * * @param kEvent $event * @return void * @access protected */ protected function OnSave(kEvent $event) { // get data from live table before it is overwritten by parent OnSave method call $ids = $this->getSelectedIDs($event, true); $is_editing = implode('', $ids); $old_statuses = $is_editing ? $this->_getCategoryStatus($ids) : Array (); /** @var CategoriesItem $object */ $object = $event->getObject(); parent::OnSave($event); if ( $event->status != kEvent::erSUCCESS ) { return; } if ( $this->Application->RecallVar('PermCache_UpdateRequired') ) { $this->Application->RemoveVar('IsRootCategory_' . $this->Application->GetVar('m_wid')); } $this->Application->StoreVar('RefreshStructureTree', 1); $this->_resetMenuCache(); if ( $is_editing ) { // send email event to category owner, when it's status is changed (from admin) $object->SwitchToLive(); $new_statuses = $this->_getCategoryStatus($ids); $process_statuses = Array (STATUS_ACTIVE, STATUS_DISABLED); foreach ($new_statuses as $category_id => $new_status) { if ( $new_status != $old_statuses[$category_id] && in_array($new_status, $process_statuses) ) { $object->Load($category_id); $email_event = $new_status == STATUS_ACTIVE ? 'CATEGORY.APPROVE' : 'CATEGORY.DENY'; $this->Application->emailUser($email_event, $object->GetDBField('CreatedById'), $object->getEmailParams()); } } } // change opener stack in case if edited category filename was changed $filename_changes = $this->Application->GetVar($event->Prefix . '_filename_changes', Array ()); if ( $filename_changes ) { /** @var kOpenerStack $opener_stack */ $opener_stack = $this->Application->makeClass('kOpenerStack'); list ($template, $params, $index_file) = $opener_stack->pop(); foreach ($filename_changes as $change_info) { $template = str_ireplace($change_info['from'], $change_info['to'], $template); } $opener_stack->push($template, $params, $index_file); $opener_stack->save(); } } /** * Returns statuses of given categories * * @param Array $category_ids * @return Array */ function _getCategoryStatus($category_ids) { $config = $this->getUnitConfig(); $id_field = $config->getIDField(); $table_name = $config->getTableName(); $sql = 'SELECT Status, ' . $id_field . ' FROM ' . $table_name . ' WHERE ' . $id_field . ' IN (' . implode(',', $category_ids) . ')'; return $this->Conn->GetCol($sql, $id_field); } /** * Creates a new item in temp table and * stores item id in App vars and Session on success * * @param kEvent $event * @return void * @access protected */ protected function OnPreSaveCreated(kEvent $event) { /** @var CategoriesItem $object */ $object = $event->getObject( Array ('skip_autoload' => true) ); if ( $object->IsRoot() ) { // don't create root category while saving permissions return; } parent::OnPreSaveCreated($event); } /** * Deletes sym link to other category * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemDelete(kEvent $event) { parent::OnAfterItemDelete($event); /** @var kDBItem $object */ $object = $event->getObject(); $sql = 'UPDATE ' . $object->TableName . ' SET SymLinkCategoryId = NULL WHERE SymLinkCategoryId = ' . $object->GetID(); $this->Conn->Query($sql); // delete direct subscriptions to category, that was deleted $sql = 'SELECT SubscriptionId FROM ' . TABLE_PREFIX . 'SystemEventSubscriptions WHERE CategoryId = ' . $object->GetID(); $ids = $this->Conn->GetCol($sql); if ( $ids ) { /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject('system-event-subscription_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event->MasterEvent)); $temp_handler->DeleteItems('system-event-subscription', '', $ids); } } /** * Exclude root categories from deleting * * @param kEvent $event * @param string $type * @return void * @access protected */ protected function customProcessing(kEvent $event, $type) { if ( $event->Name == 'OnMassDelete' && $type == 'before' ) { $ids = $event->getEventParam('ids'); if ( !$ids || $this->Application->ConfigValue('AllowDeleteRootCats') ) { return; } $root_categories = Array (); // get module root categories and exclude them foreach ($this->Application->ModuleInfo as $module_info) { $root_categories[] = $module_info['RootCat']; } $root_categories = array_unique($root_categories); if ( $root_categories && array_intersect($ids, $root_categories) ) { $event->setEventParam('ids', array_diff($ids, $root_categories)); $this->Application->StoreVar('root_delete_error', 1); } } } /** * Checks, that given template exists (physically) in given theme * * @param string $template * @param int $theme_id * @return bool */ function _templateFound($template, $theme_id = null) { static $init_made = false; if (!$init_made) { $this->Application->InitParser(true); $init_made = true; } if (!isset($theme_id)) { $theme_id = $this->_getCurrentThemeId(); } $theme_name = $this->_getThemeName($theme_id); return $this->Application->TemplatesCache->TemplateExists('theme:' . $theme_name . '/' . $template); } /** * Removes ".tpl" in template path * * @param string $template * @return string */ function _stripTemplateExtension($template) { // return preg_replace('/\.[^.\\\\\\/]*$/', '', $template); return preg_replace('/^[\\/]{0,1}(.*)\.tpl$/', "$1", $template); } /** * Deletes all selected items. * Automatically recourse into sub-items using temp handler, and deletes sub-items * by calling its Delete method if sub-item has AutoDelete set to true in its config file * * @param kEvent $event * @return void * @access protected */ protected function OnMassDelete(kEvent $event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } $to_delete = Array (); $ids = $this->StoreSelectedIDs($event); $recycle_bin = $this->Application->ConfigValue('RecycleBinFolder'); if ( $recycle_bin ) { /** @var CategoriesItem $rb */ $rb = $this->Application->recallObject('c.recycle', null, Array ('skip_autoload' => true)); $rb->Load($recycle_bin); /** @var CategoriesItem $cat */ $cat = $event->getObject(Array ('skip_autoload' => true)); foreach ($ids as $id) { $cat->Load($id); if ( preg_match('/^' . preg_quote($rb->GetDBField('ParentPath'), '/') . '/', $cat->GetDBField('ParentPath')) ) { // already in "Recycle Bin" -> delete for real $to_delete[] = $id; continue; } // just move into "Recycle Bin" category $cat->SetDBField('ParentId', $recycle_bin); $cat->Update(); } $ids = $to_delete; } $event->setEventParam('ids', $ids); $this->customProcessing($event, 'before'); $ids = $event->getEventParam('ids'); if ( $ids ) { /** @var kRecursiveHelper $recursive_helper */ $recursive_helper = $this->Application->recallObject('RecursiveHelper'); foreach ($ids as $id) { $recursive_helper->DeleteCategory($id, $event->Prefix); } } $this->clearSelectedIDs($event); $this->_ensurePermCacheRebuild($event); } /** * Add selected items to clipboard with mode = COPY (CLONE) * * @param kEvent $event */ function OnCopy($event) { $this->Application->RemoveVar('clipboard'); /** @var kClipboardHelper $clipboard_helper */ $clipboard_helper = $this->Application->recallObject('ClipboardHelper'); $clipboard_helper->setClipboard($event, 'copy', $this->StoreSelectedIDs($event)); $this->clearSelectedIDs($event); } /** * Add selected items to clipboard with mode = CUT * * @param kEvent $event */ function OnCut($event) { $this->Application->RemoveVar('clipboard'); /** @var kClipboardHelper $clipboard_helper */ $clipboard_helper = $this->Application->recallObject('ClipboardHelper'); $clipboard_helper->setClipboard($event, 'cut', $this->StoreSelectedIDs($event)); $this->clearSelectedIDs($event); } /** * Controls all item paste operations. Can occur only with filled clipboard. * * @param kEvent $event */ function OnPasteClipboard($event) { $clipboard = unserialize( $this->Application->RecallVar('clipboard') ); foreach ($clipboard as $prefix => $clipboard_data) { $paste_event = new kEvent($prefix.':OnPaste', Array('clipboard_data' => $clipboard_data)); $this->Application->HandleEvent($paste_event); $event->copyFrom($paste_event); } } /** * Checks permission for OnPaste event * * @param kEvent $event * @return bool */ function _checkPastePermission($event) { /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); $category_id = $this->Application->GetVar('m_cat_id'); if ($perm_helper->AddCheckPermission($category_id, $event->Prefix) == 0) { // no items left for editing -> no permission return $perm_helper->finalizePermissionCheck($event, false); } return true; } /** * Paste categories with sub-items from clipboard * * @param kEvent $event * @return void * @access protected */ protected function OnPaste($event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) || !$this->_checkPastePermission($event) ) { $event->status = kEvent::erFAIL; return; } $clipboard_data = $event->getEventParam('clipboard_data'); if ( !$clipboard_data['cut'] && !$clipboard_data['copy'] ) { return; } // 1. get ParentId of moved category(-es) before it gets updated!!!) $source_category_id = 0; $config = $event->getUnitConfig(); $id_field = $config->getIDField(); $table_name = $config->getTableName(); if ( $clipboard_data['cut'] ) { $sql = 'SELECT ParentId FROM ' . $table_name . ' WHERE ' . $id_field . ' = ' . $clipboard_data['cut'][0]; $source_category_id = $this->Conn->GetOne($sql); } /** @var kRecursiveHelper $recursive_helper */ $recursive_helper = $this->Application->recallObject('RecursiveHelper'); if ( $clipboard_data['cut'] ) { $recursive_helper->MoveCategories($clipboard_data['cut'], $this->Application->GetVar('m_cat_id')); } if ( $clipboard_data['copy'] ) { // don't allow to copy/paste system OR theme-linked virtual pages $sql = 'SELECT ' . $id_field . ' FROM ' . $table_name . ' WHERE ' . $id_field . ' IN (' . implode(',', $clipboard_data['copy']) . ') AND (`Type` = ' . PAGE_TYPE_VIRTUAL . ') AND (ThemeId = 0)'; $allowed_ids = $this->Conn->GetCol($sql); if ( !$allowed_ids ) { return; } foreach ($allowed_ids as $id) { $recursive_helper->PasteCategory($id, $event->Prefix); } } /** @var kPriorityHelper $priority_helper */ $priority_helper = $this->Application->recallObject('PriorityHelper'); if ( $clipboard_data['cut'] ) { $ids = $priority_helper->recalculatePriorities($event, 'ParentId = ' . $source_category_id); if ( $ids ) { $priority_helper->massUpdateChanged($event->Prefix, $ids); } } // recalculate priorities of newly pasted categories in destination category $parent_id = $this->Application->GetVar('m_cat_id'); $ids = $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id); if ( $ids ) { $priority_helper->massUpdateChanged($event->Prefix, $ids); } if ( $clipboard_data['cut'] || $clipboard_data['copy'] ) { $this->_ensurePermCacheRebuild($event); } } /** * Ensures, that category permission cache is rebuild when category is added/edited/deleted * * @param kEvent $event * @return void * @access protected */ protected function _ensurePermCacheRebuild(kEvent $event) { $this->Application->StoreVar('PermCache_UpdateRequired', 1); $this->Application->StoreVar('RefreshStructureTree', 1); } /** * Occurs when pasting category * * @param kEvent $event */ /*function OnCatPaste($event) { $inp_clipboard = $this->Application->RecallVar('ClipBoard'); $inp_clipboard = explode('-', $inp_clipboard, 2); if($inp_clipboard[0] == 'COPY') { $config = $event->getUnitConfig(); $cat_ids = $event->getEventParam('cat_ids'); $saved_cat_id = $this->Application->GetVar('m_cat_id'); $ids_sql = 'SELECT ' . $config->getIDField() . ' FROM ' . $config->getTableName() . ' WHERE ResourceId IN (%s)'; $resource_ids_sql = 'SELECT ItemResourceId FROM '.TABLE_PREFIX.'CategoryItems WHERE CategoryId = %s AND PrimaryCat = 1'; $object = $this->Application->recallObject($event->Prefix.'.item', $event->Prefix, Array('skip_autoload' => true)); foreach($cat_ids as $source_cat => $dest_cat) { $item_resource_ids = $this->Conn->GetCol( sprintf($resource_ids_sql, $source_cat) ); if(!$item_resource_ids) continue; $this->Application->SetVar('m_cat_id', $dest_cat); $item_ids = $this->Conn->GetCol( sprintf($ids_sql, implode(',', $item_resource_ids) ) ); $temp = $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event)); if($item_ids) $temp->CloneItems($event->Prefix, $event->Special, $item_ids); } $this->Application->SetVar('m_cat_id', $saved_cat_id); } }*/ /** * Clears clipboard content * * @param kEvent $event */ function OnClearClipboard($event) { $this->Application->RemoveVar('clipboard'); } /** + * Validates category data. + * + * @param kEvent $event Event. + * + * @return void + */ + protected function OnBeforeItemValidate(kEvent $event) + { + parent::OnBeforeItemValidate($event); + + /** @var kDBItem $object */ + $object = $event->getObject(); + + $friendly_url = $object->GetDBField('FriendlyURL'); + + if ( strlen($friendly_url) && $friendly_url != $object->GetOriginalField('FriendlyURL') ) { + $sql = 'SELECT CategoryId + FROM %s + WHERE NamedParentPath = ' . $this->Conn->qstr('Content/' . $friendly_url); + $duplicate_id = $this->Conn->GetOne(sprintf($sql, $object->TableName)); + + if ( $duplicate_id === false && $object->IsTempTable() ) { + $duplicate_id = $this->Conn->GetOne(sprintf( + $sql, + $this->Application->GetLiveName($object->TableName) + )); + } + + if ( $duplicate_id !== false ) { + $object->SetError('FriendlyURL', 'unique'); + } + } + } + + /** * Sets correct status for new categories created on front-end * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemCreate(kEvent $event) { parent::OnBeforeItemCreate($event); /** @var CategoriesItem $object */ $object = $event->getObject(); if ( $object->GetDBField('ParentId') <= 0 ) { // no parent category - use current (happens during import) $object->SetDBField('ParentId', $this->Application->GetVar('m_cat_id')); } $this->_beforeItemChange($event); if ( $this->Application->isAdmin || $event->Prefix == 'st' ) { // don't check category permissions when auto-creating structure pages return ; } /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); $new_status = false; $category_id = $this->Application->GetVar('m_cat_id'); if ( $perm_helper->CheckPermission('CATEGORY.ADD', 0, $category_id) ) { $new_status = STATUS_ACTIVE; } else { if ( $perm_helper->CheckPermission('CATEGORY.ADD.PENDING', 0, $category_id) ) { $new_status = STATUS_PENDING; } } if ( $new_status ) { $object->SetDBField('Status', $new_status); // don't forget to set Priority for suggested from Front-End categories $min_priority = $this->_getNextPriority($object->GetDBField('ParentId'), $object->TableName); $object->SetDBField('Priority', $min_priority); } else { $event->status = kEvent::erPERM_FAIL; return ; } } /** * Returns next available priority for given category from given table * * @param int $category_id * @param string $table_name * @return int */ function _getNextPriority($category_id, $table_name) { $sql = 'SELECT MIN(Priority) FROM ' . $table_name . ' WHERE ParentId = ' . $category_id; return (int)$this->Conn->GetOne($sql) - 1; } /** * Sets correct status for new categories created on front-end * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemUpdate(kEvent $event) { parent::OnBeforeItemUpdate($event); $this->_beforeItemChange($event); /** @var kDBItem $object */ $object = $event->getObject(); if ( $object->GetChangedFields() ) { $object->SetDBField('ModifiedById', $this->Application->RecallVar('user_id')); } } /** * Creates needed sql query to load item, * if no query is defined in config for * special requested, then use list query * * @param kEvent $event * @return string * @access protected */ protected function ItemPrepareQuery(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $sqls = $object->getFormOption('ItemSQLs', Array ()); $category_special = $this->_getCategorySpecial($event); $special = isset($sqls[$category_special]) ? $category_special : ''; // preferred special not found in ItemSQLs -> use analog from ListSQLs return isset($sqls[$special]) ? $sqls[$special] : $this->ListPrepareQuery($event); } /** * Creates needed sql query to load list, * if no query is defined in config for * special requested, then use default * query * * @param kEvent $event * @return string * @access protected */ protected function ListPrepareQuery(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $special = $this->_getCategorySpecial($event); $sqls = $object->getFormOption('ListSQLs', Array ()); return $sqls[array_key_exists($special, $sqls) ? $special : '']; } /** * Performs redirect to correct suggest confirmation template * * @param kEvent $event * @return void * @access protected */ protected function OnCreate(kEvent $event) { parent::OnCreate($event); if ( $this->Application->isAdmin || $event->status != kEvent::erSUCCESS ) { // don't sent email or rebuild cache directly after category is created by admin return; } /** @var kDBItem $object */ $object = $event->getObject(); /** @var kPermCacheUpdater $cache_updater */ $cache_updater = $this->Application->makeClass('kPermCacheUpdater', Array (null, $object->GetDBField('ParentPath'))); $cache_updater->OneStepRun(); $is_active = ($object->GetDBField('Status') == STATUS_ACTIVE); $next_template = $is_active ? 'suggest_confirm_template' : 'suggest_pending_confirm_template'; $event->redirect = $this->Application->GetVar($next_template); $event->SetRedirectParam('opener', 's'); // send email events $send_params = $object->getEmailParams(); $event_suffix = $is_active ? 'ADD' : 'ADD.PENDING'; $perm_prefix = $event->getUnitConfig()->getPermItemPrefix(); $this->Application->emailUser($perm_prefix . '.' . $event_suffix, $object->GetDBField('CreatedById'), $send_params); $this->Application->emailAdmin($perm_prefix . '.' . $event_suffix, null, $send_params); } /** * Returns current per-page setting for list * * @param kEvent $event * @return int * @access protected */ protected function getPerPage(kEvent $event) { if ( !$this->Application->isAdmin ) { $same_special = $event->getEventParam('same_special'); $event->setEventParam('same_special', true); $per_page = parent::getPerPage($event); $event->setEventParam('same_special', $same_special); } return parent::getPerPage($event); } /** * Set's correct page for list based on data provided with event * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetPagination(kEvent $event) { parent::SetPagination($event); if ( !$this->Application->isAdmin ) { $page_var = $event->getEventParam('page_var'); if ( $page_var !== false ) { $page = $this->Application->GetVar($page_var); if ( is_numeric($page) ) { /** @var kDBList $object */ $object = $event->getObject(); $object->SetPage($page); } } } } /** * Apply same processing to each item being selected in grid * * @param kEvent $event * @return void * @access protected */ protected function iterateItems(kEvent $event) { if ( $event->Name != 'OnMassApprove' && $event->Name != 'OnMassDecline' ) { parent::iterateItems($event); } if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } /** @var CategoriesItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $ids = $this->StoreSelectedIDs($event); if ( $ids ) { $propagate_category_status = $this->Application->GetVar('propagate_category_status'); $status_field = $event->getUnitConfig()->getStatusField(true); foreach ($ids as $id) { $object->Load($id); $object->SetDBField($status_field, $event->Name == 'OnMassApprove' ? 1 : 0); if ( $object->Update() ) { if ( $propagate_category_status ) { $sql = 'UPDATE ' . $object->TableName . ' SET ' . $status_field . ' = ' . $object->GetDBField($status_field) . ' WHERE TreeLeft BETWEEN ' . $object->GetDBField('TreeLeft') . ' AND ' . $object->GetDBField('TreeRight'); $this->Conn->Query($sql); } $email_event = $event->Name == 'OnMassApprove' ? 'CATEGORY.APPROVE' : 'CATEGORY.DENY'; $this->Application->emailUser($email_event, $object->GetDBField('CreatedById'), $object->getEmailParams()); } } } $this->clearSelectedIDs($event); $this->Application->StoreVar('RefreshStructureTree', 1); } /** * Checks, that currently loaded item is allowed for viewing (non permission-based) * * @param kEvent $event * @return bool * @access protected */ protected function checkItemStatus(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); if ( !$object->isLoaded() ) { return true; } if ( $object->GetDBField('Status') != STATUS_ACTIVE && $object->GetDBField('Status') != 4 ) { if ( !$object->GetDBField('DirectLinkEnabled') || !$object->GetDBField('DirectLinkAuthKey') ) { return false; } return $this->Application->GetVar('authkey') == $object->GetDBField('DirectLinkAuthKey'); } return true; } /** * Set's correct sorting for list based on data provided with event * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetSorting(kEvent $event) { $types = $event->getEventParam('types'); $types = $types ? explode(',', $types) : Array (); if ( in_array('search', $types) ) { $event->setPseudoClass('_List'); /** @var kDBList $object */ $object = $event->getObject(); // 1. no user sorting - sort by relevance $default_sortings = parent::_getDefaultSorting($event); $default_sorting = key($default_sortings['Sorting']) . ',' . current($default_sortings['Sorting']); if ( $object->isMainList() ) { $sort_by = $this->Application->GetVar('sort_by', ''); if ( !$sort_by ) { $this->Application->SetVar('sort_by', 'Relevance,desc|' . $default_sorting); } elseif ( strpos($sort_by, 'Relevance,') !== false ) { $this->Application->SetVar('sort_by', $sort_by . '|' . $default_sorting); } } else { $sorting_settings = $this->getListSetting($event, 'Sortings'); $sort_by = trim(getArrayValue($sorting_settings, 'Sort1') . ',' . getArrayValue($sorting_settings, 'Sort1_Dir'), ','); if ( !$sort_by ) { $event->setEventParam('sort_by', 'Relevance,desc|' . $default_sorting); } elseif ( strpos($sort_by, 'Relevance,') !== false ) { $event->setEventParam('sort_by', $sort_by . '|' . $default_sorting); } } $this->_removeForcedSortings($event); } parent::SetSorting($event); } /** * Removes forced sortings * * @param kEvent $event */ protected function _removeForcedSortings(kEvent $event) { $config = $event->getUnitConfig(); foreach ($config->getListSortingSpecials() as $special) { $list_sortings = $config->getListSortingsBySpecial($special); unset($list_sortings['ForcedSorting']); $config->setListSortingsBySpecial('', $list_sortings); } } /** * Default sorting in search results only comes from relevance field * * @param kEvent $event * @return Array * @access protected */ protected function _getDefaultSorting(kEvent $event) { $types = $event->getEventParam('types'); $types = $types ? explode(',', $types) : Array (); return in_array('search', $types) ? Array () : parent::_getDefaultSorting($event); } // ============= for cms page processing ======================= /** * Returns default design template * * @return string */ function _getDefaultDesign() { $default_design = trim($this->Application->ConfigValue('cms_DefaultDesign'), '/'); if (!$default_design) { // theme-based alias for default design return '#default_design#'; } if (strpos($default_design, '#') === false) { // real template, not alias, so prefix with "/" return '/' . $default_design; } // alias return $default_design; } /** * Returns default design based on given virtual template (used from kApplication::Run) * * @param string $t * @return string * @access public */ public function GetDesignTemplate($t = null) { if ( !isset($t) ) { $t = $this->Application->GetVar('t'); } /** @var CategoriesItem $page */ $page = $this->Application->recallObject($this->Prefix . '.-virtual', null, Array ('page' => $t)); if ( $page->isLoaded() ) { $real_t = $page->GetDBField('CachedTemplate'); $this->Application->SetVar('m_cat_id', $page->GetDBField('CategoryId')); if ( $page->GetDBField('FormId') ) { $this->Application->SetVar('form_id', $page->GetDBField('FormId')); } } else { $this->Application->UrlManager->show404(); } // replace alias in form #alias_name# to actual template used in this theme if ( $this->Application->isAdmin ) { /** @var kThemesHelper $themes_helper */ $themes_helper = $this->Application->recallObject('ThemesHelper'); // only, used when in "Design Mode" $this->Application->SetVar('theme.current_id', $themes_helper->getCurrentThemeId()); } /** @var kDBItem $theme */ $theme = $this->Application->recallObject('theme.current'); $template = $theme->GetField('TemplateAliases', $real_t); if ( $template ) { return $template; } return $real_t; } /** * Sets category id based on found template (used from kApplication::Run) * * @deprecated */ /*function SetCatByTemplate() { $t = $this->Application->GetVar('t'); $page = $this->Application->recallObject($this->Prefix . '.-virtual'); if ( $page->isLoaded() ) { $this->Application->SetVar('m_cat_id', $page->GetDBField('CategoryId')); } }*/ /** * Prepares template paths * * @param kEvent $event */ function _beforeItemChange($event) { /** @var CategoriesItem $object */ $object = $event->getObject(); $now = time(); if ( !$this->Application->isDebugMode() && strpos($event->Special, 'rebuild') === false ) { $object->SetDBField('Type', $object->GetOriginalField('Type')); $object->SetDBField('Protected', $object->GetOriginalField('Protected')); if ( $object->GetDBField('Protected') ) { // some fields are read-only for protected pages, when debug mode is off $object->SetDBField('AutomaticFilename', $object->GetOriginalField('AutomaticFilename')); $object->SetDBField('Filename', $object->GetOriginalField('Filename')); $object->SetDBField('Status', $object->GetOriginalField('Status')); } } $object->checkFilename(); $object->generateFilename(); // Don't allow creating records on behalf of another user. if ( !$this->Application->isAdminUser && !defined('CRON') ) { $object->SetDBField('CreatedById', $object->GetOriginalField('CreatedById')); } // Auto-assign records to currently logged-in user. if ( !$object->GetDBField('CreatedById') ) { $object->SetDBField('CreatedById', $this->Application->RecallVar('user_id')); } if ($object->GetChangedFields()) { $object->SetDBField('Modified_date', $now); $object->SetDBField('Modified_time', $now); } $object->setRequired('PageCacheKey', $object->GetDBField('OverridePageCacheKey')); $object->SetDBField('Template', $this->_stripTemplateExtension( $object->GetDBField('Template') )); - if ($object->GetDBField('Type') == PAGE_TYPE_TEMPLATE) { - if (!$this->_templateFound($object->GetDBField('Template'), $object->GetDBField('ThemeId'))) { + $category_type = $object->GetDBField('Type'); + + // Changing category type would associate/disassociate it to theme. + if ( $category_type != $object->GetOriginalField('Type') ) { + if ( $category_type == PAGE_TYPE_TEMPLATE ) { + $object->SetDBField('ThemeId', $this->_getCurrentThemeId()); + } + else { + $object->SetDBField('ThemeId', 0); + } + } + + if ( $category_type == PAGE_TYPE_TEMPLATE ) { + if ( !$this->_templateFound($object->GetDBField('Template'), $object->GetDBField('ThemeId')) ) { $object->SetError('Template', 'template_file_missing', 'la_error_TemplateFileMissing'); } } $this->_saveTitleField($object, 'Title'); $this->_saveTitleField($object, 'MenuTitle'); $root_category = $this->Application->getBaseCategory(); if ( file_exists(FULL_PATH . '/themes') && ($object->GetDBField('ParentId') == $root_category) && ($object->GetDBField('Template') == CATEGORY_TEMPLATE_INHERIT) ) { // there are themes + creating top level category $object->SetError('Template', 'no_inherit'); } if ( !$this->Application->isAdminUser && $object->isVirtualField('cust_RssSource') ) { // only administrator can set/change "cust_RssSource" field if ($object->GetDBField('cust_RssSource') != $object->GetOriginalField('cust_RssSource')) { $object->SetError('cust_RssSource', 'not_allowed', 'la_error_OperationNotAllowed'); } } if ( !$object->GetDBField('DirectLinkAuthKey') ) { $key_parts = Array ( $object->GetID(), $object->GetDBField('ParentId'), $object->GetField('Name'), 'b38' ); $object->SetDBField('DirectLinkAuthKey', substr( md5( implode(':', $key_parts) ), 0, 20 )); } } /** * Sets page name to requested field in case when: * 1. page was auto created (through theme file rebuild) * 2. requested field is empty * * @param kDBItem $object * @param string $field * @author Alex */ function _saveTitleField(&$object, $field) { $value = $object->GetField($field, 'no_default'); // current value of target field /** @var kMultiLanguage $ml_formatter */ $ml_formatter = $this->Application->recallObject('kMultiLanguage'); $src_field = $ml_formatter->LangFieldName('Name'); $dst_field = $ml_formatter->LangFieldName($field); $dst_field_not_changed = $object->GetOriginalField($dst_field) == $value; if ($value == '' || preg_match('/^_Auto: (.*)/', $value) || (($object->GetOriginalField($src_field) == $value) && $dst_field_not_changed)) { // target field is empty OR target field value starts with "_Auto: " OR (source field value // before change was equals to current target field value AND target field value wasn't changed) $object->SetField($dst_field, $object->GetField($src_field)); } } /** * Don't allow to delete system pages, when not in debug mode * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemDelete(kEvent $event) { parent::OnBeforeItemDelete($event); /** @var kDBItem $object */ $object = $event->getObject(); if ( $object->GetDBField('Protected') && !$this->Application->isDebugMode(false) ) { $event->status = kEvent::erFAIL; } } /** * Creates category based on given TPL file * * @param CategoriesItem $object * @param string $template * @param int $theme_id * @param int $system_mode * @param array $template_info * @return bool */ function _prepareAutoPage(&$object, $template, $theme_id = null, $system_mode = SMS_MODE_AUTO, $template_info = Array ()) { $template = $this->_stripTemplateExtension($template); if ($system_mode == SMS_MODE_AUTO) { $page_type = $this->_templateFound($template, $theme_id) ? PAGE_TYPE_TEMPLATE : PAGE_TYPE_VIRTUAL; } else { $page_type = $system_mode == SMS_MODE_FORCE ? PAGE_TYPE_TEMPLATE : PAGE_TYPE_VIRTUAL; } if (($page_type == PAGE_TYPE_TEMPLATE) && ($template_info === false)) { // do not auto-create system pages, when browsing through site return false; } if (!isset($theme_id)) { $theme_id = $this->_getCurrentThemeId(); } $root_category = $this->Application->getBaseCategory(); $page_category = $this->Application->GetVar('m_cat_id'); if (!$page_category) { $page_category = $root_category; $this->Application->SetVar('m_cat_id', $page_category); } if (($page_type == PAGE_TYPE_VIRTUAL) && (strpos($template, '/') !== false)) { // virtual page, but have "/" in template path -> create it's path $category_path = explode('/', $template); $template = array_pop($category_path); $page_category = $this->_getParentCategoryFromPath($category_path, $root_category, $theme_id); } $page_name = ($page_type == PAGE_TYPE_TEMPLATE) ? '_Auto: ' . $template : $template; $page_description = ''; if ($page_type == PAGE_TYPE_TEMPLATE) { $design_template = strtolower($template); // leading "/" not added ! if ($template_info) { if (array_key_exists('name', $template_info) && $template_info['name']) { $page_name = $template_info['name']; } if (array_key_exists('desc', $template_info) && $template_info['desc']) { $page_description = $template_info['desc']; } if (array_key_exists('section', $template_info) && $template_info['section']) { // this will override any global "m_cat_id" $page_category = $this->_getParentCategoryFromPath(explode('||', $template_info['section']), $root_category, $theme_id); } } } else { $design_template = $this->_getDefaultDesign(); // leading "/" added ! } $object->Clear(); $object->SetDBField('ParentId', $page_category); $object->SetDBField('Type', $page_type); $object->SetDBField('Protected', 1); // $page_type == PAGE_TYPE_TEMPLATE $object->SetDBField('IsMenu', 0); $object->SetDBField('ThemeId', $theme_id); // put all templates to then end of list (in their category) $min_priority = $this->_getNextPriority($page_category, $object->TableName); $object->SetDBField('Priority', $min_priority); $object->SetDBField('Template', $design_template); $object->SetDBField('CachedTemplate', $design_template); $primary_language = $this->Application->GetDefaultLanguageId(); $current_language = $this->Application->GetVar('m_lang'); $object->SetDBField('l' . $primary_language . '_Name', $page_name); $object->SetDBField('l' . $current_language . '_Name', $page_name); $object->SetDBField('l' . $primary_language . '_Description', $page_description); $object->SetDBField('l' . $current_language . '_Description', $page_description); return $object->Create(); } function _getParentCategoryFromPath($category_path, $base_category, $theme_id = null) { static $category_ids = Array (); if (!$category_path) { return $base_category; } if (array_key_exists(implode('||', $category_path), $category_ids)) { return $category_ids[ implode('||', $category_path) ]; } $backup_category_id = $this->Application->GetVar('m_cat_id'); /** @var CategoriesItem $object */ $object = $this->Application->recallObject($this->Prefix . '.rebuild-path', null, Array ('skip_autoload' => true)); $parent_id = $base_category; /** @var kFilenamesHelper $filenames_helper */ $filenames_helper = $this->Application->recallObject('FilenamesHelper'); $safe_category_path = array_map(Array (&$filenames_helper, 'replaceSequences'), $category_path); foreach ($category_path as $category_order => $category_name) { $this->Application->SetVar('m_cat_id', $parent_id); // get virtual category first, when possible $sql = 'SELECT ' . $object->IDField . ' FROM ' . $object->TableName . ' WHERE ( Filename = ' . $this->Conn->qstr($safe_category_path[$category_order]) . ' OR Filename = ' . $this->Conn->qstr( $filenames_helper->replaceSequences('_Auto: ' . $category_name) ) . ' ) AND (ParentId = ' . $parent_id . ') AND (ThemeId = 0 OR ThemeId = ' . $theme_id . ') ORDER BY ThemeId ASC'; $parent_id = $this->Conn->GetOne($sql); if ($parent_id === false) { // page not found $template = implode('/', array_slice($safe_category_path, 0, $category_order + 1)); // don't process system templates in sub-categories $system = $this->_templateFound($template, $theme_id) && (strpos($template, '/') === false); if (!$this->_prepareAutoPage($object, $category_name, $theme_id, $system ? SMS_MODE_FORCE : false)) { // page was not created break; } $parent_id = $object->GetID(); } } $this->Application->SetVar('m_cat_id', $backup_category_id); $category_ids[ implode('||', $category_path) ] = $parent_id; return $parent_id; } /** * Returns theme name by it's id. Used in structure page creation. * * @param int $theme_id * @return string */ function _getThemeName($theme_id) { static $themes = null; if (!isset($themes)) { $theme_config = $this->Application->getUnitConfig('theme'); $id_field = $theme_config->getIDField(); $table_name = $theme_config->getTableName(); $sql = 'SELECT Name, ' . $id_field . ' FROM ' . $table_name . ' WHERE Enabled = 1'; $themes = $this->Conn->GetCol($sql, $id_field); } return array_key_exists($theme_id, $themes) ? $themes[$theme_id] : false; } /** * Resets SMS-menu cache * * @param kEvent $event */ function OnResetCMSMenuCache($event) { if ($this->Application->GetVar('ajax') == 'yes') { $event->status = kEvent::erSTOP; } $this->_resetMenuCache(); $event->SetRedirectParam('action_completed', 1); } /** * Performs reset of category-related caches (menu, structure dropdown, template mapping) * * @return void * @access protected */ protected function _resetMenuCache() { // reset cms menu cache (all variables are automatically rebuild, when missing) if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $this->Application->rebuildCache('master:cms_menu', kCache::REBUILD_LATER, CacheSettings::$cmsMenuRebuildTime); $this->Application->rebuildCache('master:StructureTree', kCache::REBUILD_LATER, CacheSettings::$structureTreeRebuildTime); $this->Application->rebuildCache('master:template_mapping', kCache::REBUILD_LATER, CacheSettings::$templateMappingRebuildTime); } else { $this->Application->rebuildDBCache('cms_menu', kCache::REBUILD_LATER, CacheSettings::$cmsMenuRebuildTime); $this->Application->rebuildDBCache('StructureTree', kCache::REBUILD_LATER, CacheSettings::$structureTreeRebuildTime); $this->Application->rebuildDBCache('template_mapping', kCache::REBUILD_LATER, CacheSettings::$templateMappingRebuildTime); } } /** * Updates structure config * * @param kEvent $event * @return void * @access protected */ protected function OnAfterConfigRead(kEvent $event) { parent::OnAfterConfigRead($event); if (defined('IS_INSTALL') && IS_INSTALL) { // skip any processing, because Categories table doesn't exists until install is finished $this->addViewPermissionJoin($event); return ; } /** @var SiteConfigHelper $site_config_helper */ $site_config_helper = $this->Application->recallObject('SiteConfigHelper'); $settings = $site_config_helper->getSettings(); $root_category = $this->Application->getBaseCategory(); $config = $event->getUnitConfig(); // set root category $section_adjustments = Array ( 'in-portal:browse' => Array ( 'url' => Array ('m_cat_id' => $root_category), 'late_load' => Array ('m_cat_id' => $root_category), 'onclick' => 'checkCatalog(' . $root_category . ', "c")', ), 'in-portal:browse_site' => Array ( 'url' => Array ('editing_mode' => $settings['default_editing_mode']), ) ); if ( $this->Application->ConfigValue('Catalog_PreselectModuleTab') ) { $section_adjustments['in-portal:browse']['url']['anchor'] = 'tab-c'; } $config->addSectionAdjustments($section_adjustments); // prepare structure dropdown /** @var CategoryHelper $category_helper */ $category_helper = $this->Application->recallObject('CategoryHelper'); $fields = $config->getFields(); $fields['ParentId']['default'] = (int)$this->Application->GetVar('m_cat_id'); $fields['ParentId']['options'] = $category_helper->getStructureTreeAsOptions(); // limit design list by theme $theme_id = $this->_getCurrentThemeId(); $design_sql = $fields['Template']['options_sql']; $design_sql = str_replace('(tf.FilePath = "/designs")', '(' . implode(' OR ', $this->getDesignFolders()) . ')' . ' AND (t.ThemeId = ' . $theme_id . ')', $design_sql); $fields['Template']['options_sql'] = $design_sql; // adds "Inherit From Parent" option to "Template" field $fields['Template']['options'] = Array (CATEGORY_TEMPLATE_INHERIT => $this->Application->Phrase('la_opt_InheritFromParent')); $config->setFields($fields); if ($this->Application->isAdmin) { // don't sort by Front-End sorting fields $config_mapping = $config->getConfigMapping(); $remove_keys = Array ('DefaultSorting1Field', 'DefaultSorting2Field', 'DefaultSorting1Dir', 'DefaultSorting2Dir'); foreach ($remove_keys as $remove_key) { unset($config_mapping[$remove_key]); } $config->setConfigMapping($config_mapping); } else { // sort by parent path on Front-End only $config->setListSortingsBySpecial('', Array ( 'ForcedSorting' => Array ('CurrentSort' => 'asc'), )); } $this->addViewPermissionJoin($event); // add grids for advanced view (with primary category column) foreach (Array ('Default', 'Radio') as $process_grid) { $grid_data = $config->getGridByName($process_grid); $grid_data['Fields']['CachedNavbar'] = Array ('title' => 'la_col_Path', 'data_block' => 'grid_parent_category_td', 'filter_block' => 'grid_like_filter'); $config->addGrids($grid_data, $process_grid . 'ShowAll'); } } /** * Adds permission table table JOIN clause only, when advanced catalog view permissions enabled. * * @param kEvent $event Event. * * @return self * @access protected */ protected function addViewPermissionJoin(kEvent $event) { if ( $this->Application->ConfigValue('CheckViewPermissionsInCatalog') ) { $join_clause = 'LEFT JOIN ' . TABLE_PREFIX . 'CategoryPermissionsCache perm ON perm.CategoryId = %1$s.CategoryId'; } else { $join_clause = ''; } $config = $event->getUnitConfig(); foreach ( $config->getListSQLSpecials() as $special ) { $list_sql = str_replace('{PERM_JOIN}', $join_clause, $config->getListSQLsBySpecial($special)); $config->setListSQLsBySpecial($special, $list_sql); } return $this; } /** * Returns folders, that can contain design templates * * @return array * @access protected */ protected function getDesignFolders() { $ret = Array ('tf.FilePath = "/designs"', 'tf.FilePath = "/platform/designs"'); foreach ($this->Application->ModuleInfo as $module_info) { $ret[] = 'tf.FilePath = "/' . $module_info['TemplatePath'] . 'designs"'; } return array_unique($ret); } /** * Removes this item and it's children (recursive) from structure dropdown * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemLoad(kEvent $event) { parent::OnAfterItemLoad($event); if ( !$this->Application->isAdmin ) { // calculate priorities dropdown only for admin return; } /** @var kDBItem $object */ $object = $event->getObject(); // remove this category & it's children from dropdown $sql = 'SELECT ' . $object->IDField . ' FROM ' . $event->getUnitConfig()->getTableName() . ' WHERE ParentPath LIKE "' . $object->GetDBField('ParentPath') . '%"'; $remove_categories = $this->Conn->GetCol($sql); $options = $object->GetFieldOption('ParentId', 'options'); foreach ($remove_categories as $remove_category) { unset($options[$remove_category]); } $object->SetFieldOption('ParentId', 'options', $options); } /** * Occurs after creating item * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemCreate(kEvent $event) { parent::OnAfterItemCreate($event); /** @var CategoriesItem $object */ $object = $event->getObject(); // need to update path after category is created, so category is included in that path $fields_hash = $object->buildParentBasedFields(); $this->Conn->doUpdate($fields_hash, $object->TableName, $object->IDField . ' = ' . $object->GetID()); $object->SetDBFieldsFromHash($fields_hash); } /** * Enter description here... * * @param kEvent $event */ function OnAfterRebuildThemes($event) { $sql = 'SELECT t.ThemeId, CONCAT( tf.FilePath, \'/\', tf.FileName ) AS Path, tf.FileMetaInfo FROM ' . TABLE_PREFIX . 'ThemeFiles AS tf LEFT JOIN ' . TABLE_PREFIX . 'Themes AS t ON t.ThemeId = tf.ThemeId WHERE t.Enabled = 1 AND tf.FileType = 1 AND ( SELECT COUNT(CategoryId) FROM ' . TABLE_PREFIX . 'Categories c WHERE CONCAT(\'/\', c.Template, \'.tpl\') = CONCAT( tf.FilePath, \'/\', tf.FileName ) AND (c.ThemeId = t.ThemeId) ) = 0 '; $files = $this->Conn->Query($sql, 'Path'); if ( !$files ) { // all possible pages are already created return; } kUtil::setResourceLimit(); /** @var CategoriesItem $dummy */ $dummy = $this->Application->recallObject($event->Prefix . '.rebuild', NULL, Array ('skip_autoload' => true)); $error_count = 0; foreach ($files as $a_file => $file_info) { $status = $this->_prepareAutoPage($dummy, $a_file, $file_info['ThemeId'], SMS_MODE_FORCE, unserialize($file_info['FileMetaInfo'])); // create system page if ( !$status ) { $error_count++; } } if ( $this->Application->ConfigValue('CategoryPermissionRebuildMode') == CategoryPermissionRebuild::SILENT ) { /** @var kPermCacheUpdater $updater */ $updater = $this->Application->makeClass('kPermCacheUpdater'); $updater->OneStepRun(); } $this->_resetMenuCache(); if ( $error_count ) { // allow user to review error after structure page creation $event->MasterEvent->redirect = false; } } /** * Processes OnMassMoveUp, OnMassMoveDown events * * @param kEvent $event */ function OnChangePriority($event) { $this->Application->SetVar('priority_prefix', $event->getPrefixSpecial()); $event->CallSubEvent('priority:' . $event->Name); $this->Application->StoreVar('RefreshStructureTree', 1); $this->_resetMenuCache(); } /** * Completely recalculates priorities in current category * * @param kEvent $event */ function OnRecalculatePriorities($event) { if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { $event->status = kEvent::erFAIL; return; } $this->Application->SetVar('priority_prefix', $event->getPrefixSpecial()); $event->CallSubEvent('priority:' . $event->Name); $this->_resetMenuCache(); } /** * Update Preview Block for FCKEditor * * @param kEvent $event */ function OnUpdatePreviewBlock($event) { $event->status = kEvent::erSTOP; $string = $this->Application->unescapeRequestVariable($this->Application->GetVar('preview_content')); /** @var CategoryHelper $category_helper */ $category_helper = $this->Application->recallObject('CategoryHelper'); $string = $category_helper->replacePageIds($string); $this->Application->StoreVar('_editor_preview_content_', $string); } /** * Makes simple search for categories * based on keywords string * * @param kEvent $event */ function OnSimpleSearch($event) { $event->redirect = false; $keywords = $this->Application->unescapeRequestVariable(trim($this->Application->GetVar('keywords'))); /** @var kHTTPQuery $query_object */ $query_object = $this->Application->recallObject('kHTTPQuery'); /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); $search_table = $search_helper->getSearchTable(); $sql = 'SHOW TABLES LIKE "'.$search_table.'"'; if ( !isset($query_object->Get['keywords']) && !isset($query_object->Post['keywords']) && $this->Conn->Query($sql) ) { // used when navigating by pages or changing sorting in search results return; } if(!$keywords || strlen($keywords) < $this->Application->ConfigValue('Search_MinKeyword_Length')) { $search_helper->ensureEmptySearchTable(); $this->Application->SetVar('keywords_too_short', 1); return; // if no or too short keyword entered, doing nothing } $this->Application->StoreVar('keywords', $keywords); $this->saveToSearchLog($keywords, 0); // 0 - simple search, 1 - advanced search $keywords = strtr($keywords, Array('%' => '\\%', '_' => '\\_')); $event->setPseudoClass('_List'); /** @var kDBList $object */ $object = $event->getObject(); $config = $event->getUnitConfig(); $this->Application->SetVar($event->getPrefixSpecial().'_Page', 1); $lang = $this->Application->GetVar('m_lang'); $items_table = $config->getTableName(); $module_name = 'In-Portal'; $sql = 'SELECT * FROM ' . $this->Application->getUnitConfig('confs')->getTableName() . ' WHERE ModuleName = ' . $this->Conn->qstr($module_name) . ' AND SimpleSearch = 1'; $search_config = $this->Conn->Query($sql, 'FieldName'); $field_list = array_keys($search_config); $join_clauses = Array(); // field processing $weight_sum = 0; $alias_counter = 0; $custom_fields = $config->getCustomFields(); if ($custom_fields) { $custom_table = $this->Application->getUnitConfig($event->Prefix . '-cdata')->getTableName(); $join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$items_table.'.ResourceId = custom_data.ResourceId'; } // what field in search config becomes what field in sql (key - new field, value - old field (from searchconfig table)) $search_config_map = Array(); foreach ($field_list as $key => $field) { $local_table = TABLE_PREFIX.$search_config[$field]['TableName']; $weight_sum += $search_config[$field]['Priority']; // counting weight sum; used when making relevance clause // processing multilingual fields if ( !$search_config[$field]['CustomFieldId'] && $object->GetFieldOption($field, 'formatter') == 'kMultiLanguage' ) { $field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field; $field_list[$key] = 'l'.$lang.'_'.$field; if (!isset($search_config[$field]['ForeignField'])) { $field_list[$key.'_primary'] = $local_table.'.'.$field_list[$key.'_primary']; $search_config_map[ $field_list[$key.'_primary'] ] = $field; } } // processing fields from other tables $foreign_field = $search_config[$field]['ForeignField']; if ( $foreign_field ) { $exploded = explode(':', $foreign_field, 2); if ($exploded[0] == 'CALC') { // ignoring having type clauses in simple search unset($field_list[$key]); continue; } else { $multi_lingual = false; if ($exploded[0] == 'MULTI') { $multi_lingual = true; $foreign_field = $exploded[1]; } $exploded = explode('.', $foreign_field); // format: table.field_name $foreign_table = TABLE_PREFIX.$exploded[0]; $alias_counter++; $alias = 't'.$alias_counter; if ($multi_lingual) { $field_list[$key] = $alias.'.'.'l'.$lang.'_'.$exploded[1]; $field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field; $search_config_map[ $field_list[$key] ] = $field; $search_config_map[ $field_list[$key.'_primary'] ] = $field; } else { $field_list[$key] = $alias.'.'.$exploded[1]; $search_config_map[ $field_list[$key] ] = $field; } $join_clause = str_replace('{ForeignTable}', $alias, $search_config[$field]['JoinClause']); $join_clause = str_replace('{LocalTable}', $items_table, $join_clause); $join_clauses[] = ' LEFT JOIN '.$foreign_table.' '.$alias.' ON '.$join_clause; } } else { // processing fields from local table if ($search_config[$field]['CustomFieldId']) { $local_table = 'custom_data'; // search by custom field value on current language $custom_field_id = array_search($field_list[$key], $custom_fields); $field_list[$key] = 'l'.$lang.'_cust_'.$custom_field_id; // search by custom field value on primary language $field_list[$key.'_primary'] = $local_table.'.l'.$this->Application->GetDefaultLanguageId().'_cust_'.$custom_field_id; $search_config_map[ $field_list[$key.'_primary'] ] = $field; } $field_list[$key] = $local_table.'.'.$field_list[$key]; $search_config_map[ $field_list[$key] ] = $field; } } // Keyword string processing. $where_clause = Array (); foreach ($field_list as $field) { if (preg_match('/^' . preg_quote($items_table, '/') . '\.(.*)/', $field, $regs)) { // local real field $filter_data = $search_helper->getSearchClause($object, $regs[1], $keywords, false); if ($filter_data) { $where_clause[] = $filter_data['value']; } } elseif (preg_match('/^custom_data\.(.*)/', $field, $regs)) { $custom_field_name = 'cust_' . $search_config_map[$field]; $filter_data = $search_helper->getSearchClause($object, $custom_field_name, $keywords, false); if ($filter_data) { $where_clause[] = str_replace('`' . $custom_field_name . '`', $field, $filter_data['value']); } } else { $where_clause[] = $search_helper->buildWhereClause($keywords, Array ($field)); } } $where_clause = '((' . implode(') OR (', $where_clause) . '))'; // 2 braces for next clauses, see below! $where_clause = $where_clause . ' AND (' . $items_table . '.Status = ' . STATUS_ACTIVE . ')'; if ($event->MasterEvent && $event->MasterEvent->Name == 'OnListBuild') { $sub_search_ids = $event->MasterEvent->getEventParam('ResultIds'); if ( $sub_search_ids !== false ) { if ( $sub_search_ids ) { $where_clause .= 'AND (' . $items_table . '.ResourceId IN (' . implode(',', $sub_search_ids) . '))'; } else { $where_clause .= 'AND FALSE'; } } } // exclude template based sections from search results (ie. registration) if ( $this->Application->ConfigValue('ExcludeTemplateSectionsFromSearch') ) { $where_clause .= ' AND ' . $items_table . '.ThemeId = 0'; } // making relevance clause $positive_words = $search_helper->getPositiveKeywords($keywords); $this->Application->StoreVar('highlight_keywords', serialize($positive_words)); $revelance_parts = Array(); reset($search_config); foreach ($positive_words as $keyword_index => $positive_word) { $positive_word = $search_helper->transformWildcards($positive_word); $positive_words[$keyword_index] = $this->Conn->escape($positive_word); } foreach ($field_list as $field) { if (!array_key_exists($field, $search_config_map)) { $map_key = $search_config_map[$items_table . '.' . $field]; } else { $map_key = $search_config_map[$field]; } $config_elem = $search_config[ $map_key ]; $weight = $config_elem['Priority']; // search by whole words only ([[:<:]] - word boundary) /*$revelance_parts[] = 'IF('.$field.' REGEXP "[[:<:]]('.implode(' ', $positive_words).')[[:>:]]", '.$weight.', 0)'; foreach ($positive_words as $keyword) { $revelance_parts[] = 'IF('.$field.' REGEXP "[[:<:]]('.$keyword.')[[:>:]]", '.$weight.', 0)'; }*/ if ( count($positive_words) > 1 ) { $condition = $field . ' LIKE "%' . implode(' ', $positive_words) . '%"'; $revelance_parts[] = 'IF(' . $condition . ', ' . $weight_sum . ', 0)'; } // search by partial word matches too foreach ( $positive_words as $keyword ) { $revelance_parts[] = 'IF(' . $field . ' LIKE "%' . $keyword . '%", ' . $weight . ', 0)'; } } $revelance_parts = array_unique($revelance_parts); $conf_postfix = $config->getSearchConfigPostfix(); $rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_'.$conf_postfix) / 100; $rel_pop = $this->Application->ConfigValue('SearchRel_Pop_'.$conf_postfix) / 100; $rel_rating = $this->Application->ConfigValue('SearchRel_Rating_'.$conf_postfix) / 100; $relevance_clause = '('.implode(' + ', $revelance_parts).') / '.$weight_sum.' * '.$rel_keywords; if ($rel_pop && $object->isField('Hits')) { $relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop; } if ($rel_rating && $object->isField('CachedRating')) { $relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating; } // building final search query if (!$this->Application->GetVar('do_not_drop_search_table')) { $this->Conn->Query('DROP TABLE IF EXISTS '.$search_table); // erase old search table if clean k4 event $this->Application->SetVar('do_not_drop_search_table', true); } $search_table_exists = $this->Conn->Query('SHOW TABLES LIKE "'.$search_table.'"'); if ($search_table_exists) { $select_intro = 'INSERT INTO '.$search_table.' (Relevance, ItemId, ResourceId, ItemType, EdPick) '; } else { $select_intro = 'CREATE TABLE '.$search_table.' AS '; } $edpick_clause = $config->getFieldByName('EditorsPick') ? $items_table.'.EditorsPick' : '0'; $sql = $select_intro.' SELECT '.$relevance_clause.' AS Relevance, '.$items_table.'.'.$config->getIDField().' AS ItemId, '.$items_table.'.ResourceId, '.$config->getItemType().' AS ItemType, '.$edpick_clause.' AS EdPick FROM '.$object->TableName.' '.implode(' ', $join_clauses).' WHERE '.$where_clause.' GROUP BY '.$items_table.'.'.$config->getIDField().' ORDER BY Relevance DESC'; $this->Conn->Query($sql); if ( !$search_table_exists ) { $sql = 'ALTER TABLE ' . $search_table . ' ADD INDEX (ResourceId), ADD INDEX (Relevance)'; $this->Conn->Query($sql); } } /** * Enter description here... * * @param kEvent $event */ function OnSubSearch($event) { // keep search results from other items after doing a sub-search on current item type $this->Application->SetVar('do_not_drop_search_table', true); /** @var kSearchHelper $search_helper */ $search_helper = $this->Application->recallObject('SearchHelper'); $search_table = $search_helper->getSearchTable(); $sql = 'SHOW TABLES LIKE "' . $search_table . '"'; $ids = array(); if ( $this->Conn->Query($sql) ) { $item_type = $event->getUnitConfig()->getItemType(); // 1. get ids to be used as search bounds $sql = 'SELECT DISTINCT ResourceId FROM ' . $search_table . ' WHERE ItemType = ' . $item_type; $ids = $this->Conn->GetCol($sql); // 2. delete previously found ids $sql = 'DELETE FROM ' . $search_table . ' WHERE ItemType = ' . $item_type; $this->Conn->Query($sql); } $event->setEventParam('ResultIds', $ids); $event->CallSubEvent('OnSimpleSearch'); } /** * Make record to search log * * @param string $keywords * @param int $search_type 0 - simple search, 1 - advanced search */ function saveToSearchLog($keywords, $search_type = 0) { // don't save keywords for each module separately, just one time // static variable can't help here, because each module uses it's own class instance ! if (!$this->Application->GetVar('search_logged')) { $sql = 'UPDATE '.TABLE_PREFIX.'SearchLogs SET Indices = Indices + 1 WHERE Keyword = '.$this->Conn->qstr($keywords).' AND SearchType = '.$search_type; // 0 - simple search, 1 - advanced search $this->Conn->Query($sql); if ($this->Conn->getAffectedRows() == 0) { $fields_hash = Array('Keyword' => $keywords, 'Indices' => 1, 'SearchType' => $search_type); $this->Conn->doInsert($fields_hash, TABLE_PREFIX.'SearchLogs'); } $this->Application->SetVar('search_logged', 1); } } /** * Load item if id is available * * @param kEvent $event * @return void * @access protected */ protected function LoadItem(kEvent $event) { if ( !$this->_isVirtual($event) ) { parent::LoadItem($event); return; } /** @var kDBItem $object */ $object = $event->getObject(); $id = $this->getPassedID($event); if ( $object->isLoaded() && !is_array($id) && ($object->GetID() == $id) ) { // object is already loaded by same id return; } if ( $object->Load($id, null, true) ) { /** @var Params $actions */ $actions = $this->Application->recallObject('kActions'); $actions->Set($event->getPrefixSpecial() . '_id', $object->GetID()); } else { $object->setID($id); } } /** * Returns constrain for priority calculations * * @param kEvent $event * @return void * @see PriorityEventHandler * @access protected */ protected function OnGetConstrainInfo(kEvent $event) { $constrain = ''; // for OnSave $event_name = $event->getEventParam('original_event'); $actual_event_name = $event->getEventParam('actual_event'); if ( $actual_event_name == 'OnSavePriorityChanges' || $event_name == 'OnAfterItemLoad' || $event_name == 'OnAfterItemDelete' ) { /** @var kDBItem $object */ $object = $event->getObject(); $constrain = 'ParentId = ' . $object->GetDBField('ParentId'); } elseif ( $actual_event_name == 'OnPreparePriorities' ) { $constrain = 'ParentId = ' . $this->Application->GetVar('m_cat_id'); } elseif ( $event_name == 'OnSave' ) { $constrain = ''; } else { $constrain = 'ParentId = ' . $this->Application->GetVar('m_cat_id'); } $event->setEventParam('constrain_info', Array ($constrain, '')); } /** * Set's new unique resource id to user * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemValidate(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $resource_id = $object->GetDBField('ResourceId'); if ( !$resource_id ) { $object->SetDBField('ResourceId', $this->Application->NextResourceId()); } } /** * Occurs before an item has been cloned * Id of newly created item is passed as event' 'id' param * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeClone(kEvent $event) { parent::OnBeforeClone($event); /** @var kDBItem $object */ $object = $event->getObject(); $object->SetDBField('ResourceId', 0); // this will reset it } } Index: branches/5.3.x/core/units/themes/themes_config.php =================================================================== --- branches/5.3.x/core/units/themes/themes_config.php (revision 16599) +++ branches/5.3.x/core/units/themes/themes_config.php (revision 16600) @@ -1,164 +1,164 @@ 'theme', 'ItemClass' => Array ('class' => 'ThemeItem', 'file' => 'theme_item.php', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'ThemesEventHandler', 'file' => 'themes_eh.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'ThemesTagProcessor', 'file' => 'themes_tag_processor.php', 'build_event' => 'OnBuild'), 'AutoLoad' => true, 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'PerPage', 4 => 'event', 5 => 'mode', ), 'IDField' => 'ThemeId', 'StatusField' => Array ('Enabled', 'PrimaryTheme'), 'PermSection' => Array ('main' => 'in-portal:configure_themes'), 'Sections' => Array ( 'in-portal:configure_themes' => Array ( 'parent' => 'in-portal:website_setting_folder', 'icon' => 'conf_themes', 'label' => 'la_tab_Themes', 'url' => Array ('t' => 'themes/themes_list', 'pass' => 'm'), 'permissions' => Array ('view', 'add', 'edit', 'delete'), 'priority' => 5, 'type' => stTREE, ), ), 'TitleField' => 'Name', 'TitlePresets' => Array ( 'default' => Array ( 'new_status_labels' => Array ('theme' => '!la_title_Adding_Theme!'), 'edit_status_labels' => Array ('theme' => '!la_title_Editing_Theme!'), 'new_titlefield' => Array ('theme' => '!la_title_NewTheme!'), ), 'themes_list' => Array ( 'prefixes' => Array ('theme_List'), 'format' => "!la_tab_Themes!", 'toolbar_buttons' => Array ('new_item', 'edit', 'delete', 'setprimary', 'refresh', 'view', 'dbl-click'), ), 'themes_edit_general' => Array ( 'prefixes' => Array ('theme'), 'format' => "#theme_status# '#theme_titlefield#' - !la_title_General!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'themes_edit_files' => Array ( 'prefixes' => Array ('theme', 'theme-file_List'), 'format' => "#theme_status# '#theme_titlefield#' - !la_title_ThemeFiles!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next', 'edit', 'delete', 'view', 'dbl-click'), ), 'theme_file_edit' => Array ( 'prefixes' => Array ('theme', 'theme-file'), 'new_status_labels' => Array ('theme-file' => '!la_title_AddingThemeFile!'), 'edit_status_labels' => Array ('theme-file' => '!la_title_EditingThemeFile!'), 'new_titlefield' => Array ('theme-file' => '!la_title_NewThemeFile!'), 'format' => "#theme_status# '#theme_titlefield#' - #theme-file_status# '#theme-file_titlefield#'", 'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'), ), 'block_edit' => Array ('prefixes' => Array ('theme-file'), 'format' => "!la_title_EditingThemeFile! '#theme-file_titlefield#'"), ), 'EditTabPresets' => Array ( 'Default' => Array ( 'general' => Array ('title' => 'la_tab_General', 't' => 'themes/themes_edit', 'priority' => 1), 'files' => Array ('title' => 'la_tab_Files', 't' => 'themes/themes_edit_files', 'priority' => 2), ), ), 'TableName' => TABLE_PREFIX.'Themes', 'SubItems' => Array ('theme-file'), 'AutoDelete' => true, 'AutoClone' => true, 'ListSQLs' => Array ( '' => ' SELECT %1$s.* %2$s FROM %s' ), 'ListSortings' => Array ( '' => Array ( 'Sorting' => Array ('Name' => 'asc'), ) ), 'Fields' => Array ( 'ThemeId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'Name' => Array ('type' => 'string', 'not_null' => 1, 'required' => 1, 'default' => ''), 'Enabled' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_Disabled', 1 => 'la_Enabled'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1, ), - 'Description' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null), + 'Description' => Array ('type' => 'string', 'default' => null), 'PrimaryTheme' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0, ), 'CacheTimeout' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'StylesheetId' => Array ('type' => 'int', /*'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'Stylesheets', 'option_key_field' => 'StylesheetId', 'option_title_field' => 'Name',*/ 'not_null' => 1, 'default' => 0), 'LanguagePackInstalled' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'TemplateAliases' => Array ('type' => 'string', 'formatter' => 'kSerializedFormatter', 'default' => 'a:0:{}'), 'StylesheetFile' => array( 'type' => 'string', 'max_len' => 255, 'error_msgs' => array('not_found' => '!la_error_FileNotFound!'), 'not_null' => 1, 'default' => '' ), 'ImageResizeRules' => Array ('type' => 'string', 'default' => NULL), ), 'Grids' => Array ( 'Default' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', '0_0' => 'icon16_disabled.png', '0_1' => 'icon16_disabled.png', '1_0' => 'icon16_item.png', '1_1' => 'icon16_primary.png', ), 'Fields' => Array ( 'ThemeId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 50, ), 'Name' => Array ('filter_block' => 'grid_like_filter', 'width' => 200, ), 'Description' => Array ('filter_block' => 'grid_like_filter', 'width' => 250, ), 'Enabled' => Array ( 'title' => 'column:la_fld_Status', 'filter_block' => 'grid_options_filter', 'width' => 200, ), // 'PrimaryTheme' => Array ( 'title' => 'column:la_fld_Primary', 'filter_block' => 'grid_options_filter'), 'LanguagePackInstalled' => Array ('title' => 'la_col_LanguagePackInstalled', 'filter_block' => 'grid_options_filter', 'width' => 200,), 'StylesheetFile' => array('filter_block' => 'grid_like_filter', 'width' => 150, 'hidden' => 1), ), ), ), ); \ No newline at end of file Index: branches/5.3.x/core/units/themes/theme_item.php =================================================================== --- branches/5.3.x/core/units/themes/theme_item.php (revision 16599) +++ branches/5.3.x/core/units/themes/theme_item.php (revision 16600) @@ -1,87 +1,91 @@ IsTempTable() ) { + $cachable = false; + } + $default = false; if ($id == 'default') { // domain based primary theme $id = $this->Application->siteDomainField('PrimaryThemeId'); if (!$id) { $id = 1; $id_field_name = 'PrimaryTheme'; } $default = true; } $res = parent::Load($id, $id_field_name, $cachable); if ($res) { $available_themes = $this->Application->siteDomainField('Themes'); if ($available_themes) { if (strpos($available_themes, '|' . $this->GetID() . '|') === false) { // theme isn't allowed in site domain return $this->Clear(); } } } if ($default) { if (!$res) { if ($this->Application->isAdmin) { $res = parent::Load(1, $id_field_name, false); } } $this->Application->SetVar('theme.current_id', $this->GetID() ); $this->Application->SetVar('m_theme', $this->GetID() ); } return $res; } /** * Returns full path to stylesheet file. * * @param boolean $as_url Allows to return url to stylesheet file instead of it's path. * * @return string|boolean */ public function getStylesheetFile($as_url = false) { $stylesheet_file = ltrim($this->GetDBField('StylesheetFile') ?: 'inc/style.css', '/'); $theme_path = FULL_PATH . '/themes/' . $this->GetDBField('Name'); $stylesheet_file = $theme_path . '/' . $stylesheet_file; if ( !file_exists($stylesheet_file) ) { return false; } if ( $as_url ) { /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); return $file_helper->pathToUrl($stylesheet_file); } return $stylesheet_file; } } Index: branches/5.3.x/core/units/mailing_lists/mailing_lists_config.php =================================================================== --- branches/5.3.x/core/units/mailing_lists/mailing_lists_config.php (revision 16599) +++ branches/5.3.x/core/units/mailing_lists/mailing_lists_config.php (revision 16600) @@ -1,156 +1,156 @@ 'mailing-list', 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'MailingListEventHandler', 'file' => 'mailing_list_eh.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'MailingListTagProcessor', 'file' => 'mailing_list_tp.php', 'build_event' => 'OnBuild'), 'AutoLoad' => true, 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'PerPage', 4 => 'event', 5 => 'mode', ), 'ScheduledTasks' => Array ( 'generate_mailing_queue' => Array ('EventName' => 'OnGenerateEmailQueue', 'RunSchedule' => '*/30 * * * *'), ), 'IDField' => 'MailingId', 'TableName' => TABLE_PREFIX . 'MailingLists', 'TitlePresets' => Array ( 'default' => Array ( 'new_status_labels' => Array ('mailing-list' => '!la_title_AddingMailingList!'), 'edit_status_labels' => Array ('mailing-list' => '!la_title_ViewingMailingList!'), ), 'mailing_list_list' => Array ( 'prefixes' => Array ('mailing-list_List'), 'format' => "!la_title_MailingLists!", 'toolbar_buttons' => Array ('new_item', 'edit', 'delete', 'cancel', 'view', 'dbl-click'), ), 'mailing_list_edit' => Array ( 'prefixes' => Array ('mailing-list'), 'format' => "#mailing-list_status#", 'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'), ), ), 'PermSection' => Array ('main' => 'in-portal:mailing_lists'), 'Sections' => Array ( 'in-portal:mailing_folder' => Array ( 'parent' => 'in-portal:users', 'icon' => 'mailing_list', 'label' => 'la_title_MailingLists', 'use_parent_header' => 1, 'permissions' => Array (), 'priority' => 5, 'type' => stTREE, ), 'in-portal:mailing_lists' => Array ( 'parent' => 'in-portal:mailing_folder', 'icon' => 'mailing_list', 'label' => 'la_title_MailingLists', 'url' => Array ('t' => 'mailing_lists/mailing_list_list', 'pass' => 'm'), 'permissions' => Array ('view', 'add', 'edit', 'delete'), 'priority' => 5.1, // ., because this section replaces parent in tree 'type' => stTAB, ), ), 'ListSQLs' => Array ( '' => ' SELECT %1$s.* %2$s FROM %1$s', ), 'CalculatedFields' => Array ( '' => Array ( 'EmailsQueued' => 'CAST(%1$s.EmailsQueuedTotal AS SIGNED) - CAST(%1$s.EmailsSent AS SIGNED)', ), ), 'ListSortings' => Array ( '' => Array ( 'Sorting' => Array ('MailingId' => 'desc'), ) ), 'Fields' => Array ( 'MailingId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'PortalUserId' => Array ( 'type' => 'int', 'formatter' => 'kLEFTFormatter', 'options' => Array (USER_ROOT => 'root'), 'left_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Users WHERE %s', 'left_key_field' => 'PortalUserId', 'left_title_field' => USER_TITLE_FIELD, 'required' => 1, 'not_null' => 1, 'default' => USER_ROOT, ), 'To' => Array ('type' => 'string', 'required' => 1, 'default' => NULL), 'ToParsed' => Array ('type' => 'string', 'default' => NULL), 'Attachments' => Array ( 'type' => 'string', 'formatter' => 'kUploadFormatter', 'upload_dir' => ITEM_FILES_PATH, 'max_size' => 50000000, 'multiple' => 10, 'direct_links' => true, 'file_types' => '*.*', 'files_description' => '!la_hint_AllFiles!', 'default' => NULL ), 'Subject' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'required' => 1, 'default' => ''), - 'MessageText' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => NULL), + 'MessageText' => Array ('type' => 'string', 'default' => NULL), 'MessageHtml' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => NULL), 'Status' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_NotProcessed', 2 => 'la_opt_PartiallyProcessed', 3 => 'la_opt_Processed', 4 => 'la_opt_Cancelled'), 'use_phrases' => 1, 'not_null' => 1, 'required' => 1, 'default' => 1 ), 'EmailsQueuedTotal' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'EmailsSent' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'EmailsTotal' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), ), 'VirtualFields' => Array ( 'EmailsQueued' => Array ('type' => 'int', 'default' => 0), ), 'Grids' => Array ( 'Default' => Array ( 'Icons' => Array ('default' => 'icon16_item.png'), 'Fields' => Array ( 'MailingId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 70), 'Subject' => Array ('filter_block' => 'grid_like_filter', 'width' => 200), 'MessageText' => Array ('filter_block' => 'grid_like_filter', 'cut_first' => 100, 'width' => 120, 'hidden' => 1), 'MessageHtml' => Array ('title' => 'la_col_MessageHtml', 'filter_block' => 'grid_like_filter', 'cut_first' => 100, 'width' => 120, 'hidden' => 1), 'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 100), 'EmailsQueued' => Array ('filter_block' => 'grid_range_filter', 'width' => 80), 'EmailsSent' => Array ('filter_block' => 'grid_range_filter', 'width' => 80), 'EmailsTotal' => Array ('filter_block' => 'grid_range_filter', 'width' => 80), ), ), ), ); \ No newline at end of file Index: branches/5.3.x/core/units/mailing_lists/mailing_list_eh.php =================================================================== --- branches/5.3.x/core/units/mailing_lists/mailing_list_eh.php (revision 16599) +++ branches/5.3.x/core/units/mailing_lists/mailing_list_eh.php (revision 16600) @@ -1,387 +1,387 @@ Array ('self' => 'edit'), 'OnGenerateEmailQueue' => Array ('self' => true), 'OnProcessEmailQueue' => Array ('self' => true), 'OnGetHtmlBody' => Array ('self' => 'edit'), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Prepare recipient list * * @param kEvent $event * @return void * @access protected */ protected function OnNew(kEvent $event) { parent::OnNew($event); $recipient_type = $this->Application->GetVar('mailing_recipient_type'); if ( !$recipient_type ) { return; } $recipients = $this->Application->GetVar($recipient_type); if ( $recipients ) { /** @var kDBItem $object */ $object = $event->getObject(); $to = $recipient_type . '_' . implode(';' . $recipient_type . '_', array_keys($recipients)); $object->SetDBField('To', $to); } $this->setRequired($event); } /** * Prepare recipient list * * @param kEvent $event * @return void * @access protected */ protected function OnPreCreate(kEvent $event) { parent::OnPreCreate($event); $this->setRequired($event); } /** * Don't allow to delete mailings in progress * * @param kEvent $event * @param string $type * @return void * @access protected */ protected function customProcessing(kEvent $event, $type) { if ( $event->Name == 'OnMassDelete' && $type == 'before' ) { $ids = $event->getEventParam('ids'); if ( $ids ) { $config = $event->getUnitConfig(); $id_field = $config->getIDField(); $sql = 'SELECT ' . $id_field . ' FROM ' . $config->getTableName() . ' WHERE ' . $id_field . ' IN (' . implode(',', $ids) . ') AND Status <> ' . MailingList::PARTIALLY_PROCESSED; $allowed_ids = $this->Conn->GetCol($sql); $event->setEventParam('ids', $allowed_ids); } } } /** * Delete all related mails in email queue * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemDelete(kEvent $event) { parent::OnAfterItemDelete($event); $this->_deleteQueue($event); /** @var kDBItem $object */ $object = $event->getObject(); // delete mailing attachments after mailing is deleted $attachments = $object->GetField('Attachments', 'file_paths'); if ( $attachments ) { $attachments = explode('|', $attachments); foreach ($attachments as $attachment_file) { if ( file_exists($attachment_file) ) { unlink($attachment_file); } } } } /** * Cancels given mailing and deletes all it's email queue * * @param kEvent $event */ function OnCancelMailing($event) { /** @var kDBItem $object */ $object = $event->getObject( Array('skip_autoload' => true) ); $ids = $this->StoreSelectedIDs($event); if ($ids) { foreach ($ids as $id) { $object->Load($id); $object->SetDBField('Status', MailingList::CANCELLED); $object->Update(); } } $this->clearSelectedIDs($event); } /** * Checks, that at least one message text field is filled * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemCreate(kEvent $event) { parent::OnBeforeItemCreate($event); /** @var kDBItem $object */ $object = $event->getObject(); if ( !$this->Application->GetVar('mailing_recipient_type') ) { // user manually typed email addresses -> normalize $recipients = str_replace(',', ';', $object->GetDBField('To')); $recipients = array_map('trim', explode(';', $recipients)); $object->SetDBField('To', implode(';', $recipients)); } // remember user, who created mailing, because of his name // is needed for "From" field, but mailing occurs from cron $user_id = $this->Application->RecallVar('user_id'); $object->SetDBField('PortalUserId', $user_id); $this->setRequired($event); } /** * Checks, that at least one message text field is filled * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemUpdate(kEvent $event) { parent::OnBeforeItemUpdate($event); $this->setRequired($event); } /** * Dynamically changes required fields * * @param kEvent $event * @return void * @access protected */ protected function setRequired(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $object->setRequired('MessageHtml', !$object->GetDBField('MessageText')); $object->setRequired('MessageText', !$object->GetDBField('MessageHtml')); } /** * Deletes mailing list email queue, when it becomes cancelled * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemUpdate(kEvent $event) { parent::OnAfterItemUpdate($event); /** @var kDBItem $object */ $object = $event->getObject(); $status = $object->GetDBField('Status'); if ( ($status != $object->GetOriginalField('Status')) && ($status == MailingList::CANCELLED) ) { $this->_deleteQueue($event); } } /** * Deletes email queue records related with given mailing list * * @param kEvent $event */ function _deleteQueue($event) { /** @var kDBItem $object */ $object = $event->getObject(); $sql = 'DELETE FROM ' . $this->Application->getUnitConfig('email-queue')->getTableName() . ' WHERE MailingId = ' . $object->GetID(); $this->Conn->Query($sql); } /** * Allows to safely get mailing configuration variables * * @param string $variable_name Variable name. * * @return integer - * @deprecated 5.3.0-B1 + * @deprecated 5.2.2-B2 * @see MailingListHelper::getSetting() */ function _ensureDefault($variable_name) { - kUtil::deprecatedMethod(__METHOD__, '5.3.0-B1', 'MailingListHelper::getSetting'); + kUtil::deprecatedMethod(__METHOD__, '5.2.2-B2', 'MailingListHelper::getSetting'); /** @var MailingListHelper $mailing_list_helper */ $mailing_list_helper = $this->Application->recallObject('MailingListHelper'); return $mailing_list_helper->getSetting($variable_name); } /** * Generates email queue for active mailing lists * * @param kEvent $event */ function OnGenerateEmailQueue($event) { $config = $event->getUnitConfig(); $id_field = $config->getIDField(); $table_name = $config->getTableName(); $where_clause = Array ( 'Status NOT IN (' . MailingList::CANCELLED . ',' . MailingList::PROCESSED . ')', '(EmailsQueuedTotal < EmailsTotal) OR (EmailsTotal = 0)', '`To` <> ""', ); $sql = 'SELECT * FROM ' . $table_name . ' WHERE (' . implode(') AND (', $where_clause) . ') ORDER BY ' . $id_field . ' ASC'; $mailing_lists = $this->Conn->Query($sql, $id_field); if ( !$mailing_lists ) { return; } /** @var MailingListHelper $mailing_list_helper */ $mailing_list_helper = $this->Application->recallObject('MailingListHelper'); $to_queue = $mailing_list_helper->getSetting('MailingListQueuePerStep'); if ( !is_numeric($to_queue) ) { return; } foreach ($mailing_lists as $mailing_id => $mailing_data) { if ( $mailing_data['EmailsTotal'] == 0 ) { // no work performed on this mailing list -> calculate totals $updated_fields = $mailing_list_helper->generateRecipients($mailing_id, $mailing_data); $updated_fields['Status'] = MailingList::PARTIALLY_PROCESSED; $mailing_data = array_merge($mailing_data, $updated_fields); $this->Conn->doUpdate($updated_fields, $table_name, $id_field . ' = ' . $mailing_id); } $emails = unserialize($mailing_data['ToParsed']); if ( !$emails ) { continue; } // queue allowed count of emails $i = 0; $process_count = count($emails) >= $to_queue ? $to_queue : count($emails); while ($i < $process_count) { $mailing_list_helper->queueEmail($emails[$i], $mailing_id, $mailing_data); $i++; } // remove processed emails from array $to_queue -= $process_count; // decrement available for processing email count array_splice($emails, 0, $process_count); $updated_fields = Array ( 'ToParsed' => serialize($emails), 'EmailsQueuedTotal' => $mailing_data['EmailsQueuedTotal'] + $process_count, ); $this->Conn->doUpdate($updated_fields, $table_name, $id_field . ' = ' . $mailing_id); if ( !$to_queue ) { // emails to be queued per step reached -> leave break; } } } /** * [SCHEDULED TASK] Process email queue from cron * * @param kEvent $event Event. * * @return void - * @deprecated 5.3.0-B1 + * @deprecated 5.2.2-B2 * @see EmailQueueEventHandler::OnProcess() */ function OnProcessEmailQueue($event) { - kUtil::deprecatedMethod(__METHOD__, '5.3.0-B1', 'EmailQueueEventHandler::OnProcess'); + kUtil::deprecatedMethod(__METHOD__, '5.2.2-B2', 'EmailQueueEventHandler::OnProcess'); $event->CallSubEvent('email-queue:OnProcess'); } /** * Returns HTML of sent e-mail for iframe * * @param kEvent $event * @return void * @access protected */ protected function OnGetHtmlBody(kEvent $event) { $event->status = kEvent::erSTOP; /** @var kDBItem $object */ $object = $event->getObject(); echo '' . $object->GetDBField('MessageHtml') . ''; } } Index: branches/5.3.x/core/units/users/users_config.php =================================================================== --- branches/5.3.x/core/units/users/users_config.php (revision 16599) +++ branches/5.3.x/core/units/users/users_config.php (revision 16600) @@ -1,664 +1,664 @@ 'u', 'ItemClass' => Array ('class' => 'UsersItem', 'file' => 'users_item.php', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'UsersEventHandler', 'file' => 'users_event_handler.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'UsersTagProcessor', 'file' => 'users_tag_processor.php', 'build_event' => 'OnBuild'), 'RegisterClasses' => Array ( Array('pseudo' => 'UsersSyncronizeManager', 'class' => 'UsersSyncronizeManager', 'file' => 'users_syncronize.php', 'build_event' => ''), Array('pseudo' => 'UsersSyncronize', 'class' => 'UsersSyncronize', 'file' => 'users_syncronize.php', 'build_event' => ''), ), 'AutoLoad' => true, 'ConfigPriority' => 0, 'Hooks' => Array ( Array ( 'Mode' => hBEFORE, 'Conditional' => false, 'HookToPrefix' => '', 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnAfterConfigRead'), 'DoPrefix' => 'cdata', 'DoSpecial' => '*', 'DoEvent' => 'OnDefineCustomFields', ), Array ( 'Mode' => hAFTER, 'Conditional' => false, 'HookToPrefix' => 'adm', 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnStartup'), 'DoPrefix' => '', 'DoSpecial' => '*', 'DoEvent' => 'OnAutoLoginUser', ), Array ( 'Mode' => hBEFORE, 'Conditional' => false, 'HookToPrefix' => 'img', 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnAfterConfigRead'), 'DoPrefix' => '', 'DoSpecial' => '*', 'DoEvent' => 'OnCloneSubItem', ), // Captcha processing Array ( 'Mode' => hBEFORE, 'Conditional' => false, 'HookToPrefix' => '', 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnAfterConfigRead'), 'DoPrefix' => 'captcha', 'DoSpecial' => '*', 'DoEvent' => 'OnPrepareCaptcha', ), /*Array ( 'Mode' => hAFTER, 'Conditional' => false, 'HookToPrefix' => '', 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnBeforeItemCreate'), 'DoPrefix' => 'captcha', 'DoSpecial' => '*', 'DoEvent' => 'OnValidateCode', ),*/ ), 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'PerPage', 4 => 'event', 5 => 'mode', ), 'ScheduledTasks' => Array ( 'membership_expiration' => Array ('EventName' => 'OnCheckExpiredMembership', 'RunSchedule' => '*/30 * * * *'), 'delete_expired_sessions' => Array ('EventName' => 'OnDeleteExpiredSessions', 'RunSchedule' => '0 */12 * * *'), ), 'IDField' => 'PortalUserId', 'StatusField' => Array ('Status'), 'TitleField' => 'Username', 'ItemType' => 6, // used for custom fields only (on user's case) 'StatisticsInfo' => Array ( 'pending' => Array ( 'icon' => 'icon16_user_pending.gif', 'label' => 'la_Text_Users', 'js_url' => '#url#', 'url' => Array ('t' => 'users/users_list', 'pass' => 'm,u', 'u_event' => 'OnSetFilterPattern', 'u_filters' => 'show_active=0,show_pending=1,show_disabled=0'), 'status' => STATUS_PENDING, ), ), 'TitlePresets' => Array ( 'default' => Array ( 'new_status_labels' => Array ('u' => '!la_title_Adding_User!'), 'edit_status_labels' => Array ('u' => '!la_title_Editing_User!'), ), 'users_list' => Array ( 'prefixes' => Array ('u_List'), 'format' => "!la_title_Users!", 'toolbar_buttons' => Array ('new_item', 'edit', 'delete', 'setprimary', 'approve', 'decline', 'frontend_mail', 'e-mail', 'export', 'view', 'dbl-click'), ), 'users_edit' => Array ( 'prefixes' => Array ('u'), 'format' => "#u_status# #u_titlefield# - !la_title_General!", 'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'), ), 'user_edit_images' => Array ( 'prefixes' => Array ('u', 'u-img_List'), 'format' => "#u_status# '#u_titlefield#' - !la_title_Images!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next', 'new_item', 'edit', 'delete', 'approve', 'decline', 'setprimary', 'move_up', 'move_down', 'view', 'dbl-click'), ), 'user_edit_groups' => Array ( 'prefixes' => Array ('u', 'u-ug_List'), 'format' => "#u_status# '#u_titlefield#' - !la_title_Groups!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next', 'select_user', 'edit', 'delete', 'setprimary', 'view', 'dbl-click'), ), 'user_edit_items' => Array ( 'prefixes' => Array ('u'), 'format' => "#u_status# '#u_titlefield#' - !la_title_Items!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next', 'edit', 'delete', 'view', 'dbl-click'), ), 'user_edit_custom' => Array ( 'prefixes' => Array ('u'), 'format' => "#u_status# '#u_titlefield#' - !la_title_Custom!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'admin_list' => Array ( 'prefixes' => Array ('u.admins_List'), 'format' => "!la_title_Administrators!", 'toolbar_buttons' => Array ('new_item', 'edit', 'delete', 'approve', 'decline', 'clone', 'refresh', 'view', 'dbl-click'), ), 'admins_edit' => Array ( 'new_status_labels' => Array ('u' => '!la_title_AddingAdministrator!'), 'edit_status_labels' => Array ('u' => '!la_title_EditingAdministrator!'), 'prefixes' => Array ('u'), 'format' => "#u_status# #u_titlefield#", 'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'), ), 'regular_users_list' => Array ( 'prefixes' => Array ('u.regular_List'), 'format' => "!la_title_Users!", 'toolbar_buttons' => Array (), ), 'root_edit' => Array ( 'prefixes' => Array ('u'), 'format' => "!la_title_Editing_User! 'root'", 'toolbar_buttons' => Array ('select', 'cancel'), ), 'user_edit_group' => Array ( 'prefixes' => Array ('u', 'u-ug'), 'edit_status_labels' => Array ('u-ug' => '!la_title_EditingMembership!'), 'format' => "#u_status# '#u_titlefield#' - #u-ug_status# '#u-ug_titlefield#'", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'user_image_edit' => Array ( 'prefixes' => Array ('u', 'u-img'), 'new_status_labels' => Array ('u-img' => '!la_title_Adding_Image!'), 'edit_status_labels' => Array ('u-img' => '!la_title_Editing_Image!'), 'new_titlefield' => Array ('u-img' => '!la_title_New_Image!'), 'format' => "#u_status# '#u_titlefield#' - #u-img_status# '#u-img_titlefield#'", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'user_select' => Array ( 'prefixes' => Array ('u_List'), 'format' => "!la_title_Users! - !la_title_SelectUser!", 'toolbar_buttons' => Array ('select', 'cancel', 'dbl-click'), ), 'group_user_select' => Array ( 'prefixes' => Array ('u.group_List'), 'format' => "!la_title_Users! - !la_title_SelectUser!", 'toolbar_buttons' => Array ('select', 'cancel', 'view', 'dbl-click'), ), 'tree_users' => Array ('format' => '!la_section_overview!'), ), 'EditTabPresets' => Array ( 'Default' => Array ( 'general' => Array ('title' => 'la_tab_General', 't' => 'users/users_edit', 'priority' => 1), 'groups' => Array ('title' => 'la_tab_Groups', 't' => 'users/users_edit_groups', 'priority' => 2), 'images' => Array ('title' => 'la_tab_Images', 't' => 'users/user_edit_images', 'priority' => 3), 'items' => Array ('title' => 'la_tab_Items', 't' => 'users/user_edit_items', 'priority' => 4), 'custom' => Array ('title' => 'la_tab_Custom', 't' => 'users/users_edit_custom', 'priority' => 5), ), 'Admins' => Array ( 'general' => Array ('title' => 'la_tab_General', 't' => 'users/admins_edit', 'priority' => 1), 'groups' => Array ('title' => 'la_tab_Groups', 't' => 'users/admins_edit_groups', 'priority' => 2), ), ), 'PermSection' => Array ('main' => 'in-portal:user_list', 'custom' => 'in-portal:user_custom'), 'Sections' => Array ( 'in-portal:user_list' => Array ( 'parent' => 'in-portal:users', 'icon' => 'users', 'label' => 'la_title_Users', // 'la_tab_User_List', 'url' => Array ('t' => 'users/users_list', 'pass' => 'm'), 'permissions' => Array ('view', 'add', 'edit', 'delete', 'advanced:ban', 'advanced:send_email', /*'advanced:add_favorite', 'advanced:remove_favorite',*/), 'priority' => 1, 'type' => stTREE, ), 'in-portal:admins' => Array ( 'parent' => 'in-portal:users', 'icon' => 'administrators', 'label' => 'la_title_Administrators', 'url' => Array ('t' => 'users/admins_list', 'pass' => 'm'), 'permissions' => Array ('view', 'add', 'edit', 'delete'), 'perm_prefix' => 'u', 'priority' => 2, 'type' => stTREE, ), // user settings 'in-portal:user_setting_folder' => Array ( 'parent' => 'in-portal:system', 'icon' => 'conf_users', 'label' => 'la_title_Users', 'use_parent_header' => 1, 'url' => Array ('t' => 'index', 'pass_section' => true, 'pass' => 'm'), 'permissions' => Array ('view'), 'priority' => 2, 'container' => true, 'type' => stTREE, ), 'in-portal:configure_users' => Array ( 'parent' => 'in-portal:user_setting_folder', 'icon' => 'conf_users_general', 'label' => 'la_tab_ConfigSettings', 'url' => Array ('t' => 'config/config_universal', 'module' => 'In-Portal:Users', 'pass_section' => true, 'pass' => 'm'), 'permissions' => Array ('view', 'add', 'edit'), 'priority' => 1, 'type' => stTREE, ), 'in-portal:user_custom' => Array ( 'parent' => 'in-portal:user_setting_folder', 'icon' => 'conf_customfields', 'label' => 'la_tab_ConfigCustom', 'url' => Array ('t' => 'custom_fields/custom_fields_list', 'cf_type' => 6, 'pass_section' => true, 'pass' => 'm,cf'), 'permissions' => Array ('view', 'add', 'edit', 'delete'), 'priority' => 2, 'type' => stTREE, ), ), 'TableName' => TABLE_PREFIX.'Users', 'CustomDataTableName' => TABLE_PREFIX . 'UserCustomData', 'ListSQLs' => Array ( '' => ' SELECT %1$s.* %2$s FROM %1$s LEFT JOIN '.TABLE_PREFIX.'UserGroups g ON %1$s.PrimaryGroupId = g.GroupId LEFT JOIN '.TABLE_PREFIX.'%3$sUserCustomData cust ON %1$s.ResourceId = cust.ResourceId LEFT JOIN '.TABLE_PREFIX.'%3$sCatalogImages img ON img.ResourceId = %1$s.ResourceId AND img.DefaultImg = 1', 'online' => ' SELECT %1$s.* %2$s FROM %1$s LEFT JOIN '.TABLE_PREFIX.'UserSessions s ON s.PortalUserId = %1$s.PortalUserId LEFT JOIN '.TABLE_PREFIX.'UserGroups g ON %1$s.PrimaryGroupId = g.GroupId LEFT JOIN '.TABLE_PREFIX.'%3$sUserCustomData cust ON %1$s.ResourceId = cust.ResourceId LEFT JOIN '.TABLE_PREFIX.'%3$sCatalogImages img ON img.ResourceId = %1$s.ResourceId AND img.DefaultImg = 1', ), 'ListSortings' => Array ( '' => Array ( 'Sorting' => Array ('Username' => 'asc'), ) ), 'SubItems' => Array ('addr', 'u-cdata', 'u-ug', 'u-img', 'fav', 'user-profile'), /** * Required for depricated public profile templates to work */ 'UserProfileMapping' => Array ( 'pp_firstname' => 'FirstName', 'pp_lastname' => 'LastName', 'pp_dob' => 'dob', 'pp_email' => 'Email', 'pp_phone' => 'Phone', 'pp_street' => 'Street', 'pp_city' => 'City', 'pp_state' => 'State', 'pp_zip' => 'Zip', 'pp_country' => 'Country', ), 'CalculatedFields' => Array ( '' => Array ( 'PrimaryGroup' => 'g.Name', 'FullName' => 'CONCAT(%1$s.FirstName, " ", %1$s.LastName)', 'AltName' => 'img.AltName', 'SameImages' => 'img.SameImages', 'LocalThumb' => 'img.LocalThumb', 'ThumbPath' => 'img.ThumbPath', 'ThumbUrl' => 'img.ThumbUrl', 'LocalImage' => 'img.LocalImage', 'LocalPath' => 'img.LocalPath', 'FullUrl' => 'img.Url', ), ), 'Forms' => Array ( 'default' => Array ( 'Fields' => Array ( 'PortalUserId' => Array ('default' => 0), 'Username' => Array ( 'max_len' => 255, 'formatter' => 'kFormatter', 'regexp' => '/^[A-Z\d_\-\.]+$/i', 'error_msgs' => Array ( - 'unique' => '!lu_user_already_exist!', 'invalid_format' => '!la_error_InvalidLogin!', 'banned' => '!la_error_UserBanned!' + 'unique' => '!lu_user_already_exist!', 'invalid_format' => '!la_error_InvalidUsername!', 'banned' => '!la_error_UserBanned!' ), 'unique' => Array (), 'default' => '', ), 'Password' => Array ( 'formatter' => 'kPasswordFormatter', 'hashing_method_field' => 'PasswordHashingMethod', 'verify_field' => 'VerifyPassword', 'default' => '' ), 'PasswordHashingMethod' => Array ( 'formatter' => 'kOptionsFormatter', 'options' => Array ( PasswordHashingMethod::MD5 => 'md5', PasswordHashingMethod::MD5_AND_PHPPASS => 'md5+phppass', PasswordHashingMethod::PHPPASS => 'phppass' ), 'default' => PasswordHashingMethod::PHPPASS ), 'FirstName' => Array ('default' => ''), 'LastName' => Array ('default' => ''), 'Company' => Array ('default' => ''), 'Email' => Array ( 'formatter' => 'kFormatter', 'regexp' => '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', 'sample_value' => 'email@domain.com', 'error_msgs' => Array ( 'invalid_format' => '!la_invalid_email!', 'unique' => '!lu_email_already_exist!' ), 'unique' => Array (), 'required' => 1, 'default' => '' ), 'CreatedOn' => Array ('formatter' => 'kDateFormatter', 'default' => '#NOW#'), 'Phone' => Array ('default' => ''), 'Fax' => Array ('default' => ''), 'Street' => Array ('default' => ''), 'Street2' => Array ('error_field' => 'Street', 'default' => ''), 'City' => Array ('default' => ''), 'State' => Array ( 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'default' => '', ), 'Zip' => Array ('default' => ''), 'Country' => Array ( 'formatter' => 'kOptionsFormatter', 'options_sql' => ' SELECT IF(l%2$s_Name = "", l%3$s_Name, l%2$s_Name) AS Name, IsoCode FROM ' . TABLE_PREFIX . 'CountryStates WHERE Type = ' . DESTINATION_TYPE_COUNTRY . ' ORDER BY Name', 'option_key_field' => 'IsoCode', 'option_title_field' => 'Name', 'default' => '', ), 'ResourceId' => Array ('default' => 0), 'Status' => Array ( 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Enabled', 0 => 'la_Disabled', 2 => 'la_Pending'), 'use_phrases' => 1, 'default' => 1 ), 'Modified' => Array ('formatter' => 'kDateFormatter', 'default' => NULL), 'dob' => Array ('formatter' => 'kDateFormatter', 'default' => NULL), 'TimeZone' => Array ('default' => ''), 'IPAddress' => Array ('default' => ''), 'IsBanned' => Array ('default' => 0), 'PwResetConfirm' => Array ('default' => ''), 'PwRequestTime' => Array ('formatter' => 'kDateFormatter', 'default' => NULL), 'FrontLanguage' => Array ( 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Languages ORDER BY PackName', 'option_key_field' => 'LanguageId', 'option_title_field' => 'LocalName', 'default' => NULL ), 'AdminLanguage' => Array ( 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Languages ORDER BY PackName', 'option_key_field' => 'LanguageId', 'option_title_field' => 'LocalName', 'default' => NULL ), 'DisplayToPublic' => Array ( 'formatter' => 'kOptionsFormatter', 'options' => Array ( 'FirstName' => 'lu_fld_FirstName', 'LastName' => 'lu_fld_LastName', 'dob' => 'lu_fld_BirthDate', 'Email' => 'lu_fld_Email', 'Phone' => 'lu_fld_Phone', 'Street' => 'lu_fld_AddressLine1', 'Street2' => 'lu_fld_AddressLine2', 'City' => 'lu_fld_City', 'State' => 'lu_fld_State', 'Zip' => 'lu_fld_Zip', 'Country' => 'lu_fld_Country', ), 'use_phrases' => 1, 'multiple' => 1, 'default' => NULL ), 'UserType' => Array ( 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_opt_UserTypeUser', 1 => 'la_opt_UserTypeAdmin'), 'use_phrases' => 1, 'default' => 0 ), 'PrimaryGroupId' => Array ( 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %1$s FROM ' . TABLE_PREFIX . 'UserGroups WHERE Enabled = 1 AND FrontRegistration = 1', 'option_key_field' => 'GroupId', 'option_title_field' => 'Name', 'default' => NULL ), 'OldStyleLogin' => Array ( 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'default' => 0 ), 'IPRestrictions' => Array ('default' => NULL), 'EmailVerified' => Array ( 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'default' => 0 ), 'PrevEmails' => Array ('default' => NULL), ), 'VirtualFields' => Array ( 'PrimaryGroup' => Array ('default' => ''), 'RootPassword' => Array ( 'formatter' => 'kPasswordFormatter', 'hashing_method' => PasswordHashingMethod::PHPPASS, 'salt' => 'b38', 'verify_field' => 'VerifyRootPassword', 'default' => 'b38:d41d8cd98f00b204e9800998ecf8427e' ), 'EmailPassword' => Array ('default' => ''), 'FullName' => Array ('default' => ''), 'AltName' => Array ('default' => ''), 'SameImages' => Array ('default' => ''), 'LocalThumb' => Array ('default' => ''), 'ThumbPath' => Array ('default' => ''), 'ThumbUrl' => Array ('default' => ''), 'LocalImage' => Array ('default' => ''), 'LocalPath' => Array ('default' => ''), 'FullUrl' => Array ('default' => ''), 'SubscribeToMailing' => Array ( 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'lu_Yes', 0 => 'lu_No'), 'use_phrases' => 1, 'default' => 0, ), ), ), 'registration' => Array ( // Front-End user registration form /*'Fields' => Array ( 'FirstName' => Array ('required' => 1), ),*/ ), 'recommend' => Array ( 'VirtualFields' => Array ( 'RecommendEmail' => Array ( 'type' => 'string', 'formatter' => 'kFormatter', 'regexp' => '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', 'error_msgs' => Array ('required' => '!lu_InvalidEmail!', 'invalid_format' => '!lu_InvalidEmail!', 'send_error' => '!lu_email_send_error!'), 'sample_value' => 'email@domain.com', 'required' => 1, 'default' => '' ), ), ), 'subscription' => Array ( 'VirtualFields' => Array ( 'SubscriberEmail' => Array ( 'type' => 'string', 'formatter' => 'kFormatter', 'regexp' => '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', 'error_msgs' => Array ('required' => '!lu_InvalidEmail!', 'invalid_format' => '!lu_InvalidEmail!'), 'sample_value' => 'email@domain.com', 'required' => 1, 'default' => '' ), ), ), 'forgot_password' => Array ( 'VirtualFields' => Array ( 'ForgotLogin' => Array ( 'type' => 'string', 'error_msgs' => Array ( 'required' => '!lu_ferror_forgotpw_nodata!', 'unknown_username' => '!lu_ferror_unknown_username!', 'unknown_email' => '!lu_ferror_unknown_email!', 'reset_denied' => '!lu_ferror_reset_denied!', ), 'required' => 1, 'default' => '' ), ), ), 'login' => Array ( 'Fields' => Array ( // make sure all fields, required by default are not required on this form 'Email' => Array ('required' => 0), ), 'VirtualFields' => Array ( 'UserLogin' => Array ( 'type' => 'string', 'error_msgs' => Array ( 'no_permission' => '!la_no_permissions!', 'invalid_password' => '!la_invalid_password!' ), 'default' => '' ), 'UserPassword' => Array ('type' => 'string', 'default' => ''), 'UserRememberLogin' => Array ('type' => 'int', 'default' => 0), ), ), ), 'Fields' => Array ( 'PortalUserId' => Array ('type' => 'int', 'not_null' => 1), 'Username' => Array ('type' => 'string', 'not_null' => 1), 'Password' => Array ('type' => 'string', 'skip_empty' => 1), 'PasswordHashingMethod' => Array ('type' => 'int'), 'FirstName' => Array ('type' => 'string', 'not_null' => 1), 'LastName' => Array ('type' => 'string', 'not_null' => 1), 'Company' => Array ('type' => 'string', 'not_null' => 1), 'Email' => Array ('type' => 'string', 'not_null' => 1), 'CreatedOn' => Array ('type' => 'int'), 'Phone' => Array ('type' => 'string', 'not_null' => 1), 'Fax' => Array ('type' => 'string', 'not_null' => 1), 'Street' => Array ('type' => 'string', 'not_null' => 1), 'Street2' => Array ('type' => 'string', 'not_null' => 1), 'City' => Array ('type' => 'string', 'not_null' => 1), 'State' => Array ('type' => 'string', 'not_null' => 1), 'Zip' => Array ('type' => 'string', 'not_null' => 1), 'Country' => Array ('type' => 'string', 'not_null' => 1), 'ResourceId' => Array ('type' => 'int', 'not_null' => 1), 'Status' => Array ('type' => 'int', 'not_null' => 1), 'Modified' => Array ('type' => 'int'), 'dob' => Array ('type' => 'int'), 'TimeZone' => Array ('type' => 'string', 'not_null' => 1), 'IPAddress' => Array ('type' => 'string', 'not_null' => 1), 'IsBanned' => Array ('type' => 'int', 'not_null' => 1), 'PwResetConfirm' => Array ('type' => 'string', 'not_null' => 1), 'PwRequestTime' => Array ('type' => 'int'), 'FrontLanguage' => Array ('type' => 'int'), 'AdminLanguage' => Array ('type' => 'int'), 'DisplayToPublic' => Array ('type' => 'string'), 'UserType' => Array ('type' => 'int', 'not_null' => 1), 'PrimaryGroupId' => Array ('type' => 'int'), 'OldStyleLogin' => Array ('type' => 'int', 'not_null' => 1), 'IPRestrictions' => Array ('type' => 'string'), 'EmailVerified' => Array ('type' => 'int', 'not_null' => 1), 'PrevEmails' => Array ('type' => 'string'), ), 'VirtualFields' => Array ( 'PrimaryGroup' => Array ('type' => 'string'), 'RootPassword' => Array ('type' => 'string', 'skip_empty' => 1), 'EmailPassword' => Array ('type' => 'string'), 'FullName' => Array ('type' => 'string'), 'AltName' => Array ('type' => 'string'), 'SameImages' => Array ('type' => 'string'), 'LocalThumb' => Array ('type' => 'string'), 'ThumbPath' => Array ('type' => 'string'), 'ThumbUrl' => Array ('type' => 'string'), 'LocalImage' => Array ('type' => 'string'), 'LocalPath' => Array ('type' => 'string'), 'FullUrl' => Array ('type' => 'string'), 'SubscribeToMailing' => Array ('type' => 'int'), ), 'Grids' => Array ( // not in use 'Default' => Array ( 'Icons' => Array ( 0 => 'icon16_user_disabled.png', 1 => 'icon16_user.png', 2 => 'icon16_user_pending.png' ), 'Fields' => Array ( 'Username' => Array ('data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_like_filter'), 'LastName' => Array ('filter_block' => 'grid_like_filter'), 'FirstName' => Array ('filter_block' => 'grid_like_filter'), 'Email' => Array ('filter_block' => 'grid_like_filter'), 'PrimaryGroup' => Array ('title' => 'la_col_PrimaryGroup', 'filter_block' => 'grid_like_filter'), 'CreatedOn' => Array ('filter_block' => 'grid_date_range_filter'), 'Modified' => Array ('filter_block' => 'grid_date_range_filter'), 'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, ), 'IPAddress' => Array ('filter_block' => 'grid_like_filter', 'width' => 100, 'hidden' => 1), ), ), // used 'UserSelector' => Array ( 'Icons' => Array ( 0 => 'icon16_user_disabled.png', 1 => 'icon16_user.png', 2 => 'icon16_user_pending.png' ), 'Selector' => 'radio', 'Fields' => Array ( 'Username' => Array ('data_block' => 'grid_login_td', 'filter_block' => 'grid_like_filter', 'width' => 150, ), 'FirstName' => Array ('filter_block' => 'grid_like_filter', 'width' => 150, ), 'LastName' => Array ('filter_block' => 'grid_like_filter', 'width' => 150, ), 'Email' => Array ('filter_block' => 'grid_like_filter', 'width' => 200, ), 'PrimaryGroup' => Array ('title' => 'la_col_PrimaryGroup', 'filter_block' => 'grid_like_filter', 'width' => 100, ), 'CreatedOn' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 150, ), 'Modified' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 150, ), 'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, ), 'IPAddress' => Array ('filter_block' => 'grid_like_filter', 'width' => 100, 'hidden' => 1), ), ), // used 'Admins' => Array ( 'Icons' => Array ( 0 => 'icon16_admin_disabled.png', 1 => 'icon16_admin.png', 2 => 'icon16_admin_disabled.png', ), 'Fields' => Array ( 'PortalUserId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 70), 'Username' => Array ('filter_block' => 'grid_like_filter', 'width' => 150, ), 'FirstName' => Array ('filter_block' => 'grid_like_filter', 'width' => 150, ), 'LastName' => Array ('filter_block' => 'grid_like_filter', 'width' => 150, ), 'Email' => Array ('filter_block' => 'grid_like_filter', 'width' => 200, ), 'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, ), ), ), // used 'RegularUsers' => Array ( 'Icons' => Array ( 0 => 'icon16_user_disabled.png', 1 => 'icon16_user.png', 2 => 'icon16_user_pending.png' ), 'Fields' => Array ( 'PortalUserId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 70), 'Username' => Array ('filter_block' => 'grid_like_filter', 'width' => 150, ), 'FirstName' => Array ('filter_block' => 'grid_like_filter', 'width' => 150, ), 'LastName' => Array ('filter_block' => 'grid_like_filter', 'width' => 150, ), 'Email' => Array ('filter_block' => 'grid_like_filter', 'width' => 200, ), 'PrimaryGroup' => Array ('title' => 'la_col_PrimaryGroup', 'filter_block' => 'grid_like_filter', 'width' => 140), 'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, ), 'CreatedOn' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 100), 'Modified' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 100), 'IPAddress' => Array ('filter_block' => 'grid_like_filter', 'width' => 100, 'hidden' => 1), 'EmailVerified' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, 'hidden' => 1), ), ), ), ); Index: branches/5.3.x/core/units/helpers/skin_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/skin_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/skin_helper.php (revision 16600) @@ -1,261 +1,202 @@ _getStyleField( $params['type'] ); + // Returns given field of skin. + if ( array_key_exists('type', $params) ) { + return $this->_getStyleField($params['type']); } - $style_info = $this->_getStyleInfo(); - - if (file_exists( $this->getSkinPath() )) { - // returns last compiled skin + if ( file_exists($this->getSkinPath()) ) { $ret = $this->getSkinPath(true); } else { - // search for previously compiled skin - $last_compiled = $this->_getLastCompiled( mb_strtolower($style_info['Name']) ); - if ($last_compiled) { - // found - $ret = $this->getSkinPath(true, $last_compiled); - } - else { - // not found (try to compile on the fly) - /** @var kDBItem $skin */ - $skin = $this->Application->recallObject('skin.-item', null, Array ('skip_autoload' => true)); - - $skin->Load(1, 'IsPrimary'); - $last_compiled = $this->compile($skin); - $ret = $last_compiled ? $this->getSkinPath(true, $last_compiled) : ''; - } + /** @var kDBItem $skin */ + $skin = $this->Application->recallObject('skin.-item', null, array('skip_autoload' => true)); + + $skin->Load(1, 'IsPrimary'); + $ret = $this->compile($skin) ? $this->getSkinPath(true) : ''; } - if (array_key_exists('file_only', $params) && $params['file_only']) { + if ( array_key_exists('file_only', $params) && $params['file_only'] ) { return $ret; } + $ret .= '?ts=' . adodb_date('Y-m-d_H:i:s', filemtime($this->getSkinPath())); + return ''; } /** * Compiles given skin object * - * @param kDBItem $object + * @param kDBItem $object Skin. + * + * @return integer */ - function compile(&$object) + public function compile(kDBItem $object) { $ret = $object->GetDBField('CSS'); $options = $object->GetDBField('Options'); $options = unserialize($options); - $options['base_url'] = Array ('Value' => rtrim(BASE_PATH, '/')); + $options['base_url'] = array('Value' => rtrim(BASE_PATH, '/')); - foreach ($options as $key => $row) { + foreach ( $options as $key => $row ) { $ret = str_replace('@@' . $key . '@@', $row['Value'], $ret); } $compile_ts = time(); - $css_file = $this->_getStylesheetPath() . DIRECTORY_SEPARATOR . 'admin-' . mb_strtolower($object->GetDBField('Name')) . '-' . $compile_ts . '.css'; + $style_name = $this->getSkinFilename($object->GetDBField('Name')); + $css_file = $this->_getStylesheetPath() . DIRECTORY_SEPARATOR . $style_name; - $fp = fopen($css_file, 'w'); - if (!$fp) { + if ( file_put_contents($css_file, $ret) === false ) { return false; } - $prev_css = $this->_getStylesheetPath() . '/admin-' . mb_strtolower($object->GetDBField('Name')) . '-' . $object->GetDBField('LastCompiled') . '.css'; - if (file_exists($prev_css)) { - unlink($prev_css); - } - - fwrite($fp, $ret); - fclose($fp); - $sql = 'UPDATE ' . $object->TableName . ' SET LastCompiled = ' . $compile_ts . ' WHERE ' . $object->IDField . ' = ' . $object->GetID(); $this->Conn->Query($sql); $this->Application->incrementCacheSerial('skin'); $this->Application->incrementCacheSerial('skin', $object->GetID()); return $compile_ts; } /** * Returns fields of primary admin skin * - * @return Array - * @access protected + * @return array */ protected function _getStyleInfo() { $cache_key = 'primary_skin_info[%SkinSerial%]'; $ret = $this->Application->getCache($cache_key); - if ($ret === false) { + if ( $ret === false ) { $this->Conn->nextQueryCachable = true; $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'AdminSkins WHERE IsPrimary = 1'; $ret = $this->Conn->GetRow($sql); $this->Application->setCache($cache_key, $ret); } return $ret; } /** * Returns requested field value of primary admin skin * - * @param string $field + * @param string $field Field. + * * @return string */ - function _getStyleField($field) + protected function _getStyleField($field) { - if ($field == 'logo') { - // old style method of calling + // Old style method of calling. + if ( $field == 'logo' ) { $field = 'Logo'; } $style_info = $this->_getStyleInfo(); - if (!$style_info[$field]) { + if ( !$style_info[$field] ) { return ''; } - $image_fields = Array ('Logo', 'LogoBottom', 'LogoLogin'); - if (in_array($field, $image_fields)) { + $image_fields = array('Logo', 'LogoBottom', 'LogoLogin'); + + if ( in_array($field, $image_fields) ) { return $this->_getStylesheetPath(true) . '/' . $style_info[$field]; } return $style_info[$field]; } /** * Returns path, where compiled skin and it's image files are stored * - * @param bool $url + * @param boolean $url Return url or path. + * * @return string - * @access protected */ protected function _getStylesheetPath($url = false) { - if ($url) { + if ( $url ) { $sub_folder = str_replace(DIRECTORY_SEPARATOR, '/', WRITEBALE_BASE) . '/user_files'; return $this->Application->BaseURL() . ltrim($sub_folder, '/'); } return WRITEABLE . DIRECTORY_SEPARATOR . 'user_files'; } /** * Returns full path to primary admin skin using given or last compiled date * - * @param string|bool $url - * @param int $compile_date + * @param boolean $url Return url or path.. + * * @return string - * @access public */ - public function getSkinPath($url = false, $compile_date = null) + public function getSkinPath($url = false) { $style_info = $this->_getStyleInfo(); - - if ( !isset($compile_date) ) { - $compile_date = $style_info['LastCompiled']; - } - - $style_name = 'admin-' . mb_strtolower($style_info['Name']) . '-' . $compile_date . '.css'; + $style_name = $this->getSkinFilename($style_info['Name']); return $this->_getStylesheetPath($url) . ($url ? '/' : DIRECTORY_SEPARATOR) . $style_name; } /** - * Returns maximal compilation date for given skin name + * Returns skin filename without path. + * + * @param string $skin_name Skin name. * - * @param string $style_name - * @return int + * @return string */ - function _getLastCompiled($style_name) + protected function getSkinFilename($skin_name) { - $last_compiled = 0; - - $iterator = new DirectoryIterator( $this->_getStylesheetPath() . DIRECTORY_SEPARATOR ); - /** @var DirectoryIterator $file_info */ - - foreach ($iterator as $file_info) { - if ( !$file_info->isFile() ) { - continue; - } - - $regs = $this->isSkinFile( $file_info->getFilename() ); - - if ( $regs && $regs[1] == $style_name && $regs[2] > $last_compiled ) { - $last_compiled = max($last_compiled, $regs[2]); - } - } - - return $last_compiled; + return 'admin-' . mb_strtolower($skin_name) . '.css'; } /** * Deletes all compiled versions of all skins * + * @return void */ - function deleteCompiled() + public function deleteCompiled() { - $iterator = new DirectoryIterator( $this->_getStylesheetPath() . DIRECTORY_SEPARATOR ); - /** @var DirectoryIterator $file_info */ + $files = glob($this->_getStylesheetPath() . DIRECTORY_SEPARATOR . 'admin-*.css'); - foreach ($iterator as $file_info) { - if ( $file_info->isFile() && $this->isSkinFile( $file_info->getFilename() ) ) { - unlink( $file_info->getPathname() ); - } + if ( $files ) { + array_map('unlink', $files); } } - /** - * Determines if given file is admin skin file - * - * @param string $filename - * @return array|bool - * @access protected - */ - protected function isSkinFile($filename) - { - if ( preg_match(self::SKIN_REGEXP, $filename, $regs) ) { - return $regs; - } - - return false; - } - } \ No newline at end of file + } Index: branches/5.3.x/core/units/helpers/col_picker_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/col_picker_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/col_picker_helper.php (revision 16600) @@ -1,580 +1,580 @@ Application->processPrefix($prefix); $this->Init($splitted['prefix'], $splitted['special']); $this->useFreezer = $this->Application->ConfigValue('UseColumnFreezer'); $this->gridName = $grid_name; $this->pickerData = $this->loadColumns(); } /** * Loads picker data. * * @return ColumnSet */ protected function loadColumns() { $default_value = $this->Application->isAdmin ? ALLOW_DEFAULT_SETTINGS : false; $value = $this->Application->RecallPersistentVar($this->getVarName('get'), $default_value); if ( !$value ) { $columns = $this->rebuildColumns(); } else { $default_columns = $this->getDefaultColumns(); $columns = new ColumnSet(unserialize($value)); if ( !$columns->same($default_columns) ) { $columns = $this->rebuildColumns($columns); } } return $columns; } /** * Merges default column set with given one. * * @param ColumnSet $current_columns Currently used column set. * * @return ColumnSet */ protected function rebuildColumns(ColumnSet $current_columns = null) { if ( isset($current_columns) ) { $columns = $current_columns->merge($this->getDefaultColumns(), self::DEFAULT_COLUMN_WIDTH); } else { $columns = $this->getDefaultColumns(); } $this->storeCols($columns); return $columns; } /** * Returns column set built purely from grid definition in unit config. * * @return ColumnSet */ protected function getDefaultColumns() { $grid_columns = $this->getColumnsFromUnitConfig(); // we NEED to recall dummy here to apply field changes imposed by formatters, // such as replacing multilingual field titles etc. $this->Application->recallObject($this->getPrefixSpecial(), null, array('skip_autoload' => 1)); $counter = 0; $fields = $titles = $widths = $hidden = array(); foreach ( $grid_columns as $name => $options ) { if ( array_key_exists('formatter_renamed', $options) && $options['formatter_renamed'] ) { // remove language prefix from field, because formatter renamed column $this->formatterRenamed[] = $name; $name = preg_replace('/^l[\d]+_/', '', $name); } $fields[$counter] = $name; $titles[$name] = isset($options['title']) ? $options['title'] : 'column:la_fld_' . $name; $widths[$name] = isset($options['width']) ? $options['width'] : self::DEFAULT_COLUMN_WIDTH; if ( isset($options['hidden']) && $options['hidden'] ) { $hidden[$counter] = $name; } $counter++; } $cols = array( 'order' => $fields, 'titles' => $titles, 'hidden_fields' => $hidden, 'widths' => $widths, ); return new ColumnSet($cols); } /** * Returns columns as-is from unit config. * * @return array */ protected function getColumnsFromUnitConfig() { $grid = $this->getUnitConfig()->getGridByName($this->gridName); if ( $this->useFreezer ) { $freezer_column = array('__FREEZER__' => array('title' => '__FREEZER__')); return array_merge_recursive($freezer_column, $grid['Fields']); } return $grid['Fields']; } /** * Gets variable name in persistent session to store column positions in * * @param string $mode * @return string */ protected function getVarName($mode = 'get') { $view_name = $this->Application->RecallVar($this->Prefix . '_current_view'); $ret = $this->Prefix . '[' . $this->gridName . ']columns_.' . $view_name; if ( $mode == 'get' ) { // fallback to old storage system, that remember only 1 grid configuration per-unit if ( $this->Application->RecallPersistentVar($ret) === false ) { $ret = $this->Prefix . '_columns_.' . $view_name; } } return $ret; } /** * Returns picker data. * * @return ColumnSet */ public function getData() { return $this->pickerData; } protected function storeCols(ColumnSet $cols) { $this->Application->StorePersistentVar($this->getVarName('set'), serialize($cols->toArray())); } /** * Reorders given grid configuration based on picker data and removes hidden columns. * * @param array $grid_columns * * @return array */ public function apply(array $grid_columns) { uksort($grid_columns, array($this, 'compareColumns')); return $this->removeHidden($grid_columns); } /** * Removes columns, that are hidden in picker configuration. * * @param array $grid_columns Grid columns. * * @return array */ protected function removeHidden(array $grid_columns) { $to_remove = array(); foreach ( $grid_columns as $name => $options ) { if ( array_key_exists('formatter_renamed', $options) && $options['formatter_renamed'] ) { // remove language prefix from field, because formatter renamed column $name_renamed = preg_replace('/^l[\d]+_/', '', $name); } else { $name_renamed = $name; } if ( $this->pickerData->isHidden($name_renamed) ) { $to_remove[] = $name; } } foreach ( $to_remove as $name ) { unset($grid_columns[$name]); } return $grid_columns; } /** * Helper function for reordering grid columns. * * @param string $first_column * @param string $second_column * * @return integer */ protected function compareColumns($first_column, $second_column) { $first_column_order = $this->pickerData->getOrder($this->fixColumnName($first_column)); $second_column_order = $this->pickerData->getOrder($this->fixColumnName($second_column)); if ( $first_column_order == $second_column_order ) { return 0; } return ($first_column_order < $second_column_order) ? -1 : 1; } /** * Saves changes to column widths. * * @param string $picked Visible columns. * @param string $hidden Hidden columns. * * @return void */ public function saveColumns($picked, $hidden) { $order = $picked ? explode('|', $picked) : array(); $hidden = $hidden ? explode('|', $hidden) : array(); $order = array_merge($order, $hidden); $this->pickerData->allFields = $order; $this->pickerData->hiddenFields = $hidden; $this->storeCols($this->pickerData); } /** * Saves changes to column widths. * * @param array|string $widths Column width info. * * @return void */ public function saveWidths($widths) { if ( !is_array($widths) ) { $widths = explode(':', $widths); } $i = 0; array_shift($widths); // removing first col (checkbox col) width foreach ( $this->pickerData->allFields as $field ) { - if ( $field == '__FREEZER__' ) { + if ( $field == '__FREEZER__' || $this->pickerData->isHidden($field) ) { continue; } $this->pickerData->widths[$field] = isset($widths[$i]) ? $widths[$i] : self::DEFAULT_COLUMN_WIDTH; $i++; } $this->storeCols($this->pickerData); } /** * Returns width of a given column. * * @param string $column_name Column name. * * @return string */ public function getWidth($column_name) { return $this->pickerData->getWidth($this->fixColumnName($column_name)); } /** * Removes language prefix from formatter renamed column. * * @param string $name Column name. * * @return string */ protected function fixColumnName($name) { if ( in_array($name, $this->formatterRenamed) ) { // Remove language prefix from field, because formatter renamed column. $name = preg_replace('/^l[\d]+_/', '', $name); } return $name; } } class ColumnSet extends kBase { /** * List of all fields (key - order, value - field name). * * @var array */ public $allFields; /** * List of hidden fields (key - order, value - field name). * * @var array */ public $hiddenFields; /** * List of field titles (key - field name, value - label). * * @var array */ public $titles; /** * List of field widths (key - field name, value - width). * * @var array */ public $widths; /** * Creates column set. * * @param array $data Data. */ public function __construct(array $data) { $this->allFields = $data['order']; $this->hiddenFields = $data['hidden_fields']; $this->titles = $data['titles']; $this->widths = $data['widths']; } /** * Returns array representation of an object. * * @return array */ public function toArray() { $ret = array( 'order' => $this->allFields, 'hidden_fields' => $this->hiddenFields, 'titles' => $this->titles, 'widths' => $this->widths, ); return $ret; } /** * Returns title for a column. * * @param string $column_name Column name. * * @return string */ public function getTitle($column_name) { return $this->titles[$column_name]; } /** * Returns width of a column. * * @param string $column_name Column name. * @param mixed $default Default value. * * @return string */ public function getWidth($column_name, $default = false) { return isset($this->widths[$column_name]) ? $this->widths[$column_name] : $default; } /** * Returns order for a column. * * @param string $column_name Column name. * * @return integer|boolean */ public function getOrder($column_name) { return array_search($column_name, $this->allFields); } /** * Determines if a column is hidden. * * @param string $column_name Column name. * * @return boolean */ public function isHidden($column_name) { return array_search($column_name, $this->hiddenFields) !== false; } /** * Returns checksum for current column set. * * @return integer */ public function getChecksum() { $sorted_fields = $this->allFields; $sorted_titles = $this->titles; asort($sorted_fields); asort($sorted_titles); return crc32(implode(',', $sorted_fields) . implode(',', $sorted_titles)); } /** * Compares 2 column sets. * * @param ColumnSet $columns Column set. * * @return boolean */ public function same(ColumnSet $columns) { return $this->getChecksum() == $columns->getChecksum(); } /** * Merges current column set with given one. * * @param ColumnSet $default_columns Column set to merge with. * @param integer $default_width Default column width. * * @return self */ public function merge(ColumnSet $default_columns, $default_width) { // keep user column order (common columns between user's and default grid) $common = array_intersect($this->allFields, $default_columns->allFields); // get new columns (found in default grid, but not found in user's grid) $added = array_diff($default_columns->allFields, $this->allFields); // in case if freezer was added, then make it first column if ( in_array('__FREEZER__', $added) ) { array_unshift($common, '__FREEZER__'); unset($added[array_search('__FREEZER__', $added)]); } // keep added column position $this->allFields = $common; foreach ( $added as $added_column ) { $this->insertAfter($added_column, $default_columns->getPrecedingColumn($added_column)); } $this->titles = $default_columns->titles; $this->hiddenFields = array_intersect($this->allFields, $this->hiddenFields); // update width & hidden status for added columns foreach ( $added as $added_column ) { $this->widths[$added_column] = $default_columns->getWidth($added_column, $default_width); if ( $default_columns->isHidden($added_column) ) { $this->hiddenFields[$default_columns->getOrder($added_column)] = $added_column; } } return $this; } /** * Inserts one column after another. * * @param string $new_column Name of column to insert. * @param string $after_column Name of column to insert after. * * @return self */ public function insertAfter($new_column, $after_column) { $addition = array($after_column, $new_column); array_splice($this->allFields, $this->getOrder($after_column), 1, $addition); return $this; } /** * Returns preceding column. * * @param string $name Column name. * * @return string */ public function getPrecedingColumn($name) { $prev_column = reset($this->allFields); foreach ( $this->allFields as $column ) { if ( $column == $name ) { return $prev_column; } $prev_column = $column; } return ''; } } \ No newline at end of file Index: branches/5.3.x/core/units/helpers/mailing_list_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/mailing_list_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/mailing_list_helper.php (revision 16600) @@ -1,394 +1,394 @@ Application->recallObject('EmailSender'); if ($this->_mailingId != $mailing_id) { if (is_numeric($this->_mailingId)) { // clear fields after previous mailing processing $esender->Clear(); } // 1. set headers same for all emails list ($mailing_data['FromName'], $mailing_data['FromEmail']) = $this->_getSenderData($mailing_data); $esender->SetFrom($mailing_data['FromEmail'], $mailing_data['FromName']); $esender->SetSubject($mailing_data['Subject']); if ( !$mailing_data['MessageText'] ) { $mailing_data['MessageText'] = $esender->ConvertToText($mailing_data['MessageHtml']); } $esender->SetBody($mailing_data['MessageHtml'], $mailing_data['MessageText']); // 2. add attachment if any $attachments = $mailing_data['Attachments'] ? explode('|', $mailing_data['Attachments']) : Array (); foreach ($attachments as $attachment) { $esender->AddAttachment(FULL_PATH . ITEM_FILES_PATH . $attachment); } $this->_mailingId = $mailing_id; } // 3. set recipient specific fields $esender->SetTo($email, $email); if ( $this->Application->ConfigValue('EnableEmailLog') ) { // 4. write to log $log_fields_hash = Array ( 'From' => $mailing_data['FromName'] . '(' . $mailing_data['FromEmail'] . ')', 'To' => $email, 'Subject' => $mailing_data['Subject'], 'HtmlBody' => $mailing_data['MessageHtml'], 'TextBody' => $mailing_data['MessageText'], 'SentOn' => TIMENOW, 'EventParams' => serialize( Array ('MailingId' => $mailing_id) ), ); $esender->setLogData($log_fields_hash); } $esender->Deliver(null, $mailing_id, false); } /** * Returns mass mail sender name & email * * @param Array $mailing_data * @return Array * @access protected */ protected function _getSenderData(&$mailing_data) { $is_root = true; $email_address = $name = ''; if ( $mailing_data['PortalUserId'] > 0 ) { /** @var UsersItem $sender */ $sender = $this->Application->recallObject('u.-item', null, Array ('skip_autoload' => true)); $sender->Load($mailing_data['PortalUserId']); $email_address = $sender->GetDBField('Email'); $name = trim($sender->GetDBField('FirstName') . ' ' . $sender->GetDBField('LastName')); $is_root = false; } if ( $is_root || !$email_address ) { $email_address = $this->Application->ConfigValue('DefaultEmailSender'); } if ( $is_root || !$name ) { $name = strip_tags($this->Application->ConfigValue('Site_Name')); } return Array ($name, $email_address); } /** * Generates recipients emails based on "To" field value. * * @param int $id Id. * @param Array $fields_hash Fields hash. * * @return array */ function generateRecipients($id, $fields_hash) { // for each group convert ids to names $recipient_emails = Array (); $recipients_grouped = $this->groupRecipientsByType(explode(';', $fields_hash['To'])); foreach ($recipients_grouped as $recipient_type => $group_recipients) { $recipient_emails = array_merge($recipient_emails, $this->_getRecipientEmails($recipient_type, $group_recipients)); } $recipient_emails = array_unique($recipient_emails); return Array ( 'ToParsed' => serialize($recipient_emails), 'EmailsTotal' => count($recipient_emails), ); } /** * Groups recipients by type * * @param Array $recipients * @return Array * @access public */ public function groupRecipientsByType($recipients) { $recipients_grouped = Array (); foreach ($recipients as $recipient) { if ( strpos($recipient, '_') !== false ) { list ($recipient_type, $recipient_id) = explode('_', $recipient); } else { $recipient_type = 'direct'; $recipient_id = $recipient; } if ( !array_key_exists($recipient_type, $recipients_grouped) ) { $recipients_grouped[$recipient_type] = Array (); } $recipients_grouped[$recipient_type][] = $recipient_id; } return $recipients_grouped; } function _getRecipientEmails($recipient_type, $recipient_ids) { if (strpos($recipient_type, '.') !== false) { // remove special list ($recipient_type, ) = explode('.', $recipient_type); } if ($recipient_type != 'u' && $recipient_type != 'g') { // these are already emails return $recipient_ids; } switch ($recipient_type) { case 'u': $sql = 'SELECT Email FROM ' . TABLE_PREFIX . 'Users WHERE (PortalUserId IN (' . implode(',', $recipient_ids) . ')) AND (Email <> "")'; break; case 'g': $sql = 'SELECT u.Email FROM ' . TABLE_PREFIX . 'UserGroupRelations ug LEFT JOIN ' . TABLE_PREFIX . 'Users u ON u.PortalUserId = ug.PortalUserId WHERE (ug.GroupId IN (' . implode(',', $recipient_ids) . ')) AND (u.Email <> "")'; break; default: $sql = ''; break; } return $this->Conn->GetCol($sql); } function getRecipientNames($recipient_type, $recipient_ids) { if (strpos($recipient_type, '.') !== false) { // remove special list ($recipient_type, ) = explode('.', $recipient_type); } switch ($recipient_type) { case 'u': $title_field = 'Email'; break; case 'g': $title_field = 'Name'; break; default: $title_field = false; break; } if ($title_field === false || !$recipient_ids) { return $recipient_ids; } $config = $this->Application->getUnitConfig($recipient_type); $id_field = $config->getIDField(); $table_name = $config->getTableName(); $sql = 'SELECT ' . $title_field . ' FROM ' . $table_name . ' WHERE ' . $id_field . ' IN (' . implode(',', $recipient_ids) . ')'; return $this->Conn->GetCol($sql); } /** * Updates information about sent email count based on given totals by mailings * * @param Array $mailing_totals */ function _updateSentTotals($mailing_totals) { if ( array_key_exists(0, $mailing_totals) ) { // don't update sent email count for mails queued directly (not via mailing lists) unset($mailing_totals[0]); } $config = $this->Application->getUnitConfig('mailing-list'); $table_name = $config->getTableName(); // update sent email count for each processed mailing foreach ( $mailing_totals as $mailing_id => $mailing_total ) { $sql = 'UPDATE ' . $table_name . ' SET EmailsSent = EmailsSent + ' . $mailing_total . ' WHERE ' . $config->getIDField() . ' = ' . $mailing_id; $this->Conn->Query($sql); } // mark mailings, that were processed completely $sql = 'UPDATE ' . $table_name . ' SET Status = ' . MailingList::PROCESSED . ' WHERE (Status = ' . MailingList::PARTIALLY_PROCESSED . ') AND (EmailsSent = EmailsTotal)'; $this->Conn->Query($sql); } /** * Sent given messages from email queue. * * @param array|null $messages Messages. * * @return integer */ function processQueue(&$messages = null) { /** @var kEmailSendingHelper $esender */ $esender = $this->Application->recallObject('EmailSender'); if ( !isset($messages) ) { $messages = $this->getMessages(); } else { - kUtil::deprecatedArgument(__METHOD__, '5.3.0-B1', 'The "$messages" parameter is deprecated.'); + kUtil::deprecatedArgument(__METHOD__, '5.2.2-B2', 'The "$messages" parameter is deprecated.'); } $message_count = count($messages); if ( !$message_count ) { return 0; } $i = 0; $message = Array(); $mailing_totals = Array(); $queue_table = $this->Application->getUnitConfig('email-queue')->getTableName(); while ( $i < $message_count ) { $message[0] = unserialize($messages[$i]['MessageHeaders']); $message[1] =& $messages[$i]['MessageBody']; $esender->setLogData(unserialize($messages[$i]['LogData'])); $delivered = $esender->Deliver($message, true); // immediate send! if ( $delivered ) { // send succeeded, delete from queue $sql = 'DELETE FROM ' . $queue_table . ' WHERE EmailQueueId = ' . $messages[$i]['EmailQueueId']; $this->Conn->Query($sql); $mailing_id = $messages[$i]['MailingId']; if ( !array_key_exists($mailing_id, $mailing_totals) ) { $mailing_totals[$mailing_id] = 0; } $mailing_totals[$mailing_id]++; } else { // send failed, increment retries counter $sql = 'UPDATE ' . $queue_table . ' SET SendRetries = SendRetries + 1, LastSendRetry = ' . time() . ' WHERE EmailQueueId = ' . $messages[$i]['EmailQueueId']; $this->Conn->Query($sql); } $i++; } $this->_updateSentTotals($mailing_totals); return $message_count; } /** * Returns queued messages (or their count), that can be sent * * @param bool $count_only * * @return Array|int * @access public */ public function getMessages($count_only = false) { $deliver_count = $this->getSetting('MailingListSendPerStep'); if ( !is_numeric($deliver_count) ) { return $count_only ? 0 : Array(); } $queue_table = $this->Application->getUnitConfig('email-queue')->getTableName(); if ( $count_only ) { $sql = 'SELECT COUNT(*) FROM ' . $queue_table . ' WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ')'; return $this->Conn->GetOne($sql); } // regular e-mails are pressed before mailing generated ones ! $sql = 'SELECT * FROM ' . $queue_table . ' WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ') ORDER BY MailingId ASC LIMIT 0,' . $deliver_count; return $this->Conn->Query($sql); } /** * Allows to safely get mailing configuration variable * * @param string $variable_name * * @return int * @access public */ public function getSetting($variable_name) { $value = $this->Application->ConfigValue($variable_name); if ( $value === false ) { // ensure default value, when configuration variable is missing return 10; } if ( !$value ) { // configuration variable found, but it's value is empty or zero return false; } return $value; } } Index: branches/5.3.x/core/units/helpers/category_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/category_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/category_helper.php (revision 16600) @@ -1,361 +1,361 @@ Application->findModule('Name', $params['module']); } // Get module by category path. if ( $category_path ) { foreach ( array_reverse($category_path) as $module_category_id ) { $module_info = $this->Application->findModule('RootCat', $module_category_id); if ( $module_info && $module_info['Var'] != 'adm' ) { return $module_info; } } } - return array(); + return false; } /** * Converts multi-dimensional category structure in one-dimensional option array (category_id=>category_name) * * @param Array $data * @param int $parent_category_id * @param int $language_id * @param int $theme_id * @param int $level * @return Array * @access protected */ protected function _printChildren(&$data, $parent_category_id, $language_id, $theme_id, $level = 0) { if ( $data['ThemeId'] != $theme_id && $data['ThemeId'] != 0 ) { // don't show system templates from different themes return Array (); } $category_language = $data['l' . $language_id . '_Name'] ? $language_id : $this->_primaryLanguageId; $ret = Array ($parent_category_id => str_repeat('—', $level) . ' ' . $data['l' . $category_language . '_Name']); if ( $data['children'] ) { $level++; foreach ($data['children'] as $category_id => $category_data) { // numeric keys $ret = kUtil::array_merge_recursive($ret, $this->_printChildren($data['children'][$category_id], $category_id, $language_id, $theme_id, $level)); } } return $ret; } /** * Returns information about children under parent path (recursive) * * @param int $parent_category_id * @param Array $languages * @return Array * @access protected */ protected function _getChildren($parent_category_id, $languages) { static $items_by_parent = null, $parent_mapping = null; if ( !isset($items_by_parent) ) { $fields = $items_by_parent = Array (); foreach ($languages as $language_id) { $fields[] = 'l' . $language_id . '_Name'; } $sql = 'SELECT CategoryId AS id, ' . implode(', ', $fields) . ', ParentId, Template, ThemeId FROM ' . TABLE_PREFIX . 'Categories ORDER BY Priority DESC'; $items = $this->Conn->Query($sql, 'id'); foreach ($items as $item_id => $item_data) { $item_parent_id = $item_data['ParentId']; unset($item_data['ParentId']); if ( !array_key_exists($item_parent_id, $items_by_parent) ) { $items_by_parent[$item_parent_id] = Array (); } $item_data['children'] = false; $parent_mapping[$item_id] = $item_parent_id; $items_by_parent[$item_parent_id][$item_id] = $item_data; } $base_category = $this->Application->getBaseCategory(); // "Content" category if ( isset($items_by_parent[$base_category]) ) { $index_category = $this->findIndexCategoryId($items_by_parent[$base_category]); // rename "Content" into "Home" keeping it's ID $items_by_parent[$parent_mapping[$base_category]][$base_category]['l1_Name'] = $this->Application->Phrase('la_rootcategory_name'); if ( $index_category !== false ) { // remove category of "index.tpl" template unset($items_by_parent[$base_category][$index_category]); unset($parent_mapping[$index_category]); } } } $data = $items_by_parent[$parent_mapping[$parent_category_id]][$parent_category_id]; $categories = array_key_exists($parent_category_id, $items_by_parent) ? $items_by_parent[$parent_category_id] : Array (); foreach ($categories as $category_id => $category_data) { if ( $category_id == $parent_category_id ) { // don't process myself - prevents recursion continue; } $data['children'][$category_id] = $this->_getChildren($category_id, $languages); } return $data; } /** * Finds "Home" category among given top level categories * * @param Array $top_categories * @return bool|int * @access protected */ protected function findIndexCategoryId($top_categories) { foreach ($top_categories as $category_id => $category_info) { if ($category_info['Template'] == 'index') { return $category_id; } } return false; } /** * Generates OR retrieves from cache structure tree * * @return Array * @access protected */ protected function &_getStructureTree() { // get cached version of structure tree if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $data = $this->Application->getCache('master:StructureTree', false, CacheSettings::$structureTreeRebuildTime); } else { $data = $this->Application->getDBCache('StructureTree', CacheSettings::$structureTreeRebuildTime); } if ( $data ) { $data = unserialize($data); return $data; } // generate structure tree from scratch /** @var kMultiLanguageHelper $ml_helper */ $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); $languages = $ml_helper->getLanguages(); $root_category = $this->Application->getBaseCategory(); $data = $this->_getChildren($root_category, $languages); if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $this->Application->setCache('master:StructureTree', serialize($data)); } else { $this->Application->setDBCache('StructureTree', serialize($data)); } return $data; } /** * Returns template mapping (between physical and virtual pages) * * @return Array * @access public */ public function getTemplateMapping() { if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $data = $this->Application->getCache('master:template_mapping', false, CacheSettings::$templateMappingRebuildTime); } else { $data = $this->Application->getDBCache('template_mapping', CacheSettings::$templateMappingRebuildTime); } if ( $data ) { return unserialize($data); } $sql = 'SELECT IF(c.`Type` = ' . PAGE_TYPE_TEMPLATE . ', CONCAT(c.Template, ":", c.ThemeId), CONCAT("id:", c.CategoryId)) AS SrcTemplate, LOWER( IF( c.SymLinkCategoryId IS NOT NULL, (SELECT cc.NamedParentPath FROM ' . TABLE_PREFIX . 'Categories AS cc WHERE cc.CategoryId = c.SymLinkCategoryId), c.NamedParentPath ) ) AS DstTemplate, c.UseExternalUrl, c.ExternalUrl FROM ' . TABLE_PREFIX . 'Categories AS c WHERE c.Status = ' . STATUS_ACTIVE; $pages = $this->Conn->Query($sql, 'SrcTemplate'); $mapping = Array (); $base_url = $this->Application->BaseURL(); foreach ($pages as $src_template => $page) { // process external url, before placing in cache if ( $page['UseExternalUrl'] ) { $external_url = $page['ExternalUrl']; if ( !preg_match('/^(.*?):\/\/(.*)$/', $external_url) ) { // url without protocol will be relative url to our site $external_url = $base_url . $external_url; } $dst_template = 'external:' . $external_url; } else { $dst_template = preg_replace('/^Content\//i', '', $page['DstTemplate']); } $mapping[$src_template] = $dst_template; } if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $data = $this->Application->setCache('master:template_mapping', serialize($mapping)); } else { $this->Application->setDBCache('template_mapping', serialize($mapping)); } return $mapping; } /** * Returns category structure as field option list * * @return Array * @access public */ public function getStructureTreeAsOptions() { if ( (defined('IS_INSTALL') && IS_INSTALL) || !$this->Application->isAdmin ) { // no need to create category structure during install // OR on Front-End, because it's not used there return Array (); } if ( isset($this->_structureTree) ) { return $this->_structureTree; } /** @var kThemesHelper $themes_helper */ $themes_helper = $this->Application->recallObject('ThemesHelper'); $data = $this->_getStructureTree(); $theme_id = (int)$themes_helper->getCurrentThemeId(); $this->_primaryLanguageId = $this->Application->GetDefaultLanguageId(); $this->_structureTree = $this->_printChildren($data, $data['id'], $this->Application->GetVar('m_lang'), $theme_id); return $this->_structureTree; } /** * Replace links like "@@ID@@" to actual template names in given text * * @param string $text * @return string * @access public */ public function replacePageIds($text) { if ( !preg_match_all('/@@(\\d+)@@/', $text, $regs) ) { return $text; } $page_ids = $regs[1]; $sql = 'SELECT NamedParentPath, CategoryId FROM ' . TABLE_PREFIX . 'Categories WHERE CategoryId IN (' . implode(',', $page_ids) . ')'; $templates = $this->Conn->GetCol($sql, 'CategoryId'); $base_category = $this->Application->getBaseCategory(); if ( isset($templates[$base_category]) ) { // "Content" category will act as "Home Page" $templates[$base_category] .= '/Index'; } foreach ($page_ids as $page_id) { if ( !isset($templates[$page_id]) ) { // internal page was deleted, but link to it was found in given content block data continue; } $url_params = Array ('m_cat_id' => $page_id == $base_category ? 0 : $page_id, 'pass' => 'm'); $page_url = $this->Application->HREF(strtolower($templates[$page_id]), '', $url_params); /*if ($this->Application->isAdmin) { $page_url = preg_replace('/&(admin|editing_mode)=[\d]/', '', $page_url); }*/ $text = str_replace('@@' . $page_id . '@@', $page_url, $text); } return $text; } } Index: branches/5.3.x/core/units/helpers/user_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/user_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/user_helper.php (revision 16600) @@ -1,795 +1,795 @@ event) ) { $this->event = new kEvent('u:OnLogin'); } if ( !$password && !$remember_login_cookie ) { return LoginResult::INVALID_PASSWORD; } $object =& $this->getUserObject(); // process "Save Username" checkbox if ( $this->Application->isAdmin ) { $save_username = $this->Application->GetVar('cb_save_username') ? $username : ''; $this->Application->Session->SetCookie('save_username', $save_username, strtotime('+1 year')); // cookie will be set on next refresh, but refresh won't occur if // login error present, so duplicate cookie in kHTTPQuery $this->Application->SetVar('save_username', $save_username); } // logging in "root" (admin only) $super_admin = ($username == 'super-root') && $this->verifySuperAdmin(); if ( $this->Application->isAdmin && ($username == 'root') || ($super_admin && $username == 'super-root') ) { /** @var kPasswordFormatter $password_formatter */ $password_formatter = $this->Application->recallObject('kPasswordFormatter'); if ( !$password_formatter->checkPasswordFromSetting('RootPass', $password) ) { return LoginResult::INVALID_PASSWORD; } $user_id = USER_ROOT; $object->Clear($user_id); $object->SetDBField('Username', 'root'); if ( !$dry_run ) { $this->loginUserById($user_id, $remember_login_cookie); if ( $super_admin ) { $this->Application->StoreVar('super_admin', 1); } // reset counters $this->Application->resetCounters('UserSessions'); $this->_processLoginRedirect('root', $password); $this->_processInterfaceLanguage(); $this->_fixNextTemplate(); } return LoginResult::OK; } $user_id = $this->getUserId($username, $password, $remember_login_cookie); if ( $user_id ) { $object->Load($user_id); if ( !$this->checkBanRules($object) ) { return LoginResult::BANNED; } if ( $object->GetDBField('Status') == STATUS_ACTIVE ) { if ( !$this->checkLoginPermission() ) { return LoginResult::NO_PERMISSION; } if ( !$dry_run ) { $this->loginUserById($user_id, $remember_login_cookie); if ( $remember_login ) { // remember username & password when "Remember Login" checkbox us checked (when user is using login form on Front-End) $sql = 'SELECT MD5(Password) FROM ' . TABLE_PREFIX . 'Users WHERE PortalUserId = ' . $user_id; $remember_login_hash = $this->Conn->GetOne($sql); $this->Application->Session->SetCookie('remember_login', $username . '|' . $remember_login_hash, strtotime('+1 month')); } if ( !$remember_login_cookie ) { // reset counters $this->Application->resetCounters('UserSessions'); $this->_processLoginRedirect($username, $password); $this->_processInterfaceLanguage(); $this->_fixNextTemplate(); } } return LoginResult::OK; } else { $pending_template = $this->Application->GetVar('pending_disabled_template'); if ( $pending_template !== false && !$dry_run ) { // when user found, but it's not yet approved redirect hit to notification template $this->event->redirect = $pending_template; return LoginResult::OK; } else { // when no notification template given return an error return LoginResult::INVALID_PASSWORD; } } } if ( !$dry_run ) { $this->event->SetRedirectParam('pass', 'all'); // $this->event->SetRedirectParam('pass_category', 1); // to test } return LoginResult::INVALID_PASSWORD; } /** * Login user by it's id * * @param int $user_id * @param bool $remember_login_cookie */ function loginUserById($user_id, $remember_login_cookie = false) { $object =& $this->getUserObject(); $this->Application->SetVar('u.current_id', $user_id); if ( !$this->Application->isAdmin ) { // needed for "profile edit", "registration" forms ON FRONT ONLY $this->Application->SetVar('u_id', $user_id); } $this->Application->StoreVar('user_id', $user_id); $this->Application->Session->SetField('PortalUserId', $user_id); if ($user_id != USER_ROOT) { $groups = $this->Application->RecallVar('UserGroups'); list ($first_group, ) = explode(',', $groups); $this->Application->Session->SetField('GroupId', $first_group); $this->Application->Session->SetField('GroupList', $groups); $this->Application->Session->SetField('TimeZone', $object->GetDBField('TimeZone')); } $this->Application->LoadPersistentVars(); if (!$remember_login_cookie) { // don't change last login time when auto-login is used $this_login = (int)$this->Application->RecallPersistentVar('ThisLogin'); $this->Application->StorePersistentVar('LastLogin', $this_login); $this->Application->StorePersistentVar('ThisLogin', time()); } $hook_event = new kEvent('u:OnAfterLogin'); $hook_event->MasterEvent = $this->event; $this->Application->HandleEvent($hook_event); } /** * Checks login permission * * @return bool */ function checkLoginPermission() { $object =& $this->getUserObject(); $ip_restrictions = $object->GetDBField('IPRestrictions'); if ( $ip_restrictions && !$this->Application->isDebugMode() && !kUtil::ipMatch($ip_restrictions, "\n") ) { return false; } $groups = $object->getMembershipGroups(true); if ( !$groups ) { $groups = Array (); } $default_group = $this->getUserTypeGroup(); if ( $default_group !== false ) { array_push($groups, $default_group); } // store groups, because kApplication::CheckPermission will use them! array_push($groups, $this->Application->ConfigValue('User_LoggedInGroup')); $groups = array_unique($groups); $this->Application->StoreVar('UserGroups', implode(',', $groups), true); // true for optional return $this->Application->CheckPermission($this->Application->isAdmin ? 'ADMIN' : 'LOGIN', 1); } /** * Returns default user group for it's type * * @return bool|string * @access protected */ protected function getUserTypeGroup() { $group_id = false; $object =& $this->getUserObject(); if ( $object->GetDBField('UserType') == UserType::USER ) { $group_id = $this->Application->ConfigValue('User_NewGroup'); } elseif ( $object->GetDBField('UserType') == UserType::ADMIN ) { $group_id = $this->Application->ConfigValue('User_AdminGroup'); } $ip_restrictions = $this->getGroupsWithIPRestrictions(); if ( !isset($ip_restrictions[$group_id]) || kUtil::ipMatch($ip_restrictions[$group_id], "\n") ) { return $group_id; } return false; } /** * Returns groups with IP restrictions * * @return Array * @access public */ public function getGroupsWithIPRestrictions() { static $cache = null; if ( $this->Application->isDebugMode() ) { return Array (); } if ( !isset($cache) ) { $sql = 'SELECT IPRestrictions, GroupId FROM ' . TABLE_PREFIX . 'UserGroups - WHERE IPRestrictions IS NOT NULL'; + WHERE COALESCE(IPRestrictions, "") <> ""'; $cache = $this->Conn->GetCol($sql, 'GroupId'); } return $cache; } /** * Performs user logout * */ function logoutUser() { if (!isset($this->event)) { $this->event = new kEvent('u:OnLogout'); } $hook_event = new kEvent('u:OnBeforeLogout'); $hook_event->MasterEvent = $this->event; $this->Application->HandleEvent($hook_event); $this->_processLoginRedirect(); $user_id = USER_GUEST; $this->Application->SetVar('u.current_id', $user_id); /** @var UsersItem $object */ $object = $this->Application->recallObject('u.current', null, Array('skip_autoload' => true)); $object->Load($user_id); $this->Application->DestroySession(); $this->Application->StoreVar('user_id', $user_id, true); $this->Application->Session->SetField('PortalUserId', $user_id); $group_list = $this->Application->ConfigValue('User_GuestGroup') . ',' . $this->Application->ConfigValue('User_LoggedInGroup'); $this->Application->StoreVar('UserGroups', $group_list, true); $this->Application->Session->SetField('GroupList', $group_list); if ($this->Application->ConfigValue('UseJSRedirect')) { $this->event->SetRedirectParam('js_redirect', 1); } $this->Application->resetCounters('UserSessions'); $this->Application->Session->SetCookie('remember_login', '', strtotime('-1 hour')); // don't pass user prefix on logout, since resulting url will have broken "env" $this->event->SetRedirectParam('pass', MOD_REWRITE ? 'm' : 'all'); $this->_fixNextTemplate(); } /** * Returns user id based on given criteria * * @param string $username * @param string $password * @param string $remember_login_cookie * @return int */ function getUserId($username, $password, $remember_login_cookie) { if ( $remember_login_cookie ) { list ($username, $password) = explode('|', $remember_login_cookie); // 0 - username, 1 - md5(password_hash) } $sql = 'SELECT PortalUserId, Password, PasswordHashingMethod FROM ' . TABLE_PREFIX . 'Users WHERE Email = %1$s OR Username = %1$s'; $user_info = $this->Conn->GetRow(sprintf($sql, $this->Conn->qstr($username))); if ( $user_info ) { if ( $remember_login_cookie ) { - return md5($user_info['Password']) == $password; + return md5($user_info['Password']) == $password ? $user_info['PortalUserId'] : false; } else { /** @var kPasswordFormatter $password_formatter */ $password_formatter = $this->Application->recallObject('kPasswordFormatter'); $hashing_method = $user_info['PasswordHashingMethod']; if ( $password_formatter->checkPassword($password, $user_info['Password'], $hashing_method) ) { if ( $hashing_method != PasswordHashingMethod::PHPPASS ) { $this->_fixUserPassword($user_info['PortalUserId'], $password); } return $user_info['PortalUserId']; } } } return false; } /** * Apply new password hashing to given user's password * * @param int $user_id * @param string $password * @return void * @access protected */ protected function _fixUserPassword($user_id, $password) { /** @var kPasswordFormatter $password_formatter */ $password_formatter = $this->Application->recallObject('kPasswordFormatter'); $fields_hash = Array ( 'Password' => $password_formatter->hashPassword($password), 'PasswordHashingMethod' => PasswordHashingMethod::PHPPASS, ); $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Users', 'PortalUserId = ' . $user_id); } /** * Process all required data and redirect logged-in user * * @param string $username * @param string $password * @return void */ protected function _processLoginRedirect($username = null, $password = null) { // set next template $next_template = $this->Application->GetVar('next_template'); if ( $next_template ) { $this->event->redirect = $next_template; } // process IIS redirect if ( $this->Application->ConfigValue('UseJSRedirect') ) { $this->event->SetRedirectParam('js_redirect', 1); } // synchronize login /** @var UsersSyncronizeManager $sync_manager */ $sync_manager = $this->Application->recallObject('UsersSyncronizeManager', null, Array (), Array ('InPortalSyncronize')); if ( isset($username) && isset($password) ) { $sync_manager->performAction('LoginUser', $username, $password); } else { $sync_manager->performAction('LogoutUser'); } } /** * Sets correct interface language after successful login, based on user settings * * @return void * @access protected */ protected function _processInterfaceLanguage() { if ( defined('IS_INSTALL') && IS_INSTALL ) { $this->event->SetRedirectParam('m_lang', 1); // data $this->Application->Session->SetField('Language', 1); // interface return; } $language_field = $this->Application->isAdmin ? 'AdminLanguage' : 'FrontLanguage'; $primary_language_field = $this->Application->isAdmin ? 'AdminInterfaceLang' : 'PrimaryLang'; $is_root = $this->Application->RecallVar('user_id') == USER_ROOT; $object =& $this->getUserObject(); $user_language_id = $is_root ? $this->Application->RecallPersistentVar($language_field) : $object->GetDBField($language_field); $sql = 'SELECT LanguageId, IF(LanguageId = ' . (int)$user_language_id . ', 2, ' . $primary_language_field . ') AS SortKey FROM ' . TABLE_PREFIX . 'Languages WHERE Enabled = 1 HAVING SortKey <> 0 ORDER BY SortKey DESC'; $language_info = $this->Conn->GetRow($sql); $language_id = $language_info && $language_info['LanguageId'] ? $language_info['LanguageId'] : $user_language_id; if ( $user_language_id != $language_id ) { // first login OR language was deleted or disabled if ( $is_root ) { $this->Application->StorePersistentVar($language_field, $language_id); } else { $object->SetDBField($language_field, $language_id); $object->Update(); } } // set language for Admin Console & Front-End with disabled Mod-Rewrite $this->event->SetRedirectParam('m_lang', $language_id); // data $this->Application->Session->SetField('Language', $language_id); // interface } /** * Injects redirect params into next template, which doesn't happen if next template starts with "external:" * * @return void * @access protected */ protected function _fixNextTemplate() { if ( !MOD_REWRITE || !is_object($this->event) ) { return; } // solve problem, when template is "true" instead of actual template name $template = is_string($this->event->redirect) ? $this->event->redirect : ''; $url = $this->Application->HREF($template, '', $this->event->getRedirectParams(), $this->event->redirectScript); $vars = $this->Application->parseRewriteUrl($url, 'pass'); unset($vars['login'], $vars['logout']); // merge back url params, because they were ignored if this was "external:" url $vars = array_merge($vars, $this->getRedirectParams($vars['pass'], 'pass')); if ( $template != 'index' ) { // The 'index.html' becomes '', which in turn leads to current page instead of 'index.html'. $template = $vars['t']; } unset($vars['is_virtual'], $vars['t']); $this->event->redirect = $template; $this->event->setRedirectParams($vars, false); } /** * Returns current event redirect params with given $prefixes injected into 'pass'. * * @param array $prefixes List of prefixes to inject. * @param string $pass_name Name of array key in redirect params, containing comma-separated prefixes list. * * @return string * @access protected */ protected function getRedirectParams($prefixes, $pass_name = 'passed') { $redirect_params = $this->event->getRedirectParams(); if ( isset($redirect_params[$pass_name]) ) { $redirect_prefixes = explode(',', $redirect_params[$pass_name]); $prefixes = array_unique(array_merge($prefixes, $redirect_prefixes)); } $redirect_params[$pass_name] = implode(',', $prefixes); return $redirect_params; } /** * Checks that user is allowed to use super admin mode * * @return bool */ function verifySuperAdmin() { $sa_mode = kUtil::ipMatch(defined('SA_IP') ? SA_IP : ''); return $sa_mode || $this->Application->isDebugMode(); } /** * Returns user object, used during login processing * * @return UsersItem * @access public */ public function &getUserObject() { $prefix_special = $this->Application->isAdmin ? 'u.current' : 'u'; // "u" used on front not to change theme /** @var UsersItem $object */ $object = $this->Application->recallObject($prefix_special, null, Array('skip_autoload' => true)); return $object; } /** * Checks, if given user fields matches at least one of defined ban rules * * @param kDBItem $object * @return bool */ function checkBanRules(&$object) { $table = $this->Application->getUnitConfig('ban-rule')->getTableName(); if (!$this->Conn->TableFound($table)) { // when ban table not found -> assume user is ok by default return true; } $sql = 'SELECT * FROM ' . $table . ' WHERE ItemType = 6 AND Status = ' . STATUS_ACTIVE . ' ORDER BY Priority DESC'; $rules = $this->Conn->Query($sql); $found = false; foreach ($rules as $rule) { $field = $rule['ItemField']; $this_value = mb_strtolower( $object->GetDBField($field) ); $test_value = mb_strtolower( $rule['ItemValue'] ); switch ( $rule['ItemVerb'] ) { case 1: // is if ($this_value == $test_value) { $found = true; } break; case 2: // is not if ($this_value != $test_value) { $found = true; } break; case 3: // contains if ( strstr($this_value, $test_value) ) { $found = true; } break; case 4: // not contains if ( !strstr($this_value, $test_value) ) { $found = true; } break; case 7: // exists if ( strlen($this_value) > 0 ) { $found = true; } break; case 8: // unique if ( $this->_checkValueExist($field, $this_value) ) { $found = true; } break; } if ( $found ) { // check ban rules, until one of them matches if ( $rule['RuleType'] ) { // invert rule type $found = false; } break; } } return !$found; } /** * Checks if value is unique in Users table against the specified field * * @param string $field * @param string $value * @return string */ function _checkValueExist($field, $value) { $sql = 'SELECT * FROM ' . $this->Application->getUnitConfig('u')->getTableName() . ' WHERE '. $field .' = ' . $this->Conn->qstr($value); return $this->Conn->GetOne($sql); } public function validateUserCode($user_code, $code_type, $expiration_timeout = null) { $expiration_timeouts = Array ( 'forgot_password' => 'config:Users_AllowReset', 'activation' => 'config:UserEmailActivationTimeout', 'verify_email' => 'config:Users_AllowReset', 'custom' => '', ); if ( !$user_code ) { return 'code_is_not_valid'; } $sql = 'SELECT PwRequestTime, PortalUserId FROM ' . TABLE_PREFIX . 'Users WHERE PwResetConfirm = ' . $this->Conn->qstr( trim($user_code) ); $user_info = $this->Conn->GetRow($sql); if ( $user_info === false ) { return 'code_is_not_valid'; } $expiration_timeout = isset($expiration_timeout) ? $expiration_timeout : $expiration_timeouts[$code_type]; if ( preg_match('/^config:(.*)$/', $expiration_timeout, $regs) ) { $expiration_timeout = $this->Application->ConfigValue( $regs[1] ); } if ( $expiration_timeout && $user_info['PwRequestTime'] < strtotime('-' . $expiration_timeout . ' minutes') ) { return 'code_expired'; } return $user_info['PortalUserId']; } /** * Restores user's email, returns error label, if error occurred * * @param string $hash * @return string * @access public */ public function restoreEmail($hash) { if ( !preg_match('/^[a-f0-9]{32}$/', $hash) ) { return 'invalid_hash'; } $sql = 'SELECT PortalUserId, PrevEmails FROM ' . TABLE_PREFIX . 'Users WHERE PrevEmails LIKE ' . $this->Conn->qstr('%' . $hash . '%'); $user_info = $this->Conn->GetRow($sql); if ( $user_info === false ) { return 'invalid_hash'; } $prev_emails = $user_info['PrevEmails']; $prev_emails = $prev_emails ? unserialize($prev_emails) : Array (); if ( !isset($prev_emails[$hash]) ) { return 'invalid_hash'; } $email_to_restore = $prev_emails[$hash]; unset($prev_emails[$hash]); /** @var UsersItem $object */ $object = $this->Application->recallObject('u.email-restore', null, Array ('skip_autoload' => true)); $object->Load($user_info['PortalUserId']); $object->SetDBField('PrevEmails', serialize($prev_emails)); $object->SetDBField('Email', $email_to_restore); $object->SetDBField('EmailVerified', 1); return $object->Update() ? '' : 'restore_impossible'; } /** * Generates random string * * @param int $length * @param bool $special_chars * @param bool $extra_special_chars * @return string * @access public */ public function generateRandomString($length = 12, $special_chars = true, $extra_special_chars = false) { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; if ( $special_chars ) { $chars .= '!@#$%^&*()'; } if ( $extra_special_chars ) { $chars .= '-_ []{}<>~`+=,.;:/?|'; } $password = ''; for ($i = 0; $i < $length; $i++) { $password .= substr($chars, $this->_generateRandomNumber(0, strlen($chars) - 1), 1); } return $password; } /** * Generates a random number * * @param int $min Lower limit for the generated number (optional, default is 0) * @param int $max Upper limit for the generated number (optional, default is 4294967295) * @return int A random number between min and max * @access protected */ protected function _generateRandomNumber($min = 0, $max = 0) { static $rnd_value = ''; // Reset $rnd_value after 14 uses // 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value if ( strlen($rnd_value) < 8 ) { $random_seed = $this->Application->getDBCache('random_seed'); $rnd_value = md5(uniqid(microtime() . mt_rand(), true) . $random_seed); $rnd_value .= sha1($rnd_value); $rnd_value .= sha1($rnd_value . $random_seed); $random_seed = md5($random_seed . $rnd_value); $this->Application->setDBCache('random_seed', $random_seed); } // Take the first 8 digits for our value $value = substr($rnd_value, 0, 8); // Strip the first eight, leaving the remainder for the next call to wp_rand(). $rnd_value = substr($rnd_value, 8); $value = abs(hexdec($value)); // Reduce the value to be within the min - max range // 4294967295 = 0xffffffff = max random number if ( $max != 0 ) { $value = $min + (($max - $min + 1) * ($value / (4294967295 + 1))); } return abs(intval($value)); } } \ No newline at end of file Index: branches/5.3.x/core/units/helpers/deployment_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/deployment_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/deployment_helper.php (revision 16600) @@ -1,764 +1,788 @@ _event = new kEvent('adm:OnDummy'); $this->isCommandLine = isset($GLOBALS['argv']) && count($GLOBALS['argv']); if ( !$this->isCommandLine ) { $this->ip = $this->Application->getClientIp(); } else { if ( isset($GLOBALS['argv'][3]) ) { $this->ip = $GLOBALS['argv'][3]; } if ( isset($GLOBALS['argv'][4]) ) { $new_stages = explode(',', $GLOBALS['argv'][4]); $unknown_stages = array_diff($new_stages, $this->stages); if ( $unknown_stages ) { throw new InvalidArgumentException('Unknown deployment stages: ' . implode(', ', $unknown_stages)); } $this->stages = $new_stages; } } } /** * Sets event, associated with deployment. * * @param kEvent $event Event. * * @return void */ public function setEvent(kEvent $event) { $this->_event = $event; } /** * Adds message to script execution log. * * @param string $message Message. * @param boolean $new_line Jump to next line. * * @return string */ private function toLog($message, $new_line = true) { if ( $new_line ) { $message .= PHP_EOL; } $this->logData['Output'] .= $message; return $message; } /** * Loads already applied revisions list of current module. * * @return self */ private function loadAppliedRevisions() { $sql = 'SELECT RevisionNumber FROM ' . TABLE_PREFIX . 'ModuleDeploymentLog WHERE Module = ' . $this->Conn->qstr($this->moduleName); $this->appliedRevisions = array_flip($this->Conn->GetCol($sql)); return $this; } /** * Deploys changes from all installed modules. * * @param boolean $dry_run Use dry run mode? * * @return boolean */ public function deployAll($dry_run = false) { if ( !$this->isCommandLine ) { echo '
' . PHP_EOL;
 		}
 
 		$ret = true;
 		$this->dryRun = $dry_run;
 
 		if ( in_array(self::STAGE_DB_MIGRATE, $this->stages) ) {
 			foreach ( $this->Application->ModuleInfo as $module_name => $module_info ) {
 				$this->moduleName = $module_name;
 
 				if ( !file_exists($this->getModuleFile('project_upgrades.sql')) ) {
 					continue;
 				}
 
 				$ret = $ret && $this->deploy($module_name);
 			}
 		}
 
 		if ( in_array(self::STAGE_CACHE_RESET, $this->stages) ) {
 			if ( $ret && !$this->dryRun ) {
 				$this->resetCaches();
 				$this->refreshThemes();
+				$this->dumpAssets();
 			}
 		}
 
 		if ( !$this->isCommandLine ) {
 			echo kUtil::escape($this->_runShellScript());
 			echo '
' . PHP_EOL; } return $ret; } /** * Runs user-specific shell script when deployment happens from Web. * * @return string */ protected function _runShellScript() { if ( !$this->Application->isDebugMode(false) ) { return ''; } $wrapper_script = '/usr/local/bin/guest2host_server.sh'; $script_name = FULL_PATH . '/tools/' . ($this->dryRun ? 'synchronize.sh' : 'deploy.sh'); if ( file_exists($wrapper_script) && file_exists($script_name) ) { $script_name = preg_replace('/^.*\/web/', constant('DBG_LOCAL_BASE_PATH'), $script_name); return shell_exec($wrapper_script . ' ' . $script_name . ' 2>&1'); } return ''; } /** * Deploys pending changes to a site. * * @param string $module_name Module name. * * @return boolean */ private function deploy($module_name) { echo $this->colorText('Deploying Module "' . $module_name . '":', 'cyan', true) . PHP_EOL; if ( !$this->upgradeDatabase() ) { return false; } try { if ( $this->dryRun ) { $this->exportLanguagePack(); } else { $this->importLanguagePack(); } } catch ( Exception $e ) { echo $this->colorText('Failed with Module "' . $module_name . '".', 'red', true) . PHP_EOL . PHP_EOL; return false; } echo $this->colorText('Done with Module "' . $module_name . '".', 'green', true) . PHP_EOL . PHP_EOL; return true; } /** * Import latest language pack (without overwrite). * * @return self */ private function importLanguagePack() { /** @var LanguageImportHelper $language_import_helper */ $language_import_helper = $this->Application->recallObject('LanguageImportHelper'); $this->out('Importing LanguagePack ... '); $filename = $this->getModuleFile('english.lang'); $language_import_helper->performImport($filename, '|0|1|2|', $this->moduleName); $this->displayStatus('OK'); return $this; } /** * Exports latest language pack. * * @return self */ private function exportLanguagePack() { static $languages = null; if ( !isset($languages) ) { $sql = 'SELECT LanguageId FROM ' . $this->Application->getUnitConfig('lang')->getTableName() . ' WHERE Enabled = 1'; $languages = $this->Conn->GetCol($sql); } /** @var LanguageImportHelper $language_import_helper */ $language_import_helper = $this->Application->recallObject('LanguageImportHelper'); - $language_import_helper->performExport(EXPORT_PATH . '/' . $this->moduleName . '.lang', '|0|1|2|', $languages, '|' . $this->moduleName . '|'); + $this->out('Exporting LanguagePack ... '); + $language_import_helper->performExport( + EXPORT_PATH . '/' . $this->moduleName . '.lang', + '|0|1|2|', + $languages, + '|' . $this->moduleName . '|' + ); + $this->displayStatus('OK'); return $this; } /** * Resets unit and section cache. * * @return self */ private function resetCaches() { // 2. reset unit config cache (so new classes get auto-registered) $this->out('Resetting Configs Files Cache and Parsed System Data ... '); $this->_event->CallSubEvent('OnResetConfigsCache'); $this->displayStatus('OK'); // 3. reset sections cache $this->out('Resetting Admin Console Sections ... '); $this->_event->CallSubEvent('OnResetSections'); $this->displayStatus('OK'); // 4. reset mod-rewrite cache $this->out('Resetting ModRewrite Cache ... '); $this->_event->CallSubEvent('OnResetModRwCache'); $this->displayStatus('OK'); return $this; } /** * Rebuild theme files. * * @return self */ private function refreshThemes() { $this->out('Refreshing Theme Files ... '); $this->_event->CallSubEvent('OnRebuildThemes'); $this->displayStatus('OK'); return $this; } /** + * Dumps assets + * + * @return void + */ + private function dumpAssets() + { + $this->out('Dumping Assets ... '); + $this->_event->CallSubEvent('OnDumpAssets'); + $this->displayStatus('OK'); + } + + /** * Runs database upgrade script. * * @return boolean */ private function upgradeDatabase() { $this->loadAppliedRevisions(); $this->Conn->setErrorHandler(array(&$this, 'handleSqlError')); $this->out('Verifying Database Revisions ... '); if ( !$this->collectDatabaseRevisions() || !$this->checkRevisionDependencies() ) { return false; } $this->displayStatus('OK'); return $this->applyRevisions(); } /** * Collects database revisions from "project_upgrades.sql" file. * * @return boolean */ private function collectDatabaseRevisions() { $filename = $this->getModuleFile('project_upgrades.sql'); if ( !file_exists($filename) ) { return true; } $sqls = file_get_contents($filename); preg_match_all("/# r([\d]+)([^\:]*):(.*?)(\n|$)/s", $sqls, $matches, PREG_SET_ORDER + PREG_OFFSET_CAPTURE); if ( !$matches ) { $this->displayStatus('FAILED' . PHP_EOL . 'No Database Revisions Found'); return false; } $revision_numbers = array(); foreach ( $matches as $index => $match ) { $revision = $match[1][0]; if ( in_array($revision, $revision_numbers) ) { $this->displayStatus('FAILED' . PHP_EOL . 'Duplicate revision #' . $revision . ' found'); return false; } $revision_numbers[] = $revision; if ( $this->revisionApplied($revision) ) { // Skip applied revisions. continue; } // Get revision sqls. $start_pos = $match[0][1] + strlen($match[0][0]); $end_pos = isset($matches[$index + 1]) ? $matches[$index + 1][0][1] : strlen($sqls); $revision_sqls = substr($sqls, $start_pos, $end_pos - $start_pos); if ( !$revision_sqls ) { // revision without sqls continue; } $this->revisionTitles[$revision] = trim($match[3][0]); $this->revisionSqls[$revision] = $revision_sqls; $revision_dependencies = $this->parseRevisionDependencies($match[2][0]); if ( $revision_dependencies ) { $this->revisionDependencies[$revision] = $revision_dependencies; } } ksort($this->revisionSqls); ksort($this->revisionDependencies); return true; } /** * Checks that all dependent revisions are either present now OR were applied before. * * @return boolean */ private function checkRevisionDependencies() { foreach ( $this->revisionDependencies as $revision => $revision_dependencies ) { foreach ( $revision_dependencies as $revision_dependency ) { if ( $this->revisionApplied($revision_dependency) ) { // revision dependent upon already applied -> dependency fulfilled continue; } if ( $revision_dependency >= $revision ) { $this->displayStatus('FAILED' . PHP_EOL . 'Revision #' . $revision . ' has incorrect dependency to revision #' . $revision_dependency . '. Only dependencies to older revisions are allowed!'); return false; } if ( !isset($this->revisionSqls[$revision_dependency]) ) { $this->displayStatus('FAILED' . PHP_EOL . 'Revision #' . $revision . ' depends on missing revision #' . $revision_dependency . '!'); return false; } } } return true; } /** * Runs all pending sqls. * * @return boolean */ private function applyRevisions() { if ( !$this->revisionSqls ) { return true; } if ( $this->dryRun ) { + $this->out('Simulating Database Upgrade ... ', true); + foreach ( $this->revisionSqls as $revision => $sqls ) { $this->initLog($revision, ModuleDeploymentLog::MODE_MANUAL); echo PHP_EOL . $this->colorText($this->revisionTitles[$revision], 'gray', true) . PHP_EOL; // 'Processing DB Revision: #' . $revision . ' ... '; echo $this->toLog($this->colorText('SKIPPING', 'purple')); $this->saveLog(ModuleDeploymentLog::STATUS_SKIPPED); } + echo PHP_EOL; + return true; } $this->out('Upgrading Database ... ', true); foreach ( $this->revisionSqls as $revision => $sqls ) { echo PHP_EOL . $this->colorText($this->revisionTitles[$revision], 'gray', true) . PHP_EOL; // 'Processing DB Revision: #' . $revision . ' ... '; $sqls = str_replace("\r\n", "\n", $sqls); // convert to linux line endings $no_comment_sqls = preg_replace("/#\s([^;]*?)\n/is", "# \\1;\n", $sqls); // add ";" to each comment end to ensure correct split $sqls = explode(";\n", $no_comment_sqls . "\n"); // ensures that last sql won't have ";" in it $sqls = array_map('trim', $sqls); $this->initLog($revision); try { foreach ( $sqls as $sql ) { if ( substr($sql, 0, 1) == '#' ) { // output comment as is echo $this->toLog($this->colorText($sql, 'purple')); continue; } elseif ( $sql ) { echo $this->toLog($this->shortenQuery($sql), false); $this->Conn->Query($sql); $this->displayStatus('OK (' . $this->Conn->getAffectedRows() . ')', true, true); } } } catch ( Exception $e ) { // consider revisions with errors applied $this->saveLog(ModuleDeploymentLog::STATUS_ERROR); return false; } $this->saveLog(ModuleDeploymentLog::STATUS_SUCCESS); } echo PHP_EOL; return true; } /** * Returns shortened version of SQL query. * * @param string $sql SQL query. * * @return string */ protected function shortenQuery($sql) { $escaped_sql = $this->isCommandLine ? $sql : kUtil::escape($sql); $single_line_sql = preg_replace('/(\n|\t| )+/is', ' ', $escaped_sql); return mb_substr(trim($single_line_sql), 0, self::SQL_TRIM_LENGTH) . ' ... '; } /** * Initializes log record for a revision. * * @param integer $revision Revision. * @param integer $mode Mode. * * @return self */ protected function initLog($revision, $mode = ModuleDeploymentLog::MODE_AUTOMATIC) { $this->logData = array( 'Module' => $this->moduleName, 'RevisionNumber' => $revision, 'RevisionTitle' => $this->revisionTitles[$revision], 'IPAddress' => $this->ip, 'Output' => '', 'Mode' => $mode, 'Status' => ModuleDeploymentLog::STATUS_SUCCESS, ); return $this; } /** * Creates log record. * * @param integer $status Status. * * @return self */ private function saveLog($status) { $this->logData['Status'] = $status; $log = $this->Application->recallObject('module-deployment-log', null, array('skip_autoload' => true)); /* @var $log kDBItem */ $log->Clear(); $log->SetFieldsFromHash($this->logData); $log->Create(); return $this; } /** * Error handler for sql errors. * * @param int $code Error code. * @param string $msg Error message. * @param string $sql SQL query, that raised an error. * * @return void * @throws Exception When SQL error happens. */ public function handleSqlError($code, $msg, $sql) { $this->displayStatus('FAILED', true, true); $error_msg = 'SQL Error #' . $code . ': ' . $msg; $this->logData['ErrorMessage'] = $error_msg; $this->displayStatus($error_msg); $this->out('Please execute rest of SQLs in this Revision by hand and run deployment script again.', true); throw new Exception($msg, $code); } /** * Checks if given revision was already applied. * * @param int $revision Revision. * * @return boolean */ private function revisionApplied($revision) { return isset($this->appliedRevisions[$revision]); } /** * Returns path to given file in current module install folder. * * @param string $filename Filename. * * @return string */ private function getModuleFile($filename) { $module_folder = $this->Application->findModule('Name', $this->moduleName, 'Path'); return FULL_PATH . DIRECTORY_SEPARATOR . $module_folder . 'install/' . $filename; } /** * Extracts revisions from string in format "(1,3,5464,23342,3243)". * * @param string $string Comma-separated revision list. * * @return array */ private function parseRevisionDependencies($string) { if ( !$string ) { return array(); } $string = explode(',', substr($string, 1, -1)); return array_map('trim', $string); } /** * Applies requested color and bold attributes to given text string. * * @param string $text Text. * @param string $color Color. * @param boolean $bold Bold flag. * * @return string */ private function colorText($text, $color, $bold = false) { if ( $this->isCommandLine ) { $color_map = array( 'black' => 30, // dark gray (in bold) 'blue' => 34, // light blue (in bold) 'green' => 32, // light green (in bold) 'cyan' => 36, // light cyan (in bold) 'red' => 31, // light red (in bold) 'purple' => 35, // light purple (in bold) 'brown' => 33, // yellow (in bold) 'gray' => 37, // white (in bold) ); return "\033[" . ($bold ? 1 : 0) . ";" . $color_map[$color] . "m" . $text . "\033[0m"; } $html_color_map = array( 'black' => array('normal' => '#000000', 'bold' => '#666666'), 'blue' => array('normal' => '#00009C', 'bold' => '#3C3CFF'), 'green' => array('normal' => '#009000', 'bold' => '#00FF00'), 'cyan' => array('normal' => '#009C9C', 'bold' => '#00FFFF'), 'red' => array('normal' => '#9C0000', 'bold' => '#FF0000'), 'purple' => array('normal' => '#900090', 'bold' => '#F99CF9'), 'brown' => array('normal' => '#C9C909', 'bold' => '#FFFF00'), 'gray' => array('normal' => '#909090', 'bold' => '#FFFFFF'), ); $html_color = $html_color_map[$color][$bold ? 'bold' : 'normal']; return '' . kUtil::escape($text, kUtil::ESCAPE_HTML) . ''; } /** * Displays last command execution status. * * @param string $status_text Status text. * @param boolean $new_line Jump to next line. * @param boolean $to_log Also write to log. * * @return self */ private function displayStatus($status_text, $new_line = true, $to_log = false) { $color = substr($status_text, 0, 2) == 'OK' ? 'green' : 'red'; $ret = $this->colorText($status_text, $color, false); if ( $to_log ) { echo $this->toLog($ret, $new_line); } else { echo $ret . ($new_line ? PHP_EOL : ''); } return $this; } /** * Outputs a text and escapes it if necessary. * * @param string $text Text. * @param boolean $new_line Jump to next line. * * @return self */ private function out($text, $new_line = false) { if ( !$this->isCommandLine ) { $text = kUtil::escape($text); } echo $text . ($new_line ? PHP_EOL : ''); return $this; } } Index: branches/5.3.x/core/units/helpers/image_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/image_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/image_helper.php (revision 16600) @@ -1,770 +1,800 @@ fileHelper = $this->Application->recallObject('FileHelper'); } /** * Parses format string into array * * @param string $format sample format: "resize:300x500;wm:inc/wm.png|c|-20" * @return Array sample result: Array('max_width' => 300, 'max_height' => 500, 'wm_filename' => 'inc/wm.png', 'h_margin' => 'c', 'v_margin' => -20) */ function parseFormat($format) { $res = Array (); $format_parts = explode(';', $format); foreach ($format_parts as $format_part) { if (preg_match('/^resize:(\d*)x(\d*)$/', $format_part, $regs)) { $res['max_width'] = $regs[1]; $res['max_height'] = $regs[2]; } elseif (preg_match('/^wm:([^\|]*)\|([^\|]*)\|([^\|]*)$/', $format_part, $regs)) { $res['wm_filename'] = FULL_PATH.THEMES_PATH.'/'.$regs[1]; $res['h_margin'] = strtolower($regs[2]); $res['v_margin'] = strtolower($regs[3]); } elseif (preg_match('/^crop:([^\|]*)\|([^\|]*)$/', $format_part, $regs)) { $res['crop_x'] = strtolower($regs[1]); $res['crop_y'] = strtolower($regs[2]); } elseif ($format_part == 'img_size' || $format_part == 'img_sizes') { $res['image_size'] = true; } elseif (preg_match('/^fill:(.*)$/', $format_part, $regs)) { $res['fill'] = $regs[1]; } elseif ( preg_match('/^default:(.*)$/', $format_part, $regs) ) { $default_image = FULL_PATH . THEMES_PATH . '/' . $regs[1]; if ( strpos($default_image, '../') !== false ) { $default_image = realpath($default_image); } $res['default'] = $default_image; } elseif ( preg_match('/^filter:(.*)$/', $format_part, $regs) ) { $format_part_params = explode('|', $regs[1]); $res['filter_type'] = array_shift($format_part_params); $res['filter_params'] = $format_part_params; } } return $res; } /** * Resized given image to required dimensions & saves resized image to "resized" subfolder in source image folder * * @param string $src_image full path to image (on server) * @param mixed $max_width maximal allowed resized image width or false if no limit * @param mixed $max_height maximal allowed resized image height or false if no limit * * @return string direct url to resized image * @throws RuntimeException When image doesn't exist. */ function ResizeImage($src_image, $max_width, $max_height = false) { $image_size = false; if (is_numeric($max_width)) { $params['max_width'] = $max_width; $params['max_height'] = $max_height; } else { $params = $this->parseFormat($max_width); if (array_key_exists('image_size', $params)) { // image_size param shouldn't affect resized file name (crc part) $image_size = $params['image_size']; unset($params['image_size']); } } if ((!$src_image || !file_exists($src_image)) && array_key_exists('default', $params) && !(defined('DBG_IMAGE_RECOVERY') && DBG_IMAGE_RECOVERY)) { $src_image = $params['default']; } if ( !strlen($src_image) || !file_exists($src_image) ) { throw new RuntimeException(sprintf('Image "%s" doesn\'t exist', $src_image)); } - if ($params['max_width'] > 0 || $params['max_height'] > 0) { + if ( !$this->isSVG($src_image) && ($params['max_width'] > 0 || $params['max_height'] > 0) ) { list ($params['target_width'], $params['target_height'], $needs_resize) = $this->GetImageDimensions($src_image, $params['max_width'], $params['max_height'], $params); if (!is_numeric($params['max_width'])) { $params['max_width'] = $params['target_width']; } if (!is_numeric($params['max_height'])) { $params['max_height'] = $params['target_height']; } + // Optimize, because when cropping from center without resize we'll get same image back. + if ( !$needs_resize + && isset($params['crop_x']) + && $params['crop_x'] == 'c' + && $params['crop_y'] == 'c' + ) { + unset($params['crop_x'], $params['crop_y'], $params['fill']); + } + $src_path = dirname($src_image); $transform_keys = Array ('crop_x', 'crop_y', 'fill', 'wm_filename', 'filter_type'); // Resize required OR watermarking required -> change resulting image name ! if ( $needs_resize || array_intersect(array_keys($params), $transform_keys) ) { // Escape replacement patterns, like "\". $src_path_escaped = preg_replace('/(\\\[\d]+)/', '\\\\\1', $src_path); ksort($params); $params_hash = kUtil::crc32(serialize($this->fileHelper->makeRelative($params))); $dst_image = preg_replace( '/^' . preg_quote($src_path, '/') . '(.*)\.(.*)$/', $src_path_escaped . '\\1_' . $params_hash . '.\\2', $src_image ); // Keep resized version of all images under "/system/thumbs/" folder. $dst_image = preg_replace('/^' . preg_quote(FULL_PATH, '/') . '/', '', $dst_image, 1); $dst_image = FULL_PATH . THUMBS_PATH . $dst_image; $this->fileHelper->CheckFolder( dirname($dst_image) ); if (!file_exists($dst_image) || filemtime($src_image) > filemtime($dst_image)) { // resized image not available OR should be recreated due source image change $params['dst_image'] = $dst_image; $image_resized = $this->ScaleImage($src_image, $params); if (!$image_resized) { // resize failed, because of server error $dst_image = $src_image; } } // resize/watermarking ok $src_image = $dst_image; } } - if ($image_size) { - // return only image size (resized or not) + if ( $image_size ) { + if ( $this->isSVG($src_image) ) { + return 'width="' . $params['max_width'] . '" height="' . $params['max_height'] . '"'; + } + + // Return only image size (resized or not). $image_info = $this->getImageInfo($src_image); return $image_info ? $image_info[3] : ''; } return $this->fileHelper->pathToUrl($src_image); } /** * Proportionally resizes given image to destination dimensions * * @param string $src_image full path to source image (already existing) * @param Array $params * @return bool */ function ScaleImage($src_image, $params) { $image_info = $this->getImageInfo($src_image); if (!$image_info) { return false; } /*list ($params['max_width'], $params['max_height'], $resized) = $this->GetImageDimensions($src_image, $params['max_width'], $params['max_height'], $params); if (!$resized) { // image dimensions are smaller or equals to required dimensions return false; }*/ if (!$this->Application->ConfigValue('ForceImageMagickResize') && function_exists('imagecreatefromjpeg')) { // try to resize using GD $resize_map = Array ( 'image/jpeg' => 'imagecreatefromjpeg:imagejpeg:jpg', 'image/gif' => 'imagecreatefromgif:imagegif:gif', 'image/png' => 'imagecreatefrompng:imagepng:png', 'image/bmp' => 'imagecreatefrombmp:imagejpeg:bmp', 'image/x-ms-bmp' => 'imagecreatefrombmp:imagejpeg:bmp', ); $mime_type = $image_info['mime']; if (!isset($resize_map[$mime_type])) { return false; } list ($read_function, $write_function, $file_extension) = explode(':', $resize_map[$mime_type]); // when source image has large dimensions (over 1MB filesize), then 16M is not enough kUtil::setResourceLimit(); $src_image_rs = @$read_function($src_image); if ($src_image_rs) { $dst_image_rs = imagecreatetruecolor($params['target_width'], $params['target_height']); // resize target size $preserve_transparency = ($file_extension == 'gif') || ($file_extension == 'png'); if ($preserve_transparency) { // preserve transparency of PNG and GIF images $dst_image_rs = $this->_preserveTransparency($src_image_rs, $dst_image_rs, $image_info[2]); } // 1. resize imagecopyresampled($dst_image_rs, $src_image_rs, 0, 0, 0, 0, $params['target_width'], $params['target_height'], $image_info[0], $image_info[1]); $watermark_size = 'target'; if (array_key_exists('crop_x', $params) || array_key_exists('crop_y', $params)) { // 2.1. crop image to given size $dst_image_rs =& $this->_cropImage($dst_image_rs, $params, $preserve_transparency ? $image_info[2] : false); $watermark_size = 'max'; } elseif (array_key_exists('fill', $params)) { // 2.2. fill image margins from resize with given color $dst_image_rs =& $this->_applyFill($dst_image_rs, $params, $preserve_transparency ? $image_info[2] : false); $watermark_size = 'max'; } // 3. apply watermark $dst_image_rs =& $this->_applyWatermark($dst_image_rs, $params[$watermark_size . '_width'], $params[$watermark_size . '_height'], $params); if ($write_function == 'imagegif') { return @$write_function($dst_image_rs, $params['dst_image']); } // 4. apply filter $this->applyFilter($dst_image_rs, $params); return @$write_function($dst_image_rs, $params['dst_image'], $write_function == 'imagepng' ? 0 : 100); } } else { // try to resize using ImageMagick // TODO: implement crop and watermarking using imagemagick exec('/usr/bin/convert '.$src_image.' -resize '.$params['target_width'].'x'.$params['target_height'].' '.$params['dst_image'], $shell_output, $exec_status); return $exec_status == 0; } return false; } /** * Preserve transparency for GIF and PNG images * * @param resource $src_image_rs * @param resource $dst_image_rs * @param int $image_type * @return resource */ function _preserveTransparency($src_image_rs, $dst_image_rs, $image_type) { $transparent_index = imagecolortransparent($src_image_rs); // if we have a specific transparent color if ( $transparent_index >= 0 && $transparent_index < imagecolorstotal($src_image_rs) ) { // get the original image's transparent color's RGB values $transparent_color = imagecolorsforindex($src_image_rs, $transparent_index); // allocate the same color in the new image resource $transparent_index = imagecolorallocate($dst_image_rs, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); // completely fill the background of the new image with allocated color imagefill($dst_image_rs, 0, 0, $transparent_index); // set the background color for new image to transparent imagecolortransparent($dst_image_rs, $transparent_index); return $dst_image_rs; } // always make a transparent background color for PNGs that don't have one allocated already if ( $image_type == IMAGETYPE_PNG ) { // turn off transparency blending (temporarily) imagealphablending($dst_image_rs, false); // create a new transparent color for image $transparent_color = imagecolorallocatealpha($dst_image_rs, 0, 0, 0, 127); // completely fill the background of the new image with allocated color imagefill($dst_image_rs, 0, 0, $transparent_color); // restore transparency blending imagesavealpha($dst_image_rs, true); } return $dst_image_rs; } /** * Fills margins (if any) of resized are with given color * * @param resource $src_image_rs resized image resource * @param Array $params crop parameters * @param int|bool $image_type * @return resource */ function &_applyFill(&$src_image_rs, $params, $image_type = false) { $x_position = round(($params['max_width'] - $params['target_width']) / 2); // center $y_position = round(($params['max_height'] - $params['target_height']) / 2); // center // crop resized image $fill_image_rs = imagecreatetruecolor($params['max_width'], $params['max_height']); if ($image_type !== false) { $fill_image_rs = $this->_preserveTransparency($src_image_rs, $fill_image_rs, $image_type); } $fill = $params['fill']; if (substr($fill, 0, 1) == '#') { // hexdecimal color $color = imagecolorallocate($fill_image_rs, hexdec( substr($fill, 1, 2) ), hexdec( substr($fill, 3, 2) ), hexdec( substr($fill, 5, 2) )); } else { // for now we don't support color names, but we will in future return $src_image_rs; } imagefill($fill_image_rs, 0, 0, $color); imagecopy($fill_image_rs, $src_image_rs, $x_position, $y_position, 0, 0, $params['target_width'], $params['target_height']); return $fill_image_rs; } /** * Crop given image resource using given params and return resulting image resource * * @param resource $src_image_rs resized image resource * @param Array $params crop parameters * @param int|bool $image_type * @return resource */ function &_cropImage(&$src_image_rs, $params, $image_type = false) { if ($params['crop_x'] == 'c') { $x_position = round(($params['max_width'] - $params['target_width']) / 2); // center } elseif ($params['crop_x'] >= 0) { $x_position = $params['crop_x']; // margin from left } else { $x_position = $params['target_width'] - ($params['max_width'] - $params['crop_x']); // margin from right } if ($params['crop_y'] == 'c') { $y_position = round(($params['max_height'] - $params['target_height']) / 2); // center } elseif ($params['crop_y'] >= 0) { $y_position = $params['crop_y']; // margin from top } else { $y_position = $params['target_height'] - ($params['max_height'] - $params['crop_y']); // margin from bottom } // crop resized image $crop_image_rs = imagecreatetruecolor($params['max_width'], $params['max_height']); if ($image_type !== false) { $crop_image_rs = $this->_preserveTransparency($src_image_rs, $crop_image_rs, $image_type); } if (array_key_exists('fill', $params)) { // fill image margins from resize with given color $crop_image_rs =& $this->_applyFill($crop_image_rs, $params, $image_type); } imagecopy($crop_image_rs, $src_image_rs, $x_position, $y_position, 0, 0, $params['target_width'], $params['target_height']); return $crop_image_rs; } /** * Apply watermark (transparent PNG image) to given resized image resource * * @param resource $src_image_rs * @param int $max_width * @param int $max_height * @param Array $params * @return resource */ function &_applyWatermark(&$src_image_rs, $max_width, $max_height, $params) { $watermark_file = array_key_exists('wm_filename', $params) ? $params['wm_filename'] : false; if (!$watermark_file || !file_exists($watermark_file)) { // no watermark required, or provided watermark image is missing return $src_image_rs; } $watermark_img_rs = imagecreatefrompng($watermark_file); list ($watermark_width, $watermark_height) = $this->getImageInfo($watermark_file); imagealphablending($src_image_rs, true); if ($params['h_margin'] == 'c') { $x_position = round($max_width / 2 - $watermark_width / 2); // center } elseif ($params['h_margin'] >= 0) { $x_position = $params['h_margin']; // margin from left } else { $x_position = $max_width - ($watermark_width - $params['h_margin']); // margin from right } if ($params['v_margin'] == 'c') { $y_position = round($max_height / 2 - $watermark_height / 2); // center } elseif ($params['v_margin'] >= 0) { $y_position = $params['v_margin']; // margin from top } else { $y_position = $max_height - ($watermark_height - $params['v_margin']); // margin from bottom } imagecopy($src_image_rs, $watermark_img_rs, $x_position, $y_position, 0, 0, $watermark_width, $watermark_height); return $src_image_rs; } /** * Applies filter to an image. * * @param resource $src_image_rs Source image. * @param array $params Parameters. * * @return boolean * @access protected * @throws InvalidArgumentException When unknown filter type given. * @link http://php.net/manual/en/function.imagefilter.php */ protected function applyFilter(&$src_image_rs, array $params) { if ( !array_key_exists('filter_type', $params) ) { return true; } $filter_type = strtoupper($params['filter_type']); $filter_params = (array)$params['filter_params']; if ( !defined('IMG_FILTER_' . $filter_type) ) { throw new InvalidArgumentException(sprintf('Unknown filter type "%s"', $filter_type)); } array_unshift($filter_params, constant('IMG_FILTER_' . $filter_type)); array_unshift($filter_params, $src_image_rs); return call_user_func_array('imagefilter', $filter_params); } /** * Returns destination image size without actual resizing (useful for HTML tag) * * @param string $src_image full path to source image (already existing) * @param int $dst_width destination image width (in pixels) * @param int $dst_height destination image height (in pixels) * @param Array $params * @return Array resized image dimensions (0 - width, 1 - height) */ function GetImageDimensions($src_image, $dst_width, $dst_height, $params) { + // The SVG file is in vector format and can scale to any size. + if ( $this->isSVG($src_image) ) { + return array($dst_width, $dst_height, false); + } + $image_info = $this->getImageInfo($src_image); if (!$image_info) { return false; } $orig_width = $image_info[0]; $orig_height = $image_info[1]; $too_large = is_numeric($dst_width) ? ($orig_width > $dst_width) : false; $too_large = $too_large || (is_numeric($dst_height) ? ($orig_height > $dst_height) : false); if ($too_large) { $width_ratio = $dst_width ? $dst_width / $orig_width : 1; $height_ratio = $dst_height ? $dst_height / $orig_height : 1; if (array_key_exists('crop_x', $params) || array_key_exists('crop_y', $params)) { // resize by smallest inverted radio $resize_by = $this->_getCropImageMinRatio($image_info, $dst_width, $dst_height); if ($resize_by === false) { return Array ($orig_width, $orig_height, false); } $ratio = $resize_by == 'width' ? $width_ratio : $height_ratio; } else { $ratio = min($width_ratio, $height_ratio); } $width = ceil($orig_width * $ratio); $height = ceil($orig_height * $ratio); } else { $width = $orig_width; $height = $orig_height; } return Array ($width, $height, $too_large); } /** * Returns ratio type with smaller relation of original size to target size * * @param Array $image_info image information from "ImageHelper::getImageInfo" * @param int $dst_width destination image width (in pixels) * @param int $dst_height destination image height (in pixels) * @return Array */ function _getCropImageMinRatio($image_info, $dst_width, $dst_height) { $width_ratio = $dst_width ? $image_info[0] / $dst_width : 1; $height_ratio = $dst_height ? $image_info[1] / $dst_height : 1; $minimal_ratio = min($width_ratio, $height_ratio); if ($minimal_ratio < 1) { // ratio is less then 1, image will be enlarged -> don't allow that return false; } return $width_ratio < $height_ratio ? 'width' : 'height'; } /** * Returns image dimensions + checks if given file is existing image * * @param string $src_image full path to source image (already existing) * @return mixed */ function getImageInfo($src_image) { - if (!file_exists($src_image)) { + if ( !file_exists($src_image) || $this->isSVG($src_image) ) { return false; } $image_info = @getimagesize($src_image); if (!$image_info) { trigger_error('Image '.$src_image.' missing or invalid', E_USER_WARNING); return false; } return $image_info; } /** + * Checks if image is an SVG file. + * + * @param string $src_image Full path to source image (already existing). + * + * @return boolean + */ + protected function isSVG($src_image) + { + return pathinfo($src_image, PATHINFO_EXTENSION) == 'svg'; + } + + /** * Returns maximal image size (width & height) among fields specified * * @param kDBItem $object * @param string $fields * @param string $format any format, that returns full url (e.g. files_resized:WxH, resize:WxH, full_url, full_urls) * @return string */ function MaxImageSize(&$object, $fields, $format = null) { static $cached_sizes = Array (); $cache_key = $object->getPrefixSpecial().'_'.$object->GetID(); if (!isset($cached_sizes[$cache_key])) { $images = Array (); $fields = explode(',', $fields); foreach ($fields as $field) { $image_data = $object->GetField($field, $format); if (!$image_data) { continue; } $images = array_merge($images, explode('|', $image_data)); } $max_width = 0; $max_height = 0; $base_url = rtrim($this->Application->BaseURL(), '/'); foreach ($images as $image_url) { $image_path = preg_replace('/^'.preg_quote($base_url, '/').'(.*)/', FULL_PATH.'\\1', $image_url); $image_info = $this->getImageInfo($image_path); $max_width = max($max_width, $image_info[0]); $max_height = max($max_height, $image_info[1]); } $cached_sizes[$cache_key] = Array ($max_width, $max_height); } return $cached_sizes[$cache_key]; } /** * Puts existing item images (from sub-item) to virtual fields (in main item) * * @param kCatDBItem|kDBItem $object */ function LoadItemImages(&$object) { if (!$this->_canUseImages($object)) { return ; } $max_image_count = $this->Application->ConfigValue($object->Prefix.'_MaxImageCount'); $sql = 'SELECT * FROM '.TABLE_PREFIX.'CatalogImages WHERE ResourceId = '.$object->GetDBField('ResourceId').' ORDER BY Priority DESC LIMIT 0, ' . (int)$max_image_count; $item_images = $this->Conn->Query($sql); $image_counter = 1; foreach ($item_images as $item_image) { $image_path = $item_image['ThumbPath']; if ($item_image['DefaultImg'] == 1 || $item_image['Name'] == 'main') { // process primary image separately if ( $object->isField('PrimaryImage') ) { $object->SetDBField('PrimaryImage', $image_path); $object->SetOriginalField('PrimaryImage', $image_path); $object->SetFieldOption('PrimaryImage', 'original_field', $item_image['Name']); $this->_loadCustomFields($object, $item_image, 0); } continue; } if (abs($item_image['Priority'])) { // use Priority as image counter, when specified $image_counter = abs($item_image['Priority']); } if ( $object->isField('Image'.$image_counter) ) { $object->SetDBField('Image'.$image_counter, $image_path); $object->SetOriginalField('Image'.$image_counter, $image_path); $object->SetFieldOption('Image'.$image_counter, 'original_field', $item_image['Name']); $this->_loadCustomFields($object, $item_image, $image_counter); } $image_counter++; } } /** * Saves newly uploaded images to external image table * * @param kCatDBItem|kDBItem $object */ function SaveItemImages(&$object) { if (!$this->_canUseImages($object)) { return ; } $table_name = $this->Application->getUnitConfig('img')->getTableName(); $max_image_count = $object->getUnitConfig()->getImageCount(); // $this->Application->ConfigValue($object->Prefix.'_MaxImageCount'); $i = 0; while ($i < $max_image_count) { $field = $i ? 'Image'.$i : 'PrimaryImage'; $field_options = $object->GetFieldOptions($field); $image_src = $object->GetDBField($field); if ($image_src) { if (isset($field_options['original_field'])) { $key_clause = 'Name = '.$this->Conn->qstr($field_options['original_field']).' AND ResourceId = '.$object->GetDBField('ResourceId'); if ($object->GetDBField('Delete'.$field)) { // if item was cloned, then new filename is in db (not in $image_src) $sql = 'SELECT ThumbPath FROM '.$table_name.' WHERE '.$key_clause; $image_src = $this->Conn->GetOne($sql); if (@unlink(FULL_PATH.$image_src)) { $sql = 'DELETE FROM '.$table_name.' WHERE '.$key_clause; $this->Conn->Query($sql); } } else { // image record found -> update $fields_hash = Array ( 'ThumbPath' => $image_src, ); $this->_saveCustomFields($object, $fields_hash, $i); $this->Conn->doUpdate($fields_hash, $table_name, $key_clause); } } else { // image record not found -> create $fields_hash = Array ( 'ResourceId' => $object->GetDBField('ResourceId'), 'Name' => $field, 'AltName' => $field, 'Enabled' => STATUS_ACTIVE, 'DefaultImg' => $i ? 0 : 1, // first image is primary, others not primary 'ThumbPath' => $image_src, 'Priority' => ($i == 0)? 0 : $i * (-1), ); $this->_saveCustomFields($object, $fields_hash, $i); $this->Conn->doInsert($fields_hash, $table_name); $field_options['original_field'] = $field; $object->SetFieldOptions($field, $field_options); } } $i++; } } /** * Adds ability to load custom fields along with main image field * * @param kCatDBItem|kDBItem $object * @param Array $fields_hash * @param int $counter 0 - primary image, other number - additional image number */ function _loadCustomFields(&$object, $fields_hash, $counter) { $field_name = $counter ? 'Image' . $counter . 'Alt' : 'PrimaryImageAlt'; $object->SetDBField($field_name, (string)$fields_hash['AltName']); } /** * Adds ability to save custom field along with main image save * * @param kCatDBItem|kDBItem $object * @param Array $fields_hash * @param int $counter 0 - primary image, other number - additional image number */ function _saveCustomFields(&$object, &$fields_hash, $counter) { $field_name = $counter ? 'Image' . $counter . 'Alt' : 'PrimaryImageAlt'; $fields_hash['AltName'] = (string)$object->GetDBField($field_name); } /** * Checks, that item can use image upload capabilities * * @param kCatDBItem|kDBItem $object * @return bool */ function _canUseImages(&$object) { $prefix = $object->Prefix == 'p' ? 'img' : $object->Prefix . '-img'; return $this->Application->prefixRegistred($prefix); } } Index: branches/5.3.x/core/units/helpers/upload_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/upload_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/upload_helper.php (revision 16600) @@ -1,335 +1,361 @@ fileHelper = $this->Application->recallObject('FileHelper'); + // 5 minutes execution time @set_time_limit(5 * 60); } /** * Handles the upload. * * @param kEvent $event Event. * * @return string * @throws kUploaderException When upload could not be handled properly. */ public function handle(kEvent $event) { $this->disableBrowserCache(); // Uncomment this one to fake upload time // sleep(5); if ( !$this->Application->HttpQuery->Post ) { // Variables {field, id, flashsid} are always submitted through POST! // When file size is larger, then "upload_max_filesize" (in php.ini), // then these variables also are not submitted. throw new kUploaderException('File size exceeds allowed limit.', 413); } if ( !$this->checkPermissions($event) ) { // 403 Forbidden throw new kUploaderException('You don\'t have permissions to upload.', 403); } $value = $this->Application->GetVar('file'); if ( !$value || ($value['error'] != UPLOAD_ERR_OK) ) { // 413 Request Entity Too Large (file uploads disabled OR uploaded file was // too large for web server to accept, see "upload_max_filesize" in php.ini) throw new kUploaderException('File size exceeds allowed limit.', 413); } $value = $this->Application->unescapeRequestVariable($value); $tmp_path = WRITEABLE . '/tmp/'; $filename = $this->getUploadedFilename() . '.tmp'; $id = $this->Application->GetVar('id'); if ( $id ) { $filename = $id . '_' . $filename; } if ( !is_writable($tmp_path) ) { // 500 Internal Server Error // check both temp and live upload directory throw new kUploaderException('Write permissions not set on the server, please contact server administrator.', 500); } - /** @var FileHelper $file_helper */ - $file_helper = $this->Application->recallObject('FileHelper'); - $filename = $file_helper->ensureUniqueFilename($tmp_path, $filename); + $filename = $this->fileHelper->ensureUniqueFilename($tmp_path, $filename); $storage_format = $this->getStorageFormat($this->Application->GetVar('field'), $event); + $this->moveUploadedFile($tmp_path . $filename); if ( $storage_format ) { - /** @var ImageHelper $image_helper */ - $image_helper = $this->Application->recallObject('ImageHelper'); - - $this->moveUploadedFile($value['tmp_name'] . '.jpg'); // add extension, so ResizeImage can work - $url = $image_helper->ResizeImage($value['tmp_name'] . '.jpg', $storage_format); - $tmp_name = preg_replace('/^' . preg_quote($this->Application->BaseURL(), '/') . '/', '/', $url); - rename($tmp_name, $tmp_path . $filename); - } - else { - $this->moveUploadedFile($tmp_path . $filename); + $this->resizeUploadedFile($tmp_path . $filename, $storage_format); } $this->deleteTempFiles($tmp_path); $thumbs_path = preg_replace('/^' . preg_quote(FULL_PATH, '/') . '/', '', $tmp_path, 1); $thumbs_path = FULL_PATH . THUMBS_PATH . $thumbs_path; if ( file_exists($thumbs_path) ) { $this->deleteTempFiles($thumbs_path); } return preg_replace('/^' . preg_quote($id, '/') . '_/', '', $filename); } /** + * Resizes uploaded file. + * + * @param string $file_path File path. + * @param string $format Format. + * + * @return boolean + */ + public function resizeUploadedFile($file_path, $format) + { + /** @var ImageHelper $image_helper */ + $image_helper = $this->Application->recallObject('ImageHelper'); + + // Add extension, so that "ImageHelper::ResizeImage" can work. + $resize_file_path = tempnam(sys_get_temp_dir(), 'uploaded_') . '.jpg'; + + if ( rename($file_path, $resize_file_path) === false ) { + return false; + } + + $resized_file_path = $this->fileHelper->urlToPath( + $image_helper->ResizeImage($resize_file_path, $format) + ); + + return rename($resized_file_path, $file_path); + } + + /** * Sends headers to ensure, that response is never cached. * * @return void */ protected function disableBrowserCache() { header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Cache-Control: post-check=0, pre-check=0', false); header('Pragma: no-cache'); } /** * Checks, that flash uploader is allowed to perform upload * * @param kEvent $event * @return bool */ protected function checkPermissions(kEvent $event) { // Flash uploader does NOT send correct cookies, so we need to make our own check $cookie_name = 'adm_' . $this->Application->ConfigValue('SessionCookieName'); $this->Application->HttpQuery->Cookie['cookies_on'] = 1; $this->Application->HttpQuery->Cookie[$cookie_name] = $this->Application->GetVar('flashsid'); // this prevents session from auto-expiring when KeepSessionOnBrowserClose & FireFox is used $this->Application->HttpQuery->Cookie[$cookie_name . '_live'] = $this->Application->GetVar('flashsid'); /** @var Session $admin_session */ $admin_session = $this->Application->recallObject('Session.admin'); - if ( $admin_session->RecallVar('user_id') == USER_ROOT ) { + if ( $this->Application->permissionCheckingDisabled($admin_session->RecallVar('user_id')) ) { return true; } // copy some data from given session to current session $backup_user_id = $this->Application->RecallVar('user_id'); $this->Application->StoreVar('user_id', $admin_session->RecallVar('user_id')); $backup_user_groups = $this->Application->RecallVar('UserGroups'); $this->Application->StoreVar('UserGroups', $admin_session->RecallVar('UserGroups')); // check permissions using event, that have "add|edit" rule $check_event = new kEvent($event->getPrefixSpecial() . ':OnProcessSelected'); $check_event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true)); /** @var kEventHandler $event_handler */ $event_handler = $this->Application->recallObject($event->Prefix . '_EventHandler'); $allowed_to_upload = $event_handler->CheckPermission($check_event); // restore changed data, so nothing gets saved to database $this->Application->StoreVar('user_id', $backup_user_id); $this->Application->StoreVar('UserGroups', $backup_user_groups); return $allowed_to_upload; } /** * Returns uploaded filename. * * @return string */ protected function getUploadedFilename() { if ( isset($_REQUEST['name']) ) { $file_name = $_REQUEST['name']; } elseif ( !empty($_FILES) ) { $file_name = $_FILES['file']['name']; } else { $file_name = uniqid('file_'); } return $file_name; } /** * Gets storage format for a given field. * * @param string $field_name * @param kEvent $event * @return bool */ protected function getStorageFormat($field_name, kEvent $event) { $config = $event->getUnitConfig(); $field_options = $config->getFieldByName($field_name); if ( !$field_options ) { $field_options = $config->getVirtualFieldByName($field_name); } return isset($field_options['storage_format']) ? $field_options['storage_format'] : false; } /** * Moves uploaded file to given location. * * @param string $file_path File path. * * @return void * @throws kUploaderException When upload could not be handled properly. */ protected function moveUploadedFile($file_path) { // Chunking might be enabled $chunk = (int)$this->Application->GetVar('chunk', 0); $chunks = (int)$this->Application->GetVar('chunks', 0); // Open temp file if ( !$out = @fopen("{$file_path}.part", $chunks ? 'ab' : 'wb') ) { throw new kUploaderException('Failed to open output stream.', 102); } if ( !empty($_FILES) ) { if ( $_FILES['file']['error'] || !is_uploaded_file($_FILES['file']['tmp_name']) ) { throw new kUploaderException('Failed to move uploaded file.', 103); } // Read binary input stream and append it to temp file if ( !$in = @fopen($_FILES['file']['tmp_name'], 'rb') ) { throw new kUploaderException('Failed to open input stream.', 101); } } else { if ( !$in = @fopen('php://input', 'rb') ) { throw new kUploaderException('Failed to open input stream.', 101); } } while ( $buff = fread($in, 4096) ) { fwrite($out, $buff); } @fclose($out); @fclose($in); // Check if file has been uploaded if ( !$chunks || $chunk == $chunks - 1 ) { // Strip the temp .part suffix off rename("{$file_path}.part", $file_path); } } /** * Delete temporary files, that won't be used for sure * * @param string $path * @return void */ protected function deleteTempFiles($path) { $files = glob($path . '*.*'); $max_file_date = strtotime('-1 day'); foreach ( $files as $file ) { if ( filemtime($file) < $max_file_date ) { unlink($file); } } } /** * Prepares object for operations with file on given field. * * @param kEvent $event Event. * @param string $field Field. * * @return kDBItem */ public function prepareUploadedFile(kEvent $event, $field) { /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $filename = $this->getSafeFilename(); if ( !$filename ) { $object->SetDBField($field, ''); return $object; } // set current uploaded file if ( $this->Application->GetVar('tmp') ) { $options = $object->GetFieldOptions($field); $options['upload_dir'] = WRITEBALE_BASE . '/tmp/'; unset($options['include_path']); $object->SetFieldOptions($field, $options); $filename = $this->Application->GetVar('id') . '_' . $filename; } $object->SetDBField($field, $filename); return $object; } /** * Returns safe version of filename specified in url * * @return bool|string * @access protected */ protected function getSafeFilename() { $filename = $this->Application->GetVar('file'); $filename = $this->Application->unescapeRequestVariable($filename); if ( (strpos($filename, '../') !== false) || (trim($filename) !== $filename) ) { // when relative paths or special chars are found template names from url, then it's hacking attempt return false; } return $filename; } } class kUploaderException extends Exception { } Index: branches/5.3.x/core/units/helpers/csv_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/csv_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/csv_helper.php (revision 16600) @@ -1,409 +1,432 @@ "\t", 1 => ',', 2 => ';', 3 => ' ', 4 => ':'); var $enclosure_mapping = Array(0 => '"', 1 => "'"); var $separator_mapping = Array(0 => "\n", 1 => "\r\n"); function ExportStep() { $export_data = $this->Application->RecallVar('export_data'); $export_rand = $this->Application->RecallVar('export_rand'); $get_rand = $this->Application->GetVar('export_rand'); /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); if ( $export_data && $export_rand == $get_rand ) { $export_data = unserialize($export_data); $first_step = false; } else { // first step $export_data = Array (); $export_data['prefix'] = $this->PrefixSpecial; $export_data['grid'] = $this->grid; $export_data['file_name'] = EXPORT_PATH . '/' . $file_helper->ensureUniqueFilename(EXPORT_PATH, 'export_' . $export_data['prefix'] . '.csv'); $export_data['step'] = EXPORT_STEP; $export_data['delimiter'] = $this->delimiter_mapping[(int)$this->Application->ConfigValue('CSVExportDelimiter')]; $export_data['enclosure'] = $this->enclosure_mapping[(int)$this->Application->ConfigValue('CSVExportEnclosure')]; $export_data['record_separator'] = $this->separator_mapping[(int)$this->Application->ConfigValue('CSVExportSeparator')]; $export_data['page'] = 1; $export_data['source_encoding'] = strtoupper(CHARSET); $export_data['encoding'] = $this->Application->ConfigValue('CSVExportEncoding') ? false : 'UTF-16LE'; $this->Application->StoreVar('export_rand', $get_rand); $first_step = true; } $file = fopen($export_data['file_name'], $first_step ? 'w' : 'a'); $prefix_elements = preg_split('/\.|_/', $export_data['prefix'], 2); - $grid_config = $this->_getGridColumns($prefix_elements[0], $export_data['grid']); + $grid_config = $this->getGridColumns($export_data); $list_params = Array ('per_page' => $export_data['step'], 'grid' => $export_data['grid']); /** @var kDBList $list */ $list = $this->Application->recallObject(rtrim(implode('.', $prefix_elements), '.'), $prefix_elements[0] . '_List', $list_params); $list->SetPage($export_data['page']); $list->Query(); $list->GoFirst(); $picker_helper = new kColumnPickerHelper(rtrim(implode('.', $prefix_elements), '.'), $export_data['grid']); $grid_config = $picker_helper->apply($grid_config); if ( $first_step ) { // if UTF-16, write Unicode marker if ( $export_data['encoding'] == 'UTF-16LE' ) { fwrite($file, chr(0xFF) . chr(0xFE)); } // inserting header line $headers = Array (); foreach ($grid_config as $field_name => $field_data) { $use_phrases = array_key_exists('use_phrases', $field_data) ? $field_data['use_phrases'] : true; $field_title = isset($field_data['title']) ? $field_data['title'] : 'column:la_fld_' . $field_name; $header = $use_phrases ? $this->Application->Phrase($field_title) : $field_title; array_push($headers, $header); } $csv_line = kUtil::getcsvline($headers, $export_data['delimiter'], $export_data['enclosure'], $export_data['record_separator']); if ( $export_data['encoding'] ) { $csv_line = mb_convert_encoding($csv_line, $export_data['encoding'], $export_data['source_encoding']); } fwrite($file, $csv_line); } while (!$list->EOL()) { $data = Array (); foreach ($grid_config as $field_name => $field_data) { if ( isset($field_data['export_field']) ) { $field_name = $field_data['export_field']; } $value = $list->GetField($field_name, isset($field_data['format']) ? $field_data['format'] : null); $value = str_replace("\r\n", "\n", $value); $value = str_replace("\r", "\n", $value); array_push($data, $value); } if ( $export_data['encoding'] == 'UTF-16LE' ) { fwrite($file, chr(0xFF) . chr(0xFE)); } $csv_line = kUtil::getcsvline($data, $export_data['delimiter'], $export_data['enclosure'], $export_data['record_separator']); if ( $export_data['encoding'] ) { $csv_line = mb_convert_encoding($csv_line, $export_data['encoding'], $export_data['source_encoding']); } fwrite($file, $csv_line); $list->GoNext(); } $records_processed = $export_data['page'] * $export_data['step']; $percent_complete = min($records_processed / $list->GetRecordsCount() * 100, 100); fclose($file); if ( $records_processed >= $list->GetRecordsCount() ) { $this->Application->StoreVar('export_data', serialize($export_data)); $this->Application->Redirect($this->Application->GetVar('finish_template')); } echo $percent_complete; $export_data['page']++; $this->Application->StoreVar('export_data', serialize($export_data)); } function ExportData($name) { $export_data = unserialize($this->Application->RecallVar('export_data')); return isset($export_data[$name]) ? $export_data[$name] : false; } /** * Returns prefix from request or from stored import/export data * * @param bool $is_import * @return string */ public function getPrefix($is_import = false) { $prefix = $this->Application->GetVar('PrefixSpecial'); if ( !$prefix ) { return $is_import ? $this->ImportData('prefix') : $this->ExportData('prefix'); } return $prefix; } function GetCSV() { kUtil::safeDefine('DBG_SKIP_REPORTING', 1); $export_data = unserialize($this->Application->RecallVar('export_data')); $filename = preg_replace('/(.*)\.csv$/', '\1', basename($export_data['file_name'])) . '.csv'; $this->Application->setContentType('text/csv'); header('Content-Disposition: attachment; filename="' . $filename . '"'); readfile($export_data['file_name']); die(); } function ImportStart($filename) { if ( !file_exists($filename) || !is_file($filename) ) { return 'cant_open_file'; } $import_data = Array (); $import_data['source_encoding'] = strtoupper(CHARSET); $import_data['encoding'] = $this->Application->ConfigValue('CSVExportEncoding') ? false : 'UTF-16LE'; $import_data['errors'] = ''; // convert file in case of UTF-16LE if ( $import_data['source_encoding'] != $import_data['encoding'] ) { copy($filename, $filename . '.orginal'); $file_content = file_get_contents($filename); $file = fopen($filename, 'w'); fwrite($file, mb_convert_encoding(str_replace(chr(0xFF) . chr(0xFE), '', $file_content), $import_data['source_encoding'], $import_data['encoding'])); fclose($file); } $import_data['prefix'] = $this->PrefixSpecial; $import_data['grid'] = $this->grid; $import_data['file'] = $filename; $import_data['total_lines'] = count(file($filename)); if ( !$import_data['total_lines'] ) { $import_data['total_lines'] = 1; } unset($file_content); $import_data['lines_processed'] = 0; $import_data['delimiter'] = $this->delimiter_mapping[(int)$this->Application->ConfigValue('CSVExportDelimiter')]; $import_data['enclosure'] = $this->enclosure_mapping[(int)$this->Application->ConfigValue('CSVExportEnclosure')]; $import_data['step'] = IMPORT_STEP; $import_data['not_imported_lines'] = ''; $import_data['added'] = 0; $import_data['updated'] = 0; $file = fopen($filename, 'r'); // getting first line for headers $headers = fgetcsv($file, 8192, $import_data['delimiter'], $import_data['enclosure']); fclose($file); $prefix_elements = preg_split('/\.|_/', $import_data['prefix'], 2); - $grid_config = $this->_getGridColumns($prefix_elements[0], $import_data['grid']); + $grid_config = $this->getGridColumns($import_data); $field_list = Array(); foreach ($grid_config as $field_name => $field_data) { if ( isset($field_data['export_field']) ) { $field_name = $field_data['export_field']; } $field_title = isset($field_data['title']) ? $field_data['title'] : 'column:la_fld_' . $field_name; $field_label = $this->Application->Phrase($field_title); $field_pos = array_search($field_label, $headers); if ( $field_pos !== false ) { $field_list[$field_pos] = $field_name; } } if ( !count($field_list) ) { return 'no_matching_columns'; } $import_data['field_list'] = $field_list; // getting key list $field_positions = Array (); $config = $this->Application->getUnitConfig($prefix_elements[0]); $config_key_list = $config->getImportKeys(); if ( !$config_key_list ) { $config_key_list = Array (); } $key_list = Array (); array_unshift($config_key_list, Array ($config->getIDField())); foreach ($config_key_list as $arr_key => $import_key) { $key_list[$arr_key] = is_array($import_key) ? $import_key : Array ($import_key); foreach ($key_list[$arr_key] as $key_field) { $field_positions[$key_field] = array_search($key_field, $import_data['field_list']); if ( $field_positions[$key_field] === false ) { // no such key field combination in imported file unset($key_list[$arr_key]); break; } } } $import_data['key_list'] = $key_list; $import_data['field_positions'] = $field_positions; $this->Application->StoreVar('import_data', serialize($import_data)); return true; } - /** - * Returns columns of given grid - * - * @param string $prefix - * @param string $grid_name - * @return Array - * @access protected - */ - protected function _getGridColumns($prefix, $grid_name) - { - $grid = $this->Application->getUnitConfig($prefix)->getGridByName($grid_name); - - return $grid['Fields']; - } - function ImportStep() { $import_data = unserialize($this->Application->RecallVar('import_data')); $prefix_elems = preg_split('/\.|_/', $import_data['prefix'], 2); /** @var kDBItem $object */ $object = $this->Application->recallObject($prefix_elems[0].'.-csvimport', $prefix_elems[0], Array('skip_autoload' => true, 'populate_ml_fields' => true)); $file = fopen($import_data['file'], 'r'); $eof = false; // skipping lines that has been already imported for($i = 0; $i < $import_data['lines_processed'] + 1; $i++) { if(feof($file)) break; fgets($file, 8192); } $import_event = new kEvent($prefix_elems[0].'.-csvimport:OnBeforeCSVLineImport'); for($i = 0; $i < $import_data['step']; $i++) { if(feof($file)) break; $data = fgetcsv($file, 8192, $import_data['delimiter'], $import_data['enclosure']); if(!$data) continue; $object->Clear(); $action = 'Create'; // 1. trying to load object by keys foreach($import_data['key_list'] as $key) { $fail = false; $key_array = Array(); foreach($key as $key_field) { if(!isset($data[ $import_data['field_positions'][$key_field] ])) { $fail = true; break; } $key_array[$key_field] = $data[ $import_data['field_positions'][$key_field] ]; } if($fail) continue; if($object->Load($key_array)) { $action = 'Update'; break; } } - // 2. set object fields - foreach($import_data['field_list'] as $position => $field_name) { - if(isset($data[$position])) { + // 2. set object fields. + $grid_config = $this->getGridColumns($import_data); + + foreach ( $import_data['field_list'] as $position => $field_name ) { + if ( isset($data[$position]) ) { + $formatter_class = $object->GetFieldOption($field_name, 'formatter'); + + if ( $formatter_class !== false ) { + $formatter = $this->Application->recallObject($formatter_class); + + if ( $formatter instanceof kDateFormatter ) { + if ( isset($grid_config[$field_name]['format']) ) { + $format = $grid_config[$field_name]['format']; + } + else { + $format = $object->GetFieldOption($field_name, 'format'); + } + + // Use export format during import. + $object->SetFieldOption($field_name, 'input_format', $format); + + // Read date/time from single column. + $object->SetDBField($field_name . '_combined', 1); + } + } + $object->SetField($field_name, $data[$position]); } } // 3. validate item and run event $status = $object->Validate(); $import_event->status = $status ? kEvent::erSUCCESS : kEvent::erFAIL; $this->Application->HandleEvent($import_event); if($import_event->status == kEvent::erSUCCESS && $object->$action()) { $import_data[ ($action == 'Create') ? 'added' : 'updated' ]++; } else { $msg = ''; $errors = $object->GetFieldErrors(); foreach ($errors as $field => $info) { if (!$info['pseudo']) continue; $msg .= "$field: {$info['pseudo']} "; } $import_data['errors'] .= ($i + $import_data['lines_processed'] + 1).": $msg\n"; $import_data['not_imported_lines'] .= ','.($i + $import_data['lines_processed'] + 1); } } $import_data['lines_processed'] += $import_data['step']; $import_data['not_imported_lines'] = ltrim($import_data['not_imported_lines'], ','); $this->Application->StoreVar('import_data', serialize($import_data)); $feof = feof($file); fclose($file); if($feof) { $this->Application->Redirect($this->Application->GetVar('finish_template')); } else { $percent_complete = floor($import_data['lines_processed'] / $import_data['total_lines'] * 100); if($percent_complete > 99) $percent_complete = 99; echo $percent_complete; } } + /** + * Returns grid columns. + * + * @param array $import_data Import data. + * + * @return array + */ + protected function getGridColumns(array $import_data) + { + $prefix_elements = preg_split('/\.|_/', $import_data['prefix'], 2); + $grid = $this->Application->getUnitConfig($prefix_elements[0])->getGridByName($import_data['grid']); + + return $grid['Fields']; + } + function ImportData($name) { $import_data = unserialize($this->Application->RecallVar('import_data')); return isset($import_data[$name]) ? $import_data[$name] : false; } function GetNotImportedLines() { $import_data = unserialize($this->Application->RecallVar('import_data')); if(!$import_data['not_imported_lines']) return false; $line_numbers = explode(',', $import_data['not_imported_lines']); $line_numbers[] = 0; // include header row in output $file = fopen($import_data['file'], 'r'); $eof = false; $result = ''; for($i = 0; $i <= max($line_numbers); $i++) { if(feof($file)) break; $line = fgets($file, 8192); if(in_array($i, $line_numbers)) { $result .= $i.':'.$line; } } return $result."\n\n".$import_data['errors']; } } Index: branches/5.3.x/core/units/helpers/minifiers/yuicompressor-2.4.2.jar =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: branches/5.3.x/core/units/helpers/minifiers/minify_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/minifiers/minify_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/minifiers/minify_helper.php (revision 16600) @@ -1,315 +1,330 @@ debugMode = $this->Application->isDebugMode(false); $this->resourceFolder = WRITEABLE . '/cache'; } /** * When used as non-block tag, then compress given files and return url to result * * @param Array $params * @return string * @access public */ public function CompressScriptTag($params) { // put to queue if ( array_key_exists('to', $params) ) { $files = $this->Application->GetVar($params['to'], ''); $this->Application->SetVar($params['to'], $files . '|' . $params['files']); return ''; } if ( array_key_exists('from', $params) ) { // get from queue $files = $this->Application->GetVar($params['from']); } else { // get from tag $files = $params['files']; } $files = $this->_getTemplatePaths( array_map('trim', explode('|', $files)) ); if ( !$files ) { trigger_error('No files specified for compression.', E_USER_NOTICE); return ''; } $extension = pathinfo($files[0], PATHINFO_EXTENSION); $save_as = isset($params['save_as']) ? $params['save_as'] : false; $dst_file = $this->resourceFolder . DIRECTORY_SEPARATOR . ($this->debugMode ? 'd' : 'c') . '_'; /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); if ( $save_as ) { $dst_file .= $save_as . ( strpos($save_as, '.') === false ? '.' . $extension : '' ); } else { $dst_file .= $this->_getHash($file_helper->makeRelative($files)) . '.' . $extension; } $was_compressed = file_exists($dst_file); if ( !$was_compressed || ($this->debugMode && filemtime($dst_file) < $this->_getMaxFileDate($files)) ) { $string = ''; $path_length = strlen(FULL_PATH) + 1; foreach ($files as $file) { if ( !file_exists($file) ) { continue; } // add filename before for easier debugging if ( $this->debugMode ) { $string .= '/* === File: ' . substr($file, $path_length) . ' === */' . "\n"; $string .= '/* ' . str_repeat('=', strlen(substr($file, $path_length)) + 14) . ' */' . "\n\n"; } // add file content $string .= file_get_contents($file) . "\n\n"; } // replace templates base if ( isset($params['templates_base']) ) { $templates_base = $params['templates_base']; } else { $templates_base = $this->Application->ProcessParsedTag('m', 'TemplatesBase', Array ()); } $templates_base = preg_replace('/^' . preg_quote($this->Application->BaseURL(), '/') . '/', BASE_PATH . '/', $templates_base); $string = str_replace('@templates_base@', rtrim($templates_base, '/'), $string); if ( !$this->debugMode ) { // don't compress merged js/css file in debug mode to allow js/css debugging $this->compressString($string, $extension); } // save compressed file file_put_contents($dst_file, $string); } return $file_helper->pathToUrl($dst_file) . '?ts=' . date('Y-m-d_H:i:s', filemtime($dst_file)); } /** * Returns maximal modification date across given files * * @param Array $files * @return int * @access protected */ protected function _getMaxFileDate($files) { $ret = 0; foreach ($files as $file) { if ( file_exists($file) ) { $ret = max($ret, filemtime($file)); } } return $ret; } /** * Returns hash string based on given files * * @param Array $files * @return int * @access protected */ protected function _getHash($files) { $hash = $files; if ($this->Application->isAdmin) { array_unshift($hash, 'A:1'); } else { array_unshift($hash, 'A:0;T:' . $this->Application->GetVar('m_theme')); } return kUtil::crc32(implode('|', $hash)); } /** * Deletes compression info file * * @todo also delete all listed there files * @access public */ public function delete() { $iterator = new DirectoryIterator($this->resourceFolder); /** @var DirectoryIterator $file_info */ foreach ($iterator as $file_info) { if ( !$file_info->isDir() && preg_match('/^(c|d)_.*.(css|js)$/', $file_info->getFilename()) ) { unlink( $file_info->getPathname() ); } } } /** + * Dumps the assets. + * + * @return void + */ + public function dump() + { + /** @var kCurlHelper $curl_helper */ + $curl_helper = $this->Application->recallObject('CurlHelper'); + $curl_helper->setOptions(array( + CURLOPT_COOKIE => 'debug_off=1', + )); + $curl_helper->Send($this->Application->BaseURL()); + } + + /** * Compress $string based on $extension * * @param string $string * @param string $extension * @return void * @access protected */ public function compressString(&$string, $extension) { $compression_engine = kUtil::getSystemConfig()->get('CompressionEngine'); if ( !$compression_engine ) { // compression method not specified - use none return; } switch ( $compression_engine ) { case 'yui': $this->compressViaJava($string, $extension); break; case 'php': $this->compressViaPHP($string, $extension); break; } } /** * Compresses string using YUI compressor (uses Java) * * @param string $string * @param string $extension * @return void * @access protected */ protected function compressViaJava(&$string, $extension) { $tmp_file = tempnam('/tmp', 'to_compress_'); file_put_contents($tmp_file, $string); - $command = 'java -jar ' . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'yuicompressor-2.4.2.jar --type ' . $extension . ' --charset utf-8 ' . $tmp_file; + $command = 'java -jar ' . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'yuicompressor-2.4.8.jar --type ' . $extension . ' --charset utf-8 ' . $tmp_file; $string = shell_exec($command); unlink($tmp_file); } /** * Compresses string using PHP compressor * * @param string $string * @param string $extension * @return void * @access protected */ protected function compressViaPHP(&$string, $extension) { /** @var JsMinifyHelper $minifier */ $minifier = $this->Application->makeClass($extension == 'js' ? 'JsMinifyHelper' : 'CssMinifyHelper'); $string = $minifier->minify($string); } /** * Get full paths on disk for each of given templates * * @param Array $templates * @return Array * @access protected */ protected function _getTemplatePaths($templates) { $ret = Array (); $reg_exp = '/^' . preg_quote($this->Application->BaseURL(), '/') . '(.*)/'; foreach ($templates as $template) { if ( !$template ) { continue; } if ( preg_match($reg_exp, $template, $regs) ) { // full url (from current domain) to a file $ret[] = FULL_PATH . '/' . $regs[1]; } elseif ( strpos($template, '{module_path}') !== false ) { $ret = array_merge($ret, $this->_moduleInclude($template)); } else { $ret[] = $this->Application->TemplatesCache->GetRealFilename($template); } } return $ret; } /** * * @param string $template * @return Array * @access protected */ protected function _moduleInclude($template) { $ret = $included = Array (); foreach ($this->Application->ModuleInfo as $module_name => $module_data) { if ( $module_name == 'In-Portal' ) { continue; } $module_prefix = $this->Application->isAdmin ? mb_strtolower($module_name) . '/' : $module_data['TemplatePath']; if ( in_array($module_prefix, $included) ) { continue; } $ret[] = $this->Application->TemplatesCache->GetRealFilename(str_replace('{module_path}', $module_prefix, $template)); $included[] = $module_prefix; } return $ret; } } Index: branches/5.3.x/core/units/helpers/minifiers/yuicompressor-2.4.8.jar =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: branches/5.3.x/core/units/helpers/minifiers/yuicompressor-2.4.8.jar ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Index: branches/5.3.x/core/units/helpers/permissions_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/permissions_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/permissions_helper.php (revision 16600) @@ -1,848 +1,847 @@ Application->getUnitConfig('perm')->getTableName(); $perm_table = $this->Application->GetTempName($perm_table, 'prefix:'.$prefix); $sql = 'SELECT * FROM '.$perm_table.' WHERE (GroupId = '.$group_id.') AND (CatId = '.$cat_id.') AND (Type = '.$type.')'; $permissions = $this->Conn->Query($sql, 'Permission'); $this->Permissions = Array(); foreach ($permissions as $perm_name => $perm_options) { $perm_record['value'] = $perm_options['PermissionValue']; $perm_record['id'] = $perm_options['PermissionId']; $this->Permissions[$perm_name] = $perm_record; } } function getPermissionValue($perm_name) { return isset($this->Permissions[$perm_name]) ? $this->Permissions[$perm_name]['value'] : 0; } function getPermissionID($perm_name) { return isset($this->Permissions[$perm_name]) ? $this->Permissions[$perm_name]['id'] : 0; } /** * This is old permission like ADMIN or LOGIN * * @param string $section_name * @param string $perm_name * @return bool */ function isOldPermission($section_name, $perm_name) { return $section_name == 'in-portal:root' && $perm_name != 'view'; } /** * Returns permission names to check based on event name and item prefix (main item or subitem) * * @param kEvent $event * @param Array $perm_mapping * @return Array */ function getPermissionByEvent($event, $perm_mapping) { $top_prefix = $event->getEventParam('top_prefix'); $prefix_type = ($top_prefix == $event->Prefix) ? 'self' : 'subitem'; $perm_mapping = getArrayValue($perm_mapping, $event->Name); if (!$perm_mapping[$prefix_type]) { throw new Exception('Permission mappings not defined for event ' . $top_prefix . ' <- ' . $event->Prefix . ':' . $event->Name . ''); } if ($perm_mapping[$prefix_type] === true) { // event is defined in mapping but is not checked by permissions return true; } return explode('|', $perm_mapping[$prefix_type]); } /** * Common event permission checking method * * @param kEvent $event * @param Array $perm_mapping * @return bool */ function CheckEventPermission($event, $perm_mapping) { $section = $event->getSection(); if (preg_match('/^CATEGORY:(.*)/', $section)) { return $this->CheckEventCategoryPermission($event, $perm_mapping); } $top_prefix = $event->getEventParam('top_prefix'); $check_perms = $this->getPermissionByEvent($event, $perm_mapping); if ($check_perms === true) { // event is defined in mapping but is not checked by permissions return true; } $perm_status = false; foreach ($check_perms as $perm_name) { // check if at least one of required permissions is set if ($perm_name == 'debug' && $this->Application->isDebugMode(false)) { // universal "debug" permission return true; } elseif ( $perm_name == 'admin' && $this->Application->isAdminUser ) { // any logged-in admin user will suffice return true; } $perm_name = $section.'.'.$perm_name; $perm_status = $this->CheckPermission($perm_name, 1); if (($perm_name == $section.'.add') && $perm_status && ($top_prefix == $event->Prefix)) { // main item, add permission allowed, but ID is > 0, then deny permission // how to get id here } if ($perm_status) { return $perm_status; } } return $this->finalizePermissionCheck($event, $perm_status); } /** * Returns owner + primary category for each item (used for permission checking) * * @param string $prefix * @param string $ids * @param bool $temp_mode * @return Array * @author Alex */ function GetCategoryItemData($prefix, $ids, $temp_mode = false) { if (is_array($ids)) { $ids = implode(',', $ids); } $config = $this->Application->getUnitConfig($prefix); $id_field = $config->getIDField(); $table_name = $config->getTableName(); $ci_table = $this->Application->getUnitConfig('ci')->getTableName(); if ($temp_mode) { $table_name = $this->Application->GetTempName($table_name, 'prefix:' . $prefix); $ci_table = $this->Application->GetTempName($ci_table, 'prefix:' . $prefix); } $owner_field = $config->getOwnerField('CreatedById'); $sql = 'SELECT item_table.'.$id_field.', item_table.'.$owner_field.' AS CreatedById, ci.CategoryId FROM '.$table_name.' item_table LEFT JOIN '.$ci_table.' ci ON ci.ItemResourceId = item_table.ResourceId WHERE item_table.'.$id_field.' IN ('.$ids.') AND (ci.PrimaryCat = 1)'; return $this->Conn->Query($sql, $id_field); } /** * Check category-based permissions for category items * * @param kEvent $event * @param Array $event_perm_mapping * @return bool */ function _frontCheckEventCategoryPermission($event, $event_perm_mapping) { // mapping between specific permissions and common permissions static $perm_mapping = Array( 'add' => 'ADD', 'add.pending' => 'ADD.PENDING', 'edit' => 'MODIFY', 'edit.pending' => 'MODIFY.PENDING', 'delete' => 'DELETE', 'view' => 'VIEW', 'debug' => 'DEBUG', 'admin' => 'ADMIN', ); $top_prefix = $event->getEventParam('top_prefix'); /** @var kCatDBEventHandler $event_handler */ $event_handler = $this->Application->recallObject($event->Prefix . '_EventHandler'); $raise_warnings = $event->getEventParam('raise_warnings'); $event->setEventParam('raise_warnings', 0); if ( $event->Prefix != $top_prefix ) { $top_event = new kEvent($top_prefix . ':' . $event->Name); $id = $event_handler->getPassedID($top_event); } else { $id = $event_handler->getPassedID($event); } $event->setEventParam('raise_warnings', $raise_warnings); $owner_id = USER_ROOT; // owner is root if not detected if ( !$id ) { // item being created -> check by current (before editing started, saved in OnPreCreate event) category permissions // note: category in session is placed on catalog data import start $category_id = $this->Application->isAdmin ? $this->Application->RecallVar('m_cat_id') : $this->Application->GetVar('m_cat_id'); } elseif ( $top_prefix == 'c' || $top_prefix == 'st' ) { $category_id = $id; } else { // item being edited -> check by it's primary category permissions $items_info = $this->GetCategoryItemData($top_prefix, $id); if ( $items_info ) { $category_id = $items_info[$id]['CategoryId']; $owner_id = $items_info[$id]['CreatedById']; } else { // item wasn't found in database $category_id = $this->Application->GetVar('m_cat_id'); } } // specific permission check for pending & owner permissions: begin $uploader_events = Array ('OnUploadFile', 'OnDeleteFile', 'OnViewFile'); if ( in_array($event->Name, $uploader_events) ) { // don't recall target object during uploader-related, because OnItemLoad will use incorrect // $user_id in Firefox (during Flash problems session will be used from Internet Exploere) $new_item = false; } else { $new_item = $this->Application->isAdminUser && $event_handler->isNewItemCreate($event) ? true : false; $check_status = $this->checkCombinedPermissions($event, $owner_id, (int)$category_id, $new_item); } if ( isset($check_status) ) { return $this->finalizePermissionCheck($event, $check_status); } // specific permission check for pending & owner permissions: end $perm_status = false; $check_perms = $this->getPermissionByEvent($event, $event_perm_mapping); if ( $check_perms === true ) { // event is defined in mapping but is not checked by permissions return true; } $item_prefix = $this->Application->getUnitConfig($top_prefix)->getPermItemPrefix(); foreach ($check_perms as $perm_name) { // check if at least one of required permissions is set if ( !isset($perm_mapping[$perm_name]) ) { // not mapped permission (e.g. advanced:approve) -> skip continue; } if ( $perm_name == 'debug' && $this->Application->isDebugMode(false) ) { // universal "debug" permission return true; } elseif ( $perm_name == 'admin' && $this->Application->isAdminUser ) { // any logged-in admin user will suffice return true; } $perm_name = $item_prefix . '.' . $perm_mapping[$perm_name]; $perm_status = $this->CheckPermission($perm_name, 0, (int)$category_id); if ( $perm_status ) { return $perm_status; } } return $this->finalizePermissionCheck($event, $perm_status); } /** * Finalizes permission checking (with additional debug output, when in debug mode) * * @param kEvent $event * @param bool $perm_status * @return bool */ function finalizePermissionCheck($event, $perm_status) { if (!$perm_status) { if (MOD_REWRITE) { // $event->SetRedirectParam('m_cat_id', 0); // category means nothing on admin login screen $event->SetRedirectParam('next_template', 'external:' . $_SERVER['REQUEST_URI']); } else { $event->SetRedirectParam('next_template', $this->Application->GetVar('t')); } if ($this->Application->isDebugMode()) { // for debugging purposes $event->SetRedirectParam('section', $event->getSection()); $event->SetRedirectParam('main_prefix', $event->getEventParam('top_prefix')); $event->SetRedirectParam('event_name', $event->Name); } $event->status = kEvent::erPERM_FAIL; } return $perm_status; } /** * Allows to check combined permissions (*.owner, *.pending) for add/modify/delete operations from admin & front-end * * @param kEvent $event * @param int $owner_id * @param int $category_id * @param bool $new_item * @return mixed */ function checkCombinedPermissions($event, $owner_id, $category_id, $new_item = false) { $ret = null; // true/false when used, null when not used $top_prefix = $event->getEventParam('top_prefix'); // check admin permission if (substr($event->Name, 0, 9) == 'OnPreSave') { if ($new_item) { $ret = $this->AddCheckPermission($category_id, $top_prefix); } else { // add & modify because $new_item is false, when item is aready created & then saved in temp table (even with 0 id) $ret = $this->AddCheckPermission($category_id, $top_prefix) || $this->ModifyCheckPermission($owner_id, $category_id, $top_prefix); } } // check front-end permissions switch ($event->Name) { case 'OnCreate': $ret = $this->AddCheckPermission($category_id, $top_prefix); break; case 'OnUpdate': $ret = $this->ModifyCheckPermission($owner_id, $category_id, $top_prefix); break; case 'OnDelete': case 'OnMassDelete': $ret = $this->DeleteCheckPermission($owner_id, $category_id, $top_prefix); break; } if ($ret === 0) { // permission check failed (user has no permission) $event->status = kEvent::erPERM_FAIL; } return $ret; } /** * Simplified permission check for category items, when adding/editing them from advanced view. * * @param kEvent $event * @param Array $event_perm_mapping * @return mixed */ function CheckEventCategoryPermission($event, $event_perm_mapping) { if (!$this->Application->isAdmin) { // check front-end permission by old scheme return $this->_frontCheckEventCategoryPermission($event, $event_perm_mapping); } if (substr($event->Name, 0, 9) == 'OnPreSave') { // check separately, because permission mapping is not defined for OnPreSave* events $check_perms = Array ('add', 'edit'); } else { $check_perms = $this->getPermissionByEvent($event, $event_perm_mapping); } if ($check_perms === true) { // event is defined in mapping but is not checked by permissions return true; } // 1. most of events does require admin login only $perm_status = $this->Application->isAdminUser; // 2. in case, when event require more, then "view" right, then restrict it to temporary tables only if (!in_array('view', $check_perms)) { $perm_status = $perm_status && $this->Application->IsTempMode($event->Prefix, $event->Special); } return $this->finalizePermissionCheck($event, $perm_status); } function TagPermissionCheck($params, $is_owner = false) { $perm_prefix = getArrayValue($params, 'perm_prefix'); $perm_event = getArrayValue($params, 'perm_event'); $permission_groups = getArrayValue($params, 'permissions'); $check_admin = isset($params['admin']) && $params['admin']; if ($permission_groups && !$perm_event) { // check permissions by permission names in current category $permission_groups = explode('|', $permission_groups); $group_has_permission = false; $perm_category = isset($params['cat_id']) ? $params['cat_id'] : $this->Application->GetVar('m_cat_id'); if ($perm_prefix) { // use primary category of item with id from {perm_prefix}_id as base for permission checking $perm_category = $this->getPrimaryCategory($perm_prefix); } $is_system = isset($params['system']) && $params['system'] ? 1 : 0; foreach ($permission_groups as $permission_group) { $has_permission = true; $permissions = explode(',', $permission_group); if ( $check_admin ) { foreach ($permissions as $permission) { $owner_checked = (strpos($permission, '.OWNER.') !== false) ? $is_owner : true; $has_permission = $has_permission && $this->CheckAdminPermission($permission, $is_system, $perm_category) && $owner_checked; } } else { foreach ($permissions as $permission) { $owner_checked = (strpos($permission, '.OWNER.') !== false) ? $is_owner : true; $has_permission = $has_permission && $this->CheckPermission($permission, $is_system, $perm_category) && $owner_checked; } } $group_has_permission = $group_has_permission || $has_permission; if ($group_has_permission) { return true; } } return false; } elseif ($perm_event) { // check permission by event name list ($prefix, ) = explode(':', $perm_event); /** @var kEventHandler $event_handler */ $event_handler = $this->Application->recallObject($prefix . '_EventHandler'); return $event_handler->CheckPermission( new kEvent($perm_event) ); } return true; } /** * Returns item's primary category (get item_id from request) * * @param string $prefix * @return int */ function getPrimaryCategory($prefix) { $id = $this->Application->GetVar($prefix.'_id'); if (!$id) { return $this->Application->GetVar('m_cat_id'); } $config = $this->Application->getUnitConfig($prefix); $sql = 'SELECT ResourceId FROM '. $config->getTableName() .' WHERE '. $config->getIDField() .' = '.(int)$id; $resource_id = $this->Conn->GetOne($sql); $sql = 'SELECT CategoryId FROM '.$this->Application->getUnitConfig('ci')->getTableName().' WHERE ItemResourceId = '.$resource_id.' AND PrimaryCat = 1'; return $this->Conn->GetOne($sql); } /** * Returns no permission template to redirect to * * @param Array $params * @return Array */ function getPermissionTemplate($params) { $t = $this->Application->GetVar('t'); $next_t = getArrayValue($params, 'next_template'); if ( $next_t ) { $t = $next_t; } $redirect_params = $this->Application->HttpQuery->getRedirectParams(true); if (array_key_exists('pass_category', $params)) { $redirect_params['pass_category'] = $params['pass_cateogry']; } if (MOD_REWRITE) { // TODO: $next_t variable is ignored !!! (is anyone using m_RequireLogin tag with "next_template" parameter?) $redirect_params = Array ( 'm_cat_id' => 0, // category means nothing on admin login screen 'next_template' => 'external:' . $_SERVER['REQUEST_URI'], ); } else { $redirect_params['next_template'] = $t; } if ($this->Application->isAdmin) { $redirect_params['m_wid'] = ''; // remove wid, otherwise parent window may add wid to its name breaking all the frameset (for targets) $redirect_params['pass'] = 'm'; // don't pass any other (except "m") prefixes to admin login template } if (!$this->Application->LoggedIn()) { $redirect_template = array_key_exists('login_template', $params) ? $params['login_template'] : ''; if (!$redirect_template && $this->Application->isAdmin) { $redirect_template = 'login'; } } else { if (array_key_exists('no_permissions_template', $params)) { $redirect_template = $params['no_permissions_template']; } else { $redirect_template = $this->Application->isAdmin ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate'); } if ($this->Application->isDebugMode()) { $redirect_params['from_template'] = 1; $redirect_params['perms'] = $params[ isset($params['permissions']) ? 'permissions' : 'perm_event' ]; } } if (isset($params['index_file']) && $params['index_file']) { $redirect_params['index_file'] = $params['index_file']; } return Array ($redirect_template, $redirect_params); } /** * Check current user permissions based on it's group permissions in specified category (for non-system permissions) or just checks if system permission is set * * @param string $name permission name * @param int $cat_id category id, current used if not specified * @param int $type permission type {1 - system, 0 - per category} * @return int */ function CheckPermission($name, $type = 1, $cat_id = null) { $user_id = $this->Application->RecallVar('user_id'); return $this->CheckUserPermission($user_id, $name, $type, $cat_id); } /** * Check current admin permissions (when called from Front-End) based on it's group permissions in specified category (for non-system permissions) or just checks if system permission is set * * @param string $name permission name * @param int $cat_id category id, current used if not specified * @param int $type permission type {1 - system, 0 - per category} * @return int */ function CheckAdminPermission($name, $type = 1, $cat_id = null) { if ( $this->Application->isAdmin ) { return $this->CheckPermission($name, $type, $cat_id); } $user_id = $this->Application->RecallVar('admin_user_id'); return $this->CheckUserPermission($user_id, $name, $type, $cat_id); } function CheckUserPermission($user_id, $name, $type = 1, $cat_id = null) { $user_id = (int)$user_id; - if ( $user_id == USER_ROOT ) { - // "root" is allowed anywhere + if ( $this->Application->permissionCheckingDisabled($user_id) ) { return substr($name, -5) == '.deny' || $name == 'SYSTEM_ACCESS.READONLY' ? 0 : 1; } if ( !isset($cat_id) ) { $cat_id = $this->Application->GetVar('m_cat_id'); } if ( $type == 1 ) { // "system" permission are always checked per "Home" category (ID = 0) $cat_id = 0; } elseif ( "$cat_id" === "0" ) { $cat_id = $this->Application->getBaseCategory(); } // perm cache is build only based on records in db, that's why if permission is not explicitly denied, then // that (perm cache creator) code thinks that it is allowed & adds corresponding record and code below will // return incorrect results if ( $user_id == $this->Application->RecallVar('user_id') ) { $groups = $this->Application->RecallVar('UserGroups'); } else { // checking not current user $groups = $this->Application->RecallVar('UserGroups:' . $user_id); if ( $groups === false ) { // die('me'); $sql = 'SELECT GroupId FROM '.TABLE_PREFIX.'UserGroupRelations WHERE (PortalUserId = '.$user_id.') AND ( (MembershipExpires IS NULL) OR ( MembershipExpires >= UNIX_TIMESTAMP() ) )'; $groups = $this->Conn->GetCol($sql); array_push($groups, $this->Application->ConfigValue('User_LoggedInGroup') ); $groups = implode(',', $groups); $this->Application->StoreVar('UserGroups:' . $user_id, $groups); } } $groups = explode(',', $groups); $cache_key = $name . '|' . $type . '|' . $cat_id . '|' . implode(',', $groups); $perm_value = $this->Application->getCache('permissions[%' . ($type == 1 ? 'G' : 'C') . 'PermSerial%]:' . $cache_key); if ( $perm_value !== false ) { return $perm_value; } if ( preg_match('/(.*)\.VIEW$/', $name) && ($type == 0) ) { // cached view permission of category: begin if ( $this->Application->ConfigValue('CheckViewPermissionsInCatalog') ) { if ( strpos($cat_id, '|') !== false ) { $category_path = explode('|', substr($cat_id, 1, -1)); $cat_id = end($category_path); } $sql = 'SELECT PermissionConfigId FROM ' . TABLE_PREFIX . 'CategoryPermissionsConfig WHERE PermissionName = ' . $this->Conn->qstr($name); $perm_id = $this->Conn->GetOne($sql); $sql = 'SELECT PermId FROM ' . TABLE_PREFIX . 'CategoryPermissionsCache WHERE (PermId = ' . $perm_id . ') AND (CategoryId = ' . (int)$cat_id . ')'; $view_filters = Array (); foreach ($groups as $group) { $view_filters[] = 'FIND_IN_SET(' . $group . ', ACL)'; } $sql .= ' AND (' . implode(' OR ', $view_filters) . ')'; $perm_value = $this->Conn->GetOne($sql) ? 1 : 0; } else { $perm_value = 1; } $this->Application->setCache('permissions[%CPermSerial%]:' . $cache_key, $perm_value); return $perm_value; // cached view permission of category: end } if ( is_numeric($cat_id) && $cat_id == 0 ) { $cat_hierarchy = Array (0); } else { if ( strpos($cat_id, '|') !== false ) { $cat_hierarchy = $cat_id; } else { $sql = 'SELECT ParentPath FROM ' . $this->Application->getUnitConfig('c')->getTableName() . ' WHERE CategoryId = ' . $cat_id; $cat_hierarchy = $this->Conn->GetOne($sql); if ( $cat_hierarchy === false ) { // category was deleted, but reference to it stays in other tables -> data integrity is broken $cat_hierarchy = '|' . $this->Application->getBaseCategory() . '|'; } } $cat_hierarchy = explode('|', substr($cat_hierarchy, 1, -1)); $cat_hierarchy = array_reverse($cat_hierarchy); array_push($cat_hierarchy, 0); } $perm_value = 0; $groups = implode(',', $groups); foreach ($cat_hierarchy as $category_id) { $sql = 'SELECT SUM(PermissionValue) FROM ' . TABLE_PREFIX . 'Permissions WHERE Permission = "' . $name . '" AND CatId = ' . $category_id . ' AND GroupId IN (' . $groups . ') AND Type = ' . $type; $res = $this->Conn->GetOne($sql); if ( $res !== false && !is_null($res) ) { $perm_value = $res ? 1 : 0; break; } } $this->Application->setCache('permissions[%' . ($type == 1 ? 'G' : 'C') . 'PermSerial%]:' . $cache_key, $perm_value); return $perm_value; } /** * Returns categories, where given permission is set to "1" * * @param string $permission_name * @return Array */ function getPermissionCategories($permission_name) { $groups = $this->Application->RecallVar('UserGroups'); // get categories, where given permission is explicitely defined $sql = 'SELECT SUM(PermissionValue), CatId FROM ' . TABLE_PREFIX . 'Permissions WHERE Permission = "' . $permission_name . '" AND GroupId IN (' . $groups . ') AND Type = 0 GROUP BY CatId'; $permissions = $this->Conn->GetCol($sql, 'CatId'); // get all categories along with their parent path $sql = 'SELECT ParentPath, CategoryId FROM ' . TABLE_PREFIX . 'Categories'; $parent_paths = $this->Conn->GetCol($sql, 'CategoryId'); foreach ($parent_paths as $category_id => $parent_path) { if (array_key_exists($category_id, $permissions)) { // permission for given category is set explicitly continue; } $perm_value = 0; $parent_path = explode('|', substr($parent_path, 1, -1)); $parent_path = array_reverse($parent_path); array_push($parent_path, 0); foreach ($parent_path as $parent_category_id) { if (array_key_exists($parent_category_id, $permissions)) { $perm_value = $permissions[$parent_category_id] ? 1 : 0; break; } } $permissions[$category_id] = $perm_value; } // remove categories, where given permissions is denied foreach ($permissions as $category_id => $perm_value) { if (!$perm_value) { unset($permissions[$category_id]); } } return array_keys($permissions); } /** * Allows to check MODIFY & OWNER.MODFY +/- PENDING permission combinations on item * * @param int $owner_id user_id, that is owner of the item * @param int $category_id primary category of item * @param string $prefix prefix of item * @return int {0 - no MODIFY permission, 1 - has MODIFY permission, 2 - has MODIFY.PENDING permission} */ function ModifyCheckPermission($owner_id, $category_id, $prefix) { $perm_prefix = $this->Application->getUnitConfig($prefix)->getPermItemPrefix(); $live_modify = $this->CheckPermission($perm_prefix.'.MODIFY', ptCATEGORY, $category_id); if ($live_modify) { return 1; } else if ($this->CheckPermission($perm_prefix.'.MODIFY.PENDING', ptCATEGORY, $category_id)) { return 2; } if ($owner_id == $this->Application->RecallVar('user_id')) { // user is item's OWNER -> check this permissions first $live_modify = $this->CheckPermission($perm_prefix.'.OWNER.MODIFY', ptCATEGORY, $category_id); if ($live_modify) { return 1; } else if ($this->CheckPermission($perm_prefix.'.OWNER.MODIFY.PENDING', ptCATEGORY, $category_id)) { return 2; } } return 0; } /** * Allows to check DELETE & OWNER.DELETE permission combinations on item * * @param int $owner_id user_id, that is owner of the item * @param int $category_id primary category of item * @param string $prefix prefix of item * @return int {0 - no DELETE permission, 1 - has DELETE/OWNER.DELETE permission} */ function DeleteCheckPermission($owner_id, $category_id, $prefix) { $perm_prefix = $this->Application->getUnitConfig($prefix)->getPermItemPrefix(); $live_delete = $this->CheckPermission($perm_prefix.'.DELETE', ptCATEGORY, $category_id); if ($live_delete) { return 1; } if ($owner_id == $this->Application->RecallVar('user_id')) { // user is item's OWNER -> check this permissions first $live_delete = $this->CheckPermission($perm_prefix.'.OWNER.DELETE', ptCATEGORY, $category_id); if ($live_delete) { return 1; } } return 0; } /** * Allows to check ADD +/- PENDING permission combinations on item * * @param int $category_id primary category of item * @param string $prefix prefix of item * @return int {0 - no ADD permission, 1 - has ADD permission, 2 - has ADD.PENDING permission} */ function AddCheckPermission($category_id, $prefix) { $perm_prefix = $this->Application->getUnitConfig($prefix)->getPermItemPrefix(); $live_add = $this->CheckPermission($perm_prefix.'.ADD', ptCATEGORY, $category_id); if ($live_add) { return 1; } else if ($this->CheckPermission($perm_prefix.'.ADD.PENDING', ptCATEGORY, $category_id)) { return 2; } return 0; } - } \ No newline at end of file + } Index: branches/5.3.x/core/units/helpers/navigation_bar.php =================================================================== --- branches/5.3.x/core/units/helpers/navigation_bar.php (revision 16599) +++ branches/5.3.x/core/units/helpers/navigation_bar.php (revision 16600) @@ -1,381 +1,381 @@ _params = $params; $this->_params['is_first'] = 1; $home_element = $this->_getHomeElement(); if ( !getArrayValue($this->_params, 'titles') && !getArrayValue($this->_params, 'templates') ) { // no static templates given, show only category path return $home_element . $this->getCategoryPath(); } $ret = ''; $block_params = $this->_getBaseParams(); $current_template = $this->_getCurrentTemplate(); $navigation_parts = $this->getNavigationParts(); foreach ($navigation_parts as $template => $title) { $block_params['template'] = $template; if ( $title == '__categorypath__' ) { $ret .= $this->getCategoryPath(); } else { $is_current = $template == $current_template; $block_params['current'] = $is_current; if ( substr($title, 0, 2) == '__' ) { $block_params['title'] = $title; $block_params['name'] = $this->SelectParam($this->_params, 'custom_render_as,render_as'); } else { $block_params['title'] = $this->Application->Phrase($title); $block_params['name'] = $this->_params[$is_current ? 'current_render_as' : 'render_as']; } $ret .= $this->Application->ParseBlock($block_params); } } return $home_element . $ret; } /** * Returns base params for rendering each navigation bar element * * @return Array * @access protected */ protected function _getBaseParams() { $block_params = Array ( 'no_editing' => 1, 'category' => 0, 'separator' => $this->_params['separator'], 'current' => 0, ); return $block_params; } /** * Returns the name of current physical template * * @return string * @access protected */ protected function _getCurrentTemplate() { return $this->Application->getPhysicalTemplate($this->Application->GetVar('t')); } /** * Returns element for "Home" category * * @return string * @access protected */ protected function _getHomeElement() { if ( isset($this->_params['shift']) && $this->_params['shift'] ) { $home_element = ''; $this->_params['shift']--; } else { $home_element = $this->_getHomeCategoryPath(); unset($this->_params['is_first']); } return $home_element; } /** * Renders path to top catalog category * * @return string * @access protected */ protected function _getHomeCategoryPath() { $block_params = $this->_getBaseParams(); $block_params['cat_id'] = $this->Application->getBaseCategory(); $block_params['current'] = $this->_getCurrentCategoryId() == $block_params['cat_id'] ? 1 : 0; $block_params['is_first'] = $this->_params['is_first']; $block_params['template'] = ''; // to prevent warning when category element is rendered using general "render_as" block $category_name = $this->Application->Phrase(($this->Application->isAdmin ? 'la_' : 'lu_') . 'rootcategory_name'); $block_params['cat_name'] = $block_params['title'] = $category_name; $block_params['name'] = $this->SelectParam($this->_params, 'root_cat_render_as,category_render_as,render_as'); if ( $block_params['current'] ) { $block_params['name'] = $this->SelectParam($this->_params, 'current_render_as,render_as'); } return $this->Application->ParseBlock($block_params); } /** * Returns currently selected category * * @return mixed */ protected function _getCurrentCategoryId() { return isset($this->_params['cat_id']) ? $this->_params['cat_id'] : $this->Application->GetVar('m_cat_id'); } /** * Get navigation parts * * @return Array * @access protected */ protected function getNavigationParts() { $titles = explode(',', $this->_params['titles']); $templates = explode(',', $this->_params['templates']); if ( getArrayValue($this->_params, 'show_category') && !in_array('__categorypath__', $titles) ) { // insert before __item__ or first element, when __item__ isn't specified $item_index = (int)array_search('__item__', $titles); array_splice($titles, $item_index, 0, '__categorypath__'); array_splice($templates, $item_index, 0, '__categorypath__'); } return array_combine($templates, $titles); } /** * Renders path to given category using given blocks. * * @return string * @access protected */ protected function getCategoryPath() { $category_path = $this->getCategoryParentPath(); if ( !$category_path ) { // in "Home" category return ''; } $main_category_id = $this->_getCurrentCategoryId(); /** @var CategoryHelper $category_helper */ $category_helper = $this->Application->recallObject('CategoryHelper'); $module_info = $category_helper->getCategoryModule($this->_params, array_keys($category_path)); - $module_item_id = $this->Application->GetVar($module_info['Var'] . '_id'); + $module_item_id = $module_info ? $this->Application->GetVar($module_info['Var'] . '_id') : false; $ret = ''; $block_params = $this->_getBaseParams(); $block_params['category'] = 1; $block_params['template'] = ''; // to prevent warning when category element is rendered using general "render_as" block if ( isset($this->_params['is_first']) ) { $block_params['is_first'] = $this->_params['is_first']; } $block_params['separator'] = $this->_params['separator']; $no_current = isset($this->_params['no_current']) && $this->_params['no_current']; $backup_category_id = $this->Application->GetVar('c_id'); foreach ($this->shiftCategoryPath($category_path) as $category_id => $category_name) { $block_params['cat_id'] = $category_id; $block_params['cat_name'] = $block_params['title'] = $category_name; if ( $no_current ) { $block_params['current'] = 0; } else { $block_params['current'] = ($main_category_id == $category_id) && !$module_item_id ? 1 : 0; } $block_params['name'] = $this->SelectParam($this->_params, 'category_render_as,render_as'); if ( $block_params['current'] ) { $block_params['name'] = $this->SelectParam($this->_params, 'current_render_as,render_as'); } $this->Application->SetVar('c_id', $category_id); $ret .= $this->Application->ParseBlock($block_params); if ( array_key_exists('is_first', $block_params) ) { unset($block_params['is_first']); } } $this->Application->SetVar('c_id', $backup_category_id); return $ret; } /** * Shift category path. * * @param array $category_path Category path. * * @return array */ protected function shiftCategoryPath(array $category_path) { if ( isset($this->_params['shift']) && $this->_params['shift'] ) { return array_slice($category_path, $this->_params['shift'], null, true); } return $category_path; } /** * Returns given category's parent path as array of id=>name elements * * @return Array * @access protected */ protected function getCategoryParentPath() { $main_category_id = $this->_getCurrentCategoryId(); if ( $main_category_id == 0 ) { // don't query path for "Home" category return Array (); } $category_title = isset($this->_params['category_title']) ? $this->_params['category_title'] : 'Name'; $cache_key = 'parent_paths_named[%CIDSerial:' . $main_category_id . '%]:' . $category_title; $cached_path = $this->Application->getCache($cache_key); if ( $cached_path === false ) { $parent_path = explode('|', substr($this->getParentPath($main_category_id), 1, -1)); /** @var kMultiLanguage $ml_formatter */ $ml_formatter = $this->Application->recallObject('kMultiLanguage'); $navbar_field = $ml_formatter->LangFieldName($category_title); $config = $this->Application->getUnitConfig('c'); $id_field = $config->getIDField(); $this->Conn->nextQueryCachable = true; $sql = 'SELECT ' . $navbar_field . ', ' . $id_field . ' FROM ' . $config->getTableName() . ' WHERE ' . $id_field . ' IN (' . implode(',', $parent_path) . ')'; $category_names = $this->Conn->GetCol($sql, $id_field); $cached_path = Array (); $skip_category = $this->Application->getBaseCategory(); if ( $category_names ) { foreach ($parent_path as $category_id) { if ( $category_id == $skip_category ) { continue; } $cached_path[$category_id] = $category_names[$category_id]; } } $this->Application->setCache($cache_key, $cached_path); } return $cached_path; } /** * Returns parent path from a given category * * @param int $category_id * @return string * @access public */ public function getParentPath($category_id) { $cache_key = 'parent_paths[%CIDSerial:' . $category_id . '%]'; $parent_path = $this->Application->getCache($cache_key); if ( $parent_path !== false ) { return $parent_path; } $config = $this->Application->getUnitConfig('c'); $this->Conn->nextQueryCachable = true; $sql = 'SELECT ParentPath FROM ' . $config->getTableName() . ' WHERE ' . $config->getIDField() . ' = ' . $category_id; $parent_path = $this->Conn->GetOne($sql); $this->Application->setCache($cache_key, $parent_path); return $parent_path; } /** * Not tag. Method for parameter selection from list in this TagProcessor * * @param Array $params * @param Array $possible_names * * @return string * @access protected */ protected function SelectParam($params, $possible_names) { if ( !is_array($params) ) { return ''; } if ( !is_array($possible_names) ) { $possible_names = explode(',', $possible_names); } foreach ($possible_names as $name) { if ( isset($params[$name]) ) { return $params[$name]; } } return ''; } } Index: branches/5.3.x/core/units/helpers/themes_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/themes_helper.php (revision 16599) +++ branches/5.3.x/core/units/helpers/themes_helper.php (revision 16600) @@ -1,677 +1,672 @@ themesFolder = FULL_PATH.'/themes'; } /** * Updates file system changes to database for selected theme * * @param string $theme_name * * @return mixed returns ID of created/used theme or false, if none created */ function refreshTheme($theme_name) { if (!file_exists($this->themesFolder . '/' . $theme_name)) { // requested theme was not found on hdd return false; } $config = $this->Application->getUnitConfig('theme'); $id_field = $config->getIDField(); $table_name = $config->getTableName(); $sql = 'SELECT * FROM ' . $table_name . ' WHERE Name = ' . $this->Conn->qstr($theme_name); $theme_info = $this->Conn->GetRow($sql); if ($theme_info) { $theme_id = $theme_info[$id_field]; $theme_enabled = $theme_info['Enabled']; } else { $theme_id = $theme_enabled = false; } $this->themeFiles = Array (); $theme_path = $this->themesFolder . '/' . $theme_name; if ($theme_id) { if (!$theme_enabled) { // don't process existing theme files, that are disabled return $theme_id; } // reset found mark for every themes file (if theme is not new) $sql = 'UPDATE '.TABLE_PREFIX.'ThemeFiles SET FileFound = 0 WHERE ThemeId = '.$theme_id; $this->Conn->Query($sql); // get all theme files from db $sql = 'SELECT FileId, CONCAT(FilePath, "/", FileName) AS FullPath FROM '.TABLE_PREFIX.'ThemeFiles WHERE ThemeId = '.$theme_id; $this->themeFiles = $this->Conn->GetCol($sql, 'FullPath'); } else { // theme was not found in db, but found on hdd -> create new $config = $this->getConfiguration($theme_path); $theme_info = Array ( 'Name' => $theme_name, 'Enabled' => 0, 'Description' => $theme_name, 'PrimaryTheme' => 0, 'CacheTimeout' => 3600, // not in use right now 'StylesheetId' => 0, // not in use right now 'LanguagePackInstalled' => 0, 'StylesheetFile' => isset($config['stylesheet_file']) ? $config['stylesheet_file'] : '', ); $this->Conn->doInsert($theme_info, $table_name); $theme_id = $this->Conn->getInsertID(); if (!$theme_enabled) { // don't process newly created theme files, because they are disabled return $theme_id; } } $this->_themeNames[$theme_id] = $theme_name; $this->FindThemeFiles('', $theme_path, $theme_id); // search from base theme directory // delete file records from db, that were not found on hdd $sql = 'DELETE FROM '.TABLE_PREFIX.'ThemeFiles WHERE ThemeId = '.$theme_id.' AND FileFound = 0'; $this->Conn->Query($sql); // install language packs, associated with theme (if any found and wasn't aready installed) if (!$theme_info['LanguagePackInstalled']) { $this->installThemeLanguagePack($theme_path); $fields_hash = Array ( 'LanguagePackInstalled' => 1, ); $this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $theme_id); } $this->_saveThemeSettings($theme_id, $theme_path); return $theme_id; } /** * Saves information from "/_install/theme.xml" files in theme * * @param int $theme_id * @param string $theme_path * @return void * @access protected */ protected function _saveThemeSettings($theme_id, $theme_path) { $config = $this->Application->getUnitConfig('theme'); $id_field = $config->getIDField(); $table_name = $config->getTableName(); $this->Conn->doUpdate($this->_getThemeSettings($theme_id, $theme_path), $table_name, $id_field . ' = ' . $theme_id); } /** * Installs module(-s) language pack for given theme * * @param string $theme_path * @param string|bool $module_name * @return void */ function installThemeLanguagePack($theme_path, $module_name = false) { if ( $module_name === false ) { $modules = $this->Application->ModuleInfo; } else { $modules = Array ($module_name => $this->Application->ModuleInfo[$module_name]); } /** @var LanguageImportHelper $language_import_helper */ $language_import_helper = $this->Application->recallObject('LanguageImportHelper'); foreach ($modules as $module_name => $module_info) { if ( $module_name == 'In-Portal' ) { continue; } $lang_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/english.lang'; if ( file_exists($lang_file) ) { $language_import_helper->performImport($lang_file, '|0|', ''); } } } /** * Parses information, discovered from "/_install/theme.xml" files in theme * * @param int $theme_id * @param string $theme_path * @return Array * @access protected */ protected function _getThemeSettings($theme_id, $theme_path) { $setting_mapping = Array ('image_resize_rules' => 'ImageResizeRules'); $ret = Array ('TemplateAliases' => Array (), 'ImageResizeRules' => Array ()); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { $xml_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/theme.xml'; if ( $module_name == 'In-Portal' || !file_exists($xml_file) ) { continue; } $theme = simplexml_load_file($xml_file); if ( $theme === false ) { // broken xml OR no aliases defined continue; } foreach ($theme as $setting) { /** @var SimpleXMLElement $setting */ $setting_name = $setting->getName(); $setting_value = trim($setting); if ( isset($setting_mapping[$setting_name]) ) { $ret[$setting_mapping[$setting_name]][] = $setting_value; continue; } // this is template alias $module_override = (string)$setting['module']; if ( $module_override ) { // allow to put template mappings form all modules into single theme.xml file $module_folder = $this->Application->findModule('Name', $module_override, 'TemplatePath'); } else { // no module specified -> use module based on theme.xml file location $module_folder = $module_info['TemplatePath']; } // only store alias, when template exists on disk if ( $this->getTemplateId($setting_value, $theme_id) ) { $alias = '#' . $module_folder . strtolower($setting->getName()) . '#'; // remember alias in global theme mapping $ret['TemplateAliases'][$alias] = $setting_value; // store alias in theme file record to use later in design dropdown $this->updateTemplate($setting_value, $theme_id, Array ('TemplateAlias' => $alias)); } } } $ret['TemplateAliases'] = serialize($ret['TemplateAliases']); $ret['ImageResizeRules'] = implode("\n", array_filter($ret['ImageResizeRules'])); return $ret; } /** * Returns theme configuration. * * @param string $theme_path Absolute path to theme. * * @return array */ protected function getConfiguration($theme_path) { $xml_file = $theme_path . '/_install/theme.xml'; if ( !file_exists($xml_file) ) { return array(); } $theme = simplexml_load_file($xml_file); if ( $theme === false ) { // broken xml OR no aliases defined return array(); } $ret = array(); foreach ( $theme->attributes() as $name => $value ) { $ret[(string)$name] = (string)$value; } return $ret; } /** * Returns ID of given physical template (relative to theme) given from ThemeFiles table * @param string $template_path * @param int $theme_id * @return int * @access public */ public function getTemplateId($template_path, $theme_id) { $template_path = $this->Application->getPhysicalTemplate($template_path); $sql = 'SELECT FileId FROM ' . TABLE_PREFIX . 'ThemeFiles WHERE ' . $this->getTemplateWhereClause($template_path, $theme_id); return $this->Conn->GetOne($sql); } /** * Updates template record with a given data * * @param string $template_path * @param int $theme_id * @param Array $fields_hash * @return void * @access public */ public function updateTemplate($template_path, $theme_id, $fields_hash) { $where_clause = $this->getTemplateWhereClause($template_path, $theme_id); $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'ThemeFiles', $where_clause); } /** * Returns where clause to get associated record from ThemeFiles table for given template path * @param string $template_path * @param int $theme_id * @return string * @access protected */ protected function getTemplateWhereClause($template_path, $theme_id) { $folder = dirname($template_path); $where_clause = Array ( 'ThemeId = ' . $theme_id, 'FilePath = ' . $this->Conn->qstr($folder == '.' ? '' : '/' . $folder), 'FileName = ' . $this->Conn->qstr(basename($template_path) . '.tpl'), ); return '(' . implode(') AND (', $where_clause) . ')'; } /** * Installs given module language pack and refreshed it from all themes * * @param string $module_name */ function synchronizeModule($module_name) { $sql = 'SELECT `Name`, ThemeId FROM ' . TABLE_PREFIX . 'Themes'; $themes = $this->Conn->GetCol($sql, 'ThemeId'); if (!$themes) { return ; } foreach ($themes as $theme_id => $theme_name) { $theme_path = $this->themesFolder . '/' . $theme_name; // install language pack $this->installThemeLanguagePack($theme_path, $module_name); // update TemplateAliases mapping $this->_saveThemeSettings($theme_id, $theme_path); } } /** * Searches for new templates (missing in db) in specified folder * * @param string $folder_path subfolder of searchable theme * @param string $theme_path theme path from web server root * @param int $theme_id id of theme we are scanning * @param int $auto_structure_mode */ function FindThemeFiles($folder_path, $theme_path, $theme_id, $auto_structure_mode = 1) { $ignore_regexp = $this->getIgnoreRegexp($theme_path . $folder_path); $iterator = new DirectoryIterator($theme_path . $folder_path . '/'); /** @var DirectoryIterator $file_info */ foreach ($iterator as $file_info) { $filename = $file_info->getFilename(); $auto_structure = preg_match($ignore_regexp, $filename) ? 2 : $auto_structure_mode; $file_path = $folder_path . '/' . $filename; // don't pass path to theme top folder! if ( $file_info->isDir() && !$file_info->isDot() && $filename != 'CVS' && $filename != '.svn' ) { $this->FindThemeFiles($file_path, $theme_path, $theme_id, $auto_structure); } elseif ( pathinfo($filename, PATHINFO_EXTENSION) == 'tpl' ) { $meta_info = $this->_getTemplateMetaInfo(trim($file_path, '/'), $theme_id); $file_id = isset($this->themeFiles[$file_path]) ? $this->themeFiles[$file_path] : false; $file_description = array_key_exists('desc', $meta_info) ? $meta_info['desc'] : ''; if ($file_id) { // file was found in db & on hdd -> mark as existing $fields_hash = Array ( 'FileFound' => 1, 'Description' => $file_description, 'FileType' => $auto_structure, 'FileMetaInfo' => serialize($meta_info), ); $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'ThemeFiles', 'FileId = ' . $file_id); } else { // file was found on hdd, but missing in db -> create new file record $fields_hash = Array ( 'ThemeId' => $theme_id, 'FileName' => $filename, 'FilePath' => $folder_path, 'Description' => $file_description, 'FileType' => $auto_structure, // 1 - built-in, 0 - custom (not in use right now), 2 - skipped in structure 'FileMetaInfo' => serialize($meta_info), 'FileFound' => 1, ); $this->Conn->doInsert($fields_hash, TABLE_PREFIX.'ThemeFiles'); $this->themeFiles[$file_path] = $this->Conn->getInsertID(); } // echo 'FilePath: ['.$folder_path.']; FileName: ['.$filename.']; IsNew: ['.($file_id > 0 ? 'NO' : 'YES').']
'; } } } /** * Returns single regular expression to match all ignore patters, that are valid for given folder * * @param string $folder_path * @return string */ protected function getIgnoreRegexp($folder_path) { // always ignore design and element templates $ignore = '\.des\.tpl$|\.elm\.tpl$'; $sms_ignore_file = $folder_path . '/.smsignore'; if ( file_exists($sms_ignore_file) ) { $manual_patterns = array_map('trim', file($sms_ignore_file)); foreach ($manual_patterns as $manual_pattern) { $ignore .= '|' . str_replace('/', '\\/', $manual_pattern); } } return '/' . $ignore . '/'; } /** * Returns template information (name, description, path) from it's header comment * * @param string $template * @param int $theme_id * @return Array */ function _getTemplateMetaInfo($template, $theme_id) { static $init_made = false; if (!$init_made) { $this->Application->InitParser(true); $init_made = true; } $template = 'theme:' . $this->_themeNames[$theme_id] . '/' . $template; $template_file = $this->Application->TemplatesCache->GetRealFilename($template); // ".tpl" was added before return $this->parseTemplateMetaInfo($template_file); } function parseTemplateMetaInfo($template_file) { if (!file_exists($template_file)) { // when template without info it's placed in top category return Array (); } $template_data = file_get_contents($template_file); if (substr($template_data, 0, 6) == '*/ $comment_end = strpos($template_data, '##-->'); if ($comment_end === false) { // badly formatted comment return Array (); } $comment = trim( substr($template_data, 6, $comment_end - 6) ); if (preg_match_all('/<(NAME|DESC|SECTION)>(.*?)<\/(NAME|DESC|SECTION)>/is', $comment, $regs)) { $ret = Array (); foreach ($regs[1] as $param_order => $param_name) { $ret[ strtolower($param_name) ] = trim($regs[2][$param_order]); } if (array_key_exists('section', $ret) && $ret['section']) { $category_path = explode('||', $ret['section']); $category_path = array_map('trim', $category_path); $ret['section'] = implode('||', $category_path); } return $ret; } } return Array (); } /** * Updates file system changes to database for all themes (including new ones) * */ function refreshThemes() { $themes_found = Array (); try { $iterator = new DirectoryIterator($this->themesFolder . '/'); /** @var DirectoryIterator $file_info */ foreach ($iterator as $file_info) { $filename = $file_info->getFilename(); if ( $file_info->isDir() && !$file_info->isDot() && $filename != '.svn' && $filename != 'CVS' ) { $theme_id = $this->refreshTheme($filename); if ( $theme_id ) { $themes_found[] = $theme_id; // increment serial of updated themes $this->Application->incrementCacheSerial('theme', $theme_id); } } } } catch ( UnexpectedValueException $e ) { } $config = $this->Application->getUnitConfig('theme'); $id_field = $config->getIDField(); $table_name = $config->getTableName(); // 1. only one theme found -> enable it and make primary /*if (count($themes_found) == 1) { $sql = 'UPDATE ' . $table_name . ' SET Enabled = 1, PrimaryTheme = 1 WHERE ' . $id_field . ' = ' . current($themes_found); $this->Conn->Query($sql); }*/ // 2. if none themes found -> delete all from db OR delete all except of found themes $sql = 'SELECT ' . $id_field . ' FROM ' . $table_name; if ( $themes_found ) { $sql .= ' WHERE ' . $id_field . ' NOT IN (' . implode(',', $themes_found) . ')'; } $theme_ids = $this->Conn->GetCol($sql); $this->deleteThemes($theme_ids); foreach ($theme_ids as $theme_id) { // increment serial of deleted themes $this->Application->incrementCacheSerial('theme', $theme_id); } $this->Application->incrementCacheSerial('theme'); $this->Application->incrementCacheSerial('theme-file'); - - /** @var MinifyHelper $minify_helper */ - $minify_helper = $this->Application->recallObject('MinifyHelper'); - - $minify_helper->delete(); } /** * Deletes themes with ids passed from db * * @param Array $theme_ids */ function deleteThemes($theme_ids) { if (!$theme_ids) { return ; } $config = $this->Application->getUnitConfig('theme'); $id_field = $config->getIDField(); $sql = 'DELETE FROM '. $config->getTableName() .' WHERE '.$id_field.' IN ('.implode(',', $theme_ids).')'; $this->Conn->Query($sql); $sql = 'DELETE FROM '.TABLE_PREFIX.'ThemeFiles WHERE '.$id_field.' IN ('.implode(',', $theme_ids).')'; $this->Conn->Query($sql); } /** * Returns current theme (also works in admin) * * @return int */ function getCurrentThemeId() { static $theme_id = null; if (isset($theme_id)) { return $theme_id; } if ($this->Application->isAdmin) { // get theme, that user selected in catalog $theme_id = $this->Application->RecallVar('theme_id'); if ($theme_id === false) { // query, because "m_theme" is always empty in admin $config = $this->Application->getUnitConfig('theme'); $sql = 'SELECT ' . $config->getIDField() . ' FROM ' . $config->getTableName() . ' WHERE (PrimaryTheme = 1) AND (Enabled = 1)'; $theme_id = $this->Conn->GetOne($sql); } return $theme_id; } // use current theme, because it's available on Front-End $theme_id = $this->Application->GetVar('m_theme'); if (!$theme_id) { // happens in mod-rewrite mode, then requested template is not found $theme_id = $this->Application->GetDefaultThemeId(); } return $theme_id; } /** * Returns page id based on given template * * @param string $template * @param int $theme_id * @return int */ function getPageByTemplate($template, $theme_id = null) { if (!isset($theme_id)) { // during mod-rewrite url parsing current theme // is not available to kHTTPQuery class, so don't use it $theme_id = (int)$this->getCurrentThemeId(); } $template_crc = kUtil::crc32(mb_strtolower($template)); $categories_config = $this->Application->getUnitConfig('c'); $sql = 'SELECT ' . $categories_config->getIDField() . ' FROM ' . $categories_config->getTableName() . ' WHERE ( (NamedParentPathHash = ' . $template_crc . ') OR (`Type` = ' . PAGE_TYPE_TEMPLATE . ' AND CachedTemplateHash = ' . $template_crc . ') ) AND (ThemeId = ' . $theme_id . ($theme_id > 0 ? ' OR ThemeId = 0' : '') . ')'; return $this->Conn->GetOne($sql); } } Index: branches/5.3.x/core/units/content/content_tp.php =================================================================== --- branches/5.3.x/core/units/content/content_tp.php (revision 16599) +++ branches/5.3.x/core/units/content/content_tp.php (revision 16600) @@ -1,53 +1,49 @@ getObject($params); - - $params['pass'] = 'm,c,content'; - $params['c_id'] = $object->GetDBField('PageId'); $params['admin'] = 1; $params['temp_mode'] = 0; $params['template'] = 'categories/edit_content'; $params['button_icon'] = 'content_mode.png'; $params['button_class'] = 'cms-edit-btn'; $params['button_title'] = '+' . $this->Application->Phrase('la_btn_EditContent', false, true); if ( defined('DEBUG_MODE') && DEBUG_MODE ) { $params['button_title'] .= ' - #' . $params['num']; } unset($params['num']); return parent::AdminEditButton($params); } -} \ No newline at end of file + +} Index: branches/5.3.x/core/units/groups/groups_config.php =================================================================== --- branches/5.3.x/core/units/groups/groups_config.php (revision 16599) +++ branches/5.3.x/core/units/groups/groups_config.php (revision 16600) @@ -1,170 +1,170 @@ 'g', 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'GroupsEventHandler', 'file' => 'groups_event_handler.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'GroupTagProcessor', 'file' => 'group_tp.php', 'build_event' => 'OnBuild'), 'AutoLoad' => true, 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'PerPage', 4 => 'event', 5 => 'mode', ), 'IDField' => 'GroupId', 'StatusField' => Array ('Enabled'), 'TitleField' => 'Name', 'SubItems' => Array ('g-perm', 'g-ug'), 'TitlePresets' => Array ( 'default' => Array ( 'new_status_labels' => Array ('g' => '!la_title_Adding_Group!'), 'edit_status_labels' => Array ('g' => '!la_title_Editing_Group!'), 'new_titlefield' => Array ('g' => ''), ), 'group_list' => Array ( 'prefixes' => Array ('g.total_List'), 'format' => "!la_title_Groups!", 'toolbar_buttons' => Array ('new_item', 'edit', 'delete', 'e-mail', 'view', 'dbl-click'), ), 'groups_edit' => Array ( 'prefixes' => Array ('g'), 'format' => "#g_status# '#g_titlefield#' - !la_title_General!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'groups_edit_users' => Array ( 'prefixes' => Array ('g', 'g-ug_List'), 'format' => "#g_status# '#g_titlefield#' - !la_title_Users!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next', 'usertogroup', 'delete', 'view'), ), 'groups_edit_permissions' => Array ( 'prefixes' => Array ('g'), 'format' => "#g_status# '#g_titlefield#' - !la_title_Permissions!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'groups_edit_additional_permissions' => Array ( 'prefixes' => Array ('g'), 'format' => "#g_status# '#g_titlefield#' - !la_title_AdditionalPermissions!", 'toolbar_buttons' => Array ('select', 'cancel'), ), 'select_group' => Array ( 'prefixes' => Array ('g.user_List'), 'format' => "!la_title_Groups! - !la_title_SelectGroup!", 'toolbar_buttons' => Array ('select', 'cancel', 'view'), ), ), 'EditTabPresets' => Array ( 'Default' => Array ( 'general' => Array ('title' => 'la_tab_General', 't' => 'groups/groups_edit', 'priority' => 1), 'users' => Array ('title' => 'la_tab_Users', 't' => 'groups/groups_edit_users', 'priority' => 2), 'permissions' => Array ('title' => 'la_tab_Permissions', 't' => 'groups/groups_edit_permissions', 'priority' => 3), ), ), 'PermSection' => Array ('main' => 'in-portal:user_groups'), 'TableName' => TABLE_PREFIX.'UserGroups', 'ListSQLs' => Array ( '' => ' SELECT %1$s.* %2$s FROM %1$s', ), 'ListSortings' => Array ( '' => Array ( 'Sorting' => Array ('Name' => 'asc'), ), ), 'CalculatedFields' => Array ( 'total' => Array ( 'UserCount' => 'SELECT COUNT(*) FROM ' . TABLE_PREFIX . 'UserGroupRelations ug WHERE ug.GroupId = %1$s.GroupId', ), ), 'Fields' => Array ( 'GroupId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'Name' => Array ('type' => 'string', 'not_null' => 1, 'required' => 1, 'default' => ''), - 'Description' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null), + 'Description' => Array ('type' => 'string', 'default' => null), 'CreatedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'), 'System' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'Personal' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'Enabled' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Enabled', 0 => 'la_Disabled'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1), 'FrontRegistration' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'IPRestrictions' => Array ('type' => 'string', 'default' => NULL), ), 'VirtualFields' => Array ( 'UserCount' => Array ('type' => 'int', 'default' => 0), ), 'Grids' => Array ( 'Default' => Array ( 'Icons' => Array (1 => 'icon16_item.png', 0 => 'icon16_disabled.png'), 'Fields' => Array ( 'GroupId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ), 'Name' => Array ('title' => 'column:la_fld_GroupName', 'width' => 200, ), 'UserCount' => Array ('title' => 'la_col_UserCount', 'filter_block' => 'grid_range_filter', 'width' => 100, ), 'FrontRegistration' => Array ('filter_block' => 'grid_options_filter', 'width' => 150, ), ), ), 'UserGroups' => Array ( 'Icons' => Array (1 => 'icon16_item.png', 0 => 'icon16_disabled.png'), 'Fields' => Array ( 'GroupId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ), 'Name' => Array ('title' => 'column:la_fld_GroupName', 'width' => 150, ), ), ), 'Radio' => Array ( 'Icons' => Array (1 => 'icon16_item.png', 0 => 'icon16_disabled.png'), 'Selector' => 'radio', 'Fields' => Array ( 'GroupId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_radio_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ), 'Name' => Array ('title' => 'column:la_fld_GroupName', 'width' => 150, ), 'Description' => Array ('width' => 250, ), ), ), 'GroupSelector' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', 0 => 'icon16_disabled.png', 1 => 'icon16_item.png', ), 'Fields' => Array ( 'GroupId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ), 'Name' => Array ('title' => 'column:la_fld_GroupName', 'width' => 150, ), 'Description' => Array ('width' => 250, ), ), ), ), -); \ No newline at end of file +); Index: branches/5.3.x/core/units/reviews/reviews_config.php =================================================================== --- branches/5.3.x/core/units/reviews/reviews_config.php (revision 16599) +++ branches/5.3.x/core/units/reviews/reviews_config.php (revision 16600) @@ -1,214 +1,210 @@ 'rev', 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'ReviewsEventHandler', 'file' => 'reviews_event_handler.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'ReviewsTagProcessor', 'file' => 'reviews_tag_processor.php', 'build_event' => 'OnBuild'), 'AutoLoad' => true, 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'PerPage', 4 => 'event', 5 => 'mode', ), 'ParentPrefix' => 'p', // replace all usage of rev to "p-rev" and then remove this param from here and Prefix too 'ConfigMapping' => Array ( 'PerPage' => 'Comm_Perpage_Reviews', 'ReviewDelayInterval' => 'product_ReviewDelay_Value', 'ReviewDelayValue' => 'product_ReviewDelay_Interval', ), 'IDField' => 'ReviewId', 'StatusField' => Array ('Status'), // field, that is affected by Approve/Decline events 'TableName' => TABLE_PREFIX.'CatalogReviews', 'ParentTableKey' => 'ResourceId', // linked field in master table 'ForeignKey' => 'ItemId', // linked field in sub-table 'AutoDelete' => true, 'AutoClone' => true, 'TitlePresets' => Array ( 'reviews_edit' => Array ('format' => "!la_title_Editing_Review!"), 'reviews' => Array ( 'toolbar_buttons' => Array ('edit', 'delete', 'approve', 'decline', 'view', 'dbl-click'), ), ), 'CalculatedFields' => Array ( '' => Array ( 'ReviewedBy' => 'CASE %1$s.CreatedById WHEN ' . USER_ROOT . ' THEN "root" WHEN ' . USER_GUEST . ' THEN "Guest" ELSE IF(CONCAT(pu.FirstName, pu.LastName) <> "", CONCAT(pu.FirstName, " ", pu.LastName), pu.Username) END', ), 'products' => Array ( 'ReviewedBy' => 'CASE %1$s.CreatedById WHEN ' . USER_ROOT . ' THEN "root" WHEN ' . USER_GUEST . ' THEN "Guest" ELSE IF(CONCAT(pu.FirstName, pu.LastName) <> "", CONCAT(pu.FirstName, " ", pu.LastName), pu.Username) END', 'ItemName' => 'pr.l1_Name', 'ProductId' => 'pr.ProductId', ), 'product' => Array ( 'ReviewedBy' => 'CASE %1$s.CreatedById WHEN ' . USER_ROOT . ' THEN "root" WHEN ' . USER_GUEST . ' THEN "Guest" ELSE IF(CONCAT(pu.FirstName, pu.LastName) <> "", CONCAT(pu.FirstName, " ", pu.LastName), pu.Username) END', 'ItemName' => 'pr.l1_Name', 'ProductId' => 'pr.ProductId', ), ), // key - special, value - list select sql 'ListSQLs' => Array ( '' => ' SELECT %1$s.* %2$s FROM %1$s LEFT JOIN ' . TABLE_PREFIX . 'Users pu ON pu.PortalUserId = %1$s.CreatedById', 'products' => ' SELECT %1$s.* %2$s FROM %1$s LEFT JOIN ' . TABLE_PREFIX . 'Products pr ON pr.ResourceId = %1$s.ItemId LEFT JOIN ' . TABLE_PREFIX . 'Users pu ON pu.PortalUserId = %1$s.CreatedById', 'product' => ' SELECT %1$s.* %2$s FROM %1$s LEFT JOIN ' . TABLE_PREFIX . 'Products pr ON pr.ResourceId = %1$s.ItemId LEFT JOIN ' . TABLE_PREFIX . 'Users pu ON pu.PortalUserId = %1$s.CreatedById', ), 'ListSortings' => Array ( '' => Array ( 'ForcedSorting' => Array ('Priority' => 'desc'), 'Sorting' => Array ('ReviewId' => 'desc'), ) ), 'Fields' => Array ( 'ReviewId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'CreatedOn' => Array ( 'type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#', ), - 'ReviewText' => Array ( - 'type' => 'string', - 'formatter' => 'kFormatter', - 'using_fck' => 1, 'default' => null, 'required' => 1, - ), + 'ReviewText' => Array ('type' => 'string', 'default' => null, 'required' => 1), 'Rating' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array ( 0 => 'lu_None', 1 => 'lu_Rating_1', 2 => 'lu_Rating_2', 3 => 'lu_Rating_3', 4 => 'lu_Rating_4', 5 => 'lu_Rating_5'), 'use_phrases' => 1, 'min_value_inc' => 0, 'max_value_inc' => 5, 'not_null' => 1, 'default' => 0, ), 'IPAddress' => Array ( 'type' => 'string', 'max_value_inc' => 15, 'not_null' =>1, 'default' => '', ), 'ItemId' => Array ( 'type' => 'int', 'not_null' => 1, 'default' => 0 ), 'CreatedById' => Array ( 'type' => 'int', 'formatter' => 'kLEFTFormatter', 'options' => Array (USER_ROOT => 'root', USER_GUEST => 'Guest'), 'left_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Users WHERE %s', 'left_key_field' => 'PortalUserId', 'left_title_field' => USER_TITLE_FIELD, 'required' => 1, 'default' => NULL, 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'), ), 'ItemType' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'Priority' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'Status' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'use_phrases' => 1, 'options' => Array ( 0 => 'la_Disabled', 1 => 'la_Active', 2 => 'la_Pending', ), 'not_null' =>1, 'default' => 2, ), 'TextFormat' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_text', 1 => 'la_html'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0, ), 'Module' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''), 'HelpfulCount' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'NotHelpfulCount' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0) ), 'VirtualFields' => Array ( 'ReviewedBy' => Array ('type' => 'string', 'default' => ''), 'CatalogItemName' => Array ('type' => 'string', 'default' => ''), 'CatalogItemId' => Array ('type' => 'int', 'default' => 0), 'CatalogItemCategory' => Array ('type' => 'int', 'default' => 0), 'ItemName' => Array ('type' => 'string', 'default' => ''), 'ProductId' => Array ('type' => 'int', 'default' => 0), ), 'Grids' => Array ( 'Default' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', 0 => 'icon16_disabled.png', 1 => 'icon16_item.png', 2 => 'icon16_pending.png', ), 'Fields' => Array ( 'ReviewId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ), 'ReviewText' => Array ('filter_block' => 'grid_like_filter', 'width' => 210, 'first_chars' => 200, ), 'ReviewedBy' => Array ( 'title' => 'la_col_ReviewedBy', 'filter_block' => 'grid_like_filter', 'width' => 100, ), 'CreatedOn' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 145, ), 'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 80, ), 'Rating' => Array ('filter_block' => 'grid_options_filter', 'width' => 80, ), 'HelpfulCount' => Array ('filter_block' => 'grid_range_filter'), 'NotHelpfulCount' => Array ('filter_block' => 'grid_range_filter'), ), ), 'ReviewsSection' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', 0 => 'icon16_disabled.png', 1 => 'icon16_item.png', 2 => 'icon16_pending.png', ), 'Fields' => Array ( 'ReviewId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ), 'ReviewText' => Array ('data_block' => 'grid_reviewtext_td', 'filter_block' => 'grid_like_filter', 'width' => 210, 'first_chars' => 200, ), 'ReviewedBy' => Array ( 'title' => 'la_col_ReviewedBy', 'filter_block' => 'grid_like_filter', 'width' => 100, ), 'CreatedOn' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 145, ), 'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 80, ), 'Rating' => Array ('filter_block' => 'grid_options_filter', 'width' => 80, ), 'HelpfulCount' => Array ('filter_block' => 'grid_range_filter'), 'NotHelpfulCount' => Array ('filter_block' => 'grid_range_filter'), ), ), ), ); Index: branches/5.3.x/core/units/forms/forms/forms_config.php =================================================================== --- branches/5.3.x/core/units/forms/forms/forms_config.php (revision 16599) +++ branches/5.3.x/core/units/forms/forms/forms_config.php (revision 16600) @@ -1,227 +1,231 @@ 'form', 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'FormsEventHandler', 'file' => 'forms_eh.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'FormsTagProcessor', 'file' => 'forms_tp.php', 'build_event' => 'OnBuild'), 'AutoLoad' => true, 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'PerPage', 4 => 'event', 5 => 'mode', ), 'ScheduledTasks' => Array ( 'check_submission_repies' => Array ('EventName' => 'OnProcessReplies', 'RunSchedule' => '0 * * * *'), 'check_bounced_submission_repies' => Array ('EventName' => 'OnProcessBouncedReplies', 'RunSchedule' => '0 */5 * * *'), ), 'Hooks' => Array ( Array ( 'Mode' => hBEFORE, 'Conditional' => false, 'HookToPrefix' => 'form', //self 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnAfterConfigRead'), 'DoPrefix' => '', 'DoSpecial' => '', 'DoEvent' => 'OnCreateSubmissionNodes', ), ), 'TableName' => TABLE_PREFIX.'Forms', 'IDField' => 'FormId', 'TitleField' => 'Title', 'PermSection' => Array ('main' => 'in-portal:forms'), 'Sections' => Array ( 'in-portal:forms' => Array ( 'parent' => 'in-portal:site', 'icon' => 'form', 'use_parent_header' => 1, 'label' => 'la_tab_CMSForms', //'la_tab_FormsConfig', 'url' => Array ('t' => 'forms/forms_list', 'pass' => 'm'), // set "container" parameter (in section definition, not url) to true when form editing should be disabled, but submissions still visible 'permissions' => Array ('view', 'add', 'edit', 'delete'), 'priority' => 6, // 'show_mode' => smSUPER_ADMIN, 'type' => stTREE, ), ), 'TitlePresets' => Array ( 'default' => Array ( 'new_status_labels' => Array ('form' => '!la_title_Adding_Form!'), 'edit_status_labels' => Array ('form' => '!la_title_Editing_Form!'), 'new_titlefield' => Array ('form' => ''), ), 'forms_list' => Array ( 'prefixes' => Array ('form_List'), 'format' => "!la_title_Forms!", 'toolbar_buttons' => Array ('new_item', 'edit', 'delete', 'view', 'dbl-click'), ), 'forms_edit' => Array ( 'prefixes' => Array ('form'), 'format' => "#form_status# '#form_titlefield#' - !la_title_General!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'forms_edit_fields' => Array ( 'prefixes' => Array ('form'), 'format' => "#form_status# '#form_titlefield#' - !la_title_Fields!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next', 'new_item', 'edit', 'delete', 'move_up', 'move_down', 'view', 'dbl-click'), ), 'form_edit_emails' => Array ( 'prefixes' => Array ('form'), 'format' => "#form_status# '#form_titlefield#' - !la_title_EmailCommunication!", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'form_field_edit' => Array ( 'prefixes' => Array ('form', 'formflds'), 'new_status_labels' => Array ('formflds'=>"!la_title_Adding_FormField!"), 'edit_status_labels' => Array ('formflds' => '!la_title_Editing_FormField!'), 'new_titlefield' => Array ('formflds' => ''), 'format' => "#form_status# '#form_titlefield#' - #formflds_status# '#formflds_titlefield#'", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), 'tree_submissions' => Array ( 'format' => "!la_title_FormSubmissions!", ), ), 'EditTabPresets' => Array ( 'Default' => Array ( 'general' => Array ('title' => 'la_tab_General', 't' => 'forms/forms_edit', 'priority' => 1), 'fields' => Array ('title' => 'la_tab_Fields', 't' => 'forms/forms_edit_fields', 'priority' => 2), 'emails' => Array ('title' => 'la_tab_EmailCommunication', 't' => 'forms/form_edit_emails', 'priority' => 3), ), ), 'ListSQLs' => Array ( '' => ' SELECT %1$s.* %2$s FROM %1$s', ), 'SubItems' => Array ('formflds'), 'ListSortings' => Array ( '' => Array ( 'Sorting' => Array ('Title' => 'asc'), ) ), 'Fields' => Array ( 'FormId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0, 'filter_type' => 'equals'), 'Title' => Array ('type' => 'string', 'not_null' => 1, 'default' => '', 'required' => 1), 'Description' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null), 'RequireLogin' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'UseSecurityImage' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'SubmitNotifyEmail' => Array ( 'type' => 'string', 'max_len' => 255, 'formatter' => 'kFormatter', 'regexp' => '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', 'sample_value' => 'email@domain.com', 'error_msgs' => Array ('invalid_format' => '!la_invalid_email!'), 'not_null' => 1, 'default' => '' ), 'EnableEmailCommunication' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'ProcessUnmatchedEmails' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'ReplyFromName' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'ReplyFromEmail' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'ReplyCc' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'ReplyBcc' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), - 'ReplyMessageSignature' => Array ('type' => 'string', 'default' => NULL), + 'ReplyMessageSignature' => Array ( + 'type' => 'string', + 'formatter' => 'kFormatter', 'using_fck' => 1, + 'default' => NULL, + ), 'ReplyServer' => Array ( 'type' => 'string', 'max_len' => 255, 'error_msgs' => Array ( 'connection_failed' => '!la_error_ConnectionFailed!', 'message_listing_failed' => '!la_error_MessagesListReceivingFailed!', ), 'not_null' => 1, 'default' => '' ), 'ReplyPort' => Array ('type' => 'int', 'not_null' => 1, 'default' => 110), 'ReplyUsername' => Array ( 'type' => 'string', 'max_len' => 255, 'error_msgs' => Array ( 'login_failed' => '!la_error_LoginFailed!', ), 'not_null' => 1, 'default' => '' ), 'ReplyPassword' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'BounceEmail' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'BounceServer' => Array ( 'type' => 'string', 'max_len' => 255, 'error_msgs' => Array ( 'connection_failed' => '!la_error_ConnectionFailed!', 'message_listing_failed' => '!la_error_MessageListingFailed!', ), 'not_null' => 1, 'default' => '' ), 'BouncePort' => Array ('type' => 'int', 'not_null' => 1, 'default' => 110), 'BounceUsername' => Array ( 'type' => 'string', 'max_len' => 255, 'error_msgs' => Array ( 'login_failed' => '!la_error_LoginFailed!', ), 'not_null' => 1, 'default' => '' ), 'BouncePassword' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), ), 'Grids' => Array ( 'Default' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', 0 => 'icon16_disabled.png', 1 => 'icon16_item.png', 2 => 'icon16_pending.png', ), 'Fields' => Array ( 'FormId' => Array ( 'title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ), 'Title' => Array ('filter_block' => 'grid_like_filter', 'width' => 220, ), 'Description' => Array ('filter_block' => 'grid_like_filter', 'width' => 300, ), 'RequireLogin' => Array ('filter_block' => 'grid_options_filter', 'width' => 80,), 'UseSecurityImage' => Array ('filter_block' => 'grid_options_filter', 'width' => 110,), 'EnableEmailCommunication' => Array ('title' => 'la_col_EnableEmailCommunication', 'filter_block' => 'grid_options_filter', 'width' => 120,), 'SubmitNotifyEmail' => Array ('filter_block' => 'grid_like_filter'), ), ), ), ); \ No newline at end of file Index: branches/5.3.x/core/units/forms/submission_log/submission_log_config.php =================================================================== --- branches/5.3.x/core/units/forms/submission_log/submission_log_config.php (revision 16599) +++ branches/5.3.x/core/units/forms/submission_log/submission_log_config.php (revision 16600) @@ -1,130 +1,130 @@ 'submission-log', 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'SubmissionLogEventHandler', 'file' => 'submission_log_eh.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'SubmissionLogTagProcessor', 'file' => 'submission_log_tp.php', 'build_event' => 'OnBuild'), 'AutoLoad' => true, 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'event', 4 => 'form_id' ), 'IDField' => 'SubmissionLogId', 'TableName' => TABLE_PREFIX . 'FormSubmissionReplies', 'StatusField' => Array ('ReplyStatus'), 'ParentPrefix' => 'formsubs', 'ForeignKey' => 'FormSubmissionId', 'ParentTableKey' => 'FormSubmissionId', 'AutoDelete' => true, 'AutoClone' => true, 'TitleField' => 'Subject', 'ListSQLs' => Array ( '' => ' SELECT %1$s.* %2$s FROM %1$s', ), 'ListSortings' => Array ( '' => Array ( 'Sorting' => Array ('SubmissionLogId' => 'desc'), ) ), 'Fields' => Array ( 'SubmissionLogId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'FormSubmissionId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'FromEmail' => Array ( 'type' => 'string', 'max_len' => 255, 'regexp' => '/' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . '/', 'not_null' => 1, 'required' => 1, 'default' => '' ), 'ToEmail' => Array ( 'type' => 'string', 'max_len' => 255, 'regexp' => '/' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . '/', 'not_null' => 1, 'required' => 1, 'default' => '' ), 'Cc' => Array ('type' => 'string', 'default' => NULL), 'Bcc' => Array ('type' => 'string', 'default' => NULL), 'Subject' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'required' => 1, 'default' => ''), - 'Message' => Array ('type' => 'string', 'required' => 1, 'using_fck' => 1, 'default' => NULL), + 'Message' => Array ('type' => 'string', 'required' => 1, 'default' => NULL), 'Attachment' => Array ( 'type' => 'string', 'formatter' => 'kUploadFormatter', 'upload_dir' => SUBMISSION_LOG_ATTACHMENT_PATH, 'file_types' => '*.*', 'files_description' => '!la_hint_AllFiles!', 'multiple' => 100, 'default' => NULL ), 'ReplyStatus' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 // create as not replied ), 'SentStatus' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No', 2 => 'la_opt_Bounce'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 // create as not sent ), 'SentOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL), 'RepliedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL), 'VerifyCode' => Array ('type' => 'string', 'max_len' => 32, 'not_null' => 1, 'default' => ''), 'DraftId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'MessageId' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'BounceInfo' => Array ('type' => 'string', 'default' => NULL), 'BounceDate' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL), ), 'VirtualFields' => Array ( 'ReplyTo' => Array ('type' => 'int', 'default' => null), ), 'Grids' => Array ( 'Default' => Array ( 'Icons' => Array (0 => 'icon16_not_replied.gif', 1 => 'icon16_replied.gif'), 'Fields' => Array ( 'SubmissionLogId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', ), 'Subject' => Array ('data_block' => 'grid_subject_td', 'filter_block' => 'grid_like_filter',), 'Message' => Array ('filter_block' => 'grid_like_filter', 'first_chars' => 100), 'ReplyStatus' => Array ('filter_block' => 'grid_options_filter',), 'SentStatus' => Array ('filter_block' => 'grid_options_filter',), 'FromEmail' => Array ('filter_block' => 'grid_like_filter',), 'ToEmail' => Array ('filter_block' => 'grid_like_filter',), 'SentOn' => Array ('filter_block' => 'grid_date_range_filter',), 'RepliedOn' => Array ('filter_block' => 'grid_date_range_filter',), 'Cc' => Array ('filter_block' => 'grid_like_filter', 'hidden' => 1), 'Bcc' => Array ('filter_block' => 'grid_like_filter', 'hidden' => 1), 'BounceInfo' => Array ('filter_block' => 'grid_like_filter', 'hidden' => 1), 'BounceDate' => Array ('filter_block' => 'grid_date_range_filter', 'hidden' => 1), ), ), ), - ); \ No newline at end of file + ); Index: branches/5.3.x/core/units/admin/admin_events_handler.php =================================================================== --- branches/5.3.x/core/units/admin/admin_events_handler.php (revision 16599) +++ branches/5.3.x/core/units/admin/admin_events_handler.php (revision 16600) @@ -1,1420 +1,1443 @@ Array ('self' => true), 'OnGetPopupSize' => Array ('self' => true), 'OnClosePopup' => Array ('self' => true), 'OnSaveSetting' => Array ('self' => true), 'OnDropTempTablesByWID' => Array ('self' => true), 'OnProcessSelected' => Array ('self' => true), // allow CSV import file upload ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Checks user permission to execute given $event * * @param kEvent $event * @return bool * @access public */ public function CheckPermission(kEvent $event) { $perm_value = null; - $system_events = Array ( + $system_events = array( 'OnResetModRwCache', 'OnResetSections', 'OnResetConfigsCache', 'OnResetParsedData', 'OnResetMemcache', 'OnDeleteCompiledTemplates', 'OnCompileTemplates', 'OnGenerateTableStructure', 'OnSynchronizeDBRevisions', - 'OnDeploy', 'OnRebuildThemes', 'OnCheckPrefixConfig', 'OnMemoryCacheGet', 'OnMemoryCacheSet' + 'OnDeploy', 'OnRebuildThemes', 'OnDumpAssets', 'OnCheckPrefixConfig', 'OnMemoryCacheGet', + 'OnMemoryCacheSet', ); if ( in_array($event->Name, $system_events) ) { // events from "Tools -> System Tools" section are controlled via that section "edit" permission $perm_value = /*$this->Application->isDebugMode() ||*/ $this->Application->CheckPermission($event->getSection() . '.edit'); } $tools_events = Array ( 'OnBackup' => 'in-portal:backup.view', 'OnBackupProgress' => 'in-portal:backup.view', 'OnDeleteBackup' => 'in-portal:backup.view', 'OnBackupCancel' => 'in-portal:backup.view', 'OnRestore' => 'in-portal:restore.view', 'OnRestoreProgress' => 'in-portal:restore.view', 'OnRestoreCancel' => 'in-portal:backup.view', 'OnSqlQuery' => 'in-portal:sql_query.view', ); if ( array_key_exists($event->Name, $tools_events) ) { $perm_value = $this->Application->CheckPermission($tools_events[$event->Name]); } if ( $event->Name == 'OnSaveMenuFrameWidth' ) { $perm_value = $this->Application->isAdminUser; } /** @var kPermissionsHelper $perm_helper */ $perm_helper = $this->Application->recallObject('PermissionsHelper'); $csv_events = Array ('OnCSVImportBegin', 'OnCSVImportStep', 'OnExportCSV', 'OnGetCSV'); if ( in_array($event->Name, $csv_events) ) { /** @var kCSVHelper $csv_helper */ $csv_helper = $this->Application->recallObject('CSVHelper'); $prefix = $csv_helper->getPrefix(stripos($event->Name, 'import') !== false); $perm_mapping = Array ( 'OnCSVImportBegin' => 'OnProcessSelected', 'OnCSVImportStep' => 'OnProcessSelected', 'OnExportCSV' => 'OnLoad', 'OnGetCSV' => 'OnLoad', ); $tmp_event = new kEvent($prefix . ':' . $perm_mapping[$event->Name] ); $perm_value = $perm_helper->CheckEventPermission($tmp_event, $this->permMapping); } if ( isset($perm_value) ) { return $perm_helper->finalizePermissionCheck($event, $perm_value); } return parent::CheckPermission($event); } /** * Reset mod-rewrite url cache * * @param kEvent $event * @return void * @access protected */ protected function OnResetModRwCache(kEvent $event) { if ( $this->Application->GetVar('ajax') == 'yes' ) { $event->status = kEvent::erSTOP; } $this->Conn->Query('DELETE FROM ' . TABLE_PREFIX . 'CachedUrls'); $event->SetRedirectParam('action_completed', 1); } /** * Resets tree section cache and refreshes admin section tree * * @param kEvent $event * @return void * @access protected */ protected function OnResetSections(kEvent $event) { if ($this->Application->GetVar('ajax') == 'yes') { $event->status = kEvent::erSTOP; } if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $this->Application->rebuildCache('master:sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime); } else { $this->Application->rebuildDBCache('sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime); } $event->SetRedirectParam('refresh_tree', 1); $event->SetRedirectParam('action_completed', 1); } /** * Resets unit config cache * * @param kEvent $event * @return void * @access protected */ protected function OnResetConfigsCache(kEvent $event) { if ( $this->Application->GetVar('ajax') == 'yes' ) { $event->status = kEvent::erSTOP; } if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) { $this->Application->rebuildCache('master:config_files', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime); } else { $this->Application->rebuildDBCache('config_files', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime); } $this->OnResetParsedData($event); /** @var SkinHelper $skin_helper */ $skin_helper = $this->Application->recallObject('SkinHelper'); $skin_helper->deleteCompiled(); } /** * Resets parsed data from unit configs * * @param kEvent $event * @return void * @access protected */ protected function OnResetParsedData(kEvent $event) { if ( $this->Application->GetVar('ajax') == 'yes' ) { $event->status = kEvent::erSTOP; } $this->Application->DeleteUnitCache(); if ( $this->Application->GetVar('validate_configs') ) { $event->SetRedirectParam('validate_configs', 1); } $event->SetRedirectParam('action_completed', 1); } /** * Resets memory cache * * @param kEvent $event * @return void * @access protected */ protected function OnResetMemcache(kEvent $event) { if ($this->Application->GetVar('ajax') == 'yes') { $event->status = kEvent::erSTOP; } $this->Application->resetCache(); $event->SetRedirectParam('action_completed', 1); } /** * Compiles all templates (with a progress bar) * * @param kEvent $event * @return void * @access protected */ protected function OnCompileTemplates(kEvent $event) { /** @var NParserCompiler $compiler */ $compiler = $this->Application->recallObject('NParserCompiler'); $compiler->CompileTemplatesStep(); $event->status = kEvent::erSTOP; } /** * Deletes all compiled templates * * @param kEvent $event * @return void * @access protected */ protected function OnDeleteCompiledTemplates(kEvent $event) { if ( $this->Application->GetVar('ajax') == 'yes' ) { $event->status = kEvent::erSTOP; } $base_path = WRITEABLE . DIRECTORY_SEPARATOR . 'cache'; // delete debugger reports $debugger_reports = glob(RESTRICTED . '/debug_@*@.txt'); if ( $debugger_reports ) { foreach ($debugger_reports as $debugger_report) { unlink($debugger_report); } } $this->_deleteCompiledTemplates($base_path); $event->SetRedirectParam('action_completed', 1); } /** * Deletes compiled templates in a given folder * * @param string $folder * @param bool $unlink_folder * @return void * @access protected */ protected function _deleteCompiledTemplates($folder, $unlink_folder = false) { $sub_folders = glob($folder . '/*', GLOB_ONLYDIR); if ( is_array($sub_folders) ) { foreach ($sub_folders as $sub_folder) { $this->_deleteCompiledTemplates($sub_folder, true); } } $files = glob($folder . '/*.php'); if ( is_array($files) ) { foreach ($files as $file) { unlink($file); } } if ( $unlink_folder ) { rmdir($folder); } } /** * Generates structure for specified table * * @param kEvent $event * @return void * @access protected */ protected function OnGenerateTableStructure(kEvent $event) { $types_hash = Array ( 'string' => 'varchar|text|mediumtext|longtext|date|datetime|time|timestamp|char|year|enum|set', 'int' => 'smallint|mediumint|int|bigint|tinyint', 'float' => 'float|double|decimal', ); $table_name = $this->Application->GetVar('table_name'); if ( !$table_name ) { echo 'error: no table name specified'; return; } if ( TABLE_PREFIX && !preg_match('/^' . preg_quote(TABLE_PREFIX, '/') . '(.*)/', $table_name) && (strtolower($table_name) != $table_name) ) { // table name without prefix, then add it (don't affect K3 tables named in lowercase) $table_name = TABLE_PREFIX . $table_name; } if ( !$this->Conn->TableFound($table_name) ) { // table with prefix doesn't exist, assume that just config prefix passed -> resolve table name from it $prefix = preg_replace('/^' . preg_quote(TABLE_PREFIX, '/') . '/', '', $table_name); if ( $this->Application->prefixRegistred($prefix) ) { // when prefix is found -> use it's table (don't affect K3 tables named in lowecase) $table_name = $this->Application->getUnitConfig($prefix)->getTableName(); } } $table_info = $this->Conn->Query('DESCRIBE '.$table_name); // 1. prepare config keys $grids = Array ( 'Default' => Array ( 'Icons' => Array ('default' => 'icon16_item.png'), 'Fields' => Array (), ) ); $grids_fields = Array(); $id_field = ''; $fields = Array (); $float_types = Array ('float', 'double', 'numeric'); foreach ($table_info as $field_info) { if ( preg_match('/l[\d]+_.*/', $field_info['Field']) ) { // don't put multilingual fields in config continue; } $field_options = Array (); if ( $field_info['Key'] == 'PRI' ) { if ( $field_info['Field'] == 'Id' ) { $grid_col_options = Array ('filter_block' => 'grid_range_filter', 'width' => 80); } else { $grid_col_options = Array ('title' => 'column:la_fld_Id', 'filter_block' => 'grid_range_filter', 'width' => 80); } } else { $grid_col_options = Array ('filter_block' => 'grid_like_filter'); } // 1. get php field type by mysql field type foreach ($types_hash as $php_type => $db_types) { if ( preg_match('/' . $db_types . '/', $field_info['Type']) ) { $field_options['type'] = $php_type; break; } } // 2. get field default value $default_value = $field_info['Default']; $not_null = $field_info['Null'] != 'YES'; if ( is_numeric($default_value) ) { $default_value = preg_match('/[\.,]/', $default_value) ? (float)$default_value : (int)$default_value; } if ( is_null($default_value) && $not_null ) { $default_value = $field_options['type'] == 'string' ? '' : 0; } if ( in_array($php_type, $float_types) ) { // this is float number if ( preg_match('/' . $db_types . '\([\d]+,([\d]+)\)/i', $field_info['Type'], $regs) ) { // size is described in structure -> add formatter $field_options['formatter'] = 'kFormatter'; $field_options['format'] = '%01.' . $regs[1] . 'f'; if ( $not_null ) { // null fields, will most likely have NULL as default value $default_value = 0; } } elseif ( $not_null ) { // no size information, just convert to float // null fields, will most likely have NULL as default value $default_value = (float)$default_value; } } if ( preg_match('/varchar\(([\d]+)\)/i', $field_info['Type'], $regs) ) { $field_options['max_len'] = (int)$regs[1]; } if ( preg_match('/tinyint\([\d]+\)/i', $field_info['Type']) ) { $field_options['formatter'] = 'kOptionsFormatter'; $field_options['options'] = Array (1 => 'la_Yes', 0 => 'la_No'); $field_options['use_phrases'] = 1; $grid_col_options['filter_block'] = 'grid_options_filter'; } if ( $not_null ) { $field_options['not_null'] = 1; } if ( $field_info['Key'] == 'PRI' ) { $default_value = 0; $id_field = $field_info['Field']; } if ( $php_type == 'int' && !$not_null ) { // numeric null field if ( preg_match('/(On|Date)$/', $field_info['Field']) || $field_info['Field'] == 'Modified' ) { $field_options['formatter'] = 'kDateFormatter'; $grid_col_options['filter_block'] = 'grid_date_range_filter'; $grid_col_options['width'] = 120; } else { $grid_col_options['filter_block'] = 'grid_range_filter'; $grid_col_options['width'] = 80; } } if ( $php_type == 'int' && ($not_null || is_numeric($default_value)) ) { // is integer field AND not null $field_options['default'] = (int)$default_value; } else { $field_options['default'] = $default_value; } $fields[$field_info['Field']] = $field_options; $grids_fields[$field_info['Field']] = $grid_col_options; } $grids['Default']['Fields'] = $grids_fields; $ret = Array ( 'IDField' => $id_field, 'Fields' => $fields, 'Grids' => $grids, ); $decorator = new UnitConfigDecorator(); $ret = $decorator->decorate($ret); $this->Application->InitParser(); ob_start(); echo $this->Application->ParseBlock(Array('name' => 'incs/header', 'body_properties' => 'style="background-color: #E7E7E7; margin: 8px;"')); ?>
Close Window

highlightString($ret); ?>

Close Window
Application->ParseBlock(Array('name' => 'incs/footer')); echo ob_get_clean(); $event->status = kEvent::erSTOP; } /** * Refreshes ThemeFiles & Themes tables by actual content on HDD * * @param kEvent $event * @return void * @access protected */ protected function OnRebuildThemes(kEvent $event) { if ( $this->Application->GetVar('ajax') == 'yes' ) { $event->status = kEvent::erSTOP; } /** @var kThemesHelper $themes_helper */ $themes_helper = $this->Application->recallObject('ThemesHelper'); $themes_helper->refreshThemes(); $event->SetRedirectParam('action_completed', 1); } /** + * Dumps assets + * + * @param kEvent $event Event. + * + * @return void + */ + protected function OnDumpAssets(kEvent $event) + { + if ( $this->Application->GetVar('ajax') == 'yes' ) { + $event->status = kEvent::erSTOP; + } + + /** @var MinifyHelper $minify_helper */ + $minify_helper = $this->Application->recallObject('MinifyHelper'); + + $minify_helper->delete(); + $minify_helper->dump(); + + $event->SetRedirectParam('action_completed', 1); + } + + /** * Saves grid column widths after their resize by user * * @param kEvent $event * @return void * @access protected */ protected function OnSaveColumns(kEvent $event) { $picker_helper = new kColumnPickerHelper( $this->Application->GetVar('main_prefix'), $this->Application->GetLinkedVar('grid_name') ); $picked = trim($this->Application->GetVar('picked_str'), '|'); $hidden = trim($this->Application->GetVar('hidden_str'), '|'); $picker_helper->saveColumns($picked, $hidden); $this->finalizePopup($event); } /** * Saves various admin settings via ajax * * @param kEvent $event * @return void * @access protected */ protected function OnSaveSetting(kEvent $event) { if ( $this->Application->GetVar('ajax') != 'yes' ) { return; } $var_name = $this->Application->GetVar('var_name'); $var_value = $this->Application->GetVar('var_value'); $this->Application->StorePersistentVar($var_name, $var_value); $event->status = kEvent::erSTOP; } /** * Just closes popup & deletes last_template & opener_stack if popup, that is closing * * @param kEvent $event * @return void * @access protected */ protected function OnClosePopup(kEvent $event) { $event->SetRedirectParam('opener', 'u'); } /** * Occurs right after initialization of the kernel, used mainly as hook-to event * * @param kEvent $event * @return void * @access protected */ protected function OnStartup(kEvent $event) { if ( $this->Application->isAdmin ) { return; } $base_url = preg_quote($this->Application->BaseURL(), '/'); $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; if ( $referrer && !preg_match('/^' . $base_url . '/', $referrer) ) { $this->Application->Session->SetCookie('original_referrer', $referrer); $this->Application->SetVar('original_referrer', $referrer); } } /** * Occurs right before echoing the output, in Done method of application, used mainly as hook-to event * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeShutdown(kEvent $event) { } /** * Is called after tree was build (when not from cache) * * @param kEvent $event * @return void * @access protected */ protected function OnAfterBuildTree(kEvent $event) { } /** * Called by AJAX to perform CSV export * * @param kEvent $event * @return void * @access protected */ protected function OnExportCSV(kEvent $event) { /** @var kCSVHelper $csv_helper */ $csv_helper = $this->Application->recallObject('CSVHelper'); $csv_helper->PrefixSpecial = $csv_helper->getPrefix(false); $csv_helper->grid = $this->Application->GetVar('grid'); $csv_helper->ExportStep(); $event->status = kEvent::erSTOP; } /** * Returning created by AJAX CSV file * * @param kEvent $event * @return void * @access protected */ protected function OnGetCSV(kEvent $event) { /** @var kCSVHelper $csv_helper */ $csv_helper = $this->Application->recallObject('CSVHelper'); $csv_helper->GetCSV(); } /** * Start CSV import * * @param kEvent $event * @return void * @access protected */ protected function OnCSVImportBegin(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $object->setID(0); $field_values = $this->getSubmittedFields($event); $object->SetFieldsFromHash($field_values); $event->setEventParam('form_data', $field_values); $event->redirect = false; $result = 'required'; if ( $object->GetDBField('ImportFile') ) { /** @var kCSVHelper $csv_helper */ $csv_helper = $this->Application->recallObject('CSVHelper'); $csv_helper->PrefixSpecial = $csv_helper->getPrefix(true); $csv_helper->grid = $this->Application->GetVar('grid'); $result = $csv_helper->ImportStart($object->GetField('ImportFile', 'file_paths')); if ( $result === true ) { $event->redirect = $this->Application->GetVar('next_template'); $event->SetRedirectParam('PrefixSpecial', $this->Application->GetVar('PrefixSpecial')); $event->SetRedirectParam('grid', $this->Application->GetVar('grid')); } } if ( $event->redirect === false ) { $object->SetError('ImportFile', $result); $event->status = kEvent::erFAIL; } } /** * Performs one CSV import step * * @param kEvent $event * @return void * @access protected */ protected function OnCSVImportStep(kEvent $event) { /** @var kCSVHelper $import_helper */ $import_helper = $this->Application->recallObject('CSVHelper'); $import_helper->ImportStep(); $event->status = kEvent::erSTOP; } /** * Shows unit config filename, where requested prefix is defined * * @param kEvent $event * @return void * @access protected */ protected function OnCheckPrefixConfig(kEvent $event) { $prefix = $this->Application->GetVar('config_prefix'); $config_file = $this->Application->UnitConfigReader->getPrefixFile($prefix); $this->Application->InitParser(); ob_start(); echo $this->Application->ParseBlock(Array('name' => 'incs/header', 'body_properties' => 'style="background-color: #E7E7E7; margin: 8px;"')); ?> Close Window

Prefix:
Unit Config: highlightString($config_file); ?>

Close Window
Application->ParseBlock(Array ('name' => 'incs/footer')); echo ob_get_clean(); $event->status = kEvent::erSTOP; } /** * Deletes temp tables, when user closes window using "x" button in top right corner * * @param kEvent $event * @return void * @access protected */ protected function OnDropTempTablesByWID(kEvent $event) { $sid = $this->Application->GetSID(); $wid = $this->Application->GetVar('m_wid'); $tables = $this->Conn->GetCol('SHOW TABLES'); $mask_edit_table = '/' . TABLE_PREFIX . 'ses_' . $sid . '_' . $wid . '_edit_(.*)$/'; foreach ($tables as $table) { if ( preg_match($mask_edit_table, $table, $rets) ) { $this->Conn->Query('DROP TABLE IF EXISTS ' . $table); } } echo 'OK'; $event->status = kEvent::erSTOP; } /** * Backup all data * * @param kEvent $event * @return void * @access protected */ protected function OnBackup(kEvent $event) { /** @var BackupHelper $backup_helper */ $backup_helper = $this->Application->recallObject('BackupHelper'); if ( !$backup_helper->initBackup() ) { $event->status = kEvent::erFAIL; } $event->redirect = 'tools/backup2'; } /** * Perform next backup step * * @param kEvent $event * @return void * @access protected */ protected function OnBackupProgress(kEvent $event) { /** @var BackupHelper $backup_helper */ $backup_helper = $this->Application->recallObject('BackupHelper'); $done_percent = $backup_helper->performBackup(); if ( $done_percent == 100 ) { $event->redirect = 'tools/backup3'; return; } $event->status = kEvent::erSTOP; echo $done_percent; } /** * Stops Backup & redirect to Backup template * * @param kEvent $event * @return void * @access protected */ protected function OnBackupCancel(kEvent $event) { $event->redirect = 'tools/backup1'; } /** * Starts restore process * * @param kEvent $event * @return void * @access protected */ protected function OnRestore(kEvent $event) { /** @var BackupHelper $backup_helper */ $backup_helper = $this->Application->recallObject('BackupHelper'); $backup_helper->initRestore(); $event->redirect = 'tools/restore3'; } /** * Performs next restore step * * @param kEvent $event * @return void * @access protected */ protected function OnRestoreProgress(kEvent $event) { /** @var BackupHelper $backup_helper */ $backup_helper = $this->Application->recallObject('BackupHelper'); $done_percent = $backup_helper->performRestore(); if ( $done_percent == BackupHelper::SQL_ERROR_DURING_RESTORE ) { $event->redirect = 'tools/restore4'; } elseif ( $done_percent == BackupHelper::FAILED_READING_BACKUP_FILE ) { $this->Application->StoreVar('adm.restore_error', 'File read error'); $event->redirect = 'tools/restore4'; } elseif ( $done_percent == 100 ) { $backup_helper->replaceRestoredFiles(); $this->Application->StoreVar('adm.restore_success', 1); $event->redirect = 'tools/restore4'; } else { $event->status = kEvent::erSTOP; echo $done_percent; } } /** * Stops Restore & redirect to Restore template * * @param kEvent $event * @return void * @access protected */ protected function OnRestoreCancel(kEvent $event) { $event->redirect = 'tools/restore1'; } /** * Deletes one backup file * * @param kEvent $event * @return void * @access protected */ protected function OnDeleteBackup(kEvent $event) { /** @var BackupHelper $backup_helper */ $backup_helper = $this->Application->recallObject('BackupHelper'); $backup_helper->delete(); } /** * Starts restore process * * @param kEvent $event * @return void * @access protected */ protected function OnSqlQuery(kEvent $event) { $sql = $this->Application->GetVar('sql'); if ( $sql ) { $start = microtime(true); $result = $this->Conn->Query($sql); $this->Application->SetVar('sql_time', round(microtime(true) - $start, 7)); if ( $result && is_array($result) ) { $this->Application->SetVar('sql_has_rows', 1); $this->Application->SetVar('sql_rows', serialize($result)); } $check_sql = trim(strtolower($sql)); if ( preg_match('/^(insert|update|replace|delete)/', $check_sql) ) { $this->Application->SetVar('sql_has_affected', 1); $this->Application->SetVar('sql_affected', $this->Conn->getAffectedRows()); } } $this->Application->SetVar('query_status', 1); $event->status = kEvent::erFAIL; } /** * Occurs after unit config cache was successfully rebuilt * * @param kEvent $event * @return void * @access protected */ protected function OnAfterCacheRebuild(kEvent $event) { } /** * Removes "Community -> Groups" section when it is not allowed * * @param kEvent $event * @return void * @access protected */ protected function OnAfterConfigRead(kEvent $event) { parent::OnAfterConfigRead($event); $config = $event->getUnitConfig(); if ( !$this->Application->ConfigValue('AdvancedUserManagement') ) { $config->addSectionAdjustments('remove', 'in-portal:user_groups'); } $config->addSectionAdjustments(Array ( 'label' => $this->Application->ConfigValue('Site_Name') ), 'in-portal:root'); } /** * Saves menu (tree) frame width * * @param kEvent $event * @return void * @access protected */ protected function OnSaveMenuFrameWidth(kEvent $event) { $event->status = kEvent::erSTOP; if ( !$this->Application->ConfigValue('ResizableFrames') ) { return; } $this->Application->StorePersistentVar('MenuFrameWidth', (int)$this->Application->GetVar('width')); } /** * Retrieves data from memory cache * * @param kEvent $event * @return void * @access protected */ protected function OnMemoryCacheGet(kEvent $event) { $event->status = kEvent::erSTOP; $ret = Array ('message' => '', 'code' => 0); // 0 - ok, > 0 - error $key = $this->Application->GetVar('key'); if ( !$key ) { $ret['code'] = 1; $ret['message'] = 'Key name missing'; } else { $value = $this->Application->getCache($key); $ret['value'] =& $value; $ret['size'] = is_string($value) ? kUtil::formatSize(strlen($value)) : '?'; $ret['type'] = gettype($value); if ( kUtil::IsSerialized($value) ) { $value = unserialize($value); } if ( is_array($value) ) { $ret['value'] = print_r($value, true); } if ( $ret['value'] === false ) { $ret['code'] = 2; $ret['message'] = 'Key "' . $key . '" doesn\'t exist'; } } /** @var JSONHelper $json_helper */ $json_helper = $this->Application->recallObject('JSONHelper'); echo $json_helper->encode($ret); } /** * Retrieves data from memory cache * * @param kEvent $event * @return void * @access protected */ protected function OnMemoryCacheSet(kEvent $event) { $event->status = kEvent::erSTOP; $ret = Array ('message' => '', 'code' => 0); // 0 - ok, > 0 - error $key = $this->Application->GetVar('key'); if ( !$key ) { $ret['code'] = 1; $ret['message'] = 'Key name missing'; } else { $value = $this->Application->GetVar('value'); $res = $this->Application->setCache($key, $value); $ret['result'] = $res ? 'OK' : 'FAILED'; } /** @var JSONHelper $json_helper */ $json_helper = $this->Application->recallObject('JSONHelper'); echo $json_helper->encode($ret); } /** * Deploy changes * * Usage: "php tools/run_event.php adm:OnDeploy b674006f3edb1d9cd4d838c150b0567d" * * @param kEvent $event * @return void * @access protected */ protected function OnDeploy(kEvent $event) { $this->_deploymentAction($event); } /** * Synchronizes database revisions from "project_upgrades.sql" file * * @param kEvent $event * @return void * @access protected */ protected function OnSynchronizeDBRevisions(kEvent $event) { $this->_deploymentAction($event, true); } /** * Common code to invoke deployment helper * * @param kEvent $event * @param bool $dry_run * @return void * @access protected */ protected function _deploymentAction(kEvent $event, $dry_run = false) { /** @var DeploymentHelper $deployment_helper */ $deployment_helper = $this->Application->recallObject('DeploymentHelper'); $deployment_helper->setEvent($event); if ( $deployment_helper->deployAll($dry_run) ) { $event->SetRedirectParam('action_completed', 1); if ( !$deployment_helper->isCommandLine ) { // browser invocation -> don't perform redirect $event->redirect = false; // no redirect, but deployment succeeded - set redirect params directly foreach ($event->getRedirectParams() as $param_name => $param_value) { $this->Application->SetVar($param_name, $param_value); } } } else { $event->status = kEvent::erFAIL; } } /** * [SCHEDULED TASK] * 1. Delete all Debug files from system/.restricted folder (format debug_@977827436@.txt) * 2. Run MySQL OPTIMIZE SQL one by one on all In-Portal tables (found by prefix). * * @param kEvent $event * @return void * @access protected */ protected function OnOptimizePerformance(kEvent $event) { $start_time = time(); $sql = 'SELECT SessionKey FROM ' . TABLE_PREFIX . 'UserSessions WHERE LastAccessed > ' . $start_time; $active_sessions = array_flip($this->Conn->GetCol($sql)); $files = scandir(RESTRICTED); $file_path = RESTRICTED . '/'; foreach ($files AS $file_name) { if ( !preg_match('#^debug_@([0-9]{9})@.txt$#', $file_name, $matches) ) { // not debug file continue; } $sid = $matches[1]; if ( isset($active_sessions[$sid]) || (filemtime($file_path . $file_name) > $start_time) ) { // debug file belongs to an active session // debug file is recently created (after sessions snapshot) continue; } unlink($file_path . $file_name); } $system_tables = $this->Conn->GetCol('SHOW TABLES LIKE "' . TABLE_PREFIX . '%"'); foreach ($system_tables AS $table_name) { $this->Conn->Query('OPTIMIZE TABLE ' . $table_name); } } /** * [SCHEDULED TASK] Pre-resizes images, used in templates * * @param kEvent $event * @return void * @access protected */ protected function OnPreResizeImages(kEvent $event) { $scheduled_task = $event->MasterEvent->getObject(); /* @var $scheduled_task kDBItem */ $mass_resizer = new MassImageResizer(); // rules from scheduled task itself $mass_resizer->addRules($scheduled_task->GetDBField('Settings')); // rules from all enabled themes $sql = 'SELECT ImageResizeRules FROM ' . $this->Application->getUnitConfig('theme')->getTableName() . ' WHERE Enabled = 1'; $mass_resizer->addRules($this->Conn->GetCol($sql)); $mass_resizer->run(); } /** * Returns popup size (by template), if not cached, then parse template to get value * * @param kEvent $event * @return void * @access protected */ protected function OnGetPopupSize(kEvent $event) { $event->status = kEvent::erSTOP; if ( $this->Application->GetVar('ajax') != 'yes' ) { return; } $t = $this->Application->GetVar('template_name'); $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'PopupSizes WHERE TemplateName = ' . $this->Conn->qstr($t); $popup_info = $this->Conn->GetRow($sql); $this->Application->setContentType('text/plain'); if ( !$popup_info ) { // dies when SetPopupSize tag found & in ajax request $this->Application->InitParser(); $this->Application->ParseBlock(Array ('name' => $t)); // tag SetPopupSize not found in template -> use default size echo '750x400'; } else { echo $popup_info['PopupWidth'] . 'x' . $popup_info['PopupHeight']; } } /** * Writes HTTP request to System Log * * @param kEvent $event * @return void * @access public */ public function OnLogHttpRequest(kEvent $event) { if ( defined('DBG_REQUEST_LOG') && DBG_REQUEST_LOG && $this->Application->LoggedIn() ) { $log = $this->Application->log('HTTP_REQUEST')->addRequestData(); if ( !$log->write() ) { trigger_error('Unable to log Http Request due disabled "System Log"', E_USER_WARNING); } } } } /** * Resizes multiple images according to given rules */ class MassImageResizer extends kBase { /** * Rules, that tell how images must be resized * * @var Array * @access private */ private $_rules = Array (); /** * Remembers, which fields of which unit are used * * @var Array * @access private */ private $_unitFields = Array (); /** * Remembers which fields of which units require which format * * @var Array * @access private */ private $_unitFieldFormats = Array (); /** * Adds more resize rules * * @param string|Array $rules * @return void * @access public */ public function addRules($rules) { $rules = (array)$rules; foreach ($rules as $rule) { $rule = $this->_cleanup($rule); if ( $rule ) { $this->_rules = array_merge($this->_rules, $rule); } } } /** * Normalizes given set of rules * * @param string $rules * @return Array * @access private */ private function _cleanup($rules) { $ret = explode("\n", str_replace(Array ("\r\n", "\r"), "\n", $rules)); return array_filter(array_map('trim', $ret)); } /** * Transforms rules given in raw format into 3D array of easily manageable rules * * @return void * @access private */ private function _preProcessRules() { foreach ($this->_rules as $raw_rule) { list ($prefix, $field, $format) = explode(':', $raw_rule, 3); if ( !isset($this->_unitFields[$prefix]) ) { $this->_unitFields[$prefix] = Array (); $this->_unitFieldFormats[$prefix] = Array (); } $this->_unitFields[$prefix][] = $field; if ( !isset($this->_unitFieldFormats[$prefix][$field]) ) { $this->_unitFieldFormats[$prefix][$field] = Array (); } $this->_unitFieldFormats[$prefix][$field][] = $format; } } /** * Performs resize operation * * @return void * @access public */ public function run() { $this->_preProcessRules(); foreach ($this->_unitFields as $prefix => $fields) { $sql = 'SELECT ' . implode(',', array_unique($fields)) . ' FROM ' . $this->Application->getUnitConfig($prefix)->getTableName(); $unit_data = $this->Conn->GetIterator($sql); if ( !count($unit_data) ) { continue; } $object = $this->Application->recallObject($prefix . '.resize', null, Array ('skip_autoload' => true)); /* @var $object kDBItem */ foreach ($unit_data as $field_values) { foreach ($field_values as $field => $value) { if ( !$value ) { continue; } $object->SetDBField($field, $value); foreach ($this->_unitFieldFormats[$prefix][$field] as $format) { // will trigger image resize if needed $object->GetField($field, $format); } } } } } } class UnitConfigDecorator { var $parentPath = Array (); /** * Decorates given array * * @param Array $var * @param int $level * @return string */ public function decorate($var, $level = 0) { $ret = ''; $deep_level = count($this->parentPath); if ( $deep_level && ($this->parentPath[0] == 'Fields') ) { $expand = $level < 2; } elseif ( $deep_level && ($this->parentPath[0] == 'Grids') ) { if ( $deep_level == 3 && $this->parentPath[2] == 'Icons' ) { $expand = false; } else { $expand = $level < 4; } } else { $expand = $level == 0; } if ( is_array($var) ) { $ret .= 'array('; $prepend = $expand ? "\n" . str_repeat("\t", $level + 1) : ''; foreach ($var as $key => $value) { array_push($this->parentPath, $key); $ret .= $prepend . (is_string($key) ? "'" . $key . "'" : $key) . ' => ' . $this->decorate($value, $level + 1); $ret .= ',' . ($expand ? '' : ' '); array_pop($this->parentPath); } $prepend = $expand ? "\n" . str_repeat("\t", $level) : ''; if ( !$expand ) { $ret = rtrim($ret, ', '); } $ret .= $prepend . ')'; } else { if ( is_null($var) ) { $ret = 'null'; } elseif ( is_string($var) ) { $ret = "'" . $var . "'"; } else { $ret = $var; } } return $ret; } } Index: branches/5.3.x/core/units/phrases/phrases_config.php =================================================================== --- branches/5.3.x/core/units/phrases/phrases_config.php (revision 16599) +++ branches/5.3.x/core/units/phrases/phrases_config.php (revision 16600) @@ -1,248 +1,248 @@ 'phrases', 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'PhrasesEventHandler', 'file' => 'phrases_event_handler.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'PhraseTagProcessor', 'file' => 'phrase_tp.php', 'build_event' => 'OnBuild'), 'AutoLoad' => true, 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'PerPage', 4 => 'event', 5 => 'label', // labels can be edited directly 6 => 'mode', ), 'IDField' => 'PhraseId', 'TitleField' => 'Phrase', 'TitlePresets' => Array ( 'default' => Array ( 'new_status_labels' => Array ('phrases' => '!la_title_Adding_Phrase!'), 'edit_status_labels' => Array ('phrases' => '!la_title_Editing_Phrase!'), ), 'phrase_edit' => Array ( 'prefixes' => Array ('phrases'), 'format' => '#phrases_status# #phrases_titlefield#', 'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'), ), // for separate phrases list 'phrases_list_st' => Array ( 'prefixes' => Array ('phrases_List'), 'format' => "!la_title_Phrases!", 'toolbar_buttons' => Array ('new_item', 'edit', 'delete', 'export', 'view', 'dbl-click'), ), 'phrase_edit_single' => Array ( 'prefixes' => Array ('phrases'), 'format' => '#phrases_status# #phrases_titlefield#', 'toolbar_buttons' => Array ('select', 'setprimary', 'cancel', 'reset_edit', 'prev', 'next'), ), ), 'CheckSimulatniousEdit' => true, 'PermSection' => Array ('main' => 'in-portal:phrases'), 'Sections' => Array ( // "Phrases" 'in-portal:phrases' => Array ( 'parent' => 'in-portal:site', 'icon' => 'phrases_labels', 'label' => 'la_title_Phrases', 'url' => Array ('t' => 'languages/phrase_list', 'pass' => 'm'), 'permissions' => Array ('view', 'add', 'edit', 'delete'), 'priority' => 4, 'type' => stTREE, ), ), 'FilterMenu' => Array ( 'Groups' => Array ( Array ('mode' => 'AND', 'filters' => Array ('translated', 'not_translated'), 'type' => kDBList::HAVING_FILTER), ), 'Filters' => Array ( 'translated' => Array ('label' => 'la_PhraseTranslated', 'on_sql' => '', 'off_sql' => 'CurrentTranslation IS NULL'), 'not_translated' => Array ('label' => 'la_PhraseNotTranslated', 'on_sql' => '', 'off_sql' => 'CurrentTranslation IS NOT NULL'), ) ), 'TableName' => TABLE_PREFIX . 'LanguageLabels', 'CalculatedFields' => Array ( '' => Array ( 'PrimaryTranslation' => 'l%4$s_Translation', 'SourceTranslation' => 'l%4$s_Translation', 'SourceHintTranslation' => 'l%4$s_HintTranslation', 'SourceColumnTranslation' => 'l%4$s_ColumnTranslation', 'CurrentTranslation' => 'l%5$s_Translation', 'CurrentHintTranslation' => 'l%5$s_HintTranslation', 'CurrentColumnTranslation' => 'l%5$s_ColumnTranslation', 'TranslationInSync' => 'IF(l%5$s_TranslateFrom = 0, 1, 0)', 'TranslateFromLanguage' => 'l%5$s_TranslateFrom', ), ), 'ListSQLs' => Array ( '' => ' SELECT %1$s.* %2$s FROM %1$s', ), 'ListSortings' => Array ( '' => Array ( 'Sorting' => Array ('Phrase' => 'asc'), ) ), 'Fields' => Array ( 'PhraseId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'Phrase' => Array ( 'type' => 'string', 'formatter' => 'kFormatter', 'regexp' => '/^(la|lu|lc)_[A-Z\d:_\-\.]+$/i', 'unique' => Array (), 'not_null' => 1, 'required' => 1, 'default' => '', ), 'PhraseKey' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), - 'Translation' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'required' => 1, 'using_fck' => 1, 'default' => NULL, 'db_type' => 'text'), - 'HintTranslation' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'using_fck' => 1, 'default' => NULL, 'db_type' => 'text'), - 'ColumnTranslation' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'using_fck' => 1, 'default' => NULL, 'db_type' => 'text'), + 'Translation' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'required' => 1, 'default' => NULL, 'db_type' => 'text'), + 'HintTranslation' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'default' => NULL, 'db_type' => 'text'), + 'ColumnTranslation' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'default' => NULL, 'db_type' => 'text'), 'TranslateFrom' => Array ( 'type' => 'int', 'formatter' => 'kMultiLanguage', 'db_type' => 'int', 'index_type' => 'int', 'not_null' => 1, 'default' => 0 ), 'PhraseType' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_PhraseType_Front', 1 => 'la_PhraseType_Admin', 2 => 'la_PhraseType_Both'), 'use_phrases' => 1, 'not_null' => 1, 'required' => 1, 'default' => Language::PHRASE_TYPE_COMMON, ), 'LastChanged' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL), 'LastChangeIP' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''), 'Module' => Array ( 'type' => 'string', 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Modules WHERE (Loaded = 1) AND (Name <> "In-Portal") ORDER BY LoadOrder', 'option_key_field' => 'Name', 'option_title_field' => 'Name', 'not_null' => 1, 'required' => 1, 'default' => 'Core' ), ), 'VirtualFields' => Array ( 'PrimaryTranslation' => Array ('type' => 'string', 'default' => ''), 'SourceTranslation' => Array ('type' => 'string', 'default' => ''), 'SourceHintTranslation' => Array ('type' => 'string', 'default' => ''), 'SourceColumnTranslation' => Array ('type' => 'string', 'default' => ''), 'CurrentTranslation' => Array ('type' => 'string', 'default' => ''), 'CurrentHintTranslation' => Array ('type' => 'string', 'default' => ''), 'CurrentColumnTranslation' => Array ('type' => 'string', 'default' => ''), 'TranslationInSync' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'default' => 0, ), 'TranslateFromLanguage' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Languages ORDER BY PackName', 'option_title_field' => 'PackName', 'option_key_field' => 'LanguageId', 'default' => 0, ), // for language pack import/export 'LangFile' => Array ( 'type' => 'string', 'formatter' => 'kUploadFormatter', 'max_size' => MAX_UPLOAD_SIZE, 'upload_dir' => WRITEBALE_BASE . '/', 'max_len' => 255, 'default' => '' ), 'ImportOverwrite' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'default' => 0, ), 'ImportSynced' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'default' => 1, ), 'DoNotEncode' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array ( 0 => 'la_No', 1 => 'la_Yes', ), 'use_phrases' => 1, 'default' => 0, ), 'ExportPhrases' => Array ('type' => 'string', 'default' => ''), 'ExportEmailTemplates' => Array ('type' => 'string', 'default' => ''), 'ExportCountries' => Array ('type' => 'string', 'default' => ''), 'ExportDataTypes' => Array ( 'type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array ('phrases' => 'la_opt_Phrases', 'email-template' => 'la_opt_EmailTemplates', 'country-state' => 'la_opt_Countries'), 'use_phrases' => 1, 'multiple' => 1, 'default' => '|phrases|email-template|country-state|' ), ), 'Grids' => Array ( // used on "Phrases" tab in language editing in "Regional" section 'Default' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', 0 => 'icon16_disabled.png', 1 => 'icon16_item.png', ), 'Fields' => Array ( 'PhraseId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 50), 'Phrase' => Array ('title' => 'la_col_Label', 'data_block' => 'grid_checkbox_td', 'width' => 200), 'CurrentTranslation' => Array ('title' => 'column:la_fld_Phrase', 'width' => 200), 'PrimaryTranslation' => Array ('title' => 'la_col_PrimaryValue', 'width' => 200), 'PhraseType' => Array ('filter_block' => 'grid_options_filter', 'width' => 60), 'LastChanged' => Array ('title' => 'column:la_fld_Modified', 'filter_block' => 'grid_date_range_filter', 'width' => 150), 'Module' => Array ('filter_block' => 'grid_multioptions_filter', 'width' => 100), 'CurrentHintTranslation' => Array ('title' => 'la_col_HintPhrase', 'width' => 200, 'hidden' => 1), 'CurrentColumnTranslation' => Array ('title' => 'la_col_ColumnPhrase', 'width' => 200, 'hidden' => 1), ), ), // used on "Labels & Phrases" section 'Phrases' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', 0 => 'icon16_disabled.png', 1 => 'icon16_item.png', ), 'Fields' => Array ( 'PhraseId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 50), 'Phrase' => Array ('title' => 'la_col_Label', 'filter_block' => 'grid_like_filter', 'width' => 170), 'CurrentTranslation' => Array ('title' => 'column:la_fld_Phrase', 'filter_block' => 'grid_like_filter', 'width' => 180), 'CurrentHintTranslation' => Array ('title' => 'la_col_HintPhrase', 'filter_block' => 'grid_like_filter', 'width' => 200, 'hidden' => 1), 'CurrentColumnTranslation' => Array ('title' => 'la_col_ColumnPhrase', 'filter_block' => 'grid_like_filter', 'width' => 200, 'hidden' => 1), 'PhraseType' => Array ('title' => 'column:la_fld_Location', 'filter_block' => 'grid_multioptions_filter', 'width' => 80), 'LastChanged' => Array ('title' => 'column:la_fld_Modified', 'filter_block' => 'grid_date_range_filter', 'width' => 145), 'Module' => Array ('filter_block' => 'grid_multioptions_filter', 'width' => 100), 'TranslationInSync' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, 'hidden' => 1), 'TranslateFromLanguage' => Array ('filter_block' => 'grid_multioptions_filter', 'width' => 100, 'hidden' => 1), ), ), ), ); \ No newline at end of file Index: branches/5.3.x/core/units/email_templates/email_templates_config.php =================================================================== --- branches/5.3.x/core/units/email_templates/email_templates_config.php (revision 16599) +++ branches/5.3.x/core/units/email_templates/email_templates_config.php (revision 16600) @@ -1,309 +1,309 @@ 'email-template', 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'EmailTemplateEventHandler', 'file' => 'email_template_eh.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'EmailTemplateTagProcessor', 'file' => 'email_template_tp.php', 'build_event' => 'OnBuild'), 'AutoLoad' => true, 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'PerPage', 4 => 'event', 5 => 'mode', ), 'IDField' => 'TemplateId', 'StatusField' => Array ('Enabled'), 'TitleField' => 'TemplateName', 'TitlePresets' => Array ( 'default' => Array ( 'new_status_labels' => Array ('email-template' => '!la_title_AddingEmailTemplate!'), 'edit_status_labels' => Array ('email-template' => '!la_title_EditingEmailTemplate!'), 'new_titlefield' => Array ('email-template' => '!la_title_NewEmailTemplate!'), ), // for separate grid with email editing 'email_template_list' => Array ( 'prefixes' => Array ('email-template_List'), 'format' => "!la_title_EmailTemplates!", 'toolbar_buttons' => Array ('new_item', 'edit', 'delete', 'approve', 'decline', 'frontend_mail', 'export', 'process', 'view', 'dbl-click'), ), 'email_template_edit' => Array ( 'prefixes' => Array ('email-template'), 'format' => '#email-template_status# - #email-template_titlefield# - !la_section_General!', 'toolbar_buttons' => Array ('select', 'setprimary', 'cancel', 'reset_edit', 'prev', 'next'), ), 'email_template_edit_settings' => Array ( 'prefixes' => Array ('email-template'), 'format' => '#email-template_status# - #email-template_titlefield# - !la_section_Settings!', 'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'), ), // for mass mailing 'email_send_form' => Array ('prefixes' => Array (), 'format' => '!la_title_SendEmail!'), ), 'EditTabPresets' => Array ( 'Default' => Array ( 'general' => Array ('title' => 'la_tab_General', 't' => 'languages/email_template_edit', 'priority' => 1), 'settings' => Array ('title' => 'la_tab_Settings', 't' => 'languages/email_template_settings', 'priority' => 2), ), ), 'CheckSimulatniousEdit' => true, 'PermSection' => Array ('main' => 'in-portal:configemail'), 'Sections' => Array ( 'in-portal:configemail' => Array ( 'parent' => 'in-portal:site', 'icon' => 'email_templates', 'label' => 'la_title_EmailTemplates', 'url' => Array ('t' => 'languages/email_template_list', 'pass' => 'm'), 'permissions' => Array ('view', 'add', 'edit', 'delete'), 'priority' => 5, 'type' => stTREE, ), ), 'TableName' => TABLE_PREFIX . 'EmailTemplates', 'CalculatedFields' => Array ( '' => Array ( 'SourceSubject' => 'l%4$s_Subject', 'SourceHtmlBody' => 'l%4$s_HtmlBody', 'SourcePlainTextBody' => 'l%4$s_PlainTextBody', 'CurrentSubject' => 'l%5$s_Subject', 'CurrentHtmlBody' => 'l%5$s_HtmlBody', 'CurrentPlainTextBody' => 'l%5$s_PlainTextBody', 'TranslationInSync' => 'IF(l%5$s_TranslateFrom = 0, 1, 0)', 'TranslateFromLanguage' => 'l%5$s_TranslateFrom', ), ), 'ListSQLs' => Array ( '' => ' SELECT %1$s.* %2$s FROM %1$s', ), 'ListSortings' => Array ( '' => Array ( 'ForcedSorting' => Array ('Enabled' => 'desc'), 'Sorting' => Array ('TemplateName' => 'asc'), ), 'module' => Array ( 'ForcedSorting' => Array ('Enabled' => 'desc'), 'Sorting' => Array ('Description' => 'asc') ), ), 'Fields' => Array ( 'TemplateId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'TemplateName' => Array ('type' => 'string', 'not_null' => 1, 'unique' => Array ('Type'), 'required' => 1, 'default' => ''), 'Headers' => Array ('type' => 'string', 'default' => NULL), 'ReplacementTags' => Array ('type' => 'string', 'default' => NULL), 'AllowChangingSender' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'CustomSender' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_opt_DefaultAddress', 1 => 'la_opt_CustomSender'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'SenderName' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'SenderAddressType' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_Email', 2 => 'la_opt_User'), 'use_phrases' => 1, 'not_null' => 1, 'error_field' => 'SenderAddress', 'default' => 0 ), 'SenderAddress' => Array ( 'type' => 'string', 'max_len' => 255, 'error_msgs' => Array ( 'invalid_email' => '!la_err_invalid_format!', 'invalid_user' => '!la_error_UserNotFound!', ), 'not_null' => 1, 'default' => '' ), 'AllowChangingRecipient' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'CustomRecipient' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_opt_DefaultAddress', 1 => 'la_opt_CustomRecipients'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'Recipients' => Array ('type' => 'string', 'default' => NULL), 'Subject' => Array ( 'type' => 'string', 'formatter' => 'kMultiLanguage', 'db_type' => 'text', 'error_msgs' => Array ('parsing_error' => '!la_error_ParsingError!'), 'required' => 1, 'default' => null ), 'HtmlBody' => Array ( 'type' => 'string', - 'formatter' => 'kMultiLanguage', 'db_type' => 'longtext', + 'formatter' => 'kMultiLanguage', 'using_fck' => 1, 'db_type' => 'longtext', 'error_msgs' => Array ('parsing_error' => '!la_error_ParsingError!'), 'default' => null ), 'PlainTextBody' => Array ( 'type' => 'string', 'formatter' => 'kMultiLanguage', 'db_type' => 'longtext', 'error_msgs' => Array ('parsing_error' => '!la_error_ParsingError!'), 'default' => null ), 'TranslateFrom' => Array ( 'type' => 'int', 'formatter' => 'kMultiLanguage', 'db_type' => 'int', 'index_type' => 'int', 'not_null' => 1, 'default' => 0 ), 'Enabled' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1 ), 'FrontEndOnly' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'Module' => Array ( 'type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'not_null' => 1, 'required' => 1, 'default' => 'Core' ), 'Description' => Array ('type' => 'string', 'default' => NULL), 'Type' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Text_Admin', 0 => 'la_Text_User'), 'use_phrases' => 1, 'not_null' => 1, 'unique' => Array ('TemplateName'), 'required' => 1, 'default' => 0 ), 'LastChanged' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL), 'BindToSystemEvent' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), ), 'VirtualFields' => Array ( 'RecipientType' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'To', 2 => 'Cc', 3 => 'Bcc'), 'default' => 1 ), 'RecipientName' => Array ('type' => 'string', 'max_len' => 255, 'default' => ''), 'RecipientAddressType' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_Email', 2 => 'la_opt_User', 3 => 'la_opt_Group'), 'use_phrases' => 1, 'error_field' => 'RecipientAddress', 'default' => 0 ), 'RecipientAddress' => Array ( 'type' => 'string', 'max_len' => 255, 'error_msgs' => Array ( 'invalid_email' => '!la_err_invalid_format!', 'invalid_user' => '!la_error_UserNotFound!', 'invalid_group' => '!la_error_GroupNotFound!', ), 'default' => '' ), 'Tag' => Array ('type' => 'string', 'default' => ''), 'Replacement' => Array ('type' => 'string', 'default' => ''), 'ReplacementTagsXML' => Array ('type' => 'string', 'default' => ''), 'SourceSubject' => Array ('type' => 'string', 'default' => ''), 'SourceHtmlBody' => Array ('type' => 'string', 'default' => ''), 'SourcePlainTextBody' => Array ('type' => 'string', 'default' => ''), 'CurrentSubject' => Array ('type' => 'string', 'default' => ''), 'CurrentHtmlBody' => Array ('type' => 'string', 'default' => ''), 'CurrentPlainTextBody' => Array ('type' => 'string', 'default' => ''), 'TranslationInSync' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'default' => 0, ), 'TranslateFromLanguage' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Languages ORDER BY PackName', 'option_title_field' => 'PackName', 'option_key_field' => 'LanguageId', 'default' => 0, ), ), 'Grids' => Array ( // used on "Email Events" tab in language editing in "Regional" section 'Default' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', 0 => 'icon16_disabled.png', 1 => 'icon16_item.png', ), 'Fields' => Array ( 'TemplateId' => Array ('title' => 'column:la_fld_Id', 'filter_block' => 'grid_range_filter', 'width' => 70, ), 'Description' => Array ('filter_block' => 'grid_like_filter', 'width' => 250, ), 'TemplateName' => Array ('filter_block' => 'grid_like_filter', 'width' => 250, ), 'Module' => Array ('filter_block' => 'grid_multioptions_filter', 'width' => 100, ), 'Type' => Array ('filter_block' => 'grid_options_filter', 'width' => 120, ), 'Enabled' => Array ('title' => 'column:la_fld_Status', 'filter_block' => 'grid_options_filter', 'width' => 80, ), 'LastChanged' => Array ('title' => 'column:la_fld_Modified', 'filter_block' => 'grid_date_range_filter', 'width' => 150), ), ), // used on "Email Templates" section 'Emails' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', 0 => 'icon16_disabled.png', 1 => 'icon16_item.png', ), 'Fields' => Array ( 'TemplateId' => Array ('title' => 'column:la_fld_Id', 'filter_block' => 'grid_range_filter', 'width' => 60, ), 'TemplateName' => Array ('filter_block' => 'grid_like_combo_filter', 'width' => 250, ), 'CurrentSubject' => Array ('title' => 'column:la_fld_Subject', 'filter_block' => 'grid_like_filter', 'no_special' => 0, 'width' => 300, ), 'Description' => Array ('filter_block' => 'grid_like_filter', 'width' => 250, ), 'Type' => Array ('filter_block' => 'grid_options_filter', 'width' => 60, ), 'Enabled' => Array ('filter_block' => 'grid_options_filter', 'width' => 70, ), 'Module' => Array ('filter_block' => 'grid_multioptions_filter', 'width' => 100, ), 'FrontEndOnly' => Array ('filter_block' => 'grid_options_filter', 'width' => 120, 'hidden' => 1), 'LastChanged' => Array ('title' => 'column:la_fld_Modified', 'filter_block' => 'grid_date_range_filter', 'width' => 150), 'TranslationInSync' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, 'hidden' => 1), 'TranslateFromLanguage' => Array ('filter_block' => 'grid_multioptions_filter', 'width' => 100, 'hidden' => 1), ), ), ), ); Index: branches/5.3.x/core/units/email_templates/email_template_eh.php =================================================================== --- branches/5.3.x/core/units/email_templates/email_template_eh.php (revision 16599) +++ branches/5.3.x/core/units/email_templates/email_template_eh.php (revision 16600) @@ -1,758 +1,758 @@ Array ('self' => 'edit'), 'OnSaveSelected' => Array ('self' => 'view'), 'OnProcessEmailQueue' => Array ('self' => 'add|edit'), 'OnExportEmailTemplates' => Array ('self' => 'view'), 'OnSuggestAddressJSON' => Array ('self' => 'add|edit'), // events only for developers 'OnPreCreate' => Array ('self' => 'debug'), 'OnDelete' => Array ('self' => 'debug'), 'OnDeleteAll' => Array ('self' => 'debug'), 'OnMassDelete' => Array ('self' => 'debug'), 'OnMassApprove' => Array ('self' => 'debug'), 'OnMassDecline' => Array ('self' => 'debug'), 'OnSend' => Array ('self' => 'debug'), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Changes permission section to one from REQUEST, not from config * * @param kEvent $event * @return bool * @access public */ public function CheckPermission(kEvent $event) { $module = $this->Application->GetVar('module'); if ( strlen($module) > 0 ) { // checking permission when listing module email events in separate section $module = explode(':', $module, 2); if ( count($module) == 1 ) { $main_prefix = $this->Application->findModule('Name', $module[0], 'Var'); } else { $exceptions = Array ('Category' => 'c', 'Users' => 'u'); $main_prefix = $exceptions[$module[1]]; } $section = $this->Application->getUnitConfig($main_prefix)->getPermSectionByName('email'); $event->setEventParam('PermSection', $section); } // checking permission when listing all email events when editing language return parent::CheckPermission($event); } /** * Apply any custom changes to list's sql query * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetCustomQuery(kEvent $event) { parent::SetCustomQuery($event); /** @var kDBList $object */ $object = $event->getObject(); if ( $event->Special == 'module' ) { $module = $this->Application->GetVar('module'); $object->addFilter('module_filter', '%1$s.Module = ' . $this->Conn->qstr($module)); } else { $object->addFilter('module_filter', '%1$s.Module IN (SELECT Name FROM ' . TABLE_PREFIX . 'Modules WHERE Loaded = 1)'); } if ( !$event->Special && !$this->Application->isDebugMode() ) { // no special $object->addFilter('enabled_filter', '%1$s.Enabled <> ' . STATUS_DISABLED); } } /** * Prepares new kDBItem object * * @param kEvent $event * @return void * @access protected */ protected function OnNew(kEvent $event) { parent::OnNew($event); $mapping = Array ('conf' => 'VariableValue', 'site-domain' => 'DefaultEmailRecipients'); if ( isset($mapping[$event->Special]) ) { /** @var kDBItem $object */ $object = $event->getObject(); /** @var kDBList $target_object */ $target_object = $this->Application->recallObject($event->Special); $object->SetDBField('Recipients', $target_object->GetDBField($mapping[$event->Special])); } } /** * Set default headers * * @param kEvent $event * @return void * @access protected */ protected function OnPreCreate(kEvent $event) { parent::OnPreCreate($event); /** @var kDBItem $object */ $object = $event->getObject(); $object->SetDBField('Headers', $this->Application->ConfigValue('Smtp_DefaultHeaders')); $this->setRequired($event); } /** * Sets status Front-End Only to selected email events * * @param kEvent $event */ function OnFrontOnly($event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } $config = $event->getUnitConfig(); $sql = 'UPDATE ' . $config->getTableName() . ' SET FrontEndOnly = 1 WHERE ' . $config->getIDField() . ' IN (' . implode(',', $this->StoreSelectedIDs($event)) . ')'; $this->Conn->Query($sql); $this->clearSelectedIDs($event); } /** * Sets selected user to email events selected * * @param kEvent $event * @return void * @access protected */ protected function OnSelectUser(kEvent $event) { if ( $event->Special != 'module' ) { parent::OnSelectUser($event); return; } if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } $items_info = $this->Application->GetVar('u'); if ( $items_info ) { list ($user_id, ) = each($items_info); $config = $event->getUnitConfig(); $ids = $this->Application->RecallVar($event->getPrefixSpecial() . '_selected_ids'); $sql = 'UPDATE ' . $config->getTableName() . ' SET ' . $this->Application->RecallVar('dst_field') . ' = ' . $user_id . ' WHERE ' . $config->getIDField() . ' IN (' . $ids . ')'; $this->Conn->Query($sql); } $this->finalizePopup($event); } /** * Saves selected ids to session * * @param kEvent $event */ function OnSaveSelected($event) { $this->StoreSelectedIDs($event); } /** * [AJAX] Process emails from queue. * * @param kEvent $event Event. * * @return void - * @deprecated 5.3.0-B1 + * @deprecated 5.2.2-B2 * @see EmailQueueEventHandler::OnProcessAjax() */ function OnProcessEmailQueue($event) { - kUtil::deprecatedMethod(__METHOD__, '5.3.0-B1', 'EmailQueueEventHandler::OnProcessAjax'); + kUtil::deprecatedMethod(__METHOD__, '5.2.2-B2', 'EmailQueueEventHandler::OnProcessAjax'); $event->CallSubEvent('email-queue:OnProcessAjax'); } /** * Prefills module dropdown * * @param kEvent $event * @return void * @access protected */ protected function OnAfterConfigRead(kEvent $event) { parent::OnAfterConfigRead($event); $config = $event->getUnitConfig(); $fields = $config->getFields(); $fields['Module']['options'] = $this->_getModules(); if ( $this->Application->findModule('Name', 'Custom') ) { $fields['Module']['default'] = 'Custom'; } $config->setFields($fields); $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); /* @var $ml_helper kMultiLanguageHelper */ $ml_helper->replaceMLCalculatedFields($event); if ( $this->Application->GetVar('regional') ) { $config->setPopulateMlFields(true); } } /** * Returns modules, where e-mail event can be added to * * @return Array * @access protected */ protected function _getModules() { $ret = Array (); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { if ( $module_name == 'In-Portal' ) { continue; } $ret[$module_name] = $module_name; } return $ret; } /** * Prepare temp tables and populate it * with items selected in the grid * * @param kEvent $event * @return void * @access protected */ protected function OnEdit(kEvent $event) { parent::OnEdit($event); // use language from grid, instead of primary language used by default $event->SetRedirectParam('m_lang', $this->Application->GetVar('m_lang')); } /** * Fixes default recipient type * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemLoad(kEvent $event) { parent::OnAfterItemLoad($event); /** @var kDBItem $object */ $object = $event->getObject(); if ( !$this->Application->isDebugMode(false) ) { if ( $object->GetDBField('AllowChangingRecipient') ) { $object->SetDBField('RecipientType', EmailTemplate::RECIPIENT_TYPE_TO); } else { $object->SetDBField('RecipientType', EmailTemplate::RECIPIENT_TYPE_CC); } } // process replacement tags $records = Array (); $replacement_tags = $object->GetDBField('ReplacementTags'); $replacement_tags = $replacement_tags ? unserialize($replacement_tags) : Array (); foreach ($replacement_tags as $tag => $replacement) { $records[] = Array ('Tag' => $tag, 'Replacement' => $replacement); } /** @var MInputHelper $minput_helper */ $minput_helper = $this->Application->recallObject('MInputHelper'); $xml = $minput_helper->prepareMInputXML($records, Array ('Tag', 'Replacement')); $object->SetDBField('ReplacementTagsXML', $xml); $this->setRequired($event); $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); /* @var $ml_helper kMultiLanguageHelper */ $translation_fields = $this->getTranslationFields(); $source_language = $ml_helper->getSourceLanguage($object->GetDBField('TranslateFromLanguage')); foreach ($translation_fields as $translation_field) { $object->SetDBField('Source' . $translation_field, $object->GetDBField('l' . $source_language . '_' . $translation_field)); } } /** * Performs custom validation + keep read-only fields * * @param kEvent $event */ function _itemChanged($event) { /** @var kDBItem $object */ $object = $event->getObject(); if ( !$this->Application->isDebugMode(false) ) { // only allow to enable/disable event while in debug mode $to_restore = Array ('Enabled', 'AllowChangingSender', 'AllowChangingRecipient'); if ( !$object->GetOriginalField('AllowChangingSender') ) { $to_restore = array_merge($to_restore, Array ('CustomSender', 'SenderName', 'SenderAddressType', 'SenderAddress')); } if ( !$object->GetOriginalField('AllowChangingRecipient') ) { $to_restore = array_merge($to_restore, Array ('CustomRecipient' /*, 'Recipients'*/)); } // prevent specific fields from editing foreach ($to_restore as $restore_field) { $original_value = $object->GetOriginalField($restore_field); if ( $object->GetDBField($restore_field) != $original_value ) { $object->SetDBField($restore_field, $original_value); } } } // process replacement tags if ( $object->GetDBField('ReplacementTagsXML') ) { /** @var MInputHelper $minput_helper */ $minput_helper = $this->Application->recallObject('MInputHelper'); $replacement_tags = Array (); $records = $minput_helper->parseMInputXML($object->GetDBField('ReplacementTagsXML')); foreach ($records as $record) { $replacement_tags[trim($record['Tag'])] = trim($record['Replacement']); } $object->SetDBField('ReplacementTags', $replacement_tags ? serialize($replacement_tags) : NULL); } if ( $this->translationChanged($object) ) { $object->SetDBField('LastChanged_date', TIMENOW); $object->SetDBField('LastChanged_time', TIMENOW); } $this->setRequired($event); } /** * Dynamically changes required fields * * @param kEvent $event * @return void * @access protected */ protected function setRequired(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); $language_prefix = 'l' . $this->Application->GetVar('m_lang') . '_'; $object->setRequired($language_prefix . 'HtmlBody', !$object->GetField('PlainTextBody')); $object->setRequired($language_prefix . 'PlainTextBody', !$object->GetField('HtmlBody')); } /** * Checks, that at least one of phrase's translations was changed * * @param kDBItem $object * @return bool */ function translationChanged($object) { $translation_fields = $this->getTranslationFields(); $changed_fields = array_keys($object->GetChangedFields()); foreach ($changed_fields as $changed_field) { $changed_field = preg_replace('/^l[\d]+_/', '', $changed_field); if ( in_array($changed_field, $translation_fields) ) { return true; } } return false; } /** * Returns fields, that can be translated * * @return Array * @access protected */ protected function getTranslationFields() { return Array ('Subject', 'HtmlBody', 'PlainTextBody'); } /** * Don't allow to enable/disable events in non-debug mode * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemCreate(kEvent $event) { parent::OnBeforeItemCreate($event); $this->_itemChanged($event); } /** * Don't allow to enable/disable events in non-debug mode * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemUpdate(kEvent $event) { parent::OnBeforeItemUpdate($event); $this->_itemChanged($event); } /** * Suggest address based on typed address and selected address type * * @param kEvent $event */ function OnSuggestAddressJSON($event) { $event->status = kEvent::erSTOP; $address_type = $this->Application->GetVar('type'); $address = $this->Application->GetVar('term'); $limit = $this->Application->GetVar('limit'); if ( !$limit ) { $limit = 20; } switch ($address_type) { case EmailTemplate::ADDRESS_TYPE_EMAIL: $field = 'Email'; $table_name = TABLE_PREFIX . 'Users'; break; case EmailTemplate::ADDRESS_TYPE_USER: $field = 'Username'; $table_name = TABLE_PREFIX . 'Users'; break; case EmailTemplate::ADDRESS_TYPE_GROUP: $field = 'Name'; $table_name = TABLE_PREFIX . 'UserGroups'; break; default: $field = $table_name = ''; break; } if ( $field ) { $sql = 'SELECT DISTINCT ' . $field . ' FROM ' . $table_name . ' WHERE ' . $field . ' LIKE ' . $this->Conn->qstr($address . '%') . ' ORDER BY ' . $field . ' ASC LIMIT 0,' . $limit; $data = $this->Conn->GetCol($sql); } else { $data = Array (); } echo json_encode($data); } /** * Does custom validation * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemValidate(kEvent $event) { parent::OnBeforeItemValidate($event); /** @var kDBItem $object */ $object = $event->getObject(); // validate email subject and body for parsing errors $this->_validateEmailTemplate($object); // validate sender and recipient addresses if ( $object->GetDBField('CustomSender') ) { $this->_validateAddress($event, 'Sender'); } $this->_validateAddress($event, 'Recipient'); $this->_validateBindEvent($object); } /** * Validates subject and body fields of Email template * * @param kDBItem $object * @return void * @access protected */ protected function _validateEmailTemplate($object) { /** @var kEmailTemplateHelper $email_template_helper */ $email_template_helper = $this->Application->recallObject('kEmailTemplateHelper'); $email_template_helper->parseField($object, 'Subject'); $email_template_helper->parseField($object, 'HtmlBody'); $email_template_helper->parseField($object, 'PlainTextBody'); } /** * Validates address using given field prefix * * @param kEvent $event * @param string $field_prefix * @return void * @access protected */ protected function _validateAddress($event, $field_prefix) { /** @var kDBItem $object */ $object = $event->getObject(); $address_type = $object->GetDBField($field_prefix . 'AddressType'); $object->setRequired($field_prefix . 'Address', $address_type > 0); $address = $object->GetDBField($field_prefix . 'Address'); if ( !$address ) { // don't validate against empty address return; } switch ($address_type) { case EmailTemplate::ADDRESS_TYPE_EMAIL: if ( !preg_match('/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', $address) ) { $object->SetError($field_prefix . 'Address', 'invalid_email'); } break; case EmailTemplate::ADDRESS_TYPE_USER: $sql = 'SELECT PortalUserId FROM ' . TABLE_PREFIX . 'Users WHERE Username = ' . $this->Conn->qstr($address); if ( !$this->Conn->GetOne($sql) ) { $object->SetError($field_prefix . 'Address', 'invalid_user'); } break; case EmailTemplate::ADDRESS_TYPE_GROUP: $sql = 'SELECT GroupId FROM ' . TABLE_PREFIX . 'UserGroups WHERE Name = ' . $this->Conn->qstr($address); if ( !$this->Conn->GetOne($sql) ) { $object->SetError($field_prefix . 'Address', 'invalid_group'); } break; } } /** * Checks that bind event is specified in correct format and exists * * @param kDBItem $object */ protected function _validateBindEvent($object) { $event_string = $object->GetDBField('BindToSystemEvent'); if ( !$event_string ) { return; } try { $this->Application->eventImplemented(new kEvent($event_string)); } catch (Exception $e) { $object->SetError('BindToSystemEvent', 'invalid_event', '+' . $e->getMessage()); } } /** * Stores ids of selected phrases and redirects to export language step 1 * * @param kEvent $event * @return void * @access protected */ protected function OnExportEmailTemplates(kEvent $event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } $this->Application->getUnitConfig('phrases')->setAutoLoad(false); $this->StoreSelectedIDs($event); $this->Application->StoreVar('export_language_ids', $this->Application->GetVar('m_lang')); $event->setRedirectParams( Array ( 'phrases.export_event' => 'OnNew', 'pass' => 'all,phrases.export', 'export_mode' => $event->Prefix, ) ); } /** * Deletes all subscribers to e-mail event after it was deleted * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemDelete(kEvent $event) { parent::OnAfterItemDelete($event); /** @var kDBItem $object */ $object = $event->getObject(); $sql = 'SELECT SubscriptionId FROM ' . TABLE_PREFIX . 'SystemEventSubscriptions WHERE EmailTemplateId = ' . $object->GetID(); $ids = $this->Conn->GetCol($sql); if ( !$ids ) { return; } /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject('system-event-subscription_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event->MasterEvent)); $temp_handler->DeleteItems('system-event-subscription', '', $ids); } /** * Sends selected e-mail event * * @param kEvent $event * @return void * @access protected */ protected function OnSend(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $ids = $this->StoreSelectedIDs($event); foreach ($ids as $id) { $object->Load($id); if ( $object->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_ADMIN ) { $this->Application->emailAdmin($object->GetDBField('TemplateName')); } else { $this->Application->emailUser($object->GetDBField('TemplateName')); } } $this->clearSelectedIDs($event); } /** * Updates translation state for all saved phrases * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeCopyToLive(kEvent $event) { parent::OnBeforeCopyToLive($event); $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); /* @var $ml_helper kMultiLanguageHelper */ $ml_helper->updateTranslationState($event); } } Index: branches/5.3.x/core/units/languages/languages_config.php =================================================================== --- branches/5.3.x/core/units/languages/languages_config.php (revision 16599) +++ branches/5.3.x/core/units/languages/languages_config.php (revision 16600) @@ -1,278 +1,279 @@ 'lang', 'ItemClass' => Array ('class' => 'LanguagesItem', 'file' => 'languages_item.php', 'build_event' => 'OnItemBuild'), 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), 'EventHandlerClass' => Array ('class' => 'LanguagesEventHandler', 'file' => 'languages_event_handler.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'LanguagesTagProcessor', 'file' => 'languages_tag_processor.php', 'build_event' => 'OnBuild'), 'AutoLoad' => true, 'Hooks' => Array ( Array ( 'Mode' => hAFTER, 'Conditional' => false, 'HookToPrefix' => 'lang', 'HookToSpecial' => '*', 'HookToEvent' => Array ('OnSave', 'OnMassDelete'), 'DoPrefix' => '', 'DoSpecial' => '', 'DoEvent' => 'OnScheduleTopFrameReload', ), ), 'QueryString' => Array ( 1 => 'id', 2 => 'Page', 3 => 'PerPage', 4 => 'event', 5 => 'mode', ), 'IDField' => 'LanguageId', 'StatusField' => Array ('Enabled', 'PrimaryLang'), // field, that is affected by Approve/Decline events 'TitleField' => 'PackName', // field, used in bluebar when editing existing item 'TitlePresets' => Array ( 'default' => Array ( 'new_status_labels' => Array ('lang' => '!la_title_Adding_Language!'), 'edit_status_labels' => Array ('lang' => '!la_title_Editing_Language!'), ), 'languages_list' => Array ( 'prefixes' => Array ('lang_List'), 'format' => "!la_title_Configuration! - !la_title_LanguagePacks!", 'toolbar_buttons' => Array ( 'new_item', 'edit', 'delete', 'export', 'import', 'setprimary', 'refresh', 'view', 'dbl-click' ), ), 'languages_edit_general' => Array ('prefixes' => Array ('lang'), 'format' => "#lang_status# '#lang_titlefield#' - !la_title_General!"), 'phrases_list' => Array ( 'prefixes' => Array ('lang', 'phrases_List'), 'format' => "#lang_status# '#lang_titlefield#' - !la_title_Labels!" ), 'phrase_edit' => Array ( 'prefixes' => Array ('phrases'), 'new_status_labels' => Array ('phrases' => '!la_title_Adding_Phrase!'), 'edit_status_labels' => Array ('phrases' => '!la_title_Editing_Phrase!'), 'format' => "#phrases_status# '#phrases_titlefield#'", ), 'import_language' => Array ( 'prefixes' => Array ('phrases.import'), 'format' => "!la_title_InstallLanguagePackStep1!", ), 'import_language_step2' => Array ( 'prefixes' => Array ('phrases.import'), 'format' => "!la_title_InstallLanguagePackStep2!", ), 'export_language' => Array ( 'prefixes' => Array ('phrases.export'), 'format' => "!la_title_ExportLanguagePackStep1!", ), 'export_language_results' => Array ( 'prefixes' => Array (), 'format' => "!la_title_ExportLanguagePackResults!", ), 'events_list' => Array ( 'prefixes' => Array ('lang', 'email-template_List'), 'format' => "#lang_status# '#lang_titlefield#' - !la_title_EmailTemplates!", ), 'email_template_edit' => Array ( 'prefixes' => Array ('lang', 'email-template'), 'format' => "#lang_status# '#lang_titlefield#' - !la_title_EditingEmailTemplate! '#email-template_titlefield#'", 'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'), ), // for separate language list 'languages_list_st' => Array ( 'prefixes' => Array ('lang_List'), 'format' => "!la_title_LanguagesManagement!", ), ), 'EditTabPresets' => Array ( 'Default' => Array ( 'general' => Array ('title' => 'la_tab_General', 't' => 'regional/languages_edit', 'priority' => 1), 'labels' => Array ('title' => 'la_tab_Labels', 't' => 'regional/languages_edit_phrases', 'priority' => 2), 'email_events' => Array ('title' => 'la_tab_EmailTemplates', 't' => 'regional/languages_edit_email_events', 'priority' => 3), ), ), 'PermSection' => Array ('main' => 'in-portal:configure_lang'), 'Sections' => Array ( 'in-portal:configure_lang' => Array ( 'parent' => 'in-portal:website_setting_folder', 'icon' => 'conf_regional', 'label' => 'la_tab_Regional', 'url' => Array ('t' => 'regional/languages_list', 'pass' => 'm'), 'permissions' => Array ('view', 'add', 'edit', 'delete', 'advanced:set_primary', 'advanced:import', 'advanced:export'), 'priority' => 4, 'type' => stTREE, ), // "Lang. Management" /*'in-portal:lang_management' => Array ( 'parent' => 'in-portal:system', 'icon' => 'core:settings_general', 'label' => 'la_title_LangManagement', 'url' => Array ('t' => 'languages/language_list', 'pass' => 'm'), 'permissions' => Array ('view', 'add', 'edit', 'delete'), 'perm_prefix' => 'lang', 'priority' => 10.03, 'show_mode' => smSUPER_ADMIN, 'type' => stTREE, ),*/ ), 'TableName' => TABLE_PREFIX . 'Languages', 'AutoDelete' => true, 'AutoClone' => true, 'ListSQLs' => Array ( '' => ' SELECT * FROM %s' ), 'ListSortings' => Array ( '' => Array ( 'Sorting' => Array ('Priority' => 'desc', 'PackName' => 'asc'), ), ), 'Fields' => Array ( 'LanguageId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'PackName' => Array ( 'type' => 'string', 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Languages ORDER BY PackName', 'option_title_field' => 'PackName', 'option_key_field' => 'PackName', 'not_null' => 1, 'required' => 1, 'default' => '' ), 'LocalName' => Array ( 'type' => 'string', 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Languages ORDER BY PackName', 'option_title_field' => 'LocalName', 'option_key_field' => 'LocalName', 'not_null' => 1, 'required' => 1, 'default' => '' ), 'Enabled' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_Disabled', 1 => 'la_Active'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1 ), 'PrimaryLang' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'AdminInterfaceLang' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), 'Priority' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'IconURL' => Array ('type' => 'string', 'max_len' => 255, 'default' => NULL), 'IconDisabledURL' => Array ('type' => 'string', 'max_len' => 255, 'default' => NULL), 'InputDateFormat' => Array ( 'type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array ('m/d/Y' => 'mm/dd/yyyy', 'd/m/Y' => 'dd/mm/yyyy', 'm.d.Y' => 'mm.dd.yyyy', 'd.m.Y' => 'dd.mm.yyyy'), 'not_null' => 1, 'required' => 1, 'default' => 'm/d/Y' ), 'InputTimeFormat' => Array ( 'type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array ('g:i:s A' => 'g:i:s A', 'g:i A' => 'g:i A', 'H:i:s' => 'H:i:s', 'H:i' => 'H:i'), 'not_null' => '1', 'required' => 1, 'default' => 'g:i:s A', ), 'DateFormat' => Array ('type' => 'string', 'not_null' => 1, 'required' => 1, 'default' => 'm/d/Y'), 'ShortDateFormat' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => 'm/d'), 'TimeFormat' => Array ('type' => 'string', 'not_null' => 1, 'required' => 1, 'default' => 'g:i:s A'), 'ShortTimeFormat' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => 'g:i A'), 'DecimalPoint' => Array ('type' => 'string', 'not_null' => 1, 'required' => 1, 'default' => '.'), 'ThousandSep' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''), 'UnitSystem' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Metric', 2 => 'la_US_UK'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 1 ), 'FilenameReplacements' => Array ('type' => 'string', 'default' => NULL), 'Locale' => Array ( 'type' => 'string', 'formatter' => 'kOptionsFormatter', 'options_sql' => " SELECT CONCAT(LocaleName, ' ' ,'\/',Locale,'\/') AS Name, Locale FROM " . TABLE_PREFIX . 'LocalesList ORDER BY LocaleId', 'option_title_field' => 'Name', 'option_key_field' => 'Locale', 'not_null' => 1, 'default' => 'en-US', ), 'UserDocsUrl' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'SynchronizationModes' => Array ( 'type' => 'string', 'max_len' => 255, 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_SynchronizeToOthers', 2 => 'la_opt_SynchronizeFromOthers'), 'use_phrases' => 1, 'multiple' => 1, 'not_null' => 1, 'default' => '' ), 'HtmlEmailTemplate' => Array ( 'type' => 'string', + 'formatter' => 'kFormatter', 'using_fck' => 1, 'error_msgs' => Array ('parsing_error' => '!la_error_ParsingError!', 'body_missing' => '!la_error_EmailTemplateBodyMissing!'), 'default' => '$body' ), 'TextEmailTemplate' => Array ( 'type' => 'string', 'error_msgs' => Array ('parsing_error' => '!la_error_ParsingError!', 'body_missing' => '!la_error_EmailTemplateBodyMissing!'), 'default' => NULL ), ), 'VirtualFields' => Array ( 'Charset' => Array ('type' => 'string', 'default' => CHARSET), // for backwards compatibility 'CopyLabels' => Array ('type' => 'int', 'default' => 0), 'CopyFromLanguage' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Languages ORDER BY PackName', 'option_title_field' => 'PackName', 'option_key_field' => 'LanguageId', 'default' => '', ), ), 'Grids' => Array ( 'Default' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', '0_0' => 'icon16_disabled.png', '0_1' => 'icon16_disabled.png', '1_0' => 'icon16_item.png', '1_1' => 'icon16_primary.png', ), 'Fields' => Array ( 'LanguageId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 50, ), 'PackName' => Array ('filter_block' => 'grid_options_filter', 'width' => 150, ),// 'PrimaryLang' => Array ('title' => 'la_col_IsPrimaryLanguage', 'filter_block' => 'grid_options_filter', 'width' => 150, ), 'AdminInterfaceLang' => Array ('filter_block' => 'grid_options_filter', 'width' => 150, ), 'Priority' => Array ('filter_block' => 'grid_like_filter', 'width' => 60, ), 'Enabled' => Array ('filter_block' => 'grid_options_filter', 'width' => 80, ), 'SynchronizationModes' => Array ('filter_block' => 'grid_picker_filter', 'width' => 120, 'format' => ', ', 'hidden' => 1), ), ), /*'LangManagement' => Array ( 'Icons' => Array ( 'default' => 'icon16_item.png', '0_0' => 'icon16_disabled.png', '0_1' => 'icon16_disabled.png', '1_0' => 'icon16_item.png', '1_1' => 'icon16_primary.png', ), 'Fields' => Array ( 'LanguageId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60), 'PackName' => Array ('title' => 'column:la_fld_Language', 'filter_block' => 'grid_options_filter', 'width' => 120), 'LocalName' => Array ('title' => 'column:la_fld_Prefix', 'filter_block' => 'grid_options_filter', 'width' => 120), 'IconURL' => Array ('title' => 'column:la_fld_Image', 'filter_block' => 'grid_empty_filter', 'width' => 80), ), ),*/ ), -); \ No newline at end of file +); Index: branches/5.3.x/core/units/languages/languages_item.php =================================================================== --- branches/5.3.x/core/units/languages/languages_item.php (revision 16599) +++ branches/5.3.x/core/units/languages/languages_item.php (revision 16600) @@ -1,304 +1,308 @@ IDField . ') FROM ' . $this->getUnitConfig()->getTableName(); return $this->Conn->GetOne($sql) + 1; } /** * Set's current language as new primary and return previous primary language * * @param bool $reset_primary * @param bool $admin_language * @return int */ function setPrimary($reset_primary = true, $admin_language = false) { $prev_primary = false; $primary_field = $admin_language ? 'AdminInterfaceLang' : 'PrimaryLang'; if ($reset_primary) { $sql = 'SELECT ' . $this->IDField . ' FROM ' . $this->TableName . ' WHERE ' . $primary_field . ' = 1'; $prev_primary = $this->Conn->GetOne($sql); $sql = 'UPDATE '.$this->TableName.' SET '.$primary_field.' = 0'; $this->Conn->Query($sql); } $sql = 'UPDATE '.$this->TableName.' SET '.$primary_field.' = 1, Enabled = 1 WHERE '.$this->IDField.' = '.$this->GetID(); $this->Conn->Query($sql); // in case, when Update method is called for this langauge object $this->SetDBField($primary_field, 1); $this->SetDBField('Enabled', 1); // increment serial by hand, since no Update method is called $this->Application->incrementCacheSerial($this->Prefix); $this->Application->incrementCacheSerial($this->Prefix, $this->GetID()); return $prev_primary; } /** * Copies missing data on current language from given language * * @param int $from_language */ function copyMissingData($from_language) { if ( !is_numeric($from_language) || ($from_language == $this->GetID()) ) { // invalid or same language return ; } /** @var kMultiLanguageHelper $ml_helper */ $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); $to_language = $this->GetID(); $this->Application->UnitConfigReader->ReReadConfigs(); foreach ($this->Application->UnitConfigReader->getPrefixes() as $prefix) { $ml_helper->copyMissingData($prefix, $from_language, $to_language); } } /** * Allows to format number according to regional settings * * @param float $number * @param int $precision * @return float */ function formatNumber($number, $precision = null) { if (is_null($precision)) { $precision = preg_match('/[\.,]+/', $number) ? strlen(preg_replace('/^.*[\.,]+/', '', $number)) : 0; } return number_format($number, $precision, (string)$this->GetDBField('DecimalPoint'), (string)$this->GetDBField('ThousandSep')); } /** * Returns language id based on HTTP header "Accept-Language" * * @return int */ function processAcceptLanguage() { if (!array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER) || !$_SERVER['HTTP_ACCEPT_LANGUAGE']) { return false; } $accepted_languages = Array (); $language_string = explode(',', strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])); foreach ($language_string as $mixed_language) { if (strpos($mixed_language, ';') !== false) { list ($language_locale, $language_quality) = explode(';', $mixed_language); $language_quality = (float)substr($language_quality, 2); // format "q=4.45" } else { $language_locale = $mixed_language; $language_quality = 1.00; } $accepted_languages[ trim($language_locale) ] = trim($language_quality); } arsort($accepted_languages, SORT_NUMERIC); foreach ($accepted_languages as $language_locale => $language_quality) { $language_id = $this->getAvailableLanguage($language_locale); if ($language_id) { return $language_id; } } return false; } /** * Returns language ID based on given locale * * @param string $locale * @return int */ function getAvailableLanguage($locale) { $cache_key = 'available_languages[%LangSerial%]'; $available_languages = $this->Application->getCache($cache_key); if ($available_languages === false) { $this->Conn->nextQueryCachable = true; $sql = 'SELECT LanguageId, LOWER(Locale) AS Locale FROM ' . TABLE_PREFIX . 'Languages WHERE Enabled = 1'; $available_languages = $this->Conn->GetCol($sql, 'Locale'); $this->Application->setCache($cache_key, $available_languages); } if (strpos($locale, '-') !== false) { // exact language match requested $language_id = array_key_exists($locale, $available_languages) ? $available_languages[$locale] : false; if ($language_id && $this->siteDomainLanguageEnabled($language_id)) { return $language_id; } return false; } // partial (like "en" matches "en-GB" and "en-US") language match required foreach ($available_languages as $language_code => $language_id) { list ($language_code, ) = explode('-', $language_code); if (($locale == $language_code) && $this->siteDomainLanguageEnabled($language_id)) { return $language_id; } } return false; } /** * Loads item from the database by given id * * @access public * @param mixed $id item id of keys->values hash to load item by * @param string $id_field_name Optional parameter to load item by given Id field * @param bool $cachable cache this query result based on it's prefix serial * @return bool True if item has been loaded, false otherwise * @throws kRedirectException */ public function Load($id, $id_field_name = null, $cachable = true) { + if ( $cachable && $this->IsTempTable() ) { + $cachable = false; + } + $default = false; if ($id == 'default') { // domain based primary language $default = true; $id = $this->Application->siteDomainField('PrimaryLanguageId'); if ($id) { $res = parent::Load($id, $id_field_name, $cachable); } else { $res = parent::Load(1, 'PrimaryLang', $cachable); } if ( !$this->Application->isAdmin && !defined('GW_NOTIFY') && preg_match('/[\/]{0,1}index.php[\/]{0,1}/', $_SERVER['PHP_SELF']) && !$this->Application->HttpQuery->refererIsOurSite() && $this->Application->ConfigValue('UseContentLanguageNegotiation') ) { $language_id = $this->processAcceptLanguage(); if ( $language_id != $this->GetID() ) { // redirect to same page with found language $url_params = Array ( 'm_cat_id' => 0, 'm_cat_page' => 1, 'm_lang' => $language_id, 'm_opener' => 's', 'pass' => 'm' ); $this->_addLoginState($url_params); $exception = new kRedirectException('Redirect into language ID = ' . $language_id . ' according to "Accepted-Language" header "' . $_SERVER['HTTP_ACCEPT_LANGUAGE'] . '"'); $exception->setup('', $url_params); throw $exception; } } } else { $res = parent::Load($id, $id_field_name, $cachable); } if ($res) { if (!$this->siteDomainLanguageEnabled($this->GetID())) { // language isn't allowed in site domain return $this->Clear(); } } if ($default) { if (!$res) { if ($this->Application->isAdmin) { $res = parent::Load(1, $id_field_name, false); } else { if (defined('IS_INSTALL')) { // during first language import prevents sql errors $this->setID(1); $res = true; } else { $this->Application->ApplicationDie('No Primary Language Selected'); } } } $this->Application->SetVar('lang.current_id', $this->GetID() ); $this->Application->SetVar('m_lang', $this->GetID() ); } return $res; } /** * Pass login state variables into new language url * * @param $url_params * @return void * @access protected */ protected function _addLoginState(&$url_params) { $pass_along = Array ('login', 'logout'); foreach ($pass_along as $pass_along_name) { $pass_along_value = $this->Application->GetVar($pass_along_name); if ( $pass_along_value !== false ) { $url_params[$pass_along_name] = $pass_along_value; } } } /** * Checks, that language is enabled in site domain * * @param int $id * @return bool */ function siteDomainLanguageEnabled($id) { $available_languages = $this->Application->siteDomainField('Languages'); if ($available_languages) { return strpos($available_languages, '|' .$id . '|') !== false; } return true; } - } \ No newline at end of file + } Index: branches/5.3.x/core/units/general/MainRouter.php =================================================================== --- branches/5.3.x/core/units/general/MainRouter.php (revision 16599) +++ branches/5.3.x/core/units/general/MainRouter.php (revision 16600) @@ -1,305 +1,306 @@ getUrlProcessor(); $build_params = $this->extractBuildParams(); if ( $build_params === false ) { return ''; } // Add language. if ( $build_params['m_lang'] && ($build_params['m_lang'] != $rewrite_processor->primaryLanguageId) ) { $cache_key = 'language_names[%LangIDSerial:' . $build_params['m_lang'] . '%]'; $language_name = $this->Application->getCache($cache_key); if ( $language_name === false ) { $sql = 'SELECT PackName FROM ' . TABLE_PREFIX . 'Languages WHERE LanguageId = ' . $build_params['m_lang']; $language_name = $this->Conn->GetOne($sql); $this->Application->setCache($cache_key, $language_name); } $ret .= $language_name . '/'; } // Add theme. if ( $build_params['m_theme'] && ($build_params['m_theme'] != $rewrite_processor->primaryThemeId) ) { $cache_key = 'theme_names[%ThemeIDSerial:' . $build_params['m_theme'] . '%]'; $theme_name = $this->Application->getCache($cache_key); if ( $theme_name === false ) { $sql = 'SELECT Name FROM ' . TABLE_PREFIX . 'Themes WHERE ThemeId = ' . $build_params['m_theme']; $theme_name = $this->Conn->GetOne($sql); $this->Application->setCache($cache_key, $theme_name); } $ret .= $theme_name . '/'; } // Inject custom url parts made by other routers just after language/theme url parts. $inject_parts = $this->getBuildParam('inject_parts', false); if ( $inject_parts ) { $ret .= implode('/', $inject_parts) . '/'; } // Add category. if ( $build_params['m_cat_id'] > 0 && $this->getBuildParam('pass_category', false) ) { $category_filename = $this->Application->getCategoryCache($build_params['m_cat_id'], 'filenames'); preg_match('/^Content\/(.*)/i', $category_filename, $regs); if ( $regs ) { $template = $this->getBuildParam('t', false); if ( strtolower($regs[1]) == strtolower($template) ) { // We could have category path like "Content/" in this case remove template. $this->setBuildParam('pass_template', false); } $ret .= $regs[1] . '/'; } $this->setBuildParam('category_processed', true); } // Reset category page. $force_page_adding = false; $reset_category_page = $this->getBuildParam('reset', false); if ( $reset_category_page ) { $this->setBuildParam('reset'); if ( $build_params['m_cat_id'] ) { $build_params['m_cat_page'] = 1; $force_page_adding = true; } } $category_processed = $this->getBuildParam('category_processed', false); if ( ($category_processed && ($build_params['m_cat_page'] > 1)) || $force_page_adding ) { // Category name was added before AND category page number found. $ret = rtrim($ret, '/') . '_' . $build_params['m_cat_page'] . '/'; } $template = $this->getBuildParam('t', false); if ( ($build_params['m_cat_id'] > 0) && $this->getBuildParam('pass_category', false) ) { $category_template = $this->Application->getCategoryCache($build_params['m_cat_id'], 'category_designs'); } else { $category_template = ''; } if ( (strtolower($template) == '__default__') && ($build_params['m_cat_id'] == 0) ) { // For "Home" category set template to index when not set. $template = 'index'; } // Remove template from url if it is category index cached template. if ( ($template == $category_template) || (mb_strtolower($template) == '__default__') ) { // Given template is also default template for this category OR '__default__' given. $this->setBuildParam('pass_template', false); } // Remove template from url if it is site homepage on primary language & theme. if ( $template == 'index' && $build_params['m_lang'] == $rewrite_processor->primaryLanguageId && $build_params['m_theme'] == $rewrite_processor->primaryThemeId ) { // Given template is site homepage on primary language & theme. $this->setBuildParam('pass_template', false); } if ( $template && $this->getBuildParam('pass_template', false) ) { $ret .= $template . '/'; } return mb_strtolower(rtrim($ret, '/')); } /** * Parses url part. * * @param array $url_parts Url parts to parse. * @param array $params Parameters, that are used for url building or created during url parsing. * * @return boolean Return true to continue to next router; return false to stop processing at this router. */ public function parse(array &$url_parts, array &$params) { if ( $this->parseFriendlyUrl($url_parts, $params) ) { // Friendly urls work like exact match only! return false; } $this->parseCategory($url_parts, $params); return true; } /** * Checks if whole url_parts matches a whole In-CMS page * * @param array $url_parts Url parts. * @param array $params Params. * * @return boolean */ protected function parseFriendlyUrl(array $url_parts, array &$params) { if ( !$url_parts ) { return false; } $sql = 'SELECT CategoryId, NamedParentPath FROM ' . TABLE_PREFIX . 'Categories WHERE FriendlyURL = ' . $this->Conn->qstr(implode('/', $url_parts)); $friendly = $this->Conn->GetRow($sql); if ( $friendly ) { + $params['is_friendly_url'] = true; $params['m_cat_id'] = $friendly['CategoryId']; $params['t'] = preg_replace('/^Content\//i', '', $friendly['NamedParentPath']); while ( $url_parts ) { $this->partParsed(array_shift($url_parts)); } return true; } return false; } /** * Extracts category part from url * * @param array $url_parts Url parts. * @param array $params Params. * * @return boolean */ protected function parseCategory(array $url_parts, array &$params) { if ( !$url_parts ) { return false; } $res = false; $url_part = array_shift($url_parts); $category_id = 0; $last_category_info = false; $category_path = $url_part == 'content' ? '' : 'content'; $rewrite_processor = $this->getUrlProcessor(); do { $category_path = trim($category_path . '/' . $url_part, '/'); // Part: "bb_" matches "forums/bb_2". if ( !preg_match('/^bb_[\d]+$/', $url_part) && preg_match('/(.*)_([\d]+)$/', $category_path, $regs) ) { $category_path = $regs[1]; $params['m_cat_page'] = $regs[2]; } $sql = 'SELECT CategoryId, SymLinkCategoryId, NamedParentPath FROM ' . TABLE_PREFIX . 'Categories WHERE (LOWER(NamedParentPath) = ' . $this->Conn->qstr($category_path) . ') AND (ThemeId = ' . $params['m_theme'] . ' OR ThemeId = 0)'; $category_info = $this->Conn->GetRow($sql); if ( $category_info !== false ) { $last_category_info = $category_info; $rewrite_processor->partParsed($url_part); $url_part = array_shift($url_parts); $res = true; } } while ( $category_info !== false && $url_part ); if ( $last_category_info ) { // This category is symlink to other category, so use it's url instead // (used in case if url prior to symlink adding was indexed by spider or was bookmarked). if ( $last_category_info['SymLinkCategoryId'] ) { $sql = 'SELECT CategoryId, NamedParentPath FROM ' . TABLE_PREFIX . 'Categories WHERE (CategoryId = ' . $last_category_info['SymLinkCategoryId'] . ')'; $category_info = $this->Conn->GetRow($sql); if ( $category_info ) { // Web symlinked category was found use it. // TODO: maybe 302 redirect should be made to symlinked category url // (all other url parts should stay). $last_category_info = $category_info; } } // 1. Set virtual page as template, this will be replaced to physical template later in kApplication::Run. // 2. Don't set CachedTemplate field as template here, because we will loose original // page associated with it's cms blocks! $params['t'] = mb_strtolower(preg_replace('/^Content\//i', '', $last_category_info['NamedParentPath'])); $params['m_cat_id'] = $last_category_info['CategoryId']; $params['is_virtual'] = true; // For template from POST, strange code there! } return $res; } } Index: branches/5.3.x/core/admin_templates/categories/categories_edit.tpl =================================================================== --- branches/5.3.x/core/admin_templates/categories/categories_edit.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/categories/categories_edit.tpl (revision 16600) @@ -1,318 +1,318 @@
onchange="update_checkbox(this, document.getElementById(''));" onclick="reflectDirectLink();"/>
- \ No newline at end of file + Index: branches/5.3.x/core/admin_templates/promo_blocks/promo_block_edit.tpl =================================================================== --- branches/5.3.x/core/admin_templates/promo_blocks/promo_block_edit.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/promo_blocks/promo_block_edit.tpl (revision 16600) @@ -1,132 +1,132 @@
- +
Index: branches/5.3.x/core/admin_templates/mailing_lists/mailing_list_edit.tpl =================================================================== --- branches/5.3.x/core/admin_templates/mailing_lists/mailing_list_edit.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/mailing_lists/mailing_list_edit.tpl (revision 16600) @@ -1,150 +1,150 @@
<> ;
- +
" id="" value="" tabindex="" size="">
- \ No newline at end of file + Index: branches/5.3.x/core/admin_templates/tools/system_tools.tpl =================================================================== --- branches/5.3.x/core/admin_templates/tools/system_tools.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/tools/system_tools.tpl (revision 16600) @@ -1,310 +1,318 @@

: master:configs_parsed ()
"/> "/>

: master:sections_parsed ()
"/>

"/>

"/>

"/>

: master:config_files, master:configs_parsed ()
"/>

"/>

: master:cms_menu, master:template_mapping, master:StructureTree ()
"/>
Index: branches/5.3.x/core/admin_templates/js/template_manager.js =================================================================== --- branches/5.3.x/core/admin_templates/js/template_manager.js (revision 16599) +++ branches/5.3.x/core/admin_templates/js/template_manager.js (revision 16600) @@ -1,633 +1,633 @@ function TemplateManager ( $settings ) { this.languagePrefix = ''; this.pageId = 0; this.editUrl = ''; this.browseUrl = ''; this.saveLayoutUrl = ''; this.saveContentUrl = ''; this.editingMode = 0; // from {1 - browse, 2 - content, 3 - design} this.pageInfo = {editors: [], revisions: {}}; // information about page in "Content Mode" this.pageInfoUpdateTimer = null; this.revisionStatusMap = { 1: 'cms-revision-published', 2: 'cms-revision-pending', 0: 'cms-revision-declined' }; this._blocks = {}; this._blockOrder = []; this.inDrag = false; // don't process mouse over/out events while in drag mode $.extend(this, $settings); var $me = this; $(document).ready(function() { $me.init(); }); } TemplateManager.prototype.init = function () { this.searchBlocks(); if ( !this.editingMode ) { return; } // show special toolbar when in any of 3 browse modes var $template_manager = this, $head_frame = getFrame('head'), $extra_toolbar = $head_frame.$('div.front-extra-toolbar').clone(); // clone to keep original untouched $('a', $extra_toolbar).each(function () { // cut from end, because IE7 adds base_href to beginning of href var $editing_mode = $(this).attr('href'); $editing_mode = $editing_mode.substr($editing_mode.length - 1, 1); $(this).attr('href', $template_manager.browseUrl.replace('#EDITING_MODE#', $editing_mode)); if ( $editing_mode == $template_manager.editingMode ) { $(this).parents('td:first').addClass('button-active').prevAll('td:first').addClass('button-active'); } }); $head_frame.$('#extra_toolbar').html($extra_toolbar.html()); var $hover_effect = []; if ( $template_manager.editingMode > 1 ) { // all modes except for "Browse Mode" // $hover_effect.push('div.cms-section-properties-btn:first'); } if ( $template_manager.editingMode == 2 ) { // Content Mode // $hover_effect.push('div.cms-edit-btn'); // $hover_effect.push('div.admin-edit-btn'); // make all spans with phrases clickable $template_manager.setupEditTranslationButtons(document); // hide "Revision History" div on every body click (bubbled), but not a "toolbar button", that opens it $('body').click(function ($e) { var $target = $($e.target), $id = $target.attr('id'); if ( $id && ($id == 'div_history' || $target.parent().attr('id') == 'div_history') ) { return; } $('#cms-revision-dropdown:visible').hide(); }); } if ( $template_manager.editingMode == 3 ) { // Design Mode // $hover_effect.push('div.cms-save-layout-btn:first, div.cms-cancel-layout-btn:first'); $template_manager.renumberMovableElements(); $('div.movable-area').sortable({ placeholder: 'move-helper', handle: '.movable-header', items: 'div.movable-element', connectWith: ['div.movable-area'], tolerance: 'pointer', start: function (e, ui) { $template_manager.inDrag = true; ui.placeholder.height(ui.item.height()); }, stop: function (e, ui) { $template_manager.inDrag = false; // mouseout doesn't happen while in drag, so compensate it here var $header = $('.movable-header', ui.item); $('div.block-edit-block-btn-container', $header).mouseout(); }, change: function (e, ui) { $('div.cms-layout-btn-container').show(); } }); } // make requested elements fully visible on mouseover if ( $hover_effect.length ) { $($hover_effect.join(', ')) .mouseover(function (e) { $(this).css('opacity', 1); }) .mouseout(function (e) { $(this).css('opacity', 0.5); }); } // related to content revision control toolbar if ( $template_manager.revisionToolbarEnabled() ) { $template_manager.initRevisionToolbar(); } $('body') .bind('InlineEditor.Focus', function ($e, $editor_event) { $template_manager.inlineEditorFocus($editor_event); }) .bind('InlineEditor.Blur', function ($e, $editor_event) { $template_manager.inlineEditorBlur($editor_event); }); }; TemplateManager.prototype.revisionToolbarEnabled = function () { return $('#cms-revision-toolbar-layer').length == 1; }; TemplateManager.prototype.initRevisionToolbar = function () { var $template_manager = this; $('#cms-toggle-revision-toolbar').click(function ($e) { var $me = $(this); if ( $me.hasClass('opened') ) { var $height = $('#cms-revision-toolbar').height(); $('#cms-revision-toolbar-layer').animate({top: (-1) * $height}, 'fast'); $('#cms-editing-notice, #cms-revision-dropdown').hide(); setCookie('toolbar_hidden', 1); } else { $('#cms-revision-toolbar-layer').animate({top: 0}, 'fast'); setCookie('toolbar_hidden', 0); } $me.toggleClass('opened'); $e.preventDefault(); }); $('#cms-close-toolbar').click(function ($e) { var $height = $('#cms-revision-toolbar').height(); $('#cms-toggle-revision-toolbar').removeClass('opened'); $('#cms-revision-toolbar-layer').css('top', (-1) * $height); $('#cms-editing-notice, #cms-revision-dropdown').hide(); setCookie('toolbar_hidden', 1); $e.preventDefault(); }); $('#cms-close-editing-notice').click(function ($e) { $('#cms-editing-notice').hide(); $e.preventDefault(); }); $('body').on('click', '#cms-revision-dropdown .top .item', function ($e) { - $('a:first', this).click(); - - $e.preventDefault(); + window.location.assign( + $('a:first', this).attr('href') + ); }); $template_manager.requirePageInfoUpdate(); if ( !$.isEmptyObject($template_manager.pageInfo) ) { $template_manager.processPageInfo(); } }; TemplateManager.prototype.requirePageInfoUpdate = function ($now) { var $me = this; if ( $now === undefined || $now === false ) { clearTimeout(this.pageInfoUpdateTimer); this.pageInfoUpdateTimer = setInterval(function () { $me.requirePageInfoUpdate(true); }, 20 * 1000); // 20 seconds return; } $.getJSON( $('#kf_revisions_' + this.pageId).attr('action').replace('-d-', '-s-') + '&events[page-revision]=OnGetInfo', function ($data) { $me.pageInfo = $data; $me.processPageInfo(); } ); }; TemplateManager.prototype.processPageInfo = function () { this.updateCurrentRevision(); if ( $('#cms-toggle-revision-toolbar').hasClass('opened') ) { this.showEditingNotice(); } this.updateRevisionHistory(); }; TemplateManager.prototype.updateCurrentRevision = function () { var $me = this, $title = $('.revision-title', '#cms-current-revision-info'); $title.html(this.pageInfo.current_revision.title); $('.draft-saved', '#cms-current-revision-info').html(this.pageInfo.current_revision.saved); $.each(this.revisionStatusMap, function ($status, $class_name) { $title.toggleClass($class_name, $status === $me.pageInfo.current_revision.status); }); $.each(this.pageInfo.current_revision.toolbar_state, function ($button_name, $is_enabled) { a_toolbar.SetEnabled($button_name, $is_enabled); }); }; TemplateManager.prototype.showEditingNotice = function () { var $notice = $('#cms-editing-notice'); if ( this.pageInfo.editors.length ) { var $notice_span = $('span:first', $notice); if ( $notice_span.data('prev_editors') != this.pageInfo.editors.join(',') ) { // show notice, only when editors change occurs $notice_span.html(this.pageInfo.editors_warning).data('prev_editors', this.pageInfo.editors.join(',')); if ( $notice.is(':hidden') ) { $notice.fadeIn(); } } } else if ( $notice.is(':visible') ) { $notice.fadeOut(); } }; TemplateManager.prototype.updateRevisionHistory = function () { var $me = this, $revision_container = $('.top', '#cms-revision-dropdown'), $revision_mask = '
\ {TITLE} ({STATUS_LABEL})\
{DATETIME}
\
{AUTHOR}
\
\
'; $revision_container.empty(); if ( $.isArray(this.pageInfo.revisions) ) { return; } $.each(this.pageInfo.revisions, function ($revision_number, $revision_info) { var $html = $revision_mask; $.each($revision_info, function ($field, $value) { $html = $html.replace(new RegExp('{' + $field.toUpperCase() + '}', 'g'), $value); }); $html = $html.replace(/{CLASS}/g, $me.revisionStatusMap[$revision_info.status]); if ( $revision_info['draft'] ) { $html = $html.replace(/{LINK}/g, $me.browseUrl.replace('#EDITING_MODE#', '2')); } else { $html = $html.replace(/{LINK}/g, $me.browseUrl.replace('#EDITING_MODE#', '2') + '&revision=' + $revision_number.substr(1)); } $revision_container.append($html); }); }; TemplateManager.prototype.inlineEditorFocus = function ($editor_event) { var $container = $($editor_event.editor.element.$).parent('.cms-edit-btn-container'); $container.removeClass('mode-inline-edit'); }; TemplateManager.prototype.inlineEditorBlur = function ($editor_event) { var $me = this, $element = $($editor_event.editor.element.$), $container = $element.parent('.cms-edit-btn-container'), $url_params = {}, $content_id = $container.data('content-id'); if ( $element.data('no_save_on_blur') === true ) { $element.data('no_save_on_blur', null); return; } $element.css('position', 'static'); $container.addClass('mode-inline-saving'); $url_params["content[" + $content_id + "][" + this.languagePrefix + "Content]"] = $editor_event.editor.getData(); $.post( this.saveContentUrl, $url_params, function ($data) { if ( $data != 'OK' ) { return; } if ( $me.revisionToolbarEnabled() ) { $me.requirePageInfoUpdate(true); } $element.css('position', 'relative'); $container.removeClass('mode-inline-saving').addClass('mode-inline-edit'); } ); }; TemplateManager.prototype.revisionToolbarClick = function ($button_name) { // console.log('button ', $button_name, ' clicked'); var $button_event_map = { 'select': 'OnSave', 'delete': 'OnDiscard', 'approve': 'OnPublish', 'decline': 'OnDecline' }; if ( $button_event_map[$button_name] !== undefined ) { $form_name = 'kf_revisions_' + this.pageId; submit_event('page-revision', $button_event_map[$button_name]); return; } switch ( $button_name ) { case 'preview': var $url = this.browseUrl.replace('#EDITING_MODE#', 0).replace(/&(admin|editing_mode)=[\d]/g, ''); window.open($url + '&preview=1'); break; case 'history': $('#cms-revision-dropdown').toggle(); break; } }; TemplateManager.prototype.setupEditTranslationButtons = function ($container) { $("span[name='cms-translate-phrase']", $container).each(function() { var $me = $(this), $parent_link = $me.parents('a:first'); if ( $parent_link.length == 0 ) { // span in not inside "a" tag $me.prepend('
Edit
'); $('div.cms-edit-btn:first', $me).click(TemplateManager.prototype.translatePhrase); $me.dblclick(function ($e) { $('div.cms-edit-btn:first', this).click(); $e.preventDefault(); }); var $effect_element = $me; } else { // span is inside "a" tag var $clone = $me.clone(); $clone.empty().attr('title', ''); // in case if "a" tag is "display: block", then make "span" the same $clone.css('display', $parent_link.css('display')); $parent_link.html($me.html()).wrap($clone); $parent_link.before('
Edit
'); $parent_link.prev('div.cms-edit-btn:first').click(TemplateManager.prototype.translatePhrase); var $effect_element = $parent_link.parents("span[name='cms-translate-phrase']:first"); } $effect_element .mouseover(function($e) { $('div.cms-edit-btn', this).css('display', 'inline'); }) .mouseout(function($e) { $('div.cms-edit-btn', this).hide(); }); }); }; TemplateManager.prototype.translatePhrase = function ($e) { var $translate_url = $(this).parents("span[name='cms-translate-phrase']:first").attr('href'); if ( $translate_url.match(/javascript:(.*)/) ) { eval(RegExp.$1); } else { window.location.href = $translate_url; } $e.preventDefault(); }; TemplateManager.prototype.renumberMovableElements = function () { var $area_index = 0; // 1. dynamically assign IDs to all movable elements $('div.movable-area').each(function () { var $element_index = 0; $('div.movable-element', this).each(function () { $(this).attr('id', 'target_order_a' + $area_index + 'e' + $element_index); $element_index++; }); $area_index++; }); }; TemplateManager.prototype.saveLayout = function () { // prepare order string var $sort_order = []; $('div.movable-area').each(function ($area_index) { var $order = $(this).sortable('serialize').replace(/target_order\[\]/g, 'target_order[' + $area_index + '][]'); if ( $order ) { $sort_order.push($order); } }); $sort_order = $sort_order.join('&'); // save order string var $me = this; var $settings = { url: this.saveLayoutUrl + '&' + $sort_order + '&width=200&height=70&modal=true', caption: 'Layout Saving Result', onDataReceived: function ($data) { var $message = ''; if ( $data == 'OK' ) { $message = 'New Layout Saved'; $('div.cms-layout-btn-container').hide(); $me.renumberMovableElements(); } else { $message = 'Failed to Save New Layout'; } $data = '
' + $message + '

'; return $data; } }; TB.setWindowTitle(window.top.document.title.replace(main_title + ' :: ', '')); TB.show($settings); }; TemplateManager.prototype.cancelLayout = function () { window.location.href = window.location.href; }; TemplateManager.prototype.onBtnClick = function ($e, $element) { var $id = $element.id.replace(/_btn$/, ''); var $block_info = this._blocks[$id]; var $url = this.editUrl.replace('#BLOCK#', $block_info.block_name + ':' + $block_info.function_name).replace('#EVENT#', 'OnLoadBlock'); direct_edit('theme-file', $url); $e.stopPropagation(); }; TemplateManager.prototype.onMouseOver = function ($e, $element) { if ( this.inDrag ) { return; } $element = $($element); if ( $element.hasClass('block-edit-design-btn-container') ) { $($element).addClass('block-edit-design-btn-container-over'); var $button_group = $('div.cms-edit-design-btn-container:first', $element); if ( $button_group.length ) { $button_group.show(); } else { $('.cms-edit-design-btn:first', $element).show(); } } else { $($element).addClass('block-edit-block-btn-container-over'); $('.cms-edit-block-btn:first', $element).show(); } $e.stopPropagation(); }; TemplateManager.prototype.onMouseOut = function ($e, $element) { if ( this.inDrag ) { return; } $element = $($element); if ( $element.hasClass('block-edit-design-btn-container') ) { $($element).removeClass('block-edit-design-btn-container-over'); var $button_group = $('div.cms-edit-design-btn-container:first', $element); if ( $button_group.length ) { $button_group.hide(); } else { $('.cms-edit-design-btn:first', $element).hide(); } } else { $($element).removeClass('block-edit-block-btn-container-over'); $('.cms-edit-block-btn:first', $element).hide(); } $e.stopPropagation(); }; TemplateManager.prototype.searchBlocks = function () { var $design_containers = $('div.block-edit-design-btn-container'); var $block_containers = $('div.block-edit-block-btn-container'); $design_containers.each(function () { var $block_container = $('div.block-edit-block-btn-container:first', this); if ( $block_container.length ) { $block_containers = $block_containers.not($block_container); // place "Edit Block" button near "Edit Design" button var $edit_design_btn = $('.cms-edit-design-btn:first', this); var $edit_block_btn = $('.cms-edit-block-btn:first', $block_container); $edit_design_btn .wrap('
') .before($edit_block_btn.clone()); $edit_block_btn.remove(); // make "hint" from "Edit Block" button container main $(this).attr('title', $block_container.attr('title')); $block_container.attr('title', ''); TemplateManager.prototype.registerBlock.call(aTemplateManager, $block_container.get(0), ['hover']); } TemplateManager.prototype.registerBlock.call(aTemplateManager, this, ['dblclick']); }); $block_containers.each(function() { TemplateManager.prototype.registerBlock.call(aTemplateManager, this); }); /*$('div').each (function () { *//*var $id = $(this).attr('id'); if ( !$id || $id.match(/parser_block\[.*\].*_btn$/) || !$id.match(/parser_block\[.*\]/) ) { // skip other divs return true; }*//* TemplateManager.prototype.registerBlock.call(aTemplateManager, this); });*/ }; TemplateManager.prototype.registerBlock = function ($element, $skip_events) { var $params = $element.getAttribute('params').split(':'); this._blocks[$element.id] = { block_name: $params[0], function_name: $params[1] }; var $btn = document.getElementById($element.id + '_btn'); $($btn).click(function (ev) { TemplateManager.prototype.onBtnClick.call(aTemplateManager, ev, this); }); if ( $skip_events === undefined ) { $skip_events = []; } if ( !in_array('dblclick', $skip_events) ) { $($element).dblclick(function (ev) { TemplateManager.prototype.onBtnClick.call(aTemplateManager, ev, this); }); } if ( !in_array('hover', $skip_events) ) { $($element) .mouseover(function (ev) { TemplateManager.prototype.onMouseOver.call(aTemplateManager, ev, this); }) .mouseout(function (ev) { TemplateManager.prototype.onMouseOut.call(aTemplateManager, ev, this); }); } this._blockOrder.push($element.id); }; Index: branches/5.3.x/core/admin_templates/js/grid_filters.js =================================================================== --- branches/5.3.x/core/admin_templates/js/grid_filters.js (revision 16599) +++ branches/5.3.x/core/admin_templates/js/grid_filters.js (revision 16600) @@ -1,153 +1,165 @@ /* Class used to convert element $select.hide(); // create div with checkboxes and buttons var $cur_index = MultiOptions.Selectors.length; var $div = $('
'); MultiOptions.Selectors.push($id); // set defaults for missing phrases if (!phrases['la_btn_SelectAll']) phrases['la_SelectAll'] = 'Select All'; if (!phrases['la_btn_OpenMultiFilter']) phrases['la_OpenMultiFilter'] = 'Open Filter'; if (!phrases['la_btn_Search']) phrases['la_ToolTip_Search'] = 'Search'; if (!phrases['la_btn_Close']) phrases['la_tooltip_close'] = 'Close'; // create div with checkboxes var $options_div = $('
'); // add "Select All" checkbox $options_div.append( '\
' ); var $options = $('option', $select); // add each \
' ); } ); // add buttons to search or close filter $div .append($options_div) .append( '
\  \ \
' ); $('#' + jq($form_name)).append($div); // set click handlers - $('#_mutlioptions_cb_' + $cur_index + '_all') - .click( - function ($e) { - MultiOptions.SelectAll($cur_index); - } - ) - .prop('checked', $options.length == $options.filter(':selected').length > 0); + var $select_all = $('#_mutlioptions_cb_' + $cur_index + '_all'), + $new_checked = $options.length === $options.filter(':selected').length; + + $select_all.click(function ($e) { + MultiOptions.SelectAll($cur_index); + }); + + if ( $select_all.prop('checked') !== $new_checked ) { + $select_all.prop('checked', $new_checked).change(); + } $('input._mutlioptions_cb_' + $cur_index).click( function ($e) { MultiOptions.ItemChecked($cur_index); } ); // add filter placeholder, used for filter opening filter var $filter = $('
' + phrases['la_OpenMultiFilter'] + '
'); if ($select.hasClass('filter-active')) { $filter.addClass('filter-active'); } $filter .click( function($e) { var $offset = $(this).offset(); var $box_left = $offset.left; $('#' + jq($id) + '_div').css( {left: 0, top: $offset.top} ).show(); var $box_width = $('#' + jq($id) + '_div').outerWidth(); if ($box_left + $box_width > document.body.offsetWidth) { // move left $box_left -= $box_width; } $('#' + jq($id) + '_div').css('left', $box_left); } ) .insertAfter($select); } MultiOptions.CloseSelector = function(selector_index) { $('#' + jq(MultiOptions.Selectors[selector_index]) + '_div').hide(); } MultiOptions.ItemChecked = function(selector_index) { // sync hidden field var $reg_exp = new RegExp('^_mutlioptions_cb_' + selector_index + '_(?!all)([0-9A-Za-z-]+)'); update_checkbox_options($reg_exp, MultiOptions.Selectors[selector_index]); // update "Select All" checkbox var $select_all = $('#_mutlioptions_cb_' + selector_index + '_all'); var $options = $("input[type='checkbox']", '#' + jq(MultiOptions.Selectors[selector_index]) + '_div').not($select_all); + var $new_checked = $options.length === $options.filter(':checked').length; - $select_all.prop('checked', $options.length == $options.filter(':checked').length > 0); + if ( $select_all.prop('checked') !== $new_checked ) { + $select_all.prop('checked', $new_checked).change(); + } } MultiOptions.SelectAll = function(selector_index) { // set all checkbox to match "Select All" checkbox var $select_all = $('#_mutlioptions_cb_' + selector_index + '_all'); var $checked = $select_all.prop('checked'); - $("input[type='checkbox']", '#' + jq(MultiOptions.Selectors[selector_index]) + '_div').not($select_all).prop('checked', $checked); + $("input[type='checkbox']", '#' + jq(MultiOptions.Selectors[selector_index]) + '_div').not($select_all).each(function () { + var $checkbox = $(this); + + if ( $checkbox.prop('checked') !== $checked ) { + $checkbox.prop('checked', $checked).change(); + } + }); // sync hidden field var $reg_exp = new RegExp('^_mutlioptions_cb_' + selector_index + '_(?!all)([0-9A-Za-z-]+)'); update_checkbox_options($reg_exp, MultiOptions.Selectors[selector_index]); } Index: branches/5.3.x/core/admin_templates/js/forms.js =================================================================== --- branches/5.3.x/core/admin_templates/js/forms.js (revision 16599) +++ branches/5.3.x/core/admin_templates/js/forms.js (revision 16600) @@ -1,451 +1,453 @@ var last_shown_error = false; var errors = {}; var first_error = {}; var fields = {}; function show_form_error(prefix, field, sticky) { if ( isset(errors[prefix]) && isset(errors[prefix][field]) ) { span = document.getElementById('error_msg_' + prefix); span.innerHTML = fields[prefix][field] + ' - ' + errors[prefix][field]; if ( sticky ) { last_shown_error = field; } } } function hide_form_error(prefix) { span = document.getElementById('error_msg_' + prefix); if ( !span ) { return; } span.innerHTML = '
'; if ( typeof(last_shown_error) != 'undefined' && last_shown_error ) { show_form_error(prefix, last_shown_error); } } function add_form_error(prefix, field, element, error_msg, block_name) { if ( error_msg == '' ) { // no error message - do nothing return; } if ( typeof(errors[prefix]) == 'undefined' ) { errors[prefix] = {}; } errors[prefix][field] = error_msg; var $input_fields = $('#' + jq(element)); switch (block_name) { case 'inp_edit_timezone': $input_fields = $input_fields.add('#timezone_group'); break; case 'cf:datetime': case 'inp_edit_date_time': $input_fields = $input_fields.add('#' + jq(element.replace(field, field + '_date'))); $input_fields = $input_fields.add('#' + jq(element.replace(field, field + '_time'))); break; case 'inp_edit_combo_target': $input_fields = $input_fields.add('#' + jq(element.replace(field, field + 'Type'))); break; case 'cf:multiselect': case 'inp_edit_multioptions': $input_fields = $('#' + jq(element) + '_select'); break; case 'cf:checkbox': case 'inp_edit_checkbox': $input_fields = $('#_cb_' + jq(element)); break; case 'cf:radio': case 'inp_edit_radio': case 'inp_edit_checkboxes': $input_fields = $("input[id^='" + jq(element) + "_']"); break; case 'inp_edit_weight': $input_fields = $input_fields.add('#' + jq(element.replace(field, field + '_a'))); $input_fields = $input_fields.add('#' + jq(element.replace(field, field + '_b'))); break; case 'inp_edit_picker': $input_fields = $('#' + jq(element) + '_selected'); break; case 'inp_edit_cron_box': $input_fields = $input_fields.add('#' + jq(element.replace(field, field + 'Hints'))); break; } if ( $input_fields.length > 0 ) { // some controls don't have element to focus on (e.g. swf uploader) $input_fields.focus(function ($e) { show_form_error(prefix, field, true); }); $input_fields.blur(function ($e) { last_shown_error = false; }); } /*else { console.log('error: focusing failed for [', prefix, '.', field, '] = ', element); }*/ if ( typeof(first_error[prefix]) == 'undefined' || first_error[prefix] == false ) { first_error[prefix] = [field, element]; } } function FCKeditor_OnComplete( editor ) { Form.Resize(); } function InitEditors() { if ( !$.isEmptyObject($CKEditors) ) { // process all CKEditor instances CKEDITOR.on( 'instanceReady', function( ev ) { FCKeditor_OnComplete( CKEDITOR.instances[ ev.editor.name ] ); } ); ckeditors_apply_typekit(); for (var $editor_id in $CKEditors) { CKEDITOR.replace($editor_id, $CKEditors[$editor_id]); } } // process all CodePress instances if ($.isFunction(window.CodePress)) { CodePress.run(/*FCKeditor_OnComplete*/); } if ( !$.isEmptyObject($CodeMirrorEditors) ) { $.each($CodeMirrorEditors, function ($editor_id, $editor_options) { var $editor, $textarea_element = $('#' + jq($editor_id)), $height = parseInt($textarea_element.height(), 10); if ( $textarea_element.is(':disabled') ) { $editor_options.readOnly = 'nocursor'; } $editor = CodeMirror.fromTextArea($textarea_element.get(0), $editor_options); $editor.setSize(null, $height); $textarea_element .on('change', function ($e) { $editor.getDoc().setValue($textarea_element.val()); }) .on('refresh', function ($e) { $editor.setOption('readOnly', $textarea_element.is(':disabled') ? 'nocursor' : ''); }) ; }); } } function Form() {} Form = new Form(); Form.Controls = new Array(); Form.Div = false; Form.MinControlsHeight = 0; Form.Options = new Object(); Form.FlexibleCount = 0; Form.ScrollerW = 17; Form.ScrollerH = 17; Form.HasChanged = false; Form.Init = function(id) { this.Div = document.getElementById(id); if (!this.Div) { return ; } for (var i = 0; i < this.Controls.length; i++) { dim = getDimensions( document.getElementById(this.Controls[i]) ); options = this.Options[this.Controls[i]]; if (options.height) { // fixed height options.min_height = options.height; options.max_height = options.height; } if (!options.min_height) { options.min_height = $( jq('#' + this.Controls[i]) ).outerHeight(); // dim.innerHeight } // if ( $( jq('#' + this.Controls[i]) ).parents('tr:first').is(':visible') ) { this.MinControlsHeight += options.min_height; // } if (dim.innerHeight < options.min_height) { document.getElementById(this.Controls[i]).style.height = options.min_height+'px'; } // alert('adding element '+this.Controls[i]+' height: '+options.min_height+' total: '+this.MinControlsHeight) } // all [][]" name="[][]" value=""> [][]" name="_cb_[][]" checked onchange="update_checkbox(this, document.getElementById('[][]'));" onclick="">   "> " alt="" border="0"/> img/icons/icon24_.png" border="0" alt="" title="" align="absmiddle"/>
" alt="" border="0"/> [, ]
 
- \ No newline at end of file + Index: branches/5.3.x/core/admin_templates/popups/translator.tpl =================================================================== --- branches/5.3.x/core/admin_templates/popups/translator.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/popups/translator.tpl (revision 16600) @@ -1,50 +1,50 @@
"> ">
- +
- \ No newline at end of file + Index: branches/5.3.x/core/admin_templates/forms/form_edit_emails.tpl =================================================================== --- branches/5.3.x/core/admin_templates/forms/form_edit_emails.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/forms/form_edit_emails.tpl (revision 16600) @@ -1,109 +1,109 @@
- +
Index: branches/5.3.x/core/admin_templates/forms/forms_edit.tpl =================================================================== --- branches/5.3.x/core/admin_templates/forms/forms_edit.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/forms/forms_edit.tpl (revision 16600) @@ -1,89 +1,89 @@
- +
- \ No newline at end of file + Index: branches/5.3.x/core/admin_templates/incs/style_template.css =================================================================== --- branches/5.3.x/core/admin_templates/incs/style_template.css (revision 16599) +++ branches/5.3.x/core/admin_templates/incs/style_template.css (revision 16600) @@ -1,823 +1,829 @@ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! THIS IS STYLESHEET TEMPLATES USED FOR SKINS IN ADMIN IT'S NOT BEING USED DIRECTLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ /* General elements */ html { height: 100%; } body { font-family: verdana,arial,helvetica,sans-serif; color: #000000; overflow-x: auto; overflow-y: auto; margin: 0px 0px 0px 0px; text-decoration: none; } body, td { /* fix for Firefox, when font-size was not inherited in table cells */ font-size: 9pt; } a { color: #006699; text-decoration: none; } a:hover { color: #009ff0; text-decoration: none; } form { display: inline; } img { border: 0px; } body.height-100 { height: 100%; } body.regular-body { margin: 0px 10px 5px 10px; color: #000000; background-color: @@SectionBgColor@@; } body.edit-popup { margin: 0px 0px 0px 0px; } table.collapsed { border-collapse: collapse; } .bordered, table.bordered, .bordered-no-bottom { border: 1px solid #000000 !important; border-top-width: 0px; border-collapse: collapse; } .bordered-no-bottom { border-top-width: 1px; border-bottom: none; } .login-table td { padding: 1px; } .disabled { background-color: #ebebeb; } /* Head frame */ table.head-table { background: url('@@base_url@@/core/admin_templates/img/top_frame/right_background.png') top right @@HeadBgColor@@ no-repeat; } .head-table tr td, .head-table tr td a { color: @@HeadColor@@ } div#extra_toolbar td.button-active { background: url('@@base_url@@/core/admin_templates/img/top_frame/toolbar_button_background.gif') bottom left repeat-x; height: 22px; } div#extra_toolbar td.button-active a { color: black; text-decoration: none; } td.kx-block-header, .head-table tr td.kx-block-header{ color: @@HeadBarColor@@; background: url('@@base_url@@/core/admin_templates/img/top_frame/toolbar_background.gif') repeat-x top left; /*background-color: @@HeadBarBgColor@@;*/ padding-left: 7px; padding-right: 7px; } a.kx-header-link { text-decoration: underline; font-weight: bold; color: #0080C8; } a.kx-header-link:hover { color: #FFCB05; text-decoration: none; } .kx-secondary-foreground { color: #FFFFFF; /*background-color: @@HeadBarBgColor@@;*/ } .kx-login-button { background-color: #2D79D6; color: #FFFFFF; } /* General form button (yellow) */ .button { font-size: 12px; font-weight: normal; color: #000000; background: url('@@base_url@@/core/admin_templates/img/button_back.gif') #f9eeae repeat-x; text-decoration: none; } /* Disabled (grayed-out) form button */ .button-disabled { font-size: 12px; font-weight: normal; color: #676767; background: url('@@base_url@@/core/admin_templates/img/button_back_disabled.gif') #f9eeae repeat-x; text-decoration: none; } /* Tabs bar */ .tab, .tab-active { background-color: #F0F1EB; padding: 3px 7px 2px 7px; border-top: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; margin-left: 3px !important; white-space: nowrap; } .tab-active { background-color: #4487D9; } .tab a { color: #4487D9; font-weight: bold; } .tab-active a { color: #FFFFFF; font-weight: bold; } a.scroll-left, a.scroll-right { cursor: pointer; display: block; float: left; height: 18px; margin: 0px 1px; width: 18px; } a.scroll-left { background: transparent url('@@base_url@@/core/admin_templates/img/tabs/left.png') no-repeat scroll 0 0; } a.scroll-right { background: transparent url('@@base_url@@/core/admin_templates/img/tabs/right.png') no-repeat scroll 0 0; } a.disabled { visibility: hidden !important; } a.scroll-left:hover, a.scroll-right:hover { background-position: 0 -18px; } td.scroll-right-container { width: 20px; } td.scroll-right-container.disabled, td.scroll-right-container.disabled * { width: 0px; margin: 0px; } td.scroll-right-container.disabled br { display: none; } /* Toolbar */ .toolbar { font-size: 8pt; border: 1px solid #000000; border-width: 0px 1px 1px 1px; background-color: @@ToolbarBgColor@@; border-collapse: collapse; } .toolbar td { height: 100%; } .toolbar-button, .toolbar-button-disabled, .toolbar-button-over { float: left; text-align: center; font-size: 8pt; padding: 5px 5px 5px 5px; vertical-align: middle; color: #006F99; } .toolbar-button-over { color: #000; } .toolbar-button-disabled { color: #444; } /* Scrollable Grids */ .layout-only-table td { border: none !important; } /* Main Grid class */ .grid-scrollable { padding: 0px; border: 1px solid black !important; border-top: none !important; } /* Div generated by js, which contains all the scrollable grid elements, affects the style of scrollable area without data (if there are too few rows) */ .grid-container { background-color: #fff; } .grid-container table { border-collapse: collapse; } /* Inner div generated in each data-cell */ .grid-cell-div { overflow: hidden; height: auto; } /* Main row definition */ .grid-data-row td, .grid-data-row-selected td, .grid-data-row-even-selected td, .grid-data-row-mouseover td, .table-color1, .table-color2, .grid-edit-table .edit-form-odd > td, .grid-edit-table .edit-form-even > td { font-weight: normal; color: @@OddColor@@; background-color: @@OddBgColor@@; padding: 3px 5px 3px 5px; overflow: hidden; border-right: 1px solid #c9c9c9; } .grid-data-row-even td, .table-color2, .grid-edit-table .edit-form-even > td { background-color: @@EvenBgColor@@; color: @@EvenColor@@; } .grid-data-row td a, .grid-data-row-selected td a, .grid-data-row-mouseover td a { text-decoration: underline; } /* mouse-over rows */ .grid-data-row-mouseover td, table tr.grid-data-row[_row_highlighted] td { background: #FFFDF4; } /* Selected row, applies to both checkbox and data areas */ .grid-data-row-selected td, table tr.grid-data-row[_row_selected] td { background: #FEF2D6; } .grid-data-row-even-selected td, .grid-data-row-even[_row_selected] td { background: #FFF7E0; } /* General header cell definition */ .grid-header-row td { font-weight: bold; background-color: @@ColumnTitlesBgColor@@; text-decoration: none; padding: 3px 5px 3px 5px; color: @@ColumnTitlesColor@@; border-right: none; text-align: left; vertical-align: middle !important; white-space: nowrap; border-right: 1px solid #777; } /* Filters row */ tr.grid-header-row-1 td { background-color: @@FiltersBgColor@@; border-bottom: 1px solid black; } /* Grid Filters */ table.range-filter { width: 100%; } .range-filter td { padding: 0px 0px 2px 2px !important; border: none !important; font-size: 8pt !important; font-weight: normal !important; text-align: left; color: #000000 !important; } input.filter, select.filter, input.filter-active, select.filter-active { margin-bottom: 0px; border: 1px solid #aaa; } input.filter-active { background-color: #FFFF00; } select.filter-active { background-color: #FFFF00; } div.filter, div.filter-active { background-color: white; border: 1px solid #AAAAAA; color: black; font-weight: normal; padding: 3px; } div.filter-active { background-color: #FFFF00; } div.multioptions_filter { position: absolute; z-index: 100; color: black; background-color: white; border: 1px solid black; padding: 3px 5px; display: none; vertical-align: middle; } /* Column titles row */ tr.grid-header-row-0 td { height: 25px; font-weight: bold; background-color: @@ColumnTitlesBgColor@@; color: @@ColumnTitlesColor@@; border-bottom: 1px solid black; } tr.grid-header-row-0 td a { color: @@ColumnTitlesColor@@; } tr.grid-header-row-0 td a:hover { color: #FFCC00; } .grid-footer-row td { background-color: #D7D7D7; font-weight: bold; border-right: 1px solid #C9C9C9; padding: 3px 5px 3px 5px; } td.grid-header-last-cell, td.grid-data-last-cell, td.grid-footer-last-cell { border-right: none !important; } td.grid-data-col-0, td.grid-data-col-0 div { text-align: center; vertical-align: middle !important; } tr.grid-header-row-1 td.grid-header-col-1 { text-align: center; vertical-align: middle !important; } tr.grid-header-row-1 td.grid-header-col-1 div { display: table-cell; vertical-align: middle; } .grid-status-bar { border: 1px solid black; border-top: none; padding: 0px; width: 100%; border-collapse: collapse; height: 30px; } .grid-status-bar td { background-color: @@TitleBarBgColor@@; color: @@TitleBarColor@@; font-size: 11pt; font-weight: normal; padding: 2px 8px 2px 8px; } /* /Scrollable Grids */ /* Forms */ table.edit-form { border: none; border-top-width: 0px !important; border-collapse: collapse; width: 100%; } .edit-form-odd, .edit-form-even { padding: 0px; } .subsectiontitle { font-size: 10pt; font-weight: bold; background-color: #4A92CE; color: #fff; height: 25px; border-top: 1px solid black; vertical-align: middle; } /* remove top-border from first sub-section element */ table.edit-form .subsectiontitle:first-child, table.bordered .subsectiontitle:first-child { border-top-width: 0; } .subsectiontitle td { vertical-align: middle; /*padding: 3px 5px 3px 5px;*/ padding: 1px 5px; } .label-cell { background: #DEE7F6 url('@@base_url@@/core/admin_templates/img/bgr_input_name_line.gif') no-repeat right bottom; font: 12px arial, sans-serif; padding: 4px 20px; width: 160px; } .control-mid { width: 13px; border-left: 1px solid #7A95C2; background: #fff url('@@base_url@@/core/admin_templates/img/bgr_mid.gif') repeat-x left bottom; } .control-cell { font: 11px arial, sans-serif; padding: 4px 10px 5px 5px; background: #fff url('@@base_url@@/core/admin_templates/img/bgr_input_line.gif') no-repeat left bottom; width: auto; vertical-align: middle; } .CodeMirror { font-size: 13px; border: 1px solid black; } .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} .CodeMirror-activeline-background {background: #e8f2ff !important;} .label-cell-filler { background: #DEE7F6 none; } .control-mid-filler { background: #fff none; border-left: 1px solid #7A95C2; } .control-cell-filler { background: #fff none; } .highlight-area, .code-highlight-area { border: 1px solid black; padding: 8px; font-family: monospace !important; font-size: 12px; overflow: auto; } .code-highlight-area { background-color: #F6F6F6; } .error { color: red; } .error-cell { color: red; } .field-required { color: red; } .warning-table { background-color: #F0F1EB; border: 1px solid #000000; border-collapse: collapse; border-top-width: 0px; } .form-notice, .form-warning { font-size: 11px; } .form-warning { color: red; } .form-notice { color: green; } .priority { color: red; padding-left: 1px; padding-right: 1px; font-size: 11px; } .small-statistics { font-size: 11px; color: #707070; } .req-note { font-style: italic; color: #333; } #scroll_container table.tableborder { border-collapse: separate } label.checkbox { white-space: nowrap; } /* Uploader */ .uploader-queue div.file { font-size: 11px; border: 1px solid #7F99C5; padding: 3px; background-color: #DEE7F6; margin-bottom: 2px; } .uploader-queue .left { float: left; vertical-align: top; } .uploader-queue .file-label { margin-left: 5px; } .uploader-queue .preview .delete-checkbox { margin-top: -3px; } .uploader-queue .progress-container { margin: 2px 5px 0px 5px; } .uploader-queue .progress-empty { width: 150px; height: 9px; border: 1px solid black; background: url('@@base_url@@/core/admin_templates/img/progress_left.gif') repeat-x; } .uploader-queue .progress-full { height: 9px; background: url('@@base_url@@/core/admin_templates/img/progress_done.gif'); } .uploader-queue .thumbnail { /*margin-bottom: 2px;*/ border: 1px solid black; background-color: grey; } /* To be sorted */ span#category_path, span#category_path a { color: #FFFFFF; } span#category_path a { text-decoration: underline; } /* Section title, right to the big icon */ .admintitle { font-size: 16pt; font-weight: bold; color: @@SectionColor@@; text-decoration: none; } /* Page header (bluebar) */ .page-title td { background-color: @@TitleBarBgColor@@; color: @@TitleBarColor@@; font-size: 11pt; font-weight: normal; padding: 2px 8px 2px 8px; } /* Right side of bluebar */ .tablenav, tablenav a { font-size: 11pt; font-weight: bold; color: @@TitleBarColor@@; text-decoration: none; background-color: @@TitleBarBgColor@@; background-image: none; } /* Section title in the bluebar * -- why 'link'? :S */ .tablenav_link { font-size: 11pt; font-weight: bold; color: @@TitleBarColor@@; text-decoration: none; } /* Active page in top and bottom bluebars pagination */ .current_page { font-size: 10pt; font-weight: bold; background-color: #fff; color: #2D79D6; padding: 3px 2px 3px 3px; } /* Other pages and arrows in pagination on blue */ .nav_url { font-size: 10pt; font-weight: bold; color: #fff; padding: 3px 2px 3px 3px; } /* Tree */ .tree-body { background-color: @@TreeBgColor@@; height: 100% } .tree_head.td, .tree_head, .tree_head:hover { font-weight: bold; font-size: 10px; color: #FFFFFF; font-family: Verdana, Arial; text-decoration: none; } .tree { padding: 0px; border: none; border-collapse: collapse; } .tree tr td { padding: 0px; margin: 0px; font-family: helvetica, arial, verdana,; font-size: 11px; white-space: nowrap; } .tree tr td a { font-size: 11px; color: @@TreeColor@@; font-family: Helvetica, Arial, Verdana; text-decoration: none; padding: 2px; } .tree tr td a:hover, .tree tr td a.debug-only-item:hover { color: @@TreeHoverColor@@; } .tree tr.highlighted td a, .tree tr.highlighted td a.debug-only-item { color: @@TreeHighColor@@; background-color: @@TreeHighBgColor@@; } .tree tr.highlighted td a:hover { color: @@TreeHighHoverColor@@; } .tree tr td a.debug-only-item { color: grey; } /* Ajax Dropdown */ .suggest-box { border: 1px solid #999; background-color: #fff; } .suggest-item, .suggest-item-over { padding: 1px 2px 0px 2px; font-family: arial,verdana; font-size: 12px; } .suggest-item-over { background-color: #3366CC; color: #fff; } /* Dashboard Summary Boxes */ .summary-box { border: 1px solid black; margin-bottom: 4px; } .summary-box .title { color: white; font-weight: bold; padding: 6px 5px; vertical-align: middle; background-color: #4A92CE; border-bottom: 1px solid black; } .summary-box .content { padding: 4px; background-color: #F6F6F6; } .summary-box .group { border-bottom: 1px solid black; margin-bottom: 10px; padding: 0 0 10px 10px; } .summary-box .group.last { border-width: 0px; margin-bottom: 0; padding-bottom: 5px; } .summary-box h4 { margin: 0; padding: 0 0 3px 0; font-size: 11px; font-weight: bold; } .summary-box .hint { font-size: 10px; color: grey; margin-bottom: 3px; } .summary-box .hint .cache-key { margin-bottom: 7px; margin-left: 3px; } .summary-box ul { margin-top: 5px; margin-bottom: 3px; padding-left: 30px; } .summary-box li { padding-bottom: 4px; } span.cke_skin_kama { border-width: 0px !important; -moz-border-radius: 0px !important; -webkit-border-radius: 0px !important; padding: 0px !important; } .cke_wrapper{ border-width: 0px !important; -moz-border-radius: 0px !important; -webkit-border-radius: 0px !important; } + +/* Inline CKEditor styles dropdown enlargement */ +div.cke_combopanel__styles { + width: 200px; + height: 300px; +} Index: branches/5.3.x/core/admin_templates/incs/footer.tpl =================================================================== --- branches/5.3.x/core/admin_templates/incs/footer.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/incs/footer.tpl (revision 16600) @@ -1,78 +1,61 @@ - - -

-
-
-
Index: branches/5.3.x/core/admin_templates/incs/form_blocks.tpl =================================================================== --- branches/5.3.x/core/admin_templates/incs/form_blocks.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/incs/form_blocks.tpl (revision 16600) @@ -1,1401 +1,1415 @@ + + + + + + +
+
- -
> +
-
id="">
    style=""> - +   
()
  ()   () " style="cursor: pointer; margin-right: 5px" title="Date selector" /> ()   () " style="cursor: pointer; margin-right: 5px" title="Date selector" /> () - + + + + +
- + - + - +
+ + + + ', '', 'popups/translator', 1);" title="">
');">
style="display: none;"> style="display: none;">
: "" name="" id="_" value="" tabindex="" onclick="" onchange="">  name="" id="_" value="" tabindex="" onclick="" onchange="">  '': '', '': '', {} {} class="" onchange="update_checkbox(this, document.getElementById(''));" onclick="">
 

 
checked id="_" value="" onclick="update_checkbox_options(/^_([0-9A-Za-z-]+)/, '');"> 








 
_move_left_button"/>
_move_right_button"/>

0%
100%

: n/a
: n/a
: n/a
.HideButton('prev'); .HideButton('next'); .DisableButton('next'); .DisableButton('prev'); .AddButton( new ToolBarButton( '', '::', '', function() { } ) );


:
* 
* 


   " onclick="delete_preset()">



:


Index: branches/5.3.x/core/admin_templates/regional/email_template_edit.tpl =================================================================== --- branches/5.3.x/core/admin_templates/regional/email_template_edit.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/regional/email_template_edit.tpl (revision 16600) @@ -1,76 +1,76 @@
- \ No newline at end of file + Index: branches/5.3.x/core/admin_templates/regional/languages_edit.tpl =================================================================== --- branches/5.3.x/core/admin_templates/regional/languages_edit.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/regional/languages_edit.tpl (revision 16600) @@ -1,119 +1,119 @@
- +
:   " name="" value=""> " type="checkbox" id="_cb_CopyLabels" name="_cb_CopyLabels" onclick="update_checkbox(this, document.getElementById(''))">
- \ No newline at end of file + Index: branches/5.3.x/core/admin_templates/config/config_search.tpl =================================================================== --- branches/5.3.x/core/admin_templates/config/config_search.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/config/config_search.tpl (revision 16600) @@ -1,142 +1,144 @@
" id="_cb_" onclick="update_checkbox(this, document.getElementById(''))" > " name="" value=""> " value="" size="3" /> ">
[ID: ; DisplayOrder: ; Field: ]
 
"> ][VariableValue]" VALUE="">% "> ][VariableValue]" value="">%     ][VariableValue]" value="">%     ][VariableValue]" value="">% "> ][VariableValue]" id="_cb_conf[][VariableValue]" onclick="update_checkbox(this, document.getElementById('conf[][VariableValue]'))" > ][VariableValue]" name="conf[][VariableValue]" value=""> - style="border-bottom-width: 0px;"> - -
- - - - -
-
+
+ style="border-bottom-width: 0px;"> + +
+ + + + +
+
+
Index: branches/5.3.x/core/admin_templates/config/config_universal.tpl =================================================================== --- branches/5.3.x/core/admin_templates/config/config_universal.tpl (revision 16599) +++ branches/5.3.x/core/admin_templates/config/config_universal.tpl (revision 16600) @@ -1,151 +1,153 @@
- - -
+
+ + +
+
Index: branches/5.3.x/core/install/install_data.sql =================================================================== --- branches/5.3.x/core/install/install_data.sql (revision 16599) +++ branches/5.3.x/core/install/install_data.sql (revision 16600) @@ -1,1044 +1,1044 @@ # Section "in-portal:configure_categories": INSERT INTO SystemSettings VALUES(DEFAULT, 'Category_Sortfield', 'Name', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_category_sortfield_prompt', 'select', '', 'Name=la_opt_Title||Description=la_opt_Description||CreatedOn=la_opt_CreatedOn||EditorsPick=la_opt_EditorsPick||SELECT Prompt AS OptionName, CONCAT("cust_", FieldName) AS OptionValue FROM CustomFields WHERE (Type = 1) AND (IsSystem = 0)', 10.01, 1, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Category_Sortorder', 'asc', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_category_sortfield_prompt', 'select', '', 'asc=la_common_Ascending||desc=la_common_Descending', 10.01, 2, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Category_Sortfield2', 'Description', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_category_sortfield2_prompt', 'select', '', 'Name=la_opt_Title||Description=la_opt_Description||CreatedOn=la_opt_CreatedOn||EditorsPick=la_opt_EditorsPick||SELECT Prompt AS OptionName, CONCAT("cust_", FieldName) AS OptionValue FROM CustomFields WHERE (Type = 1) AND (IsSystem = 0)', 10.02, 1, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Category_Sortorder2', 'asc', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_category_sortfield2_prompt', 'select', '', 'asc=la_common_Ascending||desc=la_common_Descending', 10.02, 2, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Perpage_Category', '20', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_category_perpage_prompt', 'text', '', '', 10.03, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Perpage_Category_Short', '3', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_category_perpage__short_prompt', 'text', '', '', 10.04, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Category_DaysNew', '8', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_category_daysnew_prompt', 'text', '', '', 10.05, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Category_ShowPick', '', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_category_showpick_prompt', 'checkbox', '', '', 10.06, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'MaxImportCategoryLevels', '10', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_prompt_max_import_category_levels', 'text', '', '', 10.07, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'AllowDeleteRootCats', '1', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_AllowDeleteRootCats', 'checkbox', NULL, NULL, 10.08, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Catalog_PreselectModuleTab', '1', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_CatalogPreselectModuleTab', 'checkbox', NULL, NULL, 10.09, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'RecycleBinFolder', '', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_RecycleBinFolder', 'text', NULL, NULL, 10.10, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'CheckViewPermissionsInCatalog', '0', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_CheckViewPermissionsInCatalog', 'radio', NULL, '1=la_Yes||0=la_No', 10.11, 0, 1, 'hint:la_config_CheckViewPermissionsInCatalog'); INSERT INTO SystemSettings VALUES(DEFAULT, 'CategoryPermissionRebuildMode', '3', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_CategoryPermissionRebuildMode', 'select', NULL, '1=la_opt_Manual||2=la_opt_Silent||3=la_opt_Automatic', 10.12, 0, 0, 'hint:la_config_CategoryPermissionRebuildMode'); INSERT INTO SystemSettings VALUES(DEFAULT, 'FilenameSpecialCharReplacement', '-', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_FilenameSpecialCharReplacement', 'select', NULL, '_=+_||-=+-', 10.13, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Search_MinKeyword_Length', '3', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_Search_MinKeyword_Length', 'text', NULL, NULL, 10.14, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'ExcludeTemplateSectionsFromSearch', '0', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_ExcludeTemplateSectionsFromSearch', 'checkbox', '', '', 10.15, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UpdateCountersOnFilterChange', '1', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_UpdateCountersOnFilterChange', 'checkbox', '', '', 10.16, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Category_MetaKey', '', 'In-Portal', 'in-portal:configure_categories', 'la_Text_MetaInfo', 'la_category_metakey', 'textarea', '', '', 20.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Category_MetaDesc', '', 'In-Portal', 'in-portal:configure_categories', 'la_Text_MetaInfo', 'la_category_metadesc', 'textarea', '', '', 20.02, 0, 1, NULL); # Section "in-portal:configure_general": INSERT INTO SystemSettings VALUES(DEFAULT, 'Site_Name', 'In-Portal CMS', 'In-Portal', 'in-portal:configure_general', 'la_section_SettingsWebsite', 'la_config_website_name', 'text', '', '', 10.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'FirstDayOfWeek', '1', 'In-Portal', 'in-portal:configure_general', 'la_Text_Date_Time_Settings', 'la_config_first_day_of_week', 'select', '', '0=la_sunday||1=la_monday', 20.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Config_Site_Time', '', 'In-Portal', 'in-portal:configure_general', 'la_Text_Date_Time_Settings', 'la_config_site_zone', 'select', '', NULL, 20.02, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'DefaultEmailSender', 'portal@user.domain.name', 'In-Portal', 'in-portal:configure_general', 'la_section_SettingsMailling', 'la_prompt_AdminMailFrom', 'text', NULL, 'size="40"', 30.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SessionTimeout', '3600', 'In-Portal', 'in-portal:configure_general', 'la_section_SettingsSession', 'la_prompt_session_timeout', 'text', 'a:3:{s:4:"type";s:3:"int";s:13:"min_value_inc";i:1;s:8:"required";i:1;}', '', 40.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'AdminConsoleInterface', 'simple', 'In-Portal', 'in-portal:configure_general', 'la_section_SettingsAdmin', 'la_config_AdminConsoleInterface', 'select', '', 'simple=+simple||advanced=+advanced||custom=+custom', 50.01, 1, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'AllowAdminConsoleInterfaceChange', '1', 'In-Portal', 'in-portal:configure_general', 'la_section_SettingsAdmin', 'la_config_AdminConsoleInterface', 'checkbox', NULL, NULL, 50.01, 2, 0, NULL); # Section "in-portal:configure_advanced": INSERT INTO SystemSettings VALUES(DEFAULT, 'PageHitCounter', '0', 'In-Portal', 'in-portal:configure_advanced', '', '', '', NULL, NULL, 0, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseModRewrite', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_use_modrewrite', 'checkbox', '', '', 10.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'ModRewriteUrlEnding', '.html', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_ModRewriteUrlEnding', 'select', '', '=+||/=+/||.html=+.html', 10.011, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'ForceCanonicalUrls', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_ForceCanonicalUrls', 'checkbox', '', '', 10.0125, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'ForceModRewriteUrlEnding', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_ForceModRewriteUrlEnding', 'checkbox', '', NULL, 10.012, 0, 0, 'hint:la_config_ForceModRewriteUrlEnding'); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseContentLanguageNegotiation', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_UseContentLanguageNegotiation', 'checkbox', '', '', 10.013, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'cms_DefaultDesign', '#default_design#', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_DefaultDesignTemplate', 'text', NULL, NULL, 10.02, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'ErrorTemplate', 'error_notfound', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_error_template', 'text', '', '', 10.03, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'NoPermissionTemplate', 'no_permission', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_nopermission_template', 'text', '', '', 10.04, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UsePageHitCounter', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_UsePageHitCounter', 'checkbox', '', '', 10.05, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'ForceImageMagickResize', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_ForceImageMagickResize', 'checkbox', '', '', 10.06, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'CheckStopWords', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_CheckStopWords', 'checkbox', '', '', 10.07, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseVisitorTracking', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_UseVisitorTracking', 'checkbox', '', '', 10.08, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'cms_DefaultTrackingCode', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_DefaultTrackingCode', 'textarea', NULL, 'COLS=40 ROWS=5', 10.09, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'PerformExactSearch', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_PerformExactSearch', 'checkbox', '', '', '10.10', 0, 0, 'hint:la_config_PerformExactSearch'); INSERT INTO SystemSettings VALUES(DEFAULT, 'MaintenanceMessageFront', 'Website is currently undergoing the upgrades. Please come back shortly!', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMaintenance', 'la_config_MaintenanceMessageFront', 'textarea', '', 'style="width: 100%; height: 100px;"', '15.01', 0, 0, 'hint:la_config_MaintenanceMessageFront'); INSERT INTO SystemSettings VALUES(DEFAULT, 'MaintenanceMessageAdmin', 'Website is currently undergoing the upgrades. Please come back shortly!', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMaintenance', 'la_config_MaintenanceMessageAdmin', 'textarea', '', 'style="width: 100%; height: 100px;"', '15.02', 0, 0, 'hint:la_config_MaintenanceMessageAdmin'); INSERT INTO SystemSettings VALUES(DEFAULT, 'SoftMaintenanceTemplate', 'maintenance', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMaintenance', 'la_config_SoftMaintenanceTemplate', 'text', '', 'style="width: 200px;"', '15.03', 0, 0, 'hint:la_config_SoftMaintenanceTemplate'); INSERT INTO SystemSettings VALUES(DEFAULT, 'HardMaintenanceTemplate', 'maintenance', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMaintenance', 'la_config_HardMaintenanceTemplate', 'text', '', 'style="width: 200px;"', '15.04', 0, 0, 'hint:la_config_HardMaintenanceTemplate'); INSERT INTO SystemSettings VALUES(DEFAULT, 'CookieSessions', '2', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSession', 'la_prompt_session_management', 'select', NULL, '0=la_opt_QueryString||1=la_opt_Cookies||2=la_opt_AutoDetect', 20.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SessionCookieName', 'sid', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSession', 'la_prompt_session_cookie_name', 'text', '', '', 20.02, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SessionCookieDomains', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSession', 'la_config_SessionCookieDomains', 'textarea', '', 'rows="5" cols="40"', 20.021, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'KeepSessionOnBrowserClose', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSession', 'la_config_KeepSessionOnBrowserClose', 'checkbox', '', '', 20.03, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SessionBrowserSignatureCheck', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSession', 'la_config_SessionBrowserSignatureCheck', 'checkbox', NULL, NULL, 20.04, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SessionIPAddressCheck', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSession', 'la_config_SessionIPAddressCheck', 'checkbox', NULL, NULL, 20.05, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseJSRedirect', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSession', 'la_config_use_js_redirect', 'checkbox', '', '', 20.06, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SSLDomain', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSSL', 'la_config_SSLDomain', 'text', '', '', 30.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'AdminSSLDomain', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSSL', 'la_config_AdminSSLDomain', 'text', '', '', 30.02, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Require_SSL', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSSL', 'la_config_require_ssl', 'checkbox', '', '', 30.03, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Require_AdminSSL', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSSL', 'la_config_RequireSSLAdmin', 'checkbox', '', '', 30.04, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Force_HTTP_When_SSL_Not_Required', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSSL', 'la_config_force_http', 'checkbox', '', '', 30.05, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseModRewriteWithSSL', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSSL', 'la_config_use_modrewrite_with_ssl', 'checkbox', '', '', 30.06, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'RootPass', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_prompt_root_pass', 'password', NULL, NULL, 40.01, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseToolbarLabels', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_UseToolbarLabels', 'checkbox', NULL, NULL, 40.02, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseSmallHeader', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_UseSmallHeader', 'checkbox', '', '', 40.03, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseColumnFreezer', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_UseColumnFreezer', 'checkbox', '', '', 40.04, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UsePopups', '2', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_UsePopups', 'select', '', '0=la_opt_SameWindow||1=la_opt_PopupWindow||2=la_opt_ModalWindow', 40.05, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'StickyGridSelection', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_StickyGridSelection', 'radio', '', '1=la_Yes||0=la_No', 40.06, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseDoubleSorting', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_UseDoubleSorting', 'radio', '', '1=la_Yes||0=la_No', 40.07, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'MenuFrameWidth', '200', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_prompt_MenuFrameWidth', 'text', NULL, NULL, 40.08, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'ResizableFrames', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_ResizableFrames', 'checkbox', '', '', 40.09, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'AutoRefreshIntervals', '1,5,15,30,60,120,240', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_AutoRefreshIntervals', 'text', '', '', 40.10, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'DefaultGridPerPage', '20', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_DefaultGridPerPage', 'select', '', '10=+10||20=+20||50=+50||100=+100||500=+500', 40.11, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'DebugOnlyFormConfigurator', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_DebugOnlyFormConfigurator', 'checkbox', '', '', 40.12, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'DebugOnlyPromoBlockGroupConfigurator', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_DebugOnlyPromoBlockGroupConfigurator', 'checkbox', '', '', 40.13, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'RememberLastAdminTemplate', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_RememberLastAdminTemplate', 'checkbox', '', '', 40.14, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseHTTPAuth', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_UseHTTPAuth', 'checkbox', '', '', 40.15, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'HTTPAuthUsername', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_HTTPAuthUsername', 'text', '', '', 40.16, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'HTTPAuthPassword', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_HTTPAuthPassword', 'password', NULL, NULL, 40.17, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'HTTPAuthBypassIPs', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_HTTPAuthBypassIPs', 'text', '', '', 40.18, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'EnablePageContentRevisionControl', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_EnablePageContentRevisionControl', 'checkbox', '', '', 40.19, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Smtp_Server', NULL, 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_prompt_mailserver', 'text', NULL, NULL, 50.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Smtp_Port', NULL, 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_prompt_mailport', 'text', NULL, NULL, 50.02, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Smtp_Authenticate', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_prompt_mailauthenticate', 'checkbox', NULL, NULL, 50.03, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Smtp_User', NULL, 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_prompt_smtp_user', 'text', NULL, NULL, 50.04, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Smtp_Pass', NULL, 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_prompt_smtp_pass', 'text', NULL, NULL, 50.05, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Smtp_DefaultHeaders', 'X-Mailer: In-Portal', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_prompt_smtpheaders', 'textarea', NULL, 'COLS=40 ROWS=5', 50.06, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'MailFunctionHeaderSeparator', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_config_MailFunctionHeaderSeparator', 'radio', NULL, '1=la_Linux||2=la_Windows', 50.07, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'MailingListQueuePerStep', '10', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_config_MailingListQueuePerStep', 'text', NULL, NULL, 50.08, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'MailingListSendPerStep', '10', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_config_MailingListSendPerStep', 'text', NULL, NULL, 50.09, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'DefaultEmailRecipients', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_config_DefaultEmailRecipients', 'text', NULL, NULL, 50.10, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'EmailDelivery', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_config_EmailDelivery', 'radio', NULL, '1=la_opt_EmailDeliveryQueue||2=la_opt_EmailDeliveryImmediate', 50.11, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseOutputCompression', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_UseOutputCompression', 'checkbox', '', '', 60.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'OutputCompressionLevel', '7', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_OutputCompressionLevel', 'text', '', '', 60.02, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'TrimRequiredFields', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_TrimRequiredFields', 'checkbox', '', '', 60.03, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'RunScheduledTasksFromCron', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_UseCronForRegularEvent', 'checkbox', NULL, NULL, 60.04, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UseChangeLog', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_UseChangeLog', 'checkbox', '', '', 60.05, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Backup_Path', '/home/alex/web/in-portal.rc/system/backupdata', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_backup_path', 'text', '', '', 60.06, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SystemTagCache', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_prompt_syscache_enable', 'checkbox', NULL, NULL, 60.07, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SocketBlockingMode', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_prompt_socket_blocking_mode', 'checkbox', NULL, NULL, 60.08, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'RandomString', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_RandomString', 'text', '', '', 60.09, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'PlainTextCookies', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_PlainTextCookies', 'text', '', '', 60.10, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'EnableEmailLog', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_EnableEmailLog', 'radio', NULL, '1=la_Yes||0=la_No', 65.01, 0, 1, 'hint:la_config_EnableEmailLog'); INSERT INTO SystemSettings VALUES(DEFAULT, 'EmailLogRotationInterval', '2419200', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_EmailLogRotationInterval', 'select', NULL, '86400=la_opt_OneDay||604800=la_opt_OneWeek||1209600=la_opt_TwoWeeks||2419200=la_opt_OneMonth||7257600=la_opt_ThreeMonths||29030400=la_opt_OneYear||-1=la_opt_EmailLogKeepForever', 65.02, 0, 0, 'hint:la_config_EmailLogRotationInterval'); INSERT INTO SystemSettings VALUES(DEFAULT, 'SystemLogRotationInterval', '2419200', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_SystemLogRotationInterval', 'select', NULL, '86400=la_opt_OneDay||604800=la_opt_OneWeek||1209600=la_opt_TwoWeeks||2419200=la_opt_OneMonth||7257600=la_opt_ThreeMonths||29030400=la_opt_OneYear||-1=la_opt_SystemLogKeepForever', 65.03, 0, 1, 'hint:la_config_SystemLogRotationInterval'); INSERT INTO SystemSettings VALUES(DEFAULT, 'SystemLogNotificationEmail', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_SystemLogNotificationEmail', 'text', 'a:5:{s:4:"type";s:6:"string";s:9:"formatter";s:10:"kFormatter";s:6:"regexp";s:85:"/^([-a-zA-Z0-9!\\#$%&*+\\/=?^_`{|}~.]+@[a-zA-Z0-9]{1}[-.a-zA-Z0-9_]*\\.[a-zA-Z]{2,6})$/i";s:10:"error_msgs";a:1:{s:14:"invalid_format";s:18:"!la_invalid_email!";}s:7:"default";s:0:"";}', NULL, 65.04, 0, 1, 'hint:la_config_SystemLogNotificationEmail'); INSERT INTO SystemSettings VALUES(DEFAULT, 'SessionLogRotationInterval', '2629800', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_SessionLogRotationInterval', 'select', '', '86400=la_opt_OneDay||604800=la_opt_OneWeek||1209600=la_opt_TwoWeeks||2629800=la_opt_OneMonth||7889400=la_opt_ThreeMonths||31557600=la_opt_OneYear||63115200=la_opt_TwoYears||94672800=la_opt_ThreeYears||157788000=la_opt_FiveYears||-1=la_opt_EmailLogKeepForever', 65.05, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'CSVExportDelimiter', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsCSVExport', 'la_config_CSVExportDelimiter', 'select', NULL, '0=la_opt_Tab||1=la_opt_Comma||2=la_opt_Semicolon||3=la_opt_Space||4=la_opt_Colon', 70.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'CSVExportEnclosure', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsCSVExport', 'la_config_CSVExportEnclosure', 'radio', NULL, '0=la_Doublequotes||1=la_Quotes', 70.02, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'CSVExportSeparator', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsCSVExport', 'la_config_CSVExportSeparator', 'radio', NULL, '0=la_Linux||1=la_Windows', 70.03, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'CSVExportEncoding', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsCSVExport', 'la_config_CSVExportEncoding', 'radio', NULL, '0=la_Unicode||1=la_Regular', 70.04, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'YahooApplicationId', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_Settings3rdPartyAPI', 'la_config_YahooApplicationId', 'text', NULL, NULL, 80.01, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'l_GoogleMapsAPIKey', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_Settings3rdPartyAPI', 'la_fld_LinkGoogleMapsAPIKey', 'text', NULL, NULL, 80.02, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'CKFinderLicenseName', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_Settings3rdPartyAPI', 'la_config_CKFinderLicenseName', 'text', NULL, NULL, 80.03, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'CKFinderLicenseKey', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_Settings3rdPartyAPI', 'la_config_CKFinderLicenseKey', 'text', NULL, NULL, 80.04, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'TypeKitId', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_Settings3rdPartyAPI', 'la_config_TypeKitId', 'text', NULL, NULL, 80.05, 0, 1, NULL); # Section "in-portal:configure_users": INSERT INTO SystemSettings VALUES(DEFAULT, 'User_Allow_New', '3', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_users_allow_new', 'radio', '', '1=la_opt_UserInstantRegistration||2=la_opt_UserNotAllowedRegistration||3=la_opt_UserUponApprovalRegistration||4=la_opt_UserEmailActivation', 10.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'AdvancedUserManagement', '0', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_prompt_AdvancedUserManagement', 'checkbox', NULL, NULL, 10.011, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'RegistrationUsernameRequired', '0', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_config_RegistrationUsernameRequired', 'checkbox', NULL, NULL, 10.02, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'RegistrationCaptcha', '0', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_registration_captcha', 'checkbox', NULL, NULL, 10.025, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Min_UserName', '3', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_text_min_username', 'text', '', 'style="width: 50px;"', 10.03, 1, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'MaxUserName', '', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_text_min_username', 'text', '', 'style="width: 50px;"', 10.03, 2, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Min_Password', '5', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_text_min_password', 'text', '', '', 10.04, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'Users_AllowReset', '180', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_prompt_allow_reset', 'text', NULL, NULL, 10.05, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'UserEmailActivationTimeout', '', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_config_UserEmailActivationTimeout', 'text', NULL, NULL, 10.051, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'User_Password_Auto', '0', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_users_password_auto', 'checkbox', '', '', 10.06, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'User_MembershipExpirationReminder', '10', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_MembershipExpirationReminder', 'text', NULL, '', 10.07, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'User_NewGroup', '13', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_users_new_group', 'select', NULL, '0=lu_none||SELECT GroupId as OptionValue, Name as OptionName FROM UserGroups WHERE Enabled=1 AND Personal=0', 10.08, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'User_LoggedInGroup', '15', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_users_assign_all_to', 'select', NULL, '0=lu_none||SELECT GroupId as OptionValue, Name as OptionName FROM UserGroups WHERE Enabled=1 AND Personal=0', 10.09, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'User_GuestGroup', '14', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_users_guest_group', 'select', NULL, '0=lu_none||SELECT GroupId as OptionValue, Name as OptionName FROM UserGroups WHERE Enabled=1 AND Personal=0', 10.1, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'User_SubscriberGroup', '12', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_users_subscriber_group', 'select', NULL, '0=lu_none||SELECT GroupId as OptionValue, Name as OptionName FROM UserGroups WHERE Enabled=1 AND Personal=0', 10.11, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'User_AdminGroup', '11', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_users_admin_group', 'select', NULL, '0=lu_none||SELECT GroupId as OptionValue, Name as OptionName FROM UserGroups WHERE Enabled=1 AND Personal=0', 10.12, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'User_Default_Registration_Country', '', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_config_DefaultRegistrationCountry', 'select', NULL, '=+||SELECT l%3$s_Name AS OptionName, CountryStateId AS OptionValue FROM CountryStates WHERE Type = 1 ORDER BY OptionName', 10.13, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'AllowSelectGroupOnFront', '0', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_config_AllowSelectGroupOnFront', 'checkbox', NULL, NULL, 10.14, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'DefaultSettingsUserId', '-1', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_prompt_DefaultUserId', 'text', NULL, NULL, 10.15, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'u_MaxImageCount', '5', 'In-Portal:Users', 'in-portal:configure_users', 'la_section_ImageSettings', 'la_config_MaxImageCount', 'text', '', '', 30.01, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'u_ThumbnailImageWidth', '120', 'In-Portal:Users', 'in-portal:configure_users', 'la_section_ImageSettings', 'la_config_ThumbnailImageWidth', 'text', '', '', 30.02, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'u_ThumbnailImageHeight', '120', 'In-Portal:Users', 'in-portal:configure_users', 'la_section_ImageSettings', 'la_config_ThumbnailImageHeight', 'text', '', '', 30.03, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'u_FullImageWidth', '450', 'In-Portal:Users', 'in-portal:configure_users', 'la_section_ImageSettings', 'la_config_FullImageWidth', 'text', '', '', 30.04, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'u_FullImageHeight', '450', 'In-Portal:Users', 'in-portal:configure_users', 'la_section_ImageSettings', 'la_config_FullImageHeight', 'text', '', '', 30.05, 0, 0, NULL); # Section "in-portal:configuration_search": INSERT INTO SystemSettings VALUES(DEFAULT, 'SearchRel_Increase_category', '30', 'In-Portal', 'in-portal:configuration_search', 'la_config_DefaultIncreaseImportance', 'la_text_increase_importance', 'text', NULL, NULL, 0, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SearchRel_Keyword_category', '90', 'In-Portal', 'in-portal:configuration_search', 'la_config_SearchRel_DefaultKeyword', 'la_text_keyword', 'text', NULL, NULL, 0, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SearchRel_Pop_category', '5', 'In-Portal', 'in-portal:configuration_search', 'la_config_DefaultPop', 'la_text_popularity', 'text', NULL, NULL, 0, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SearchRel_Rating_category', '5', 'In-Portal', 'in-portal:configuration_search', 'la_config_DefaultRating', 'la_prompt_Rating', 'text', NULL, NULL, 0, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'CategoriesRebuildSerial', '0', 'In-Portal', '', '', '', '', NULL, NULL, 0, 0, 0, NULL); INSERT INTO ItemTypes VALUES (1, 'In-Portal', 'c', 'Categories', 'Name', 'CreatedById', NULL, NULL, 'la_ItemTab_Categories', 1, 'admin/category/addcategory.php', 'clsCategory', 'Category'); INSERT INTO ItemTypes VALUES (6, 'In-Portal', 'u', 'Users', 'Username', 'PortalUserId', NULL, NULL, '', 0, '', 'clsPortalUser', 'User'); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.ADD', NULL, 1, 0, 'Core', 'Add User', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.ADD', NULL, 1, 1, 'Core', 'Add User', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.APPROVE', NULL, 1, 0, 'Core', 'Approve User', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.APPROVE', NULL, 1, 1, 'Core', 'Approve User', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.VALIDATE', NULL, 1, 0, 'Core', 'Validate User', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.VALIDATE', NULL, 1, 1, 'Core', 'Validate User', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.DENY', NULL, 1, 0, 'Core', 'Deny User', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.DENY', NULL, 1, 1, 'Core', 'Deny User', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.ADD.PENDING', NULL, 1, 0, 'Core', 'Add Pending User', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.ADD.PENDING', NULL, 1, 1, 'Core', 'Add Pending User', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'CATEGORY.ADD', NULL, 1, 0, 'Core', 'Add Category', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'CATEGORY.ADD.PENDING', NULL, 1, 0, 'Core', 'Add Pending Category', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'CATEGORY.ADD.PENDING', NULL, 1, 1, 'Core', 'Add Pending Category', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'CATEGORY.ADD', NULL, 1, 1, 'Core', 'Add Category', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'CATEGORY.APPROVE', NULL, 1, 0, 'Core', 'Approve Category', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'CATEGORY.DENY', NULL, 1, 0, 'Core', 'Deny Category', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.SUBSCRIBE', NULL, 1, 0, 'Core', 'User subscribed', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.SUBSCRIBE', NULL, 1, 1, 'Core', 'User subscribed', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.UNSUBSCRIBE', NULL, 1, 0, 'Core', 'User unsubscribed', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.UNSUBSCRIBE', NULL, 1, 1, 'Core', 'User unsubscribed', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.SUGGEST', NULL, 1, 0, 'Core', 'Suggest to a friend', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.SUGGEST', NULL, 1, 1, 'Core', 'Suggest to a friend', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.PSWDC', NULL, 1, 0, 'Core', 'Password Confirmation', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.MEMBERSHIP.EXPIRED', NULL, 1, 0, 'Core', 'Membership expired', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.MEMBERSHIP.EXPIRED', NULL, 1, 0, 'Core', 'Membership expired', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.MEMBERSHIP.EXPIRATION.NOTICE', NULL, 1, 0, 'Core', 'Membership expiration notice', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.MEMBERSHIP.EXPIRATION.NOTICE', NULL, 1, 0, 'Core', 'Membership expiration notice', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'COMMON.FOOTER', NULL, 1, 0, 'Core', 'Common Footer Template', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'FORM.SUBMITTED', NULL, 1, 0, 'Core', 'This e-mail is sent to a user after filling in the Contact Us form', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'FORM.SUBMITTED', NULL, 1, 0, 'Core', 'This e-mail is sent to a user after filling in the Contact Us form', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.TO.USER', NULL, 1, 0, 'Core', 'Admin Reply to User Form Submission', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER', NULL, 1, 0, 'Core', 'User Replied to It\'s Form Submission', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED', NULL, 1, 0, 'Core', 'Form Submission Admin Reply Delivery Failure', 1, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.NEW.PASSWORD', NULL, 1, 0, 'Core', 'Sends new password to an existing user', 0, 1, 0); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.ADD.BYADMIN', NULL, 1, 0, 'Core', 'Sends password to a new user', 0, 1, 0); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ROOT.RESET.PASSWORD', NULL, 1, 0, 'Core', 'Root Reset Password', 1, 1, 0); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.EMAIL.CHANGE.VERIFY', NULL, 1, 0, 'Core', 'Changed E-mail Verification', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.EMAIL.CHANGE.UNDO', NULL, 1, 0, 'Core', 'Changed E-mail Rollback', 0, 1, 1); INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'SYSTEM.LOG.NOTIFY', NULL, 1, 0, 'Core', 'Notification about message added to System Log', 1, 1, 1); INSERT INTO IdGenerator VALUES ('100'); INSERT INTO UserGroups VALUES(15, 'Everyone', 'Everyone', 0, 1, 0, 1, 0, NULL); INSERT INTO UserGroups VALUES(13, 'Member', '', 1054738682, 0, 0, 1, 1, NULL); INSERT INTO UserGroups VALUES(12, 'Subscribers', '', 1054738670, 0, 0, 1, 0, NULL); INSERT INTO UserGroups VALUES(14, 'Guest', 'Guest User', 0, 1, 0, 1, 0, NULL); INSERT INTO UserGroups VALUES(11, 'admin', NULL, 1054738405, 0, 0, 1, 0, NULL); INSERT INTO CountryStates (CountryStateId, Type, StateCountryId, IsoCode, ShortIsoCode) VALUES (1, 1, NULL, 'AFG', 'AF'), (2, 1, NULL, 'ALB', 'AL'), (3, 1, NULL, 'DZA', 'DZ'), (4, 1, NULL, 'ASM', 'AS'), (5, 1, NULL, 'AND', 'AD'), (6, 1, NULL, 'AGO', 'AO'), (7, 1, NULL, 'AIA', 'AI'), (8, 1, NULL, 'ATA', 'AQ'), (9, 1, NULL, 'ATG', 'AG'), (10, 1, NULL, 'ARG', 'AR'), (11, 1, NULL, 'ARM', 'AM'), (12, 1, NULL, 'ABW', 'AW'), (13, 1, NULL, 'AUS', 'AU'), (14, 1, NULL, 'AUT', 'AT'), (15, 1, NULL, 'AZE', 'AZ'), (16, 1, NULL, 'BHS', 'BS'), (17, 1, NULL, 'BHR', 'BH'), (18, 1, NULL, 'BGD', 'BD'), (19, 1, NULL, 'BRB', 'BB'), (20, 1, NULL, 'BLR', 'BY'), (21, 1, NULL, 'BEL', 'BE'), (22, 1, NULL, 'BLZ', 'BZ'), (23, 1, NULL, 'BEN', 'BJ'), (24, 1, NULL, 'BMU', 'BM'), (25, 1, NULL, 'BTN', 'BT'), (26, 1, NULL, 'BOL', 'BO'), (27, 1, NULL, 'BIH', 'BA'), (28, 1, NULL, 'BWA', 'BW'), (29, 1, NULL, 'BVT', 'BV'), (30, 1, NULL, 'BRA', 'BR'), (31, 1, NULL, 'IOT', 'IO'), (32, 1, NULL, 'BRN', 'BN'), (33, 1, NULL, 'BGR', 'BG'), (34, 1, NULL, 'BFA', 'BF'), (35, 1, NULL, 'BDI', 'BI'), (36, 1, NULL, 'KHM', 'KH'), (37, 1, NULL, 'CMR', 'CM'), (38, 1, NULL, 'CAN', 'CA'), (39, 1, NULL, 'CPV', 'CV'), (40, 1, NULL, 'CYM', 'KY'), (41, 1, NULL, 'CAF', 'CF'), (42, 1, NULL, 'TCD', 'TD'), (43, 1, NULL, 'CHL', 'CL'), (44, 1, NULL, 'CHN', 'CN'), (45, 1, NULL, 'CXR', 'CX'), (46, 1, NULL, 'CCK', 'CC'), (47, 1, NULL, 'COL', 'CO'), (48, 1, NULL, 'COM', 'KM'), (49, 1, NULL, 'COD', 'CD'), (50, 1, NULL, 'COG', 'CG'), (51, 1, NULL, 'COK', 'CK'), (52, 1, NULL, 'CRI', 'CR'), (53, 1, NULL, 'CIV', 'CI'), (54, 1, NULL, 'HRV', 'HR'), (55, 1, NULL, 'CUB', 'CU'), (56, 1, NULL, 'CYP', 'CY'), (57, 1, NULL, 'CZE', 'CZ'), (58, 1, NULL, 'DNK', 'DK'), (59, 1, NULL, 'DJI', 'DJ'), (60, 1, NULL, 'DMA', 'DM'), (61, 1, NULL, 'DOM', 'DO'), (62, 1, NULL, 'TLS', 'TL'), (63, 1, NULL, 'ECU', 'EC'), (64, 1, NULL, 'EGY', 'EG'), (65, 1, NULL, 'SLV', 'SV'), (66, 1, NULL, 'GNQ', 'GQ'), (67, 1, NULL, 'ERI', 'ER'), (68, 1, NULL, 'EST', 'EE'), (69, 1, NULL, 'ETH', 'ET'), (70, 1, NULL, 'FLK', 'FK'), (71, 1, NULL, 'FRO', 'FO'), (72, 1, NULL, 'FJI', 'FJ'), (73, 1, NULL, 'FIN', 'FI'), (74, 1, NULL, 'FRA', 'FR'), (75, 1, NULL, 'FXX', 'FX'), (76, 1, NULL, 'GUF', 'GF'), (77, 1, NULL, 'PYF', 'PF'), (78, 1, NULL, 'ATF', 'TF'), (79, 1, NULL, 'GAB', 'GA'), (80, 1, NULL, 'GMB', 'GM'), (81, 1, NULL, 'GEO', 'GE'), (82, 1, NULL, 'DEU', 'DE'), (83, 1, NULL, 'GHA', 'GH'), (84, 1, NULL, 'GIB', 'GI'), (85, 1, NULL, 'GRC', 'GR'), (86, 1, NULL, 'GRL', 'GL'), (87, 1, NULL, 'GRD', 'GD'), (88, 1, NULL, 'GLP', 'GP'), (89, 1, NULL, 'GUM', 'GU'), (90, 1, NULL, 'GTM', 'GT'), (91, 1, NULL, 'GIN', 'GN'), (92, 1, NULL, 'GNB', 'GW'), (93, 1, NULL, 'GUY', 'GY'), (94, 1, NULL, 'HTI', 'HT'), (95, 1, NULL, 'HMD', 'HM'), (96, 1, NULL, 'HND', 'HN'), (97, 1, NULL, 'HKG', 'HK'), (98, 1, NULL, 'HUN', 'HU'), (99, 1, NULL, 'ISL', 'IS'), (100, 1, NULL, 'IND', 'IN'), (101, 1, NULL, 'IDN', 'ID'), (102, 1, NULL, 'IRN', 'IR'), (103, 1, NULL, 'IRQ', 'IQ'), (104, 1, NULL, 'IRL', 'IE'), (105, 1, NULL, 'ISR', 'IL'), (106, 1, NULL, 'ITA', 'IT'), (107, 1, NULL, 'JAM', 'JM'), (108, 1, NULL, 'JPN', 'JP'), (109, 1, NULL, 'JOR', 'JO'), (110, 1, NULL, 'KAZ', 'KZ'), (111, 1, NULL, 'KEN', 'KE'), (112, 1, NULL, 'KIR', 'KI'), (113, 1, NULL, 'PRK', 'KP'), (114, 1, NULL, 'KOR', 'KR'), (115, 1, NULL, 'KWT', 'KW'), (116, 1, NULL, 'KGZ', 'KG'), (117, 1, NULL, 'LAO', 'LA'), (118, 1, NULL, 'LVA', 'LV'), (119, 1, NULL, 'LBN', 'LB'), (120, 1, NULL, 'LSO', 'LS'), (121, 1, NULL, 'LBR', 'LR'), (122, 1, NULL, 'LBY', 'LY'), (123, 1, NULL, 'LIE', 'LI'), (124, 1, NULL, 'LTU', 'LT'), (125, 1, NULL, 'LUX', 'LU'), (126, 1, NULL, 'MAC', 'MO'), (127, 1, NULL, 'MKD', 'MK'), (128, 1, NULL, 'MDG', 'MG'), (129, 1, NULL, 'MWI', 'MW'), (130, 1, NULL, 'MYS', 'MY'), (131, 1, NULL, 'MDV', 'MV'), (132, 1, NULL, 'MLI', 'ML'), (133, 1, NULL, 'MLT', 'MT'), (134, 1, NULL, 'MHL', 'MH'), (135, 1, NULL, 'MTQ', 'MQ'), (136, 1, NULL, 'MRT', 'MR'), (137, 1, NULL, 'MUS', 'MU'), (138, 1, NULL, 'MYT', 'YT'), (139, 1, NULL, 'MEX', 'MX'), (140, 1, NULL, 'FSM', 'FM'), (141, 1, NULL, 'MDA', 'MD'), (142, 1, NULL, 'MCO', 'MC'), (143, 1, NULL, 'MNG', 'MN'), (144, 1, NULL, 'MSR', 'MS'), (145, 1, NULL, 'MAR', 'MA'), (146, 1, NULL, 'MOZ', 'MZ'), (147, 1, NULL, 'MMR', 'MM'), (148, 1, NULL, 'NAM', 'NA'), (149, 1, NULL, 'NRU', 'NR'), (150, 1, NULL, 'NPL', 'NP'), (151, 1, NULL, 'NLD', 'NL'), (152, 1, NULL, 'ANT', 'AN'), (153, 1, NULL, 'NCL', 'NC'), (154, 1, NULL, 'NZL', 'NZ'), (155, 1, NULL, 'NIC', 'NI'), (156, 1, NULL, 'NER', 'NE'), (157, 1, NULL, 'NGA', 'NG'), (158, 1, NULL, 'NIU', 'NU'), (159, 1, NULL, 'NFK', 'NF'), (160, 1, NULL, 'MNP', 'MP'), (161, 1, NULL, 'NOR', 'NO'), (162, 1, NULL, 'OMN', 'OM'), (163, 1, NULL, 'PAK', 'PK'), (164, 1, NULL, 'PLW', 'PW'), (165, 1, NULL, 'PSE', 'PS'), (166, 1, NULL, 'PAN', 'PA'), (167, 1, NULL, 'PNG', 'PG'), (168, 1, NULL, 'PRY', 'PY'), (169, 1, NULL, 'PER', 'PE'), (170, 1, NULL, 'PHL', 'PH'), (171, 1, NULL, 'PCN', 'PN'), (172, 1, NULL, 'POL', 'PL'), (173, 1, NULL, 'PRT', 'PT'), (174, 1, NULL, 'PRI', 'PR'), (175, 1, NULL, 'QAT', 'QA'), (176, 1, NULL, 'REU', 'RE'), (177, 1, NULL, 'ROU', 'RO'), (178, 1, NULL, 'RUS', 'RU'), (179, 1, NULL, 'RWA', 'RW'), (180, 1, NULL, 'KNA', 'KN'), (181, 1, NULL, 'LCA', 'LC'), (182, 1, NULL, 'VCT', 'VC'), (183, 1, NULL, 'WSM', 'WS'), (184, 1, NULL, 'SMR', 'SM'), (185, 1, NULL, 'STP', 'ST'), (186, 1, NULL, 'SAU', 'SA'), (187, 1, NULL, 'SEN', 'SN'), (188, 1, NULL, 'SYC', 'SC'), (189, 1, NULL, 'SLE', 'SL'), (190, 1, NULL, 'SGP', 'SG'), (191, 1, NULL, 'SVK', 'SK'), (192, 1, NULL, 'SVN', 'SI'), (193, 1, NULL, 'SLB', 'SB'), (194, 1, NULL, 'SOM', 'SO'), (195, 1, NULL, 'ZAF', 'ZA'), (196, 1, NULL, 'SGS', 'GS'), (197, 1, NULL, 'ESP', 'ES'), (198, 1, NULL, 'LKA', 'LK'), (199, 1, NULL, 'SHN', 'SH'), (200, 1, NULL, 'SPM', 'PM'), (201, 1, NULL, 'SDN', 'SD'), (202, 1, NULL, 'SUR', 'SR'), (203, 1, NULL, 'SJM', 'SJ'), (204, 1, NULL, 'SWZ', 'SZ'), (205, 1, NULL, 'SWE', 'SE'), (206, 1, NULL, 'CHE', 'CH'), (207, 1, NULL, 'SYR', 'SY'), (208, 1, NULL, 'TWN', 'TW'), (209, 1, NULL, 'TJK', 'TJ'), (210, 1, NULL, 'TZA', 'TZ'), (211, 1, NULL, 'THA', 'TH'), (212, 1, NULL, 'TGO', 'TG'), (213, 1, NULL, 'TKL', 'TK'), (214, 1, NULL, 'TON', 'TO'), (215, 1, NULL, 'TTO', 'TT'), (216, 1, NULL, 'TUN', 'TN'), (217, 1, NULL, 'TUR', 'TR'), (218, 1, NULL, 'TKM', 'TM'), (219, 1, NULL, 'TCA', 'TC'), (220, 1, NULL, 'TUV', 'TV'), (221, 1, NULL, 'UGA', 'UG'), (222, 1, NULL, 'UKR', 'UA'), (223, 1, NULL, 'ARE', 'AE'), (224, 1, NULL, 'GBR', 'GB'), (225, 1, NULL, 'USA', 'US'), (226, 1, NULL, 'UMI', 'UM'), (227, 1, NULL, 'URY', 'UY'), (228, 1, NULL, 'UZB', 'UZ'), (229, 1, NULL, 'VUT', 'VU'), (230, 1, NULL, 'VAT', 'VA'), (231, 1, NULL, 'VEN', 'VE'), (232, 1, NULL, 'VNM', 'VN'), (233, 1, NULL, 'VGB', 'VG'), (234, 1, NULL, 'VIR', 'VI'), (235, 1, NULL, 'WLF', 'WF'), (236, 1, NULL, 'ESH', 'EH'), (237, 1, NULL, 'YEM', 'YE'), (238, 1, NULL, 'YUG', 'YU'), (239, 1, NULL, 'ZMB', 'ZM'), (240, 1, NULL, 'ZWE', 'ZW'), (370, 2, 38, 'YT', NULL), (369, 2, 38, 'SK', NULL), (368, 2, 38, 'QC', NULL), (367, 2, 38, 'PE', NULL), (366, 2, 38, 'ON', NULL), (365, 2, 38, 'NU', NULL), (364, 2, 38, 'NS', NULL), (363, 2, 38, 'NT', NULL), (362, 2, 38, 'NL', NULL), (361, 2, 38, 'NB', NULL), (360, 2, 38, 'MB', NULL), (359, 2, 38, 'BC', NULL), (358, 2, 38, 'AB', NULL), (357, 2, 225, 'DC', NULL), (356, 2, 225, 'WY', NULL), (355, 2, 225, 'WI', NULL), (354, 2, 225, 'WV', NULL), (353, 2, 225, 'WA', NULL), (352, 2, 225, 'VA', NULL), (351, 2, 225, 'VT', NULL), (350, 2, 225, 'UT', NULL), (349, 2, 225, 'TX', NULL), (348, 2, 225, 'TN', NULL), (347, 2, 225, 'SD', NULL), (346, 2, 225, 'SC', NULL), (345, 2, 225, 'RI', NULL), (344, 2, 225, 'PR', NULL), (343, 2, 225, 'PA', NULL), (342, 2, 225, 'OR', NULL), (341, 2, 225, 'OK', NULL), (340, 2, 225, 'OH', NULL), (339, 2, 225, 'ND', NULL), (338, 2, 225, 'NC', NULL), (337, 2, 225, 'NY', NULL), (336, 2, 225, 'NM', NULL), (335, 2, 225, 'NJ', NULL), (334, 2, 225, 'NH', NULL), (333, 2, 225, 'NV', NULL), (332, 2, 225, 'NE', NULL), (331, 2, 225, 'MT', NULL), (330, 2, 225, 'MO', NULL), (329, 2, 225, 'MS', NULL), (328, 2, 225, 'MN', NULL), (327, 2, 225, 'MI', NULL), (326, 2, 225, 'MA', NULL), (325, 2, 225, 'MD', NULL), (324, 2, 225, 'ME', NULL), (323, 2, 225, 'LA', NULL), (322, 2, 225, 'KY', NULL), (321, 2, 225, 'KS', NULL), (320, 2, 225, 'IA', NULL), (319, 2, 225, 'IN', NULL), (318, 2, 225, 'IL', NULL), (317, 2, 225, 'ID', NULL), (316, 2, 225, 'HI', NULL), (315, 2, 225, 'GA', NULL), (314, 2, 225, 'FL', NULL), (313, 2, 225, 'DE', NULL), (312, 2, 225, 'CT', NULL), (311, 2, 225, 'CO', NULL), (310, 2, 225, 'CA', NULL), (309, 2, 225, 'AR', NULL), (308, 2, 225, 'AZ', NULL), (307, 2, 225, 'AK', NULL), (306, 2, 225, 'AL', NULL); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'CATEGORY.VIEW', 'la_PermName_Category.View_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'CATEGORY.ADD', 'la_PermName_Category.Add_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'CATEGORY.DELETE', 'la_PermName_Category.Delete_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'CATEGORY.ADD.PENDING', 'la_PermName_Category.AddPending_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'CATEGORY.MODIFY', 'la_PermName_Category.Modify_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'CATEGORY.REVISION.ADD', 'la_PermName_Category.Revision.Add_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'CATEGORY.REVISION.ADD.PENDING', 'la_PermName_Category.Revision.Add.Pending_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'CATEGORY.REVISION.MODERATE', 'la_PermName_Category.Revision.Moderate_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'CATEGORY.REVISION.HISTORY.VIEW', 'la_PermName_Category.Revision.History.View_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'CATEGORY.REVISION.HISTORY.RESTORE', 'la_PermName_Category.Revision.History.Restore_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'ADMIN', 'la_PermName_Admin_desc', 'Admin', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'LOGIN', 'la_PermName_Login_desc', 'Front', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'DEBUG.ITEM', 'la_PermName_Debug.Item_desc', 'Admin', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'DEBUG.LIST', 'la_PermName_Debug.List_desc', 'Admin', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'DEBUG.INFO', 'la_PermName_Debug.Info_desc', 'Admin', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'PROFILE.MODIFY', 'la_PermName_Profile.Modify_desc', 'Admin', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'SHOWLANG', 'la_PermName_ShowLang_desc', 'Admin', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'FAVORITES', 'la_PermName_favorites_desc', 'In-Portal', 1); INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'SYSTEM_ACCESS.READONLY', 'la_PermName_SystemAccess.ReadOnly_desc', 'Admin', 1); INSERT INTO CategoryPermissionsCache VALUES (DEFAULT, 0, 1, '11,12,13,14,15'); INSERT INTO Permissions VALUES (DEFAULT, 'LOGIN', 13, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'LOGIN', 12, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'LOGIN', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'ADMIN', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:root.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:website_setting_folder.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_setting_folder.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_advanced.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_advanced.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_advanced.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_list.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_list.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_list.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_list.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:admins.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:admins.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:admins.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:admins.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_lang.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_lang.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_lang.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_lang.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:phrases.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:phrases.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:phrases.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:phrases.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configemail.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configemail.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configemail.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configemail.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.VIEW', 15, 1, 0, 1); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.ADD', 11, 1, 0, 1); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.ADD.PENDING', 13, 1, 0, 1); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.DELETE', 11, 1, 0, 1); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.MODIFY', 11, 1, 0, 1); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.REVISION.ADD', 11, 1, 0, 1); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.REVISION.HISTORY.VIEW', 11, 1, 0, 1); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.REVISION.HISTORY.RESTORE', 11, 1, 0, 1); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:service.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:service.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:scheduled_tasks.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:scheduled_tasks.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:scheduled_tasks.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:scheduled_tasks.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:site_domains.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:site_domains.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:site_domains.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:site_domains.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:country_states.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:country_states.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:country_states.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:country_states.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spelling_dictionary.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spelling_dictionary.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spelling_dictionary.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spelling_dictionary.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:ban_rulelist.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:ban_rulelist.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:ban_rulelist.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:site.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:browse.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:advanced_view.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:reviews.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_categories.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_categories.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_categories.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configuration_search.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configuration_search.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configuration_custom.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configuration_custom.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configuration_custom.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configuration_custom.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:users.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_list.advanced:ban', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_list.advanced:send_email', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_groups.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_groups.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_groups.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_groups.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_groups.advanced:send_email', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_groups.advanced:manage_permissions', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_users.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_users.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_users.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_custom.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_custom.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_custom.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_custom.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_banlist.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_banlist.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_banlist.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_banlist.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:reports.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:log_summary.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:searchlog.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:searchlog.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:sessionlog.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:sessionlog.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:emaillog.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:emaillog.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:emaillog.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:visits.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:visits.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_logs.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_logs.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_logs.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spam_reports.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spam_reports.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spam_reports.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_general.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_general.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_general.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:modules.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mod_status.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mod_status.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mod_status.advanced:approve', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mod_status.advanced:decline', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:permission_types.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:permission_types.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:permission_types.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:permission_types.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:item_filters.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:item_filters.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:item_filters.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:item_filters.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:addmodule.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:addmodule.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:addmodule.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:tag_library.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_themes.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_themes.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_themes.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_themes.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_styles.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_styles.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_styles.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_styles.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_lang.advanced:set_primary', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_lang.advanced:import', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_lang.advanced:export', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:tools.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:backup.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:restore.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:export.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:main_import.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:sql_query.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:sql_query.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:server_info.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:help.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:browse_site.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:forms.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:forms.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:forms.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:forms.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:submissions.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:promo_block_groups.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:promo_block_groups.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:promo_block_groups.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:promo_block_groups.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mailing_lists.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mailing_lists.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mailing_lists.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mailing_lists.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_event_subscriptions.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_event_subscriptions.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_event_subscriptions.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_event_subscriptions.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:email_queue.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:email_queue.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:session_logs.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:session_logs.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:change_logs.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:change_logs.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:change_logs.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:stop_words.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:stop_words.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:stop_words.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:stop_words.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:thesaurus.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:thesaurus.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:thesaurus.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:thesaurus.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:skins.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:skins.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:skins.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:skins.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:module_deployment_log.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:module_deployment_log.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:module_deployment_log.delete', 11, 1, 1, 0); -INSERT INTO AdminSkins VALUES(DEFAULT, 'Default', '/* General elements */\r\n\r\nhtml {\r\n height: 100%;\r\n}\r\n\r\nbody {\r\n font-family: verdana,arial,helvetica,sans-serif;\r\n color: #000000;\r\n overflow-x: auto; overflow-y: auto;\r\n margin: 0px 0px 0px 0px;\r\n text-decoration: none;\r\n}\r\n\r\nbody, td {\r\n /* fix for Firefox, when font-size was not inherited in table cells */\r\n font-size: 9pt;\r\n}\r\n\r\na {\r\n color: #006699;\r\n text-decoration: none;\r\n}\r\n\r\na:hover {\r\n color: #009ff0;\r\n text-decoration: none;\r\n}\r\n\r\nform {\r\n display: inline;\r\n}\r\n\r\nimg { border: 0px; }\r\n\r\nbody.height-100 {\r\n height: 100%;\r\n}\r\n\r\nbody.regular-body {\r\n margin: 0px 10px 5px 10px;\r\n color: #000000;\r\n background-color: @@SectionBgColor@@;\r\n}\r\n\r\nbody.edit-popup {\r\n margin: 0px 0px 0px 0px;\r\n}\r\n\r\ntable.collapsed {\r\n border-collapse: collapse;\r\n}\r\n\r\n.bordered, table.bordered, .bordered-no-bottom {\r\n border: 1px solid #000000 !important;\r\n border-top-width: 0px;\r\n border-collapse: collapse;\r\n}\r\n\r\n.bordered-no-bottom {\r\n border-top-width: 1px;\r\n border-bottom: none;\r\n}\r\n\r\n.login-table td {\r\n padding: 1px;\r\n}\r\n\r\n.disabled {\r\n background-color: #ebebeb;\r\n}\r\n\r\n/* Head frame */\r\ntable.head-table {\r\n background: url(\'@@base_url@@/core/admin_templates/img/top_frame/right_background.png\') top right @@HeadBgColor@@ no-repeat;\r\n}\r\n\r\n.head-table tr td, .head-table tr td a {\r\n color: @@HeadColor@@\r\n}\r\n\r\ndiv#extra_toolbar td.button-active {\r\n background: url(\'@@base_url@@/core/admin_templates/img/top_frame/toolbar_button_background.gif\') bottom left repeat-x;\r\n height: 22px;\r\n}\r\n\r\ndiv#extra_toolbar td.button-active a {\r\n color: black;\r\n text-decoration: none;\r\n}\r\n\r\ntd.kx-block-header, .head-table tr td.kx-block-header{\r\n color: @@HeadBarColor@@;\r\n background: url(\'@@base_url@@/core/admin_templates/img/top_frame/toolbar_background.gif\') repeat-x top left;\r\n /*background-color: @@HeadBarBgColor@@;*/\r\n padding-left: 7px;\r\n padding-right: 7px;\r\n}\r\n\r\na.kx-header-link {\r\n text-decoration: underline;\r\n font-weight: bold;\r\n color: #0080C8;\r\n}\r\n\r\na.kx-header-link:hover {\r\n color: #FFCB05;\r\n text-decoration: none;\r\n}\r\n\r\n.kx-secondary-foreground {\r\n color: #FFFFFF;\r\n /*background-color: @@HeadBarBgColor@@;*/\r\n}\r\n\r\n.kx-login-button {\r\n background-color: #2D79D6;\r\n color: #FFFFFF;\r\n}\r\n\r\n/* General form button (yellow) */\r\n.button {\r\n font-size: 12px;\r\n font-weight: normal;\r\n color: #000000;\r\n background: url(\'@@base_url@@/core/admin_templates/img/button_back.gif\') #f9eeae repeat-x;\r\n text-decoration: none;\r\n}\r\n\r\n/* Disabled (grayed-out) form button */\r\n.button-disabled {\r\n font-size: 12px;\r\n font-weight: normal;\r\n color: #676767;\r\n background: url(\'@@base_url@@/core/admin_templates/img/button_back_disabled.gif\') #f9eeae repeat-x;\r\n text-decoration: none;\r\n}\r\n\r\n/* Tabs bar */\r\n\r\n.tab, .tab-active {\r\n background-color: #F0F1EB;\r\n padding: 3px 7px 2px 7px;\r\n border-top: 1px solid black;\r\n border-left: 1px solid black;\r\n border-right: 1px solid black;\r\n margin-left: 3px !important;\r\n white-space: nowrap;\r\n}\r\n\r\n.tab-active {\r\n background-color: #4487D9;\r\n}\r\n\r\n.tab a {\r\n color: #4487D9;\r\n font-weight: bold;\r\n}\r\n\r\n.tab-active a {\r\n color: #FFFFFF;\r\n font-weight: bold;\r\n}\r\n\r\na.scroll-left, a.scroll-right {\r\n cursor: pointer;\r\n display: block;\r\n float: left;\r\n height: 18px;\r\n margin: 0px 1px;\r\n width: 18px;\r\n}\r\n\r\na.scroll-left {\r\n background: transparent url(\'@@base_url@@/core/admin_templates/img/tabs/left.png\') no-repeat scroll 0 0;\r\n}\r\n\r\na.scroll-right {\r\n background: transparent url(\'@@base_url@@/core/admin_templates/img/tabs/right.png\') no-repeat scroll 0 0;\r\n}\r\n\r\na.disabled {\r\n visibility: hidden !important;\r\n}\r\n\r\na.scroll-left:hover, a.scroll-right:hover {\r\n background-position: 0 -18px;\r\n}\r\n\r\ntd.scroll-right-container {\r\n width: 20px;\r\n}\r\n\r\ntd.scroll-right-container.disabled, td.scroll-right-container.disabled * {\r\n width: 0px;\r\n margin: 0px;\r\n}\r\n\r\ntd.scroll-right-container.disabled br {\r\n display: none;\r\n}\r\n\r\n/* Toolbar */\r\n\r\n.toolbar {\r\n font-size: 8pt;\r\n border: 1px solid #000000;\r\n border-width: 0px 1px 1px 1px;\r\n background-color: @@ToolbarBgColor@@;\r\n border-collapse: collapse;\r\n}\r\n\r\n.toolbar td {\r\n height: 100%;\r\n}\r\n\r\n.toolbar-button, .toolbar-button-disabled, .toolbar-button-over {\r\n float: left;\r\n text-align: center;\r\n font-size: 8pt;\r\n padding: 5px 5px 5px 5px;\r\n vertical-align: middle;\r\n color: #006F99;\r\n}\r\n\r\n.toolbar-button-over {\r\n color: #000;\r\n}\r\n\r\n.toolbar-button-disabled {\r\n color: #444;\r\n}\r\n\r\n/* Scrollable Grids */\r\n\r\n\r\n.layout-only-table td {\r\n border: none !important;\r\n}\r\n\r\n/* Main Grid class */\r\n.grid-scrollable {\r\n padding: 0px;\r\n border: 1px solid black !important;\r\n border-top: none !important;\r\n}\r\n\r\n/* Div generated by js, which contains all the scrollable grid elements, affects the style of scrollable area without data (if there are too few rows) */\r\n.grid-container {\r\n background-color: #fff;\r\n}\r\n\r\n.grid-container table {\r\n border-collapse: collapse;\r\n}\r\n\r\n/* Inner div generated in each data-cell */\r\n.grid-cell-div {\r\n overflow: hidden;\r\n height: auto;\r\n}\r\n\r\n/* Main row definition */\r\n.grid-data-row td, .grid-data-row-selected td, .grid-data-row-even-selected td, .grid-data-row-mouseover td, .table-color1, .table-color2, .grid-edit-table .edit-form-odd > td, .grid-edit-table .edit-form-even > td {\r\n font-weight: normal;\r\n color: @@OddColor@@;\r\n background-color: @@OddBgColor@@;\r\n padding: 3px 5px 3px 5px;\r\n overflow: hidden;\r\n border-right: 1px solid #c9c9c9;\r\n}\r\n.grid-data-row-even td, .table-color2, .grid-edit-table .edit-form-even > td {\r\n background-color: @@EvenBgColor@@;\r\n color: @@EvenColor@@;\r\n}\r\n.grid-data-row td a, .grid-data-row-selected td a, .grid-data-row-mouseover td a {\r\n text-decoration: underline;\r\n}\r\n\r\n/* mouse-over rows */\r\n.grid-data-row-mouseover td, table tr.grid-data-row[_row_highlighted] td {\r\n background: #FFFDF4;\r\n}\r\n\r\n/* Selected row, applies to both checkbox and data areas */\r\n.grid-data-row-selected td, table tr.grid-data-row[_row_selected] td {\r\n background: #FEF2D6;\r\n}\r\n\r\n.grid-data-row-even-selected td, .grid-data-row-even[_row_selected] td {\r\n background: #FFF7E0;\r\n}\r\n\r\n/* General header cell definition */\r\n.grid-header-row td {\r\n font-weight: bold;\r\n background-color: @@ColumnTitlesBgColor@@;\r\n text-decoration: none;\r\n padding: 3px 5px 3px 5px;\r\n color: @@ColumnTitlesColor@@;\r\n border-right: none;\r\n text-align: left;\r\n vertical-align: middle !important;\r\n white-space: nowrap;\r\n border-right: 1px solid #777;\r\n}\r\n\r\n/* Filters row */\r\ntr.grid-header-row-1 td {\r\n background-color: @@FiltersBgColor@@;\r\n border-bottom: 1px solid black;\r\n}\r\n\r\n/* Grid Filters */\r\ntable.range-filter {\r\n width: 100%;\r\n}\r\n\r\n.range-filter td {\r\n padding: 0px 0px 2px 2px !important;\r\n border: none !important;\r\n font-size: 8pt !important;\r\n font-weight: normal !important;\r\n text-align: left;\r\n color: #000000 !important;\r\n}\r\n\r\ninput.filter, select.filter, input.filter-active, select.filter-active {\r\n margin-bottom: 0px;\r\n border: 1px solid #aaa;\r\n}\r\n\r\ninput.filter-active {\r\n background-color: #FFFF00;\r\n}\r\n\r\nselect.filter-active {\r\n background-color: #FFFF00;\r\n}\r\n\r\ndiv.filter, div.filter-active {\r\n background-color: white;\r\n border: 1px solid #AAAAAA;\r\n color: black;\r\n font-weight: normal;\r\n padding: 3px;\r\n}\r\n\r\ndiv.filter-active {\r\n background-color: #FFFF00;\r\n}\r\n\r\ndiv.multioptions_filter {\r\n position: absolute;\r\n z-index: 100;\r\n color: black;\r\n background-color: white;\r\n border: 1px solid black;\r\n padding: 3px 5px;\r\n display: none;\r\n vertical-align: middle;\r\n}\r\n\r\n/* Column titles row */\r\ntr.grid-header-row-0 td {\r\n height: 25px;\r\n font-weight: bold;\r\n background-color: @@ColumnTitlesBgColor@@;\r\n color: @@ColumnTitlesColor@@;\r\n border-bottom: 1px solid black;\r\n}\r\n\r\ntr.grid-header-row-0 td a {\r\n color: @@ColumnTitlesColor@@;\r\n}\r\n\r\ntr.grid-header-row-0 td a:hover {\r\n color: #FFCC00;\r\n}\r\n\r\n\r\n.grid-footer-row td {\r\n background-color: #D7D7D7;\r\n font-weight: bold;\r\n border-right: 1px solid #C9C9C9;\r\n padding: 3px 5px 3px 5px;\r\n}\r\n\r\ntd.grid-header-last-cell, td.grid-data-last-cell, td.grid-footer-last-cell {\r\n border-right: none !important;\r\n}\r\n\r\ntd.grid-data-col-0, td.grid-data-col-0 div {\r\n text-align: center;\r\n vertical-align: middle !important;\r\n}\r\n\r\ntr.grid-header-row-1 td.grid-header-col-1 {\r\n text-align: center;\r\n vertical-align: middle !important;\r\n}\r\n\r\ntr.grid-header-row-1 td.grid-header-col-1 div {\r\n display: table-cell;\r\n vertical-align: middle;\r\n}\r\n\r\n.grid-status-bar {\r\n border: 1px solid black;\r\n border-top: none;\r\n padding: 0px;\r\n width: 100%;\r\n border-collapse: collapse;\r\n height: 30px;\r\n}\r\n\r\n.grid-status-bar td {\r\n background-color: @@TitleBarBgColor@@;\r\n color: @@TitleBarColor@@;\r\n font-size: 11pt;\r\n font-weight: normal;\r\n padding: 2px 8px 2px 8px;\r\n}\r\n\r\n/* /Scrollable Grids */\r\n\r\n\r\n/* Forms */\r\ntable.edit-form {\r\n border: none;\r\n border-top-width: 0px !important;\r\n border-collapse: collapse;\r\n width: 100%;\r\n}\r\n\r\n.edit-form-odd, .edit-form-even {\r\n padding: 0px;\r\n}\r\n\r\n.subsectiontitle {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n background-color: #4A92CE;\r\n color: #fff;\r\n height: 25px;\r\n border-top: 1px solid black;\r\n vertical-align: middle;\r\n}\r\n\r\n/* remove top-border from first sub-section element */\r\ntable.edit-form .subsectiontitle:first-child, table.bordered .subsectiontitle:first-child {\r\n border-top-width: 0;\r\n}\r\n\r\n.subsectiontitle td {\r\n vertical-align: middle;\r\n /*padding: 3px 5px 3px 5px;*/\r\n padding: 1px 5px;\r\n}\r\n\r\n.label-cell {\r\n background: #DEE7F6 url(\'@@base_url@@/core/admin_templates/img/bgr_input_name_line.gif\') no-repeat right bottom;\r\n font: 12px arial, sans-serif;\r\n padding: 4px 20px;\r\n width: 160px;\r\n}\r\n\r\n.control-mid {\r\n width: 13px;\r\n border-left: 1px solid #7A95C2;\r\n background: #fff url(\'@@base_url@@/core/admin_templates/img/bgr_mid.gif\') repeat-x left bottom;\r\n}\r\n\r\n.control-cell {\r\n font: 11px arial, sans-serif;\r\n padding: 4px 10px 5px 5px;\r\n background: #fff url(\'@@base_url@@/core/admin_templates/img/bgr_input_line.gif\') no-repeat left bottom;\r\n width: auto;\r\n vertical-align: middle;\r\n}\r\n\r\n.CodeMirror {\r\n font-size: 13px;\r\n border: 1px solid black;\r\n}\r\n\r\n.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}\r\n.CodeMirror-activeline-background {background: #e8f2ff !important;}\r\n\r\n.label-cell-filler {\r\n background: #DEE7F6 none;\r\n}\r\n.control-mid-filler {\r\n background: #fff none;\r\n border-left: 1px solid #7A95C2;\r\n}\r\n.control-cell-filler {\r\n background: #fff none;\r\n}\r\n\r\n.highlight-area, .code-highlight-area {\r\n border: 1px solid black;\r\n padding: 8px;\r\n font-family: monospace !important;\r\n font-size: 12px;\r\n overflow: auto;\r\n}\r\n\r\n.code-highlight-area {\r\n background-color: #F6F6F6;\r\n}\r\n\r\n.error {\r\n color: red;\r\n}\r\n.error-cell {\r\n color: red;\r\n}\r\n\r\n.field-required {\r\n color: red;\r\n}\r\n\r\n.warning-table {\r\n background-color: #F0F1EB;\r\n border: 1px solid #000000;\r\n border-collapse: collapse;\r\n border-top-width: 0px;\r\n}\r\n\r\n.form-notice, .form-warning {\r\n font-size: 11px;\r\n}\r\n\r\n.form-warning {\r\n color: red;\r\n}\r\n\r\n.form-notice {\r\n color: green;\r\n}\r\n\r\n.priority {\r\n color: red;\r\n padding-left: 1px;\r\n padding-right: 1px;\r\n font-size: 11px;\r\n}\r\n\r\n.small-statistics {\r\n font-size: 11px;\r\n color: #707070;\r\n}\r\n\r\n.req-note {\r\n font-style: italic;\r\n color: #333;\r\n}\r\n\r\n#scroll_container table.tableborder {\r\n border-collapse: separate\r\n}\r\n\r\nlabel.checkbox {\r\n white-space: nowrap;\r\n}\r\n\r\n/* Uploader */\r\n.uploader-queue div.file {\r\n font-size: 11px;\r\n border: 1px solid #7F99C5;\r\n padding: 3px;\r\n background-color: #DEE7F6;\r\n margin-bottom: 2px;\r\n}\r\n\r\n.uploader-queue .left {\r\n float: left;\r\n vertical-align: top;\r\n}\r\n\r\n.uploader-queue .file-label {\r\n margin-left: 5px;\r\n}\r\n\r\n.uploader-queue .preview .delete-checkbox {\r\n margin-top: -3px;\r\n}\r\n\r\n.uploader-queue .progress-container {\r\n margin: 2px 5px 0px 5px;\r\n}\r\n\r\n.uploader-queue .progress-empty {\r\n width: 150px;\r\n height: 9px;\r\n border: 1px solid black;\r\n background: url(\'@@base_url@@/core/admin_templates/img/progress_left.gif\') repeat-x;\r\n}\r\n\r\n.uploader-queue .progress-full {\r\n height: 9px;\r\n background: url(\'@@base_url@@/core/admin_templates/img/progress_done.gif\');\r\n}\r\n\r\n.uploader-queue .thumbnail {\r\n /*margin-bottom: 2px;*/\r\n border: 1px solid black;\r\n background-color: grey;\r\n}\r\n\r\n/* To be sorted */\r\nspan#category_path, span#category_path a {\r\n color: #FFFFFF;\r\n}\r\n\r\nspan#category_path a {\r\n text-decoration: underline;\r\n}\r\n\r\n/* Section title, right to the big icon */\r\n.admintitle {\r\n font-size: 16pt;\r\n font-weight: bold;\r\n color: @@SectionColor@@;\r\n text-decoration: none;\r\n}\r\n\r\n/* Page header (bluebar) */\r\n.page-title td {\r\n background-color: @@TitleBarBgColor@@;\r\n color: @@TitleBarColor@@;\r\n font-size: 11pt;\r\n font-weight: normal;\r\n padding: 2px 8px 2px 8px;\r\n}\r\n\r\n/* Right side of bluebar */\r\n.tablenav, tablenav a {\r\n font-size: 11pt;\r\n font-weight: bold;\r\n color: @@TitleBarColor@@;\r\n\r\n text-decoration: none;\r\n background-color: @@TitleBarBgColor@@;\r\n background-image: none;\r\n}\r\n\r\n/* Section title in the bluebar * -- why \'link\'? :S */\r\n.tablenav_link {\r\n font-size: 11pt;\r\n font-weight: bold;\r\n color: @@TitleBarColor@@;\r\n text-decoration: none;\r\n}\r\n\r\n/* Active page in top and bottom bluebars pagination */\r\n.current_page {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n background-color: #fff;\r\n color: #2D79D6;\r\n padding: 3px 2px 3px 3px;\r\n}\r\n\r\n/* Other pages and arrows in pagination on blue */\r\n.nav_url {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n color: #fff;\r\n padding: 3px 2px 3px 3px;\r\n}\r\n\r\n/* Tree */\r\n.tree-body {\r\n background-color: @@TreeBgColor@@;\r\n height: 100%\r\n}\r\n\r\n.tree_head.td, .tree_head, .tree_head:hover {\r\n font-weight: bold;\r\n font-size: 10px;\r\n color: #FFFFFF;\r\n font-family: Verdana, Arial;\r\n text-decoration: none;\r\n}\r\n\r\n.tree {\r\n padding: 0px;\r\n border: none;\r\n border-collapse: collapse;\r\n}\r\n\r\n.tree tr td {\r\n padding: 0px;\r\n margin: 0px;\r\n font-family: helvetica, arial, verdana,;\r\n font-size: 11px;\r\n white-space: nowrap;\r\n}\r\n\r\n.tree tr td a {\r\n font-size: 11px;\r\n color: @@TreeColor@@;\r\n font-family: Helvetica, Arial, Verdana;\r\n text-decoration: none;\r\n padding: 2px;\r\n}\r\n\r\n.tree tr td a:hover, .tree tr td a.debug-only-item:hover {\r\n color: @@TreeHoverColor@@;\r\n}\r\n\r\n.tree tr.highlighted td a, .tree tr.highlighted td a.debug-only-item {\r\n color: @@TreeHighColor@@;\r\n background-color: @@TreeHighBgColor@@;\r\n}\r\n\r\n.tree tr.highlighted td a:hover {\r\n color: @@TreeHighHoverColor@@;\r\n}\r\n\r\n.tree tr td a.debug-only-item {\r\n color: grey;\r\n}\r\n\r\n/* Ajax Dropdown */\r\n.suggest-box {\r\n border: 1px solid #999;\r\n background-color: #fff;\r\n}\r\n\r\n.suggest-item, .suggest-item-over {\r\n padding: 1px 2px 0px 2px;\r\n font-family: arial,verdana;\r\n font-size: 12px;\r\n}\r\n\r\n.suggest-item-over {\r\n background-color: #3366CC;\r\n color: #fff;\r\n}\r\n\r\n/* Dashboard Summary Boxes */\r\n.summary-box {\r\n border: 1px solid black;\r\n margin-bottom: 4px;\r\n}\r\n\r\n.summary-box .title {\r\n color: white;\r\n font-weight: bold;\r\n padding: 6px 5px;\r\n vertical-align: middle;\r\n background-color: #4A92CE;\r\n border-bottom: 1px solid black;\r\n}\r\n\r\n.summary-box .content {\r\n padding: 4px;\r\n background-color: #F6F6F6;\r\n}\r\n\r\n.summary-box .group {\r\n border-bottom: 1px solid black;\r\n margin-bottom: 10px;\r\n padding: 0 0 10px 10px;\r\n}\r\n\r\n.summary-box .group.last {\r\n border-width: 0px;\r\n margin-bottom: 0;\r\n padding-bottom: 5px;\r\n}\r\n\r\n.summary-box h4 {\r\n margin: 0;\r\n padding: 0 0 3px 0;\r\n font-size: 11px;\r\n font-weight: bold;\r\n}\r\n\r\n.summary-box .hint {\r\n font-size: 10px;\r\n color: grey;\r\n margin-bottom: 3px;\r\n}\r\n\r\n.summary-box .hint .cache-key {\r\n margin-bottom: 7px;\r\n margin-left: 3px;\r\n}\r\n\r\n.summary-box ul {\r\n margin-top: 5px;\r\n margin-bottom: 3px;\r\n padding-left: 30px;\r\n}\r\n\r\n.summary-box li {\r\n padding-bottom: 4px;\r\n}\r\n\r\nspan.cke_skin_kama {\r\n border-width: 0px !important;\r\n -moz-border-radius: 0px !important;\r\n -webkit-border-radius: 0px !important;\r\n padding: 0px !important;\r\n}\r\n\r\n.cke_wrapper{\r\n border-width: 0px !important;\r\n -moz-border-radius: 0px !important;\r\n -webkit-border-radius: 0px !important;\r\n}\r\n', 'in-portal_logo_img.jpg', 'in-portal_logo_img2.jpg', 'in-portal_logo_login.gif', 'a:22:{s:11:"HeadBgColor";a:2:{s:11:"Description";s:27:"Head frame background color";s:5:"Value";s:7:"#007BF4";}s:9:"HeadColor";a:2:{s:11:"Description";s:21:"Head frame text color";s:5:"Value";s:7:"#FFFFFF";}s:14:"SectionBgColor";a:2:{s:11:"Description";s:28:"Section bar background color";s:5:"Value";s:7:"#FFFFFF";}s:12:"SectionColor";a:2:{s:11:"Description";s:22:"Section bar text color";s:5:"Value";s:7:"#2D79D6";}s:12:"HeadBarColor";a:1:{s:5:"Value";s:7:"#000000";}s:14:"HeadBarBgColor";a:1:{s:5:"Value";s:7:"#1961B8";}s:13:"TitleBarColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:15:"TitleBarBgColor";a:1:{s:5:"Value";s:7:"#2D79D6";}s:14:"ToolbarBgColor";a:1:{s:5:"Value";s:7:"#F0F1EB";}s:14:"FiltersBgColor";a:1:{s:5:"Value";s:7:"#D7D7D7";}s:17:"ColumnTitlesColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:19:"ColumnTitlesBgColor";a:1:{s:5:"Value";s:7:"#999999";}s:8:"OddColor";a:1:{s:5:"Value";s:7:"#000000";}s:10:"OddBgColor";a:1:{s:5:"Value";s:7:"#F6F6F6";}s:9:"EvenColor";a:1:{s:5:"Value";s:7:"#000000";}s:11:"EvenBgColor";a:1:{s:5:"Value";s:7:"#EBEBEB";}s:9:"TreeColor";a:1:{s:5:"Value";s:7:"#000000";}s:14:"TreeHoverColor";a:1:{s:5:"Value";s:7:"#009FF0";}s:13:"TreeHighColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:18:"TreeHighHoverColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:15:"TreeHighBgColor";a:1:{s:5:"Value";s:7:"#4A92CE";}s:11:"TreeBgColor";a:1:{s:5:"Value";s:7:"#DCECF6";}}', 1482759870, 1, 1); +INSERT INTO AdminSkins VALUES(DEFAULT, 'Default', '/* General elements */\r\n\r\nhtml {\r\n height: 100%;\r\n}\r\n\r\nbody {\r\n font-family: verdana,arial,helvetica,sans-serif;\r\n color: #000000;\r\n overflow-x: auto; overflow-y: auto;\r\n margin: 0px 0px 0px 0px;\r\n text-decoration: none;\r\n}\r\n\r\nbody, td {\r\n /* fix for Firefox, when font-size was not inherited in table cells */\r\n font-size: 9pt;\r\n}\r\n\r\na {\r\n color: #006699;\r\n text-decoration: none;\r\n}\r\n\r\na:hover {\r\n color: #009ff0;\r\n text-decoration: none;\r\n}\r\n\r\nform {\r\n display: inline;\r\n}\r\n\r\nimg { border: 0px; }\r\n\r\nbody.height-100 {\r\n height: 100%;\r\n}\r\n\r\nbody.regular-body {\r\n margin: 0px 10px 5px 10px;\r\n color: #000000;\r\n background-color: @@SectionBgColor@@;\r\n}\r\n\r\nbody.edit-popup {\r\n margin: 0px 0px 0px 0px;\r\n}\r\n\r\ntable.collapsed {\r\n border-collapse: collapse;\r\n}\r\n\r\n.bordered, table.bordered, .bordered-no-bottom {\r\n border: 1px solid #000000 !important;\r\n border-top-width: 0px;\r\n border-collapse: collapse;\r\n}\r\n\r\n.bordered-no-bottom {\r\n border-top-width: 1px;\r\n border-bottom: none;\r\n}\r\n\r\n.login-table td {\r\n padding: 1px;\r\n}\r\n\r\n.disabled {\r\n background-color: #ebebeb;\r\n}\r\n\r\n/* Head frame */\r\ntable.head-table {\r\n background: url(\'@@base_url@@/core/admin_templates/img/top_frame/right_background.png\') top right @@HeadBgColor@@ no-repeat;\r\n}\r\n\r\n.head-table tr td, .head-table tr td a {\r\n color: @@HeadColor@@\r\n}\r\n\r\ndiv#extra_toolbar td.button-active {\r\n background: url(\'@@base_url@@/core/admin_templates/img/top_frame/toolbar_button_background.gif\') bottom left repeat-x;\r\n height: 22px;\r\n}\r\n\r\ndiv#extra_toolbar td.button-active a {\r\n color: black;\r\n text-decoration: none;\r\n}\r\n\r\ntd.kx-block-header, .head-table tr td.kx-block-header{\r\n color: @@HeadBarColor@@;\r\n background: url(\'@@base_url@@/core/admin_templates/img/top_frame/toolbar_background.gif\') repeat-x top left;\r\n /*background-color: @@HeadBarBgColor@@;*/\r\n padding-left: 7px;\r\n padding-right: 7px;\r\n}\r\n\r\na.kx-header-link {\r\n text-decoration: underline;\r\n font-weight: bold;\r\n color: #0080C8;\r\n}\r\n\r\na.kx-header-link:hover {\r\n color: #FFCB05;\r\n text-decoration: none;\r\n}\r\n\r\n.kx-secondary-foreground {\r\n color: #FFFFFF;\r\n /*background-color: @@HeadBarBgColor@@;*/\r\n}\r\n\r\n.kx-login-button {\r\n background-color: #2D79D6;\r\n color: #FFFFFF;\r\n}\r\n\r\n/* General form button (yellow) */\r\n.button {\r\n font-size: 12px;\r\n font-weight: normal;\r\n color: #000000;\r\n background: url(\'@@base_url@@/core/admin_templates/img/button_back.gif\') #f9eeae repeat-x;\r\n text-decoration: none;\r\n}\r\n\r\n/* Disabled (grayed-out) form button */\r\n.button-disabled {\r\n font-size: 12px;\r\n font-weight: normal;\r\n color: #676767;\r\n background: url(\'@@base_url@@/core/admin_templates/img/button_back_disabled.gif\') #f9eeae repeat-x;\r\n text-decoration: none;\r\n}\r\n\r\n/* Tabs bar */\r\n\r\n.tab, .tab-active {\r\n background-color: #F0F1EB;\r\n padding: 3px 7px 2px 7px;\r\n border-top: 1px solid black;\r\n border-left: 1px solid black;\r\n border-right: 1px solid black;\r\n margin-left: 3px !important;\r\n white-space: nowrap;\r\n}\r\n\r\n.tab-active {\r\n background-color: #4487D9;\r\n}\r\n\r\n.tab a {\r\n color: #4487D9;\r\n font-weight: bold;\r\n}\r\n\r\n.tab-active a {\r\n color: #FFFFFF;\r\n font-weight: bold;\r\n}\r\n\r\na.scroll-left, a.scroll-right {\r\n cursor: pointer;\r\n display: block;\r\n float: left;\r\n height: 18px;\r\n margin: 0px 1px;\r\n width: 18px;\r\n}\r\n\r\na.scroll-left {\r\n background: transparent url(\'@@base_url@@/core/admin_templates/img/tabs/left.png\') no-repeat scroll 0 0;\r\n}\r\n\r\na.scroll-right {\r\n background: transparent url(\'@@base_url@@/core/admin_templates/img/tabs/right.png\') no-repeat scroll 0 0;\r\n}\r\n\r\na.disabled {\r\n visibility: hidden !important;\r\n}\r\n\r\na.scroll-left:hover, a.scroll-right:hover {\r\n background-position: 0 -18px;\r\n}\r\n\r\ntd.scroll-right-container {\r\n width: 20px;\r\n}\r\n\r\ntd.scroll-right-container.disabled, td.scroll-right-container.disabled * {\r\n width: 0px;\r\n margin: 0px;\r\n}\r\n\r\ntd.scroll-right-container.disabled br {\r\n display: none;\r\n}\r\n\r\n/* Toolbar */\r\n\r\n.toolbar {\r\n font-size: 8pt;\r\n border: 1px solid #000000;\r\n border-width: 0px 1px 1px 1px;\r\n background-color: @@ToolbarBgColor@@;\r\n border-collapse: collapse;\r\n}\r\n\r\n.toolbar td {\r\n height: 100%;\r\n}\r\n\r\n.toolbar-button, .toolbar-button-disabled, .toolbar-button-over {\r\n float: left;\r\n text-align: center;\r\n font-size: 8pt;\r\n padding: 5px 5px 5px 5px;\r\n vertical-align: middle;\r\n color: #006F99;\r\n}\r\n\r\n.toolbar-button-over {\r\n color: #000;\r\n}\r\n\r\n.toolbar-button-disabled {\r\n color: #444;\r\n}\r\n\r\n/* Scrollable Grids */\r\n\r\n\r\n.layout-only-table td {\r\n border: none !important;\r\n}\r\n\r\n/* Main Grid class */\r\n.grid-scrollable {\r\n padding: 0px;\r\n border: 1px solid black !important;\r\n border-top: none !important;\r\n}\r\n\r\n/* Div generated by js, which contains all the scrollable grid elements, affects the style of scrollable area without data (if there are too few rows) */\r\n.grid-container {\r\n background-color: #fff;\r\n}\r\n\r\n.grid-container table {\r\n border-collapse: collapse;\r\n}\r\n\r\n/* Inner div generated in each data-cell */\r\n.grid-cell-div {\r\n overflow: hidden;\r\n height: auto;\r\n}\r\n\r\n/* Main row definition */\r\n.grid-data-row td, .grid-data-row-selected td, .grid-data-row-even-selected td, .grid-data-row-mouseover td, .table-color1, .table-color2, .grid-edit-table .edit-form-odd > td, .grid-edit-table .edit-form-even > td {\r\n font-weight: normal;\r\n color: @@OddColor@@;\r\n background-color: @@OddBgColor@@;\r\n padding: 3px 5px 3px 5px;\r\n overflow: hidden;\r\n border-right: 1px solid #c9c9c9;\r\n}\r\n.grid-data-row-even td, .table-color2, .grid-edit-table .edit-form-even > td {\r\n background-color: @@EvenBgColor@@;\r\n color: @@EvenColor@@;\r\n}\r\n.grid-data-row td a, .grid-data-row-selected td a, .grid-data-row-mouseover td a {\r\n text-decoration: underline;\r\n}\r\n\r\n/* mouse-over rows */\r\n.grid-data-row-mouseover td, table tr.grid-data-row[_row_highlighted] td {\r\n background: #FFFDF4;\r\n}\r\n\r\n/* Selected row, applies to both checkbox and data areas */\r\n.grid-data-row-selected td, table tr.grid-data-row[_row_selected] td {\r\n background: #FEF2D6;\r\n}\r\n\r\n.grid-data-row-even-selected td, .grid-data-row-even[_row_selected] td {\r\n background: #FFF7E0;\r\n}\r\n\r\n/* General header cell definition */\r\n.grid-header-row td {\r\n font-weight: bold;\r\n background-color: @@ColumnTitlesBgColor@@;\r\n text-decoration: none;\r\n padding: 3px 5px 3px 5px;\r\n color: @@ColumnTitlesColor@@;\r\n border-right: none;\r\n text-align: left;\r\n vertical-align: middle !important;\r\n white-space: nowrap;\r\n border-right: 1px solid #777;\r\n}\r\n\r\n/* Filters row */\r\ntr.grid-header-row-1 td {\r\n background-color: @@FiltersBgColor@@;\r\n border-bottom: 1px solid black;\r\n}\r\n\r\n/* Grid Filters */\r\ntable.range-filter {\r\n width: 100%;\r\n}\r\n\r\n.range-filter td {\r\n padding: 0px 0px 2px 2px !important;\r\n border: none !important;\r\n font-size: 8pt !important;\r\n font-weight: normal !important;\r\n text-align: left;\r\n color: #000000 !important;\r\n}\r\n\r\ninput.filter, select.filter, input.filter-active, select.filter-active {\r\n margin-bottom: 0px;\r\n border: 1px solid #aaa;\r\n}\r\n\r\ninput.filter-active {\r\n background-color: #FFFF00;\r\n}\r\n\r\nselect.filter-active {\r\n background-color: #FFFF00;\r\n}\r\n\r\ndiv.filter, div.filter-active {\r\n background-color: white;\r\n border: 1px solid #AAAAAA;\r\n color: black;\r\n font-weight: normal;\r\n padding: 3px;\r\n}\r\n\r\ndiv.filter-active {\r\n background-color: #FFFF00;\r\n}\r\n\r\ndiv.multioptions_filter {\r\n position: absolute;\r\n z-index: 100;\r\n color: black;\r\n background-color: white;\r\n border: 1px solid black;\r\n padding: 3px 5px;\r\n display: none;\r\n vertical-align: middle;\r\n}\r\n\r\n/* Column titles row */\r\ntr.grid-header-row-0 td {\r\n height: 25px;\r\n font-weight: bold;\r\n background-color: @@ColumnTitlesBgColor@@;\r\n color: @@ColumnTitlesColor@@;\r\n border-bottom: 1px solid black;\r\n}\r\n\r\ntr.grid-header-row-0 td a {\r\n color: @@ColumnTitlesColor@@;\r\n}\r\n\r\ntr.grid-header-row-0 td a:hover {\r\n color: #FFCC00;\r\n}\r\n\r\n\r\n.grid-footer-row td {\r\n background-color: #D7D7D7;\r\n font-weight: bold;\r\n border-right: 1px solid #C9C9C9;\r\n padding: 3px 5px 3px 5px;\r\n}\r\n\r\ntd.grid-header-last-cell, td.grid-data-last-cell, td.grid-footer-last-cell {\r\n border-right: none !important;\r\n}\r\n\r\ntd.grid-data-col-0, td.grid-data-col-0 div {\r\n text-align: center;\r\n vertical-align: middle !important;\r\n}\r\n\r\ntr.grid-header-row-1 td.grid-header-col-1 {\r\n text-align: center;\r\n vertical-align: middle !important;\r\n}\r\n\r\ntr.grid-header-row-1 td.grid-header-col-1 div {\r\n display: table-cell;\r\n vertical-align: middle;\r\n}\r\n\r\n.grid-status-bar {\r\n border: 1px solid black;\r\n border-top: none;\r\n padding: 0px;\r\n width: 100%;\r\n border-collapse: collapse;\r\n height: 30px;\r\n}\r\n\r\n.grid-status-bar td {\r\n background-color: @@TitleBarBgColor@@;\r\n color: @@TitleBarColor@@;\r\n font-size: 11pt;\r\n font-weight: normal;\r\n padding: 2px 8px 2px 8px;\r\n}\r\n\r\n/* /Scrollable Grids */\r\n\r\n\r\n/* Forms */\r\ntable.edit-form {\r\n border: none;\r\n border-top-width: 0px !important;\r\n border-collapse: collapse;\r\n width: 100%;\r\n}\r\n\r\n.edit-form-odd, .edit-form-even {\r\n padding: 0px;\r\n}\r\n\r\n.subsectiontitle {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n background-color: #4A92CE;\r\n color: #fff;\r\n height: 25px;\r\n border-top: 1px solid black;\r\n vertical-align: middle;\r\n}\r\n\r\n/* remove top-border from first sub-section element */\r\ntable.edit-form .subsectiontitle:first-child, table.bordered .subsectiontitle:first-child {\r\n border-top-width: 0;\r\n}\r\n\r\n.subsectiontitle td {\r\n vertical-align: middle;\r\n /*padding: 3px 5px 3px 5px;*/\r\n padding: 1px 5px;\r\n}\r\n\r\n.label-cell {\r\n background: #DEE7F6 url(\'@@base_url@@/core/admin_templates/img/bgr_input_name_line.gif\') no-repeat right bottom;\r\n font: 12px arial, sans-serif;\r\n padding: 4px 20px;\r\n width: 160px;\r\n}\r\n\r\n.control-mid {\r\n width: 13px;\r\n border-left: 1px solid #7A95C2;\r\n background: #fff url(\'@@base_url@@/core/admin_templates/img/bgr_mid.gif\') repeat-x left bottom;\r\n}\r\n\r\n.control-cell {\r\n font: 11px arial, sans-serif;\r\n padding: 4px 10px 5px 5px;\r\n background: #fff url(\'@@base_url@@/core/admin_templates/img/bgr_input_line.gif\') no-repeat left bottom;\r\n width: auto;\r\n vertical-align: middle;\r\n}\r\n\r\n.CodeMirror {\r\n font-size: 13px;\r\n border: 1px solid black;\r\n}\r\n\r\n.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}\r\n.CodeMirror-activeline-background {background: #e8f2ff !important;}\r\n\r\n.label-cell-filler {\r\n background: #DEE7F6 none;\r\n}\r\n.control-mid-filler {\r\n background: #fff none;\r\n border-left: 1px solid #7A95C2;\r\n}\r\n.control-cell-filler {\r\n background: #fff none;\r\n}\r\n\r\n.highlight-area, .code-highlight-area {\r\n border: 1px solid black;\r\n padding: 8px;\r\n font-family: monospace !important;\r\n font-size: 12px;\r\n overflow: auto;\r\n}\r\n\r\n.code-highlight-area {\r\n background-color: #F6F6F6;\r\n}\r\n\r\n.error {\r\n color: red;\r\n}\r\n.error-cell {\r\n color: red;\r\n}\r\n\r\n.field-required {\r\n color: red;\r\n}\r\n\r\n.warning-table {\r\n background-color: #F0F1EB;\r\n border: 1px solid #000000;\r\n border-collapse: collapse;\r\n border-top-width: 0px;\r\n}\r\n\r\n.form-notice, .form-warning {\r\n font-size: 11px;\r\n}\r\n\r\n.form-warning {\r\n color: red;\r\n}\r\n\r\n.form-notice {\r\n color: green;\r\n}\r\n\r\n.priority {\r\n color: red;\r\n padding-left: 1px;\r\n padding-right: 1px;\r\n font-size: 11px;\r\n}\r\n\r\n.small-statistics {\r\n font-size: 11px;\r\n color: #707070;\r\n}\r\n\r\n.req-note {\r\n font-style: italic;\r\n color: #333;\r\n}\r\n\r\n#scroll_container table.tableborder {\r\n border-collapse: separate\r\n}\r\n\r\nlabel.checkbox {\r\n white-space: nowrap;\r\n}\r\n\r\n/* Uploader */\r\n.uploader-queue div.file {\r\n font-size: 11px;\r\n border: 1px solid #7F99C5;\r\n padding: 3px;\r\n background-color: #DEE7F6;\r\n margin-bottom: 2px;\r\n}\r\n\r\n.uploader-queue .left {\r\n float: left;\r\n vertical-align: top;\r\n}\r\n\r\n.uploader-queue .file-label {\r\n margin-left: 5px;\r\n}\r\n\r\n.uploader-queue .preview .delete-checkbox {\r\n margin-top: -3px;\r\n}\r\n\r\n.uploader-queue .progress-container {\r\n margin: 2px 5px 0px 5px;\r\n}\r\n\r\n.uploader-queue .progress-empty {\r\n width: 150px;\r\n height: 9px;\r\n border: 1px solid black;\r\n background: url(\'@@base_url@@/core/admin_templates/img/progress_left.gif\') repeat-x;\r\n}\r\n\r\n.uploader-queue .progress-full {\r\n height: 9px;\r\n background: url(\'@@base_url@@/core/admin_templates/img/progress_done.gif\');\r\n}\r\n\r\n.uploader-queue .thumbnail {\r\n /*margin-bottom: 2px;*/\r\n border: 1px solid black;\r\n background-color: grey;\r\n}\r\n\r\n/* To be sorted */\r\nspan#category_path, span#category_path a {\r\n color: #FFFFFF;\r\n}\r\n\r\nspan#category_path a {\r\n text-decoration: underline;\r\n}\r\n\r\n/* Section title, right to the big icon */\r\n.admintitle {\r\n font-size: 16pt;\r\n font-weight: bold;\r\n color: @@SectionColor@@;\r\n text-decoration: none;\r\n}\r\n\r\n/* Page header (bluebar) */\r\n.page-title td {\r\n background-color: @@TitleBarBgColor@@;\r\n color: @@TitleBarColor@@;\r\n font-size: 11pt;\r\n font-weight: normal;\r\n padding: 2px 8px 2px 8px;\r\n}\r\n\r\n/* Right side of bluebar */\r\n.tablenav, tablenav a {\r\n font-size: 11pt;\r\n font-weight: bold;\r\n color: @@TitleBarColor@@;\r\n\r\n text-decoration: none;\r\n background-color: @@TitleBarBgColor@@;\r\n background-image: none;\r\n}\r\n\r\n/* Section title in the bluebar * -- why \'link\'? :S */\r\n.tablenav_link {\r\n font-size: 11pt;\r\n font-weight: bold;\r\n color: @@TitleBarColor@@;\r\n text-decoration: none;\r\n}\r\n\r\n/* Active page in top and bottom bluebars pagination */\r\n.current_page {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n background-color: #fff;\r\n color: #2D79D6;\r\n padding: 3px 2px 3px 3px;\r\n}\r\n\r\n/* Other pages and arrows in pagination on blue */\r\n.nav_url {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n color: #fff;\r\n padding: 3px 2px 3px 3px;\r\n}\r\n\r\n/* Tree */\r\n.tree-body {\r\n background-color: @@TreeBgColor@@;\r\n height: 100%\r\n}\r\n\r\n.tree_head.td, .tree_head, .tree_head:hover {\r\n font-weight: bold;\r\n font-size: 10px;\r\n color: #FFFFFF;\r\n font-family: Verdana, Arial;\r\n text-decoration: none;\r\n}\r\n\r\n.tree {\r\n padding: 0px;\r\n border: none;\r\n border-collapse: collapse;\r\n}\r\n\r\n.tree tr td {\r\n padding: 0px;\r\n margin: 0px;\r\n font-family: helvetica, arial, verdana,;\r\n font-size: 11px;\r\n white-space: nowrap;\r\n}\r\n\r\n.tree tr td a {\r\n font-size: 11px;\r\n color: @@TreeColor@@;\r\n font-family: Helvetica, Arial, Verdana;\r\n text-decoration: none;\r\n padding: 2px;\r\n}\r\n\r\n.tree tr td a:hover, .tree tr td a.debug-only-item:hover {\r\n color: @@TreeHoverColor@@;\r\n}\r\n\r\n.tree tr.highlighted td a, .tree tr.highlighted td a.debug-only-item {\r\n color: @@TreeHighColor@@;\r\n background-color: @@TreeHighBgColor@@;\r\n}\r\n\r\n.tree tr.highlighted td a:hover {\r\n color: @@TreeHighHoverColor@@;\r\n}\r\n\r\n.tree tr td a.debug-only-item {\r\n color: grey;\r\n}\r\n\r\n/* Ajax Dropdown */\r\n.suggest-box {\r\n border: 1px solid #999;\r\n background-color: #fff;\r\n}\r\n\r\n.suggest-item, .suggest-item-over {\r\n padding: 1px 2px 0px 2px;\r\n font-family: arial,verdana;\r\n font-size: 12px;\r\n}\r\n\r\n.suggest-item-over {\r\n background-color: #3366CC;\r\n color: #fff;\r\n}\r\n\r\n/* Dashboard Summary Boxes */\r\n.summary-box {\r\n border: 1px solid black;\r\n margin-bottom: 4px;\r\n}\r\n\r\n.summary-box .title {\r\n color: white;\r\n font-weight: bold;\r\n padding: 6px 5px;\r\n vertical-align: middle;\r\n background-color: #4A92CE;\r\n border-bottom: 1px solid black;\r\n}\r\n\r\n.summary-box .content {\r\n padding: 4px;\r\n background-color: #F6F6F6;\r\n}\r\n\r\n.summary-box .group {\r\n border-bottom: 1px solid black;\r\n margin-bottom: 10px;\r\n padding: 0 0 10px 10px;\r\n}\r\n\r\n.summary-box .group.last {\r\n border-width: 0px;\r\n margin-bottom: 0;\r\n padding-bottom: 5px;\r\n}\r\n\r\n.summary-box h4 {\r\n margin: 0;\r\n padding: 0 0 3px 0;\r\n font-size: 11px;\r\n font-weight: bold;\r\n}\r\n\r\n.summary-box .hint {\r\n font-size: 10px;\r\n color: grey;\r\n margin-bottom: 3px;\r\n}\r\n\r\n.summary-box .hint .cache-key {\r\n margin-bottom: 7px;\r\n margin-left: 3px;\r\n}\r\n\r\n.summary-box ul {\r\n margin-top: 5px;\r\n margin-bottom: 3px;\r\n padding-left: 30px;\r\n}\r\n\r\n.summary-box li {\r\n padding-bottom: 4px;\r\n}\r\n\r\nspan.cke_skin_kama {\r\n border-width: 0px !important;\r\n -moz-border-radius: 0px !important;\r\n -webkit-border-radius: 0px !important;\r\n padding: 0px !important;\r\n}\r\n\r\n.cke_wrapper{\r\n border-width: 0px !important;\r\n -moz-border-radius: 0px !important;\r\n -webkit-border-radius: 0px !important;\r\n}\r\n\r\n/* Inline CKEditor styles dropdown enlargement */\r\ndiv.cke_combopanel__styles {\r\n width: 200px;\r\n height: 300px;\r\n}\r\n', 'in-portal_logo_img.jpg', 'in-portal_logo_img2.jpg', 'in-portal_logo_login.gif', 'a:22:{s:11:"HeadBgColor";a:2:{s:11:"Description";s:27:"Head frame background color";s:5:"Value";s:7:"#007BF4";}s:9:"HeadColor";a:2:{s:11:"Description";s:21:"Head frame text color";s:5:"Value";s:7:"#FFFFFF";}s:14:"SectionBgColor";a:2:{s:11:"Description";s:28:"Section bar background color";s:5:"Value";s:7:"#FFFFFF";}s:12:"SectionColor";a:2:{s:11:"Description";s:22:"Section bar text color";s:5:"Value";s:7:"#2D79D6";}s:12:"HeadBarColor";a:1:{s:5:"Value";s:7:"#000000";}s:14:"HeadBarBgColor";a:1:{s:5:"Value";s:7:"#1961B8";}s:13:"TitleBarColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:15:"TitleBarBgColor";a:1:{s:5:"Value";s:7:"#2D79D6";}s:14:"ToolbarBgColor";a:1:{s:5:"Value";s:7:"#F0F1EB";}s:14:"FiltersBgColor";a:1:{s:5:"Value";s:7:"#D7D7D7";}s:17:"ColumnTitlesColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:19:"ColumnTitlesBgColor";a:1:{s:5:"Value";s:7:"#999999";}s:8:"OddColor";a:1:{s:5:"Value";s:7:"#000000";}s:10:"OddBgColor";a:1:{s:5:"Value";s:7:"#F6F6F6";}s:9:"EvenColor";a:1:{s:5:"Value";s:7:"#000000";}s:11:"EvenBgColor";a:1:{s:5:"Value";s:7:"#EBEBEB";}s:9:"TreeColor";a:1:{s:5:"Value";s:7:"#000000";}s:14:"TreeHoverColor";a:1:{s:5:"Value";s:7:"#009FF0";}s:13:"TreeHighColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:18:"TreeHighHoverColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:15:"TreeHighBgColor";a:1:{s:5:"Value";s:7:"#4A92CE";}s:11:"TreeBgColor";a:1:{s:5:"Value";s:7:"#DCECF6";}}', 1501273509, 1, 1); INSERT INTO LocalesList VALUES (1, '0x0436', 'Afrikaans (South Africa)', 'af-ZA', 'Latn', '1252'), (2, '0x041c', 'Albanian (Albania)', 'sq-AL', 'Latn', '1252'), (3, '0x0484', 'Alsatian (France)', 'gsw-FR', '', ''), (4, '0x045e', 'Amharic (Ethiopia)', 'am-ET', '', 'UTF-8'), (5, '0x1401', 'Arabic (Algeria)', 'ar-DZ', 'Arab', '1256'), (6, '0x3c01', 'Arabic (Bahrain)', 'ar-BH', 'Arab', '1256'), (7, '0x0c01', 'Arabic (Egypt)', 'ar-EG', 'Arab', '1256'), (8, '0x0801', 'Arabic (Iraq)', 'ar-IQ', 'Arab', '1256'), (9, '0x2c01', 'Arabic (Jordan)', 'ar-JO', 'Arab', '1256'), (10, '0x3401', 'Arabic (Kuwait)', 'ar-KW', 'Arab', '1256'), (11, '0x3001', 'Arabic (Lebanon)', 'ar-LB', 'Arab', '1256'), (12, '0x1001', 'Arabic (Libya)', 'ar-LY', 'Arab', '1256'), (13, '0x1801', 'Arabic (Morocco)', 'ar-MA', 'Arab', '1256'), (14, '0x2001', 'Arabic (Oman)', 'ar-OM', 'Arab', '1256'), (15, '0x4001', 'Arabic (Qatar)', 'ar-QA', 'Arab', '1256'), (16, '0x0401', 'Arabic (Saudi Arabia)', 'ar-SA', 'Arab', '1256'), (17, '0x2801', 'Arabic (Syria)', 'ar-SY', 'Arab', '1256'), (18, '0x1c01', 'Arabic (Tunisia)', 'ar-TN', 'Arab', '1256'), (19, '0x3801', 'Arabic (U.A.E.)', 'ar-AE', 'Arab', '1256'), (20, '0x2401', 'Arabic (Yemen)', 'ar-YE', 'Arab', '1256'), (21, '0x042b', 'Armenian (Armenia)', 'hy-AM', 'Armn', 'UTF-8'), (22, '0x044d', 'Assamese (India)', 'as-IN', '', 'UTF-8'), (23, '0x082c', 'Azeri (Azerbaijan, Cyrillic)', 'az-Cyrl-AZ', 'Cyrl', '1251'), (24, '0x042c', 'Azeri (Azerbaijan, Latin)', 'az-Latn-AZ', 'Latn', '1254'), (25, '0x046d', 'Bashkir (Russia)', 'ba-RU', '', ''), (26, '0x042d', 'Basque (Basque)', 'eu-ES', 'Latn', '1252'), (27, '0x0423', 'Belarusian (Belarus)', 'be-BY', 'Cyrl', '1251'), (28, '0x0445', 'Bengali (India)', 'bn-IN', 'Beng', 'UTF-8'), (29, '0x201a', 'Bosnian (Bosnia and Herzegovina, Cyrillic)', 'bs-Cyrl-BA', 'Cyrl', '1251'), (30, '0x141a', 'Bosnian (Bosnia and Herzegovina, Latin)', 'bs-Latn-BA', 'Latn', '1250'), (31, '0x047e', 'Breton (France)', 'br-FR', 'Latn', '1252'), (32, '0x0402', 'Bulgarian (Bulgaria)', 'bg-BG', 'Cyrl', '1251'), (33, '0x0403', 'Catalan (Catalan)', 'ca-ES', 'Latn', '1252'), (34, '0x0c04', 'Chinese (Hong Kong SAR, PRC)', 'zh-HK', 'Hant', '950'), (35, '0x1404', 'Chinese (Macao SAR)', 'zh-MO', 'Hant', '950'), (36, '0x0804', 'Chinese (PRC)', 'zh-CN', 'Hans', '936'), (37, '0x1004', 'Chinese (Singapore)', 'zh-SG', 'Hans', '936'), (38, '0x0404', 'Chinese (Taiwan)', 'zh-TW', 'Hant', '950'), (39, '0x101a', 'Croatian (Bosnia and Herzegovina, Latin)', 'hr-BA', 'Latn', '1250'), (40, '0x041a', 'Croatian (Croatia)', 'hr-HR', 'Latn', '1250'), (41, '0x0405', 'Czech (Czech Republic)', 'cs-CZ', 'Latn', '1250'), (42, '0x0406', 'Danish (Denmark)', 'da-DK', 'Latn', '1252'), (43, '0x048c', 'Dari (Afghanistan)', 'prs-AF', 'Arab', '1256'), (44, '0x0465', 'Divehi (Maldives)', 'dv-MV', 'Thaa', 'UTF-8'), (45, '0x0813', 'Dutch (Belgium)', 'nl-BE', 'Latn', '1252'), (46, '0x0413', 'Dutch (Netherlands)', 'nl-NL', 'Latn', '1252'), (47, '0x0c09', 'English (Australia)', 'en-AU', 'Latn', '1252'), (48, '0x2809', 'English (Belize)', 'en-BZ', 'Latn', '1252'), (49, '0x1009', 'English (Canada)', 'en-CA', 'Latn', '1252'), (50, '0x2409', 'English (Caribbean)', 'en-029', 'Latn', '1252'), (51, '0x4009', 'English (India)', 'en-IN', 'Latn', '1252'), (52, '0x1809', 'English (Ireland)', 'en-IE', 'Latn', '1252'), (53, '0x2009', 'English (Jamaica)', 'en-JM', 'Latn', '1252'), (54, '0x4409', 'English (Malaysia)', 'en-MY', 'Latn', '1252'), (55, '0x1409', 'English (New Zealand)', 'en-NZ', 'Latn', '1252'), (56, '0x3409', 'English (Philippines)', 'en-PH', 'Latn', '1252'), (57, '0x4809', 'English (Singapore)', 'en-SG', 'Latn', '1252'), (58, '0x1c09', 'English (South Africa)', 'en-ZA', 'Latn', '1252'), (59, '0x2c09', 'English (Trinidad and Tobago)', 'en-TT', 'Latn', '1252'), (60, '0x0809', 'English (United Kingdom)', 'en-GB', 'Latn', '1252'), (61, '0x0409', 'English (United States)', 'en-US', 'Latn', '1252'), (62, '0x3009', 'English (Zimbabwe)', 'en-ZW', 'Latn', '1252'), (63, '0x0425', 'Estonian (Estonia)', 'et-EE', 'Latn', '1257'), (64, '0x0438', 'Faroese (Faroe Islands)', 'fo-FO', 'Latn', '1252'), (65, '0x0464', 'Filipino (Philippines)', 'fil-PH', 'Latn', '1252'), (66, '0x040b', 'Finnish (Finland)', 'fi-FI', 'Latn', '1252'), (67, '0x080c', 'French (Belgium)', 'fr-BE', 'Latn', '1252'), (68, '0x0c0c', 'French (Canada)', 'fr-CA', 'Latn', '1252'), (69, '0x040c', 'French (France)', 'fr-FR', 'Latn', '1252'), (70, '0x140c', 'French (Luxembourg)', 'fr-LU', 'Latn', '1252'), (71, '0x180c', 'French (Monaco)', 'fr-MC', 'Latn', '1252'), (72, '0x100c', 'French (Switzerland)', 'fr-CH', 'Latn', '1252'), (73, '0x0462', 'Frisian (Netherlands)', 'fy-NL', 'Latn', '1252'), (74, '0x0456', 'Galician (Spain)', 'gl-ES', 'Latn', '1252'), (75, '0x0437', 'Georgian (Georgia)', 'ka-GE', 'Geor', 'UTF-8'), (76, '0x0c07', 'German (Austria)', 'de-AT', 'Latn', '1252'), (77, '0x0407', 'German (Germany)', 'de-DE', 'Latn', '1252'), (78, '0x1407', 'German (Liechtenstein)', 'de-LI', 'Latn', '1252'), (79, '0x1007', 'German (Luxembourg)', 'de-LU', 'Latn', '1252'), (80, '0x0807', 'German (Switzerland)', 'de-CH', 'Latn', '1252'), (81, '0x0408', 'Greek (Greece)', 'el-GR', 'Grek', '1253'), (82, '0x046f', 'Greenlandic (Greenland)', 'kl-GL', 'Latn', '1252'), (83, '0x0447', 'Gujarati (India)', 'gu-IN', 'Gujr', 'UTF-8'), (84, '0x0468', 'Hausa (Nigeria, Latin)', 'ha-Latn-NG', 'Latn', '1252'), (85, '0x040d', 'Hebrew (Israel)', 'he-IL', 'Hebr', '1255'), (86, '0x0439', 'Hindi (India)', 'hi-IN', 'Deva', 'UTF-8'), (87, '0x040e', 'Hungarian (Hungary)', 'hu-HU', 'Latn', '1250'), (88, '0x040f', 'Icelandic (Iceland)', 'is-IS', 'Latn', '1252'), (89, '0x0470', 'Igbo (Nigeria)', 'ig-NG', '', ''), (90, '0x0421', 'Indonesian (Indonesia)', 'id-ID', 'Latn', '1252'), (91, '0x085d', 'Inuktitut (Canada, Latin)', 'iu-Latn-CA', 'Latn', '1252'), (92, '0x045d', 'Inuktitut (Canada, Syllabics)', 'iu-Cans-CA', 'Cans', 'UTF-8'), (93, '0x083c', 'Irish (Ireland)', 'ga-IE', 'Latn', '1252'), (94, '0x0410', 'Italian (Italy)', 'it-IT', 'Latn', '1252'), (95, '0x0810', 'Italian (Switzerland)', 'it-CH', 'Latn', '1252'), (96, '0x0411', 'Japanese (Japan)', 'ja-JP', 'Hani;Hira;Kana', '932'), (97, '0x044b', 'Kannada (India)', 'kn-IN', 'Knda', 'UTF-8'), (98, '0x043f', 'Kazakh (Kazakhstan)', 'kk-KZ', 'Cyrl', '1251'), (99, '0x0453', 'Khmer (Cambodia)', 'kh-KH', 'Khmr', 'UTF-8'), (100, '0x0486', 'K''iche (Guatemala)', 'qut-GT', 'Latn', '1252'), (101, '0x0487', 'Kinyarwanda (Rwanda)', 'rw-RW', 'Latn', '1252'), (102, '0x0457', 'Konkani (India)', 'kok-IN', 'Deva', 'UTF-8'), (103, '0x0812', 'Windows 95, Windows NT 4.0 only: Korean (Johab)', '', '', ''), (104, '0x0412', 'Korean (Korea)', 'ko-KR', 'Hang;Hani', '949'), (105, '0x0440', 'Kyrgyz (Kyrgyzstan)', 'ky-KG', 'Cyrl', '1251'), (106, '0x0454', 'Lao (Lao PDR)', 'lo-LA', 'Laoo', 'UTF-8'), (107, '0x0426', 'Latvian (Latvia)', 'lv-LV', 'Latn', '1257'), (108, '0x0427', 'Lithuanian (Lithuania)', 'lt-LT', 'Latn', '1257'), (109, '0x082e', 'Lower Sorbian (Germany)', 'dsb-DE', 'Latn', '1252'), (110, '0x046e', 'Luxembourgish (Luxembourg)', 'lb-LU', 'Latn', '1252'), (111, '0x042f', 'Macedonian (Macedonia, FYROM)', 'mk-MK', 'Cyrl', '1251'), (112, '0x083e', 'Malay (Brunei Darussalam)', 'ms-BN', 'Latn', '1252'), (113, '0x043e', 'Malay (Malaysia)', 'ms-MY', 'Latn', '1252'), (114, '0x044c', 'Malayalam (India)', 'ml-IN', 'Mlym', 'UTF-8'), (115, '0x043a', 'Maltese (Malta)', 'mt-MT', 'Latn', '1252'), (116, '0x0481', 'Maori (New Zealand)', 'mi-NZ', 'Latn', '1252'), (117, '0x047a', 'Mapudungun (Chile)', 'arn-CL', 'Latn', '1252'), (118, '0x044e', 'Marathi (India)', 'mr-IN', 'Deva', 'UTF-8'), (119, '0x047c', 'Mohawk (Canada)', 'moh-CA', 'Latn', '1252'), (120, '0x0450', 'Mongolian (Mongolia)', 'mn-Cyrl-MN', 'Cyrl', '1251'), (121, '0x0850', 'Mongolian (PRC)', 'mn-Mong-CN', 'Mong', 'UTF-8'), (122, '0x0850', 'Nepali (India)', 'ne-IN', '__', 'UTF-8'), (123, '0x0461', 'Nepali (Nepal)', 'ne-NP', 'Deva', 'UTF-8'), (124, '0x0414', 'Norwegian (Bokmål, Norway)', 'nb-NO', 'Latn', '1252'), (125, '0x0814', 'Norwegian (Nynorsk, Norway)', 'nn-NO', 'Latn', '1252'), (126, '0x0482', 'Occitan (France)', 'oc-FR', 'Latn', '1252'), (127, '0x0448', 'Oriya (India)', 'or-IN', 'Orya', 'UTF-8'), (128, '0x0463', 'Pashto (Afghanistan)', 'ps-AF', '', ''), (129, '0x0429', 'Persian (Iran)', 'fa-IR', 'Arab', '1256'), (130, '0x0415', 'Polish (Poland)', 'pl-PL', 'Latn', '1250'), (131, '0x0416', 'Portuguese (Brazil)', 'pt-BR', 'Latn', '1252'), (132, '0x0816', 'Portuguese (Portugal)', 'pt-PT', 'Latn', '1252'), (133, '0x0446', 'Punjabi (India)', 'pa-IN', 'Guru', 'UTF-8'), (134, '0x046b', 'Quechua (Bolivia)', 'quz-BO', 'Latn', '1252'), (135, '0x086b', 'Quechua (Ecuador)', 'quz-EC', 'Latn', '1252'), (136, '0x0c6b', 'Quechua (Peru)', 'quz-PE', 'Latn', '1252'), (137, '0x0418', 'Romanian (Romania)', 'ro-RO', 'Latn', '1250'), (138, '0x0417', 'Romansh (Switzerland)', 'rm-CH', 'Latn', '1252'), (139, '0x0419', 'Russian (Russia)', 'ru-RU', 'Cyrl', '1251'), (140, '0x243b', 'Sami (Inari, Finland)', 'smn-FI', 'Latn', '1252'), (141, '0x103b', 'Sami (Lule, Norway)', 'smj-NO', 'Latn', '1252'), (142, '0x143b', 'Sami (Lule, Sweden)', 'smj-SE', 'Latn', '1252'), (143, '0x0c3b', 'Sami (Northern, Finland)', 'se-FI', 'Latn', '1252'), (144, '0x043b', 'Sami (Northern, Norway)', 'se-NO', 'Latn', '1252'), (145, '0x083b', 'Sami (Northern, Sweden)', 'se-SE', 'Latn', '1252'), (146, '0x203b', 'Sami (Skolt, Finland)', 'sms-FI', 'Latn', '1252'), (147, '0x183b', 'Sami (Southern, Norway)', 'sma-NO', 'Latn', '1252'), (148, '0x1c3b', 'Sami (Southern, Sweden)', 'sma-SE', 'Latn', '1252'), (149, '0x044f', 'Sanskrit (India)', 'sa-IN', 'Deva', 'UTF-8'), (150, '0x1c1a', 'Serbian (Bosnia and Herzegovina, Cyrillic)', 'sr-Cyrl-BA', 'Cyrl', '1251'), (151, '0x181a', 'Serbian (Bosnia and Herzegovina, Latin)', 'sr-Latn-BA', 'Latn', '1250'), (152, '0x0c1a', 'Serbian (Serbia, Cyrillic)', 'sr-Cyrl-CS', 'Cyrl', '1251'), (153, '0x081a', 'Serbian (Serbia, Latin)', 'sr-Latn-CS', 'Latn', '1250'), (154, '0x046c', 'Sesotho sa Leboa/Northern Sotho (South Africa)', 'ns-ZA', 'Latn', '1252'), (155, '0x0432', 'Setswana/Tswana (South Africa)', 'tn-ZA', 'Latn', '1252'), (156, '0x045b', 'Sinhala (Sri Lanka)', 'si-LK', 'Sinh', 'UTF-8'), (157, '0x041b', 'Slovak (Slovakia)', 'sk-SK', 'Latn', '1250'), (158, '0x0424', 'Slovenian (Slovenia)', 'sl-SI', 'Latn', '1250'), (159, '0x2c0a', 'Spanish (Argentina)', 'es-AR', 'Latn', '1252'), (160, '0x400a', 'Spanish (Bolivia)', 'es-BO', 'Latn', '1252'), (161, '0x340a', 'Spanish (Chile)', 'es-CL', 'Latn', '1252'), (162, '0x240a', 'Spanish (Colombia)', 'es-CO', 'Latn', '1252'), (163, '0x140a', 'Spanish (Costa Rica)', 'es-CR', 'Latn', '1252'), (164, '0x1c0a', 'Spanish (Dominican Republic)', 'es-DO', 'Latn', '1252'), (165, '0x300a', 'Spanish (Ecuador)', 'es-EC', 'Latn', '1252'), (166, '0x440a', 'Spanish (El Salvador)', 'es-SV', 'Latn', '1252'), (167, '0x100a', 'Spanish (Guatemala)', 'es-GT', 'Latn', '1252'), (168, '0x480a', 'Spanish (Honduras)', 'es-HN', 'Latn', '1252'), (169, '0x080a', 'Spanish (Mexico)', 'es-MX', 'Latn', '1252'), (170, '0x4c0a', 'Spanish (Nicaragua)', 'es-NI', 'Latn', '1252'), (171, '0x180a', 'Spanish (Panama)', 'es-PA', 'Latn', '1252'), (172, '0x3c0a', 'Spanish (Paraguay)', 'es-PY', 'Latn', '1252'), (173, '0x280a', 'Spanish (Peru)', 'es-PE', 'Latn', '1252'), (174, '0x500a', 'Spanish (Puerto Rico)', 'es-PR', 'Latn', '1252'), (175, '0x0c0a', 'Spanish (Spain)', 'es-ES', 'Latn', '1252'), (176, '0x040a', 'Spanish (Spain, Traditional Sort)', 'es-ES_tradnl', 'Latn', '1252'), (177, '0x540a', 'Spanish (United States)', 'es-US', '', ''), (178, '0x380a', 'Spanish (Uruguay)', 'es-UY', 'Latn', '1252'), (179, '0x200a', 'Spanish (Venezuela)', 'es-VE', 'Latn', '1252'), (180, '0x0441', 'Swahili (Kenya)', 'sw-KE', 'Latn', '1252'), (181, '0x081d', 'Swedish (Finland)', 'sv-FI', 'Latn', '1252'), (182, '0x041d', 'Swedish (Sweden)', 'sv-SE', 'Latn', '1252'), (183, '0x045a', 'Syriac (Syria)', 'syr-SY', 'Syrc', 'UTF-8'), (184, '0x0428', 'Tajik (Tajikistan)', 'tg-Cyrl-TJ', 'Cyrl', '1251'), (185, '0x085f', 'Tamazight (Algeria, Latin)', 'tzm-Latn-DZ', 'Latn', '1252'), (186, '0x0449', 'Tamil (India)', 'ta-IN', 'Taml', 'UTF-8'), (187, '0x0444', 'Tatar (Russia)', 'tt-RU', 'Cyrl', '1251'), (188, '0x044a', 'Telugu (India)', 'te-IN', 'Telu', 'UTF-8'), (189, '0x041e', 'Thai (Thailand)', 'th-TH', 'Thai', '874'), (190, '0x0851', 'Tibetan (Bhutan)', 'bo-BT', 'Tibt', 'UTF-8'), (191, '0x0451', 'Tibetan (PRC)', 'bo-CN', 'Tibt', 'UTF-8'), (192, '0x041f', 'Turkish (Turkey)', 'tr-TR', 'Latn', '1254'), (193, '0x0442', 'Turkmen (Turkmenistan)', 'tk-TM', 'Cyrl', '1251'), (194, '0x0480', 'Uighur (PRC)', 'ug-CN', 'Arab', '1256'), (195, '0x0422', 'Ukrainian (Ukraine)', 'uk-UA', 'Cyrl', '1251'), (196, '0x042e', 'Upper Sorbian (Germany)', 'wen-DE', 'Latn', '1252'), (197, '0x0820', 'Urdu (India)', 'tr-IN', '', ''), (198, '0x0420', 'Urdu (Pakistan)', 'ur-PK', 'Arab', '1256'), (199, '0x0843', 'Uzbek (Uzbekistan, Cyrillic)', 'uz-Cyrl-UZ', 'Cyrl', '1251'), (200, '0x0443', 'Uzbek (Uzbekistan, Latin)', 'uz-Latn-UZ', 'Latn', '1254'), (201, '0x042a', 'Vietnamese (Vietnam)', 'vi-VN', 'Latn', '1258'), (202, '0x0452', 'Welsh (United Kingdom)', 'cy-GB', 'Latn', '1252'), (203, '0x0488', 'Wolof (Senegal)', 'wo-SN', 'Latn', '1252'), (204, '0x0434', 'Xhosa/isiXhosa (South Africa)', 'xh-ZA', 'Latn', '1252'), (205, '0x0485', 'Yakut (Russia)', 'sah-RU', 'Cyrl', '1251'), (206, '0x0478', 'Yi (PRC)', 'ii-CN', 'Yiii', 'UTF-8'), (207, '0x046a', 'Yoruba (Nigeria)', 'yo-NG', '', ''), (208, '0x0435', 'Zulu/isiZulu (South Africa)', 'zu-ZA', 'Latn', '1252'); INSERT INTO SearchConfig VALUES ('Categories', 'NewItem', 0, 1, 'lu_fielddesc_category_newitem', 'lc_field_newitem', 'In-Portal', 'la_text_category', 18, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'PopItem', 0, 1, 'lu_fielddesc_category_popitem', 'lc_field_popitem', 'In-Portal', 'la_text_category', 19, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'HotItem', 0, 1, 'lu_fielddesc_category_hotitem', 'lc_field_hotitem', 'In-Portal', 'la_text_category', 17, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'MetaDescription', 0, 1, 'lu_fielddesc_category_metadescription', 'lc_field_MetaDescription', 'In-Portal', 'la_text_category', 16, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'ParentPath', 0, 1, 'lu_fielddesc_category_parentpath', 'lc_field_ParentPath', 'In-Portal', 'la_text_category', 15, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'ResourceId', 0, 1, 'lu_fielddesc_category_resourceid', 'lc_field_resourceid', 'In-Portal', 'la_text_category', 14, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'CreatedById', 0, 1, 'lu_fielddesc_category_createdbyid', 'lc_field_createdbyid', 'In-Portal', 'la_text_category', 13, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'CachedNavbar', 0, 1, 'lu_fielddesc_category_cachednavbar', 'lc_field_CachedNavBar', 'In-Portal', 'la_text_category', 12, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'CachedDescendantCatsQty', 0, 1, 'lu_fielddesc_category_cacheddescendantcatsqty', 'lc_field_CachedDescendantCatsQty', 'In-Portal', 'la_text_category', 11, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'MetaKeywords', 0, 1, 'lu_fielddesc_category_metakeywords', 'lc_field_MetaKeywords', 'In-Portal', 'la_text_category', 10, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'Priority', 0, 1, 'lu_fielddesc_category_priority', 'lc_field_priority', 'In-Portal', 'la_text_category', 9, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'Status', 0, 1, 'lu_fielddesc_category_status', 'lc_field_status', 'In-Portal', 'la_text_category', 7, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'EditorsPick', 0, 1, 'lu_fielddesc_category_editorspick', 'lc_field_EditorsPick', 'In-Portal', 'la_text_category', 6, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'CreatedOn', 0, 1, 'lu_fielddesc_category_createdon', 'lc_field_createdon', 'In-Portal', 'la_text_category', 5, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'Description', 1, 1, 'lu_fielddesc_category_description', 'lc_field_description', 'In-Portal', 'la_text_category', 4, DEFAULT, 2, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'Name', 1, 1, 'lu_fielddesc_category_name', 'lc_field_name', 'In-Portal', 'la_text_category', 3, DEFAULT, 2, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'ParentId', 0, 1, 'lu_fielddesc_category_parentid', 'lc_field_ParentId', 'In-Portal', 'la_text_category', 2, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'CategoryId', 0, 1, 'lu_fielddesc_category_categoryid', 'lc_field_CategoryId', 'In-Portal', 'la_text_category', 0, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'Modified', 0, 1, 'lu_fielddesc_category_modified', 'lc_field_modified', 'In-Portal', 'la_text_category', 20, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Categories', 'ModifiedById', 0, 1, 'lu_fielddesc_category_modifiedbyid', 'lc_field_modifiedbyid', 'In-Portal', 'la_text_category', 21, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'PortalUserId', -1, 0, 'lu_fielddesc_user_portaluserid', 'lu_field_portaluserid', 'In-Portal', 'la_text_user', 0, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'Username', -1, 0, 'lu_fielddesc_user_login', 'lu_field_login', 'In-Portal', 'la_text_user', 1, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'Password', -1, 0, 'lu_fielddesc_user_password', 'lu_field_password', 'In-Portal', 'la_text_user', 2, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'TimeZone', -1, 0, 'lu_fielddesc_user_tz', 'lu_field_tz', 'In-Portal', 'la_text_user', 17, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'dob', -1, 0, 'lu_fielddesc_user_dob', 'lu_field_dob', 'In-Portal', 'la_text_user', 16, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'Modified', -1, 0, 'lu_fielddesc_user_modified', 'lc_field_modified', 'In-Portal', 'la_text_user', 15, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'Status', -1, 0, 'lu_fielddesc_user_status', 'lc_field_status', 'In-Portal', 'la_text_user', 14, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'ResourceId', -1, 0, 'lu_fielddesc_user_resourceid', 'lc_field_resourceid', 'In-Portal', 'la_text_user', 13, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'Country', -1, 0, 'lu_fielddesc_user_country', 'lu_field_country', 'In-Portal', 'la_text_user', 12, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'Zip', -1, 0, 'lu_fielddesc_user_zip', 'lu_field_zip', 'In-Portal', 'la_text_user', 11, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'State', -1, 0, 'lu_fielddesc_user_state', 'lu_field_state', 'In-Portal', 'la_text_user', 10, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'City', -1, 0, 'lu_fielddesc_user_city', 'lu_field_city', 'In-Portal', 'la_text_user', 9, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'Street', -1, 0, 'lu_fielddesc_user_street', 'lu_field_street', 'In-Portal', 'la_text_user', 8, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'Phone', -1, 0, 'lu_fielddesc_user_phone', 'lu_field_phone', 'In-Portal', 'la_text_user', 7, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'CreatedOn', -1, 0, 'lu_fielddesc_user_createdon', 'lc_field_createdon', 'In-Portal', 'la_text_user', 6, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'Email', -1, 0, 'lu_fielddesc_user_email', 'lu_field_email', 'In-Portal', 'la_text_user', 5, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'LastName', -1, 0, 'lu_fielddesc_user_lastname', 'lu_field_lastname', 'In-Portal', 'la_text_user', 4, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO SearchConfig VALUES ('Users', 'FirstName', -1, 0, 'lu_fielddesc_user_firstname', 'lu_field_firstname', 'In-Portal', 'la_text_user', 3, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT count(*) FROM <%prefix%>Categories WHERE Status=1 ', NULL, 'la_prompt_ActiveCategories', '0', '1'); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT count(*) FROM <%prefix%>Users WHERE Status=1 ', NULL, 'la_prompt_ActiveUsers', '0', '1'); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT count(*) FROM <%prefix%>UserSessions', NULL, 'la_prompt_CurrentSessions', '0', '1'); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) as CategoryCount FROM <%prefix%>Categories', NULL, 'la_prompt_TotalCategories', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS ActiveCategories FROM <%prefix%>Categories WHERE Status = 1', NULL, 'la_prompt_ActiveCategories', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS PendingCategories FROM <%prefix%>Categories WHERE Status = 2', NULL, 'la_prompt_PendingCategories', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS DisabledCategories FROM <%prefix%>Categories WHERE Status = 0', NULL, 'la_prompt_DisabledCategories', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS NewCategories FROM <%prefix%>Categories WHERE (NewItem = 1) OR ( (UNIX_TIMESTAMP() - CreatedOn) <= <%m:config name="Category_DaysNew"%>*86400 AND (NewItem = 2) )', NULL, 'la_prompt_NewCategories', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) FROM <%prefix%>Categories WHERE EditorsPick = 1', NULL, 'la_prompt_CategoryEditorsPick', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT <%m:post_format field="MAX(CreatedOn)" type="date"%> FROM <%prefix%>Categories', NULL, 'la_prompt_NewestCategoryDate', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT <%m:post_format field="MAX(Modified)" type="date"%> FROM <%prefix%>Categories', NULL, 'la_prompt_LastCategoryUpdate', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS TotalUsers FROM <%prefix%>Users', NULL, 'la_prompt_TopicsUsers', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS ActiveUsers FROM <%prefix%>Users WHERE Status = 1', NULL, 'la_prompt_UsersActive', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS PendingUsers FROM <%prefix%>Users WHERE Status = 2', NULL, 'la_prompt_UsersPending', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS DisabledUsers FROM <%prefix%>Users WHERE Status = 0', NULL, 'la_prompt_UsersDisabled', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT <%m:post_format field="MAX(CreatedOn)" type="date"%> FROM <%prefix%>Users', NULL, 'la_prompt_NewestUserDate', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT( DISTINCT LOWER( Country ) ) FROM <%prefix%>Users WHERE LENGTH(Country) > 0', NULL, 'la_prompt_UsersUniqueCountries', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT( DISTINCT LOWER( State ) ) FROM <%prefix%>Users WHERE LENGTH(State) > 0', NULL, 'la_prompt_UsersUniqueStates', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS TotalUserGroups FROM <%prefix%>UserGroups', NULL, 'la_prompt_TotalUserGroups', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS BannedUsers FROM <%prefix%>Users WHERE IsBanned = 1', NULL, 'la_prompt_BannedUsers', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS NonExipedSessions FROM <%prefix%>UserSessions WHERE Status = 1', NULL, 'la_prompt_NonExpiredSessions', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS ThemeCount FROM <%prefix%>Themes', NULL, 'la_prompt_ThemeCount', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', 'SELECT COUNT(*) AS RegionsCount FROM <%prefix%>Languages', NULL, 'la_prompt_RegionsCount', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', '<%m:sql_action sql="SHOW+TABLES" action="COUNT" field="*"%>', NULL, 'la_prompt_TablesCount', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', '<%m:sql_action sql="SHOW+TABLE+STATUS" action="SUM" field="Rows"%>', NULL, 'la_prompt_RecordsCount', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', '<%m:custom_action sql="empty" action="SysFileSize"%>', NULL, 'la_prompt_SystemFileSize', 0, 2); INSERT INTO StatItem VALUES (DEFAULT, 'In-Portal', '<%m:sql_action sql="SHOW+TABLE+STATUS" action="SUM" format_as="file" field="Data_length"%>', NULL, 'la_prompt_DataSize', 0, 2); INSERT INTO Counters VALUES (DEFAULT, 'members_count', 'SELECT COUNT(*) FROM <%PREFIX%>Users WHERE Status = 1', NULL , NULL , '3600', '0', '|Users|'); INSERT INTO Counters VALUES (DEFAULT, 'members_online', 'SELECT COUNT(*) FROM <%PREFIX%>UserSessions WHERE PortalUserId > 0', NULL , NULL , '3600', '0', '|UserSessions|'); INSERT INTO Counters VALUES (DEFAULT, 'guests_online', 'SELECT COUNT(*) FROM <%PREFIX%>UserSessions WHERE PortalUserId <= 0', NULL , NULL , '3600', '0', '|UserSessions|'); INSERT INTO Counters VALUES (DEFAULT, 'users_online', 'SELECT COUNT(*) FROM <%PREFIX%>UserSessions', NULL , NULL , '3600', '0', '|UserSessions|'); INSERT INTO StopWords VALUES (90, '~'),(152, 'on'),(157, 'see'),(156, 'put'),(128, 'and'),(154, 'or'),(155, 'other'),(153, 'one'),(126, 'as'),(127, 'at'),(125, 'are'),(91, '!'),(92, '@'),(93, '#'),(94, '$'),(95, '%'),(96, '^'),(97, '&'),(98, '*'),(99, '('),(100, ')'),(101, '-'),(102, '_'),(103, '='),(104, '+'),(105, '['),(106, '{'),(107, ']'),(108, '}'),(109, '\\'),(110, '|'),(111, ';'),(112, ':'),(113, ''''),(114, '"'),(115, '<'),(116, '.'),(117, '>'),(118, '/'),(119, '?'),(120, 'ah'),(121, 'all'),(122, 'also'),(123, 'am'),(124, 'an'),(151, 'of'),(150, 'note'),(149, 'not'),(148, 'no'),(147, 'may'),(146, 'its'),(145, 'it'),(144, 'is'),(143, 'into'),(142, 'in'),(141, 'had'),(140, 'has'),(139, 'have'),(138, 'from'),(137, 'form'),(136, 'for'),(135, 'end'),(134, 'each'),(133, 'can'),(132, 'by'),(130, 'be'),(131, 'but'),(129, 'any'),(158, 'that'),(159, 'the'),(160, 'their'),(161, 'there'),(162, 'these'),(163, 'they'),(164, 'this'),(165, 'through'),(166, 'thus'),(167, 'to'),(168, 'two'),(169, 'too'),(170, 'up'),(171, 'where'),(172, 'which'),(173, 'with'),(174, 'were'),(175, 'was'),(176, 'you'),(177, 'yet'); #INSERT INTO PageContent VALUES (DEFAULT, 1, 1, 'In-portal is a revolutionary Web Site management system that allows you to automate and facilitate management of large portal and community web sites. Regardless of whether you are running a directory site or a content news portal, a community site or an online mall, In-portal will enhance your web site management experience with innovative.

We are proud to present our newly developed "default" theme that introduces a fresh look as well totally new approach in the template system.
', NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0); INSERT INTO PromoBlockGroups VALUES (DEFAULT, 'Default Group', UNIX_TIMESTAMP(), '1', '7.00', '0.60', '1', 'fade', ''); INSERT INTO Modules VALUES ('Core', 'core/', 'InPortal\\Core', 'adm', DEFAULT, 1, 1, '', 0, NULL); INSERT INTO Modules VALUES ('In-Portal', 'core/', 'InPortal\\Core', 'm', DEFAULT, 1, 0, '', 0, NULL); Index: branches/5.3.x/core/install/upgrades.css =================================================================== --- branches/5.3.x/core/install/upgrades.css (revision 16599) +++ branches/5.3.x/core/install/upgrades.css (revision 16600) @@ -1,876 +1,892 @@ # ===== v 5.0.0 ===== Index: style_template.css =================================================================== --- style_template.css (revision 1.2.8.6) +++ style_template.css (working copy) @@ -14,13 +14,17 @@ body { font-family: verdana,arial,helvetica,sans-serif; - font-size: 9pt; color: #000000; overflow-x: auto; overflow-y: auto; margin: 0px 0px 0px 0px; text-decoration: none; } +body, td { + /* fix for Firefox, when font-size was not inherited in table cells */ + font-size: 9pt; +} + a { color: #006699; text-decoration: none; @@ -73,21 +77,36 @@ } /* Head frame */ +table.head-table { + background: url(@@base_url@@/core/admin_templates/img/top_frame/right_background.jpg) top right @@HeadBgColor@@ no-repeat; +} + .head-table tr td { - background-color: @@HeadBgColor@@; color: @@HeadColor@@ } +div#extra_toolbar td.button-active { + background: url(@@base_url@@/core/admin_templates/img/top_frame/toolbar_button_background.gif) bottom left repeat-x; + height: 22px; +} + +div#extra_toolbar td.button-active a { + color: black; + text-decoration: none; +} + td.kx-block-header, .head-table tr td.kx-block-header{ color: @@HeadBarColor@@; - background-color: @@HeadBarBgColor@@; + background: url(@@base_url@@/core/admin_templates/img/top_frame/toolbar_background.gif) repeat-x top left; + /*background-color: @@HeadBarBgColor@@;*/ padding-left: 7px; padding-right: 7px; } a.kx-header-link { text-decoration: underline; - color: #FFFFFF; + font-weight: bold; + color: #0080C8; } a.kx-header-link:hover { @@ -96,8 +115,8 @@ } .kx-secondary-foreground { - color: @@HeadBarColor@@; - background-color: @@HeadBarBgColor@@; + color: #FFFFFF; + /*background-color: @@HeadBarBgColor@@;*/ } .kx-login-button { @@ -110,7 +129,7 @@ font-size: 12px; font-weight: normal; color: #000000; - background: url(@@base_url@@/proj-base/admin_templates/img/button_back.gif) #f9eeae repeat-x; + background: url(@@base_url@@/core/admin_templates/img/button_back.gif) #f9eeae repeat-x; text-decoration: none; } @@ -119,7 +138,7 @@ font-size: 12px; font-weight: normal; color: #676767; - background: url(@@base_url@@/proj-base/admin_templates/img/button_back_disabled.gif) #f9eeae repeat-x; + background: url(@@base_url@@/core/admin_templates/img/button_back_disabled.gif) #f9eeae repeat-x; text-decoration: none; } @@ -131,23 +150,48 @@ border-top: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; + margin-left: 3px !important; + white-space: nowrap; } .tab-active { - background-color: #2D79D6; - border-bottom: 1px solid #2D79D6; + background-color: #4487D9; } .tab a { - color: #00659C; + color: #4487D9; font-weight: bold; } .tab-active a { - color: #fff; + color: #FFFFFF; font-weight: bold; } +a.scroll-left, a.scroll-right { + cursor: pointer; + display: block; + float: left; + height: 18px; + margin: 0px 1px; + width: 18px; +} + +a.scroll-left { + background: transparent url(@@base_url@@/core/admin_templates/img/tabs/left.png) no-repeat scroll 0 0; +} + +a.scroll-right { + background: transparent url(@@base_url@@/core/admin_templates/img/tabs/right.png) no-repeat scroll 0 0; +} + +a.disabled { + visibility: hidden !important; +} + +a.scroll-left:hover, a.scroll-right:hover { + background-position: 0 -18px; +} /* Toolbar */ @@ -255,7 +299,7 @@ } /* Filters row */ -tr.grid-header-row-0 td { +tr.grid-header-row-1 td { background-color: @@FiltersBgColor@@; border-bottom: 1px solid black; } @@ -288,18 +332,19 @@ } /* Column titles row */ -tr.grid-header-row-1 td { +tr.grid-header-row-0 td { height: 25px; font-weight: bold; background-color: @@ColumnTitlesBgColor@@; color: @@ColumnTitlesColor@@; + border-bottom: 1px solid black; } -tr.grid-header-row-1 td a { +tr.grid-header-row-0 td a { color: @@ColumnTitlesColor@@; } -tr.grid-header-row-1 td a:hover { +tr.grid-header-row-0 td a:hover { color: #FFCC00; } @@ -307,7 +352,7 @@ .grid-footer-row td { background-color: #D7D7D7; font-weight: bold; - border-right: none; + border-right: 1px solid #C9C9C9; padding: 3px 5px 3px 5px; } @@ -320,12 +365,12 @@ vertical-align: middle !important; } -tr.grid-header-row-0 td.grid-header-col-0 { +tr.grid-header-row-1 td.grid-header-col-1 { text-align: center; vertical-align: middle !important; } -tr.grid-header-row-0 td.grid-header-col-0 div { +tr.grid-header-row-1 td.grid-header-col-1 div { display: table-cell; vertical-align: middle; } @@ -374,11 +419,12 @@ .subsectiontitle td { vertical-align: middle; - padding: 3px 5px 3px 5px; + /*padding: 3px 5px 3px 5px;*/ + padding: 1px 5px; } .label-cell { - background: #DEE7F6 url(@@base_url@@/proj-base/admin_templates/img/bgr_input_name_line.gif) no-repeat right bottom; + background: #DEE7F6 url(@@base_url@@/core/admin_templates/img/bgr_input_name_line.gif) no-repeat right bottom; font: 12px arial, sans-serif; padding: 4px 20px; width: 150px; @@ -387,13 +433,13 @@ .control-mid { width: 13px; border-left: 1px solid #7A95C2; - background: #fff url(@@base_url@@/proj-base/admin_templates/img/bgr_mid.gif) repeat-x left bottom; + background: #fff url(@@base_url@@/core/admin_templates/img/bgr_mid.gif) repeat-x left bottom; } .control-cell { font: 11px arial, sans-serif; padding: 4px 10px 5px 5px; - background: #fff url(@@base_url@@/proj-base/admin_templates/img/bgr_input_line.gif) no-repeat left bottom; + background: #fff url(@@base_url@@/core/admin_templates/img/bgr_input_line.gif) no-repeat left bottom; width: auto; vertical-align: middle; } @@ -420,8 +466,28 @@ color: red; } +.warning-table { + background-color: #F0F1EB; + border: 1px solid #000000; + border-collapse: collapse; + border-top-width: 0px; +} + .form-warning { color: red; + font-size: 11px; +} + +.priority { + color: red; + padding-left: 1px; + padding-right: 1px; + font-size: 11px; +} + +.small-statistics { + font-size: 11px; + color: #707070; } .req-note { @@ -474,7 +540,13 @@ /* To be sorted */ +span#category_path, span#category_path a { + color: #FFFFFF; +} +span#category_path a { + text-decoration: underline; +} /* Section title, right to the big icon */ .admintitle { @@ -484,7 +556,7 @@ text-decoration: none; } -/* Left sid of bluebar */ +/* Left side of bluebar */ .header_left_bg { background-color: @@TitleBarBgColor@@; background-image: none; @@ -560,7 +632,7 @@ color: @@TreeColor@@; font-family: Helvetica, Arial, Verdana; text-decoration: none; - padding: 2px 0px 2px 2px; + padding: 2px; } .tree tr.highlighted td a { # ===== v 5.0.1 ===== Index: style_template.css =================================================================== --- style_template.css (revision 13764) +++ style_template.css (working copy) @@ -78,15 +78,15 @@ /* Head frame */ table.head-table { - background: url(@@base_url@@/core/admin_templates/img/top_frame/right_background.jpg) top right @@HeadBgColor@@ no-repeat; + background: url('@@base_url@@/core/admin_templates/img/top_frame/right_background.png') top right @@HeadBgColor@@ no-repeat; } -.head-table tr td { +.head-table tr td, .head-table tr td a { color: @@HeadColor@@ } div#extra_toolbar td.button-active { - background: url(@@base_url@@/core/admin_templates/img/top_frame/toolbar_button_background.gif) bottom left repeat-x; + background: url('@@base_url@@/core/admin_templates/img/top_frame/toolbar_button_background.gif') bottom left repeat-x; height: 22px; } @@ -97,7 +97,7 @@ td.kx-block-header, .head-table tr td.kx-block-header{ color: @@HeadBarColor@@; - background: url(@@base_url@@/core/admin_templates/img/top_frame/toolbar_background.gif) repeat-x top left; + background: url('@@base_url@@/core/admin_templates/img/top_frame/toolbar_background.gif') repeat-x top left; /*background-color: @@HeadBarBgColor@@;*/ padding-left: 7px; padding-right: 7px; @@ -129,7 +129,7 @@ font-size: 12px; font-weight: normal; color: #000000; - background: url(@@base_url@@/core/admin_templates/img/button_back.gif) #f9eeae repeat-x; + background: url('@@base_url@@/core/admin_templates/img/button_back.gif') #f9eeae repeat-x; text-decoration: none; } @@ -138,7 +138,7 @@ font-size: 12px; font-weight: normal; color: #676767; - background: url(@@base_url@@/core/admin_templates/img/button_back_disabled.gif) #f9eeae repeat-x; + background: url('@@base_url@@/core/admin_templates/img/button_back_disabled.gif') #f9eeae repeat-x; text-decoration: none; } @@ -178,11 +178,11 @@ } a.scroll-left { - background: transparent url(@@base_url@@/core/admin_templates/img/tabs/left.png) no-repeat scroll 0 0; + background: transparent url('@@base_url@@/core/admin_templates/img/tabs/left.png') no-repeat scroll 0 0; } a.scroll-right { - background: transparent url(@@base_url@@/core/admin_templates/img/tabs/right.png) no-repeat scroll 0 0; + background: transparent url('@@base_url@@/core/admin_templates/img/tabs/right.png') no-repeat scroll 0 0; } a.disabled { @@ -193,6 +193,19 @@ background-position: 0 -18px; } +td.scroll-right-container { + width: 20px; +} + +td.scroll-right-container.disabled, td.scroll-right-container.disabled * { + width: 0px; + margin: 0px; +} + +td.scroll-right-container.disabled br { + display: none; +} + /* Toolbar */ .toolbar { @@ -424,22 +437,22 @@ } .label-cell { - background: #DEE7F6 url(@@base_url@@/core/admin_templates/img/bgr_input_name_line.gif) no-repeat right bottom; + background: #DEE7F6 url('@@base_url@@/core/admin_templates/img/bgr_input_name_line.gif') no-repeat right bottom; font: 12px arial, sans-serif; padding: 4px 20px; - width: 150px; + width: 160px; } .control-mid { width: 13px; border-left: 1px solid #7A95C2; - background: #fff url(@@base_url@@/core/admin_templates/img/bgr_mid.gif) repeat-x left bottom; + background: #fff url('@@base_url@@/core/admin_templates/img/bgr_mid.gif') repeat-x left bottom; } .control-cell { font: 11px arial, sans-serif; padding: 4px 10px 5px 5px; - background: #fff url(@@base_url@@/core/admin_templates/img/bgr_input_line.gif) no-repeat left bottom; + background: #fff url('@@base_url@@/core/admin_templates/img/bgr_input_line.gif') no-repeat left bottom; width: auto; vertical-align: middle; } @@ -528,14 +541,14 @@ width: 100%; border: 1px solid black; height: 20px; - background: #fff url(@@base_url@@/core/admin_templates/img/progress_left.gif); + background: #fff url('@@base_url@@/core/admin_templates/img/progress_left.gif'); } .uploader-done { width: 0%; background-color: green; height: 20px; - background: #4A92CE url(@@base_url@@/core/admin_templates/img/progress_done.gif); + background: #4A92CE url('@@base_url@@/core/admin_templates/img/progress_done.gif'); } @@ -635,15 +648,15 @@ padding: 2px; } +.tree tr td a:hover { + color: @@TreeHoverColor@@; +} + .tree tr.highlighted td a { + color: @@TreeHighColor@@; background-color: @@TreeHighBgColor@@; - color: @@TreeHighColor@@; } .tree tr.highlighted td a:hover { - color: #fff; -} - -.tree tr td a:hover { - color: #000000; + color: @@TreeHighHoverColor@@; } \ No newline at end of file # ===== v 5.1.0-B1 ===== Index: style_template.css =================================================================== --- style_template.css (revision 13764) +++ style_template.css (working copy) @@ -648,15 +648,36 @@ padding: 2px; } -.tree tr td a:hover { +.tree tr td a:hover, .tree tr td a.debug-only-item:hover { color: @@TreeHoverColor@@; } -.tree tr.highlighted td a { +.tree tr.highlighted td a, .tree tr.highlighted td a.debug-only-item { color: @@TreeHighColor@@; background-color: @@TreeHighBgColor@@; } .tree tr.highlighted td a:hover { color: @@TreeHighHoverColor@@; +} + +.tree tr td a.debug-only-item { + color: grey; +} + +/* Ajax Dropdown */ +.suggest-box { + border: 1px solid #999; + background-color: #fff; +} + +.suggest-item, .suggest-item-over { + padding: 1px 2px 0px 2px; + font-family: arial,verdana; + font-size: 12px; +} + +.suggest-item-over { + background-color: #3366CC; + color: #fff; } \ No newline at end of file # ===== v 5.1.0-B2 ===== Index: style_template.css =================================================================== --- style_template.css (revision 13764) +++ style_template.css (working copy) @@ -512,45 +512,49 @@ border-collapse: separate } - /* Uploader */ - -.uploader-main { - position: absolute; - display: none; - z-index: 10; - border: 1px solid #777; - padding: 10px; - width: 350px; - height: 120px; - overflow: hidden; - background-color: #fff; +.uploader-queue div.file { + font-size: 11px; + border: 1px solid #7F99C5; + padding: 3px; + background-color: #DEE7F6; + margin-bottom: 2px; } -.uploader-percent { - width: 100%; - padding-top: 3px; - text-align: center; - position: relative; - z-index: 20; +.uploader-queue .left { float: left; - font-weight: bold; + vertical-align: top; } -.uploader-left { - width: 100%; +.uploader-queue .file-label { + margin-left: 5px; +} + +.uploader-queue .preview .delete-checkbox { + margin-top: -3px; +} + +.uploader-queue .progress-container { + margin: 2px 5px 0px 5px; +} + +.uploader-queue .progress-empty { + width: 150px; + height: 9px; border: 1px solid black; - height: 20px; - background: #fff url('@@base_url@@/core/admin_templates/img/progress_left.gif'); + background: url('@@base_url@@/core/admin_templates/img/progress_left.gif') repeat-x; } -.uploader-done { - width: 0%; - background-color: green; - height: 20px; - background: #4A92CE url('@@base_url@@/core/admin_templates/img/progress_done.gif'); +.uploader-queue .progress-full { + height: 9px; + background: url('@@base_url@@/core/admin_templates/img/progress_done.gif'); } +.uploader-queue .thumbnail { + /*margin-bottom: 2px;*/ + border: 1px solid black; + background-color: grey; +} /* To be sorted */ span#category_path, span#category_path a { # ===== v 5.1.1-B1 ===== Index: style_template.css =================================================================== --- style_template.css (revision 13862) +++ style_template.css (working copy) @@ -61,10 +61,12 @@ .bordered, table.bordered, .bordered-no-bottom { border: 1px solid #000000; + border-top-width: 0px; border-collapse: collapse; } .bordered-no-bottom { + border-top-width: 1px; border-bottom: none; } @@ -430,6 +432,11 @@ vertical-align: middle; } +/* remove top-border from first sub-section element */ +table.edit-form .subsectiontitle:first-child, table.bordered .subsectiontitle:first-child { + border-top-width: 0; +} + .subsectiontitle td { vertical-align: middle; /*padding: 3px 5px 3px 5px;*/ @@ -684,4 +691,64 @@ .suggest-item-over { background-color: #3366CC; color: #fff; +} + +/* Dashboard Summary Boxes */ +.summary-box { + border: 1px solid black; + margin-bottom: 4px; +} + +.summary-box .title { + color: white; + font-weight: bold; + padding: 6px 5px; + vertical-align: middle; + background-color: #4A92CE; + border-bottom: 1px solid black; +} + +.summary-box .content { + padding: 4px; + background-color: #F6F6F6; +} + +.summary-box .group { + border-bottom: 1px solid black; + margin-bottom: 10px; + padding: 0 0 10px 10px; +} + +.summary-box .group.last { + border-width: 0px; + margin-bottom: 0; + padding-bottom: 5px; +} + +.summary-box h4 { + margin: 0; + padding: 0 0 3px 0; + font-size: 11px; + font-weight: bold; +} + +.summary-box .hint { + font-size: 10px; + color: grey; + margin-bottom: 3px; +} + +.summary-box .hint .cache-key { + margin-bottom: 7px; + margin-left: 3px; +} + +.summary-box ul { + margin-top: 5px; + margin-bottom: 3px; + padding-left: 30px; +} + +.summary-box li { + padding-bottom: 4px; } \ No newline at end of file # ===== v 5.2.0-B1 ===== Index: style_template.css =================================================================== --- style_template.css (revision 14590) +++ style_template.css (working copy) @@ -60,7 +60,7 @@ } .bordered, table.bordered, .bordered-no-bottom { - border: 1px solid #000000; + border: 1px solid #000000 !important; border-top-width: 0px; border-collapse: collapse; } @@ -269,7 +269,7 @@ } /* Main row definition */ -.grid-data-row td, .grid-data-row-selected td, .grid-data-row-even-selected td, .grid-data-row-mouseover td, .table-color1, .table-color2 { +.grid-data-row td, .grid-data-row-selected td, .grid-data-row-even-selected td, .grid-data-row-mouseover td, .table-color1, .table-color2, .grid-edit-table .edit-form-odd > td, .grid-edit-table .edit-form-even > td { font-weight: normal; color: @@OddColor@@; background-color: @@OddBgColor@@; @@ -277,7 +277,7 @@ overflow: hidden; border-right: 1px solid #c9c9c9; } -.grid-data-row-even td, .table-color2 { +.grid-data-row-even td, .table-color2, .grid-edit-table .edit-form-even > td { background-color: @@EvenBgColor@@; color: @@EvenColor@@; } @@ -346,6 +346,29 @@ background-color: #FFFF00; } +div.filter, div.filter-active { + background-color: white; + border: 1px solid #AAAAAA; + color: black; + font-weight: normal; + padding: 3px; +} + +div.filter-active { + background-color: #FFFF00; +} + +div.multioptions_filter { + position: absolute; + z-index: 100; + color: black; + background-color: white; + border: 1px solid black; + padding: 3px 5px; + display: none; + vertical-align: middle; +} + /* Column titles row */ tr.grid-header-row-0 td { height: 25px; @@ -413,7 +436,7 @@ /* Forms */ table.edit-form { border: none; - border-top-width: 0px; + border-top-width: 0px !important; border-collapse: collapse; width: 100%; } @@ -493,11 +516,18 @@ border-top-width: 0px; } +.form-notice, .form-warning { + font-size: 11px; +} + .form-warning { color: red; - font-size: 11px; } +.form-notice { + color: green; +} + .priority { color: red; padding-left: 1px; @@ -751,4 +781,17 @@ .summary-box li { padding-bottom: 4px; +} + +span.cke_skin_kama { + border-width: 0px !important; + -moz-border-radius: 0px !important; + -webkit-border-radius: 0px !important; + padding: 0px !important; +} + +.cke_wrapper{ + border-width: 0px !important; + -moz-border-radius: 0px !important; + -webkit-border-radius: 0px !important; } \ No newline at end of file # ===== v 5.2.0 ===== Index: style_template.css =================================================================== --- style_template.css (revision 15359) +++ style_template.css (working copy) @@ -424,7 +424,7 @@ .grid-status-bar td { background-color: @@TitleBarBgColor@@; - color: @@TitleBarColor@@; + color: @@TitleBarColor@@; font-size: 11pt; font-weight: normal; padding: 2px 8px 2px 8px; @@ -610,11 +610,13 @@ text-decoration: none; } -/* Left side of bluebar */ -.header_left_bg { +/* Page header (bluebar) */ +.page-title td { background-color: @@TitleBarBgColor@@; - background-image: none; - padding-left: 5px; + color: @@TitleBarColor@@; + font-size: 11pt; + font-weight: normal; + padding: 2px 8px 2px 8px; } /* Right side of bluebar */ # ===== v 5.2.2-B1 ===== Index: style_template.css =================================================================== --- style_template.css (revision 16300) +++ style_template.css (working copy) @@ -549,6 +549,10 @@ border-collapse: separate } +label.checkbox { + white-space: nowrap; +} + /* Uploader */ .uploader-queue div.file { font-size: 11px; +# ===== v 5.2.2-B2 ===== +Index: style_template.css +=================================================================== +--- style_template.css (revision 16502) ++++ style_template.css (working copy) +@@ -801,3 +801,9 @@ + -moz-border-radius: 0px !important; + -webkit-border-radius: 0px !important; + } ++ ++/* Inline CKEditor styles dropdown enlargement */ ++div.cke_combopanel__styles { ++ width: 200px; ++ height: 300px; ++} + # ===== v 5.3.0-B1 ===== Index: style_template.css =================================================================== --- style_template.css (revision 16502) +++ style_template.css (working copy) @@ -487,6 +487,14 @@ vertical-align: middle; } +.CodeMirror { + font-size: 13px; + border: 1px solid black; +} + +.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} +.CodeMirror-activeline-background {background: #e8f2ff !important;} + .label-cell-filler { background: #DEE7F6 none; } @@ -498,6 +506,18 @@ background: #fff none; } +.highlight-area, .code-highlight-area { + border: 1px solid black; + padding: 8px; + font-family: monospace !important; + font-size: 12px; + overflow: auto; +} + +.code-highlight-area { + background-color: #F6F6F6; +} + .error { color: red; } Index: branches/5.3.x/core/install/upgrades.sql =================================================================== --- branches/5.3.x/core/install/upgrades.sql (revision 16599) +++ branches/5.3.x/core/install/upgrades.sql (revision 16600) @@ -1,3060 +1,3073 @@ # ===== v 4.0.1 ===== ALTER TABLE EmailLog ADD EventParams TEXT NOT NULL; INSERT INTO ConfigurationAdmin VALUES ('MailFunctionHeaderSeparator', 'la_Text_smtp_server', 'la_config_MailFunctionHeaderSeparator', 'radio', NULL, '1=la_Linux,2=la_Windows', 30.08, 0, 0); INSERT INTO ConfigurationValues VALUES (0, 'MailFunctionHeaderSeparator', 1, 'In-Portal', 'in-portal:configure_general'); ALTER TABLE PersistantSessionData DROP PRIMARY KEY ; ALTER TABLE PersistantSessionData ADD INDEX ( `PortalUserId` ) ; # ===== v 4.1.0 ===== ALTER TABLE EmailMessage ADD ReplacementTags TEXT AFTER Template; ALTER TABLE Phrase CHANGE Translation Translation TEXT NOT NULL, CHANGE Module Module VARCHAR(30) NOT NULL DEFAULT 'In-Portal'; ALTER TABLE Category CHANGE Description Description TEXT, CHANGE l1_Description l1_Description TEXT, CHANGE l2_Description l2_Description TEXT, CHANGE l3_Description l3_Description TEXT, CHANGE l4_Description l4_Description TEXT, CHANGE l5_Description l5_Description TEXT, CHANGE CachedNavbar CachedNavbar text, CHANGE l1_CachedNavbar l1_CachedNavbar text, CHANGE l2_CachedNavbar l2_CachedNavbar text, CHANGE l3_CachedNavbar l3_CachedNavbar text, CHANGE l4_CachedNavbar l4_CachedNavbar text, CHANGE l5_CachedNavbar l5_CachedNavbar text, CHANGE ParentPath ParentPath TEXT NULL DEFAULT NULL, CHANGE NamedParentPath NamedParentPath TEXT NULL DEFAULT NULL; ALTER TABLE ConfigurationAdmin CHANGE ValueList ValueList TEXT; ALTER TABLE EmailQueue CHANGE `Subject` `Subject` TEXT, CHANGE toaddr toaddr TEXT, CHANGE fromaddr fromaddr TEXT; ALTER TABLE Category DROP Pop; ALTER TABLE PortalUser CHANGE CreatedOn CreatedOn INT DEFAULT NULL, CHANGE dob dob INT(11) NULL DEFAULT NULL, CHANGE PassResetTime PassResetTime INT(11) UNSIGNED NULL DEFAULT NULL, CHANGE PwRequestTime PwRequestTime INT(11) UNSIGNED NULL DEFAULT NULL, CHANGE `Password` `Password` VARCHAR(255) NULL DEFAULT 'd41d8cd98f00b204e9800998ecf8427e'; ALTER TABLE Modules CHANGE BuildDate BuildDate INT UNSIGNED NULL DEFAULT NULL, CHANGE Version Version VARCHAR(10) NOT NULL DEFAULT '0.0.0', CHANGE `Var` `Var` VARCHAR(100) NOT NULL DEFAULT ''; ALTER TABLE Language CHANGE Enabled Enabled INT(11) NOT NULL DEFAULT '1', CHANGE InputDateFormat InputDateFormat VARCHAR(50) NOT NULL DEFAULT 'm/d/Y', CHANGE InputTimeFormat InputTimeFormat VARCHAR(50) NOT NULL DEFAULT 'g:i:s A', CHANGE DecimalPoint DecimalPoint VARCHAR(10) NOT NULL DEFAULT '', CHANGE ThousandSep ThousandSep VARCHAR(10) NOT NULL DEFAULT ''; ALTER TABLE Events CHANGE FromUserId FromUserId INT(11) NOT NULL DEFAULT '-1'; ALTER TABLE StdDestinations CHANGE DestAbbr2 DestAbbr2 CHAR(2) NULL DEFAULT NULL; ALTER TABLE PermCache DROP DACL; ALTER TABLE PortalGroup CHANGE CreatedOn CreatedOn INT UNSIGNED NULL DEFAULT NULL; ALTER TABLE UserSession CHANGE SessionKey SessionKey INT UNSIGNED NULL DEFAULT NULL , CHANGE CurrentTempKey CurrentTempKey INT UNSIGNED NULL DEFAULT NULL , CHANGE PrevTempKey PrevTempKey INT UNSIGNED NULL DEFAULT NULL , CHANGE LastAccessed LastAccessed INT UNSIGNED NOT NULL DEFAULT '0', CHANGE PortalUserId PortalUserId INT(11) NOT NULL DEFAULT '-2', CHANGE Language Language INT(11) NOT NULL DEFAULT '1', CHANGE Theme Theme INT(11) NOT NULL DEFAULT '1'; CREATE TABLE Counters ( CounterId int(10) unsigned NOT NULL auto_increment, Name varchar(100) NOT NULL default '', CountQuery text, CountValue text, LastCounted int(10) unsigned default NULL, LifeTime int(10) unsigned NOT NULL default '3600', IsClone tinyint(3) unsigned NOT NULL default '0', TablesAffected text, PRIMARY KEY (CounterId), UNIQUE KEY Name (Name) ); CREATE TABLE Skins ( `SkinId` int(11) NOT NULL auto_increment, `Name` varchar(255) default NULL, `CSS` text, `Logo` varchar(255) default NULL, `Options` text, `LastCompiled` int(11) NOT NULL default '0', `IsPrimary` int(1) NOT NULL default '0', PRIMARY KEY (`SkinId`) ); INSERT INTO Skins VALUES (DEFAULT, 'Default', '/* General elements */\r\n\r\nhtml {\r\n height: 100%;\r\n}\r\n\r\nbody {\r\n font-family: verdana,arial,helvetica,sans-serif;\r\n font-size: 9pt;\r\n color: #000000;\r\n overflow-x: auto; overflow-y: auto;\r\n margin: 0px 0px 0px 0px;\r\n text-decoration: none;\r\n}\r\n\r\na {\r\n color: #006699;\r\n text-decoration: none;\r\n}\r\n\r\na:hover {\r\n color: #009ff0;\r\n text-decoration: none;\r\n}\r\n\r\nform {\r\n display: inline;\r\n}\r\n\r\nimg { border: 0px; }\r\n\r\nbody.height-100 {\r\n height: 100%;\r\n}\r\n\r\nbody.regular-body {\r\n margin: 0px 10px 5px 10px;\r\n color: #000000;\r\n background-color: @@SectionBgColor@@;\r\n}\r\n\r\nbody.edit-popup {\r\n margin: 0px 0px 0px 0px;\r\n}\r\n\r\ntable.collapsed {\r\n border-collapse: collapse;\r\n}\r\n\r\n.bordered, table.bordered, .bordered-no-bottom {\r\n border: 1px solid #000000;\r\n border-collapse: collapse;\r\n}\r\n\r\n.bordered-no-bottom {\r\n border-bottom: none;\r\n}\r\n\r\n.login-table td {\r\n padding: 1px;\r\n}\r\n\r\n.disabled {\r\n background-color: #ebebeb;\r\n}\r\n\r\n/* Head frame */\r\n.head-table tr td {\r\n background-color: @@HeadBgColor@@;\r\n color: @@HeadColor@@\r\n}\r\n\r\ntd.kx-block-header, .head-table tr td.kx-block-header{\r\n color: @@HeadBarColor@@;\r\n background-color: @@HeadBarBgColor@@;\r\n padding-left: 7px;\r\n padding-right: 7px;\r\n}\r\n\r\na.kx-header-link {\r\n text-decoration: underline;\r\n color: #FFFFFF;\r\n}\r\n\r\na.kx-header-link:hover {\r\n color: #FFCB05;\r\n text-decoration: none;\r\n}\r\n\r\n.kx-secondary-foreground {\r\n color: @@HeadBarColor@@;\r\n background-color: @@HeadBarBgColor@@;\r\n}\r\n\r\n.kx-login-button {\r\n background-color: #2D79D6;\r\n color: #FFFFFF;\r\n}\r\n\r\n/* General form button (yellow) */\r\n.button {\r\n font-size: 12px;\r\n font-weight: normal;\r\n color: #000000;\r\n background: url(@@base_url@@/proj-base/admin_templates/img/button_back.gif) #f9eeae repeat-x;\r\n text-decoration: none;\r\n}\r\n\r\n/* Disabled (grayed-out) form button */\r\n.button-disabled {\r\n font-size: 12px;\r\n font-weight: normal;\r\n color: #676767;\r\n background: url(@@base_url@@/proj-base/admin_templates/img/button_back_disabled.gif) #f9eeae repeat-x;\r\n text-decoration: none;\r\n}\r\n\r\n/* Tabs bar */\r\n\r\n.tab, .tab-active {\r\n background-color: #F0F1EB;\r\n padding: 3px 7px 2px 7px;\r\n border-top: 1px solid black;\r\n border-left: 1px solid black;\r\n border-right: 1px solid black;\r\n}\r\n\r\n.tab-active {\r\n background-color: #2D79D6;\r\n border-bottom: 1px solid #2D79D6;\r\n}\r\n\r\n.tab a {\r\n color: #00659C;\r\n font-weight: bold;\r\n}\r\n\r\n.tab-active a {\r\n color: #fff;\r\n font-weight: bold;\r\n}\r\n\r\n\r\n/* Toolbar */\r\n\r\n.toolbar {\r\n font-size: 8pt;\r\n border: 1px solid #000000;\r\n border-width: 0px 1px 1px 1px;\r\n background-color: @@ToolbarBgColor@@;\r\n border-collapse: collapse;\r\n}\r\n\r\n.toolbar td {\r\n height: 100%;\r\n}\r\n\r\n.toolbar-button, .toolbar-button-disabled, .toolbar-button-over {\r\n float: left;\r\n text-align: center;\r\n font-size: 8pt;\r\n padding: 5px 5px 5px 5px;\r\n vertical-align: middle;\r\n color: #006F99;\r\n}\r\n\r\n.toolbar-button-over {\r\n color: #000;\r\n}\r\n\r\n.toolbar-button-disabled {\r\n color: #444;\r\n}\r\n\r\n/* Scrollable Grids */\r\n\r\n\r\n/* Main Grid class */\r\n.grid-scrollable {\r\n padding: 0px;\r\n border: 1px solid black !important;\r\n border-top: none !important;\r\n}\r\n\r\n/* Div generated by js, which contains all the scrollable grid elements, affects the style of scrollable area without data (if there are too few rows) */\r\n.grid-container {\r\n background-color: #fff;\r\n}\r\n\r\n.grid-container table {\r\n border-collapse: collapse;\r\n}\r\n\r\n/* Inner div generated in each data-cell */\r\n.grid-cell-div {\r\n overflow: hidden;\r\n height: auto;\r\n}\r\n\r\n/* Main row definition */\r\n.grid-data-row td, .grid-data-row-selected td, .grid-data-row-even-selected td, .grid-data-row-mouseover td, .table-color1, .table-color2 {\r\n font-weight: normal;\r\n color: @@OddColor@@;\r\n background-color: @@OddBgColor@@;\r\n padding: 3px 5px 3px 5px;\r\n height: 30px;\r\n overflow: hidden;\r\n /* border-right: 1px solid black; */\r\n}\r\n.grid-data-row-even td, .table-color2 {\r\n background-color: @@EvenBgColor@@;\r\n color: @@EvenColor@@;\r\n}\r\n.grid-data-row td a, .grid-data-row-selected td a, .grid-data-row-mouseover td a {\r\n text-decoration: underline;\r\n}\r\n\r\n/* mouse-over rows */\r\n.grid-data-row-mouseover td {\r\n background: #FFFDF4;\r\n}\r\n\r\n/* Selected row, applies to both checkbox and data areas */\r\n.grid-data-row-selected td {\r\n background: #FEF2D6;\r\n}\r\n\r\n.grid-data-row-even-selected td {\r\n background: #FFF7E0;\r\n}\r\n\r\n/* General header cell definition */\r\n.grid-header-row td {\r\n font-weight: bold;\r\n background-color: @@ColumnTitlesBgColor@@;\r\n text-decoration: none;\r\n padding: 3px 5px 3px 5px;\r\n color: @@ColumnTitlesColor@@;\r\n border-right: none;\r\n text-align: left;\r\n vertical-align: middle !important;\r\n white-space: nowrap;\r\n /* border-right: 1px solid black; */\r\n}\r\n\r\n/* Filters row */\r\ntr.grid-header-row-0 td {\r\n background-color: @@FiltersBgColor@@;\r\n border-bottom: 1px solid black;\r\n}\r\n\r\n/* Grid Filters */\r\ntable.range-filter {\r\n width: 100%;\r\n}\r\n\r\n.range-filter td {\r\n padding: 0px 0px 2px 2px !important;\r\n border: none !important;\r\n font-size: 8pt !important;\r\n font-weight: normal !important;\r\n text-align: left;\r\n color: #000000 !important;\r\n}\r\n\r\ninput.filter, select.filter {\r\n margin-bottom: 0px;\r\n width: 85%;\r\n}\r\n\r\ninput.filter-active {\r\n background-color: #FFFF00;\r\n}\r\n\r\nselect.filter-active {\r\n background-color: #FFFF00;\r\n}\r\n\r\n/* Column titles row */\r\ntr.grid-header-row-1 td {\r\n height: 25px;\r\n font-weight: bold;\r\n background-color: @@ColumnTitlesBgColor@@;\r\n color: @@ColumnTitlesColor@@;\r\n}\r\n\r\ntr.grid-header-row-1 td a {\r\n color: @@ColumnTitlesColor@@;\r\n}\r\n\r\ntr.grid-header-row-1 td a:hover {\r\n color: #FFCC00;\r\n}\r\n\r\n\r\n.grid-footer-row td {\r\n background-color: #D7D7D7;\r\n font-weight: bold;\r\n border-right: none;\r\n padding: 3px 5px 3px 5px;\r\n}\r\n\r\ntd.grid-header-last-cell, td.grid-data-last-cell, td.grid-footer-last-cell {\r\n border-right: none !important;\r\n}\r\n\r\ntd.grid-data-col-0, td.grid-data-col-0 div {\r\n text-align: center;\r\n vertical-align: middle !important;\r\n}\r\n\r\ntr.grid-header-row-0 td.grid-header-col-0 {\r\n text-align: center;\r\n vertical-align: middle !important;\r\n}\r\n\r\ntr.grid-header-row-0 td.grid-header-col-0 div {\r\n display: table-cell;\r\n vertical-align: middle;\r\n}\r\n\r\n.grid-status-bar {\r\n border: 1px solid black;\r\n border-top: none;\r\n padding: 0px;\r\n width: 100%;\r\n border-collapse: collapse;\r\n height: 30px;\r\n}\r\n\r\n.grid-status-bar td {\r\n background-color: @@TitleBarBgColor@@;\r\n color: @@TitleBarColor@@;\r\n font-size: 11pt;\r\n font-weight: normal;\r\n padding: 2px 8px 2px 8px;\r\n}\r\n\r\n/* /Scrollable Grids */\r\n\r\n\r\n/* Forms */\r\ntable.edit-form {\r\n border: none;\r\n border-top-width: 0px;\r\n border-collapse: collapse;\r\n width: 100%;\r\n}\r\n\r\n.edit-form-odd, .edit-form-even {\r\n padding: 0px;\r\n}\r\n\r\n.subsectiontitle {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n background-color: #4A92CE;\r\n color: #fff;\r\n height: 25px;\r\n border-top: 1px solid black;\r\n}\r\n\r\n.label-cell {\r\n background: #DEE7F6 url(@@base_url@@/proj-base/admin_templates/img/bgr_input_name_line.gif) no-repeat right bottom;\r\n font: 12px arial, sans-serif;\r\n padding: 4px 20px;\r\n width: 150px;\r\n}\r\n\r\n.control-mid {\r\n width: 13px;\r\n border-left: 1px solid #7A95C2;\r\n background: #fff url(@@base_url@@/proj-base/admin_templates/img/bgr_mid.gif) repeat-x left bottom;\r\n}\r\n\r\n.control-cell {\r\n font: 11px arial, sans-serif;\r\n padding: 4px 10px 5px 5px;\r\n background: #fff url(@@base_url@@/proj-base/admin_templates/img/bgr_input_line.gif) no-repeat left bottom;\r\n width: auto;\r\n vertical-align: middle;\r\n}\r\n\r\n.label-cell-filler {\r\n background: #DEE7F6 none;\r\n}\r\n.control-mid-filler {\r\n background: #fff none;\r\n border-left: 1px solid #7A95C2;\r\n}\r\n.control-cell-filler {\r\n background: #fff none;\r\n}\r\n\r\n\r\n.error-cell {\r\n background-color: #fff;\r\n color: red;\r\n}\r\n\r\n.form-warning {\r\n color: red;\r\n}\r\n\r\n.req-note {\r\n font-style: italic;\r\n color: #333;\r\n}\r\n\r\n#scroll_container table.tableborder {\r\n border-collapse: separate\r\n}\r\n\r\n\r\n/* Uploader */\r\n\r\n.uploader-main {\r\n position: absolute;\r\n display: none;\r\n z-index: 10;\r\n border: 1px solid #777;\r\n padding: 10px;\r\n width: 350px;\r\n height: 120px;\r\n overflow: hidden;\r\n background-color: #fff;\r\n}\r\n\r\n.uploader-percent {\r\n width: 100%;\r\n padding-top: 3px;\r\n text-align: center;\r\n position: relative;\r\n z-index: 20;\r\n float: left;\r\n font-weight: bold;\r\n}\r\n\r\n.uploader-left {\r\n width: 100%;\r\n border: 1px solid black;\r\n height: 20px;\r\n background: #fff url(@@base_url@@/core/admin_templates/img/progress_left.gif);\r\n}\r\n\r\n.uploader-done {\r\n width: 0%;\r\n background-color: green;\r\n height: 20px;\r\n background: #4A92CE url(@@base_url@@/core/admin_templates/img/progress_done.gif);\r\n}\r\n\r\n\r\n/* To be sorted */\r\n\r\n\r\n/* Section title, right to the big icon */\r\n.admintitle {\r\n font-size: 16pt;\r\n font-weight: bold;\r\n color: @@SectionColor@@;\r\n text-decoration: none;\r\n}\r\n\r\n/* Left sid of bluebar */\r\n.header_left_bg {\r\n background-color: @@TitleBarBgColor@@;\r\n background-image: none;\r\n padding-left: 5px;\r\n}\r\n\r\n/* Right side of bluebar */\r\n.tablenav, tablenav a {\r\n font-size: 11pt;\r\n font-weight: bold;\r\n color: @@TitleBarColor@@;\r\n\r\n text-decoration: none;\r\n background-color: @@TitleBarBgColor@@;\r\n background-image: none;\r\n}\r\n\r\n/* Section title in the bluebar * -- why ''link''? :S */\r\n.tablenav_link {\r\n font-size: 11pt;\r\n font-weight: bold;\r\n color: @@TitleBarColor@@;\r\n text-decoration: none;\r\n}\r\n\r\n/* Active page in top and bottom bluebars pagination */\r\n.current_page {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n background-color: #fff;\r\n color: #2D79D6;\r\n padding: 3px 2px 3px 3px;\r\n}\r\n\r\n/* Other pages and arrows in pagination on blue */\r\n.nav_url {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n color: #fff;\r\n padding: 3px 2px 3px 3px;\r\n}\r\n\r\n/* Tree */\r\n.tree-body {\r\n background-color: @@TreeBgColor@@;\r\n height: 100%\r\n}\r\n\r\n.tree_head.td, .tree_head, .tree_head:hover {\r\n font-weight: bold;\r\n font-size: 10px;\r\n color: #FFFFFF;\r\n font-family: Verdana, Arial;\r\n text-decoration: none;\r\n}\r\n\r\n.tree {\r\n padding: 0px;\r\n border: none;\r\n border-collapse: collapse;\r\n}\r\n\r\n.tree tr td {\r\n padding: 0px;\r\n margin: 0px;\r\n font-family: helvetica, arial, verdana,;\r\n font-size: 11px;\r\n white-space: nowrap;\r\n}\r\n\r\n.tree tr td a {\r\n font-size: 11px;\r\n color: @@TreeColor@@;\r\n font-family: Helvetica, Arial, Verdana;\r\n text-decoration: none;\r\n padding: 2px 0px 2px 2px;\r\n}\r\n\r\n.tree tr.highlighted td a {\r\n background-color: @@TreeHighBgColor@@;\r\n color: @@TreeHighColor@@;\r\n}\r\n\r\n.tree tr.highlighted td a:hover {\r\n color: #fff;\r\n}\r\n\r\n.tree tr td a:hover {\r\n color: #000000;\r\n}', 'just_logo.gif', 'a:20:{s:11:"HeadBgColor";a:2:{s:11:"Description";s:27:"Head frame background color";s:5:"Value";s:7:"#1961B8";}s:9:"HeadColor";a:2:{s:11:"Description";s:21:"Head frame text color";s:5:"Value";s:7:"#CCFF00";}s:14:"SectionBgColor";a:2:{s:11:"Description";s:28:"Section bar background color";s:5:"Value";s:7:"#FFFFFF";}s:12:"SectionColor";a:2:{s:11:"Description";s:22:"Section bar text color";s:5:"Value";s:7:"#2D79D6";}s:12:"HeadBarColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:14:"HeadBarBgColor";a:1:{s:5:"Value";s:7:"#1961B8";}s:13:"TitleBarColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:15:"TitleBarBgColor";a:1:{s:5:"Value";s:7:"#2D79D6";}s:14:"ToolbarBgColor";a:1:{s:5:"Value";s:7:"#F0F1EB";}s:14:"FiltersBgColor";a:1:{s:5:"Value";s:7:"#D7D7D7";}s:17:"ColumnTitlesColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:19:"ColumnTitlesBgColor";a:1:{s:5:"Value";s:7:"#999999";}s:8:"OddColor";a:1:{s:5:"Value";s:7:"#000000";}s:10:"OddBgColor";a:1:{s:5:"Value";s:7:"#F6F6F6";}s:9:"EvenColor";a:1:{s:5:"Value";s:7:"#000000";}s:11:"EvenBgColor";a:1:{s:5:"Value";s:7:"#EBEBEB";}s:9:"TreeColor";a:1:{s:5:"Value";s:7:"#006F99";}s:11:"TreeBgColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:13:"TreeHighColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:15:"TreeHighBgColor";a:1:{s:5:"Value";s:7:"#4A92CE";}}', 1178706881, 1); INSERT INTO Permissions VALUES (0, 'in-portal:skins.view', 11, 1, 1, 0), (0, 'in-portal:skins.add', 11, 1, 1, 0), (0, 'in-portal:skins.edit', 11, 1, 1, 0), (0, 'in-portal:skins.delete', 11, 1, 1, 0); # ===== v 4.1.1 ===== DROP TABLE EmailQueue; CREATE TABLE EmailQueue ( EmailQueueId int(10) unsigned NOT NULL auto_increment, ToEmail varchar(255) NOT NULL default '', `Subject` varchar(255) NOT NULL default '', MessageHeaders text, MessageBody longtext, Queued int(10) unsigned NOT NULL default '0', SendRetries int(10) unsigned NOT NULL default '0', LastSendRetry int(10) unsigned NOT NULL default '0', PRIMARY KEY (EmailQueueId), KEY LastSendRetry (LastSendRetry), KEY SendRetries (SendRetries) ); ALTER TABLE Events ADD ReplacementTags TEXT AFTER Event; # ===== v 4.2.0 ===== ALTER TABLE CustomField ADD MultiLingual TINYINT UNSIGNED NOT NULL DEFAULT '1' AFTER FieldLabel; ALTER TABLE Category ADD TreeLeft BIGINT NOT NULL AFTER ParentPath, ADD TreeRight BIGINT NOT NULL AFTER TreeLeft; ALTER TABLE Category ADD INDEX (TreeLeft); ALTER TABLE Category ADD INDEX (TreeRight); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'CategoriesRebuildSerial', '0', 'In-Portal', ''); UPDATE ConfigurationAdmin SET `element_type` = 'textarea' WHERE `VariableName` IN ('Category_MetaKey', 'Category_MetaDesc'); ALTER TABLE PortalUser CHANGE FirstName FirstName VARCHAR(255) NOT NULL DEFAULT '', CHANGE LastName LastName VARCHAR(255) NOT NULL DEFAULT ''; # ===== v 4.2.1 ===== INSERT INTO ConfigurationAdmin VALUES ('UseSmallHeader', 'la_Text_Website', 'la_config_UseSmallHeader', 'checkbox', '', '', 10.21, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'UseSmallHeader', '0', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('User_Default_Registration_Country', 'la_Text_General', 'la_config_DefaultRegistrationCountry', 'select', NULL , '=+,SELECT DestName AS OptionName, DestId AS OptionValue FROM StdDestinations WHERE DestParentId IS NULL Order BY OptionName', 10.111, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'User_Default_Registration_Country', '', 'In-Portal:Users', 'in-portal:configure_users'); ALTER TABLE Category ADD SymLinkCategoryId INT UNSIGNED NULL DEFAULT NULL AFTER `Type`, ADD INDEX (SymLinkCategoryId); ALTER TABLE ConfigurationValues CHANGE VariableValue VariableValue TEXT NULL DEFAULT NULL; ALTER TABLE Language ADD AdminInterfaceLang TINYINT UNSIGNED NOT NULL AFTER PrimaryLang, ADD Priority INT NOT NULL AFTER AdminInterfaceLang; UPDATE Language SET AdminInterfaceLang = 1 WHERE PrimaryLang = 1; DELETE FROM PersistantSessionData WHERE VariableName = 'lang_columns_.'; ALTER TABLE SessionData CHANGE VariableValue VariableValue longtext NOT NULL; INSERT INTO ConfigurationAdmin VALUES ('CSVExportDelimiter', 'la_Text_CSV_Export', 'la_config_CSVExportDelimiter', 'select', NULL, '0=la_Tab,1=la_Comma,2=la_Semicolon,3=la_Space,4=la_Colon', 40.1, 0, 1); INSERT INTO ConfigurationAdmin VALUES ('CSVExportEnclosure', 'la_Text_CSV_Export', 'la_config_CSVExportEnclosure', 'radio', NULL, '0=la_Doublequotes,1=la_Quotes', 40.2, 0, 1); INSERT INTO ConfigurationAdmin VALUES ('CSVExportSeparator', 'la_Text_CSV_Export', 'la_config_CSVExportSeparator', 'radio', NULL, '0=la_Linux,1=la_Windows', 40.3, 0, 1); INSERT INTO ConfigurationAdmin VALUES ('CSVExportEncoding', 'la_Text_CSV_Export', 'la_config_CSVExportEncoding', 'radio', NULL, '0=la_Unicode,1=la_Regular', 40.4, 0, 1); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'CSVExportDelimiter', '0', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'CSVExportEnclosure', '0', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'CSVExportSeparator', '0', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'CSVExportEncoding', '0', 'In-Portal', 'in-portal:configure_general'); # ===== v 4.2.2 ===== INSERT INTO ConfigurationAdmin VALUES ('UseColumnFreezer', 'la_Text_Website', 'la_config_UseColumnFreezer', 'checkbox', '', '', 10.22, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'UseColumnFreezer', '0', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('TrimRequiredFields', 'la_Text_Website', 'la_config_TrimRequiredFields', 'checkbox', '', '', 10.23, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'TrimRequiredFields', '0', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('MenuFrameWidth', 'la_title_General', 'la_prompt_MenuFrameWidth', 'text', NULL, NULL, '11', '0', '0'); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'MenuFrameWidth', 200, 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('DefaultSettingsUserId', 'la_title_General', 'la_prompt_DefaultUserId', 'text', NULL, NULL, '12', '0', '0'); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'DefaultSettingsUserId', -1, 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('KeepSessionOnBrowserClose', 'la_title_General', 'la_prompt_KeepSessionOnBrowserClose', 'checkbox', NULL, NULL, '13', '0', '0'); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'KeepSessionOnBrowserClose', 0, 'In-Portal', 'in-portal:configure_general'); ALTER TABLE PersistantSessionData ADD VariableId BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST; # ===== v 4.3.0 ===== INSERT INTO ConfigurationAdmin VALUES ('u_MaxImageCount', 'la_section_ImageSettings', 'la_config_MaxImageCount', 'text', '', '', 30.01, 0, 0); INSERT INTO ConfigurationAdmin VALUES ('u_ThumbnailImageWidth', 'la_section_ImageSettings', 'la_config_ThumbnailImageWidth', 'text', '', '', 30.02, 0, 0); INSERT INTO ConfigurationAdmin VALUES ('u_ThumbnailImageHeight', 'la_section_ImageSettings', 'la_config_ThumbnailImageHeight', 'text', '', '', 30.03, 0, 0); INSERT INTO ConfigurationAdmin VALUES ('u_FullImageWidth', 'la_section_ImageSettings', 'la_config_FullImageWidth', 'text', '', '', 30.04, 0, 0); INSERT INTO ConfigurationAdmin VALUES ('u_FullImageHeight', 'la_section_ImageSettings', 'la_config_FullImageHeight', 'text', '', '', 30.05, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_MaxImageCount', 5, 'In-Portal:Users', 'in-portal:configure_users'); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_ThumbnailImageWidth', 120, 'In-Portal:Users', 'in-portal:configure_users'); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_ThumbnailImageHeight', 120, 'In-Portal:Users', 'in-portal:configure_users'); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_FullImageWidth', 450, 'In-Portal:Users', 'in-portal:configure_users'); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_FullImageHeight', 450, 'In-Portal:Users', 'in-portal:configure_users'); CREATE TABLE ChangeLogs ( ChangeLogId bigint(20) NOT NULL auto_increment, PortalUserId int(11) NOT NULL default '0', SessionLogId int(11) NOT NULL default '0', `Action` tinyint(4) NOT NULL default '0', OccuredOn int(11) NOT NULL default '0', Prefix varchar(255) NOT NULL default '', ItemId bigint(20) NOT NULL default '0', Changes text NOT NULL, MasterPrefix varchar(255) NOT NULL default '', MasterId bigint(20) NOT NULL default '0', PRIMARY KEY (ChangeLogId), KEY PortalUserId (PortalUserId), KEY SessionLogId (SessionLogId), KEY `Action` (`Action`), KEY OccuredOn (OccuredOn), KEY Prefix (Prefix), KEY MasterPrefix (MasterPrefix) ); CREATE TABLE SessionLogs ( SessionLogId bigint(20) NOT NULL auto_increment, PortalUserId int(11) NOT NULL default '0', SessionId int(10) NOT NULL default '0', `Status` tinyint(4) NOT NULL default '1', SessionStart int(11) NOT NULL default '0', SessionEnd int(11) default NULL, IP varchar(15) NOT NULL default '', AffectedItems int(11) NOT NULL default '0', PRIMARY KEY (SessionLogId), KEY SessionId (SessionId), KEY `Status` (`Status`), KEY PortalUserId (PortalUserId) ); ALTER TABLE CustomField ADD INDEX (MultiLingual), ADD INDEX (DisplayOrder), ADD INDEX (OnGeneralTab), ADD INDEX (IsSystem); ALTER TABLE ConfigurationAdmin ADD INDEX (DisplayOrder), ADD INDEX (GroupDisplayOrder), ADD INDEX (Install); ALTER TABLE EmailSubscribers ADD INDEX (EmailMessageId), ADD INDEX (PortalUserId); ALTER TABLE Events ADD INDEX (`Type`), ADD INDEX (Enabled); ALTER TABLE Language ADD INDEX (Enabled), ADD INDEX (PrimaryLang), ADD INDEX (AdminInterfaceLang), ADD INDEX (Priority); ALTER TABLE Modules ADD INDEX (Loaded), ADD INDEX (LoadOrder); ALTER TABLE PhraseCache ADD INDEX (CacheDate), ADD INDEX (ThemeId), ADD INDEX (StylesheetId); ALTER TABLE PortalGroup ADD INDEX (CreatedOn); ALTER TABLE PortalUser ADD INDEX (Status), ADD INDEX (Modified), ADD INDEX (dob), ADD INDEX (IsBanned); ALTER TABLE Theme ADD INDEX (Enabled), ADD INDEX (StylesheetId), ADD INDEX (PrimaryTheme); ALTER TABLE UserGroup ADD INDEX (MembershipExpires), ADD INDEX (ExpirationReminderSent); ALTER TABLE EmailLog ADD INDEX (`timestamp`); ALTER TABLE StdDestinations ADD INDEX (DestType), ADD INDEX (DestParentId); ALTER TABLE Category ADD INDEX (Status), ADD INDEX (CreatedOn), ADD INDEX (EditorsPick); ALTER TABLE Stylesheets ADD INDEX (Enabled), ADD INDEX (LastCompiled); ALTER TABLE Counters ADD INDEX (IsClone), ADD INDEX (LifeTime), ADD INDEX (LastCounted); ALTER TABLE Skins ADD INDEX (IsPrimary), ADD INDEX (LastCompiled); INSERT INTO ConfigurationAdmin VALUES ('UseChangeLog', 'la_Text_Website', 'la_config_UseChangeLog', 'checkbox', '', '', 10.25, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'UseChangeLog', '0', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('AutoRefreshIntervals', 'la_Text_Website', 'la_config_AutoRefreshIntervals', 'text', '', '', 10.26, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'AutoRefreshIntervals', '1,5,15,30,60,120,240', 'In-Portal', 'in-portal:configure_general'); DELETE FROM Cache WHERE SUBSTRING(VarName, 1, 7) = 'mod_rw_'; ALTER TABLE Category CHANGE `Status` `Status` TINYINT(4) NOT NULL DEFAULT '2'; # ===== v 4.3.1 ===== INSERT INTO ConfigurationAdmin VALUES ('RememberLastAdminTemplate', 'la_Text_General', 'la_config_RememberLastAdminTemplate', 'checkbox', '', '', 10.13, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'RememberLastAdminTemplate', '', 'In-Portal:Users', 'in-portal:configure_users'); INSERT INTO ConfigurationAdmin VALUES ('AllowSelectGroupOnFront', 'la_Text_General', 'la_config_AllowSelectGroupOnFront', 'checkbox', NULL, NULL, 10.13, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'AllowSelectGroupOnFront', '0', 'In-Portal:Users', 'in-portal:configure_users'); CREATE TABLE StatisticsCapture ( StatisticsId int(10) unsigned NOT NULL auto_increment, TemplateName varchar(255) NOT NULL default '', Hits int(10) unsigned NOT NULL default '0', LastHit int(11) NOT NULL default '0', ScriptTimeMin decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', ScriptTimeAvg decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', ScriptTimeMax decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', SqlTimeMin decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', SqlTimeAvg decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', SqlTimeMax decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', SqlCountMin decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', SqlCountAvg decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', SqlCountMax decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', PRIMARY KEY (StatisticsId), KEY TemplateName (TemplateName), KEY Hits (Hits), KEY LastHit (LastHit), KEY ScriptTimeMin (ScriptTimeMin), KEY ScriptTimeAvg (ScriptTimeAvg), KEY ScriptTimeMax (ScriptTimeMax), KEY SqlTimeMin (SqlTimeMin), KEY SqlTimeAvg (SqlTimeAvg), KEY SqlTimeMax (SqlTimeMax), KEY SqlCountMin (SqlCountMin), KEY SqlCountAvg (SqlCountAvg), KEY SqlCountMax (SqlCountMax) ); CREATE TABLE SlowSqlCapture ( CaptureId int(10) unsigned NOT NULL auto_increment, TemplateNames text, Hits int(10) unsigned NOT NULL default '0', LastHit int(11) NOT NULL default '0', SqlQuery text, TimeMin decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', TimeAvg decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', TimeMax decimal(40,20) unsigned NOT NULL default '0.00000000000000000000', QueryCrc int(11) NOT NULL default '0', PRIMARY KEY (CaptureId), KEY Hits (Hits), KEY LastHit (LastHit), KEY TimeMin (TimeMin), KEY TimeAvg (TimeAvg), KEY TimeMax (TimeMax), KEY QueryCrc (QueryCrc) ); ALTER TABLE PortalGroup ADD FrontRegistration TINYINT UNSIGNED NOT NULL; UPDATE PortalGroup SET FrontRegistration = 1 WHERE GroupId = 13; INSERT INTO ConfigurationAdmin VALUES ('ForceImageMagickResize', 'la_Text_Website', 'la_config_ForceImageMagickResize', 'checkbox', '', '', 10.28, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'ForceImageMagickResize', '0', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('AdminSSL_URL', 'la_Text_Website', 'la_config_AdminSSL_URL', 'text', '', '', 10.091, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'AdminSSL_URL', '', 'In-Portal', 'in-portal:configure_general'); # ===== v 4.3.9 ===== ALTER TABLE CustomField CHANGE ValueList ValueList TEXT NULL DEFAULT NULL, ADD DefaultValue VARCHAR(255) NOT NULL AFTER ValueList, ADD INDEX (DefaultValue); UPDATE CustomField SET ValueList = REPLACE(ValueList, ',', '||'); CREATE TABLE Agents ( AgentId int(11) NOT NULL auto_increment, AgentName varchar(255) NOT NULL default '', AgentType tinyint(3) unsigned NOT NULL default '1', Status tinyint(3) unsigned NOT NULL default '1', Event varchar(255) NOT NULL default '', RunInterval int(10) unsigned NOT NULL default '0', RunMode tinyint(3) unsigned NOT NULL default '2', LastRunOn int(10) unsigned default NULL, LastRunStatus tinyint(3) unsigned NOT NULL default '1', NextRunOn int(11) default NULL, RunTime int(10) unsigned NOT NULL default '0', PRIMARY KEY (AgentId), KEY Status (Status), KEY RunInterval (RunInterval), KEY RunMode (RunMode), KEY AgentType (AgentType), KEY LastRunOn (LastRunOn), KEY LastRunStatus (LastRunStatus), KEY RunTime (RunTime), KEY NextRunOn (NextRunOn) ); INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:agents.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:agents.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:agents.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:agents.view', 11, 1, 1, 0); INSERT INTO ConfigurationAdmin VALUES ('FilenameSpecialCharReplacement', 'la_Text_General', 'la_config_FilenameSpecialCharReplacement', 'select', NULL, '_=+_,-=+-', 10.16, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'FilenameSpecialCharReplacement', '_', 'In-Portal', 'in-portal:configure_categories'); CREATE TABLE SpellingDictionary ( SpellingDictionaryId int(11) NOT NULL auto_increment, MisspelledWord varchar(255) NOT NULL default '', SuggestedCorrection varchar(255) NOT NULL default '', PRIMARY KEY (SpellingDictionaryId), KEY MisspelledWord (MisspelledWord), KEY SuggestedCorrection (SuggestedCorrection) ); INSERT INTO ConfigurationValues VALUES(NULL, 'YahooApplicationId', '', 'In-Portal', 'in-portal:configure_categories'); INSERT INTO ConfigurationAdmin VALUES('YahooApplicationId', 'la_Text_General', 'la_config_YahooApplicationId', 'text', NULL, NULL, 10.15, 0, 0); CREATE TABLE Thesaurus ( ThesaurusId int(11) NOT NULL auto_increment, SearchTerm varchar(255) NOT NULL default '', ThesaurusTerm varchar(255) NOT NULL default '', ThesaurusType tinyint(3) unsigned NOT NULL default '0', PRIMARY KEY (ThesaurusId), KEY ThesaurusType (ThesaurusType), KEY SearchTerm (SearchTerm) ); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:ban_rulelist.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:ban_rulelist.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:ban_rulelist.add', 11, 1, 1, 0); ALTER TABLE Language ADD FilenameReplacements TEXT NULL AFTER UnitSystem; ALTER TABLE Language ADD Locale varchar(10) NOT NULL default 'en-US' AFTER FilenameReplacements; CREATE TABLE LocalesList ( LocaleId int(11) NOT NULL auto_increment, LocaleIdentifier varchar(6) NOT NULL default '', LocaleName varchar(255) NOT NULL default '', Locale varchar(20) NOT NULL default '', ScriptTag varchar(255) NOT NULL default '', ANSICodePage varchar(10) NOT NULL default '', PRIMARY KEY (LocaleId) ); INSERT INTO LocalesList VALUES (1, '0x0436', 'Afrikaans (South Africa)', 'af-ZA', 'Latn', '1252'), (2, '0x041c', 'Albanian (Albania)', 'sq-AL', 'Latn', '1252'), (3, '0x0484', 'Alsatian (France)', 'gsw-FR', '', ''), (4, '0x045e', 'Amharic (Ethiopia)', 'am-ET', '', 'UTF-8'), (5, '0x1401', 'Arabic (Algeria)', 'ar-DZ', 'Arab', '1256'), (6, '0x3c01', 'Arabic (Bahrain)', 'ar-BH', 'Arab', '1256'), (7, '0x0c01', 'Arabic (Egypt)', 'ar-EG', 'Arab', '1256'), (8, '0x0801', 'Arabic (Iraq)', 'ar-IQ', 'Arab', '1256'), (9, '0x2c01', 'Arabic (Jordan)', 'ar-JO', 'Arab', '1256'), (10, '0x3401', 'Arabic (Kuwait)', 'ar-KW', 'Arab', '1256'), (11, '0x3001', 'Arabic (Lebanon)', 'ar-LB', 'Arab', '1256'), (12, '0x1001', 'Arabic (Libya)', 'ar-LY', 'Arab', '1256'), (13, '0x1801', 'Arabic (Morocco)', 'ar-MA', 'Arab', '1256'), (14, '0x2001', 'Arabic (Oman)', 'ar-OM', 'Arab', '1256'), (15, '0x4001', 'Arabic (Qatar)', 'ar-QA', 'Arab', '1256'), (16, '0x0401', 'Arabic (Saudi Arabia)', 'ar-SA', 'Arab', '1256'), (17, '0x2801', 'Arabic (Syria)', 'ar-SY', 'Arab', '1256'), (18, '0x1c01', 'Arabic (Tunisia)', 'ar-TN', 'Arab', '1256'), (19, '0x3801', 'Arabic (U.A.E.)', 'ar-AE', 'Arab', '1256'), (20, '0x2401', 'Arabic (Yemen)', 'ar-YE', 'Arab', '1256'), (21, '0x042b', 'Armenian (Armenia)', 'hy-AM', 'Armn', 'UTF-8'), (22, '0x044d', 'Assamese (India)', 'as-IN', '', 'UTF-8'), (23, '0x082c', 'Azeri (Azerbaijan, Cyrillic)', 'az-Cyrl-AZ', 'Cyrl', '1251'), (24, '0x042c', 'Azeri (Azerbaijan, Latin)', 'az-Latn-AZ', 'Latn', '1254'), (25, '0x046d', 'Bashkir (Russia)', 'ba-RU', '', ''), (26, '0x042d', 'Basque (Basque)', 'eu-ES', 'Latn', '1252'), (27, '0x0423', 'Belarusian (Belarus)', 'be-BY', 'Cyrl', '1251'), (28, '0x0445', 'Bengali (India)', 'bn-IN', 'Beng', 'UTF-8'), (29, '0x201a', 'Bosnian (Bosnia and Herzegovina, Cyrillic)', 'bs-Cyrl-BA', 'Cyrl', '1251'), (30, '0x141a', 'Bosnian (Bosnia and Herzegovina, Latin)', 'bs-Latn-BA', 'Latn', '1250'), (31, '0x047e', 'Breton (France)', 'br-FR', 'Latn', '1252'), (32, '0x0402', 'Bulgarian (Bulgaria)', 'bg-BG', 'Cyrl', '1251'), (33, '0x0403', 'Catalan (Catalan)', 'ca-ES', 'Latn', '1252'), (34, '0x0c04', 'Chinese (Hong Kong SAR, PRC)', 'zh-HK', 'Hant', '950'), (35, '0x1404', 'Chinese (Macao SAR)', 'zh-MO', 'Hant', '950'), (36, '0x0804', 'Chinese (PRC)', 'zh-CN', 'Hans', '936'), (37, '0x1004', 'Chinese (Singapore)', 'zh-SG', 'Hans', '936'), (38, '0x0404', 'Chinese (Taiwan)', 'zh-TW', 'Hant', '950'), (39, '0x101a', 'Croatian (Bosnia and Herzegovina, Latin)', 'hr-BA', 'Latn', '1250'), (40, '0x041a', 'Croatian (Croatia)', 'hr-HR', 'Latn', '1250'), (41, '0x0405', 'Czech (Czech Republic)', 'cs-CZ', 'Latn', '1250'), (42, '0x0406', 'Danish (Denmark)', 'da-DK', 'Latn', '1252'), (43, '0x048c', 'Dari (Afghanistan)', 'prs-AF', 'Arab', '1256'), (44, '0x0465', 'Divehi (Maldives)', 'dv-MV', 'Thaa', 'UTF-8'), (45, '0x0813', 'Dutch (Belgium)', 'nl-BE', 'Latn', '1252'), (46, '0x0413', 'Dutch (Netherlands)', 'nl-NL', 'Latn', '1252'), (47, '0x0c09', 'English (Australia)', 'en-AU', 'Latn', '1252'), (48, '0x2809', 'English (Belize)', 'en-BZ', 'Latn', '1252'), (49, '0x1009', 'English (Canada)', 'en-CA', 'Latn', '1252'), (50, '0x2409', 'English (Caribbean)', 'en-029', 'Latn', '1252'), (51, '0x4009', 'English (India)', 'en-IN', 'Latn', '1252'), (52, '0x1809', 'English (Ireland)', 'en-IE', 'Latn', '1252'), (53, '0x2009', 'English (Jamaica)', 'en-JM', 'Latn', '1252'), (54, '0x4409', 'English (Malaysia)', 'en-MY', 'Latn', '1252'), (55, '0x1409', 'English (New Zealand)', 'en-NZ', 'Latn', '1252'), (56, '0x3409', 'English (Philippines)', 'en-PH', 'Latn', '1252'), (57, '0x4809', 'English (Singapore)', 'en-SG', 'Latn', '1252'), (58, '0x1c09', 'English (South Africa)', 'en-ZA', 'Latn', '1252'), (59, '0x2c09', 'English (Trinidad and Tobago)', 'en-TT', 'Latn', '1252'), (60, '0x0809', 'English (United Kingdom)', 'en-GB', 'Latn', '1252'), (61, '0x0409', 'English (United States)', 'en-US', 'Latn', '1252'), (62, '0x3009', 'English (Zimbabwe)', 'en-ZW', 'Latn', '1252'), (63, '0x0425', 'Estonian (Estonia)', 'et-EE', 'Latn', '1257'), (64, '0x0438', 'Faroese (Faroe Islands)', 'fo-FO', 'Latn', '1252'), (65, '0x0464', 'Filipino (Philippines)', 'fil-PH', 'Latn', '1252'), (66, '0x040b', 'Finnish (Finland)', 'fi-FI', 'Latn', '1252'), (67, '0x080c', 'French (Belgium)', 'fr-BE', 'Latn', '1252'), (68, '0x0c0c', 'French (Canada)', 'fr-CA', 'Latn', '1252'), (69, '0x040c', 'French (France)', 'fr-FR', 'Latn', '1252'), (70, '0x140c', 'French (Luxembourg)', 'fr-LU', 'Latn', '1252'), (71, '0x180c', 'French (Monaco)', 'fr-MC', 'Latn', '1252'), (72, '0x100c', 'French (Switzerland)', 'fr-CH', 'Latn', '1252'), (73, '0x0462', 'Frisian (Netherlands)', 'fy-NL', 'Latn', '1252'), (74, '0x0456', 'Galician (Spain)', 'gl-ES', 'Latn', '1252'), (75, '0x0437', 'Georgian (Georgia)', 'ka-GE', 'Geor', 'UTF-8'), (76, '0x0c07', 'German (Austria)', 'de-AT', 'Latn', '1252'), (77, '0x0407', 'German (Germany)', 'de-DE', 'Latn', '1252'), (78, '0x1407', 'German (Liechtenstein)', 'de-LI', 'Latn', '1252'), (79, '0x1007', 'German (Luxembourg)', 'de-LU', 'Latn', '1252'), (80, '0x0807', 'German (Switzerland)', 'de-CH', 'Latn', '1252'), (81, '0x0408', 'Greek (Greece)', 'el-GR', 'Grek', '1253'), (82, '0x046f', 'Greenlandic (Greenland)', 'kl-GL', 'Latn', '1252'), (83, '0x0447', 'Gujarati (India)', 'gu-IN', 'Gujr', 'UTF-8'), (84, '0x0468', 'Hausa (Nigeria, Latin)', 'ha-Latn-NG', 'Latn', '1252'), (85, '0x040d', 'Hebrew (Israel)', 'he-IL', 'Hebr', '1255'), (86, '0x0439', 'Hindi (India)', 'hi-IN', 'Deva', 'UTF-8'), (87, '0x040e', 'Hungarian (Hungary)', 'hu-HU', 'Latn', '1250'), (88, '0x040f', 'Icelandic (Iceland)', 'is-IS', 'Latn', '1252'), (89, '0x0470', 'Igbo (Nigeria)', 'ig-NG', '', ''), (90, '0x0421', 'Indonesian (Indonesia)', 'id-ID', 'Latn', '1252'), (91, '0x085d', 'Inuktitut (Canada, Latin)', 'iu-Latn-CA', 'Latn', '1252'), (92, '0x045d', 'Inuktitut (Canada, Syllabics)', 'iu-Cans-CA', 'Cans', 'UTF-8'), (93, '0x083c', 'Irish (Ireland)', 'ga-IE', 'Latn', '1252'), (94, '0x0410', 'Italian (Italy)', 'it-IT', 'Latn', '1252'), (95, '0x0810', 'Italian (Switzerland)', 'it-CH', 'Latn', '1252'), (96, '0x0411', 'Japanese (Japan)', 'ja-JP', 'Hani;Hira;Kana', '932'), (97, '0x044b', 'Kannada (India)', 'kn-IN', 'Knda', 'UTF-8'), (98, '0x043f', 'Kazakh (Kazakhstan)', 'kk-KZ', 'Cyrl', '1251'), (99, '0x0453', 'Khmer (Cambodia)', 'kh-KH', 'Khmr', 'UTF-8'), (100, '0x0486', 'K''iche (Guatemala)', 'qut-GT', 'Latn', '1252'), (101, '0x0487', 'Kinyarwanda (Rwanda)', 'rw-RW', 'Latn', '1252'), (102, '0x0457', 'Konkani (India)', 'kok-IN', 'Deva', 'UTF-8'), (103, '0x0812', 'Windows 95, Windows NT 4.0 only: Korean (Johab)', '', '', ''), (104, '0x0412', 'Korean (Korea)', 'ko-KR', 'Hang;Hani', '949'), (105, '0x0440', 'Kyrgyz (Kyrgyzstan)', 'ky-KG', 'Cyrl', '1251'), (106, '0x0454', 'Lao (Lao PDR)', 'lo-LA', 'Laoo', 'UTF-8'), (107, '0x0426', 'Latvian (Latvia)', 'lv-LV', 'Latn', '1257'), (108, '0x0427', 'Lithuanian (Lithuania)', 'lt-LT', 'Latn', '1257'), (109, '0x082e', 'Lower Sorbian (Germany)', 'dsb-DE', 'Latn', '1252'), (110, '0x046e', 'Luxembourgish (Luxembourg)', 'lb-LU', 'Latn', '1252'), (111, '0x042f', 'Macedonian (Macedonia, FYROM)', 'mk-MK', 'Cyrl', '1251'), (112, '0x083e', 'Malay (Brunei Darussalam)', 'ms-BN', 'Latn', '1252'), (113, '0x043e', 'Malay (Malaysia)', 'ms-MY', 'Latn', '1252'), (114, '0x044c', 'Malayalam (India)', 'ml-IN', 'Mlym', 'UTF-8'), (115, '0x043a', 'Maltese (Malta)', 'mt-MT', 'Latn', '1252'), (116, '0x0481', 'Maori (New Zealand)', 'mi-NZ', 'Latn', '1252'), (117, '0x047a', 'Mapudungun (Chile)', 'arn-CL', 'Latn', '1252'), (118, '0x044e', 'Marathi (India)', 'mr-IN', 'Deva', 'UTF-8'), (119, '0x047c', 'Mohawk (Canada)', 'moh-CA', 'Latn', '1252'), (120, '0x0450', 'Mongolian (Mongolia)', 'mn-Cyrl-MN', 'Cyrl', '1251'), (121, '0x0850', 'Mongolian (PRC)', 'mn-Mong-CN', 'Mong', 'UTF-8'), (122, '0x0850', 'Nepali (India)', 'ne-IN', '__', 'UTF-8'), (123, '0x0461', 'Nepali (Nepal)', 'ne-NP', 'Deva', 'UTF-8'), (124, '0x0414', 'Norwegian (Bokmål, Norway)', 'nb-NO', 'Latn', '1252'), (125, '0x0814', 'Norwegian (Nynorsk, Norway)', 'nn-NO', 'Latn', '1252'), (126, '0x0482', 'Occitan (France)', 'oc-FR', 'Latn', '1252'), (127, '0x0448', 'Oriya (India)', 'or-IN', 'Orya', 'UTF-8'), (128, '0x0463', 'Pashto (Afghanistan)', 'ps-AF', '', ''), (129, '0x0429', 'Persian (Iran)', 'fa-IR', 'Arab', '1256'), (130, '0x0415', 'Polish (Poland)', 'pl-PL', 'Latn', '1250'), (131, '0x0416', 'Portuguese (Brazil)', 'pt-BR', 'Latn', '1252'), (132, '0x0816', 'Portuguese (Portugal)', 'pt-PT', 'Latn', '1252'), (133, '0x0446', 'Punjabi (India)', 'pa-IN', 'Guru', 'UTF-8'), (134, '0x046b', 'Quechua (Bolivia)', 'quz-BO', 'Latn', '1252'), (135, '0x086b', 'Quechua (Ecuador)', 'quz-EC', 'Latn', '1252'), (136, '0x0c6b', 'Quechua (Peru)', 'quz-PE', 'Latn', '1252'), (137, '0x0418', 'Romanian (Romania)', 'ro-RO', 'Latn', '1250'), (138, '0x0417', 'Romansh (Switzerland)', 'rm-CH', 'Latn', '1252'), (139, '0x0419', 'Russian (Russia)', 'ru-RU', 'Cyrl', '1251'), (140, '0x243b', 'Sami (Inari, Finland)', 'smn-FI', 'Latn', '1252'), (141, '0x103b', 'Sami (Lule, Norway)', 'smj-NO', 'Latn', '1252'), (142, '0x143b', 'Sami (Lule, Sweden)', 'smj-SE', 'Latn', '1252'), (143, '0x0c3b', 'Sami (Northern, Finland)', 'se-FI', 'Latn', '1252'), (144, '0x043b', 'Sami (Northern, Norway)', 'se-NO', 'Latn', '1252'), (145, '0x083b', 'Sami (Northern, Sweden)', 'se-SE', 'Latn', '1252'), (146, '0x203b', 'Sami (Skolt, Finland)', 'sms-FI', 'Latn', '1252'), (147, '0x183b', 'Sami (Southern, Norway)', 'sma-NO', 'Latn', '1252'), (148, '0x1c3b', 'Sami (Southern, Sweden)', 'sma-SE', 'Latn', '1252'), (149, '0x044f', 'Sanskrit (India)', 'sa-IN', 'Deva', 'UTF-8'), (150, '0x1c1a', 'Serbian (Bosnia and Herzegovina, Cyrillic)', 'sr-Cyrl-BA', 'Cyrl', '1251'), (151, '0x181a', 'Serbian (Bosnia and Herzegovina, Latin)', 'sr-Latn-BA', 'Latn', '1250'), (152, '0x0c1a', 'Serbian (Serbia, Cyrillic)', 'sr-Cyrl-CS', 'Cyrl', '1251'), (153, '0x081a', 'Serbian (Serbia, Latin)', 'sr-Latn-CS', 'Latn', '1250'), (154, '0x046c', 'Sesotho sa Leboa/Northern Sotho (South Africa)', 'ns-ZA', 'Latn', '1252'), (155, '0x0432', 'Setswana/Tswana (South Africa)', 'tn-ZA', 'Latn', '1252'), (156, '0x045b', 'Sinhala (Sri Lanka)', 'si-LK', 'Sinh', 'UTF-8'), (157, '0x041b', 'Slovak (Slovakia)', 'sk-SK', 'Latn', '1250'), (158, '0x0424', 'Slovenian (Slovenia)', 'sl-SI', 'Latn', '1250'), (159, '0x2c0a', 'Spanish (Argentina)', 'es-AR', 'Latn', '1252'), (160, '0x400a', 'Spanish (Bolivia)', 'es-BO', 'Latn', '1252'), (161, '0x340a', 'Spanish (Chile)', 'es-CL', 'Latn', '1252'), (162, '0x240a', 'Spanish (Colombia)', 'es-CO', 'Latn', '1252'), (163, '0x140a', 'Spanish (Costa Rica)', 'es-CR', 'Latn', '1252'), (164, '0x1c0a', 'Spanish (Dominican Republic)', 'es-DO', 'Latn', '1252'), (165, '0x300a', 'Spanish (Ecuador)', 'es-EC', 'Latn', '1252'), (166, '0x440a', 'Spanish (El Salvador)', 'es-SV', 'Latn', '1252'), (167, '0x100a', 'Spanish (Guatemala)', 'es-GT', 'Latn', '1252'), (168, '0x480a', 'Spanish (Honduras)', 'es-HN', 'Latn', '1252'), (169, '0x080a', 'Spanish (Mexico)', 'es-MX', 'Latn', '1252'), (170, '0x4c0a', 'Spanish (Nicaragua)', 'es-NI', 'Latn', '1252'), (171, '0x180a', 'Spanish (Panama)', 'es-PA', 'Latn', '1252'), (172, '0x3c0a', 'Spanish (Paraguay)', 'es-PY', 'Latn', '1252'), (173, '0x280a', 'Spanish (Peru)', 'es-PE', 'Latn', '1252'), (174, '0x500a', 'Spanish (Puerto Rico)', 'es-PR', 'Latn', '1252'), (175, '0x0c0a', 'Spanish (Spain)', 'es-ES', 'Latn', '1252'), (176, '0x040a', 'Spanish (Spain, Traditional Sort)', 'es-ES_tradnl', 'Latn', '1252'), (177, '0x540a', 'Spanish (United States)', 'es-US', '', ''), (178, '0x380a', 'Spanish (Uruguay)', 'es-UY', 'Latn', '1252'), (179, '0x200a', 'Spanish (Venezuela)', 'es-VE', 'Latn', '1252'), (180, '0x0441', 'Swahili (Kenya)', 'sw-KE', 'Latn', '1252'), (181, '0x081d', 'Swedish (Finland)', 'sv-FI', 'Latn', '1252'), (182, '0x041d', 'Swedish (Sweden)', 'sv-SE', 'Latn', '1252'), (183, '0x045a', 'Syriac (Syria)', 'syr-SY', 'Syrc', 'UTF-8'), (184, '0x0428', 'Tajik (Tajikistan)', 'tg-Cyrl-TJ', 'Cyrl', '1251'), (185, '0x085f', 'Tamazight (Algeria, Latin)', 'tzm-Latn-DZ', 'Latn', '1252'), (186, '0x0449', 'Tamil (India)', 'ta-IN', 'Taml', 'UTF-8'), (187, '0x0444', 'Tatar (Russia)', 'tt-RU', 'Cyrl', '1251'), (188, '0x044a', 'Telugu (India)', 'te-IN', 'Telu', 'UTF-8'), (189, '0x041e', 'Thai (Thailand)', 'th-TH', 'Thai', '874'), (190, '0x0851', 'Tibetan (Bhutan)', 'bo-BT', 'Tibt', 'UTF-8'), (191, '0x0451', 'Tibetan (PRC)', 'bo-CN', 'Tibt', 'UTF-8'), (192, '0x041f', 'Turkish (Turkey)', 'tr-TR', 'Latn', '1254'), (193, '0x0442', 'Turkmen (Turkmenistan)', 'tk-TM', 'Cyrl', '1251'), (194, '0x0480', 'Uighur (PRC)', 'ug-CN', 'Arab', '1256'), (195, '0x0422', 'Ukrainian (Ukraine)', 'uk-UA', 'Cyrl', '1251'), (196, '0x042e', 'Upper Sorbian (Germany)', 'wen-DE', 'Latn', '1252'), (197, '0x0820', 'Urdu (India)', 'tr-IN', '', ''), (198, '0x0420', 'Urdu (Pakistan)', 'ur-PK', 'Arab', '1256'), (199, '0x0843', 'Uzbek (Uzbekistan, Cyrillic)', 'uz-Cyrl-UZ', 'Cyrl', '1251'), (200, '0x0443', 'Uzbek (Uzbekistan, Latin)', 'uz-Latn-UZ', 'Latn', '1254'), (201, '0x042a', 'Vietnamese (Vietnam)', 'vi-VN', 'Latn', '1258'), (202, '0x0452', 'Welsh (United Kingdom)', 'cy-GB', 'Latn', '1252'), (203, '0x0488', 'Wolof (Senegal)', 'wo-SN', 'Latn', '1252'), (204, '0x0434', 'Xhosa/isiXhosa (South Africa)', 'xh-ZA', 'Latn', '1252'), (205, '0x0485', 'Yakut (Russia)', 'sah-RU', 'Cyrl', '1251'), (206, '0x0478', 'Yi (PRC)', 'ii-CN', 'Yiii', 'UTF-8'), (207, '0x046a', 'Yoruba (Nigeria)', 'yo-NG', '', ''), (208, '0x0435', 'Zulu/isiZulu (South Africa)', 'zu-ZA', 'Latn', '1252'); UPDATE Phrase SET Module = 'Core' WHERE Module IN ('Proj-Base', 'In-Portal'); UPDATE Phrase SET Module = 'Core' WHERE Phrase IN ('la_fld_Phone', 'la_fld_City', 'la_fld_State', 'la_fld_Zip'); UPDATE Phrase SET Module = 'Core' WHERE Phrase IN ('la_col_Image', 'la_col_Username', 'la_fld_AddressLine1', 'la_fld_AddressLine2', 'la_fld_Comments', 'la_fld_Country', 'la_fld_Email', 'la_fld_Language', 'la_fld_Login', 'la_fld_MessageText', 'la_fld_MetaDescription', 'la_fld_MetaKeywords', 'la_fld_Password', 'la_fld_Username', 'la_fld_Type'); UPDATE Phrase SET Phrase = 'la_Add' WHERE Phrase = 'LA_ADD'; UPDATE Phrase SET Phrase = 'la_col_MembershipExpires' WHERE Phrase = 'la_col_membershipexpires'; UPDATE Phrase SET Phrase = 'la_ShortToolTip_Clone' WHERE Phrase = 'la_shorttooltip_clone'; UPDATE Phrase SET Phrase = 'la_ShortToolTip_Edit' WHERE Phrase = 'LA_SHORTTOOLTIP_EDIT'; UPDATE Phrase SET Phrase = 'la_ShortToolTip_Export' WHERE Phrase = 'LA_SHORTTOOLTIP_EXPORT'; UPDATE Phrase SET Phrase = 'la_ShortToolTip_GoUp' WHERE Phrase = 'LA_SHORTTOOLTIP_GOUP'; UPDATE Phrase SET Phrase = 'la_ShortToolTip_Import' WHERE Phrase = 'LA_SHORTTOOLTIP_IMPORT'; UPDATE Phrase SET Phrase = 'la_ShortToolTip_MoveUp' WHERE Phrase = 'la_shorttooltip_moveup'; UPDATE Phrase SET Phrase = 'la_ShortToolTip_MoveDown' WHERE Phrase = 'la_shorttooltip_movedown'; UPDATE Phrase SET Phrase = 'la_ShortToolTip_RescanThemes' WHERE Phrase = 'la_shorttooltip_rescanthemes'; UPDATE Phrase SET Phrase = 'la_ShortToolTip_SetPrimary' WHERE Phrase = 'LA_SHORTTOOLTIP_SETPRIMARY'; UPDATE Phrase SET Phrase = 'la_ShortToolTip_Rebuild' WHERE Phrase = 'LA_SHORTTOOLTIP_REBUILD'; UPDATE Phrase SET Phrase = 'la_Tab_Service' WHERE Phrase = 'la_tab_service'; UPDATE Phrase SET Phrase = 'la_tab_Files' WHERE Phrase = 'la_tab_files'; UPDATE Phrase SET Phrase = 'la_ToolTipShort_Edit_Current_Category' WHERE Phrase = 'LA_TOOLTIPSHORT_EDIT_CURRENT_CATEGORY'; UPDATE Phrase SET Phrase = 'la_ToolTip_Add' WHERE Phrase = 'LA_TOOLTIP_ADD'; UPDATE Phrase SET Phrase = 'la_ToolTip_Add_Product' WHERE Phrase = 'LA_TOOLTIP_ADD_PRODUCT'; UPDATE Phrase SET Phrase = 'la_ToolTip_NewSearchConfig' WHERE Phrase = 'LA_TOOLTIP_NEWSEARCHCONFIG'; UPDATE Phrase SET Phrase = 'la_ToolTip_Prev' WHERE Phrase = 'la_tooltip_prev'; UPDATE Phrase SET Phrase = 'la_Invalid_Password' WHERE Phrase = 'la_invalid_password'; UPDATE Events SET Module = REPLACE(Module, 'In-Portal', 'Core'); DROP TABLE ImportScripts; CREATE TABLE BanRules ( RuleId int(11) NOT NULL auto_increment, RuleType tinyint(4) NOT NULL default '0', ItemField varchar(255) default NULL, ItemVerb tinyint(4) NOT NULL default '0', ItemValue varchar(255) NOT NULL default '', ItemType int(11) NOT NULL default '0', Priority int(11) NOT NULL default '0', Status tinyint(4) NOT NULL default '1', ErrorTag varchar(255) default NULL, PRIMARY KEY (RuleId), KEY Status (Status), KEY Priority (Priority), KEY ItemType (ItemType) ); CREATE TABLE CountCache ( ListType int(11) NOT NULL default '0', ItemType int(11) NOT NULL default '-1', Value int(11) NOT NULL default '0', CountCacheId int(11) NOT NULL auto_increment, LastUpdate int(11) NOT NULL default '0', ExtraId varchar(50) default NULL, TodayOnly tinyint(4) NOT NULL default '0', PRIMARY KEY (CountCacheId) ); CREATE TABLE Favorites ( FavoriteId int(11) NOT NULL auto_increment, PortalUserId int(11) NOT NULL default '0', ResourceId int(11) NOT NULL default '0', ItemTypeId int(11) NOT NULL default '0', Modified int(11) NOT NULL default '0', PRIMARY KEY (FavoriteId), UNIQUE KEY main (PortalUserId,ResourceId), KEY Modified (Modified), KEY ItemTypeId (ItemTypeId) ); CREATE TABLE Images ( ImageId int(11) NOT NULL auto_increment, ResourceId int(11) NOT NULL default '0', Url varchar(255) NOT NULL default '', Name varchar(255) NOT NULL default '', AltName VARCHAR(255) NOT NULL DEFAULT '', ImageIndex int(11) NOT NULL default '0', LocalImage tinyint(4) NOT NULL default '1', LocalPath varchar(240) NOT NULL default '', Enabled int(11) NOT NULL default '1', DefaultImg int(11) NOT NULL default '0', ThumbUrl varchar(255) default NULL, Priority int(11) NOT NULL default '0', ThumbPath varchar(255) default NULL, LocalThumb tinyint(4) NOT NULL default '1', SameImages tinyint(4) NOT NULL default '1', PRIMARY KEY (ImageId), KEY ResourceId (ResourceId), KEY Enabled (Enabled), KEY Priority (Priority) ); CREATE TABLE ItemRating ( RatingId int(11) NOT NULL auto_increment, IPAddress varchar(255) NOT NULL default '', CreatedOn INT UNSIGNED NULL DEFAULT NULL, RatingValue int(11) NOT NULL default '0', ItemId int(11) NOT NULL default '0', PRIMARY KEY (RatingId), KEY CreatedOn (CreatedOn), KEY ItemId (ItemId), KEY RatingValue (RatingValue) ); CREATE TABLE ItemReview ( ReviewId int(11) NOT NULL auto_increment, CreatedOn INT UNSIGNED NULL DEFAULT NULL, ReviewText longtext NOT NULL, Rating tinyint(3) unsigned default NULL, IPAddress varchar(255) NOT NULL default '', ItemId int(11) NOT NULL default '0', CreatedById int(11) NOT NULL default '-1', ItemType tinyint(4) NOT NULL default '0', Priority int(11) NOT NULL default '0', Status tinyint(4) NOT NULL default '2', TextFormat int(11) NOT NULL default '0', Module varchar(255) NOT NULL default '', PRIMARY KEY (ReviewId), KEY CreatedOn (CreatedOn), KEY ItemId (ItemId), KEY ItemType (ItemType), KEY Priority (Priority), KEY Status (Status) ); CREATE TABLE ItemTypes ( ItemType int(11) NOT NULL default '0', Module varchar(50) NOT NULL default '', Prefix varchar(20) NOT NULL default '', SourceTable varchar(100) NOT NULL default '', TitleField varchar(50) default NULL, CreatorField varchar(255) NOT NULL default '', PopField varchar(255) default NULL, RateField varchar(255) default NULL, LangVar varchar(255) NOT NULL default '', PrimaryItem int(11) NOT NULL default '0', EditUrl varchar(255) NOT NULL default '', ClassName varchar(40) NOT NULL default '', ItemName varchar(50) NOT NULL default '', PRIMARY KEY (ItemType), KEY Module (Module) ); CREATE TABLE ItemFiles ( FileId int(11) NOT NULL auto_increment, ResourceId int(11) unsigned NOT NULL default '0', FileName varchar(255) NOT NULL default '', FilePath varchar(255) NOT NULL default '', Size int(11) NOT NULL default '0', `Status` tinyint(4) NOT NULL default '1', CreatedOn int(11) unsigned NOT NULL default '0', CreatedById int(11) NOT NULL default '-1', MimeType varchar(255) NOT NULL default '', PRIMARY KEY (FileId), KEY ResourceId (ResourceId), KEY CreatedOn (CreatedOn), KEY Status (Status) ); CREATE TABLE Relationship ( RelationshipId int(11) NOT NULL auto_increment, SourceId int(11) default NULL, TargetId int(11) default NULL, SourceType tinyint(4) NOT NULL default '0', TargetType tinyint(4) NOT NULL default '0', Type int(11) NOT NULL default '0', Enabled int(11) NOT NULL default '1', Priority int(11) NOT NULL default '0', PRIMARY KEY (RelationshipId), KEY RelSource (SourceId), KEY RelTarget (TargetId), KEY `Type` (`Type`), KEY Enabled (Enabled), KEY Priority (Priority), KEY SourceType (SourceType), KEY TargetType (TargetType) ); CREATE TABLE SearchConfig ( TableName varchar(40) NOT NULL default '', FieldName varchar(40) NOT NULL default '', SimpleSearch tinyint(4) NOT NULL default '1', AdvancedSearch tinyint(4) NOT NULL default '1', Description varchar(255) default NULL, DisplayName varchar(80) default NULL, ModuleName VARCHAR(20) NOT NULL DEFAULT 'In-Portal', ConfigHeader varchar(255) default NULL, DisplayOrder int(11) NOT NULL default '0', SearchConfigId int(11) NOT NULL auto_increment, Priority int(11) NOT NULL default '0', FieldType varchar(20) NOT NULL default 'text', ForeignField TEXT, JoinClause TEXT, IsWhere text, IsNotWhere text, ContainsWhere text, NotContainsWhere text, CustomFieldId int(11) default NULL, PRIMARY KEY (SearchConfigId), KEY SimpleSearch (SimpleSearch), KEY AdvancedSearch (AdvancedSearch), KEY DisplayOrder (DisplayOrder), KEY Priority (Priority), KEY CustomFieldId (CustomFieldId) ); CREATE TABLE SearchLog ( SearchLogId int(11) NOT NULL auto_increment, Keyword varchar(255) NOT NULL default '', Indices bigint(20) NOT NULL default '0', SearchType int(11) NOT NULL default '0', PRIMARY KEY (SearchLogId), KEY SearchType (SearchType) ); CREATE TABLE IgnoreKeywords ( keyword varchar(20) NOT NULL default '', PRIMARY KEY (keyword) ); CREATE TABLE SpamControl ( ItemResourceId int(11) NOT NULL default '0', IPaddress varchar(20) NOT NULL default '', Expire INT UNSIGNED NULL DEFAULT NULL, PortalUserId int(11) NOT NULL default '0', DataType varchar(20) default NULL, KEY PortalUserId (PortalUserId), KEY Expire (Expire), KEY ItemResourceId (ItemResourceId) ); CREATE TABLE StatItem ( StatItemId int(11) NOT NULL auto_increment, Module varchar(20) NOT NULL default '', ValueSQL varchar(255) default NULL, ResetSQL varchar(255) default NULL, ListLabel varchar(255) NOT NULL default '', Priority int(11) NOT NULL default '0', AdminSummary int(11) NOT NULL default '0', PRIMARY KEY (StatItemId), KEY AdminSummary (AdminSummary), KEY Priority (Priority) ); CREATE TABLE SuggestMail ( email varchar(255) NOT NULL default '', sent INT UNSIGNED NULL DEFAULT NULL, PRIMARY KEY (email), KEY sent (sent) ); CREATE TABLE SysCache ( SysCacheId int(11) NOT NULL auto_increment, Name varchar(255) NOT NULL default '', Value mediumtext, Expire INT UNSIGNED NULL DEFAULT NULL, Module varchar(20) default NULL, Context varchar(255) default NULL, GroupList varchar(255) NOT NULL default '', PRIMARY KEY (SysCacheId), KEY Name (Name) ); CREATE TABLE TagLibrary ( TagId int(11) NOT NULL auto_increment, name varchar(255) NOT NULL default '', description text, example text, scope varchar(20) NOT NULL default 'global', PRIMARY KEY (TagId) ); CREATE TABLE TagAttributes ( AttrId int(11) NOT NULL auto_increment, TagId int(11) NOT NULL default '0', Name varchar(255) NOT NULL default '', AttrType varchar(20) default NULL, DefValue varchar(255) default NULL, Description TEXT, Required int(11) NOT NULL default '0', PRIMARY KEY (AttrId), KEY TagId (TagId) ); CREATE TABLE ImportScripts ( ImportId INT(11) NOT NULL auto_increment, Name VARCHAR(255) NOT NULL DEFAULT '', Description TEXT NOT NULL, Prefix VARCHAR(10) NOT NULL DEFAULT '', Module VARCHAR(50) NOT NULL DEFAULT '', ExtraFields VARCHAR(255) NOT NULL DEFAULT '', Type VARCHAR(10) NOT NULL DEFAULT '', Status TINYINT NOT NULL, PRIMARY KEY (ImportId), KEY Module (Module), KEY Status (Status) ); CREATE TABLE StylesheetSelectors ( SelectorId int(11) NOT NULL auto_increment, StylesheetId int(11) NOT NULL default '0', Name varchar(255) NOT NULL default '', SelectorName varchar(255) NOT NULL default '', SelectorData text NOT NULL, Description text NOT NULL, Type tinyint(4) NOT NULL default '0', AdvancedCSS text NOT NULL, ParentId int(11) NOT NULL default '0', PRIMARY KEY (SelectorId), KEY StylesheetId (StylesheetId), KEY ParentId (ParentId), KEY `Type` (`Type`) ); CREATE TABLE Visits ( VisitId int(11) NOT NULL auto_increment, VisitDate int(10) unsigned NOT NULL default '0', Referer varchar(255) NOT NULL default '', IPAddress varchar(15) NOT NULL default '', AffiliateId int(10) unsigned NOT NULL default '0', PortalUserId int(11) NOT NULL default '-2', PRIMARY KEY (VisitId), KEY PortalUserId (PortalUserId), KEY AffiliateId (AffiliateId), KEY VisitDate (VisitDate) ); CREATE TABLE ImportCache ( CacheId int(11) NOT NULL auto_increment, CacheName varchar(255) NOT NULL default '', VarName int(11) NOT NULL default '0', VarValue text NOT NULL, PRIMARY KEY (CacheId), KEY CacheName (CacheName), KEY VarName (VarName) ); CREATE TABLE RelatedSearches ( RelatedSearchId int(11) NOT NULL auto_increment, ResourceId int(11) NOT NULL default '0', Keyword varchar(255) NOT NULL default '', ItemType tinyint(4) NOT NULL default '0', Enabled tinyint(4) NOT NULL default '1', Priority int(11) NOT NULL default '0', PRIMARY KEY (RelatedSearchId), KEY Enabled (Enabled), KEY ItemType (ItemType), KEY ResourceId (ResourceId) ); UPDATE Modules SET Path = 'core/', Version='4.3.9' WHERE Name = 'In-Portal'; UPDATE Skins SET Logo = 'just_logo.gif' WHERE Logo = 'just_logo_1.gif'; UPDATE ConfigurationAdmin SET prompt = 'la_config_PathToWebsite' WHERE VariableName = 'Site_Path'; # ===== v 5.0.0 ===== CREATE TABLE StopWords ( StopWordId int(11) NOT NULL auto_increment, StopWord varchar(255) NOT NULL default '', PRIMARY KEY (StopWordId), KEY StopWord (StopWord) ); INSERT INTO StopWords VALUES (90, '~'),(152, 'on'),(157, 'see'),(156, 'put'),(128, 'and'),(154, 'or'),(155, 'other'),(153, 'one'),(126, 'as'),(127, 'at'),(125, 'are'),(91, '!'),(92, '@'),(93, '#'),(94, '$'),(95, '%'),(96, '^'),(97, '&'),(98, '*'),(99, '('),(100, ')'),(101, '-'),(102, '_'),(103, '='),(104, '+'),(105, '['),(106, '{'),(107, ']'),(108, '}'),(109, '\\'),(110, '|'),(111, ';'),(112, ':'),(113, ''''),(114, '"'),(115, '<'),(116, '.'),(117, '>'),(118, '/'),(119, '?'),(120, 'ah'),(121, 'all'),(122, 'also'),(123, 'am'),(124, 'an'),(151, 'of'),(150, 'note'),(149, 'not'),(148, 'no'),(147, 'may'),(146, 'its'),(145, 'it'),(144, 'is'),(143, 'into'),(142, 'in'),(141, 'had'),(140, 'has'),(139, 'have'),(138, 'from'),(137, 'form'),(136, 'for'),(135, 'end'),(134, 'each'),(133, 'can'),(132, 'by'),(130, 'be'),(131, 'but'),(129, 'any'),(158, 'that'),(159, 'the'),(160, 'their'),(161, 'there'),(162, 'these'),(163, 'they'),(164, 'this'),(165, 'through'),(166, 'thus'),(167, 'to'),(168, 'two'),(169, 'too'),(170, 'up'),(171, 'where'),(172, 'which'),(173, 'with'),(174, 'were'),(175, 'was'),(176, 'you'),(177, 'yet'); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:stop_words.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:stop_words.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:stop_words.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:stop_words.delete', 11, 1, 1, 0); INSERT INTO ConfigurationAdmin VALUES ('CheckStopWords', 'la_Text_Website', 'la_config_CheckStopWords', 'checkbox', '', '', 10.29, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'CheckStopWords', '0', 'In-Portal', 'in-portal:configure_general'); ALTER TABLE SpamControl ADD INDEX (DataType); CREATE TABLE MailingLists ( MailingId int(10) unsigned NOT NULL auto_increment, PortalUserId int(11) NOT NULL default '-1', `To` longtext, ToParsed longtext, Attachments text, `Subject` varchar(255) NOT NULL, MessageText longtext, MessageHtml longtext, `Status` tinyint(3) unsigned NOT NULL default '1', EmailsQueued int(10) unsigned NOT NULL, EmailsSent int(10) unsigned NOT NULL, EmailsTotal int(10) unsigned NOT NULL, PRIMARY KEY (MailingId), KEY EmailsTotal (EmailsTotal), KEY EmailsSent (EmailsSent), KEY EmailsQueued (EmailsQueued), KEY `Status` (`Status`), KEY PortalUserId (PortalUserId) ); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mailing_lists.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mailing_lists.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mailing_lists.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:mailing_lists.delete', 11, 1, 1, 0); ALTER TABLE EmailQueue ADD MailingId INT UNSIGNED NOT NULL, ADD INDEX (MailingId); INSERT INTO ConfigurationAdmin VALUES ('MailingListQueuePerStep', 'la_Text_smtp_server', 'la_config_MailingListQueuePerStep', 'text', NULL, NULL, 30.09, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'MailingListQueuePerStep', 10, 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('MailingListSendPerStep', 'la_Text_smtp_server', 'la_config_MailingListSendPerStep', 'text', NULL, NULL, 30.10, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'MailingListSendPerStep', 10, 'In-Portal', 'in-portal:configure_general'); ALTER TABLE Events ADD INDEX (Event); ALTER TABLE SearchLog ADD INDEX (Keyword); ALTER TABLE Skins ADD LogoBottom VARCHAR(255) NOT NULL AFTER Logo, ADD LogoLogin VARCHAR(255) NOT NULL AFTER LogoBottom; UPDATE Skins SET Logo = 'in-portal_logo_img.jpg', LogoBottom = 'in-portal_logo_img2.jpg', LogoLogin = 'in-portal_logo_login.gif' WHERE Logo = 'just_logo_1.gif' OR Logo = 'just_logo.gif'; INSERT INTO ConfigurationValues VALUES (DEFAULT, 'SiteNameSubTitle', '', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('SiteNameSubTitle', 'la_Text_Website', 'la_config_SiteNameSubTitle', 'text', '', '', 10.021, 0, 0); INSERT INTO ConfigurationAdmin VALUES ('ResizableFrames', 'la_Text_Website', 'la_config_ResizableFrames', 'checkbox', '', '', 10.30, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'ResizableFrames', '0', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('QuickCategoryPermissionRebuild', 'la_Text_General', 'la_config_QuickCategoryPermissionRebuild', 'checkbox', NULL , NULL , 10.12, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'QuickCategoryPermissionRebuild', '1', 'In-Portal', 'in-portal:configure_categories'); ALTER TABLE Language ADD UserDocsUrl VARCHAR(255) NOT NULL; UPDATE Category SET Template = CategoryTemplate WHERE CategoryTemplate <> ''; ALTER TABLE Category ADD ThemeId INT UNSIGNED NOT NULL, ADD INDEX (ThemeId), ADD COLUMN UseExternalUrl tinyint(3) unsigned NOT NULL default '0' AFTER Template, ADD COLUMN ExternalUrl varchar(255) NOT NULL default '' AFTER UseExternalUrl, ADD COLUMN UseMenuIconUrl tinyint(3) unsigned NOT NULL default '0' AFTER ExternalUrl, ADD COLUMN MenuIconUrl varchar(255) NOT NULL default '' AFTER UseMenuIconUrl, CHANGE MetaKeywords MetaKeywords TEXT, CHANGE MetaDescription MetaDescription TEXT, CHANGE CachedCategoryTemplate CachedTemplate VARCHAR(255) NOT NULL, DROP CategoryTemplate; UPDATE Category SET l1_MenuTitle = l1_Name WHERE l1_MenuTitle = '' OR l1_MenuTitle LIKE '_Auto: %'; UPDATE Category SET l2_MenuTitle = l2_Name WHERE l2_MenuTitle = '' OR l2_MenuTitle LIKE '_Auto: %'; UPDATE Category SET l3_MenuTitle = l3_Name WHERE l3_MenuTitle = '' OR l3_MenuTitle LIKE '_Auto: %'; UPDATE Category SET l4_MenuTitle = l4_Name WHERE l4_MenuTitle = '' OR l4_MenuTitle LIKE '_Auto: %'; UPDATE Category SET l5_MenuTitle = l5_Name WHERE l5_MenuTitle = '' OR l5_MenuTitle LIKE '_Auto: %'; UPDATE Category SET Template = '/platform/designs/general' WHERE Template = '/in-edit/designs/general'; UPDATE Category SET CachedTemplate = '/platform/designs/general' WHERE CachedTemplate = '/in-edit/designs/general'; UPDATE Category SET CachedTemplate = Template WHERE Template <> ''; CREATE TABLE PageContent ( PageContentId int(11) NOT NULL auto_increment, ContentNum int(11) NOT NULL default '0', PageId int(11) NOT NULL default '0', l1_Content text, l2_Content text, l3_Content text, l4_Content text, l5_Content text, l1_Translated tinyint(4) NOT NULL default '0', l2_Translated tinyint(4) NOT NULL default '0', l3_Translated tinyint(4) NOT NULL default '0', l4_Translated tinyint(4) NOT NULL default '0', l5_Translated tinyint(4) NOT NULL default '0', PRIMARY KEY (PageContentId), KEY ContentNum (ContentNum,PageId) ); CREATE TABLE FormFields ( FormFieldId int(11) NOT NULL auto_increment, FormId int(11) NOT NULL default '0', Type int(11) NOT NULL default '0', FieldName varchar(255) NOT NULL default '', FieldLabel varchar(255) default NULL, Heading varchar(255) default NULL, Prompt varchar(255) default NULL, ElementType varchar(50) NOT NULL default '', ValueList varchar(255) default NULL, Priority int(11) NOT NULL default '0', IsSystem tinyint(3) unsigned NOT NULL default '0', Required tinyint(1) NOT NULL default '0', DisplayInGrid tinyint(1) NOT NULL default '1', DefaultValue text NOT NULL, Validation TINYINT NOT NULL DEFAULT '0', PRIMARY KEY (FormFieldId), KEY `Type` (`Type`), KEY FormId (FormId), KEY Priority (Priority), KEY IsSystem (IsSystem), KEY DisplayInGrid (DisplayInGrid) ); CREATE TABLE FormSubmissions ( FormSubmissionId int(11) NOT NULL auto_increment, FormId int(11) NOT NULL default '0', SubmissionTime int(11) NOT NULL default '0', PRIMARY KEY (FormSubmissionId), KEY FormId (FormId), KEY SubmissionTime (SubmissionTime) ); CREATE TABLE Forms ( FormId int(11) NOT NULL auto_increment, Title VARCHAR(255) NOT NULL DEFAULT '', Description text, PRIMARY KEY (FormId) ); UPDATE Events SET Module = 'Core:Category', Description = 'la_event_FormSubmitted' WHERE Event = 'FORM.SUBMITTED'; DELETE FROM PersistantSessionData WHERE VariableName LIKE '%img%'; UPDATE Modules SET TemplatePath = Path WHERE TemplatePath <> ''; UPDATE ConfigurationValues SET VariableValue = '/platform/designs/general' WHERE VariableName = 'cms_DefaultDesign'; UPDATE ConfigurationValues SET ModuleOwner = 'In-Portal', Section = 'in-portal:configure_categories' WHERE VariableName = 'cms_DefaultDesign'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.15 WHERE VariableName = 'cms_DefaultDesign'; UPDATE Phrase SET Phrase = 'la_Regular' WHERE Phrase = 'la_regular'; UPDATE Phrase SET Module = 'Core' WHERE Phrase IN ('la_Hide', 'la_Show', 'la_fld_Requied', 'la_col_Modified', 'la_col_Referer', 'la_Regular'); UPDATE Phrase SET Phrase = 'la_title_Editing_E-mail' WHERE Phrase = 'la_title_editing_e-mail'; ALTER TABLE Phrase ADD UNIQUE (LanguageId, Phrase); ALTER TABLE CustomField ADD IsRequired tinyint(3) unsigned NOT NULL default '0'; DELETE FROM Permissions WHERE (Permission LIKE 'proj-cms:structure%') OR (Permission LIKE 'proj-cms:submissions%') OR (Permission LIKE 'proj-base:users%') OR (Permission LIKE 'proj-base:system_variables%') OR (Permission LIKE 'proj-base:email_settings%') OR (Permission LIKE 'proj-base:other_settings%') OR (Permission LIKE 'proj-base:sysconfig%'); UPDATE Permissions SET Permission = REPLACE(Permission, 'proj-cms:browse', 'in-portal:browse_site'); UPDATE Permissions SET Permission = REPLACE(Permission, 'proj-cms:', 'in-portal:'); UPDATE Permissions SET Permission = REPLACE(Permission, 'proj-base:', 'in-portal:'); ALTER TABLE CategoryItems ADD INDEX (ItemResourceId); ALTER TABLE CategoryItems DROP INDEX Filename; ALTER TABLE CategoryItems ADD INDEX Filename(Filename); DROP TABLE Pages; DELETE FROM PermissionConfig WHERE PermissionName LIKE 'PAGE.%'; DELETE FROM Permissions WHERE Permission LIKE 'PAGE.%'; DELETE FROM SearchConfig WHERE TableName = 'Pages'; DELETE FROM ConfigurationAdmin WHERE VariableName LIKE '%_pages'; DELETE FROM ConfigurationValues WHERE VariableName LIKE '%_pages'; DELETE FROM ConfigurationAdmin WHERE VariableName LIKE 'PerPage_Pages%'; DELETE FROM ConfigurationValues WHERE VariableName LIKE 'PerPage_Pages%'; INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:website_setting_folder.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:user_setting_folder.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_advanced.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:configure_advanced.edit', 11, 1, 1, 0); #INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spelling_dictionary.delete', 11, 1, 1, 0); #INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spelling_dictionary.edit', 11, 1, 1, 0); #INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spelling_dictionary.add', 11, 1, 1, 0); #INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spelling_dictionary.view', 11, 1, 1, 0); UPDATE ConfigurationValues SET ModuleOwner = 'In-Portal', Section = 'in-portal:configure_general' WHERE ModuleOwner = 'Proj-Base' AND Section IN ('proj-base:system_variables', 'proj-base:email_settings'); UPDATE ConfigurationValues SET ModuleOwner = 'In-Portal', Section = 'in-portal:configure_advanced' WHERE ModuleOwner = 'Proj-Base' AND Section IN ('proj-base:other_settings', 'proj-base:sysconfig'); UPDATE ConfigurationAdmin SET heading = 'la_Text_General' WHERE VariableName IN ('AdvancedUserManagement', 'RememberLastAdminTemplate', 'DefaultSettingsUserId'); UPDATE ConfigurationAdmin SET DisplayOrder = 10.011 WHERE VariableName = 'AdvancedUserManagement'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.14 WHERE VariableName = 'RememberLastAdminTemplate'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.15 WHERE VariableName = 'DefaultSettingsUserId'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.13 WHERE VariableName = 'FilenameSpecialCharReplacement'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.14 WHERE VariableName = 'YahooApplicationId'; UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsMailling', prompt = 'la_prompt_AdminMailFrom', ValueList = 'size="40"', DisplayOrder = 30.07 WHERE VariableName = 'Smtp_AdminMailFrom'; UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsWebsite' WHERE VariableName IN ('Site_Path','SiteNameSubTitle','UseModRewrite','Config_Server_Time','Config_Site_Time','ErrorTemplate','NoPermissionTemplate','UsePageHitCounter','ForceImageMagickResize','CheckStopWords','Site_Name'); UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsSession' WHERE VariableName IN ('CookieSessions','SessionCookieName','SessionTimeout','KeepSessionOnBrowserClose','SessionReferrerCheck','UseJSRedirect'); UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsSSL' WHERE VariableName IN ('SSL_URL','AdminSSL_URL','Require_SSL','Require_AdminSSL','Force_HTTP_When_SSL_Not_Required','UseModRewriteWithSSL'); UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsAdmin' WHERE VariableName IN ('UseToolbarLabels','UseSmallHeader','UseColumnFreezer','UsePopups','UseDoubleSorting','MenuFrameWidth','ResizableFrames','AutoRefreshIntervals'); UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsMailling' WHERE VariableName IN ('Smtp_Server','Smtp_Port','Smtp_Authenticate','Smtp_User','Smtp_Pass','Smtp_DefaultHeaders','MailFunctionHeaderSeparator','MailingListQueuePerStep','MailingListSendPerStep'); UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsSystem' WHERE VariableName IN ('UseOutputCompression','OutputCompressionLevel','TrimRequiredFields','UseCronForRegularEvent','UseChangeLog','Backup_Path','SystemTagCache','SocketBlockingMode'); UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsCSVExport' WHERE VariableName IN ('CSVExportDelimiter','CSVExportEnclosure','CSVExportSeparator','CSVExportEncoding'); UPDATE ConfigurationAdmin SET DisplayOrder = 10.01 WHERE VariableName = 'Site_Path'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.02 WHERE VariableName = 'SiteNameSubTitle'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.03 WHERE VariableName = 'UseModRewrite'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.04 WHERE VariableName = 'Config_Server_Time'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.05 WHERE VariableName = 'Config_Site_Time'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.06 WHERE VariableName = 'ErrorTemplate'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.07 WHERE VariableName = 'NoPermissionTemplate'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.08 WHERE VariableName = 'UsePageHitCounter'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.09 WHERE VariableName = 'ForceImageMagickResize'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.10 WHERE VariableName = 'CheckStopWords'; UPDATE ConfigurationAdmin SET DisplayOrder = 20.01 WHERE VariableName = 'CookieSessions'; UPDATE ConfigurationAdmin SET DisplayOrder = 20.02 WHERE VariableName = 'SessionCookieName'; UPDATE ConfigurationAdmin SET DisplayOrder = 20.03 WHERE VariableName = 'SessionTimeout'; UPDATE ConfigurationAdmin SET DisplayOrder = 20.04 WHERE VariableName = 'KeepSessionOnBrowserClose'; UPDATE ConfigurationAdmin SET DisplayOrder = 20.05 WHERE VariableName = 'SessionReferrerCheck'; UPDATE ConfigurationAdmin SET DisplayOrder = 20.06 WHERE VariableName = 'UseJSRedirect'; UPDATE ConfigurationAdmin SET DisplayOrder = 30.01 WHERE VariableName = 'SSL_URL'; UPDATE ConfigurationAdmin SET DisplayOrder = 30.02 WHERE VariableName = 'AdminSSL_URL'; UPDATE ConfigurationAdmin SET DisplayOrder = 30.03 WHERE VariableName = 'Require_SSL'; UPDATE ConfigurationAdmin SET DisplayOrder = 30.04 WHERE VariableName = 'Require_AdminSSL'; UPDATE ConfigurationAdmin SET DisplayOrder = 30.05 WHERE VariableName = 'Force_HTTP_When_SSL_Not_Required'; UPDATE ConfigurationAdmin SET DisplayOrder = 30.06 WHERE VariableName = 'UseModRewriteWithSSL'; UPDATE ConfigurationAdmin SET DisplayOrder = 40.01 WHERE VariableName = 'UseToolbarLabels'; UPDATE ConfigurationAdmin SET DisplayOrder = 40.02 WHERE VariableName = 'UseSmallHeader'; UPDATE ConfigurationAdmin SET DisplayOrder = 40.03 WHERE VariableName = 'UseColumnFreezer'; UPDATE ConfigurationAdmin SET DisplayOrder = 40.04 WHERE VariableName = 'UsePopups'; UPDATE ConfigurationAdmin SET DisplayOrder = 40.05 WHERE VariableName = 'UseDoubleSorting'; UPDATE ConfigurationAdmin SET DisplayOrder = 40.06 WHERE VariableName = 'MenuFrameWidth'; UPDATE ConfigurationAdmin SET DisplayOrder = 40.07 WHERE VariableName = 'ResizableFrames'; UPDATE ConfigurationAdmin SET DisplayOrder = 40.08 WHERE VariableName = 'AutoRefreshIntervals'; UPDATE ConfigurationAdmin SET DisplayOrder = 50.01 WHERE VariableName = 'Smtp_Server'; UPDATE ConfigurationAdmin SET DisplayOrder = 50.02 WHERE VariableName = 'Smtp_Port'; UPDATE ConfigurationAdmin SET DisplayOrder = 50.03 WHERE VariableName = 'Smtp_Authenticate'; UPDATE ConfigurationAdmin SET DisplayOrder = 50.04 WHERE VariableName = 'Smtp_User'; UPDATE ConfigurationAdmin SET DisplayOrder = 50.05 WHERE VariableName = 'Smtp_Pass'; UPDATE ConfigurationAdmin SET DisplayOrder = 50.06 WHERE VariableName = 'Smtp_DefaultHeaders'; UPDATE ConfigurationAdmin SET DisplayOrder = 50.07 WHERE VariableName = 'MailFunctionHeaderSeparator'; UPDATE ConfigurationAdmin SET DisplayOrder = 50.08 WHERE VariableName = 'MailingListQueuePerStep'; UPDATE ConfigurationAdmin SET DisplayOrder = 50.09 WHERE VariableName = 'MailingListSendPerStep'; UPDATE ConfigurationAdmin SET DisplayOrder = 60.01 WHERE VariableName = 'UseOutputCompression'; UPDATE ConfigurationAdmin SET DisplayOrder = 60.02 WHERE VariableName = 'OutputCompressionLevel'; UPDATE ConfigurationAdmin SET DisplayOrder = 60.03 WHERE VariableName = 'TrimRequiredFields'; UPDATE ConfigurationAdmin SET DisplayOrder = 60.04 WHERE VariableName = 'UseCronForRegularEvent'; UPDATE ConfigurationAdmin SET DisplayOrder = 60.05 WHERE VariableName = 'UseChangeLog'; UPDATE ConfigurationAdmin SET DisplayOrder = 60.06 WHERE VariableName = 'Backup_Path'; UPDATE ConfigurationAdmin SET DisplayOrder = 60.07 WHERE VariableName = 'SystemTagCache'; UPDATE ConfigurationAdmin SET DisplayOrder = 60.08 WHERE VariableName = 'SocketBlockingMode'; UPDATE ConfigurationAdmin SET DisplayOrder = 70.01 WHERE VariableName = 'CSVExportDelimiter'; UPDATE ConfigurationAdmin SET DisplayOrder = 70.02 WHERE VariableName = 'CSVExportEnclosure'; UPDATE ConfigurationAdmin SET DisplayOrder = 70.03 WHERE VariableName = 'CSVExportSeparator'; UPDATE ConfigurationAdmin SET DisplayOrder = 70.04 WHERE VariableName = 'CSVExportEncoding'; UPDATE Phrase SET Phrase = 'la_section_SettingsWebsite' WHERE Phrase = 'la_Text_Website'; UPDATE Phrase SET Phrase = 'la_section_SettingsMailling' WHERE Phrase = 'la_Text_smtp_server'; UPDATE Phrase SET Phrase = 'la_section_SettingsCSVExport' WHERE Phrase = 'la_Text_CSV_Export'; DELETE FROM Phrase WHERE Phrase IN ( 'la_Text_BackupPath', 'la_config_AllowManualFilenames', 'la_fld_cat_MenuLink', 'la_fld_UseCategoryTitle', 'la_In-Edit', 'la_ItemTab_Pages', 'la_Text_Pages', 'la_title_Pages', 'la_title_Page_Categories', 'lu_Pages', 'lu_page_HtmlTitle', 'lu_page_OnPageTitle', 'la_tab_AllPages', 'la_title_AllPages', 'la_title_ContentManagement', 'la_title_ContentManagment', 'lu_ViewSubPages', 'la_CMS_FormSubmitted' ); DELETE FROM Phrase WHERE (Phrase LIKE 'la_Description_In-Edit%') OR (Phrase LIKE 'la_Pages_PerPage%') OR (Phrase LIKE 'lu_PermName_Page.%'); UPDATE ConfigurationValues SET VariableValue = 1, ModuleOwner = 'In-Portal:Users', Section = 'in-portal:configure_users' WHERE VariableName = 'RememberLastAdminTemplate'; UPDATE ConfigurationValues SET ModuleOwner = 'In-Portal:Users', Section = 'in-portal:configure_users' WHERE VariableName IN ('AdvancedUserManagement', 'DefaultSettingsUserId'); INSERT INTO ConfigurationAdmin VALUES ('Search_MinKeyword_Length', 'la_Text_General', 'la_config_Search_MinKeyword_Length', 'text', NULL, NULL, 10.19, 0, 0); UPDATE ConfigurationValues SET Section = 'in-portal:configure_categories' WHERE VariableName = 'Search_MinKeyword_Length'; UPDATE ConfigurationAdmin SET ValueList = '=+,SELECT DestName AS OptionName, DestId AS OptionValue FROM StdDestinations WHERE COALESCE(DestParentId, 0) = 0 ORDER BY OptionName' WHERE VariableName = 'User_Default_Registration_Country'; UPDATE ConfigurationValues SET ModuleOwner = 'In-Portal', Section = 'in-portal:configure_advanced' WHERE VariableName IN ( 'Site_Path', 'SiteNameSubTitle', 'CookieSessions', 'SessionCookieName', 'SessionTimeout', 'SessionReferrerCheck', 'SystemTagCache', 'SocketBlockingMode', 'SSL_URL', 'AdminSSL_URL', 'Require_SSL', 'Force_HTTP_When_SSL_Not_Required', 'UseModRewrite', 'UseModRewriteWithSSL', 'UseJSRedirect', 'UseCronForRegularEvent', 'ErrorTemplate', 'NoPermissionTemplate', 'UseOutputCompression', 'OutputCompressionLevel', 'UseToolbarLabels', 'UseSmallHeader', 'UseColumnFreezer', 'TrimRequiredFields', 'UsePageHitCounter', 'UseChangeLog', 'AutoRefreshIntervals', 'KeepSessionOnBrowserClose', 'ForceImageMagickResize', 'CheckStopWords', 'ResizableFrames', 'Config_Server_Time', 'Config_Site_Time', 'Smtp_Server', 'Smtp_Port', 'Smtp_Authenticate', 'Smtp_User', 'Smtp_Pass', 'Smtp_DefaultHeaders', 'MailFunctionHeaderSeparator', 'MailingListQueuePerStep', 'MailingListSendPerStep', 'Backup_Path', 'CSVExportDelimiter', 'CSVExportEnclosure', 'CSVExportSeparator', 'CSVExportEncoding' ); DELETE FROM ConfigurationValues WHERE VariableName IN ( 'Columns_Category', 'Perpage_Archive', 'debug', 'Perpage_User', 'Perpage_LangEmail', 'Default_FromAddr', 'email_replyto', 'email_footer', 'Default_Theme', 'Default_Language', 'User_SortField', 'User_SortOrder', 'Suggest_MinInterval', 'SubCat_ListCount', 'Timeout_Rating', 'Perpage_Relations', 'Group_SortField', 'Group_SortOrder', 'Default_FromName', 'Relation_LV_Sortfield', 'ampm_time', 'Perpage_Template', 'Perpage_Phrase', 'Perpage_Sessionlist', 'Perpage_Items', 'GuestSessions', 'Perpage_Email', 'LinksValidation_LV_Sortfield', 'CustomConfig_LV_Sortfield', 'Event_LV_SortField', 'Theme_LV_SortField', 'Template_LV_SortField', 'Lang_LV_SortField', 'Phrase_LV_SortField', 'LangEmail_LV_SortField', 'CustomData_LV_SortField', 'Summary_SortField', 'Session_SortField', 'SearchLog_SortField', 'Perpage_StatItem', 'Perpage_Groups', 'Perpage_Event', 'Perpage_BanRules', 'Perpage_SearchLog', 'Perpage_LV_lang', 'Perpage_LV_Themes', 'Perpage_LV_Catlist', 'Perpage_Reviews', 'Perpage_Modules', 'Perpage_Grouplist', 'Perpage_Images', 'EmailsL_SortField', 'Perpage_EmailsL', 'Perpage_CustomData', 'Perpage_Review', 'SearchRel_DefaultIncrease', 'SearchRel_DefaultKeyword', 'SearchRel_DefaultPop', 'SearchRel_DefaultRating', 'Category_Highlight_OpenTag', 'Category_Highlight_CloseTag', 'DomainSelect', 'MetaKeywords', 'MetaDescription', 'Config_Name', 'Config_Company', 'Config_Reg_Number', 'Config_Website_Name', 'Config_Web_Address', 'Smtp_SendHTML', 'ProjCMSAllowManualFilenames' ); DELETE FROM ConfigurationAdmin WHERE VariableName IN ('Domain_Detect', 'Server_Name', 'ProjCMSAllowManualFilenames'); DROP TABLE SuggestMail; ALTER TABLE ThemeFiles ADD FileMetaInfo TEXT NULL; UPDATE SearchConfig SET SimpleSearch = 0 WHERE FieldType NOT IN ('text', 'range') AND SimpleSearch = 1; DELETE FROM PersistantSessionData WHERE VariableName IN ('c_columns_.', 'c.showall_columns_.', 'emailevents_columns_.', 'emailmessages_columns_.'); INSERT INTO ConfigurationAdmin VALUES ('DebugOnlyFormConfigurator', 'la_section_SettingsAdmin', 'la_config_DebugOnlyFormConfigurator', 'checkbox', '', '', 40.09, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'DebugOnlyFormConfigurator', '0', 'In-Portal', 'in-portal:configure_advanced'); CREATE TABLE Semaphores ( SemaphoreId int(11) NOT NULL auto_increment, SessionKey int(10) unsigned NOT NULL, Timestamp int(10) unsigned NOT NULL, MainPrefix varchar(255) NOT NULL, PRIMARY KEY (SemaphoreId), KEY SessionKey (SessionKey), KEY Timestamp (Timestamp), KEY MainPrefix (MainPrefix) ); ALTER TABLE Language ADD IconDisabledURL VARCHAR(255) NULL DEFAULT NULL AFTER IconURL; UPDATE Phrase SET Translation = REPLACE(Translation, 'category', 'section') WHERE (Phrase IN ( 'la_confirm_maintenance', 'la_error_move_subcategory', 'la_error_RootCategoriesDelete', 'la_error_unknown_category', 'la_fld_IsBaseCategory', 'la_nextcategory', 'la_prevcategory', 'la_prompt_max_import_category_levels', 'la_prompt_root_name', 'la_SeparatedCategoryPath', 'la_title_category_select' ) OR Phrase LIKE 'la_Description_%') AND (PhraseType = 1); UPDATE Phrase SET Translation = REPLACE(Translation, 'Category', 'Section') WHERE PhraseType = 1; UPDATE Phrase SET Translation = REPLACE(Translation, 'categories', 'sections') WHERE (Phrase IN ( 'la_category_perpage_prompt', 'la_category_showpick_prompt', 'la_category_sortfield_prompt', 'la_Description_in-portal:advanced_view', 'la_Description_in-portal:browse', 'la_Description_in-portal:site', 'la_error_copy_subcategory', 'la_Msg_PropagateCategoryStatus', 'la_Text_DataType_1' )) AND (PhraseType = 1); UPDATE Phrase SET Translation = REPLACE(Translation, 'Categories', 'Sections') WHERE PhraseType = 1; UPDATE Phrase SET Translation = REPLACE(Translation, 'Page', 'Section') WHERE (Phrase IN ('la_col_PageTitle', 'la_col_System', 'la_fld_IsIndex', 'la_fld_PageTitle', 'la_section_Page')) AND (PhraseType = 1); DELETE FROM Phrase WHERE Phrase IN ('la_title_Adding_Page', 'la_title_Editing_Page', 'la_title_New_Page', 'la_fld_PageId'); INSERT INTO ConfigurationAdmin VALUES ('UseModalWindows', 'la_section_SettingsAdmin', 'la_config_UseModalWindows', 'checkbox', '', '', 40.10, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'UseModalWindows', '1', 'In-Portal', 'in-portal:configure_advanced'); UPDATE Language SET UserDocsUrl = 'http://docs.in-portal.org/eng/index.php'; DELETE FROM Modules WHERE Name = 'Proj-Base'; DELETE FROM Phrase WHERE Phrase IN ('la_fld_ImageId', 'la_fld_RelationshipId', 'la_fld_ReviewId', 'la_prompt_CensorhipId', 'my_account_title', 'Next Theme', 'Previous Theme', 'test 1', 'la_article_reviewed', 'la_configerror_review', 'la_link_reviewed', 'la_Prompt_ReviewedBy', 'la_prompt_ReviewId', 'la_prompt_ReviewText', 'la_reviewer', 'la_review_added', 'la_review_alreadyreviewed', 'la_review_error', 'la_tab_Editing_Review', 'la_tab_Review', 'la_ToolTip_New_Review', 'la_topic_reviewed', 'lu_add_review', 'lu_article_reviews', 'lu_ferror_review_duplicate', 'lu_link_addreview_confirm_pending_text', 'lu_link_reviews', 'lu_link_review_confirm', 'lu_link_review_confirm_pending', 'lu_link_addreview_confirm_text', 'lu_news_addreview_confirm_text', 'lu_news_addreview_confirm__pending_text', 'lu_news_review_confirm', 'lu_news_review_confirm_pending', 'lu_prompt_review', 'lu_reviews_updated', 'lu_review_access_denied', 'lu_review_article', 'lu_review_link', 'lu_review_news', 'lu_review_this_article', 'lu_fld_Review', 'lu_product_reviews', 'lu_ReviewProduct', ' lu_resetpw_confirm_text', 'lu_resetpw_confirm_text'); UPDATE Modules SET Version = '5.0.0', Loaded = 1 WHERE Name = 'In-Portal'; # ===== v 5.0.1 ===== UPDATE ConfigurationAdmin SET ValueList = '1=la_opt_UserInstantRegistration,2=la_opt_UserNotAllowedRegistration,3=la_opt_UserUponApprovalRegistration,4=la_opt_UserEmailActivation' WHERE VariableName = 'User_Allow_New'; UPDATE ConfigurationValues SET VariableValue = '1' WHERE VariableName = 'ResizableFrames'; UPDATE Phrase SET Translation = REPLACE(Translation, 'Page', 'Section') WHERE (Phrase IN ('la_col_PageTitle', 'la_col_System', 'la_fld_IsIndex', 'la_fld_PageTitle', 'la_section_Page')) AND (PhraseType = 1); DELETE FROM Phrase WHERE Phrase IN ('la_Tab', 'la_Colon', 'la_Semicolon', 'la_Space', 'la_Colon', 'la_User_Instant', 'la_User_Not_Allowed', 'la_User_Upon_Approval', 'lu_title_PrivacyPolicy'); UPDATE ConfigurationAdmin SET ValueList = '0=la_opt_Tab,1=la_opt_Comma,2=la_opt_Semicolon,3=la_opt_Space,4=la_opt_Colon' WHERE VariableName = 'CSVExportDelimiter'; UPDATE ConfigurationAdmin SET ValueList = '0=lu_opt_QueryString,1=lu_opt_Cookies,2=lu_opt_AutoDetect' WHERE VariableName = 'CookieSessions'; UPDATE ConfigurationAdmin SET ValueList = 'Name=la_opt_Title,Description=la_opt_Description,CreatedOn=la_opt_CreatedOn,EditorsPick=la_opt_EditorsPick,SELECT Prompt AS OptionName, CONCAT("cust_", FieldName) AS OptionValue FROM CustomField WHERE (Type = 1) AND (IsSystem = 0)' WHERE VariableName = 'Category_Sortfield'; UPDATE ConfigurationAdmin SET ValueList = 'Name=la_opt_Title,Description=la_opt_Description,CreatedOn=la_opt_CreatedOn,EditorsPick=la_opt_EditorsPick,SELECT Prompt AS OptionName, CONCAT("cust_", FieldName) AS OptionValue FROM CustomField WHERE (Type = 1) AND (IsSystem = 0)' WHERE VariableName = 'Category_Sortfield2'; UPDATE Category SET Template = '#inherit#' WHERE COALESCE(Template, '') = ''; ALTER TABLE Category CHANGE Template Template VARCHAR(255) NOT NULL DEFAULT '#inherit#'; UPDATE Phrase SET Phrase = 'la_config_DefaultDesignTemplate' WHERE Phrase = 'la_prompt_DefaultDesignTemplate'; UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsWebsite', prompt = 'la_config_DefaultDesignTemplate', DisplayOrder = 10.06 WHERE VariableName = 'cms_DefaultDesign'; UPDATE ConfigurationValues SET Section = 'in-portal:configure_advanced' WHERE VariableName = 'cms_DefaultDesign'; UPDATE ConfigurationAdmin SET DisplayOrder = DisplayOrder + 0.01 WHERE VariableName IN ('ErrorTemplate', 'NoPermissionTemplate'); UPDATE ConfigurationAdmin SET DisplayOrder = 10.15 WHERE VariableName = 'Search_MinKeyword_Length'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.01 WHERE VariableName = 'Site_Name'; UPDATE ConfigurationAdmin SET DisplayOrder = 20.01 WHERE VariableName = 'FirstDayOfWeek'; UPDATE ConfigurationAdmin SET DisplayOrder = 30.01 WHERE VariableName = 'Smtp_AdminMailFrom'; UPDATE ConfigurationAdmin SET heading = 'la_Text_Date_Time_Settings', DisplayOrder = DisplayOrder + 9.98 WHERE VariableName IN ('Config_Server_Time', 'Config_Site_Time'); UPDATE ConfigurationValues SET Section = 'in-portal:configure_general' WHERE VariableName IN ('Config_Server_Time', 'Config_Site_Time'); UPDATE ConfigurationAdmin SET DisplayOrder = DisplayOrder - 0.02 WHERE VariableName IN ('cms_DefaultDesign', 'ErrorTemplate', 'NoPermissionTemplate', 'UsePageHitCounter', 'ForceImageMagickResize', 'CheckStopWords'); UPDATE ConfigurationAdmin SET DisplayOrder = 40.01 WHERE VariableName = 'SessionTimeout'; UPDATE ConfigurationValues SET Section = 'in-portal:configure_general' WHERE VariableName = 'SessionTimeout'; UPDATE ConfigurationAdmin SET DisplayOrder = DisplayOrder - 0.01 WHERE VariableName IN ('KeepSessionOnBrowserClose', 'SessionReferrerCheck', 'UseJSRedirect'); ALTER TABLE Events ADD FrontEndOnly TINYINT UNSIGNED NOT NULL DEFAULT '0' AFTER Enabled, ADD INDEX (FrontEndOnly); UPDATE Events SET FrontEndOnly = 1 WHERE Enabled = 2; UPDATE Events SET Enabled = 1 WHERE Enabled = 2; ALTER TABLE Events CHANGE FromUserId FromUserId INT(11) NULL DEFAULT NULL; UPDATE Events SET FromUserId = NULL WHERE FromUserId = 0; DELETE FROM ConfigurationAdmin WHERE VariableName = 'SiteNameSubTitle'; DELETE FROM ConfigurationValues WHERE VariableName = 'SiteNameSubTitle'; UPDATE ConfigurationAdmin SET DisplayOrder = DisplayOrder - 0.01 WHERE VariableName IN ('UseModRewrite', 'cms_DefaultDesign', 'ErrorTemplate' 'NoPermissionTemplate', 'UsePageHitCounter', 'ForceImageMagickResize', 'CheckStopWords'); ALTER TABLE ConfigurationAdmin CHANGE validation Validation TEXT NULL DEFAULT NULL; UPDATE ConfigurationAdmin SET Validation = 'a:3:{s:4:"type";s:3:"int";s:13:"min_value_inc";i:1;s:8:"required";i:1;}' WHERE VariableName = 'SessionTimeout'; INSERT INTO ConfigurationAdmin VALUES ('AdminConsoleInterface', 'la_section_SettingsAdmin', 'la_config_AdminConsoleInterface', 'select', '', 'simple=+simple,advanced=+advanced,custom=+custom', 50.01, 0, 1); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'AdminConsoleInterface', 'simple', 'In-Portal', 'in-portal:configure_general'); INSERT INTO ConfigurationAdmin VALUES ('AllowAdminConsoleInterfaceChange', 'la_section_SettingsAdmin', 'la_config_AllowAdminConsoleInterfaceChange', 'checkbox', NULL , NULL , 40.01, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'AllowAdminConsoleInterfaceChange', '1', 'In-Portal', 'in-portal:configure_advanced'); UPDATE ConfigurationAdmin SET DisplayOrder = DisplayOrder + 0.01 WHERE VariableName IN ('UseToolbarLabels', 'UseSmallHeader', 'UseColumnFreezer', 'UsePopups', 'UseDoubleSorting', 'MenuFrameWidth', 'ResizableFrames', 'AutoRefreshIntervals', 'DebugOnlyFormConfigurator', 'UseModalWindows'); INSERT INTO ConfigurationAdmin VALUES ('UseTemplateCompression', 'la_section_SettingsSystem', 'la_config_UseTemplateCompression', 'checkbox', '', '', 60.03, 0, 1); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'UseTemplateCompression', '0', 'In-Portal', 'in-portal:configure_advanced'); UPDATE ConfigurationAdmin SET DisplayOrder = DisplayOrder + 0.01 WHERE VariableName IN ('TrimRequiredFields', 'UseCronForRegularEvent', 'UseChangeLog', 'Backup_Path', 'SystemTagCache', 'SocketBlockingMode'); DELETE FROM ConfigurationAdmin WHERE VariableName = 'UseModalWindows'; DELETE FROM ConfigurationValues WHERE VariableName = 'UseModalWindows'; DELETE FROM Phrase WHERE Phrase = 'la_config_UseModalWindows'; UPDATE ConfigurationAdmin SET element_type = 'select', ValueList = '0=la_opt_SameWindow,1=la_opt_PopupWindow,2=la_opt_ModalWindow' WHERE VariableName = 'UsePopups'; UPDATE Phrase SET Translation = 'Editing Window Style' WHERE Phrase = 'la_config_UsePopups'; INSERT INTO ConfigurationAdmin VALUES ('UseVisitorTracking', 'la_section_SettingsWebsite', 'la_config_UseVisitorTracking', 'checkbox', '', '', 10.09, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'UseVisitorTracking', '0', 'In-Portal', 'in-portal:configure_advanced'); DELETE FROM ConfigurationAdmin WHERE VariableName = 'SessionReferrerCheck'; DELETE FROM ConfigurationValues WHERE VariableName = 'SessionReferrerCheck'; DELETE FROM Phrase WHERE Phrase = 'la_promt_ReferrerCheck'; INSERT INTO ConfigurationAdmin VALUES ('SessionBrowserSignatureCheck', 'la_section_SettingsSession', 'la_config_SessionBrowserSignatureCheck', 'checkbox', NULL, NULL, 20.04, 0, 1); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'SessionBrowserSignatureCheck', '0', 'In-Portal', 'in-portal:configure_advanced'); INSERT INTO ConfigurationAdmin VALUES ('SessionIPAddressCheck', 'la_section_SettingsSession', 'la_config_SessionIPAddressCheck', 'checkbox', NULL, NULL, 20.05, 0, 1); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'SessionIPAddressCheck', '0', 'In-Portal', 'in-portal:configure_advanced'); UPDATE ConfigurationAdmin SET DisplayOrder = DisplayOrder + 0.01 WHERE VariableName = 'UseJSRedirect'; ALTER TABLE UserSession DROP CurrentTempKey, DROP PrevTempKey, ADD BrowserSignature VARCHAR(32) NOT NULL, ADD INDEX (BrowserSignature); UPDATE ConfigurationAdmin SET DisplayOrder = DisplayOrder + 0.01 WHERE heading = 'la_section_SettingsAdmin' AND DisplayOrder > 40 AND DisplayOrder < 50; UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsAdmin', DisplayOrder = 40.01 WHERE VariableName = 'RootPass'; UPDATE ConfigurationValues SET ModuleOwner = 'In-Portal', Section = 'in-portal:configure_advanced' WHERE VariableName = 'RootPass'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.12 WHERE VariableName = 'User_Default_Registration_Country'; UPDATE ConfigurationAdmin SET heading = 'la_section_SettingsAdmin', DisplayOrder = 40.12 WHERE VariableName = 'RememberLastAdminTemplate'; UPDATE ConfigurationValues SET ModuleOwner = 'In-Portal', Section = 'in-portal:configure_advanced' WHERE VariableName = 'RememberLastAdminTemplate'; UPDATE ConfigurationAdmin SET DisplayOrder = 10.14 WHERE VariableName = 'DefaultSettingsUserId'; INSERT INTO ConfigurationAdmin VALUES ('UseHTTPAuth', 'la_section_SettingsAdmin', 'la_config_UseHTTPAuth', 'checkbox', '', '', 40.13, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'UseHTTPAuth', '0', 'In-Portal', 'in-portal:configure_advanced'); INSERT INTO ConfigurationAdmin VALUES ('HTTPAuthUsername', 'la_section_SettingsAdmin', 'la_config_HTTPAuthUsername', 'text', '', '', 40.14, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'HTTPAuthUsername', '', 'In-Portal', 'in-portal:configure_advanced'); INSERT INTO ConfigurationAdmin VALUES ('HTTPAuthPassword', 'la_section_SettingsAdmin', 'la_config_HTTPAuthPassword', 'password', NULL, NULL, 40.15, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'HTTPAuthPassword', '', 'In-Portal', 'in-portal:configure_advanced'); INSERT INTO ConfigurationAdmin VALUES ('HTTPAuthBypassIPs', 'la_section_SettingsAdmin', 'la_config_HTTPAuthBypassIPs', 'text', '', '', 40.15, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'HTTPAuthBypassIPs', '', 'In-Portal', 'in-portal:configure_advanced'); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:service.edit', 11, 1, 1, 0); UPDATE Phrase SET Phrase = 'la_col_Rating' WHERE Phrase = 'la_col_rating'; UPDATE Phrase SET Phrase = 'la_text_Review' WHERE Phrase = 'la_text_review'; UPDATE Phrase SET Phrase = 'la_title_Reviews' WHERE Phrase = 'la_title_reviews'; UPDATE Phrase SET Phrase = 'la_ToolTip_cancel' WHERE Phrase = 'la_tooltip_cancel'; ALTER TABLE Phrase ADD PhraseKey VARCHAR(255) NOT NULL AFTER Phrase, ADD INDEX (PhraseKey); UPDATE Phrase SET PhraseKey = UPPER(Phrase); UPDATE Modules SET Loaded = 1 WHERE `Name` = 'In-Portal'; # ===== v 5.0.2-B1 ===== ALTER TABLE PortalGroup DROP ResourceId; ALTER TABLE Category DROP l1_Translated, DROP l2_Translated, DROP l3_Translated, DROP l4_Translated, DROP l5_Translated; ALTER TABLE PageContent DROP l1_Translated, DROP l2_Translated, DROP l3_Translated, DROP l4_Translated, DROP l5_Translated; ALTER TABLE Category CHANGE CachedTemplate CachedTemplate varchar(255) NOT NULL DEFAULT '', CHANGE ThemeId ThemeId int(10) unsigned NOT NULL DEFAULT '0'; ALTER TABLE UserSession CHANGE BrowserSignature BrowserSignature varchar(32) NOT NULL DEFAULT ''; ALTER TABLE ChangeLogs CHANGE Changes Changes text NULL, CHANGE OccuredOn OccuredOn INT(11) NULL DEFAULT NULL; ALTER TABLE EmailLog CHANGE EventParams EventParams text NULL; ALTER TABLE FormFields CHANGE DefaultValue DefaultValue text NULL; ALTER TABLE ImportCache CHANGE VarValue VarValue text NULL; ALTER TABLE ImportScripts CHANGE Description Description text NULL; ALTER TABLE PersistantSessionData CHANGE VariableValue VariableValue text NULL; ALTER TABLE Phrase CHANGE `Translation` `Translation` text NULL, CHANGE PhraseKey PhraseKey VARCHAR(255) NOT NULL DEFAULT '', CHANGE LastChanged LastChanged INT(10) UNSIGNED NULL DEFAULT NULL; ALTER TABLE PhraseCache CHANGE PhraseList PhraseList text NULL; ALTER TABLE Stylesheets CHANGE AdvancedCSS AdvancedCSS text NULL, CHANGE LastCompiled LastCompiled INT(10) UNSIGNED NULL DEFAULT NULL; ALTER TABLE StylesheetSelectors CHANGE SelectorData SelectorData text NULL, CHANGE Description Description text NULL, CHANGE AdvancedCSS AdvancedCSS text NULL; ALTER TABLE Category CHANGE `Status` `Status` TINYINT(4) NOT NULL DEFAULT '1', CHANGE CreatedOn CreatedOn INT(11) NULL DEFAULT NULL, CHANGE Modified Modified INT(11) NULL DEFAULT NULL; ALTER TABLE Language CHANGE UserDocsUrl UserDocsUrl VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE MailingLists CHANGE Subject Subject VARCHAR(255) NOT NULL DEFAULT '', CHANGE EmailsQueued EmailsQueued INT(10) UNSIGNED NOT NULL DEFAULT '0', CHANGE EmailsSent EmailsSent INT(10) UNSIGNED NOT NULL DEFAULT '0', CHANGE EmailsTotal EmailsTotal INT(10) UNSIGNED NOT NULL DEFAULT '0'; ALTER TABLE EmailQueue CHANGE MailingId MailingId INT(10) UNSIGNED NOT NULL DEFAULT '0', CHANGE Queued Queued INT(10) UNSIGNED NULL DEFAULT NULL, CHANGE LastSendRetry LastSendRetry INT(10) UNSIGNED NULL DEFAULT NULL; ALTER TABLE ImportScripts CHANGE `Status` `Status` TINYINT(4) NOT NULL DEFAULT '1'; ALTER TABLE Semaphores CHANGE SessionKey SessionKey INT(10) UNSIGNED NOT NULL DEFAULT '0', CHANGE `Timestamp` `Timestamp` INT(10) UNSIGNED NOT NULL DEFAULT '0', CHANGE MainPrefix MainPrefix VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE Skins CHANGE LogoBottom LogoBottom VARCHAR(255) NOT NULL DEFAULT '', CHANGE LogoLogin LogoLogin VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE ItemReview CHANGE ReviewText ReviewText LONGTEXT NULL; ALTER TABLE SessionData CHANGE VariableValue VariableValue LONGTEXT NULL; ALTER TABLE PortalUser CHANGE `Status` `Status` TINYINT(4) NOT NULL DEFAULT '1', CHANGE Modified Modified INT(11) NULL DEFAULT NULL; ALTER TABLE ItemFiles CHANGE CreatedOn CreatedOn INT(11) UNSIGNED NULL DEFAULT NULL; ALTER TABLE FormSubmissions CHANGE SubmissionTime SubmissionTime INT(11) NULL DEFAULT NULL; ALTER TABLE SessionLogs CHANGE SessionStart SessionStart INT(11) NULL DEFAULT NULL; ALTER TABLE Visits CHANGE VisitDate VisitDate INT(10) UNSIGNED NULL DEFAULT NULL; # ===== v 5.0.2-B2 ===== ALTER TABLE Theme ADD LanguagePackInstalled TINYINT UNSIGNED NOT NULL DEFAULT '0', ADD TemplateAliases TEXT, ADD INDEX (LanguagePackInstalled); ALTER TABLE ThemeFiles ADD TemplateAlias VARCHAR(255) NOT NULL DEFAULT '' AFTER FilePath, ADD INDEX (TemplateAlias); UPDATE Phrase SET PhraseType = 1 WHERE Phrase IN ('la_ToolTip_MoveUp', 'la_ToolTip_MoveDown', 'la_invalid_state', 'la_Pending', 'la_text_sess_expired', 'la_ToolTip_Export'); DELETE FROM Phrase WHERE Phrase IN ('la_ToolTip_Move_Up', 'la_ToolTip_Move_Down'); UPDATE Phrase SET Phrase = 'lu_btn_SendPassword' WHERE Phrase = 'LU_BTN_SENDPASSWORD'; ALTER TABLE Category DROP IsIndex; DELETE FROM Phrase WHERE Phrase IN ('la_CategoryIndex', 'la_Container', 'la_fld_IsIndex', 'lu_text_Redirecting', 'lu_title_Redirecting', 'lu_zip_code'); ALTER TABLE PortalUser ADD AdminLanguage INT(11) NULL DEFAULT NULL, ADD INDEX (AdminLanguage); # ===== v 5.0.2-RC1 ===== # ===== v 5.0.2 ===== # ===== v 5.0.3-B1 ===== ALTER TABLE PermCache ADD INDEX (ACL); INSERT INTO ConfigurationAdmin VALUES ('cms_DefaultTrackingCode', 'la_section_SettingsWebsite', 'la_config_DefaultTrackingCode', 'textarea', NULL, 'COLS=40 ROWS=5', 10.10, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'cms_DefaultTrackingCode', '', 'In-Portal', 'in-portal:configure_advanced'); UPDATE Phrase SET Module = 'Core' WHERE Phrase IN ('la_fld_Image', 'la_fld_Qty'); # ===== v 5.0.3-B2 ===== UPDATE CustomField SET ValueList = REPLACE(ValueList, '=+||', '') WHERE ElementType = 'radio'; # ===== v 5.0.3-RC1 ===== # ===== v 5.0.3 ===== # ===== v 5.0.4-B1 ===== # ===== v 5.0.4-B2 ===== # ===== v 5.0.4 ===== # ===== v 5.1.0-B1 ===== DROP TABLE EmailMessage; DELETE FROM PersistantSessionData WHERE VariableName = 'emailevents_columns_.'; INSERT INTO Permissions (Permission, GroupId, PermissionValue, Type, CatId) SELECT 'in-portal:configemail.add' AS Permission, GroupId, PermissionValue, Type, CatId FROM <%TABLE_PREFIX%>Permissions WHERE Permission = 'in-portal:configemail.edit'; INSERT INTO Permissions (Permission, GroupId, PermissionValue, Type, CatId) SELECT 'in-portal:configemail.delete' AS Permission, GroupId, PermissionValue, Type, CatId FROM <%TABLE_PREFIX%>Permissions WHERE Permission = 'in-portal:configemail.edit'; ALTER TABLE Events ADD l1_Description text; UPDATE Events e SET e.l1_Description = ( SELECT p.l<%PRIMARY_LANGUAGE%>_Translation FROM <%TABLE_PREFIX%>Phrase p WHERE p.Phrase = e.Description ); UPDATE Events SET Description = l1_Description; ALTER TABLE Events DROP l1_Description, CHANGE Description Description TEXT NULL; DELETE FROM Phrase WHERE Phrase LIKE 'la_event_%'; DELETE FROM PersistantSessionData WHERE VariableName = 'phrases_columns_.'; UPDATE Category SET FormId = NULL WHERE FormId = 0; INSERT INTO ConfigurationAdmin VALUES ('MemcacheServers', 'la_section_SettingsCaching', 'la_config_MemcacheServers', 'text', '', '', 80.02, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'MemcacheServers', 'localhost:11211', 'In-Portal', 'in-portal:configure_advanced'); ALTER TABLE Category ADD EnablePageCache TINYINT NOT NULL DEFAULT '0', ADD OverridePageCacheKey TINYINT NOT NULL DEFAULT '0', ADD PageCacheKey VARCHAR(255) NOT NULL DEFAULT '', ADD PageExpiration INT NULL DEFAULT NULL , ADD INDEX (EnablePageCache), ADD INDEX (OverridePageCacheKey), ADD INDEX (PageExpiration); DELETE FROM Cache WHERE VarName LIKE 'mod_rw_%'; CREATE TABLE CachedUrls ( UrlId int(11) NOT NULL AUTO_INCREMENT, Url varchar(255) NOT NULL DEFAULT '', DomainId int(11) NOT NULL DEFAULT '0', `Hash` int(11) NOT NULL DEFAULT '0', Prefixes varchar(255) NOT NULL DEFAULT '', ParsedVars text NOT NULL, Cached int(10) unsigned DEFAULT NULL, LifeTime int(11) NOT NULL DEFAULT '-1', PRIMARY KEY (UrlId), KEY Url (Url), KEY `Hash` (`Hash`), KEY Prefixes (Prefixes), KEY Cached (Cached), KEY LifeTime (LifeTime), KEY DomainId (DomainId) ); INSERT INTO ConfigurationAdmin VALUES ('CacheHandler', 'la_section_SettingsCaching', 'la_config_CacheHandler', 'select', NULL, 'Fake=la_None||Memcache=+Memcached||Apc=+Alternative PHP Cache||XCache=+XCache', 80.01, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'CacheHandler', 'Fake', 'In-Portal', 'in-portal:configure_advanced'); ALTER TABLE ConfigurationValues ADD Heading varchar(255) NOT NULL DEFAULT '', ADD Prompt varchar(255) NOT NULL DEFAULT '', ADD ElementType varchar(255) NOT NULL DEFAULT '', ADD Validation text, ADD ValueList text, ADD DisplayOrder double NOT NULL DEFAULT '0', ADD GroupDisplayOrder double NOT NULL DEFAULT '0', ADD Install int(11) NOT NULL DEFAULT '1', ADD INDEX (DisplayOrder), ADD INDEX (GroupDisplayOrder), ADD INDEX (Install); UPDATE ConfigurationValues cv SET cv.Heading = (SELECT ca1.heading FROM <%TABLE_PREFIX%>ConfigurationAdmin ca1 WHERE ca1.VariableName = cv.VariableName), cv.Prompt = (SELECT ca2.prompt FROM <%TABLE_PREFIX%>ConfigurationAdmin ca2 WHERE ca2.VariableName = cv.VariableName), cv.ElementType = (SELECT ca3.element_type FROM <%TABLE_PREFIX%>ConfigurationAdmin ca3 WHERE ca3.VariableName = cv.VariableName), cv.Validation = (SELECT ca4.Validation FROM <%TABLE_PREFIX%>ConfigurationAdmin ca4 WHERE ca4.VariableName = cv.VariableName), cv.ValueList = (SELECT ca5.ValueList FROM <%TABLE_PREFIX%>ConfigurationAdmin ca5 WHERE ca5.VariableName = cv.VariableName), cv.DisplayOrder = (SELECT ca6.DisplayOrder FROM <%TABLE_PREFIX%>ConfigurationAdmin ca6 WHERE ca6.VariableName = cv.VariableName), cv.GroupDisplayOrder = (SELECT ca7.GroupDisplayOrder FROM <%TABLE_PREFIX%>ConfigurationAdmin ca7 WHERE ca7.VariableName = cv.VariableName), cv.`Install` = (SELECT ca8.`Install` FROM <%TABLE_PREFIX%>ConfigurationAdmin ca8 WHERE ca8.VariableName = cv.VariableName); DROP TABLE ConfigurationAdmin; UPDATE ConfigurationValues SET ValueList = '=+||SELECT l%3$s_Name AS OptionName, CountryStateId AS OptionValue FROM CountryStates WHERE Type = 1 ORDER BY OptionName' WHERE ValueList = '=+||SELECT DestName AS OptionName, DestId AS OptionValue FROM StdDestinations WHERE COALESCE(DestParentId, 0) = 0 ORDER BY OptionName'; ALTER TABLE Forms ADD RequireLogin TINYINT NOT NULL DEFAULT '0', ADD INDEX (RequireLogin), ADD UseSecurityImage TINYINT NOT NULL DEFAULT '0', ADD INDEX (UseSecurityImage), ADD EnableEmailCommunication TINYINT NOT NULL DEFAULT '0', ADD INDEX (EnableEmailCommunication), ADD ReplyFromName VARCHAR(255) NOT NULL DEFAULT '', ADD ReplyFromEmail VARCHAR(255) NOT NULL DEFAULT '', ADD ReplyCc VARCHAR(255) NOT NULL DEFAULT '', ADD ReplyBcc VARCHAR(255) NOT NULL DEFAULT '', ADD ReplyMessageSignature TEXT, ADD ReplyServer VARCHAR(255) NOT NULL DEFAULT '', ADD ReplyPort INT(10) NOT NULL DEFAULT '110', ADD ReplyUsername VARCHAR(255) NOT NULL DEFAULT '', ADD ReplyPassword VARCHAR(255) NOT NULL DEFAULT '', ADD BounceEmail VARCHAR(255) NOT NULL DEFAULT '', ADD BounceServer VARCHAR(255) NOT NULL DEFAULT '', ADD BouncePort INT(10) NOT NULL DEFAULT '110', ADD BounceUsername VARCHAR(255) NOT NULL DEFAULT '', ADD BouncePassword VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE FormFields ADD Visibility TINYINT NOT NULL DEFAULT '1', ADD INDEX (Visibility), ADD EmailCommunicationRole TINYINT NOT NULL DEFAULT '0', ADD INDEX (EmailCommunicationRole); ALTER TABLE FormSubmissions ADD IPAddress VARCHAR(15) NOT NULL DEFAULT '' AFTER SubmissionTime, ADD ReferrerURL VARCHAR(255) NOT NULL DEFAULT '' AFTER IPAddress, ADD LogStatus TINYINT UNSIGNED NOT NULL DEFAULT '2' AFTER ReferrerURL, ADD LastUpdatedOn INT UNSIGNED NULL AFTER LogStatus, ADD Notes TEXT NULL AFTER LastUpdatedOn, ADD INDEX (LogStatus), ADD INDEX (LastUpdatedOn); CREATE TABLE SubmissionLog ( SubmissionLogId int(11) NOT NULL AUTO_INCREMENT, FormSubmissionId int(10) unsigned NOT NULL, FromEmail varchar(255) NOT NULL DEFAULT '', ToEmail varchar(255) NOT NULL DEFAULT '', Cc text, Bcc text, `Subject` varchar(255) NOT NULL DEFAULT '', Message text, Attachment text, ReplyStatus tinyint(3) unsigned NOT NULL DEFAULT '0', SentStatus tinyint(3) unsigned NOT NULL DEFAULT '0', SentOn int(10) unsigned DEFAULT NULL, RepliedOn int(10) unsigned DEFAULT NULL, VerifyCode varchar(32) NOT NULL DEFAULT '', DraftId int(10) unsigned NOT NULL DEFAULT '0', MessageId varchar(255) NOT NULL DEFAULT '', BounceInfo text, BounceDate int(11) DEFAULT NULL, PRIMARY KEY (SubmissionLogId), KEY FormSubmissionId (FormSubmissionId), KEY ReplyStatus (ReplyStatus), KEY SentStatus (SentStatus), KEY SentOn (SentOn), KEY RepliedOn (RepliedOn), KEY VerifyCode (VerifyCode), KEY DraftId (DraftId), KEY BounceDate (BounceDate), KEY MessageId (MessageId) ); CREATE TABLE Drafts ( DraftId int(11) NOT NULL AUTO_INCREMENT, FormSubmissionId int(10) unsigned NOT NULL DEFAULT '0', CreatedOn int(10) unsigned DEFAULT NULL, CreatedById int(11) NOT NULL, Message text, PRIMARY KEY (DraftId), KEY FormSubmissionId (FormSubmissionId), KEY CreatedOn (CreatedOn), KEY CreatedById (CreatedById) ); INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.TO.USER', NULL, 1, 0, NULL, 'Core:Category', 'Admin Reply to User Form Submission', 1); INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER', NULL, 1, 0, NULL, 'Core:Category', 'User Replied to It\'s Form Submission', 1); INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, FromUserId, Module, Description, Type) VALUES(DEFAULT, 'FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED', NULL, 1, 0, NULL, 'Core:Category', 'Form Submission Admin Reply Delivery Failure', 1); ALTER TABLE ConfigurationValues ADD HintLabel VARCHAR(255) NULL DEFAULT NULL, ADD INDEX (HintLabel); UPDATE ConfigurationValues SET HintLabel = 'la_hint_MemcacheServers' WHERE VariableName = 'MemcacheServers'; INSERT INTO ConfigurationValues VALUES(DEFAULT, 'ModRewriteUrlEnding', '.html', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_ModRewriteUrlEnding', 'select', '', '=+||/=+/||.html=+.html', 10.021, 0, 0, NULL); INSERT INTO ConfigurationValues VALUES(DEFAULT, 'ForceModRewriteUrlEnding', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_ForceModRewriteUrlEnding', 'checkbox', '', NULL, 10.022, 0, 0, 'la_hint_ForceModRewriteUrlEnding'); UPDATE Phrase SET l<%PRIMARY_LANGUAGE%>_Translation = 'Enable SEO-friendly URLs mode (MOD-REWRITE)' WHERE Phrase = 'la_config_use_modrewrite' AND l<%PRIMARY_LANGUAGE%>_Translation = 'Use MOD REWRITE'; INSERT INTO ConfigurationValues VALUES(DEFAULT, 'UseContentLanguageNegotiation', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_UseContentLanguageNegotiation', 'checkbox', '', '', 10.023, 0, 0, NULL); INSERT INTO ConfigurationValues VALUES(DEFAULT, 'SessionCookieDomains', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSession', 'la_config_SessionCookieDomains', 'textarea', '', 'rows="5" cols="40"', 20.021, 0, 0, NULL); CREATE TABLE SiteDomains ( DomainId int(11) NOT NULL AUTO_INCREMENT, DomainName varchar(255) NOT NULL DEFAULT '', DomainNameUsesRegExp tinyint(4) NOT NULL DEFAULT '0', SSLUrl varchar(255) NOT NULL DEFAULT '', SSLUrlUsesRegExp tinyint(4) NOT NULL DEFAULT '0', AdminEmail varchar(255) NOT NULL DEFAULT '', Country varchar(3) NOT NULL DEFAULT '', PrimaryLanguageId int(11) NOT NULL DEFAULT '0', Languages varchar(255) NOT NULL DEFAULT '', PrimaryThemeId int(11) NOT NULL DEFAULT '0', Themes varchar(255) NOT NULL DEFAULT '', DomainIPRange text, ExternalUrl varchar(255) NOT NULL DEFAULT '', RedirectOnIPMatch tinyint(4) NOT NULL DEFAULT '0', Priority int(11) NOT NULL DEFAULT '0', PRIMARY KEY (DomainId), KEY DomainName (DomainName), KEY DomainNameUsesRegExp (DomainNameUsesRegExp), KEY SSLUrl (SSLUrl), KEY SSLUrlUsesRegExp (SSLUrlUsesRegExp), KEY AdminEmail (AdminEmail), KEY Country (Country), KEY PrimaryLanguageId (PrimaryLanguageId), KEY Languages (Languages), KEY PrimaryThemeId (PrimaryThemeId), KEY Themes (Themes), KEY ExternalUrl (ExternalUrl), KEY RedirectOnIPMatch (RedirectOnIPMatch), KEY Priority (Priority) ); DELETE FROM Phrase WHERE Phrase = 'la_config_time_server'; DELETE FROM ConfigurationValues WHERE VariableName = 'Config_Server_Time'; UPDATE ConfigurationValues SET ValueList = NULL, DisplayOrder = 20.02 WHERE VariableName = 'Config_Site_Time'; UPDATE ConfigurationValues SET VariableValue = '' WHERE VariableName = 'Config_Site_Time' AND VariableValue = 14; UPDATE Events SET AllowChangingSender = 1, AllowChangingRecipient = 1; UPDATE Events SET Module = 'Core' WHERE Module LIKE 'Core:%'; DELETE FROM Permissions WHERE Permission LIKE 'in-portal:configuration_email%'; DELETE FROM Permissions WHERE Permission LIKE 'in-portal:user_email%'; DELETE FROM Phrase WHERE Phrase IN ('la_fld_FromToUser', 'la_col_FromToUser'); # ===== v 5.1.0-B2 ===== # ===== v 5.1.0-RC1 ===== UPDATE Phrase SET Module = 'Core' WHERE Phrase = 'la_fld_Group'; UPDATE PermissionConfig SET Description = REPLACE(Description, 'lu_PermName_', 'la_PermName_'), ErrorMessage = REPLACE(ErrorMessage, 'lu_PermName_', 'la_PermName_'); UPDATE Phrase SET Phrase = REPLACE(Phrase, 'lu_PermName_', 'la_PermName_'), PhraseKey = REPLACE(PhraseKey, 'LU_PERMNAME_', 'LA_PERMNAME_'), PhraseType = 1 WHERE PhraseKey LIKE 'LU_PERMNAME_%'; UPDATE Phrase SET Phrase = 'la_no_permissions', PhraseKey = 'LA_NO_PERMISSIONS', PhraseType = 1 WHERE PhraseKey = 'LU_NO_PERMISSIONS'; UPDATE Phrase SET PhraseType = 0 WHERE PhraseKey IN ( 'LU_FERROR_FORGOTPW_NODATA', 'LU_FERROR_UNKNOWN_USERNAME', 'LU_FERROR_UNKNOWN_EMAIL' ); DELETE FROM ConfigurationValues WHERE VariableName = 'Root_Name'; DELETE FROM Phrase WHERE PhraseKey = 'LA_PROMPT_ROOT_NAME'; UPDATE ConfigurationValues SET DisplayOrder = DisplayOrder - 0.01 WHERE ModuleOwner = 'In-Portal' AND `Section` = 'in-portal:configure_categories' AND DisplayOrder > 10.07; # ===== v 5.1.0 ===== UPDATE Events SET Headers = NULL WHERE Headers = ''; UPDATE Events SET MessageType = 'text' WHERE Event = 'FORM.SUBMISSION.REPLY.TO.USER'; ALTER TABLE Forms ADD ProcessUnmatchedEmails TINYINT NOT NULL DEFAULT '0' AFTER EnableEmailCommunication, ADD INDEX (ProcessUnmatchedEmails); ALTER TABLE FormSubmissions ADD MessageId VARCHAR(255) NULL DEFAULT NULL AFTER Notes, ADD INDEX (MessageId); # ===== v 5.1.1-B1 ===== ALTER TABLE PortalUser ADD DisplayToPublic TEXT NULL; UPDATE Phrase SET l<%PRIMARY_LANGUAGE%>_Translation = 'Comments' WHERE PhraseKey = 'LA_FLD_COMMENTS'; ALTER TABLE Category CHANGE `Type` `Type` INT(11) NOT NULL DEFAULT '1', CHANGE `IsSystem` `Protected` TINYINT( 4 ) NOT NULL DEFAULT '0', ADD INDEX ( `Protected` ); UPDATE Category SET `Type` = IF(`Protected` = 1, 2, 1); UPDATE Category SET `Protected` = 1 WHERE ThemeId > 0; ALTER TABLE Category CHANGE CachedDescendantCatsQty CachedDescendantCatsQty INT(11) NOT NULL DEFAULT '0'; ALTER TABLE Events CHANGE `Module` `Module` VARCHAR(40) NOT NULL DEFAULT 'Core'; ALTER TABLE Language CHANGE DateFormat DateFormat VARCHAR(50) NOT NULL DEFAULT 'm/d/Y', CHANGE TimeFormat TimeFormat VARCHAR(50) NOT NULL DEFAULT 'g:i:s A', CHANGE DecimalPoint DecimalPoint VARCHAR(10) NOT NULL DEFAULT '.', CHANGE Charset Charset VARCHAR(20) NOT NULL DEFAULT 'utf-8'; ALTER TABLE ItemReview CHANGE Rating Rating TINYINT(3) UNSIGNED NOT NULL DEFAULT '0'; UPDATE PortalUser SET tz = NULL; ALTER TABLE Category CHANGE CreatedById CreatedById INT(11) NULL DEFAULT NULL, CHANGE ModifiedById ModifiedById INT(11) NULL DEFAULT NULL; UPDATE Category SET CreatedById = NULL WHERE CreatedById = 0; UPDATE Category SET ModifiedById = NULL WHERE ModifiedById = 0; ALTER TABLE ItemFiles CHANGE CreatedById CreatedById INT(11) NULL DEFAULT NULL; ALTER TABLE Drafts CHANGE CreatedById CreatedById INT(11) NULL DEFAULT NULL; UPDATE Drafts SET CreatedById = NULL WHERE CreatedById = 0; ALTER TABLE ItemReview CHANGE CreatedById CreatedById INT(11) NULL DEFAULT NULL; # ===== v 5.1.1-B2 ===== UPDATE Phrase SET `Module` = 'Core' WHERE PhraseKey = 'LU_SECTION_FILES'; # ===== v 5.1.1-RC1 ===== ALTER TABLE PortalUser CHANGE Phone Phone VARCHAR(255) NOT NULL DEFAULT '', CHANGE City City VARCHAR(255) NOT NULL DEFAULT '', CHANGE Street Street VARCHAR(255) NOT NULL DEFAULT '', CHANGE Zip Zip VARCHAR(20) NOT NULL DEFAULT '', CHANGE ip ip VARCHAR(20) NOT NULL DEFAULT ''; UPDATE Phrase SET l<%PRIMARY_LANGUAGE%>_Translation = 'Use Cron to run Agents' WHERE PhraseKey = 'LA_USECRONFORREGULAREVENT' AND l<%PRIMARY_LANGUAGE%>_Translation = 'Use Cron for Running Regular Events'; # ===== v 5.1.1 ===== # ===== v 5.1.2-B1 ===== DROP TABLE EmailSubscribers; DROP TABLE IgnoreKeywords; DROP TABLE IgnoreKeywords; ALTER TABLE PermissionConfig DROP ErrorMessage; # ===== v 5.1.2-B2 ===== # ===== v 5.1.2-RC1 ===== DROP TABLE Stylesheets; DROP TABLE StylesheetSelectors; DROP TABLE SysCache; DROP TABLE TagAttributes; DROP TABLE TagLibrary; DELETE FROM Phrase WHERE PhraseKey IN ( 'LA_FLD_STYLESHEETID', 'LA_PROMPT_STYLESHEET', 'LA_TAB_STYLESHEETS', 'LA_TITLE_ADDING_STYLESHEET', 'LA_TITLE_EDITING_STYLESHEET', 'LA_TITLE_NEW_STYLESHEET', 'LA_TITLE_STYLESHEETS', 'LA_TOOLTIP_NEWSTYLESHEET', 'LA_COL_SELECTORNAME', 'LA_COL_BASEDON', 'LA_FLD_SELECTORBASE', 'LA_FLD_SELECTORDATA', 'LA_FLD_SELECTORID', 'LA_FLD_SELECTORNAME' ); # ===== v 5.1.2 ===== # ===== v 5.1.3-B1 ===== ALTER TABLE FormSubmissions CHANGE ReferrerURL ReferrerURL TEXT NULL; INSERT INTO ConfigurationValues VALUES (DEFAULT, 'UserEmailActivationTimeout', '', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_config_UserEmailActivationTimeout', 'text', NULL, NULL, 10.051, 0, 0, NULL); # ===== v 5.1.3-B2 ===== ALTER TABLE Modules ADD AppliedDBRevisions TEXT NULL; # ===== v 5.1.3-RC1 ===== # ===== v 5.1.3-RC2 ===== UPDATE Events SET l<%PRIMARY_LANGUAGE%>_Subject = 'New User Registration ( - Activation Email)' WHERE Event = 'USER.ADD.PENDING' AND `Type` = 0 AND l<%PRIMARY_LANGUAGE%>_Subject LIKE '% - Activation Email)%'; INSERT INTO ConfigurationValues VALUES(DEFAULT, 'MaxUserName', '', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_text_min_username', 'text', '', 'style="width: 50px;"', 10.03, 2, 0, NULL); UPDATE ConfigurationValues SET GroupDisplayOrder = 1, ValueList = 'style="width: 50px;"' WHERE VariableName = 'Min_UserName'; UPDATE Phrase SET l<%PRIMARY_LANGUAGE%>_Translation = 'User name length (min - max)' WHERE PhraseKey = 'LA_TEXT_MIN_USERNAME' AND l<%PRIMARY_LANGUAGE%>_Translation = 'Minimum user name length'; # ===== v 5.1.3 ===== UPDATE PortalUser SET Modified = NULL; INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:site_domains.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:site_domains.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:site_domains.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:site_domains.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:country_states.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:country_states.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:country_states.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:country_states.view', 11, 1, 1, 0); # ===== v 5.2.0-B1 ===== ALTER TABLE PortalUser ADD UserType TINYINT NOT NULL, ADD PrimaryGroupId INT NULL, ADD INDEX (UserType); UPDATE PortalUser u SET u.PrimaryGroupId = (SELECT ug.GroupId FROM <%TABLE_PREFIX%>UserGroup ug WHERE ug.PortalUserId = u.PortalUserId AND ug.PrimaryGroup = 1); UPDATE PortalUser u SET u.UserType = IF(u.PrimaryGroupId = 11, 1, 0); ALTER TABLE UserGroup DROP PrimaryGroup; UPDATE ConfigurationValues SET DisplayOrder = DisplayOrder + 0.01 WHERE `ModuleOwner` = 'In-Portal:Users' AND `Section` = 'in-portal:configure_users' AND DisplayOrder BETWEEN 10.12 AND 20.00; INSERT INTO ConfigurationValues VALUES(DEFAULT, 'User_AdminGroup', '11', 'In-Portal:Users', 'in-portal:configure_users', 'la_title_General', 'la_users_admin_group', 'select', NULL, '0=lu_none||SELECT GroupId as OptionValue, Name as OptionName FROM PortalGroup WHERE Enabled=1 AND Personal=0', 10.12, 0, 1, NULL); ALTER TABLE PortalUser DROP INDEX Login, ADD INDEX Login (Login); ALTER TABLE PortalUser CHANGE Login Login VARCHAR(255) NOT NULL; ALTER TABLE PortalUser ADD OldStyleLogin TINYINT NOT NULL; UPDATE PortalUser SET OldStyleLogin = 1 WHERE (Login <> '') AND (Login NOT REGEXP '^[A-Z0-9_\\-\\.]+$'); DELETE FROM Events WHERE Event = 'USER.PSWD'; UPDATE Phrase SET l<%PRIMARY_LANGUAGE%>_Translation = 'Your password has been reset.' WHERE PhraseKey = 'LU_TEXT_FORGOTPASSHASBEENRESET' AND l<%PRIMARY_LANGUAGE%>_Translation = 'Your password has been reset. The new password has been sent to your e-mail address. You may now login with the new password.'; ALTER TABLE PortalUser DROP MinPwResetDelay, DROP PassResetTime, CHANGE PwResetConfirm PwResetConfirm VARCHAR(255) NOT NULL; UPDATE PortalUser SET PwRequestTime = NULL WHERE PwRequestTime = 0; ALTER TABLE Category ADD DirectLinkEnabled TINYINT NOT NULL DEFAULT '1', ADD DirectLinkAuthKey VARCHAR(20) NOT NULL; UPDATE Category SET DirectLinkAuthKey = SUBSTRING( MD5( CONCAT(CategoryId, ':', ParentId, ':', l<%PRIMARY_LANGUAGE%>_Name, ':b38') ), 1, 20) WHERE DirectLinkAuthKey = ''; INSERT INTO ConfigurationValues VALUES(DEFAULT, 'ExcludeTemplateSectionsFromSearch', '0', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_ExcludeTemplateSectionsFromSearch', 'checkbox', '', '', 10.15, 0, 0, NULL); ALTER TABLE Agents ADD SiteDomainLimitation VARCHAR(255) NOT NULL, ADD INDEX (SiteDomainLimitation); UPDATE ConfigurationValues SET DisplayOrder = DisplayOrder + 0.01 WHERE VariableName = 'HTTPAuthBypassIPs'; UPDATE ConfigurationValues SET DisplayOrder = DisplayOrder + 0.01 WHERE ModuleOwner = 'In-Portal' AND `Section` = 'in-portal:configure_advanced' AND Heading = 'la_section_SettingsAdmin' AND DisplayOrder > 40.06; INSERT INTO ConfigurationValues VALUES (DEFAULT, 'StickyGridSelection', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_StickyGridSelection', 'radio', '', '1=la_Yes||0=la_No', 40.07, 0, 0, NULL); ALTER TABLE Forms ADD SubmitNotifyEmail VARCHAR(255) NOT NULL DEFAULT '' AFTER UseSecurityImage; ALTER TABLE FormFields ADD UploadExtensions VARCHAR(255) NOT NULL DEFAULT '' AFTER Validation, ADD UploadMaxSize INT NULL AFTER UploadExtensions; ALTER TABLE Language ADD SynchronizationModes VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE PortalUser CHANGE ip IPAddress VARCHAR(15) NOT NULL, ADD IPRestrictions TEXT NULL; ALTER TABLE PortalGroup ADD IPRestrictions TEXT NULL; INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ROOT.RESET.PASSWORD', NULL, 1, 0, 'Core', 'Root Reset Password', 1, 1, 0); ALTER TABLE Skins ADD DisplaySiteNameInHeader TINYINT(1) NOT NULL DEFAULT '1'; DELETE FROM PersistantSessionData WHERE VariableName LIKE 'formsubs_Sort%' AND VariableValue = 'FormFieldId'; ALTER TABLE ItemReview ADD HelpfulCount INT NOT NULL , ADD NotHelpfulCount INT NOT NULL; ALTER TABLE PermissionConfig ADD IsSystem TINYINT(1) NOT NULL DEFAULT '0'; UPDATE PermissionConfig SET IsSystem = 1; INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:permission_types.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:permission_types.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:permission_types.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:permission_types.delete', 11, 1, 1, 0); ALTER TABLE Agents ADD Timeout INT(10) UNSIGNED NULL AFTER RunTime, ADD LastTimeoutOn int(10) unsigned default NULL AFTER Timeout, ADD INDEX (Timeout); CREATE TABLE CurlLog ( LogId int(11) NOT NULL AUTO_INCREMENT, Message varchar(255) NOT NULL, PageUrl varchar(255) NOT NULL, RequestUrl varchar(255) NOT NULL, PortalUserId int(11) NOT NULL, SessionKey int(11) NOT NULL, IsAdmin tinyint(4) NOT NULL, PageData text, RequestData text, ResponseData text, RequestDate int(11) DEFAULT NULL, ResponseDate int(11) DEFAULT NULL, ResponseHttpCode int(11) NOT NULL, CurlError varchar(255) NOT NULL, PRIMARY KEY (LogId), KEY Message (Message), KEY PageUrl (PageUrl), KEY RequestUrl (RequestUrl), KEY PortalUserId (PortalUserId), KEY SessionKey (SessionKey), KEY IsAdmin (IsAdmin), KEY RequestDate (RequestDate), KEY ResponseDate (ResponseDate), KEY ResponseHttpCode (ResponseHttpCode), KEY CurlError (CurlError) ); DELETE FROM ConfigurationValues WHERE VariableName = 'Site_Path'; UPDATE ConfigurationValues SET DisplayOrder = DisplayOrder + 0.01 WHERE `Section` = 'in-portal:configure_advanced' AND Heading = 'la_section_SettingsWebsite'; UPDATE ItemTypes SET TitleField = 'Username' WHERE SourceTable = 'PortalUser' AND TitleField = 'Login'; UPDATE SearchConfig SET FieldName = 'Username' WHERE TableName = 'PortalUser' AND FieldName = 'Login'; ALTER TABLE PortalUser DROP INDEX Login; ALTER TABLE PortalUser CHANGE Login Username VARCHAR(255) NOT NULL; ALTER TABLE PortalUser ADD INDEX Username (Username); UPDATE Events SET l<%PRIMARY_LANGUAGE%>_Subject = REPLACE(l<%PRIMARY_LANGUAGE%>_Subject, 'name="Login"', 'name="Username"'), l<%PRIMARY_LANGUAGE%>_Body = REPLACE(l<%PRIMARY_LANGUAGE%>_Body, 'name="Login"', 'name="Username"'); DELETE FROM PersistantSessionData WHERE (VariableName LIKE 'u%]columns_.') OR (VariableName LIKE 'u%_sort%'); DELETE FROM Phrase WHERE Phrase = 'LU_FLD_LOGIN'; UPDATE BanRules SET ItemField = 'Username' WHERE ItemField = 'Login'; DELETE FROM Phrase WHERE PhraseKey IN ( 'LU_USERNAME', 'LU_EMAIL', 'LU_PASSWORD', 'LA_TEXT_LOGIN', 'LA_PROMPT_PASSWORD', 'LA_USE_EMAILS_AS_LOGIN', 'LU_USER_AND_EMAIL_ALREADY_EXIST', 'LU_ENTERFORGOTEMAIL' ); UPDATE ConfigurationValues SET VariableName = 'RegistrationUsernameRequired', Prompt = 'la_config_RegistrationUsernameRequired' WHERE VariableName = 'Email_As_Login'; UPDATE ConfigurationValues SET VariableValue = IF(VariableValue = 1, 0, 1) WHERE VariableName = 'RegistrationUsernameRequired'; INSERT INTO ConfigurationValues VALUES (DEFAULT, 'PerformExactSearch', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_PerformExactSearch', 'checkbox', '', '', '10.10', 0, 0, 'la_hint_PerformExactSearch'); UPDATE Phrase SET PhraseType = 1 WHERE PhraseKey IN ( 'LA_USERS_SUBSCRIBER_GROUP', 'LA_PROMPT_DUPREVIEWS', 'LA_PROMPT_DUPREVIEWS', 'LA_PROMPT_DUPRATING', 'LA_PROMPT_OVERWRITEPHRASES', 'LA_TEXT_BACKUP_ACCESS', 'LA_PHRASETYPE_BOTH', 'LA_TOOLTIP_NEWLISTING' ); UPDATE Phrase SET PhraseType = 0 WHERE PhraseKey IN ('LU_TITLE_SHIPPINGINFORMATION', 'LU_COMM_LASTQUATER'); UPDATE Phrase SET Phrase = REPLACE(Phrase, 'lu_', 'la_'), PhraseKey = UPPER(Phrase) WHERE PhraseKey IN ('LU_OPT_AUTODETECT', 'LU_OPT_COOKIES', 'LU_OPT_QUERYSTRING'); UPDATE ConfigurationValues SET ValueList = REPLACE(ValueList, 'lu_', 'la_') WHERE VariableName = 'CookieSessions'; DELETE FROM Phrase WHERE PhraseKey IN ('LU_INVALID_PASSWORD', 'LA_OF', 'LU_TITLE_REVIEWPRODUCT'); UPDATE Phrase SET PhraseType = 2 WHERE PhraseType = 1 AND (PhraseKey LIKE 'lu_field_%' OR PhraseKey = 'LA_TEXT_VALID'); UPDATE Phrase SET Phrase = REPLACE(Phrase, 'la_', 'lc_'), PhraseKey = UPPER(Phrase) WHERE PhraseType = 2; UPDATE Phrase SET Phrase = REPLACE(Phrase, 'lu_', 'lc_'), PhraseKey = UPPER(Phrase) WHERE PhraseType = 2; UPDATE SearchConfig SET DisplayName = REPLACE(DisplayName, 'lu_', 'lc_') WHERE DisplayName IN ( 'lu_field_newitem', 'lu_field_popitem', 'lu_field_hotitem', 'lu_field_resourceid', 'lu_field_createdbyid', 'lu_field_priority', 'lu_field_status', 'lu_field_createdon', 'lu_field_description', 'lu_field_name', 'lu_field_modified', 'lu_field_modifiedbyid', 'lu_field_ParentPath', 'lu_field_ParentId', 'lu_field_MetaKeywords', 'lu_field_MetaDescription', 'lu_field_EditorsPick', 'lu_field_CategoryId', 'lu_field_CachedNavBar', 'lu_field_CachedDescendantCatsQty', 'lu_field_hits', 'lu_field_cachedrating', 'lu_field_cachedvotesqty', 'lu_field_cachedreviewsqty', 'lu_field_orgid' ); CREATE TABLE SpamReports ( ReportId int(11) NOT NULL AUTO_INCREMENT, ItemPrefix varchar(255) NOT NULL, ItemId int(11) NOT NULL, MessageText text, ReportedOn int(11) DEFAULT NULL, ReportedById int(11) DEFAULT NULL, PRIMARY KEY (ReportId), KEY ItemPrefix (ItemPrefix), KEY ItemId (ItemId), KEY ReportedById (ReportedById) ); DELETE FROM Phrase WHERE PhraseKey IN ( 'LA_SECTION_SETTINGSCACHING', 'LA_CONFIG_CACHEHANDLER', 'LA_CONFIG_MEMCACHESERVERS', 'LA_HINT_MEMCACHESERVERS' ); DELETE FROM ConfigurationValues WHERE VariableName IN ('CacheHandler', 'MemcacheServers'); CREATE TABLE PromoBlocks ( BlockId int(11) NOT NULL AUTO_INCREMENT, Title varchar(50) NOT NULL DEFAULT '', Priority int(11) NOT NULL DEFAULT '0', Status tinyint(1) NOT NULL DEFAULT '0', l1_Image varchar(255) NOT NULL DEFAULT '', l2_Image varchar(255) NOT NULL DEFAULT '', l3_Image varchar(255) NOT NULL DEFAULT '', l4_Image varchar(255) NOT NULL DEFAULT '', l5_Image varchar(255) NOT NULL DEFAULT '', CSSClassName varchar(255) NOT NULL DEFAULT '', LinkType tinyint(1) NOT NULL DEFAULT '1', CategoryId int(11) NOT NULL DEFAULT '0', ExternalLink varchar(255) NOT NULL DEFAULT '', OpenInNewWindow tinyint(3) unsigned NOT NULL DEFAULT '0', ScheduleFromDate int(11) DEFAULT NULL, ScheduleToDate int(11) DEFAULT NULL, NumberOfClicks int(11) NOT NULL DEFAULT '0', NumberOfViews int(11) NOT NULL DEFAULT '0', Sticky tinyint(1) NOT NULL DEFAULT '0', Html text, l1_Html text, l2_Html text, l3_Html text, l4_Html text, l5_Html text, PRIMARY KEY (BlockId), KEY OpenInNewWindow (OpenInNewWindow) ); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'PromoRotationDelay', '7', 'In-Portal', 'in-portal:configure_promo_blocks', 'la_Text_PromoSettings', 'la_config_PromoRotationDelay', 'text', '', '', 10.01, 0, 0, NULL); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'PromoTransitionTime', '0.6', 'In-Portal', 'in-portal:configure_promo_blocks', 'la_Text_PromoSettings', 'la_config_PromoTransitionTime', 'text', '', '', 10.02, 0, 0, NULL); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'PromoTransitionControls', '1', 'In-Portal', 'in-portal:configure_promo_blocks', 'la_Text_PromoSettings', 'la_config_PromoTransitionControls', 'select', '', '1=la_Enabled||0=la_Disabled', 10.03, 0, 0, NULL); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'PromoTransitionEffect', 'fade', 'In-Portal', 'in-portal:configure_promo_blocks', 'la_Text_PromoSettings', 'la_config_PromoTransitionEffect', 'select', '', 'fade=la_opt_AnimationFade||slide=la_opt_AnimationSlide', 10.04, 0, 0, NULL); UPDATE Phrase SET l<%PRIMARY_LANGUAGE%>_ColumnTranslation = l<%PRIMARY_LANGUAGE%>_Translation WHERE PhraseKey IN ('LA_FLD_CATEGORY', 'LA_FLD_ORDER'); CREATE TABLE PageRevisions ( RevisionId int(11) NOT NULL AUTO_INCREMENT, PageId int(11) NOT NULL, RevisionNumber int(11) NOT NULL, IsDraft tinyint(4) NOT NULL, FromRevisionId int(11) NOT NULL, CreatedById int(11) DEFAULT NULL, CreatedOn int(11) DEFAULT NULL, AutoSavedOn int(11) DEFAULT NULL, `Status` tinyint(4) NOT NULL DEFAULT '2', PRIMARY KEY (RevisionId), KEY PageId (PageId), KEY RevisionNumber (RevisionNumber), KEY IsDraft (IsDraft), KEY `Status` (`Status`) ); ALTER TABLE Category ADD LiveRevisionNumber INT NOT NULL DEFAULT '1' AFTER PageExpiration, ADD INDEX (LiveRevisionNumber); ALTER TABLE PageContent ADD RevisionId INT NOT NULL AFTER PageId, ADD INDEX (RevisionId); ALTER TABLE PermissionConfig CHANGE PermissionName PermissionName VARCHAR(255) NOT NULL DEFAULT ''; INSERT INTO PermissionConfig VALUES (DEFAULT, 'CATEGORY.REVISION.ADD', 'la_PermName_Category.Revision.Add_desc', 'In-Portal', 1); INSERT INTO PermissionConfig VALUES (DEFAULT, 'CATEGORY.REVISION.ADD.PENDING', 'la_PermName_Category.Revision.Add.Pending_desc', 'In-Portal', 1); INSERT INTO PermissionConfig VALUES (DEFAULT, 'CATEGORY.REVISION.MODERATE', 'la_PermName_Category.Revision.Moderate_desc', 'In-Portal', 1); INSERT INTO PermissionConfig VALUES (DEFAULT, 'CATEGORY.REVISION.HISTORY.VIEW', 'la_PermName_Category.Revision.History.View_desc', 'In-Portal', 1); INSERT INTO PermissionConfig VALUES (DEFAULT, 'CATEGORY.REVISION.HISTORY.RESTORE', 'la_PermName_Category.Revision.History.Restore_desc', 'In-Portal', 1); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.REVISION.ADD', 11, 1, 0, 1); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.REVISION.HISTORY.VIEW', 11, 1, 0, 1); INSERT INTO Permissions VALUES(DEFAULT, 'CATEGORY.REVISION.HISTORY.RESTORE', 11, 1, 0, 1); ALTER TABLE EmailQueue ADD `LogData` TEXT; UPDATE Permissions SET Permission = REPLACE(Permission, 'agents', 'scheduled_tasks') WHERE Permission LIKE 'in-portal:agents%'; DELETE FROM Phrase WHERE PhraseKey IN ( 'LA_TITLE_ADDINGAGENT', 'LA_TITLE_EDITINGAGENT', 'LA_TITLE_NEWAGENT', 'LA_TITLE_AGENTS', 'LA_TOOLTIP_NEWAGENT' ); UPDATE Phrase SET l<%PRIMARY_LANGUAGE%>_Translation = REPLACE(l<%PRIMARY_LANGUAGE%>_Translation, 'Agents', 'Scheduled Tasks') WHERE PhraseKey IN ( 'LA_USECRONFORREGULAREVENT', 'LA_HINT_SYSTEMTOOLSRESETPARSEDCACHEDDATA', 'LA_HINT_SYSTEMTOOLSRESETCONFIGSANDPARSEDDATA' ); DELETE FROM PersistantSessionData WHERE VariableName LIKE 'agent%'; RENAME TABLE <%TABLE_PREFIX%>Agents TO <%TABLE_PREFIX%>ScheduledTasks; ALTER TABLE ScheduledTasks CHANGE AgentId ScheduledTaskId INT(11) NOT NULL AUTO_INCREMENT, CHANGE AgentName Name VARCHAR(255) NOT NULL DEFAULT '', CHANGE AgentType `Type` TINYINT(3) UNSIGNED NOT NULL DEFAULT '1'; ALTER TABLE ScheduledTasks DROP INDEX AgentType, ADD INDEX `Type` (`Type`); UPDATE ConfigurationValues SET VariableName = 'RunScheduledTasksFromCron' WHERE VariableName = 'UseCronForRegularEvent'; CREATE TABLE ItemFilters ( FilterId int(11) NOT NULL AUTO_INCREMENT, ItemPrefix varchar(255) NOT NULL, FilterField varchar(255) NOT NULL, FilterType varchar(100) NOT NULL, Enabled tinyint(4) NOT NULL DEFAULT '1', RangeCount int(11) DEFAULT NULL, PRIMARY KEY (FilterId), KEY ItemPrefix (ItemPrefix), KEY Enabled (Enabled) ); UPDATE ConfigurationValues SET HintLabel = CONCAT('hint:', Prompt) WHERE VariableName IN ('ForceModRewriteUrlEnding', 'PerformExactSearch'); DELETE FROM Phrase WHERE PhraseKey IN ( 'LA_TEXT_PROMOSETTINGS', 'LA_CONFIG_PROMOROTATIONDELAY', 'LA_CONFIG_PROMOTRANSITIONTIME', 'LA_CONFIG_PROMOTRANSITIONCONTROLS', 'LA_CONFIG_PROMOTRANSITIONEFFECT' ); DELETE FROM ConfigurationValues WHERE VariableName IN ('PromoRotationDelay', 'PromoTransitionTime', 'PromoTransitionControls', 'PromoTransitionEffect'); DELETE FROM Permissions WHERE Permission LIKE 'in-portal:promo_blocks.%'; CREATE TABLE PromoBlockGroups ( PromoBlockGroupId int(11) NOT NULL AUTO_INCREMENT, Title varchar(255) NOT NULL DEFAULT '', CreatedOn int(10) unsigned DEFAULT NULL, `Status` tinyint(1) NOT NULL DEFAULT '1', RotationDelay decimal(9,2) DEFAULT NULL, TransitionTime decimal(9,2) DEFAULT NULL, TransitionControls tinyint(1) NOT NULL DEFAULT '1', TransitionEffect varchar(255) NOT NULL DEFAULT '', TransitionEffectCustom varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (PromoBlockGroupId) ); ALTER TABLE Category ADD PromoBlockGroupId int(10) unsigned NOT NULL DEFAULT '0', ADD INDEX (PromoBlockGroupId); ALTER TABLE PromoBlocks ADD PromoBlockGroupId int(10) unsigned NOT NULL DEFAULT '0', ADD INDEX (PromoBlockGroupId); INSERT INTO ConfigurationValues VALUES(DEFAULT, 'DebugOnlyPromoBlockGroupConfigurator', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_DebugOnlyPromoBlockGroupConfigurator', 'checkbox', '', '', 40.13, 0, 0, NULL); UPDATE ConfigurationValues SET DisplayOrder = DisplayOrder + 0.01 WHERE VariableName IN ('RememberLastAdminTemplate', 'UseHTTPAuth', 'HTTPAuthUsername', 'HTTPAuthPassword', 'HTTPAuthBypassIPs'); INSERT INTO PromoBlockGroups VALUES (DEFAULT, 'Default Group', UNIX_TIMESTAMP(), '1', '7.00', '0.60', '1', 'fade', ''); UPDATE PromoBlocks SET PromoBlockGroupId = 1; INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:promo_block_groups.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:promo_block_groups.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:promo_block_groups.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:promo_block_groups.delete', 11, 1, 1, 0); INSERT INTO ConfigurationValues VALUES(DEFAULT, 'MaintenanceMessageFront', 'Website is currently undergoing the upgrades. Please come back shortly!', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMaintenance', 'la_config_MaintenanceMessageFront', 'textarea', '', 'style="width: 100%; height: 100px;"', '15.01', 0, 0, 'hint:la_config_MaintenanceMessageFront'); INSERT INTO ConfigurationValues VALUES(DEFAULT, 'MaintenanceMessageAdmin', 'Website is currently undergoing the upgrades. Please come back shortly!', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMaintenance', 'la_config_MaintenanceMessageAdmin', 'textarea', '', 'style="width: 100%; height: 100px;"', '15.02', 0, 0, 'hint:la_config_MaintenanceMessageAdmin'); INSERT INTO ConfigurationValues VALUES(DEFAULT, 'SoftMaintenanceTemplate', 'maintenance', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMaintenance', 'la_config_SoftMaintenanceTemplate', 'text', '', 'style="width: 200px;"', '15.03', 0, 0, 'hint:la_config_SoftMaintenanceTemplate'); INSERT INTO ConfigurationValues VALUES(DEFAULT, 'HardMaintenanceTemplate', 'maintenance', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMaintenance', 'la_config_HardMaintenanceTemplate', 'text', '', 'style="width: 200px;"', '15.04', 0, 0, 'hint:la_config_HardMaintenanceTemplate'); UPDATE ConfigurationValues SET VariableName = 'DefaultEmailSender' WHERE VariableName = 'Smtp_AdminMailFrom'; INSERT INTO ConfigurationValues VALUES(DEFAULT, 'DefaultEmailRecipients', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_config_DefaultEmailRecipients', 'text', NULL, NULL, 50.10, 0, 0, NULL); ALTER TABLE SiteDomains ADD DefaultEmailRecipients TEXT NULL AFTER AdminEmail; UPDATE ConfigurationValues SET Section = 'in-portal:configure_advanced', Heading = 'la_section_Settings3rdPartyAPI', DisplayOrder = 80.01 WHERE VariableName = 'YahooApplicationId'; UPDATE ConfigurationValues SET DisplayOrder = DisplayOrder - 0.01 WHERE VariableName IN ('Search_MinKeyword_Length', 'ExcludeTemplateSectionsFromSearch'); UPDATE Phrase SET l<%PRIMARY_LANGUAGE%>_ColumnTranslation = l<%PRIMARY_LANGUAGE%>_Translation WHERE PhraseKey IN ('LA_FLD_ADDRESSLINE1', 'LA_FLD_ADDRESSLINE2', 'LA_FLD_CITY', 'LA_FLD_COMPANY', 'LA_FLD_FAX', 'LA_FLD_STATE', 'LA_FLD_ZIP'); DELETE FROM Phrase WHERE PhraseKey IN ('LA_TEXT_RESTRICTIONS', 'LA_USERS_REVIEW_DENY', 'LA_USERS_VOTES_DENY'); DELETE FROM ConfigurationValues WHERE VariableName IN ('User_Review_Deny', 'User_Votes_Deny'); ALTER TABLE PortalUser ADD FrontLanguage INT(11) NULL AFTER PwRequestTime; ALTER TABLE PortalUser DROP INDEX AdminLanguage; UPDATE PortalUser SET FrontLanguage = 1 WHERE UserType = 0; ALTER TABLE PortalUser ADD PrevEmails TEXT NULL AFTER Email, ADD EmailVerified TINYINT NOT NULL AFTER `Status`; UPDATE PortalUser SET EmailVerified = 1; INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.EMAIL.CHANGE.VERIFY', NULL, 1, 0, 'Core', 'Changed E-mail Verification', 0, 1, 1); INSERT INTO Events (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.EMAIL.CHANGE.UNDO', NULL, 1, 0, 'Core', 'Changed E-mail Rollback', 0, 1, 1); ALTER TABLE Category ADD RequireSSL TINYINT NOT NULL DEFAULT '0', ADD RequireLogin TINYINT NOT NULL DEFAULT '0'; INSERT INTO ConfigurationValues VALUES(DEFAULT, 'UpdateCountersOnFilterChange', '1', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_UpdateCountersOnFilterChange', 'checkbox', '', '', 10.15, 0, 0, NULL); # use new table name (see /core/install.php:390)! ALTER TABLE UserSessions DROP `tz`; ALTER TABLE UserSessions ADD `TimeZone` VARCHAR(255) NOT NULL AFTER `GroupList`; ALTER TABLE PortalUser DROP `tz`; ALTER TABLE PortalUser ADD `TimeZone` VARCHAR(255) NOT NULL AFTER `dob`; UPDATE SearchConfig SET FieldName = 'TimeZone' WHERE FieldName = 'tz' AND TableName = 'PortalUser'; RENAME TABLE <%TABLE_PREFIX%>BanRules TO <%TABLE_PREFIX%>UserBanRules; RENAME TABLE <%TABLE_PREFIX%>Cache TO <%TABLE_PREFIX%>SystemCache; RENAME TABLE <%TABLE_PREFIX%>ConfigurationValues TO <%TABLE_PREFIX%>SystemSettings; RENAME TABLE <%TABLE_PREFIX%>Category TO <%TABLE_PREFIX%>Categories; UPDATE ItemTypes SET SourceTable = 'Categories' WHERE ItemType = 1; UPDATE ItemTypes SET SourceTable = 'Users' WHERE ItemType = 6; UPDATE SearchConfig SET TableName = 'Categories' WHERE TableName = 'Category'; UPDATE SearchConfig SET TableName = 'CustomFields' WHERE TableName = 'CustomField'; UPDATE SearchConfig SET TableName = 'Users' WHERE TableName = 'PortalUser'; UPDATE StatItem SET ValueSQL = REPLACE(ValueSQL, '<%prefix%>Category', '<%prefix%>Categories'); UPDATE StatItem SET ValueSQL = REPLACE(ValueSQL, '<%prefix%>ItemReview', '<%prefix%>CatalogReviews'); UPDATE StatItem SET ValueSQL = REPLACE(ValueSQL, '<%prefix%>Language', '<%prefix%>Languages'); UPDATE StatItem SET ValueSQL = REPLACE(ValueSQL, '<%prefix%>PortalGroup', '<%prefix%>UserGroups'); UPDATE StatItem SET ValueSQL = REPLACE(ValueSQL, '<%prefix%>PortalUser', '<%prefix%>Users'); UPDATE StatItem SET ValueSQL = REPLACE(ValueSQL, '<%prefix%>Theme', '<%prefix%>Themes'); UPDATE StatItem SET ValueSQL = REPLACE(ValueSQL, '<%prefix%>UserSession', '<%prefix%>UserSessions'); UPDATE SystemSettings SET ValueList = REPLACE(ValueList, 'CustomField', 'CustomFields'); UPDATE SystemSettings SET ValueList = REPLACE(ValueList, 'PortalGroup', 'UserGroups'); UPDATE Counters SET CountQuery = 'SELECT COUNT(*) FROM <%PREFIX%>Users WHERE Status = 1', TablesAffected = '|Users|' WHERE `Name` = 'members_count'; UPDATE Counters SET CountQuery = REPLACE(CountQuery, '<%PREFIX%>UserSession', '<%PREFIX%>UserSessions'), TablesAffected = REPLACE(TablesAffected, '|UserSession|', '|UserSessions|'); RENAME TABLE <%TABLE_PREFIX%>CustomField TO <%TABLE_PREFIX%>CustomFields; RENAME TABLE <%TABLE_PREFIX%>Drafts TO <%TABLE_PREFIX%>FormSubmissionReplyDrafts; RENAME TABLE <%TABLE_PREFIX%>Events TO <%TABLE_PREFIX%>EmailEvents; DELETE FROM PersistantSessionData WHERE VariableName LIKE '%custom_filter%'; RENAME TABLE <%TABLE_PREFIX%>Favorites TO <%TABLE_PREFIX%>UserFavorites; RENAME TABLE <%TABLE_PREFIX%>Images TO <%TABLE_PREFIX%>CatalogImages; RENAME TABLE <%TABLE_PREFIX%>ItemFiles TO <%TABLE_PREFIX%>CatalogFiles; RENAME TABLE <%TABLE_PREFIX%>ItemRating TO <%TABLE_PREFIX%>CatalogRatings; RENAME TABLE <%TABLE_PREFIX%>ItemReview TO <%TABLE_PREFIX%>CatalogReviews; RENAME TABLE <%TABLE_PREFIX%>Language TO <%TABLE_PREFIX%>Languages; RENAME TABLE <%TABLE_PREFIX%>PermCache TO <%TABLE_PREFIX%>CategoryPermissionsCache; RENAME TABLE <%TABLE_PREFIX%>PermissionConfig TO <%TABLE_PREFIX%>CategoryPermissionsConfig; RENAME TABLE <%TABLE_PREFIX%>Phrase TO <%TABLE_PREFIX%>LanguageLabels; RENAME TABLE <%TABLE_PREFIX%>PortalGroup TO <%TABLE_PREFIX%>UserGroups; RENAME TABLE <%TABLE_PREFIX%>PersistantSessionData TO <%TABLE_PREFIX%>UserPersistentSessionData; RENAME TABLE <%TABLE_PREFIX%>PortalUser TO <%TABLE_PREFIX%>Users; RENAME TABLE <%TABLE_PREFIX%>PortalUserCustomData TO <%TABLE_PREFIX%>UserCustomData; RENAME TABLE <%TABLE_PREFIX%>RelatedSearches TO <%TABLE_PREFIX%>CategoryRelatedSearches; RENAME TABLE <%TABLE_PREFIX%>Relationship TO <%TABLE_PREFIX%>CatalogRelationships; RENAME TABLE <%TABLE_PREFIX%>SearchLog TO <%TABLE_PREFIX%>SearchLogs; RENAME TABLE <%TABLE_PREFIX%>Skins TO <%TABLE_PREFIX%>AdminSkins; RENAME TABLE <%TABLE_PREFIX%>SubmissionLog TO <%TABLE_PREFIX%>FormSubmissionReplies; RENAME TABLE <%TABLE_PREFIX%>Theme TO <%TABLE_PREFIX%>Themes; RENAME TABLE <%TABLE_PREFIX%>UserGroup TO <%TABLE_PREFIX%>UserGroupRelations; RENAME TABLE <%TABLE_PREFIX%>Visits TO <%TABLE_PREFIX%>UserVisits; RENAME TABLE <%TABLE_PREFIX%>SessionLogs TO <%TABLE_PREFIX%>UserSessionLogs; DELETE FROM LanguageLabels WHERE PhraseKey = 'LA_FLD_RUNMODE'; ALTER TABLE ScheduledTasks DROP RunMode; INSERT INTO SystemSettings VALUES(DEFAULT, 'CKFinderLicenseName', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_Settings3rdPartyAPI', 'la_config_CKFinderLicenseName', 'text', NULL, NULL, 80.03, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'CKFinderLicenseKey', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_Settings3rdPartyAPI', 'la_config_CKFinderLicenseKey', 'text', NULL, NULL, 80.04, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'EnablePageContentRevisionControl', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_EnablePageContentRevisionControl', 'checkbox', '', '', 40.19, 0, 0, NULL); # ===== v 5.2.0-B2 ===== ALTER TABLE Users CHANGE Username Username varchar(255) NOT NULL DEFAULT '', CHANGE IPAddress IPAddress varchar(15) NOT NULL DEFAULT '', CHANGE PwResetConfirm PwResetConfirm varchar(255) NOT NULL DEFAULT ''; ALTER TABLE UserSessions CHANGE TimeZone TimeZone varchar(255) NOT NULL DEFAULT ''; ALTER TABLE CountryStates CHANGE l1_Name l1_Name varchar(255) NOT NULL DEFAULT '', CHANGE l2_Name l2_Name varchar(255) NOT NULL DEFAULT '', CHANGE l3_Name l3_Name varchar(255) NOT NULL DEFAULT '', CHANGE l4_Name l4_Name varchar(255) NOT NULL DEFAULT '', CHANGE l5_Name l5_Name varchar(255) NOT NULL DEFAULT ''; ALTER TABLE Categories CHANGE DirectLinkAuthKey DirectLinkAuthKey varchar(20) NOT NULL DEFAULT ''; ALTER TABLE ScheduledTasks CHANGE SiteDomainLimitation SiteDomainLimitation varchar(255) NOT NULL DEFAULT ''; ALTER TABLE ItemFilters CHANGE ItemPrefix ItemPrefix varchar(255) NOT NULL DEFAULT '', CHANGE FilterField FilterField varchar(255) NOT NULL DEFAULT '', CHANGE FilterType FilterType varchar(100) NOT NULL DEFAULT ''; ALTER TABLE SpamReports CHANGE ItemPrefix ItemPrefix varchar(255) NOT NULL DEFAULT ''; ALTER TABLE CachedUrls CHANGE ParsedVars ParsedVars text; ALTER TABLE CurlLog CHANGE Message Message varchar(255) NOT NULL DEFAULT '', CHANGE PageUrl PageUrl varchar(255) NOT NULL DEFAULT '', CHANGE RequestUrl RequestUrl varchar(255) NOT NULL DEFAULT '', CHANGE CurlError CurlError varchar(255) NOT NULL DEFAULT ''; UPDATE SystemSettings SET DisplayOrder = DisplayOrder + 0.01 WHERE ModuleOwner = 'In-Portal' AND Section = 'in-portal:configure_advanced' AND Heading = 'la_section_SettingsAdmin' AND DisplayOrder > 40.11; INSERT INTO SystemSettings VALUES(DEFAULT, 'DefaultGridPerPage', '20', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsAdmin', 'la_config_DefaultGridPerPage', 'select', '', '10=+10||20=+20||50=+50||100=+100||500=+500', 40.12, 0, 0, NULL); ALTER TABLE EmailEvents ADD LastChanged INT UNSIGNED NULL; ALTER TABLE PromoBlocks DROP Html, CHANGE Status Status TINYINT(1) NOT NULL DEFAULT '1', CHANGE CategoryId CategoryId INT(11) NULL; # ===== v 5.2.0-B3 ===== ALTER TABLE Languages ADD HtmlEmailTemplate TEXT NULL, ADD TextEmailTemplate TEXT NULL; ALTER TABLE EmailLog CHANGE fromuser `From` VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE EmailLog CHANGE addressto `To` VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE EmailLog CHANGE subject `Subject` VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE EmailLog CHANGE `timestamp` SentOn INT(11) NULL; ALTER TABLE EmailLog CHANGE `event` EventName VARCHAR(255) NOT NULL DEFAULT ''; ALTER TABLE EmailLog ADD OtherRecipients TEXT NULL AFTER `To`; ALTER TABLE EmailLog ADD HtmlBody LONGTEXT NULL AFTER `Subject`, ADD TextBody LONGTEXT NULL AFTER HtmlBody; ALTER TABLE EmailLog ADD AccessKey VARCHAR(32) NOT NULL DEFAULT ''; INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:emaillog.edit', 11, 1, 1, 0); DELETE FROM LanguageLabels WHERE PhraseKey = 'LA_PROMPT_FROMUSERNAME'; INSERT INTO SystemSettings VALUES(DEFAULT, 'EmailLogRotationInterval', '-1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_config_EmailLogRotationInterval', 'select', NULL, '=la_opt_EmailLogKeepNever||86400=la_opt_OneDay||604800=la_opt_OneWeek||1209600=la_opt_TwoWeeks||2419200=la_opt_OneMonth||7257600=la_opt_ThreeMonths||29030400=la_opt_OneYear||-1=la_opt_EmailLogKeepForever', 50.11, 0, 0, 'hint:la_config_EmailLogRotationInterval'); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spam_reports.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spam_reports.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:spam_reports.delete', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:item_filters.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:item_filters.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:item_filters.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:item_filters.delete', 11, 1, 1, 0); ALTER TABLE SlowSqlCapture CHANGE QueryCrc QueryCrc BIGINT(11) NOT NULL DEFAULT '0'; UPDATE SlowSqlCapture SET QueryCrc = CAST((QueryCrc & 0xFFFFFFFF) AS UNSIGNED INTEGER) WHERE QueryCrc < 0; ALTER TABLE ImportCache CHANGE VarName VarName BIGINT(11) NOT NULL DEFAULT '0'; UPDATE ImportCache SET VarName = CAST((VarName & 0xFFFFFFFF) AS UNSIGNED INTEGER) WHERE VarName < 0; ALTER TABLE PageContent CHANGE ContentNum ContentNum BIGINT(11) NOT NULL DEFAULT '0'; UPDATE PageContent SET ContentNum = CAST((ContentNum & 0xFFFFFFFF) AS UNSIGNED INTEGER) WHERE ContentNum < 0; ALTER TABLE CachedUrls CHANGE Hash Hash BIGINT(11) NOT NULL DEFAULT '0'; UPDATE CachedUrls SET Hash = CAST((Hash & 0xFFFFFFFF) AS UNSIGNED INTEGER) WHERE Hash < 0; ALTER TABLE EmailEvents ADD BindToSystemEvent VARCHAR(255) NOT NULL DEFAULT ''; CREATE TABLE SystemEventSubscriptions ( SubscriptionId int(11) NOT NULL AUTO_INCREMENT, EmailEventId int(11) DEFAULT NULL, SubscriberEmail varchar(255) NOT NULL DEFAULT '', UserId int(11) DEFAULT NULL, CategoryId int(11) DEFAULT NULL, IncludeSublevels tinyint(4) NOT NULL DEFAULT '1', ItemId int(11) DEFAULT NULL, ParentItemId int(11) DEFAULT NULL, SubscribedOn int(11) DEFAULT NULL, PRIMARY KEY (SubscriptionId), KEY EmailEventId (EmailEventId) ); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_event_subscriptions.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_event_subscriptions.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_event_subscriptions.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:system_event_subscriptions.delete', 11, 1, 1, 0); UPDATE LanguageLabels SET l1_ColumnTranslation = l1_Translation, l2_ColumnTranslation = l2_Translation, l3_ColumnTranslation = l3_Translation, l4_ColumnTranslation = l4_Translation, l5_ColumnTranslation = l5_Translation WHERE PhraseKey IN ('LA_FLD_BINDTOSYSTEMEVENT', 'LA_FLD_CATEGORYID'); UPDATE Categories SET l1_MenuTitle = l1_Name WHERE l1_Name = 'Content'; UPDATE SystemSettings SET ValueList = '0=la_opt_QueryString||1=la_opt_Cookies||2=la_opt_AutoDetect' WHERE VariableName = 'CookieSessions'; # ===== v 5.2.0-RC1 ===== UPDATE LanguageLabels SET l<%PRIMARY_LANGUAGE%>_Translation = '<TITLE> Tag' WHERE PhraseKey = 'LA_FLD_PAGECONTENTTITLE'; ALTER TABLE EmailLog ADD EventType TINYINT(4) NULL AFTER EventName; DELETE FROM UserPersistentSessionData WHERE VariableName IN ('email-log[Default]columns_.', 'promo-block[Default]columns_.'); ALTER TABLE Categories ADD NamedParentPathHash INT UNSIGNED NOT NULL DEFAULT '0' AFTER NamedParentPath, ADD CachedTemplateHash INT UNSIGNED NOT NULL DEFAULT '0' AFTER CachedTemplate, ADD INDEX (NamedParentPathHash), ADD INDEX (CachedTemplateHash); # ===== v 5.2.0 ===== INSERT INTO SystemSettings VALUES(DEFAULT, 'CategoryPermissionRebuildMode', '3', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_CategoryPermissionRebuildMode', 'select', NULL, '1=la_opt_Manual||2=la_opt_Silent||3=la_opt_Automatic', 10.11, 0, 0, 'hint:la_config_CategoryPermissionRebuildMode'); DELETE FROM LanguageLabels WHERE PhraseKey = 'LA_CONFIG_QUICKCATEGORYPERMISSIONREBUILD'; ALTER TABLE ScheduledTasks ADD RunSchedule VARCHAR(255) NOT NULL DEFAULT '* * * * *' AFTER Event; DELETE FROM UserPersistentSessionData WHERE VariableName = 'scheduled-task[Default]columns_.'; DELETE FROM LanguageLabels WHERE PhraseKey = 'LA_FLD_RUNINTERVAL'; ALTER TABLE Languages ADD ShortDateFormat VARCHAR(255) NOT NULL DEFAULT 'm/d' AFTER DateFormat, ADD ShortTimeFormat VARCHAR(255) NOT NULL DEFAULT 'g:i A' AFTER TimeFormat; UPDATE Languages SET ShortDateFormat = REPLACE(REPLACE(DateFormat, '/Y', ''), '/y', ''), ShortTimeFormat = REPLACE(TimeFormat, ':s', ''); UPDATE SystemSettings SET GroupDisplayOrder = 1 WHERE VariableName = 'AdminConsoleInterface'; UPDATE SystemSettings SET Section = 'in-portal:configure_general', Prompt = 'la_config_AdminConsoleInterface', DisplayOrder = 50.01, GroupDisplayOrder = 2 WHERE VariableName = 'AllowAdminConsoleInterfaceChange'; DELETE FROM LanguageLabels WHERE PhraseKey = 'LA_CONFIG_ALLOWADMINCONSOLEINTERFACECHANGE'; UPDATE SystemSettings SET DisplayOrder = DisplayOrder - 0.01 WHERE ModuleOwner = 'In-Portal' AND Section = 'in-portal:configure_advanced' AND DisplayOrder > 40.02 AND DisplayOrder < 50; UPDATE SystemSettings SET VariableValue = 1 WHERE VariableName = 'UseOutputCompression'; ALTER TABLE EmailQueue CHANGE LogData LogData LONGTEXT NULL DEFAULT NULL; DELETE FROM UserPersistentSessionData WHERE VariableName = 'mailing-list[Default]columns_.'; INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:configure_general.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:configure_advanced.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:configure_categories.add', 11, 1, 1, 0); INSERT INTO Permissions VALUES(DEFAULT, 'in-portal:configure_users.add', 11, 1, 1, 0); # ===== v 5.2.1-B1 ===== UPDATE SystemSettings SET DisplayOrder = 30.05 WHERE VariableName = 'Force_HTTP_When_SSL_Not_Required'; INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.NEW.PASSWORD', NULL, 1, 0, 'Core', 'Sends new password to an existing user', 0, 1, 0); INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.ADD.BYADMIN', NULL, 1, 0, 'Core', 'Sends password to a new user', 0, 1, 0); CREATE TABLE SystemLog ( LogId int(11) NOT NULL AUTO_INCREMENT, LogUniqueId int(11) DEFAULT NULL, LogLevel tinyint(4) NOT NULL DEFAULT '7', LogType tinyint(4) NOT NULL DEFAULT '3', LogCode int(11) DEFAULT NULL, LogMessage longtext, LogTimestamp int(11) DEFAULT NULL, LogDate datetime DEFAULT NULL, LogEventName varchar(100) NOT NULL DEFAULT '', LogHostname varchar(255) NOT NULL DEFAULT '', LogRequestSource tinyint(4) DEFAULT NULL, LogRequestURI varchar(255) NOT NULL DEFAULT '', LogRequestData longtext, LogUserId int(11) DEFAULT NULL, LogInterface tinyint(4) DEFAULT NULL, IpAddress varchar(15) NOT NULL DEFAULT '', LogSessionKey int(11) DEFAULT NULL, LogSessionData longtext, LogBacktrace longtext, LogSourceFilename varchar(255) NOT NULL DEFAULT '', LogSourceFileLine int(11) DEFAULT NULL, LogProcessId bigint(20) unsigned DEFAULT NULL, LogMemoryUsed bigint(20) unsigned NOT NULL, LogUserData longtext NOT NULL, LogNotificationStatus tinyint(4) NOT NULL DEFAULT '0', PRIMARY KEY (LogId), KEY LogLevel (LogLevel), KEY LogType (LogType), KEY LogNotificationStatus (LogNotificationStatus) ); INSERT INTO SystemSettings VALUES(DEFAULT, 'EnableEmailLog', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_EnableEmailLog', 'radio', NULL, '1=la_Yes||0=la_No', 65.01, 0, 1, 'hint:la_config_EnableEmailLog'); UPDATE SystemSettings SET DisplayOrder = 65.02, Heading = 'la_section_SettingsLogs', ValueList = '86400=la_opt_OneDay||604800=la_opt_OneWeek||1209600=la_opt_TwoWeeks||2419200=la_opt_OneMonth||7257600=la_opt_ThreeMonths||29030400=la_opt_OneYear||-1=la_opt_EmailLogKeepForever' WHERE VariableName = 'EmailLogRotationInterval'; UPDATE LanguageLabels SET l<%PRIMARY_LANGUAGE%>_Translation = 'Keep "E-mail Log" for', l<%PRIMARY_LANGUAGE%>_HintTranslation = 'This setting allows you to control for how long "E-mail Log" messages will be stored in the log and then automatically deleted. Use option "Forever" with caution since it will completely disable automatic log cleanup and can lead to large size of database table that stores e-mail messages.' WHERE PhraseKey = 'LA_CONFIG_EMAILLOGROTATIONINTERVAL' AND l<%PRIMARY_LANGUAGE%>_Translation = 'Keep Email Log for'; DELETE FROM LanguageLabels WHERE PhraseKey = 'LA_OPT_EMAILLOGKEEPNEVER'; INSERT INTO SystemSettings VALUES(DEFAULT, 'SystemLogRotationInterval', '2419200', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_SystemLogRotationInterval', 'select', NULL, '86400=la_opt_OneDay||604800=la_opt_OneWeek||1209600=la_opt_TwoWeeks||2419200=la_opt_OneMonth||7257600=la_opt_ThreeMonths||29030400=la_opt_OneYear||-1=la_opt_SystemLogKeepForever', 65.03, 0, 1, 'hint:la_config_SystemLogRotationInterval'); INSERT INTO SystemSettings VALUES(DEFAULT, 'SystemLogNotificationEmail', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_SystemLogNotificationEmail', 'text', 'a:5:{s:4:"type";s:6:"string";s:9:"formatter";s:10:"kFormatter";s:6:"regexp";s:85:"/^([-a-zA-Z0-9!\\#$%&*+\\/=?^_`{|}~.]+@[a-zA-Z0-9]{1}[-.a-zA-Z0-9_]*\\.[a-zA-Z]{2,6})$/i";s:10:"error_msgs";a:1:{s:14:"invalid_format";s:18:"!la_invalid_email!";}s:7:"default";s:0:"";}', NULL, 65.04, 0, 1, 'hint:la_config_SystemLogNotificationEmail'); INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'SYSTEM.LOG.NOTIFY', NULL, 1, 0, 'Core', 'Notification about message added to System Log', 1, 1, 1); ALTER TABLE Users ADD PasswordHashingMethod TINYINT NOT NULL DEFAULT '3' AFTER Password; UPDATE Users SET PasswordHashingMethod = 1; INSERT INTO SystemSettings VALUES(DEFAULT, 'TypeKitId', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_Settings3rdPartyAPI', 'la_config_TypeKitId', 'text', NULL, NULL, 80.05, 0, 1, NULL); ALTER TABLE MailingLists CHANGE EmailsQueued EmailsQueuedTotal INT(10) UNSIGNED NOT NULL DEFAULT '0'; RENAME TABLE <%TABLE_PREFIX%>EmailEvents TO <%TABLE_PREFIX%>EmailTemplates; ALTER TABLE EmailTemplates CHANGE `Event` TemplateName VARCHAR(40) NOT NULL DEFAULT ''; ALTER TABLE EmailTemplates CHANGE EventId TemplateId INT(11) NOT NULL AUTO_INCREMENT; ALTER TABLE SystemEventSubscriptions CHANGE EmailEventId EmailTemplateId INT(11) NULL DEFAULT NULL; DELETE FROM LanguageLabels WHERE PhraseKey IN ( 'LA_FLD_EXPORTEMAILEVENTS', 'LA_FLD_EVENT', 'LA_TITLE_EMAILMESSAGES', 'LA_TAB_E-MAILS', 'LA_COL_EMAILEVENTS', 'LA_OPT_EMAILEVENTS', 'LA_FLD_EMAILEVENT', 'LA_TITLE_EMAILEVENTS', 'LA_TITLE_ADDING_E-MAIL', 'LA_TITLE_EDITING_E-MAIL', 'LA_TITLE_EDITINGEMAILEVENT', 'LA_TITLE_NEWEMAILEVENT', 'LA_TAB_EMAILEVENTS' ); DELETE FROM UserPersistentSessionData WHERE VariableName IN ('system-event-subscription[Default]columns_.', 'email-log[Default]columns_.'); ALTER TABLE EmailLog CHANGE EventName TemplateName VARCHAR(255) NOT NULL DEFAULT ''; # ===== v 5.2.1-B2 ===== DELETE FROM LanguageLabels WHERE PhraseKey = 'LA_TAB_REPORTS'; ALTER TABLE Modules ADD ClassNamespace VARCHAR(255) NOT NULL DEFAULT '' AFTER Path; UPDATE Modules SET ClassNamespace = 'Intechnic\\InPortal\\Core' WHERE `Name` IN ('Core', 'In-Portal'); UPDATE SystemSettings SET DisplayOrder = DisplayOrder + 0.01 WHERE ModuleOwner = 'In-Portal' AND Section = 'in-portal:configure_categories' AND DisplayOrder > 10.10 AND DisplayOrder < 20; INSERT INTO SystemSettings VALUES(DEFAULT, 'CheckViewPermissionsInCatalog', '1', 'In-Portal', 'in-portal:configure_categories', 'la_title_General', 'la_config_CheckViewPermissionsInCatalog', 'radio', NULL, '1=la_Yes||0=la_No', 10.11, 0, 1, 'hint:la_config_CheckViewPermissionsInCatalog'); # ===== v 5.2.1-RC1 ===== UPDATE LanguageLabels SET l1_Translation = REPLACE(l1_Translation, '
', '\n') WHERE PhraseKey = 'LA_EDITINGINPROGRESS'; UPDATE LanguageLabels SET l1_ColumnTranslation = 'Helpful' WHERE PhraseKey = 'LA_FLD_HELPFULCOUNT'; UPDATE LanguageLabels SET l1_ColumnTranslation = 'Not Helpful' WHERE PhraseKey = 'LA_FLD_NOTHELPFULCOUNT'; UPDATE LanguageLabels SET Module = 'Core' WHERE PhraseKey = 'LA_SECTION_FILE'; # ===== v 5.2.1 ===== # ===== v 5.2.2-B1 ===== UPDATE LanguageLabels SET l1_Translation = 'Incorrect data format, please use {type}' WHERE PhraseKey = 'LA_ERR_BAD_TYPE'; UPDATE LanguageLabels SET l1_Translation = 'Field value is out of range, possible values from {min_value} to {max_value}' WHERE PhraseKey = 'LA_ERR_VALUE_OUT_OF_RANGE'; UPDATE LanguageLabels SET l1_Translation = 'Field value length is out of range, possible value length from {min_length} to {max_length}' WHERE PhraseKey = 'LA_ERR_LENGTH_OUT_OF_RANGE'; ALTER TABLE Themes ADD StylesheetFile VARCHAR( 255 ) NOT NULL DEFAULT ''; UPDATE Themes SET StylesheetFile = 'platform/inc/styles.css' WHERE `Name` = 'advanced'; UPDATE EmailTemplates SET l1_Subject = REPLACE(l1_Subject, "Field name='Username'", 'UserTitle'), l1_HtmlBody = REPLACE(l1_HtmlBody, "Field name='Username'", 'UserTitle') WHERE TemplateName LIKE 'USER%'; UPDATE EmailTemplates SET l1_Subject = REPLACE(l1_Subject, 'Field name="Username"', 'UserTitle'), l1_HtmlBody = REPLACE(l1_HtmlBody, 'Field name="Username"', 'UserTitle') WHERE TemplateName LIKE 'USER%'; UPDATE SystemSettings SET VariableValue = 1 WHERE VariableName = 'CSVExportEncoding'; ALTER TABLE Semaphores ADD MainIDs INT NULL DEFAULT NULL AFTER MainPrefix; # ===== v 5.2.2-B2 ===== UPDATE Modules SET ClassNamespace = 'InPortal\\Core' WHERE `Name` IN ('Core', 'In-Portal'); +DELETE FROM CachedUrls; + +UPDATE LanguageLabels +SET l1_Translation = 'Incorrect date format, please use ({format}) ex. ({sample})' +WHERE PhraseKey = 'LA_ERR_BAD_DATE_FORMAT'; + +UPDATE LanguageLabels +SET l1_HintTranslation = REPLACE(l1_HintTranslation, '
  • This deploy script will reset all caches at once
  • ', '
  • This deploy script will reset all caches at once.
  • \r\n
  • This deploy script will dump production assets.
  • \r\n') +WHERE PhraseKey = 'LA_TITLE_SYSTEMTOOLSDEPLOY'; + +INSERT INTO SystemSettings VALUES(DEFAULT, 'EmailDelivery', '2', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_config_EmailDelivery', 'radio', NULL, '1=la_opt_EmailDeliveryQueue||2=la_opt_EmailDeliveryImmediate', 50.11, 0, 1, NULL); + # ===== v 5.3.0-B1 ===== ALTER TABLE ScheduledTasks ADD Settings TEXT NULL; ALTER TABLE Themes ADD ImageResizeRules TEXT NULL; DELETE FROM UserPersistentSessionData WHERE VariableName = 'emailevents[Emails]columns_.'; INSERT INTO SystemCache (VarName, Data) SELECT 'tmp_translation' AS VarName, l<%PRIMARY_LANGUAGE%>_Translation AS Data FROM <%TABLE_PREFIX%>LanguageLabels WHERE PhraseKey = 'LC_IMPORTLANG_PHRASEWARNING'; UPDATE LanguageLabels SET Phrase = 'la_fld_ImportOverwrite', PhraseKey = 'LA_FLD_IMPORTOVERWRITE', l<%PRIMARY_LANGUAGE%>_HintTranslation = (SELECT Data FROM <%TABLE_PREFIX%>SystemCache WHERE VarName = 'tmp_translation' LIMIT 1) WHERE PhraseKey = 'LA_PROMPT_OVERWRITEPHRASES'; DELETE FROM LanguageLabels WHERE PhraseKey = 'LC_IMPORTLANG_PHRASEWARNING'; DELETE FROM LanguageLabels WHERE PhraseKey = 'LA_CONFIG_USETEMPLATECOMPRESSION'; DELETE FROM SystemSettings WHERE VariableName = 'UseTemplateCompression'; UPDATE SystemSettings SET DisplayOrder = ROUND(DisplayOrder - 0.01, 2) WHERE (DisplayOrder BETWEEN 60.04 AND 60.10) AND (ModuleOwner = 'In-Portal') AND (Section = 'in-portal:configure_advanced'); INSERT INTO SystemSettings VALUES(DEFAULT, 'RandomString', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_RandomString', 'text', '', '', 60.09, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'PlainTextCookies', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_PlainTextCookies', 'text', '', '', 60.10, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'ForceCanonicalUrls', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsWebsite', 'la_config_ForceCanonicalUrls', 'checkbox', '', '', 10.0125, 0, 0, NULL); UPDATE LanguageLabels SET l1_HintTranslation = '
      \r\n
    • This deploy script will apply all Database Changes stored in [module]/project_upgrades.sql to the current website and save applied Revisions in AppliedDBRevisions.
    • \r\n
    • This deploy script will create all new language phrases by re-importing [module]/install/english.lang file.
    • \r\n
    • This deploy script will reset all caches at once.
    • \r\n
    ' WHERE Phrase = 'la_title_SystemToolsDeploy'; -INSERT INTO SystemSettings VALUES(DEFAULT, 'EmailDelivery', '2', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_config_EmailDelivery', 'radio', NULL, '1=la_opt_EmailDeliveryQueue||2=la_opt_EmailDeliveryImmediate', 50.11, 0, 1, NULL); +# Backported in http://jira.in-portal.org/browse/INP-1723. +# INSERT INTO SystemSettings VALUES(DEFAULT, 'EmailDelivery', '2', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsMailling', 'la_config_EmailDelivery', 'radio', NULL, '1=la_opt_EmailDeliveryQueue||2=la_opt_EmailDeliveryImmediate', 50.11, 0, 1, NULL); DELETE FROM UserPersistentSessionData WHERE VariableName = 'email-queue[Default]columns_.'; ALTER TABLE EmailLog ADD ToUserId INT(11) DEFAULT NULL, ADD ItemPrefix VARCHAR(50) NOT NULL DEFAULT '', ADD ItemId INT(11) DEFAULT NULL; DELETE FROM UserPersistentSessionData WHERE VariableName = 'email-log[Default]columns_.'; ALTER TABLE EmailLog ADD Status TINYINT NOT NULL DEFAULT '1' AFTER TextBody, ADD ErrorMessage VARCHAR(255) NOT NULL DEFAULT '' AFTER Status; ALTER TABLE ScheduledTasks ADD Module varchar(30) NOT NULL DEFAULT 'Core'; CREATE TABLE ModuleDeploymentLog ( Id int(11) NOT NULL AUTO_INCREMENT, Module varchar(30) NOT NULL DEFAULT 'In-Portal', RevisionNumber int(11) NOT NULL DEFAULT '0', RevisionTitle varchar(255) NOT NULL DEFAULT '', CreatedOn int(10) unsigned DEFAULT NULL, IPAddress varchar(15) NOT NULL DEFAULT '', Output text, ErrorMessage varchar(255) NOT NULL DEFAULT '', Mode tinyint(1) NOT NULL DEFAULT '1', Status tinyint(1) NOT NULL DEFAULT '1', PRIMARY KEY (Id), KEY CreatedOn (CreatedOn), KEY Mode (Mode), KEY Status (Status) ); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:module_deployment_log.view', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:module_deployment_log.edit', 11, 1, 1, 0); INSERT INTO Permissions VALUES (DEFAULT, 'in-portal:module_deployment_log.delete', 11, 1, 1, 0); UPDATE EmailTemplates SET l<%PRIMARY_LANGUAGE%>_Subject = REPLACE(l<%PRIMARY_LANGUAGE%>_Subject, '', ''), l<%PRIMARY_LANGUAGE%>_PlainTextBody = REPLACE(l<%PRIMARY_LANGUAGE%>_PlainTextBody, '', ''), l<%PRIMARY_LANGUAGE%>_HtmlBody = REPLACE(l<%PRIMARY_LANGUAGE%>_HtmlBody, '', '') WHERE TemplateName IN ('USER.SUBSCRIBE', 'USER.UNSUBSCRIBE'); ALTER TABLE CategoryItems ADD Id int(11) NOT NULL auto_increment FIRST, ADD PRIMARY KEY (Id); ALTER TABLE UserGroupRelations DROP PRIMARY KEY; ALTER TABLE UserGroupRelations ADD Id int(11) NOT NULL auto_increment FIRST, ADD PRIMARY KEY (Id), ADD UNIQUE KEY UserGroup (PortalUserId, GroupId); DELETE FROM UserPersistentSessionData WHERE VariableName IN ('u-ug[Default]columns_.', 'g-ug[Default]columns_.'); ALTER TABLE SpamControl ADD Id int(11) NOT NULL auto_increment FIRST, ADD PRIMARY KEY (Id); INSERT INTO SystemSettings VALUES(DEFAULT, 'SSLDomain', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSSL', 'la_config_SSLDomain', 'text', '', '', 30.01, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'AdminSSLDomain', '', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSSL', 'la_config_AdminSSLDomain', 'text', '', '', 30.02, 0, 0, NULL); DELETE FROM LanguageLabels WHERE PhraseKey IN ('LA_CONFIG_SSL_URL', 'LA_CONFIG_ADMINSSL_URL', 'LA_FLD_SSLURL'); ALTER TABLE SiteDomains CHANGE SSLUrl SSLDomainName VARCHAR(255) NOT NULL DEFAULT '', CHANGE SSLUrlUsesRegExp SSLDomainNameUsesRegExp TINYINT(4) NOT NULL DEFAULT '0'; DELETE FROM UserPersistentSessionData WHERE VariableName = 'site-domain[Default]columns_.'; # Backported in http://jira.in-portal.org/browse/INP-1690. # UPDATE Modules # SET ClassNamespace = 'InPortal\\Core' # WHERE `Name` IN ('Core', 'In-Portal'); UPDATE EmailTemplates SET l1_Subject = REPLACE(l1_Subject, ' JGJvZHkNCjxici8+PGJyLz4NCg0KU2luY2VyZWx5LDxici8+PGJyLz4NCg0KV2Vic2l0ZSBhZG1pbmlzdHJhdGlvbi4NCg0KPCEtLSMjIDxpbnAyOmVtYWlsLWxvZ19JdGVtTGluayB0ZW1wbGF0ZT0icGxhdGZvcm0vbXlfYWNjb3VudC9lbWFpbCIvPiAjIy0tPg== QWN0aXZl QWRk QWRkIFRv QWRtaW5pc3RyYXRpdmUgQ29uc29sZQ== YWxsb3cgY2hhbmdpbmc= QWxsb3cgZGVsZXRpbmcgTW9kdWxlIFJvb3QgU2VjdGlvbg== VmlldyBpbiBCcm93c2UgTW9kZQ== R28gSW5zaWRl QWx3YXlz YW5k QXV0bw== QXV0b21hdGlj QXZhaWxhYmxlIENvbHVtbnM= QXZhaWxhYmxlIEl0ZW1z QmFja2dyb3VuZA== Qm9yZGVycw== QWRk RWRpdCBJdGVt QnJvd3NlIE1vZGU= Q2FuY2Vs Q2hhbmdl Q2xlYXI= Q29udGVudCBNb2Rl RGVsZXRl RGVsZXRl ZGVsZXRlIHJldmlldw== RGVwbG95 RGVzaWduIE1vZGU= RG93bg== + RHVtcA== RWRpdA== RWRpdCBCbG9jaw== RWRpdCBDb250ZW50 RWRpdCBEZXNpZ24= R2VuZXJhdGU= R2VuZXJhdGUgUGFnZQ== R2V0IFZhbHVl TG9jYXRl TW92ZSBEb3du TW92ZSBVcA== UHVibGlzaGluZyBUb29scw== UmVidWlsZA== UmVjb21waWxl UmVmcmVzaA== UmVzZXQ= UmVzZXQgJmFtcDsgVmFsaWRhdGUgQ29uZmlnIEZpbGVz UmVzZXQgInJvb3QiIHBhc3N3b3Jk U2F2ZQ== U2F2ZSBDaGFuZ2Vz U2VjdGlvbiBQcm9wZXJ0aWVz U2VjdGlvbiBUZW1wbGF0ZQ== U2VsZWN0IEFsbA== U2V0IFZhbHVl U2hvdyBTdHJ1Y3R1cmU= U3luY2hyb25pemU= VW5zZWxlY3Q= VXA= VXNl Ynk= Q2FuY2Vs U2VjdGlvbg== TnVtYmVyIG9mIGRheXMgZm9yIGEgY2F0LiB0byBiZSBORVc= RGVmYXVsdCBNRVRBIGRlc2NyaXB0aW9u RGVmYXVsdCBNRVRBIEtleXdvcmRz TnVtYmVyIG9mIHNlY3Rpb25zIHBlciBwYWdl U2VjdGlvbnMgUGVyIFBhZ2UgKFNob3J0bGlzdCk= RGlzcGxheSBlZGl0b3IgUElDS3MgYWJvdmUgcmVndWxhciBzZWN0aW9ucw== QW5kIHRoZW4gYnk= T3JkZXIgc2VjdGlvbnMgYnk= Q2xvc2U= QWNjZXNz QWRkaXRpb25hbA== QWZmZWN0ZWQgSXRlbXM= QWx0IFZhbHVl QnVpbGQgRGF0ZQ== U2VjdGlvbiBOYW1l Q29sdW1uIFBocmFzZQ== RWZmZWN0aXZl RS1tYWlsIFRlbXBsYXRlcw== RW5hYmxlIEUtbWFpbCBDb21tdW5pY2F0aW9u Jm5ic3A7 RXZlbnQgRGVzY3JpcHRpb24= RXZlbnQgUGFyYW1z SGludCBQaHJhc2U= U3RhdHVz SW1hZ2U= VVJM SW5oZXJpdGVk SW5oZXJpdGVkIEZyb20= SW4gTWVudQ== SVAgQWRkcmVzcw== UG9wdWxhcg== VXNlciBQcmltYXJ5 S2V5d29yZA== TGFiZWw= TGFuZ3VhZ2UgUGFjayBJbnN0YWxsZWQ= TGFzdCBDaGFuZ2Vk TGFzdCBDb21waWxlZA== TGFzdCBBdHRlbXB0 TGluayBVUkw= TWFpbGluZyBMaXN0 TWVtYmVyc2hpcCBFeHBpcmVz TWVzc2FnZSBIZWFkZXJz SFRNTA== T3JpZ2luYWwgVmFsdWU= UGF0aA== QWRk RGVsZXRl RWRpdA== UGVybWlzc2lvbiBOYW1l QWNjZXNz Vmlldw== UGhyYXNlcw== VXNlciBJRA== UHJldmlldw== UHJpbWFyeSBHcm91cA== UHJpbWFyeSBWYWx1ZQ== RmllbGQgUHJvbXB0 UXVldWVk UmVmZXJlcg== UmVzZXQgdG8gZGVmYXVsdA== Q29tbWVudHM= Q3JlYXRlZCBieQ== U2NoZWR1bGUgRnJvbSBEYXRl U2NoZWR1bGUgVG8gRGF0ZQ== QXR0ZW1wdHMg U2Vzc2lvbiBFbmQ= U2Vzc2lvbiBTdGFydA== U29ydCBieQ== VHlwZQ== U3lzdGVtIFBhdGg= SXRlbSBUeXBl VXNlcnM= TGFzdG5hbWUgRmlyc3RuYW1l RmllbGQgVmFsdWU= VmlzaWJsZQ== VmlzaXQgRGF0ZQ== QXNjZW5kaW5n RGVzY2VuZGluZw== QWRtaW4gQ29uc29sZSBJbnRlcmZhY2U= U1NMIERvbWFpbiBmb3IgQWRtaW5pc3RyYXRpdmUgQ29uc29sZSAod3d3LmRvbWFpbi5jb20p QWxsb3cgdG8gc2VsZWN0IG1lbWJlcnNoaXAgZ3JvdXAgb24gRnJvbnQtZW5k TGlzdCBhdXRvbWF0aWMgcmVmcmVzaCBpbnRlcnZhbHMgKGluIG1pbnV0ZXMp QmFja3VwIFBhdGg= U3dpdGNoIENhdGFsb2cgdGFicyBiYXNlZCBvbiBNb2R1bGU= U2VjdGlvbiBQZXJtaXNzaW9uIFJlYnVpbGQgTW9kZQ== Q2hlY2sgU3RvcCBXb3Jkcw== RW5hYmxlICJWaWV3IFBlcm1pc3Npb25zIiBDaGVjayBpbiBDYXRhbG9n Q0tGaW5kZXIgTGljZW5zZSBLZXk= Q0tGaW5kZXIgTGljZW5zZSBOYW1l RGVmYXVsdCBDU1YgRXhwb3J0IERlbGltaXRlcg== RGVmYXVsdCBDU1YgRXhwb3J0IEVuY2xvc3VyZSBDaGFyYWN0ZXI= RGVmYXVsdCBDU1YgRXhwb3J0IEVuY29kaW5n RGVmYXVsdCBDU1YgRXhwb3J0IE5ldyBMaW5lIFNlcGFyYXRvcg== U2hvdyAiRm9ybXMgRWRpdG9yIiBpbiBERUJVRyBtb2RlIG9ubHk= U2hvdyAiUHJvbW8gQmxvY2sgR3JvdXBzIEVkaXRvciIgaW4gREVCVUcgbW9kZSBvbmx5 RGVmYXVsdCBEZXNpZ24gVGVtcGxhdGU= RGVmYXVsdCBFLW1haWwgUmVjaXBpZW50cw== RGVmYXVsdCAiUGVyIFBhZ2UiIHNldHRpbmcgaW4gR3JpZHM= RGVmYXVsdCBSZWdpc3RyYXRpb24gQ291bnRyeQ== RGVmYXVsdCBBbmFseXRpY3MgVHJhY2tpbmcgQ29kZQ== RW1haWwgRGVsaXZlcnk= S2VlcCAiRS1tYWlsIExvZyIgZm9y RW5hYmxlICJFLW1haWwgTG9nIg== RW5hYmxlIFJldmlzaW9uIENvbnRyb2wgZm9yIFNlY3Rpb24gQ29udGVudA== VGVtcGxhdGUgZm9yICJGaWxlIG5vdCBmb3VuZCAoNDA0KSIgRXJyb3I= RXhjbHVkZSB0ZW1wbGF0ZSBiYXNlZCBTZWN0aW9ucyBmcm9tIFNlYXJjaCBSZXN1bHRzIChpZS4gVXNlciBSZWdpc3RyYXRpb24p RmlsZW5hbWUgU3BlY2lhbCBDaGFyIFJlcGxhY2VtZW50 Rmlyc3QgRGF5IE9mIFdlZWs= Rm9yY2UgQ2Fub25pY2FsIFVSTHM= QWx3YXlzIHVzZSBJbWFnZU1hZ2ljayB0byByZXNpemUgaW1hZ2Vz Rm9yY2UgUmVkaXJlY3QgdG8gU2VsZWN0ZWQgVVJMIEVuZGluZw== UmVkaXJlY3QgdG8gSFRUUCB3aGVuIFNTTCBpcyBub3QgcmVxdWlyZWQ= RnVsbCBpbWFnZSBIZWlnaHQ= RnVsbCBpbWFnZSBXaWR0aA== VGVtcGxhdGUgZm9yIEhhcmQgTWFpbnRlbmFuY2U= QnlwYXNzIEhUVFAgQXV0aGVudGljYXRpb24gZnJvbSBJUHMgKHNlcGFyYXRlZCBieSBzZW1pY29sb25zKQ== UGFzc3dvcmQgZm9yIEhUVFAgQXV0aGVudGljYXRpb24= VXNlcm5hbWUgZm9yIEhUVFAgQXV0aGVudGljYXRpb24= S2VlcCBTZXNzaW9uIGFsaXZlIG9uIEJyb3dzZXIgY2xvc2U= TWFpbCBGdW5jdGlvbiBIZWFkZXIgU2VwYXJhdG9y TWFpbGluZyBMaXN0IFF1ZXVlIFBlciBTdGVw TWFpbGluZyBMaXN0IFNlbmQgUGVyIFN0ZXA= TWFpbnRlbmFuY2UgTWVzc2FnZSBmb3IgQWRtaW4= TWFpbnRlbmFuY2UgTWVzc2FnZSBmb3IgRnJvbnQgRW5k TWF4aW11bSBudW1iZXIgb2YgaW1hZ2Vz RGVmYXVsdCBVUkwgRW5kaW5nIGluIFNFTy1mcmllbmRseSBtb2Rl VGVtcGxhdGUgZm9yICJJbnN1ZmZpY2llbnQgUGVybWlzc2lvbnMiIEVycm9y R1pJUCBjb21wcmVzc2lvbiBsZXZlbCAwLTk= UGF0aCB0byBXZWJzaXRl UGVyZm9ybSBFeGFjdCBTZWFyY2g= Q29tbWVudHMgcGVyIHBhZ2U= UGxhaW4gVGV4dCBDb29raWVz UmFuZG9tIFN0cmluZw== IlJlY3ljbGUgQmluIiBTZWN0aW9uSWQ= VXNlcm5hbWUgUmVxdWlyZWQgRHVyaW5nIFJlZ2lzdHJhdGlvbg== UmVzdG9yZSBsYXN0IHZpc2l0ZWQgQWRtaW4gU2VjdGlvbiBhZnRlciBMb2dpbg== UmVxdWlyZSBTU0wgZm9yIEFkbWluaXN0cmF0aXZlIENvbnNvbGU= UmVxdWlyZSBTU0wgZm9yIGxvZ2luICYgY2hlY2tvdXQ= RnJhbWVzIGluIGFkbWluaXN0cmF0aXZlIGNvbnNvbGUgYXJlIHJlc2l6YWJsZQ== TWluaW1hbCBTZWFyY2ggS2V5d29yZCBMZW5ndGg= U2Vzc2lvbiBTZWN1cml0eSBDaGVjayBiYXNlZCBvbiBCcm93c2VyIFNpZ25hdHVyZQ== U2Vzc2lvbiBDb29raWUgRG9tYWlucyAoc2luZ2xlIGRvbWFpbiBwZXIgbGluZSk= U2Vzc2lvbiBTZWN1cml0eSBDaGVjayBiYXNlZCBvbiBJUA== S2VlcCAiU2Vzc2lvbiBMb2ciIGZvcg== V2Vic2l0ZSBTdWJ0aXRsZQ== VGltZSB6b25lIG9mIHRoZSBzaXRl VGVtcGxhdGUgZm9yIFNvZnQgTWFpbnRlbmFuY2U= U1NMIERvbWFpbiAod3d3LmRvbWFpbi5jb20p VXNlIFN0aWNreSBHcmlkIFNlbGVjdGlvbg== U2VuZCBVc2VyLWRlZmluZWQgIlN5c3RlbSBMb2ciIG1lc3NhZ2VzIHRv S2VlcCAiU3lzdGVtIExvZyIgZm9y VGh1bWJuYWlsIEhlaWdodA== VGh1bWJuYWlsIFdpZHRo VHJpbSBSZXF1aXJlZCBGaWVsZHM= VHlwZUtpdCBJRA== VXBkYXRlIGNvdW50ZXJzIChpbiBvdGhlciBmaWx0ZXJzKSBvbiBmaWx0ZXIgY2hhbmdl VHJhY2sgZGF0YWJhc2UgY2hhbmdlcyB0byBjaGFuZ2UgbG9n VXNlIENvbHVtbiBGcmVlemVy QXV0by1kZXRlY3QgVXNlcidzIGxhbmd1YWdlIGJhc2VkIG9uIGl0J3MgQnJvd3NlciBzZXR0aW5ncw== VXNlIERvdWJsZSBTb3J0aW5n RW5hYmxlIEhUVFAgQXV0aGVudGljYXRpb24= RW5hYmxlIEhUTUwgR1pJUCBjb21wcmVzc2lvbg== VXNlIFBhZ2VIaXQgY291bnRlcg== RWRpdGluZyBXaW5kb3cgU3R5bGU= RW1haWwgYWN0aXZhdGlvbiBleHBpcmF0aW9uIHRpbWVvdXQgKGluIG1pbnV0ZXMp VXNlIFNtYWxsIFNlY3Rpb24gSGVhZGVycw== VXNlIFRvb2xiYXIgTGFiZWxz VXNlIFZpc2l0b3IgVHJhY2tpbmc= VXNlIEphdmFTY3JpcHQgcmVkaXJlY3Rpb24gYWZ0ZXIgbG9naW4vbG9nb3V0IChmb3IgSUlTKQ== RW5hYmxlIFNFTy1mcmllbmRseSBVUkxzIG1vZGUgKE1PRC1SRVdSSVRFKQ== RW5hYmxlIE1PRF9SRVdSSVRFIGZvciBTU0w= V2Vic2l0ZSBuYW1l WWFob28gQXBwbGljYXRpb25JZA== QXJlIHlvdSBzdXJlIHlvdSB3YW50IHRvIGRlbGV0ZSBzZWxlY3RlZCBFeHBvcnQgUHJlc2V0Pw== VGhlIHNlY3Rpb24gdHJlZSBtdXN0IGJlIHVwZGF0ZWQgdG8gcmVmbGVjdCB0aGUgbGF0ZXN0IGNoYW5nZXM= Q3VycmVudCBUaGVtZQ== RGF0YSBHcmlkcw== RGF0YSBHcmlkcyAy ZGF5cw== QXJlIHlvdSBzdXJlIHlvdSB3YW50IHRvIGRlbGV0ZSB0aGUgaXRlbShzKT8gVGhpcyBhY3Rpb24gY2Fubm90IGJlIHVuZG9uZS4= VGhpcyBzZWN0aW9uIGFsbG93cyB5b3UgdG8gbWFuYWdlIHNlY3Rpb25zIGFuZCBpdGVtcyBhY3Jvc3MgYWxsIHNlY3Rpb25z VGhpcyBzZWN0aW9uIGFsbG93cyB5b3UgdG8gYnJvd3NlIHRoZSBjYXRhbG9nIGFuZCBtYW5hZ2Ugc2VjdGlvbnMgYW5kIGl0ZW1z TWFuYWdlIHRoZSBzdHJ1Y3R1cmUgb2YgeW91ciBzaXRlLCBpbmNsdWRpbmcgc2VjdGlvbnMsIGl0ZW1zIGFuZCBzZWN0aW9uIHNldHRpbmdzLg== RGlzYWJsZWQ= RG91YmxlLVF1b3Rlcw== RG93bmxvYWQgQ1NW RG93bmxvYWQgRXhwb3J0IEZpbGU= RG93bmxvYWQgTGFuZ3VhZ2UgRXhwb3J0 RHJhZnQ= RHJhZnQgQXZhaWxhYmxl ZHJhZnQgc2F2ZWQgYXQgJXM= Q29udGVudCBFZGl0b3I= WW91IGhhdmUgbm90IHNhdmVkIGNoYW5nZXMgdG8gdGhlIGl0ZW0geW91IGFyZSBlZGl0aW5nITxiciAvPkNsaWNrIE9LIHRvIGxvb3NlIGNoYW5nZXMgYW5kIGdvIHRvIHRoZSBzZWxlY3RlZCBzZWN0aW9uPGJyIC8+b3IgQ2FuY2VsIHRvIHN0YXkgaW4gdGhlIGN1cnJlbnQgc2VjdGlvbi4= RGVmYXVsdCB0ZXh0 RmlsZSBpcyBlbXB0eQ== RmlsZSBpcyBlbXB0eQ== RW5hYmxlZA== Q2FuJ3QgZGVsZXRlIHN5c3RlbSBwZXJtaXNzaW9u Q2FuJ3Qgb3BlbiB0aGUgZmlsZQ== Q2FuJ3Qgc2F2ZSBhIGZpbGU= Q29ubmVjdGlvbiBGYWlsZWQ= RXJyb3IgY29weWluZyBzdWJzZWN0aW9ucw== Q3VzdG9tIGZpZWxkIHdpdGggaWRlbnRpY2FsIG5hbWUgYWxyZWFkeSBleGlzdHM= RW1haWwgRGVzaWduIFRlbXBsYXRlIHNob3VsZCBjb250YWluIGF0IGxlYXN0ICIkYm9keSIgdGFnIGluIGl0Lg== RmlsZSBub3QgZm91bmQ= RmlsZSBpcyB0b28gbGFyZ2U= + VGhpcyBVUkwgaXMgY29uZmxpY3Rpbmcgd2l0aCBleGlzdGluZyBVUkwgYW5kIGNhbid0IGJlIHVzZWQ= Z3JvdXAgbm90IGZvdW5k RmllbGQgZG9lc24ndCBleGlzdCBpbiAiJXMiIHVuaXQgY29uZmln SW52YWxpZCBGaWxlIEZvcm1hdA== VW5pdCBjb25maWcgcHJlZml4IG5vdCBmb3VuZA== aW52YWxpZCBvcHRpb24= + VGhlIHVzZXJuYW1lIGNhbiBjb250YWluIG9ubHk6IGxldHRlcnMsIG51bWJlcnMsIHVuZGVyc2NvcmVzLCBkYXNoZXMgYW5kIGRvdHM= TG9naW4gRmFpbGVk UmVjZWl2aW5nIGxpc3Qgb2YgbWVzc2FnZXMgZnJvbSB0aGUgU2VydmVyIGhhcyBmYWlsZWQ= RXJyb3IgbW92aW5nIHN1YnNlY3Rpb24= Q2FuJ3QgaW5oZXJpdCB0ZW1wbGF0ZSBmcm9tIHRvcCBjYXRlZ29yeQ== Tm8gbWF0Y2hpbmcgY29sdW1ucyBhcmUgZm91bmQ= VGhpcyBvcGVyYXRpb24gaXMgbm90IGFsbG93ZWQh VmFsaWRhdGlvbiBlcnJvciwgcGxlYXNlIGRvdWJsZS1jaGVjayBJbi1Qb3J0YWwgdGFncw== UGFzc3dvcmRzIGRvIG5vdCBtYXRjaCE= Q2FuJ3QgRGVsZXRlIE5vbi1FbXB0eSBQcm9tbyBCbG9jayBHcm91cA== UmVxdWlyZWQgZmllbGQoLXMpIG5vdCBmaWxsZWQ= cmVxdWlyZWQgY29sdW1ucyBtaXNzaW5n Um9vdCBzZWN0aW9uIG9mIHRoZSBtb2R1bGUocykgY2FuIG5vdCBiZSBkZWxldGVkIQ== U2VsZWN0IGF0IGxlYXN0IG9uZSBpdGVtIHRvIG1vdmU= VGVtcGxhdGUgZmlsZSBpcyBtaXNzaW5n Q29weWluZyBvcGVyYXRpb24gaW4gVGVtcG9yYXJ5IHRhYmxlcyBoYXMgZmFpbGVkLiBQbGVhc2UgY29udGFjdCB3ZWJzaXRlIGFkbWluaXN0cmF0b3Iu UmVjb3JkIGlzIG5vdCB1bmlxdWU= U2VjdGlvbiBmaWVsZCBub3QgdW5pcXVl VW5rbm93biBzZWN0aW9u VW5rbm93biBzZWN0aW9u VXNlciBCYW5uZWQ= dXNlciBub3QgZm91bmQ= IlNjaGVkdWxlZCBUbyIgZGF0ZS90aW1lIG11c3QgYmUgYmVmb3JlICJTY2hlZHVsZWQgRnJvbSI= WW91IG11c3Qgc2VsZWN0IG9ubHkgb25lIHVzZXI= - SW5jb3JyZWN0IGRhdGUgZm9ybWF0LCBwbGVhc2UgdXNlICglcykgZXguICglcyk= + SW5jb3JyZWN0IGRhdGUgZm9ybWF0LCBwbGVhc2UgdXNlICh7Zm9ybWF0fSkgZXguICh7c2FtcGxlfSk= SW5jb3JyZWN0IGRhdGEgZm9ybWF0LCBwbGVhc2UgdXNlIHt0eXBlfQ== SW52YWxpZCBGb3JtYXQ= RmllbGQgdmFsdWUgbGVuZ3RoIGlzIG91dCBvZiByYW5nZSwgcG9zc2libGUgdmFsdWUgbGVuZ3RoIGZyb20ge21pbl9sZW5ndGh9IHRvIHttYXhfbGVuZ3RofQ== UHJpbWFyeSBMYW5nLiB2YWx1ZSBSZXF1aXJlZA== RmllbGQgaXMgcmVxdWlyZWQ= RmllbGQgdmFsdWUgbXVzdCBiZSB1bmlxdWU= RmllbGQgdmFsdWUgaXMgb3V0IG9mIHJhbmdlLCBwb3NzaWJsZSB2YWx1ZXMgZnJvbSB7bWluX3ZhbHVlfSB0byB7bWF4X3ZhbHVlfQ== RXhwb3J0IGZvbGRlciBpcyBub3Qgd3JpdGFibGU= RXJyb3IgY3JlYXRpbmcgZm9sZGVyLiBFcnJvciBudW1iZXI6 UGxlYXNlIG5hbWUgeW91ciBmaWxlcyB0byBiZSB3ZWItZnJpZW5kbHkuIFdlIHJlY29tbWVuZCB1c2luZyBvbmx5IHRoZXNlIGNoYXJhY3RlcnMgaW4gZmlsZSBuYW1lczogDQpMZXR0ZXJzIGEteiwgQS1aLCBOdW1iZXJzIDAtOSwgIl8iICh1bmRlcnNjb3JlKSwgIi0iIChkYXNoKSwgIiAiIChzcGFjZSksICIuIiAocGVyaW9kKQ0KUGxlYXNlIGF2b2lkIHVzaW5nIGFueSBvdGhlciBjaGFyYWN0ZXJzIGxpa2UgcXVvdGVzLCBicmFja2V0cywgcXVvdGF0aW9uIG1hcmtzLCAiPyIsICIhIiwgIj0iLCBmb3JlaWduIHN5bWJvbHMsIGV0Yy4= RXJyb3Igb24gZmlsZSB1cGxvYWQuIEVycm9yIG51bWJlcjo= QSBmaWxlIHdpdGggdGhlIHNhbWUgbmFtZSBpcyBhbHJlYWR5IGF2YWlsYWJsZQ== RGF0ZQ== RmlsZSBOYW1l U2l6ZQ== Rm9sZGVyIGFscmVhZHkgZXhpc3Rz SW52YWxpZCBmaWxlIHR5cGUgZm9yIHRoaXMgZm9kZXI= SW52YWxpZCBmb2xkZXIgbmFtZQ== WW91IGhhdmUgbm8gcGVybWlzc2lvbnMgdG8gY3JlYXRlIHRoZSBmb2xkZXI= UGxlYXNlIHR5cGUgdGhlIGZvbGRlciBuYW1l VHlwZSB0aGUgbmFtZSBvZiB0aGUgbmV3IGZvbGRlcjo= VW5rbm93biBlcnJvciBjcmVhdGluZyBmb2xkZXI= RmllbGQ= RGlzcGxheSBPcmRlcg== T3JkZXI= QWN0aW9u QWRkcmVzcyBMaW5lIDE= QWRkcmVzcyBMaW5lIDI= TWVzc2FnZXMgZnJvbSBTaXRlIEFkbWluIGFyZSBmcm9t QWRtaW4gUHJpbWFyeQ== TGFuZ3VhZ2U= QWR2YW5jZWQgQ1NT QWR2YW5jZWQgU2VhcmNo QWxsb3cgQ2hhbmdpbmcgIlRvIiBSZWNpcGllbnQ= QWxsb3cgQ2hhbmdpbmcgU2VuZGVy QWx0IFZhbHVl QW5zd2Vy QXNzaWduZWQgdG8gU2VjdGlvbnM= QXR0YWNobWVudA== QXV0byBDcmVhdGUgRmlsZSBOYW1l QXV0b21hdGljIEZpbGVuYW1l QXZhaWxhYmxlIENvbHVtbnM= QmFja2dyb3VuZA== QmFja2dyb3VuZCBBdHRhY2htZW50 QmFja2dyb3VuZCBDb2xvcg== QmFja2dyb3VuZCBJbWFnZQ== QmFja2dyb3VuZCBQb3NpdGlvbg== QmFja2dyb3VuZCBSZXBlYXQ= QmNj QmluZCB0byBTeXN0ZW0gRXZlbnQ= RWxlbWVudCBQb3NpdGlvbg== Qm9yZGVyIEJvdHRvbQ== Qm9yZGVyIExlZnQ= Qm9yZGVyIFJpZ2h0 Qm9yZGVycw== Qm9yZGVyIFRvcA== Qm91bmNlIERhdGU= Qm91bmNlIEVtYWls Qm91bmNlIEluZm8= QnV0dG9uIFRleHQ= U2VjdGlvbg== U2VjdGlvbiBGb3JtYXQ= U2VjdGlvbiBJRA== U2VjdGlvbiBzZXBhcmF0b3I= U2VjdGlvbiBUZW1wbGF0ZQ== Q2M= Q2hhbmdlcw== Q2hhcnNldA== Q2hlY2sgRHVwbGljYXRlcyBieQ== Q2l0eQ== Q29sdW1uIFBocmFzZQ== Q29tbWVudHM= Q29tcGFueQ== Q29uZmlndXJhdGlvbiBIZWFkZXIgTGFiZWw= Q29udGVudCBCbG9jaw== Q1RSLCAl Q29weSBMYWJlbHMgZnJvbSB0aGlzIExhbmd1YWdl Q291bnRyeQ== Q3JlYXRlZCBCeQ== Q3JlYXRlZCBPbg== Q29tbW9uIFNldHRpbmdz RGF5 SG91cg== TWludXRl TW9udGg= V2Vla2RheQ== Q1NTIFRlbXBsYXRl Q1NTIENsYXNzIE5hbWU= Q3Vyc29y Q3VzdG9tIERldGFpbHMgVGVtcGxhdGU= U2VuZCBFbWFpbCBUbw== U2VuZCBFbWFpbCBGcm9t DQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KRGV0YWlscyBUZW1wbGF0ZQ== RGF0ZSBGb3JtYXQ= RGVjaW1hbCBQb2ludA== RGVzY3JpcHRpb24= QWNjZXNzIHdpdGggTGluaw== RGlzcGxheQ== RGlzcGxheSBpbiBHcmlk RmllbGQgTGFiZWw= RGlzcGxheSBzaXRlIG5hbWUgaW4gSGVhZGVy RGlzcGxheSBUbyBQdWJsaWM= UmFuZ2Ugb2YgSVBz RG9tYWluIE5hbWU= QXMgUGxhaW4gVGV4dA== RHVyYXRpb24= RWRpdG9ycyBQaWNr RWxhcHNlZCBUaW1l RS1tYWls RS1tYWlsIENvbW11bmljYXRpb24gUm9sZQ== RS1tYWlsIG9yIFVzZXJuYW1l RS1tYWlsICI8c3Ryb25nPntwYXNzd29yZH08L3N0cm9uZz4iIHBhc3N3b3JkIHRvIHVzZXI= RW1haWxzIGluIFF1ZXVl RW1haWxzIFNlbnQ= RW1haWxzIFRvdGFs RS1tYWlsIFRlbXBsYXRlIE5hbWU= RW1haWwgVmVyaWZpZWQ= RW5hYmxl RW5hYmxlZA== RW5hYmxlIENhY2hpbmcgZm9yIHRoaXMgU2VjdGlvbg== RXJyb3IgTWVzc2FnZQ== RXJyb3IgVGFn RXN0aW1hdGVkIFRpbWU= RXZlbnQ= RXhwaXJl RXhwb3J0IGNvbHVtbnM= RXhwb3J0IFNwZWNpZmllZCBDb3VudHJpZXM= RGF0YSBUeXBlcyB0byBFeHBvcnQ= RXhwb3J0IFNwZWNpZmllZCBFLW1haWwgVGVtcGxhdGVz RXhwb3J0IEZpbGVuYW1l RXhwb3J0IGZvcm1hdA== RXhwb3J0IE1vZHVsZXM= RXhwb3J0IFNwZWNpZmllZCBQaHJhc2Vz RXhwb3J0IFBocmFzZSBUeXBlcw== RXhwb3J0IFByZXNldCBUaXRsZQ== RXhwb3J0IFByZXNldA== U2F2ZS9VcGRhdGUgRXhwb3J0IFByZXNldA== RXh0ZXJuYWwgTGluaw== RXh0ZXJuYWwgVVJM RXh0cmEgSGVhZGVycw== RmF4 TWF0Y2ggVHlwZQ== RmllbGQgTmFtZQ== RmllbGRzIGVuY2xvc2VkIGJ5 RmllbGRzIHNlcGFyYXRlZCBieQ== RmllbGQgVGl0bGVz RmllbGQgVHlwZQ== TWF0Y2ggVmFsdWU= RmlsZSBDb250ZW50cw== RmlsZW5hbWU= RmlsZW5hbWUgUmVwbGFjZW1lbnRz UGF0aA== RmlsdGVyIEZpZWxk RmlsdGVyIFR5cGU= Rmlyc3QgTmFtZQ== Rm9udA== Rm9udCBDb2xvcg== Rm9udCBGYW1pbHk= Rm9udCBTaXpl Rm9udCBTdHlsZQ== Rm9udCBXZWlnaHQ= T25saW5lIEZvcm0= T25saW5lIEZvcm0gU3VibWl0dGVkIFRlbXBsYXRl U2hvcnQgVVJM RnJvbSBFbWFpbA== RnJvbnQtRW5kIE9ubHk= TGFuZ3VhZ2U= QWxsb3cgUmVnaXN0cmF0aW9uIG9uIEZyb250LWVuZA== RnVsbCBOYW1l VXNlciBHcm91cA== R3JvdXAgRGlzcGxheSBPcmRlcg== SUQ= R3JvdXAgTmFtZQ== SGVpZ2h0 UmV2aWV3IFdhcyBIZWxwZnVs SGludCBQaHJhc2U= SGl0cw== SG90 SFRNTCBWZXJzaW9u SFRNTCBWZXJzaW9u SWNvbiBVUkwgKGRpc2FibGVkKQ== SWNvbiBVUkw= SUQ= SW1hZ2U= SW1wb3J0IFNlY3Rpb24= SW1wb3J0IENvbHVtbnM= SW1wb3J0IEZpbGU= SW1wb3J0IEZpbGVuYW1l T3ZlcndyaXRlIEV4aXN0aW5nIFBocmFzZXM= SW1wb3J0IE5ldyBQaHJhc2VzIGFzIFN5bmNlZA== SW5jbHVkZSBmaWVsZCB0aXRsZXM= SW5jbHVkZSBTdWJsZXZlbHM= SW5wdXQgRGF0ZSBGb3JtYXQ= SW5wdXQgVGltZSBGb3JtYXQ= SW5zdGFsbCBNb2R1bGVz SW5zdGFsbCBQaHJhc2UgVHlwZXM= SVAgQWRkcmVzcw== SVAgUmVzdHJpY3Rpb25z VXNlIGN1cnJlbnQgc2VjdGlvbiBhcyByb290IGZvciB0aGUgZXhwb3J0 SVNPIENvZGU= UHJpbWFyeQ== UmVxdWlyZWQ= SXMgU3lzdGVt U3lzdGVtIFRlbXBsYXRl VXNlciBGaWVsZA== SXRlbSBJRA== SXRlbSBOYW1l SXRlbSBQcmVmaXg= SXRlbSBUZW1wbGF0ZQ== TGFuZ3VhZ2U= TGFuZ3VhZ2UgRmlsZQ== TGFuZ3VhZ2UgSUQ= TGFuZ3VhZ2Vz TGFzdCBOYW1l TGFzdCBSdW4gT24= TGFzdCBSdW4gU3RhdHVz TGFzdCBUaW1lb3V0IE9u TGFzdCBVcGRhdGVkIE9u TGVmdA== TGluZSBlbmRpbmdz TGluZSBFbmRpbmdzIEluc2lkZSBGaWVsZHM= TGluayBUeXBl SUQ= TGlzdGluZyBUeXBl TG9jYWxl TG9jYWwgTmFtZQ== TG9jYXRpb24= QmFja3RyYWNl Q29kZQ== RXZlbnQgTmFtZQ== SG9zdG5hbWU= TG9naW4= SW50ZXJmYWNl TG9nIExldmVs TWVtb3J5IFVzZWQ= TWVzc2FnZQ== Tm90aWZpY2F0aW9uIFN0YXR1cw== TG9nbyBpbWFnZQ== Qm90dG9tIExvZ28gSW1hZ2U= TG9nbyBMb2dpbg== UHJvY2VzcyBJRA== UmVxdWVzdCBEYXRh UmVxdWVzdCBTb3VyY2U= UmVxdWVzdCBVUkk= U2Vzc2lvbiBEYXRh U2Vzc2lvbiBLZXk= U291cmNlIEZpbGUgTGluZQ== U291cmNlIEZpbGVuYW1l VGltZXN0YW1w VHlwZQ== VXNlciBEYXRh TWFyZ2luIEJvdHRvbQ== TWFyZ2luIExlZnQ= TWFyZ2luIFJpZ2h0 TWFyZ2lucw== TWFyZ2luIFRvcA== TWFzdGVyIElE TWFzdGVyIFByZWZpeA== TWF4aW11bSBudW1iZXIgb2YgU2VjdGlvbnMgb24gSXRlbSBjYW4gYmUgYWRkZWQgdG8= Q3VzdG9tIE1lbnUgSWNvbiAoaWUuIGltZy9tZW51X3Byb2R1Y3RzLmdpZik= TWVudSBTdGF0dXM= TWVyZ2UgdG8gU3VibWlzc2lvbg== TWVzc2FnZQ== TWVzc2FnZSBCb2R5 UGxhaW4gVGV4dCBWZXJzaW9u TWVzc2FnZSBUeXBl TWV0YSBEZXNjcmlwdGlvbg== TWV0YSBLZXl3b3Jkcw== TWlzc3BlbGxlZCBXb3Jk TW9kZQ== TW9kaWZpZWQ= TW9kdWxl TW9kdWxl TXVsdGlsaW5ndWFs TmFtZQ== TmV3 TmV4dCBSdW4gT24= Tm90ZXM= UmV2aWV3IFdhc24ndCBIZWxwZnVs TnVtYmVyIE9mIENsaWNrcw== TnVtYmVyIE9mIFZpZXdz T2NjdXJlZCBPbg== T3BlbiBJbiBOZXcgV2luZG93 T3B0aW9ucw== T3B0aW9uIFRpdGxl T3JkZXI= T3RoZXIgUmVjaXBpZW50cw== T3V0cHV0 T3ZlcndyaXRlIERlZmF1bHQgQ2FjaGluZyBLZXk= UGFjayBOYW1l UGFkZGluZyBCb3R0b20= UGFkZGluZyBMZWZ0 UGFkZGluZyBSaWdodA== UGFkZGluZ3M= UGFkZGluZyBUb3A= Q3VzdG9tIENhY2hpbmcgS2V5 Jmx0O1RJVExFJmd0OyBUYWc= Q2FjaGUgRXhwaXJhdGlvbiBpbiBzZWNvbmRz VGl0bGUgKE1lbnUgSXRlbSk= U2VjdGlvbiBUaXRsZQ== UGFyZW50IEl0ZW0gSUQ= UGFyZW50IEl0ZW0gTmFtZQ== UGFyZW50IFNlY3Rpb24= UGFzc3dvcmQ= UGVyY2VudHMgQ29tcGxldGVk UGhvbmU= TGFiZWw= UGhyYXNlIFR5cGU= UG9w UG9wdWxhcg== UG9ydA== UG9zaXRpb24= UHJlZml4 UHJpbWFyeQ== UHJpbWFyeSBTZWN0aW9u UHJpbWFyeQ== UHJpbWFyeSBMYW5ndWFnZSBQaHJhc2U= T3JkZXI= Q29udmVydCB1bm1hdGNoZWQgZS1tYWlscyBpbnRvIG5ldyBzdWJtaXNzaW9ucw== UHJvbW8gQmxvY2sgR3JvdXA= UHJvdGVjdGVk UXVhbnRpdHk= UmFuZ2UgQ291bnQ= UmF0aW5n UmVjaXBpZW50 UmVjaXBpZW50J3MgQWRkcmVzcw== UmVjaXBpZW50J3MgQWRkcmVzcyBUeXBl UmVjaXBpZW50J3MgTmFtZQ== UmVjaXBpZW50cw== UmVjaXBpZW50IFR5cGU= UmVjaXBpZW50IFVzZXI= Rm9yY2UgUmVkaXJlY3QgKHdoZW4gdXNlcidzIElQIG1hdGNoZXMp UmVmZXJyZXIgVVJM S2V5d29yZA== VHlwZQ== UmVtb3RlIFVSTA== UmVwbGFjZSBEdXBsaWNhdGVz UmVwbGFjZW1lbnQ= UmVwbGFjZW1lbnQgVGFncw== UmVwbGllZCBPbg== UmVwbHkgQmNj UmVwbHkgQ2M= UmVwbHkgRnJvbSBFLW1haWw= UmVwbHkgRnJvbSBOYW1l UmVwbHkgTWVzc2FnZSBTaWduYXR1cmU= UmVwbGllZA== UmVwb3J0ZWQgQnk= UmVwb3J0ZWQgT24= UmVxdWlyZWQ= UmVxdWlyZSBMb2dpbg== UmVxdWlyZSBTU0w= Q29tbWVudA== UmV2aXNpb24gTnVtYmVy UmV2aXNpb24gVGl0bGU= UHJvbW8gUm90YXRpb24gRGVsYXkgKHNlY29uZHMp UnVsZSBUeXBl UnVuIFNjaGVkdWxl UnVuIFRpbWU= U2FtZSBBcyBUaHVtYg== U2NoZWR1bGUgRnJvbQ== U2NoZWR1bGUgVG8= U2VhcmNoIFRlcm0= U2VuZGVy U2VuZGVyJ3MgQWRkcmVzcw== U2VuZGVyJ3MgTmFtZQ== U2VudCBPbg== U2VudA== U2VydmVy U2Vzc2lvbiBMb2cgSUQ= U2V0dGluZ3M= U2hvcnQgRGF0ZSBGb3JtYXQ= U2hvcnQgSVNPIENvZGU= U2hvcnQgVGltZSBGb3JtYXQ= U2ltcGxlIFNlYXJjaA== U2l0ZSBEb21haW4gTGltaXRhdGlvbg== TmFtZQ== U2tpcCBGaXJzdCBSb3c= U29ydCBWYWx1ZXM= U291cmNlIENvbHVtbiBQaHJhc2UgKGZyb20gJXMp U291cmNlIEhpbnQgUGhyYXNlIChmcm9tICVzKQ== U291cmNlIEhUTUwgVmVyc2lvbiAoZnJvbSAlcyk= U291cmNlIFRleHQgVmVyc2lvbiAoZnJvbSAlcyk= U291cmNlIFN1YmplY3QgKGZyb20gJXMp U291cmNlIFBocmFzZSAoZnJvbSAlcyk= U1NMIERvbWFpbiBOYW1l U3RhcnQgRGF0ZQ== U3RhdGU= U3RhdGUgQ291bnRyeQ== U3RhdHVz U3RpY2t5 U3RvcCBXb3Jk U3R5bGVzaGVldCBGaWxl U3ViamVjdA== U3VibWl0dGVkIE9u U3VibWlzc2lvbiBOb3RpZmljYXRpb24gRW1haWw= U3Vic2NyaWJlZCBPbg== U3VnZ2VzdGVkIENvcnJlY3Rpb24= UG9pbnRzIHRvIFNlY3Rpb24= U3luY2hyb25pemUgTGFuZ3VhZ2U= U3lzdGVtIEV2ZW50 U2V0dGluZyBIaW50IExhYmVs U2V0dGluZyBOYW1l U2VjdGlvbg== VmFsaWRhdGlvbiBMb2dpYw== U2V0dGluZyBWYWx1ZQ== VGFibGUgTmFtZSBpbiBEYXRhYmFzZSA= VGFn SXRlbQ== VGVtcGxhdGUgRmlsZQ== VGVtcGxhdGUgTmFtZQ== VGVtcGxhdGU= VGV4dA== VGV4dCBBbGlnbg== VGV4dCBEZWNvcmF0aW9u VGV4dCBWZXJzaW9u VGV4dCBWZXJzaW9u VGhlbWU= VGhlbWVz VGhlc2F1cnVzIFRlcm0= VGhlc2F1cnVzIFR5cGU= VGhvdXNhbmRzIFNlcGFyYXRvcg== VGltZSBGb3JtYXQ= VGltZW91dA== VGltZSBab25l VGl0bGU= VG8= VG8gRS1tYWls VG9w QW5hbHl0aWNzIFRyYWNraW5nIENvZGU= UHJvbW8gVHJhbnNpdGlvbiBDb250cm9scw== UHJvbW8gVHJhbnNpdGlvbiBFZmZlY3Q= UHJvbW8gVHJhbnNpdGlvbiBFZmZlY3QgKGN1c3RvbSk= VHJhbnNpdGlvbiBEZWxheSAoc2Vjb25kcyk= VHJhbnNsYXRlIEZyb20gTGFuZ2F1Z2U= UGhyYXNl VHJhbnNsYXRpb24gaW4gU3luYw== VHlwZQ== TWVhc3VyZXMgU3lzdGVt VXBsb2FkIEZpbGUgRnJvbSBMb2NhbCBQQw== QWxsb3dlZCBGaWxlIEV4dGVuc2lvbnM= TWF4aW11bSBGaWxlIFNpemU= VVJM TGluayB0byBFeHRlcm5hbCBVUkw= VXNlIEN1c3RvbSBNZW51IEljb24= VXNlciBEb2N1bWVudGF0aW9uIFVSTA== VXNlciBHcm91cHM= VXNlcm5hbWU= VXNlIFNlY3VyaXR5IEltYWdl UmUtZW50ZXIgUGFzc3dvcmQ= VmVyc2lvbg== VmlzaWJpbGl0eQ== Vm90ZXM= V2lkdGg= Wi1JbmRleA== WklQ Rm9udCBQcm9wZXJ0aWVz RG8geW91IHdhbnQgdG8gc2F2ZSB0aGUgY2hhbmdlcz8= QXJlIHlvdSBzdXJlIHlvdSB3b3VsZCBsaWtlIHRvIGRpc2NhcmQgdGhlIGNoYW5nZXM/ RnJvbQ== RnJvbSBEYXRl R2VuZXJhbCBTZWN0aW9ucw== SGVhZCBGcmFtZQ== SGlkZQ== QWxsIEZpbGVz Q2xpY2sgdG8gZWRpdA== Q1NWIEZpbGVz SW1hZ2UgRmlsZXM= UE9QMyBTZXJ2ZXIgUG9ydC4gRm9yIGV4LiAiMTEwIiBmb3IgcmVndWxhciBjb25uZWN0aW9uLCAiOTk1IiBmb3Igc2VjdXJlIGNvbm5lY3Rpb24u UE9QMyBTZXJ2ZXIgQWRkcmVzcy4gRm9yIGV4LiB1c2UgInNzbDovL3BvcC5nbWFpbC5jb20iIGZvciBHbWFpbCwgInBvcC5tYWlsLnlhaG9vLmNvbSIgZm9yIFlhaG9vLg== Q2FjaGUgS2V5KHMp ZGF0YWJhc2UgY2FjaGU= bWVtb3J5IGNhY2hl VXNpbmcgUmVndWxhciBFeHByZXNzaW9u SG90 SFRNTA== SUQgRmllbGQ= SW52YWxpZCBFLU1haWw= SW5jb3JyZWN0IGRhdGEgZm9ybWF0LCBwbGVhc2UgdXNlIGludGVnZXI= TWlzc2luZyBvciBpbnZhbGlkIEluLVBvcnRhbCBMaWNlbnNl SW5jb3JyZWN0IFVzZXJuYW1lIG9yIFBhc3N3b3Jk SW52YWxpZCBzdGF0ZQ== U2VjdGlvbnM= PCAxIHNlYy4= RGlzcGxheSBlZGl0b3IgUElDS3MgYWJvdmUgcmVndWxhciBsaW5rcw== TnVtYmVyIG9mIGRheXMgZm9yIGEgbGluayB0byBiZSBORVc= TnVtYmVyIG9mIGxpbmtzIHBlciBwYWdl TnVtYmVyIG9mIGxpbmtzIHBlciBwYWdlIG9uIGEgc2hvcnQgbGlzdGluZw== QW5kIHRoZW4gYnk= T3JkZXIgbGlua3MgYnk= TGludXg= TG9jYWw= TG9jYWwgSW1hZ2U= RnVuY3Rpb24= TG9nZ2VkIGluIGFz TG9naW4= TG9nb3V0 KEdNVCk= KEdNVCAtMDE6MDAp KEdNVCAtMTA6MDAp KEdNVCAtMTE6MDAp KEdNVCAtMTI6MDAp KEdNVCAtMDI6MDAp KEdNVCAtMDM6MDAp KEdNVCAtMDQ6MDAp KEdNVCAtMDU6MDAp KEdNVCAtMDY6MDAp KEdNVCAtMDc6MDAp KEdNVCAtMDg6MDAp KEdNVCAtMDk6MDAp TWFyZ2lucw== R3JvdXAgTWVtYmVyc2hpcCBFeHBpcmF0aW9uIFJlbWluZGVyIChkYXlzKQ== TWV0cmlj U2VjdGlvbiBwYXRoIGluIG9uZSBmaWVsZA== TW9kdWxlIG5vdCBsaWNlbnNlZA== TW9uZGF5 Q2hhbmdlIGxvZyBpcyBjdXJyZW50bHkgZGlzYWJsZWQuIFR1cm4gb24gIiVzIiBzZXR0aW5nIHRvIGVuYWJsZSBpdC4= RW5hYmxlIHRyYWNraW5nIGRhdGFiYXNlIGNoYW5nZXMgdG8gY2hhbmdlIGxvZz8= TGFzdCBvcGVyYXRpb24gaGFzIGJlZW4gc3VjY2Vzc2Z1bGx5IGNvbXBsZXRlZCE= QXBwbHkgdG8gYWxsIFN1Yi1zZWN0aW9ucz8= WW91ciAicm9vdCIgcGFzc3dvcmQgaGFzIGJlZW4gcmVzZXQuIFBsZWFzZSByZW1vdmUgREJHX1JFU0VUX1JPT1QgY29uc3RhbnQgYW5kIGNoZWNrIHlvdXIgZS1tYWlsIGFkZHJlc3Mu WW91ciBjaGFuZ2VzIHdlcmUgc3VjY2Vzc2Z1bGx5IHNhdmVkIQ== TmV2ZXI= TmV2ZXIgRXhwaXJlcw== TmV3 TmV4dCBzZWN0aW9u Tm8= Tm9uZQ== Tm8gUGVybWlzc2lvbnM= bmQ= cmQ= c3Q= dGg= T2Zm T24= T25lIFdheQ== b24gbGluZQ== Y3JlYXRlZA== ZGVsZXRlZA== dXBkYXRlZA== QWN0aXZl QWRkcmVzcw== QWZ0ZXI= QWxsb3c= Q3VzdG9t RmFkZQ== U2xpZGU= QXByaWw= QXVndXN0 QXV0by1EZXRlY3Q= QXV0b21hdGlj QmVmb3Jl Qm91bmNlZA== Q2FuY2VsZWQ= Q2l0eQ== Q29sb24= Q29tbWE= Q29tbWVudCBUZXh0 Q29va2llcw== Q291bnRyaWVz Q291bnRyeQ== Q3JlYXRlZCBPbg== LS0gQ29tbW9uIFNldHRpbmdzIC0t LS0gRGF5cyAtLQ== RXZlcnkgZGF5 RXZlcnkgMTUgbWludXRlcw== RXZlcnkgNSBtaW51dGVz RXZlcnkgNCBob3Vycw== RXZlcnkgaG91cg== RXZlcnkgbWludXRl RXZlcnkgbW9udGg= RXZlcnkgb3RoZXIgZGF5 RXZlcnkgb3RoZXIgaG91cg== RXZlcnkgb3RoZXIgbWludXRl RXZlcnkgb3RoZXIgbW9udGg= RXZlcnkgNiBob3Vycw== RXZlcnkgNiBtb250aHM= RXZlcnkgMTAgbWludXRlcw== RXZlcnkgMzAgbWludXRlcw== RXZlcnkgMyBob3Vycw== RXZlcnkgMyBtb250aHM= RXZlcnkgMTIgaG91cnM= RXZlcnkgd2Vla2RheQ== LS0gSG91cnMgLS0= LS0gTWludXRlcyAtLQ== TW9uIHRocnUgRnJp TW9uLCBXZWQsIEZyaQ== LS0gTW9udGhzIC0t T25jZSBhIGRheQ== T25jZSBhIG1vbnRo T25jZSBhbiBob3Vy T25jZSBhIHdlZWs= T25jZSBhIHllYXI= U2F0IGFuZCBTdW4= VHVlcywgVGh1cnM= VHdpY2UgYSBkYXk= MXN0IGFuZCAxNXRo VHdpY2UgYW4gaG91cg== LS0gV2Vla2RheXMgLS0= Q3VycmVudCBEb21haW4= Q3VzdG9tICJUbyIgUmVjaXBpZW50KC1zKQ== Q3VzdG9tIFNlbmRlcg== ZGF5KHMp RGVjZW1iZXI= RGVjbGluZWQ= RGVmYXVsdCBXZWJzaXRlIGFkZHJlc3M= RGVueQ== RGVzY3JpcHRpb24= RGlzYWJsZWQ= RG9lc24ndCBtYXRjaA== RWRpdG9yJ3MgUGljaw== RS1tYWls RS1tYWlsIEJvZHk= SW1tZWRpYXRl RW1haWwgUXVldWU= Rm9yZXZlciAobmV2ZXIgZGVsZXRlZCBhdXRvbWF0aWNhbGx5KQ== RS1tYWlsIFN1YmplY3Q= RS1tYWlsIFRlbXBsYXRlcw== RXJyb3I= RXZlcnlvbmU= RXhhY3Q= RXhwaXJlZA== RXh0ZXJuYWw= RXh0ZXJuYWwgVXJs RmFpbGVk RmVicnVhcnk= Rmlyc3QgTmFtZQ== NSB5ZWFycw== RnJpZGF5 R3JvdXA= R3Vlc3RzIE9ubHk= aG91cihzKQ== SW5oZXJpdCBmcm9tIFBhcmVudA== SW50ZXJuYWw= SW52YWxpZA== SVAgQWRkcmVzcw== SXMgdW5pcXVl SmFudWFyeQ== SnVseQ== SnVuZQ== TGFzdCBOYW1l TG9nZ2VkIE91dA== RGlzYWJsZWQ= UGVuZGluZw== U2VudA== RGF0YWJhc2U= T3RoZXI= UEhQ TWFudWFs TWFyY2g= TWF5 bWludXRlKHMp TW9kYWwgV2luZG93 TW9uZGF5 bW9udGgocyk= TmV3IEUtbWFpbA== Tm90IGVtcHR5 Tm90IGxpa2U= Tm90IFByb2Nlc3NlZA== Tm90IFJlcGxpZWQ= Tm92ZW1iZXI= T2N0b2Jlcg== MSBkYXk= MSBtb250aA== MSB3ZWVr MSB5ZWFy UGFydGlhbGx5IFByb2Nlc3NlZA== UGVuZGluZw== UGhvbmU= TGFiZWxz UG9wdXAgV2luZG93 UHJvY2Vzc2Vk UHVibGlzaGVk UXVlcnkgU3RyaW5nIChTSUQp UmF0aW5n UmVjaXBpZW50IEUtbWFpbA== UmVjaXBpZW50IE5hbWU= UmVwbGllZA== UnVubmluZw== U2FtZSBXaW5kb3c= U2F0dXJkYXk= c2Vjb25kKHMp U2VtaS1jb2xvbg== U2VudA== U2VwdGVtYmVy U2lsZW50 U2tpcHBlZA== U3BhY2U= U3RhdGU= U3ViLW1hdGNo U3VjY2Vzcw== U3VuZGF5 RnJvbSBvdGhlcnM= VG8gb3RoZXJz U3lzdGVt Rm9yZXZlciAobmV2ZXIgZGVsZXRlZCBhdXRvbWF0aWNhbGx5KQ== VGFi VGVtcGxhdGU= MyBtb250aHM= MyB5ZWFycw== VGh1cnNkYXk= VGl0bGU= VHVlc2RheQ== MiB3ZWVrcw== MiB5ZWFycw== VXNlcg== RW1haWwgQWN0aXZhdGlvbg== SW1tZWRpYXRlIA== VXNlcm5hbWU= Tm90IEFsbG93ZWQ= VXBvbiBBcHByb3ZhbA== VmlydHVhbA== V2VkbmVzZGF5 d2VlayhzKQ== eWVhcihzKQ== Wmlw T3RoZXIgRmllbGRz b3V0IG9m KEdNVCArMDE6MDAp KEdNVCArMTA6MDAp KEdNVCArMTE6MDAp KEdNVCArMTI6MDAp KEdNVCArMTM6MDAp KEdNVCArMDI6MDAp KEdNVCArMDM6MDAp KEdNVCArMDQ6MDAp KEdNVCArMDU6MDAp KEdNVCArMDY6MDAp KEdNVCArMDc6MDAp KEdNVCArMDg6MDAp KEdNVCArMDk6MDAp UGFkZGluZ3M= UGFnZQ== QXR0ZW50aW9uOiAlcyBpcyBjdXJyZW50bHkgZWRpdGluZyB0aGlzIHNlY3Rpb24h QXR0ZW50aW9uOiAlcyBhcmUgY3VycmVudGx5IGVkaXRpbmcgdGhpcyBzZWN0aW9uISA= QXR0ZW50aW9uOiAlcyBhcmUgY3VycmVudGx5IGVkaXRpbmcgdGhpcyBzZWN0aW9uIQ== UGFzc3dvcmRzIGRvIG5vdCBtYXRjaA== UGFzc3dvcmQgaXMgdG9vIHNob3J0LCBwbGVhc2UgZW50ZXIgYXQgbGVhc3QgJXMgY2hhcmFjdGVycw== UGVuZGluZw== UGVyZm9ybWluZyBCYWNrdXA= UGVyZm9ybWluZyBJbXBvcnQ= UGVyZm9ybWluZyBSZXN0b3Jl RXhwb3J0IExhbmd1YWdlIHBhY2s= SW1wb3J0IExhbmd1YWdlIHBhY2s= U2V0IFByaW1hcnkgTGFuZ3VhZ2U= RW5hYmxlIE1vZHVsZXM= RGlzYWJsZSBNb2R1bGVz TWFuYWdlIFBlcm1pc3Npb25z U2VuZCBFLW1haWwgdG8gR3JvdXBzIGluIEFkbWlu QmFuIFVzZXJz U2VuZCBFLW1haWwgdG8gVXNlcnMgaW4gQWRtaW4= QWRtaW4gTG9naW4= QWRkIFBlbmRpbmcgQ2F0ZWdvcnk= QWRkIENhdGVnb3J5 RGVsZXRlIENhdGVnb3J5 TW9kaWZ5IENhdGVnb3J5 QWxsb3cgQWRkaW5nIFBlbmRpbmcgQ29udGVudCBSZXZpc2lvbnM= QWxsb3cgQWRkaW5nIENvbnRlbnQgUmV2aXNpb25z QWxsb3cgUmVzdG9yaW5nIENvbnRlbnQgUmV2aXNpb25zIGZyb20gSGlzdG9yeQ== QWxsb3cgVmlld2luZyBIaXN0b3J5IG9mIENvbnRlbnQgUmV2aXNpb25z QWxsb3cgTW9kZXJhdGluZyAoQXBwcm92ZS9EZWNsaW5lKSBDb250ZW50IFJldmlzaW9ucw== VmlldyBDYXRlZ29yeQ== QXBwZW5kIHBocGluZm8gdG8gYWxsIHBhZ2VzIChEZWJ1Zyk= RGlzcGxheSBJdGVtIFF1ZXJpZXMgKERlYnVnKQ== RGlzcGxheSBJdGVtIExpc3QgUXVlcmllcyAoRGVidWcp QWxsb3cgZmF2b3JpdGVz QWxsb3cgTG9naW4= Q2hhbmdlIFVzZXIgUHJvZmlsZXM= U2hvdyBMYW5ndWFnZSBUYWdz UmVhZC1Pbmx5IEFjY2VzcyBUbyBEYXRhYmFzZQ== Tm90IFRyYW5zbGF0ZWQ= VHJhbnNsYXRlZA== QWRtaW4= Qm90aA== RnJvbnQ= UGljaw== U2VsZWN0ZWQgQ29sdW1ucw== UG9wdWxhcg== UG9zaXRpb24gQW5kIFZpc2liaWxpdHk= UHJldmlvdXMgc2VjdGlvbg== UHJpbWFyeQ== QWN0aXZlIFNlY3Rpb25z QWN0aXZlIFVzZXJz U2VudCBUbw== TWVzc2FnZXMgZnJvbSBTaXRlIEFkbWluIGFyZSBmcm9t QWR2YW5jZWQgU2VhcmNo QWR2YW5jZWQgVXNlciBNYW5hZ2VtZW50 QWxsb3cgcGFzc3dvcmQgcmVzZXQgYWZ0ZXI= R2VuZXJhdGUgZnJvbSB0aGUgYXJ0aWNsZSBib2R5 RGF0ZSBvZiBCYWNrdXA6 QmFja3VwIFBhdGg= QmFja3VwIHN0YXR1cw== QmFubmVkIFVzZXJz RGF0ZSBvZiBCaXJ0aA== RWRpdG9yJ3MgUGljayBTZWN0aW9ucw== Q3VycmVudCBTZXNzaW9ucw== VG90YWwgU2l6ZSBvZiB0aGUgRGF0YWJhc2U= RGVmYXVsdA== VXNlciBJRCBmb3IgRGVmYXVsdCBQZXJzaXN0ZW50IFNldHRpbmdz RGVmYXVsdCBWYWx1ZQ== RGlzYWJsZWQgU2VjdGlvbnM= RGlzcGxheSBpbiBHcmlk RGlzcGxheSBPcmRlcg== QWxsb3cgRHVwbGljYXRlIFJhdGluZyBWb3Rlcw== QWxsb3cgRHVwbGljYXRlIFJldmlld3M= RWRpdG9yJ3MgUGljaw== VHlwZQ== VGhlIEVtYWlsIE1lc3NhZ2UgaGFzIGJlZW4gc2VudA== RXhwb3J0IENvbXBsZXRlIQ== RmllbGQgSWQ= RmllbGQgTGFiZWw= RmllbGQgTmFtZQ== RmllbGQgUHJvbXB0 RnJlcXVlbmN5 SGVhZGluZw== KE1pbmltdW0gNCk= SW1wb3J0IFNvdXJjZQ== SW5wdXQgVHlwZQ== S2VlcCBTZXNzaW9uIFdoZW4gQnJvc3dlciBJcyBDbG9zZWQ= TGFuZ3VhZ2UgQ2FjaGUgVGltZW91dA== TGFzdCBTZWN0aW9uIFVwZGF0ZQ== TGFzdCBVcGRhdGVkIExpbms= U2VydmVyIFJlcXVpcmVzIEF1dGhlbnRpY2F0aW9u UG9ydCAoZS5nLiBwb3J0IDI1KQ== TWFpbCBTZXJ2ZXIgQWRkcmVzcw== TWF4aW1hbCBpbXBvcnRlZCBzZWN0aW9uIGxldmVs TWVtYmVyc2hpcCBFeHBpcmVz TGVmdCBNZW51IChUcmVlKSBXaWR0aA== TW92ZSBkb3du TW92ZSB1cA== U2hvdyBtdWx0aXBsZQ== TmV3IFNlY3Rpb25z TmV3ZXN0IFNlY3Rpb24gRGF0ZQ== TmV3ZXN0IExpbmsgRGF0ZQ== TmV3ZXN0IFVzZXIgRGF0ZQ== Q3VycmVudGx5IEFjdGl2ZSBVc2VyIFNlc3Npb25z UGVuZGluZyBTZWN0aW9ucw== UGVuZGluZyBJdGVtcw== UGVyZm9ybSB0aGlzIG9wZXJhdGlvbiBub3c/ UGVyIFBhZ2U= UGVyc29uYWwgSW5mb3JtYXRpb24= UHJpbWFyeSBHcm91cA== UHJpb3JpdHk= UmF0aW5n KE1pbmltdW0gMCwgTWF4aW11bSA1KQ== TnVtYmVyIG9mIERhdGFiYXNlIFJlY29yZHM= TnVtYmVyIG9mIFJlZ2lvbiBQYWNrcw== U2VhcmNoIFJlbGV2YW5jZSBkZXBlbmRzIG9u U2VhcmNoIFJlbGV2ZW5jZSBTZXR0aW5ncw== UmVxdWlyZWQ= SW5jcmVhc2UgaW1wb3J0YW5jZSBpZiBmaWVsZCBjb250YWlucyBhIHJlcXVpcmVkIGtleXdvcmQgYnk= UmVzdG9yZSBoYXMgZmFpbGVkIGFuIGVycm9yIG9jY3VyZWQ6 Q2hvb3NlIG9uZSBvZiB0aGUgZm9sbG93aW5nIGJhY2t1cCBkYXRlcyB0byByZXN0b3JlIG9yIGRlbGV0ZQ== UmVzdG9yZSBTdGF0dXM= UmVzdG9yZSBoYXMgYmVlbiBjb21wbGV0ZWQgc3VjY2Vzc2Z1bGx5 U2VsZWN0IE1vZHVsZSBSb290IFNlY3Rpb246 Um9vdCBQYXNzd29yZA== U2VhcmNoIFR5cGU= U2VsZWN0IFNvdXJjZSBMYW5ndWFnZQ== U2VudCBPbg== U2Vzc2lvbiBDb29raWUgTmFtZQ== U2Vzc2lvbiBNYW5hZ2VtZW50IE1ldGhvZA== U2Vzc2lvbiBJbmFjdGl2aXR5IFRpbWVvdXQgKHNlY29uZHMp U2hvdyBvbiB0aGUgZ2VuZXJhbCB0YWI= U2ltcGxlIFNlYXJjaA== QWRkaXRpb25hbCBNZXNzYWdlIEhlYWRlcnM= TWFpbCBTZXJ2ZXIgUGFzc3dvcmQ= TWFpbCBTZXJ2ZXIgVXNlcm5hbWU= VXNlIG5vbi1ibG9ja2luZyBzb2NrZXQgbW9kZQ== U1FMIFF1ZXJ5Og== UGVyZm9ybSBTUUwgUXVlcnk= U3RlcCBPbmU= U3VibWl0dGVkIE9u RW5hYmxlIFRhZyBDYWNoaW5n VG90YWwgU2l6ZSBvZiBTeXN0ZW0gRmlsZXM= TnVtYmVyIG9mIERhdGFiYXNlIFRhYmxlcw== TnVtYmVyIG9mIFRoZW1lcw== VG90YWwgU2VjdGlvbnM= VG90YWwgVXNlciBHcm91cHM= QWN0aXZlIFVzZXJz RGlzYWJsZWQgVXNlcnM= UGVuZGluZyBVc2Vycw== TnVtYmVyIG9mIFVuaXF1ZSBDb3VudHJpZXMgb2YgVXNlcnM= TnVtYmVyIG9mIFVuaXF1ZSBTdGF0ZXMgb2YgVXNlcnM= VmFsaWRhdGlvbg== TGlzdCBvZiBWYWx1ZXM= KE1pbmltdW0gMSk= V2FybmluZyE= V2VpZ2h0 U2luZ2xlLVF1b3RlcyAoaWUuICcp UmVjaXByb2NhbA== UmVjb3Jkcw== VGhpcyByZWNvcmQgaXMgYmVpbmcgZWRpdGVkIGJ5IHRoZSBmb2xsb3dpbmcgdXNlcnM6DQolcw== VXNlIENhcHRjaGEgY29kZSBvbiBSZWdpc3RyYXRpb24= UmVndWxhcg== UmVtb3ZlIEZyb20= Tm90IGFsbCByZXF1aXJlZCBmaWVsZHMgYXJlIGZpbGxlZC4gUGxlYXNlIGZpbGwgdGhlbSBmaXJzdC4= Q29tbWVudHMgcGVyIFBhZ2U= Q29tbWVudHMgcGVyIFBhZ2UgKHNob3J0LWxpc3Qp UmV2aXNpb24gIyVz SG9tZQ== U2FtcGxlIFRleHQ= c2F2ZWQgYXQgJXM= U2F2ZSBVc2VybmFtZSBvbiBUaGlzIENvbXB1dGVy U2VhcmNo QmFzaWMgUGVybWlzc2lvbnM= U2VjdGlvbg== Q29uZmlnIEZpbGVz Q291bnRlcnM= Q3VzdG9tIEZpZWxkcw== U3VibWlzc2lvbiBEYXRh RS1tYWlsIERlc2lnbiBUZW1wbGF0ZXM= RmlsZQ== RnJvbnQtZW5k RnVsbCBTaXplIEltYWdl R2VuZXJhbA== SW1hZ2U= SW1hZ2UgU2V0dGluZ3M= SW1wb3J0IENvbXBsZXRlZA== VXNlciBJdGVtcw== TWVtb3J5IENhY2hl TWVzc2FnZQ== U2VjdGlvbiBPdmVydmlldw== U2VjdGlvbiBQcm9wZXJ0aWVz U2VjdGlvbiBDYWNoaW5n UHJvamVjdCBEZXBsb3ltZW50 UHJvcGVydGllcw== UXVpY2sgTGlua3M= UmVjaXBpZW50cyBJbmZvcm1hdGlvbg== UmVsYXRpb24= UmVwbGFjZW1lbnQgVGFncw== U2VuZGVyIEluZm9ybWF0aW9u U2V0dGluZ3M= M3JkIFBhcnR5IEFQSSBTZXR0aW5ncw== QWRtaW4gQ29uc29sZSBTZXR0aW5ncw== Q1NWIEV4cG9ydCBTZXR0aW5ncw== TG9ncyBTZXR0aW5ncw== TWFpbGluZyBTZXR0aW5ncw== TWFpbnRlbmFuY2UgU2V0dGluZ3M= U2Vzc2lvbiBTZXR0aW5ncw== U1NMIFNldHRpbmdz U3lzdGVtIFNldHRpbmdz V2Vic2l0ZSBTZXR0aW5ncw== U3VibWlzc2lvbiBOb3Rlcw== VGVtcGxhdGVz VGh1bWJuYWlsIEltYWdl VHJhbnNsYXRpb24= U2VhcmNoIFVzZXJz VmFsdWVz U2VsZWN0IENvbHVtbnM= U2VsZWN0ZWQgSXRlbXM= U2VsZWN0aW5nIFNlY3Rpb25z T25lIGZpZWxkIGZvciBlYWNoIHNlY3Rpb24gbGV2ZWw= Q2xvbmU= Q2xvbmU= Q29udGludWU= RWRpdA== RXhwb3J0 R28gVXA= SW1wb3J0 RG93bg== VXA= TmV3 UmVidWlsZA== UmVzY2FuIFRoZW1lcw== UmVzZXQ= UHJpbWFyeQ== U3luY2hyb25pemU= Vmlldw== U2hvdw== QWZmZWN0ZWQgcm93cw== RXhlY3V0ZWQgaW46 U3RlcA== RGVmaW5pdGlvbg== UHJldmlldw== U3VuZGF5 U3lzdGVt QWRtaW5pc3RyYXRpb24gUGFuZWwgVUk= QWR2YW5jZWQgVmlldw== QmFja3Vw QmFuIFJ1bGVz QmFzZSBTdHlsZXM= QmxvY2sgU3R5bGVz Q2F0YWxvZw== QnJvd3NlIFdlYnNpdGU= U2VjdGlvbnM= Q2hhbmdlcyBMb2c= Rm9ybXM= VXNlciBNYW5hZ2VtZW50 Q3VzdG9tIEZpZWxkcw== RS1tYWlsIEV2ZW50cw== R2VuZXJhbCBTZXR0aW5ncw== T3V0cHV0 U2VhcmNo R2VuZXJhbA== Q3VzdG9t RS1tYWlsIENvbW11bmljYXRpb24= RS1tYWlsIExvZw== RW1haWwgUXVldWU= RS1tYWlsIFRlbXBsYXRlcw== RmllbGRz RmlsZXM= Rm9ybXMgQ29uZmlndXJhdGlvbg== R2VuZXJhbA== R2VuZXJhbA== R3JvdXBz SGVscA== SW1hZ2Vz SW1wb3J0IERhdGE= SXRlbXM= TGFiZWxz TG9ncyAmIFJlcG9ydHM= TWVzc2FnZXM= UGFja2FnZSBDb250ZW50 UGVybWlzc2lvbnM= UGVybWlzc2lvbiBUeXBlcw== UHJvbW8gQmxvY2tz UHJvcGVydGllcw== UXVlcnkgRGF0YWJhc2U= UmVnaW9uYWw= UmVsYXRlZCBTZWFyY2hlcw== UmVsYXRpb25z UmVzdG9yZQ== Q29tbWVudHM= U2VhcmNo U2VhcmNoIExvZw== UEhQIEluZm9ybWF0aW9u U3lzdGVtIFRvb2xz U2Vzc2lvbiBMb2c= U2Vzc2lvbiBMb2c= U2V0dGluZ3M= U2hvdyBBbGw= U2hvdyBTdHJ1Y3R1cmU= V2Vic2l0ZSAmIENvbnRlbnQ= QWRtaW4gU2tpbnM= U3VtbWFyeQ== U3lzdGVtIExvZw== Q29uZmlndXJhdGlvbg== VGFnIGxpYnJhcnk= VGhlbWVz VG9vbHM= VXNlcnM= R3JvdXBz VXNlcnM= VmlzaXRvciBMb2c= VmlzaXRz dGV4dA== QWRtaW4= QWR2YW5jZWQ= QWxs QXV0by1SZWZyZXNo QmFjayB1cCBoYXMgYmVlbiBjb21wbGV0ZWQuIFRoZSBiYWNrdXAgZmlsZSBpczo= SW4tUG9ydGFsIGRvZXMgbm90IGhhdmUgYWNjZXNzIHRvIHdyaXRlIHRvIHRoaXMgZGlyZWN0b3J5 VGhpcyB1dGlsaXR5IGFsbG93cyB5b3UgdG8gYmFja3VwIHlvdXIgSW4tUG9ydGFsIGRhdGFiYXNlIHNvIGl0IGNhbiBiZSByZXN0b3JlZCBhdCBsYXRlciBpbiBuZWVkZWQu Ynl0ZXM= Q2F0YWxvZw== U2VjdGlvbnM= U2VjdGlvbg== WW91IGFyZSBhYm91dCB0byBjbGVhciBjbGlwYm9hcmQgY29udGVudCENClByZXNzIE9LIHRvIGNvbnRpbnVlIG9yIENhbmNlbCB0byByZXR1cm4gdG8gcHJldmlvdXMgc2NyZWVuLg== Q3VzdG9tIEZpZWxkcw== c2VjdGlvbnM= RGF0ZS9UaW1lIFNldHRpbmdz UnVubmluZyB0aGlzIHV0aWxpdHkgd2lsbCBhZmZlY3QgeW91ciBkYXRhYmFzZS4gUGxlYXNlIGJlIGFkdmlzZWQgdGhhdCB5b3UgY2FuIHVzZSB0aGlzIHV0aWxpdHkgYXQgeW91ciBvd24gcmlzay4gSW4tUG9ydGFsIG9yIGl0J3MgZGV2ZWxvcGVycyBjYW4gbm90IGJlIGhlbGQgbGlhYmxlIGZvciBhbnkgY29ycnVwdCBkYXRhIG9yIGRhdGEgbG9zcy4= RGVmYXVsdA== RGVsZXRl RGlzYWJsZQ== UnVubmluZyB0aGlzIHV0aWxpdHkgd2lsbCBhZmZlY3QgeW91ciBkYXRhYmFzZS4gUGxlYXNlIGJlIGFkdmlzZWQgdGhhdCB5b3UgY2FuIHVzZSB0aGlzIHV0aWxpdHkgYXQgeW91ciBvd24gcmlzay4gSW4tUG9ydGFsIG9yIGl0J3MgZGV2ZWxvcGVycyBjYW4gbm90IGJlIGhlbGQgbGlhYmxlIGZvciBhbnkgY29ycnVwdCBkYXRhIG9yIGRhdGEgbG9zcy4= UGxlYXNlIG1ha2Ugc3VyZSB0byBCQUNLVVAgeW91ciBkYXRhYmFzZShzKSBiZWZvcmUgcnVubmluZyB0aGlzIHV0aWxpdHkh RWRpdA== RW1haWw= Rm9sbG93aW5nIGxpbmVzIHdlcmUgTk9UIGltcG9ydGVk RnJvbnQtRW5kIE9ubHk= R2VuZXJhbA== SG90 SSBhZ3JlZSB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnM= SW1wb3J0IFJlc3VsdHM= SW4gRGV2ZWxvcG1lbnQ= SW52ZXJ0 S2V5d29yZA== TGluaw== RGVmYXVsdCBNRVRBIGtleXdvcmRz TWluaW11bSBwYXNzd29yZCBsZW5ndGg= VXNlciBuYW1lIGxlbmd0aCAobWluIC0gbWF4KQ== U2hvdyBtdWx0aXBsZQ== TmV3 Tm9uZQ== Tm8gUGVybWlzc2lvbg== b3I= UGhvbmU= UG9wdWxhcg== UG9wdWxhcml0eQ== UmVhZHkgdG8gSW5zdGFsbA== cmVjb3JkcyBhZGRlZA== cmVjb3JkcyB1cGRhdGVk UmVxdWlyZWQgZmllbGRz SGVyZSB5b3UgY2FuIHJlc3RvcmUgeW91ciBkYXRhYmFzZSBmcm9tIGEgcHJldmlvdXNseSBiYWNrZWQgdXAgc25hcHNob3QuIFJlc3RvcmluZyB5b3VyIGRhdGFiYXNlIHdpbGwgZGVsZXRlIGFsbCBvZiB5b3VyIGN1cnJlbnQgZGF0YSBhbmQgbG9nIHlvdSBvdXQgb2YgdGhlIHN5c3RlbS4= Q29tbWVudA== Q29tbWVudHM= TW9kdWxlIFJvb3QgU2VjdGlvbg== U2F2ZQ== U2VsZWN0 U2Vzc2lvbiBFeHBpcmVk U2ltcGxl U29ydA== VW5zZWxlY3Q= VXNlcg== VXNlcnM= VmVyc2lvbg== Vmlldw== QWRkaW5nIEFkbWluaXN0cmF0b3I= QWRkaW5nIEJhbiBSdWxl QWRkaW5nIENvdW50cnkvU3RhdGU= QWRkaW5nIEN1c3RvbSBGaWVsZA== QWRkaW5nIEUtbWFpbCBUZW1wbGF0ZQ== QWRkaW5nIEZpbGU= QWRkaW5nIEl0ZW0gRmlsdGVy QWRkaW5nIE1haWxpbmcgTGlzdA== QWRkaW5nIFBlcm1pc3Npb24gVHlwZQ== QWRkaW5nIFByb21vIEJsb2Nr QWRkaW5nIFByb21vIEJsb2NrIEdyb3Vw QWRkaW5nIFNjaGVkdWxlZCBUYXNr QWRkaW5nIFNpdGUgRG9tYWlu QWRkaW5nIFNraW4= QWRkaW5nIFNwZWxsaW5nIERpY3Rpb25hcnk= QWRkaW5nIFN0b3AgV29yZA== QWRkaW5nIFN5c3RlbSBFdmVudCBTdWJzY3JpcHRpb24= QWRkaW5nIFN5c3RlbSBTZXR0aW5n QWRkaW5nIFRoZW1lIFRlbXBsYXRl QWRkaW5nIFRoZXNhdXJ1cw== QWRkaW5nIEJhc2UgU3R5bGU= QWRkaW5nIEJsb2NrIFN0eWxl QWRkaW5nIFNlY3Rpb24= QWRkaW5nIFNlYXJjaCBGaWVsZA== QWRkaW5nIENNUyBCbG9jaw== QWRkaW5nIEZvcm0= QWRkaW5nIEZvcm0gRmllbGQ= QWRkaW5nIEdyb3Vw QWRkaW5nIEltYWdl QWRkaW5nIExhbmd1YWdl QWRkaW5nIFBocmFzZQ== QWRkaW5nIEtleXdvcmQ= QWRkaW5nIFJlbGF0aW9uc2hpcA== QWRkaW5nIENvbW1lbnQ= QWRkaW5nIFRoZW1l QWRkaW5nIFVzZXI= QWRkaXRpb25hbCBQZXJtaXNzaW9ucw== QWRtaW5pc3RyYXRvcnM= QWR2YW5jZWQ= U2hvd2luZyBhbGwgcmVnYXJkbGVzcyBvZiBTdHJ1Y3R1cmU= QmFzZSBTdHlsZXM= QmxvY2sgU3R5bGVz Qm91bmNlIFBPUDMgU2VydmVyIFNldHRpbmdz U2VjdGlvbnM= U2VsZWN0IHNlY3Rpb24= Q29sdW1uIFBpY2tlcg== Q29uZmlndXJhdGlvbg== Q29udGFjdCBJbmZvcm1hdGlvbg== Q291bnRyaWVzICYgU3RhdGVz Q1NWIEV4cG9ydA== Q1NWIEltcG9ydA== Q3VzdG9t Q3VzdG9tIEZpZWxkcw== RGVwbG95bWVudA== RWRpdGluZyBBZG1pbmlzdHJhdG9y RWRpdGluZyBCYW4gUnVsZQ== RWRpdGluZyBDaGFuZ2VzIExvZw== Q29udGVudCBFZGl0b3IgLSBBdXRvLXNhdmVkIGF0ICVz RWRpdGluZyBDb3VudHJ5L1N0YXRl RWRpdGluZyBEcmFmdCAoJTIkcyk= RWRpdGluZyBFLW1haWwgVGVtcGxhdGU= RWRpdGluZyBGaWxl RWRpdGluZyBJdGVtIEZpbHRlcg== RWRpdGluZyBNZW1iZXJzaGlw RWRpdGluZyBQZXJtaXNzaW9uIFR5cGU= RWRpdGluZyBQcm9tbyBCbG9jaw== RWRpdGluZyBQcm9tbyBCbG9jayBHcm91cA== RWRpdGluZyBTY2hlZHVsZWQgVGFzaw== RWRpdGluZyBTaXRlIERvbWFpbg== RWRpdGluZyBTa2lu RWRpdGluZyBTUEFNIFJlcG9ydA== RWRpdGluZyBTcGVsbGluZyBEaWN0aW9uYXJ5 RWRpdGluZyBTdG9wIFdvcmQ= RWRpdGluZyBTdHlsZQ== RWRpdGluZyBTeXN0ZW0gRXZlbnQgU3Vic2NyaXB0aW9u RWRpdGluZyBTeXN0ZW0gU2V0dGluZw== RWRpdGluZyBUaGVtZSBGaWxl RWRpdGluZyBUaGVzYXVydXM= RWRpdGluZyBUcmFuc2xhdGlvbg== RWRpdGluZyBCYXNlIFN0eWxl RWRpdGluZyBCbG9jayBTdHlsZQ== RWRpdGluZyBTZWN0aW9u RWRpdGluZyBDTVMgQmxvY2s= RWRpdGluZyBDdXN0b20gRmllbGQ= RWRpdGluZyBGb3Jt RWRpdGluZyBGb3JtIEZpZWxk RWRpdGluZyBHcm91cA== RWRpdGluZyBJbWFnZQ== RWRpdGluZyBMYW5ndWFnZQ== RWRpdGluZyBQaHJhc2U= RWRpdGluZyBLZXl3b3Jk RWRpdGluZyBSZWxhdGlvbnNoaXA= RWRpdGluZyBDb21tZW50 RWRpdGluZyBUaGVtZQ== RWRpdGluZyBVc2Vy RS1tYWlsIENvbW11bmljYXRpb24= RS1tYWlsIFNldHRpbmdz RS1tYWlsIFRlbXBsYXRlcw== RXhwb3J0IExhbmd1YWdlIFBhY2sgLSBSZXN1bHRz RXhwb3J0IExhbmd1YWdlIFBhY2sgLSBTdGVwMQ== RmllbGRz RmlsZXM= Rm9ybXM= Rm9ybSBTdWJtaXNzaW9ucw== R2VuZXJhbA== R3JvdXBz SW1hZ2Vz SW5zdGFsbCBMYW5ndWFnZSBQYWNrIC0gU3RlcCAx SW5zdGFsbCBMYW5ndWFnZSBQYWNrIC0gU3RlcCAy SXRlbSBGaWx0ZXJz SXRlbXM= TGFiZWxz TGFuZy4gTWFuYWdlbWVudA== TGFuZ3VhZ2UgUGFja3M= TGFuZ3VhZ2VzIE1hbmFnZW1lbnQ= TG9hZGluZyAuLi4= T3RoZXI= UmVxdWVzdA== U2Vzc2lvbg== U291cmNl TWFpbGluZ3M= TWVzc2FnZXM= TW9kdWxlIERlcGxveW1lbnQgTG9n TW9kdWxlcw== TmV3IEUtbWFpbCBUZW1wbGF0ZQ== TmV3IEZpbGU= TmV3IFJlcGx5 TmV3IFNjaGVkdWxlZCBUYXNr TmV3IFRoZW1l TmV3IFRoZW1lIFRlbXBsYXRl TmV3IEJhc2UgU3R5bGU= TmV3IEJsb2NrIFN0eWxl TmV3IFNlY3Rpb24= TmV3IEZpZWxk TmV3IEltYWdl TmV3IFJlbGF0aW9uc2hpcA== TmV3IENvbW1lbnQ= Tm8gUGVybWlzc2lvbnM= UGVybWlzc2lvbnM= TGFiZWxzICYgUGhyYXNlcw== UGxlYXNlIFdhaXQ= UHJvbW8gQmxvY2sgR3JvdXBz UHJvbW8gQmxvY2tz UHJvcGVydGllcw== UmVsYXRlZCBTZWFyY2hlcw== UmVsYXRpb25z UmVwbHkgUE9QMyBTZXJ2ZXIgU2V0dGluZ3M= Q29tbWVudHM= UnVuIFNjaGVkdWxl UnVuIFNldHRpbmdz U2NoZWR1bGVkIFRhc2tz U2VsZWN0IEdyb3VwKHMp U2VsZWN0IFVzZXI= U2VuZCBFLW1haWw= U2VuZGluZyBQcmVwYXJlZCBFLW1haWxz TWFpbCBoYXMgYmVlbiBzZW50IFN1Y2Nlc3NmdWxseQ== U2l0ZSBEb21haW5z U1BBTSBSZXBvcnRz U3BlbGxpbmcgRGljdGlvbmFyeQ== U3RvcCBXb3Jkcw== U3RydWN0dXJlICYgRGF0YQ== U3lzdGVtIEN1c3RvbSBGaWVsZHM= VXNlciBTdWJzY3JpcHRpb25z U3lzdGVtIFRvb2xz Q2xlYXIgVGVtcGxhdGVzIENhY2hl Q29tbW9ubHkgVXNlZCBLZXlz - RGVwbG95IENoYW5nZXM= + RGVwbG95IENoYW5nZXM= + RHVtcCBBc3NldHM= S2V5IE5hbWU= S2V5IFZhbHVl TG9jYXRlIFVuaXQgQ29uZmlnIEZpbGU= UmVidWlsZCBNdWx0aWxpbmd1YWwgRmllbGRz UmVjb21waWxlIFRlbXBsYXRlcw== UmVmcmVzaCBUaGVtZSBGaWxlcw== UmVzZXQgQWRtaW4gQ29uc29sZSBTZWN0aW9ucw== UmVzZXQgQWxsIEtleXM= UmVzZXQgQ29uZmlncyBGaWxlcyBDYWNoZSBhbmQgUGFyc2VkIFN5c3RlbSBEYXRh UmVzZXQgTW9kUmV3cml0ZSBDYWNoZQ== UmVzZXQgUGFyc2VkIGFuZCBDYWNoZWQgU3lzdGVtIERhdGE= UmVzZXQgU01TIE1lbnUgQ2FjaGU= U2hvdyBEYXRhYmFzZSBUYWJsZSBTdHJ1Y3R1cmU= U3luY2hyb25pemUgRGF0YWJhc2UgUmV2aXNpb25z VGhlbWUgRmlsZXM= VGhlc2F1cnVz VXBkYXRpbmcgU2VjdGlvbnM= VXNlcnM= Vmlld2luZyBFbWFpbCBMb2c= Vmlld2luZyBmb3JtIHN1Ym1pc3Npb24= Vmlld2luZyBNYWlsaW5nIExpc3Q= Vmlld2luZyBNb2R1bGUgRGVwbG95bWVudCBMb2c= Vmlld2luZyBSZXBseQ== Vmlld2luZyBSZXZpc2lvbiAjJXMgKCVzKQ== Vmlld2luZyBTeXN0ZW0gTG9n VmlzaXRz V2Vic2l0ZQ== dG8= Q3Vyci4gU2VjdGlvbg== RG93bg== VXA= QWRk QWRkIFVzZXIgdG8gR3JvdXA= QWRkIFVzZXIgVG8gR3JvdXA= QXBwcm92ZQ== QmFjaw== Q2FuY2Vs Q2xlYXIgQ2xpcGJvYXJk Q2xvbmU= Q2xvbmUgVXNlcnM= Q2xvc2U= Q29weQ== Q3V0 RGVjbGluZQ== RGVsZXRl RGVsZXRlIEFsbA== RGVsZXRlIFJldmlldw== RGVsZXRlIFJlcG9ydCBPbmx5 RGVueQ== RGV0YWlscw== RGlzYWJsZQ== RGlzY2FyZA== RWRpdA== RWRpdCBDdXJyZW50IFNlY3Rpb24= RnJvbnQtRW5kIE9ubHk= RW5hYmxl RXhwb3J0 RXhwb3J0IExhbmd1YWdl SGlkZSBNZW51 SGlzdG9yeQ== SG9tZQ== SW1wb3J0 SW1wb3J0IExhbmd1YWdl TG9naW4gQXM= TW92ZSBEb3du TW92ZSBVcA== TmV3IEJhc2UgU3R5bGU= TmV3IEJsb2NrIFN0eWxl TmV3IENvdW50cnkvU3RhdGU= TmV3IEdyb3Vw TmV3IGxhYmVs TmV3IExhbmd1YWdl TmV3IFBlcm1pc3Npb24= TmV3IFBocmFzZQ== TmV3IENvbW1lbnQ= TmV3IFNjaGVkdWxlZCBUYXNr TmV3IFNlYXJjaCBGaWVsZA== TmV3IFNpdGUgRG9tYWlu TmV3IFN0b3AgV29yZA== TmV3IFN5c3RlbSBTZXR0aW5n TmV3IFRlcm0= TmV3IFRoZW1l TmV3IFVzZXI= TmV3IFNlY3Rpb24= TmV3IEN1c3RvbSBGaWVsZA== TmV3IEZvcm0= TmV3IEZvcm0gRmllbGQ= TmV3IEltYWdlcw== QWRkIEtleXdvcmQ= TmV3IFJlbGF0aW9u TmV3IFRlbXBsYXRl TmV4dA== UGFzdGU= UHJldmlvdXM= UHJldmlldw== U2V0IFByaW1hcnkgR3JvdXA= UHJpbnQ= UHJvY2VzcyBRdWV1ZQ== UHVibGlzaA== UmVidWlsZCBTZWN0aW9uIENhY2hl UmVjYWxjdWxhdGUgUHJpb3JpdGllcw== UmVmcmVzaA== UmVwbHk= UmVzY2FuIFRoZW1lcw== UmVzZW5k UmVzZXQ= UmVzZXQgQ291bnRlcnM= UmVzZXQgUGVyc2lzdGVudCBTZXR0aW5ncw== UmVzZXQgVG8gQmFzZQ== UnVu UnVuIFNRTA== U2F2ZQ== U2F2ZSBhcyBEcmFmdA== U2VhcmNo UmVzZXQ= U2VsZWN0IFVzZXI= U2VuZA== U2VuZCBFLW1haWw= U2VuZCBFLW1haWw= U2V0IFByaW1hcnk= U2V0IFByaW1hcnkgU2VjdGlvbg== U2V0IFByaW1hcnkgTGFuZ3VhZ2U= VXNlIGFzIFByaW1hcnk= U2V0IFN0aWNreQ== U2V0dGluZ3M= U2hvdyBNZW51 U3luY2hyb25pemUgTGFuZ3VhZ2Vz VG9vbHM= VXAgYSBTZWN0aW9u VmFsaWRhdGU= Vmlldw== VmlldyBEZXRhaWxz Vmlldw== VG8gRGF0ZQ== VHJhbnNsYXRl VHJhbnNsYXRlZA== VHJlZQ== Q2hlY2tib3hlcw== RGF0ZQ== RGF0ZSAmIFRpbWU= TGFiZWw= TXVsdGlwbGUgU2VsZWN0 UGFzc3dvcmQgZmllbGQ= UmFkaW8gYnV0dG9ucw== UmFuZ2UgU2xpZGVy RHJvcCBkb3duIGZpZWxk Q2hlY2tib3g= VGV4dCBmaWVsZA== VGV4dCBhcmVh RmlsZSBVcGxvYWQ= VW5jaGFuZ2Vk VW5pY29kZQ== VXBkYXRpbmcgQ29uZmlndXJhdGlvbg== VXBsb2Fk VXNlIENyb24gdG8gcnVuIFNjaGVkdWxlZCBUYXNrcw== QXNzaWduIGFkbWluaXN0cmF0b3JzIHRvIGdyb3Vw QWxsb3cgbmV3IHVzZXIgcmVnaXN0cmF0aW9u QXNzaWduIEFsbCBVc2VycyBUbyBHcm91cA== QXNzaWduIHVzZXJzIG5vdCBsb2dnZWQgaW4gdG8gZ3JvdXA= QXNzaWduIHJlZ2lzdGVyZWQgdXNlcnMgdG8gZ3JvdXA= QXNzaWduIHBhc3N3b3JkIGF1dG9tYXRpY2FsbHk= QXNzaWduIG1haWxpbmcgbGlzdCBzdWJzY3JpYmVycyB0byBncm91cA== VVMvVUs= RS1tYWlsIGFkZHJlc3M= VmFsdWU= RGlyZWN0IGFjY2VzcyBvciBib29rbWFyaw== V2FybmluZzogRW5hYmxpbmcgSFRNTCBpcyBhIHNlY3VyaXR5IHJpc2sgYW5kIGNvdWxkIGRhbWFnZSB0aGUgc3lzdGVtIGlmIHVzZWQgaW1wcm9wZXJseSE= QSBzZWFyY2ggb3IgYSBmaWx0ZXIgaXMgaW4gZWZmZWN0LiBZb3UgbWF5IG5vdCBiZSBzZWVpbmcgYWxsIG9mIHRoZSBkYXRhLg== T25lIG9yIG1vcmUgZmllbGRzIG9uIHRoaXMgZm9ybSBoYXMgYW4gZXJyb3IuPGJyLz4NCjxzbWFsbD5QbGVhc2UgbW92ZSB5b3VyIG1vdXNlIG92ZXIgdGhlIGZpZWxkcyBtYXJrZWQgd2l0aCByZWQgdG8gc2VlIHRoZSBlcnJvciBkZXRhaWxzLjwvc21hbGw+ TW9kaWZpY2F0aW9ucyB3aWxsIG5vdCB0YWtlIGVmZmVjdCB1bnRpbCB5b3UgY2xpY2sgdGhlIFNhdmUgYnV0dG9uIQ== d2Vlaw== V2luZG93cw== eWVhcg== WWVz U3ViLXNlY3Rpb25zIFF1YW50aXR5 TmF2aWdhdGlvbiBCYXI= UmF0aW5n TnVtYmVyIG9mIFJldmlld3M= TnVtYmVyIG9mIFJhdGluZyBWb3Rlcw== U2VjdGlvbiBJRA== Q3JlYXRlZCBCeSBVc2VyIElE RGF0ZSBDcmVhdGVk RGVzY3JpcHRpb24= RWRpdG9ycyBQaWNr SGl0cw== SXRlbSBJcyBIb3Q= TGluayBJRA== TWV0YSBEZXNjcmlwdGlvbg== TWV0YSBLZXl3b3Jkcw== TGFzdCBNb2RpZmllZCBEYXRl TW9kaWZpZWQgQnkgVXNlciBJRA== TmFtZQ== SXRlbSBJcyBOZXc= Tm90aWZ5IE93bmVyIG9mIENoYW5nZXM= T3JpZ2luYWwgSXRlbSBJRA== T3duZXIgVXNlciBJRA== UGFyZW50IElE UGFyZW50IFBhdGg= SXRlbSBJcyBQb3B1bGFy UHJpb3JpdHk= UXR5IFNvbGQ= UmVzb3VyY2UgSUQ= U3RhdHVz SXRlbSBJcyBhIFRvcCBTZWxsZXI= VVJM b2Y= SW52YWxpZA== Tm90IFZhbGlkYXRlZA== VmFsaWQ= TmV3IENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIC0gQWRkZWQ= WW91ciBzdWdnZXN0ZWQgY2F0ZWdvcnkgIjxpbnAyOmNfRmllbGQgbmFtZT0iTmFtZSIvPiIgaGFzIGJlZW4gYWRkZWQu TmV3IENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIFN1Ym1pdHRlZCBieSBVc2Vycw== QSBjYXRlZ29yeSAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBhZGRlZC4= U3VnZ2VzdGVkIENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIGlzIFBlbmRpbmc= VGhlIGNhdGVnb3J5IHlvdSBzdWdnZXN0ZWQgIjxpbnAyOmNfRmllbGQgbmFtZT0iTmFtZSIvPiIgaXMgcGVuZGluZyBmb3IgYWRtaW5pc3RyYXRpdmUgYXBwcm92YWwuDQoNClRoYW5rIHlvdSE= U3VnZ2VzdGVkIENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIGlzIFBlbmRpbmc= QSBjYXRlZ29yeSAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBhZGRlZCwgcGVuZGluZyB5b3VyIGNvbmZpcm1hdGlvbi4gIFBsZWFzZSByZXZpZXcgdGhlIGNhdGVnb3J5IGFuZCBhcHByb3ZlIG9yIGRlbnkgaXQu QSBjYXRlZ29yeSBoYXMgYmVlbiBhcHByb3ZlZA== WW91ciBzdWdnZXN0ZWQgY2F0ZWdvcnkgIjxpbnAyOmNfRmllbGQgbmFtZT0iTmFtZSIvPiIgaGFzIGJlZW4gYXBwcm92ZWQu WW91ciBDYXRlZ29yeSAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBEZW5pZWQ= WW91ciBjYXRlZ29yeSBzdWdnZXN0aW9uICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIGhhcyBiZWVuIGRlbmllZC4= TmV3IEVtYWlsIFJFUExZIFJlY2VpdmVkIGluICJGZWVkYmFjayBNYW5hZ2VyIiAoPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRmllbGQgbmFtZT0iRm9ybVN1Ym1pc3Npb25JZCIvPik= TmV3IEVtYWlsIFJFUExZIFJlY2VpdmVkIGluICZxdW90O0ZlZWRiYWNrIE1hbmFnZXImcXVvdDsuPGJyIC8+DQo8YnIgLz4NCk9yaWdpbmFsIEZlZWRiYWNrSWQ6IDxpbnAyOmZvcm1zdWJzLi1pdGVtX0ZpZWxkIG5hbWU9IkZvcm1TdWJtaXNzaW9uSWQiLz4gPGJyIC8+DQpPcmlnaW5hbCBTdWJqZWN0OiA8aW5wMjpmb3Jtc3Vicy4taXRlbV9Gb3JtRmllbGQgcm9sZT0ic3ViamVjdCIvPiA8YnIgLz4NCjxiciAvPg0KUGxlYXNlIHByb2NlZWQgdG8gdGhlIEFkbWluIENvbnNvbGUgaW4gb3JkZXIgdG8gcmV2aWV3IGFuZCByZXBseSB0byB0aGUgdXNlci4= TmV3IEVtYWlsIC0gRGVsaXZlcnkgRmFpbHVyZSBSZWNlaXZlZCBpbiAiRmVlZGJhY2sgTWFuYWdlciIgKDxpbnAyOmZvcm1zdWJzLi1pdGVtX0ZpZWxkIG5hbWU9IkZvcm1TdWJtaXNzaW9uSWQiLz4p TmV3IEVtYWlsIERlbGl2ZXJ5IEZhaWx1cmUgUmVjZWl2ZWQgaW4gJnF1b3Q7RmVlZGJhY2sgTWFuYWdlciZxdW90Oy48YnIgLz4NCjxiciAvPg0KT3JpZ2luYWwgRmVlZGJhY2tJZDogPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRmllbGQgbmFtZT0iRm9ybVN1Ym1pc3Npb25JZCIvPiA8YnIgLz4NCk9yaWdpbmFsIFN1YmplY3Q6IDxpbnAyOmZvcm1zdWJzLi1pdGVtX0Zvcm1GaWVsZCByb2xlPSJzdWJqZWN0Ii8+IDxiciAvPg0KPGJyIC8+DQpQbGVhc2UgcHJvY2VlZCB0byB0aGUgQWRtaW4gQ29uc29sZSBpbiBvcmRlciB0byByZXZpZXcgYW5kIHJlcGx5IHRvIHRoZSB1c2VyLg== PGlucDI6bV9QYXJhbSBuYW1lPSJzdWJqZWN0Ii8+ICN2ZXJpZnk8aW5wMjpzdWJtaXNzaW9uLWxvZ19GaWVsZCBuYW1lPSJWZXJpZnlDb2RlIi8+ PGlucDI6bV9QYXJhbSBuYW1lPSJtZXNzYWdlIi8+ VGhhbmsgWW91IGZvciBDb250YWN0aW5nIFVzIQ== PHA+VGhhbmsgeW91IGZvciBjb250YWN0aW5nIHVzLiBXZSdsbCBiZSBpbiB0b3VjaCB3aXRoIHlvdSBzaG9ydGx5ITwvcD4= TmV3IGZvcm0gc3VibWlzc2lvbg== PHA+Rm9ybSBoYXMgYmVlbiBzdWJtaXR0ZWQuIFBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIHRvIHJldmlldyB0aGUgc3VibWlzc2lvbiE8L3A+ Um9vdCBSZXNldCBQYXNzd29yZA== WW91ciBuZXcgcGFzc3dvcmQgaXM6IDxpbnAyOm1fUGFyYW0gbmFtZT0icGFzc3dvcmQiLz4= U3lzdGVtIExvZyBOb3RpZmljYXRpb25zICg8aW5wMjpzeXN0ZW0tbG9nLmVtYWlsX1RvdGFsUmVjb3Jkcy8+KQ== PGlucDI6bV9EZWZpbmVFbGVtZW50IG5hbWU9ImJhY2t0cmFjZV9lbGVtZW50Ij4NCgk8bGk+PGlucDI6bV9QaHJhc2UgbmFtZT0ibGFfTG9nQmFja3RyYWNlRnVuY3Rpb24iLz46IDxpbnAyOm1fUGFyYW0gbmFtZT0iZmlsZV9pbmZvIi8+PC9saT4NCjwvaW5wMjptX0RlZmluZUVsZW1lbnQ+DQoNCjxpbnAyOm1fRGVmaW5lRWxlbWVudCBuYW1lPSJzeXN0ZW1fbG9nX2VsZW1lbnQiPg0KCTxoND48aW5wMjpGaWVsZCBuYW1lPSJMb2dUaW1lc3RhbXAiIGZvcm1hdD0iTSBkIEg6aTpzIi8+IDxpbnAyOkZpZWxkIG5hbWU9IkxvZ0hvc3RuYW1lIi8+IDxpbnAyOlJlcXVlc3RVUkkgaHRtbF9lc2NhcGU9IjEiLz5bUElEPTxpbnAyOkZpZWxkIG5hbWU9IkxvZ1Byb2Nlc3NJZCIvPixVSUQ9PGlucDI6RmllbGQgbmFtZT0iTG9nVW5pcXVlSWQiLz5dPC9oND4NCglbPGlucDI6RmllbGQgbmFtZT0iTG9nTGV2ZWwiLz5dICM8aW5wMjpGaWVsZCBuYW1lPSJMb2dDb2RlIi8+OiA8aW5wMjpGaWVsZCBuYW1lPSJMb2dNZXNzYWdlIiBub19zcGVjaWFsPSIxIi8+IGluIDxpbnAyOkZpbGVuYW1lLz4gb24gbGluZSA8aW5wMjpGaWVsZCBuYW1lPSJMb2dTb3VyY2VGaWxlTGluZSIvPjxici8+DQoNCgk8aW5wMjptX2lmIGNoZWNrPSJGaWVsZCIgbmFtZT0iTG9nQmFja3RyYWNlIiBkYj0iZGIiPg0KCQk8YnIvPkJhY2t0cmFjZToNCg0KCQk8b2wgc3R5bGU9Im1hcmdpbjogMDsgcGFkZGluZy1sZWZ0OiAyNXB4OyBmb250LXNpemU6IDEycHg7Ij4NCgkJCTxpbnAyOlByaW50QmFja3RyYWNlIHJlbmRlcl9hcz0iYmFja3RyYWNlX2VsZW1lbnQiLz4NCgkJPC9vbD4NCgk8L2lucDI6bV9pZj4NCg0KCTxpbnAyOm1faWZub3QgY2hlY2s9Im1fUGFyYW0iIG5hbWU9ImlzX2xhc3QiPjxoci8+PC9pbnAyOm1faWZub3Q+DQo8L2lucDI6bV9EZWZpbmVFbGVtZW50Pg0KDQo8aW5wMjpzeXN0ZW0tbG9nLmVtYWlsX1ByaW50TGlzdCByZW5kZXJfYXM9InN5c3RlbV9sb2dfZWxlbWVudCIvPg== PGlucDI6bV9EZWZpbmVFbGVtZW50IG5hbWU9ImJhY2t0cmFjZV9wbGFpbl9lbGVtZW50Ij4NCjxpbnAyOkJhY2t0cmFjZUluZGV4Lz4uIDxpbnAyOm1fUGhyYXNlIG5hbWU9ImxhX0xvZ0JhY2t0cmFjZUZ1bmN0aW9uIi8+OiA8aW5wMjptX1BhcmFtIG5hbWU9ImZpbGVfaW5mbyIvPg0KPGlucDI6bV9pZm5vdCBjaGVjaz0ibV9QYXJhbSIgbmFtZT0iaXNfbGFzdCI+DQoNCjwvaW5wMjptX2lmbm90Pg0KPC9pbnAyOm1fRGVmaW5lRWxlbWVudD4NCjxpbnAyOm1fRGVmaW5lRWxlbWVudCBuYW1lPSJzeXN0ZW1fbG9nX3BsYWluX2VsZW1lbnQiPg0KPGlucDI6RmllbGQgbmFtZT0iTG9nVGltZXN0YW1wIiBmb3JtYXQ9Ik0gZCBIOmk6cyIvPiA8aW5wMjpGaWVsZCBuYW1lPSJMb2dIb3N0bmFtZSIvPiA8aW5wMjpSZXF1ZXN0VVJJLz5bUElEPTxpbnAyOkZpZWxkIG5hbWU9IkxvZ1Byb2Nlc3NJZCIvPixVSUQ9PGlucDI6RmllbGQgbmFtZT0iTG9nVW5pcXVlSWQiLz5dDQpbPGlucDI6RmllbGQgbmFtZT0iTG9nTGV2ZWwiLz5dICM8aW5wMjpGaWVsZCBuYW1lPSJMb2dDb2RlIi8+OiA8aW5wMjpGaWVsZCBuYW1lPSJMb2dNZXNzYWdlIiBub19zcGVjaWFsPSIxIi8+IGluIDxpbnAyOkZpbGVuYW1lLz4gb24gbGluZSA8aW5wMjpGaWVsZCBuYW1lPSJMb2dTb3VyY2VGaWxlTGluZSIvPg0KPGlucDI6bV9pZiBjaGVjaz0iRmllbGQiIG5hbWU9IkxvZ0JhY2t0cmFjZSIgZGI9ImRiIj4NCg0KQmFja3RyYWNlOg0KPGlucDI6UHJpbnRCYWNrdHJhY2UgcmVuZGVyX2FzPSJiYWNrdHJhY2VfcGxhaW5fZWxlbWVudCIgc3RyaXBfdGFncz0iMSIvPjwvaW5wMjptX2lmPg0KPGlucDI6bV9pZm5vdCBjaGVjaz0ibV9QYXJhbSIgbmFtZT0iaXNfbGFzdCI+DQotLS0tLS0tLS0tLS0tDQoNCjwvaW5wMjptX2lmbm90Pg0KPC9pbnAyOm1fRGVmaW5lRWxlbWVudD4NCjxpbnAyOnN5c3RlbS1sb2cuZW1haWxfUHJpbnRMaXN0IHJlbmRlcl9hcz0ic3lzdGVtX2xvZ19wbGFpbl9lbGVtZW50Ii8+ SW4tcG9ydGFsIHJlZ2lzdHJhdGlvbg== RGVhciA8aW5wMjp1LnJlZ2lzdGVyX0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIgLz4gPGlucDI6dS5yZWdpc3Rlcl9GaWVsZCBuYW1lPSJMYXN0TmFtZSIgLz4sDQoNClRoYW5rIHlvdSBmb3IgcmVnaXN0ZXJpbmcgb24gPGlucDI6bV9MaW5rIHRlbXBsYXRlPSJpbmRleCIvPi4gWW91ciByZWdpc3RyYXRpb24gaXMgbm93IGFjdGl2ZS4NCjxpbnAyOm1faWYgY2hlY2s9InUucmVnaXN0ZXJfRmllbGQiIG5hbWU9IkVtYWlsIj4NCjxici8+PGJyLz4NClBsZWFzZSBjbGljayBoZXJlIHRvIHZlcmlmeSB5b3VyIEUtbWFpbCBhZGRyZXNzOg0KPGEgaHJlZj0iPGlucDI6dS5yZWdpc3Rlcl9Db25maXJtUGFzc3dvcmRMaW5rIHQ9InBsYXRmb3JtL215X2FjY291bnQvdmVyaWZ5X2VtYWlsIiBub19hbXA9IjEiLz4iPjxpbnAyOnUucmVnaXN0ZXJfQ29uZmlybVBhc3N3b3JkTGluayB0PSJwbGF0Zm9ybS9teV9hY2NvdW50L3ZlcmlmeV9lbWFpbCIgbm9fYW1wPSIxIi8+PC9hPjxici8+PGJyLz4NCjwvaW5wMjptX2lmPg== TmV3IFVzZXIgUmVnaXN0cmF0aW9uICg8aW5wMjp1LnJlZ2lzdGVyX1VzZXJUaXRsZS8+KQ== QSBuZXcgdXNlciAiPGlucDI6dS5yZWdpc3Rlcl9Vc2VyVGl0bGUvPiIgaGFzIGJlZW4gYWRkZWQu TmV3IHVzZXIgaGFzIGJlZW4gY3JlYXRlZA== RGVhciA8aW5wMjp1X0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIvPiwNCg0KQSBuZXcgdXNlciBoYXMgYmVlbiBjcmVhdGVkIGFuZCBhc3NpZ25lZCB0byB5b3UNCg0KTm93IHlvdSBjYW4gbG9naW4gdXNpbmcgdGhlIGZvbGxvd2luZyBjcmVkZW50aWFsczoNCg0KPGlucDI6bV9pZiBjaGVjaz0idV9GaWVsZCIgbmFtZT0iVXNlcm5hbWUiPlVzZXJuYW1lOiA8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+PGlucDI6bV9lbHNlLz5FLW1haWw6IDxpbnAyOnVfRmllbGQgbmFtZT0iRW1haWwiLz48L2lucDI6bV9pZj4gDQpQYXNzd29yZDogPGlucDI6dV9GaWVsZCBuYW1lPSJQYXNzd29yZF9wbGFpbiIvPiANCg== TmV3IFVzZXIgUmVnaXN0cmF0aW9uICg8aW5wMjp1LnJlZ2lzdGVyX1VzZXJUaXRsZS8+PGlucDI6bV9pZiBjaGVjaz0ibV9HZXRDb25maWciIG5hbWU9IlVzZXJfQWxsb3dfTmV3IiBlcXVhbHNfdG89IjQiPiAtIEFjdGl2YXRpb24gRW1haWw8L2lucDI6bV9pZj4p RGVhciA8aW5wMjp1LnJlZ2lzdGVyX0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIgLz4gPGlucDI6dS5yZWdpc3Rlcl9GaWVsZCBuYW1lPSJMYXN0TmFtZSIgLz4sPGJyIC8+DQo8YnIgLz4NCjxpbnAyOm1faWYgY2hlY2s9Im1fR2V0Q29uZmlnIiBuYW1lPSJVc2VyX0FsbG93X05ldyIgZXF1YWxzX3RvPSI0Ij4NCglUaGFuayB5b3UgZm9yIHJlZ2lzdGVyaW5nIG9uIDxpbnAyOm1fTGluayB0ZW1wbGF0ZT0iaW5kZXgiLz4gd2Vic2l0ZS4gVG8gYWN0aXZhdGUgeW91ciByZWdpc3RyYXRpb24gcGxlYXNlIGZvbGxvdyBsaW5rIGJlbG93LiA8aW5wMjp1LnJlZ2lzdGVyX0FjdGl2YXRpb25MaW5rIHRlbXBsYXRlPSJwbGF0Zm9ybS9sb2dpbi9hY3RpdmF0ZV9jb25maXJtIi8+DQo8aW5wMjptX2Vsc2UvPg0KCVRoYW5rIHlvdSBmb3IgcmVnaXN0ZXJpbmcgb24gPGlucDI6bV9MaW5rIHRlbXBsYXRlPSJpbmRleCIvPiB3ZWJzaXRlLiBZb3VyIHJlZ2lzdHJhdGlvbiB3aWxsIGJlIGFjdGl2ZSBhZnRlciBhcHByb3ZhbC4gDQoJDQoJPGlucDI6bV9pZiBjaGVjaz0idS5yZWdpc3Rlcl9GaWVsZCIgbmFtZT0iRW1haWwiPg0KCQk8YnIvPjxici8+DQoJCVBsZWFzZSBjbGljayBoZXJlIHRvIHZlcmlmeSB5b3VyIEUtbWFpbCBhZGRyZXNzOg0KCQk8YSBocmVmPSI8aW5wMjp1LnJlZ2lzdGVyX0NvbmZpcm1QYXNzd29yZExpbmsgdD0icGxhdGZvcm0vbXlfYWNjb3VudC92ZXJpZnlfZW1haWwiIG5vX2FtcD0iMSIvPiI+PGlucDI6dS5yZWdpc3Rlcl9Db25maXJtUGFzc3dvcmRMaW5rIHQ9InBsYXRmb3JtL215X2FjY291bnQvdmVyaWZ5X2VtYWlsIiBub19hbXA9IjEiLz48L2E+PGJyLz48YnIvPg0KCTwvaW5wMjptX2lmPg0KPC9pbnAyOm1faWY+ TmV3IFVzZXIgUmVnaXN0ZXJlZA== QSBuZXcgdXNlciAiPGlucDI6dS5yZWdpc3Rlcl9Vc2VyVGl0bGUvPiIgaGFzIHJlZ2lzdGVyZWQgYW5kIGlzIHBlbmRpbmcgYWRtaW5pc3RyYXRpdmUgYXBwcm92YWwu WW91ciBBY2NvdW50IGlzIEFjdGl2ZQ== V2VsY29tZSB0byA8aW5wMjptX0xpbmsgdGVtcGxhdGU9ImluZGV4Ii8+IQ0KDQpZb3VyIHVzZXIgcmVnaXN0cmF0aW9uIGhhcyBiZWVuIGFwcHJvdmVkLiBZb3VyIHVzZXIgbmFtZSBpczogIjxpbnAyOnVfVXNlclRpdGxlLz4iLg== TmV3IFVzZXIgQWNjb3VudCAiPGlucDI6dV9Vc2VyVGl0bGUvPiIgd2FzIEFwcHJvdmVk VXNlciAiPGlucDI6dV9Vc2VyVGl0bGUvPiIgaGFzIGJlZW4gYXBwcm92ZWQu WW91ciBSZWdpc3RyYXRpb24gaGFzIGJlZW4gRGVuaWVk WW91ciByZWdpc3RyYXRpb24gb24gPGEgaHJlZj0iPGlucDI6bV9MaW5rIHRlbXBsYXRlPSJpbmRleCIvPiI+PGlucDI6bV9MaW5rIHRlbXBsYXRlPSJpbmRleCIvPjwvYT4gd2Vic2l0ZSBoYXMgYmVlbiBkZW5pZWQu VXNlciBSZWdpc3RyYXRpb24gZm9yICAiPGlucDI6dV9Vc2VyVGl0bGUvPiIgaGFzIGJlZW4gRGVuaWVk VXNlciAiPGlucDI6dV9Vc2VyVGl0bGUvPiIgaGFzIGJlZW4gZGVuaWVkLg== Q2hhbmdlZCBFLW1haWwgUm9sbGJhY2s= SGVsbG8sPGJyLz48YnIvPg0KDQpJdCBzZWVtcyB0aGF0IHlvdSBoYXZlIGNoYW5nZWQgZS1tYWlsIGluIHlvdXIgSW4tcG9ydGFsIGFjY291bnQuIFlvdSBtYXkgdW5kbyB0aGlzIGNoYW5nZSBieSBjbGlja2luZyBvbiB0aGUgbGluayBiZWxvdzo8YnIvPjxici8+DQoNCjxhIGhyZWY9IjxpbnAyOnVfVW5kb0VtYWlsQ2hhbmdlTGluayB0ZW1wbGF0ZT0icGxhdGZvcm0vbXlfYWNjb3VudC9yZXN0b3JlX2VtYWlsIi8+Ij48aW5wMjp1X1VuZG9FbWFpbENoYW5nZUxpbmsgdGVtcGxhdGU9InBsYXRmb3JtL215X2FjY291bnQvcmVzdG9yZV9lbWFpbCIvPjwvYT48YnIvPjxici8+DQoNCklmIHlvdSBiZWxpZXZlIHlvdSBoYXZlIHJlY2VpdmVkIHRoaXMgZW1haWwgaW4gZXJyb3IsIHBsZWFzZSBpZ25vcmUgdGhpcyBlbWFpbC4gWW91ciBhY2NvdW50IHdpbGwgYmUgbGlua2VkIHRvIGFub3RoZXIgZS1tYWlsIHVubGVzcyB5b3UgaGF2ZSBjbGlja2VkIG9uIHRoZSBhYm92ZSBsaW5rLg== Q2hhbmdlZCBFLW1haWwgVmVyaWZpY2F0aW9u SGVsbG8sPGJyLz48YnIvPg0KDQpJdCBzZWVtcyB0aGF0IHlvdSBoYXZlIGNoYW5nZWQgZS1tYWlsIGluIHlvdXIgSW4tcG9ydGFsIGFjY291bnQuIFBsZWFzZSB2ZXJpZnkgdGhpcyBuZXcgZS1tYWlsIGJ5IGNsaWNraW5nIG9uIHRoZSBsaW5rIGJlbG93Ojxici8+PGJyLz4NCg0KPGEgaHJlZj0iPGlucDI6dV9Db25maXJtUGFzc3dvcmRMaW5rIHQ9InBsYXRmb3JtL215X2FjY291bnQvdmVyaWZ5X2VtYWlsIiBub19hbXA9IjEiLz4iPjxpbnAyOnVfQ29uZmlybVBhc3N3b3JkTGluayB0PSJwbGF0Zm9ybS9teV9hY2NvdW50L3ZlcmlmeV9lbWFpbCIgbm9fYW1wPSIxIi8+PC9hPjxici8+PGJyLz4NCg0KSWYgeW91IGJlbGlldmUgeW91IGhhdmUgcmVjZWl2ZWQgdGhpcyBlbWFpbCBpbiBlcnJvciwgcGxlYXNlIGlnbm9yZSB0aGlzIGVtYWlsLiBZb3VyIGVtYWlsIHdpbGwgbm90IGdldCB2ZXJpZmllZCBzdGF0dXMgdW5sZXNzIHlvdSBoYXZlIGNsaWNrZWQgb24gdGhlIGFib3ZlIGxpbmsuDQo= TWVtYmVyc2hpcCBFeHBpcmF0aW9uIE5vdGljZQ== WW91ciBtZW1iZXJzaGlwIG9uIDxpbnAyOm1fTGluayB0ZW1wbGF0ZT0iaW5kZXgiLz4gd2Vic2l0ZSB3aWxsIHNvb24gZXhwaXJlLg== TWVtYmVyc2hpcCBFeHBpcmF0aW9uIE5vdGljZSBmb3IgIjxpbnAyOlVzZXJUaXRsZS8+IiBTZW50 VXNlciA8aW5wMjpVc2VyVGl0bGUvPiBtZW1iZXJzaGlwIHdpbGwgZXhwaXJlIHNvb24u WW91ciBNZW1iZXJzaGlwIEV4cGlyZWQ= WW91ciBtZW1iZXJzaGlwIG9uIDxpbnAyOm1fTGluayB0ZW1wbGF0ZT0iaW5kZXgiLz4gd2Vic2l0ZSBoYXMgZXhwaXJlZC4= VXNlcidzIE1lbWJlcnNoaXAgRXhwaXJlZCAoIDxpbnAyOlVzZXJUaXRsZS8+KQ== VXNlcidzICg8aW5wMjpVc2VyVGl0bGUvPikgbWVtYmVyc2hpcCBvbiA8aW5wMjptX0xpbmsgdGVtcGxhdGU9ImluZGV4Ii8+IHdlYnNpdGUgaGFzIGV4cGlyZWQu TmV3IHBhc3N3b3JkIGdlbmVyYXRlZA== RGVhciA8aW5wMjp1X0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIvPiwNCg0KQSBuZXcgcGFzc3dvcmQgaGFzIGJlZW4gZ2VuZXJhdGVkIGZvciB5b3VyIHVzZXIuDQoNCk5vdyB5b3UgY2FuIGxvZ2luIHVzaW5nIHRoZSBmb2xsb3dpbmcgY3JlZGVudGlhbHM6DQoNCjxpbnAyOm1faWYgY2hlY2s9InVfRmllbGQiIG5hbWU9IlVzZXJuYW1lIj5Vc2VybmFtZTogPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPjxpbnAyOm1fZWxzZS8+RS1tYWlsOiA8aW5wMjp1X0ZpZWxkIG5hbWU9IkVtYWlsIi8+PC9pbnAyOm1faWY+IA0KUGFzc3dvcmQ6IDxpbnAyOnVfRmllbGQgbmFtZT0iUGFzc3dvcmRfcGxhaW4iLz4g UmVzZXQgUGFzc3dvcmQgQ29uZmlybWF0aW9u SGVsbG8sPGJyLz48YnIvPg0KDQpJdCBzZWVtcyB0aGF0IHlvdSBoYXZlIHJlcXVlc3RlZCBhIHBhc3N3b3JkIHJlc2V0IGZvciB5b3VyIEluLXBvcnRhbCBhY2NvdW50LiBJZiB5b3Ugd291bGQgbGlrZSB0byBwcm9jZWVkIGFuZCBjaGFuZ2UgdGhlIHBhc3N3b3JkLCBwbGVhc2UgY2xpY2sgb24gdGhlIGxpbmsgYmVsb3c6PGJyLz48YnIvPg0KDQo8YSBocmVmPSI8aW5wMjp1X0NvbmZpcm1QYXNzd29yZExpbmsgbm9fYW1wPSIxIi8+Ij48aW5wMjp1X0NvbmZpcm1QYXNzd29yZExpbmsgbm9fYW1wPSIxIi8+PC9hPjxici8+PGJyLz4NCg0KWW91IHdpbGwgcmVjZWl2ZSBhIHNlY29uZCBlbWFpbCB3aXRoIHlvdXIgbmV3IHBhc3N3b3JkIHNob3J0bHkuPGJyLz48YnIvPg0KDQpJZiB5b3UgYmVsaWV2ZSB5b3UgaGF2ZSByZWNlaXZlZCB0aGlzIGVtYWlsIGluIGVycm9yLCBwbGVhc2UgaWdub3JlIHRoaXMgZW1haWwuIFlvdXIgcGFzc3dvcmQgd2lsbCBub3QgYmUgY2hhbmdlZCB1bmxlc3MgeW91IGhhdmUgY2xpY2tlZCBvbiB0aGUgYWJvdmUgbGluay4NCg== U3Vic2NyaWJlZCB0byBhIE1haWxpbmcgTGlzdCBvbiA8aW5wMjptX0xpbmsgdGVtcGxhdGU9ImluZGV4Ii8+ WW91IGhhdmUgc3Vic2NyaWJlZCB0byBhIG1haWxpbmcgbGlzdCBvbiA8aW5wMjptX0xpbmsgdGVtcGxhdGU9ImluZGV4Ii8+IHdlYnNpdGUu TmV3IFVzZXIgaGFzIFN1YnNjcmliZWQgdG8gYSBNYWxsaW5nIExpc3Q= TmV3IHVzZXIgPGlucDI6RmllbGQgbmFtZT0iRW1haWwiLz4gaGFzIHN1YnNjcmliZWQgdG8gYSBtYWlsaW5nIGxpc3Qgb24gPGEgaHJlZj0iPGlucDI6bV9MaW5rIHRlbXBsYXRlPSJpbmRleCIvPiI+PGlucDI6bV9MaW5rIHRlbXBsYXRlPSJpbmRleCIvPjwvYT4gd2Vic2l0ZS4= Q2hlY2sgb3V0IHRoaXMgV2Vic2l0ZQ== SGVsbG8sPC9icj48L2JyPg0KDQpUaGlzIG1lc3NhZ2UgaGFzIGJlZW4gc2VudCB0byB5b3UgZnJvbSBvbmUgb2YgeW91ciBmcmllbmRzLjwvYnI+PC9icj4NCkNoZWNrIG91dCB0aGlzIHNpdGU6IDxhIGhyZWY9IjxpbnAyOm1fTGluayB0ZW1wbGF0ZT0iaW5kZXgiLz4iPjxpbnAyOm1fTGluayB0ZW1wbGF0ZT0iaW5kZXgiLz48L2E+IQ== V2Vic2l0ZSBTdWdnZXN0ZWQgdG8gYSBGcmllbmQ= QSB2aXNpdG9yIHN1Z2dlc3RlZCA8YSBocmVmPSI8aW5wMjptX0xpbmsgdGVtcGxhdGU9ImluZGV4Ii8+Ij48aW5wMjptX0xpbmsgdGVtcGxhdGU9ImluZGV4Ii8+PC9hPiB3ZWJzaXRlIHRvIGEgZnJpZW5kLg== WW91IGhhdmUgYmVlbiB1bnN1YnNjcmliZWQ= WW91IGhhdmUgc3VjY2Vzc2Z1bGx5IHVuc3Vic2NyaWJlZCBmcm9tIHRoZSBtYWlsaW5nIGxpc3Qgb24gPGEgaHJlZj0iPGlucDI6bV9CYXNlVXJsIC8+Ij48aW5wMjptX0Jhc2VVcmwgLz48L2E+IHdlYnNpdGUu VXNlciBVbnN1YnNyaWJlZCBmcm9tIE1haWxpbmcgTGlzdA== QSB1c2VyICI8aW5wMjpGaWVsZCBuYW1lPSJFbWFpbCIvPiIgaGFzIHVuc3Vic2NyaWJlZCBmcm9tIHRoZSBtYWlsaW5nIGxpc3Qgb24gPGEgaHJlZj0iPGlucDI6bV9MaW5rIHRlbXBsYXRlPSJpbmRleCIvPiI+PGlucDI6bV9MaW5rIHRlbXBsYXRlPSJpbmRleCIvPjwvYT4u VXNlciBSZWdpc3RyYXRpb24gaXMgVmFsaWRhdGVk V2VsY29tZSB0byBJbi1wb3J0YWwhPGJyLz48YnIvPg0KDQpZb3VyIHVzZXIgcmVnaXN0cmF0aW9uIGhhcyBiZWVuIGFwcHJvdmVkLiBZb3UgY2FuIGxvZ2luIG5vdyA8YSBocmVmPSI8aW5wMjptX0xpbmsgdGVtcGxhdGU9ImluZGV4Ii8+Ij48aW5wMjptX0xpbmsgdGVtcGxhdGU9ImluZGV4Ii8+PC9hPiB1c2luZyB0aGUgZm9sbG93aW5nIGluZm9ybWF0aW9uOjxici8+PGJyLz4NCg0KPT09PT09PT09PT09PT09PT09PGJyLz4NClVzZXJuYW1lOiAiPGlucDI6dV9Vc2VyVGl0bGUvPiI8YnIvPg0KUGFzc3dvcmQ6ICI8aW5wMjp1X0ZpZWxkIG5hbWU9IlBhc3N3b3JkX3BsYWluIi8+Ijxici8+DQo9PT09PT09PT09PT09PT09PT08YnIvPjxici8+DQo= TmV3IFVzZXIgUmVnaXN0cmF0aW9uIGlzIFZhbGlkYXRlZA== VXNlciAiPGlucDI6dV9Vc2VyVGl0bGUvPiIgaGFzIGJlZW4gdmFsaWRhdGVkLg== Index: branches/5.3.x/.htaccess =================================================================== --- branches/5.3.x/.htaccess (revision 16599) +++ branches/5.3.x/.htaccess (revision 16600) @@ -1,71 +1,81 @@ ### File security # Exclude direct access to tpl, tpl.xml, inc.php, sql extensions # order allow,deny deny from all satisfy all ExpiresActive on - ExpiresByType text/css "access plus 1 month" + ExpiresByType text/css "a`ccess plus 1 month" ExpiresByType application/x-javascript "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/png "access plus 1 month" + ExpiresByType image/svg+xml "access plus 1 month" ExpiresByType image/x-icon "access plus 1 month" ExpiresByType image/icon "access plus 1 month" + ExpiresByType application/vnd.ms-fontobject "access plus 1 month" + ExpiresByType application/x-font-opentype "access plus 1 month" + ExpiresByType application/x-font-ttf "access plus 1 month" + ExpiresByType application/font-woff "access plus 1 month" ## Tell PHP that the mod_rewrite module is ENABLED. SetEnv HTTP_MOD_REWRITE On ## Enable mod-rewrite RewriteEngine On ###### Rewrite rule to force 'www.' prefix. Use only if needed # If your site can be accessed both with and without the 'www.' prefix, # use the following setting to redirect all users to access the site with the 'www.' # when they access without 'www.'. Uncomment and MAKE sure to adapt for your domain name # # RewriteCond %{HTTP_HOST} ^example\.com$ [NC] # RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301] ###### Rewrite rules to block common hacks ## If you experience problems comment out the operations listed below ## Block out any script trying to base64_encode crap to send via URL RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [OR] ## Block out any script that includes a