Merge branch 'sprint/sunhao/table_overflow_type'
This commit is contained in:
@@ -7,8 +7,8 @@ XVERSION = $(shell head -n 1 xuanxuan/XVERSION)
|
||||
#RELEASE_PATH := $(if $(ZENTAO_RELEASE_PATH),$(ZENTAO_RELEASE_PATH),$(shell pwd))
|
||||
XUANPATH := /home/gitlab-runner/ci/gitlab/xuan/
|
||||
XUAN_WEB_PATH := /home/gitlab-runner/ci/packages/web
|
||||
BUILD_PATH := /home/z/ci/build/
|
||||
RELEASE_PATH := /home/z/ci/release/
|
||||
BUILD_PATH := /home/z/ci/pip_build/
|
||||
RELEASE_PATH := /home/z/ci/pip_release/
|
||||
|
||||
all:
|
||||
make clean
|
||||
@@ -143,9 +143,10 @@ zentaoxx:
|
||||
sed -i "s#\$this->app->getModuleRoot() . 'im/apischeme.json'#\$this->app->getExtensionRoot() . 'xuan/im/apischeme.json'#g" zentaoxx/extension/xuan/im/model.php
|
||||
sed -i "s/'..\/..\/common\/view\/header.html.php'/\$$app->getModuleRoot() . 'common\/view\/header.html.php'/g" zentaoxx/extension/xuan/conference/view/admin.html.php
|
||||
sed -i "s/'..\/..\/common\/view\/footer.html.php'/\$$app->getModuleRoot() . 'common\/view\/footer.html.php'/g" zentaoxx/extension/xuan/conference/view/admin.html.php
|
||||
sed -i "s/\$$this->im->userGetChangedPassword()/array()/" zentaoxx/extension/xuan/im/control.php
|
||||
echo "ALTER TABLE \`zt_user\` ADD \`pinyin\` varchar(255) NOT NULL DEFAULT '' AFTER \`realname\`;" >> zentaoxx/db/xuanxuan.sql
|
||||
mkdir zentaoxx/tools; cp tools/cn2tw.php zentaoxx/tools; cd zentaoxx/tools; php cn2tw.php
|
||||
cp tools/en2de.php zentaoxx/tools; cd zentaoxx/tools; php en2de.php ../
|
||||
cp tools/en2other.php zentaoxx/tools; cd zentaoxx/tools; php en2other.php ../
|
||||
rm -rf zentaoxx/tools
|
||||
#zip -rqm -9 zentaoxx.$(VERSION).zip zentaoxx/*
|
||||
#rm -rf xuan.zip xuan zentaoxx
|
||||
|
||||
@@ -24,7 +24,7 @@ class productplansEntry extends entry
|
||||
if(!$productID) return $this->sendError(400, 'No product id.');
|
||||
|
||||
$control = $this->loadController('productplan', 'browse');
|
||||
$control->browse($productID, $this->param('branch', 0), $this->param('status', 'all'), $this->param('order', 'begin_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$control->browse($productID, $this->param('branch', 0), $this->param('status', 'all'), $this->param('query', 0), $this->param('order', 'begin_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
|
||||
@@ -195,7 +195,7 @@ class userEntry extends Entry
|
||||
if(!common::hasPriv('my', 'work')) break;
|
||||
|
||||
$control = $this->loadController('my', 'task');
|
||||
$control->task($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1));
|
||||
$control->task($this->param('type', 'assignedTo'), 0, $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if($data->status == 'success')
|
||||
@@ -210,7 +210,7 @@ class userEntry extends Entry
|
||||
if(!common::hasPriv('my', 'work')) break;
|
||||
|
||||
$control = $this->loadController('my', 'bug');
|
||||
$control->bug($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1));
|
||||
$control->bug($this->param('type', 'assignedTo'), 0, $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if($data->status == 'success')
|
||||
@@ -266,7 +266,7 @@ class userEntry extends Entry
|
||||
if(!common::hasPriv('my', 'work')) break;
|
||||
|
||||
$control = $this->loadController('my', 'story');
|
||||
$control->story($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1));
|
||||
$control->story($this->param('type', 'assignedTo'), 0, $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if($data->status == 'success')
|
||||
@@ -290,7 +290,7 @@ class userEntry extends Entry
|
||||
if($this->config->edition == 'max')
|
||||
{
|
||||
$control = $this->loadController('my', 'issue');
|
||||
$control->issue('createdBy', 'id_desc', 0, $this->param('limit', 5), 1);
|
||||
$control->issue('createdBy', 0, 'id_desc', 0, $this->param('limit', 5), 1);
|
||||
$data = $this->getData();
|
||||
|
||||
if($data->status == 'success')
|
||||
@@ -307,7 +307,7 @@ class userEntry extends Entry
|
||||
if($this->config->edition == 'max')
|
||||
{
|
||||
$control = $this->loadController('my', 'risk');
|
||||
$control->risk('createdBy', 'id_desc', 0, $this->param('limit', 5), 1);
|
||||
$control->risk('createdBy', 0, 'id_desc', 0, $this->param('limit', 5), 1);
|
||||
$data = $this->getData();
|
||||
|
||||
if($data->status == 'success')
|
||||
@@ -324,7 +324,7 @@ class userEntry extends Entry
|
||||
if($this->config->edition == 'max')
|
||||
{
|
||||
$control = $this->loadController('my', 'myMeeting');
|
||||
$control->myMeeting('all', 'id_desc', 0, $this->param('limit', 5), 1);
|
||||
$control->myMeeting('all', '', 'id_desc', 0, $this->param('limit', 5), 1);
|
||||
$data = $this->getData();
|
||||
|
||||
if($data->status == 'success')
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
|
||||
if(!function_exists('getWebRoot')){function getWebRoot(){}}
|
||||
|
||||
/* 基本设置。Basic settings. */
|
||||
$config->version = '17.2'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
|
||||
$config->version = '17.4'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
|
||||
$config->liteVersion = '1.2'; // 迅捷版版本。 The version of Lite.
|
||||
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
|
||||
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
|
||||
|
||||
@@ -271,6 +271,7 @@ $filter->project->task->cookie['projectTaskOrder'] = 'reg::orderBy';
|
||||
$filter->project->task->cookie['windowWidth'] = 'int';
|
||||
$filter->project->export->cookie['checkedItem'] = 'reg::checked';
|
||||
$filter->project->execution->cookie['pagerExecutionAll'] = 'int';
|
||||
$filter->project->execution->cookie['showTask'] = 'code';
|
||||
|
||||
$filter->projectstory->story->cookie['storyModuleParam'] = 'int';
|
||||
$filter->projectstory->story->cookie['pagerProductBrowse'] = 'int';
|
||||
|
||||
@@ -221,6 +221,7 @@ $config->openMethods[] = 'kanban.finishcard';
|
||||
$config->openMethods[] = 'kanban.deleteobjectcard';
|
||||
$config->openMethods[] = 'admin.ignore';
|
||||
$config->openMethods[] = 'personnel.unbindwhitelist';
|
||||
$config->openMethods[] = 'tree.viewhistory';
|
||||
|
||||
/* Define the tables. */
|
||||
define('TABLE_COMPANY', '`' . $config->db->prefix . 'company`');
|
||||
@@ -270,6 +271,7 @@ define('TABLE_PROJECTCASE', '`' . $config->db->prefix . 'projectcase`');
|
||||
define('TABLE_TASKESTIMATE', '`' . $config->db->prefix . 'taskestimate`');
|
||||
define('TABLE_EFFORT', '`' . $config->db->prefix . 'effort`');
|
||||
define('TABLE_BURN', '`' . $config->db->prefix . 'burn`');
|
||||
define('TABLE_CFD', '`' . $config->db->prefix . 'cfd`');
|
||||
define('TABLE_BUILD', '`' . $config->db->prefix . 'build`');
|
||||
define('TABLE_ACL', '`' . $config->db->prefix . 'acl`');
|
||||
|
||||
@@ -370,16 +372,22 @@ $config->objectTables['kanbanorder'] = TABLE_KANBANORDER;
|
||||
$config->objectTables['kanbangroup'] = TABLE_KANBANGROUP;
|
||||
$config->objectTables['kanbancard'] = TABLE_KANBANCARD;
|
||||
$config->objectTables['sonarqube'] = TABLE_PIPELINE;
|
||||
$config->objectTables['gitea'] = TABLE_PIPELINE;
|
||||
$config->objectTables['gitlab'] = TABLE_PIPELINE;
|
||||
$config->objectTables['jebkins'] = TABLE_PIPELINE;
|
||||
$config->objectTables['stage'] = TABLE_STAGE;
|
||||
$config->objectTables['apistruct'] = TABLE_APISTRUCT;
|
||||
$config->objectTables['repo'] = TABLE_REPO;
|
||||
|
||||
$config->newFeatures = array('introduction', 'tutorial', 'youngBlueTheme', 'visions');
|
||||
|
||||
$config->pipelineTypeList = array('gitlab', 'sonarqube', 'jenkins', 'gitea');
|
||||
|
||||
/* Program privs.*/
|
||||
$config->programPriv = new stdclass();
|
||||
$config->programPriv->scrum = array('story', 'projectstory', 'projectrelease', 'project', 'execution', 'build', 'bug', 'testcase', 'testreport', 'doc', 'repo', 'meeting', 'stakeholder', 'testtask');
|
||||
$config->programPriv->waterfall = array_merge($config->programPriv->scrum, array('task', 'workestimation', 'durationestimation', 'budget', 'programplan', 'review', 'reviewissue', 'weekly', 'cm', 'milestone', 'design', 'issue', 'risk', 'opportunity', 'measrecord', 'auditplan', 'trainplan', 'gapanalysis', 'pssp', 'researchplan', 'researchreport'));
|
||||
|
||||
$config->waterfallModules = array('workestimation', 'durationestimation', 'budget', 'programplan', 'review', 'reviewissue', 'weekly', 'cm', 'milestone', 'design', 'opportunity', 'auditplan', 'trainplan', 'gapanalysis', 'pssp', 'researchplan', 'researchreport');
|
||||
|
||||
$config->showMainMenu = true;
|
||||
|
||||
@@ -30,7 +30,7 @@ CREATE TABLE `zt_acl` (
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
CREATE TABLE `zt_action` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`id` int(9) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`objectType` varchar(30) NOT NULL DEFAULT '',
|
||||
`objectID` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`product` text NOT NULL,
|
||||
@@ -1009,7 +1009,7 @@ CREATE TABLE `zt_grouppriv` (
|
||||
UNIQUE KEY `group` (`group`,`module`,`method`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
CREATE TABLE `zt_history` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`id` int(9) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`action` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`field` varchar(30) NOT NULL DEFAULT '',
|
||||
`old` text NOT NULL,
|
||||
@@ -1091,6 +1091,7 @@ CREATE TABLE `zt_im_chat` (
|
||||
`editedDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`lastActiveTime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`lastMessage` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`lastMessageIndex` int(11) unsigned NOT NULL DEFAULT 0,
|
||||
`dismissDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`pinnedMessages` text NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
@@ -1107,6 +1108,8 @@ CREATE TABLE `zt_im_chat_message_index` (
|
||||
`tableName` char(64) NOT NULL,
|
||||
`start` int(11) unsigned NOT NULL,
|
||||
`end` int(11) unsigned NOT NULL,
|
||||
`startIndex` int(11) unsigned NOT NULL,
|
||||
`endIndex` int(11) unsigned NOT NULL,
|
||||
`startDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`endDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`count` mediumint(8) unsigned NOT NULL,
|
||||
@@ -1115,7 +1118,9 @@ CREATE TABLE `zt_im_chat_message_index` (
|
||||
KEY `start` (`start`),
|
||||
KEY `end` (`end`),
|
||||
KEY `startDate` (`startDate`),
|
||||
KEY `endDate` (`endDate`)
|
||||
KEY `endDate` (`endDate`),
|
||||
KEY `chatstartindex` (`gid`,`startIndex`),
|
||||
KEY `chatendindex` (`gid`,`endIndex`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
CREATE TABLE `zt_im_chatuser` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
@@ -1130,6 +1135,7 @@ CREATE TABLE `zt_im_chatuser` (
|
||||
`quit` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`category` varchar(40) NOT NULL DEFAULT '',
|
||||
`lastReadMessage` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`lastReadMessageIndex` int(11) unsigned NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `chatuser` (`cgid`,`user`),
|
||||
KEY `cgid` (`cgid`),
|
||||
@@ -1179,6 +1185,7 @@ CREATE TABLE `zt_im_message` (
|
||||
`cgid` char(40) NOT NULL DEFAULT '',
|
||||
`user` varchar(30) NOT NULL DEFAULT '',
|
||||
`date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`index` int(11) unsigned NOT NULL DEFAULT 0,
|
||||
`type` enum('normal','broadcast','notify','bulletin') NOT NULL DEFAULT 'normal',
|
||||
`content` text NOT NULL,
|
||||
`contentType` enum('text','plain','emotion','image','file','object','code') NOT NULL DEFAULT 'text',
|
||||
@@ -1196,6 +1203,7 @@ CREATE TABLE `zt_im_message_backup` (
|
||||
`cgid` char(40) NOT NULL DEFAULT '',
|
||||
`user` varchar(30) NOT NULL DEFAULT '',
|
||||
`date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`index` int(11) unsigned NOT NULL DEFAULT 0,
|
||||
`type` enum('normal','broadcast','notify') NOT NULL DEFAULT 'normal',
|
||||
`content` text NOT NULL,
|
||||
`contentType` enum('text','plain','emotion','image','file','object','code') NOT NULL DEFAULT 'text',
|
||||
@@ -2560,6 +2568,8 @@ CREATE TABLE `zt_story` (
|
||||
`approvedDate` date NOT NULL,
|
||||
`lastEditedBy` varchar(30) NOT NULL DEFAULT '',
|
||||
`lastEditedDate` datetime NOT NULL,
|
||||
`changedBy` VARCHAR(30) NOT NULL,
|
||||
`changedDate` DATETIME NOT NULL,
|
||||
`reviewedBy` varchar(255) NOT NULL,
|
||||
`reviewedDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`closedBy` varchar(30) NOT NULL DEFAULT '',
|
||||
@@ -3180,6 +3190,7 @@ CREATE TABLE `zt_workflowaction` (
|
||||
`show` enum('dropdownlist','direct') NOT NULL DEFAULT 'dropdownlist',
|
||||
`order` smallint(5) unsigned NOT NULL,
|
||||
`buildin` tinyint(1) unsigned NOT NULL,
|
||||
`role` varchar(10) NOT NULL DEFAULT 'custom',
|
||||
`virtual` tinyint(1) unsigned NOT NULL,
|
||||
`conditions` text NOT NULL,
|
||||
`verifications` text NOT NULL,
|
||||
@@ -3241,6 +3252,7 @@ CREATE TABLE `zt_workflowfield` (
|
||||
`isValue` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`readonly` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`buildin` tinyint(1) unsigned NOT NULL,
|
||||
`role` varchar(10) NOT NULL DEFAULT 'custom',
|
||||
`desc` text NOT NULL,
|
||||
`createdBy` varchar(30) NOT NULL,
|
||||
`createdDate` datetime NOT NULL,
|
||||
@@ -3262,6 +3274,7 @@ CREATE TABLE `zt_workflowlabel` (
|
||||
`orderBy` text NOT NULL,
|
||||
`order` tinyint(3) NOT NULL,
|
||||
`buildin` tinyint(1) unsigned NOT NULL,
|
||||
`role` varchar(10) NOT NULL DEFAULT 'custom',
|
||||
`createdBy` char(30) NOT NULL,
|
||||
`createdDate` datetime NOT NULL,
|
||||
`editedBy` char(30) NOT NULL,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+18
-1
@@ -18,4 +18,21 @@ ALTER TABLE `zt_kanban` ADD `showWIP` enum('0','1') NOT NULL DEFAULT '1' AFTER `
|
||||
ALTER TABLE `zt_kanban` ADD `alignment` varchar(10) NOT NULL DEFAULT 'center' AFTER `object`;
|
||||
|
||||
ALTER TABLE `zt_module` ADD `from` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `type`;
|
||||
ALTER TABLE `zt_workflow` ADD `approval` enum('enabled', 'disabled') NOT NULL DEFAULT 'disabled' AFTER `status`;
|
||||
|
||||
ALTER TABLE `zt_story` ADD `changedBy` VARCHAR(30) NOT NULL AFTER `lastEditedDate`;
|
||||
ALTER TABLE `zt_story` ADD `changedDate` DATETIME NOT NULL AFTER `changedBy`;
|
||||
|
||||
ALTER TABLE `zt_action` CHANGE `id` `id` int(9) unsigned NOT NULL AUTO_INCREMENT FIRST;
|
||||
ALTER TABLE `zt_history` CHANGE `id` `id` int(9) unsigned NOT NULL AUTO_INCREMENT FIRST;
|
||||
|
||||
ALTER TABLE `zt_workflow` ADD `approval` enum('enabled', 'disabled') NOT NULL DEFAULT 'disabled' AFTER `status`;
|
||||
ALTER TABLE `zt_workflowaction` ADD `role` varchar(10) NOT NULL DEFAULT 'custom' AFTER `buildin`;
|
||||
ALTER TABLE `zt_workflowfield` ADD `role` varchar(10) NOT NULL DEFAULT 'custom' AFTER `buildin`;
|
||||
ALTER TABLE `zt_workflowlabel` ADD `role` varchar(10) NOT NULL DEFAULT 'custom' AFTER `buildin`;
|
||||
|
||||
UPDATE `zt_workflowaction` SET `role` = 'buildin' WHERE `role` = 'custom' AND `buildin` = '1';
|
||||
UPDATE `zt_workflowaction` SET `role` = 'virtual' WHERE `role` = 'custom' AND `virtual` = '1';
|
||||
UPDATE `zt_workflowaction` SET `role` = 'default' WHERE `role` = 'custom' AND `action` IN ('browse', 'create', 'batchcreate', 'edit', 'view', 'delete', 'link', 'unlink', 'export', 'exporttemplate', 'import', 'showimport', 'report', 'assign', 'batchedit', 'batchassign');
|
||||
UPDATE `zt_workflowfield` SET `role` = 'buildin' WHERE `role` = 'custom' AND (`buildin` = '1' OR `field` = 'subStatus');
|
||||
UPDATE `zt_workflowfield` SET `role` = 'default' WHERE `role` = 'custom' AND `field` IN ('id', 'parent', 'assignedTo', 'status', 'createdBy', 'createdDate', 'editedBy', 'editedDate', 'assignedBy', 'assignedDate' 'mailto', 'deleted');
|
||||
UPDATE `zt_workflowlabel` SET `role` = 'buildin' WHERE `role` = 'custom' AND `buildin` = '1';
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
CREATE TABLE `zt_cfd` (
|
||||
`id` int(8) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`execution` int(8) NOT NULL,
|
||||
`type` char(30) NOT NULL,
|
||||
`name` char(30) NOT NULL,
|
||||
`count` smallint NOT NULL,
|
||||
`date` date NOT NULL,
|
||||
UNIQUE KEY `execution_type_name_date` (`execution`,`type`,`name`,`date`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
INSERT INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type`, `buildin`, `status`, `lastTime`) VALUES ('30', '23', '*', '*', '*', 'moduleName=execution&methodName=computecfd', '更新累积流图', 'zentao', 1, 'normal', '0000-00-00 00:00:00');
|
||||
|
||||
ALTER TABLE `zt_doc` CHANGE `assignedDate` `assignedDate` datetime NOT NULL AFTER `assignedTo`;
|
||||
|
||||
UPDATE `zt_approval` SET `createdDate` = '';
|
||||
ALTER TABLE `zt_approval` CHANGE `createdDate` `createdDate` datetime NOT NULL AFTER `createdBy`;
|
||||
|
||||
ALTER TABLE `zt_reviewissue` ADD `approval` MEDIUMINT NOT NULL AFTER `review`;
|
||||
|
||||
ALTER TABLE `zt_approvalnode` ADD INDEX `idx_reviewed_date` (`reviewedDate`);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
ALTER TABLE `zt_mr` CHANGE COLUMN `gitlabID` `hostID` mediumint(8) UNSIGNED NOT NULL AFTER `id`;
|
||||
ALTER TABLE `zt_mr` MODIFY COLUMN `sourceProject` varchar(50) NOT NULL AFTER `hostID`;
|
||||
ALTER TABLE `zt_mr` MODIFY COLUMN `targetProject` varchar(50) NOT NULL AFTER `sourceBranch`;
|
||||
UPDATE `zt_project` SET `status`='closed' WHERE `type` IN ('sprint', 'stage', 'kanban') AND `model`='' AND `status` = 'done';
|
||||
ALTER TABLE `zt_repo` ADD COLUMN `serviceHost` varchar(50) NOT NULL AFTER `client`;
|
||||
ALTER TABLE `zt_repo` ADD COLUMN `serviceProject` varchar(100) NOT NULL AFTER `serviceHost`;
|
||||
UPDATE `zt_repo` SET `serviceHost` = `client`, `serviceProject` = `path` WHERE `SCM` = 'Gitlab' AND `client` <> '' AND `path` <> '';
|
||||
UPDATE `zt_repo` SET `client` = '', `path` = '' WHERE `SCM` = 'Gitlab';
|
||||
|
||||
UPDATE `zt_workflowfield` SET `options`='user' WHERE `buildin`='1' AND `options`='8';
|
||||
INSERT IGNORE INTO `zt_workflowfield` (`module`, `field`, `type`, `length`, `name`, `control`, `expression`, `options`, `default`, `rules`, `placeholder`, `order`, `searchOrder`, `exportOrder`, `canExport`, `canSearch`, `isValue`, `readonly`, `buildin`, `desc`, `createdBy`, `createdDate`, `editedBy`, `editedDate`) VALUES
|
||||
('testtask', 'execution', 'mediumint', '8', '所属执行', 'select', '', '44', '0', '', '', 5, 0, 0, '0', '1', '0', '1', 1, '', '', '2022-03-18 09:16:38', '', '0000-00-00 00:00:00'),
|
||||
('testcase', 'execution', 'mediumint', '8', '所属执行', 'select', '', '44', '0', '', '', 4, 0, 0, '0', '1', '0', '1', 1, '', '', '2022-03-18 09:16:38', '', '0000-00-00 00:00:00'),
|
||||
('task', 'execution', 'mediumint', '8', '所属执行', 'select', '', '44', '0', '', '', 4, 0, 0, '0', '1', '0', '1', 1, '', '', '2022-03-18 09:16:38', '', '0000-00-00 00:00:00'),
|
||||
('bug', 'execution', 'mediumint', '8', '所属执行', 'select', '', '44', '0', '', '', 6, 0, 0, '0', '1', '0', '1', 1, '', '', '2022-03-18 09:16:38', '', '0000-00-00 00:00:00'),
|
||||
('build', 'execution', 'mediumint', '8', '所属执行', 'select', '', '44', '0', '', '', 5, 0, 0, '0', '1', '0', '1', 1, '', '', '2022-03-18 09:16:38', '', '0000-00-00 00:00:00');
|
||||
@@ -0,0 +1,24 @@
|
||||
ALTER TABLE `zt_story` ADD COLUMN `linkRequirements` varchar(255) NOT NULL AFTER `linkStories`;
|
||||
|
||||
ALTER TABLE `zt_searchindex` ADD FULLTEXT `title_content` (`title`, `content`);
|
||||
ALTER TABLE `zt_searchindex` DROP INDEX `title`;
|
||||
ALTER TABLE `zt_searchindex` DROP INDEX `content`;
|
||||
|
||||
ALTER TABLE `zt_productplan` ADD `createdBy` varchar(30) NOT NULL AFTER `closedReason`;
|
||||
ALTER TABLE `zt_productplan` ADD `createdDate` datetime NOT NULL AFTER `createdBy`;
|
||||
|
||||
ALTER TABLE `zt_release` ADD `createdBy` varchar(30) NOT NULL AFTER `subStatus`;
|
||||
ALTER TABLE `zt_release` ADD `createdDate` datetime NOT NULL AFTER `createdBy`;
|
||||
|
||||
ALTER TABLE `zt_testtask` ADD `createdBy` varchar(30) NOT NULL AFTER `subStatus`;
|
||||
ALTER TABLE `zt_testtask` ADD `createdDate` datetime NOT NULL AFTER `createdBy`;
|
||||
|
||||
INSERT IGNORE INTO `zt_workflowfield` (`module`, `field`, `type`, `length`, `name`, `control`, `expression`, `options`, `default`, `rules`, `placeholder`, `order`, `searchOrder`, `exportOrder`, `canExport`, `canSearch`, `isValue`, `readonly`, `buildin`, `role`, `desc`, `createdBy`, `createdDate`, `editedBy`, `editedDate`) VALUES
|
||||
('testtask', 'createdBy', 'varchar', '30', '由谁创建', 'select', '', 'user', '', '', '', 393, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'),
|
||||
('testtask', 'createdDate', 'datetime', '', '创建时间', 'datetime', '', '', '', '', '', 394, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'),
|
||||
('productplan', 'createdBy', 'varchar', '30', '由谁创建', 'select', '', 'user', '', '', '', 11, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'),
|
||||
('productplan', 'createdDate', 'datetime', '', '创建时间', 'datetime', '', '', '', '', '', 12, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'),
|
||||
('release', 'createdBy', 'varchar', '30', '由谁创建', 'select', '', 'user', '', '', '', 14, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'),
|
||||
('release', 'createdDate', 'datetime', '', '创建时间', 'datetime', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00');
|
||||
|
||||
UPDATE `zt_project` SET `closedDate`='' AND `closedBy`='' WHERE `status` != 'closed';
|
||||
+261
-227
File diff suppressed because it is too large
Load Diff
+211
@@ -1,3 +1,214 @@
|
||||
2022-07-27 17.4
|
||||
完成的需求
|
||||
开源版:
|
||||
25633 项目集可以按照状态进行检索
|
||||
30848 通用看板团队成员可以从系统通讯录中添加
|
||||
32326 地盘最新动态区块中过滤掉当前用户无权访问的动态
|
||||
32327 组织动态列表中过滤掉当前用户无权访问的动态
|
||||
32331 计划的需求列表打开需求后返回列表时,保持列表排序
|
||||
32679 添加待办页面增加指派给操作
|
||||
33311 Bug关联相关Bug后可以实现互相关联
|
||||
33316 软件需求详情的相关信息中增加相关版本信息
|
||||
33317 软件需求详情的相关信息中增加相关发布信息
|
||||
33594 地盘项目统计区块的排序规则和项目集列表保持一致
|
||||
34037 调整文档中富文本和Markdown类型文档的创建流程
|
||||
34136 详情页点击撤销评审后保留在该页面局部刷新
|
||||
34172 全局设置中增加是否启用代号的设置功能
|
||||
34282 调整文档全局创建流程第一步
|
||||
34285 调整文档全局创建流程第二步
|
||||
34292 文档编辑默认进入创建页面
|
||||
34486 开启或关闭代号功能后项目集的代号信息处理规则
|
||||
34487 开启或关闭代号功能后产品的代号信息处理规则
|
||||
34488 开启或关闭代号功能后项目的代号信息处理规则
|
||||
34489 开启或关闭代号功能后执行的代号信息处理规则
|
||||
34577 已删除的项目集、产品、项目、执行不参与是否同名和同代号的判断
|
||||
34732 专业研发看板项目二级导航中打印设置菜单
|
||||
34733 打印专业研发看板项目设置功能的三级导航菜单
|
||||
34734 实现专业研发看板项目的白名单页面及功能
|
||||
34735 实现专业研发看板项目的产品页面及功能
|
||||
34736 实现专业研发看板项目的团队页面及功能
|
||||
34737 专业研发看板二级导航中打印设置菜单
|
||||
34738 打印看板设置功能的三级导航菜单
|
||||
34739 实现专业研发看板的概况页面及功能
|
||||
34740 实现专业研发看板的产品页面及功能
|
||||
34741 实现专业研发看板的团队页面及功能
|
||||
34806 计划的Bug列表打开Bug后返回列表时,保持列表排序
|
||||
34888 权限成员维护页面支持长按鼠标拖动后批量勾选功能
|
||||
34923 在权限维护页面点击保存后继续保留在当前页面
|
||||
35191 任务提交页面中,测试任务类型的多选文案显示完整
|
||||
35205 实现专业研发看板的白名单页面及功能
|
||||
35305 搜索展开保存条件时,保存搜索条件按钮左移
|
||||
34618 调用API浏览Gitea合并请求列表
|
||||
34619 调用API浏览Gitea合并请求概述
|
||||
34620 调用API查看Gitea合并请求中的代码改动
|
||||
34633 Gitea合并请求可以关联禅道的需求、任务以及Bug
|
||||
34634 调用API创建Gitea合并请求
|
||||
34635 调用API删除Gitea合并请求
|
||||
34636 调用API实现Gitea合并请求的评审
|
||||
34637 Gitea合并请求合并后调用API删除源分支
|
||||
34638 调用API实现Gitea合并请求的合并
|
||||
35241 在合并请求列表显示创建时间
|
||||
35249 合并请求概况页面显示历史记录
|
||||
35251 实现Gitea代码库下的代码对比功能
|
||||
企业版:
|
||||
29884 执行任务导出数据的名称增加来源Bug的信息
|
||||
32192 组织菜单调整为团队、日程、日志、动态、公司
|
||||
33191 加班申请通过后,办公我的考勤列表中操作/状态列展示“已加班”
|
||||
33201 办公考勤的列表的标题字号修改为16px
|
||||
33219 办公公司考勤页面中列表表头固定
|
||||
33222 增加办公公司考勤表格的底部栏高度
|
||||
33242 反馈页的通知改为“接收邮件通知”
|
||||
33244 创建反馈时必填项校验在字段下方红字展示
|
||||
33248 办公请假页面展示逻辑优化
|
||||
33252 反馈功能的权限模块icon调整
|
||||
33254 反馈权限列表中用户数量超出列宽时用省略号示意
|
||||
33397 缩短办公节假日页面中左侧的时间目录宽度
|
||||
33421 运维服务列表页面字段过长时省略显示
|
||||
33423 运维账号页面列表为空时的快捷新建页面改为弹窗样式
|
||||
34683 增加反馈转研发需求页面中父需求的标题宽度
|
||||
34684 增大反馈转研发需求页面中反馈者的输入框宽度
|
||||
34721 组织日志页面置顶显示滚动条
|
||||
34730 固定组织日志页面日志详情的展示位置
|
||||
旗舰版:
|
||||
31845 修改项目风险列表中的挂起操作图标
|
||||
33122 修改问题列表的创建日期显示内容
|
||||
33305 项目问题列表页面优先级字段居中显示
|
||||
33511 修改资产问题库中问题列表中“优先级”为“P”
|
||||
33512 修改资产风险库列表页面“优先级”为“P”
|
||||
33514 修改资产机会库列表页面“优先级”为“P”
|
||||
33525 资产需求库需求列表页面审批字段居左显示
|
||||
33528 资产问题库问题列表页面审批字段居左显示
|
||||
33529 资产风险库风险列表页面审批字段居左显示
|
||||
33530 资产机会库机会列表页面审批字段居左显示
|
||||
33823 问题指派页面增加备注
|
||||
34097 修改执行QA不符合项详情页面中解决图标
|
||||
34729 QA质量保证计划可以批量编辑
|
||||
30071 项目甘特图中增加任务名称的显示
|
||||
28556 瀑布项目中计划的甘特图支持按日/周/月维度查看
|
||||
29700 项目甘特图中的任务支持点击查看详情
|
||||
29944 项目甘特图中支持显示阶段和任务的负责人
|
||||
34795 项目甘特图可以在阶段或任务前增加图标显示状态
|
||||
34742 项目甘特图中没有起止日期的任务的时间显示为所属阶段时间
|
||||
禅道客户端:
|
||||
34124 XXD可以从XXB主动拉取配置
|
||||
34123 喧喧增加禅道的checktable.php以便自动修复数据库
|
||||
34122 去掉XXD中无意义的错误日志
|
||||
33667 通知中心的信息通知逻辑优化
|
||||
33665 修改通知中心的样式
|
||||
33464 禅道客户端支持弹窗显示
|
||||
33216 禅道客户端重连后不用跳到地盘页面
|
||||
33213 喧喧webview中增加加载中的过渡页面
|
||||
33196 合并禅道客户端禅道上方导航栏和窗口控制栏
|
||||
33187 喧喧一键安装包采用新的控制面板
|
||||
33068 实现客户端修改个人信息的功能
|
||||
33066 将群的设为公开和白名单设置放入群设置弹窗
|
||||
33065 实现只有群主和管理员才能添加群成员的功能
|
||||
33063 实现禁用移动端的功能
|
||||
33062 实现群主被删除后自动转让的功能
|
||||
32013 输出roadrunner相关文档
|
||||
修复的Bug
|
||||
24009 內禅任务详情页面上一个下一个切换错误
|
||||
25389 升级时需要把项目负责人加到团队中
|
||||
25439 需求换了执行对应的用例无法关联测试单
|
||||
22844 项目中创建或者编辑会议页面关联迭代后会清除之前选择的参会人员
|
||||
23200 多人任务串行,可以操作出负的消耗工时
|
||||
24357 多人任务填写日志后把日志删除对应的消耗工时仍然存在
|
||||
25185 内置报表里,执行状态的下拉框里都没有已完成
|
||||
25603 修复新版一键安装包中XXD服务可能安装失败的问题。
|
||||
|
||||
2022-07-13 17.3
|
||||
完成的需求
|
||||
14130 点击按钮执行升级后禁用升级按钮
|
||||
14578 总计消耗不为0时再次点击完成任务后消耗工时可以填写为0
|
||||
15349 产品模块的维护增加历史记录
|
||||
26444 重新激活父任务时需要同步更新子任务的历史记录
|
||||
27723 年度总结按部门查看增加权限控制
|
||||
30114 实现禅道中累积流图的帮助功能
|
||||
30121 实现禅道执行视图下的需求累积流图
|
||||
30128 实现禅道执行视图下的任务累积流图
|
||||
30190 创建看板时增加复制看板功能
|
||||
31342 批量创建任务表单的右侧增加添加和删除行的操作
|
||||
31746 Scrum看板中任务看板按需求分组时需求以卡片方式展示
|
||||
31848 删除测试测试单列表中操作按钮中间的小竖线
|
||||
32329 跨应用跳转页面时直接展示跳转后的页面
|
||||
32584 瀑布项目阶段列表中阶段名称前增加展开、收起按钮
|
||||
32834 任务创建页面修改自定义表单后不影响已录入内容
|
||||
32994 时间设置错误提示删除日历自动展开效果
|
||||
33003 非所有标签的列表内容为空时,删除新建操作
|
||||
33085 需求提交页面修改自定义表单后不影响已录入内容
|
||||
33132 修改干系人新增页面中用户字段未定义提示
|
||||
33168 复制执行页面增加项目的选择菜单
|
||||
33170 BUG提交页面修改自定义表单后不影响已录入内容
|
||||
33171 用例提交页面修改自定义表单后不影响已录入内容
|
||||
33180 批量提需求表单的右侧增加添加和删除行的操作
|
||||
33181 批量提Bug表单的右侧增加添加和删除行的操作
|
||||
33182 批量建用例表单的右侧增加添加和删除行的操作
|
||||
33307 加大bug提交页面中操作系统输入框的宽度
|
||||
33308 加大bug提交页面中“关键词“字段标题框宽度
|
||||
33415 用例库中的用例可以多次导入到同一个产品的不同模块
|
||||
33418 瀑布项目阶段设置页面里程碑字段居中显示
|
||||
33419 瀑布项目阶段设置页面中操作字段居中显示
|
||||
33438 缩短组织下团队列表页面姓名跟用户名字段的间距
|
||||
33445 bug提交页面中刷新按钮改为图标显示
|
||||
33446 列表中日期没有定义时展示为空
|
||||
33448 缩小bug编辑页面中标题输入框宽度
|
||||
33516 后台全局设置中文档模板列表的的删除按钮改为垃圾桶样式
|
||||
33519 后台自定义页面修改提示语样式
|
||||
33540 优化搜索条件保存按钮样式
|
||||
33542 用例列表页面的执行时间格式调整
|
||||
33547 项目测试单列表的报告列表按钮修改
|
||||
33607 项目集列表中对展开和收起的状态做记录
|
||||
33617 瀑布项目阶段列表增加显示任务设置
|
||||
33673 我参与标签中能显示我负责和我在团队中的空间和看板
|
||||
33705 项目中测试的Bug列表增加产品模块功能
|
||||
33706 执行中测试的Bug列表增加产品模块功能
|
||||
33707 执行中测试的用例列表增加产品模块功能
|
||||
33775 详情页面中附件增加预览和下载按钮
|
||||
33777 研发需求变更页面增加附件编辑操作
|
||||
33782 地盘仪表盘待处理区块对齐调整
|
||||
33807 产品矩阵列表居左显示
|
||||
33879 阶段列表中展示任务列表
|
||||
33896 实现禅道执行视图下的Bug累积流图
|
||||
33939 后台通知设置页面中“评论”字段修改为“备注”
|
||||
33953 项目创建页面中,关联产品下拉框增加不可点击状态
|
||||
33970 测试仪表盘测试统计区块中统计字体颜色调整
|
||||
33972 增加国际版地盘任务列表页面截止日期字段的宽度
|
||||
33973 计划详情列表中返回路径优化
|
||||
33983 我的地盘日程中右侧任务和软需切换样式调整
|
||||
33986 产品发布创建页面里程碑选中状态修改
|
||||
33987 执行任务列表预计、消耗、剩余、进度字段居右显示
|
||||
33988 执行任务列表"截止"字段居左显示
|
||||
33999 统计产品页面删除“筛选条件"字段
|
||||
34028 后台二次开发API列表页面表头字段加粗
|
||||
34029 执行任务列表页面“完成者”字段内容过多时省略显示
|
||||
34036 专业研发看板项目的执行模块添加累积流图入口
|
||||
34038 累积流图中增加更新按钮
|
||||
34048 累积流图页增加下拉框支持切换类型
|
||||
34049 累积流图展示平均周期时间和吞吐率
|
||||
34050 累积流图中增加悬浮样式
|
||||
34138 scrum看板页面卡片局部刷新
|
||||
34139 通用看板页面卡片局部刷新
|
||||
34140 看板项目专业研发看板编辑区域后自动刷新
|
||||
34142 专业研发看板页面卡片局部刷新
|
||||
34266 修改产品计划详情页面提研发需求按钮的下拉菜单为右对齐
|
||||
34349 国际版地盘仪表盘添加区块弹窗中待办和待处理的英文修改
|
||||
34350 国际版中编辑和详情页面附件重命名的英文修改为Rename
|
||||
34354 修改产品研发需求提交页面中附件操作按钮颜色
|
||||
34367 累积流图增加隐藏周末按钮
|
||||
34387 需求提交页面产品分支输入框显示完整
|
||||
34497 邮箱修改密码优化格式校验提示语
|
||||
34580 任务详情编辑页面中,团队设置弹窗增加关闭按钮
|
||||
34609 修改产品分支合并的提示样式
|
||||
34610 当所有标签的列表内容均为空时,增加新建按钮
|
||||
34611 修改后台系统安全设置页面的提示语样式
|
||||
修复的Bug
|
||||
23123 项目/执行的Bug页左上角下拉组件未显示多分支产品的分支下拉
|
||||
23827 批量编辑项目时,提示文案不清晰
|
||||
24923 英文下项目集下新增干系人页面字段名称换行
|
||||
24976 内禅3.3版本需求列表需求名称显示3个点
|
||||
24981 隐藏来源没有同步隐藏其关联的文本框
|
||||
25070 后台-自定义-必填项-任务-建任务页面设置最初预计为必填项,创建多人任务团队成员预计工时为空也可以保存
|
||||
|
||||
2022-06-29 17.2
|
||||
完成的需求
|
||||
12709 创建某一类型的待办时,若无指派给我的内容列表提示用户
|
||||
|
||||
@@ -151,6 +151,10 @@
|
||||
<span class='attend-<?php echo $status;?>'>
|
||||
<?php extCommonModel::printLink('leave', 'create', "date=" . $date, $leave, "data-toggle='modal' data-width='700px'");?>
|
||||
</span>
|
||||
<?php elseif($status == 'overtime'):?>
|
||||
<span class='attend-<?php echo $status;?>'>
|
||||
<?php extCommonModel::printLink('overtime', 'create', "date=" . $date, $overtime, "data-toggle='modal' data-width='700px'");?>
|
||||
</span>
|
||||
<?php elseif($status == 'lieu'):?>
|
||||
<span class='attend-<?php echo $status;?>'>
|
||||
<?php extCommonModel::printLink('lieu', 'create', "date=" . $date, $lieu, "data-toggle='modal' data-width='700px'");?>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<?php
|
||||
include $app->getExtensionRoot() . '/biz/attend/ext/view/stat.oa.html.hook.php';
|
||||
?>
|
||||
@@ -1,3 +1,3 @@
|
||||
<script>
|
||||
$('#assigntomeBlock>ul>li>a:not([href$="todo"]):not([href$="task"])').parent().remove();
|
||||
$('#assigntomeBlock>ul>li>a:not([href$="todo"]):not([href$="task"]:not[href$="feedback"])').parent().remove();
|
||||
</script>
|
||||
|
||||
@@ -13,6 +13,14 @@ $lang->custom->object['todo'] = 'Todo';
|
||||
$lang->custom->object['user'] = 'User';
|
||||
$lang->custom->object['block'] = 'Block';
|
||||
|
||||
$lang->custom->menuOrder = array();
|
||||
$lang->custom->menuOrder[10] = 'execution';
|
||||
$lang->custom->menuOrder[15] = 'story';
|
||||
$lang->custom->menuOrder[20] = 'task';
|
||||
$lang->custom->menuOrder[25] = 'todo';
|
||||
$lang->custom->menuOrder[30] = 'user';
|
||||
$lang->custom->menuOrder[35] = 'block';
|
||||
|
||||
$lang->custom->task = new stdClass();
|
||||
$lang->custom->task->fields['priList'] = 'Priority';
|
||||
$lang->custom->task->fields['typeList'] = 'Type';
|
||||
|
||||
@@ -13,6 +13,14 @@ $lang->custom->object['todo'] = 'Todo';
|
||||
$lang->custom->object['user'] = 'User';
|
||||
$lang->custom->object['block'] = 'Block';
|
||||
|
||||
$lang->custom->menuOrder = array();
|
||||
$lang->custom->menuOrder[10] = 'execution';
|
||||
$lang->custom->menuOrder[15] = 'story';
|
||||
$lang->custom->menuOrder[20] = 'task';
|
||||
$lang->custom->menuOrder[25] = 'todo';
|
||||
$lang->custom->menuOrder[30] = 'user';
|
||||
$lang->custom->menuOrder[35] = 'block';
|
||||
|
||||
$lang->custom->task = new stdClass();
|
||||
$lang->custom->task->fields['priList'] = 'Priority';
|
||||
$lang->custom->task->fields['typeList'] = 'Type';
|
||||
|
||||
@@ -13,6 +13,14 @@ $lang->custom->object['todo'] = 'Todo';
|
||||
$lang->custom->object['user'] = 'User';
|
||||
$lang->custom->object['block'] = 'Block';
|
||||
|
||||
$lang->custom->menuOrder = array();
|
||||
$lang->custom->menuOrder[10] = 'execution';
|
||||
$lang->custom->menuOrder[15] = 'story';
|
||||
$lang->custom->menuOrder[20] = 'task';
|
||||
$lang->custom->menuOrder[25] = 'todo';
|
||||
$lang->custom->menuOrder[30] = 'user';
|
||||
$lang->custom->menuOrder[35] = 'block';
|
||||
|
||||
$lang->custom->task = new stdClass();
|
||||
$lang->custom->task->fields['priList'] = 'Priority';
|
||||
$lang->custom->task->fields['typeList'] = 'Type';
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<script>
|
||||
$("#createCaseActionMenu").parent('.btn-group').remove();
|
||||
$("#actionbox .histories-list li").each(function()
|
||||
{
|
||||
var text = $(this).find('a').text();
|
||||
$(this).find('a').parent().text(text);
|
||||
});
|
||||
</script>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/flow/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/flow/ext/view/' . basename(__FILE__);?>
|
||||
@@ -551,8 +551,8 @@ $lang->resource->task->recordEstimate = 'recordEstimateAction';
|
||||
$lang->resource->task->editEstimate = 'editEstimate';
|
||||
$lang->resource->task->deleteEstimate = 'deleteEstimate';
|
||||
$lang->resource->task->report = 'reportChart';
|
||||
$lang->resource->task->exportTemplet = 'exportTemplet';
|
||||
$lang->resource->task->import = 'import';
|
||||
if($config->edition != 'open') $lang->resource->task->exportTemplet = 'exportTemplet';
|
||||
if($config->edition != 'open') $lang->resource->task->import = 'import';
|
||||
|
||||
$lang->task->methodOrder[5] = 'create';
|
||||
$lang->task->methodOrder[10] = 'batchCreate';
|
||||
|
||||
@@ -12,10 +12,11 @@ public function __construct($appName = '')
|
||||
* @param int $browseType
|
||||
* @param int $groupBy
|
||||
* @param string $searchValue
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getKanban4Group($executionID, $browseType, $groupBy, $searchValue = '')
|
||||
public function getKanban4Group($executionID, $browseType, $groupBy, $searchValue = '', $orderBy = 'pri_asc')
|
||||
{
|
||||
/* Get card data. */
|
||||
$cardList = array();
|
||||
@@ -23,7 +24,8 @@ public function getKanban4Group($executionID, $browseType, $groupBy, $searchValu
|
||||
if($browseType == 'bug') $cardList = $this->loadModel('bug')->getExecutionBugs($executionID);
|
||||
if($browseType == 'task') $cardList = $this->loadModel('execution')->getKanbanTasks($executionID, "id");
|
||||
|
||||
$lanes = $this->getLanes4Group($executionID, $browseType, $groupBy, $cardList);
|
||||
if($groupBy == 'story' and $browseType == 'task' and !isset($this->lang->kanban->orderList[$orderBy])) $orderBy = 'pri_asc';
|
||||
$lanes = $this->getLanes4Group($executionID, $browseType, $groupBy, $cardList, $orderBy);
|
||||
if(empty($lanes)) return array();
|
||||
|
||||
$execution = $this->loadModel('execution')->getByID($executionID);
|
||||
@@ -70,6 +72,33 @@ public function getKanban4Group($executionID, $browseType, $groupBy, $searchValu
|
||||
$laneData['type'] = $browseType;
|
||||
$laneData['defaultCardType'] = $browseType;
|
||||
|
||||
if($browseType == 'task' and $groupBy == 'story')
|
||||
{
|
||||
$columnData[0]['id'] = 0;
|
||||
$columnData[0]['type'] = 'story';
|
||||
$columnData[0]['name'] = zget($this->lang->kanban->orderList, $orderBy, '');
|
||||
$columnData[0]['color'] = '#333';
|
||||
$columnData[0]['limit'] = '-1';
|
||||
$columnData[0]['laneType'] = $browseType;
|
||||
$columnData[0]['asParent'] = false;
|
||||
$columnData[0]['parentType'] = '';
|
||||
$columnData[0]['actions'] = array();
|
||||
|
||||
if(empty($searchValue) or strpos($lane->name, $searchValue) !== false)
|
||||
{
|
||||
$cardData = array();
|
||||
$cardData['id'] = $laneID;
|
||||
$cardData['title'] = $lane->name;
|
||||
$cardData['order'] = 1;
|
||||
$cardData['pri'] = $lane->pri;
|
||||
$cardData['estimate'] = '';
|
||||
$cardData['assignedTo'] = $lane->assignedTo;
|
||||
$cardData['deadline'] = '';
|
||||
$cardData['severity'] = '';
|
||||
$laneData['cards']['story'][] = $cardData;
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct kanban column data. */
|
||||
foreach($columns as $column)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@ body {margin-bottom: 25px;}
|
||||
#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text {color: #fff;}
|
||||
#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text:after {border-bottom: unset;}
|
||||
.body-modal #mainMenu>.btn-toolbar {width: auto;}
|
||||
.assignedTo{border-radius: 4px !important;}
|
||||
</style>
|
||||
<?php js::set('browseType', $browseType);?>
|
||||
<?php js::set('productID', $productID);?>
|
||||
@@ -171,11 +172,6 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
<strong>
|
||||
<?php echo $this->product->getByID($productID)->name ?>
|
||||
</strong>
|
||||
<div class="linkButton" onclick="handleLinkButtonClick()">
|
||||
<span title="<?php echo $lang->viewDetails;?>">
|
||||
<i class="icon icon-import icon-rotate-270"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div id="mainContent" class="main-row fade">
|
||||
@@ -411,7 +407,7 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
|
||||
<?php if($canBatchAssignTo):?>
|
||||
<div class="btn-group dropup">
|
||||
<button data-toggle="dropdown" type="button" class="btn"><?php echo $lang->story->assignedTo;?> <span class="caret"></span></button>
|
||||
<button data-toggle="dropdown" type="button" class="btn assignedTo"><?php echo $lang->story->assignedTo;?> <span class="caret"></span></button>
|
||||
<?php
|
||||
$withSearch = count($users) > 10;
|
||||
$actionLink = $this->createLink('story', 'batchAssignTo', "productID=$productID");
|
||||
@@ -587,11 +583,5 @@ function setBadgeStyle(obj, isShow)
|
||||
$label.find('.label-badge').css({"color":"#838a9d", "border-color":"#838a9d"});
|
||||
}
|
||||
}
|
||||
|
||||
function handleLinkButtonClick()
|
||||
{
|
||||
var xxcUrl = "xxc:openInApp/zentao-integrated/" + encodeURIComponent(window.location.href.replace(/.display=card/, '').replace(/\.xhtml/, '.html'));
|
||||
window.open(xxcUrl);
|
||||
}
|
||||
</script>
|
||||
<?php include $this->app->getModuleRoot() . '/common/view/footer.html.php';?>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<script>
|
||||
if(config.onlybody == 'yes') $('#storyList .c-title').width(110);
|
||||
</script>
|
||||
@@ -21,6 +21,9 @@ class project extends control
|
||||
if($this->execution->isClickable($kanban, 'delete')) $executionActions[$kanbanID][] = 'delete';
|
||||
}
|
||||
|
||||
$allExecution = $this->execution->getList($projectID, 'all', 'all');
|
||||
$this->view->allExecutionsNum = empty($allExecution);
|
||||
|
||||
$this->view->title = $this->lang->project->kanban;
|
||||
|
||||
$this->view->kanbanList = array_values($kanbanList);
|
||||
|
||||
@@ -40,10 +40,12 @@
|
||||
<th><?php echo $lang->project->name;?></th>
|
||||
<td class="col-main"><?php echo html::input('name', $name, "class='form-control' required");?></td>
|
||||
</tr>
|
||||
<?php if(!isset($config->setCode) or $config->setCode == 1):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->code;?></th>
|
||||
<td><?php echo html::input('code', '', "class='form-control' required");?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->PM;?></th>
|
||||
<td><?php echo html::select('PM', $pmUsers, '', "class='form-control chosen'" . (strpos($requiredFields, 'PM') !== false ? ' required' : ''));?></td>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->execution->noExecution;?></span>
|
||||
<?php if(common::hasPriv('execution', 'create')):?>
|
||||
<?php if(common::hasPriv('execution', 'create') and $allExecutionsNum):?>
|
||||
<?php echo html::a($this->createLink('execution', 'create', "projectID=$projectID"), "<i class='icon icon-plus'></i> " . $lang->project->createKanban, '', "class='btn btn-info' data-app='project'");?>
|
||||
<?php endif;?>
|
||||
</p>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<th class='c-spec<?php echo zget($visibleFields, 'spec', ' hidden') . zget($requiredFields, 'spec', '', ' required');?>'><?php echo $lang->story->spec;?></th>
|
||||
<th class='c-pri<?php echo zget($requiredFields, 'pri', '', ' required');?>'><?php echo $lang->story->pri;?></th>
|
||||
<th class='c-estimate<?php echo zget($requiredFields, 'estimate', '', ' required');?>'><?php echo $lang->story->estimate;?></th>
|
||||
<th style="width: 200px !important"><?php echo $lang->story->reviewedBy;?></th>
|
||||
<th class="<?php if($forceReview) echo ' required'?>" style="width: 200px !important"><?php echo $lang->story->reviewedBy;?></th>
|
||||
<th class='c-keywords<?php echo zget($requiredFields, 'keywords', '', ' required');?>'><?php echo $lang->story->keywords;?></th>
|
||||
<?php
|
||||
$extendFields = $this->story->getFlowExtendFields();
|
||||
|
||||
@@ -16,13 +16,6 @@
|
||||
<?php js::set('sysurl', common::getSysUrl());?>
|
||||
<?php if(strpos($_SERVER["QUERY_STRING"], 'isNotice=1') === false):?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<?php if($this->app->getViewType() == 'xhtml'):?>
|
||||
<div class="linkButton" onclick="handleLinkButtonClick()">
|
||||
<span title="<?php echo $lang->viewDetails;?>">
|
||||
<i class="icon icon-import icon-rotate-270"></i>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div class="btn-toolbar pull-left">
|
||||
<?php if(!isonlybody()):?>
|
||||
<?php echo html::a($browseLink, '<i class="icon icon-back icon-sm"></i> ' . $lang->goback, '', "class='btn btn-secondary'");?>
|
||||
@@ -344,11 +337,6 @@ js::set('cancel', $lang->cancel);
|
||||
js::set('rawModule', $this->app->rawModule);
|
||||
?>
|
||||
<script>
|
||||
function handleLinkButtonClick()
|
||||
{
|
||||
var xxcUrl = "xxc:openInApp/zentao-integrated/" + encodeURIComponent(window.location.href.replace(/.display=card/, '').replace(/\.xhtml/, '.html'));
|
||||
window.open(xxcUrl);
|
||||
}
|
||||
</script>
|
||||
<?php include $this->app->getModuleRoot() . 'common/view/syntaxhighlighter.html.php';?>
|
||||
<?php include $this->app->getModuleRoot() . 'common/view/footer.html.php';?>
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
<div class='input-group'>
|
||||
<?php echo html::select("story[%s]", $stories, $currentStory, "class='form-control chosen' onchange='setStoryRelated(\"%s\")'");?>
|
||||
<span class='input-group-btn'>
|
||||
<a id="preview%s" href='#' class='btn iframe btn-link btn-icon btn-copy' disabled='disabled' title='<?php echo $lang->preview; ?>'><i class='icon-search'></i></a>
|
||||
<a id="preview%s" href='#' class='btn iframe btn-link btn-icon btn-copy' disabled='disabled' title='<?php echo $lang->preview; ?>'><i class='icon-eye'></i></a>
|
||||
<a href='javascript:copyStoryTitle("%s")' class='btn btn-link btn-icon btn-copy' title='<?php echo $lang->task->copyStoryTitle; ?>'><i class='icon-arrow-right'></i></a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
<tr>
|
||||
<th><?php echo $lang->task->story;?></th>
|
||||
<td colspan='3'>
|
||||
<span id='storyBox' class="<?php if(!empty($stories)) echo 'hidden';?> "><?php printf($lang->task->noticeLinkStory, html::a($this->createLink('story', 'create', "productID=$productID&branch=0&moduleID=0&storyID=0&projectID=$projectID&bugID=0&planID=0&todoID=0&extra=&type=story"), $lang->execution->linkStory, '_blank', 'class="text-primary"'), html::a("javascript:loadStories($execution->id)", $lang->refresh, '', 'class="text-primary"'));?></span>
|
||||
<span id='storyBox' class="<?php if(!empty($stories)) echo 'hidden';?> "><?php printf($lang->task->noticeLinkStory, html::a($this->createLink('story', 'create', "productID=$productID&branch=0&moduleID=0&storyID=0&projectID=$projectID&bugID=0&planID=0&todoID=0&extra=&type=story&_single"), $lang->execution->linkStory, '_blank', 'class="text-primary"'), html::a("javascript:loadStories($execution->id)", $lang->refresh, '', 'class="text-primary"'));?></span>
|
||||
<div class='input-group <?php if(empty($stories)) echo "hidden";?>'>
|
||||
<?php echo html::select('story', $stories, $task->story, "class='form-control chosen' onchange='setStoryRelated();'");?>
|
||||
<span class='input-group-btn' id='preview'><a href='#' class='btn iframe'><?php echo $lang->preview;?></a></span>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
.hide-sidebar #sidebar > .cell {display: none;}
|
||||
.hide-sidebar #sidebar > .sidebar-toggle > .icon:before {content: "\e314";}
|
||||
#date {float: left; margin-right: 10px; margin-left: 0px;}
|
||||
.cell .nav>li>a:focus {background-color: unset;}
|
||||
</style>
|
||||
<?php js::set('moreLang', $this->lang->side->more);?>
|
||||
<?php js::set('moduleList', $config->todo->moduleList);?>
|
||||
|
||||
@@ -37,7 +37,7 @@ $('#toStoryLink').click(function()
|
||||
$('#toStoryButtonByProject').click(function()
|
||||
{
|
||||
var onlybody = config.onlybody == 'yes';
|
||||
var projectID = $('#projectToStory').val();
|
||||
var projectID = $('#projectToStory').val();
|
||||
var link = createLink('story', 'create', 'productID=0&branch=0&moduleID=0&storyID=0&projectID=' + projectID + '&bugID=0&planID=0&todoID=' + todoID, config.defaultView, onlybody);
|
||||
|
||||
if(!onlybody) window.parent.$.apps.open(link, 'project');
|
||||
@@ -75,4 +75,4 @@ function createProject()
|
||||
config.onlybody = onlybody;
|
||||
parent.location.href = link;
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflow/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflow/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1,4 +1,3 @@
|
||||
<script>
|
||||
$('#submit').after('<input type="hidden" name="vision" id="vision" value="<?php echo $this->config->vision;?>">');
|
||||
$('#ajaxForm #submit').after('<input type="hidden" name="vision" id="vision" value="<?php echo $this->config->vision;?>">');
|
||||
</script>
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflow/ext/view/' . basename(__FILE__);?>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<script>
|
||||
$('#submit').after('<input type="hidden" name="vision" id="vision" value="<?php echo $this->config->vision;?>">');
|
||||
$('#createForm #submit').after('<input type="hidden" name="vision" id="vision" value="<?php echo $this->config->vision;?>">');
|
||||
</script>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflow/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflow/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflow/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflow/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflow/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflow/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowaction/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1,4 +1,3 @@
|
||||
<script>
|
||||
$('#submit').after('<input type="hidden" name="vision" id="vision" value="lite">');
|
||||
</script>
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowaction/ext/view/' . basename(__FILE__);?>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowaction/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowaction/ext/view/' . basename(__FILE__);?>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
$this->config->workflowdatasource->excludeDatasource = 'litefeedbackStatus,litefeedbackModules,litefeedbackType,litefeedbackSolution,litefeedbackclosedReason';
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* Get datasource list.
|
||||
*
|
||||
* @param string $orderBy
|
||||
* @param objcet $pager
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getList($orderBy = 'id_desc', $pager = null)
|
||||
{
|
||||
return $this->dao->select('*')->from(TABLE_WORKFLOWDATASOURCE)
|
||||
->where(1)
|
||||
->beginIF(!empty($this->config->vision))->andWhere('vision')->eq($this->config->vision)->fi()
|
||||
->beginIF($this->config->visions == ',lite,')->andWhere('code')->notin($this->config->workflowdatasource->excludeDatasource)->fi()
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll();
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowdatasource/ext/view/' . basename(__FILE__);?>
|
||||
@@ -3,4 +3,3 @@ $('#submit').after('<input type="hidden" id="vision" name="vision" value="<?php
|
||||
$("#name").parent().addClass('required');
|
||||
$("#datasource").addClass('required');
|
||||
</script>
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowdatasource/ext/view/' . basename(__FILE__);?>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowdatasource/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowfield/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1,4 +1,3 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowfield/ext/view/' . basename(__FILE__);?>
|
||||
<?php if($config->visions == ',lite,'):?>
|
||||
<?php $feedbackDatasources = $this->dao->select('id')->from(TABLE_WORKFLOWDATASOURCE)->where('code')->like('litefeedback%')->andWhere('vision')->eq('lite')->fetchPairs('id', 'id');?>
|
||||
<?php if($feedbackDatasources):?>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowhook/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowhook/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowlabel/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowlayout/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowrelation/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowrule/ext/view/' . basename(__FILE__);?>
|
||||
@@ -1,4 +1,4 @@
|
||||
<script>
|
||||
$("#name").parent().addClass('required');
|
||||
$("#rule").parent().addClass('required');
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<?php include $this->app->getExtensionRoot() . 'biz/workflowrule/ext/view/' . basename(__FILE__);?>
|
||||
@@ -535,7 +535,7 @@ class baseEntry
|
||||
|
||||
/* Format array. */
|
||||
$value = array();
|
||||
if(is_array($object->$key))
|
||||
if(is_array($object->$key) or is_object($object->$key))
|
||||
{
|
||||
foreach($object->$key as $v) $value[] = $this->cast($v, $type);
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ class baseHelper
|
||||
$sign = strpos($link, '?') === false ? "?" : "&";
|
||||
$appendString = '';
|
||||
if($onlyBody or self::inOnlyBodyMode()) $appendString = $sign . "onlybody=yes";
|
||||
if(self::isWithTID()) $appendString .= empty($appendString) ? "{$sign}tid={$_GET['tid']}" : "&tid={$_GET['tid']}";
|
||||
if(self::isWithTID() and strpos($link, 'tid=') === false) $appendString .= empty($appendString) ? "{$sign}tid={$_GET['tid']}" : "&tid={$_GET['tid']}";
|
||||
return $link . $appendString;
|
||||
}
|
||||
|
||||
|
||||
@@ -658,6 +658,20 @@ class baseRouter
|
||||
$_POST = validater::filterSuper($_POST);
|
||||
$_GET = validater::filterSuper($_GET);
|
||||
$_COOKIE = validater::filterSuper($_COOKIE);
|
||||
|
||||
/* Filter common get and cookie vars. */
|
||||
if($this->config->framework->filterParam == 2)
|
||||
{
|
||||
global $filter;
|
||||
foreach($filter->default->get as $key => $rules)
|
||||
{
|
||||
if(isset($_GET[$key]) and !validater::checkByRule($_GET[$key], $rules)) unset($_GET[$key]);
|
||||
}
|
||||
foreach($filter->default->cookie as $key => $rules)
|
||||
{
|
||||
if(isset($_COOKIE[$key]) and !validater::checkByRule($_COOKIE[$key], $rules)) unset($_COOKIE[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -714,7 +728,7 @@ class baseRouter
|
||||
if(empty($account) and isset($_GET['account'])) $account = $_GET['account'];
|
||||
|
||||
$vision = '';
|
||||
if($this->config->installed)
|
||||
if($this->config->installed and validater::checkAccount($account))
|
||||
{
|
||||
$sql = new sql();
|
||||
$account = $sql->quote($account);
|
||||
@@ -982,14 +996,7 @@ class baseRouter
|
||||
if($writable)
|
||||
{
|
||||
$ztSessionHandler = new ztSessionHandler($_GET['tid']);
|
||||
session_set_save_handler(
|
||||
array($ztSessionHandler, "open"),
|
||||
array($ztSessionHandler, "close"),
|
||||
array($ztSessionHandler, "read"),
|
||||
array($ztSessionHandler, "write"),
|
||||
array($ztSessionHandler, "destroy"),
|
||||
array($ztSessionHandler, "gc")
|
||||
);
|
||||
session_set_save_handler($ztSessionHandler, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3093,7 +3100,7 @@ class EndResponseException extends \Exception
|
||||
*
|
||||
* @package framework
|
||||
*/
|
||||
class ztSessionHandler
|
||||
class ztSessionHandler implements SessionHandlerInterface
|
||||
{
|
||||
public $sessSavePath;
|
||||
public $tagID;
|
||||
@@ -3233,7 +3240,8 @@ class ztSessionHandler
|
||||
public function destroy($id)
|
||||
{
|
||||
$sessFile = $this->getSessionFile($id);
|
||||
@unlink($sessFile);
|
||||
unlink($sessFile);
|
||||
unlink($this->rawFile);
|
||||
touch($sessFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -312,6 +312,26 @@ class control extends baseControl
|
||||
chdir($currentPWD);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个方法的输出内容,这样我们可以在一个方法里获取其他模块方法的内容。
|
||||
* 如果模块名为空,则调用该模块、该方法;如果设置了模块名,调用指定模块指定方法。
|
||||
*
|
||||
* Get the output of one module's one method as a string, thus in one module's method, can fetch other module's content.
|
||||
* If the module name is empty, then use the current module and method. If set, use the user defined module and method.
|
||||
*
|
||||
* @param string $moduleName module name.
|
||||
* @param string $methodName method name.
|
||||
* @param array $params params.
|
||||
* @access public
|
||||
* @return string the parsed html.
|
||||
*/
|
||||
public function fetch($moduleName = '', $methodName = '', $params = array(), $appName = '')
|
||||
{
|
||||
if($moduleName != $this->moduleName) $this->app->fetchModule = $moduleName;
|
||||
|
||||
return parent::fetch($moduleName, $methodName, $params, $appName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build operate menu of a method.
|
||||
*
|
||||
|
||||
@@ -157,6 +157,21 @@ class model extends baseModel
|
||||
}
|
||||
if(empty($relations)) $relations = $this->dao->select('next, actions')->from(TABLE_WORKFLOWRELATION)->where('prev')->eq($moduleName)->fetchPairs();
|
||||
|
||||
$this->loadModel('flow');
|
||||
|
||||
$approvalProgressMenu = '';
|
||||
if($type == 'view' && !empty($this->config->openedApproval) && commonModel::hasPriv('approval', 'progress'))
|
||||
{
|
||||
$flow = $this->loadModel('workflow', 'flow')->getByModule($moduleName);
|
||||
if($flow->approval == 'enabled')
|
||||
{
|
||||
$approvalID = isset($data->approval) ? $data->approval : 0;
|
||||
$extraClass = strpos(',testsuite,build,release,productplan,', ",{$moduleName},") !== false ? 'btn-link' : '';
|
||||
$approvalProgressMenu .= "<div class='divider'></div>";
|
||||
$approvalProgressMenu .= baseHTML::a(helper::createLink('approval', 'progress', "approvalID={$approvalID}", '', true), $this->lang->flow->approvalProgress, "class='btn {$extraClass} iframe'");
|
||||
}
|
||||
}
|
||||
|
||||
$menu = '';
|
||||
if($show)
|
||||
{
|
||||
@@ -164,8 +179,10 @@ class model extends baseModel
|
||||
{
|
||||
if(strpos($action->position, $type) === false || $action->show != $show) continue;
|
||||
|
||||
$menu .= $this->loadModel('flow')->buildActionMenu($moduleName, $action, $data, $type, $relations);
|
||||
$menu .= $this->flow->buildActionMenu($moduleName, $action, $data, $type, $relations);
|
||||
}
|
||||
|
||||
if($approvalProgressMenu) $menu .= $approvalProgressMenu;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -174,10 +191,12 @@ class model extends baseModel
|
||||
{
|
||||
if(strpos($action->position, $type) === false) continue;
|
||||
|
||||
if($type == 'view' || $action->show == 'direct') $menu .= $this->loadModel('flow')->buildActionMenu($moduleName, $action, $data, $type, $relations);
|
||||
if($type == 'browse' && $action->show == 'dropdownlist') $dropdownMenu .= $this->loadModel('flow')->buildActionMenu($moduleName, $action, $data, $type, $relations);
|
||||
if($type == 'view' || $action->show == 'direct') $menu .= $this->flow->buildActionMenu($moduleName, $action, $data, $type, $relations);
|
||||
if($type == 'browse' && $action->show == 'dropdownlist') $dropdownMenu .= $this->flow->buildActionMenu($moduleName, $action, $data, $type, $relations);
|
||||
}
|
||||
|
||||
if($approvalProgressMenu) $menu .= $approvalProgressMenu;
|
||||
|
||||
if($type == 'browse' && $dropdownMenu)
|
||||
{
|
||||
$menu .= "<div class='dropdown'><a href='javascript:;' data-toggle='dropdown'>{$this->lang->more}<span class='caret'> </span></a>";
|
||||
|
||||
@@ -46,6 +46,15 @@ class router extends baseRouter
|
||||
*/
|
||||
public $isFlow = false;
|
||||
|
||||
/**
|
||||
* Fetch的模块名。
|
||||
* The fetched module name.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $fetchModule;
|
||||
|
||||
/**
|
||||
* Get the $moduleRoot var.
|
||||
*
|
||||
|
||||
@@ -501,8 +501,6 @@ class baseHTML
|
||||
$gobackList = isset($_COOKIE['goback']) ? json_decode($_COOKIE['goback'], true) : array();
|
||||
$gobackLink = isset($gobackList[$tab]) ? $gobackList[$tab] : '';
|
||||
|
||||
if(strpos($misc, 'data-app') === false) $misc .= " data-app='" . $tab . "'";
|
||||
|
||||
/* If the link of the referer is not the link of the current page or the link of the index, the cookie and gobackLink will be updated. */
|
||||
if(!preg_match("/(m=|\/)(index|search|$currentModule)(&f=|-)(index|buildquery|$currentMethod)(&|-|\.)?/", strtolower($refererLink)))
|
||||
{
|
||||
@@ -968,8 +966,9 @@ class baseJS
|
||||
{
|
||||
$cancleAction = "$cancleTarget.location = '$cancleURL';";
|
||||
}
|
||||
|
||||
$js .= <<<EOT
|
||||
if(strpos($_SERVER['HTTP_USER_AGENT'], 'xuanxuan') === false)
|
||||
{
|
||||
$js .= <<<EOT
|
||||
if(confirm("$message"))
|
||||
{
|
||||
$confirmAction
|
||||
@@ -979,6 +978,12 @@ else
|
||||
$cancleAction
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
else
|
||||
{
|
||||
$js .= $confirmAction;
|
||||
}
|
||||
|
||||
$js .= self::end();
|
||||
return $js;
|
||||
}
|
||||
@@ -1027,6 +1032,8 @@ EOT;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can not locate the url that has '#app', so remove it. */
|
||||
if(strpos($url, '#app=') !== false) $url = substr($url, 0, strpos($url, '#app='));
|
||||
$js .= "$target.location='$url';\n";
|
||||
}
|
||||
return $js . self::end();
|
||||
|
||||
@@ -280,16 +280,6 @@ class basePager
|
||||
if(strtolower($key) == 'recperpage') $this->params[$key] = $this->recPerPage;
|
||||
if(strtolower($key) == 'pageid') $this->params[$key] = $this->pageID;
|
||||
}
|
||||
|
||||
parse_str(strip_tags(urldecode($_SERVER['QUERY_STRING'])), $query);
|
||||
if(!empty($query['m']) && !empty($query['f']) && $query['m'] == $this->moduleName && $query['f'] == $this->methodName)
|
||||
{
|
||||
unset($query['m']);
|
||||
unset($query['f']);
|
||||
unset($query['t']);
|
||||
|
||||
$this->params = array_merge($this->params, $query);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,7 +48,7 @@ class dao extends baseDAO
|
||||
/* Check current module is buildin workflow. */
|
||||
if(isset($config->workflow->buildin->modules))
|
||||
{
|
||||
$currentModule = $app->rawModule;
|
||||
$currentModule = $app->fetchModule ? $app->fetchModule : $app->rawModule;
|
||||
foreach($config->workflow->buildin->modules as $appModules)
|
||||
{
|
||||
if(!empty($appModules->$currentModule))
|
||||
|
||||
@@ -51,7 +51,7 @@ class fixer extends baseFixer
|
||||
{
|
||||
global $app, $dbh;
|
||||
$flowFields = array();
|
||||
$moduleName = $app->rawModule;
|
||||
$moduleName = $app->fetchModule ? $app->fetchModule : $app->rawModule;
|
||||
$stmt = $dbh->query("SELECT * FROM " . TABLE_WORKFLOWFIELD . " WHERE `module` = '{$moduleName}' and `buildin` = '0'");
|
||||
while($flowField = $stmt->fetch()) $flowFields[$flowField->field] = $flowField;
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ class html extends baseHTML
|
||||
if(empty($target)) $target = '_self';
|
||||
if($target != '_self') $misc .= " target='$target'";
|
||||
if($target == '_blank') $misc .= " rel='noopener noreferrer'";
|
||||
if(strpos($misc, 'disabled')) $href = '#';
|
||||
return parent::a($href, $title, $misc, $newline);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,693 @@
|
||||
<?php
|
||||
class Gitea
|
||||
{
|
||||
public $client;
|
||||
public $root;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param string $client
|
||||
* @param string $root
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $encoding
|
||||
* @param object $repo
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($client, $root, $username, $password, $encoding = 'UTF-8', $repo = null)
|
||||
{
|
||||
putenv('LC_CTYPE=en_US.UTF-8');
|
||||
|
||||
$this->client = $client;
|
||||
$this->root = rtrim($root, DIRECTORY_SEPARATOR);
|
||||
if(!realpath($this->root) and !empty($repo))
|
||||
{
|
||||
global $app;
|
||||
$project = $app->control->loadModel('gitea')->apiGetSingleProject($repo->serviceHost, $repo->serviceProject);
|
||||
if(isset($project->tokenCloneUrl))
|
||||
{
|
||||
$cmd = 'git clone --progress -v "' . $project->tokenCloneUrl . '" "' . $this->root . '"';
|
||||
exec($cmd);
|
||||
}
|
||||
}
|
||||
|
||||
$branch = isset($_COOKIE['repoBranch']) ? $_COOKIE['repoBranch'] : '';
|
||||
if($branch)
|
||||
{
|
||||
$branches = $this->branch();
|
||||
if(isset($branches[$branch])) $branch = "origin/$branch";
|
||||
}
|
||||
$this->branch = $branch;
|
||||
|
||||
chdir($this->root);
|
||||
exec("{$this->client} config core.quotepath false");
|
||||
}
|
||||
|
||||
/**
|
||||
* List files.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $revision
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function ls($path, $revision = 'HEAD')
|
||||
{
|
||||
if(!scm::checkRevision($revision)) return array();
|
||||
|
||||
$path = ltrim($path, DIRECTORY_SEPARATOR);
|
||||
$sub = '';
|
||||
chdir($this->root);
|
||||
if(!empty($path)) $sub = ":$path";
|
||||
if(!empty($this->branch))$revision = $this->branch;
|
||||
execCmd(escapeCmd("$this->client pull"));
|
||||
$cmd = escapeCmd("$this->client ls-tree -l $revision$sub");
|
||||
$list = execCmd($cmd . ' 2>&1', 'array', $result);
|
||||
if($result) return array();
|
||||
|
||||
$infos = array();
|
||||
foreach($list as $entry)
|
||||
{
|
||||
list($mod, $kind, $revision, $size, $name) = preg_split('/[\t ]+/', $entry);
|
||||
|
||||
/* Get commit info. */
|
||||
$pathName = ltrim($path . DIRECTORY_SEPARATOR . $name, DIRECTORY_SEPARATOR);
|
||||
$cmd = escapeCmd("$this->client log -1 $this->branch -- $pathName");
|
||||
$commit = execCmd($cmd, 'array');
|
||||
$logs = $this->parseLog($commit);
|
||||
|
||||
if($size > 1024 * 1024)
|
||||
{
|
||||
$size = round($size / (1024 * 1024), 2) . 'MB';
|
||||
}
|
||||
else if($size > 1024)
|
||||
{
|
||||
$size = round($size / 1024, 2) . 'KB';
|
||||
}
|
||||
else
|
||||
{
|
||||
$size .= 'Bytes';
|
||||
}
|
||||
|
||||
$info = new stdClass();
|
||||
$info->name = $name;
|
||||
$info->kind = $kind == 'tree' ? 'dir' : 'file';
|
||||
$info->revision = $logs ? $logs[0]->revision : $revision;
|
||||
$info->size = $size;
|
||||
$info->account = $logs ? $logs[0]->committer : '';
|
||||
$info->date = $logs ? $logs[0]->time : '';
|
||||
$info->comment = $logs ? $logs[0]->comment : '';
|
||||
$infos[] = $info;
|
||||
unset($info);
|
||||
}
|
||||
|
||||
/* Sort by kind */
|
||||
foreach($infos as $key => $info) $kinds[$key] = $info->kind;
|
||||
if($infos) array_multisort($kinds, SORT_ASC, $infos);
|
||||
|
||||
return $infos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tags
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $revision
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function tags($path, $revision = 'HEAD')
|
||||
{
|
||||
if(!scm::checkRevision($revision)) return array();
|
||||
|
||||
chdir($this->root);
|
||||
$cmd = escapeCmd("$this->client tag --sort=taggerdate");
|
||||
$list = execCmd($cmd . ' 2>&1', 'array', $result);
|
||||
if($result) return array();
|
||||
|
||||
foreach($list as $key => $tag)
|
||||
{
|
||||
if(!$tag) unset($list[$key]);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get branch.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function branch()
|
||||
{
|
||||
chdir($this->root);
|
||||
|
||||
/* Get local branch. */
|
||||
$cmd = escapeCmd("$this->client branch -a");
|
||||
$list = execCmd($cmd . ' 2>&1', 'array', $result);
|
||||
if($result) return array();
|
||||
|
||||
/* Get default branch. */
|
||||
$defaultBranch = execCmd("$this->client symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'");
|
||||
$defaultBranch = trim($defaultBranch);
|
||||
|
||||
$branches = array();
|
||||
foreach($list as $localBranch)
|
||||
{
|
||||
$localBranch = trim($localBranch);
|
||||
if(substr($localBranch, 0, 19) == 'remotes/origin/HEAD') continue;
|
||||
if(substr($localBranch, 0, 1) == '*') $localBranch = substr($localBranch, 1);
|
||||
if(substr($localBranch, 0, 15) == 'remotes/origin/') $localBranch = substr($localBranch, 15);
|
||||
|
||||
$localBranch = trim($localBranch);
|
||||
if(empty($localBranch))continue;
|
||||
if($localBranch != $defaultBranch) $branches[$localBranch] = $localBranch;
|
||||
}
|
||||
|
||||
asort($branches);
|
||||
if($defaultBranch) $branches = array($defaultBranch => $defaultBranch) + $branches;
|
||||
|
||||
return $branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last log.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $count
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getLastLog($path, $count = 10)
|
||||
{
|
||||
$path = ltrim($path, DIRECTORY_SEPARATOR);
|
||||
$revision = $this->branch ? $this->branch : 'HEAD';
|
||||
|
||||
chdir($this->root);
|
||||
$list = execCmd(escapeCmd("$this->client log -10 $revision -- $path"), 'array');
|
||||
$logs = $this->parseLog($list);
|
||||
|
||||
return $logs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get logs
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $fromRevision
|
||||
* @param string $toRevision
|
||||
* @param int $count
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function log($path, $fromRevision = 0, $toRevision = 'HEAD', $count = 0)
|
||||
{
|
||||
if(!scm::checkRevision($fromRevision)) return array();
|
||||
if(!scm::checkRevision($toRevision)) return array();
|
||||
|
||||
$path = ltrim($path, DIRECTORY_SEPARATOR);
|
||||
$count = $count == 0 ? '' : "-n $count";
|
||||
/* compatible with svn. */
|
||||
if($fromRevision == 'HEAD' and $this->branch) $fromRevision = $this->branch;
|
||||
if($toRevision == 'HEAD' and $this->branch) $toRevision = $this->branch;
|
||||
if($fromRevision === $toRevision)
|
||||
{
|
||||
$logs = array();
|
||||
chdir($this->root);
|
||||
|
||||
$list = execCmd(escapeCmd("$this->client log --stat=1024 --name-status --stat-name-width=1000 -1 $fromRevision -- $path"), 'array');
|
||||
$logs = $this->parseLog($list);
|
||||
return $logs;
|
||||
}
|
||||
|
||||
if(!$fromRevision)
|
||||
{
|
||||
$revisions = " $toRevision";
|
||||
}
|
||||
else
|
||||
{
|
||||
$revisions = "$fromRevision..$toRevision";
|
||||
}
|
||||
chdir($this->root);
|
||||
$list = execCmd(escapeCmd("$this->client log --stat=1024 --name-status --stat-name-width=1000 $count $revisions -- $path"), 'array');
|
||||
$logs = $this->parseLog($list);
|
||||
|
||||
return $logs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blame file
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $revision
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function blame($path, $revision)
|
||||
{
|
||||
if(!scm::checkRevision($revision)) return array();
|
||||
|
||||
$path = ltrim($path, DIRECTORY_SEPARATOR);
|
||||
chdir($this->root);
|
||||
$list = execCmd(escapeCmd("$this->client blame -l $revision -- $path"), 'array');
|
||||
|
||||
$blames = array();
|
||||
$revLine = 0;
|
||||
$revision = '';
|
||||
foreach($list as $line)
|
||||
{
|
||||
if(empty($line)) continue;
|
||||
if($line[0] == '^') $line = substr($line, 1);
|
||||
preg_match('/^([0-9a-f]{39,40})\s.*\((\S+)\s+([\d-]+)\s(.*)\s(\d+)\)(.*)$/U', $line, $matches);
|
||||
|
||||
if(isset($matches[1]) and $matches[1] != $revision)
|
||||
{
|
||||
$blame = array();
|
||||
$blame['revision'] = $matches[1];
|
||||
$blame['committer'] = $matches[2];
|
||||
$blame['time'] = $matches[3];
|
||||
$blame['line'] = $matches[5];
|
||||
$blame['lines'] = 1;
|
||||
$blame['content'] = strpos($matches[6], ' ') === false ? $matches[6] : substr($matches[6], 1);
|
||||
|
||||
$revision = $matches[1];
|
||||
$revLine = $matches[5];
|
||||
$blames[$revLine] = $blame;
|
||||
}
|
||||
elseif(isset($matches[5]))
|
||||
{
|
||||
$blame = array();
|
||||
$blame['line'] = $matches[5];
|
||||
$blame['content'] = strpos($matches[6], ' ') === false ? $matches[6] : substr($matches[6], 1);
|
||||
|
||||
$blames[$matches[5]] = $blame;
|
||||
$blames[$revLine]['lines'] ++;
|
||||
}
|
||||
}
|
||||
return $blames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diff file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $fromRevision
|
||||
* @param string $toRevision
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function diff($path, $fromRevision, $toRevision, $extra = '')
|
||||
{
|
||||
if(!scm::checkRevision($fromRevision) and $extra != 'isBranchOrTag') return array();
|
||||
if(!scm::checkRevision($toRevision) and $extra != 'isBranchOrTag') return array();
|
||||
|
||||
$path = ltrim($path, DIRECTORY_SEPARATOR);
|
||||
chdir($this->root);
|
||||
if($toRevision == 'HEAD' and $this->branch) $toRevision = $this->branch;
|
||||
if($fromRevision == '^') $fromRevision = $toRevision . '^';
|
||||
if(strpos($fromRevision, '^') !== false)
|
||||
{
|
||||
$list = execCmd(escapeCmd("$this->client log -2 $toRevision --pretty=format:%H -- $path"), 'array');
|
||||
if(isset($list[1])) $fromRevision = $list[1];
|
||||
}
|
||||
$lines = execCmd(escapeCmd("$this->client diff $fromRevision $toRevision -- $path"), 'array');
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cat file.
|
||||
*
|
||||
* @param string $entry
|
||||
* @param string $revision
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function cat($entry, $revision = 'HEAD')
|
||||
{
|
||||
if(!scm::checkRevision($revision)) return false;
|
||||
|
||||
chdir($this->root);
|
||||
if($revision == 'HEAD' and $this->branch) $revision = $this->branch;
|
||||
$cmd = escapeCmd("$this->client show $revision:$entry");
|
||||
$content = execCmd($cmd);
|
||||
if(is_array($content)) $content = implode("\n", $content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get info.
|
||||
*
|
||||
* @param string $entry
|
||||
* @param string $revision
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function info($entry, $revision = 'HEAD')
|
||||
{
|
||||
if(!scm::checkRevision($revision)) return false;
|
||||
|
||||
chdir($this->root);
|
||||
if($revision == 'HEAD' and $this->branch) $revision = $this->branch;
|
||||
$path = ltrim($entry, DIRECTORY_SEPARATOR);
|
||||
$cmd = escapeCmd("$this->client ls-tree $revision -- $path");
|
||||
$result = execCmd($cmd);
|
||||
$kind = '';
|
||||
if($result)
|
||||
{
|
||||
$results = explode("\n", trim($result));
|
||||
if(count($results) >= 2)
|
||||
{
|
||||
$kind = 'dir';
|
||||
}
|
||||
else
|
||||
{
|
||||
list($mode, $type) = explode(' ', $results[0]);
|
||||
$kind = $type == 'tree' ? 'dir' : 'file';
|
||||
}
|
||||
}
|
||||
|
||||
$list = execCmd(escapeCmd("$this->client log -1 $revision --pretty=format:%H -- $path"), 'array');
|
||||
$revision = $list[0];
|
||||
$info = new stdclass();
|
||||
$info->kind = $kind;
|
||||
$info->path = $entry;
|
||||
$info->revision = $revision;
|
||||
$info->root = $this->root;
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exec git cmd.
|
||||
*
|
||||
* @param string $cmd
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function exec($cmd)
|
||||
{
|
||||
chdir($this->root);
|
||||
return execCmd(escapeCmd("$this->client $cmd"), 'array');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse diff.
|
||||
*
|
||||
* @param array $lines
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function parseDiff($lines)
|
||||
{
|
||||
if(empty($lines)) return array();
|
||||
$diffs = array();
|
||||
$num = count($lines);
|
||||
$endLine = end($lines);
|
||||
if(strpos($endLine, '\ No newline at end of file') === 0) $num -= 1;
|
||||
|
||||
$newFile = false;
|
||||
$allFiles = array();
|
||||
for($i = 0; $i < $num; $i ++)
|
||||
{
|
||||
$diffFile = new stdclass();
|
||||
if(strpos($lines[$i], "diff --git ") === 0)
|
||||
{
|
||||
$fileInfo = explode(' ',$lines[$i]);
|
||||
$fileName = substr($fileInfo[2], strpos($fileInfo[2], '/') + 1);
|
||||
|
||||
/* Prevent duplicate display of files. */
|
||||
if(in_array($fileName, $allFiles)) continue;
|
||||
$allFiles[] = $fileName;
|
||||
|
||||
$diffFile->fileName = $fileName;
|
||||
for($i++; $i < $num; $i ++)
|
||||
{
|
||||
$diff = new stdclass();
|
||||
/* Fix bug #1757. */
|
||||
if($lines[$i] == '+++ /dev/null') $newFile = true;
|
||||
if(strpos($lines[$i], '+++', 0) !== false) continue;
|
||||
if(strpos($lines[$i], '---', 0) !== false) continue;
|
||||
if(strpos($lines[$i], '======', 0) !== false) continue;
|
||||
if(preg_match('/^@@ -(\\d+)(,(\\d+))?\\s+\\+(\\d+)(,(\\d+))?\\s+@@/A', $lines[$i]))
|
||||
{
|
||||
$startLines = trim(str_replace(array('@', '+', '-'), '', $lines[$i]));
|
||||
list($oldStartLine, $newStartLine) = explode(' ', $startLines);
|
||||
list($diff->oldStartLine) = explode(',', $oldStartLine);
|
||||
list($diff->newStartLine) = explode(',', $newStartLine);
|
||||
$oldCurrentLine = $diff->oldStartLine;
|
||||
$newCurrentLine = $diff->newStartLine;
|
||||
if($newFile)
|
||||
{
|
||||
$oldCurrentLine = $diff->newStartLine;
|
||||
$newCurrentLine = $diff->oldStartLine;
|
||||
}
|
||||
$newLines = array();
|
||||
for($i++; $i < $num; $i ++)
|
||||
{
|
||||
if(preg_match('/^@@ -(\\d+)(,(\\d+))?\\s+\\+(\\d+)(,(\\d+))?\\s+@@/A', $lines[$i]))
|
||||
{
|
||||
$i --;
|
||||
break;
|
||||
}
|
||||
if(strpos($lines[$i], "diff --git ") === 0) break;
|
||||
|
||||
$line = $lines[$i];
|
||||
if(strpos($line, '\ No newline at end of file') === 0)continue;
|
||||
$sign = empty($line) ? '' : $line[0];
|
||||
if($sign == '-' and $newFile) $sign = '+';
|
||||
$type = $sign != '-' ? $sign == '+' ? 'new' : 'all' : 'old';
|
||||
if($sign == '-' || $sign == '+')
|
||||
{
|
||||
$line = substr_replace($line, ' ', 1, 0);
|
||||
if($newFile) $line = preg_replace('/^\-/', '+', $line);
|
||||
}
|
||||
|
||||
$newLine = new stdclass();
|
||||
$newLine->type = $type;
|
||||
$newLine->oldlc = $type != 'new' ? $oldCurrentLine : '';
|
||||
$newLine->newlc = $type != 'old' ? $newCurrentLine : '';
|
||||
$newLine->line = htmlSpecialString($line);
|
||||
|
||||
if($type != 'new') $oldCurrentLine++;
|
||||
if($type != 'old') $newCurrentLine++;
|
||||
|
||||
$newLines[] = $newLine;
|
||||
}
|
||||
|
||||
$diff->lines = $newLines;
|
||||
$diffFile->contents[] = $diff;
|
||||
}
|
||||
|
||||
if(isset($lines[$i]) and strpos($lines[$i], "diff --git ") === 0)
|
||||
{
|
||||
$i --;
|
||||
$newFile = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$diffs[] = $diffFile;
|
||||
}
|
||||
}
|
||||
return $diffs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get commit count.
|
||||
*
|
||||
* @param int $commits
|
||||
* @param string $lastVersion
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getCommitCount($commits = 0, $lastVersion = '')
|
||||
{
|
||||
if(!scm::checkRevision($lastVersion)) return false;
|
||||
|
||||
chdir($this->root);
|
||||
$revision = $this->branch ? $this->branch : 'HEAD';
|
||||
return execCmd(escapeCmd("$this->client rev-list --count $revision -- ./"), 'string');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get first revision.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getFirstRevision()
|
||||
{
|
||||
chdir($this->root);
|
||||
$list = execCmd(escapeCmd("$this->client rev-list --reverse HEAD -- ./"), 'array');
|
||||
return $list[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get latest revision
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getLatestRevision()
|
||||
{
|
||||
chdir($this->root);
|
||||
$revision = $this->branch ? $this->branch : 'HEAD';
|
||||
$list = execCmd(escapeCmd("$this->client rev-list -1 $revision -- ./"), 'array');
|
||||
return $list[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get commits.
|
||||
*
|
||||
* @param string $rversion
|
||||
* @param int $count
|
||||
* @param string $branch
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getCommits($revision = '', $count = 0, $branch = '')
|
||||
{
|
||||
if(!scm::checkRevision($revision)) return array();
|
||||
|
||||
if($revision == 'HEAD' and $branch) $revision = $branch;
|
||||
$revision = is_numeric($revision) ? "--skip=$revision $branch" : $revision;
|
||||
$count = $count == 0 ? '' : "-n $count";
|
||||
|
||||
chdir($this->root);
|
||||
if($branch)
|
||||
{
|
||||
execCmd(escapeCmd("$this->client checkout $branch"));
|
||||
execCmd(escapeCmd("$this->client pull"));
|
||||
}
|
||||
|
||||
$list = execCmd(escapeCmd("$this->client log $count $revision -- ./"), 'array');
|
||||
$commits = $this->parseLog($list);
|
||||
|
||||
$logs = array();
|
||||
foreach($commits as $commit)
|
||||
{
|
||||
$hash = $commit->revision;
|
||||
$log = new stdClass();
|
||||
$log->committer = $commit->committer;
|
||||
$log->revision = $commit->revision;
|
||||
$log->comment = $commit->comment;
|
||||
$log->time = $commit->time;
|
||||
$logs['commits'][$hash] = $log;
|
||||
$logs['files'][$hash] = array();
|
||||
}
|
||||
if(empty($logs)) return $logs;
|
||||
|
||||
$hash = '';
|
||||
$files = execCmd(escapeCmd("$this->client whatchanged $count $revision --pretty=format:%an@_@%cd@_@%H@_@%s -- ./"), 'array');
|
||||
foreach($files as $commit)
|
||||
{
|
||||
$commit = trim($commit);
|
||||
if(empty($commit)) continue;
|
||||
$parsedCommit = explode('@_@', $commit);
|
||||
if(count($parsedCommit) == 4)
|
||||
{
|
||||
list($account, $date, $hash, $comment) = $parsedCommit;
|
||||
}
|
||||
else
|
||||
{
|
||||
$file = explode(' ', $commit);
|
||||
$file = explode("\t", end($file));
|
||||
if(!isset($file[1])) $file[1] = '';
|
||||
list($action, $path) = $file;
|
||||
|
||||
$parsedFile = new stdclass();
|
||||
$parsedFile->revision = $hash;
|
||||
$parsedFile->path = '/' . trim($path);
|
||||
$parsedFile->type = 'file';
|
||||
$parsedFile->action = $action;
|
||||
$logs['files'][$hash][] = $parsedFile;
|
||||
}
|
||||
}
|
||||
return $logs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get clone url.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getCloneUrl()
|
||||
{
|
||||
$url = new stdclass();
|
||||
$remote = execCmd(escapeCmd("$this->client remote -v"), 'array');
|
||||
$pregHttp = '/http(s)?:\/\/(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+)*\.git/';
|
||||
$pregSSH = '/ssh:\/\/git@[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+)*\.git/';
|
||||
|
||||
if(preg_match($pregHttp, $remote[0], $matches)) $url->http = $matches[0];
|
||||
if(preg_match($pregSSH, $remote[0], $matches)) $url->ssh = $matches[0];
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse log.
|
||||
*
|
||||
* @param array $logs
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function parseLog($logs)
|
||||
{
|
||||
$parsedLogs = array();
|
||||
$i = 0;
|
||||
foreach($logs as $line)
|
||||
{
|
||||
if(strpos($line, 'commit ') === 0)
|
||||
{
|
||||
if(isset($log))
|
||||
{
|
||||
$log->comment = trim($comment);
|
||||
$log->change = $changes;
|
||||
$parsedLogs[$i] = $log;
|
||||
$i++;
|
||||
}
|
||||
|
||||
$log = new stdclass();
|
||||
$comment = '';
|
||||
$changes = array();
|
||||
|
||||
$log->revision = trim(preg_replace('/^commit/', '', $line));
|
||||
}
|
||||
elseif(strpos($line, 'Author:') === 0)
|
||||
{
|
||||
$account = preg_replace('/^Author:/', '', $line);
|
||||
$log->committer = trim(preg_replace('/<[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-\.]+>/', '', $account));
|
||||
}
|
||||
elseif(strpos($line, 'Date:') === 0)
|
||||
{
|
||||
$date = trim(preg_replace('/^Date:/', '', $line));
|
||||
$log->time = date('Y-m-d H:i:s', strtotime($date));
|
||||
}
|
||||
elseif(preg_match('/^\s{2,}/', $line))
|
||||
{
|
||||
$comment .= $line;
|
||||
}
|
||||
elseif(strpos($line, "\t") !== false)
|
||||
{
|
||||
list($action, $entry) = explode("\t", $line);
|
||||
$entry = '/' . trim($entry);
|
||||
$pathInfo = array();
|
||||
$pathInfo['action'] = $action;
|
||||
$pathInfo['kind'] = 'file';
|
||||
$changes[$entry] = $pathInfo;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($log))
|
||||
{
|
||||
$log->comment = trim($comment);
|
||||
$log->change = $changes;
|
||||
$parsedLogs[$i] = $log;
|
||||
}
|
||||
|
||||
return $parsedLogs;
|
||||
}
|
||||
}
|
||||
@@ -7,15 +7,16 @@ class gitlab
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param string $client gitlab api url.
|
||||
* @param string $root id of gitlab project.
|
||||
* @param string $username null
|
||||
* @param string $password token of gitlab api.
|
||||
* @param string $encoding
|
||||
* @param string $client gitlab api url.
|
||||
* @param string $root id of gitlab project.
|
||||
* @param string $username null
|
||||
* @param string $password token of gitlab api.
|
||||
* @param string $encoding
|
||||
* @param object $repo
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($client, $root, $username, $password, $encoding = 'UTF-8')
|
||||
public function __construct($client, $root, $username, $password, $encoding = 'UTF-8', $repo = null)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->root = rtrim($root, '/') . '/';
|
||||
@@ -834,4 +835,21 @@ class gitlab
|
||||
|
||||
return $parsedLogs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get download url.
|
||||
*
|
||||
* @param string $branch
|
||||
* @param string $ext
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getDownloadUrl($branch = 'master', $ext = 'zip')
|
||||
{
|
||||
$params = (array) $params;
|
||||
$params['private_token'] = $this->token;
|
||||
$params['sha'] = $branch;
|
||||
|
||||
return "{$this->root}archive.{$ext}" . '?' . http_build_query($params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,16 +12,24 @@ class GitRepo
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $encoding
|
||||
* @param object $repo
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($client, $root, $username, $password, $encoding = 'UTF-8')
|
||||
public function __construct($client, $root, $username, $password, $encoding = 'UTF-8', $repo = null)
|
||||
{
|
||||
putenv('LC_CTYPE=en_US.UTF-8');
|
||||
|
||||
$this->client = $client;
|
||||
$this->root = rtrim($root, DIRECTORY_SEPARATOR);
|
||||
$this->branch = isset($_COOKIE['repoBranch']) ? $_COOKIE['repoBranch'] : '';
|
||||
|
||||
$branch = isset($_COOKIE['repoBranch']) ? $_COOKIE['repoBranch'] : '';
|
||||
if($branch)
|
||||
{
|
||||
$branches = $this->branch();
|
||||
if(isset($branches[$branch])) $branch = "origin/$branch";
|
||||
}
|
||||
$this->branch = $branch;
|
||||
|
||||
chdir($this->root);
|
||||
exec("{$this->client} config core.quotepath false");
|
||||
@@ -107,11 +115,17 @@ class GitRepo
|
||||
$cmd = escapeCmd("$this->client tag --sort=taggerdate");
|
||||
$list = execCmd($cmd . ' 2>&1', 'array', $result);
|
||||
if($result) return array();
|
||||
|
||||
foreach($list as $key => $tag)
|
||||
{
|
||||
if(!$tag) unset($list[$key]);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get branch
|
||||
* Get branch.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
@@ -121,17 +135,21 @@ class GitRepo
|
||||
chdir($this->root);
|
||||
|
||||
/* Get local branch. */
|
||||
$cmd = escapeCmd("$this->client branch");
|
||||
$cmd = escapeCmd("$this->client branch -a");
|
||||
$list = execCmd($cmd . ' 2>&1', 'array', $result);
|
||||
if($result) return array();
|
||||
|
||||
/* Get default branch. */
|
||||
$defaultBranch = execCmd("$this->client symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'");
|
||||
$defaultBranch = trim($defaultBranch);
|
||||
|
||||
$branches = array();
|
||||
foreach($list as $localBranch)
|
||||
{
|
||||
$localBranch = trim($localBranch);
|
||||
if(substr($localBranch, 0, 19) == 'remotes/origin/HEAD') continue;
|
||||
if(substr($localBranch, 0, 1) == '*') $localBranch = substr($localBranch, 1);
|
||||
if(substr($localBranch, 0, 15) == 'remotes/origin/') $localBranch = substr($localBranch, 15);
|
||||
|
||||
$localBranch = trim($localBranch);
|
||||
if(empty($localBranch))continue;
|
||||
@@ -139,7 +157,7 @@ class GitRepo
|
||||
}
|
||||
|
||||
asort($branches);
|
||||
$branches = array($defaultBranch => $defaultBranch) + $branches;
|
||||
if($defaultBranch) $branches = array($defaultBranch => $defaultBranch) + $branches;
|
||||
|
||||
return $branches;
|
||||
}
|
||||
@@ -527,6 +545,8 @@ class GitRepo
|
||||
$count = $count == 0 ? '' : "-n $count";
|
||||
|
||||
chdir($this->root);
|
||||
if($branch) execCmd(escapeCmd("$this->client checkout $branch"), 'array');
|
||||
|
||||
$list = execCmd(escapeCmd("$this->client log $count $revision -- ./"), 'array');
|
||||
$commits = $this->parseLog($list);
|
||||
|
||||
@@ -573,6 +593,25 @@ class GitRepo
|
||||
return $logs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get clone url.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getCloneUrl()
|
||||
{
|
||||
$url = new stdclass();
|
||||
$remote = execCmd(escapeCmd("$this->client remote -v"), 'array');
|
||||
$pregHttp = '/http(s)?:\/\/(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+)*\.git/';
|
||||
$pregSSH = '/ssh:\/\/git@[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+)*\.git/';
|
||||
|
||||
if(preg_match($pregHttp, $remote[0], $matches)) $url->http = $matches[0];
|
||||
if(preg_match($pregSSH, $remote[0], $matches)) $url->ssh = $matches[0];
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse log.
|
||||
*
|
||||
|
||||
+25
-1
@@ -15,7 +15,7 @@ class scm
|
||||
$className = $repo->SCM;
|
||||
if($className == 'Git') $className = 'GitRepo';
|
||||
if(!class_exists($className)) require(strtolower($className) . '.class.php');
|
||||
$this->engine = new $className($repo->client, $repo->path, $repo->account, $repo->password, $repo->encoding);
|
||||
$this->engine = new $className($repo->client, $repo->path, $repo->account, $repo->password, $repo->encoding, $repo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,6 +220,17 @@ class scm
|
||||
return $this->engine->getCommits($version, $count, $branch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get clone url.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getCloneUrl()
|
||||
{
|
||||
return $this->engine->getCloneUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check revision
|
||||
*
|
||||
@@ -233,6 +244,19 @@ class scm
|
||||
if(preg_match('/[^a-z0-9\-_\.\^\w][\x{4e00}-\x{9fa5}]/ui', $revision)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get download url.
|
||||
*
|
||||
* @param string $branch
|
||||
* @param string $ext
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getDownloadUrl($branch = '', $ext = 'zip')
|
||||
{
|
||||
return $this->engine->getDownloadUrl($branch, $ext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,17 +11,18 @@ class Subversion
|
||||
public $svnVersion;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param string $client
|
||||
* @param string $root
|
||||
* @param string $account
|
||||
* @param string $password
|
||||
* @param string $encoding
|
||||
* Construct
|
||||
*
|
||||
* @param string $client
|
||||
* @param string $root
|
||||
* @param string $account
|
||||
* @param string $password
|
||||
* @param string $encoding
|
||||
* @param object $repo
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($client, $root, $account, $password, $encoding = 'UTF-8')
|
||||
public function __construct($client, $root, $account, $password, $encoding = 'UTF-8', $repo = null)
|
||||
{
|
||||
putenv('LC_CTYPE=en_US.UTF-8');
|
||||
$this->root = str_replace(array('%3A', '%2F', '+'), array(':', '/', ' '), urlencode(rtrim($root, '/')));
|
||||
@@ -37,10 +38,10 @@ class Subversion
|
||||
}
|
||||
|
||||
/**
|
||||
* List files.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $revision
|
||||
* List files.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $revision
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -91,10 +92,10 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Get tags.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $revision
|
||||
* @param bool $onlyDir
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $revision
|
||||
* @param bool $onlyDir
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -129,7 +130,7 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Get branch.
|
||||
*
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -140,9 +141,9 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Get last log.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $count
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $count
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -170,8 +171,8 @@ class Subversion
|
||||
foreach($parsedComments->logentry as $entry)
|
||||
{
|
||||
$log = new stdclass();
|
||||
$log->committer = (string)$entry->author;
|
||||
$log->revision = (int)$entry['revision'];
|
||||
$log->committer = (string)$entry->author;
|
||||
$log->revision = (int)$entry['revision'];
|
||||
$log->comment = trim((string)$entry->msg);
|
||||
$log->time = date('Y-m-d H:i:s', strtotime($entry->date));
|
||||
$log->change = array();
|
||||
@@ -188,12 +189,12 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Get log.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $fromRevision
|
||||
* @param string $toRevision
|
||||
* @param int $count
|
||||
* @param bool $quiet
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $fromRevision
|
||||
* @param string $toRevision
|
||||
* @param int $count
|
||||
* @param bool $quiet
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -229,17 +230,17 @@ class Subversion
|
||||
foreach($parsedComments->logentry as $entry)
|
||||
{
|
||||
$log = new stdclass();
|
||||
$log->committer = (string)$entry->author;
|
||||
$log->revision = (int)$entry['revision'];
|
||||
$log->committer = (string)$entry->author;
|
||||
$log->revision = (int)$entry['revision'];
|
||||
$log->comment = trim((string)$entry->msg);
|
||||
$log->time = date('Y-m-d H:i:s', strtotime($entry->date));
|
||||
$log->change = array();
|
||||
if(!empty($entry->paths))
|
||||
{
|
||||
foreach($entry->paths->path as $path)
|
||||
foreach($entry->paths->path as $path)
|
||||
{
|
||||
$pathInfo = array();
|
||||
foreach($path->attributes() as $attr => $value) $pathInfo[$attr] = (string)$value;
|
||||
foreach($path->attributes() as $attr => $value) $pathInfo[$attr] = (string)$value;
|
||||
$log->change[(string)$path] = $pathInfo;
|
||||
}
|
||||
}
|
||||
@@ -257,9 +258,9 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Blame file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $revision
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $revision
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -298,7 +299,7 @@ class Subversion
|
||||
{
|
||||
foreach($parsedResult->target->entry as $line)
|
||||
{
|
||||
if($line->commit['revision'] != $revision)
|
||||
if($line->commit['revision'] != $revision)
|
||||
{
|
||||
$blame = array();
|
||||
$blame['revision'] = (int)$line->commit['revision'];
|
||||
@@ -327,10 +328,10 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Diff file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $fromRevision
|
||||
* @param int $toRevision
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $fromRevision
|
||||
* @param int $toRevision
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -355,9 +356,9 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Cat file.
|
||||
*
|
||||
* @param string $entry
|
||||
* @param string $revision
|
||||
*
|
||||
* @param string $entry
|
||||
* @param string $revision
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
@@ -380,9 +381,9 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Get info.
|
||||
*
|
||||
* @param string $entry
|
||||
* @param string $revision
|
||||
*
|
||||
* @param string $entry
|
||||
* @param string $revision
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
@@ -421,8 +422,8 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Exec svn cmd.
|
||||
*
|
||||
* @param string $cmd
|
||||
*
|
||||
* @param string $cmd
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -434,8 +435,8 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Parse diff.
|
||||
*
|
||||
* @param array $lines
|
||||
*
|
||||
* @param array $lines
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -514,9 +515,9 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Get commit count.
|
||||
*
|
||||
* @param int $commits
|
||||
* @param int $lastVersion
|
||||
*
|
||||
* @param int $commits
|
||||
* @param int $lastVersion
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
@@ -547,7 +548,7 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Get first revision.
|
||||
*
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
@@ -561,7 +562,7 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Get latest revision.
|
||||
*
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
@@ -573,9 +574,9 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Get commits.
|
||||
*
|
||||
* @param string $version
|
||||
* @param int $count
|
||||
*
|
||||
* @param string $version
|
||||
* @param int $count
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -608,8 +609,8 @@ class Subversion
|
||||
foreach($parsedComments->logentry as $entry)
|
||||
{
|
||||
$parsedLog = new stdClass();
|
||||
$parsedLog->committer = (string)$entry->author;
|
||||
$parsedLog->revision = (int)$entry['revision'];
|
||||
$parsedLog->committer = (string)$entry->author;
|
||||
$parsedLog->revision = (int)$entry['revision'];
|
||||
$parsedLog->comment = trim((string)$entry->msg);
|
||||
$parsedLog->time = date('Y-m-d H:i:s', strtotime($entry->date));
|
||||
$logs['commits'][$parsedLog->revision] = $parsedLog;
|
||||
@@ -632,8 +633,8 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Replace svn auth.
|
||||
*
|
||||
* @param string $cmd
|
||||
*
|
||||
* @param string $cmd
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
@@ -643,11 +644,11 @@ class Subversion
|
||||
}
|
||||
|
||||
/**
|
||||
* Build command.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $action
|
||||
* @param string $param
|
||||
* Build command.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $action
|
||||
* @param string $param
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
@@ -668,8 +669,8 @@ class Subversion
|
||||
|
||||
/**
|
||||
* Get SVN version.
|
||||
*
|
||||
* @param string $client
|
||||
*
|
||||
* @param string $client
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
|
||||
@@ -43,8 +43,10 @@ $config->action->objectNameFields['kanban'] = 'name';
|
||||
$config->action->objectNameFields['kanbancard'] = 'name';
|
||||
$config->action->objectNameFields['sonarqube'] = 'name';
|
||||
$config->action->objectNameFields['gitlab'] = 'name';
|
||||
$config->action->objectNameFields['gitea'] = 'name';
|
||||
$config->action->objectNameFields['stage'] = 'name';
|
||||
$config->action->objectNameFields['apistruct'] = 'name';
|
||||
$config->action->objectNameFields['repo'] = 'name';
|
||||
|
||||
$config->action->commonImgSize = 870;
|
||||
|
||||
@@ -59,8 +61,8 @@ $config->action->majorList['project'] = array('opened', 'edited');
|
||||
$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,testcase,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,kanbanlane,kanbancolumn,';
|
||||
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,sonarqube,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,execution,project,traincategory,apistruct,program,product,user,entry,';
|
||||
$config->action->needGetRelateField = ',story,productplan,release,task,build,bug,testcase,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,kanbanlane,kanbancolumn,module,';
|
||||
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,gitea,sonarqube,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,execution,project,traincategory,apistruct,program,product,user,entry,repo,';
|
||||
|
||||
$config->action->preferredTypeNum = 10;
|
||||
|
||||
|
||||
@@ -138,18 +138,92 @@ class action extends control
|
||||
* Undelete an object.
|
||||
*
|
||||
* @param int $actionID
|
||||
* @param string $browseType
|
||||
* @param string $confirmChange
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function undelete($actionID)
|
||||
public function undelete($actionID, $browseType = 'all', $confirmChange = 'no')
|
||||
{
|
||||
$oldAction = $this->action->getById($actionID);
|
||||
$extra = $oldAction->extra == ACTIONMODEL::BE_HIDDEN ? 'hidden' : 'all';
|
||||
|
||||
if(in_array($oldAction->objectType, array('program', 'project', 'execution', 'product')))
|
||||
{
|
||||
if($oldAction->objectType == 'product')
|
||||
{
|
||||
$product = $this->dao->select('*')->from(TABLE_PRODUCT)->where('id')->eq($oldAction->objectID)->fetch();
|
||||
$programID = isset($product->program) ? $product->program : 0;
|
||||
$repeatObject = $this->dao->select('*')->from(TABLE_PRODUCT)
|
||||
->where('id')->ne($oldAction->objectID)
|
||||
->andWhere("(name = '{$product->name}' and program = {$programID})", true)
|
||||
->beginIF($product->code)->orWhere("code = '{$product->code}'")->fi()
|
||||
->markRight(1)
|
||||
->andWhere('deleted')->eq('0')
|
||||
->fetch();
|
||||
}
|
||||
else
|
||||
{
|
||||
$project = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($oldAction->objectID)->fetch();
|
||||
$sprintProject = isset($project->project) ? $project->project : '0';
|
||||
$repeatObject = $this->dao->select('*')->from(TABLE_PROJECT)
|
||||
->where('id')->ne($oldAction->objectID)
|
||||
->beginIF($oldAction->objectType == 'program' or $oldAction->objectType == 'project')->andWhere("(name = '{$project->name}' and parent = {$project->parent})", true)->fi()
|
||||
->beginIF($oldAction->objectType == 'execution')->andWhere("(name = '{$project->name}' and project = {$sprintProject})", true)->fi()
|
||||
->beginIF($oldAction->objectType == 'project' and $project->code)->orWhere("(code = '{$project->code}' and model = '$project->model')")->fi()
|
||||
->beginIF($oldAction->objectType == 'execution' and $project->code)->orWhere("code = '{$project->code}'")->fi()
|
||||
->markRight(1)
|
||||
->beginIF($oldAction->objectType == 'program')->andWhere('type')->eq('program')->fi()
|
||||
->beginIF($oldAction->objectType == 'project')->andWhere('type')->eq('project')->fi()
|
||||
->beginIF($oldAction->objectType == 'execution')->andWhere('type')->in('sprint,stage,kanban')->fi()
|
||||
->andWhere('deleted')->eq('0')
|
||||
->fetch();
|
||||
}
|
||||
|
||||
if($repeatObject)
|
||||
{
|
||||
$table = $oldAction->objectType == 'product' ? TABLE_PRODUCT : TABLE_PROJECT;
|
||||
$object = $oldAction->objectType == 'product' ? $product : $project;
|
||||
|
||||
$existNames = $this->dao->select('name')->from($table)->where('name')->like($repeatObject->name . '_%')->fetchPairs();
|
||||
for($i = 1; $i < 10000; $i ++)
|
||||
{
|
||||
$replaceName = $repeatObject->name . '_' . $i;
|
||||
if(!in_array($replaceName, $existNames)) break;
|
||||
}
|
||||
$replaceCode = '';
|
||||
if($object->code)
|
||||
{
|
||||
$existCodes = $this->dao->select('code')->from($table)->where('code')->like($repeatObject->code . '_%')->fetchPairs();
|
||||
for($i = 1; $i < 10000; $i ++)
|
||||
{
|
||||
$replaceCode = $repeatObject->code . '_' . $i;
|
||||
if(!in_array($replaceCode, $existCodes)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if($repeatObject->name == $object->name and $repeatObject->code and $repeatObject->code == $object->code)
|
||||
{
|
||||
if($confirmChange == 'no') return print(js::confirm(sprintf($this->lang->action->repeatChange, $this->lang->{$oldAction->objectType}->common, $replaceName, $replaceCode), $this->createLink('action', 'undelete', "action={$actionID}&browseType={$browseType}&confirmChange=yes")));
|
||||
if($confirmChange == 'yes') $this->dao->update($table)->set('name')->eq($replaceName)->set('code')->eq($replaceCode)->where('id')->eq($oldAction->objectID)->exec();
|
||||
}
|
||||
elseif($repeatObject->name == $object->name)
|
||||
{
|
||||
if($confirmChange == 'no') return print(js::confirm(sprintf($this->lang->action->nameRepeatChange, $this->lang->{$oldAction->objectType}->common, $replaceName), $this->createLink('action', 'undelete', "action={$actionID}&browseType={$browseType}&confirmChange=yes")));
|
||||
if($confirmChange == 'yes') $this->dao->update($table)->set('name')->eq($replaceName)->where('id')->eq($oldAction->objectID)->exec();
|
||||
}
|
||||
elseif($repeatObject->code and $repeatObject->code == $object->code)
|
||||
{
|
||||
if($confirmChange == 'no') return print(js::confirm(sprintf($this->lang->action->codeRepeatChange, $this->lang->{$oldAction->objectType}->common, $replaceCode), $this->createLink('action', 'undelete', "action={$actionID}&browseType={$browseType}&confirmChange=yes")));
|
||||
if($confirmChange == 'yes') $this->dao->update($table)->set('code')->eq($replaceCode)->where('id')->eq($oldAction->objectID)->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->action->undelete($actionID);
|
||||
|
||||
$sameTypeObjects = $this->action->getTrashes($oldAction->objectType, $extra, 'id_desc', null);
|
||||
$browseType = $sameTypeObjects ? $oldAction->objectType : 'all';
|
||||
$browseType = ($sameTypeObjects and $browseType != 'all') ? $oldAction->objectType : 'all';
|
||||
|
||||
return print(js::locate($this->createLink('action', 'trash', "browseType=$browseType&type=$extra"), 'parent'));
|
||||
}
|
||||
@@ -158,17 +232,18 @@ class action extends control
|
||||
* Hide an deleted object.
|
||||
*
|
||||
* @param int $actionID
|
||||
* @param string $browseType
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function hideOne($actionID)
|
||||
public function hideOne($actionID, $browseType = 'all')
|
||||
{
|
||||
$oldAction = $this->action->getById($actionID);
|
||||
|
||||
$this->action->hideOne($actionID);
|
||||
|
||||
$sameTypeObjects = $this->action->getTrashes($oldAction->objectType, 'all', 'id_desc', null);
|
||||
$browseType = $sameTypeObjects ? $oldAction->objectType : 'all';
|
||||
$browseType = ($sameTypeObjects and $browseType != 'all') ? $oldAction->objectType : 'all';
|
||||
|
||||
return print(js::locate($this->createLink('action', 'trash', "browseType=$browseType"), 'parent'));
|
||||
}
|
||||
@@ -214,7 +289,7 @@ class action extends control
|
||||
$story = $this->loadModel('story')->getById($objectID);
|
||||
$executions = explode(',', $this->app->user->view->sprints);
|
||||
$products = explode(',', $this->app->user->view->products);
|
||||
if(!array_intersect(array_keys($story->executions), $executions) and !in_array($story->product, $products)) return print(js::error($this->lang->error->accessDenied));
|
||||
if(!array_intersect(array_keys($story->executions), $executions) and !in_array($story->product, $products) and empty($story->lib)) return print(js::error($this->lang->error->accessDenied));
|
||||
}
|
||||
|
||||
$actionID = $this->action->create($objectType, $objectID, 'Commented', $this->post->comment);
|
||||
|
||||
@@ -58,6 +58,10 @@ $lang->action->noDynamic = 'Kein Verlauf. ';
|
||||
$lang->action->undeletedTips = 'This data did not participate in the merging process during the version upgrade process, so restore is not supported.';
|
||||
$lang->action->executionNoProject = 'The execution does not belong to a project,please restore the project first';
|
||||
|
||||
$lang->action->repeatChange = '%s with the same name and code already exists in the system, After recovery, the name are \"%s\",the code are \"%s\".';
|
||||
$lang->action->nameRepeatChange = '%s with the same name already exists in the system, After recovery, the name are \"%s\".';
|
||||
$lang->action->codeRepeatChange = '%s with the same code already exists in the system, After recovery, the code are \"%s\".';
|
||||
|
||||
$lang->action->history = new stdclass();
|
||||
$lang->action->history->action = 'Link';
|
||||
$lang->action->history->field = 'Feld';
|
||||
@@ -123,6 +127,7 @@ $lang->action->objectTypes['team'] = 'Team';
|
||||
$lang->action->objectTypes['whitelist'] = 'Whitelist';
|
||||
$lang->action->objectTypes['pipeline'] = 'GitLib';
|
||||
$lang->action->objectTypes['gitlab'] = 'GitLab Server';
|
||||
$lang->action->objectTypes['gitea'] = 'Gitea Server';
|
||||
$lang->action->objectTypes['jenkins'] = 'Jenkins';
|
||||
$lang->action->objectTypes['mr'] = 'Merge Request';
|
||||
$lang->action->objectTypes['gitlabproject'] = 'GitLab Project';
|
||||
@@ -132,6 +137,7 @@ $lang->action->objectTypes['gitlabbranch'] = 'GitLab Branch';
|
||||
$lang->action->objectTypes['gitlabbranchpriv'] = 'GitLab Protected Branches';
|
||||
$lang->action->objectTypes['gitlabtag'] = 'GitLab Tag';
|
||||
$lang->action->objectTypes['gitlabtagpriv'] = 'GitLab Tag Protected';
|
||||
$lang->action->objectTypes['giteauser'] = 'Gitea User';
|
||||
$lang->action->objectTypes['kanbanspace'] = 'Kanban Space';
|
||||
$lang->action->objectTypes['kanban'] = 'Kanban';
|
||||
$lang->action->objectTypes['kanbanregion'] = 'Kanban Region';
|
||||
@@ -142,6 +148,7 @@ $lang->action->objectTypes['sonarqube'] = 'SonarQube Server';
|
||||
$lang->action->objectTypes['sonarqubeproject'] = 'SonarQube Project';
|
||||
$lang->action->objectTypes['stage'] = 'Stage';
|
||||
$lang->action->objectTypes['patch'] = 'Patch';
|
||||
$lang->action->objectTypes['repo'] = 'Repo';
|
||||
|
||||
/* Used to describe operation history. */
|
||||
$lang->action->desc = new stdclass();
|
||||
@@ -208,6 +215,9 @@ $lang->action->desc->importedbuild = '$date, imported to <strong>$extra</
|
||||
$lang->action->desc->fromsonarqube = '$date, created by <strong>$actor</strong> from <strong>SonarQube Issue</strong>.' . "\n";
|
||||
$lang->action->desc->tolib = '$date, imported by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->updatetolib = '$date, updated to ' . $lang->testcase->common . ' by <strong>$actor</strong>.' . "\n";
|
||||
$lang->action->desc->adjusttasktowait = '$date, System Reminder: The task status will be set to Not Started as the consumed work hour is adjusted to 0. ' . "\n";
|
||||
$lang->action->desc->reopen = '$date, reopened by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->merged = '$date, merged by <strong>$actor</strong> .' . "\n";
|
||||
|
||||
/* Used to describe the history of operations related to parent-child tasks. */
|
||||
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> created a child task <strong>$extra</strong>。' . "\n";
|
||||
@@ -230,10 +240,10 @@ $lang->action->desc->linkrelatedcase = '$date, <strong>$actor</strong> hat ein
|
||||
$lang->action->desc->unlinkrelatedcase = '$date, <strong>$actor</strong> hate eine Fallverknüpfung aufgelöst <strong>$extra</strong>.' . "\n";
|
||||
|
||||
/* Used to describe the history of operations link story and bug to productplan. */
|
||||
$lang->action->desc->linkstory = '$date, 由 <strong>$actor</strong> 关联需求 <strong>$extra</strong> 到计划。' . "\n";
|
||||
$lang->action->desc->linkbug = '$date, 由 <strong>$actor</strong> 关联BUG <strong>$extra</strong> 到计划。' . "\n";
|
||||
$lang->action->desc->unlinkstory = '$date, 由 <strong>$actor</strong> 从计划移除需求 <strong>$extra</strong>。' . "\n";
|
||||
$lang->action->desc->unlinkbug = '$date, 由 <strong>$actor</strong> 从计划移除BUG <strong>$extra</strong>。' . "\n";
|
||||
$lang->action->desc->linkstory = '$date, <strong>$actor</strong> link stories <strong>$extra</strong> to plan.' . "\n";
|
||||
$lang->action->desc->linkbug = '$date, <strong>$actor</strong> link bugs <strong>$extra</strong> to plan.' . "\n";
|
||||
$lang->action->desc->unlinkstory = '$date, <strong>$actor</strong> remove stories <strong>$extra</strong> from plan.' . "\n";
|
||||
$lang->action->desc->unlinkbug = '$date, <strong>$actor</strong> remove bugs <strong>$extra</strong> from plan.' . "\n";
|
||||
|
||||
/* Used to display dynamic information. */
|
||||
$lang->action->label = new stdclass();
|
||||
@@ -304,7 +314,7 @@ $lang->action->label->suspended = 'suspended ';
|
||||
$lang->action->label->login = 'Login';
|
||||
$lang->action->label->logout = "Logout";
|
||||
$lang->action->label->notified = "Notified";
|
||||
$lang->action->label->deleteestimate = "deleted ";
|
||||
$lang->action->label->deleteestimate = "deleted hours";
|
||||
$lang->action->label->linked2build = "linked ";
|
||||
$lang->action->label->linked2bug = "linked ";
|
||||
$lang->action->label->linked2testtask = "linked";
|
||||
@@ -635,6 +645,10 @@ $lang->action->dynamicAction->gitlab['created'] = 'Create GitLab Server';
|
||||
$lang->action->dynamicAction->gitlab['edited'] = 'Edit GitLab Server';
|
||||
$lang->action->dynamicAction->gitlab['deleted'] = 'Delete GitLab Server';
|
||||
|
||||
$lang->action->dynamicAction->gitea['created'] = 'Create Gitea Server';
|
||||
$lang->action->dynamicAction->gitea['edited'] = 'Edit Gitea Server';
|
||||
$lang->action->dynamicAction->gitea['deleted'] = 'Delete Gitea Server';
|
||||
|
||||
/* Generate the corresponding object link. */
|
||||
$lang->action->label->product = $lang->productCommon . '|product|view|productID=%s';
|
||||
$lang->action->label->productplan = 'Plan|productplan|view|productID=%s';
|
||||
@@ -680,6 +694,7 @@ $lang->action->label->kanbancard = 'Kanban Card|kanban|view|kanbanID=%s';
|
||||
$lang->action->label->mr = 'Merge Request|mr|view|id=%s';
|
||||
$lang->action->label->gitlab = 'GitLab Server|gitlab|view|id=%s';
|
||||
$lang->action->label->stage = 'Stage|stage|browse|';
|
||||
$lang->action->label->module = 'Module|tree|browse|productid=%s&type=story¤tModuleID=0&branch=all';
|
||||
|
||||
/* Object type. */
|
||||
$lang->action->search = new stdclass();
|
||||
|
||||
@@ -58,6 +58,10 @@ $lang->action->noDynamic = 'No dynamics. ';
|
||||
$lang->action->undeletedTips = 'This data did not participate in the merging process during the version upgrade process, so restore is not supported.';
|
||||
$lang->action->executionNoProject = 'The execution does not belong to a project,please restore the project first';
|
||||
|
||||
$lang->action->repeatChange = '%s with the same name and code already exists in the system, After recovery, the name are \"%s\",the code are \"%s\".';
|
||||
$lang->action->nameRepeatChange = '%s with the same name already exists in the system, After recovery, the name are \"%s\".';
|
||||
$lang->action->codeRepeatChange = '%s with the same code already exists in the system, After recovery, the code are \"%s\".';
|
||||
|
||||
$lang->action->history = new stdclass();
|
||||
$lang->action->history->action = 'Link';
|
||||
$lang->action->history->field = 'Field';
|
||||
@@ -123,6 +127,7 @@ $lang->action->objectTypes['team'] = 'Team';
|
||||
$lang->action->objectTypes['whitelist'] = 'Whitelist';
|
||||
$lang->action->objectTypes['pipeline'] = 'GitLab Server';
|
||||
$lang->action->objectTypes['gitlab'] = 'GitLab Server';
|
||||
$lang->action->objectTypes['gitea'] = 'Gitea Server';
|
||||
$lang->action->objectTypes['jenkins'] = 'Jenkins';
|
||||
$lang->action->objectTypes['mr'] = 'Merge Request';
|
||||
$lang->action->objectTypes['gitlabproject'] = 'GitLab Project';
|
||||
@@ -132,6 +137,7 @@ $lang->action->objectTypes['gitlabbranch'] = 'GitLab Branch';
|
||||
$lang->action->objectTypes['gitlabbranchpriv'] = 'GitLab Protected Branches';
|
||||
$lang->action->objectTypes['gitlabtag'] = 'GitLab Tag';
|
||||
$lang->action->objectTypes['gitlabtagpriv'] = 'GitLab Tag Protected';
|
||||
$lang->action->objectTypes['giteauser'] = 'Gitea User';
|
||||
$lang->action->objectTypes['kanbanspace'] = 'Kanban Space';
|
||||
$lang->action->objectTypes['kanban'] = 'Kanban';
|
||||
$lang->action->objectTypes['kanbanregion'] = 'Kanban Region';
|
||||
@@ -142,6 +148,7 @@ $lang->action->objectTypes['sonarqube'] = 'SonarQube Server';
|
||||
$lang->action->objectTypes['sonarqubeproject'] = 'SonarQube Project';
|
||||
$lang->action->objectTypes['stage'] = 'Stage';
|
||||
$lang->action->objectTypes['patch'] = 'Patch';
|
||||
$lang->action->objectTypes['repo'] = 'Repo';
|
||||
|
||||
/* Used to describe operation history. */
|
||||
$lang->action->desc = new stdclass();
|
||||
@@ -208,6 +215,9 @@ $lang->action->desc->importedbuild = '$date, imported to <strong>$extra</
|
||||
$lang->action->desc->fromsonarqube = '$date, created by <strong>$actor</strong> from <strong>SonarQube Issue</strong>.' . "\n";
|
||||
$lang->action->desc->tolib = '$date, imported by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->updatetolib = '$date, updated to ' . $lang->testcase->common . ' by <strong>$actor</strong>.' . "\n";
|
||||
$lang->action->desc->adjusttasktowait = '$date, System Reminder: The task status will be set to Not Started as the consumed work hour is adjusted to 0. ' . "\n";
|
||||
$lang->action->desc->reopen = '$date, reopened by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->merged = '$date, merged by <strong>$actor</strong> .' . "\n";
|
||||
|
||||
/* Used to describe the history of operations related to parent-child tasks. */
|
||||
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> created a child task <strong>$extra</strong>。' . "\n";
|
||||
@@ -230,10 +240,10 @@ $lang->action->desc->linkrelatedcase = '$date, <strong>$actor</strong> linked
|
||||
$lang->action->desc->unlinkrelatedcase = '$date, <strong>$actor</strong> unlinked a case <strong>$extra</strong>.' . "\n";
|
||||
|
||||
/* Used to describe the history of operations link story and bug to productplan. */
|
||||
$lang->action->desc->linkstory = '$date, 由 <strong>$actor</strong> 关联需求 <strong>$extra</strong> 到计划。' . "\n";
|
||||
$lang->action->desc->linkbug = '$date, 由 <strong>$actor</strong> 关联BUG <strong>$extra</strong> 到计划。' . "\n";
|
||||
$lang->action->desc->unlinkstory = '$date, 由 <strong>$actor</strong> 从计划移除需求 <strong>$extra</strong>。' . "\n";
|
||||
$lang->action->desc->unlinkbug = '$date, 由 <strong>$actor</strong> 从计划移除BUG <strong>$extra</strong>。' . "\n";
|
||||
$lang->action->desc->linkstory = '$date, <strong>$actor</strong> link stories <strong>$extra</strong> to plan.' . "\n";
|
||||
$lang->action->desc->linkbug = '$date, <strong>$actor</strong> link bugs <strong>$extra</strong> to plan.' . "\n";
|
||||
$lang->action->desc->unlinkstory = '$date, <strong>$actor</strong> remove stories <strong>$extra</strong> from plan.' . "\n";
|
||||
$lang->action->desc->unlinkbug = '$date, <strong>$actor</strong> remove bugs <strong>$extra</strong> from plan.' . "\n";
|
||||
|
||||
/* Used to display dynamic information. */
|
||||
$lang->action->label = new stdclass();
|
||||
@@ -304,7 +314,7 @@ $lang->action->label->suspended = 'suspended ';
|
||||
$lang->action->label->login = 'login';
|
||||
$lang->action->label->logout = "logout";
|
||||
$lang->action->label->notified = "Notified";
|
||||
$lang->action->label->deleteestimate = "deleted ";
|
||||
$lang->action->label->deleteestimate = "deleted hours";
|
||||
$lang->action->label->linked2build = "linked ";
|
||||
$lang->action->label->linked2bug = "linked ";
|
||||
$lang->action->label->linked2testtask = "linked";
|
||||
@@ -635,6 +645,10 @@ $lang->action->dynamicAction->gitlab['created'] = 'Create GitLab Server';
|
||||
$lang->action->dynamicAction->gitlab['edited'] = 'Edit GitLab Server';
|
||||
$lang->action->dynamicAction->gitlab['deleted'] = 'Delete GitLab Server';
|
||||
|
||||
$lang->action->dynamicAction->gitea['created'] = 'Create Gitea Server';
|
||||
$lang->action->dynamicAction->gitea['edited'] = 'Edit Gitea Server';
|
||||
$lang->action->dynamicAction->gitea['deleted'] = 'Delete Gitea Server';
|
||||
|
||||
/* Generate the corresponding object link. */
|
||||
$lang->action->label->product = $lang->productCommon . '|product|view|productID=%s';
|
||||
$lang->action->label->productplan = 'Plan|productplan|view|productID=%s';
|
||||
@@ -680,6 +694,7 @@ $lang->action->label->kanbancard = 'Kanban Card|kanban|view|kanbanID=%s';
|
||||
$lang->action->label->mr = 'Merge Request|mr|view|id=%s';
|
||||
$lang->action->label->gitlab = 'GitLab Server|gitlab|view|id=%s';
|
||||
$lang->action->label->stage = 'Stage|stage|browse|';
|
||||
$lang->action->label->module = 'Module|tree|browse|productid=%s&type=story¤tModuleID=0&branch=all';
|
||||
|
||||
/* Object type. */
|
||||
$lang->action->search = new stdclass();
|
||||
|
||||
@@ -58,6 +58,10 @@ $lang->action->noDynamic = "Pas d'historique.";
|
||||
$lang->action->undeletedTips = 'This data did not participate in the merging process during the version upgrade process, so restore is not supported.';
|
||||
$lang->action->executionNoProject = 'The execution does not belong to a project,please restore the project first';
|
||||
|
||||
$lang->action->repeatChange = '%s with the same name and code already exists in the system, After recovery, the name are \"%s\",the code are \"%s\".';
|
||||
$lang->action->nameRepeatChange = '%s with the same name already exists in the system, After recovery, the name are \"%s\".';
|
||||
$lang->action->codeRepeatChange = '%s with the same code already exists in the system, After recovery, the code are \"%s\".';
|
||||
|
||||
$lang->action->history = new stdclass();
|
||||
$lang->action->history->action = 'Lien';
|
||||
$lang->action->history->field = 'Champ';
|
||||
@@ -123,6 +127,7 @@ $lang->action->objectTypes['team'] = 'Team';
|
||||
$lang->action->objectTypes['whitelist'] = 'Whitelist';
|
||||
$lang->action->objectTypes['pipeline'] = 'GitLib';
|
||||
$lang->action->objectTypes['gitlab'] = 'GitLab Server';
|
||||
$lang->action->objectTypes['gitea'] = 'Gitea Server';
|
||||
$lang->action->objectTypes['jenkins'] = 'Jenkins';
|
||||
$lang->action->objectTypes['mr'] = 'Merge Request';
|
||||
$lang->action->objectTypes['gitlabproject'] = 'GitLab Project';
|
||||
@@ -132,6 +137,7 @@ $lang->action->objectTypes['gitlabbranch'] = 'GitLab Branch';
|
||||
$lang->action->objectTypes['gitlabbranchpriv'] = 'GitLab Protected Branches';
|
||||
$lang->action->objectTypes['gitlabtag'] = 'GitLab Tag';
|
||||
$lang->action->objectTypes['gitlabtagpriv'] = 'GitLab Tag Protected';
|
||||
$lang->action->objectTypes['giteauser'] = 'Gitea User';
|
||||
$lang->action->objectTypes['kanbanspace'] = 'Kanban Space';
|
||||
$lang->action->objectTypes['kanban'] = 'Kanban';
|
||||
$lang->action->objectTypes['kanbanregion'] = 'Kanban Region';
|
||||
@@ -142,6 +148,7 @@ $lang->action->objectTypes['sonarqube'] = 'SonarQube Server';
|
||||
$lang->action->objectTypes['sonarqubeproject'] = 'SonarQube Project';
|
||||
$lang->action->objectTypes['stage'] = 'Stage';
|
||||
$lang->action->objectTypes['patch'] = 'Patch';
|
||||
$lang->action->objectTypes['repo'] = 'Repo';
|
||||
|
||||
/* Used to describe operation history. */
|
||||
$lang->action->desc = new stdclass();
|
||||
@@ -208,6 +215,9 @@ $lang->action->desc->importedbuild = '$date, imported to <strong>$extra</
|
||||
$lang->action->desc->fromsonarqube = '$date, created by <strong>$actor</strong> from <strong>SonarQube Issue</strong>.' . "\n";
|
||||
$lang->action->desc->tolib = '$date, Importé par <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->updatetolib = '$date, MàJ de ' . $lang->testcase->common . ' par <strong>$actor</strong>.' . "\n";
|
||||
$lang->action->desc->adjusttasktowait = '$date, System Reminder: The task status will be set to Not Started as the consumed work hour is adjusted to 0. ' . "\n";
|
||||
$lang->action->desc->reopen = '$date, reopened by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->merged = '$date, merged by <strong>$actor</strong> .' . "\n";
|
||||
|
||||
/* Used to describe the history of operations related to parent-child tasks. */
|
||||
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> a créé un sous-tâche <strong>$extra</strong>。' . "\n";
|
||||
@@ -230,10 +240,10 @@ $lang->action->desc->linkrelatedcase = '$date, <strong>$actor</strong> a fait
|
||||
$lang->action->desc->unlinkrelatedcase = '$date, <strong>$actor</strong> a délié le CasTest <strong>$extra</strong>.' . "\n";
|
||||
|
||||
/* Used to describe the history of operations link story and bug to productplan. */
|
||||
$lang->action->desc->linkstory = '$date, 由 <strong>$actor</strong> 关联需求 <strong>$extra</strong> 到计划。' . "\n";
|
||||
$lang->action->desc->linkbug = '$date, 由 <strong>$actor</strong> 关联BUG <strong>$extra</strong> 到计划。' . "\n";
|
||||
$lang->action->desc->unlinkstory = '$date, 由 <strong>$actor</strong> 从计划移除需求 <strong>$extra</strong>。' . "\n";
|
||||
$lang->action->desc->unlinkbug = '$date, 由 <strong>$actor</strong> 从计划移除BUG <strong>$extra</strong>。' . "\n";
|
||||
$lang->action->desc->linkstory = '$date, <strong>$actor</strong> link stories <strong>$extra</strong> to plan.' . "\n";
|
||||
$lang->action->desc->linkbug = '$date, <strong>$actor</strong> link bugs <strong>$extra</strong> to plan.' . "\n";
|
||||
$lang->action->desc->unlinkstory = '$date, <strong>$actor</strong> remove stories <strong>$extra</strong> from plan.' . "\n";
|
||||
$lang->action->desc->unlinkbug = '$date, <strong>$actor</strong> remove bugs <strong>$extra</strong> from plan.' . "\n";
|
||||
|
||||
/* Used to display dynamic information. */
|
||||
$lang->action->label = new stdclass();
|
||||
@@ -635,6 +645,10 @@ $lang->action->dynamicAction->gitlab['created'] = 'Create GitLab Server';
|
||||
$lang->action->dynamicAction->gitlab['edited'] = 'Edit GitLab Server';
|
||||
$lang->action->dynamicAction->gitlab['deleted'] = 'Delete GitLab Server';
|
||||
|
||||
$lang->action->dynamicAction->gitea['created'] = 'Create Gitea Server';
|
||||
$lang->action->dynamicAction->gitea['edited'] = 'Edit Gitea Server';
|
||||
$lang->action->dynamicAction->gitea['deleted'] = 'Delete Gitea Server';
|
||||
|
||||
/* Generate the corresponding object link. */
|
||||
$lang->action->label->product = $lang->productCommon . '|product|view|productID=%s';
|
||||
$lang->action->label->productplan = 'Plan|productplan|view|productID=%s';
|
||||
@@ -680,6 +694,7 @@ $lang->action->label->kanbancard = 'Kanban Card|kanban|view|kanbanID=%s';
|
||||
$lang->action->label->mr = 'Merge Request|mr|view|id=%s';
|
||||
$lang->action->label->gitlab = 'GitLab Server|gitlab|view|id=%s';
|
||||
$lang->action->label->stage = 'Stage|stage|browse|';
|
||||
$lang->action->label->module = 'Module|tree|browse|productid=%s&type=story¤tModuleID=0&branch=all';
|
||||
|
||||
/* Object type. */
|
||||
$lang->action->search = new stdclass();
|
||||
|
||||
+80
-35
@@ -65,41 +65,64 @@ $lang->action->periods['lastweek'] = $lang->action->dynamic->lastWeek;
|
||||
$lang->action->periods['thismonth'] = $lang->action->dynamic->thisMonth;
|
||||
$lang->action->periods['lastmonth'] = $lang->action->dynamic->lastMonth;
|
||||
|
||||
$lang->action->objectTypes['product'] = $lang->productCommon;
|
||||
$lang->action->objectTypes['branch'] = 'Nhánh';
|
||||
$lang->action->objectTypes['story'] = $lang->SRCommon;
|
||||
$lang->action->objectTypes['design'] = 'Design';
|
||||
$lang->action->objectTypes['productplan'] = 'Plan';
|
||||
$lang->action->objectTypes['release'] = 'Phát hành';
|
||||
$lang->action->objectTypes['program'] = 'Program';
|
||||
$lang->action->objectTypes['project'] = 'Project';
|
||||
$lang->action->objectTypes['execution'] = $lang->executionCommon;
|
||||
$lang->action->objectTypes['task'] = 'Nhiệm vụ';
|
||||
$lang->action->objectTypes['build'] = 'Bản dựng';
|
||||
$lang->action->objectTypes['job'] = 'Job';
|
||||
$lang->action->objectTypes['bug'] = 'Bug';
|
||||
$lang->action->objectTypes['case'] = 'Tình huống';
|
||||
$lang->action->objectTypes['caseresult'] = 'Kết quả tình huống';
|
||||
$lang->action->objectTypes['stepresult'] = 'Các bước tình huống';
|
||||
$lang->action->objectTypes['caselib'] = 'Thư viện';
|
||||
$lang->action->objectTypes['testsuite'] = 'Suite';
|
||||
$lang->action->objectTypes['testtask'] = 'Test bản dựng';
|
||||
$lang->action->objectTypes['testreport'] = 'Báo cáo';
|
||||
$lang->action->objectTypes['doc'] = 'Tài liệu';
|
||||
$lang->action->objectTypes['doclib'] = 'Thư viện tài liệu';
|
||||
$lang->action->objectTypes['todo'] = 'Việc làm';
|
||||
$lang->action->objectTypes['risk'] = 'Risk';
|
||||
$lang->action->objectTypes['issue'] = 'Issue';
|
||||
$lang->action->objectTypes['module'] = 'Module';
|
||||
$lang->action->objectTypes['user'] = 'Người dùng';
|
||||
$lang->action->objectTypes['stakeholder'] = 'Stakeholder';
|
||||
$lang->action->objectTypes['budget'] = 'Cost Estimate';
|
||||
$lang->action->objectTypes['entry'] = 'Entry';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['job'] = 'Job';
|
||||
$lang->action->objectTypes['team'] = 'Team';
|
||||
$lang->action->objectTypes['whitelist'] = 'Whitelist';
|
||||
$lang->action->objectTypes['pipeline'] = 'GitLib';
|
||||
$lang->action->objectTypes['product'] = $lang->productCommon;
|
||||
$lang->action->objectTypes['branch'] = 'Nhánh';
|
||||
$lang->action->objectTypes['story'] = $lang->SRCommon;
|
||||
$lang->action->objectTypes['design'] = 'Design';
|
||||
$lang->action->objectTypes['productplan'] = 'Plan';
|
||||
$lang->action->objectTypes['release'] = 'Phát hành';
|
||||
$lang->action->objectTypes['program'] = 'Program';
|
||||
$lang->action->objectTypes['project'] = 'Project';
|
||||
$lang->action->objectTypes['execution'] = $lang->executionCommon;
|
||||
$lang->action->objectTypes['task'] = 'Nhiệm vụ';
|
||||
$lang->action->objectTypes['build'] = 'Bản dựng';
|
||||
$lang->action->objectTypes['job'] = 'Job';
|
||||
$lang->action->objectTypes['bug'] = 'Bug';
|
||||
$lang->action->objectTypes['case'] = 'Tình huống';
|
||||
$lang->action->objectTypes['caseresult'] = 'Kết quả tình huống';
|
||||
$lang->action->objectTypes['stepresult'] = 'Các bước tình huống';
|
||||
$lang->action->objectTypes['caselib'] = 'Thư viện';
|
||||
$lang->action->objectTypes['testsuite'] = 'Suite';
|
||||
$lang->action->objectTypes['testtask'] = 'Test bản dựng';
|
||||
$lang->action->objectTypes['testreport'] = 'Báo cáo';
|
||||
$lang->action->objectTypes['doc'] = 'Tài liệu';
|
||||
$lang->action->objectTypes['doclib'] = 'Thư viện tài liệu';
|
||||
$lang->action->objectTypes['todo'] = 'Việc làm';
|
||||
$lang->action->objectTypes['risk'] = 'Risk';
|
||||
$lang->action->objectTypes['issue'] = 'Issue';
|
||||
$lang->action->objectTypes['module'] = 'Module';
|
||||
$lang->action->objectTypes['user'] = 'Người dùng';
|
||||
$lang->action->objectTypes['stakeholder'] = 'Stakeholder';
|
||||
$lang->action->objectTypes['budget'] = 'Cost Estimate';
|
||||
$lang->action->objectTypes['entry'] = 'Entry';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['job'] = 'Job';
|
||||
$lang->action->objectTypes['team'] = 'Team';
|
||||
$lang->action->objectTypes['whitelist'] = 'Whitelist';
|
||||
$lang->action->objectTypes['pipeline'] = 'GitLib';
|
||||
$lang->action->objectTypes['gitlab'] = 'GitLab Server';
|
||||
$lang->action->objectTypes['gitea'] = 'Gitea Server';
|
||||
$lang->action->objectTypes['jenkins'] = 'Jenkins';
|
||||
$lang->action->objectTypes['mr'] = 'Merge Request';
|
||||
$lang->action->objectTypes['gitlabproject'] = 'GitLab Project';
|
||||
$lang->action->objectTypes['gitlabuser'] = 'GitLab User';
|
||||
$lang->action->objectTypes['gitlabgroup'] = 'GitLab Group';
|
||||
$lang->action->objectTypes['gitlabbranch'] = 'GitLab Branch';
|
||||
$lang->action->objectTypes['gitlabbranchpriv'] = 'GitLab Protected Branches';
|
||||
$lang->action->objectTypes['gitlabtag'] = 'GitLab Tag';
|
||||
$lang->action->objectTypes['gitlabtagpriv'] = 'GitLab Tag Protected';
|
||||
$lang->action->objectTypes['giteauser'] = 'Gitea User';
|
||||
$lang->action->objectTypes['kanbanspace'] = 'Kanban Space';
|
||||
$lang->action->objectTypes['kanban'] = 'Kanban';
|
||||
$lang->action->objectTypes['kanbanregion'] = 'Kanban Region';
|
||||
$lang->action->objectTypes['kanbanlane'] = 'Kanban Lane';
|
||||
$lang->action->objectTypes['kanbancolumn'] = 'Kanban Column';
|
||||
$lang->action->objectTypes['kanbancard'] = 'Kanban Card';
|
||||
$lang->action->objectTypes['sonarqube'] = 'SonarQube Server';
|
||||
$lang->action->objectTypes['sonarqubeproject'] = 'SonarQube Project';
|
||||
$lang->action->objectTypes['stage'] = 'Stage';
|
||||
$lang->action->objectTypes['patch'] = 'Patch';
|
||||
$lang->action->objectTypes['repo'] = 'Repo';
|
||||
|
||||
/* Used to describe operation history. */
|
||||
$lang->action->desc = new stdclass();
|
||||
@@ -153,6 +176,8 @@ $lang->action->desc->run = '$date, by <strong>$actor</strong> execut
|
||||
$lang->action->desc->syncprogram = '$date, started by <strong>$actor</strong>(starting the project sets the program status as Ongoing).' . "\n";
|
||||
$lang->action->desc->syncproject = '$date, starting the execution sets the project status as Ongoing.' . "\n";
|
||||
$lang->action->desc->syncexecution = '$date, starting the task sets the execution status as Ongoing.' . "\n";
|
||||
$lang->action->desc->reopen = '$date, reopened by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->merged = '$date, merged by <strong>$actor</strong> .' . "\n";
|
||||
|
||||
/* Used to describe the history of operations related to parent-child tasks. */
|
||||
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> created a child task <strong>$extra</strong>。' . "\n";
|
||||
@@ -462,6 +487,26 @@ $lang->action->dynamicAction->user['loginxuanxuan'] = 'Login Desktop';
|
||||
$lang->action->dynamicAction->entry['created'] = 'Thêm ứng dụng';
|
||||
$lang->action->dynamicAction->entry['edited'] = 'Sửa ứng dụng';
|
||||
|
||||
$lang->action->dynamicAction->job['created'] = 'Create Job';
|
||||
$lang->action->dynamicAction->job['edited'] = 'Edit Job';
|
||||
$lang->action->dynamicAction->job['executed'] = 'Execute Job';
|
||||
$lang->action->dynamicAction->job['deleted'] = 'Delete Job';
|
||||
$lang->action->dynamicAction->job['undeleted'] = 'Undelete Job';
|
||||
|
||||
$lang->action->dynamicAction->sonarqube['created'] = 'Create SonarQube Server';
|
||||
$lang->action->dynamicAction->sonarqube['edited'] = 'Edit SonarQube Server';
|
||||
$lang->action->dynamicAction->sonarqube['deleted'] = 'Delete SonarQube Server';
|
||||
|
||||
$lang->action->dynamicAction->sonarqubeproject['deleted'] = 'Delete SonarQube Project';
|
||||
|
||||
$lang->action->dynamicAction->gitlab['created'] = 'Create GitLab Server';
|
||||
$lang->action->dynamicAction->gitlab['edited'] = 'Edit GitLab Server';
|
||||
$lang->action->dynamicAction->gitlab['deleted'] = 'Delete GitLab Server';
|
||||
|
||||
$lang->action->dynamicAction->gitea['created'] = 'Create Gitea Server';
|
||||
$lang->action->dynamicAction->gitea['edited'] = 'Edit Gitea Server';
|
||||
$lang->action->dynamicAction->gitea['deleted'] = 'Delete Gitea Server';
|
||||
|
||||
/* Generate the corresponding object link. */
|
||||
global $config;
|
||||
$lang->action->label->product = $lang->productCommon . '|product|view|productID=%s';
|
||||
|
||||
@@ -58,6 +58,10 @@ $lang->action->noDynamic = '暂时没有动态。';
|
||||
$lang->action->undeletedTips = '该数据在版本升级过程中未参与数据归并流程,不支持还原。';
|
||||
$lang->action->executionNoProject = '该执行没有所属的项目,请先还原项目再还原执行';
|
||||
|
||||
$lang->action->repeatChange = '系统内已有同名、同代号的%s,恢复后名称为\"%s\"、代号为\"%s\"。';
|
||||
$lang->action->nameRepeatChange = '系统内已有同名的%s,恢复后名称为\"%s\"。';
|
||||
$lang->action->codeRepeatChange = '系统内已有同代号的%s,恢复后代号为\"%s\"。';
|
||||
|
||||
$lang->action->history = new stdclass();
|
||||
$lang->action->history->action = '关联日志';
|
||||
$lang->action->history->field = '字段';
|
||||
@@ -123,6 +127,7 @@ $lang->action->objectTypes['team'] = '团队';
|
||||
$lang->action->objectTypes['whitelist'] = '白名单';
|
||||
$lang->action->objectTypes['pipeline'] = 'GitLab服务器';
|
||||
$lang->action->objectTypes['gitlab'] = 'GitLab服务器';
|
||||
$lang->action->objectTypes['gitea'] = 'Gitea服务器';
|
||||
$lang->action->objectTypes['jenkins'] = 'Jenkins';
|
||||
$lang->action->objectTypes['mr'] = '合并请求';
|
||||
$lang->action->objectTypes['gitlabproject'] = 'GitLab项目';
|
||||
@@ -132,6 +137,7 @@ $lang->action->objectTypes['gitlabbranch'] = 'GitLab分支';
|
||||
$lang->action->objectTypes['gitlabbranchpriv'] = 'GitLab保护分支';
|
||||
$lang->action->objectTypes['gitlabtag'] = 'GitLab标签';
|
||||
$lang->action->objectTypes['gitlabtagpriv'] = 'GitLab标签保护';
|
||||
$lang->action->objectTypes['giteauser'] = 'Gitea用户';
|
||||
$lang->action->objectTypes['kanbanspace'] = '看板空间';
|
||||
$lang->action->objectTypes['kanban'] = '看板';
|
||||
$lang->action->objectTypes['kanbanregion'] = '看板区域';
|
||||
@@ -142,6 +148,7 @@ $lang->action->objectTypes['sonarqube'] = 'SonarQube服务器';
|
||||
$lang->action->objectTypes['sonarqubeproject'] = 'SonarQube项目';
|
||||
$lang->action->objectTypes['stage'] = '阶段';
|
||||
$lang->action->objectTypes['patch'] = '补丁';
|
||||
$lang->action->objectTypes['repo'] = '代码库';
|
||||
|
||||
/* 用来描述操作历史记录。*/
|
||||
$lang->action->desc = new stdclass();
|
||||
@@ -208,6 +215,9 @@ $lang->action->desc->importedbuild = '$date, 由 <strong>$actor</strong>
|
||||
$lang->action->desc->fromsonarqube = '$date, 由 <strong>$actor</strong> 从<strong>SonarQube问题</strong>转化而来。' . "\n";
|
||||
$lang->action->desc->tolib = '$date, 由 <strong>$actor</strong> 导入。' . "\n";
|
||||
$lang->action->desc->updatetolib = '$date, 由 <strong>$actor</strong> 从' . $lang->testcase->common . '更新。' . "\n";
|
||||
$lang->action->desc->adjusttasktowait = '$date, 系统判断由于消耗工时调整为0,将任务状态置为未开始。' . "\n";
|
||||
$lang->action->desc->reopen = '$date, 由 <strong>$actor</strong> 重新打开。' . "\n";
|
||||
$lang->action->desc->merged = '$date, 由 <strong>$actor</strong> 合并。' . "\n";
|
||||
|
||||
/* 用来描述和父子任务相关的操作历史记录。*/
|
||||
$lang->action->desc->createchildren = '$date, 由 <strong>$actor</strong> 创建子任务 <strong>$extra</strong>。' . "\n";
|
||||
@@ -632,9 +642,13 @@ $lang->action->dynamicAction->sonarqube['deleted'] = '删除SonarQube服务器';
|
||||
$lang->action->dynamicAction->sonarqubeproject['deleted'] = '删除SonarQube项目';
|
||||
|
||||
$lang->action->dynamicAction->gitlab['created'] = '创建GitLab服务器';
|
||||
$lang->action->dynamicAction->gitlab['edited'] = '设置GitLab服务器';
|
||||
$lang->action->dynamicAction->gitlab['edited'] = '编辑GitLab服务器';
|
||||
$lang->action->dynamicAction->gitlab['deleted'] = '删除GitLab服务器';
|
||||
|
||||
$lang->action->dynamicAction->gitea['created'] = '创建Gitea服务器';
|
||||
$lang->action->dynamicAction->gitea['edited'] = '编辑Gitea服务器';
|
||||
$lang->action->dynamicAction->gitea['deleted'] = '删除Gitea服务器';
|
||||
|
||||
/* 用来生成相应对象的链接。*/
|
||||
$lang->action->label->product = $lang->productCommon . '|product|view|productID=%s';
|
||||
$lang->action->label->productplan = "计划|productplan|view|productID=%s";
|
||||
@@ -680,6 +694,7 @@ $lang->action->label->kanbancard = '看板卡片|kanban|view|kanbanID=%s';
|
||||
$lang->action->label->mr = '合并请求|mr|view|id=%s';
|
||||
$lang->action->label->gitlab = 'GitLab服务器|gitlab|view|id=%s';
|
||||
$lang->action->label->stage = '瀑布模型的阶段|stage|browse|';
|
||||
$lang->action->label->module = '模块|tree|browse|productid=%s&type=story¤tModuleID=0&branch=all';
|
||||
|
||||
/* Object type. */
|
||||
$lang->action->search = new stdclass();
|
||||
|
||||
@@ -127,12 +127,14 @@ $lang->action->objectTypes['gitlabgroup'] = 'GitLab群組';
|
||||
$lang->action->objectTypes['gitlabbranch'] = 'GitLab分支';
|
||||
$lang->action->objectTypes['gitlabbranchpriv'] = 'GitLab保護分支';
|
||||
$lang->action->objectTypes['gitlabtag'] = 'GitLab標籤';
|
||||
$lang->action->objectTypes['giteauser'] = 'Gitea用戶';
|
||||
$lang->action->objectTypes['kanbanspace'] = '看板空間';
|
||||
$lang->action->objectTypes['kanban'] = '看板';
|
||||
$lang->action->objectTypes['kanbanregion'] = '看板區域';
|
||||
$lang->action->objectTypes['kanbanlane'] = '看板泳道';
|
||||
$lang->action->objectTypes['kanbancolumn'] = '看板列';
|
||||
$lang->action->objectTypes['kanbancard'] = '看板卡片';
|
||||
$lang->action->objectTypes['repo'] = '代码库';
|
||||
|
||||
/* 用來描述操作歷史記錄。*/
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
+87
-28
@@ -73,7 +73,7 @@ class actionModel extends model
|
||||
if($this->post->uid) $this->file->updateObjectID($this->post->uid, $objectID, $objectType);
|
||||
|
||||
/* Call the message notification function. */
|
||||
$this->loadModel('message')->send(strtolower($objectType), $objectID, $actionType, $actionID, $actor);
|
||||
$this->loadModel('message')->send(strtolower($objectType), $objectID, $actionType, $actionID, $actor, $extra);
|
||||
|
||||
/* Add index for global search. */
|
||||
$this->saveIndex($objectType, $objectID, $actionType);
|
||||
@@ -282,6 +282,11 @@ class actionModel extends model
|
||||
if($extra == 'project') $record['project'] = $objectID;
|
||||
if($extra == 'sprint' or $extra == 'stage') $record['execution'] = $objectID;
|
||||
break;
|
||||
case 'module':
|
||||
if(strpos(',deleted,', ",$actionType,") === false) $module = $this->dao->select('*')->from(TABLE_MODULE)->where('id')->in($extra)->fetch();
|
||||
if(strpos(',deleted,', ",$actionType,") !== false) $module = $this->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($objectID)->fetch();
|
||||
if(!empty($module) and $module->type == 'story') $record['product'] = $module->root;
|
||||
break;
|
||||
default:
|
||||
$result = $this->dao->select('*')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
|
||||
$record['product'] = zget($result, 'product', '0');
|
||||
@@ -318,13 +323,19 @@ class actionModel extends model
|
||||
*/
|
||||
public function getList($objectType, $objectID)
|
||||
{
|
||||
$modules = $objectType == 'module' ? $this->dao->select('id')->from(TABLE_MODULE)->where('root')->eq($objectID)->fetchPairs('id') : array();
|
||||
$commiters = $this->loadModel('user')->getCommiters();
|
||||
$actions = $this->dao->select('*')->from(TABLE_ACTION)
|
||||
->beginIF($objectType == 'project')
|
||||
->where("objectType IN('project', 'testtask', 'build')")
|
||||
->andWhere('project')->eq((int)$objectID)
|
||||
->fi()
|
||||
->beginIF($objectType != 'project')
|
||||
->beginIF($objectType == 'module')
|
||||
->where('objectType')->eq($objectType)
|
||||
->andWhere('((action')->ne('deleted')->andWhere('objectID')->eq((int)$objectID)->markRight(1)
|
||||
->orWhere('(action')->eq('deleted')->andWhere('objectID')->in($modules)->markRight(1)->markRight(1)
|
||||
->fi()
|
||||
->beginIF($objectType != 'project' and $objectType != 'module')
|
||||
->where('objectType')->eq($objectType)
|
||||
->andWhere('objectID')->eq((int)$objectID)
|
||||
->fi()
|
||||
@@ -395,7 +406,7 @@ class actionModel extends model
|
||||
$name = $this->dao->select('name')->from(TABLE_TESTTASK)->where('id')->eq($action->extra)->fetch('name');
|
||||
if($name) $action->extra = common::hasPriv('testtask', 'view') ? html::a(helper::createLink('testtask', 'view', "taskID=$action->extra"), $name) : $name;
|
||||
}
|
||||
elseif($actionName == 'moved')
|
||||
elseif($actionName == 'moved' and $action->objectType != 'module')
|
||||
{
|
||||
$name = $this->dao->select('name')->from(TABLE_PROJECT)->where('id')->eq($action->extra)->fetch('name');
|
||||
if($name) $action->extra = common::hasPriv('execution', 'task') ? html::a(helper::createLink('execution', 'task', "executionID=$action->extra"), "#$action->extra " . $name) : "#$action->extra " . $name;
|
||||
@@ -776,7 +787,7 @@ class actionModel extends model
|
||||
*/
|
||||
public function getHistory($actionID)
|
||||
{
|
||||
return $this->dao->select()->from(TABLE_HISTORY)->where('action')->in($actionID)->orderBy('id')->fetchGroup('action');
|
||||
return $this->dao->select()->from(TABLE_HISTORY)->where('action')->in($actionID)->fetchGroup('action');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -836,6 +847,10 @@ class actionModel extends model
|
||||
{
|
||||
$desc = $this->lang->$objectType->action->changebychild;
|
||||
}
|
||||
elseif($action->objectType == 'module' and in_array($action->action, array('created', 'moved', 'deleted')))
|
||||
{
|
||||
$desc = $this->lang->$objectType->action->{$action->action};
|
||||
}
|
||||
elseif($action->action == 'createmr' and strpos($action->extra, '::') !== false)
|
||||
{
|
||||
list($mrCreatedDate, $mrActor, $mrLink) = explode('::', $action->extra);
|
||||
@@ -920,6 +935,21 @@ class actionModel extends model
|
||||
$actionDesc = str_replace('$extra', $desc['extra'][$extra], $desc['main']);
|
||||
}
|
||||
}
|
||||
|
||||
if($action->objectType == 'module' and strpos(',created,moved,', $action->action) !== false)
|
||||
{
|
||||
$moduleNames = $this->loadModel('tree')->getOptionMenu($action->objectID, 'story', 0, 'all', '');
|
||||
$modules = explode(',', $action->extra);
|
||||
$moduleNames = array_intersect_key($moduleNames, array_combine($modules, $modules));
|
||||
$moduleNames = implode(', ', $moduleNames);
|
||||
$actionDesc = str_replace('$extra', $moduleNames, $desc['main']);
|
||||
}
|
||||
elseif($action->objectType == 'module' and $action->action == 'deleted')
|
||||
{
|
||||
$module = $this->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($action->objectID)->fetch();
|
||||
$moduleNames = $this->loadModel('tree')->getOptionMenu($module->root, 'story', 0, 'all', '');
|
||||
$actionDesc = str_replace('$extra', zget($moduleNames, $action->objectID), $desc['main']);
|
||||
}
|
||||
echo $actionDesc;
|
||||
}
|
||||
else
|
||||
@@ -954,24 +984,31 @@ class actionModel extends model
|
||||
$executions = array();
|
||||
if(!$this->app->user->admin)
|
||||
{
|
||||
if($productID == 'all') $authedProducts = $this->app->user->view->products;
|
||||
if($projectID == 'all') $authedProjects = $this->app->user->view->projects;
|
||||
if($executionID == 'all') $authedExecutions = $this->app->user->view->sprints;
|
||||
$aclViews = isset($this->app->user->rights['acls']['views']) ? $this->app->user->rights['acls']['views'] : array();
|
||||
if($productID == 'all') $authedProducts = (empty($aclViews) or (!empty($aclViews) and !empty($aclViews['product']))) ? $this->app->user->view->products : '0';
|
||||
if($projectID == 'all') $authedProjects = (empty($aclViews) or (!empty($aclViews) and !empty($aclViews['project']))) ? $this->app->user->view->projects : '0';
|
||||
if($executionID == 'all') $authedExecutions = (empty($aclViews) or (!empty($aclViews) and !empty($aclViews['execution']))) ? $this->app->user->view->sprints : '0';
|
||||
|
||||
if($productID == 'all' and $projectID == 'all')
|
||||
{
|
||||
$productCondition = "product " . helper::dbIN($authedProducts);
|
||||
$productCondition = '';
|
||||
foreach(explode(',', $authedProducts) as $product) $productCondition = empty($productCondition) ? "product LIKE '%,$product,%'" : "$productCondition OR product LIKE '%,$product,%'";
|
||||
|
||||
$projectCondition = "project " . helper::dbIN($authedProjects);
|
||||
$executionCondition = isset($authedExecutions) ? "execution " . helper::dbIN($authedExecutions) : '';
|
||||
}
|
||||
elseif($productID == 'all' and is_numeric($projectID))
|
||||
{
|
||||
$products = $this->loadModel('product')->getProductPairsByProject($projectID);
|
||||
$executions = $this->loadModel('execution')->getPairs($projectID) + array(0 => 0);
|
||||
$executions = $this->loadModel('execution')->getPairs($projectID);
|
||||
|
||||
$authedExecutions = isset($authedExecutions) ? array_intersect(array_keys($executions), explode(',', $authedExecutions)) : array_keys($executions);
|
||||
|
||||
$productCondition = '';
|
||||
foreach(array_keys($products) as $product) $productCondition = empty($productCondition) ? "product LIKE '%,$product,%'" : "$productCondition OR product LIKE '%,$product,%'";
|
||||
|
||||
$productCondition = "product " . helper::dbIN(array_keys($products));
|
||||
$projectCondition = "project = $projectID";
|
||||
$executionCondition = "execution " . helper::dbIN(array_keys($executions));
|
||||
$executionCondition = "execution " . helper::dbIN($authedExecutions);
|
||||
}
|
||||
elseif(is_numeric($productID) and $projectID == 'all')
|
||||
{
|
||||
@@ -979,15 +1016,18 @@ class actionModel extends model
|
||||
$projects = $this->product->getProjectPairsByProduct($productID);
|
||||
$executions = $this->product->getExecutionPairsByProduct($productID);
|
||||
|
||||
$productCondition = "product = $productID";
|
||||
$projectCondition = "project " . helper::dbIN(array_keys($projects));
|
||||
$executionCondition = "execution " . helper::dbIN(array_keys($executions));
|
||||
$authedProjects = array_intersect(array_keys($projects), explode(',', $authedProjects));
|
||||
$authedExecutions = isset($authedExecutions) ? array_intersect(array_keys($executions), explode(',', $authedExecutions)) : array_keys($executions);
|
||||
|
||||
$productCondition = "product like '%,$productID,%'";
|
||||
$projectCondition = 'project ' . helper::dbIN($authedProjects);
|
||||
$executionCondition = 'execution ' . helper::dbIN($authedExecutions);
|
||||
}
|
||||
|
||||
$condition = "((product =',0,' or product=0) AND project = '0' AND execution = 0)";
|
||||
if(!empty($productCondition)) $condition .= ' OR ' . $productCondition;
|
||||
if(!empty($projectCondition)) $condition .= ' OR ' . $projectCondition;
|
||||
if(!empty($executionCondition)) $condition .= ' OR ' . $executionCondition;
|
||||
$condition = "((product =',0,' or product = '0' or product=',,') AND project = '0' AND execution = '0')";
|
||||
if(!empty($productCondition)) $condition .= " OR $productCondition";
|
||||
if(!empty($projectCondition)) $condition .= " OR $projectCondition";
|
||||
if(!empty($executionCondition)) $condition .= " OR $executionCondition";
|
||||
}
|
||||
|
||||
$actionCondition = $this->getActionCondition();
|
||||
@@ -1004,6 +1044,8 @@ class actionModel extends model
|
||||
if($this->app->getMethodName() == 'dynamic') $beginDate = $year - 1 . '-01-01';
|
||||
}
|
||||
|
||||
$programCondition = empty($this->app->user->view->programs) ? '0' : $this->app->user->view->programs;
|
||||
|
||||
/* Get actions. */
|
||||
$actions = $this->dao->select('*')->from(TABLE_ACTION)
|
||||
->where('objectType')->notIN('kanbanregion,kanbanlane,kanbancolumn')
|
||||
@@ -1030,6 +1072,7 @@ class actionModel extends model
|
||||
->beginIF($actionCondition)->andWhere("($actionCondition)")->fi()
|
||||
/* Filter out client login/logout actions. */
|
||||
->andWhere('action')->notin('disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan')
|
||||
->andWhere("IF((objectType = 'program'), (objectID in ($programCondition)), '1=1')")
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll();
|
||||
@@ -1056,6 +1099,7 @@ class actionModel extends model
|
||||
|
||||
foreach($this->app->user->rights['acls']['actions'] as $moduleName => $actions)
|
||||
{
|
||||
if(isset($this->lang->mainNav->$moduleName) and !empty($this->app->user->rights['acls']['views']) and !isset($this->app->user->rights['acls']['views'][$moduleName])) continue;
|
||||
$actionCondition .= "(`objectType` = '$moduleName' and `action` " . helper::dbIN($actions) . ") or ";
|
||||
}
|
||||
$actionCondition = trim($actionCondition, 'or ');
|
||||
@@ -1178,8 +1222,17 @@ class actionModel extends model
|
||||
$relatedProjects = $relatedData['relatedProjects'];
|
||||
$requirements = $relatedData['requirements'];
|
||||
|
||||
$aclViews = isset($this->app->user->rights['acls']['views']) ? $this->app->user->rights['acls']['views'] : array();
|
||||
$authedProjects = (empty($aclViews) or (!empty($aclViews) and !empty($aclViews['project']))) ? ",{$this->app->user->view->projects}," : '';
|
||||
$authedExecutions = (empty($aclViews) or (!empty($aclViews) and !empty($aclViews['execution']))) ? ",{$this->app->user->view->sprints},": '';
|
||||
|
||||
foreach($actions as $i => $action)
|
||||
{
|
||||
if(($action->execution != '0' and strpos($authedExecutions, ",$action->execution,") === false) or ($action->execution == '0' and $action->project != '0' and strpos($authedProjects, ",$action->project,") === false))
|
||||
{
|
||||
unset($actions[$i]);
|
||||
continue;
|
||||
}
|
||||
/* Add name field to the actions. */
|
||||
$action->objectName = isset($objectNames[$action->objectType][$action->objectID]) ? $objectNames[$action->objectType][$action->objectID] : '';
|
||||
|
||||
@@ -1204,6 +1257,11 @@ class actionModel extends model
|
||||
$objectName = $objectType == 'productplan' ? 'title' : 'name';
|
||||
$action->objectName = $this->dao->select($objectName)->from($objectTable)->where('id')->eq($action->extra)->fetch($objectName);
|
||||
}
|
||||
elseif($action->objectType == 'module' and !empty($action->extra) and $action->action != 'deleted')
|
||||
{
|
||||
$modules = $this->dao->select('id,name')->from(TABLE_MODULE)->where('id')->in(explode(',', $action->extra))->fetchPairs('id');
|
||||
$action->objectName = implode(',', $modules);
|
||||
}
|
||||
|
||||
$projectID = isset($relatedProjects[$action->objectType][$action->objectID]) ? $relatedProjects[$action->objectType][$action->objectID] : 0;
|
||||
|
||||
@@ -1219,15 +1277,11 @@ class actionModel extends model
|
||||
/* If action type is login or logout, needn't link. */
|
||||
if($actionType == 'svncommited' or $actionType == 'gitcommited') $action->actor = zget($commiters, $action->actor);
|
||||
|
||||
/* Get gitlab objectname. */
|
||||
if(empty($action->objectName) and substr($objectType, 0, 6) == 'gitlab') $action->objectName = $action->extra;
|
||||
/* Get gitlab or gitea objectname. */
|
||||
if(empty($action->objectName) and (substr($objectType, 0, 6) == 'gitlab' or substr($objectType, 0, 5) == 'gitea')) $action->objectName = $action->extra;
|
||||
|
||||
/* Other actions, create a link. */
|
||||
if(!$this->setObjectLink($action, $deptUsers))
|
||||
{
|
||||
unset($actions[$i]);
|
||||
continue;
|
||||
}
|
||||
$this->setObjectLink($action, $deptUsers);
|
||||
|
||||
/* Set merge request link. */
|
||||
if(empty($action->objectName) and $action->objectType == 'mr') $action->objectLink = '';
|
||||
@@ -1402,7 +1456,6 @@ class actionModel extends model
|
||||
|
||||
/* Fix bug #2961. */
|
||||
$isLoginOrLogout = $action->objectType == 'user' and ($action->action == 'login' or $action->action == 'logout');
|
||||
if(!common::hasPriv($moduleName, $methodName) and !$isLoginOrLogout) return false;
|
||||
|
||||
$action->objectLabel = $objectLabel;
|
||||
$action->product = trim($action->product, ',');
|
||||
@@ -1466,6 +1519,10 @@ class actionModel extends model
|
||||
{
|
||||
$params = sprintf($vars, $action->extra);
|
||||
}
|
||||
elseif($action->objectType == 'module' and $action->action == 'deleted')
|
||||
{
|
||||
$params = sprintf($vars, trim($action->product, ','));
|
||||
}
|
||||
else
|
||||
{
|
||||
$params = sprintf($vars, $action->objectID);
|
||||
@@ -1497,11 +1554,12 @@ class actionModel extends model
|
||||
$action->objectLink = !isset($deptUsers[$action->objectID]) ? 'javascript:void(0)' : helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID));
|
||||
}
|
||||
}
|
||||
if(!common::hasPriv($moduleName, $methodName) and !$isLoginOrLogout) $action->objectLink = '';
|
||||
}
|
||||
elseif($action->objectType == 'team')
|
||||
{
|
||||
if($action->project) $action->objectLink = helper::createLink('project', 'team', 'projectID=' . $action->project);
|
||||
if($action->execution) $action->objectLink = helper::createLink('execution', 'team', 'executionID=' . $action->execution);
|
||||
if($action->project) $action->objectLink = common::hasPriv('project', 'team') ? helper::createLink('project', 'team', 'projectID=' . $action->project) : '';
|
||||
if($action->execution) $action->objectLink = common::hasPriv('execution', 'team') ? helper::createLink('execution', 'team', 'executionID=' . $action->execution) : '';
|
||||
}
|
||||
|
||||
if($action->objectType == 'stakeholder' and $action->project == 0) $action->objectLink = '';
|
||||
@@ -1611,6 +1669,7 @@ class actionModel extends model
|
||||
{
|
||||
$fieldName = $history->field;
|
||||
$history->fieldLabel = (isset($this->lang->$objectType) && isset($this->lang->$objectType->$fieldName)) ? $this->lang->$objectType->$fieldName : $fieldName;
|
||||
if($objectType == 'module') $history->fieldLabel = $this->lang->tree->$fieldName;
|
||||
if(($length = strlen($history->fieldLabel)) > $maxLength) $maxLength = $length;
|
||||
$history->diff ? $historiesWithDiff[] = $history : $historiesWithoutDiff[] = $history;
|
||||
}
|
||||
|
||||
@@ -139,8 +139,8 @@
|
||||
<td><?php echo $action->date;?></td>
|
||||
<td>
|
||||
<?php
|
||||
common::printLink('action', 'undelete', "actionid=$action->id", $lang->action->undelete, 'hiddenwin');
|
||||
if($type == 'all') common::printLink('action', 'hideOne', "actionid=$action->id", $lang->action->hideOne, 'hiddenwin');
|
||||
common::printLink('action', 'undelete', "actionid=$action->id&browseType=$currentObjectType", $lang->action->undelete, 'hiddenwin');
|
||||
if($type == 'all') common::printLink('action', 'hideOne', "actionid=$action->id&browseType=$currentObjectType", $lang->action->hideOne, 'hiddenwin');
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -10,7 +10,11 @@
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<style>.table-form>tbody>tr>th{width:118px !important;}</style>
|
||||
<style>
|
||||
.table-form>tbody>tr>th {width:118px !important;}
|
||||
.icon-exclamation-sign.icon {color:#2667E3; margin-right: 8px;}
|
||||
.notice {color:#2667E3; margin-left: 12px;}
|
||||
</style>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
@@ -36,15 +40,21 @@
|
||||
<tr>
|
||||
<th class='thWidth'><?php echo $lang->admin->safe->password?></th>
|
||||
<td class='w-250px'><?php echo html::radio('mode', $lang->admin->safe->modeList, isset($config->safe->mode) ? $config->safe->mode : 0, "onclick=showModeRule(this.value)")?></td>
|
||||
<td><?php echo $lang->admin->safe->noticeMode?></td>
|
||||
<td class='notice'><?php echo $lang->admin->safe->noticeMode?></td>
|
||||
</tr>
|
||||
<tr id='mode1Rule' class='hidden'>
|
||||
<th></th>
|
||||
<td colspan='2'><span style='color:#03b8cf;font-weight:bold;'><?php echo $lang->admin->safe->modeRuleList[1] . $lang->admin->safe->noticeStrong;?></span></td>
|
||||
<td colspan='2'>
|
||||
<i class="icon icon-exclamation-sign"></i>
|
||||
<span style='color:#5E626D;font-weight:bold;font-size:13px;'><?php echo $lang->admin->safe->modeRuleList[1] . $lang->admin->safe->noticeStrong;?></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='mode2Rule' class='hidden'>
|
||||
<th></th>
|
||||
<td colspan='2'><span style='color:#03b8cf;font-weight:bold;'><?php echo $lang->admin->safe->modeRuleList[2] . $lang->admin->safe->noticeStrong;?></span></td>
|
||||
<td colspan='2'>
|
||||
<i class="icon icon-exclamation-sign"></i>
|
||||
<span style='color:#5E626D;font-weight:bold;font-size:13px;'><?php echo $lang->admin->safe->modeRuleList[2] . $lang->admin->safe->noticeStrong;?></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->admin->safe->weak?></th>
|
||||
|
||||
@@ -251,9 +251,10 @@ class api extends control
|
||||
|
||||
|
||||
$id = $this->api->createStruct($data);
|
||||
if(dao::isError()) return $this->sendError(dao::getError());
|
||||
|
||||
$this->action->create('apistruct', $id, 'Created');
|
||||
|
||||
if(dao::isError()) return $this->sendError(dao::getError());
|
||||
return $this->sendSuccess(array('locate' => helper::createLink('api', 'struct', "libID=$libID")));
|
||||
}
|
||||
|
||||
@@ -352,7 +353,7 @@ class api extends control
|
||||
|
||||
$this->view->type = $type;
|
||||
$this->view->groups = $this->loadModel('group')->getPairs();
|
||||
$this->view->users = $this->user->getPairs('nocode');
|
||||
$this->view->users = $this->user->getPairs('nocode|noclosed');
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -387,7 +388,7 @@ class api extends control
|
||||
|
||||
$this->view->doc = $doc;
|
||||
$this->view->groups = $this->loadModel('group')->getPairs();
|
||||
$this->view->users = $this->user->getPairs('nocode');
|
||||
$this->view->users = $this->user->getPairs('nocode|noclosed');
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -455,7 +456,7 @@ class api extends control
|
||||
$this->getTypeOptions($api->lib);
|
||||
|
||||
$this->view->title = $api->title . $this->lang->api->edit;
|
||||
$this->view->gobackLink = $this->createLink('api', 'index', "libID={$api->lib}&moduleID={$api->module}");
|
||||
$this->view->gobackLink = $this->createLink('api', 'index', "libID={$api->lib}&moduleID={$api->module}&apiID=$apiID");
|
||||
$this->view->user = $this->app->user->account;
|
||||
$this->view->allUsers = $this->loadModel('user')->getPairs('devfirst|noclosed');;
|
||||
$this->view->moduleOptionMenu = $this->loadModel('tree')->getOptionMenu($api->lib, 'api', $startModuleID = 0);
|
||||
@@ -635,7 +636,7 @@ class api extends control
|
||||
if(intval($libID) > 0 and common::hasPriv('api', 'create'))
|
||||
{
|
||||
$menu .= "<li>";
|
||||
$menu .= html::a(helper::createLink('api', 'create', "libID=$libID&moduleID=$moduleID"), "<i class='icon-rich-text icon'></i> " . $this->lang->api->apiDoc, '', "data-app='{$this->app->tab}'");
|
||||
$menu .= html::a(helper::createLink('api', 'create', "libID=$libID&moduleID=$moduleID"), "<i class='icon-rich-text icon'></i> " . $this->lang->api->createApi, '', "data-app='{$this->app->tab}'");
|
||||
$menu .= "</li>";
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#whiteListBox .input-group:last-child {margin-top: 10px;}
|
||||
@@ -910,7 +910,7 @@ class apiModel extends model
|
||||
$this->config->api->search['module'] = 'api';
|
||||
$this->config->api->search['queryID'] = $queryID;
|
||||
$this->config->api->search['actionURL'] = $actionURL;
|
||||
$this->config->api->search['params']['lib']['values'] = array($lib->id => $lib->name) + array('all' => $this->lang->api->allLibs);
|
||||
$this->config->api->search['params']['lib']['values'] = (!empty($lib)) ? array($lib->id => $lib->name) + array('all' => $this->lang->api->allLibs) : array('all' => $this->lang->api->allLibs);
|
||||
|
||||
$this->loadModel('search')->setSearchParams($this->config->api->search);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
<tr>
|
||||
<th><?php echo $lang->api->control;?></th>
|
||||
<td>
|
||||
<span><?php echo html::radio('acl', $lang->api->aclList, 'open', "onchange='toggleAcl(this.value, \"lib\")'")?></span>
|
||||
<?php $isDisabled = $type == 'demo' ? 'disabled' : '';?>
|
||||
<span><?php echo html::radio('acl', $lang->api->aclList, 'open', "onchange='toggleAcl(this.value, \"lib\")' $isDisabled")?></span>
|
||||
<span class='text-info' id='noticeAcl'><?php echo $lang->api->noticeAcl['open'];?></span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
+48
-28
@@ -597,9 +597,9 @@ class block extends control
|
||||
*/
|
||||
public function printTodoBlock()
|
||||
{
|
||||
$limit = $this->viewType == 'json' ? 0 : (int)$this->params->count;
|
||||
$limit = ($this->viewType == 'json' or !isset($this->params->count)) ? 0 : (int)$this->params->count;
|
||||
$todos = $this->loadModel('todo')->getList('all', $this->app->user->account, 'wait, doing', $limit, $pager = null, $orderBy = 'date, begin');
|
||||
$uri = $this->app->getURI(true);
|
||||
$uri = $this->createLink('my', 'index');
|
||||
|
||||
$this->session->set('todoList', $uri, 'my');
|
||||
$this->session->set('bugList', $uri, 'qa');
|
||||
@@ -629,7 +629,7 @@ class block extends control
|
||||
*/
|
||||
public function printTaskBlock()
|
||||
{
|
||||
$this->session->set('taskList', $this->app->getURI(true), 'execution');
|
||||
$this->session->set('taskList', $this->createLink('my', 'index'), 'execution');
|
||||
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
|
||||
|
||||
$account = $this->app->user->account;
|
||||
@@ -647,7 +647,7 @@ class block extends control
|
||||
*/
|
||||
public function printBugBlock()
|
||||
{
|
||||
$this->session->set('bugList', $this->app->getURI(true), 'qa');
|
||||
$this->session->set('bugList', $this->createLink('my', 'index'), 'qa');
|
||||
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
|
||||
|
||||
$projectID = $this->lang->navGroup->qa == 'project' ? $this->session->project : 0;
|
||||
@@ -663,7 +663,7 @@ class block extends control
|
||||
*/
|
||||
public function printCaseBlock()
|
||||
{
|
||||
$this->session->set('caseList', $this->app->getURI(true), 'qa');
|
||||
$this->session->set('caseList', $this->createLink('my', 'index'), 'qa');
|
||||
$this->app->loadLang('testcase');
|
||||
$this->app->loadLang('testtask');
|
||||
|
||||
@@ -708,9 +708,10 @@ class block extends control
|
||||
{
|
||||
$this->app->loadLang('testtask');
|
||||
|
||||
$this->session->set('productList', $this->app->getURI(true), 'product');
|
||||
$this->session->set('testtaskList', $this->app->getURI(true), 'qa');
|
||||
$this->session->set('buildList', $this->app->getURI(true), 'execution');
|
||||
$uri = $this->createLink('my', 'index');
|
||||
$this->session->set('productList', $uri, 'product');
|
||||
$this->session->set('testtaskList', $uri, 'qa');
|
||||
$this->session->set('buildList', $uri, 'execution');
|
||||
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
|
||||
|
||||
$this->view->testtasks = $this->dao->select('distinct t1.*,t2.name as productName,t3.name as buildName,t4.name as projectName')->from(TABLE_TESTTASK)->alias('t1')
|
||||
@@ -736,7 +737,7 @@ class block extends control
|
||||
*/
|
||||
public function printStoryBlock()
|
||||
{
|
||||
$this->session->set('storyList', $this->app->getURI(true), 'product');
|
||||
$this->session->set('storyList', $this->createLink('my', 'index'), 'product');
|
||||
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
|
||||
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
@@ -897,7 +898,7 @@ class block extends control
|
||||
|
||||
/* Get projects. */
|
||||
$excludedModel = $this->config->edition == 'max' ? '' : 'waterfall';
|
||||
$projects = $this->loadModel('project')->getOverviewList('byStatus', $status, 'id_desc', $count, $excludedModel);
|
||||
$projects = $this->loadModel('project')->getOverviewList('byStatus', $status, 'order_asc', $count, $excludedModel);
|
||||
if(empty($projects))
|
||||
{
|
||||
$this->view->projects = $projects;
|
||||
@@ -1079,10 +1080,10 @@ class block extends control
|
||||
|
||||
/* Get tasks. Fix bug #2918.*/
|
||||
$yesterday = date('Y-m-d', strtotime('-1 day'));
|
||||
$taskGroups = $this->dao->select("id,parent,project,status,finishedDate,estimate,consumed,`left`")->from(TABLE_TASK)
|
||||
->where('project')->in($executionIdList)
|
||||
$taskGroups = $this->dao->select("id,parent,execution,status,finishedDate,estimate,consumed,`left`")->from(TABLE_TASK)
|
||||
->where('execution')->in($executionIdList)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchGroup('project', 'id');
|
||||
->fetchGroup('execution', 'id');
|
||||
|
||||
$tasks = array();
|
||||
foreach($taskGroups as $executionID => $taskGroup)
|
||||
@@ -1095,7 +1096,7 @@ class block extends control
|
||||
|
||||
foreach($taskGroup as $taskID => $task)
|
||||
{
|
||||
if(strpos('wait|doing|pause', $task->status) !== false) $undoneTasks ++;
|
||||
if(strpos('wait|doing|pause|cancel', $task->status) !== false) $undoneTasks ++;
|
||||
if(strpos($task->finishedDate, $yesterday) !== false) $yesterdayFinished ++;
|
||||
|
||||
if($task->parent == '-1') continue;
|
||||
@@ -1131,11 +1132,11 @@ class block extends control
|
||||
}
|
||||
|
||||
/* Get bugs. */
|
||||
$bugs = $this->dao->select("project, count(status) as totalBugs, count(status = 'active' or null) as activeBugs, count(resolvedDate like '{$yesterday}%' or null) as yesterdayResolved")->from(TABLE_BUG)
|
||||
->where('project')->in($executionIdList)
|
||||
$bugs = $this->dao->select("execution, count(status) as totalBugs, count(status = 'active' or null) as activeBugs, count(resolvedDate like '{$yesterday}%' or null) as yesterdayResolved")->from(TABLE_BUG)
|
||||
->where('execution')->in($executionIdList)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->groupBy('project')
|
||||
->fetchAll('project');
|
||||
->groupBy('execution')
|
||||
->fetchAll('execution');
|
||||
|
||||
foreach($bugs as $executionID => $bug)
|
||||
{
|
||||
@@ -1717,6 +1718,7 @@ class block extends control
|
||||
if(common::hasPriv('risk', 'view') and $this->config->edition == 'max' and $this->config->vision != 'lite') $hasViewPriv['risk'] = true;
|
||||
if(common::hasPriv('issue', 'view') and $this->config->edition == 'max' and $this->config->vision != 'lite') $hasViewPriv['issue'] = true;
|
||||
if(common::hasPriv('meeting', 'view') and $this->config->edition == 'max' and $this->config->vision != 'lite') $hasViewPriv['meeting'] = true;
|
||||
if(common::hasPriv('feedback', 'view') and in_array($this->config->edition, array('max', 'biz'))) $hasViewPriv['feedback'] = true;
|
||||
|
||||
$params = $this->get->param;
|
||||
$params = json_decode(base64_decode($params));
|
||||
@@ -1725,8 +1727,14 @@ class block extends control
|
||||
$objectCountList = array('todo' => 'todoCount', 'task' => 'taskCount', 'bug' => 'bugCount', 'story' => 'storyCount', 'requirement' => 'requirementCount');
|
||||
if($this->config->edition == 'max')
|
||||
{
|
||||
$objectList += array('risk' => 'risks', 'issue' => 'issues');
|
||||
$objectCountList += array('risk' => 'riskCount', 'issue' => 'issueCount');
|
||||
$objectList += array('risk' => 'risks', 'issue' => 'issues', 'feedback' => 'feedbacks');
|
||||
$objectCountList += array('risk' => 'riskCount', 'issue' => 'issueCount', 'feedback' => 'feedbackCount');
|
||||
}
|
||||
|
||||
if($this->config->edition == 'biz')
|
||||
{
|
||||
$objectList += array('feedback' => 'feedbacks');
|
||||
$objectCountList += array('feedback' => 'feedbackCount');
|
||||
}
|
||||
|
||||
$tasks = $this->loadModel('task')->getUserSuspendedTasks($this->app->user->account);
|
||||
@@ -1741,6 +1749,7 @@ class block extends control
|
||||
->beginIF($objectType == 'story' or $objectType == 'requirement')->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product=t2.id')->fi()
|
||||
->beginIF($objectType == 'bug')->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product=t2.id')->fi()
|
||||
->beginIF($objectType == 'task')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution=t2.id')->fi()
|
||||
->beginIF($objectType == 'issue' or $objectType == 'risk')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')->fi()
|
||||
->where('t1.deleted')->eq(0)
|
||||
->andWhere('t1.assignedTo')->eq($this->app->user->account)->fi()
|
||||
->beginIF($objectType == 'story')->andWhere('t1.type')->eq('story')->andWhere('t2.deleted')->eq('0')->fi()
|
||||
@@ -1749,6 +1758,8 @@ class block extends control
|
||||
->beginIF($objectType == 'story' or $objectType == 'requirement')->andWhere('t2.deleted')->eq('0')->fi()
|
||||
->beginIF($objectType == 'todo')->andWhere('t1.cycle')->eq(0)->andWhere('t1.status')->eq('wait')->andWhere('t1.vision')->eq($this->config->vision)->fi()
|
||||
->beginIF($objectType != 'todo')->andWhere('t1.status')->ne('closed')->fi()
|
||||
->beginIF($objectType == 'feedback')->andWhere('t1.status')->in('wait, noreview')->fi()
|
||||
->beginIF($objectType == 'issue' or $objectType == 'risk')->andWhere('t2.deleted')->eq(0)->fi()
|
||||
->orderBy($orderBy)
|
||||
->beginIF($limitCount)->limit($limitCount)->fi()
|
||||
->fetchAll();
|
||||
@@ -1787,6 +1798,13 @@ class block extends control
|
||||
if($objectType == 'risk') $this->app->loadLang('risk');
|
||||
if($objectType == 'issue') $this->app->loadLang('issue');
|
||||
|
||||
if($objectType == 'feedback')
|
||||
{
|
||||
$this->app->loadLang('feedback');
|
||||
$this->view->users = $this->loadModel('user')->getPairs('all,noletter');
|
||||
$this->view->products = $this->dao->select('id, name')->from(TABLE_PRODUCT)->where('deleted')->eq('0')->fetchPairs('id', 'name');
|
||||
}
|
||||
|
||||
$count[$objectType] = count($objects);
|
||||
$this->view->{$objectList[$objectType]} = $objects;
|
||||
}
|
||||
@@ -1798,16 +1816,18 @@ class block extends control
|
||||
$now = date('H:i:s', strtotime(helper::now()));
|
||||
$meetingCount = isset($params->meetingCount) ? isset($params->meetingCount) : 0;
|
||||
|
||||
$meetings = $this->dao->select('*')->from(TABLE_MEETING)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere('(date')->gt($today)
|
||||
->orWhere('(begin')->gt($now)
|
||||
->andWhere('date')->eq($today)
|
||||
$meetings = $this->dao->select('*')->from(TABLE_MEETING)->alias('t1')
|
||||
->leftjoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
|
||||
->where('t1.deleted')->eq('0')
|
||||
->andWhere('t2.deleted')->eq('0')
|
||||
->andWhere('(t1.date')->gt($today)
|
||||
->orWhere('(t1.begin')->gt($now)
|
||||
->andWhere('t1.date')->eq($today)
|
||||
->markRight(2)
|
||||
->andwhere('(host')->eq($this->app->user->account)
|
||||
->orWhere('participant')->in($this->app->user->account)
|
||||
->andwhere('(t1.host')->eq($this->app->user->account)
|
||||
->orWhere('t1.participant')->in($this->app->user->account)
|
||||
->markRight(1)
|
||||
->orderBy('id_desc')
|
||||
->orderBy('t1.id_desc')
|
||||
->beginIF($meetingCount)->limit($meetingCount)->fi()
|
||||
->fetchAll();
|
||||
|
||||
|
||||
@@ -357,6 +357,7 @@ $lang->block->availableBlocks->testtask = 'Testaufgaben';
|
||||
$lang->block->availableBlocks->risk = 'My Risks';
|
||||
$lang->block->availableBlocks->issue = 'My Issues';
|
||||
$lang->block->availableBlocks->meeting = 'My Meetings';
|
||||
$lang->block->availableBlocks->feedback = 'My Feedbacks';
|
||||
|
||||
if($config->systemMode == 'new') $lang->block->moduleList['project'] = 'Project';
|
||||
$lang->block->moduleList['product'] = $lang->productCommon;
|
||||
@@ -469,13 +470,14 @@ $lang->block->orderByList->story['status_desc'] = 'Status Absteigend';
|
||||
$lang->block->orderByList->story['stage_asc'] = 'Phase Aufsteigend';
|
||||
$lang->block->orderByList->story['stage_desc'] = 'Phase Absteigend';
|
||||
|
||||
$lang->block->todoCount = 'Todos';
|
||||
$lang->block->taskCount = 'Aufgaben';
|
||||
$lang->block->bugCount = 'Bugs';
|
||||
$lang->block->riskCount = 'Risk';
|
||||
$lang->block->issueCount = 'Issues';
|
||||
$lang->block->storyCount = 'Stories';
|
||||
$lang->block->meetingCount = 'Meetings';
|
||||
$lang->block->todoCount = 'Todos';
|
||||
$lang->block->taskCount = 'Aufgaben';
|
||||
$lang->block->bugCount = 'Bugs';
|
||||
$lang->block->riskCount = 'Risk';
|
||||
$lang->block->issueCount = 'Issues';
|
||||
$lang->block->storyCount = 'Stories';
|
||||
$lang->block->meetingCount = 'Meetings';
|
||||
$lang->block->feedbackCount = 'Feedbacks';
|
||||
|
||||
$lang->block->typeList = new stdclass();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user