Index: core/units/logs/module_deployment_logs/module_deployment_log_eh.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/units/logs/module_deployment_logs/module_deployment_log_eh.php (revision ) +++ core/units/logs/module_deployment_logs/module_deployment_log_eh.php (revision ) @@ -0,0 +1,54 @@ + Array ('self' => true), + 'OnGetOutput' => Array ('self' => 'edit'), + ); + + $this->permMapping = array_merge($this->permMapping, $permissions); + } + + /** + * Returns HTML of deployment output for iframe + * + * @param kEvent $event + * @return void + * @access protected + */ + protected function OnGetOutput(kEvent $event) + { + $event->status = kEvent::erSTOP; + + $object = $event->getObject(); + /* @var $object kDBItem */ + + echo '' . nl2br($object->GetDBField('Output')) . ''; + } +} Index: core/kernel/db/db_load_balancer.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/kernel/db/db_load_balancer.php (revision 15931) +++ core/kernel/db/db_load_balancer.php (revision ) @@ -27,10 +27,10 @@ /** * Function to handle sql errors * - * @var string - * @access public + * @var mixed + * @access protected */ - public $errorHandler = ''; + protected $errorHandler = ''; /** * Database connection settings @@ -116,16 +116,30 @@ * Creates new instance of load balancer class * * @param string $db_type - * @param Array|string $error_handler + * @param mixed $error_handler */ function __construct($db_type, $error_handler = '') { parent::__construct(); $this->dbType = $db_type; - $this->errorHandler = $error_handler; + $this->setErrorHandler($error_handler); $this->DBClusterTimeout *= 1e6; // convert to milliseconds + } + + /** + * Sets new error handler. + * + * @param mixed $error_handler Error handler. + * + * @return self + */ + public function setErrorHandler($error_handler) + { + $this->errorHandler = $error_handler; + + return $this; } /** Index: core/kernel/constants.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/kernel/constants.php (revision 15944) +++ core/kernel/constants.php (revision ) @@ -219,4 +219,17 @@ class TranslationSaveMode { const SYNC_WITH_PRIMARY = 1; const MAKE_PRIMARY = 2; - } \ No newline at end of file + } + + class ModuleDeploymentLog { + + const MODE_AUTOMATIC = 1; + + const MODE_MANUAL = 2; + + const STATUS_SUCCESS = 1; + + const STATUS_ERROR = 2; + + const STATUS_SKIPPED = 3; + } Index: core/install/install_schema.sql IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/install/install_schema.sql (revision 15945) +++ core/install/install_schema.sql (revision ) @@ -208,10 +208,26 @@ TemplatePath varchar(255) NOT NULL DEFAULT '', RootCat int(11) NOT NULL DEFAULT '0', BuildDate int(10) unsigned DEFAULT NULL, - AppliedDBRevisions text, PRIMARY KEY (`Name`), KEY Loaded (Loaded), KEY LoadOrder (LoadOrder) +); + +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) ); CREATE TABLE UserPersistentSessionData ( \ No newline at end of file Index: core/install/remove_schema.sql IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/install/remove_schema.sql (revision 15908) +++ core/install/remove_schema.sql (revision ) @@ -8,6 +8,7 @@ DROP TABLE IdGenerator; DROP TABLE Languages; DROP TABLE Modules; +DROP TABLE ModuleDeploymentLog; DROP TABLE UserPersistentSessionData; DROP TABLE LanguageLabels; DROP TABLE PhraseCache; Index: core/admin_templates/logs/module_deployment_logs/module_deployment_log_edit.tpl IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/admin_templates/logs/module_deployment_logs/module_deployment_log_edit.tpl (revision ) +++ core/admin_templates/logs/module_deployment_logs/module_deployment_log_edit.tpl (revision ) @@ -0,0 +1,74 @@ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+
+ + Index: core/units/modules/modules_config.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/units/modules/modules_config.php (revision 15908) +++ core/units/modules/modules_config.php (revision ) @@ -48,16 +48,26 @@ 'PermSection' => Array ('main' => 'in-portal:mod_status'), 'Sections' => Array ( - 'in-portal:mod_status' => Array ( + 'in-portal:modules_folder' => Array ( 'parent' => 'in-portal:website_setting_folder', 'icon' => 'conf_modules', 'label' => 'la_title_Module_Status', - 'url' => Array ('t' => 'modules/modules_list', 'pass' => 'm'), - 'permissions' => Array ('view', 'edit', 'advanced:approve', 'advanced:decline'), + 'use_parent_header' => 1, + 'permissions' => Array (), 'priority' => 12, 'type' => stTREE, ), + 'in-portal:mod_status' => Array ( + 'parent' => 'in-portal:modules_folder', + 'icon' => 'conf_modules', + 'label' => 'la_title_Module_Status', + 'url' => Array ('t' => 'modules/modules_list', 'pass' => 'm'), + 'permissions' => Array ('view', 'edit', 'advanced:approve', 'advanced:decline'), + 'priority' => 12.1, + 'type' => stTAB, + ), + // "Configuration" -> "Modules and Settings" /*'in-portal:tag_library' => Array ( 'parent' => 'in-portal:modules', @@ -94,7 +104,6 @@ 'TemplatePath' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''), 'RootCat' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'BuildDate' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => null), - 'AppliedDBRevisions' => Array ('type' => 'string', 'default' => NULL) ), 'Grids' => Array ( \ No newline at end of file Index: core/admin_templates/modules/modules_tabs.tpl IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/admin_templates/modules/modules_tabs.tpl (revision ) +++ core/admin_templates/modules/modules_tabs.tpl (revision ) @@ -0,0 +1,5 @@ + + + + + Index: core/install/upgrades.sql IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/install/upgrades.sql (revision 15945) +++ core/install/upgrades.sql (revision ) @@ -2961,3 +2961,24 @@ 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); Index: core/kernel/db/db_connection.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/kernel/db/db_connection.php (revision 15931) +++ core/kernel/db/db_connection.php (revision ) @@ -63,10 +63,10 @@ /** * Function to handle sql errors * - * @var Array|string - * @access public + * @var mixed + * @access protected */ - public $errorHandler = ''; + protected $errorHandler = ''; /** * Error code @@ -147,7 +147,7 @@ * db type to used in future * * @param string $db_type - * @param string $error_handler + * @param mixed $error_handler * @param int $server_index * @access public */ @@ -159,15 +159,22 @@ } $this->serverIndex = $server_index; - - if ( !$error_handler ) { - $this->errorHandler = Array(&$this, 'handleError'); + $this->setErrorHandler($error_handler ? $error_handler : array(&$this, 'handleError')); + $this->_captureStatistics = defined('DBG_CAPTURE_STATISTICS') && DBG_CAPTURE_STATISTICS && !(defined('ADMIN') && ADMIN); - } + } - else { + + /** + * Sets new error handler. + * + * @param mixed $error_handler Error handler. + * + * @return self + */ + public function setErrorHandler($error_handler) + { - $this->errorHandler = $error_handler; + $this->errorHandler = $error_handler; - } - $this->_captureStatistics = defined('DBG_CAPTURE_STATISTICS') && DBG_CAPTURE_STATISTICS && !(defined('ADMIN') && ADMIN); + return $this; } /** Index: core/admin_templates/logs/module_deployment_logs/module_deployment_log_list.tpl IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/admin_templates/logs/module_deployment_logs/module_deployment_log_list.tpl (revision ) +++ core/admin_templates/logs/module_deployment_logs/module_deployment_log_list.tpl (revision ) @@ -0,0 +1,58 @@ + + + + + + + + + + +
+ + + + + + +
+ +
+
+ + + + + + Index: core/install/upgrades.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/install/upgrades.php (revision 15945) +++ core/install/upgrades.php (revision ) @@ -1,6 +1,6 @@ updateDeploymentLog(); } + } + + /** + * Upgrades project deployment log. + * + * @return void + */ + protected function updateDeploymentLog() + { + $log = $this->Application->recallObject('module-deployment-log', null, array('skip_autoload' => true)); + /* @var $log kDBItem */ + + $table_name = $this->Application->getUnitConfig('mod')->getTableName(); + $structure = $this->Conn->Query('DESCRIBE ' . $table_name, 'Field'); + + if ( !isset($structure['AppliedDBRevisions']) ) { + return; + } + + $sql = 'SELECT Name, Path, AppliedDBRevisions + FROM ' . $table_name . ' + WHERE COALESCE(AppliedDBRevisions, "") <> ""'; + $modules = $this->Conn->Query($sql, 'Name'); + + foreach ( $modules as $module_name => $module_data ) { + $filename = FULL_PATH . DIRECTORY_SEPARATOR . $module_data['Path'] . 'install/project_upgrades.sql'; + + if ( !file_exists($filename) ) { + continue; + } + + $sqls = file_get_contents($filename); + preg_match_all("/# r([\d]+)([^\:]*):(.*?)(\n|$)/s", $sqls, $matches, PREG_SET_ORDER + PREG_OFFSET_CAPTURE); + + if ( !$matches ) { + continue; + } + + $revisions = array_flip(explode(',', $module_data['AppliedDBRevisions'])); + + foreach ( $matches as $match ) { + $revision_number = $match[1][0]; + + if ( !isset($revisions[$revision_number]) ) { + continue; + } + + $log->Clear(); + $log->SetDBField('Module', $module_name); + $log->SetDBField('RevisionNumber', $revision_number); + $log->SetDBField('RevisionTitle', trim($match[3][0])); + $log->SetDBField('IPAddress', '0.0.0.0'); + $log->SetDBField('Output', 'IMPORTED'); + $log->Create(); + } + } + + $sql = 'ALTER TABLE ' . $table_name . ' DROP AppliedDBRevisions'; + $this->Conn->Query($sql); } } \ No newline at end of file Index: core/units/helpers/deployment_helper.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/units/helpers/deployment_helper.php (revision 15928) +++ core/units/helpers/deployment_helper.php (revision ) @@ -17,79 +17,83 @@ class DeploymentHelper extends kHelper { /** - * How many symbols from sql should be shown + * How many symbols from sql should be shown. */ const SQL_TRIM_LENGTH = 120; /** - * Name of module, that is processed right now + * Name of module, that is processed right now. * * @var string - * @access private */ private $moduleName = ''; /** - * List of sqls, associated with each revision (from project_upgrades.sql file) + * List of sqls, associated with each revision (from project_upgrades.sql file). * - * @var Array - * @access private + * @var array */ - private $revisionSqls = Array (); + private $revisionSqls = array(); /** - * List of revision titles as user typed them (from project_upgrades.sql file) - * @var Array + * List of revision titles as user typed them (from project_upgrades.sql file). + * + * @var array */ - private $revisionTitles = Array (); + private $revisionTitles = array(); /** - * Revision dependencies + * Revision dependencies. * - * @var Array - * @access private + * @var array */ - private $revisionDependencies = Array (); + private $revisionDependencies = array(); /** - * Numbers of revisions, that were already applied + * Numbers of revisions, that were already applied. * - * @var Array - * @access private + * @var array */ - private $appliedRevisions = Array (); + private $appliedRevisions = array(); /** - * Don't change database, but only check syntax of project_upgrades.sql file and mark all revisions discovered as applied + * Don't change database, but only check syntax of project_upgrades.sql file and mark all revisions discovered as applied. * - * @var bool - * @access private + * @var boolean */ private $dryRun = false; /** - * Remembers script invocation method + * Remembers script invocation method. * - * @var bool - * @access public + * @var boolean */ public $isCommandLine = false; /** - * IP Address of script invoker + * IP Address of script invoker. * * @var string */ public $ip = ''; /** - * Event, that triggered deployment + * Event, that triggered deployment. * * @var kEvent - * @access private */ private $_event; + /** + * Field values for log record. + * + * @var string + */ + private $logData = array(); + + /** + * Creates class instance. + */ public function __construct() { parent::__construct(); @@ -108,11 +112,11 @@ } /** - * Sets event, associated with deployment + * Sets event, associated with deployment. * - * @param kEvent $event + * @param kEvent $event Event. + * * @return void - * @access public */ public function setEvent(kEvent $event) { @@ -120,64 +124,45 @@ } /** - * Adds message to script execution log + * Adds message to script execution log. * - * @param string $message - * @param bool $new_line - * @return void - * @access private + * @param string $message Message. + * @param boolean $new_line Jump to next line. + * + * @return string */ private function toLog($message, $new_line = true) { - $log_file = (defined('RESTRICTED') ? RESTRICTED : WRITEABLE) . '/project_upgrades.log'; + if ( $new_line ) { + $message .= PHP_EOL; + } - $fp = fopen($log_file, 'a'); - fwrite($fp, $message . ($new_line ? "\n" : '')); - fclose($fp); + $this->logData['Output'] .= $message; - chmod($log_file, 0666); + return $message; } /** - * Loads already applied revisions list of current module + * Loads already applied revisions list of current module. * - * @return void - * @access private + * @return self */ private function loadAppliedRevisions() { - $sql = 'SELECT AppliedDBRevisions - FROM ' . TABLE_PREFIX . 'Modules - WHERE Name = ' . $this->Conn->qstr($this->moduleName); - $revisions = $this->Conn->GetOne($sql); + $sql = 'SELECT RevisionNumber + FROM ' . TABLE_PREFIX . 'ModuleDeploymentLog + WHERE Module = ' . $this->Conn->qstr($this->moduleName); + $this->appliedRevisions = array_flip($this->Conn->GetCol($sql)); - $this->appliedRevisions = $revisions ? explode(',', $revisions) : Array (); + return $this; } /** - * Saves applied revision numbers to current module record + * Deploys changes from all installed modules. * - * @return void - * @access private - */ - private function saveAppliedRevisions() - { - // maybe optimize - sort($this->appliedRevisions); - - $fields_hash = Array ( - 'AppliedDBRevisions' => implode(',', $this->appliedRevisions), - ); - - $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Modules', '`Name` = ' . $this->Conn->qstr($this->moduleName)); - } - - /** - * Deploys changes from all installed modules + * @param boolean $dry_run Use dry run mode? * - * @param bool $dry_run - * @return bool - * @access public + * @return boolean */ public function deployAll($dry_run = false) { @@ -188,9 +173,7 @@ $ret = true; $this->dryRun = $dry_run; - $this->toLog(PHP_EOL . '[' . date('Y-m-d H:i:s') . '] === ' . $this->ip . ' ==='); - - foreach ($this->Application->ModuleInfo as $module_name => $module_info) { + foreach ( $this->Application->ModuleInfo as $module_name => $module_info ) { $this->moduleName = $module_name; if ( !file_exists($this->getModuleFile('project_upgrades.sql')) ) { @@ -214,10 +197,9 @@ } /** - * Runs user-specific shell script when deployment happens from Web + * Runs user-specific shell script when deployment happens from Web. * * @return string - * @access protected */ protected function _runShellScript() { @@ -226,7 +208,7 @@ } $wrapper_script = '/usr/local/bin/guest2host_server.sh'; - $script_name = FULL_PATH .'/tools/' . ($this->dryRun ? 'synchronize.sh' : 'deploy.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); @@ -238,11 +220,11 @@ } /** - * Deploys pending changes to a site + * Deploys pending changes to a site. * - * @param string $module_name - * @return bool - * @access private + * @param string $module_name Module name. + * + * @return boolean */ private function deploy($module_name) { @@ -265,10 +247,9 @@ } /** - * Import latest languagepack (without overwrite) + * Import latest language pack (without overwrite). * - * @return void - * @access private + * @return self */ private function importLanguagePack() { @@ -279,13 +260,14 @@ $filename = $this->getModuleFile('english.lang'); $language_import_helper->performImport($filename, '|0|1|2|', $this->moduleName); $this->displayStatus('OK'); + + return $this; } /** - * Exports latest language pack + * Exports latest language pack. * - * @return void - * @access private + * @return self */ private function exportLanguagePack() { @@ -302,13 +284,14 @@ /* @var $language_import_helper LanguageImportHelper */ $language_import_helper->performExport(EXPORT_PATH . '/' . $this->moduleName . '.lang', '|0|1|2|', $languages, '|' . $this->moduleName . '|'); + + return $this; } /** - * Resets unit and section cache + * Resets unit and section cache. * - * @return void - * @access private + * @return self */ private function resetCaches() { @@ -326,31 +309,33 @@ $this->out('Resetting ModRewrite Cache ... '); $this->_event->CallSubEvent('OnResetModRwCache'); $this->displayStatus('OK'); + + return $this; } /** - * Rebuild theme files + * Rebuild theme files. * - * @return void - * @access private + * @return self */ private function refreshThemes() { $this->out('Refreshing Theme Files ... '); $this->_event->CallSubEvent('OnRebuildThemes'); $this->displayStatus('OK'); + + return $this; } /** - * Runs database upgrade script + * Runs database upgrade script. * - * @return bool - * @access private + * @return boolean */ private function upgradeDatabase() { $this->loadAppliedRevisions(); - $this->Conn->errorHandler = Array (&$this, 'handleSqlError'); + $this->Conn->setErrorHandler(array(&$this, 'handleSqlError')); $this->out('Verifying Database Revisions ... '); @@ -360,17 +345,13 @@ $this->displayStatus('OK'); - $applied = $this->applyRevisions(); - $this->saveAppliedRevisions(); - - return $applied; + return $this->applyRevisions(); } /** * Collects database revisions from "project_upgrades.sql" file. * - * @return bool - * @access private + * @return boolean */ private function collectDatabaseRevisions() { @@ -381,7 +362,7 @@ } $sqls = file_get_contents($filename); - preg_match_all("/# r([\d]+)([^\:]*):.*?(\n|$)/s", $sqls, $matches, PREG_SET_ORDER + PREG_OFFSET_CAPTURE); + 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'); @@ -389,7 +370,7 @@ return false; } - foreach ($matches as $index => $match) { + foreach ( $matches as $index => $match ) { $revision = $match[1][0]; if ( $this->revisionApplied($revision) ) { @@ -410,16 +391,16 @@ $revision_sqls = substr($sqls, $start_pos, $end_pos - $start_pos); if ( !$revision_sqls ) { - // resision without sqls + // revision without sqls continue; } - $this->revisionTitles[$revision] = trim($match[0][0]); + $this->revisionTitles[$revision] = trim($match[3][0]); $this->revisionSqls[$revision] = $revision_sqls; - $revision_lependencies = $this->parseRevisionDependencies($match[2][0]); + $revision_dependencies = $this->parseRevisionDependencies($match[2][0]); - if ( $revision_lependencies ) { - $this->revisionDependencies[$revision] = $revision_lependencies; + if ( $revision_dependencies ) { + $this->revisionDependencies[$revision] = $revision_dependencies; } } @@ -430,17 +411,16 @@ } /** - * Checks that all dependent revisions are either present now OR were applied before + * Checks that all dependent revisions are either present now OR were applied before. * - * @return bool - * @access private + * @return boolean */ private function checkRevisionDependencies() { - foreach ($this->revisionDependencies as $revision => $revision_dependencies) { + foreach ( $this->revisionDependencies as $revision => $revision_dependencies ) { - foreach ($revision_dependencies as $revision_dependency) { + foreach ( $revision_dependencies as $revision_dependency ) { if ( $this->revisionApplied($revision_dependency) ) { - // revision dependend upon already applied -> depencency fulfilled + // revision dependent upon already applied -> dependency fulfilled continue; } @@ -462,10 +442,9 @@ } /** - * Runs all pending sqls + * Runs all pending sqls. * - * @return bool - * @access private + * @return boolean */ private function applyRevisions() { @@ -474,14 +453,21 @@ } if ( $this->dryRun ) { - $this->appliedRevisions = array_merge($this->appliedRevisions, array_keys($this->revisionSqls)); + 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); + } + return true; } $this->out('Upgrading Database ... ', true); - foreach ($this->revisionSqls as $revision => $sqls) { + 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 @@ -490,34 +476,32 @@ $sqls = explode(";\n", $no_comment_sqls . "\n"); // ensures that last sql won't have ";" in it $sqls = array_map('trim', $sqls); + $this->initLog($revision); + - foreach ($sqls as $sql) { + foreach ( $sqls as $sql ) { if ( substr($sql, 0, 1) == '#' ) { // output comment as is - $this->toLog($sql); - echo $this->colorText($sql, 'purple') . PHP_EOL; + echo $this->toLog($this->colorText($sql, 'purple')); + continue; } elseif ( $sql ) { - $this->toLog($sql . ' ... ', false); - $escaped_sql = $this->isCommandLine ? $sql : kUtil::escape($sql); - echo mb_substr(trim(preg_replace('/(\n|\t| )+/is', ' ', $escaped_sql)), 0, self::SQL_TRIM_LENGTH) . ' ... '; - + echo $this->toLog($this->shortenQuery($sql), false); $this->Conn->Query($sql); if ( $this->Conn->hasError() ) { // consider revisions with errors applied - $this->appliedRevisions[] = $revision; + $this->saveLog(ModuleDeploymentLog::STATUS_ERROR); return false; } else { - $this->toLog('OK (' . $this->Conn->getAffectedRows() . ')'); - $this->displayStatus('OK (' . $this->Conn->getAffectedRows() . ')'); + $this->displayStatus('OK (' . $this->Conn->getAffectedRows() . ')', true, true); } } } - $this->appliedRevisions[] = $revision; + $this->saveLog(ModuleDeploymentLog::STATUS_SUCCESS); } echo PHP_EOL; @@ -526,56 +510,104 @@ } /** - * Error handler for sql errors + * Returns shortened version of SQL query. * - * @param int $code - * @param string $msg - * @param string $sql - * @return bool - * @access public + * @param string $sql SQL query. + * + * @return string */ - public function handleSqlError($code, $msg, $sql) + protected function shortenQuery($sql) { - $this->toLog('FAILED' . PHP_EOL . 'SQL Error #' . $code . ': ' . $msg); + $escaped_sql = $this->isCommandLine ? $sql : kUtil::escape($sql); + $single_line_sql = preg_replace('/(\n|\t| )+/is', ' ', $escaped_sql); - $this->displayStatus('FAILED' . PHP_EOL . 'SQL Error #' . $code . ': ' . $msg); - $this->out('Please execute rest of SQLs in this Revision by hand and run deployment script again.', true); + return mb_substr(trim($single_line_sql), 0, self::SQL_TRIM_LENGTH) . ' ... '; + } - return true; + /** + * 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; } /** - * Checks if given revision was already applied + * Creates log record. * - * @param int $revision - * @return bool - * @access private + * @param integer $status Status. + * + * @return self */ - private function revisionApplied($revision) + private function saveLog($status) { - foreach ($this->appliedRevisions as $applied_revision) { - // revision range - $applied_revision = explode('-', $applied_revision, 2); + $this->logData['Status'] = $status; - if ( !isset($applied_revision[1]) ) { - // convert single revision to revision range - $applied_revision[1] = $applied_revision[0]; + $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; - } + } - if ( $revision >= $applied_revision[0] && $revision <= $applied_revision[1] ) { + /** + * 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 boolean + */ + 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); + - return true; - } + return true; + } - } - return false; + /** + * 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 + * Returns path to given file in current module install folder. * - * @param string $filename + * @param string $filename Filename. + * * @return string - * @access private */ private function getModuleFile($filename) { @@ -585,16 +617,16 @@ } /** - * Extracts revisions from string in format "(1,3,5464,23342,3243)" + * Extracts revisions from string in format "(1,3,5464,23342,3243)". * - * @param string $string - * @return Array - * @access private + * @param string $string Comma-separated revision list. + * + * @return array */ private function parseRevisionDependencies($string) { if ( !$string ) { - return Array (); + return array(); } $string = explode(',', substr($string, 1, -1)); @@ -603,18 +635,18 @@ } /** - * Applies requested color and bold attributes to given text string + * Applies requested color and bold attributes to given text string. * - * @param string $text - * @param string $color - * @param bool $bold + * @param string $text Text. + * @param string $color Color. + * @param boolean $bold Bold flag. + * * @return string - * @access private */ private function colorText($text, $color, $bold = false) { if ( $this->isCommandLine ) { - $color_map = Array ( + $color_map = array( 'black' => 30, // dark gray (in bold) 'blue' => 34, // light blue (in bold) 'green' => 32, // light green (in bold) @@ -628,15 +660,15 @@ 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_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']; @@ -645,30 +677,36 @@ } /** - * Displays last command execution status + * Displays last command execution status. * - * @param string $status_text - * @param bool $new_line - * @return void - * @access private + * @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) + 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); - echo $this->colorText($status_text, $color, false); - - if ( $new_line ) { - echo PHP_EOL; + 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 + * Outputs a text and escapes it if necessary. * - * @param string $text - * @param bool $new_line - * @return void + * @param string $text Text. + * @param boolean $new_line Jump to next line. + * + * @return self */ private function out($text, $new_line = false) { @@ -677,5 +715,8 @@ } echo $text . ($new_line ? PHP_EOL : ''); + + return $this; } + } \ No newline at end of file Index: core/install/install_data.sql IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/install/install_data.sql (revision 15930) +++ core/install/install_data.sql (revision ) @@ -744,6 +744,9 @@ 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\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}', '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";}}', 1375200926, 1, 1); @@ -1036,5 +1039,5 @@ INSERT INTO PromoBlockGroups VALUES (DEFAULT, 'Default Group', UNIX_TIMESTAMP(), '1', '7.00', '0.60', '1', 'fade', ''); -INSERT INTO Modules VALUES ('Core', 'core/', 'Intechnic\\InPortal\\Core', 'adm', DEFAULT, 1, 1, '', 0, NULL, NULL); -INSERT INTO Modules VALUES ('In-Portal', 'core/', 'Intechnic\\InPortal\\Core', 'm', DEFAULT, 1, 0, '', 0, NULL, NULL); \ No newline at end of file +INSERT INTO Modules VALUES ('Core', 'core/', 'Intechnic\\InPortal\\Core', 'adm', DEFAULT, 1, 1, '', 0, NULL); +INSERT INTO Modules VALUES ('In-Portal', 'core/', 'Intechnic\\InPortal\\Core', 'm', DEFAULT, 1, 0, '', 0, NULL); \ No newline at end of file Index: core/install/english.lang IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/install/english.lang (revision 15949) +++ core/install/english.lang (revision ) @@ -566,6 +566,7 @@ TWV0YSBEZXNjcmlwdGlvbg== TWV0YSBLZXl3b3Jkcw== TWlzc3BlbGxlZCBXb3Jk + TW9kZQ== TW9kaWZpZWQ= TW9kdWxl TW9kdWxl @@ -583,6 +584,7 @@ T3B0aW9uIFRpdGxl T3JkZXI= T3RoZXIgUmVjaXBpZW50cw== + T3V0cHV0 T3ZlcndyaXRlIERlZmF1bHQgQ2FjaGluZyBLZXk= UGFjayBOYW1l UGFkZGluZyBCb3R0b20= @@ -647,6 +649,8 @@ UmVxdWlyZSBMb2dpbg== UmVxdWlyZSBTU0w= Q29tbWVudA== + UmV2aXNpb24gTnVtYmVy + UmV2aXNpb24gVGl0bGU= UHJvbW8gUm90YXRpb24gRGVsYXkgKHNlY29uZHMp UnVsZSBUeXBl UnVuIFNjaGVkdWxl @@ -975,6 +979,7 @@ U2VudA== U2VwdGVtYmVy U2lsZW50 + U2tpcHBlZA== U3BhY2U= U3RhdGU= U3ViLW1hdGNo @@ -1448,6 +1453,7 @@ Q1NWIEltcG9ydA== Q3VzdG9t Q3VzdG9tIEZpZWxkcw== + RGVwbG95bWVudA== RWRpdGluZyBBZG1pbmlzdHJhdG9y RWRpdGluZyBCYW4gUnVsZQ== RWRpdGluZyBDaGFuZ2VzIExvZw== @@ -1516,6 +1522,7 @@ U291cmNl TWFpbGluZ3M= TWVzc2FnZXM= + TW9kdWxlIERlcGxveW1lbnQgTG9n TW9kdWxlcw== TmV3IEUtbWFpbCBUZW1wbGF0ZQ== TmV3IEZpbGU= @@ -1581,6 +1588,7 @@ Vmlld2luZyBFbWFpbCBMb2c= Vmlld2luZyBmb3JtIHN1Ym1pc3Npb24= Vmlld2luZyBNYWlsaW5nIExpc3Q= + Vmlld2luZyBNb2R1bGUgRGVwbG95bWVudCBMb2c= Vmlld2luZyBSZXBseQ== Vmlld2luZyBSZXZpc2lvbiAjJXMgKCVzKQ== Vmlld2luZyBTeXN0ZW0gTG9n Index: core/admin_templates/modules/modules_list.tpl IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/admin_templates/modules/modules_list.tpl (revision 15931) +++ core/admin_templates/modules/modules_list.tpl (revision ) @@ -1,5 +1,5 @@ - + \ No newline at end of file Index: core/units/logs/module_deployment_logs/module_deployment_logs_config.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/units/logs/module_deployment_logs/module_deployment_logs_config.php (revision ) +++ core/units/logs/module_deployment_logs/module_deployment_logs_config.php (revision ) @@ -0,0 +1,126 @@ + 'module-deployment-log', + 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'), + 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'), + 'EventHandlerClass' => Array ('class' => 'ModuleDeploymentLogEventHandler', 'file' => 'module_deployment_log_eh.php', 'build_event' => 'OnBuild'), + 'TagProcessorClass' => Array ('class' => 'kDBTagProcessor', 'file' => '', 'build_event' => 'OnBuild'), + + 'AutoLoad' => true, + + 'QueryString' => Array ( + 1 => 'id', + 2 => 'Page', + 3 => 'PerPage', + 4 => 'event', + 5 => 'mode', + ), + + 'IDField' => 'Id', + + 'TableName' => TABLE_PREFIX . 'ModuleDeploymentLog', + + 'TitlePresets' => Array ( + 'default' => Array ( + 'new_status_labels' => Array ('module-deployment-log' => '!la_title_AddingModuleDeploymentLog!'), + 'edit_status_labels' => Array ('module-deployment-log' => '!la_title_ViewingModuleDeploymentLog!'), + ), + + 'module_deployment_log_list' => Array ( + 'prefixes' => Array ('module-deployment-log_List'), 'format' => "!la_title_ModuleDeploymentLog!", + 'toolbar_buttons' => Array ('edit', 'delete', 'cancel', 'view', 'dbl-click'), + ), + + 'module_deployment_log_edit' => Array ( + 'prefixes' => Array ('module-deployment-log'), 'format' => "#module-deployment-log_status#", + 'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'), + ), + ), + + 'PermSection' => Array ('main' => 'in-portal:module_deployment_log'), + + 'Sections' => Array ( + + 'in-portal:module_deployment_log' => Array ( + 'parent' => 'in-portal:modules_folder', + 'icon' => 'conf_modules', + 'label' => 'la_title_Deployment', + 'url' => Array ('t' => 'logs/module_deployment_logs/module_deployment_log_list', 'pass' => 'm'), + 'permissions' => Array ('view', 'edit', 'delete'), + 'priority' => 12.2, // ., because this section replaces parent in tree + 'type' => stTAB, + ), + + ), + + 'ListSQLs' => Array ( + '' => ' SELECT %1$s.* %2$s + FROM %1$s', + ), + + 'ListSortings' => Array ( + '' => Array ( + 'Sorting' => Array ('Id' => 'desc'), + ) + ), + + 'Fields' => Array ( + 'Id' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), + 'Module' => Array ( + 'type' => 'string', 'max_len' => 30, + '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, 'default' => 'In-Portal' + ), + 'RevisionNumber' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), + 'RevisionTitle' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), + 'CreatedOn' => Array ('formatter' => 'kDateFormatter', 'default' => '#NOW#'), + 'IPAddress' => Array ('type' => 'string', 'max_len' => 15, 'not_null' => 1, 'default' => ''), + 'Output' => Array ('type' => 'string', 'default' => NULL), + 'ErrorMessage' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), + 'Mode' => Array ( + 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array ( + ModuleDeploymentLog::MODE_AUTOMATIC => 'la_opt_Automatic', + ModuleDeploymentLog::MODE_MANUAL => 'la_opt_Manual' + ), 'use_phrases' => 1, 'not_null' => 1, 'default' => ModuleDeploymentLog::MODE_AUTOMATIC + ), + 'Status' => Array ( + 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array ( + ModuleDeploymentLog::STATUS_SUCCESS => 'la_opt_Success', + ModuleDeploymentLog::STATUS_ERROR => 'la_opt_Error', + ModuleDeploymentLog::STATUS_SKIPPED => 'la_opt_Skipped' + ), 'use_phrases' => 1, 'not_null' => 1, 'default' => ModuleDeploymentLog::STATUS_SUCCESS + ), + ), + + 'Grids' => Array ( + 'Default' => Array ( + 'Icons' => Array ('default' => 'icon16_item.png'), + 'Fields' => Array ( + 'Id' => Array ('filter_block' => 'grid_range_filter', 'width' => 80), + 'Module' => Array ('filter_block' => 'grid_like_filter'), + 'RevisionNumber' => Array ('filter_block' => 'grid_like_filter'), + 'RevisionTitle' => Array ('filter_block' => 'grid_like_filter'), + 'CreatedOn' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 120), + 'IPAddress' => Array ('filter_block' => 'grid_like_filter'), + 'ErrorMessage' => Array ('filter_block' => 'grid_like_filter'), + 'Mode' => Array ('filter_block' => 'grid_options_filter'), + 'Status' => Array ('filter_block' => 'grid_options_filter') + ), + ), + ), +); Index: core/kernel/db/i_db_connection.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/kernel/db/i_db_connection.php (revision 15922) +++ core/kernel/db/i_db_connection.php (revision ) @@ -21,6 +21,15 @@ interface IDBConnection { /** + * Sets new error handler. + * + * @param mixed $error_handler Error handler. + * + * @return self + */ + public function setErrorHandler($error_handler); + + /** * Checks if previous query execution raised an error. * * @return bool