From ff4eca94c23771f06abb47d94e7484857d4b20e8 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Thu, 26 Feb 2015 09:35:34 +0800 Subject: [PATCH 1/5] * fix a bug. --- module/task/control.php | 1 + 1 file changed, 1 insertion(+) diff --git a/module/task/control.php b/module/task/control.php index f99ab111a5..2f012c27bf 100644 --- a/module/task/control.php +++ b/module/task/control.php @@ -1100,6 +1100,7 @@ class task extends control /* Set related files. */ if(isset($relatedFiles[$task->id])) { + $task->files = ''; foreach($relatedFiles[$task->id] as $file) { $fileURL = 'http://' . $this->server->http_host . $this->config->webRoot . "data/upload/{$this->app->company->id}/" . $file->pathname; From c56d8e69c617749a32510d26c7332b43eadb359e Mon Sep 17 00:00:00 2001 From: wangyidong Date: Sat, 28 Feb 2015 14:56:35 +0800 Subject: [PATCH 2/5] * finish task #2206, 2207. --- config/config.php | 2 + db/update7.0.sql | 44 ++++++ module/backup/control.php | 55 ++++--- module/backup/view/index.html.php | 4 +- module/common/lang/en.php | 4 + module/common/lang/zh-cn.php | 4 + module/common/view/footer.html.php | 1 + module/cron/config.php | 8 + module/cron/control.php | 216 +++++++++++++++++++++++++++ module/cron/lang/zh-cn.php | 46 ++++++ module/cron/model.php | 228 +++++++++++++++++++++++++++++ module/cron/view/create.html.php | 68 +++++++++ module/cron/view/edit.html.php | 68 +++++++++ module/cron/view/index.html.php | 70 +++++++++ module/git/model.php | 39 ++++- module/my/view/index.html.php | 98 ++++++------- module/project/control.php | 6 +- module/svn/model.php | 39 ++++- www/js/my.full.js | 9 ++ 19 files changed, 924 insertions(+), 85 deletions(-) create mode 100644 db/update7.0.sql create mode 100644 module/cron/config.php create mode 100644 module/cron/control.php create mode 100644 module/cron/lang/zh-cn.php create mode 100644 module/cron/model.php create mode 100644 module/cron/view/create.html.php create mode 100644 module/cron/view/edit.html.php create mode 100644 module/cron/view/index.html.php diff --git a/config/config.php b/config/config.php index a6ac4f1c7d..3b810f72df 100644 --- a/config/config.php +++ b/config/config.php @@ -139,6 +139,8 @@ define('TABLE_ACTION', '`' . $config->db->prefix . 'action`'); define('TABLE_FILE', '`' . $config->db->prefix . 'file`'); define('TABLE_HISTORY', '`' . $config->db->prefix . 'history`'); define('TABLE_EXTENSION', '`' . $config->db->prefix . 'extension`'); +define('TABLE_CRON', '`' . $config->db->prefix . 'cron`'); +define('TABLE_MAILQUEUE', '`' . $config->db->prefix . 'mailqueue`'); if(!defined('TABLE_LANG')) define('TABLE_LANG', '`' . $config->db->prefix . 'lang`'); $config->objectTables['product'] = TABLE_PRODUCT; diff --git a/db/update7.0.sql b/db/update7.0.sql new file mode 100644 index 0000000000..8970ce7386 --- /dev/null +++ b/db/update7.0.sql @@ -0,0 +1,44 @@ +REPLACE INTO `zt_config` (`owner`, `module`, `section`, `key`, `value`) VALUES ('system', 'common', 'global', 'cron', '0'); + +DROP TABLE IF EXISTS `zt_cron`; +CREATE TABLE `zt_cron` ( + `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `m` varchar(20) NOT NULL, + `h` varchar(20) NOT NULL, + `dom` varchar(20) NOT NULL, + `mon` varchar(20) NOT NULL, + `dow` varchar(20) NOT NULL, + `command` text NOT NULL, + `remark` varchar(255) NOT NULL, + `type` varchar(20) NOT NULL, + `buildin` tinyint(1) NOT NULL DEFAULT '0', + `status` varchar(20) NOT NULL, + `lastTime` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +TRUNCATE `zt_cron`; +INSERT INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type`, `buildin`, `status`, `lastTime`) VALUES +('*', '*', '*', '*', '*', '', '监控定时任务', 'zentao', 1, 'normal', '0000-00-00 00:00:00'), +('30', '23', '*', '*', '*', 'moduleName=project&methodName=computeburn', '更新燃尽图', 'zentao', 1, 'normal', '0000-00-00 00:00:00'), +('0', '1', '*', '*', '*', 'moduleName=report&methodName=remind', '每日任务提醒', 'zentao', 1, 'normal', '0000-00-00 00:00:00'), +('*/5', '*', '*', '*', '*', 'moduleName=svn&methodName=run', '同步SVN', 'zentao', 1, 'normal', '0000-00-00 00:00:00'), +('*/5', '*', '*', '*', '*', 'moduleName=git&methodName=run', '同步GIT', 'zentao', 1, 'normal', '0000-00-00 00:00:00'), +('30', '0', '*', '*', '*', 'moduleName=backup&methodName=backup', '备份数据和附件', 'zentao', 1, 'normal', '0000-00-00 00:00:00'), +('*/5', '*', '*', '*', '*', 'moduleName=mail&methodName=asyncSend', '异步发信', 'zentao', 1, 'normal', '0000-00-00 00:00:00'); + + +DROP TABLE IF EXISTS `zt_mailqueue`; +CREATE TABLE `zt_mailqueue` ( + `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `toList` varchar(255) NOT NULL, + `ccList` varchar(255) NOT NULL, + `subject` varchar(255) NOT NULL, + `body` text NOT NULL, + `addedBy` char(30) NOT NULL, + `addedDate` datetime NOT NULL, + `sendTime` datetime NOT NULL, + `status` varchar(10) NOT NULL DEFAULT 'wait', + `failReason` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/module/backup/control.php b/module/backup/control.php index 492bf819be..1e4eaec9cd 100644 --- a/module/backup/control.php +++ b/module/backup/control.php @@ -17,9 +17,9 @@ class backup extends control * @access public * @return void */ - public function __construct() + public function __construct($moduleName = '', $methodName = '') { - parent::__construct(); + parent::__construct($moduleName, $methodName); $this->backupPath = $this->app->getTmpRoot() . 'backup/'; if(!is_dir($this->backupPath)) @@ -75,31 +75,52 @@ class backup extends control * @access public * @return void */ - public function backup() + public function backup($reload = 'no') { set_time_limit(0); $fileName = date('YmdHis') . mt_rand(0, 9); $result = $this->backup->backSQL($this->backupPath . $fileName . '.sql.php'); if(!$result->result) { - echo js::alert(sprintf($this->lang->backup->error->noWritable, $this->backupPath)); - die(js::reload('parent')); + if($reload == 'yes') + { + echo js::alert(sprintf($this->lang->backup->error->noWritable, $this->backupPath)); + die(js::reload('parent')); + } + else + { + printf($this->lang->backup->error->noWritable, $this->backupPath); + } } $this->backup->addFileHeader($this->backupPath . $fileName . '.sql.php'); - if(extension_loaded('zlib')) - { - $result = $this->backup->backFile($this->backupPath . $fileName . '.file.zip.php'); - if(!$result->result) - { - echo js::alert(sprintf($this->lang->backup->error->backupFile, $result->error)); - die(js::reload('parent')); - } - $this->backup->addFileHeader($this->backupPath . $fileName . '.file.zip.php'); - } + if(extension_loaded('zlib')) + { + $result = $this->backup->backFile($this->backupPath . $fileName . '.file.zip.php'); + if(!$result->result) + { + if($reload == 'yes') + { + echo js::alert(sprintf($this->lang->backup->error->backupFile, $result->error)); + die(js::reload('parent')); + } + else + { + printf($this->lang->backup->error->backupFile, $result->error); + } + } + $this->backup->addFileHeader($this->backupPath . $fileName . '.file.zip.php'); + } - echo js::alert($this->lang->backup->success->backup); - die(js::reload('parent')); + if($reload == 'yes') + { + echo js::alert($this->lang->backup->success->backup); + die(js::reload('parent')); + } + else + { + echo $this->lang->backup->success->backup . "\n"; + } } /** diff --git a/module/backup/view/index.html.php b/module/backup/view/index.html.php index 76fadcded1..2acf82fbf5 100644 --- a/module/backup/view/index.html.php +++ b/module/backup/view/index.html.php @@ -19,7 +19,7 @@
backup->common;?>
-
+
@@ -47,7 +47,7 @@ 1) echo "rowspan='$rowspan'"?>> name"), $lang->backup->backup, 'hiddenwin', "class='restore'"); + if(common::hasPriv('backup', 'restore')) echo html::a(inlink('restore', "file=$backupFile->name"), $lang->backup->restore, 'hiddenwin', "class='restore'"); if(common::hasPriv('backup', 'delete')) echo html::a(inlink('delete', "file=$backupFile->name"), $lang->delete, 'hiddenwin'); ?> diff --git a/module/common/lang/en.php b/module/common/lang/en.php index b4d8ae6db0..bb15d7ec8b 100644 --- a/module/common/lang/en.php +++ b/module/common/lang/en.php @@ -283,6 +283,7 @@ $lang->admin->menu->custom = array('link' => 'Custom|custom|index', 'subModul $lang->admin->menu->mail = array('link' => 'Email|mail|index', 'subModule' => 'mail'); $lang->admin->menu->convert = array('link' => 'Import|convert|index', 'subModule' => 'convert'); $lang->admin->menu->backup = array('link' => 'Backup|backup|index', 'subModule' => 'backup'); +$lang->admin->menu->cron = array('link' => 'Cron|cron|index', 'subModule' => 'cron'); $lang->admin->menu->trashes = array('link' => 'Trash|action|trash', 'subModule' => 'action'); $lang->convert = new stdclass(); @@ -293,11 +294,13 @@ $lang->extension = new stdclass(); $lang->custom = new stdclass(); $lang->editor = new stdclass(); $lang->mail = new stdclass(); +$lang->cron = new stdclass(); $lang->convert->menu = $lang->admin->menu; $lang->upgrade->menu = $lang->admin->menu; $lang->action->menu = $lang->admin->menu; $lang->backup->menu = $lang->admin->menu; +$lang->cron->menu = $lang->admin->menu; $lang->extension->menu = $lang->admin->menu; $lang->custom->menu = $lang->admin->menu; $lang->editor->menu = $lang->admin->menu; @@ -322,6 +325,7 @@ $lang->menugroup->dept = 'company'; $lang->menugroup->todo = 'my'; $lang->menugroup->action = 'admin'; $lang->menugroup->backup = 'admin'; +$lang->menugroup->cron = 'admin'; $lang->menugroup->extension = 'admin'; $lang->menugroup->custom = 'admin'; $lang->menugroup->editor = 'admin'; diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index 0e78f20a9e..6ab2d88035 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -283,6 +283,7 @@ $lang->admin->menu->custom = array('link' => '自定义|custom|index', 'subMo $lang->admin->menu->mail = array('link' => '发信|mail|index', 'subModule' => 'mail'); $lang->admin->menu->convert = array('link' => '导入|convert|index', 'subModule' => 'convert'); $lang->admin->menu->backup = array('link' => '备份|backup|index', 'subModule' => 'backup'); +$lang->admin->menu->cron = array('link' => '计划任务|cron|index', 'subModule' => 'cron'); $lang->admin->menu->trashes = array('link' => '回收站|action|trash', 'subModule' => 'action'); $lang->convert = new stdclass(); @@ -293,11 +294,13 @@ $lang->extension = new stdclass(); $lang->custom = new stdclass(); $lang->editor = new stdclass(); $lang->mail = new stdclass(); +$lang->cron = new stdclass(); $lang->convert->menu = $lang->admin->menu; $lang->upgrade->menu = $lang->admin->menu; $lang->action->menu = $lang->admin->menu; $lang->backup->menu = $lang->admin->menu; +$lang->cron->menu = $lang->admin->menu; $lang->extension->menu = $lang->admin->menu; $lang->custom->menu = $lang->admin->menu; $lang->editor->menu = $lang->admin->menu; @@ -322,6 +325,7 @@ $lang->menugroup->dept = 'company'; $lang->menugroup->todo = 'my'; $lang->menugroup->action = 'admin'; $lang->menugroup->backup = 'admin'; +$lang->menugroup->cron = 'admin'; $lang->menugroup->extension = 'admin'; $lang->menugroup->custom = 'admin'; $lang->menugroup->editor = 'admin'; diff --git a/module/common/view/footer.html.php b/module/common/view/footer.html.php index 6b6c198d0d..ce9f7884f8 100755 --- a/module/common/view/footer.html.php +++ b/module/common/view/footer.html.php @@ -21,6 +21,7 @@ loadModel('cron')->runable()) js::execute('startCron()'); if(isset($pageJS)) js::execute($pageJS); // load the js for current page. /* Load hook files for current page. */ diff --git a/module/cron/config.php b/module/cron/config.php new file mode 100644 index 0000000000..48d311f2a5 --- /dev/null +++ b/module/cron/config.php @@ -0,0 +1,8 @@ +cron = new stdclass(); +$config->cron->create = new stdclass(); +$config->cron->edit = new stdclass(); +$config->cron->create->requiredFields = 'm,h,dom,mon,dow,command'; +$config->cron->edit->requiredFields = 'm,h,dom,mon,dow,command'; + +$config->cron->maxRunDays = 3; diff --git a/module/cron/control.php b/module/cron/control.php new file mode 100644 index 0000000000..6a644e8919 --- /dev/null +++ b/module/cron/control.php @@ -0,0 +1,216 @@ + + * @package cron + * @version $Id$ + * @link http://www.zentao.net + */ +class cron extends control +{ + /** + * Index page. + * + * @access public + * @return void + */ + public function index() + { + $this->view->title = $this->lang->cron->common; + $this->view->position[] = $this->lang->cron->common; + + $this->view->crons = $this->cron->getCrons(); + $this->display(); + } + + /** + * Turnon cron. + * + * @access public + * @return void + */ + public function turnon() + { + $turnon = $this->config->global->cron ? 0 : 1; + $this->loadModel('setting')->setItem('system.common.global.cron', $turnon); + die(js::reload('parent')); + } + + /** + * Create cron. + * + * @access public + * @return void + */ + public function create() + { + if($_POST) + { + $this->cron->create(); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate(inlink('index'), 'parent')); + } + $this->view->title = $this->lang->cron->create . $this->lang->cron->common; + $this->view->position[] = html::a(inlink('index'), $this->lang->cron->common); + $this->view->position[] = $this->lang->cron->create; + + $this->display(); + } + + /** + * Edit cron. + * + * @param int $cronID + * @access public + * @return void + */ + public function edit($cronID) + { + if($_POST) + { + $this->cron->update($cronID); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate(inlink('index'), 'parent')); + } + $this->view->title = $this->lang->cron->edit . $this->lang->cron->common; + $this->view->position[] = html::a(inlink('index'), $this->lang->cron->common); + $this->view->position[] = $this->lang->cron->edit; + + $this->view->cron = $this->cron->getById($cronID); + $this->display(); + } + + /** + * Toggle run cron. + * + * @param int $cronID + * @param int $status + * @access public + * @return void + */ + public function toggle($cronID, $status) + { + $this->cron->changeStatus($cronID, $status); + die(js::reload('parent')); + } + + /** + * Delete cron. + * + * @param int $cronID + * @param string $confirm + * @access public + * @return void + */ + public function delete($cronID, $confirm = 'no') + { + if($confirm == 'no') die(js::confirm($this->lang->cron->confirmDelete, inlink('delete', "cronID=$cronID&confirm=yes"))); + + $this->dao->delete()->from(TABLE_CRON)->where('id')->eq($cronID)->exec(); + die(js::reload('parent')); + } + + /** + * Ajax exec cron. + * + * @access public + * @return void + */ + public function ajaxExec() + { + ignore_user_abort(true); + set_time_limit(0); + session_write_close(); + /* Check cron turnon. */ + if(!$this->config->global->cron) die(); + + /* make cron status to running. */ + $configID = $this->cron->getConfigID(); + $configID = $this->cron->markCronStatus('running', $configID); + + /* Get and parse crons. */ + $crons = $this->cron->getCrons('nostop'); + $parsedCrons = $this->cron->parseCron($crons); + + /* Update last time. */ + $this->cron->changeStatus(key($parsedCrons), 'normal', true); + $startedTime = time(); + while(true) + { + /* When cron is null then die. */ + if(empty($crons)) die(); + if(empty($parsedCrons)) die(); + + /* Run crons. */ + $now = new datetime('now'); + foreach($parsedCrons as $id => $cron) + { + /* Skip stop and running cron.*/ + $cronInfo = $this->cron->getById($id); + if(empty($cronInfo) or $cronInfo->status == 'stop' or $cronInfo->status == 'running') continue; + + if($now > $cron['time']) + { + $this->cron->changeStatus($id, 'running'); + $parsedCrons[$id]['time'] = $cron['cron']->getNextRunDate(); + + /* Execution command. */ + $output = ''; + $return = ''; + if($cron['command']) + { + if(isset($crons[$id]) and $crons[$id]->type == 'zentao') + { + parse_str($cron['command'], $params); + if(isset($params['moduleName']) and isset($params['methodName'])) + { + $output = $this->fetch($params['moduleName'], $params['methodName']); + } + } + elseif(isset($crons[$id]) and $crons[$id]->type == 'system') + { + exec($cron['command'], $output, $return); + if($output) $output = join("\n", $output); + } + } + + /* Save log. */ + if($output and $this->config->debug) + { + $log = ''; + $time = $now->format('G:i:s'); + $log = "$time task " . $id . " executed,\ncommand: $cron[command].\nreturn : $return.\noutput : $output\n"; + $this->cron->logCron($log); + unset($log); + } + + /* Revert cron status. */ + $this->cron->changeStatus($id, 'normal'); + } + } + + /* Check whether the task change. */ + $newCrons = $this->cron->getCrons('nostop'); + $changed = $this->cron->checkChange(); + if(count($newCrons) != count($crons) or $changed) + { + $crons = $newCrons; + $parsedCrons = $this->cron->parseCron($newCrons); + } + + /* Sleep some seconds. */ + $sleepTime = 60 - ((time() - $now->getTimestamp()) % 60); + sleep($sleepTime); + + /* Break while. */ + if(connection_status() != CONNECTION_NORMAL) break; + if(((time() - $startedTime) / 3600 / 24) >= $this->config->cron->maxRunDays) break; + } + + /* Revert cron status to stop. */ + $this->cron->markCronStatus('stop', $configID); + } +} diff --git a/module/cron/lang/zh-cn.php b/module/cron/lang/zh-cn.php new file mode 100644 index 0000000000..af6da9ef70 --- /dev/null +++ b/module/cron/lang/zh-cn.php @@ -0,0 +1,46 @@ +cron->common = '计划任务'; +$lang->cron->list = '任务列表'; +$lang->cron->create = '添加'; +$lang->cron->edit = '编辑'; +$lang->cron->delete = '删除'; +$lang->cron->toggle = '激活/禁用'; +$lang->cron->turnon = '打开/关闭'; + +$lang->cron->m = '分'; +$lang->cron->h = '小时'; +$lang->cron->dom = '天'; +$lang->cron->mon = '月'; +$lang->cron->dow = '周'; +$lang->cron->command = '命令'; +$lang->cron->status = '状态'; +$lang->cron->type = '任务类型'; +$lang->cron->remark = '备注'; +$lang->cron->lastTime = '最后执行'; + +$lang->cron->turnonList['1'] = '打开'; +$lang->cron->turnonList['0'] = '关闭'; + +$lang->cron->statusList['normal'] = '正常'; +$lang->cron->statusList['running'] = '运行中'; +$lang->cron->statusList['stop'] = '停止'; + +$lang->cron->typeList['zentao'] = '禅道自调用'; +$lang->cron->typeList['system'] = '操作系统命令'; + +$lang->cron->toggleList['start'] = '激活'; +$lang->cron->toggleList['stop'] = '禁用'; + +$lang->cron->confirmDelete = '是否删除该计划任务?'; +$lang->cron->introduction = <<计划任务功能可以定时执行诸如更新燃尽图、备份等操作,免除自己布置定时任务。

+

该功能还有待完善,所以默认关闭该功能

+

是否开启该功能?打开计划任务

+EOD; + +$lang->cron->notice = new stdclass(); +$lang->cron->notice->m = '取值范围:0-59,"*"代表取值范围内的数字,"/"代表"每", "-"代表从数字范围。'; +$lang->cron->notice->h = '取值范围:0-23'; +$lang->cron->notice->dom = '取值范围:1-31'; +$lang->cron->notice->mon = '取值范围:1-12'; +$lang->cron->notice->dow = '取值范围:0-6'; diff --git a/module/cron/model.php b/module/cron/model.php new file mode 100644 index 0000000000..45209170e2 --- /dev/null +++ b/module/cron/model.php @@ -0,0 +1,228 @@ + + * @package cron + * @version $Id$ + * @link http://www.zentao.net + */ +class cronModel extends model +{ + /** + * Get by Id. + * + * @param int $cronID + * @access public + * @return object + */ + public function getById($cronID) + { + return $this->dao->select('*')->from(TABLE_CRON)->where('id')->eq($cronID)->fetch(); + } + + /** + * Get crons. + * + * @param string $params + * @access public + * @return array + */ + public function getCrons($params = '') + { + return $this->dao->select('*')->from(TABLE_CRON) + ->where('1=1') + ->beginIF(strpos($params, 'nostop') !== false)->andWhere('status')->ne('stop')->fi() + ->fetchAll('id'); + } + + /** + * Parse crons. + * + * @param array $crons + * @access public + * @return array + */ + public function parseCron($crons) + { + $this->app->loadClass('crontab', true); + + $parsedCron = array(); + foreach($crons as $cron) + { + $row = "{$cron->m} {$cron->h} {$cron->dom} {$cron->mon} {$cron->dow} {$cron->command}"; + preg_match_all('/(\S+\s+){5}|.*/', $row, $matchs); + if($matchs[0]) + { + try + { + $parsedCron = array(); + $parsedCron['schema'] = trim($matchs[0][0]); + $parsedCron['command'] = trim($matchs[0][1]); + $parsedCron['cron'] = CronExpression::factory($parsedCron['schema']); + $parsedCron['time'] = $parsedCron['cron']->getNextRunDate(); + $parsedCrons[$cron->id] = $parsedCron; + } + catch(InvalidArgumentException $e) + { + $this->dao->update(TABLE_CRON)->set('status')->eq('stop')->where('id')->eq($cron->id)->exec(); + continue; + } + } + } + $this->dao->update(TABLE_CRON)->set('lastTime')->eq(date(DT_DATETIME1))->where('lastTime')->eq('0000-00-00 00:00:00')->andWhere('status')->ne('stop')->exec(); + return $parsedCrons; + } + + /** + * Change cron status. + * + * @param int $cronID + * @param string $status + * @param bool $changeTime + * @access public + * @return bool + */ + public function changeStatus($cronID, $status, $changeTime = false) + { + $data = new stdclass(); + $data->status = $status; + if($status == 'running' or $changeTime) $data->lastTime = date(DT_DATETIME1); + $this->dao->update(TABLE_CRON)->data($data)->where('id')->eq($cronID)->exec(); + return dao::isError() ? false : true; + } + + /** + * Log cron. + * + * @param string $log + * @access public + * @return void + */ + public function logCron($log) + { + if(!is_writable($this->app->getLogRoot())) return false; + + $file = $this->app->getLogRoot() . 'cron.' . date('Ymd') . '.log.php'; + if(!is_file($file)) $log = "dao->select('*')->from(TABLE_CRON)->orderBy('lastTime desc')->limit(1)->fetch('lastTime'); + } + + /** + * Runable cron. + * + * @access public + * @return bool + */ + public function runable() + { + if(!$this->config->global->cron) return false; + + $lastTime = $this->getLastTime(); + if($lastTime == '0000-00-00 00:00:00' or ((time() - strtotime($lastTime)) / 3600 > 1)) return true; + if(!isset($this->config->cron->run->status)) return true; + if($this->config->cron->run->status == 'stop') return true; + + return false; + } + + /** + * Check change cron. + * + * @access public + * @return bool + */ + public function checkChange() + { + $updatedCron = $this->dao->select('*')->from(TABLE_CRON)->where('lastTime')->eq('0000-00-00 00:00:00')->andWhere('status')->ne('stop')->fetch(); + return $updatedCron ? true : false; + } + + /** + * Create cron. + * + * @access public + * @return int + */ + public function create() + { + $cron = fixer::input('post') + ->add('type', 'custom') + ->add('status', 'normal') + ->add('lastTime', '0000-00-00 00:00:00') + ->skipSpecial('m,h,dom,mon,dow,command') + ->get(); + $this->dao->insert(TABLE_CRON)->data($cron) + ->autoCheck() + ->batchCheck($this->config->cron->create->requiredFields, 'notempty') + ->exec(); + + return $this->dao->lastInsertID(); + } + + /** + * Update cron. + * + * @param int $cronID + * @access public + * @return bool + */ + public function update($cronID) + { + $cron = fixer::input('post') + ->add('lastTime', '0000-00-00 00:00:00') + ->skipSpecial('m,h,dom,mon,dow,command') + ->get(); + $this->dao->update(TABLE_CRON)->data($cron) + ->autoCheck() + ->batchCheck($this->config->cron->create->requiredFields, 'notempty') + ->where('id')->eq($cronID)->exec(); + return dao::isError() ? false : true; + } + + public function markCronStatus($status, $configID = 0) + { + if($configID) + { + $this->dao->update(TABLE_CONFIG)->set('value')->eq($status)->where('id')->eq($configID)->exec(); + return $configID; + } + else + { + $data = new stdclass(); + $data->owner = 'system'; + $data->module = 'cron'; + $data->section = 'run'; + $data->key = 'status'; + $data->value = $status; + $this->dao->insert(TABLE_CONFIG)->data($data)->exec(); + return $this->dao->lastInsertID(); + } + } + + public function getConfigID() + { + return $this->dao->select('*')->from(TABLE_CONFIG) + ->where('owner')->eq('system') + ->andWhere('module')->eq('cron') + ->andWhere('section')->eq('run') + ->andWhere('`key`')->eq('status') + ->fetch('id'); + } +} diff --git a/module/cron/view/create.html.php b/module/cron/view/create.html.php new file mode 100644 index 0000000000..4b782c7508 --- /dev/null +++ b/module/cron/view/create.html.php @@ -0,0 +1,68 @@ + + * @package cron + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+
+
+ cron->common?> + cron->create?> +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
cron->m;?>cron->notice->m;?>
cron->h;?>cron->notice->h;?>
cron->dom;?>cron->notice->dom;?>
cron->mon;?>cron->notice->mon;?>
cron->dow;?>cron->notice->dow;?>
cron->command;?>
cron->remark;?>
cron->type;?>cron->typeList, 'system', "class='form-control'")?>
+
+
+ + diff --git a/module/cron/view/edit.html.php b/module/cron/view/edit.html.php new file mode 100644 index 0000000000..f846c6d969 --- /dev/null +++ b/module/cron/view/edit.html.php @@ -0,0 +1,68 @@ + + * @package cron + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+
+
+ cron->common?> + cron->edit?> +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
cron->m;?>m, "class='form-control'")?>cron->notice->m;?>
cron->h;?>h, "class='form-control'")?>cron->notice->h;?>
cron->dom;?>dom, "class='form-control'")?>cron->notice->dom;?>
cron->mon;?>mon, "class='form-control'")?>cron->notice->mon;?>
cron->dow;?>dow, "class='form-control'")?>cron->notice->dow;?>
cron->command;?>command), "class='form-control'")?>
cron->remark;?>remark, "class='form-control'")?>
cron->type;?>cron->typeList, $cron->type, "class='form-control'")?>
+
+
+ + diff --git a/module/cron/view/index.html.php b/module/cron/view/index.html.php new file mode 100644 index 0000000000..0c689c978f --- /dev/null +++ b/module/cron/view/index.html.php @@ -0,0 +1,70 @@ + + * @package cron + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+
cron->common;?>
+
global->cron) echo html::a(inlink('turnon'), $lang->cron->turnonList[0] . $lang->cron->common, 'hiddenwin', "class='btn'");?>
+
+ +global->cron):?> +
+
+ cron->list?> +
cron->create, '', "class='btn btn-primary btn-sm'")?>
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
cron->m?>cron->h?>cron->dom?>cron->mon?>cron->dow?>cron->command?>cron->remark?>cron->lastTime?>cron->status?>actions;?>
m;?>h;?>dom;?>mon;?>dow;?>command;?>remark;?>lastTime, 2);?>cron->statusList, $cron->status);?> + command)) echo html::a(inlink('toggle', "id=$cron->id&status=" . ($cron->status == 'stop' ? 'normal' : 'stop')), $cron->status == 'stop' ? $lang->cron->toggleList['start'] : $lang->cron->toggleList['stop'], 'hiddenwin'); + if($cron->buildin == 0 and common::hasPriv('cron', 'edit')) echo html::a(inlink('edit', "id=$cron->id"), $lang->edit); + if($cron->buildin == 0 and common::hasPriv('cron', 'delete')) echo html::a(inlink('delete', "id=$cron->id"), $lang->delete, 'hiddenwin'); + ?> +
+
+ +
+
cron->introduction, inlink('turnon'))?>
+
+ + + diff --git a/module/git/model.php b/module/git/model.php index 209f764333..bf7f2b97c7 100644 --- a/module/git/model.php +++ b/module/git/model.php @@ -82,6 +82,8 @@ class gitModel extends model public function run() { $this->setRepos(); + if(empty($this->repos)) return false; + $this->setLogRoot(); $this->setRestartFile(); @@ -90,11 +92,13 @@ class gitModel extends model $this->printLog("begin repo $name"); $repo = (object)$repo; $repo->name = $name; - $this->setRepo($repo); + if(!$this->setRepo($repo)) return false; $savedRevision = $this->getSavedRevision(); $this->printLog("start from revision $savedRevision"); $logs = $this->getRepoLogs($repo, $savedRevision); + if(empty($logs)) return false; + $this->printLog("get " . count($logs) . " logs"); if(empty($logs)) continue; @@ -171,12 +175,18 @@ class gitModel extends model * Set the repos. * * @access public - * @return void + * @return bool */ public function setRepos() { - if(!$this->config->git->repos) die("You must set one git repo.\n"); + if(!$this->config->git->repos) + { + echo "You must set one git repo.\n"; + return false; + } + $this->repos = $this->config->git->repos; + return true; } /** @@ -184,13 +194,16 @@ class gitModel extends model * * @param object $repo * @access public - * @return void + * @return bool */ public function setRepo($repo) { $this->setClient($repo); + if(empty($this->client)) return false; + $this->setLogFile($repo->name); $this->setRepoRoot($repo); + return true; } /** @@ -198,12 +211,18 @@ class gitModel extends model * * @param object $repo * @access public - * @return void + * @return bool */ public function setClient($repo) { - if($this->config->git->client == '') die("You must set the git client file.\n"); + if($this->config->git->client == '') + { + echo "You must set the git client file.\n"; + return false; + } + $this->client = $this->config->git->client; + return true; } /** @@ -253,7 +272,11 @@ class gitModel extends model } exec($cmd, $list, $return); - if(!$list and $return) die("Some error occers: \nThe command is $cmd\n"); + if(!$list and $return) + { + echo "Some error occers: \nThe command is $cmd\n"; + return false; + } if(!$list and !$return) return array(); /* Process logs. */ @@ -375,6 +398,7 @@ class gitModel extends model if(!$repo) return false; $this->setClient($repo); + if(empty($this->client)) return false; putenv('LC_CTYPE=en_US.UTF-8'); $path = str_replace('%2F', '/', urlencode($path)); @@ -399,6 +423,7 @@ class gitModel extends model if(!$repo) return false; $this->setClient($repo); + if(empty($this->client)) return false; putenv('LC_CTYPE=en_US.UTF-8'); diff --git a/module/my/view/index.html.php b/module/my/view/index.html.php index 9cf1c038f2..1e7401fa11 100644 --- a/module/my/view/index.html.php +++ b/module/my/view/index.html.php @@ -1,51 +1,51 @@ - - * @package ZenTaoPMS - * @version $Id: index.html.php 1947 2011-06-29 11:58:03Z wwccss $ - */ -?> - - -version);?> -
-
- - -
-
- -
-
-
-
- -
- user->role and strpos('qa|qd', $app->user->role) !== false):?> -
- -
-
- -
- user->role and strpos('po|pd', $app->user->role) !== false):?> -
- -
-
- -
- -
- -
-
- -
- -
- + * @author Chunsheng Wang + * @package ZenTaoPMS + * @version $Id: index.html.php 1947 2011-06-29 11:58:03Z wwccss $ + */ +?> + + +version);?> +
+
+ + +
+
+ +
+
+
+
+ +
+ user->role and strpos('qa|qd', $app->user->role) !== false):?> +
+ +
+
+ +
+ user->role and strpos('po|pd', $app->user->role) !== false):?> +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ diff --git a/module/project/control.php b/module/project/control.php index 52ad1ece45..e86fecd892 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -18,9 +18,9 @@ class project extends control * @access public * @return void */ - public function __construct() + public function __construct($moduleName = '', $methodName = '') { - parent::__construct(); + parent::__construct($moduleName, $methodName); if($this->methodName != 'computeburn') { $this->projects = $this->project->getPairs('nocode'); @@ -789,7 +789,7 @@ class project extends control { $this->view->burns = $this->project->computeBurn(); if($reload == 'yes') die(js::reload('parent')); - die($this->display()); + $this->display(); } /** diff --git a/module/svn/model.php b/module/svn/model.php index 2e3a7079cb..3b303240a9 100644 --- a/module/svn/model.php +++ b/module/svn/model.php @@ -82,6 +82,8 @@ class svnModel extends model public function run() { $this->setRepos(); + if(empty($this->repos)) return false; + $this->setLogRoot(); $this->setRestartFile(); @@ -90,11 +92,13 @@ class svnModel extends model $this->printLog("begin repo $name"); $repo = (object)$repo; $repo->name = $name; - $this->setRepo($repo); + if(!$this->setRepo($repo)) return false; $savedRevision = $this->getSavedRevision(); $this->printLog("start from revision $savedRevision"); $logs = $this->getRepoLogs($repo, $savedRevision); + if(empty($logs)) return false; + $this->printLog("get " . count($logs) . " logs"); $this->printLog('begin parsing logs'); @@ -169,12 +173,18 @@ class svnModel extends model * Set the repos. * * @access public - * @return void + * @return bool */ public function setRepos() { - if(!$this->config->svn->repos) die("You must set one svn repo.\n"); + if(!$this->config->svn->repos) + { + echo "You must set one svn repo.\n"; + return false; + } + $this->repos = $this->config->svn->repos; + return true; } /** @@ -182,13 +192,16 @@ class svnModel extends model * * @param object $repo * @access public - * @return void + * @return bool */ public function setRepo($repo) { $this->setClient($repo); + if(empty($this->client)) return false; + $this->setLogFile($repo->name); $this->setRepoRoot($repo); + return true; } /** @@ -196,11 +209,16 @@ class svnModel extends model * * @param object $repo * @access public - * @return void + * @return bool */ public function setClient($repo) { - if($this->config->svn->client == '') die("You must set the svn client file.\n"); + if($this->config->svn->client == '') + { + echo "You must set the svn client file.\n"; + return false; + } + $this->client = $this->config->svn->client . " --non-interactive"; if(stripos($repo->path, 'https') === 0 or stripos($repo->path, 'svn') === 0) { @@ -212,6 +230,7 @@ class svnModel extends model } } if(isset($repo->username)) $this->client .= " --username $repo->username --password $repo->password --no-auth-cache"; + return true; } /** @@ -258,7 +277,11 @@ class svnModel extends model $cmd = $this->client . " log -r $fromRevision:HEAD -v --xml $repo->path"; $rawLogs = `$cmd`; $logs = @simplexml_load_string($rawLogs); // Convert it to object. - if(!$logs) die("Some error occers: \nThe command is $cmd\n the svn logs is $rawLogs\n"); + if(!$logs) + { + echo "Some error occers: \nThe command is $cmd\n the svn logs is $rawLogs\n"; + return false; + } /* Process logs. */ foreach($logs->logentry as $entry) $parsedLogs[] = $this->convertLog($entry); @@ -367,6 +390,7 @@ class svnModel extends model if(!$repo) return false; $this->setClient($repo); + if(empty($this->client)) return false; putenv('LC_CTYPE=en_US.UTF-8'); $oldRevision = $revision - 1; @@ -393,6 +417,7 @@ class svnModel extends model if(!$repo) return false; $this->setClient($repo); + if(empty($this->client)) return false; putenv('LC_CTYPE=en_US.UTF-8'); diff --git a/www/js/my.full.js b/www/js/my.full.js index f5528bb267..10292dbaff 100644 --- a/www/js/my.full.js +++ b/www/js/my.full.js @@ -1178,6 +1178,15 @@ function fixStyle() if($actions.length) $('#titlebar > .heading').css('padding-right', $actions.width()); } +function startCron() +{ + $.ajax({ + type: "GET", + timeout: 100, + url: createLink('cron', 'ajaxExec') + }); +} + /* Ping the server every some minutes to keep the session. */ needPing = true; From e3276297c551011455c6d6c044e666c701ec71a7 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Sat, 28 Feb 2015 17:26:27 +0800 Subject: [PATCH 3/5] * finish task #2208. --- module/common/lang/menuOrder.php | 6 +- module/mail/control.php | 101 ++++++++++++++++++++++++++++++- module/mail/lang/en.php | 19 +++++- module/mail/lang/zh-cn.php | 18 ++++++ module/mail/model.php | 55 +++++++++++++++++ module/mail/view/browse.html.php | 70 +++++++++++++++++++++ module/mail/view/edit.html.php | 7 +++ 7 files changed, 271 insertions(+), 5 deletions(-) create mode 100644 module/mail/view/browse.html.php diff --git a/module/common/lang/menuOrder.php b/module/common/lang/menuOrder.php index 510bc45774..9ba1d94e04 100644 --- a/module/common/lang/menuOrder.php +++ b/module/common/lang/menuOrder.php @@ -112,8 +112,9 @@ $lang->admin->menuOrder[20] = 'editor'; $lang->admin->menuOrder[25] = 'mail'; $lang->admin->menuOrder[30] = 'custom'; $lang->admin->menuOrder[40] = 'convert'; -$lang->admin->menuOrder[45] = 'backup'; -$lang->admin->menuOrder[50] = 'trashes'; +$lang->admin->menuOrder[45] = 'cron'; +$lang->admin->menuOrder[50] = 'backup'; +$lang->admin->menuOrder[55] = 'trashes'; $lang->convert->menuOrder = $lang->admin->menuOrder; $lang->upgrade->menuOrder = $lang->admin->menuOrder; $lang->action->menuOrder = $lang->admin->menuOrder; @@ -123,3 +124,4 @@ $lang->editor->menuOrder = $lang->admin->menuOrder; $lang->mail->menuOrder = $lang->admin->menuOrder; $lang->custom->menuOrder = $lang->admin->menuOrder; $lang->backup->menuOrder = $lang->admin->menuOrder; +$lang->cron->menuOrder = $lang->admin->menuOrder; diff --git a/module/mail/control.php b/module/mail/control.php index cacf3bb2a5..33919f2be9 100755 --- a/module/mail/control.php +++ b/module/mail/control.php @@ -17,9 +17,9 @@ class mail extends control * @access public * @return void */ - public function __construct() + public function __construct($moduleName = '', $methodName = '') { - parent::__construct(); + parent::__construct($moduleName, $methodName); /* Task #1967. check the function of fsocket. */ if(!function_exists('fsockopen')) @@ -121,6 +121,7 @@ class mail extends control $mailConfig->turnon = $this->post->turnon; $mailConfig->mta = 'smtp'; + $mailConfig->async = $this->post->async; $mailConfig->fromAddress = trim($this->post->fromAddress); $mailConfig->fromName = trim($this->post->fromName); $mailConfig->smtp->host = trim($this->post->host); @@ -218,4 +219,100 @@ class mail extends control $this->dao->delete('*')->from(TABLE_CONFIG)->where('module')->eq('mail')->exec(); $this->locate(inlink('detect')); } + + /** + * Async send mail. + * + * @access public + * @return void + */ + public function asyncSend() + { + $queueList = $this->mail->getQueue('wait', 'id_asc'); + $now = helper::now(); + if(isset($this->config->mail->async))$this->config->mail->async = 0; + foreach($queueList as $queue) + { + $this->mail->send($queue->toList, $queue->subject, $queue->body, $queue->ccList); + + $data = new stdclass(); + $data->sendTime = $now; + $data->status = 'send'; + if($this->mail->isError()) + { + $data->status = 'fail'; + $data->failReason = join("\n", $this->mail->getError()); + } + $this->dao->update(TABLE_MAILQUEUE)->data($data)->where('id')->eq($queue->id)->exec(); + + $log = "Send #$query->id result is $data->status\n"; + if($data->status == 'fail') $log .= "reason is $data->failReason\n"; + echo $log; + } + echo "OK\n"; + } + + /** + * Browse mail queue. + * + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function browse($orderBy = 'id_desc', $recTotal = 0, $recPerPage = 100, $pageID = 1) + { + $this->app->loadClass('pager', $static = true); + $pager = new pager($recTotal, $recPerPage, $pageID); + + $this->view->title = $this->lang->mail->browse; + $this->view->position[] = html::a(inlink('edit'), $this->lang->mail->common); + $this->view->position[] = $this->lang->mail->browse; + + $this->view->queueList = $this->mail->getQueue(null, $orderBy, $pager); + $this->view->pager = $pager; + $this->view->orderBy = $orderBy; + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->display(); + } + + /** + * Delete mail queue. + * + * @param int $id + * @param string $confirm + * @access public + * @return void + */ + public function delete($id, $confirm = 'no') + { + if($confirm == 'no') die(js::confirm($this->lang->mail->confirmDelete, inlink('delete', "id=$id&confirm=yes"))); + + $this->dao->delete()->from(TABLE_MAILQUEUE)->where('id')->eq($id)->exec(); + die(js::reload('parent')); + } + + /** + * Batch delete mail queue. + * + * @param string $confirm + * @access public + * @return void + */ + public function batchDelete($confirm = 'no') + { + if($confirm == 'no') + { + if(empty($_POST)) die(js::reload('parent')); + $idList = join('|', $this->post->mailIDList); + die(js::confirm($this->lang->mail->confirmDelete, inlink('batchDelete', "confirm=yes") . ($this->config->requestType == 'GET' ? '&' : '?') . "idList=$idList")); + } + $idList = array(); + if(isset($_GET['idList'])) $idList = explode(',', $_GET['idList']); + + if($idList) $this->dao->delete()->from(TABLE_MAILQUEUE)->where('id')->in($idList)->exec(); + die(js::reload('parent')); + } } diff --git a/module/mail/lang/en.php b/module/mail/lang/en.php index 633a8b2dd9..2b0a9e112d 100755 --- a/module/mail/lang/en.php +++ b/module/mail/lang/en.php @@ -6,8 +6,10 @@ $lang->mail->edit = 'Configure'; $lang->mail->save = 'Successfully saved'; $lang->mail->test = 'Testing'; $lang->mail->reset = 'Reset'; +$lang->mail->browse = 'Mail list'; $lang->mail->turnon = 'Turnon'; +$lang->mail->async = 'Asynchronous'; $lang->mail->fromAddress = 'From email'; $lang->mail->fromName = 'From title'; $lang->mail->mta = 'MTA'; @@ -20,9 +22,24 @@ $lang->mail->secure = 'Secure'; $lang->mail->debug = 'Debug'; $lang->mail->charset = 'Charset'; +$lang->mail->toList = 'Addressee'; +$lang->mail->subjectName = 'Subject'; +$lang->mail->addedBy = 'Sender'; +$lang->mail->addedDate = 'Added date'; +$lang->mail->sendTime = 'Send time'; +$lang->mail->status = 'Status'; +$lang->mail->ccList = 'Copy to'; +$lang->mail->failReason = 'Fail Reason'; + +$lang->mail->statusList['send'] = 'Success'; +$lang->mail->statusList['fail'] = 'Fail'; + $lang->mail->turnonList[1] = 'on'; $lang->mail->turnonList[0] = 'off'; +$lang->mail->asyncList[1] = 'Yes'; +$lang->mail->asyncList[0] = 'No'; + $lang->mail->debugList[0] = 'off'; $lang->mail->debugList[1] = 'normal'; $lang->mail->debugList[2] = 'high'; @@ -40,8 +57,8 @@ $lang->mail->successSaved = 'The configuration has been successfully saved.'; $lang->mail->subject = "It's a testing email from zentao."; $lang->mail->content = 'If you can see this, the email notification feature can work now!'; $lang->mail->successSended = 'Successfully sended!'; +$lang->mail->confirmDelete = 'Confirm delete mail?'; $lang->mail->sendmailTips = 'Tips: system will not send mail to current user.'; $lang->mail->needConfigure = "I can not find the configuration, please configure it first."; $lang->mail->nofsocket = 'The fsocket correlation function is disabled, not letter! Please enlarge the setting of allow_url_fopen to On in php.ini and open the extension of openssl. Restart apache.'; $lang->mail->noOpenssl = 'Please open the extension of openssl when use tls. Restart apache.'; -$lang->mail->noCurl = 'Please open the extension of curl when use tls and ssl. Restart apache.'; diff --git a/module/mail/lang/zh-cn.php b/module/mail/lang/zh-cn.php index 49fc836cad..51df961c36 100755 --- a/module/mail/lang/zh-cn.php +++ b/module/mail/lang/zh-cn.php @@ -6,8 +6,10 @@ $lang->mail->edit = '编辑配置'; $lang->mail->save = '成功保存'; $lang->mail->test = '测试发信'; $lang->mail->reset = '重置'; +$lang->mail->browse = '邮件列表'; $lang->mail->turnon = '是否打开'; +$lang->mail->async = '异步发送'; $lang->mail->fromAddress = '发信邮箱'; $lang->mail->fromName = '发信人'; $lang->mail->mta = '发信方式'; @@ -20,9 +22,24 @@ $lang->mail->secure = '是否加密'; $lang->mail->debug = '调试级别'; $lang->mail->charset = '编码'; +$lang->mail->toList = '收信人'; +$lang->mail->subjectName = '主题'; +$lang->mail->addedBy = '发送者'; +$lang->mail->addedDate = '创建时间'; +$lang->mail->sendTime = '发送时间'; +$lang->mail->status = '状态'; +$lang->mail->ccList = '抄送给'; +$lang->mail->failReason = '失败原因'; + +$lang->mail->statusList['send'] = '成功'; +$lang->mail->statusList['fail'] = '失败'; + $lang->mail->turnonList[1] = '打开'; $lang->mail->turnonList[0] = '关闭'; +$lang->mail->asyncList[1] = '是'; +$lang->mail->asyncList[0] = '否'; + $lang->mail->debugList[0] = '关闭'; $lang->mail->debugList[1] = '一般'; $lang->mail->debugList[2] = '较高'; @@ -40,6 +57,7 @@ $lang->mail->successSaved = '配置信息已经成功保存。'; $lang->mail->subject = '测试邮件'; $lang->mail->content = '邮箱设置成功'; $lang->mail->successSended = '成功发送!'; +$lang->mail->confirmDelete = '是否删除邮件?'; $lang->mail->sendmailTips = '提示:系统不会为当前操作者发信。'; $lang->mail->needConfigure = '无法找到邮件配置信息,请先配置邮件发送参数。'; $lang->mail->nofsocket = 'fsocket相关函数被禁用,不能发信!请在php.ini中修改allow_url_fopen为On,打开openssl扩展。 保存并重新启动apache。'; diff --git a/module/mail/model.php b/module/mail/model.php index 064b721558..03156fb004 100644 --- a/module/mail/model.php +++ b/module/mail/model.php @@ -242,6 +242,7 @@ class mailModel extends model public function send($toList, $subject, $body = '', $ccList = '', $includeMe = false) { if(!$this->config->mail->turnon) return; + if(isset($this->config->mail->async) and $this->config->mail->async) return $this->addQueue($toList, $subject, $body, $ccList, $includeMe); ob_start(); $toList = $toList ? explode(',', str_replace(' ', '', $toList)) : array(); @@ -436,4 +437,58 @@ class mailModel extends model $this->errors = array(); return $errors; } + + /** + * Add queue. + * + * @param string $toList + * @param string $subject + * @param string $body + * @param string $ccList + * @param bool $includeMe + * @access public + * @return void + */ + public function addQueue($toList, $subject, $body = '', $ccList = '', $includeMe = false) + { + $toList = $toList ? explode(',', str_replace(' ', '', $toList)) : array(); + $ccList = $ccList ? explode(',', str_replace(' ', '', $ccList)) : array(); + + /* Process toList and ccList, remove current user from them. If toList is empty, use the first cc as to. */ + if($includeMe == false) + { + $account = isset($this->app->user->account) ? $this->app->user->account : ''; + + foreach($toList as $key => $to) if(trim($to) == $account or !trim($to)) unset($toList[$key]); + foreach($ccList as $key => $cc) if(trim($cc) == $account or !trim($cc)) unset($ccList[$key]); + } + $toList = join(',', $toList); + $ccList = join(',', $ccList); + + $data = new stdclass(); + $data->toList = $toList; + $data->ccList = $ccList; + $data->subject = $subject; + $data->body = $body; + $data->addedBy = $this->app->user->account; + $data->addedDate = helper::now(); + $this->dao->insert(TABLE_MAILQUEUE)->data($data)->autocheck()->batchCheck('toList,subject', 'notempty')->exec(); + } + + /** + * Get queue. + * + * @param string $status + * @access public + * @return array + */ + public function getQueue($status = '', $orderBy = 'id_desc', $pager = null) + { + return $this->dao->select('*')->from(TABLE_MAILQUEUE) + ->where('1=1') + ->beginIF($status)->andWhere('status')->eq($status)->fi() + ->orderBy($orderBy) + ->page($pager) + ->fetchAll(); + } } diff --git a/module/mail/view/browse.html.php b/module/mail/view/browse.html.php new file mode 100644 index 0000000000..854833ae57 --- /dev/null +++ b/module/mail/view/browse.html.php @@ -0,0 +1,70 @@ + + * @package mail + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+
mail->browse?>
+
+
' target='hiddenwin'> +
+ + recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idAB);?> mail->toList);?> mail->subjectName);?> mail->addedBy);?> mail->addedDate);?> mail->sendTime);?> mail->status);?> mail->failReason;?> actions;?>
+ + id?> + toList, $queue->toList)?>subject?>addedBy, $queue->addedBy)?>addedDate?>sendTime?>mail->statusList, $queue->status)?>failReason?>id"), $lang->delete, 'hiddenwin');?>
+" . html::selectButton() . ''; + if(common::hasPriv('mail', 'batchDelete')) echo html::submitButton($lang->delete); +} +$pager->show(); +?> +
+
+
+ + diff --git a/module/mail/view/edit.html.php b/module/mail/view/edit.html.php index 0240ecaf1a..162bbeb166 100755 --- a/module/mail/view/edit.html.php +++ b/module/mail/view/edit.html.php @@ -25,6 +25,12 @@ include '../../common/view/header.html.php'; mail->turnon; ?> mail->turnonList, 1);?> + global->cron):?> + + mail->async?> + mail->asyncList, zget($config->mail, 'async', 0))?> + + mail->fromAddress; ?> fromAddress, "class='form-control'");?> @@ -72,6 +78,7 @@ include '../../common/view/header.html.php'; echo html::submitButton(); if($this->config->mail->turnon and $mailExist) echo html::linkButton($lang->mail->test, inlink('test')); echo html::linkButton($lang->mail->reset, inlink('reset')); + if(common::hasPriv('mail', 'browse') and isset($config->mail->async) and $config->mail->async and $config->global->cron) echo html::linkButton($lang->mail->browse, inlink('browse')); ?> From a9e6dcc529840cd357e19dc726a05ae874c9c38a Mon Sep 17 00:00:00 2001 From: wangyidong Date: Mon, 2 Mar 2015 14:24:44 +0800 Subject: [PATCH 4/5] * change for group priv. --- module/cron/config.php | 2 +- module/cron/lang/en.php | 47 ++++++++++++++++++++++++ module/cron/lang/zh-cn.php | 5 ++- module/dev/lang/en.php | 14 +++++++ module/group/lang/resource.php | 40 ++++++++++++++++++++ module/mail/lang/en.php | 2 + module/mail/lang/zh-cn.php | 2 + module/project/view/taskheader.html.php | 2 +- module/testcase/view/caseheader.html.php | 2 +- module/testtask/view/caseheader.html.php | 2 +- 10 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 module/cron/lang/en.php diff --git a/module/cron/config.php b/module/cron/config.php index 48d311f2a5..11de4238d2 100644 --- a/module/cron/config.php +++ b/module/cron/config.php @@ -5,4 +5,4 @@ $config->cron->edit = new stdclass(); $config->cron->create->requiredFields = 'm,h,dom,mon,dow,command'; $config->cron->edit->requiredFields = 'm,h,dom,mon,dow,command'; -$config->cron->maxRunDays = 3; +$config->cron->maxRunDays = 8; diff --git a/module/cron/lang/en.php b/module/cron/lang/en.php new file mode 100644 index 0000000000..f08d350eb7 --- /dev/null +++ b/module/cron/lang/en.php @@ -0,0 +1,47 @@ +cron->common = 'Cron'; +$lang->cron->index = 'Index'; +$lang->cron->list = 'List'; +$lang->cron->create = 'Create'; +$lang->cron->edit = 'Edit'; +$lang->cron->delete = 'Delete'; +$lang->cron->toggle = 'Activation/Disable'; +$lang->cron->turnon = 'Open/Close'; + +$lang->cron->m = 'Minute'; +$lang->cron->h = 'Hour'; +$lang->cron->dom = 'Day'; +$lang->cron->mon = 'Month'; +$lang->cron->dow = 'Week'; +$lang->cron->command = 'Command'; +$lang->cron->status = 'Status'; +$lang->cron->type = 'Type'; +$lang->cron->remark = 'Remark'; +$lang->cron->lastTime = 'Last run time'; + +$lang->cron->turnonList['1'] = 'Open'; +$lang->cron->turnonList['0'] = 'Close'; + +$lang->cron->statusList['normal'] = 'Normal'; +$lang->cron->statusList['running'] = 'Running'; +$lang->cron->statusList['stop'] = 'Stop'; + +$lang->cron->typeList['zentao'] = 'Self call'; +$lang->cron->typeList['system'] = 'System command'; + +$lang->cron->toggleList['start'] = 'Activation'; +$lang->cron->toggleList['stop'] = 'Disable'; + +$lang->cron->confirmDelete = 'Do you want to delete the task?'; +$lang->cron->introduction = <<Timing tasks such as compute burn , backup. Absolve themselves of layout timing task.

