This commit is contained in:
reneeteng
2021-08-11 14:38:08 +08:00
414 changed files with 7988 additions and 3104 deletions
+1
View File
@@ -16,6 +16,7 @@ clean:
rm -fr lampp
common:
mkdir zentaopms
cp -fr api zentaopms/
cp -fr bin zentaopms/
cp -fr config zentaopms/ && rm -fr zentaopms/config/my.php
cp -fr db zentaopms/
+1 -1
View File
@@ -1 +1 @@
15.2
15.3
+1 -1
View File
@@ -11,7 +11,7 @@ class bugsEntry extends entry
public function get($productID)
{
$control = $this->loadController('bug', 'browse');
$control->browse($productID);
$control->browse($productID, $this->param('branch', ''), $this->param('status', ''), 0, $this->param('order', ''), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
+1 -1
View File
@@ -11,7 +11,7 @@ class executionsEntry extends entry
public function get($projectID = 0)
{
$control = $this->loadController('execution', 'all');
$control->all($this->param('status', 'all'), $this->param('project', $projectID));
$control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
+18
View File
@@ -0,0 +1,18 @@
<?php
/**
* 禅道API的my地盘资源类
* 版本V1
*
* The bug entry point of zentaopms
* Version 1
*/
class myEntry extends entry
{
public function get()
{
$info = $this->loadModel('my')->getInfo();
if(!$info) return $this->sendError(400, $info->message);
$this->send(200, $info);
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ class ProgramsEntry extends Entry
public function get()
{
$program = $this->loadController('program', 'browse');
$program->browse();
$program->browse($this->param('status', 'all'), $this->param('order', 'order_asc'));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
+97
View File
@@ -0,0 +1,97 @@
<?php
/**
* 禅道API的project issues资源类
* 版本V1
* 目前适用于Gitlab
*
* The project issues entry point of zentaopms
* Version 1
*/
class projectIssueEntry extends entry
{
public function get($issueID)
{
$this->loadModel('entry');
$this->setParam('timeFormat', 'utc');
$idParams = explode('-', $issueID);
if(count($idParams) < 2) $this->sendError(400, 'The id of issue is wrong.');
$type = $idParams[0];
$id = intval($idParams[1]);
$issue = new stdclass();
switch($type)
{
case 'story':
$this->app->loadLang('story');
$storyStatus = array('' => '', 'draft' => 'opened', 'active' => 'opened', 'changed' => 'opened', 'closed' => 'closed');
$story = $this->dao->select('*')->from(TABLE_STORY)->where('id')->eq($id)->fetch();
if(!$story) $this->send404();
$issue->id = $issueID;
$issue->title = $story->title;
$issue->labels = array($this->app->lang->story->common, zget($this->app->lang->story->categoryList, $story->category));
$issue->pri = $story->pri;
$issue->assignedTo = $this->entry->getAssignees('story', $story);
$issue->openedDate = $story->openedDate;
$issue->openedBy = $this->entry->getUser($story->openedBy);
$issue->lastEditedDate = $story->lastEditedDate < '1970-01-01 01:01:01' ? $story->openedDate : $story->lastEditedDate;
$issue->lastEditedBy = $story->lastEditedDate < '1970-01-01 01:01:01' ? $story->openedBy : $story->lastEditedBy;
$issue->status = $storyStatus[$story->status];
$issue->url = helper::createLink('story', 'view', "storyID=$id");
$storySpec = $this->dao->select('*')->from(TABLE_STORYSPEC)->where('story')->eq($id)->andWhere('version')->eq($story->version)->fetch();
$issue->desc = $storySpec->spec;
break;
case 'bug':
$this->app->loadLang('bug');
$bugStatus = array('' => '', 'active' => 'opened', 'resolved' => 'opened', 'closed' => 'closed');
$bug = $this->dao->select('*')->from(TABLE_BUG)->where('id')->eq($id)->fetch();
if(!$bug) $this->send404();
$issue->id = $issueID;
$issue->title = $bug->title;
$issue->labels = array($this->app->lang->bug->common, zget($this->app->lang->bug->typeList, $bug->type));
$issue->pri = $bug->pri;
$issue->assignedTo = $this->entry->getAssignees('bug', $bug);
$issue->openedDate = $bug->openedDate;
$issue->openedBy = $this->entry->getUser($bug->openedBy);
$issue->lastEditedDate = $bug->lastEditedDate < '1970-01-01 01:01:01' ? $bug->openedDate : $bug->lastEditedDate;
$issue->lastEditedBy = $bug->lastEditedDate < '1970-01-01 01:01:01' ? $bug->openedBy : $bug->lastEditedBy;
$issue->status = $bugStatus[$bug->status];
$issue->url = helper::createLink('bug', 'view', "bugID=$id");
$issue->desc = $bug->steps;
break;
case 'task':
$this->app->loadLang('task');
$taskStatus = array('' => '', 'wait' => 'opened', 'doing' => 'opened', 'done' => 'opened', 'pause' => 'opened', 'cancel' => 'opened', 'closed' => 'closed');
$task = $this->dao->select('*')->from(TABLE_TASK)->where('id')->eq($id)->fetch();
if(!$task) $this->send404();
$issue->id = $issueID;
$issue->title = $task->name;
$issue->labels = array($this->app->lang->task->common, zget($this->app->lang->task->typeList, $task->type));
$issue->pri = $task->pri;
$issue->assignedTo = $this->entry->getAssignees('task', $task);
$issue->openedDate = $task->openedDate;
$issue->openedBy = $this->entry->getUser($task->openedBy);
$issue->lastEditedDate = $task->lastEditedDate < '1970-01-01 01:01:01' ? $task->openedDate : $task->lastEditedDate;
$issue->lastEditedBy = $task->lastEditedDate < '1970-01-01 01:01:01' ? $task->openedBy : $task->lastEditedBy;
$issue->status = $taskStatus[$task->status];
$issue->url = helper::createLink('task', 'view', "taskID=$id");
$issue->desc = $task->desc;
break;
default:
$this->send404();
}
$actions = $this->loadModel('action')->getList($type, $issueID);
$this->send(200, array('issue' => $this->format($issue, 'openedDate:time,lastEditedDate:time')));
}
}
+217
View File
@@ -0,0 +1,217 @@
<?php
/**
* 禅道API的project issues资源类
* 版本V1
* 目前适用于Gitlab
*
* The project issues entry point of zentaopms
* Version 1
*/
class projectIssuesEntry extends entry
{
public function get($productID)
{
if(!is_numeric($productID)) $this->sendError(400, 'The project_id is not supported');
$this->setParam('timeFormat', 'utc');
$taskFields = 'id,status';
$taskStatus = array('' => '');
$taskStatus['opened'] = 'wait,doing,done,pause';
$taskStatus['closed'] = 'closed';
$storyFields = 'id,status';
$storyStatus = array('' => '');
$storyStatus['opened'] = 'draft,active,changed';
$storyStatus['closed'] = 'closed';
$bugFields = 'id,status';
$bugStatus = array('' => '');
$bugStatus['opened'] = 'active,resolved';
$bugStatus['closed'] = 'closed';
$productID = (int)$productID;
$status = $this->param('status', '');
$label = $this->param('label', '');
$search = $this->param('search', '');
$page = intval($this->param('page', 1));
$limit = intval($this->param('limit', 20));
$order = $this->param('order', 'openedDate_desc');
$orderParams = explode('_', $order);
$order = $orderParams[0];
$sort = (isset($orderParams[1]) and strtolower($orderParams[1]) == 'asc') ? 'asc' : 'desc';
if($status == 'all') $status = '';
if(!in_array($status, array('opened', 'closed', ''))) $this->sendError(400, 'The status is not supported');
switch($order)
{
case 'openedDate':
$taskFields .= ',openedDate';
$storyFields .= ',openedDate';
$bugFields .= ',openedDate';
break;
case 'title':
$taskFields .= ',name as title';
$storyFields .= ',title';
$bugFields .= ',title';
break;
case 'lastEditedDate':
$taskFields .= ",if(lastEditedDate < '1970-01-01 01-01-01', openedDate, lastEditedDate) as lastEditedDate";
$storyFields .= ",if(lastEditedDate < '1970-01-01 01-01-01', openedDate, lastEditedDate) as lastEditedDate";
$bugFields .= ",if(lastEditedDate < '1970-01-01 01-01-01', openedDate, lastEditedDate) as lastEditedDate";
break;
default:
$this->sendError(400, 'The order is not supported');
}
$issues = array();
$executions = $this->dao->select('project')->from(TABLE_PROJECTPRODUCT)->where('product')->eq($productID)->fetchPairs();
$tasks = $this->dao->select($taskFields)->from(TABLE_TASK)->where('execution')->in(array_values($executions))
->beginIF($search)->andWhere('name')->like("%$search%")->fi()
->beginIF($label)->andWhere('type')->eq($label)->fi()
->beginIF($status)->andWhere('status')->in($taskStatus[$status])->fi()
->andWhere('deleted')->eq(0)
->fetchAll();
foreach($tasks as $task) $issues[] = array('id' => $task->id, 'type' => 'task', 'order' => $task->$order, 'status' => $this->getKey($task->status, $taskStatus));
$stories = $this->dao->select($storyFields)->from(TABLE_STORY)->where('product')->eq($productID)
->beginIF($search)->andWhere('title')->like("%$search%")->fi()
->beginIF($label)->andWhere('type')->eq($label)->fi()
->beginIF($status)->andWhere('status')->in($storyStatus[$status])->fi()
->andWhere('deleted')->eq(0)
->fetchAll();
foreach($stories as $story)
{
$issues[] = array('id' => $story->id, 'type' => 'story', 'order' => $story->$order, 'status' => $this->getKey($story->status, $storyStatus));
}
$bugs = $this->dao->select($bugFields)->from(TABLE_BUG)->where('product')->eq($productID)
->beginIF($search)->andWhere('title')->like("%$search%")->fi()
->beginIF($label)->andWhere('type')->eq($label)->fi()
->beginIF($status)->andWhere('status')->in($bugStatus[$status])->fi()
->andWhere('deleted')->eq(0)
->fetchAll();
foreach($bugs as $bug)
{
$issues[] = array('id' => $bug->id, 'type' => 'bug', 'order' => $bug->$order, 'status' => $this->getKey($bug->status, $bugStatus));
}
array_multisort(array_column($issues, 'order'), $sort == 'asc' ? SORT_ASC : SORT_DESC, $issues);
$total = count($issues);
$issues = $page < 1 ? array() : array_slice($issues, ($page-1) * $limit, $limit);
$result = $this->processIssues($issues);
$this->send(200, array('page' => $page, 'total' => $total, 'limit' => $limit, 'issues' => $result));
}
/**
* Process issues, format fields.
*
* @param array $issues
* @param int $page
* @param int $limit
* @access public
* @return array
*/
public function processIssues($issues)
{
$this->app->loadLang('task');
$this->app->loadLang('story');
$this->app->loadLang('bug');
$this->loadModel('entry');
$tasks = array();
$stories = array();
$bugs = array();
foreach($issues as $issue)
{
if($issue['type'] == 'story') $stories[] = $issue['id'];
if($issue['type'] == 'task') $tasks[] = $issue['id'];
if($issue['type'] == 'bug') $bugs[] = $issue['id'];
}
if(!empty($tasks)) $tasks = $this->dao->select('*')->from(TABLE_TASK)->where('id')->in($tasks)->fetchAll('id');
if(!empty($stories)) $stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($stories)->fetchAll('id');
if(!empty($bugs)) $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($bugs)->fetchAll('id');
$result = array();
foreach($issues as $issue)
{
$r = new stdclass();
if($issue['type'] == 'task')
{
$task = $tasks[$issue['id']];
$r->id = 'task-' . $task->id;
$r->title = $task->name;
$r->labels = array($this->app->lang->task->common, zget($this->app->lang->task->typeList, $task->type));
$r->pri = $task->pri;
$r->assignedTo = $this->entry->getAssignees('task', $task);
$r->openedDate = $task->openedDate;
$r->openedBy = $this->entry->getUser($task->openedBy);
$r->lastEditedDate = $task->lastEditedDate < '1970-01-01 01:01:01' ? $task->openedDate : $task->lastEditedDate;
$r->lastEditedBy = $task->lastEditedDate < '1970-01-01 01:01:01' ? $task->openedBy : $task->lastEditedBy;
$r->status = $issue['status'];
$r->url = helper::createLink('task', 'view', "taskID=$task->id");
}
else if($issue['type'] == 'story')
{
$story = $stories[$issue['id']];
$r->id = 'story-' . $story->id;
$r->title = $story->title;
$r->labels = array($this->app->lang->story->common, zget($this->app->lang->story->categoryList, $story->category));
$r->pri = $story->pri;
$r->assignedTo = $this->entry->getAssignees('story', $story);
$r->openedDate = $story->openedDate;
$r->openedBy = $this->entry->getUser($story->openedBy);
$r->lastEditedDate = $story->lastEditedDate < '1970-01-01 01:01:01' ? $story->openedDate : $story->lastEditedDate;
$r->lastEditedBy = $story->lastEditedDate < '1970-01-01 01:01:01' ? $story->openedBy : $story->lastEditedBy;
$r->status = $issue['status'];
$r->url = helper::createLink('story', 'view', "storyID=$story->id");
}
else if($issue['type'] == 'bug')
{
$bug = $bugs[$issue['id']];
$r->id = 'bug-' . $bug->id;
$r->title = $bug->title;
$r->labels = array($this->app->lang->bug->common, zget($this->app->lang->bug->typeList, $bug->type));
$r->pri = $bug->pri;
$r->assignedTo = $this->entry->getAssignees('bug', $bug);
$r->openedDate = $bug->openedDate;
$r->openedBy = $this->entry->getUser($bug->openedBy);
$r->lastEditedDate = $bug->lastEditedDate < '1970-01-01 01:01:01' ? $bug->openedDate : $bug->lastEditedDate;
$r->lastEditedBy = $bug->lastEditedDate < '1970-01-01 01:01:01' ? $bug->openedBy : $bug->lastEditedBy;
$r->status = $issue['status'];
$r->url = helper::createLink('bug', 'view', "bugID=$bug->id");
}
$result[] = $this->format($r, 'openedDate:time,lastEditedDate:time');
}
return $result;
}
/**
* Get key in array by value.
*
* @param string $value
* @param array $array
* @access private
* @return string
*/
private function getKey($value, $array)
{
foreach($array as $key => $values)
{
if($values and strpos($values, $value) !== FALSE) return $key;
}
return '';
}
}
+3 -3
View File
@@ -11,18 +11,18 @@ class projectsEntry extends entry
public function get()
{
$control = $this->loadController('project', 'browse');
$control->browse();
$control->browse(0, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$pager = $data->data->pager;
$pager = $data->data->pager;
$result = array();
foreach($data->data->projectStats as $project)
{
$result[] = $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'projects' => $result));
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => (int)$pager->recPerPage, 'projects' => $result));
}
if(isset($data->status) and $data->status == 'fail')
+1 -1
View File
@@ -11,7 +11,7 @@ class storiesEntry extends entry
public function get($productID)
{
$control = $this->loadController('product', 'browse');
$control->browse($productID);
$control->browse($productID, $this->param('branch', 0), $this->param('type', ''), 0, 'story', $this->param('order', ''), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
+1 -1
View File
@@ -11,7 +11,7 @@ class tasksEntry extends entry
public function get($executionID)
{
$control = $this->loadController('execution', 'task');
$control->task($executionID, 'all');
$control->task($executionID, $this->param('status', 'all'), 0, $this->param('order', ''), $this->param('total', 0), $this->param('limit', 100), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
+2 -2
View File
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
if(!function_exists('getWebRoot')){function getWebRoot(){}}
/* 基本设置。Basic settings. */
$config->version = '15.2'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->version = '15.3'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
$config->timezone = 'Asia/Shanghai'; // 时区设置。 The time zone setting, for more see http://www.php.net/manual/en/timezones.php.
@@ -109,7 +109,7 @@ $config->framework->purifier = true; // 是否对数据做purifier处理
$config->framework->logDays = 14; // 日志文件保存的天数。 The days to save log files.
$config->framework->autoRepairTable = true;
$config->framework->autoLang = false;
$config->framework->filterCSRF = false;
$config->framework->filterCSRF = true;
$config->framework->setCookieSecure = true;
$config->framework->sendXCTO = true; // Send X-Content-Type-Options header.
$config->framework->sendXXP = true; // Send X-XSS-Protection header.
+12
View File
@@ -36,6 +36,7 @@ $filter->branch = new stdclass();
$filter->qa = new stdclass();
$filter->story = new stdclass();
$filter->task = new stdclass();
$filter->execution = new stdclass();
$filter->testcase = new stdclass();
$filter->program = new stdclass();
$filter->project = new stdclass();
@@ -57,6 +58,7 @@ $filter->git = new stdclass();
$filter->svn = new stdclass();
$filter->search = new stdclass();
$filter->gitlab = new stdclass();
$filter->ci = new stdclass();
$filter->block->default = new stdclass();
$filter->block->main = new stdclass();
@@ -112,6 +114,7 @@ $filter->svn->cat = new stdclass();
$filter->svn->diff = new stdclass();
$filter->task->create = new stdclass();
$filter->task->export = new stdclass();
$filter->execution->story = new stdclass();
$filter->testcase->default = new stdclass();
$filter->testcase->create = new stdclass();
$filter->testcase->browse = new stdclass();
@@ -133,6 +136,7 @@ $filter->repo->ajaxsynccommit = new stdclass();
$filter->search->index = new stdclass();
$filter->gitlab->webhook = new stdclass();
$filter->gitlab->importissue = new stdclass();
$filter->ci->checkCompileStatus = new stdclass();
$filter->bug->batchcreate->cookie['preBranch'] = 'int';
$filter->bug->browse->cookie['bugModule'] = 'int';
@@ -187,6 +191,7 @@ $filter->project->default->cookie['lastProject'] = 'int';
$filter->project->default->cookie['lastPRJ'] = 'int';
$filter->project->default->cookie['projectMode'] = 'code';
$filter->project->browse->cookie['involved'] = 'code';
$filter->project->browse->cookie['projectType'] = 'code';
$filter->project->story->cookie['storyModuleParam'] = 'int';
$filter->project->story->cookie['storyPreProjectID'] = 'int';
$filter->project->story->cookie['storyProductParam'] = 'int';
@@ -212,6 +217,12 @@ $filter->story->export->cookie['checkedItem'] = 'reg::checked';
$filter->task->create->cookie['lastTaskModule'] = 'int';
$filter->task->export->cookie['checkedItem'] = 'reg::checked';
$filter->execution->story->cookie['storyPreExecutionID'] = 'int';
$filter->execution->story->cookie['storyModuleParam'] = 'int';
$filter->execution->story->cookie['storyProductParam'] = 'int';
$filter->execution->story->cookie['storyBranchParam'] = 'int';
$filter->execution->story->cookie['executionStoryOrder'] = 'code';
$filter->testcase->browse->cookie['caseModule'] = 'int';
$filter->testcase->browse->cookie['caseSuite'] = 'int';
$filter->testcase->browse->cookie['preBranch'] = 'int';
@@ -323,3 +334,4 @@ $filter->gitlab->importissue->get['product'] = 'string';
$filter->gitlab->importissue->get['project'] = 'int';
$filter->gitlab->importissue->get['repo'] = 'int';
$filter->ci->checkCompileStatus->get['gitlabOnly'] = 'string';
+4 -1
View File
@@ -33,9 +33,12 @@ $routes['/tasks/:id/finish'] = 'taskFinish';
$routes['/users'] = 'users';
$routes['/users/:id'] = 'user';
$routes['/user'] = 'user';
$routes['/my'] = 'my';
$routes['/programs'] = 'programs';
$routes['/programs/:id'] = 'program';
$routes['/issues/:issueID'] = 'projectIssue';
$routes['/projects/:projectID/issues'] = 'projectIssues';
$config->routes = $routes;
+5 -2
View File
@@ -98,8 +98,8 @@ $config->hourPointCommonList['vi'][0] = 'giờ';
$config->hourPointCommonList['vi'][1] = 'điểm';
$config->hourPointCommonList['vi'][2] = 'function point';
$config->manualUrl['home'] = 'https://www.zentao.net/book/zentaopmshelp.html?fullScreen=zentao';
$config->manualUrl['int'] = 'https://www.zentao.pm/book/zentaomanual/zentao-installation-11.html?fullScreen=zentao';
$config->manualUrl['home'] = 'https://www.zentao.net/book/zentaopmshelp.html?fullScreen=zentao&theme=' . $_COOKIE['theme'];
$config->manualUrl['int'] = 'https://www.zentao.pm/book/zentaomanual/zentao-installation-11.html?fullScreen=zentao&theme=' . $_COOKIE['theme'];
/* Supported charsets. */
$config->charsets['zh-cn']['utf-8'] = 'UTF-8';
@@ -137,6 +137,8 @@ $config->openMethods[] = 'sso.gettodolist';
$config->openMethods[] = 'file.read';
$config->openMethods[] = 'index.changelog';
$config->openMethods[] = 'my.preference';
$config->openMethods[] = 'my.changepassword';
$config->openMethods[] = 'my.profile';
/* Define the tables. */
define('TABLE_COMPANY', '`' . $config->db->prefix . 'company`');
@@ -226,6 +228,7 @@ if(!defined('TABLE_SEARCHDICT')) define('TABLE_SEARCHDICT', $config->db->prefi
$config->objectTables['product'] = TABLE_PRODUCT;
$config->objectTables['productplan'] = TABLE_PRODUCTPLAN;
$config->objectTables['story'] = TABLE_STORY;
$config->objectTables['requirement'] = TABLE_STORY;
$config->objectTables['release'] = TABLE_RELEASE;
$config->objectTables['program'] = TABLE_PROJECT;
$config->objectTables['project'] = TABLE_PROJECT;
File diff suppressed because it is too large Load Diff
+3
View File
@@ -3,3 +3,6 @@ ADD `engine` varchar(20) NOT NULL AFTER `frame`,
CHANGE `jkHost` `server` mediumint(0) UNSIGNED NOT NULL AFTER `frame`,
CHANGE `jkJob` `pipeline` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `server`;
UPDATE `zt_job` SET `engine` = 'jenkins' WHERE `engine` = '';
UPDATE `zt_cron` SET `remark` = '执行DevOps构建任务' WHERE `remark` = '执行Jenkins任务';
UPDATE `zt_cron` SET `remark` = '同步DevOps构建任务状态' WHERE `remark` = '同步Jenkins任务状态';
+1
View File
@@ -0,0 +1 @@
ALTER TABLE `zt_testtask` ADD `realFinishedDate` datetime NOT NULL AFTER `end`;
+15 -3
View File
@@ -858,7 +858,7 @@ CREATE TABLE IF NOT EXISTS `zt_searchdict` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_searchindex`;
CREATE TABLE IF NOT EXISTS `zt_searchindex` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`objectType` char(20) NOT NULL,
`objectID` mediumint(9) NOT NULL,
`title` text NOT NULL,
@@ -1153,6 +1153,7 @@ CREATE TABLE IF NOT EXISTS `zt_testtask` (
`pri` tinyint(3) unsigned NOT NULL default '0',
`begin` date NOT NULL,
`end` date NOT NULL,
`realFinishedDate` datetime NOT NULL,
`mailto` text,
`desc` text NOT NULL,
`report` text NOT NULL,
@@ -1325,8 +1326,8 @@ INSERT INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type
('*/5', '*', '*', '*', '*', 'moduleName=admin&methodName=deleteLog', '删除过期日志', 'zentao', 1, 'normal', '0000-00-00 00:00:00'),
('1', '1', '*', '*', '*', 'moduleName=todo&methodName=createCycle', '生成周期性待办', 'zentao', 1, 'normal', '0000-00-00 00:00:00'),
('1', '0', '*', '*', '*', 'moduleName=ci&methodName=initQueue', '创建周期性任务', 'zentao', 1, 'normal', '0000-00-00 00:00:00'),
('*/5', '*', '*', '*', '*', 'moduleName=ci&methodName=checkCompileStatus', '同步Jenkins任务状态', 'zentao', 1, 'normal', '0000-00-00 00:00:00'),
('*/5', '*', '*', '*', '*', 'moduleName=ci&methodName=exec', '执行Jenkins任务', 'zentao', 1, 'normal', '0000-00-00 00:00:00');
('*/5', '*', '*', '*', '*', 'moduleName=ci&methodName=checkCompileStatus', '同步DevOps构建任务状态', 'zentao', 1, 'normal', '0000-00-00 00:00:00'),
('*/5', '*', '*', '*', '*', 'moduleName=ci&methodName=exec', '执行DevOps构建任务', 'zentao', 1, 'normal', '0000-00-00 00:00:00');
INSERT INTO `zt_group` (`id`, `name`, `role`, `desc`) VALUES
(1, 'ADMIN', 'admin', 'for administrator'),
@@ -1445,6 +1446,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(1,'doc','edit'),
(1,'doc','editLib'),
(1,'doc','index'),
(1,'doc','tableContents'),
(1,'doc','objectLibs'),
(1,'doc','showFiles'),
(1,'doc','sort'),
@@ -1860,6 +1862,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(2,'doc','create'),
(2,'doc','edit'),
(2,'doc','index'),
(2,'doc','tableContents'),
(2,'doc','objectLibs'),
(2,'doc','showFiles'),
(2,'doc','view'),
@@ -2055,6 +2058,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(3,'doc','create'),
(3,'doc','edit'),
(3,'doc','index'),
(3,'doc','tableContents'),
(3,'doc','objectLibs'),
(3,'doc','showFiles'),
(3,'doc','view'),
@@ -2305,6 +2309,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(4,'doc','edit'),
(4,'doc','editLib'),
(4,'doc','index'),
(4,'doc','tableContents'),
(4,'doc','objectLibs'),
(4,'doc','showFiles'),
(4,'doc','view'),
@@ -2599,6 +2604,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(5,'doc','edit'),
(5,'doc','editLib'),
(5,'doc','index'),
(5,'doc','tableContents'),
(5,'doc','objectLibs'),
(5,'doc','showFiles'),
(5,'doc','view'),
@@ -2921,6 +2927,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(6,'doc','edit'),
(6,'doc','editLib'),
(6,'doc','index'),
(6,'doc','tableContents'),
(6,'doc','objectLibs'),
(6,'doc','showFiles'),
(6,'doc','view'),
@@ -3197,6 +3204,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(7,'doc','edit'),
(7,'doc','editLib'),
(7,'doc','index'),
(7,'doc','tableContents'),
(7,'doc','objectLibs'),
(7,'doc','showFiles'),
(7,'doc','view'),
@@ -3485,6 +3493,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(8,'doc','edit'),
(8,'doc','editLib'),
(8,'doc','index'),
(8,'doc','tableContents'),
(8,'doc','objectLibs'),
(8,'doc','showFiles'),
(8,'doc','view'),
@@ -3768,6 +3777,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(9,'doc','edit'),
(9,'doc','editLib'),
(9,'doc','index'),
(9,'doc','tableContents'),
(9,'doc','objectLibs'),
(9,'doc','showFiles'),
(9,'doc','view'),
@@ -3980,6 +3990,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(10,'doc','allLibs'),
(10,'doc','browse'),
(10,'doc','index'),
(10,'doc','tableContents'),
(10,'doc','objectLibs'),
(10,'doc','showFiles'),
(10,'doc','view'),
@@ -4101,6 +4112,7 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(11,'doc','allLibs'),
(11,'doc','browse'),
(11,'doc','index'),
(11,'doc','tableContents'),
(11,'doc','objectLibs'),
(11,'doc','showFiles'),
(11,'doc','view'),
+106 -1
View File
@@ -1,3 +1,108 @@
2021-08-04 15.3
完成的需求
27092 文档下拉菜单中增加附件库的选择
26857 禅道右下角显示禅道版本号方便商务支持同事排查问题节省交互时间
26773 在文档全屏的时候显示上一篇、下一篇的操作
26772 文档增加全屏查看功能
26771 文档大纲支持展开/收起功能
26770 文档详情页面增加文档大纲功能
15718 项目集列表中,负责人名称前显示头像
26766 目录的操作按钮放置到目录页面的右侧
26765 对创建下拉菜单中的内容进行分组
26764 在具体的文档库页面增加我的收藏快速入口
26763 文档库增加目录页面
26469 文档名称的font-size使用20px
26467 编辑文档页面,去掉三级导航
26465 创建文档页面,去掉三级导航
26463 手册模块中增加目录的高度
26461 文档模块中增加目录信息
26400 创建文档名称调整为创建
26768 将关键词作为标签放到文档名称下面
27489 实现附件库的卡片展示方式
27488 实现附件库的列表展示方式
27477 执行二级导航中执行名称前显示项目名称
27476 禅道升级新版本后,引导用户使用青春蓝的主题
27474 禅道更新全新icon
27433 禅道新增配色样式
27432 实现项目卡片展示方式
27098 项目库下拉菜单中可以搜索和查看已结束的项目文档
27430 项目列表增加卡片视图的切换方式
27429 调整产品列表中字段的显示顺序
27428 产品列表中增加项目集、产品线列表的数据统计
27427 产品列表中将编辑产品线调整到添加产品按钮前面
27426 项目集列表中项目名称前的项目icon调整为模型icon
27425 项目集列表增加进度显示
27424 调整项目集列表中字段的显示顺序
27421 项目集列表调整项目和项目集添加方式的位置
27389 任务bug列表把截止日期展示出来
27270 升级程序中的sql需要兼容引擎只支持innodb的环境
27260 文档目录中在具体的文档前面增加icon
27431 项目卡片视图中增加项目集筛选菜单
修复的Bug
11198 升级到旗舰版后系统用户默认权限没有添加导致用户登录后无法正常访问
12197 项目下新建文档保存后页面未正确展示
12318 max2.0rc1 关于工作流:1.字段-公示类型的,无法生效 2.详情 动作界面,编辑--区块,无法添加
12573 客户端消息右键创建任务页面所属执行没有列出阶段
12846 word类型文档编辑页面文档类型没有默认值
13141 新版本动作界面附件字段不显示
13386 biz4.1按老版本习惯升级后,待办转任务未关联处项目数据
13460 工作流项目流程字段和动作展示问题
13536 请假详情页点击拒绝后跳转到了编辑页
13039 任务看板导出和页面显示内容不一致
13092 所有产品、项目不支持导出
13377 pro7.1按老版本习惯升级后,新建产品保存时有错误提示信息
12807 数据量多的时候创建索引时间很久
12476 客户端中进入禅道相关页面加载错误
12930 年底统计报表中需求创建数量不对
13420 集成gitlab后查看代码页面报错
13638 gitlab类型的版本库页面有代码报错
13639 关联issue页面有代码报错
13722 执行动态页面报错
13647 创建需求、任务、Bug同步到gitlab,有js报错
11269 beta3中有测试代码导致报错
12412 主表设计下载的模板全是报错
12422 主表字段导入确认页面显示问题
12673 干系人相关动态文案需修改
12928 权限分组列表显示的数据不全
13059 创建的scrum项目无法保存
13096 项目矩阵显示了与该项目无关的需求
13097 任务不能记录日志
13238 问题确认弹窗显示异常,无法操作
13239 问题解决方式为转任务后,保存提示开始时间不能为空
13278 旗舰版新增工作流发布在执行二级导航时,页面跳转有问题
13332 瀑布模式单独创建阶段还需要维护阶段代号
13346 通过阶段设置插入阶段会修改之前阶段的ID
13512 评审页面查看用例所属的产品时闪现代码
13523 集成测试用例评审页面查看用例时有代码报错
13530 自定义配置的模板类型发起评审时也列出来了
13532 评审用户需求说明书页面有代码报错
13538 评审软件需求说明书页面有代码报错
13717 给瀑布项目会显示“所属迭代”
13486 创建FAQ页面有代码报错
13559 项目内置流程新增字段在列表不显示
13608 工作流新增字段默认值设置不生效
12201 统计里报表涉及到项目的都显示为执行了
13213 专业版App发布详情页有报错
13243 变更需求导出 word 最后编辑日期为 0000-00-00
13244 需求导出 word 展示模块取值错误
13258 需求导出 word 图片大小适配问题
13265 产品项目列表的迭代改为项目
13564 自定义报表中项目计划完成日期统计有问题
13724 移动端需求排序报错
12106 批量编辑需求阶段显示报错
13716 权限名称和对应页面菜单名字不一致
6900 搜索用户名时,不显示用户名信息
13045 新建产品是否需要强制关联产品规则统一
13216 php5.3环境代码兼容问题
13516 早上在执行下面操作完成第一个任务后会提示你无权限访问该迭代
13616 再次编辑飞书配置时丢失秘钥
13632 测试单中查看报表报错
13659 测试单生成报表报错
13701 批量编辑任务页面起止日期字段显示不全
13703 甘特图百分比统计错误
13721 按老版本习惯升级后,jenkins服务器数据丢失
13725 测试-用例-导出模板-CSV文件名字拼错
2021-07-20 15.2
完成的需求
27297 调整产品下拉菜单信息展现方式
@@ -2122,7 +2227,7 @@
1601 版本列表区块,版本ID显示为1、2,统一为001、002
1600 Bug详情页,解决操作没有图标,严重程度图标数字太靠上
1599 右上角,用户名--切换语言。显示的是英文 language ,简体和繁体下应显示为中文
1597 永久关闭区块的提示文案,第二句开头少一个‘关’字,最后少个句号 [BUG#1597]
1597 永久关闭区块的提示文案,第二句开头少一个‘关’字,最后少个句号
1595 我的地盘里,编辑页面的 保存和取消 按钮的间距宽度比较宽,是否整个系统里统一一下保存和取消(返回)的间距宽度
1592 我的待办区块,添加待办成功后,跳转到区块底部
1591 我的待办区块,点击待办名称,然后编辑,待办名称必填项与边框有重叠
+32 -6
View File
@@ -10,6 +10,8 @@ class entry extends baseEntry
parent::__construct();
if(!isset($this->app->user)) $this->sendError(401, 'Unauthorized');
$this->dao = $this->loadModel('common')->dao;
}
}
@@ -47,8 +49,9 @@ class baseEntry
*/
public function __construct()
{
global $app;
$this->app = $app;
global $app, $config;
$this->app = $app;
$this->config = $config;
$this->parseRequestBody();
}
@@ -83,6 +86,20 @@ class baseEntry
return $defaultValue;
}
/**
* 设置请求参数
* Set request param.
*
* @param string $key
* @param mixed $value
* @access public
* @return mixed
*/
public function setParam($key, $value)
{
$_GET[$key] = $value;
}
/**
* 解析请求数据
* Parse body of request data.
@@ -202,6 +219,17 @@ class baseEntry
$this->send($code, $response);
}
/**
* Send 404 response.
*
* @access public
* @return void
*/
public function send404()
{
$this->sendError(404, '404 Not found');
}
/**
* 加载禅道的控制器类
* Load controller of zentaopms
@@ -305,9 +333,8 @@ class baseEntry
*/
public function getData()
{
$output = ob_get_clean();
$output = helper::removeUTF8Bom(ob_get_clean());
$output = json_decode($output);
if(isset($output->data)) $output->data = json_decode($output->data);
return $output;
@@ -476,9 +503,8 @@ class baseEntry
return gmdate("Y-m-d\TH:i:s\Z", strtotime($value));
}
return $value;
case 'int':
case 'bool':
return $value;
return boolval($value) ? true : false;
default:
return $value;
}
+219
View File
@@ -0,0 +1,219 @@
<?php
/**
* ZenTaoAPI的helper类。
* The helper class file of ZenTao API.
*
* The author disclaims copyright to this source code. In place of
* a legal notice, here is a blessing:
*
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
*/
include dirname(dirname(__FILE__)) . '/base/helper.class.php';
class helper extends baseHelper
{
public static function getViewType($source = false)
{
global $config, $app;
if($config->requestType != 'GET')
{
$pathInfo = $app->getPathInfo();
if(!empty($pathInfo))
{
$dotPos = strrpos($pathInfo, '.');
if($dotPos)
{
$viewType = substr($pathInfo, $dotPos + 1);
}
else
{
$config->default->view = $config->default->view == 'mhtml' ? 'html' : $config->default->view;
}
}
}
elseif($config->requestType == 'GET')
{
if(isset($_GET[$config->viewVar]))
{
$viewType = $_GET[$config->viewVar];
}
else
{
/* Set default view when url has not module name. such as only domain. */
$config->default->view = ($config->default->view == 'mhtml' and isset($_GET[$config->moduleVar])) ? 'html' : $config->default->view;
}
}
if($source and isset($viewType)) return $viewType;
if(isset($viewType) and strpos($config->views, ',' . $viewType . ',') === false) $viewType = $config->default->view;
return isset($viewType) ? $viewType : $config->default->view;
}
/**
* Encode json for $.parseJSON
*
* @param array $data
* @param int $options
* @static
* @access public
* @return string
*/
public static function jsonEncode4Parse($data, $options = 0)
{
$json = json_encode($data);
if($options) $json = str_replace(array("'", '"'), array('\u0027', '\u0022'), $json);
$escapers = array("\\", "/", "\"", "'", "\n", "\r", "\t", "\x08", "\x0c", "\\\\u");
$replacements = array("\\\\", "\\/", "\\\"", "\'", "\\n", "\\r", "\\t", "\\f", "\\b", "\\u");
return str_replace($escapers, $replacements, $json);
}
/**
* Convert encoding.
*
* @param string $string
* @param string $fromEncoding
* @param string $toEncoding
* @static
* @access public
* @return string
*/
public static function convertEncoding($string, $fromEncoding, $toEncoding = 'utf-8')
{
$toEncoding = str_replace('utf8', 'utf-8', $toEncoding);
if(function_exists('mb_convert_encoding'))
{
/* Remove like utf-8//TRANSLIT. */
$position = strpos($toEncoding, '//');
if($position !== false) $toEncoding = substr($toEncoding, 0, $position);
/* Check string encoding. */
$encodings = array_merge(array('GB2312','GBK','BIG5'), mb_list_encodings());
$encoding = strtolower(mb_detect_encoding($string, $encodings));
if($encoding == $toEncoding) return $string;
return mb_convert_encoding($string, $toEncoding, $encoding);
}
elseif(function_exists('iconv'))
{
if($fromEncoding == $toEncoding) return $string;
$convertString = @iconv($fromEncoding, $toEncoding, $string);
/* iconv error then return original. */
if(!$convertString) return $string;
return $convertString;
}
return $string;
}
/**
* Calculate two working days.
*
* @param string $begin
* @param string $end
*
* @return bool|float
*/
public static function workDays($begin, $end)
{
$begin = strtotime($begin);
$end = strtotime($end);
if($end < $begin) return false;
$double = floor(($end - $begin) / (7 * 24 * 3600));
$begin = date('w', $begin);
$end = date('w', $end);
$end = $begin > $end ? $end + 5 : $end;
return $double * 5 + $end - $begin;
}
/**
* Unify string to standard chars.
*
* @param string $string
* @param string $to
* @static
* @access public
* @return string
*/
public static function unify($string, $to = ',')
{
$labels = array('_', '、', ' ', '-', '?', '@', '&', '%', '~', '`', '+', '*', '/', '\\', '', '。');
$string = str_replace($labels, $to, $string);
return preg_replace("/[{$to}]+/", $to, trim($string, $to));
}
/**
* Create url of issue.
*
* @param string $module
* @param string $method
* @param string $vars
* @static
* @access public
* @return string
*/
static public function createLink($moduleName, $methodName = 'index', $vars = '', $viewType = '', $onlyBody = false)
{
global $config;
$link = parent::createLink($moduleName, $methodName, $vars, 'html');
$pos = strpos($link, '.php');
/* The requestTypes are: GET, PATH_INFO2, PATH_INFO */
if($config->requestType == 'GET')
{
$link = '/index' . substr($link, $pos);
}
elseif($config->requestType == 'PATH_INFO2')
{
$link = substr($link, $pos + 4);
}
return common::getSysURL() . $link;
}
}
/**
* 检查是否是onlybody模式。
* Check exist onlybody param.
*
* @access public
* @return void
*/
function isonlybody()
{
return helper::inOnlyBodyMode();
}
/**
* Format time.
*
* @param int $time
* @param string $format
* @access public
* @return void
*/
function formatTime($time, $format = '')
{
$time = str_replace('0000-00-00', '', $time);
$time = str_replace('00:00:00', '', $time);
if(trim($time) == '') return ;
if($format) return date($format, strtotime($time));
return trim($time);
}
/**
* Fix for session error.
*
* @param int $class
* @access protected
* @return void
*/
function autoloader($class)
{
if(!class_exists($class))
{
if($class == 'post_max_size' or $class == 'max_input_vars') eval('class ' . $class . ' {};');
}
}
spl_autoload_register('autoloader');
+1 -1
View File
@@ -843,7 +843,7 @@ function getWebRoot($full = false)
/**
* 当数组/对象变量$var存在$key项时,返回存在的对应值或设定值,否则返回$key或不存在的设定值。
* When the $var has the $key, return it, esle result one default value.
* When there is a $key in the array/object $var, it returns it or $valueWhenExists, otherwise returns $key or $valueWhenNone.
*
* @param array|object $var
* @param string|int $key
+26 -24
View File
@@ -7,7 +7,7 @@
*
* The author disclaims copyright to this source code. In place of
* a legal notice, here is a blessing:
*
*
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
@@ -17,7 +17,7 @@ class baseModel
/**
* 全局对象$app。
* The global $app object.
*
*
* @var object
* @access public
*/
@@ -26,7 +26,7 @@ class baseModel
/**
* 应用名称$appName。
* The global appName.
*
*
* @var string
* @access public
*/
@@ -35,7 +35,7 @@ class baseModel
/**
* 全局对象$config。
* The global $config object.
*
*
* @var object
* @access public
*/
@@ -44,7 +44,7 @@ class baseModel
/**
* 全局对象$lang。
* The global $lang object.
*
*
* @var object
* @access public
*/
@@ -53,7 +53,7 @@ class baseModel
/**
* 全局对象$dbh,数据库连接句柄。
* The global $dbh object, the database connection handler.
*
*
* @var object
* @access public
*/
@@ -62,7 +62,7 @@ class baseModel
/**
* $dao对象,用于访问或者更新数据库。
* The $dao object, used to access or update database.
*
*
* @var object
* @access public
*/
@@ -71,7 +71,7 @@ class baseModel
/**
* $post对象,用于访问$_POST变量。
* The $post object, used to access the $_POST var.
*
*
* @var object
* @access public
*/
@@ -80,7 +80,7 @@ class baseModel
/**
* $get对象,用于访问$_GET变量。
* The $get object, used to access the $_GET var.
*
*
* @var object
* @access public
*/
@@ -89,7 +89,7 @@ class baseModel
/**
* $session对象,用于访问$_SESSION变量。
* The $session object, used to access the $_SESSION var.
*
*
* @var object
* @access public
*/
@@ -98,7 +98,7 @@ class baseModel
/**
* $server对象,用于访问$_SERVER变量。
* The $server object, used to access the $_SERVER var.
*
*
* @var object
* @access public
*/
@@ -107,7 +107,7 @@ class baseModel
/**
* $cookie对象,用于访问$_COOKIE变量。
* The $cookie object, used to access the $_COOKIE var.
*
*
* @var object
* @access public
*/
@@ -116,7 +116,7 @@ class baseModel
/**
* $global对象,用于访问$_GLOBAL变量。
* The $global object, used to access the $_GLOBAL var.
*
*
* @var object
* @access public
*/
@@ -126,12 +126,12 @@ class baseModel
* 构造方法。
* 1. 将全局变量设为model类的成员变量,方便model的派生类调用;
* 2. 设置$config, $lang, $dbh, $dao。
*
*
* The construct function.
* 1. global the global vars, refer them by the class member such as $this->app.
* 2. set the pathes, config, lang of current module
*
* @param string $appName
* @param string $appName
* @access public
* @return void
*/
@@ -158,7 +158,7 @@ class baseModel
* 这个方法通过去掉该model类名的'ext''model'字符串,来获取当前模块名。
* 不要使用$app->getModuleName(),因为其返回的是用户请求的模块名。
* 另一个model可以通过loadModel()加载进来,与请求的模块名不一致。
*
*
* Get the module name of this model. Not the module user visiting.
*
* This method replace the 'ext' and 'model' string from the model class name, thus get the module name.
@@ -180,7 +180,7 @@ class baseModel
/**
* 设置全局超级变量。
* Set the super vars.
*
*
* @access public
* @return void
*/
@@ -198,7 +198,7 @@ class baseModel
* 比如:loadModel('user')引入user模块的model实例对象,可以通过$this->user来访问它。
*
* Load the model of one module. After loaded, can use $this->$moduleName to visit the model object.
*
*
* @param string $moduleName
* @access public
* @return object|bool the model object or false if model file not exists.
@@ -207,6 +207,7 @@ class baseModel
{
if(empty($moduleName)) return false;
if(empty($appName)) $appName = $this->appName;
$moduleName = strtolower($moduleName);
global $loadedModels;
if(isset($loadedModels[$appName][$moduleName]))
@@ -242,9 +243,9 @@ class baseModel
* And call them by the ext/model/$extension.php like this: $this->loadExtension('myextension')->method().
* You can encrypt the code in ext/model/class/*.class.php.
* Because the framework will merge the extension files in ext/model/*.php to the module/model.php.
*
* @param string $extensionName
* @param string $moduleName
*
* @param string $extensionName
* @param string $moduleName
* @access public
* @return void
*/
@@ -253,8 +254,9 @@ class baseModel
if(empty($extensionName)) return false;
/* 设置扩展的名字和相应的文件。Set extenson name and extension file. */
$extensionName = strtolower($extensionName);
$moduleName = $moduleName ? $moduleName : $this->getModuleName();
$moduleName = strtolower($moduleName);
$extensionName = strtolower($extensionName);
$moduleExtPath = $this->app->getModuleExtPath($this->appName, $moduleName, 'model');
if(!empty($moduleExtPath['site'])) $extensionFile = $moduleExtPath['site'] . 'class/' . $extensionName . '.class.php';
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['common'] . 'class/' . $extensionName . '.class.php';
@@ -278,7 +280,7 @@ class baseModel
/**
* 加载DAO。
* Load DAO.
*
*
* @access public
* @return void
*/
@@ -290,7 +292,7 @@ class baseModel
/**
* 删除记录。
* Delete one record.
*
*
* @param string $table the table name
* @param string $id the id value of the record to be deleted
* @access public
+17 -14
View File
@@ -609,8 +609,12 @@ class baseRouter
if($this->config->framework->filterCSRF)
{
$httpType = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? 'https' : 'http';
if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') $httpType = 'https';
if(isset($_SERVER['REQUEST_SCHEME']) and strtolower($_SERVER['REQUEST_SCHEME']) == 'https') $httpType = 'https';
$httpHost = $_SERVER['HTTP_HOST'];
if((!defined('RUN_MODE') or RUN_MODE != 'api') and strpos($this->server->http_referer, "$httpType://$httpHost") !== 0) $_FILES = $_POST = array();
$isAPI = (defined('RUN_MODE') && RUN_MODE == 'api') || isset($_GET[$this->config->sessionVar]);
if(!$isAPI && strpos($this->server->http_referer, "$httpType://$httpHost") !== 0) $_FILES = $_POST = array();
}
$_FILES = validater::filterFiles();
@@ -849,23 +853,22 @@ class baseRouter
*/
public function startSession()
{
if(!defined('SESSION_STARTED'))
{
/* If request header has token, use it as session for authentication. */
if(isset($_SERVER['HTTP_TOKEN'])) session_id($_SERVER['HTTP_TOKEN']);
if(defined('SESSION_STARTED')) return;
$sessionName = $this->config->sessionVar;
session_name($sessionName);
session_set_cookie_params(0, $this->config->webRoot, '', $this->config->cookieSecure, true);
if($this->config->customSession) session_save_path($this->getTmpRoot() . 'session');
session_start();
/* If request header has token, use it as session for authentication. */
if(isset($_SERVER['HTTP_TOKEN'])) session_id($_SERVER['HTTP_TOKEN']);
$this->sessionID = session_id();
$sessionName = $this->config->sessionVar;
session_name($sessionName);
session_set_cookie_params(0, $this->config->webRoot, '', $this->config->cookieSecure, true);
if($this->config->customSession) session_save_path($this->getTmpRoot() . 'session');
session_start();
if(isset($_GET[$this->config->sessionVar])) helper::restartSession($_GET[$this->config->sessionVar]);
$this->sessionID = session_id();
define('SESSION_STARTED', true);
}
if(isset($_GET[$this->config->sessionVar])) helper::restartSession($_GET[$this->config->sessionVar]);
define('SESSION_STARTED', true);
}
/**
+12 -13
View File
@@ -513,11 +513,9 @@ class router extends baseRouter
if($methodName == 'batchOperate') array_unshift($params, $this->rawMethod); // $params = array('close', 1);
if($methodName == 'browse')
{
if(!(isset($params[0]) and $params[0] == 'bysearch'))
{
array_unshift($params, 'browse');
}
if(!(isset($params[0]) and $params[0] == 'bysearch')) array_unshift($params, 'browse');
}
array_unshift($params, $this->rawModule); // $params = array($module, 'close', 1);
array_unshift($params, $methodName); // $params = array('operate', $module, 'close', 1);
array_unshift($params, $moduleName); // $params = array('flow', 'operate', $module, 'close', 1);
@@ -541,22 +539,23 @@ class router extends baseRouter
/* Prepend other params. */
if($methodName == 'browse')
{
if(isset($params['label']) and $params['label'] == 'bysearch')
{
$params['label'] = '';
$params['mode'] = 'bysearch';
}
else
{
$params['mode'] = 'browse';
}
if(!(isset($params['mode']) and $params['mode'] == 'bysearch')) $params['mode'] = 'browse';
}
$params['module'] = $this->rawModule; // $param = array('label' => 1, 'mode' => 'search', 'module' => $module);
$params[$this->config->methodVar] = $methodName; // $param = array('label' => 1, 'mode' => 'search', 'module' => $module, 'f' => 'browse');
$params[$this->config->moduleVar] = $moduleName; // $param = array('label' => 1, 'mode' => 'search', 'module' => $module, 'f' => 'browse', 'm' => 'flow');
$params = array_reverse($params); // $params = array('m' => 'flow', 'f' => 'browse', 'module' => $module, 'mode' => 'search', 'label' => 1);
/* Reset $_GET for setParamsByGET. */
$get = $params;
foreach($_GET as $key => $value)
{
if(!isset($get[$key])) $get[$key] = $value;
}
$_GET = $get;
$this->URI = $path . '?' . http_build_query($params); // $this->URI = '/index.php?m=flow&f=browse&module=$module&mode=search&label=1';
}
}
+3 -3
View File
@@ -131,10 +131,10 @@ class basePager
$this->setModuleName();
$this->setMethodName();
$this->setRecTotal($recTotal);
$this->setRecPerPage($recPerPage);
$this->setRecTotal((int)$recTotal);
$this->setRecPerPage((int)$recPerPage);
$this->setPageTotal();
$this->setPageID($pageID);
$this->setPageID((int)$pageID);
}
/**
+8 -8
View File
@@ -5,7 +5,7 @@
*
* The author disclaims copyright to this source code. In place of
* a legal notice, here is a blessing:
*
*
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
@@ -15,7 +15,7 @@ helper::import(dirname(dirname(__FILE__)) . '/base/pager/pager.class.php');
/**
* pager类.
* Pager class.
*
*
* @package framework
*/
class pager extends basePager
@@ -23,7 +23,7 @@ class pager extends basePager
/**
* 设置模块名。
* Set the $moduleName property.
*
*
* @access public
* @return void
*/
@@ -44,7 +44,7 @@ class pager extends basePager
/**
* 设置方法名。
* Set the $methodName property.
*
*
* @access public
* @return void
*/
@@ -65,7 +65,7 @@ class pager extends basePager
/**
* 如果设置了请求的原始模块名和方法名,则去掉module参数,以便分页功能生成原始请求的URL而不是转换后的工作流URL。
* If the original module name and method name of the request are set, the module parameter is removed so that
* the paging function generates the URL of the original request instead of the converted workflow URL.
* the paging function generates the URL of the original request instead of the converted workflow URL.
*
* @access public
* @return void
@@ -87,9 +87,9 @@ class pager extends basePager
/**
* Show pager.
*
* @param string $align
* @param string $type
*
* @param string $align
* @param string $type
* @access public
* @return void
*/
+9 -3
View File
@@ -111,6 +111,7 @@ class gitlab
if(!empty($commits))
{
$commit = $commits[0];
$file->revision = $commit->id;
$file->committer = $commit->committer_name;
$file->comment = $commit->message;
$file->date = date('Y-m-d H:i:s', strtotime($commit->committed_date));
@@ -168,10 +169,15 @@ class gitlab
$list = $this->fetch($api, $params);
if(empty($list)) break;
foreach($list as $branch) $branches[$branch->name] = $branch->name;
foreach($list as $branch)
{
if(!isset($branch->name)) continue;
$branches[$branch->name] = $branch->name;
}
if(count($list) < $params['per_page']) break;
}
if(empty($branches)) $branches['master'] = 'master';
asort($branches);
return $branches;
}
@@ -517,7 +523,8 @@ class gitlab
if(!scm::checkRevision($version)) return array();
$api = "commits";
if(empty($count)) $count = 100;
/* TODO Put getCommits into cron job. And check best size of $count. */
if(empty($count)) $count = 10;
$params = array();
$params['ref_name'] = $branch;
@@ -617,7 +624,6 @@ class gitlab
$params->per_page = 100;
$allResults = array();
$files = array();
while(true)
{
$results = $this->fetch($api, $params);
-1
View File
@@ -125,7 +125,6 @@ class GitRepo
$list = execCmd($cmd . ' 2>&1', 'array', $result);
if($result) return array();
$branches = array();
foreach($list as $localBranch)
{
+1
View File
@@ -46,3 +46,4 @@ $config->action->majorList['execution'] = array('opened', 'edited');
$config->action->needGetProjectType = 'build,task,bug,case,testcase,caselib,testtask,testsuite,testreport,doc,issue,release,risk,design,opportunity,trainplan,gapanalysis,researchplan,researchreport,';
$config->action->needGetRelateField = ',story,productplan,release,task,build,bug,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,';
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,pipeline,jenkins,';
+1
View File
@@ -441,6 +441,7 @@ $lang->action->dynamicAction->doc['hidden'] = 'Hide Document';
$lang->action->dynamicAction->user['created'] = 'Create User';
$lang->action->dynamicAction->user['edited'] = 'Edit User';
$lang->action->dynamicAction->user['deleted'] = 'Delete User';
$lang->action->dynamicAction->user['login'] = 'Login';
$lang->action->dynamicAction->user['logout'] = 'Logout';
$lang->action->dynamicAction->user['undeleted'] = 'Restore User';
+5 -2
View File
@@ -103,7 +103,9 @@ $lang->action->objectTypes['entry'] = 'Entry';
$lang->action->objectTypes['webhook'] = 'Webhook';
$lang->action->objectTypes['team'] = 'Team';
$lang->action->objectTypes['whitelist'] = 'Whitelist';
$lang->action->objectTypes['pipeline'] = 'GitLib';
$lang->action->objectTypes['pipeline'] = 'GitLab';
$lang->action->objectTypes['gitlab'] = 'GitLab';
$lang->action->objectTypes['jenkins'] = 'Jenkins';
/* Used to describe operation history. */
$lang->action->desc = new stdclass();
@@ -445,6 +447,7 @@ $lang->action->dynamicAction->doc['hidden'] = 'Hide Document';
$lang->action->dynamicAction->user['created'] = 'Create User';
$lang->action->dynamicAction->user['edited'] = 'Edit User';
$lang->action->dynamicAction->user['deleted'] = 'Delete User';
$lang->action->dynamicAction->user['login'] = 'Login';
$lang->action->dynamicAction->user['logout'] = 'Logout';
$lang->action->dynamicAction->user['undeleted'] = 'Restore User';
@@ -477,7 +480,7 @@ $lang->action->label->testtask = 'Request|testtask|view|caseID=%s';
$lang->action->label->testsuite = 'Test Suite|testsuite|view|suiteID=%s';
$lang->action->label->caselib = 'Case Library|caselib|view|libID=%s';
$lang->action->label->todo = 'Todo|todo|view|todoID=%s';
$lang->action->label->doclib = 'Doc Library|doc|browse|libID=%s';
$lang->action->label->doclib = 'Doc Library|doc|objectLibs|type=%s&objectID=%s&libID=%s&docID=&version=&appendLib=%s';
$lang->action->label->doc = 'Doc|doc|view|docID=%s';
$lang->action->label->user = 'User|user|view|account=%s';
$lang->action->label->testreport = 'Report|testreport|view|report=%s';
+1
View File
@@ -454,6 +454,7 @@ $lang->action->dynamicAction->doc['hidden'] = 'Masquer Document';
$lang->action->dynamicAction->user['created'] = 'Créer User';
$lang->action->dynamicAction->user['edited'] = 'Editer User';
$lang->action->dynamicAction->user['deleted'] = 'Delete User';
$lang->action->dynamicAction->user['login'] = 'Connexion';
$lang->action->dynamicAction->user['logout'] = 'Déconnexion';
$lang->action->dynamicAction->user['undeleted'] = 'Restaure User';
+1
View File
@@ -441,6 +441,7 @@ $lang->action->dynamicAction->doc['hidden'] = 'Ẩn tài liệu';
$lang->action->dynamicAction->user['created'] = 'Tạo người dùng';
$lang->action->dynamicAction->user['edited'] = 'Sửa người dùng';
$lang->action->dynamicAction->user['deleted'] = 'Delete User';
$lang->action->dynamicAction->user['login'] = 'Đăng nhập';
$lang->action->dynamicAction->user['logout'] = 'Thoát';
$lang->action->dynamicAction->user['undeleted'] = 'Khôi phục người dùng';
+5 -2
View File
@@ -103,7 +103,9 @@ $lang->action->objectTypes['entry'] = '应用';
$lang->action->objectTypes['webhook'] = 'Webhook';
$lang->action->objectTypes['team'] = '团队';
$lang->action->objectTypes['whitelist'] = '白名单';
$lang->action->objectTypes['pipeline'] = 'GitLib';
$lang->action->objectTypes['pipeline'] = 'GitLab';
$lang->action->objectTypes['gitlab'] = 'GitLab';
$lang->action->objectTypes['jenkins'] = 'Jenkins';
/* 用来描述操作历史记录。*/
$lang->action->desc = new stdclass();
@@ -445,6 +447,7 @@ $lang->action->dynamicAction->doc['hidden'] = '隐藏文档';
$lang->action->dynamicAction->user['created'] = '创建用户';
$lang->action->dynamicAction->user['edited'] = '编辑用户';
$lang->action->dynamicAction->user['deleted'] = '删除用户';
$lang->action->dynamicAction->user['login'] = '用户登录';
$lang->action->dynamicAction->user['logout'] = '用户退出';
$lang->action->dynamicAction->user['undeleted'] = '还原用户';
@@ -477,7 +480,7 @@ $lang->action->label->testtask = '测试单|testtask|view|caseID=%s';
$lang->action->label->testsuite = '测试套件|testsuite|view|suiteID=%s';
$lang->action->label->caselib = '用例库|caselib|view|libID=%s';
$lang->action->label->todo = '待办|todo|view|todoID=%s';
$lang->action->label->doclib = '文档库|doc|objectLibs|type=&objectID=&libID=%s';
$lang->action->label->doclib = '文档库|doc|objectLibs|type=%s&objectID=%s&libID=%s&docID=&version=&appendLib=%s';
$lang->action->label->doc = '文档|doc|view|docID=%s';
$lang->action->label->user = '用户|user|view|account=%s';
$lang->action->label->testreport = '报告|testreport|view|report=%s';
+5 -2
View File
@@ -103,7 +103,9 @@ $lang->action->objectTypes['entry'] = '應用';
$lang->action->objectTypes['webhook'] = 'Webhook';
$lang->action->objectTypes['team'] = '團隊';
$lang->action->objectTypes['whitelist'] = '白名單';
$lang->action->objectTypes['pipeline'] = 'GitLib';
$lang->action->objectTypes['pipeline'] = 'GitLab';
$lang->action->objectTypes['gitlab'] = 'GitLab';
$lang->action->objectTypes['jenkins'] = 'Jenkins';
/* 用來描述操作歷史記錄。*/
$lang->action->desc = new stdclass();
@@ -445,6 +447,7 @@ $lang->action->dynamicAction->doc['hidden'] = '隱藏文檔';
$lang->action->dynamicAction->user['created'] = '創建用戶';
$lang->action->dynamicAction->user['edited'] = '編輯用戶';
$lang->action->dynamicAction->user['deleted'] = '刪除用戶';
$lang->action->dynamicAction->user['login'] = '用戶登錄';
$lang->action->dynamicAction->user['logout'] = '用戶退出';
$lang->action->dynamicAction->user['undeleted'] = '還原用戶';
@@ -477,7 +480,7 @@ $lang->action->label->testtask = '測試單|testtask|view|caseID=%s';
$lang->action->label->testsuite = '測試套件|testsuite|view|suiteID=%s';
$lang->action->label->caselib = '用例庫|caselib|view|libID=%s';
$lang->action->label->todo = '待辦|todo|view|todoID=%s';
$lang->action->label->doclib = '文檔庫|doc|objectLibs|type=&objectID=&libID=%s';
$lang->action->label->doclib = '文檔庫|doc|objectLibs|type=%s&objectID=%s&libID=%s&docID=&version=&appendLib=%s';
$lang->action->label->doc = '文檔|doc|view|docID=%s';
$lang->action->label->user = '用戶|user|view|account=%s';
$lang->action->label->testreport = '報告|testreport|view|report=%s';
+44 -9
View File
@@ -36,7 +36,7 @@ class actionModel extends model
$actor = $actor ? $actor : $this->app->user->account;
$actionType = strtolower($actionType);
$actor = $actionType == 'openedbysystem' ? '' : $actor;
$actor = ($actionType == 'openedbysystem' or $actionType == 'closedbysystem') ? '' : $actor;
if($actor == 'guest' and $actionType == 'logout') return false;
$objectType = str_replace('`', '', $objectType);
@@ -49,8 +49,7 @@ class actionModel extends model
$action->date = helper::now();
$action->extra = $extra;
if($objectType == 'story' and $actionType !== 'reviewed' and strpos('reviewclosed,passreviewed,clarifyreviewed', $actionType) !== false) $action->actor = 'System';
if($objectType == 'story' and $actionType !== 'reviewed' and strpos(',reviewclosed,passreviewed,clarifyreviewed,', ",$actionType,") !== false) $action->actor = 'System';
/* Use purifier to process comment. Fix bug #2683. */
$action->comment = fixer::stripDataTags($comment);
@@ -570,12 +569,29 @@ class actionModel extends model
$objectIds = array_unique($objectIds);
$table = $this->config->objectTables[$objectType];
$field = $this->config->action->objectNameFields[$objectType];
$objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs();
if($objectType == 'pipeline')
{
$objectNames['jenkins'] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->andWhere('type')->eq('jenkins')->fetchPairs();
$objectNames['gitlab'] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->andWhere('type')->eq('gitlab')->fetchPairs();
}
else
{
$objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs();
}
}
/* Add name field to the trashes. */
foreach($trashes as $trash) $trash->objectName = isset($objectNames[$trash->objectType][$trash->objectID]) ? $objectNames[$trash->objectType][$trash->objectID] : '';
foreach($trashes as $trash)
{
$objectType = $trash->objectType;
if($objectType == 'pipeline')
{
if(isset($objectNames['gitlab'][$trash->objectID])) $objectType = 'gitlab';
if(isset($objectNames['jenkins'][$trash->objectID])) $objectType = 'jenkins';
$trash->objectType = $objectType;
}
$trash->objectName = isset($objectNames[$objectType][$trash->objectID]) ? $objectNames[$objectType][$trash->objectID] : '';
}
return $trashes;
}
@@ -928,6 +944,7 @@ class actionModel extends model
public function transformActions($actions)
{
$this->app->loadLang('todo');
$this->app->loadLang('stakeholder');
$requirements = array();
/* Get commiters. */
@@ -948,7 +965,7 @@ class actionModel extends model
$objectName = array();
$objectProject = array();
if(strpos($this->config->action->needGetProjectType, $objectType) !== false)
if(strpos(",{$this->config->action->needGetProjectType},", ",{$objectType},") !== false)
{
$objectInfo = $this->dao->select("id, project, $field AS name")->from($table)->where('id')->in($objectIds)->fetchAll();
foreach($objectInfo as $object)
@@ -989,6 +1006,13 @@ class actionModel extends model
if($object->type == 'project') $objectProject[$object->id] = $object->id;
}
}
elseif($objectType == 'stakeholder'){
$objectName = $this->dao->select("t1.id, t2.realname")->from($table)->alias('t1')
->leftJoin(TABLE_USER)->alias('t2')->on("t1.{$field} = t2.account")
->where('t1.id')->in($objectIds)
->fetchPairs();
$objectProject = array();
}
else
{
$objectName = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs();
@@ -1029,7 +1053,7 @@ class actionModel extends model
$objectType = strtolower($action->objectType);
$action->originalDate = $action->date;
$action->date = date(DT_MONTHTIME2, strtotime($action->date));
$action->actionLabel = isset($this->lang->action->label->$actionType) ? $this->lang->action->label->$actionType : $action->action;
$action->actionLabel = isset($this->lang->action->label->$actionType) ? $this->lang->action->label->$actionType : (isset($this->lang->$objectType->$actionType) ? $this->lang->$objectType->$actionType : $action->action);
$action->objectLabel = $objectType;
if(isset($this->lang->action->label->$objectType))
{
@@ -1086,7 +1110,18 @@ class actionModel extends model
}
else
{
$action->objectLink = helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID), '', '', $projectID);
if($action->objectType == 'doclib')
{
$docLib = $this->dao->select('type,product,project,execution,deleted')->from(TABLE_DOCLIB)->where('id')->eq($action->objectID)->fetch();
$docLib->type = $docLib->type == 'execution' ? 'project' : $docLib->type;
$docLib->objectID = strpos('product,project', $docLib->type) !== false ? $docLib->{$docLib->type} : 0;
$appendLib = $docLib->deleted == '1' ? $action->objectID : 0;
$action->objectLink = helper::createLink('doc', 'objectLibs', sprintf($vars, $docLib->type, $docLib->objectID, $action->objectID, $appendLib));
}
else
{
$action->objectLink = helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID), '', '', $projectID);
}
}
$action->objectLabel = $objectLabel;
}
+1 -1
View File
@@ -62,7 +62,7 @@
$flow = $config->action->customFlows[$action->objectType];
$module = $flow->module;
}
if(strpos(',doclib,module,webhook,', ",{$module},") !== false)
if(strpos($this->config->action->noLinkModules, ",{$module},") !== false)
{
echo $action->objectName;
}
+1 -1
View File
@@ -36,7 +36,7 @@
<?php echo $lang->backup->history?>
</h2>
<div class='pull-right'>
<?php common::printLink('backup', 'setting', '', "<i class='icon icon-cog'></i>" . $lang->backup->setting, '', "data-width='500' class='iframe btn btn-primary'");?>
<?php common::printLink('backup', 'setting', '', "<i class='icon icon-cog'></i> " . $lang->backup->setting, '', "data-width='500' class='iframe btn btn-primary'");?>
<?php common::printLink('backup', 'backup', 'reload=yes', "<i class='icon icon-copy'></i> " . $lang->backup->backup, 'hiddenwin', "class='btn btn-primary backup'");?>
</div>
</div>
+7 -4
View File
@@ -1750,7 +1750,7 @@ class block extends control
$today = helper::today();
$now = date('H:i:s', strtotime(helper::now()));
$meetings = $this->dao->select('*')->from(TABLE_MEETING)
$stmt = $this->dao->select('*')->from(TABLE_MEETING)
->Where('deleted')->eq('0')
->andWhere('(date')->gt($today)
->orWhere('(begin')->gt($now)
@@ -1759,9 +1759,10 @@ class block extends control
->andwhere('(host')->eq($this->app->user->account)
->orWhere('participant')->in($this->app->user->account)
->markRight(1)
->orderBy('id_desc')
->beginIF(isset($params->meetingNum))->limit($params->meetingNum)
->fetchAll();
->orderBy('id_desc');
if(isset($params->meetingNum)) $stmt->limit($params->meetingNum);
$meetings = $stmt->fetchAll();
$count['meeting'] = count($meetings);
$this->view->meetings = $meetings;
@@ -1832,6 +1833,8 @@ class block extends control
/* Get projects. */
$this->app->loadLang('task');
$this->app->loadLang('program');
$this->app->loadLang('execution');
$this->view->projects = $this->loadModel('project')->getOverviewList('byStatus', $status, $orderBy, $count);
}
-1
View File
@@ -121,7 +121,6 @@ $(function()
custom: response.data.content,
width: 600
});
myModalTrigger.show();
$('#showAnnual').click(function(){myModalTrigger.close()});
});
}
+2 -2
View File
@@ -57,8 +57,8 @@
<td class="c-hours" title="<?php echo $execution->hours->totalLeft . ' ' . $lang->execution->workHour;?>"><?php echo $execution->hours->totalLeft . $lang->execution->workHourUnit;?></td>
<?php endif;?>
<td class="c-progress">
<div class='progress-pie' data-doughnut-size='90' data-color='#00da88' data-value='<?php echo $execution->hours->progress;?>' data-width='24' data-height='24' data-back-color='#e8edf3'>
<div class='progress-info'><?php echo $execution->hours->progress;?></div>
<div class='progress-pie' data-doughnut-size='90' data-color='#3CB371' data-value='<?php echo round($execution->hours->progress);?>' data-width='24' data-height='24' data-back-color='#e8edf3'>
<div class='progress-info'><?php echo round($execution->hours->progress);?></div>
</div>
</td>
<?php if($longBlock):?>
@@ -157,7 +157,7 @@ $(function()
</div>
<?php else:?>
<div class="actions">
<?php common::printLink('productplan', 'create', "productID={$product->id}", "<i class='icon icon-plus'></i>" . $lang->productplan->create, '', "class='btn btn-info'");?>
<?php common::printLink('productplan', 'create', "productID={$product->id}", "<i class='icon icon-plus'></i> " . $lang->productplan->create, '', "class='btn btn-info'");?>
</div>
<?php endif;?>
<div class="type-info">
@@ -190,7 +190,7 @@ $(function()
</div>
<?php else:?>
<div class="actions">
<?php common::printLink('release', 'create', "productID={$product->id}", "<i class='icon icon-plus'></i>" . $lang->release->create, '', "class='btn btn-info'");?>
<?php common::printLink('release', 'create', "productID={$product->id}", "<i class='icon icon-plus'></i> " . $lang->release->create, '', "class='btn btn-info'");?>
</div>
<?php endif;?>
<div class="type-info">
+1 -1
View File
@@ -34,7 +34,7 @@
<?php if($longBlock):?>
<td class='text-center'><?php echo $project->teamCount;?></td>
<td class='text-right' title="<?php echo $project->consumed . ' ' . $lang->execution->workHour;?>"><?php echo $project->consumed . $lang->execution->workHourUnit;?></td>
<?php $programBudget = in_array($this->app->getClientLang(), ['zh-cn','zh-tw']) ? round((float)$project->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$project->budget, 2);?>
<?php $programBudget = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')) ? round((float)$project->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$project->budget, 2);?>
<td class='text-right'><?php echo $project->budget != 0 ? zget($lang->project->currencySymbol, $project->budgetUnit) . ' ' . $programBudget : $lang->project->future;?></td>
<td class='text-center'><?php echo $project->leftStories;?></td>
<td class='text-center'><?php echo $project->leftTasks;?></td>
@@ -221,7 +221,7 @@ $(function()
<span><?php echo $lang->project->budget . ':';?></span>
<span class='project-info'>
<?php
$projectBudget = in_array($this->app->getClientLang(), ['zh-cn','zh-tw']) ? round((float)$project->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$project->budget, 2);
$projectBudget = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')) ? round((float)$project->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$project->budget, 2);
echo $project->budget != 0 ? $projectBudget : $this->lang->project->future;
?>
</span>
@@ -229,7 +229,7 @@ $(function()
<div class="col-1-5"></div>
</div>
<div class="table-row text-center waterfall-title small col-12 center-block">
<?php $isChineseLang = in_array($this->app->getClientLang(), ['zh-cn','zh-tw']);?>
<?php $isChineseLang = in_array($this->app->getClientLang(), array('zh-cn','zh-tw'));?>
<div class="col-1-5"><?php echo $isChineseLang ? $lang->project->pv . '(' . $lang->project->pvTitle . ')' : $lang->project->pv; ?></div>
<div class="col-1-5"><?php echo $isChineseLang ? $lang->project->ev . '(' . $lang->project->evTitle . ')' : $lang->project->ev;?></div>
<div class="col-1-5"><?php echo $isChineseLang ? $lang->project->ac . '(' . $lang->project->acTitle . ')' : $lang->project->ac;?></div>
+2 -2
View File
@@ -57,8 +57,8 @@
<td class="c-hours" title="<?php echo $execution->hours->totalLeft . ' ' . $lang->execution->workHour;?>"><?php echo $execution->hours->totalLeft . $lang->execution->workHourUnit;?></td>
<?php endif;?>
<td class="c-progress">
<div class='progress-pie' data-doughnut-size='90' data-color='#00da88' data-value='<?php echo $execution->hours->progress;?>' data-width='24' data-height='24' data-back-color='#e8edf3'>
<div class='progress-info'><?php echo $execution->hours->progress;?></div>
<div class='progress-pie' data-doughnut-size='90' data-color='#3CB371' data-value='<?php echo round($execution->hours->progress);?>' data-width='24' data-height='24' data-back-color='#e8edf3'>
<div class='progress-info'><?php echo round($execution->hours->progress);?></div>
</div>
</td>
<?php if($longBlock):?>
+29 -45
View File
@@ -38,7 +38,6 @@ class bug extends control
public function __construct($moduleName = '', $methodName = '')
{
parent::__construct($moduleName, $methodName);
$products = array();
$this->loadModel('product');
$this->loadModel('tree');
$this->loadModel('user');
@@ -48,25 +47,32 @@ class bug extends control
$this->loadModel('qa');
/* Get product data. */
$products = array();
$objectID = 0;
if($this->app->openApp == 'project')
$openApp = ($this->app->openApp == 'project' or $this->app->openApp == 'execution') ? $this->app->openApp : 'qa';
if(!isonlybody())
{
$objectID = $this->session->project;
$products = $this->loadModel('project')->getProducts($objectID, false);
}
elseif($this->app->openApp == 'execution')
{
$objectID = $this->session->execution;
$products = $this->loadModel('execution')->getProducts($objectID, false);
if($this->app->openApp == 'project')
{
$objectID = $this->session->project;
$products = $this->loadModel('project')->getProducts($objectID, false);
}
elseif($this->app->openApp == 'execution')
{
$objectID = $this->session->execution;
$products = $this->loadModel('execution')->getProducts($objectID, false);
}
else
{
$products = $this->product->getPairs('', 0, 'program_asc');
}
if(empty($products) and !helper::isAjaxRequest()) die($this->locate($this->createLink('product', 'showErrorNone', "moduleName=$openApp&activeMenu=bug&objectID=$objectID")));
}
else
{
$products = $this->product->getPairs('', 0, 'program_asc');
}
$this->view->products = $this->products = $products;
$openApp = ($this->app->openApp == 'project' or $this->app->openApp == 'execution') ? $this->app->openApp : 'qa';
if(empty($this->products) and !helper::isAjaxRequest()) die($this->locate($this->createLink('product', 'showErrorNone', "moduleName=$openApp&activeMenu=bug&objectID=$objectID")));
}
/**
@@ -98,15 +104,13 @@ class bug extends control
{
$this->loadModel('datatable');
$products = $this->loadModel('product')->getPairs('noclosed');
$productID = $this->product->saveState($productID, $products);
$this->qa->setMenu($products, $productID, $branch);
$productID = $this->product->saveState($productID, $this->products);
$this->qa->setMenu($this->products, $productID, $branch);
/* Set browse type. */
$browseType = strtolower($browseType);
/* Set productID, moduleID, queryID and branch. */
if(!$this->projectID) $productID = $this->product->saveState($productID, $this->products);
$branch = ($branch == '') ? (int)$this->cookie->preBranch : (int)$branch;
setcookie('preProductID', $productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
setcookie('preBranch', (int)$branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
@@ -521,7 +525,7 @@ class bug extends control
$projects = array(0 => '');
if($executionID)
{
$products = array();
$products = array();
$linkedProducts = $this->loadModel('execution')->getProducts($executionID);
foreach($linkedProducts as $product) $products[$product->id] = $product->name;
@@ -569,17 +573,6 @@ class bug extends control
$this->view->customFields = $customFields;
$this->view->showFields = $this->config->bug->custom->createFields;
/* Set gitlabProjects. */
$this->loadModel('gitlab');
$allGitlabs = $this->gitlab->getPairs();
$gitlabProjects = $this->gitlab->getProjectsByExecution($executionID);
foreach($allGitlabs as $id => $name)
{
if($id and !isset($gitlabProjects[$id])) unset($allGitlabs[$id]);
}
$this->view->gitlabList = $allGitlabs;
$this->view->gitlabProjects = $gitlabProjects;
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->create;
$this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
$this->view->position[] = $this->lang->bug->create;
@@ -749,6 +742,11 @@ class bug extends control
$this->repo->setMenu($repos);
$this->lang->navGroup->bug = 'devops';
}
if($this->app->openApp == 'product')
{
$this->loadModel('product')->setMenu($bug->product);
$this->lang->product->menu->plan['subModule'] .= ',bug';
}
}
/* Get product info. */
@@ -1298,9 +1296,6 @@ class bug extends control
$this->qa->setMenu($this->products, $productID, $bug->branch);
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve;
$this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
$this->view->position[] = $this->lang->bug->resolve;
$this->view->bug = $bug;
$this->view->users = $users;
$this->view->assignedTo = $assignedTo;
@@ -1478,16 +1473,8 @@ class bug extends control
$_POST = array();
$bugs = $this->bug->getByList($bugIDList);
$this->loadModel('gitlab');
foreach($bugs as $bugID => $bug)
{
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
if(!empty($relation))
{
$currentIssue = $this->gitlab->apiGetSingleIssue($relation->gitlabID, $relation->projectID, $relation->issueID);
if($currentIssue->state != 'closed') $this->gitlab->apiUpdateIssue($relation->gitlabID, $relation->projectID, $relation->issueID, 'bug', $bug);
}
if($bug->status != 'resolved')
{
if($bug->status != 'closed') $skipBugs[$bugID] = $bugID;
@@ -1571,11 +1558,6 @@ class bug extends control
}
else
{
/* Delete related issue in gitlab. */
$this->loadModel('gitlab');
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
if(!empty($relation)) $this->gitlab->deleteIssue('bug', $bugID, $relation->issueID);
$this->bug->delete(TABLE_BUG, $bugID);
if($bug->toTask != 0)
{
@@ -1592,7 +1574,9 @@ class bug extends control
$this->executeHooks($bugID);
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess));
die(js::locate($this->session->bugList, 'parent'));
$locateLink = $this->session->bugList ? $this->session->bugList : inlink('browse', "productID={$bug->product}");
die(js::locate($locateLink, 'parent'));
}
}
+1
View File
@@ -5,3 +5,4 @@
.chosen-choices li.search-choice {word-break: break-all;}
#linkBugBox > li {margin-left: -56px;}
#branch {width: 95px;}
#storyIdBox .chosen-auto-max-width {width: 215px !important;}
+5 -1
View File
@@ -525,7 +525,11 @@ function loadAssignedTo(executionID, selectedUser)
$('#assignedTo').next('.picker').remove();
$('#assignedTo').replaceWith(data);
var defaultAssignedTo = $('#assignedTo').val();
if(defaultAssignedTo !== oldAssignedTo && selectedUser == '') $('#assignedTo').append(defaultOption);
if(defaultAssignedTo !== oldAssignedTo && selectedUser == '')
{
if($('#assignedTo option[value="' + oldAssignedTo + '"]').length > 0) $('#assignedTo option[value="' + oldAssignedTo + '"]').remove();
$('#assignedTo').append(defaultOption);
}
$('#assignedTo').chosen();
});
}
-18
View File
@@ -168,21 +168,3 @@ $(function()
$(window).unload(function(){
if(blockID) window.parent.refreshBlock($('#block' + blockID));
});
$(document).ready(function()
{
$('#gitlab').change(function()
{
host = $('#gitlab').val();
if(host == '') return false;
projects = '';
$.each(gitlabProjects[host], function(id, obj){projects = projects + ',' + obj.gitlabProject});
url = createLink('repo', 'ajaxgetgitlabprojects', "host=" + host + "&projects=" + projects);
$.get(url, function(response)
{
$('#gitlabProject').html('').append(response);
$('#gitlabProject').chosen().trigger("chosen:updated");
});
});
});
+1 -1
View File
@@ -79,7 +79,7 @@ $lang->bug->lastEditedDate = 'Bearbeitet am';
$lang->bug->fromCase = 'Von Fall';
$lang->bug->toCase = 'Zu Fall';
$lang->bug->colorTag = 'Farb Tag';
$lang->bug->repairRate = 'Repair Rate';
$lang->bug->fixedRate = 'Fixed Rate';
/* 方法列表。*/
$lang->bug->index = 'Home';
+1 -2
View File
@@ -24,7 +24,6 @@ $lang->bug->storyVersion = 'Story Version';
$lang->bug->color = 'Color';
$lang->bug->task = 'Task';
$lang->bug->title = 'Title';
$lang->bug->sync2gitlab = 'Sync gitlab';
$lang->bug->severity = 'Severity';
$lang->bug->severityAB = 'S';
$lang->bug->pri = 'Priority';
@@ -80,7 +79,7 @@ $lang->bug->lastEditedDate = 'EditedDate';
$lang->bug->fromCase = 'From Case';
$lang->bug->toCase = 'To Case';
$lang->bug->colorTag = 'Color';
$lang->bug->repairRate = 'Repair Rate';
$lang->bug->fixedRate = 'Fixed Rate';
/* Method list. */
$lang->bug->index = 'Bug Home';
+1 -1
View File
@@ -79,7 +79,7 @@ $lang->bug->lastEditedDate = 'Date Modif';
$lang->bug->fromCase = 'du CasTest';
$lang->bug->toCase = 'vers CasTest';
$lang->bug->colorTag = 'Couleur';
$lang->bug->repairRate = 'Repair Rate';
$lang->bug->fixedRate = 'Repair Rate';
/* 方法列表。*/
$lang->bug->index = 'Accueil Bug';
+1 -1
View File
@@ -79,7 +79,7 @@ $lang->bug->lastEditedDate = 'Ngày sửa';
$lang->bug->fromCase = 'Từ tình huống';
$lang->bug->toCase = 'Tới tình huống';
$lang->bug->colorTag = 'Màu';
$lang->bug->repairRate = 'Repair Rate';
$lang->bug->fixedRate = 'Repair Rate';
/* Method list. */
$lang->bug->index = 'Trang Bug';
+1 -2
View File
@@ -24,7 +24,6 @@ $lang->bug->storyVersion = "{$lang->SRCommon}版本";
$lang->bug->color = '标题颜色';
$lang->bug->task = '相关任务';
$lang->bug->title = 'Bug标题';
$lang->bug->sync2gitlab = '同步gitlab';
$lang->bug->severity = '严重程度';
$lang->bug->severityAB = '级别';
$lang->bug->pri = '优先级';
@@ -80,7 +79,7 @@ $lang->bug->lastEditedDate = '修改日期';
$lang->bug->fromCase = '来源用例';
$lang->bug->toCase = '生成用例';
$lang->bug->colorTag = '颜色标签';
$lang->bug->repairRate = '修复率';
$lang->bug->fixedRate = '修复率';
/* 方法列表。*/
$lang->bug->index = '首页';
+2 -1
View File
@@ -24,7 +24,6 @@ $lang->bug->storyVersion = "{$lang->SRCommon}版本";
$lang->bug->color = '標題顏色';
$lang->bug->task = '相關任務';
$lang->bug->title = 'Bug標題';
$lang->bug->sync2gitlab = '同步gitlab';
$lang->bug->severity = '嚴重程度';
$lang->bug->severityAB = '級別';
$lang->bug->pri = '優先順序';
@@ -60,6 +59,7 @@ $lang->bug->resolvedBuild = '解決版本';
$lang->bug->resolvedDate = '解決日期';
$lang->bug->resolvedDateAB = '解決日期';
$lang->bug->deadline = '截止日期';
$lang->bug->deadlineAB = '截止';
$lang->bug->plan = '所屬' . '計劃';
$lang->bug->closedBy = '由誰關閉';
$lang->bug->closedDate = '關閉日期';
@@ -79,6 +79,7 @@ $lang->bug->lastEditedDate = '修改日期';
$lang->bug->fromCase = '來源用例';
$lang->bug->toCase = '生成用例';
$lang->bug->colorTag = '顏色標籤';
$lang->bug->fixedRate = '修復率';
/* 方法列表。*/
$lang->bug->index = '首頁';
+3 -63
View File
@@ -84,13 +84,11 @@ class bugModel extends model
/* Use classic mode to replace required project. */
if($this->config->systemMode == 'classic' and strpos($this->config->bug->create->requiredFields, 'project') !== false) $this->config->bug->create->requiredFields = str_replace('project', 'execution', $this->config->bug->create->requiredFields);
$this->dao->insert(TABLE_BUG)->data($bug, $skip = 'gitlab,gitlabProject')->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec();
$this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec();
if(!dao::isError())
{
$bugID = $this->dao->lastInsertID();
$this->loadModel('gitlab')->apiCreateIssue($this->post->gitlab, $this->post->gitlabProject, 'bug', $bugID, $bug);
$this->file->updateObjectID($this->post->uid, $bugID, 'bug');
$this->file->saveUpload('bug', $bugID);
empty($bug->case) ? $this->loadModel('score')->create('bug', 'create', $bugID) : $this->loadModel('score')->create('bug', 'createFormCase', $bug->case);
@@ -342,7 +340,7 @@ class bugModel extends model
elseif($browseType == 'bysearch') $bugs = $this->getBySearch($productIDList, $branch, $queryID, $sort, '', $pager, $projectID);
elseif($browseType == 'overduebugs') $bugs = $this->getOverdueBugs($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
return $this->checkDelayBugs($bugs);
return $this->checkDelayedBugs($bugs);
}
/**
@@ -352,7 +350,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function checkDelayBugs($bugs)
public function checkDelayedBugs($bugs)
{
foreach ($bugs as $bug) $bug = $this->checkDelayBug($bug);
@@ -675,12 +673,6 @@ class bugModel extends model
if(!empty($bug->resolvedBy)) $this->loadModel('score')->create('bug', 'resolve', $bugID);
$this->file->updateObjectID($this->post->uid, $bugID, 'bug');
if(!empty($bug))
{
$this->loadModel('gitlab');
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
if($relation) $this->gitlab->apiUpdateIssue($relation->gitlabID, $relation->projectID, $relation->issueID, 'bug', $bug, $bugID);
}
return common::createChanges($oldBug, $bug);
}
}
@@ -802,11 +794,6 @@ class bugModel extends model
$this->executeHooks($bugID);
$allChanges[$bugID] = common::createChanges($oldBug, $bug);
/* update bug to gitlab issue. */
$this->loadModel('gitlab');
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
if($relation) $this->gitlab->apiUpdateIssue($relation->gitlabID, $relation->projectID, $relation->issueID, 'bug', $bug, $bugID);
}
else
{
@@ -859,15 +846,8 @@ class bugModel extends model
}
/* Update bugs. */
$this->loadModel('gitlab');
foreach($activateBugs as $bugID => $bug)
{
if(!empty($bug))
{
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
if($relation) $this->gitlab->apiUpdateIssue($relation->gitlabID, $relation->projectID, $relation->issueID, 'bug', (Object)$bug, $bugID);
}
$oldBug = $bugs[$bugID];
$this->dao->update(TABLE_BUG)->data($bug, $skipFields = 'comment')->autoCheck()->where('id')->eq((int)$bugID)->exec();
if(dao::isError()) die(js::error('bug#' . $bugID . dao::getError(true)));
@@ -902,16 +882,6 @@ class bugModel extends model
->autoCheck()
->where('id')->eq($bugID)->exec();
$this->loadModel('gitlab');
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
$bug = $this->getById($bugID); // Get full bug object to update issue.
$bug->assignee_id = $this->gitlab->getGitlabUserID($relation->gitlabID, $bug->assignedTo);
if($bug->assignee_id != '')
{
/* TODO(dingguodong) we should alert to operator when can not find the user, and the operator should reconfigure user binding. */
$this->gitlab->apiUpdateIssue($relation->gitlabID, $relation->projectID, $relation->issueID, 'bug', $bug, $bugID);
}
if(!dao::isError()) return common::createChanges($oldBug, $bug);
}
@@ -956,7 +926,6 @@ class bugModel extends model
{
$now = helper::now();
$bugs = $this->getByList($bugIDList);
$this->loadModel('gitlab');
foreach($bugIDList as $bugID)
{
if($bugs[$bugID]->confirmed) continue;
@@ -967,12 +936,6 @@ class bugModel extends model
$bug->lastEditedDate = $now;
$bug->confirmed = 1;
if(!empty($bug))
{
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
if($relation) $this->gitlab->apiUpdateIssue($relation->gitlabID, $relation->projectID, $relation->issueID, 'bug', $bug, $bugID);
}
$this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec();
$this->executeHooks($bugID);
}
@@ -1064,10 +1027,6 @@ class bugModel extends model
/* Link bug to build and release. */
$this->linkBugToBuild($bugID, $bug->resolvedBuild);
$this->loadModel('gitlab');
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
if($relation) $this->gitlab->apiUpdateIssue($relation->gitlabID, $relation->projectID, $relation->issueID, 'bug', $bug, $bugID);
return common::createChanges($oldBug, $bug);
}
@@ -1197,11 +1156,6 @@ class bugModel extends model
$this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec();
$this->executeHooks($bugID);
/* batch resolve issure bugs.*/
$this->loadModel('gitlab');
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
if($relation) $this->gitlab->apiUpdateIssue($relation->gitlabID, $relation->projectID, $relation->issueID, 'bug', $bug, $bugID);
$changes[$bugID] = common::createChanges($oldBug, $bug);
}
@@ -1259,13 +1213,6 @@ class bugModel extends model
}
}
if(!empty($bug))
{
$this->loadModel('gitlab');
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
if($relation) $this->gitlab->apiUpdateIssue($relation->gitlabID, $relation->projectID, $relation->issueID, 'bug', $bug, $bugID);
}
$bug->activatedCount += 1;
return common::createChanges($oldBug, $bug);
}
@@ -1295,13 +1242,6 @@ class bugModel extends model
$this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec();
$this->loadModel('gitlab');
$relation = $this->gitlab->getRelationByObject('bug', $bugID);
if(!empty($relation))
{
$currentIssue = $this->gitlab->apiGetSingleIssue($relation->gitlabID, $relation->projectID, $relation->issueID);
if($currentIssue->state != 'closed') $this->gitlab->apiUpdateIssue($relation->gitlabID, $relation->projectID, $relation->issueID, 'bug', $bug, $bugID);
}
return common::createChanges($oldBug, $bug);
}
+1 -1
View File
@@ -181,7 +181,7 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow
<li <?php echo $disabled?>>
<?php
$batchLink = $this->createLink('bug', 'batchCreate', "productID=$productID&branch=$branch&executionID=0&moduleID=$moduleID");
echo "<li>" . html::a($batchLink, "<i class='icon icon-plus'></i>" . $lang->bug->batchCreate) . "</li>";
echo "<li>" . html::a($batchLink, "<i class='icon icon-plus'></i> " . $lang->bug->batchCreate) . "</li>";
?>
</li>
</ul>
+1 -1
View File
@@ -13,7 +13,7 @@
<?php include '../../common/view/header.html.php';?>
<div id="mainMenu" class="clearfix">
<div class="btn-toolbar pull-left">
<?php echo html::a($this->createLink('bug', 'browse', "productID=$productID&branch=0&browseType=$browseType&moduleID=$moduleID"), "<i class='icon icon-back icon-sm'> </i>" . $lang->goback, '', "class='btn btn-link'");?>
<?php echo html::a($this->createLink('bug', 'browse', "productID=$productID&branch=0&browseType=$browseType&moduleID=$moduleID"), "<i class='icon icon-back icon-sm'> </i> " . $lang->goback, '', "class='btn btn-link'");?>
<div class='divider'></div>
<div class='page-title'>
<span class='text'><?php echo $lang->bug->report->common;?></span>
+10 -4
View File
@@ -32,7 +32,7 @@
<div class="btn-toolbar pull-right">
<?php if(common::canModify('product', $product)):?>
<?php $openApp = strpos('|execution|project|qa|', $this->app->openApp) !== false ? $this->app->openApp : 'qa';?>
<?php common::printLink('bug', 'create', "productID={$bug->product}&branch={$bug->branch}&extra=moduleID={$bug->module},projectID={$bug->project},executionID={$bug->execution}", "<i class='icon icon-plus'></i>" . $lang->bug->create, '', "class='btn btn-primary' data-app='$openApp'"); ?>
<?php if($this->app->openApp != 'product') common::printLink('bug', 'create', "productID={$bug->product}&branch={$bug->branch}&extra=moduleID={$bug->module},projectID={$bug->project},executionID={$bug->execution}", "<i class='icon icon-plus'></i> " . $lang->bug->create, '', "class='btn btn-primary' data-app='$openApp'"); ?>
<?php endif;?>
</div>
<?php endif;?>
@@ -86,14 +86,20 @@
common::printIcon('bug', 'close', $params, $bug, 'button', '', '', 'text-danger iframe showinonlybody', true);
common::printIcon('bug', 'activate', $params, $bug, 'button', '', '', 'text-success iframe showinonlybody', true);
common::printIcon('bug', 'toStory', "product=$bug->product&branch=$bug->branch&module=0&story=0&execution=0&bugID=$bug->id", $bug, 'button', $lang->icons['story'], '', '', '', "data-app='" . ($this->app->openApp == 'project' ? 'project' : 'product') . "'", $lang->bug->toStory);
common::printIcon('bug', 'createCase', $convertParams, $bug, 'button', 'sitemap');
if($this->app->openApp != 'product')
{
common::printIcon('bug', 'toStory', "product=$bug->product&branch=$bug->branch&module=0&story=0&execution=0&bugID=$bug->id", $bug, 'button', $lang->icons['story'], '', '', '', "data-app='" . ($this->app->openApp == 'project' ? 'project' : 'product') . "'", $lang->bug->toStory);
common::printIcon('bug', 'createCase', $convertParams, $bug, 'button', 'sitemap');
}
echo $this->buildOperateMenu($bug, 'view');
echo "<div class='divider'></div>";
common::printIcon('bug', 'edit', $params, $bug);
common::printIcon('bug', 'create', $copyParams, $bug, 'button', 'copy', '', '', false, "data-app='qa'");
if($this->app->openApp != 'product')
{
common::printIcon('bug', 'create', $copyParams, $bug, 'button', 'copy', '', '', false, "data-app='qa'");
}
common::printIcon('bug', 'delete', $params, $bug, 'button', 'trash', 'hiddenwin');
?>
<?php endif;?>
+3 -1
View File
@@ -274,7 +274,9 @@ class build extends control
*/
public function delete($buildID, $confirm = 'no')
{
if($confirm == 'no') { die(js::confirm($this->lang->build->confirmDelete, $this->createLink('build', 'delete', "buildID=$buildID&confirm=yes")));
if($confirm == 'no')
{
die(js::confirm($this->lang->build->confirmDelete, $this->createLink('build', 'delete', "buildID=$buildID&confirm=yes")));
}
else
{
+4 -3
View File
@@ -227,18 +227,19 @@ class buildModel extends model
*
* @param int $executionID
* @param int $productID
* @param int $branch
* @param string $params noempty|notrunk, can be a set of them
* @param int $buildID
* @param string $buildIDList
* @access public
* @return array
*/
public function getExecutionBuildPairs($executionID, $productID, $branch = 0, $params = '', $buildID = 0)
public function getExecutionBuildPairs($executionID, $productID, $branch = 0, $params = '', $buildIDList = '')
{
$sysBuilds = array();
$selectedBuilds = array();
if(strpos($params, 'noempty') === false) $sysBuilds = array('' => '');
if(strpos($params, 'notrunk') === false) $sysBuilds = $sysBuilds + array('trunk' => $this->lang->trunk);
if($buildID != 0) $selectedBuilds = $this->dao->select('id, name')->from(TABLE_BUILD)->where('id')->in($buildID)->andWhere('execution')->eq($executionID)->fetchPairs();
if($buildIDList) $selectedBuilds = $this->dao->select('id, name')->from(TABLE_BUILD)->where('id')->in($buildIDList)->andWhere('execution')->eq($executionID)->fetchPairs();
$executionBuilds = $this->dao->select('t1.id, t1.name, t1.execution, t2.status as executionStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName')->from(TABLE_BUILD)->alias('t1')
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')
+1 -1
View File
@@ -475,7 +475,7 @@ class caselibModel extends model
}
else
{
$caseData->project = $this->session->project;
$caseData->project = (int)$this->session->project;
$caseData->version = 1;
$caseData->openedBy = $this->app->user->account;
$caseData->openedDate = $now;
+4 -4
View File
@@ -51,16 +51,16 @@ js::set('flow', $config->global->flow);
if(common::hasPriv('caselib', 'view'))
{
$link = helper::createLink('caselib', 'view', "libID=$libID");
echo html::a($link, "<i class='icon icon-list-alt muted'> </i>" . $this->lang->caselib->view, '', "class='btn btn-link'");
echo html::a($link, "<i class='icon icon-list-alt muted'> </i> " . $this->lang->caselib->view, '', "class='btn btn-link'");
}
?>
</div>
<div class='btn-toolbar pull-right'>
<div class='btn-group'>
<?php common::printLink('caselib', 'exportTemplet', "libID=$libID", "<i class='icon icon-export muted'> </i>" . $lang->caselib->exportTemplet, '', "class='btn btn-link export' data-width='40%'");?>
<?php common::printLink('caselib', 'import', "libID=$libID", "<i class='icon muted icon-import'> </i>" . $lang->testcase->fileImport, '', "class='btn btn-link export'");?>
<?php common::printLink('caselib', 'exportTemplet', "libID=$libID", "<i class='icon icon-export muted'> </i> " . $lang->caselib->exportTemplet, '', "class='btn btn-link export' data-width='40%'");?>
<?php common::printLink('caselib', 'import', "libID=$libID", "<i class='icon muted icon-import'> </i> " . $lang->testcase->fileImport, '', "class='btn btn-link export'");?>
</div>
<?php echo html::a($this->createLink('caselib', 'create'), "<i class='icon icon-plus'> </i>" . $lang->caselib->create, '', 'class="btn btn-secondary"');?>
<?php echo html::a($this->createLink('caselib', 'create'), "<i class='icon icon-plus'> </i> " . $lang->caselib->create, '', 'class="btn btn-secondary"');?>
<div class='btn-group dropdown'>
<?php
$params = "libID=$libID&moduleID=" . (isset($moduleID) ? $moduleID : 0);
+2 -2
View File
@@ -41,10 +41,10 @@
if(count($moduleOptionMenu) == 1)
{
echo "<span class='input-group-btn'>";
echo html::a($this->createLink('tree', 'browse', "rootID=$libID&view=caselib&currentModuleID=0"), "<i class='icon icon-cog'></i>", '_blank', "data-toggle='tooltip' class='btn' title='{$lang->tree->manage}'");
echo html::a($this->createLink('tree', 'browse', "rootID=$libID&view=caselib&currentModuleID=0", 'html', true), "<i class='icon icon-cog'></i>", '', "data-toggle='tooltip' class='btn iframe' title='{$lang->tree->manage}'");
echo '</span>';
echo "<span class='input-group-btn'>";
echo html::a("javascript:loadLibModules($libID)", "<i class='icon icon-refresh'></i>", '', "data-toggle='tooltip' class='btn' title='{$lang->refresh}'");
echo html::a("javascript:void(0)", "<i class='icon icon-refresh'></i>", '', "class='btn refresh' title='{$lang->refresh}' onclick='loadLibModules($libID)'");
echo '</span>';
}
?>
+9 -7
View File
@@ -59,22 +59,23 @@ class ci extends control
}
/**
* Send a request to jenkins to check build status.
* Send a request to jenkins or gitlab to check build status.
*
* @param int $compileID
* @access public
* @return void
*/
public function checkCompileStatus()
public function checkCompileStatus($compileID = 0)
{
$this->ci->checkCompileStatus();
$this->ci->checkCompileStatus($compileID);
if(dao::isError())
{
echo json_encode(dao::getError());
return true;
}
else
{
echo 'success';
}
echo 'success';
}
/**
@@ -122,6 +123,7 @@ class ci extends control
$caseResult = $post->funcResult;
$firstCase = array_shift($caseResult);
$productID = $firstCase->productId;
if(empty($productID) and !empty($firstCase->id)) $productID = $this->dao->select('product')->from(TABLE_CASE)->where('id')->eq((int)$firstCase->id)->fetch('product');
}
if(empty($productID)) die(json_encode(array('result' => 'fail', 'message' => 'productID is not found')));
+3 -2
View File
@@ -1,6 +1,7 @@
<?php
$lang->ci->common = 'CI';
$lang->ci->commitResult = 'Interface: Commit Test Result.';
$lang->ci->common = 'CI';
$lang->ci->commitResult = 'Interface: Commit Test Result.';
$lang->ci->checkCompileStatus = 'Interface: Fetch Test Result.';
$lang->ci->job = 'Job';
$lang->ci->task = 'Task';
+3 -2
View File
@@ -1,6 +1,7 @@
<?php
$lang->ci->common = '持续集成';
$lang->ci->commitResult = '接口:提交测试结果';
$lang->ci->common = '持续集成';
$lang->ci->commitResult = '接口:提交测试结果';
$lang->ci->checkCompileStatus = '接口:获取测试结果';
$lang->ci->job = '构建';
$lang->ci->task = '构建任务';
+3 -2
View File
@@ -1,6 +1,7 @@
<?php
$lang->ci->common = '持續整合';
$lang->ci->commitResult = '介面:提交測試結果';
$lang->ci->common = '持續整合';
$lang->ci->commitResult = '介面:提交測試結果';
$lang->ci->checkCompileStatus = '介面:獲取測試結果';
$lang->ci->job = '構建';
$lang->ci->task = '構建任務';
+66 -11
View File
@@ -23,20 +23,23 @@ class ciModel extends model
/**
* Send a request to jenkins to check build status.
*
* @param int $compileID
* @access public
* @return void
*/
public function checkCompileStatus()
public function checkCompileStatus($compileID = 0)
{
$compiles = $this->dao->select('t1.*, t2.pipeline, t3.name as jenkinsName,t3.url,t3.account,t3.token,t3.password')
->from(TABLE_COMPILE)->alias('t1')
->leftJoin(TABLE_JOB)->alias('t2')->on('t1.job=t2.id')
->leftJoin(TABLE_PIPELINE)->alias('t3')->on('t2.server=t3.id')
->where('t1.status')->ne('success')
->andWhere('t1.status')->ne('failure')
->andWhere('t1.status')->ne('create_fail')
->andWhere('t1.status')->ne('timeout')
->andWhere('t1.createdDate')->gt(date(DT_DATETIME1, strtotime("-1 day")))
$compiles = $this->dao->select('compile.*, job.engine,job.pipeline, pipeline.name as jenkinsName,job.server,pipeline.url,pipeline.account,pipeline.token,pipeline.password')
->from(TABLE_COMPILE)->alias('compile')
->leftJoin(TABLE_JOB)->alias('job')->on('compile.job=job.id')
->leftJoin(TABLE_PIPELINE)->alias('pipeline')->on('job.server=pipeline.id')
->where('compile.status')->ne('success')
->andWhere('compile.status')->ne('failure')
->andWhere('compile.status')->ne('create_fail')
->andWhere('compile.status')->ne('timeout')
->andWhere('compile.status')->ne('canceled')
->beginIf($compileID)->andWhere('compile.id')->eq($compileID)->fi()
->andWhere('compile.createdDate')->gt(date(DT_DATETIME1, strtotime("-1 day")))
->fetchAll();
foreach($compiles as $compile) $this->syncCompileStatus($compile);
@@ -57,6 +60,7 @@ class ciModel extends model
return false;
}
if($compile->engine == 'gitlab') return $this->syncGitlabTaskStatus($compile);
$jenkinsServer = $compile->url;
$jenkinsUser = $compile->account;
$jenkinsPassword = $compile->token ? $compile->token : base64_decode($compile->password);
@@ -65,7 +69,7 @@ class ciModel extends model
$response = common::http($queueUrl, '', array(CURLOPT_USERPWD => $userPWD));
$this->dao->update(TABLE_COMPILE)->set('times = times + 1')->where('id')->eq($compile->id)->exec();
if($compile->engine != 'gitlab') $this->dao->update(TABLE_COMPILE)->set('times = times + 1')->where('id')->eq($compile->id)->exec();
if(strripos($response, "404") > -1)
{
$infoUrl = sprintf("%s/job/%s/api/xml?tree=builds[id,number,result,queueId]&xpath=//build[queueId=%s]", $jenkinsServer, $compile->pipeline, $compile->queue);
@@ -112,6 +116,57 @@ class ciModel extends model
}
}
/**
* Sync gitlab task status.
*
* @param object $compile
* @access public
* @return void
*/
public function syncGitlabTaskStatus($compile)
{
$this->loadModel('gitlab');
$now = helper::now();
$pipeline = $this->gitlab->apiGetSinglePipeline($compile->server, $compile->pipeline, $compile->queue);
$jobs = $this->gitlab->apiGetJobs($compile->server, $compile->pipeline, $compile->queue);
$data = new stdclass;
$data->status = $pipeline->status;
$data->updateDate = $now;
foreach($jobs as $job)
{
if(empty($job->duration) or $job->duration == '') $job->duration = '-';
$data->logs = "<font style='font-weight:bold'>&gt;&gt;&gt; Job: $job->name, Stage: $job->stage, Status: $job->status, Duration: $job->duration Sec\r\n </font>";
$data->logs .= "Job URL: <a href=\"$job->web_url\" target='_blank'>$job->web_url</a> \r\n";
$data->logs .= $this->transformAnsiToHtml($this->gitlab->apiGetJobLog($compile->server, $compile->pipeline, $job->id));
}
$this->dao->update(TABLE_COMPILE)->data($data)->where('id')->eq($compile->id)->exec();
$this->dao->update(TABLE_JOB)->set('lastExec')->eq($now)->set('lastStatus')->eq($pipeline->status)->where('id')->eq($compile->job)->exec();
}
/**
* Transform ansi text to html.
*
* @param string $text
* @access public
* @return string
*/
public function transformAnsiToHtml($text)
{
$text = preg_replace("/\x1B\[31;40m/", '<font style="color: red">', $text);
$text = preg_replace("/\x1B\[32;1m/", '<font style="color: green">', $text);
$text = preg_replace("/\x1B\[32;1m/", '<font style="color: green">', $text);
$text = preg_replace("/\x1B\[36;1m/", '<font style="color: cyan">', $text);
$text = preg_replace("/\x1B\[0;33m/", '<font style="color: yellow">', $text);
$text = preg_replace("/\x1B\[1m/", '<font style="font-weight:bold">', $text);
$text = preg_replace("/\x1B\[0;m/", '</font><br>', $text);
$text = preg_replace("/\x1B\[0K/", '<br>', $text);
return $text;
}
/**
* Update ci build status.
*
+1
View File
@@ -269,6 +269,7 @@ $lang->lang = 'Sprache';
/* Theme style. */
$lang->theme = 'Theme';
$lang->themes['default'] = 'ZenTao Blau (Standard)';
$lang->themes['blue'] = 'Blau';
$lang->themes['green'] = 'Grün';
$lang->themes['red'] = 'Rot';
$lang->themes['purple'] = 'Lila';
+19 -16
View File
@@ -25,21 +25,22 @@ $lang->ellipsis = '…';
$lang->percent = '%';
$lang->dash = '-';
$lang->zentaoPMS = 'ZenTao';
$lang->logoImg = 'zt-logo-en.png';
$lang->welcome = "%s ALM";
$lang->logout = 'Logout';
$lang->login = 'Login';
$lang->help = 'Help';
$lang->aboutZenTao = 'About';
$lang->profile = 'Profile';
$lang->changePassword = 'Password';
$lang->unfoldMenu = 'Unfold Menu';
$lang->collapseMenu = 'Collapse Menu';
$lang->preference = 'Preference';
$lang->runInfo = "<div class='row'><div class='u-1 a-center' id='debugbar'>Time %s MS, Memory %s KB, Query %s. </div></div>";
$lang->agreement = "I have read and agreed to the terms and conditions of <a href='http://zpl.pub/page/zplv12.html' target='_blank'> Z PUBLIC LICENSE 1.2 </a>. <span class='text-danger'>Without authorization, I should not remove, hide or cover any logos/links of ZenTao.</span>";
$lang->designedByAIUX = "<a href='https://api.zentao.net/goto.php?item=aiux' class='link-aiux' target='_blank'><i class='icon icon-aiux'></i> AIUX</a>";
$lang->zentaoPMS = 'ZenTao';
$lang->proName = 'Pro';
$lang->logoImg = 'zt-logo-en.png';
$lang->welcome = "%s ALM";
$lang->logout = 'Logout';
$lang->login = 'Login';
$lang->help = 'Help';
$lang->aboutZenTao = 'About';
$lang->profile = 'Profile';
$lang->changePassword = 'Password';
$lang->unfoldMenu = 'Unfold Menu';
$lang->collapseMenu = 'Collapse Menu';
$lang->preference = 'Preference';
$lang->runInfo = "<div class='row'><div class='u-1 a-center' id='debugbar'>Time %s MS, Memory %s KB, Query %s. </div></div>";
$lang->agreement = "I have read and agreed to the terms and conditions of <a href='http://zpl.pub/page/zplv12.html' target='_blank'> Z PUBLIC LICENSE 1.2 </a>. <span class='text-danger'>Without authorization, I should not remove, hide or cover any logos/links of ZenTao.</span>";
$lang->designedByAIUX = "<a href='https://api.zentao.net/goto.php?item=aiux' class='link-aiux' target='_blank'><i class='icon icon-aiux'></i> AIUX</a>";
$lang->reset = 'Reset';
$lang->cancel = 'Cancel';
@@ -112,7 +113,7 @@ $lang->loading = 'Loading...';
$lang->notFound = 'Not found!';
$lang->notPage = 'Sorry, the features you are visiting are in development!';
$lang->showAll = '[[Show All]]';
$lang->selectedItems = 'Seleted <strong>{0}</strong> items';
$lang->selectedItems = 'Selected <strong>{0}</strong> items';
$lang->future = 'Waiting';
$lang->year = 'Year';
@@ -153,6 +154,7 @@ $lang->custom->common = 'Custom';
$lang->extension->common = 'Extension';
$lang->company->common = 'Company';
$lang->dept->common = 'Dept';
$lang->upgrade->common = 'Update';
$lang->program->list = 'Program List';
$lang->execution->list = "{$lang->executionCommon} List";
@@ -288,6 +290,7 @@ $lang->lang = 'Language';
/* Theme style. */
$lang->theme = 'Theme';
$lang->themes['default'] = 'Default';
$lang->themes['blue'] = 'Blue';
$lang->themes['green'] = 'Green';
$lang->themes['red'] = 'Red';
$lang->themes['purple'] = 'Purple';
+1
View File
@@ -269,6 +269,7 @@ $lang->lang = 'Langue';
/* Theme style. */
$lang->theme = 'Theme';
$lang->themes['default'] = 'Default';
$lang->themes['blue'] = 'Blue';
$lang->themes['green'] = 'Green';
$lang->themes['red'] = 'Red';
$lang->themes['purple'] = 'Purple';
+8 -8
View File
@@ -146,7 +146,7 @@ $lang->product->menu->release = array('link' => "{$lang->release->common}|re
$lang->product->menu->roadmap = array('link' => "{$lang->roadmap}|product|roadmap|productID=%s");
$lang->product->menu->project = array('link' => "{$lang->project->common}|product|project|status=all&productID=%s");
$lang->product->menu->track = array('link' => "{$lang->track}|story|track|productID=%s");
$lang->product->menu->doc = array('link' => "{$lang->doc->common}|doc|objectLibs|type=product&objectID=%s", 'subModule' => 'doc');
$lang->product->menu->doc = array('link' => "{$lang->doc->common}|doc|tableContents|type=product&objectID=%s", 'subModule' => 'doc');
$lang->product->menu->dynamic = array('link' => "{$lang->dynamic}|product|dynamic|productID=%s");
$lang->product->menu->settings = array('link' => "{$lang->settings}|product|view|productID=%s", 'subModule' => 'tree,branch', 'alias' => 'edit,whitelist,addwhitelist');
@@ -184,7 +184,7 @@ $lang->scrum->menu = new stdclass();
$lang->scrum->menu->index = array('link' => "{$lang->dashboard}|project|index|project=%s");
$lang->scrum->menu->execution = array('link' => "$lang->executionCommon|project|execution|status=all&projectID=%s", 'exclude' => 'execution-testreport');
$lang->scrum->menu->story = array('link' => "$lang->SRCommon|projectstory|story|projectID=%s", 'subModule' => 'projectstory,tree', 'alias' => 'story,track');
$lang->scrum->menu->doc = array('link' => "{$lang->doc->common}|doc|objectLibs|type=project&objectID=%s", 'subModule' => 'doc');
$lang->scrum->menu->doc = array('link' => "{$lang->doc->common}|doc|tableContents|type=project&objectID=%s", 'subModule' => 'doc');
$lang->scrum->menu->qa = array('link' => "{$lang->qa->common}|project|bug|projectID=%s", 'subModule' => 'testcase,testtask,bug,testreport,execution', 'alias' => 'bug,testtask,testcase,testreport', 'exclude' => 'execution-create,execution-batchedit');
$lang->scrum->menu->devops = array('link' => "{$lang->repo->common}|repo|browse|repoID=0&branchID=&objectID=%s", 'subModule' => 'repo');
$lang->scrum->menu->build = array('link' => "{$lang->build->common}|project|build|project=%s");
@@ -236,7 +236,7 @@ $lang->execution->menu->view = array('link' => "$lang->view|execution|groupt
$lang->execution->menu->story = array('link' => "$lang->SRCommon|execution|story|executionID=%s", 'subModule' => 'story', 'alias' => 'batchcreate,linkstory,storykanban');
$lang->execution->menu->qa = array('link' => "{$lang->qa->common}|execution|bug|executionID=%s", 'subModule' => 'bug,testcase,testtask,testreport', 'alias' => 'qa,bug,testcase,testtask,testreport');
$lang->execution->menu->devops = array('link' => "{$lang->repo->common}|repo|browse|repoID=0&branchID=&objectID=%s", 'subModule' => 'repo');
$lang->execution->menu->doc = array('link' => "{$lang->doc->common}|doc|objectLibs|type=execution&objectID=%s", 'subModule' => 'doc');
$lang->execution->menu->doc = array('link' => "{$lang->doc->common}|doc|tableContents|type=execution&objectID=%s", 'subModule' => 'doc');
$lang->execution->menu->build = array('link' => "{$lang->build->common}|execution|build|executionID=%s", 'subModule' => 'build');
$lang->execution->menu->action = array('link' => "$lang->dynamic|execution|dynamic|executionID=%s");
$lang->execution->menu->settings = array('link' => "$lang->settings|execution|view|executionID=%s", 'subModule' => 'personnel', 'alias' => 'edit,manageproducts,team,whitelist,addwhitelist,managemembers', 'class' => 'dropdown dropdown-hover');
@@ -329,16 +329,16 @@ $lang->devops->menuOrder[20] = 'jenkins';
$lang->devops->menuOrder[25] = 'maintain';
$lang->devops->menuOrder[30] = 'rules';
/* Doc menu.*/
/* Doc menu. */
$lang->doc->menu = new stdclass();
$lang->doc->menu->dashboard = array('link' => "{$lang->dashboard}|doc|index");
$lang->doc->menu->recent = array('link' => "{$lang->doc->recent}|doc|browse|browseTyp=byediteddate", 'alias' => 'recent');
$lang->doc->menu->my = array('link' => "{$lang->doc->my}|doc|browse|browseTyp=openedbyme", 'alias' => 'my');
$lang->doc->menu->collect = array('link' => "{$lang->doc->favorite}|doc|browse|browseTyp=collectedbyme", 'alias' => 'collect');
$lang->doc->menu->product = array('link' => "{$lang->doc->product}|doc|objectLibs|type=product", 'alias' => 'product');
if($config->systemMode == 'new') $lang->doc->menu->project = array('link' => "{$lang->doc->project}|doc|objectLibs|type=project", 'alias' => 'project');
if($config->systemMode == 'classic') $lang->doc->menu->execution = array('link' => "{$lang->doc->execution}|doc|objectLibs|type=execution", 'alias' => 'execution');
$lang->doc->menu->custom = array('link' => "{$lang->doc->custom}|doc|objectLibs|type=custom", 'alias' => 'custom');
$lang->doc->menu->product = array('link' => "{$lang->doc->product}|doc|tableContents|type=product", 'alias' => 'showfiles,product');
if($config->systemMode == 'new') $lang->doc->menu->project = array('link' => "{$lang->doc->project}|doc|tableContents|type=project", 'alias' => 'showfiles,project');
if($config->systemMode == 'classic') $lang->doc->menu->execution = array('link' => "{$lang->doc->execution}|doc|tableContents|type=execution", 'alias' => 'showfiles,execution');
$lang->doc->menu->custom = array('link' => "{$lang->doc->custom}|doc|tableContents|type=custom", 'alias' => 'custom');
$lang->doc->dividerMenu = ',product,';
+1
View File
@@ -269,6 +269,7 @@ $lang->lang = 'Ngôn ngữ';
/* Theme style. */
$lang->theme = 'Theme';
$lang->themes['default'] = 'Mặc định';
$lang->themes['blue'] = 'Blue';
$lang->themes['green'] = 'Green';
$lang->themes['red'] = 'Red';
$lang->themes['purple'] = 'Purple';
+18 -15
View File
@@ -25,21 +25,22 @@ $lang->ellipsis = '…';
$lang->percent = '%';
$lang->dash = '-';
$lang->zentaoPMS = '禅道';
$lang->logoImg = 'zt-logo.png';
$lang->welcome = "%s项目管理系统";
$lang->logout = '退出';
$lang->login = '登录';
$lang->help = '帮助';
$lang->aboutZenTao = '关于禅道';
$lang->profile = '个人档案';
$lang->changePassword = '修改密码';
$lang->unfoldMenu = '展开导航';
$lang->collapseMenu = '收起导航';
$lang->preference = '个性化设置';
$lang->runInfo = "<div class='row'><div class='u-1 a-center' id='debugbar'>时间: %s 毫秒, 内存: %s KB, 查询: %s. </div></div>";
$lang->agreement = "已阅读并同意<a href='http://zpl.pub/page/zplv12.html' target='_blank'>《Z PUBLIC LICENSE授权协议1.2》</a>。<span class='text-danger'>未经许可,不得去除、隐藏或遮掩禅道软件的任何标志及链接。</span>";
$lang->designedByAIUX = "<a href='https://api.zentao.net/goto.php?item=aiux' class='link-aiux' target='_blank'><i class='icon icon-aiux'></i> 艾体验设计</a>";
$lang->zentaoPMS = '禅道';
$lang->proName = '专业版';
$lang->logoImg = 'zt-logo.png';
$lang->welcome = "%s项目管理系统";
$lang->logout = '退出';
$lang->login = '登录';
$lang->help = '帮助';
$lang->aboutZenTao = '关于禅道';
$lang->profile = '个人档案';
$lang->changePassword = '修改密码';
$lang->unfoldMenu = '展开导航';
$lang->collapseMenu = '收起导航';
$lang->preference = '个性化设置';
$lang->runInfo = "<div class='row'><div class='u-1 a-center' id='debugbar'>时间: %s 毫秒, 内存: %s KB, 查询: %s. </div></div>";
$lang->agreement = "已阅读并同意<a href='http://zpl.pub/page/zplv12.html' target='_blank'>《Z PUBLIC LICENSE授权协议1.2》</a>。<span class='text-danger'>未经许可,不得去除、隐藏或遮掩禅道软件的任何标志及链接。</span>";
$lang->designedByAIUX = "<a href='https://api.zentao.net/goto.php?item=aiux' class='link-aiux' target='_blank'><i class='icon icon-aiux'></i> 艾体验设计</a>";
$lang->reset = '重填';
$lang->cancel = '取消';
@@ -153,6 +154,7 @@ $lang->custom->common = '自定义';
$lang->extension->common = '插件';
$lang->company->common = '公司';
$lang->dept->common = '部门';
$lang->upgrade->common = '升级';
$lang->program->list = '项目集列表';
$lang->execution->list = "{$lang->executionCommon}列表";
@@ -288,6 +290,7 @@ $lang->lang = 'Language';
/* 风格列表。*/
$lang->theme = '主题';
$lang->themes['default'] = '禅道蓝(默认)';
$lang->themes['blue'] = '青春蓝';
$lang->themes['green'] = '叶兰绿';
$lang->themes['red'] = '赤诚红';
$lang->themes['purple'] = '玉烟紫';
+18 -15
View File
@@ -25,21 +25,22 @@ $lang->ellipsis = '…';
$lang->percent = '%';
$lang->dash = '-';
$lang->zentaoPMS = '禪道';
$lang->logoImg = 'zt-logo.png';
$lang->welcome = "%s項目管理系統";
$lang->logout = '退出';
$lang->login = '登錄';
$lang->help = '幫助';
$lang->aboutZenTao = '關於禪道';
$lang->profile = '個人檔案';
$lang->changePassword = '修改密碼';
$lang->unfoldMenu = '展開導航';
$lang->collapseMenu = '收起導航';
$lang->preference = '個性化設置';
$lang->runInfo = "<div class='row'><div class='u-1 a-center' id='debugbar'>時間: %s 毫秒, 內存: %s KB, 查詢: %s. </div></div>";
$lang->agreement = "已閲讀並同意<a href='http://zpl.pub/page/zplv12.html' target='_blank'>《Z PUBLIC LICENSE授權協議1.2》</a>。<span class='text-danger'>未經許可,不得去除、隱藏或遮掩禪道軟件的任何標誌及連結。</span>";
$lang->designedByAIUX = "<a href='https://api.zentao.net/goto.php?item=aiux' class='link-aiux' target='_blank'><i class='icon icon-aiux'></i> 艾體驗設計</a>";
$lang->zentaoPMS = '禪道';
$lang->proName = '專業版';
$lang->logoImg = 'zt-logo.png';
$lang->welcome = "%s項目管理系統";
$lang->logout = '退出';
$lang->login = '登錄';
$lang->help = '幫助';
$lang->aboutZenTao = '關於禪道';
$lang->profile = '個人檔案';
$lang->changePassword = '修改密碼';
$lang->unfoldMenu = '展開導航';
$lang->collapseMenu = '收起導航';
$lang->preference = '個性化設置';
$lang->runInfo = "<div class='row'><div class='u-1 a-center' id='debugbar'>時間: %s 毫秒, 內存: %s KB, 查詢: %s. </div></div>";
$lang->agreement = "已閲讀並同意<a href='http://zpl.pub/page/zplv12.html' target='_blank'>《Z PUBLIC LICENSE授權協議1.2》</a>。<span class='text-danger'>未經許可,不得去除、隱藏或遮掩禪道軟件的任何標誌及連結。</span>";
$lang->designedByAIUX = "<a href='https://api.zentao.net/goto.php?item=aiux' class='link-aiux' target='_blank'><i class='icon icon-aiux'></i> 艾體驗設計</a>";
$lang->reset = '重填';
$lang->cancel = '取消';
@@ -153,6 +154,7 @@ $lang->custom->common = '自定義';
$lang->extension->common = '插件';
$lang->company->common = '公司';
$lang->dept->common = '部門';
$lang->upgrade->common = '升級';
$lang->program->list = '項目集列表';
$lang->execution->list = "{$lang->executionCommon}列表";
@@ -288,6 +290,7 @@ $lang->lang = 'Language';
/* 風格列表。*/
$lang->theme = '主題';
$lang->themes['default'] = '禪道藍(預設)';
$lang->themes['blue'] = '青春藍';
$lang->themes['green'] = '葉蘭綠';
$lang->themes['red'] = '赤誠紅';
$lang->themes['purple'] = '玉煙紫';
+84 -20
View File
@@ -185,6 +185,7 @@ class commonModel extends model
if($this->loadModel('user')->isLogon() or ($this->app->company->guest and $this->app->user->account == 'guest'))
{
if(stripos($method, 'ajax') !== false) return true;
if($module == 'my' and $method == 'guidechangetheme') return true;
if($module == 'misc' and $method == 'downloadclient') return true;
if($module == 'misc' and $method == 'changelog') return true;
if($module == 'tutorial' and $method == 'start') return true;
@@ -544,7 +545,8 @@ class commonModel extends model
if($config->systemMode == 'classic' and $openApp == 'execution') $icon = zget($lang->navIcons, 'project', '');
$link = helper::createLink($currentModule, $currentMethod);
$html = $link ? html::a($link, "$icon {$lang->$openApp->common}", '', "class='btn'") : "$icon {$lang->$openApp->common}";
$className = $openApp == 'devops' ? 'btn num' : 'btn';
$html = $link ? html::a($link, "$icon {$lang->$openApp->common}", '', "class='$className'") : "$icon {$lang->$openApp->common}";
echo "<div class='btn-group header-btn'>" . $html . '</div>';
}
@@ -576,7 +578,24 @@ class commonModel extends model
/* When last divider is not used in mainNav, use it next menu. */
$divider = ($divider || ($lastItem != $key) && strpos($lang->dividerMenu, ",{$group},") !== false) ? true : false;
if(!common::hasPriv($currentModule, $currentMethod)) continue;
if(!common::hasPriv($currentModule, $currentMethod))
{
$hidden = true;
if($currentModule == 'assetlib')
{
$methodList = array('caselib', 'issuelib', 'risklib', 'opportunitylib', 'practicelib', 'componentlib');
foreach($methodList as $method)
{
if(common::hasPriv($currentModule, $method))
{
$hidden = false;
$currentMethod = $method;
break;
}
}
}
if($hidden) continue;
}
if($divider and !empty($items))
{
@@ -1333,7 +1352,14 @@ EOD;
$link = $linkTemplate ? sprintf($linkTemplate, $preAndNext->pre->$id) : helper::createLink($moduleName, 'view', "ID={$preAndNext->pre->$id}");
$link .= '#app=' . $app->openApp;
echo html::a($link, '<i class="icon-pre icon-chevron-left"></i>', '', "id='prevPage' class='btn' title='{$title}'");
if(isset($preAndNext->pre->objectType) and $preAndNext->pre->objectType == 'doc')
{
echo html::a('javascript:void(0)', '<i class="icon-pre icon-chevron-left"></i>', '', "id='prevPage' class='btn' title='{$title}' data-url='{$link}'");
}
else
{
echo html::a($link, '<i class="icon-pre icon-chevron-left"></i>', '', "id='prevPage' class='btn' title='{$title}'");
}
}
if(isset($preAndNext->next) and $preAndNext->next)
{
@@ -1342,7 +1368,14 @@ EOD;
$title = '#' . $preAndNext->next->$id . ' ' . $title . ' ' . $lang->nextShortcutKey;
$link = $linkTemplate ? sprintf($linkTemplate, $preAndNext->next->$id) : helper::createLink($moduleName, 'view', "ID={$preAndNext->next->$id}");
$link .= '#app=' . $app->openApp;
echo html::a($link, '<i class="icon-pre icon-chevron-right"></i>', '', "id='nextPage' class='btn' title='$title'");
if(isset($preAndNext->next->objectType) and $preAndNext->next->objectType == 'doc')
{
echo html::a('javascript:void(0)', '<i class="icon-pre icon-chevron-right"></i>', '', "id='nextPage' class='btn' title='$title' data-url='{$link}'");
}
else
{
echo html::a($link, '<i class="icon-pre icon-chevron-right"></i>', '', "id='nextPage' class='btn' title='$title'");
}
}
echo '</nav>';
}
@@ -1350,13 +1383,14 @@ EOD;
/**
* Create changes of one object.
*
* @param mixed $old the old object
* @param mixed $new the new object
* @param mixed $old the old object
* @param mixed $new the new object
* @param string $moduleName
* @static
* @access public
* @return array
*/
public static function createChanges($old, $new)
public static function createChanges($old, $new, $moduleName = '')
{
global $app, $config;
@@ -1373,7 +1407,7 @@ EOD;
if($oldID && $oldStatus && $newStatus && !$newSubStatus && $oldStatus != $newStatus)
{
$moduleName = $app->getModuleName();
if(empty($moduleName)) $moduleName = $app->getModuleName();
$field = $app->dbh->query('SELECT options FROM ' . TABLE_WORKFLOWFIELD . " WHERE `module` = '$moduleName' AND `field` = 'subStatus'")->fetch();
if(!empty($field->options)) $field->options = json_decode($field->options, true);
@@ -1963,6 +1997,7 @@ EOD;
{
$httpType = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? 'https' : 'http';
if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') $httpType = 'https';
if(isset($_SERVER['REQUEST_SCHEME']) and strtolower($_SERVER['REQUEST_SCHEME']) == 'https') $httpType = 'https';
$httpHost = $_SERVER['HTTP_HOST'];
return "$httpType://$httpHost";
}
@@ -2024,6 +2059,29 @@ EOD;
return $convertedItems;
}
/**
* Check an entry of new API.
*
* @access public
* @return void
*/
private function checkNewEntry()
{
$entry = $this->loadModel('entry')->getByKey(session_id());
if(!$entry or !$entry->account or !$this->checkIP($entry->ip)) return false;
$user = $this->dao->findByAccount($entry->account)->from(TABLE_USER)->andWhere('deleted')->eq(0)->fetch();
if(!$user) return false;
$user->last = time();
$user->rights = $this->loadModel('user')->authorize($user->account);
$user->groups = $this->user->getGroups($user->account);
$user->view = $this->user->grantUserView($user->account, $user->rights['acls']);
$user->admin = strpos($this->app->company->admins, ",{$user->account},") !== false;
$this->session->set('user', $user);
$this->app->user = $user;
}
/**
* Check an entry.
*
@@ -2032,20 +2090,18 @@ EOD;
*/
public function checkEntry()
{
if($this->isOpenMethod($_GET[$this->config->moduleVar], $_GET[$this->config->methodVar])) return true;
/* if the API is new version, goto checkNewEntry. */
if($this->app->version) return $this->checkNewEntry();
$this->loadModel('entry');
if($this->session->valid_entry)
{
if(!$this->session->entry_code) $this->response('SESSION_CODE_MISSING');
if($this->session->valid_entry != md5(md5($this->get->code) . $this->server->remote_addr)) $this->response('SESSION_VERIFY_FAILED');
return true;
}
/* Old version. */
if(!isset($_GET[$this->config->moduleVar]) or !isset($_GET[$this->config->methodVar])) $this->response('EMPTY_ENTRY');
if($this->isOpenMethod($_GET[$this->config->moduleVar], $_GET[$this->config->methodVar])) return true;
if(!$this->get->code) $this->response('PARAM_CODE_MISSING');
if(!$this->get->token) $this->response('PARAM_TOKEN_MISSING');
$entry = $this->entry->getByCode($this->get->code);
$entry = $this->loadModel('entry')->getByCode($this->get->code);
if(!$entry) $this->response('EMPTY_ENTRY');
if(!$entry->key) $this->response('EMPTY_KEY');
if(!$this->checkIP($entry->ip)) $this->response('IP_DENIED');
@@ -2205,10 +2261,18 @@ EOD;
public function response($code)
{
$response = new stdclass();
$response->errcode = $this->config->entry->errcode[$code];
$response->errmsg = urlencode($this->lang->entry->errmsg[$code]);
if(isset($this->config->entry->errcode))
{
$response->errcode = $this->config->entry->errcode[$code];
$response->errmsg = urlencode($this->lang->entry->errmsg[$code]);
die(urldecode(json_encode($response)));
die(urldecode(json_encode($response)));
}
else
{
$response->error = $code;
die(urldecode(json_encode($response)));
}
}
/**
+17 -10
View File
@@ -10,8 +10,6 @@ $editor['id'] = explode(',', $editor['id']);
<?php js::import($jsRoot . 'markdown/simplemde.min.js'); ?>
<style>
.CodeMirror,.CodeMirror-scroll{min-height:200px!important;}
.CodeMirror-fullscreen + .editor-preview-side{display:block;}
.CodeMirror-fullscreen, .editor-preview-side{margin-bottom:40px;}
.editor-preview-side table > tbody > tr:last-child td{border:1px solid #e5e5e5 !important}
.editor-toolbar {padding: 1px;}
.editor-toolbar .icon-html:before {content:"HTML"; font-size: 12px; padding: 0 2px;}
@@ -37,15 +35,29 @@ $editor['id'] = explode(',', $editor['id']);
$(function()
{
var markdownEditor = <?php echo json_encode($editor);?>;
var toolbar = ["bold", "italic", "heading", "|", "quote", "unordered-list", "ordered-list", "|", "link", "image", "code", "table", "|", "preview", "side-by-side", "fullscreen", "|", "guide"];
var withchange = ["bold", "italic", "heading", "|", "quote", "unordered-list", "ordered-list", "|", "link", "image", "code", "table", "|", "preview", "side-by-side", "fullscreen", "|", "guide", {name: "html", action: function customFunction(editor){toggleEditor("html")}, className:'icon icon-html', title:"HTML"}];
const customFullscreen =
{
name: 'fullscreen',
className: 'icon icon-expand-full',
title: 'Fullscreen',
action: function(editor)
{
editor.toggleFullScreen();
if(editor.isFullscreenActive() && !editor.isSideBySideActive())
{
editor.toggleSideBySide();
}
}
};
var toolbar = ["bold", "italic", "heading", "|", "quote", "unordered-list", "ordered-list", "|", "link", "image", "code", "table", "|", "preview", "side-by-side", customFullscreen, "|", "guide"];
var withchange = ["bold", "italic", "heading", "|", "quote", "unordered-list", "ordered-list", "|", "link", "image", "code", "table", "|", "preview", "side-by-side", customFullscreen, "|", "guide", {name: "html", action: function customFunction(editor){toggleEditor && toggleEditor("html")}, className:'icon icon-html', title:"HTML"}];
function initMarkdown(config, afterInit)
{
config = config || markdownEditor;
$.each(markdownEditor.id, function(key, markdownEditorID)
{
if(typeof(markdownEditor.tools) != 'undefined' && markdownEditor.tools == 'withchange') toolbar = withchange;
var options =
var options =
{
toolbar: toolbar,
element: $('#' + markdownEditorID)[0],
@@ -56,11 +68,6 @@ $(function()
var markdown = new SimpleMDE(options);
if(!window.markdownEditor) window.markdownEditor = {};
window.markdownEditor['#'] = window.markdownEditor[markdownEditorID] = markdown;
// markdown.codemirror.on('focus', function(){window.markdownEditor[markdownEditorID].toggleSideBySide();});
// markdown.codemirror.on('change', function()
// {
// if($('#' + markdownEditorID).parent().find('.editor-preview-active-side').size() == 0) window.markdownEditor[markdownEditorID].toggleSideBySide();
// });
});
if($.isFunction(afterInit)) afterInit();
-1
View File
@@ -2,7 +2,6 @@
<style>
tbody.sortable > tr.drag-shadow {display: none}
tbody.sortable > tr > td.sort-handler {cursor: move; color: #999;}
tbody.sortable > tr > td.sort-handler > i {position: relative; top: 2px}
tbody.sortable-sorting > tr {transition: all .2s; position: relative; z-index: 5; opacity: .3;}
tbody.sortable-sorting {cursor: move;}
tbody.sortable-sorting > tr.drag-row {opacity: 1; z-index: 10; box-shadow: 0 2px 4px red}
+1 -1
View File
@@ -64,7 +64,7 @@
<?php $openApp = '';?>
<?php if($action->objectType == 'meeting') $openApp = $action->project ? "data-app='project'" : "data-app='my'";?>
<?php
if(isset($config->maxVersion) and strpos($config->action->assetType, $action->objectType) !== false and empty($action->objectName))
if((isset($config->maxVersion) and strpos($config->action->assetType, $action->objectType) !== false) or empty($action->objectName))
{
echo '#' . $action->objectID;
}
+3
View File
@@ -64,8 +64,11 @@ class compile extends control
public function logs($buildID)
{
$build = $this->compile->getByID($buildID);
$job = $this->loadModel('job')->getByID($build->job);
$this->view->logs = str_replace("\r\n","<br />", $build->logs);
$this->view->build = $build;
$this->view->job = $job;
$this->view->title = $this->lang->ci->job . $this->lang->colon . $this->lang->compile->logs;
$this->view->position[] = html::a($this->createLink('job', 'browse'), $this->lang->ci->job);
+13
View File
@@ -0,0 +1,13 @@
$().ready(function()
{
$('#refreshBtn').click(function()
{
$url = $(this).attr('href');
$.get($url, function(response)
{
window.location.reload();
});
return false;
});
});
+11 -6
View File
@@ -3,15 +3,20 @@ $lang->compile->common = 'Compile';
$lang->compile->browse = 'History';
$lang->compile->logs = 'Log';
$lang->compile->id = 'ID';
$lang->compile->name = 'Name';
$lang->compile->status = 'Status';
$lang->compile->time = 'Time';
$lang->compile->result = 'Result';
$lang->compile->id = 'ID';
$lang->compile->name = 'Name';
$lang->compile->buildType = 'Engine';
$lang->compile->status = 'Status';
$lang->compile->time = 'Time';
$lang->compile->result = 'Result';
$lang->compile->refresh = 'Refresh';
$lang->compile->statusList['success'] = 'Done';
$lang->compile->statusList['failure'] = 'Failed';
$lang->compile->statusList['created'] = 'Created';
$lang->compile->statusList['building'] = 'Creating';
$lang->compile->statusList['pending'] = 'Pending';
$lang->compile->statusList['running'] = 'Running';
$lang->compile->statusList['building'] = 'Building';
$lang->compile->statusList['create_fail'] = 'Failed to create';
$lang->compile->statusList['timeout'] = 'Timeout';
$lang->compile->statusList['canceled'] = 'Canceled';
+4
View File
@@ -9,10 +9,14 @@ $lang->compile->buildType = '构建引擎';
$lang->compile->status = '构建状态';
$lang->compile->time = '构建时间';
$lang->compile->result = '构建结果';
$lang->compile->refresh = '刷新';
$lang->compile->statusList['success'] = '成功';
$lang->compile->statusList['failure'] = '失败';
$lang->compile->statusList['created'] = '新建';
$lang->compile->statusList['pending'] = '队列中';
$lang->compile->statusList['running'] = '运行中';
$lang->compile->statusList['building'] = '构建中';
$lang->compile->statusList['create_fail'] = '创建失败';
$lang->compile->statusList['timeout'] = '执行超时';
$lang->compile->statusList['canceled'] = '已取消';
+10 -5
View File
@@ -3,15 +3,20 @@ $lang->compile->common = '構建';
$lang->compile->browse = '構建歷史';
$lang->compile->logs = '構建日誌';
$lang->compile->id = 'ID';
$lang->compile->name = '構建名稱';
$lang->compile->status = '構建狀態';
$lang->compile->time = '構建時間';
$lang->compile->result = '構建結果';
$lang->compile->id = 'ID';
$lang->compile->name = '構建名稱';
$lang->compile->buildType = '構建引擎';
$lang->compile->status = '構建狀態';
$lang->compile->time = '構建時間';
$lang->compile->result = '構建結果';
$lang->compile->refresh = '刷新';
$lang->compile->statusList['success'] = '成功';
$lang->compile->statusList['failure'] = '失敗';
$lang->compile->statusList['created'] = '新建';
$lang->compile->statusList['pending'] = '隊列中';
$lang->compile->statusList['running'] = '運行中';
$lang->compile->statusList['building'] = '構建中';
$lang->compile->statusList['create_fail'] = '創建失敗';
$lang->compile->statusList['timeout'] = '執行超時';
$lang->compile->statusList['canceled'] = '已取消';
+15 -15
View File
@@ -12,9 +12,9 @@
class compileModel extends model
{
/**
* Get by id
*
* @param int $buildID
* Get by id
*
* @param int $buildID
* @access public
* @return object
*/
@@ -25,10 +25,10 @@ class compileModel extends model
/**
* Get build list.
*
* @param int $jobID
* @param string $orderBy
* @param object $pager
*
* @param int $jobID
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
@@ -48,7 +48,7 @@ class compileModel extends model
/**
* Get unexecuted list.
*
*
* @access public
* @return array
*/
@@ -59,7 +59,7 @@ class compileModel extends model
/**
* Get last result.
*
*
* @param int $jobID
* @access public
* @return object
@@ -71,7 +71,7 @@ class compileModel extends model
/**
* Get build url.
*
*
* @param object $jenkins
* @access public
* @return object
@@ -91,10 +91,10 @@ class compileModel extends model
/**
* Save build by job
*
* @param int $jobID
* @param string $data
* @param string $type
*
* @param int $jobID
* @param string $data
* @param string $type
* @access public
* @return void
*/
@@ -114,7 +114,7 @@ class compileModel extends model
/**
* Execute compile
*
*
* @param object $compile
* @access public
* @return bool
+7 -2
View File
@@ -19,7 +19,11 @@
?>
</div>
</div>
<?php if(empty($buildList)):?>
<div class="table-empty-tip">
<p><span class="text-muted"><?php echo $lang->noData;?></span></p>
</div>
<?php else:?>
<div id='mainContent'>
<form class='main-table' id='ajaxForm' method='post'>
<table id='buildList' class='table has-sort-head table-fixed'>
@@ -40,7 +44,7 @@
<?php foreach($buildList as $id => $build):?>
<tr>
<td class='text-center'><?php echo $id;?></td>
<td title='<?php echo $build->name;?>'><?php echo common::hasPriv('job', 'view') ? html::a($this->createLink('job', 'view', "jobID={$build->job}&compileID={$build->id}", 'html', true), $build->name, '', "class='iframe' data-width='90%'") : $build->name;?></td>
<td class='c-name' title='<?php echo $build->name;?>'><?php echo common::hasPriv('job', 'view') ? html::a($this->createLink('job', 'view', "jobID={$build->job}&compileID={$build->id}", 'html', true), $build->name, '', "class='iframe' data-width='90%'") : $build->name;?></td>
<td title='<?php echo $build->engine;?>'><?php echo $build->engine;?></td>
<td title='<?php echo $build->repoName;?>'><?php echo $build->repoName;?></td>
<?php $jenkins = urldecode($build->pipeline) . '@' . $build->jenkinsName;?>
@@ -67,4 +71,5 @@
<?php endif; ?>
</form>
</div>
<?php endif;?>
<?php include '../../common/view/footer.html.php';?>
+1
View File
@@ -18,6 +18,7 @@
</div>
</div>
<div class="btn-toolbar pull-right">
<?php if($job->engine == 'gitlab') echo html::a(helper::createLink('ci', "checkCompileStatus", "compileID={$build->id}"), "<i class='icon icon-eye icon-sm'></i> ". $lang->compile->refresh, '', "class='btn btn-secondary' id='refreshBtn'");?>
<?php echo html::a(helper::createLink('compile', "browse", "jobID=$build->job"), "<i class='icon icon-back icon-sm'></i> ". $lang->goback, '', "class='btn btn-secondary'");?>
</div>
</div>
+1 -1
View File
@@ -16,7 +16,7 @@
common::printLink('custom', $sysObject, "", "<span class='text'>{$lang->custom->$sysObject}</span>", '', "class='btn btn-link' id='{$sysObject}Tab'");
}
common::printLink('custom', 'mode', "", "<span class='text'>{$lang->custom->mode}</span>", '', "class='btn btn-link' id='modeTab'");
if($config->systemMode == 'classic') common::printLink('custom', 'mode', "", "<span class='text'>{$lang->custom->mode}</span>", '', "class='btn btn-link' id='modeTab'");
?>
</div>
</div>
+9
View File
@@ -28,6 +28,15 @@ $config->doc->editor->view = array('id' => 'comment,lastComment', 'tools' => '
$config->doc->markdown = new stdclass();
$config->doc->markdown->create = array('id' => 'contentMarkdown', 'tools' => 'withchange');
$config->doc->collectionLimit = 10;
$config->doc->iconList['html'] = 'rich-text';
$config->doc->iconList['markdown'] = 'markdown';
$config->doc->iconList['url'] = 'text-link';
$config->doc->iconList['word'] = 'word';
$config->doc->iconList['ppt'] = 'ppt';
$config->doc->iconList['excel'] = 'excel';
$config->doc->search['module'] = 'doc';
$config->doc->search['fields']['title'] = $lang->doc->title;
$config->doc->search['fields']['id'] = $lang->doc->id;
+179 -98
View File
@@ -70,7 +70,12 @@ class doc extends control
*/
public function browse($browseType = 'all', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
$this->session->set('docList', $this->app->getURI(true), 'doc');
/* Save session, load module. */
$uri = $this->app->getURI(true);
$this->session->set('docList', $uri, 'doc');
$this->session->set('productList', $uri, 'product');
$this->session->set('executionList', $uri, 'execution');
$this->session->set('projectList', $uri, 'project');
$this->loadModel('search');
/* Set browseType.*/
@@ -163,9 +168,9 @@ class doc extends control
}
$libTypeList = $this->lang->doc->libTypeList;
if(empty($products)) unset($libTypeList['product']);
if(empty($projects)) unset($libTypeList['project']);
if(empty($executions)) unset($libTypeList['execution']);
if(empty($products)) unset($libTypeList['product']);
if(empty($projects)) unset($libTypeList['project']);
if(empty($executions) or ($this->config->systemMode == 'new' and $this->app->openApp == 'doc')) unset($libTypeList['execution']);
$this->view->groups = $this->loadModel('group')->getPairs();
$this->view->users = $this->user->getPairs('nocode');
@@ -223,16 +228,18 @@ class doc extends control
* Delete a library.
*
* @param int $libID
* @param string $confirm yes|no
* @param string $confirm yes|no
* @param string $from lib|book
* @access public
* @return void
*/
public function deleteLib($libID, $confirm = 'no')
public function deleteLib($libID, $confirm = 'no', $from = 'lib')
{
if($libID == 'product' or $libID == 'execution') die();
if($confirm == 'no')
{
die(js::confirm($this->lang->doc->confirmDeleteLib, $this->createLink('doc', 'deleteLib', "libID=$libID&confirm=yes")));
$deleteTip = $from == 'book' ? $this->lang->doc->confirmDeleteBook : $this->lang->doc->confirmDeleteLib;
die(js::confirm($deleteTip, $this->createLink('doc', 'deleteLib', "libID=$libID&confirm=yes")));
}
else
{
@@ -291,7 +298,8 @@ class doc extends control
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $docID));
$objectID = zget($lib, $lib->type, '');
$params = "type={$lib->type}&objectID=$objectID&libID={$lib->id}&docID=" . $docResult['id'];
$libType = ($lib->type == 'execution' and $this->app->openApp != 'execution') ? 'project' : $lib->type;
$params = "type={$libType}&objectID=$objectID&libID={$lib->id}&docID=" . $docResult['id'];
$link = $this->createLink('doc', 'objectLibs', $params);
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $link));
}
@@ -315,8 +323,9 @@ class doc extends control
{
$this->app->rawMethod = $objectType;
unset($this->lang->doc->menu->product['subMenu']);
if($this->config->systemMode == 'new') unset($this->lang->doc->menu->project['subMenu']);
unset($this->lang->doc->menu->custom['subMenu']);
if($this->config->systemMode == 'new') unset($this->lang->doc->menu->project['subMenu']);
if($this->config->systemMode == 'classic') unset($this->lang->doc->menu->execution['subMenu']);
}
$lib = $this->doc->getLibByID($libID);
@@ -419,8 +428,9 @@ class doc extends control
$this->app->rawMethod = $objectType;
unset($this->lang->doc->menu->product['subMenu']);
if($this->config->systemMode == 'new') unset($this->lang->doc->menu->project['subMenu']);
unset($this->lang->doc->menu->custom['subMenu']);
if($this->config->systemMode == 'new') unset($this->lang->doc->menu->project['subMenu']);
if($this->config->systemMode == 'classic') unset($this->lang->doc->menu->execution['subMenu']);
/* High light menu. */
if(strpos(',product,project,execution,custom,book,', ",$objectType,") !== false)
@@ -742,6 +752,63 @@ class doc extends control
die($select);
}
/**
* Show files.
*
* @param string $type
* @param int $objectID
* @param string $viewType
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function showFiles($type, $objectID, $viewType = '', $orderBy = 't1.id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
if(empty($viewType)) $viewType = !empty($_COOKIE['docFilesViewType']) ? $this->cookie->docFilesViewType : 'card';
setcookie('docFilesViewType', $viewType, $this->config->cookieLife, $this->config->webRoot, '', false, true);
$objects = $this->doc->getOrderedObjects($type);
$objectID = $this->{$type}->saveState($objectID, $objects);
$libs = $this->doc->getLibsByObject($type, $objectID);
$this->lang->modulePageNav = $this->doc->select($type, $objects, $objectID, $libs);
$openApp = strpos('doc,product,project,execution', $this->app->openApp) !== false ? $this->app->openApp : 'doc';
if($openApp != 'doc') $this->loadModel($openApp)->setMenu($objectID);
$table = $this->config->objectTables[$type];
$object = $this->dao->select('id,name,status')->from($table)->where('id')->eq($objectID)->fetch();
$this->lang->TRActions = $this->doc->buildCollectButton4Doc();
$this->lang->TRActions .= $this->doc->buildBrowseSwitch($type, $objectID, $viewType);
/* Load pager. */
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$files = $this->doc->getLibFiles($type, $objectID, $orderBy, $pager);
$this->view->title = $object->name;
$this->view->position[] = $object->name;
$this->view->type = $type;
$this->view->object = $object;
$this->view->files = $files;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->pager = $pager;
$this->view->viewType = $viewType;
$this->view->orderBy = $orderBy;
$this->view->objectID = $objectID;
$this->view->canBeChanged = common::canModify($type, $object); // Determines whether an object is editable.
$this->view->summary = $this->doc->summary($files);
$this->view->sourcePairs = $this->doc->getFileSourcePairs($files);
$this->view->fileIcon = $this->doc->getFileIcon($files);
$this->display();
}
/**
* Show all libs by type.
*
@@ -815,95 +882,17 @@ class doc extends control
* @param int $libID
* @param int $docID
* @param int $version
* @param int $appendLib
* @access public
* @return void
*/
public function objectLibs($type, $objectID = 0, $libID = 0, $docID = 0, $version = 0)
public function objectLibs($type, $objectID = 0, $libID = 0, $docID = 0, $version = 0, $appendLib = 0)
{
if(empty($type))
{
$doclib = $this->doc->getLibById($libID);
$type = $doclib->type == 'execution' ? 'project' : $doclib->type;
$objectID = $type == 'custom' or $type == 'book' ? 0 : $doclib->$type;
}
$lib = $this->doc->getLibById($libID);
if(!empty($lib) and $lib->deleted == '1') $appendLib = $libID;
$this->session->set('docList', $this->app->getURI(true), $this->app->openApp);
$objects = $this->doc->getOrderedObjects($type);
if($type == 'custom')
{
$libs = $this->doc->getLibsByObject('custom', 0);
$this->app->rawMethod = 'custom';
if($libID == 0) $libID = key($libs);
$this->lang->modulePageNav = $this->doc->select($type, $objects, $objectID, $libs, $libID);
$object = new stdclass();
$object->id = 0;
}
elseif($type == 'book')
{
$libs = $this->doc->getLibsByObject('book', 0);
$this->app->rawMethod = 'book';
if($libID == 0 and !empty($libs)) $libID = reset($libs)->id;
$this->lang->modulePageNav = $this->doc->select($type, $objects, $objectID, $libs, $libID);
if(!$docID) $docID = $this->dao->select('id')->from(TABLE_DOC)
->where('lib')->eq($libID)
->andWhere('type')->eq('article')
->andWhere('deleted')->eq(0)
->orderBy('editedDate_desc,id_desc')
->fetch('id');
$object = new stdclass();
$object->id = 0;
}
else
{
if($type == 'product')
{
$objectID = $this->product->saveState($objectID, $objects);
$table = TABLE_PRODUCT;
$libs = $this->doc->getLibsByObject('product', $objectID);
if($libID == 0) $libID = key($libs);
$this->lang->modulePageNav = $this->doc->select($type, $objects, $objectID, $libs, $libID);
$this->app->rawMethod = 'product';
}
else if($type == 'project')
{
$objectID = $this->project->saveState($objectID, $objects);
$table = TABLE_PROJECT;
$libs = $this->doc->getLibsByObject('project', $objectID);
if($libID == 0) $libID = key($libs);
$this->lang->modulePageNav = $this->doc->select($type, $objects, $objectID, $libs, $libID);
$this->app->rawMethod = 'project';
}
else if($type == 'execution')
{
$objectID = $this->execution->saveState($objectID, $objects);
$table = TABLE_EXECUTION;
$libs = $this->doc->getLibsByObject('execution', $objectID);
if($libID == 0) $libID = key($libs);
$this->lang->modulePageNav = $this->doc->select($type, $objects, $objectID, $libs, $libID);
$this->app->rawMethod = 'execution';
}
$object = $this->dao->select('id,name,status')->from($table)->where('id')->eq($objectID)->fetch();
if(empty($object)) $this->locate($this->createLink($type, 'create', '', '', '', $this->session->project));
}
if(!$libID) $libID = key($libs);
$openApp = strpos('doc,product,project,execution', $this->app->openApp) !== false ? $this->app->openApp : 'doc';
if($openApp != 'doc') $this->loadModel($openApp)->setMenu($objectID);
if($this->config->systemMode == 'classic' and $type == 'project') $type = 'execution';
list($libs, $libID, $object, $objectID) = $this->doc->setMenuByType($type, $objectID, $libID, $appendLib);
/* Set Custom. */
foreach(explode(',', $this->config->doc->customObjectLibs) as $libType) $customObjectLibs[$libType] = $this->lang->doc->customObjectLibs[$libType];
@@ -911,8 +900,6 @@ class doc extends control
$actionURL = $this->createLink('doc', 'browse', "lib=0&browseType=bySearch&queryID=myQueryID");
$this->doc->buildSearchForm(0, array(), 0, $actionURL, 'objectLibs');
$this->lang->TRActions = common::hasPriv('doc', 'create') ? $this->doc->buildCreateButton4Doc($type, $objectID, $libID) : '';
$moduleTree = $type == 'book' ? $this->doc->getBookStructure($libID) : $this->doc->getTreeMenu($type, $objectID, $libID, 0, $docID);
/* Get doc. */
@@ -923,7 +910,7 @@ class doc extends control
if($doc->keywords)
{
$doc->keywords = preg_replace("/(\n)|(\s)|(\t)|(\')|(')|()/", ',', $doc->keywords);
$doc->keywords = str_replace("", ',', $doc->keywords);
$doc->keywords = explode(',', $doc->keywords);
}
@@ -934,6 +921,70 @@ class doc extends control
}
}
if(isset($doc) and ($doc->type == 'text' || $doc->type == 'article'))
{
/* Split content into an array. */
$content = explode("\n", $doc->content);
/* Get the head element, for example h1,h2,etc. */
$includeHeadElement = array();
foreach($content as $index => $element)
{
preg_match('/<(h[1-6])([\S\s]*?)>([\S\s]*?)<\/\1>/', $element, $headElement);
if(isset($headElement[1]) and !in_array($headElement[1], $includeHeadElement) and strip_tags($headElement[3]) != '') $includeHeadElement[] = $headElement[1];
}
/* Get the two elements with the highest rank. */
sort($includeHeadElement);
$includeHeadElement = array_slice($includeHeadElement, 0, 2);
if($includeHeadElement)
{
$outline = '<ul class="tree tree-angles" data-ride="tree" id="outline">';
$preElement = '';
foreach($content as $index => $element)
{
preg_match('/<(h[1-6])([\S\s]*?)>([\S\s]*?)<\/\1>/', $element, $headElement);
/* The current element is existed, the element is in the includeHeadElement, and the text in the element is not null. */
if(isset($headElement[1]) and in_array($headElement[1], $includeHeadElement) and strip_tags($headElement[3]) != '')
{
/* The element is the first level. */
if(array_search($headElement[1], $includeHeadElement) == 0)
{
/* The second level is existed, and previous element is the second level element. */
if(isset($includeHeadElement[1]) and $preElement == $includeHeadElement[1]) $outline .= '</ul></li>';
if($preElement == $includeHeadElement[0]) $outline .= '</li>';
/* Add the anchor to the element. */
$content[$index] = str_replace('<' . $includeHeadElement[0] . $headElement[2] . '>', '<' . $includeHeadElement[0] . $headElement[2] . " id='anchor{$index}'" . '>', $content[$index]);
$outline .= '<li class="text-ellipsis">' . html::a('#anchor' . $index, strip_tags($headElement[3]), '', "title='" . strip_tags($headElement[3]) . "'");
$preElement = $headElement[1];
}
elseif(array_search($headElement[1], $includeHeadElement) == 1)
{
if($preElement == '') $outline .= '<li><ul>';
if($preElement == $includeHeadElement[0]) $outline .= '<ul>';
/* Add the anchor to the element. */
$content[$index] = str_replace('<' . $includeHeadElement[1] . $headElement[2] . '>', '<' . $includeHeadElement[1] . $headElement[2] . " id='anchor{$index}'" . '>', $content[$index]);
$outline .= '<li class="text-ellipsis">' . html::a('#anchor' . $index, strip_tags($headElement[3]), '', "title='" . strip_tags($headElement[3]) . "'") . '</li>';
$preElement = $includeHeadElement[1];
}
}
if(isset($includeHeadElement[1]) and $preElement == $includeHeadElement[1] and !isset($content[$index+1])) $outline .= '</ul></li>';
}
$outline .= '</ul>';
$doc->content = implode("\n", $content);
$this->view->outline = $outline;
}
}
$this->view->customObjectLibs = $customObjectLibs;
$this->view->showLibs = $this->config->doc->custom->objectLibs;
@@ -949,12 +1000,42 @@ class doc extends control
$this->view->objectType = $type;
$this->view->libID = $libID;
$this->view->lib = isset($libs[$libID]) ? $libs[$libID] : new stdclass();
$this->view->libs = $this->doc->getLibsByObject($type, $objectID);
$this->view->moduleTree = $moduleTree;
$this->view->canBeChanged = common::canModify($type, $object); // Determines whether an object is editable.
$this->view->actions = $docID ? $this->action->getList('doc', $docID) : array();
$this->view->users = $this->user->getPairs('noclosed,noletter');
$this->view->preAndNext = $this->doc->getPreAndNextDoc($docID, $libID);
$this->display();
}
/**
* Show the catalog of the doc library.
*
* @param string $type
* @param int $objectID
* @param int $libID
* @access public
* @return void
*/
public function tableContents($type, $objectID = 0, $libID = 0)
{
list($libs, $libID, $object, $objectID) = $this->doc->setMenuByType($type, $objectID, $libID);
$libID = empty($libID) ? 0 : $libID;
$moduleTree = $type == 'book' ? $this->doc->getBookStructure($libID) : $this->doc->getTreeMenu($type, $objectID, $libID);
$title = ($type == 'book' or $type == 'custom') ? $this->lang->doc->tableContents : $object->name . $this->lang->colon . $this->lang->doc->tableContents;
$this->view->title = $title;
$this->view->type = $type;
$this->view->libs = $libs;
$this->view->objectID = $objectID;
$this->view->libID = $libID;
$this->view->moduleTree = $moduleTree;
$this->view->users = $this->user->getPairs('noletter');
$this->display();
}
}
+11 -1
View File
@@ -80,4 +80,14 @@ td.c-name a:visited {color: #082999;}
#pageNav .dropdown-menu {max-height: 350px; overflow-y: auto;}
#createDropdown ul.dropdown-menu {width: 100%;}
ol, ul {margin-bottom: 0}
#subHeader #dropMenu .table-col .list-group {padding-top: 5px;}
#createDropdown ul.dropdown-menu {text-align: left;}
#collection-menu {max-width: 300px;}
#collection-menu li a {overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
#project, #product, #custom, #book, #execution {min-height: 160px;}
#title .menu-title {font-size: 15px; font-weight: 600; position: relative; padding: 2px 0 2px 15px; list-style: none;}
#title .dropdown-menu {top: 38px;}
.tree li > a {white-space: nowrap; text-overflow: ellipsis; overflow: hidden;}
.side-col .menu-actions {position: absolute; top: 0; right: 0; padding: 7px 8px;}
.menu-actions i {font-size: 15px; color: #8c8c8c;}
+1
View File
@@ -1 +1,2 @@
#whiteListBox .input-group:last-child {margin-top: 10px;}
#mainContent .main-header h2 {width: 90%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
+20 -10
View File
@@ -2,8 +2,8 @@
.addbtn {padding-top: 22px; height: 63px; border: 1px dashed #ddd; width: 60px;}
.addbtn .icon-plus {font-size: 18px; display: block; opacity: 0.5; transition: opacity .2s; text-shadow: 1px 1px 3px rgba(0,0,0,.2);}
.addbtn:hover .icon-plus {opacity: .9; animation: flash-icon 1s linear alternate infinite;}
#dropMenu {min-width: 250px; box-sizing: inhert;}
#dropMenu .table-col .list-group {padding-top: 10px;}
#subHeader #dropMenu {min-width: 250px; box-sizing: inhert; max-height: inherit;}
#subHeader #dropMenu .table-col .list-group {padding-top: 10px;}
.main-col .block-files .panel-heading {padding-right: 20px;}
.main-col .block-files .panel-heading .panel-title {height: 35px; line-height: 30px;}
.side-col .action a {margin: 0 auto 3px; display: block; max-width: 200px;}
@@ -13,20 +13,30 @@
.main-col .doc-title .info {flex: 1 1 0;}
.main-col .doc-title .version a {font-size: 13px; color: #8c8c8c;}
.main-col .doc-title .version .dropdown-menu a:hover {color: #ffffff;}
.main-col .doc-title .actions a {margin-right: 8px;}
.main-col .doc-title .actions a + a {margin-left: 8px;}
.main-col .doc-title .actions i {font-size: 15px; color: #8c8c8c;}
#content .title {max-width: 54%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
#mainContent .scrollbar-hover {max-height: 2000px; overflow: scroll;}
#sidebar {width: 275px;}
#sidebar>.cell {width: 100%;}
#sidebar>.sidebar-toggle {left: 3px; right: auto;}
#project, #product, #custom, #book {min-height: 160px;}
#title .menu-title {font-size: 15px; font-weight: 600; position: relative; padding: 2px 0 2px 15px;list-style: none;}
#title .dropdown-menu-book {left: -67px; top: 38px;}
#title .dropdown-menu-doc {left: -80px; top: 38px;}
.hide-sidebar #sidebar>.cell {left: -270px;}
.hide-sidebar #sidebar>.cell {display: none;}
.hide-sidebar #sidebar>.sidebar-toggle>.icon:before {content: "\e314";}
.detail.empty {line-height: 200px;}
.main-col+.side-col {padding-left: 16px;}
.main-col iframe {min-height: 380px;}
.menu-actions {position: absolute; top: 0; right: 0; padding: 7px 8px;}
.menu-actions i {font-size: 15px; color: #8c8c8c;}
.article-content .keywords {margin-bottom: 15px;}
.article-content {width: 100%; display: inline-block;}
.outline {position: relative;}
.outline .outline-toggle i.icon-angle-right, i.icon-angle-left {width: 18px; height: 18px; background: #efefef; border-radius: 50%; position: absolute; padding-left: 2px; padding-top: 1px;}
.outline .outline-toggle i.icon-angle-right:before {content: "\e314"; cursor: pointer;}
.outline .outline-toggle i.icon-angle-left:before {content: "\e315"; cursor: pointer;}
.outline ul li {list-style: none;}
.outline-content {display: none; padding-top: 18px;}
.outline-content a {color: #838A9D;}
.outline-content li.text-ellipsis.active>a {font-weight: 700; color: #0c64eb;}
#outline li.has-list.open:before {content: unset;}
.title {font-size: 20px !important;}
.article-content.comment {width: 100% !important;}
+23
View File
@@ -0,0 +1,23 @@
.main-content {padding-top: 0; padding-bottom: 0;}
.main-content #createDropdown {display: inline-block;}
.main-content #createDropdown ul {position: absolute;}
#pageNav .dropdown-menu {max-height: inherit;}
.no-content {width: 100px; height: 100px; margin: 0 auto;}
.notice {text-align: center; padding-left: 15px; padding-top: 20px;}
.no-content-button {text-align: center; padding-top: 20px;}
.no-content-button a:nth-child(2) {margin-left: 20px;}
.cell .detail .detail-title {padding-left: 5px; list-style: none;}
.menu-actions {position: absolute; top: 7px; right: 45px; padding: 7px 8px;}
.catalog>a {color: #838a9d !important;}
.detail ul {position: relative;}
.tail-info {position: absolute; right: 0; padding-left: 10px; padding-top: 1px;}
.tail-info, .doc-title, span.item {background: #fff;}
span.item>a {padding-left: 6px;}
span.dotted-line+a {display: block;}
#modules li.doc:before, .chapterNode:before, .independent:before {content: " "; width: 100%; border-bottom: 1px dashed #b5b9c5; position: absolute; top: 13px; right: 0; left: 30px;}
.doc-title {display: inline-block !important; position: relative; padding-right: 10px;}
.tree li.has-list.open:before {content: unset;}
#modules i.icon-file-text {color: #D0D2D6; font-size: 14px;}
.tree li>a {max-width: 80%;}
+7
View File
@@ -0,0 +1,7 @@
$('.ajaxCollect').click(function()
{
if(browseType == 'collectedbyme')
{
window.location.reload();
}
})
+18 -18
View File
@@ -46,7 +46,7 @@ function setBrowseType(type)
$(document).ready(function()
{
// hide #module chosen dropdown on #lib dropdown show
/* hide #module chosen dropdown on #lib dropdown show */
$('#lib').on('chosen:showing_dropdown', function()
{
$('#module').trigger('chosen:close');
@@ -85,8 +85,7 @@ $(document).ready(function()
var NAME = 'zui.splitRow'; // model name
// File input list
// The SplitRow model class
/* The SplitRow model class */
var SplitRow = function(element, options)
{
var that = this;
@@ -166,7 +165,8 @@ $(document).ready(function()
if (options.middleSize) $col.toggleClass('col-md-size', $col.width() < options.middleSize);
};
var resizeCols = function() {
var resizeCols = function()
{
var cellHeight = $(window).height() - $('#footer').outerHeight() - $('#header').outerHeight() - 42;
$cols.children('.panel').height(cellHeight).css('maxHeight', cellHeight).find('.panel-body').css('position', 'absolute');
var sideHeight = cellHeight - $cols.find('.nav-tabs').height() - $cols.find('.side-footer').height() - 35;
@@ -181,7 +181,7 @@ $(document).ready(function()
resizeCols();
};
// default options
/* default options */
SplitRow.DEFAULTS =
{
spliter: '<div class="col-spliter"></div>',
@@ -189,7 +189,7 @@ $(document).ready(function()
middleSize: 850
};
// Extense jquery element
/* Extense jquery element */
$.fn.splitRow = function(option)
{
return this.each(function()
@@ -205,7 +205,7 @@ $(document).ready(function()
$.fn.splitRow.Constructor = SplitRow;
// Auto call splitRow after document load complete
/* Auto call splitRow after document load complete */
$(function()
{
$('.split-row').splitRow();
@@ -225,17 +225,17 @@ $(document).ready(function()
var url = obj.data('url');
$.get(url, function(response)
{
if(response.status == 'yes')
{
obj.children('i').removeClass().addClass('icon icon-star text-yellow');
obj.parent().prev().children('.file-name').children('i').remove('.icon');
obj.parent().prev().children('.file-name').prepend('<i class="icon icon-star text-yellow"></i> ');
}
else
{
obj.children('i').removeClass().addClass('icon icon-star-empty');
obj.parent().prev().children('.file-name').children('i').remove(".icon");
}
if(response.status == 'yes')
{
obj.children('i').removeClass().addClass('icon icon-star text-yellow');
obj.parent().prev().children('.file-name').children('i').remove('.icon');
obj.parent().prev().children('.file-name').prepend('<i class="icon icon-star text-yellow"></i> ');
}
else
{
obj.children('i').removeClass().addClass('icon icon-star-empty');
obj.parent().prev().children('.file-name').children('i').remove(".icon");
}
}, 'json');
return false;
});
+115 -12
View File
@@ -19,7 +19,7 @@ function ajaxDeleteDoc(link, replaceID, notice)
$.get(link, function(data)
{
location.href = JSON.parse(data).locate;
})
});
}
}
@@ -44,38 +44,141 @@ function deleteFile(fileID)
*/
function fullScreen()
{
var element = document.getElementById("content");
var element = document.getElementById('content');
var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen;
if(requestMethod)
{
$('#content .actions').addClass('hidden');
requestMethod.call(element);
$.cookie('isFullScreen', 1);
var afterEnterFullscreen = function()
{
$('#mainActions').removeClass('hidden');
$('#content').addClass('scrollbar-hover');
$('#content .actions').addClass('hidden');
$('#content .file-image .right-icon').addClass('hidden');
$('#content .detail').eq(1).addClass('hidden');
$.cookie('isFullScreen', 1);
};
var whenFailEnterFullscreen = function(error)
{
$.cookie('isFullScreen', 0);
};
try
{
var result = requestMethod.call(element);
if(result && (typeof result.then === 'function' || result instanceof window.Promise))
{
result.then(afterEnterFullscreen).catch(whenFailEnterFullscreen);
}
else
{
afterEnterFullscreen();
}
}
catch (error)
{
whenFailEnterFullscreen(error);
}
}
}
/**
* Exit full screen.
*
* @access public
* @return void
*/
function exitFullScreen()
{
$('#mainActions').addClass('hidden');
$('#content').removeClass('scrollbar-hover');
$('#content .actions').removeClass('hidden');
$('#content .file-image .right-icon').removeClass('hidden');
$('#content .detail').eq(1).removeClass('hidden');
$.cookie('isFullScreen', 0);
}
document.addEventListener("fullscreenchange", function (e)
document.addEventListener('fullscreenchange', function (e)
{
if(!document.fullscreenElement) exitFullScreen();
})
});
document.addEventListener("webkitfullscreenchange", function (e)
document.addEventListener('webkitfullscreenchange', function (e)
{
if(!document.webkitFullscreenElement) exitFullScreen();
})
});
document.addEventListener("mozfullscreenchange", function (e)
document.addEventListener('mozfullscreenchange', function (e)
{
if(!document.mozFullScreenElement) exitFullScreen();
})
});
document.addEventListener("msfullscreenChange", function (e)
document.addEventListener('msfullscreenChange', function (e)
{
if(!document.msfullscreenElement) exitFullScreen();
});
$(function()
{
$(document).keydown(function(event)
{
if($.cookie('isFullScreen') == 1)
{
if(event.keyCode == 37) $('#prevPage').click();
if(event.keyCode == 39) $('#nextPage').click();
}
});
$('.outline').height($('.article-content').height());
$('#content').on('click', '.outline .outline-toggle i.icon-angle-right', function()
{
$('.article-content').width('85%');
$('.outline').css({'min-width' : '180px', 'border-left' : '2px solid #efefef'});
$(this).removeClass('icon-angle-right').addClass('icon-angle-left').css('left', '-9px');
$('.outline-content').show();
if($('#sidebar>.cell').is(':visible')) $('#sidebar .icon.icon-angle-right').trigger("click");
}).on('click', '.outline .outline-toggle i.icon-angle-left', function()
{
$('.article-content').width('100%');
$(this).removeClass('icon-angle-left').addClass('icon-angle-right');
$('.outline-content').hide();
}).on('click', '#outline li', function(e)
{
$('#outline li.active').removeClass('active');
$(e.target).closest('li').addClass('active');
});
$('#outline li.has-list').addClass('open in');
$('#outline li.has-list>i+ul').prev('i').remove();
$(document).on('click', '.detail-content a', function(event)
{
var target = $(this).attr('target');
if($.cookie('isFullScreen') == 1 && target != '_blank') exitFullScreen();
})
/* Update doc content silently on switch doc version, story #40503 */
$(document).on('click', '.doc-version-menu a, #mainActions .container a', function(event)
{
var $tmpDiv = $('<div>');
$tmpDiv.load($(this).data('url') + ' #mainContent', function()
{
$('#content').html($tmpDiv.find('#content').html());
$('#sidebarContent').html($tmpDiv.find('#sidebarContent').html());
$('#actionbox .histories-list').html($tmpDiv.find('#actionbox .histories-list').html());
if($.cookie('isFullScreen') == 1) fullScreen();
$('#content [data-ride="tree"]').tree();
$('#outline li.has-list').addClass('open in');
$('#outline li.has-list>i+ul').prev('i').remove();
});
});
$('#sidebar .icon.icon-angle-right').click(function()
{
if($('#sidebar>.cell').is(':hidden') && $('.outline-content').is(':visible'))
{
$('.outline .outline-toggle i.icon-angle-left').trigger("click");
}
})
$('.outline .outline-toggle i.icon-angle-right').trigger("click");
})

Some files were not shown because too many files have changed in this diff Show More