+

This function has yet to be perfect, so the function is turned off by default

+

Whether to open the function? Open timing task

+EOD; + +$lang->cron->notice = new stdclass(); +$lang->cron->notice->m = 'Range : 0-59,"*" express the range of numbers, "/" express "Every", "-" express digital range.'; +$lang->cron->notice->h = 'Range : 0-23'; +$lang->cron->notice->dom = 'Range : 1-31'; +$lang->cron->notice->mon = 'Range : 1-12'; +$lang->cron->notice->dow = 'Range : 0-6'; diff --git a/module/cron/lang/zh-cn.php b/module/cron/lang/zh-cn.php index af6da9ef70..8bf433ba6e 100644 --- a/module/cron/lang/zh-cn.php +++ b/module/cron/lang/zh-cn.php @@ -1,5 +1,6 @@ cron->common = '计划任务'; +$lang->cron->common = '定时任务'; +$lang->cron->index = '首页'; $lang->cron->list = '任务列表'; $lang->cron->create = '添加'; $lang->cron->edit = '编辑'; @@ -39,7 +40,7 @@ $lang->cron->introduction = <<cron->notice = new stdclass(); -$lang->cron->notice->m = '取值范围:0-59,"*"代表取值范围内的数字,"/"代表"每", "-"代表从数字范围。'; +$lang->cron->notice->m = '取值范围:0-59,"*"代表取值范围内的数字,"/"代表"每", "-"代表数字范围。'; $lang->cron->notice->h = '取值范围:0-23'; $lang->cron->notice->dom = '取值范围:1-31'; $lang->cron->notice->mon = '取值范围:1-12'; diff --git a/module/dev/lang/en.php b/module/dev/lang/en.php index e69de29bb2..b62689b604 100644 --- a/module/dev/lang/en.php +++ b/module/dev/lang/en.php @@ -0,0 +1,14 @@ +dev->common = 'Dev'; +$lang->dev->api = 'API'; +$lang->dev->db = 'Database'; +$lang->dev->editor = 'Editor'; +$lang->dev->dbList = 'Datebases'; + +$lang->dev->fields = array(); +$lang->dev->fields['id'] = 'ID'; +$lang->dev->fields['name'] = 'Field'; +$lang->dev->fields['desc'] = 'Desc'; +$lang->dev->fields['type'] = 'Type'; +$lang->dev->fields['length'] = 'Length'; +$lang->dev->fields['null'] = 'Empty'; diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index 51368836a1..bc0ab774a0 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -53,6 +53,8 @@ $lang->moduleOrder[155] = 'api'; $lang->moduleOrder[160] = 'file'; $lang->moduleOrder[165] = 'misc'; $lang->moduleOrder[170] = 'backup'; +$lang->moduleOrder[175] = 'cron'; +$lang->moduleOrder[180] = 'dev'; $lang->resource = new stdclass(); @@ -535,6 +537,9 @@ $lang->resource->mail->edit = 'edit'; $lang->resource->mail->save = 'save'; $lang->resource->mail->test = 'test'; $lang->resource->mail->reset = 'reset'; +$lang->resource->mail->browse = 'browse'; +$lang->resource->mail->delete = 'delete'; +$lang->resource->mail->batchDelete = 'batchDelete'; $lang->mail->methodOrder[5] = 'index'; $lang->mail->methodOrder[10] = 'detect'; @@ -542,6 +547,9 @@ $lang->mail->methodOrder[15] = 'edit'; $lang->mail->methodOrder[20] = 'save'; $lang->mail->methodOrder[25] = 'test'; $lang->mail->methodOrder[30] = 'reset'; +$lang->mail->methodOrder[35] = 'browse'; +$lang->mail->methodOrder[40] = 'delete'; +$lang->mail->methodOrder[45] = 'batchDelete'; /* custom. */ $lang->resource->custom = new stdclass(); @@ -825,6 +833,28 @@ $lang->backup->methodOrder[10] = 'backup'; $lang->backup->methodOrder[15] = 'restore'; $lang->backup->methodOrder[20] = 'delete'; +$lang->resource->cron = new stdclass(); +$lang->resource->cron->index = 'index'; +$lang->resource->cron->turnon = 'turnon'; +$lang->resource->cron->create = 'create'; +$lang->resource->cron->edit = 'edit'; +$lang->resource->cron->toggle = 'toggle'; +$lang->resource->cron->delete = 'delete'; + +$lang->cron->methodOrder[5] = 'index'; +$lang->cron->methodOrder[10] = 'turnon'; +$lang->cron->methodOrder[15] = 'create'; +$lang->cron->methodOrder[20] = 'edit'; +$lang->cron->methodOrder[25] = 'toggle'; +$lang->cron->methodOrder[30] = 'delete'; + +$lang->resource->dev = new stdclass(); +$lang->resource->dev->api = 'api'; +$lang->resource->dev->db = 'db'; + +$lang->dev->methodOrder[5] = 'api'; +$lang->dev->methodOrder[10] = 'db'; + /* Every version of new privilege. */ $lang->changelog['1.0.1'][] = 'project-computeBurn'; @@ -1015,3 +1045,13 @@ $lang->changelog['6.4'][] = 'release-linkBug'; $lang->changelog['6.4'][] = 'release-unlinkBug'; $lang->changelog['6.4'][] = 'release-batchUnlinkBug'; $lang->changelog['6.4'][] = 'story-batchAssignTo'; + +$lang->changelog['7.1'][] = 'cron-index'; +$lang->changelog['7.1'][] = 'cron-turnon'; +$lang->changelog['7.1'][] = 'cron-create'; +$lang->changelog['7.1'][] = 'cron-edit'; +$lang->changelog['7.1'][] = 'cron-toggle'; +$lang->changelog['7.1'][] = 'cron-delete'; +$lang->changelog['7.1'][] = 'mail-browse'; +$lang->changelog['7.1'][] = 'mail-delete'; +$lang->changelog['7.1'][] = 'mail-batchDelete'; diff --git a/module/mail/lang/en.php b/module/mail/lang/en.php index 2b0a9e112d..7d22165893 100755 --- a/module/mail/lang/en.php +++ b/module/mail/lang/en.php @@ -7,6 +7,8 @@ $lang->mail->save = 'Successfully saved'; $lang->mail->test = 'Testing'; $lang->mail->reset = 'Reset'; $lang->mail->browse = 'Mail list'; +$lang->mail->delete = 'Delete mail'; +$lang->mail->batchDelete = 'Batch delete'; $lang->mail->turnon = 'Turnon'; $lang->mail->async = 'Asynchronous'; diff --git a/module/mail/lang/zh-cn.php b/module/mail/lang/zh-cn.php index 51df961c36..e6ff6c4e2e 100755 --- a/module/mail/lang/zh-cn.php +++ b/module/mail/lang/zh-cn.php @@ -7,6 +7,8 @@ $lang->mail->save = '成功保存'; $lang->mail->test = '测试发信'; $lang->mail->reset = '重置'; $lang->mail->browse = '邮件列表'; +$lang->mail->delete = '删除邮件'; +$lang->mail->batchDelete = '批量删除'; $lang->mail->turnon = '是否打开'; $lang->mail->async = '异步发送'; diff --git a/module/project/view/taskheader.html.php b/module/project/view/taskheader.html.php index 0903651910..e893318413 100644 --- a/module/project/view/taskheader.html.php +++ b/module/project/view/taskheader.html.php @@ -91,6 +91,6 @@ $headerHooks = glob(dirname(dirname(__FILE__)) . "/ext/view/featurebar.*.html.hook.php"); if(!empty($headerHooks)) { - foreach($headerHooks as $fileName) helper::import($fileName); + foreach($headerHooks as $fileName) include($fileName); } ?> diff --git a/module/testcase/view/caseheader.html.php b/module/testcase/view/caseheader.html.php index fd0d17ea2c..299231b280 100644 --- a/module/testcase/view/caseheader.html.php +++ b/module/testcase/view/caseheader.html.php @@ -60,6 +60,6 @@ $headerHooks = glob(dirname(dirname(__FILE__)) . "/ext/view/featurebar.*.html.hook.php"); if(!empty($headerHooks)) { - foreach($headerHooks as $fileName) helper::import($fileName); + foreach($headerHooks as $fileName) include($fileName); } ?> diff --git a/module/testtask/view/caseheader.html.php b/module/testtask/view/caseheader.html.php index 220bcb4096..60a6f22bb9 100644 --- a/module/testtask/view/caseheader.html.php +++ b/module/testtask/view/caseheader.html.php @@ -43,6 +43,6 @@ $headerHooks = glob(dirname(dirname(__FILE__)) . "/ext/view/featurebar.*.html.hook.php"); if(!empty($headerHooks)) { - foreach($headerHooks as $fileName) helper::import($fileName); + foreach($headerHooks as $fileName) include($fileName); } ?> From fdc283afd74c3cf379fd24153ece79fe519c0b20 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Wed, 4 Mar 2015 14:42:27 +0800 Subject: [PATCH 5/5] * adjust for upload extension file. --- module/extension/control.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/module/extension/control.php b/module/extension/control.php index 17905290d9..64ae887790 100644 --- a/module/extension/control.php +++ b/module/extension/control.php @@ -424,8 +424,19 @@ class extension extends control { $tmpName = $_FILES['file']['tmp_name']; $fileName = $_FILES['file']['name']; - $extension = basename($fileName, '.zip'); move_uploaded_file($tmpName, $this->app->getTmpRoot() . "/extension/$fileName"); + $extension = basename($fileName, '.zip'); + $return = $this->extension->extractPackage($extension); + if($return->result != 'ok') die(js::alert(sprintf($this->lang->extension->errorExtracted, $packageFile, $return->error))); + + $info = $this->extension->parseExtensionCFG($extension); + if(isset($info->code) and $info->code != $extension) + { + $classFile = $this->app->loadClass('zfile'); + $classFile->removeDir("ext/$extension"); + $extension = $info->code; + } + $info = $this->extension->getInfoFromDB($extension); $type = $info->status == 'installed' ? 'upgrade' : 'install'; $link = $type == 'install' ? inlink('install', "extension=$extension") : inlink('upgrade', "extension=$extension");