* merge current 18.x into ai.

This commit is contained in:
liwenrui
2023-08-16 10:28:06 +08:00
1522 changed files with 26414 additions and 902918 deletions
+1
View File
@@ -33,3 +33,4 @@ CodeSniffer.conf
test/runtime/*
test/www
!/**/.gitkeep
build/*.gz
Vendored Executable → Regular
+886 -148
View File
File diff suppressed because it is too large Load Diff
+168
View File
@@ -0,0 +1,168 @@
pipeline {
agent {
kubernetes {
inheritFrom "build-docker code-scan xuanim mysql-server"
}
}
environment {
ZENTAO_VERSION = """${sh(
returnStdout: true,
script: 'cat VERSION'
).trim()}"""
MYSQL_SERVER_HOST = """${sh(
returnStdout: true,
script: 'hostname -I'
).trim()}"""
MYSQL_ROOT_PASSWORD = 'pass4ci'
MIDDLE_IMAGE_REPO = "hub.qc.oop.cc/zentao-ztf"
MIDDLE_IMAGE_TAG = """${sh(
returnStdout: true,
script: 'echo $BUILD_ID-${GIT_COMMIT}'
).trim()}"""
}
stages {
stage("checkout code") {
steps {
echo "checkout code success"
}
}
stage('Sonar Scanner') {
parallel {
stage('SonarQube') {
steps {
container('sonar') {
withSonarQubeEnv('sonarqube') {
sh 'git config --global --add safe.directory $(pwd)'
sh 'sonar-scanner -Dsonar.inclusions=$(git diff --name-only HEAD~1|tr "\\n" ",") -Dsonar.analysis.user=$(git show -s --format=%an)'
}
}
}
post {
success {
container('xuanimbot') {
sh 'git config --global --add safe.directory $(pwd)'
sh '/usr/local/bin/xuanimbot --users "$(git show -s --format=%an)" --title "sonar scanner" --url "https://sonar.qc.oop.cc/dashboard?id=zentaopms&branch=${GIT_BRANCH}" --content "sonar scanner success" --debug --custom'
}
}
failure {
container('xuanimbot') {
sh 'git config --global --add safe.directory $(pwd)'
sh '/usr/local/bin/xuanimbot --users "$(git show -s --format=%an)" --title "sonar scanner" --url "https://sonar.qc.oop.cc/dashboard?id=zentaopms&branch=${GIT_BRANCH}" --content "sonar scanner failure" --debug --custom'
}
}
}
}
stage('Build Image') {
steps {
container('docker') {
sh 'docker build --pull . -f Dockerfile.test --build-arg VERSION=${ZENTAO_VERSION} --build-arg MIRROR=true --build-arg MYSQL_HOST=${MYSQL_SERVER_HOST} --build-arg MYSQL_PASSWORD=${MYSQL_ROOT_PASSWORD} -t ${MIDDLE_IMAGE_REPO}:${MIDDLE_IMAGE_TAG}'
sh 'docker push ${MIDDLE_IMAGE_REPO}:${MIDDLE_IMAGE_TAG}'
}
}
post {
success {
echo 'build image success'
}
failure {
container('xuanimbot') {
sh 'git config --global --add safe.directory $(pwd)'
sh '/usr/local/bin/xuanimbot --users "$(git show -s --format=%an)" --title "build image" --url "${RUN_DISPLAY_URL}" --content "Build unit test image failure" --debug --custom'
}
}
}
}
}
}
stage('Unit Test'){
stages{
stage('Init') {
agent {
kubernetes {
inheritFrom "xuanim"
containerTemplate {
name "zentao"
image "${MIDDLE_IMAGE_REPO}:${MIDDLE_IMAGE_TAG}"
command "sleep"
args "99d"
}
}
}
options { skipDefaultCheckout() }
steps {
container('zentao') {
sh 'initdb.php ; /apps/zentao/test/ztest init'
}
}
post {
success {
sh 'echo "stage unit init success"'
}
failure {
container('xuanimbot') {
sh 'git config --global --add safe.directory $(pwd)'
sh '/usr/local/bin/xuanimbot --users "$(git show -s --format=%an)" --title "unittest init" --url "${RUN_DISPLAY_URL}" --content "Unit test database initialization failed" --debug --custom'
}
}
}
}
stage('Run') {
matrix {
agent {
kubernetes {
inheritFrom "xuanim"
containerTemplate {
name "zentao"
image "${MIDDLE_IMAGE_REPO}:${MIDDLE_IMAGE_TAG}"
command "sleep"
args "99d"
}
}
}
options { skipDefaultCheckout() }
axes {
axis {
name "SEQUENCE"
values "P1", "P2", "P3", "P4", "P5", "P6", "P7"
}
}
stages {
stage("Run") {
steps {
container('zentao') {
sh 'initdb.php config'
sh '/apps/zentao/test/ztest extract ; /apps/zentao/test/ztest ${SEQUENCE} | tee /apps/zentao/test/${SEQUENCE}.log'
sh 'pipeline-unittest.sh /apps/zentao/test/${SEQUENCE}.log'
}
}
}
}
}
post{
success{
container('xuanimbot') {
sh 'git config --global --add safe.directory /home/jenkins/agent/workspace/pangu_pangu_xuanimbot_master'
sh '/usr/local/bin/xuanimbot --users "$(git show -s --format=%an)" --title "unittest" --url "${RUN_DISPLAY_URL}" --content "Unit test passed" --debug --custom'
}
}
failure{
container('xuanimbot') {
sh 'git config --global --add safe.directory $(pwd)'
sh '/usr/local/bin/xuanimbot --users "$(git show -s --format=%an)" --title "unittest" --url "${RUN_DISPLAY_URL}" --content "Unit test failed" --debug --custom'
}
}
}
}//End unittest
}
}
} // End Root Stages
} // End pipeline
+26 -14
View File
@@ -1,6 +1,6 @@
VERSION = $(shell head -n 1 VERSION)
XUANVERSION = $(shell head -n 1 xuanxuan/XUANVERSION)
XVERSION = $(shell head -n 1 xuanxuan/XVERSION)
XUANVERSION = $(shell jq -r .pkg.xuanxuan.gitVersion < ci.json)
XVERSION = $(shell jq -r .pkg.xuanxuan.version < ci.json)
XHPROF_VERSION = 2.3.9
XUANPATH := $(XUANXUAN_SRC_PATH)
@@ -8,6 +8,9 @@ BUILD_PATH := $(if $(ZENTAO_BUILD_PATH),$(ZENTAO_BUILD_PATH),$(shell pwd))
RELEASE_PATH := $(if $(ZENTAO_RELEASE_PATH),$(ZENTAO_RELEASE_PATH),$(shell pwd))
XUAN_WEB_PATH := $(ZENTAO_BUILD_PATH)/web
DOWNGRADE_ENABLED := $(or $(DOWNGRADE_ENABLED),$(shell jq -r .downgrade.enabled < ci.json))
DOWNGRADE_VERSIONS := $(or $(DOWNGRADE_VERSIONS),$(shell jq -r .downgrade.versions < ci.json))
all:
make clean
make ci
@@ -68,9 +71,9 @@ zentaoxx:
mkdir -p zentaoxx/db
mkdir -p zentaoxx/www
mkdir -p zentaoxx/extension/xuan/common/ext/model/
cd $(XUANPATH); git pull; git archive --format=zip --prefix=xuan/ $(XUANVERSION) > xuan.zip
cd $(XUANPATH); git archive --format=zip --prefix=xuan/ $(XUANVERSION) > xuan.zip
mv $(XUANPATH)/xuan.zip .
unzip xuan.zip
unzip -q xuan.zip
cp xuan/xxb/config/ext/_0_xuanxuan.php zentaoxx/config/ext/
cp -r xuan/xxb/lib/phpaes zentaoxx/lib/
cp -r xuan/xxb/framework/xuanxuan.class.php zentaoxx/framework/
@@ -98,6 +101,8 @@ zentaoxx:
cp -r $(XUAN_WEB_PATH) zentaoxx/www/data/xuanxuan/
mv zentaoxx/db/ zentaoxx/db_bak
mkdir zentaoxx/db/
sed -i "s/datetime NOT NULL DEFAULT '0000-00-00 00:00:00'/datetime NULL/" zentaoxx/db_bak/*.sql
sed -i "/`xxb_user` ADD `clientStatus`/d; /`xxb_user` ADD `clientLang`/d; /`xxb_file` CHANGE `pathname`/d" zentaoxx/db_bak/xuanxuan.sql
cp zentaoxx/db_bak/upgradexuanxuan*.sql zentaoxx/db_bak/xuanxuan.sql zentaoxx/db/
rm -rf zentaoxx/db_bak/
sed -i "s/\$$accountAdmin = \$$this->dao->select('account, admin')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch();/\$$accountAdmin = \$$this->dao->select('account')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch();\n\$$sysAdmins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\n\$$sysAdminArray = explode(',', \$$sysAdmins);\n\$$accountAdmin->admin = in_array(\$$accountAdmin->account, \$$sysAdminArray) ? 'super' : '';\n/" zentaoxx/extension/xuan/im/model/chat.php
@@ -132,6 +137,7 @@ zentaoxx:
sed -i '/xxb_entry/d' zentaoxx/db/*.sql
sed -i '/deviceToken/d' zentaoxx/db/*.sql
sed -i '/deviceType/d' zentaoxx/db/*.sql
sed -i 's/xxb_/zt_/g' zentaoxx/db/*.sql
sed -i "/fetch('push', 'pushMessage');/d" zentaoxx/extension/xuan/im/control.php
#sed -i "s/marked\.html\.php';?>/marked\.html\.php';?>\n<div id='mainMenu' class='clearfix'><div class='btn-toolbar pull-left'><?php common::printAdminSubMenu('xuanxuan');?><\/div><\/div>/g" zentaoxx/extension/xuan/client/view/checkupgrade.html.php
sed -i '/var serverVersions/d' zentaoxx/extension/xuan/client/js/checkupgrade.js
@@ -146,7 +152,7 @@ zentaoxx:
sed -i 's/v\.//g' zentaoxx/extension/xuan/client/js/checkupgrade.js
sed -i 's/commonModel::getLicensePropertyValue/extCommonModel::getLicensePropertyValue/g' zentaoxx/extension/xuan/im/control.php
sed -i 's/commonModel::getLicensePropertyValue/extCommonModel::getLicensePropertyValue/g' zentaoxx/extension/xuan/im/model/conference.php
sed -i 's/xxb_/zt_/g' zentaoxx/db/*.sql
sed -i 's/commonModel::isLicensedMethod([^\)]*)/false/g' zentaoxx/extension/xuan/conference/model.php
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
@@ -154,7 +160,7 @@ zentaoxx:
sed -i "/.*->getAllDepts();/d" zentaoxx/extension/xuan/im/ext/bot/default.bot.php
sed -i "s/lang->user->status/lang->user->clientStatus/" zentaoxx/extension/xuan/im/ext/bot/default.bot.php
sed -i "s/.*->getRoleList();/\$$depts = \$$this->im->loadModel('dept')->getDeptPairs();\n\$$deptList = array_map(function(\$$k, \$$v) {return (object)array('id' => \$$k, 'name' => \$$v);}, array_keys(\$$depts), \$$depts);\n\$$roleList = \$$this->im->lang->user->roleList;/" zentaoxx/extension/xuan/im/ext/bot/default.bot.php
echo "ALTER TABLE \`zt_user\` ADD \`pinyin\` varchar(255) NOT NULL DEFAULT '' AFTER \`realname\`;" >> zentaoxx/db/xuanxuan.sql
find zentaoxx/extension/xuan/ -name '*.php' -exec sed -i -r 's|->ne(["'\'']0000-00-00 00:00:00["'\''])|->notZeroDatetime()|g; s|["'\'']\)->eq\(["'\'']0000-00-00( 00:00:00)?| is null|g; s|([=!]=) ?["'\'']0000-00-00( 00:00:00)?["'\'']|\1 null|g; s|([^!=]=) ?["'\'']0000-00-00( 00:00:00)?["'\'']|\1 null|g; s|(["'\''])(,.*)\)->eq\(["'\'']0000-00-00( 00:00:00)?["'\'']| is null\1\2|g; s|["'\'']0000-00-00 00:00:00["'\'']|null|g' {} +
mkdir zentaoxx/tools; cp tools/cn2tw.php zentaoxx/tools; cd zentaoxx/tools; php cn2tw.php
cp tools/en2other.php zentaoxx/tools; cd zentaoxx/tools; php en2other.php ../
rm -rf zentaoxx/tools
@@ -254,9 +260,9 @@ enrpm:
rpmbuild -ba ~/rpmbuild/SPECS/zentaopms.spec
cp ~/rpmbuild/RPMS/noarch/zentaoalm-${VERSION}-1.noarch.rpm ./
rm -rf ~/rpmbuild
cleanAssets:
find zentaopms/ -type f \( -name "*.js.map" -o -name "*.gz" \) -delete
ciCommon:
make clean
git pull
make common
ifneq ($(XUANPATH), )
@@ -266,14 +272,20 @@ ciCommon:
endif
make package
make cleanAssets
zip -rq -9 ZenTaoPMS.$(VERSION).zip zentaopms
# en
cd zentaopms/; grep -rl 'zentao.net'|xargs sed -i 's/zentao.net/zentao.pm/g';
cd zentaopms/; grep -rl 'http://www.zentao.pm'|xargs sed -i 's/http:\/\/www.zentao.pm/https:\/\/www.zentao.pm/g';
cd zentaopms/config/; echo >> config.php; echo '$$config->isINT = true;' >> config.php
mv zentaopms zentaoalm
zip -r -9 ZenTaoALM.$(VERSION).int.zip zentaoalm
rm -fr zentaoalm
cp -a zentaopms zentaoalm
cd zentaoalm/; grep -rl 'zentao.net'|xargs sed -i 's/zentao.net/zentao.pm/g';
cd zentaoalm/; grep -rl 'http://www.zentao.pm'|xargs sed -i 's/http:\/\/www.zentao.pm/https:\/\/www.zentao.pm/g';
cd zentaoalm/config/; echo >> config.php; echo '$$config->isINT = true;' >> config.php
zip -rq -9 ZenTaoALM.$(VERSION).int.zip zentaoalm
# downgrade
@test "$(DOWNGRADE_ENABLED)" != "true" && echo "skip downgrade" || ./misc/downgrade.sh -p "$(DOWNGRADE_VERSIONS)" -i -r zentaopms -o "$(RELEASE_PATH)" framework/ module/*
rm -fr zentaopms zentaoalm
# move pms zip to build and release path.
rm -f $(BUILD_PATH)/ZenTao*.zip $(RELEASE_PATH)/ZenTaoPMS.$(VERSION).zip $(RELEASE_PATH)/ZenTaoALM.$(VERSION).int.zip
cp ZenTaoPMS.$(VERSION).zip $(BUILD_PATH)
+1 -1
View File
@@ -1 +1 @@
18.4.beta1
18.6
+1 -1
View File
@@ -92,6 +92,6 @@ class bugsEntry extends entry
$bug = $this->loadModel('bug')->getByID($data->id);
return $this->send(200, $this->format($bug, 'activatedDate:time,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,mailto:userList,resolvedBy:user,resolvedDate:time,closedBy:user,closedDate:time,lastEditedBy:user,lastEditedDate:time,deadline:date,deleted:bool'));
return $this->send(201, $this->format($bug, 'activatedDate:time,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,mailto:userList,resolvedBy:user,resolvedDate:time,closedBy:user,closedDate:time,lastEditedBy:user,lastEditedDate:time,deadline:date,deleted:bool'));
}
}
+7 -4
View File
@@ -23,8 +23,8 @@ class buildsEntry extends entry
if(empty($projectID)) $projectID = $this->param('project', 0);
if(empty($projectID)) return $this->sendError(400, "Need project id.");
$control = $this->loadController('project', 'build');
$control->build($projectID, $this->param('type', 'all'), $this->param('param', 0), $this->param('order', 't1.date_desc,t1.id_desc'));
$control = $this->loadController('projectbuild', 'browse');
$control->browse($projectID, $this->param('type', 'all'), $this->param('param', 0), $this->param('order', 't1.date_desc,t1.id_desc'));
$data = $this->getData();
if(!isset($data->status)) return $this->sendError(400, 'error');
@@ -51,7 +51,9 @@ class buildsEntry extends entry
if(!$projectID) $projectID = $this->param('project', 0);
$project = $this->loadModel('project')->getByID($projectID);
if(!$project) return $this->send404();
if(!$project) return $this->sendError(404, 'Error project id');
$this->setPost('project', $projectID);
$fields = 'execution,product,name,builder,date,scmPath,filePath,desc,branch';
$this->batchSetPost($fields);
@@ -59,7 +61,8 @@ class buildsEntry extends entry
$control = $this->loadController('build', 'create');
$this->requireFields('execution,product,name,builder,date');
$control->create(0, 0, $projectID);
$executionID = isset($_POST['execution']) ? $_POST['execution'] : 0;
$control->create($executionID, 0, $projectID);
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
+3 -1
View File
@@ -119,8 +119,10 @@ class executionEntry extends entry
{
$oldExecution = $this->loadModel('execution')->getByID($executionID);
$useCode = $this->checkCodeUsed();
/* Set $_POST variables. */
$fields = 'project,code,name,begin,end,lifetime,desc,days,acl,status,PO,PM,QD,RD';
$fields = 'project,name,begin,end,lifetime,desc,days,acl,status,PO,PM,QD,RD';
if($useCode) $fields .= 'code';
$this->batchSetPost($fields, $oldExecution);
$this->setPost('whitelist', $this->request('whitelist', explode(',', $oldExecution->whitelist)));
+11 -5
View File
@@ -55,8 +55,6 @@ class executionsEntry extends entry
$result = array();
foreach($data->data->executionStats as $execution)
{
foreach($execution->hours as $field => $value) $execution->$field = $value;
$execution = $this->filterFields($execution, 'id,name,project,code,type,parent,begin,end,status,openedBy,openedDate,delay,progress,children,' . $appendFields);
$result[] = $this->format($execution, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,PM:user,PO:user,RD:user,QD:user,whitelist:userList,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool');
}
@@ -80,7 +78,10 @@ class executionsEntry extends entry
*/
public function post($projectID = 0)
{
$fields = 'project,code,name,begin,end,lifetime,desc,days,percent,parent';
$useCode = $this->checkCodeUsed();
$fields = 'project,name,begin,end,lifetime,desc,days,percent,parent';
if($useCode) $fields .= 'code';
$this->batchSetPost($fields);
$projectID = $this->param('project', $projectID);
@@ -94,7 +95,12 @@ class executionsEntry extends entry
$this->setPost('products', $this->request('products', array()));
$this->setPost('plans', $this->request('plans', array()));
$control = $this->loadController('execution', 'create'); $this->requireFields('name,code,begin,end,days');
$control = $this->loadController('execution', 'create');
$requireFields = 'name,begin,end';
if($useCode) $requireFields .= ',code';
$this->requireFields($requireFields);
$control->create($projectID);
$data = $this->getData();
@@ -122,7 +128,7 @@ class executionsEntry extends entry
$account = $this->app->user->account;
$projects = $data->data->projects;
$dropMenu = array('involved' => array(), 'other' => array(), 'closed' => array());
foreach($data->data->executions as $projectID => $projectExecutions)
foreach($data->data->projectExecutions as $projectID => $projectExecutions)
{
foreach($projectExecutions as $execution)
{
+1 -3
View File
@@ -28,10 +28,8 @@ class feedbackEntry extends entry
$feedback = $data->data->feedback;
$feedback->publicStatus = $feedback->public;
$feedback->productName = $data->data->product;
$feedback->productName = is_object($data->data->product) ? $data->data->product->name : $data->data->product;
$feedback->moduleName = isset($data->data->modulePath[0]->name) ? $data->data->modulePath[0]->name : '/';
$feedback->resultType = $data->data->type;
if(isset($feedback->resultInfo) and $feedback->resultInfo->deleted == 0) $feedback->resultStatus = $this->loadModel('feedback')->processStatus($feedback->resultType, $feedback->resultInfo);
if(!$data or !isset($data->status)) return $this->send400('error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
+1
View File
@@ -21,6 +21,7 @@ class feedbacksEntry extends entry
{
if(strpos(strtolower($this->param('fields')), 'moduleandproduct') !== false) return $this->getModuleAndProduct();
$this->app->session->set('feedbackProduct', 'all');
$control = $this->loadController('feedback', 'admin');
$control->admin($this->param('status', 'unclosed'), 0, $this->param('orderBy', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
+2
View File
@@ -30,6 +30,8 @@ class langsEntry extends entry
global $filter;
$rule = $filter->default->moduleName;
if($modules == 'all') $modules = 'upgrade,task,block,testtask,execution,story,project,cron,todo,productplan,release,product,doc,file,customer,action,design,bug,mr,webhook,error,effort,report,programplan,my,search,feedback,score,user,api,program,stakeholder,branch,testcase,meeting,searchObjects,index,dev,personnel,workfloweditor,devops,oa';
$modules = explode(',', $modules);
foreach($modules as $module)
{
+2
View File
@@ -107,10 +107,12 @@ class productEntry extends entry
*/
public function put($productID)
{
$useCode = $this->checkCodeUsed();
$oldProduct = $this->loadModel('product')->getByID($productID);
/* Set $_POST variables. */
$fields = 'program,line,name,PO,QD,RD,type,desc,whitelist,status,acl';
if($useCode) $fields .= ',code';
$this->batchSetPost($fields, $oldProduct);
$control = $this->loadController('product', 'edit');
+1 -1
View File
@@ -85,7 +85,7 @@ class productplansEntry extends entry
$plan = $this->loadModel('productplan')->getByID($data->id);
$plan->stories = array();
$plan->bugs = array();
return $this->send(200, $this->format($plan, 'begin:date,end:date,deleted:bool,project:int'));
return $this->send(201, $this->format($plan, 'begin:date,end:date,deleted:bool,project:int'));
}
$this->sendError(400, array('message' => isset($data->message) ? $data->message : 'error'));
+9 -3
View File
@@ -112,14 +112,20 @@ class productsEntry extends entry
*/
public function post()
{
$fields = 'program,code,line,name,PO,QD,RD,type,desc,whitelist';
$useCode = $this->checkCodeUsed();
$fields = 'program,line,name,PO,QD,RD,type,desc,whitelist';
if($useCode) $fields .= ',code';
$this->batchSetPost($fields);
$this->setPost('acl', $this->request('acl', 'private'));
$this->setPost('whitelist', $this->request('whitelist', array()));
$control = $this->loadController('product', 'create');
$this->requireFields('name,code');
$requireFields = 'name';
if($useCode) $requireFields .= ',code';
$this->requireFields($requireFields);
$control->create($this->request('program', 0));
@@ -130,7 +136,7 @@ class productsEntry extends entry
$product = $this->loadModel('product')->getByID($data->id);
$product = $this->format($product, 'createdDate:time,whitelist:userList,createdBy:user,PO:user,RD:user,QD:user');
return $this->send(200, $product);
return $this->send(201, $product);
}
/**
+3 -1
View File
@@ -45,7 +45,9 @@ class programEntry extends entry
$control = $this->loadController('program', 'edit');
$control->edit($programID);
$this->getData();
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$program = $this->program->getByID($programID);
return $this->send(200, $this->format($program, 'begin:date,end:date,PO:user,PM:user,QD:user,RD:user,realBegan:date,realEnd:date,openedBy:user,openedDate:time,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,deleted:bool,whitelist:userList'));
}
+1 -4
View File
@@ -28,19 +28,16 @@ class programsEntry extends entry
if(stripos(strtolower(",{$fields},"), ",dropmenu,") !== false) return $this->getDropMenu();
$program = $this->loadController('program', 'browse');
$program->browse($this->param('status', 'all'), $this->param('order', 'order_asc'));
$program->browse($this->param('status', 'all'), $this->param('order', 'order_asc'), 0, 10000, 1);
$data = $this->getData();
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$programs = $data->data->programs;
$progressList = $data->data->progressList;
$users = $data->data->users;
$result = array();
foreach($programs as $program)
{
if(isset($progressList->{$program->id})) $program->progress = $progressList->{$program->id};
$program = $this->format($program, 'begin:date,end:date,PO:user,PM:user,QD:user,RD:user,realBegan:date,realEnd:date,openedBy:user,openedDate:time,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,deleted:bool,whitelist:userList');
if($mergeChildren)
+4 -2
View File
@@ -101,8 +101,10 @@ class projectEntry extends entry
$oldProject = $this->loadModel('project')->getByID($projectID);
$linkedProducts = $this->loadModel('product')->getProducts($projectID);
$useCode = $this->checkCodeUsed();
/* Set $_POST variables. */
$fields = 'name,code,begin,end,acl,parent,desc,PM,whitelist,model';
$fields = 'name,begin,end,acl,parent,desc,PM,whitelist,model';
if($useCode) $fields .= ',code';
$this->batchSetPost($fields, $oldProject);
$products = array();
@@ -119,7 +121,7 @@ class projectEntry extends entry
$control->edit($projectID);
$data = $this->getData();
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(isset($data->result) and $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(!isset($data->result)) return $this->sendError(400, 'error');
$project = $this->project->getByID($projectID);
+2 -1
View File
@@ -35,9 +35,10 @@ class projectReleasesEntry extends entry
{
$result = array();
$releases = $data->data->releases;
$pager = $data->data->pager;
foreach($releases as $release) $result[] = $this->format($release, 'deleted:bool,date:date,mailto:userList');
return $this->send(200, array('total' => count($result), 'releases' => $result));
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'releases' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
+8 -4
View File
@@ -48,8 +48,6 @@ class projectsEntry extends entry
$result = array();
foreach($data->data->projectStats as $project)
{
foreach($project->hours as $field => $value) $project->$field = $value;
$result[] = $this->format($project, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,realBegan:date,realEnd:date,PM:user,whitelist:userList,deleted:bool');
}
@@ -79,8 +77,11 @@ class projectsEntry extends entry
{
$fields = 'name,begin,end,products';
$this->batchSetPost($fields);
if(isset($_POST['products'])) $_POST['hasProduct'] = true;
$this->setPost('code', $this->request('code', ''));
$useCode = $this->checkCodeUsed();
if($useCode) $this->setPost('code', $this->request('code', ''));
$this->setPost('acl', $this->request('acl', 'private'));
$this->setPost('parent', $this->request('program', 0));
$this->setPost('whitelist', $this->request('whitelist', array()));
@@ -89,7 +90,10 @@ class projectsEntry extends entry
$this->setPost('parent', $this->request('parent', 0));
$control = $this->loadController('project', 'create');
$this->requireFields('name,code,begin,end,products');
$requireFields = 'name,begin,end,products';
if($useCode) $requireFields .= ',code';
$this->requireFields($requireFields);
$control->create($this->request('model', 'scrum'));
+2 -1
View File
@@ -32,9 +32,10 @@ class releasesEntry extends entry
{
$result = array();
$releases = $data->data->releases;
$pager = $data->data->pager;
foreach($releases as $release) $result[] = $this->format($release, 'deleted:bool,date:date,mailto:userList');
return $this->send(200, array('total' => count($result), 'releases' => $result));
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'releases' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
+2 -2
View File
@@ -162,7 +162,7 @@ class reportsEntry extends entry
$newProject->id = $project->id;
$newProject->name = $project->name;
$newProject->status = $project->status;
$newProject->progress = round($project->hours->progress, 1);
$newProject->progress = isset($project->progress) ? $project->progress : round($project->hours->progress, 1);
$newProject->totalConsumed = round($project->hours->totalConsumed, 1);
$newProject->totalLeft = round($project->hours->totalLeft, 1);
if(isset($project->delay)) $newProject->delay = $project->delay;
@@ -206,7 +206,7 @@ class reportsEntry extends entry
$newExecution->id = $execution->id;
$newExecution->name = $execution->name;
$newExecution->status = $execution->status;
$newExecution->progress = round($execution->hours->progress, 1);
$newExecution->progress = isset($execution->progress) ? $execution->progress : round($execution->hours->progress, 1);
$newExecution->totalConsumed = round($execution->hours->totalConsumed, 1);
$newExecution->totalLeft = round($execution->hours->totalLeft, 1);
if(isset($execution->delay)) $newExecution->delay = $execution->delay;
+1 -1
View File
@@ -92,6 +92,6 @@ class storiesEntry extends entry
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
$story = $this->loadModel('story')->getByID($data->id);
return $this->send(200, $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
return $this->send(201, $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
}
}
+2 -2
View File
@@ -104,8 +104,8 @@ class storyEntry extends entry
$data = $this->getData();
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(!isset($data->status)) return $this->sendError(400, 'error');
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
if(!isset($data->result)) return $this->sendError(400, 'error');
$story = $this->story->getByID($storyID);
return $this->send(200, $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
+4 -3
View File
@@ -28,17 +28,18 @@ class taskFinishEntry extends entry
$fields = 'finishedDate,comment';
$this->batchSetPost($fields);
$realStarted = $this->request('realStarted', (isset($task->realStarted) and !helper::isZeroDate($task->realStarted)) ? $task->realStarted : '');
if($realStarted) $this->setPost('realStarted', $realStarted);
$this->setPost('currentConsumed', $this->request('currentConsumed', 0));
$this->setPost('consumed', $this->request('currentConsumed', 0) + $task->consumed);
$control = $this->loadController('task', 'finish');
$this->requireFields('assignedTo,currentConsumed,realStarted,finishedDate');
$this->requireFields('currentConsumed,realStarted,finishedDate');
$control->finish($taskID);
$data = $this->getData();
if(!$data) return $this->send400('error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(isset($data->result) and $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$task = $this->loadModel('task')->getByID($taskID);
+1 -1
View File
@@ -30,7 +30,7 @@ class taskPauseEntry extends entry
$data = $this->getData();
if(!$data) return $this->send400('error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$task = $this->loadModel('task')->getByID($taskID);
+1 -1
View File
@@ -52,7 +52,7 @@ class taskRecordEstimateEntry extends entry
{
if($this->loadModel('effort'))
{
$fields = 'id,dates,consumed,left,objectType,objectID,work';
$fields = 'id,dates,consumed,left,objectType,objectID,work,date';
$this->batchSetPost($fields);
$control = $this->loadController('effort', 'createForObject');
$control->createForObject('task', $taskID);
+1 -1
View File
@@ -34,7 +34,7 @@ class taskRestartEntry extends entry
$data = $this->getData();
if(!$data) return $this->send400('error');
if(isset($data->result) and $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$task = $this->loadModel('task')->getByID($taskID);
+3 -2
View File
@@ -104,8 +104,9 @@ class tasksEntry extends entry
$fields = 'name,type,assignedTo,estimate,story,execution,project,module,pri,desc,estStarted,deadline,mailto,team,teamEstimate,multiple,uid';
$this->batchSetPost($fields);
$assignedTo = $this->request('assignedTo');
if($assignedTo and !is_array($assignedTo)) $this->setPost('assignedTo', array($assignedTo));
$assignedTo = $this->request('assignedTo', array(0 => ''));
if($assignedTo and !is_array($assignedTo)) $assignedTo = array($assignedTo);
$this->setPost('assignedTo', $assignedTo);
if($this->request('multiple'))
{
if(count($this->request('team')) != count($this->request('teamEstimate'))) return $this->sendError(400, 'Arrays team and teamEstimate should be the same length');
+4 -4
View File
@@ -22,17 +22,17 @@ class taskStartEntry extends entry
{
$task = $this->loadModel('task')->getByID($taskID);
$fields = 'assignedTo,realStarted,consumed,left,comment';
$fields = 'assignedTo,consumed,left,comment';
$this->batchSetPost($fields);
$this->setPost('realStarted', $this->request('realStarted', helper::now()));
$control = $this->loadController('task', 'start');
$this->requireFields('left');
$control->start($taskID);
$data = $this->getData();
if(!$data) return $this->send400('error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(isset($data->result) and $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$task = $this->loadModel('task')->getByID($taskID);
+4 -4
View File
@@ -166,7 +166,7 @@ class userEntry extends entry
{
$myExecutions['owner'] = array();
$myExecutions['other'] = array();
foreach($data->data->executions as $projectID => $projectExecutions)
foreach($data->data->projectExecutions as $projectID => $projectExecutions)
{
foreach($projectExecutions as $execution)
{
@@ -298,7 +298,7 @@ class userEntry extends entry
$info->issue = array('total' => 0, 'issues' => array());
if(!common::hasPriv('my', 'work')) break;
if($this->config->edition == 'max')
if($this->config->edition == 'max' or $this->config->edition == 'ipd')
{
global $app;
$app->rawMethod = 'work';
@@ -318,7 +318,7 @@ class userEntry extends entry
$info->risk = array('total' => 0, 'risks' => array());
if(!common::hasPriv('my', 'work')) break;
if($this->config->edition == 'max')
if($this->config->edition == 'max' or $this->config->edition == 'ipd')
{
global $app;
$app->rawMethod = 'work';
@@ -338,7 +338,7 @@ class userEntry extends entry
$info->meeting = array('total' => 0, 'meetings' => array());
if(!common::hasPriv('my', 'work')) break;
if($this->config->edition == 'max')
if($this->config->edition == 'max' or $this->config->edition == 'ipd')
{
global $app;
$app->rawMethod = 'work';
+18
View File
@@ -64,6 +64,24 @@ class ztfSubmitEntry extends baseEntry
->set('ZTFResult')->eq(json_encode($post))
->where('id')->eq($post->task)
->exec();
$result = $this->dao->select('*')->from(TABLE_TESTRESULT)
->where('id')->eq($post->task)
->fetch();
if($result->run)
{
$runStatus = $result->caseResult == 'blocked' ? 'blocked' : 'normal';
$this->dao->update(TABLE_TESTRUN)
->set('lastRunResult')->eq($result->caseResult)
->set('status')->eq($runStatus)
->set('lastRunner')->eq($result->lastRunner)
->set('lastRunDate')->eq($result->date)
->where('id')->eq($result->run)
->exec();
}
$this->dao->update(TABLE_CASE)->set('lastRunner')->eq($result->lastRunner)->set('lastRunDate')->eq($result->date)->set('lastRunResult')->eq($result->caseResult)->where('id')->eq($result->case)->exec();
}
else
{
+54
View File
@@ -0,0 +1,54 @@
<?php
chdir(dirname(dirname(dirname(__FILE__))));
include './framework/router.class.php';
include './framework/control.class.php';
include './framework/model.class.php';
include './framework/helper.class.php';
$app = router::createApp('pms', dirname(dirname(dirname(__FILE__))), 'router');
$cacheConfig = $app->config->cache;
if(!$cacheConfig->enable && !$cacheConfig->enableFullPage)
{
echo 'Cache is disabled.', PHP_EOL;
exit;
}
function traverseDirectory($directory, &$cleanNum)
{
$files = glob($directory . DS . '*.cache');
foreach($files as $file)
{
$result = viewFileContent($file);
if(!$result) $cleanNum ++;
}
$subdirectories = glob($directory . DS . '*', GLOB_ONLYDIR);
foreach($subdirectories as $subdirectory) traverseDirectory($subdirectory, $cleanNum);
}
function isExpired($payload)
{
if(is_null($payload['time'])) return false;
return time() > $payload['time'];
}
function viewFileContent($file)
{
$content = file_get_contents($file);
$content = unserialize($content);
if(isExpired($content))
{
unlink($file);
return false;
}
return true;
}
$cleanNum = 0;
traverseDirectory(rtrim($app->getCacheRoot(), DS), $cleanNum);
echo "Cleaned {$cleanNum} cache files.", PHP_EOL;
+29
View File
@@ -0,0 +1,29 @@
{
"pkg": {
"xuanxuan": {
"gitVersion": "e08cd0387cbfcf4cbc28b3b3e829683066ee3bc7",
"version": "7.2.1"
},
"zentaoext": {
"gitVersion": "18.x",
"gitRepo": "https://git.zcorp.cc/easycorp/zentaoext.git"
},
"zdoo": {
"gitVersion": "master"
},
"zdooext": {
"gitVersion": "master"
}
},
"downgrade": {
"enabled": false,
"versions": "7.2,7.1,7.0,5.4"
},
"upload": {
"bucket": "download"
},
"notice": {
"users": "qishiyao,hufangzhou",
"groups": "84be4c6e-02e3-4fdc-b081-318c0c1eca02,31a0008b-6e3e-4b7f-9b7b-396a46b1f8f4"
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
/* 缓存设置。Cache settings. */
$config->cache = new stdclass();
$config->cache->enable = false; // 是否开启缓存。Enable cache or not.
$config->cache->lifetime = 5 * 60; // 缓存生存时间。The lifetime of cache.
$config->cache->driver = 'File'; // 缓存驱动。 The driver of cache. can be File|Yac|Apcu.
$config->cache->enableFullPage = false; // 是否开启整页缓存。Enable full page cache or not.
$config->cache->fullPageLifetime = 5 * 60;
$config->cache->fullPageDriver = 'File';
$config->cache->fullPages = array(); // 需要整页缓存的页面,格式为:模块名|方法名。模块和方法名都是小写。The pages need to be cached, format: module|method. Both module and method are lowercase.
$config->cache->fullPages[] = 'program|browse';
$config->cache->fullPages[] = 'product|all';
$config->cache->fullPages[] = 'project|browse';
$config->cache->fullPages[] = 'block|printblock';
$config->cache->fullPages[] = 'screen|view';
$config->cacheKeys = new stdclass();
$config->cacheKeys->block = new stdclass();
$config->cacheKeys->block->welcome = 'welcome';
$config->cacheKeys->block->contribute = 'contribute';
$config->cacheKeys->block->projectStatistic = 'projectStatistic%s%s%s';
$config->cacheKeys->block->recentProject = 'recentProject';
$config->cacheKeys->execution = new stdclass();
$config->cacheKeys->execution->ajaxGetDropMenuProjects = 'ajaxDropMenuProjects';
$config->cacheKeys->execution->ajaxGetDropMenuExecutions = 'ajaxDropMenuExecutions';
$config->cacheKeys->bug = new stdclass();
$config->cacheKeys->bug->browse = 'bugBrowse%s';
+9 -8
View File
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
if(!function_exists('getWebRoot')){function getWebRoot(){}}
/* 基本设置。Basic settings. */
$config->version = '18.4.beta1'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->version = '18.6'; // 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.
@@ -34,7 +34,7 @@ $config->methodVar = 'f'; // 请求类型为GET:模块
$config->viewVar = 't'; // 请求类型为GET:视图变量名。 requestType=GET: the view var name.
$config->sessionVar = 'zentaosid'; // 请求类型为GET:session变量名。 requestType=GET: the session var name.
$config->views = ',html,json,mhtml,xhtml,'; // 支持的视图类型。 Supported view formats.
$config->visions = ',rnd,lite,'; // 支持的界面类型。 Supported vision formats.
$config->visions = ',or,rnd,lite,'; // 支持的界面类型。 Supported vision formats.
/* 支持的主题和语言。Supported thems and languages. */
$config->themes['default'] = 'default';
@@ -71,12 +71,6 @@ $config->slaveDB->driver = 'mysql';
$config->slaveDB->encoding = 'UTF8';
$config->slaveDB->strictMode = false;
/* 缓存设置。Cache settings. */
$config->cache = new stdclass();
$config->cache->enable = false; // 是否开启缓存。Enable cache or not.
$config->cache->lifetime = 5 * 60; // 缓存生存时间。The lifetime of cache.
$config->cache->driver = 'File'; // 缓存驱动。 The driver of cache. can be File|Yac|Apcu.
/* 可用域名后缀列表。Domain postfix lists. */
$config->domainPostfix = "|com|com.cn|com.hk|com.tw|com.vc|edu.cn|es|";
$config->domainPostfix .= "|eu|fm|gov.cn|gs|hk|im|in|info|jp|kr|la|me|";
@@ -167,6 +161,7 @@ $config->wideSize = 1400;
$config->timeout = 30000;
$config->duplicateTime = 30;
$config->maxCount = 500;
$config->batchMaxCount = 20;
$config->moreLinks = array();
/* 配置参数过滤。Filter param settings. */
@@ -177,6 +172,10 @@ if(file_exists($filterConfig)) include $filterConfig;
$dbConfig = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'db.php';
if(file_exists($dbConfig)) include $dbConfig;
/* 引用缓存的配置。 Include the cache config file. */
$cacheConfig = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'cache.php';
if(file_exists($cacheConfig)) include $cacheConfig;
/* 引用自定义的配置。 Include the custom config file. */
$myConfig = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'my.php';
if(file_exists($myConfig)) include $myConfig;
@@ -198,9 +197,11 @@ if($config->edition != 'open')
{
$config->version = $config->edition . $config->{$config->edition . 'Version'};
if($config->edition != 'max') unset($config->maxVersion);
if($config->edition != 'ipd') unset($config->ipdVersion);
}
else
{
unset($config->bizVersion);
unset($config->maxVersion);
unset($config->ipdVersion);
}
+10
View File
@@ -21,6 +21,7 @@ $filter->default->paramValue = 'reg::paramValue';
$filter->default->get['onlybody'] = 'equal::yes';
$filter->default->get['_single'] = 'equal::1';
$filter->default->get['_nocache'] = 'equal::1';
$filter->default->get['tid'] = 'reg::word';
$filter->default->get['HTTP_X_REQUESTED_WITH'] = 'equal::XMLHttpRequest';
@@ -85,6 +86,8 @@ $filter->bug->browse = new stdclass();
$filter->bug->default = new stdclass();
$filter->bug->create = new stdclass();
$filter->bug->export = new stdclass();
$filter->bug->ajaxgetproductcases = new stdclass();
$filter->bug->ajaxgetproductbugs = new stdclass();
$filter->caselib->create = new stdclass();
$filter->doc->create = new stdclass();
$filter->doc->browse = new stdclass();
@@ -300,6 +303,7 @@ $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->project->execution->cookie['showStage'] = 'code';
$filter->project->testcase->cookie['showAutoCase'] = 'int';
$filter->project->testcase->cookie['onlyScene'] = 'code';
@@ -466,3 +470,9 @@ $filter->tree->browse->cookie['preBranch'] = 'reg::word';
$filter->kanban->space->cookie['showClosed'] = 'code';
$filter->group->editmanagepriv->cookie['managePrivEditType'] = 'string';
$filter->bug->ajaxgetproductcases->get['search'] = 'reg::any';
$filter->bug->ajaxgetproductcases->get['limit'] = 'int';
$filter->bug->ajaxgetproductbugs->get['search'] = 'reg::any';
$filter->bug->ajaxgetproductbugs->get['limit'] = 'int';
+1
View File
@@ -34,6 +34,7 @@ $routes['/configurations/:name'] = 'config';
$routes['/programs/:id/products'] = 'products';
$routes['/products'] = 'products';
$routes['/products/:id'] = 'product';
$routes['/product/:id'] = 'product';
$routes['/productlines'] = 'productLines';
$routes['/productlines/:id'] = 'productLine';
+3 -3
View File
@@ -197,6 +197,7 @@ $config->openMethods[] = 'misc.checkupdate';
$config->openMethods[] = 'misc.ping';
$config->openMethods[] = 'misc.captcha';
$config->openMethods[] = 'misc.features';
$config->openMethods[] = 'misc.getremind';
$config->openMethods[] = 'sso.login';
$config->openMethods[] = 'sso.logout';
$config->openMethods[] = 'sso.bind';
@@ -316,6 +317,7 @@ define('TABLE_API_LIB_RELEASE', '`' . $config->db->prefix . 'api_lib_release`');
define('TABLE_MODULE', '`' . $config->db->prefix . 'module`');
define('TABLE_ACTION', '`' . $config->db->prefix . 'action`');
define('TABLE_ACTIONRECENT', '`' . $config->db->prefix . 'actionrecent`');
define('TABLE_FILE', '`' . $config->db->prefix . 'file`');
define('TABLE_HOLIDAY', '`' . $config->db->prefix . 'holiday`');
define('TABLE_HISTORY', '`' . $config->db->prefix . 'history`');
@@ -369,9 +371,6 @@ define('TABLE_DATASET', '`' . $config->db->prefix . 'dataset`');
define('TABLE_DATAVIEW', '`' . $config->db->prefix . 'dataview`');
define('TABLE_DIMENSION', '`' . $config->db->prefix . 'dimension`');
define('TABLE_SCENE', '`' . $config->db->prefix . 'scene`');
define('VIEW_SCENECASE', '`ztv_scenecase`');
define('CHANGEVALUE', 100000000);
define('TABLE_PRIV', '`' . $config->db->prefix . 'priv`');
define('TABLE_PRIVLANG', '`' . $config->db->prefix . 'privlang`');
@@ -455,6 +454,7 @@ $config->programPriv->scrum = array('story', 'requirement', 'productplan
$config->programPriv->waterfall = array_merge($config->programPriv->scrum, array('workestimation', 'durationestimation', 'budget', 'programplan', 'review', 'reviewissue', 'weekly', 'cm', 'milestone', 'design', 'issue', 'risk', 'opportunity', 'measrecord', 'auditplan', 'trainplan', 'gapanalysis', 'pssp', 'researchplan', 'researchreport'));
$config->programPriv->agileplus = $config->programPriv->scrum;
$config->programPriv->waterfallplus = $config->programPriv->waterfall;
$config->programPriv->ipd = $config->programPriv->waterfall;
$config->safeFileTimeout = 3600;
$config->waterfallModules = array('workestimation', 'durationestimation', 'budget', 'programplan', 'review', 'reviewissue', 'weekly', 'cm', 'milestone', 'design', 'opportunity', 'auditplan', 'trainplan', 'gapanalysis', 'pssp', 'researchplan', 'researchreport');
+2 -2
View File
@@ -383,8 +383,8 @@ INSERT INTO `zt_product` (`id`, `program`, `name`, `code`, `bind`, `line`, `type
INSERT INTO `zt_productplan` (`id`, `product`, `branch`, `parent`, `title`, `desc`, `begin`, `end`, `order`, `deleted`, `createdBy`, `createdDate`) VALUES
(1, 1, 0, 0, '1.0版本', '开发出企业网站1.0版本。<br />', '2020-06-05', '2021-06-04', '', '0', 'tester1', '2021-04-01 11:08:09');
INSERT INTO `zt_project` (`id`, `project`, `model`, `type`, `lifetime`, `budget`, `budgetUnit`, `attribute`, `percent`, `milestone`, `output`, `auth`, `parent`, `path`, `grade`, `name`, `code`, `begin`, `end`, `realBegan`, `realEnd`, `days`, `status`, `subStatus`, `pri`, `desc`, `version`, `parentVersion`, `planDuration`, `realDuration`, `openedBy`, `openedDate`, `openedVersion`, `lastEditedBy`, `lastEditedDate`, `closedBy`, `closedDate`, `canceledBy`, `canceledDate`, `PO`, `PM`, `QD`, `RD`, `team`, `acl`, `whitelist`, `order`, `deleted`) VALUES
(1, 7, '', 'sprint', 'long', '0', 'CNY', '', 0, '0', '', '', 7, ',7,1,', 1, '企业网站第一期', 'coWeb1', '2020-06-05', '2021-12-04', '0000-00-00', '0000-00-00', 391, 'doing', '', '1', '开发企业网站的基本雏形。<br />', 0, 0, 0, 0, '', '0000-00-00 00:00:00', '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', 'productManager', 'projectManager', 'testManager', 'productManager', '公司开发团队', 'open', '', 5, '0'),
(2, 7, '', 'sprint', 'long', '0', 'CNY', '', 0, '0', '', '', 7, ',7,2,', 1, '企业网站第二期', 'coWebsite2', '2021-06-05', '2022-06-04', '0000-00-00', '0000-00-00', 260, 'wait', '', '1', '', 0, 0, 0, 0, '', '0000-00-00 00:00:00', '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', 'productManager', 'projectManager', 'testManager', 'productManager', '公司开发团队', 'open', '', 10, '0'),
(1, 7, '', 'sprint', 'long', '0', 'CNY', '', 0, '0', '', '', 7, ',7,1,', 1, '企业网站第一期', 'coWeb1', '2020-06-05', '2021-12-04', '0000-00-00', '0000-00-00', 391, 'doing', '', '1', '开发企业网站的基本雏形。<br />', 0, 0, 0, 0, '', '0000-00-00 00:00:00', '15.0.rc3', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', 'productManager', 'projectManager', 'testManager', 'productManager', '公司开发团队', 'open', '', 5, '0'),
(2, 7, '', 'sprint', 'long', '0', 'CNY', '', 0, '0', '', '', 7, ',7,2,', 1, '企业网站第二期', 'coWebsite2', '2021-06-05', '2022-06-04', '0000-00-00', '0000-00-00', 260, 'wait', '', '1', '', 0, 0, 0, 0, '', '0000-00-00 00:00:00', '15.0.rc3', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', 'productManager', 'projectManager', 'testManager', 'productManager', '公司开发团队', 'open', '', 10, '0'),
(7, 0, 'scrum', 'project', '', '0', 'CNY', '', 0, '0', '', 'extend', 6, ',6,7,', 2, '企业管理系统', '', '2021-06-05', '2022-06-04', '0000-00-00', '0000-00-00', 0, 'doing', '', '1', '', 0, 0, 0, 0, 'admin', '2021-04-28 11:22:04', '15.0.rc3', 'admin', '2021-04-28 11:22:04', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 'projectManager', '', '', '', 'open', ',tester3,admin', 35, '0'),
(6, 0, '', 'program', '', '0', 'CNY', '', 0, '0', '', '', 0, ',6,', 1, '企业管理', '', '2021-06-05', '2022-06-04', '0000-00-00', '0000-00-00', 0, 'doing', '', '1', '', 0, 0, 0, 0, 'admin', '2021-04-28 11:22:04', '15.0.rc3', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '', '', '', '', 'open', '', 30, '0');
INSERT INTO `zt_projectcase` (`project`, `product`, `case`, `count`, `version`, `order`) VALUES
+4
View File
@@ -0,0 +1,4 @@
TRUNCATE TABLE `zt_pivot`;
TRUNCATE TABLE `zt_chart`;
TRUNCATE TABLE `zt_basicmeas`;
DELETE FROM `zt_screen` WHERE id IN (1,2,4,6,7,8);
File diff suppressed because it is too large Load Diff
+14 -1
View File
@@ -727,7 +727,7 @@ CREATE TABLE `zt_cron` (
`lastTime` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `lastTime` (`lastTime`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
CREATE TABLE `zt_dashboard` (
`id` mediumint(8) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
@@ -2148,6 +2148,19 @@ CREATE TABLE `zt_product` (
`acl` enum('open','private','custom') NOT NULL DEFAULT 'open',
`whitelist` text NOT NULL,
`reviewer` text NOT NULL,
`draftStories` mediumint(8) NOT NULL DEFAULT '0',
`activeStories` mediumint(8) NOT NULL DEFAULT '0',
`changingStories` mediumint(8) NOT NULL DEFAULT '0',
`reviewingStories` mediumint(8) NOT NULL DEFAULT '0',
`closedStories` mediumint(8) NOT NULL DEFAULT '0',
`totalStories` mediumint(8) NOT NULL DEFAULT '0',
`unresolvedBugs` mediumint(8) NOT NULL DEFAULT '0',
`closedBugs` mediumint(8) NOT NULL DEFAULT '0',
`fixedBugs` mediumint(8) NOT NULL DEFAULT '0',
`totalBugs` mediumint(8) NOT NULL DEFAULT '0',
`plans` mediumint(8) NOT NULL DEFAULT '0',
`releases` mediumint(8) NOT NULL DEFAULT '0',
`finishedStories` mediumint(9) NOT NULL DEFAULT '0',
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`createdVersion` varchar(20) NOT NULL,
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+5 -2
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+42
View File
@@ -0,0 +1,42 @@
INSERT INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type`, `buildin`, `status`) VALUES ('0','*','*','*','*','moduleName=misc&methodName=cleanCache', '清理缓存文件','zentao', 1, 'normal');
ALTER TABLE `zt_product`
ADD `draftStories` mediumint(8) NOT NULL DEFAULT '0' AFTER `reviewer`,
ADD `activeStories` mediumint(8) NOT NULL DEFAULT '0' AFTER `draftStories`,
ADD `changingStories` mediumint(8) NOT NULL DEFAULT '0' AFTER `activeStories`,
ADD `reviewingStories` mediumint(8) NOT NULL DEFAULT '0' AFTER `changingStories`,
ADD `finishedStories` mediumint NOT NULL DEFAULT '0' AFTER `reviewingStories`,
ADD `closedStories` mediumint(8) NOT NULL DEFAULT '0' AFTER `finishedStories`,
ADD `totalStories` mediumint(8) NOT NULL DEFAULT '0' AFTER `closedStories`,
ADD `unresolvedBugs` mediumint(8) NOT NULL DEFAULT '0' AFTER `totalStories`,
ADD `closedBugs` mediumint(8) NOT NULL DEFAULT '0' AFTER `unresolvedBugs`,
ADD `fixedBugs` mediumint(8) NOT NULL DEFAULT '0' AFTER `closedBugs`,
ADD `totalBugs` mediumint(8) NOT NULL DEFAULT '0' AFTER `fixedBugs`,
ADD `plans` mediumint(8) NOT NULL DEFAULT '0' AFTER `totalBugs`,
ADD `releases` mediumint(8) NOT NULL DEFAULT '0' AFTER `plans`;
UPDATE `zt_pivot` SET `sql` = 'SELECT \n t1.name AS \'产品\', \n IFNULL(t2.name, \'/\') AS \'一级项目集\', \n IFNULL(t3.name, \'/\') AS \'产品线\', \n IFNULL(t6.exfixedstorys, 0) AS \'研发完成需求数\', \n round(IFNULL(t6.exfixedstorysmate, 0),3) AS \'研发完成需求规模数\',\n IFNULL(t8.storycases, 0) AS \'需求用例数\',\n round(storycases/exfixedstorysmate,3) AS \'用例密度\',\n round(IFNULL(t10.casestorys/t6.exfixedstorys,0),3) AS \'用例覆盖率\',\n IFNULL(t7.bug, 0) AS \'Bug数\',\n IFNULL(t7.effbugs, 0) AS \'有效Bug数\',\n IFNULL(t7.pri12bugs, 0) AS \'优先级为1,2的Bug数\',\n round(bug/exfixedstorysmate,3) AS \'Bug密度\',\n IFNULL(t7.fixedbugs, 0) AS \'修复Bug数\',\n round(t7.fixedbugs/bug,3) \'Bug修复率\'\nFROM \n zt_product AS t1 \n LEFT JOIN zt_project AS t2 ON t1.program = t2.id AND t2.type = \'program\' AND t2.grade = 1 \n LEFT JOIN zt_module AS t3 ON t1.line = t3.id AND t3.type = \'line\' \n LEFT JOIN (\n SELECT\n product, \n count(id) exfixedstorys, \n sum(estimate) exfixedstorysmate\n FROM zt_story \n WHERE deleted = \'0\' and (stage in (\'developed\',\'testing\',\'verfied\',\'released\') or (status=\'closed\' and closedReason=\'done\'))\n GROUP BY product) AS t6 ON t1.id = t6.product \n LEFT JOIN (SELECT product, COUNT(id) AS bug,\n SUM(case when resolution in (\'fixed\',\'postponed\') or status=\'active\' then 1 else 0 end) effbugs, \n SUM(CASE WHEN resolution=\'fixed\' then 1 else 0 end) fixedbugs,\n SUM(CASE WHEN severity in (1,2) then 1 else 0 end) pri12bugs\n FROM zt_bug WHERE deleted = \'0\' GROUP BY product) AS t7 ON t1.id = t7.product \n LEFT JOIN (SELECT product, COUNT(id) AS storycases FROM zt_case WHERE deleted=\'0\' GROUP BY product) AS t8 ON t1.id=t8.product\n LEFT JOIN (\n select \n t9.product, \n count(t9.story) casestorys\n from(\n SELECT \n zt_case.product,zt_case.story \n FROM zt_case \n left join zt_story\n on zt_case.story=zt_story.id\n WHERE zt_case.deleted=\'0\' and zt_case.story !=\'0\' and zt_story.deleted=\'0\' and (zt_story.stage in (\'developed\',\'testing\',\'verfied\',\'released\') or (zt_story.status=\'closed\' and zt_story.closedReason=\'done\'))\n GROUP BY product, story) t9\n group by product) t10\n on t1.id=t10.product\nWHERE t1.deleted = \'0\' AND t1.status != \'closed\' AND t1.shadow = \'0\'AND t1.vision = \'rnd\'\nORDER BY t1.order'
WHERE id = 1002;
UPDATE `zt_chart` SET `settings` = '{\"value\": {\"type\": \"agg\", \"field\": \"taskleft\", \"agg\": \"sum\"}, \"title\": {\"type\": \"text\", \"name\": \"\"}, \"type\": \"value\"}'
WHERE id = 10112;
UPDATE `zt_priv` SET `edition`=',biz,max,ipd,' where `module`='feedback' and `method`='toUserStory';
UPDATE `zt_pivot` SET `stage` = 'published', `sql` = 'select t1.id,t3.name as project,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t2.id as bugID,t2.type from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution\r\nleft join zt_project as t3 on t3.id=t1.project\r\nwhere t1.deleted=\'0\' and t2.deleted=\'0\' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)'
WHERE `sql` = 'select t1.id,t3.name as project,t3.id,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t2.id as bugID,t2.type from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution\r\nleft join zt_project as t3 on t3.id=t1.project\r\nwhere t1.deleted=\'0\' and t2.deleted=\'0\' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)';
UPDATE `zt_pivot` SET `stage` = 'published', `sql` = 'select t1.id,t4.name as project,IF(t4.multiple=\"1\",t1.name,\"\") as execution,t1.status,t2.number as tasks,round(t2.consumed,2) as consumed,round(t2.`left`,2) as `left`,t3.stories,t2.undone as undoneTask,t3.undone as undoneStory,t2.totalReal from zt_project as t1 \r\nleft join ztv_executionsummary as t2 on t1.id=t2.execution\r\nleft join ztv_projectstories as t3 on t1.id=t3.execution\r\nleft join zt_project as t4 on t4.id=t1.project\r\nwhere t1.deleted=\'0\' and t1.type in (\'sprint\',\'stage\') and if($project=\'\',1,t4.id=$project) and if($execution=\'\',1,t1.id=$execution) and if($status=\'\',1,t1.status=$status)'
WHERE `sql` = 'select t1.id,t4.name as project,t4.id,IF(t4.multiple=\"1\",t1.name,\"\") as execution,t1.status,t2.number as tasks,round(t2.consumed,2) as consumed,round(t2.`left`,2) as `left`,t3.stories,t2.undone as undoneTask,t3.undone as undoneStory,t2.totalReal from zt_project as t1 \r\nleft join ztv_executionsummary as t2 on t1.id=t2.execution\r\nleft join ztv_projectstories as t3 on t1.id=t3.execution\r\nleft join zt_project as t4 on t4.id=t1.project\r\nwhere t1.deleted=\'0\' and t1.type in (\'sprint\',\'stage\') and if($project=\'\',1,t4.id=$project) and if($execution=\'\',1,t1.id=$execution) and if($status=\'\',1,t1.status=$status)';
UPDATE `zt_pivot` SET `stage` = 'published', `sql` = 'select t1.id, t5.name as project,IF(t5.multiple=\"1\",t1.name,\"\") as execution,t2.stories,(t2.stories-t2.undone) as doneStory,t3.number,(t3.number-t3.undone) as doneTask,t4.bugs,t4.resolutions, round(t4.bugs/(t2.stories-t2.undone),2) as bugthanstory,round(t4.bugs/(t3.number-t3.undone),2) as bugthantask,t4.seriousBugs from zt_project as t1 \r\nleft join ztv_projectstories as t2 on t1.id=t2.execution\r\nleft join ztv_executionsummary as t3 on t1.id=t3.execution\r\nleft join ztv_projectbugs as t4 on t1.id=t4.execution\r\nleft join zt_project as t5 on t5.id=t1.project\r\nwhere t1.deleted=\'0\' and t1.type in (\'sprint\',\'stage\') and t1.grade=\'1\' and if($project=\'\',1,t5.id=$project) and if($execution=\'\',1,t1.id=$execution)'
WHERE `sql` = 'select t1.id, t5.name as project,t5.id,IF(t5.multiple=\"1\",t1.name,\"\") as execution,t2.stories,(t2.stories-t2.undone) as doneStory,t3.number,(t3.number-t3.undone) as doneTask,t4.bugs,t4.resolutions, round(t4.bugs/(t2.stories-t2.undone),2) as bugthanstory,round(t4.bugs/(t3.number-t3.undone),2) as bugthantask,t4.seriousBugs from zt_project as t1 \r\nleft join ztv_projectstories as t2 on t1.id=t2.execution\r\nleft join ztv_executionsummary as t3 on t1.id=t3.execution\r\nleft join ztv_projectbugs as t4 on t1.id=t4.execution\r\nleft join zt_project as t5 on t5.id=t1.project\r\nwhere t1.deleted=\'0\' and t1.type in (\'sprint\',\'stage\') and t1.grade=\'1\' and if($project=\'\',1,t5.id=$project) and if($execution=\'\',1,t1.id=$execution)';
UPDATE `zt_pivot` SET `stage` = 'published', `sql` = 'select t1.id,t3.name as project,t3.id as projectID,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t1.id as bugID,t2.assignedTo from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution \r\nleft join zt_project as t3 on t3.id=t1.project\r\nwhere t1.deleted=\'0\' and t2.deleted=\'0\' having bugID!=\'\' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)'
WHERE `sql` = 'select t1.id,t3.name as project,t3.id,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t1.id as bugID,t2.assignedTo from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution \r\nleft join zt_project as t3 on t3.id=t1.project\r\nwhere t1.deleted=\'0\' and t2.deleted=\'0\' having bugID!=\'\' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)';
UPDATE `zt_pivot` SET `stage` = 'published', `sql` = 'select t1.id,t3.name as project,t3.id as projectID,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t1.id as bugID,t2.resolvedBy from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution\r\nleft join zt_project as t3 on t3.id=t1.project\r\nwhere t1.deleted=\'0\' and t2.deleted=\'0\' and t2.status!=\'active\' and t2.resolvedBy!=\'\' having bugID!=\'\' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)'
WHERE `sql` = 'select t1.id,t3.name as project,t3.id,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t1.id as bugID,t2.resolvedBy from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution\r\nleft join zt_project as t3 on t3.id=t1.project\r\nwhere t1.deleted=\'0\' and t2.deleted=\'0\' and t2.status!=\'active\' and t2.resolvedBy!=\'\' having bugID!=\'\' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)';
UPDATE `zt_pivot` SET `stage` = 'published', `sql` = 'select t1.id,t3.name as project,t3.id as projectID,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t1.id as bugID,t2.openedBy from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution\r\nleft join zt_project as t3 on t3.id=t1.project\r\nwhere t1.deleted=\'0\' and t2.deleted=\'0\' having bugID!=\'\' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)'
WHERE `sql` = 'select t1.id,t3.name as project,t3.id,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t1.id as bugID,t2.openedBy from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution\r\nleft join zt_project as t3 on t3.id=t1.project\r\nwhere t1.deleted=\'0\' and t2.deleted=\'0\' having bugID!=\'\' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)';
UPDATE `zt_pivot` SET `stage` = 'published', `sql` = 'select t1.id,t3.name as project,t3.id as projectID,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t1.id as bugID,t2.status from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution\r\nleft join zt_project as t3 on t3.id=t1.project\r\nwhere t1.deleted=\'0\' and t2.deleted=\'0\' having bugID!=\' \' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)'
WHERE `sql` = 'select t1.id,t3.name as project,t3.id,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t1.id as bugID,t2.status from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution\r\nleft join zt_project as t3 on t3.id=t1.project\r\nwhere t1.deleted=\'0\' and t2.deleted=\'0\' having bugID!=\' \' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)';
UPDATE `zt_pivot` SET `stage` = 'published', `sql` = 'select t1.id,t3.name as project,t3.id as projectID,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t1.id as bugID,t2.resolution from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution\r\nleft join zt_project as t3 on t3.id=t1.project\r\n where t1.deleted=\'0\' and t2.deleted=\'0\' and t2.resolution!=\'\' having bugID!=\'\' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)'
WHERE `sql` = 'select t1.id,t3.name as project,t3.id,IF(t3.multiple=\"1\",t1.name,\"\") as execution,t1.id as bugID,t2.resolution from zt_project as t1 \r\nleft join zt_bug as t2 on t1.id=t2.execution\r\nleft join zt_project as t3 on t3.id=t1.project\r\n where t1.deleted=\'0\' and t2.deleted=\'0\' and t2.resolution!=\'\' having bugID!=\'\' and if($project=\'\',1,t3.id=$project) and if($execution=\'\',1,t1.id=$execution)';
UPDATE `zt_chart` SET `createdBy` = 'admin' WHERE `id` <= 1110;
+56
View File
@@ -0,0 +1,56 @@
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('traincourse', 'cloudImport', '125', ',biz,max,ipd,', ',rnd,', '1', '10');
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('dataview', 'export', '650', ',biz,max,ipd,', ',rnd,', '1', '30');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2107, 'priv', 'de', 'traincourse-cloudImport', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2107, 'priv', 'en', 'traincourse-cloudImport', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2107, 'priv', 'fr', 'traincourse-cloudImport', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2107, 'priv', 'zh-cn', 'traincourse-cloudImport', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2107, 'priv', 'zh-tw', 'traincourse-cloudImport', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2108, 'priv', 'de', 'dataview-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2108, 'priv', 'en', 'dataview-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2108, 'priv', 'fr', 'dataview-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2108, 'priv', 'zh-cn', 'dataview-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2108, 'priv', 'zh-tw', 'dataview-export', '', '');
REPLACE INTO zt_privmanager (id, parent, code, `type`, edition, vision, `order`) VALUES (650, 445, '', 'package', ',biz,max,ipd,', ',rnd,', 20);
REPLACE INTO zt_privlang (objectID, objectType, lang, `key`, value, `desc`) VALUES(650, 'manager', 'zh-cn', '', '导出数据表', '');
REPLACE INTO zt_privrelation (priv, `type`, relationPriv) VALUES(2108, 'depend', 1648);
REPLACE INTO zt_privrelation (priv, `type`, relationPriv) VALUES(2108, 'depend', 1651);
ALTER TABLE `zt_traincourse` ADD `importedStatus` enum('','wait','doing','done') NOT NULL DEFAULT '';
ALTER TABLE `zt_traincourse` ADD `lastUpdatedTime` int UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE `zt_traincourse` MODIFY `code` varchar(255) NOT NULL DEFAULT '';
UPDATE `zt_im_chat` SET `createdDate` = NULL WHERE `createdDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_chat` SET `editedDate` = NULL WHERE `editedDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_chat` SET `mergedDate` = NULL WHERE `mergedDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_chat` SET `lastActiveTime` = NULL WHERE `lastActiveTime` = '0000-00-00 00:00:00';
UPDATE `zt_im_chat` SET `dismissDate` = NULL WHERE `dismissDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_chat` SET `archiveDate` = NULL WHERE `archiveDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_chatuser` SET `join` = NULL WHERE `join` = '0000-00-00 00:00:00';
UPDATE `zt_im_chatuser` SET `quit` = NULL WHERE `quit` = '0000-00-00 00:00:00';
UPDATE `zt_im_client` SET `createdDate` = NULL WHERE `createdDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_client` SET `editedDate` = NULL WHERE `editedDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_message` SET `date` = NULL WHERE `date` = '0000-00-00 00:00:00';
UPDATE `zt_im_message_backup` SET `date` = NULL WHERE `date` = '0000-00-00 00:00:00';
UPDATE `zt_im_message_index` SET `startDate` = NULL WHERE `startDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_message_index` SET `endDate` = NULL WHERE `endDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_chat_message_index` SET `startDate` = NULL WHERE `startDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_chat_message_index` SET `endDate` = NULL WHERE `endDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_queue` SET `addDate` = NULL WHERE `addDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_queue` SET `processDate` = NULL WHERE `processDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_conference` SET `openedDate` = NULL WHERE `openedDate` = '0000-00-00 00:00:00';
UPDATE `zt_im_conferenceaction` SET `date` = NULL WHERE `date` = '0000-00-00 00:00:00';
UPDATE `zt_im_userdevice` SET `validUntil` = NULL WHERE `validUntil` = '0000-00-00 00:00:00';
UPDATE `zt_im_userdevice` SET `lastLogin` = NULL WHERE `lastLogin` = '0000-00-00 00:00:00';
UPDATE `zt_im_userdevice` SET `lastLogout` = NULL WHERE `lastLogout` = '0000-00-00 00:00:00';
CREATE INDEX `project` ON `zt_project` (`project`);
UPDATE `zt_privlang` SET `value`='删除风险' WHERE `objectID`=197 AND `objectType`='manager';
UPDATE `zt_auditcl` SET `deleted` = '0' WHERE `deleted` = '';
UPDATE `zt_workflowdatasource` SET `vision` = 'rnd' WHERE `code` IN ('products','projects','productLines','stories','tasks','bugs','groups','users','branches','builds','modules','plans','productType','productStatus','productAcl','projectType','projectStatus','projectAcl','releaseStatus','storySource','storyPri','storyStatus','storyStage','bugSeverity','bugPri','bugType','bugOs','bugBrowser','bugStatus','taskType','taskPri','taskStatus','testcasePri','testcaseType','testcaseStage','testcaseStatus','testtaskPri','testtaskStatus','feedbackStatus','bugResolution','cases','feedbackModules','storyType','executions','projectModel','feedbackType','feedbackSolution','feedbackclosedReason','taskReason','testsuiteAuth','programs','storyClosedReason');
UPDATE `zt_product` SET `shadow` = 1 WHERE `vision` = 'lite';
+81
View File
File diff suppressed because one or more lines are too long
+255
View File
@@ -0,0 +1,255 @@
CREATE TABLE `zt_demandpool` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`desc` mediumtext NOT NULL,
`status` char(30) NOT NULL,
`createdBy` char(30) NOT NULL,
`createdDate` date NOT NULL,
`owner` text NOT NULL,
`reviewer` text NOT NULL,
`acl` char(30) NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `zt_demand` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`pool` int(8) NOT NULL,
`module` int(8) NOT NULL,
`product` mediumint(8) NOT NULL,
`parent` mediumint(8) NOT NULL,
`pri` char(30) NOT NULL,
`category` char(30) NOT NULL,
`source` char(30) NOT NULL,
`sourceNote` varchar(255) NOT NULL,
`title` varchar(255) NOT NULL,
`feedbackedBy` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`assignedTo` char(30) NOT NULL,
`assignedDate` datetime NOT NULL,
`reviewedBy` text NOT NULL,
`reviewedDate` datetime NOT NULL,
`status` char(30) NOT NULL,
`duration` char(30) NOT NULL,
`BSA` char(30) NOT NULL,
`story` mediumint(8) NOT NULL,
`roadmap` mediumint(8) NOT NULL,
`createdBy` char(30) NOT NULL,
`createdDate` datetime NOT NULL,
`mailto` text NOT NULL,
`duplicateDemand` mediumint(8) NOT NULL,
`childDemands` varchar(255) NOT NULL,
`version` varchar(255) NOT NULL,
`vision` varchar(255) NOT NULL DEFAULT 'or',
`color` varchar(255) NOT NULL,
`changedBy` char(30) NOT NULL,
`changedDate` datetime NOT NULL,
`closedBy` char(30) NOT NULL,
`closedDate` datetime NOT NULL,
`closedReason` varchar(30) NOT NULL,
`submitedBy` varchar(30) NOT NULL,
`lastEditedBy` varchar(30) NOT NULL DEFAULT '',
`lastEditedDate` datetime NOT NULL,
`activatedDate` datetime NOT NULL,
`distributedBy` varchar(30) NOT NULL DEFAULT '',
`distributedDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `zt_demandspec` (
`demand` mediumint(9) NOT NULL,
`version` smallint(6) NOT NULL,
`title` varchar(255) NOT NULL,
`spec` mediumtext NOT NULL,
`verify` mediumtext NOT NULL,
`files` text NOT NULL,
UNIQUE KEY `demand` (`demand`,`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `zt_demandreview` (
`demand` mediumint(9) NOT NULL,
`version` smallint(6) NOT NULL,
`reviewer` varchar(30) NOT NULL,
`result` varchar(30) NOT NULL,
`reviewDate` datetime NOT NULL,
UNIQUE KEY `demand` (`demand`,`version`,`reviewer`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `zt_charter` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`level` int(8) NOT NULL,
`category` char(30) NOT NULL,
`market` varchar(30) NOT NULL,
`appliedBy` char(30) NOT NULL,
`appliedDate` datetime NOT NULL,
`budget` char(30) NOT NULL,
`budgetUnit` char(30) NOT NULL,
`product` mediumint(8) NOT NULL,
`roadmap` mediumint(8) NOT NULL,
`spec` mediumtext NOT NULL,
`status` char(30) NOT NULL,
`createdBy` char(30) NOT NULL,
`createdDate` datetime NOT NULL,
`charterFiles` text NOT NULL,
`reviewedBy` char(30) NOT NULL,
`reviewedResult` char(30) NOT NULL,
`reviewedDate` datetime NOT NULL,
`meetingDate` date NOT NULL,
`meetingLocation` varchar(255) NOT NULL,
`meetingMinutes` mediumtext NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
REPLACE INTO `zt_config` (`vision`, `owner`, `module`, `section`, `key`, `value`) VALUES ('or', 'system', 'demand', '', 'reviewRules', 'allpass');
REPLACE INTO `zt_config` (`vision`, `owner`, `module`, `section`, `key`, `value`) VALUES ('or', 'system', 'demand', '', 'needReview', 1);
ALTER TABLE `zt_story` ADD `BSA` char(30) NOT NULL AFTER `notifyEmail`;
ALTER TABLE `zt_story` ADD `duration` char(30) NOT NULL AFTER `notifyEmail`;
ALTER TABLE `zt_story` ADD `demand` mediumint(8) NOT NULL AFTER `notifyEmail`;
ALTER TABLE `zt_product` ADD `PMT` text COLLATE 'utf8_general_ci' NOT NULL AFTER `reviewer`;
ALTER TABLE `zt_story` ADD `submitedBy` varchar(30) NOT NULL AFTER `changedDate`;
ALTER TABLE `zt_story` ADD `roadmap` VARCHAR(255) NOT NULL DEFAULT '' AFTER `plan`;
ALTER TABLE `zt_charter` ADD `check` enum('0','1') NOT NULL DEFAULT '0';
ALTER TABLE `zt_charter` modify column reviewedBy varchar(255);
CREATE TABLE `zt_roadmap` (
`id` mediumint(8) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`product` mediumint(8) NOT NULL,
`branch` mediumint(8) NOT NULL,
`name` varchar(255) NOT NULL,
`status` char(30) NOT NULL,
`begin` date NOT NULL,
`end` date NOT NULL,
`desc` longtext NOT NULL,
`createdBy` char(30) NOT NULL,
`createdDate` date NOT NULL,
`closedBy` char(30) NOT NULL,
`closedDate` datetime NOT NULL,
`closedReason` enum('done','canceled') DEFAULT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `zt_roadmapstory` (
`roadmap` mediumint(8) unsigned NOT NULL,
`story` mediumint(8) unsigned NOT NULL,
`order` MEDIUMINT UNSIGNED NOT NULL,
UNIQUE KEY `roadmap_story` (`roadmap`,`story`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `zt_story` MODIFY `status` enum('','changing','active','draft','closed','reviewing','launched','developing') NOT NULL DEFAULT '' AFTER `estimate`;
ALTER TABLE `zt_project`
ADD `charter` mediumint(8) NOT NULL DEFAULT 0 AFTER `project`,
ADD `category` char(30) COLLATE 'utf8_general_ci' NOT NULL AFTER `type`;
REPLACE INTO `zt_stage` (`name`, `percent`, `type`, `projectType`, `createdBy`, `createdDate`, `editedBy`, `editedDate`, `deleted`) VALUES
('概念', '10', 'concept', 'ipd', 'admin', '2020-02-08 21:08:30', 'admin', '2020-02-12 13:50:27', '0'),
('计划', '10', 'plan', 'ipd', 'admin', '2020-02-08 21:08:30', 'admin', '2020-02-12 13:50:27', '0'),
('开发', '50', 'develop', 'ipd', 'admin', '2020-02-08 21:08:30', 'admin', '2020-02-12 13:50:27', '0'),
('验证', '15', 'qualify', 'ipd', 'admin', '2020-02-08 21:08:30', 'admin', '2020-02-12 13:50:27', '0'),
('发布', '10', 'launch', 'ipd', 'admin', '2020-02-08 21:08:30', 'admin', '2020-02-12 13:50:27', '0'),
('全生命周期', '5', 'lifecycle', 'ipd', 'admin', '2020-02-08 21:08:45', 'admin', '2020-02-12 13:50:27', '0');
ALTER TABLE `zt_review` ADD `begin` date NULL AFTER `createdDate`;
ALTER TABLE `zt_review` MODIFY `doc` varchar(255);
ALTER TABLE `zt_review` MODIFY `docVersion` varchar(255);
ALTER TABLE `zt_object` ADD `end` date NULL AFTER `designEst`;
ALTER TABLE `zt_charter` ADD `closedBy` char(30) NULL;
ALTER TABLE `zt_charter` ADD `closedDate` datetime NULL;
ALTER TABLE `zt_charter` ADD `closedReason` varchar(255) NULL;
ALTER TABLE `zt_charter` ADD `activatedBy` char(30) NULL;
ALTER TABLE `zt_charter` ADD `activatedDate` datetime NULL;
UPDATE `zt_priv` SET `vision` = ',rnd,or,' WHERE `module` = 'requirement' AND `method` = 'import';
UPDATE `zt_priv` SET `vision` = ',rnd,or,' WHERE `module` = 'requirement' AND `method` = 'exportTemplate';
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('demand', 'export', '643', ',ipd,', ',or,', '1', '210');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2109, 'priv', 'de', 'demand-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2109, 'priv', 'en', 'demand-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2109, 'priv', 'fr', 'demand-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2109, 'priv', 'zh-cn', 'demand-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2109, 'priv', 'zh-tw', 'demand-export', '', '');
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('demand', 'exportTemplate', '643', ',ipd,', ',or,', '1', '220');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2110, 'priv', 'de', 'demand-exportTemplate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2110, 'priv', 'en', 'demand-exportTemplate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2110, 'priv', 'fr', 'demand-exportTemplate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2110, 'priv', 'zh-cn', 'demand-exportTemplate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2110, 'priv', 'zh-tw', 'demand-exportTemplate', '', '');
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('demand', 'import', '643', ',ipd,', ',or,', '1', '230');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2111, 'priv', 'de', 'demand-import', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2111, 'priv', 'en', 'demand-import', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2111, 'priv', 'fr', 'demand-import', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2111, 'priv', 'zh-cn', 'demand-import', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2111, 'priv', 'zh-tw', 'demand-import', '', '');
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2109, 'depend', 2075);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2109, 'recommend', 2110);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2109, 'recommend', 2111);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2110, 'depend', 2075);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2110, 'recommend', 2109);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2111, 'depend', 2075);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2111, 'depend', 2110);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2111, 'recommend', 2109);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2111, 'recommend', 2076);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2111, 'recommend', 2077);
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('requirement', 'batchChangeRoadmap', '32', ',ipd,', ',or,', '1', '125');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2112, 'priv', 'de', 'requirement-batchChangeRoadmap', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2112, 'priv', 'en', 'requirement-batchChangeRoadmap', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2112, 'priv', 'fr', 'requirement-batchChangeRoadmap', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2112, 'priv', 'zh-cn', 'requirement-batchChangeRoadmap', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2112, 'priv', 'zh-tw', 'requirement-batchChangeRoadmap', '', '');
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2112, 'depend', 65);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2112, 'recommend', 121);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2112, 'recommend', 122);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2112, 'recommend', 123);
UPDATE `zt_privlang` SET `value` = '创建维护立项' WHERE `objectID` = 638 and `objectType` = 'manager';
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('charter', 'close', '638', ',ipd,', ',or,', '1', '80');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2113, 'priv', 'de', 'charter-close', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2113, 'priv', 'en', 'charter-close', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2113, 'priv', 'fr', 'charter-close', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2113, 'priv', 'zh-cn', 'charter-close', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2113, 'priv', 'zh-tw', 'charter-close', '', '');
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('charter', 'activate', '638', ',ipd,', ',or,', '1', '90');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2114, 'priv', 'de', 'charter-activate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2114, 'priv', 'en', 'charter-activate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2114, 'priv', 'fr', 'charter-activate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2114, 'priv', 'zh-cn', 'charter-activate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2114, 'priv', 'zh-tw', 'charter-activate', '', '');
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2113, 'depend', 2061);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2113, 'depend', 2064);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2113, 'recommend', 2062);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2113, 'recommend', 2063);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2113, 'recommend', 2114);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2114, 'depend', 2061);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2114, 'depend', 2064);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2114, 'recommend', 2062);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2114, 'recommend', 2063);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2114, 'recommend', 2113);
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('requirement', 'relation', '32', ',max,ipd,', ',rnd,', '1', '130');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2115, 'priv', 'de', 'requirement-relation', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2115, 'priv', 'en', 'requirement-relation', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2115, 'priv', 'fr', 'requirement-relation', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2115, 'priv', 'zh-cn', 'requirement-relation', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2115, 'priv', 'zh-tw', 'requirement-relation', '', '');
UPDATE `zt_priv` SET `vision` = ',rnd,or,' WHERE `module` = 'user' AND `method` = 'export';
UPDATE `zt_priv` SET `vision` = ',rnd,or,' WHERE `module` = 'user' AND `method` = 'exportTemplate';
UPDATE `zt_priv` SET `vision` = ',rnd,or,' WHERE `module` = 'user' AND `method` = 'import';
UPDATE `zt_priv` SET `vision` = ',rnd,or,' WHERE `module` = 'user' AND `method` = 'importldap';
Executable → Regular
+1637 -587
View File
File diff suppressed because one or more lines are too long
+360 -34
View File
@@ -1,3 +1,329 @@
2023-08-15 18.6
完成的需求
开源版:
39958 文档按版本记录每个版本下的附件内容
46723 新增区域页面中调整复制区域样式的名称
31901 产品中设置的评审人默认具备产品访问权限
39958 文档按版本记录每个版本下的附件内容
44084 文档详情对比后内容区域优化删除和新增的样式
46723 新增区域页面中调整复制区域样式的名称
42686 版本关联需求时搜索列表中过滤掉草稿、评审中、变更中的需求
44726 文档详情中文章内容大纲支持显示所有层级
39958 文档按版本记录每个版本下的附件内容
42686 版本关联需求时搜索列表中过滤掉草稿、评审中、变更中的需求
45887 优化树状图中任务的显示规则
46723 新增区域页面中调整复制区域样式的名称
30539 数据备份前自动检查空间大小空间不足时给出提示
43731 附件增加单独的预览权限
45316 创建文档时调整选择模板的方式
47076 测试下面的测试单中创建测试报告与执行下面测试单创建测试报告逻辑保持一致
47293 升级流程中在执行SQL环节增加进度展示
企业版:
47188 汇总设置增加提示文案
47126 透视表设计器实现汇总设置参数的开关
47127 在未勾选汇总设置时实现下一步按钮和流程标签的校验逻辑
47130 前台支持切换查看透视表和原始数据
47137 前台支持查看未勾选汇总设置的透视表
47138 前台支持查看透视表的原始数据
47132 老用户未设置报表设计参数的水晶报表时也可以正常升级
47137 前台支持查看未勾选汇总设置的透视表
47138 前台支持查看透视表的原始数据
46528 浏览数据表时可以分页查看数据表
旗舰版:
47077 调整瀑布项目甘特图中任务计划起止日期的显示规则
46637 检查清单中的不符合项不直接影响评审结果
46631 地盘待处理区块中标签下无数据时隐藏该标签
46630 地盘待处理区块中将审批标签调整到日程后面
46629 工时明细表中列表数据超过一屏时底部滚动条置顶显示
44213 融合瀑布模型中看板和迭代工时数据参与挣值计算
46639 批量创建质量保证计划时可以按过程内容默认填充所有活动、文档
46636 评审问题列表中增加搜索功能
46626 不符合项列表增加搜索功能
46625 质量保证计划列表增加搜索功能
修复的Bug
开源版:
36686 产品下创建非激活状态需求没有记录动态和历史记录
36654 升级后产品需求的数据不正确
36958 修改需求的所属产品异常
36954 任务起止时间设置必填不生效
36722 升级18.5系列版本,出现一致性检查需要手动执行SQL
36910 更新燃尽图计算有误
36959 禅道项目空间提研发需求提示【所属计划】不能为空
35520 无产品无迭代项目用户需求列表点击SR处数字提示无权限
35526 无产品无迭代项目研发需求列表切换为看板视图后无法再切换到用户需求
36945 全局搜索无迭代项目下任务,点击没有跳转项目标签
36055 通用看板模块的“泳道高度”设置“自定义”后卡片展示没有按照高度变化来呈现
36102 mysql8下文档仪表盘下的产品文档区块sql报错
36961 评审用例时选了了多人,用例列表中显示用户名,不显示姓名
36074 附件下载链接带sid信息
36826 执行的工时重复统计了父子任务的工时
37048 后台文档模板中编辑模板的字段显示的是“创建模板”
36981 无产品无迭代项目下文档详情页1.5级导航丢失
36916 链接类型的文档升级后链接没有渲染出来
35404 系统权限保存速度太慢
35786 无产品的融合敏捷项目下的看板,批量提需求后,页面未刷新
36405 创建产品页面选择项目集或删除项目集后产品线控件处加载2次
37052 【性能】权限保存20s+
25993 scrum看板任务看板按需分组切换排序条件卡片渲染不出来
37122 在地盘仪表盘移动【我的待处理】区块,进入审批中的onlybody超链接,跳转到了页面而不是弹窗
37046 多分支产品下提研发需求页面的“用户需求”无法正常加载
35381 【4.4alpha1】无迭代项目需求分解任务慢
26408 gogs服务器用户1千人时,进入绑定用户页面无加载信息
27044 项目集下项目过多时,页面反应慢
37084 18.5版本用例数据较多时,页面卡顿
37243 多分支产品创建研发需求,用户需求没有根据分支联动
37241 所有分支下创建研发需求,显示所有的用户需求
37045 研发看板卡片拖动排序后刷新页面排序不成功
34331 维护部门时,页面样式不正确
37230 二次开发数据字典中左侧目录树无法正常展示
企业版:
36779 Bug类型统计表表头类型显示的不是中文
36857 透视表下的项目Bug类型统计表中类型显示为了键名
36920 BI下导出按钮失效
36626 登录有代码报错
旗舰版:
34960 文档链接复制后在新页签中打开报错
36453 linux一键安装包瀑布项目评审保存结果有报错
33583 瀑布项目甘特图中阶段显示的计划开始、结束时间不正确
36465 工作流开启审批流后进行评审时不发送webhook应用通知
36115 私有产品可访问权限,增加项目所属项目集干系人
35661 【调整优化】达梦数据库版本的禅道升级时,数据库备份页面需优化
36051 地盘仪表盘中未完成的项目统计瀑布项目进度没有跟随周报进度
37040 新增工作流字段后项目阶段测试用例搜索异常
35828 状态为“已入库”的数据依然可以进行批量审批
37235 里程碑报告中开始周数和结束周数不正确
2023-07-27 ipd1.0
完成的需求
42981 实现需求的导入功能
42982 实现导出需求模板功能
42983 实现导出需求数据功能
43034 在需求列表的右上角打印导入导出按钮
43407 实现关闭路标功能
43408 实现删除路标功能
43413 实现在路标用户需求列表的批量操作按钮组中打印路标菜单
43414 实现在路标的用户需求列表中批量移除用户需求功能
43415 实现在路标的用户需求列表中批量编辑用户需求功能
43416 实现在路标的用户需求列表中批量调整所属路标功能
43432 实现激活路标功能
43511 实现将产品用户需求批量关联到路标中
43974 实现关闭立项申请功能
44225 实现激活立项申请功能
44913 甘特图中可以修改评审点的截止日期
44914 阶段列表中可以修改评审点的截止日期
45138 根据关联的产品用户需求判断需求池需求的状态
46700 一级导航中菜单名称与图标上下居中对齐显示
46708 产品中提交需求保存后返回到全部列表
46709 需求池中提交需求保存后返回到全部列表
46710 产品提需求页面中BSA字段增加解释信息
47058 地盘使用帮助中界面切换增加需求与市场管理界面
47289 实现从禅道其他版本升级到IPD版本功能
47395 用户需求详情页面增加所属路标字段
修复的Bug
35072 发起评审,相关文档内容及顺序显示错误
35191 OR界面下导出的产品字段与页面不一致
35252 英法德语下提交立项页面的类型显示不全
35253 分发需求可以选择所有状态的路标
35262 评审点都通过了,子阶段也都关闭了,但是父阶段仍是进行中的状态
35312 将路标与立项解除关联,路标状态未改变
35333 编辑需求所属产品下拉菜单宽度没有限制
35418 研发用户到达授权人数,提示信息不准确
35422 甘特图列表中可以点父级阶段进入阶段中
35438 评审点计划完成时间显示错误
35471 Windows新版一键安装包,系统右下角没有隐藏升级按钮
35472 地盘-仪表盘中界面切换隐藏
35473 OR界面点击仪表盘最新动态更多跳转到了组织动态页面
35480 需求列表中细分需求的按钮与用户需求按钮不对齐
35485 编辑需求页面所属产品下拉样式错误
35490 阶段列表中评审点评审完成后还高亮评审按钮
35493 多分支产品,研发需求无法关联到用户需求
35523 运用管理界面中反馈办公工作流没有权限包
36122 权限包信息显示不完整
36477 OR界面产品列表中代码报错
36479 激活立项后立项的状态显示成了英文
36480 OR界面产品列表页代码报错
36497 批量移除路标的用户需求,点击取消后移除按钮变白了
36522 立项关闭后列表和详细页显示closed
36533 阶段列表页草稿状态的评审点没有显示编辑按钮
36536 阶段列表中编辑按钮只有icon部分可以点
36551 英文下激活立项弹窗中没有显示提示文案
36623 在路标的用户需求列表批量指派需求提示没有研发需求批量指派权限
36624 甘特图中计划完成的编辑按钮可触范围与按钮大小不匹配
36625 分支下的用户需求批量关联路标时列出了主干的路标
36638 IPD界面产品路标下访问用户需求详情页提示访问对象不存在
36645 批量编辑阶段更改状态可无视阶段进度
36660 超级管理员在IPD界面项目用户需求列表中无法全选
36672 15.3升级ipd1.0后,admin用户默认没有需求与管理界面的权限
36677 IPD1.0.beta1升级到IPD1.0.stable版本删除文件后有报错
36678 IPD界面下全局搜索项目集后进入项目集下可访问人员有代码报错
36684 需求池导入需求,没有带入指派给和类别
36687 需求池草稿需求提交评审提示502
36689 修改评审点计划完成计划时间翻页时,控件位置移动到了左上角
36696 OR界面添加产品区块报错
36697 OR界面区块,没有统计未关闭产品信息
36706 超级管理员在IPD项目用户需求列表页无法全选
36707 超级管理员在IPD项目的用户需求列表页时,二级导航高亮了两个
36710 分批次创建的阶段,会默认从最新添加的阶段开始
36711 需求的指派给和最后修改时间应显示为空
36712 地盘待处理不显示待我评审的用户需求
36713 max4.5轻量模式升级到IPD1.0不是全生命周期模式
36714 max4.0升级到ipd1.0,OR界面产品列表页代码报错
36715 升级至ipd版本,用户需求应该默认开启
36716 max4.0升级到ipd1.0后,无法创建IPD类型的项目
36717 升级成功后超级管理员维护“需求与市场管理界面”权限保存后界面和内容不对应
36718 关闭路标选择关闭原因后点保存控制台有报错
36719 给admin OR界面权限后,界面显示错误
36720 升级后OR界面没有默认权限分组
36721 biz8.5升级ipd1.0,普通用户在OR界面看不到
36726 需求池下导入权限有多余
36728 需求池导入需求时提示需求名称不符合
36740 批量编辑产品下用户需求可以将非激活状态需求编辑到路标下
36741 升级后开启用户需求后二级导航同时高亮了用户需求和研发需求
36743 18.4升ipd1.0,BI显示开源版的引导弹窗
36744 路标关联了非激活状态的需求后,解除关联,需求状态变为了激活
36745 没有打开用户需求功能的IPD界面,点击路标的需求列表的用户需求超链接二级导航没有高亮
36747 路标中批量操作按钮应该隐藏评审按钮
36748 IPD项目下编辑阶段页面选择父阶段后提示信息中显示undefined
36749 biz4.1.3升级到ipd1.0.授权没替换成功
36750 IPD界面学堂从云端导入课程,发送邮件内容有误
36753 路标关联需求点击搜索搜索不到内容
36760 1.0beta1升级到1.0stable版本后IPD项目下可以创建多套阶段
36765 ipd项目创建评审,评审文档错误
36766 创建文档保存后会保存两个文档
36767 评审页面报错
36771 IPD研发项目下打基线页面三级导航缺失
36772 提交评审时选择一个以上文档,在评审页面文档内容为空
36786 工单转研发需求选择来源后有代码报错
36795 IPD界面创建的产品,在OR界面批量编辑后变成了已关闭状态
36800 研发需求提交评审变成了页面
36810 项目集列表页IPD项目前未显示复选框
36831 瀑布/融合瀑布项目下的配置菜单没有了
36858 OR界面产品总览区块统计数据不正确
2023-07-05 18.5
完成的需求
开源版:
45633 优化产品模块中用户需求列表性能
45632 优化产品模块中研发需求列表性能
45630 优化项目列表性能
45256 版本数据过多影响bug编辑页面加载速度
企业版:
46105 从云端导入课程完成后给用户邮件通知
45927 后台BI权限实现数据表的导出权限
45924 数据表浏览页面实现导出功能
45498 学堂导入课程默认为上线状态
45497 学堂后台课程列表中增加默认引导语
45496 私有部署禅道实现从云端导入课程功能
45268 项目型项目支持反馈功能
44991 yaml课程打包工具支持打包PDF文件
44918 调整授权到期规则,授权到期前30天在登录页面给用户提示
43764 学堂后台课程列表中打印从云端导入按钮
40829 学堂播放器支持PDF文件播放功能
修复的Bug
开源版:
36161 运营界面点击任务默认跳转到看板视图
36142 产品列表中需求完成率计算不对
企业版:
36057 透视表前台筛选条件能不正常查询
36218 scrum项目型项目反馈转需求,点击反馈详情页历史记录的超链接报错
禅道客户端:
13775 成员被踢出讨论组后,还停留在讨论组会话页面
15925 内网喧喧有新消息时不提醒
16398 iOS端音视频会议没有声音
16720 喧喧聊天窗口中的聊天记录的滚动条体验需要增强
16806 跳转到某个比较老的消息后,会话列表消息中间会缺失一段范围
17240 移动端登录后未读消息的情况与桌面端未读情况不一致
17617 喧喧后台运行时再次打开喧喧有用户正在会议中实际没有在进行会议
20444 右击复制聊天窗口收到的图片执行失败
21380 喧喧文件查看卡白
21533 设置白名单弹窗宽度过大且文字不居中
21587 移动端收到的新消息少了一条
21602 消息记录中存在搜索不到消息的情况
21610 偶发新的消息只在左侧消息栏中部分显示
21782 部门结构和按钮样式不统一
21864 应用标签的前后按钮和窗口操作项重叠
22053 从聊天列表中移除自己多次才可以生效
22176 群合并人员退出群组白名单展示不对
23356 消息记录搜索后无法收起下拉框
26134 群管理员不能移除用户
26215 6.2版本群设置白名单成员不成功
27093 群组重命名后名字没有刷新
27329 讨论组消息记录窗口白屏
28232 打开固定到左侧边栏的应用时“一口X”会遮挡应用
28907 群组归档完取消归档转发之前的消息界面崩溃(偶发)
29117 开始会议挂断后一分钟后频繁提示连接超时
29145 @成员的时候错误地把在群里的成员标红色
29257 分组出现空分组
29262 群管理--搜索的时候下方出现横线
29391 低版本的xxc小喧喧提示小喧喧头像展示需优化
29392 打开小喧喧对话框,发送指令,小喧喧的头像和名称展示有误
29393 小喧喧头像展示不对
29394 进入授权信息bot输入指令提示指令不存在
29395 讨论组右上角下拉菜单出现横线
29480 禅道客户端--小喧喧会话进入内置应用退出不了
30293 两个用户同时退出讨论组点击两次才可以完全退出
30738 小喧喧提醒左侧消息栏不展示该条信息
31173 查看小喧喧消息记录提示获取消息记录失败
31185 非admin账号私人会话协作文档入口没有了
31340 会议共享屏幕非常模糊
31590 freemind预览,没有展示图标
31593 freemind预览中,文字颜色与原文件不一致
32612 7.1版本喧喧用户点击查看图片放大、缩小按钮置灰不能点击
32661 喧喧客户端登录内网,会话界面报错
32808 讨论组成员列表群主右键踢人弹窗不展示有报错。
32855 云端同步的数据量大的时候,喧喧客户端会卡顿,点击取消同步无响应
33105 客户端7.1发着送信息过程中掉线了点重新发送提示需优化
36060 文件应用,只显示了一个image.png
2023-06-14 18.4
修复的Bug
开源版:
34705 pms升级到biz6.5过程报错
35836 项目迭代页面有报错
34720 后台聊天首页有代码报错
35775 发布详情页点击右上角导出HTML控制台有很多报错
企业版:
35845 达梦数据库工作流中删除新增的流程失败
35730 组织-日志汇总表按照上级部门统计显示没有数据
35659 达梦数据库安装企业版8.4写入my.php完成后跳转到了upgrade.php
35622 导入工单后联系人字段显示不正确
34756 运营管理界面,创建工作流报错
34716 工作流新增字段报错
34656 【达梦】创建工作流报错
34051 【按版本升级即可】同步代码缺少文件,打开浏览代码导致服务502
35827 老版本水晶报表SQL查询中使用了左右连接的,升级后会报错
35824 达梦数据库内置工作流添加字段/动作保存时报错
35820 业务界面创建工作流保存时报错
35758 biz4.1.3升级到biz8.4.beta1,反馈转研发需求报错
35729 升级成功后没插入原内置的水晶报表
35726 达梦数据库添加数据源sql报错
35718 达梦数据库全文检索sql报错
35700 达梦数据库,多平台产品,点击产品->矩阵导航,sql异常
34819 达梦安装方式,透视表下不显示检索标签
34610 创建上线计划有SQL报错
30371 添加中间表所属分组的下拉菜单遮挡
35852 达梦下BI透视表页面报错
35724 达梦数据库 产品Bug类型统计表代码报错
35722 达梦数据库透视表下的产品/项目/测试/组织下的内置透视表报错
34920 大屏页面sql报错
34930 产品Bug类型统计表有代码报错
34931 透视表项目下有SQL报错
34932 透视表组织下有SQL报错
35854 反馈设置页面有报错
35858 没有产品访问权限时无法提交反馈
旗舰版:
35829 英文语言下项目中问题列表有报错
35748 biz5.3.1升级到max4.4beta1过程中代码报错
35715 从其他软件点击禅道链接,可以看到本不能看到的内容
34732 后台功能配置的创建度量数据页面有报错
35559 升级时处理自定义水晶报表报错
35554 无产品项目下研发需求从需求库导入页面二级导航下拉高亮不对
34410 mysql慢日志反馈
33930 产品计划列表有代码报错
33391 选择审批人后提示保存成功,但是还提示数据未找到
33171 反馈转风险类型的待办页面关联不到待办名称
27055 后台文档模板中设置了文档目录无法使用
2023-05-31 18.4.beta1
完成的需求
开源版:
@@ -3568,29 +3894,29 @@
2021-12-06 16.0.beat1
完成的需求
14005 能够按照平台分支浏览用户需求
14005 能够按照平台分支浏览用户需求
14429 父需求支持变更
14761 选择某一个分支之后点击其他菜单希望能够保持分支下拉菜单状态
14771 启用多分支功能后增加分支字样显示的控制
14772 需求修改所属分支时如果有冲突给出提示
14778 分支设置默认分支功能
14877 根据分支提示上次版本计划名称
14761 选择某一个分支之后点击其他菜单希望能够保持分支下拉菜单状态
14771 启用多分支功能后增加分支字样显示的控制
14772 需求修改所属分支时如果有冲突给出提示
14778 分支设置默认分支功能
14877 根据分支提示上次版本计划名称
15134 员工负载表增加备注说明
15470 看板可以设置一个单元格里面卡片的排列方式
15478 我的地盘bug列表增加确认字段
25665 梳理项目和执行关联产品分支的逻辑
25666 可以将某一个分支关闭
25667 将所有分支概念改为主干并处理历史数据
25670 多分支产品浏览需求的时候将所有和主干区分开
25673 分支增加排序功能
15478 我的地盘bug列表增加确认字段
25665 梳理项目和执行关联产品分支的逻辑
25666 可以将某一个分支关闭
25667 将所有分支概念改为主干并处理历史数据
25670 多分支产品浏览需求的时候将所有和主干区分开
25673 分支增加排序功能
27484 文档库右侧目录增加文件的浮动操作菜单
27485 文档库右侧目录增加目录的浮动操作菜单
27486 wiki目录中,当鼠标悬浮到文章名称时展示文章快捷操作
27487 wiki目录中,鼠标悬浮到具体章节时展示章节的快捷操作
27927 执行看板默认只显示一屏滚动时再往下加载
28098 需求批量转任务时对已经转换过任务的需求进行提示
28131 待处理任务列表中子任务名称前显示父任务
28138 员工负载表中增加项目名称信息
28098 需求批量转任务时对已经转换过任务的需求进行提示
28131 待处理任务列表中子任务名称前显示父任务
28138 员工负载表中增加项目名称信息
28147 统计列表中具备横向滚动条的列表可以直接展示出来
28153 Bug创建表中优化执行查询条件
28235 关闭项目时增加实际完成日期的记录
@@ -3599,9 +3925,9 @@
28238 关闭执行时增加实际完成日期的记录
28239 执行工时统计中增加实际开始和实际完成的信息
28310 未开始的项目
28466 测试Bug列表中增加按所属项目的搜索条件
28509 项目概况中增加项目代号的显示
28510 项目列表中增加项目代号字段显示
28466 测试Bug列表中增加按所属项目的搜索条件
28509 项目概况中增加项目代号的显示
28510 项目列表中增加项目代号字段显示
28719 项目看板中看板列显示数量汇总
28727 计划创建迭代时选择项目点击下一步后自动关闭选择弹窗
28809 执行看板中进行中项目排序规则调整
@@ -3616,29 +3942,29 @@
28816 产品看板中调整项目集和产品的排序规则
28817 项目集看板中调整项目集和产品的排序规则
28818 项目集看板中看板列显示数量汇总
28819 调整项目集/产品/项目/执行重名规则
28833 创建执行页面可以直接维护相关负责人信息
28819 调整项目集/产品/项目/执行重名规则
28833 创建执行页面可以直接维护相关负责人信息
28834 项目的分组权限中移除无用的模块和方法
28835 关联多个产品的项目也可以选择归并方式
28904 优化项目列表“我参与的”筛选结果 结
28928 可以设置哪些人不需要提醒
28929 编辑bug修改状态时如果未修改成功希望有错误提示
28931 调整分支管理功能
28932 实现分支的批量操作
28941 重新登陆系统后产品下拉菜单应当保持上次选中的产品名称
28931 调整分支管理功能
28932 实现分支的批量操作
28941 重新登陆系统后产品下拉菜单应当保持上次选中的产品名称
28944 在开源版中增加瀑布模型的相关功能
28959 老版本升级新版本数据归并的时候,可以修改项目、执行名称。
28960 调整产品列表页面的宽度展示比例
28965 实现分支的新增/编辑操作
28965 实现分支的新增/编辑操作
28970 需求列表批量选中希望可以通过shift快捷键操作
28972 产品列表左侧的模块设置调整为显示设置
28973 提交Bug时分支与影响版本要跟着联动
28974 产品列表批量调整计划时在计划名称前显示分支信息
28972 产品列表左侧的模块设置调整为显示设置
28973 提交Bug时分支与影响版本要跟着联动
28974 产品列表批量调整计划时在计划名称前显示分支信息
28993 创建或者编辑用例时调整所属需求的查询逻辑
29000 产品列表中调整字段显示宽度
29002 动态支持按正序/倒序切换排序
29030 已挂起的项目/执行下面的任务不在待办/待处理的任务中展示
29059 多分支产品批量创建需求时分支字段设为默认项
29059 多分支产品批量创建需求时分支字段设为默认项
29069 组织团队成员任务列表增加优先级排序功能
29074 用户下拉菜单中增加人员的头像/部门/职位信息
29108 提交/编辑软件需求页面中增加反馈者和通知邮箱信息
@@ -3647,12 +3973,12 @@
29127 计划的Bug列表中增加批量编辑和调整计划功能
29131 产品概况中增加评审人员的设置
29134 看板页面的刷新不要抖动用更加平滑的方式呈现
29141 启用多分支功能后要用例增加分支字样显示的控制
29142 启用多分支功能后要Bug增加分支字样显示的控制
29143 批量创建需求/BUG/用例时所属模块选择同上,需要检测上一行数据的所属分支和当前行的所属分支是否一致
29144 所有分支下批量编辑需求/BUG/用例,所属模块数据默认为所有分支的模块时,需要处理分支与模块不一致的问题
29145 项目和执行关联了产品的多个分支及计划时调整概况页面显示方式
29147 产品下软件需求列表需求名称前显示主干的分支名
29141 启用多分支功能后要用例增加分支字样显示的控制
29142 启用多分支功能后要Bug增加分支字样显示的控制
29143 批量创建需求/BUG/用例时所属模块选择同上,需要检测上一行数据的所属分支和当前行的所属分支是否一致
29144 所有分支下批量编辑需求/BUG/用例,所属模块数据默认为所有分支的模块时,需要处理分支与模块不一致的问题
29145 项目和执行关联了产品的多个分支及计划时调整概况页面显示方式
29147 产品下软件需求列表需求名称前显示主干的分支名
29156 启用多分支功能后项目需求列表增加是否显示分支名
29157 启用多分支功能后执行需求列表增加是否显示分支名
29158 启用多分支功能后执行任务列表增加是否显示分支名
+1 -1
View File
@@ -963,7 +963,7 @@ $lang->resource->projectreview = new stdclass();
$lang->resource->projecttrack = new stdclass();
$lang->resource->projectqa = new stdclass();
if($config->edition == 'biz' or $config->edition == 'max')
if($config->edition != 'open')
{
/* My module. */
$lang->resource->my->effort = 'effort'; // pro effort
+3 -2
View File
@@ -1,10 +1,11 @@
<?php
public function getExecutionStoryPairs($executionID = 0, $productID = 0, $branch = 'all', $moduleIdList = 0, $type = 'full', $status = 'all')
public function getExecutionStoryPairs($executionID = 0, $productID = 0, $branch = 'all', $moduleIdList = 0, $type = 'full', $status = 'all', $storyType = 'story')
{
if($this->config->vision == 'lite')
{
$execution = $this->loadModel('execution')->getById($executionID);
if($execution->project) $executionID = $execution->project;
}
return parent::getExecutionStoryPairs($executionID, $productID, $branch, $moduleIdList, $type, $status);
return parent::getExecutionStoryPairs($executionID, $productID, $branch, $moduleIdList, $type, $status, $storyType);
}
+119
View File
@@ -0,0 +1,119 @@
<?php
$lang->SRCommon = 'Requirement';
$lang->demandpool = new stdclass();
$lang->demandpool->common = 'RM Hub';
$lang->demand = new stdclass();
$lang->demand->common = 'Demand';
$lang->charter = new stdclass();
$lang->charter->common = 'Charter';
$lang->navIcons['demandpool'] = "<i class='icon icon-bars'></i>";
/* Main Navigation. */
$lang->mainNav = new stdclass();
$lang->mainNav->my = "{$lang->navIcons['my']} {$lang->my->shortCommon}|my|index|";
$lang->mainNav->demandpool = "{$lang->navIcons['demandpool']} {$lang->demandpool->common}|demandpool|browse|";
$lang->mainNav->product = "{$lang->navIcons['product']} {$lang->productCommon}|product|all|";
$lang->mainNav->charter = "{$lang->navIcons['project']} {$lang->charter->common}|charter|browse|";
$lang->mainNav->doc = "{$lang->navIcons['doc']} {$lang->doc->common}|doc|index|";
$lang->mainNav->admin = "{$lang->navIcons['admin']} {$lang->admin->common}|admin|index|";
//if($config->edition != 'open')
//{
// $lang->navIcons['feedback'] = "<i class='icon icon-feedback'></i>";
//
// $lang->mainNav->feedback = $lang->navIcons['feedback'] . 'Feedback|feedback|browse|browseType=unclosed';
//
// if($config->visions == ',lite,') unset($lang->mainNav->feedback);
//}
$lang->mainNav->menuOrder[5] = 'my';
$lang->mainNav->menuOrder[10] = 'demandpool';
$lang->mainNav->menuOrder[15] = 'product';
$lang->mainNav->menuOrder[20] = 'charter';
//$lang->mainNav->menuOrder[25] = 'feedback';
$lang->mainNav->menuOrder[30] = 'doc';
$lang->mainNav->menuOrder[35] = 'admin';
$lang->navGroup->demandpool = 'demandpool';
$lang->navGroup->demand = 'demandpool';
$lang->navGroup->roadmap = 'product';
$lang->navGroup->charter = 'charter';
$lang->demandpool->menu = new stdclass();
$lang->demandpool->menu->browse = array('link' => "{$lang->demand->common}|demand|browse|poolID=%s", 'alias' => 'create,batchcreate,edit,managetree,view,tostory,showimport,review,change');
//$lang->demandpool->menu->review = array('link' => "Review|demand|review|poolID=%s");
//$lang->demandpool->menu->kanban = array('link' => "Kanban|demand|kanban|poolID=%s");
//$lang->demandpool->menu->track = array('link' => "Track|demand|track|demandID=%s");
//$lang->demandpool->menu->insight = array('link' => "Insight|demand|insight|demandID=%s");
$lang->demandpool->menu->view = array('link' => "View|demandpool|view|poolID=%s", 'alias' => 'edit');
$lang->demandpool->menuOrder[5] = 'browse';
$lang->demandpool->menuOrder[10] = 'review';
$lang->demandpool->menuOrder[15] = 'kanban';
$lang->demandpool->menuOrder[20] = 'track';
$lang->demandpool->menuOrder[25] = 'insight';
$lang->demandpool->menuOrder[30] = 'view';
$lang->product->menu = new stdclass();
$lang->product->menu->requirement = array('link' => "Requirement|product|browse|productID=%s&branch=&browseType=assignedtome&param=0&storyType=requirement", 'alias' => 'batchedit', 'subModule' => 'story');
$lang->product->menu->roadmap = array('link' => "Roadmap|roadmap|browse|productID=%s");
#$lang->product->menu->initiating = array('link' => "Initiating|product|initiating|productID=%s");
$lang->product->menu->settings = array('link' => "{$lang->settings}|product|view|productID=%s", 'subModule' => 'tree,branch', 'alias' => 'edit,whitelist,addwhitelist');
$lang->product->menu->settings['subMenu'] = new stdclass();
$lang->product->menu->settings['subMenu']->view = array('link' => "{$lang->overview}|product|view|productID=%s", 'alias' => 'edit');
$lang->product->menu->settings['subMenu']->module = array('link' => "{$lang->module}|tree|browse|product=%s&view=story", 'subModule' => 'tree');
$lang->product->menu->settings['subMenu']->branch = array('link' => "@branch@|branch|manage|product=%s", 'subModule' => 'branch');
$lang->product->menu->settings['subMenu']->whitelist = array('link' => "{$lang->whitelist}|product|whitelist|product=%s", 'subModule' => 'personnel');
$lang->product->menuOrder = array();
$lang->product->menuOrder[5] = 'requirement';
$lang->product->menuOrder[10] = 'roadmap';
$lang->product->menuOrder[15] = 'initiating';
$lang->product->menuOrder[20] = 'settings';
unset($lang->product->homeMenu->home);
unset($lang->product->homeMenu->kanban);
$lang->charter->menu = new stdclass();
$lang->charter->menu->all = array('link' => "All|charter|browse|browseType=all");
$lang->charter->menu->wait = array('link' => "Wait|charter|browse|browseType=wait");
$lang->charter->menu->launched = array('link' => "Launched|charter|browse|browseType=launched");
$lang->charter->menu->failed = array('link' => "Failed|charter|browse|browseType=failed");
//$lang->charter->menu->settings = array('link' => "{$lang->settings}|charter|view|charterID=%s", 'subModule' => 'tree,branch', 'alias' => 'edit,whitelist,addwhitelist');
unset($lang->my->menu->project);
unset($lang->my->menu->execution);
unset($lang->my->menu->contribute);
unset($lang->my->menu->meeting);
unset($lang->doc->menu->project);
unset($lang->doc->menu->api);
$lang->my->menu->work = array('link' => "{$lang->my->work}|my|work|mode=requirement", 'subModule' => 'task');
$lang->my->menu->work['subMenu'] = new stdclass();
$lang->my->menu->work['subMenu']->requirement = "$lang->URCommon|my|work|mode=requirement";
unset($lang->createIcons['bug']);
unset($lang->createIcons['story']);
unset($lang->createIcons['task']);
unset($lang->createIcons['testcase']);
unset($lang->createIcons['program']);
unset($lang->createIcons['project']);
unset($lang->createIcons['execution']);
unset($lang->createIcons['kanbanspace']);
unset($lang->createIcons['kanban']);
$lang->searchObjects = array();
$lang->searchObjects['all'] = 'All';
$lang->searchObjects['story'] = 'Requirement';
$lang->searchObjects['demandpool'] = 'DemandPool';
$lang->searchObjects['demand'] = 'Demand';
$lang->searchObjects['roadmap'] = 'Roadmap';
$lang->searchObjects['charter'] = 'Charter';
$lang->searchObjects['product'] = $lang->productCommon;
$lang->searchObjects['doc'] = 'Document';
$lang->searchTips = 'ID(ctrl+g)';
+119
View File
@@ -0,0 +1,119 @@
<?php
$lang->SRCommon = 'Requirement';
$lang->demandpool = new stdclass();
$lang->demandpool->common = 'RM Hub';
$lang->demand = new stdclass();
$lang->demand->common = 'Demand';
$lang->charter = new stdclass();
$lang->charter->common = 'Charter';
$lang->navIcons['demandpool'] = "<i class='icon icon-bars'></i>";
/* Main Navigation. */
$lang->mainNav = new stdclass();
$lang->mainNav->my = "{$lang->navIcons['my']} {$lang->my->shortCommon}|my|index|";
$lang->mainNav->demandpool = "{$lang->navIcons['demandpool']} {$lang->demandpool->common}|demandpool|browse|";
$lang->mainNav->product = "{$lang->navIcons['product']} {$lang->productCommon}|product|all|";
$lang->mainNav->charter = "{$lang->navIcons['project']} {$lang->charter->common}|charter|browse|";
$lang->mainNav->doc = "{$lang->navIcons['doc']} {$lang->doc->common}|doc|index|";
$lang->mainNav->admin = "{$lang->navIcons['admin']} {$lang->admin->common}|admin|index|";
//if($config->edition != 'open')
//{
// $lang->navIcons['feedback'] = "<i class='icon icon-feedback'></i>";
//
// $lang->mainNav->feedback = $lang->navIcons['feedback'] . 'Feedback|feedback|browse|browseType=unclosed';
//
// if($config->visions == ',lite,') unset($lang->mainNav->feedback);
//}
$lang->mainNav->menuOrder[5] = 'my';
$lang->mainNav->menuOrder[10] = 'demandpool';
$lang->mainNav->menuOrder[15] = 'product';
$lang->mainNav->menuOrder[20] = 'charter';
//$lang->mainNav->menuOrder[25] = 'feedback';
$lang->mainNav->menuOrder[30] = 'doc';
$lang->mainNav->menuOrder[35] = 'admin';
$lang->navGroup->demandpool = 'demandpool';
$lang->navGroup->demand = 'demandpool';
$lang->navGroup->roadmap = 'product';
$lang->navGroup->charter = 'charter';
$lang->demandpool->menu = new stdclass();
$lang->demandpool->menu->browse = array('link' => "{$lang->demand->common}|demand|browse|poolID=%s", 'alias' => 'create,batchcreate,edit,managetree,view,tostory,showimport,review,change');
//$lang->demandpool->menu->review = array('link' => "Review|demand|review|poolID=%s");
//$lang->demandpool->menu->kanban = array('link' => "Kanban|demand|kanban|poolID=%s");
//$lang->demandpool->menu->track = array('link' => "Track|demand|track|demandID=%s");
//$lang->demandpool->menu->insight = array('link' => "Insight|demand|insight|demandID=%s");
$lang->demandpool->menu->view = array('link' => "View|demandpool|view|poolID=%s", 'alias' => 'edit');
$lang->demandpool->menuOrder[5] = 'browse';
$lang->demandpool->menuOrder[10] = 'review';
$lang->demandpool->menuOrder[15] = 'kanban';
$lang->demandpool->menuOrder[20] = 'track';
$lang->demandpool->menuOrder[25] = 'insight';
$lang->demandpool->menuOrder[30] = 'view';
$lang->product->menu = new stdclass();
$lang->product->menu->requirement = array('link' => "Requirement|product|browse|productID=%s&branch=&browseType=assignedtome&param=0&storyType=requirement", 'alias' => 'batchedit', 'subModule' => 'story');
$lang->product->menu->roadmap = array('link' => "Roadmap|roadmap|browse|productID=%s");
#$lang->product->menu->initiating = array('link' => "Initiating|product|initiating|productID=%s");
$lang->product->menu->settings = array('link' => "{$lang->settings}|product|view|productID=%s", 'subModule' => 'tree,branch', 'alias' => 'edit,whitelist,addwhitelist');
$lang->product->menu->settings['subMenu'] = new stdclass();
$lang->product->menu->settings['subMenu']->view = array('link' => "{$lang->overview}|product|view|productID=%s", 'alias' => 'edit');
$lang->product->menu->settings['subMenu']->module = array('link' => "{$lang->module}|tree|browse|product=%s&view=story", 'subModule' => 'tree');
$lang->product->menu->settings['subMenu']->branch = array('link' => "@branch@|branch|manage|product=%s", 'subModule' => 'branch');
$lang->product->menu->settings['subMenu']->whitelist = array('link' => "{$lang->whitelist}|product|whitelist|product=%s", 'subModule' => 'personnel');
$lang->product->menuOrder = array();
$lang->product->menuOrder[5] = 'requirement';
$lang->product->menuOrder[10] = 'roadmap';
$lang->product->menuOrder[15] = 'initiating';
$lang->product->menuOrder[20] = 'settings';
unset($lang->product->homeMenu->home);
unset($lang->product->homeMenu->kanban);
$lang->charter->menu = new stdclass();
$lang->charter->menu->all = array('link' => "All|charter|browse|browseType=all");
$lang->charter->menu->wait = array('link' => "Wait|charter|browse|browseType=wait");
$lang->charter->menu->launched = array('link' => "Launched|charter|browse|browseType=launched");
$lang->charter->menu->failed = array('link' => "Failed|charter|browse|browseType=failed");
//$lang->charter->menu->settings = array('link' => "{$lang->settings}|charter|view|charterID=%s", 'subModule' => 'tree,branch', 'alias' => 'edit,whitelist,addwhitelist');
unset($lang->my->menu->project);
unset($lang->my->menu->execution);
unset($lang->my->menu->contribute);
unset($lang->my->menu->meeting);
unset($lang->doc->menu->project);
unset($lang->doc->menu->api);
$lang->my->menu->work = array('link' => "{$lang->my->work}|my|work|mode=requirement", 'subModule' => 'task');
$lang->my->menu->work['subMenu'] = new stdclass();
$lang->my->menu->work['subMenu']->requirement = "$lang->URCommon|my|work|mode=requirement";
unset($lang->createIcons['bug']);
unset($lang->createIcons['story']);
unset($lang->createIcons['task']);
unset($lang->createIcons['testcase']);
unset($lang->createIcons['program']);
unset($lang->createIcons['project']);
unset($lang->createIcons['execution']);
unset($lang->createIcons['kanbanspace']);
unset($lang->createIcons['kanban']);
$lang->searchObjects = array();
$lang->searchObjects['all'] = 'All';
$lang->searchObjects['story'] = 'Requirement';
$lang->searchObjects['demandpool'] = 'DemandPool';
$lang->searchObjects['demand'] = 'Demand';
$lang->searchObjects['roadmap'] = 'Roadmap';
$lang->searchObjects['charter'] = 'Charter';
$lang->searchObjects['product'] = $lang->productCommon;
$lang->searchObjects['doc'] = 'Document';
$lang->searchTips = 'ID(ctrl+g)';
+119
View File
@@ -0,0 +1,119 @@
<?php
$lang->SRCommon = 'Requirement';
$lang->demandpool = new stdclass();
$lang->demandpool->common = 'RM Hub';
$lang->demand = new stdclass();
$lang->demand->common = 'Demand';
$lang->charter = new stdclass();
$lang->charter->common = 'Charter';
$lang->navIcons['demandpool'] = "<i class='icon icon-bars'></i>";
/* Main Navigation. */
$lang->mainNav = new stdclass();
$lang->mainNav->my = "{$lang->navIcons['my']} {$lang->my->shortCommon}|my|index|";
$lang->mainNav->demandpool = "{$lang->navIcons['demandpool']} {$lang->demandpool->common}|demandpool|browse|";
$lang->mainNav->product = "{$lang->navIcons['product']} {$lang->productCommon}|product|all|";
$lang->mainNav->charter = "{$lang->navIcons['project']} {$lang->charter->common}|charter|browse|";
$lang->mainNav->doc = "{$lang->navIcons['doc']} {$lang->doc->common}|doc|index|";
$lang->mainNav->admin = "{$lang->navIcons['admin']} {$lang->admin->common}|admin|index|";
//if($config->edition != 'open')
//{
// $lang->navIcons['feedback'] = "<i class='icon icon-feedback'></i>";
//
// $lang->mainNav->feedback = $lang->navIcons['feedback'] . 'Feedback|feedback|browse|browseType=unclosed';
//
// if($config->visions == ',lite,') unset($lang->mainNav->feedback);
//}
$lang->mainNav->menuOrder[5] = 'my';
$lang->mainNav->menuOrder[10] = 'demandpool';
$lang->mainNav->menuOrder[15] = 'product';
$lang->mainNav->menuOrder[20] = 'charter';
//$lang->mainNav->menuOrder[25] = 'feedback';
$lang->mainNav->menuOrder[30] = 'doc';
$lang->mainNav->menuOrder[35] = 'admin';
$lang->navGroup->demandpool = 'demandpool';
$lang->navGroup->demand = 'demandpool';
$lang->navGroup->roadmap = 'product';
$lang->navGroup->charter = 'charter';
$lang->demandpool->menu = new stdclass();
$lang->demandpool->menu->browse = array('link' => "{$lang->demand->common}|demand|browse|poolID=%s", 'alias' => 'create,batchcreate,edit,managetree,view,tostory,showimport,review,change');
//$lang->demandpool->menu->review = array('link' => "Review|demand|review|poolID=%s");
//$lang->demandpool->menu->kanban = array('link' => "Kanban|demand|kanban|poolID=%s");
//$lang->demandpool->menu->track = array('link' => "Track|demand|track|demandID=%s");
//$lang->demandpool->menu->insight = array('link' => "Insight|demand|insight|demandID=%s");
$lang->demandpool->menu->view = array('link' => "View|demandpool|view|poolID=%s", 'alias' => 'edit');
$lang->demandpool->menuOrder[5] = 'browse';
$lang->demandpool->menuOrder[10] = 'review';
$lang->demandpool->menuOrder[15] = 'kanban';
$lang->demandpool->menuOrder[20] = 'track';
$lang->demandpool->menuOrder[25] = 'insight';
$lang->demandpool->menuOrder[30] = 'view';
$lang->product->menu = new stdclass();
$lang->product->menu->requirement = array('link' => "Requirement|product|browse|productID=%s&branch=&browseType=assignedtome&param=0&storyType=requirement", 'alias' => 'batchedit', 'subModule' => 'story');
$lang->product->menu->roadmap = array('link' => "Roadmap|roadmap|browse|productID=%s");
#$lang->product->menu->initiating = array('link' => "Initiating|product|initiating|productID=%s");
$lang->product->menu->settings = array('link' => "{$lang->settings}|product|view|productID=%s", 'subModule' => 'tree,branch', 'alias' => 'edit,whitelist,addwhitelist');
$lang->product->menu->settings['subMenu'] = new stdclass();
$lang->product->menu->settings['subMenu']->view = array('link' => "{$lang->overview}|product|view|productID=%s", 'alias' => 'edit');
$lang->product->menu->settings['subMenu']->module = array('link' => "{$lang->module}|tree|browse|product=%s&view=story", 'subModule' => 'tree');
$lang->product->menu->settings['subMenu']->branch = array('link' => "@branch@|branch|manage|product=%s", 'subModule' => 'branch');
$lang->product->menu->settings['subMenu']->whitelist = array('link' => "{$lang->whitelist}|product|whitelist|product=%s", 'subModule' => 'personnel');
$lang->product->menuOrder = array();
$lang->product->menuOrder[5] = 'requirement';
$lang->product->menuOrder[10] = 'roadmap';
$lang->product->menuOrder[15] = 'initiating';
$lang->product->menuOrder[20] = 'settings';
unset($lang->product->homeMenu->home);
unset($lang->product->homeMenu->kanban);
$lang->charter->menu = new stdclass();
$lang->charter->menu->all = array('link' => "All|charter|browse|browseType=all");
$lang->charter->menu->wait = array('link' => "Wait|charter|browse|browseType=wait");
$lang->charter->menu->launched = array('link' => "Launched|charter|browse|browseType=launched");
$lang->charter->menu->failed = array('link' => "Failed|charter|browse|browseType=failed");
//$lang->charter->menu->settings = array('link' => "{$lang->settings}|charter|view|charterID=%s", 'subModule' => 'tree,branch', 'alias' => 'edit,whitelist,addwhitelist');
unset($lang->my->menu->project);
unset($lang->my->menu->execution);
unset($lang->my->menu->contribute);
unset($lang->my->menu->meeting);
unset($lang->doc->menu->project);
unset($lang->doc->menu->api);
$lang->my->menu->work = array('link' => "{$lang->my->work}|my|work|mode=requirement", 'subModule' => 'task');
$lang->my->menu->work['subMenu'] = new stdclass();
$lang->my->menu->work['subMenu']->requirement = "$lang->URCommon|my|work|mode=requirement";
unset($lang->createIcons['bug']);
unset($lang->createIcons['story']);
unset($lang->createIcons['task']);
unset($lang->createIcons['testcase']);
unset($lang->createIcons['program']);
unset($lang->createIcons['project']);
unset($lang->createIcons['execution']);
unset($lang->createIcons['kanbanspace']);
unset($lang->createIcons['kanban']);
$lang->searchObjects = array();
$lang->searchObjects['all'] = 'All';
$lang->searchObjects['story'] = 'Requirement';
$lang->searchObjects['demandpool'] = 'DemandPool';
$lang->searchObjects['demand'] = 'Demand';
$lang->searchObjects['roadmap'] = 'Roadmap';
$lang->searchObjects['charter'] = 'Charter';
$lang->searchObjects['product'] = $lang->productCommon;
$lang->searchObjects['doc'] = 'Document';
$lang->searchTips = 'ID(ctrl+g)';
+119
View File
@@ -0,0 +1,119 @@
<?php
$lang->SRCommon = '用户需求';
$lang->demandpool = new stdclass();
$lang->demandpool->common = '需求池';
$lang->demand = new stdclass();
$lang->demand->common = '需求';
$lang->charter = new stdclass();
$lang->charter->common = '立项';
$lang->navIcons['demandpool'] = "<i class='icon icon-bars'></i>";
/* Main Navigation. */
$lang->mainNav = new stdclass();
$lang->mainNav->my = "{$lang->navIcons['my']} {$lang->my->shortCommon}|my|index|";
$lang->mainNav->demandpool = "{$lang->navIcons['demandpool']} {$lang->demandpool->common}|demandpool|browse|";
$lang->mainNav->product = "{$lang->navIcons['product']} {$lang->productCommon}|product|all|";
$lang->mainNav->charter = "{$lang->navIcons['project']} {$lang->charter->common}|charter|browse|";
$lang->mainNav->doc = "{$lang->navIcons['doc']} {$lang->doc->common}|doc|index|";
$lang->mainNav->admin = "{$lang->navIcons['admin']} {$lang->admin->common}|admin|index|";
//if($config->edition != 'open')
//{
// $lang->navIcons['feedback'] = "<i class='icon icon-feedback'></i>";
//
// $lang->mainNav->feedback = $lang->navIcons['feedback'] . '反馈|feedback|browse|browseType=unclosed';
//
// if($config->visions == ',lite,') unset($lang->mainNav->feedback);
//}
$lang->mainNav->menuOrder[5] = 'my';
$lang->mainNav->menuOrder[10] = 'demandpool';
$lang->mainNav->menuOrder[15] = 'product';
$lang->mainNav->menuOrder[20] = 'charter';
//$lang->mainNav->menuOrder[25] = 'feedback';
$lang->mainNav->menuOrder[30] = 'doc';
$lang->mainNav->menuOrder[35] = 'admin';
$lang->navGroup->demandpool = 'demandpool';
$lang->navGroup->demand = 'demandpool';
$lang->navGroup->roadmap = 'product';
$lang->navGroup->charter = 'charter';
$lang->demandpool->menu = new stdclass();
$lang->demandpool->menu->browse = array('link' => "{$lang->demand->common}|demand|browse|poolID=%s", 'alias' => 'create,batchcreate,edit,managetree,view,tostory,showimport,review,change');
//$lang->demandpool->menu->review = array('link' => "评审|demand|review|poolID=%s");
//$lang->demandpool->menu->kanban = array('link' => "看板|demand|kanban|poolID=%s");
//$lang->demandpool->menu->track = array('link' => "矩阵图|demand|track|demandID=%s");
//$lang->demandpool->menu->insight = array('link' => "洞察|demand|insight|demandID=%s");
$lang->demandpool->menu->view = array('link' => "概况|demandpool|view|poolID=%s", 'alias' => 'edit');
$lang->demandpool->menuOrder[5] = 'browse';
$lang->demandpool->menuOrder[10] = 'review';
$lang->demandpool->menuOrder[15] = 'kanban';
$lang->demandpool->menuOrder[20] = 'track';
$lang->demandpool->menuOrder[25] = 'insight';
$lang->demandpool->menuOrder[30] = 'view';
$lang->product->menu = new stdclass();
$lang->product->menu->requirement = array('link' => "{$lang->URCommon}|product|browse|productID=%s&branch=&browseType=assignedtome&param=0&storyType=requirement", 'alias' => 'batchedit', 'subModule' => 'story');
$lang->product->menu->roadmap = array('link' => "路标|roadmap|browse|productID=%s");
#$lang->product->menu->initiating = array('link' => "立项|product|initiating|productID=%s");
$lang->product->menu->settings = array('link' => "{$lang->settings}|product|view|productID=%s", 'subModule' => 'tree,branch', 'alias' => 'edit,whitelist,addwhitelist');
$lang->product->menu->settings['subMenu'] = new stdclass();
$lang->product->menu->settings['subMenu']->view = array('link' => "{$lang->overview}|product|view|productID=%s", 'alias' => 'edit');
$lang->product->menu->settings['subMenu']->module = array('link' => "{$lang->module}|tree|browse|product=%s&view=story", 'subModule' => 'tree');
$lang->product->menu->settings['subMenu']->branch = array('link' => "@branch@|branch|manage|product=%s", 'subModule' => 'branch');
$lang->product->menu->settings['subMenu']->whitelist = array('link' => "{$lang->whitelist}|product|whitelist|product=%s", 'subModule' => 'personnel');
$lang->product->menuOrder = array();
$lang->product->menuOrder[5] = 'requirement';
$lang->product->menuOrder[10] = 'roadmap';
$lang->product->menuOrder[15] = 'initiating';
$lang->product->menuOrder[20] = 'settings';
unset($lang->product->homeMenu->home);
unset($lang->product->homeMenu->kanban);
$lang->charter->menu = new stdclass();
$lang->charter->menu->all = array('link' => "全部|charter|browse|browseType=all");
$lang->charter->menu->wait = array('link' => "待立项|charter|browse|browseType=wait");
$lang->charter->menu->launched = array('link' => "已立项|charter|browse|browseType=launched");
$lang->charter->menu->failed = array('link' => "未通过|charter|browse|browseType=failed");
//$lang->charter->menu->settings = array('link' => "{$lang->settings}|charter|view|charterID=%s", 'subModule' => 'tree,branch', 'alias' => 'edit,whitelist,addwhitelist');
unset($lang->my->menu->project);
unset($lang->my->menu->execution);
unset($lang->my->menu->contribute);
unset($lang->my->menu->meeting);
unset($lang->doc->menu->project);
unset($lang->doc->menu->api);
$lang->my->menu->work = array('link' => "{$lang->my->work}|my|work|mode=requirement", 'subModule' => 'task');
$lang->my->menu->work['subMenu'] = new stdclass();
$lang->my->menu->work['subMenu']->requirement = "$lang->URCommon|my|work|mode=requirement";
unset($lang->createIcons['bug']);
unset($lang->createIcons['story']);
unset($lang->createIcons['task']);
unset($lang->createIcons['testcase']);
unset($lang->createIcons['program']);
unset($lang->createIcons['project']);
unset($lang->createIcons['execution']);
unset($lang->createIcons['kanbanspace']);
unset($lang->createIcons['kanban']);
$lang->searchObjects = array();
$lang->searchObjects['all'] = '全部';
$lang->searchObjects['story'] = '需求';
$lang->searchObjects['demandpool'] = '需求池';
$lang->searchObjects['demand'] = '需求池需求';
$lang->searchObjects['roadmap'] = '路标';
$lang->searchObjects['charter'] = '立项';
$lang->searchObjects['product'] = $lang->productCommon;
$lang->searchObjects['doc'] = '文档';
$lang->searchTips = '编号(ctrl+g)';
+13 -1
View File
@@ -417,7 +417,6 @@ class baseEntry
*/
public function setPost($key, $value)
{
if(in_array($key, array('desc', 'spec', 'verify', 'steps'))) $value = htmlspecialchars($value);
$_POST[$key] = $value;
}
@@ -476,6 +475,19 @@ class baseEntry
}
}
/**
* 检查是否在后台启用了代号.
* Check whether config->setCode are used in product,project,execution.
*
* @access public
* @return bool
*/
public function checkCodeUsed()
{
return isset($this->config->setCode) ? $this->config->setCode : 0;
}
/**
* 格式化数据的字段类型.
* Format fields of response data.
+34
View File
@@ -279,4 +279,38 @@ class api extends router
return $output;
}
/**
* 设置vision。
* set Debug.
*
* @access public
* @return void
*/
public function setVision()
{
$account = isset($_SESSION['user']) ? $_SESSION['user']->account : '';
if(empty($account) and isset($_POST['account'])) $account = $_POST['account'];
if(empty($account) and isset($_GET['account'])) $account = $_GET['account'];
$vision = 'rnd';
if($this->config->installed and validater::checkAccount($account))
{
$sql = new sql();
$account = $sql->quote($account);
$user = $this->dbh->query("SELECT * FROM " . TABLE_USER . " WHERE account = $account AND deleted = '0' LIMIT 1")->fetch();
if(!empty($user->visions))
{
$userVisions = explode(',', $user->visions);
if(!in_array($vision, $userVisions)) $vision = '';
if(empty($vision)) list($vision) = $userVisions;
}
}
list($defaultVision) = explode(',', trim($this->config->visions, ','));
if($vision and strpos($this->config->visions, ",{$vision},") === false) $vision = $defaultVision;
$this->config->vision = $vision ? $vision : $defaultVision;
}
}
+1
View File
@@ -955,6 +955,7 @@ class baseControl
for($i = 0; $i < $obLevel; $i++) ob_end_clean();
$response = helper::removeUTF8Bom(urldecode(json_encode($data)));
$this->app->outputXhprof();
die($response);
}
+14
View File
@@ -255,6 +255,7 @@ class baseHelper
return "IN ('" . join("','", $idList) . "')";
}
if(is_null($idList)) $idList = '';
if(!is_string($idList)) $idList = json_encode($idList);
$idList = addslashes($idList);
return "IN ('" . str_replace(',', "','", str_replace(' ', '', $idList)) . "')";
@@ -786,6 +787,19 @@ class baseHelper
return null;
}
/**
* 检查是否启用缓存。
* Check is enable cache.
*
* @return bool
*/
public static function isCacheEnabled()
{
if(isset($_GET['_nocache']) || isset($_SERVER['HTTP_X_ZT_REFRESH'])) return false;
global $config;
return $config->cache->enable;
}
}
//------------------------------- 常用函数。Some tool functions.-------------------------------//
+39 -1
View File
@@ -718,7 +718,7 @@ class baseRouter
*
* @return bool
*/
protected function outputXhprof()
public function outputXhprof()
{
if(empty($this->config->debug) || $this->config->debug < 4 || !extension_loaded('xhprof')) return false;
@@ -2250,11 +2250,49 @@ class baseRouter
return $module;
} catch (EndResponseException $endResponseException) {
echo $endResponseException->getContent();
return false;
}
return isset($module) ? $module : false;
}
/**
* 输出内容。
* Output the content.
*
* @return string
*/
public function outputPage()
{
$cacheEnable = $this->config->cache->enableFullPage;
/* If caching is not turned on, pages that do not need to be cached, or when searching, they are not cached. */
if(!$cacheEnable || !in_array("{$this->moduleName}|{$this->methodName}", $this->config->cache->fullPages) || stripos($this->server->request_uri, 'search') !== false || isset($_GET['_nocache']) || $this->server->http_x_zt_refresh)
{
$this->loadModule();
return helper::removeUTF8Bom(ob_get_clean());
}
$this->loadClass('cache', $static = true);
$cacheKey = md5($this->server->request_uri);
$namespace = isset($this->session->user->account) ? $this->session->user->account : 'guest';
$cache = cache::create($this->config->cache->fullPageDriver, $namespace, $this->config->cache->fullPageLifetime);
if($cache->has($cacheKey))
{
if(!headers_sent()) header('X-Zt-Hit-Cache: 1');
$content = $cache->get($cacheKey);
}
else
{
ob_start();
$result = $this->loadModule();
$content = helper::removeUTF8Bom(ob_get_clean());
/* If the module is loaded successfully, cache the content. */
if($result !== false) $cache->set($cacheKey, $content);
}
return $content;
}
/**
* 加载指定模块下的某种对象。
* Load the target object of one module.
+1 -1
View File
@@ -121,7 +121,7 @@ class control extends baseControl
*/
public function setDefaultPrivByWorkflow()
{
$actionList = $this->dao->select('module, action')->from(TABLE_WORKFLOWACTION)
$actionList = $this->dao->select('module, `action`')->from(TABLE_WORKFLOWACTION)
->where('createdBy')->eq($this->app->user->account)
->andWhere('buildin')->eq('0')
->fetchGroup('module');
+3
View File
@@ -350,6 +350,9 @@ class helper extends baseHelper
}
/**
* 是否是内网。
* Check is intranet.
*
* @return bool
*/
public static function isIntranet()
+6 -2
View File
@@ -97,10 +97,12 @@ class model extends baseModel
if(empty($module)) $module = $moduleName;
if(empty($method)) $method = $methodName;
static $actions = array();
static $actions = array();
static $hasAction = array();
if(!isset($hasAction[$moduleName])) $hasAction[$moduleName] = true;
if($this->config->edition != 'open')
{
if(empty($actions[$moduleName]))
if($hasAction[$moduleName] and empty($actions[$moduleName]))
{
$actions[$moduleName] = $this->dao->select('*')->from(TABLE_WORKFLOWACTION)
->where('module')->eq($moduleName)
@@ -108,6 +110,8 @@ class model extends baseModel
->andWhere('status')->eq('enable')
->beginIF(!empty($this->config->vision))->andWhere('vision')->eq($this->config->vision)->fi()
->fetchAll('action');
if(empty($actions[$moduleName])) $hasAction[$moduleName] = false;
}
}
+4 -1
View File
@@ -506,7 +506,10 @@ class router extends baseRouter
}
else
{
$action = $this->dbh->query("SELECT * FROM " . TABLE_WORKFLOWACTION . " WHERE `module` = '$this->moduleName' AND `action` = '$this->methodName' AND `vision` = '{$this->config->vision}'")->fetch();
$actionQuery = "SELECT * FROM " . TABLE_WORKFLOWACTION . " WHERE `module` = '$this->moduleName' AND `action` = '$this->methodName'";
if(isset($this->app->user) && $this->app->user->account != 'guest') $actionQuery .= " AND `vision` = '{$this->config->vision}'";
$action = $this->dbh->query($actionQuery)->fetch();
if(zget($action, 'extensionType') == 'override')
{
$this->rawModule = $this->moduleName;
+1 -1
View File
@@ -1259,7 +1259,7 @@ EOT;
* Set js value.
*
* @param string $key
* @param mix $value
* @param mixed $value
* @static
* @access public
* @return string
+121 -8
View File
@@ -151,14 +151,15 @@ class dbh
public function tableExits($tableName)
{
$tableName = str_replace('`', "'", $tableName);
$sql = "SHOW TABLES FROM {$this->config->name} like $tableName";
$tableName = str_replace("'", "", $tableName);
$sql = "SHOW TABLES FROM {$this->config->name} like '{$tableName}'";
switch($this->config->driver)
{
case 'mysql':
$sql = "SHOW TABLES FROM {$this->config->name} like {$tableName}";
$sql = "SHOW TABLES FROM {$this->config->name} like '{$tableName}'";
break;
case 'dm':
$sql = "SELECT * FROM all_tables WHERE owner='{$this->config->name}' AND table_name={$tableName}";
$sql = "SELECT * FROM all_tables WHERE owner='{$this->config->name}' AND table_name='{$tableName}'";
break;
default:
$sql = '';
@@ -255,7 +256,8 @@ class dbh
public function formatDmSQL($sql)
{
$sql = trim($sql);
$sql = str_replace(array('\r', '\n'), ' ', $sql);
/* '\\\\n' try to compatible screen json like \u0232\\nBug. */
$sql = str_replace(array('\\\\n', '\r', '\n'), ' ', $sql);
$sql = $this->formatFunction($sql);
$actionPos = strpos($sql, ' ');
@@ -266,7 +268,10 @@ class dbh
case 'SELECT':
return $this->formatField($sql);
case 'REPLACE':
$sql = str_replace('REPLACE', 'INSERT', $sql);
$result = $this->processReplace($sql);
if($result != $sql) return $result;
$sql = str_replace('REPLACE', 'INSERT', $sql);
$action = 'INSERT';
case 'INSERT':
case 'UPDATE':
@@ -278,7 +283,7 @@ class dbh
if(strpos($sql, '\\\\') !== FALSE) $sql = str_replace('\\\\', '\\', $sql);
break;
case 'CREATE':
if(stripos($sql, 'CREATE VIEW') === 0) return '';
if(stripos($sql, 'CREATE VIEW') === 0) $sql = str_replace('CREATE VIEW', 'CREATE OR REPLACE VIEW', $sql);
if(stripos($sql, 'CREATE FUNCTION') === 0) return '';
if(stripos($sql, 'CREATE OR REPLACE VIEW ') === 0)
@@ -306,10 +311,11 @@ class dbh
$fields = implode(',', $fieldList);
return substr($sql, 0, $fieldsBegin+6) . $fields . substr($sql, $fieldsEnd);
}
elseif(stripos($sql, 'CREATE UNIQUE INDEX') === 0)
elseif(stripos($sql, 'CREATE UNIQUE INDEX') === 0 || stripos($sql, 'CREATE INDEX') === 0)
{
preg_match('/ON\ +[0-9a-zA-Z\_\.]+\`([0-9a-zA-Z\_]+)\`/', $sql, $matches);
$tableName = explode('_', $matches[1]);
$tableName = str_replace($this->config->prefix, '', $matches);
$sql = preg_replace('/INDEX\ +\`/', 'INDEX `' . strtolower($tableName[1]) . '_', $sql);
}
case 'ALTER':
@@ -320,6 +326,9 @@ class dbh
if(stripos($sql, 'SET SCHEMA') === 0) return $sql;
case 'USE':
return '';
case 'DESC';
$tableName = str_replace('DESC ', '', $sql);
return "select COLUMN_NAME as Field from all_tab_columns where Table_Name='$tableName'";
case 'DROP':
return $this->formatField($sql);
}
@@ -452,11 +461,115 @@ class dbh
$sql = preg_replace('/\,\s+key[\_\"0-9a-z ]+\(+[\,\_\"0-9a-z ]+\)+/i', '', $sql);
$sql = preg_replace('/\,\s*(unique|fulltext)*\s+key[\_\"0-9a-z ]+\(+[\,\_\"0-9a-z ]+\)+/i', '', $sql);
$sql = preg_replace('/ float\s*\(+[\,\_\"0-9a-z ]+\)+/i', ' float', $sql);
/* Convert "date" datetime to "date" datetime(0) to fix bug 25725, dm database datetime default 6 */
preg_match_all('/"[0-9a-zA-Z]+" datetime/', $sql, $datetimeMatch);
if(!empty($datetimeMatch))
{
foreach($datetimeMatch[0] as $match) $sql = str_replace($match, $match . '(0)', $sql);
}
if(strpos($sql, "ALTER TABLE") !== false) $sql = $this->convertAlterTableSql($sql);
}
return $sql;
}
/**
* Process replace into sql.
*
* @param mixed $sql
* @access public
* @return void
*/
public function processReplace($sql)
{
// 解析REPLACE INTO语句,提取出表名、字段和值
$matches = [];
preg_match('/^REPLACE\s+INTO\s+`?([\w_]+)`?\s*\((.*)\)\s+VALUES\s*\((.*?)\)\s*$/i', $sql, $matches);
$table_name = $matches[1];
$columns = array_map('trim', explode(',', $matches[2]));
$values = array_map('trim', explode(', ', $matches[3]));
if($table_name == '' or $columns == '' or $values == '') return $sql;
// 构造SELECT语句,查询数据是否存在
$where = [];
foreach ($columns as $index => $column) {
$value = trim($values[$index], "'");
$column = trim($column, '`');
$values[$index] = $value;
$columns[$index] = $column;
$where[] = "`$column` = '$value'";
}
$select_sql = "SELECT * FROM `$table_name` WHERE " . implode(' AND ', $where);
$result = $this->query($select_sql);
$result = $result->fetchAll();
$sql = in_array('id', $columns) ? "SET IDENTITY_INSERT `$table_name` ON;" : '';
if($result)
{
// 数据已存在,构造UPDATE语句并执行
$set = [];
$where = [];
foreach ($columns as $index => $column) {
$value = $values[$index];
$set[] = "`$column` = '$value'";
$where[] = "`$column` = '$value'";
}
$sql .= "UPDATE `$table_name` SET " . implode(', ', $set) . " WHERE " . implode(' AND ', $where);
}
else
{
// 数据不存在,构造INSERT INTO语句并执行
$selectColumn = array();
$selectValue = array();
foreach ($columns as $index => $column) {
$selectColumn[] .= "`$column`";
$selectValue[] .= "'{$values[$index]}'";
}
$sql .= "INSERT INTO `$table_name` (" . implode(', ', $selectColumn) . ") VALUES (" . implode(', ', $selectValue) . ")";
}
return $sql;
}
/**
* Convert alter table sql.
*
* @param mixed $sql
* @access public
* @return void
*/
public function convertAlterTableSql($sql)
{
/* If table has datas and sql no default values defined, add default ''/0. */
if(strpos($sql, "NOT NULL") !== false && strpos($sql, "DEFAULT") === false)
{
$default = '';
if(strpos($sql, "integer") !== false) $default = 0;
$sql = str_replace("NOT NULL", "NOT NULL DEFAULT '" . $default ."'", $sql);
}
$pattern = '/ALTER TABLE "(.*?)" CHANGE "(.*?)" "(.*?)" (.*?)(?:;|$)/';
preg_match($pattern, $sql, $matches);
if(count($matches) != 5) return $sql;
$tableName = $matches[1];
$oldColumnName = $matches[2];
$newColumnName = $matches[3];
$params = str_replace("'", "''", $matches[4]);
$sql = 'begin ';
if($oldColumnName != $newColumnName) $sql .= "execute immediate 'ALTER TABLE $tableName ALTER " . '"' . $oldColumnName . '" RENAME TO "' . $newColumnName . '"' . "';";
$sql .= "execute immediate 'ALTER TABLE $tableName MODIFY " . '"' . $newColumnName . '" ' . $params . "';";
$sql .= 'end;';
return $sql;
}
/**
* Quote.
*
+4 -4
View File
@@ -218,7 +218,7 @@ class mobile
'iPad' => 'iPad|iPad.*Mobile',
// Removed |^.*Android.*Nexus(?!(?:Mobile).)*$
// @see #442
'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone.
// http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI)\b',
@@ -756,11 +756,11 @@ class mobile
return self::$uaHttpHeaders;
}
/**
* Set CloudFront headers
* http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
*
*
* @param array $cfHeaders List of HTTP headers
*
* @return boolean If there were CloudFront headers to be set
@@ -1213,7 +1213,7 @@ class mobile
*/
public function match($regex, $userAgent = null)
{
$match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches);
$match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : ($this->userAgent ? $this->userAgent : '')), $matches);
// If positive match is found, store the results for debug.
if ($match) {
$this->matchingRegex = $regex;
+36
View File
@@ -20,6 +20,28 @@ helper::import(dirname(dirname(__FILE__)) . '/base/pager/pager.class.php');
*/
class pager extends basePager
{
/**
* 分页查询起始偏移量。
* offset
*
* @var float
* @access public
*/
public $offset = 0;
/**
* 设置分页查询起始偏移量。
* Set offset of paging query.
*
* @param int $offset
* @access public
* @return void
*/
public function setOffset($offset)
{
$this->offset = $offset;
}
/**
* 设置模块名。
* Set the $moduleName property.
@@ -85,6 +107,20 @@ class pager extends basePager
if($this->app->isFlow) unset($this->params['module']);
}
/**
* 创建limit语句。
* Create the limit string.
*
* @access public
* @return string
*/
public function limit()
{
$limit = '';
if($this->pageTotal > 1) $limit = ' lImiT ' . ($this->offset + ($this->pageID - 1) * $this->recPerPage) . ", $this->recPerPage";
return $limit;
}
/**
* Show pager.
*
+3 -1
View File
@@ -15,7 +15,9 @@ 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, $repo);
$repoRoot = $repo->path;
if('Subversion' == $className && !empty($repo->prefix)) $repoRoot = substr($repo->path, 0, strlen($repo->path) - strlen($repo->prefix));
$this->engine = new $className($repo->client, $repoRoot, $repo->account, $repo->password, $repo->encoding, $repo);
}
/**
+28 -1
View File
@@ -257,7 +257,7 @@ class zdb
/* Create a value sql. */
$value = array_values($row);
$value = array_map('addslashes', $value);
$value = $this->addslashes($value);
$value = join("','", $value);
$value = "'" . $value . "'";
$sql = "INSERT INTO `$table`($keys) VALUES (" . $value . ");\n";
@@ -367,4 +367,31 @@ class zdb
return $return;
}
}
/**
* Add slashes for string or string list.
*
* @param string|string[] $data
* @return string|string[]
*/
public function addslashes($data)
{
if(is_string($data)) return addslashes($data);
if((function_exists('array_is_list') && array_is_list($data)) || (is_array($data) && array_keys($data) === array_keys(array_keys($data))))
{
$result = array();
foreach($data as $item)
{
if(is_string($item))
$result[] = addslashes($item);
elseif(is_null($item))
$result[] = null;
else
$result[] = $item;
}
return $result;
}
return $data;
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"require-dev": {
"rector/rector": "0.15.*"
},
"scripts": {
"rector": [
"Composer\\Config::disableProcessTimeout",
"rector process --no-diffs --no-progress-bar"
],
"rector-nocache": [
"Composer\\Config::disableProcessTimeout",
"rector process --no-diffs --no-progress-bar --clear-cache"
]
}
}
+319
View File
@@ -0,0 +1,319 @@
#!/bin/bash
set -e
phpVer="7.4"
installRector="false"
codeRootDir=$PWD
composerDir="$(dirname "$(realpath "$0")")"
outputDir="$PWD/build"
helper() {
cat << EOF
Usage: $0 -p version dirs...
Arguments:
-p php版本号,如 7.4
可以指定多个版本,用逗号分隔,如 7.4,7.0,5.4
-i 在 misc 目录执行 composer install, 安装 rector
-r 指定要降级的代码根目录, 默认为当前目录
-o 降级补丁包输出目录
EOF
}
# 处理命令行参数, 获取要降级的目录
[ $# -eq 0 ] && helper
while getopts "ir:p:o:" opt; do
case $opt in
"p")
phpVer=$OPTARG
;;
"r")
codeRootDir=$(realpath "$OPTARG")
;;
"i")
installRector="true"
;;
"o")
outputDir=$OPTARG
;;
*)
helper
exit 1
;;
esac
done
shift $((OPTIND - 1))
if [ "$#" -eq 0 ];then
echo "need at least one file or directory"
exit 2
fi
# 处理降级目录路径
downGradeDirs=()
for d in "$@"
do
targetDir="$codeRootDir/$d"
test -d "$targetDir" || (echo "$d ($targetDir) is not a directory, abort."; exit 2)
downGradeDirs+=("${targetDir}")
done
# 结束命令行参数处理
excludeRegexList=(
module/holiday/ext/
lib/purifier/HTMLPurifier.autoload-legacy.php
lib/sqlparser/vendor/
)
##################################
# 在非容器环境,返回 cpu 核数减一
# 在容器环境,如未对 cpu 做限制,返回宿主机核数减一,否则按实际限制的 cpu 核数
##################################
quotaFile="/sys/fs/cgroup/cpu.max"
getCpuQuota() {
if [ -f $quotaFile ];then
quota=$(cut -d ' ' -f 1 $quotaFile)
period=$(cut -d ' ' -f 2 $quotaFile)
if [ "$quota" = "max" ];then
echo $(($(nproc)-1))
return
else
echo $((quota/period))
return
fi
else
echo $(($(nproc)-1))
return
fi
}
# 检查要降级版本的 php 命令行是否存在,将用于校验语法
existsPHPCli() {
phpVersion="$1"
which php"${phpVersion}" >/dev/null
}
#########################################
# 执行降级命令
# 参数:
# 1. 降级版本, 如 7.4, 7.0
# 2. 关闭缓存 (可选项), nocache
# 3. 并行执行 (可选项), parallel
# * 降级目录列表
# 说明
# 1. 由于降级命令有可能会发生异常,故设置了重试,
# 在函数运行时,缓存目录不变,故重试时会减少部分时间
# 2. 并行执行的个数,根据 cpu 最大核数减一处理,如果是容器环境,按分配的核数
# 并行执行需要安装 parallel 包
##########################################
maxRectorRetries=3
downGradeDir() {
rectorCmd="rector"
export PHP_VERSION=${1/./}
shift
if [ "$1" = "nocache" ];then
rectorCmd="rector-nocache"
shift
fi
withParallel="false"
if [ "$1" = "parallel" ];then
withParallel="true"
shift
fi
downDirs=("$@")
echo "set PHP_VERSION to $PHP_VERSION"
echo "do downgrade on dir ${downDirs[*]}"
lastDir=$PWD
cd "$composerDir" || exit
rectorResult=0
set +e
for ((i=0;i<maxRectorRetries;i++)) {
if [ "$withParallel" = "true" ];then
quotaCpu=$(getCpuQuota)
parallel -j "$quotaCpu" -k composer "${rectorCmd}" ::: "${downDirs[@]}"
else
composer ${rectorCmd} -- "${downDirs[@]}"
fi
rectorResult="$?"
if [ "$rectorResult" -eq 0 ];then
break
fi
}
set -e
if [ "$rectorResult" -ne 0 ];then
echo "Rector failed"
return $rectorResult
fi
cd "$lastDir" || exit
}
############################
# 校验单个 php 文件语法
# 返回值
# 0 没有语法错误
# 1 语法异常,或是执行时异常
############################
syntaxCheck() {
phpVersion="$1"
phpFilePath="$2"
phpCli=$(which php"${phpVersion}")
$phpCli -l "$phpFilePath" | grep -v 'No syntax errors detected' && return 1 || return 0
}
########################################
# 确保php文件语法正确
# 第一次校验失败后,对文件所在目录执行一次降级
# 再做第二次校验,如继续失败,返回错误
########################################
ensureSyntaxPassed() {
phpVersion="$1"
phpFilePath="$2"
beforeMD5=$(md5sum "$phpFilePath" | awk '{print $1}')
if syntaxCheck "$phpVersion" "$phpFilePath";then
echo "Syntax OK, $phpFilePath"
else
downGradeDir "$phpVersion" "nocache" "$(dirname "$phpFilePath")"
afterMD5=$(md5sum "$phpFilePath" | awk '{print $1}')
if ! syntaxCheck "$phpVersion" "$phpFilePath";then
echo "downgrade failed"
echo "md5 compare (before:$beforeMD5) (after:$afterMD5)"
return 1
else
echo "Syntax OK, $phpFilePath"
fi
fi
}
#########################################
# 将变更的文件打包
# 判断条件为文件修改时间晚于脚本开始执行的时间
#########################################
archiveChangedFiles() {
phpVersion="$1"
pointTime=$2
archiveDir=$3
find "$archiveDir" -type f -name '*.php' -newermt "$pointTime" -printf "%P\n" > /tmp/changedFiles
lastDir=$PWD
cd "$archiveDir" || exit 1
mkdir -p build/
test -d "$outputDir" || mkdir -pv "$outputDir"
downPatchFile="${outputDir}/downgrade-php$phpVersion.tar.gz"
tar zcf "$downPatchFile" --files-from=/tmp/changedFiles
echo "Release downgrade patch file: $downPatchFile"
cd "$lastDir"
}
# 正则匹配要排除的文件,跳过校验
matchExclude() {
filePath="$1"
for reg in "${excludeRegexList[@]}"
do
if [[ "$filePath" =~ $reg ]];then
echo "true"
return
fi
done
echo "false"
}
#############################
# 对单个 php 版本降级的主函数
# 参数:
# 1. php 版本
# 2. 起始时间, 用于比较降级后变更的文件
# * 降级目录列表
# 步骤:
# 设置临时缓存目录,执行降级
# 对降级目录里所有 php 文件校验语法,确保通过
# 打包变更文件
########################################
DownGrade() {
phpVersion="$1"
pointTime="$2"
shift 2
downDirs=("$@")
RECTOR_CACHE_DIR=$(mktemp -d)
export RECTOR_CACHE_DIR
startTime="$(date +%s)"
if which parallel >/dev/null ;then
downGradeDir "$phpVersion" parallel "${downDirs[@]}"
else
for d in "${downDirs[@]}"
do
downGradeDir "$phpVersion" "$d"
done
fi
for f in $(find "${downGradeDirs[@]}" -type f -name '*.php')
do
shouldIgnore=$(matchExclude "$f")
if [ "$shouldIgnore" = "true" ];then
echo "$f is excluded"
continue
fi
ensureSyntaxPassed "$phpVersion" "$f"
done
archiveChangedFiles "$phpVersion" "$pointTime" "$codeRootDir"
test -d "$RECTOR_CACHE_DIR" && rm -rf "$RECTOR_CACHE_DIR"
endTime="$(date +%s)"
echo "downgrade to ${phpVersion} cost $((endTime-startTime)) seconds"
echo
}
# 设置脚本启动时间
startPointTime=$(date +'%Y-%m-%d %H:%M:%S')
# 执行 composer 组件安装
if [ "$installRector" = "true" ];then
lastDir=$PWD
cd "$composerDir" || exit 1
composer config -g repo.packagist composer https://mirrors.cloud.tencent.com/composer/
composer install
cd "$lastDir" || exit 1
fi
# 检查 -p 参数, 执行多版本降级或是单版本降级
if [[ "$phpVer" =~ ^.*, ]];then
IFS=',' read -r -a verList <<< "$phpVer"
for v in "${verList[@]}"
do
existsPHPCli "$v" || (echo "php${v} is not found, abort."; exit 3)
done
for v in "${verList[@]}"
do
DownGrade "$v" "$startPointTime" "${downGradeDirs[@]}"
done
else
existsPHPCli "$phpVer" || (echo "php${phpVer} is not found, abort."; exit 3)
DownGrade "$phpVer" "$startPointTime" "${downGradeDirs[@]}"
fi
# syntaxCheck "$phpVer" /code/module/pipeline/model.php
# downGradeDir "$phpVer" "${downGradeDirs[@]}"
# archiveChangedFiles "$t" "$codeRootDir"
+87
View File
@@ -0,0 +1,87 @@
#!/bin/bash
finishTime=$(date '+%Y-%m-%d %H:%M:%S')
blankLine() {
echo
}
outputFrame() {
printf "$1"
}
outputLine() {
echo "$1"
}
renderGitWebUrl() {
if [ -z "$GIT_URL" ];then
return
fi
echo $GIT_URL | sed -r -e 's/^.+@/https:\/\//' -e 's/\.git$//'
}
renderTagUrl() {
GIT_WEB_BASE=$(renderGitWebUrl)
if [ -n "$GIT_WEB_BASE" ];then
echo "[${TAG_NAME}](${GIT_WEB_BASE}/src/tag/${TAG_NAME})"
else
echo ${TAG_NAME}
fi
}
renderCommitUrl() {
GIT_WEB_BASE=$(renderGitWebUrl)
if [ -n "$GIT_WEB_BASE" ];then
echo "[${GIT_COMMIT:0:7}](${GIT_WEB_BASE}/commit/${GIT_COMMIT}) ([提交历史](${GIT_WEB_BASE}/commits/tag/${TAG_NAME}))"
else
echo ${GIT_COMMIT:0:7}
fi
}
outputLine "完成时间 **$finishTime**"
blankLine
outputLine "#### Git 信息"
outputLine "* 触发 Tag: $(renderTagUrl)"
outputLine "* CommitId: $(renderCommitUrl)"
outputLine "* 触发人: ${GIT_TAGGER_NAME}"
blankLine
# 触发人: qishiyao
subGroupPath=`echo $GIT_TAG_BUILD_GROUP | sed 's/\./\//'`
outputLine "#### 下载地址"
outputLine "##### 开源版"
outputFrame "[${PMS_VERSION} (中文)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/pmsPack/$subGroupPath/ZenTaoPMS/${PMS_VERSION}/)"
outputFrame "\t\t"
outputLine "[${PMS_VERSION} (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/pmsPack/$subGroupPath/ZenTaoALM/${PMS_VERSION}/)"
outputLine "##### 企业版"
outputFrame "[${BIZ_VERSION:3} (中文)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/bizPack/$subGroupPath/ZenTaoPMS/${BIZ_VERSION}/)"
outputFrame "\t\t"
outputLine "[${BIZ_VERSION:3} (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/bizPack/$subGroupPath/ZenTaoALM/${BIZ_VERSION}/)"
outputLine "##### 旗舰版"
outputFrame "[${MAX_VERSION:3} (中文)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/maxPack/$subGroupPath/ZenTaoPMS/${MAX_VERSION}/)"
outputFrame "\t\t"
outputLine "[${MAX_VERSION:3} (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/maxPack/$subGroupPath/ZenTaoALM/${MAX_VERSION}/)"
if [ -n "$IPD_VERSION" ];then
outputLine "##### IPD版"
outputFrame "[${IPD_VERSION:3} (中文)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/ipdPack/$subGroupPath/ZenTaoPMS/${IPD_VERSION}/)"
outputFrame "\t\t"
outputLine "[${IPD_VERSION:3} (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/ipdPack/$subGroupPath/ZenTaoALM/${IPD_VERSION}/)"
fi
outputLine "##### 历史版本"
outputLine "[查看历史版本](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/#browse/browse:${ARTIFACT_REPOSITORY})"
+37
View File
@@ -0,0 +1,37 @@
#!/bin/bash
TAG=$1
FIELD=$2
frameCount=`echo $TAG| grep -o '_' | wc -l`
build_id=''
if [ $frameCount -eq 3 ];then
build_id=`echo $TAG | cut -d _ -f 3`
fi
case $FIELD in
group)
case $frameCount in
1)
echo release
;;
*)
build_date=${TAG##*_}
if [ -n "$build_id" ];then
echo "$build_date.$build_id"
else
echo "$build_date.release"
fi
;;
esac
;;
type)
if [ -n "$build_id" ];then
echo snapshot
else
echo release
fi
;;
esac
+23
View File
@@ -0,0 +1,23 @@
<?php
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\DowngradeLevelSetList;
use Rector\Set\ValueObject\DowngradeSetList;
use Rector\Core\ValueObject\PhpVersion;
use Rector\Caching\ValueObject\Storage\FileCacheStorage;
$version = getenv('PHP_VERSION');
$version = $version ?: '72';
$cacheDir = getenv('RECTOR_CACHE_DIR');
$cacheDir = $cacheDir ?: '/tmp/rector_cached_files';
return static function (RectorConfig $rectorConfig) use ($version,$cacheDir): void {
$rectorConfig->skip([
'test/*',
]);
$rectorConfig->phpVersion(constant(PhpVersion::class . '::PHP_' . $version));
$rectorConfig->sets([constant(DowngradeLevelSetList::class . '::DOWN_TO_PHP_' . $version)]);
// $rectorConfig->sets([constant(DowngradeSetList::class . '::PHP_' . $version)]);
$rectorConfig->cacheClass(FileCacheStorage::class);
$rectorConfig->cacheDirectory($cacheDir);
};
+3 -1
View File
@@ -71,7 +71,7 @@ $config->action->majorList['doc'] = array('releaseddoc', 'collected');
$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 = ',branch,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,review,';
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,gitea,gogs,sonarqube,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,execution,project,traincategory,apistruct,program,product,user,entry,repo,';
$config->action->ignoreObjectType4Dynamic = 'kanbanregion,kanbanlane,kanbancolumn';
$config->action->ignoreObjectType4Dynamic = 'kanbanregion,kanbanlane,kanbancolumn,disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan,editmr,removemr';
$config->action->preferredTypeNum = 10;
@@ -93,3 +93,5 @@ $config->trash->search['params']['objectName'] = array('operator' => 'include',
$config->trash->search['params']['objectID'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
$config->trash->search['params']['actor'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
$config->trash->search['params']['date'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
$config->action->latestDateList = array('today', 'yesterday', 'thisWeek', 'lastWeek', 'thisMonth');
+11
View File
@@ -453,4 +453,15 @@ class action extends control
return true;
}
/**
* Clear dynamic records older than one month.
*
* @access public
* @return void
*/
public function cleanActions()
{
$this->action->cleanActions();
}
}
+2
View File
@@ -388,11 +388,13 @@ $lang->action->label->estimated = 'estimated';
$lang->action->label->reviewpassed = 'Pass';
$lang->action->label->reviewrejected = 'Reject';
$lang->action->label->reviewclarified = 'Clarify';
$lang->action->label->reviewreverted = 'Revert';
$lang->action->label->commitsummary = 'Commit Summary';
$lang->action->label->updatetrainee = 'Update Trainee';
$lang->action->label->setdefaultbranch = 'Set default branch';
$lang->action->label->syncprogram = 'start';
$lang->action->label->syncproject = 'start';
$lang->action->label->syncmultipleproject = 'start';
$lang->action->label->syncexecution = 'start';
$lang->action->label->syncexecutionbychild = 'start';
$lang->action->label->startProgram = '(The start of the project sets the status of the program as Ongoing)';
+2
View File
@@ -388,11 +388,13 @@ $lang->action->label->estimated = 'estimated';
$lang->action->label->reviewpassed = 'Pass';
$lang->action->label->reviewrejected = 'Reject';
$lang->action->label->reviewclarified = 'Clarify';
$lang->action->label->reviewreverted = 'Revert';
$lang->action->label->commitsummary = 'Commit Summary';
$lang->action->label->updatetrainee = 'Update Trainee';
$lang->action->label->setdefaultbranch = 'Set default branch';
$lang->action->label->syncprogram = 'start';
$lang->action->label->syncproject = 'start';
$lang->action->label->syncmultipleproject = 'start';
$lang->action->label->syncexecution = 'start';
$lang->action->label->syncexecutionbychild = 'start';
$lang->action->label->startProgram = '(The start of the project sets the status of the program as Ongoing)';
+2
View File
@@ -388,11 +388,13 @@ $lang->action->label->estimated = 'estimated';
$lang->action->label->reviewpassed = 'Pass';
$lang->action->label->reviewrejected = 'Reject';
$lang->action->label->reviewclarified = 'Clarify';
$lang->action->label->reviewreverted = 'Revert';
$lang->action->label->commitsummary = 'Commit Summary';
$lang->action->label->updatetrainee = 'Update Trainee';
$lang->action->label->setdefaultbranch = 'Set default branch';
$lang->action->label->syncprogram = 'start';
$lang->action->label->syncproject = 'start';
$lang->action->label->syncmultipleproject = 'start';
$lang->action->label->syncexecution = 'start';
$lang->action->label->syncexecutionbychild = 'start';
$lang->action->label->startProgram = '(The start of the project sets the status of the program as Ongoing)';
+1
View File
@@ -309,6 +309,7 @@ $lang->action->label->commitsummary = 'Commit Summary';
$lang->action->label->updatetrainee = 'Update Trainee';
$lang->action->label->syncprogram = 'start';
$lang->action->label->syncproject = 'start';
$lang->action->label->syncmultipleproject = 'start';
$lang->action->label->syncexecution = 'start';
$lang->action->label->startProgram = '(The start of the project sets the status of the program as Ongoing)';
$lang->action->label->submitreview = 'submitted';
+2
View File
@@ -388,11 +388,13 @@ $lang->action->label->estimated = '估算了';
$lang->action->label->reviewpassed = '确认通过';
$lang->action->label->reviewrejected = '拒绝了';
$lang->action->label->reviewclarified = '有待明确';
$lang->action->label->reviewreverted = '撤销变更';
$lang->action->label->commitsummary = '提交了培训总结';
$lang->action->label->updatetrainee = '更新了培训人员';
$lang->action->label->setdefaultbranch = '设置了默认分支';
$lang->action->label->syncprogram = '开始了';
$lang->action->label->syncproject = '开始了';
$lang->action->label->syncmultipleproject = '开始了';
$lang->action->label->syncexecution = '开始了';
$lang->action->label->syncexecutionbychild = '开始了';
$lang->action->label->startProgram = "(因{$lang->projectCommon}开始而启动项目集)";
+173 -83
View File
@@ -71,6 +71,7 @@ class actionModel extends model
$this->dao->insert(TABLE_ACTION)->data($action)->autoCheck()->exec();
$actionID = $this->dao->lastInsertID();
$this->dao->insert(TABLE_ACTIONRECENT)->data($action)->autoCheck()->exec();
if($this->post->uid) $this->file->updateObjectID($this->post->uid, $objectID, $objectType);
/* Call the message notification function. */
@@ -249,7 +250,7 @@ class actionModel extends model
case 'release':
$result = $this->dao->select('product, build')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
$record['product'] = $result->product;
$record['project'] = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->eq($result->build)->fetch('project');
$record['project'] = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->in($result->build)->fetch('project');
break;
case 'task':
$fields = 'project, execution, story';
@@ -356,7 +357,7 @@ class actionModel extends model
->andWhere('((action')->ne('deleted')->andWhere('objectID')->in($objectID)->markRight(1)
->orWhere('(action')->eq('deleted')->andWhere('objectID')->in($modules)->markRight(1)->markRight(1)
->fi()
->beginIF(strpos('project,case,story,module', $objectType) === false)
->beginIF(!in_array($objectType, array('project', 'case', 'story', 'module')))
->where('objectType')->eq($objectType)
->andWhere('objectID')->in($objectID)
->fi()
@@ -406,13 +407,23 @@ class actionModel extends model
$productID = trim($action->product, ',');
$name = $project->name;
$method = $project->model == 'kanban' ? 'index' : 'view';
if($name) $action->extra = common::hasPriv('project', $method) ? html::a(helper::createLink('project', $method, "projectID=$action->project"), $name) : $name;
if($name) $action->extra = (common::hasPriv('project', $method) and $this->config->vision != 'or') ? html::a(helper::createLink('project', $method, "projectID=$action->project"), $name) : $name;
}
elseif($actionName == 'linked2plan')
{
$title = $this->dao->select('title')->from(TABLE_PRODUCTPLAN)->where('id')->eq($action->extra)->fetch('title');
if($title) $action->extra = common::hasPriv('productplan', 'view') ? html::a(helper::createLink('productplan', 'view', "planID=$action->extra"), $title) : $title;
}
elseif($actionName == 'changedbycharter')
{
$name = $this->dao->select('name')->from(TABLE_CHARTER)->where('id')->eq($action->extra)->fetch('name');
if($name) $action->extra = common::hasPriv('charter', 'view') ? html::a(helper::createLink('charter', 'view', "charterID=$action->extra"), $name) : $name;
}
elseif($actionName == 'linked2roadmap' and $action->objectType == 'story')
{
$name = $this->dao->select('name')->from(TABLE_ROADMAP)->where('id')->eq($action->extra)->fetch('name');
if($name) $action->extra = common::hasPriv('roadmap', 'view') ? html::a(helper::createLink('roadmap', 'view', "roadmapID=$action->extra"), $name) : $name;
}
elseif($actionName == 'linked2build')
{
$name = $this->dao->select('name')->from(TABLE_BUILD)->where('id')->eq($action->extra)->fetch('name');
@@ -477,6 +488,11 @@ class actionModel extends model
$title = $this->dao->select('title')->from(TABLE_PRODUCTPLAN)->where('id')->eq($action->extra)->fetch('title');
if($title) $action->extra = common::hasPriv('productplan', 'view') ? html::a(helper::createLink('productplan', 'view', "planID=$action->extra"), "#$action->extra " . $title) : "#$action->extra " . $title;
}
elseif($actionName == 'unlinkedfromroadmap' and $action->objectType == 'story')
{
$name = $this->dao->select('name')->from(TABLE_ROADMAP)->where('id')->eq($action->extra)->fetch('name');
if($name) $action->extra = common::hasPriv('roadmap', 'view') ? html::a(helper::createLink('roadmap', 'view', "roadmapID=$action->extra"), "#$action->extra " . $name) : "#$action->extra " . $name;
}
elseif($actionName == 'unlinkedfromtesttask')
{
$name = $this->dao->select('name')->from(TABLE_TESTTASK)->where('id')->eq($action->extra)->fetch('name');
@@ -533,6 +549,11 @@ class actionModel extends model
$name = $this->dao->select('title')->from(TABLE_STORY)->where('id')->eq($action->extra)->fetch('title');
if($name) $action->extra = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$action->extra"), "#$action->extra " . $name) : "#$action->extra " . $name;
}
elseif($actionName == 'deletechildrendemand')
{
$name = $this->dao->select('title')->from(TABLE_DEMAND)->where('id')->eq($action->extra)->fetch('title');
if($name) $action->extra = common::hasPriv('demand', 'view') ? html::a(helper::createLink('demand', 'view', "demandID=$action->extra"), "#$action->extra " . $name) : "#$action->extra " . $name;
}
elseif($actionName == 'buildopened')
{
$name = $this->dao->select('name')->from(TABLE_BUILD)->where('id')->eq($action->objectID)->fetch('name');
@@ -548,7 +569,7 @@ class actionModel extends model
$name = $this->dao->select('name')->from(TABLE_TESTSUITE)->where('id')->eq($action->extra)->fetch('name');
if($name) $action->extra = common::hasPriv('caselib', 'browse') ? html::a(helper::createLink('caselib', 'browse', "libID=$action->extra"), $name) : $name;
}
elseif(strpos(',importfromstorylib,importfromrisklib,importfromissuelib,importfromopportunitylib,', ",{$actionName},") !== false and $this->config->edition == 'max')
elseif(strpos(',importfromstorylib,importfromrisklib,importfromissuelib,importfromopportunitylib,', ",{$actionName},") !== false and ($this->config->edition == 'max' or $this->config->edition == 'ipd'))
{
$name = $this->dao->select('name')->from(TABLE_ASSETLIB)->where('id')->eq($action->extra)->fetch('name');
if($name) $action->extra = common::hasPriv('assetlib', $action->objectType) ? html::a(helper::createLink('assetlib', $action->objectType, "libID=$action->extra"), $name) : $name;
@@ -569,6 +590,21 @@ class actionModel extends model
}
}
}
elseif($actionName == 'closed' and $action->objectType == 'demand')
{
$action->appendLink = '';
if(strpos($action->extra, '|') !== false) $action->extra = substr($action->extra, 0, strpos($action->extra, '|'));
if(strpos($action->extra, ':') !== false)
{
list($extra, $id) = explode(':', $action->extra);
$action->extra = $extra;
if($id)
{
$name = $this->dao->select('title')->from(TABLE_DEMAND)->where('id')->eq($id)->fetch('title');
if($name) $action->appendLink = html::a(helper::createLink($action->objectType, 'view', "id=$id"), "#$id " . $name);
}
}
}
elseif($actionName == 'finished' and $objectType == 'todo')
{
$action->appendLink = '';
@@ -613,7 +649,7 @@ class actionModel extends model
if($history->field == 'git') $history->diff = str_replace('+', '%2B', $history->diff);
}
}
elseif(strpos(',linkstory,unlinkstory,createchildrenstory,', ",$actionName,") !== false)
elseif(strpos(',linkstory,unlinkstory,createchildrenstory,linkur,unlinkur,', ",$actionName,") !== false)
{
$extra = '';
foreach(explode(',', $action->extra) as $id) $extra .= common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$id"), "#$id ") . ', ' : "#$id, ";
@@ -777,7 +813,7 @@ class actionModel extends model
$trashQuery = $this->session->trashQuery;
$trashQuery = str_replace(array('`objectID`', '`actor`', '`date`'), array('t1.`objectID`', 't1.`actor`', 't1.`date`'), $trashQuery);
$table = $this->config->objectTables[$objectType];
$nameField = isset($this->config->action->objectNameFields[$objectType]) ? 't2.' . "`{$this->config->action->objectNameFields[$objectType]}`" : '';
$nameField = isset($this->config->action->objectNameFields[$objectType]) ? 't2.' . '`' . $this->config->action->objectNameFields[$objectType] . '`' : '';
if($nameField) $trashQuery = preg_replace("/`objectName`/", $nameField, $trashQuery);
@@ -887,7 +923,7 @@ class actionModel extends model
*/
if(empty($desc))
{
if($action->objectType == 'story' and $action->action == 'reviewed' and strpos($action->extra, ',') !== false)
if(($action->objectType == 'story' or $action->objectType == 'demand') and $action->action == 'reviewed' and strpos($action->extra, ',') !== false)
{
$desc = $this->lang->$objectType->action->rejectreviewed;
}
@@ -909,7 +945,7 @@ class actionModel extends model
$this->app->loadLang('mr');
$desc = sprintf($this->lang->mr->$mrAction, $mrDate, $mrActor, $mrLink);
}
elseif($this->config->edition == 'max' and strpos($this->config->action->assetType, ",{$action->objectType},") !== false and $action->action == 'approved')
elseif(($this->config->edition == 'max' or $this->config->edition == 'ipd') and strpos($this->config->action->assetType, ",{$action->objectType},") !== false and $action->action == 'approved')
{
$desc = empty($this->lang->action->approve->{$action->extra}) ? '' : $this->lang->action->approve->{$action->extra};
}
@@ -974,7 +1010,7 @@ class actionModel extends model
$actionDesc = str_replace('$extra', $action->extra, $desc['main']);
}
if($action->objectType == 'story' and $action->action == 'reviewed')
if(($action->objectType == 'story' or $action->objectType == 'demand') and $action->action == 'reviewed')
{
if(strpos($action->extra, ',') !== false)
{
@@ -1029,7 +1065,7 @@ class actionModel extends model
* @param string $account
* @param string $period
* @param string $orderBy
* @param object $pager
* @param int $limit
* @param string|int $productID all|int(like 123)|notzero all => include zero, notzero, greater than 0
* @param string|int $projectID same as productID
* @param string|int $executionID same as productID
@@ -1038,8 +1074,10 @@ class actionModel extends model
* @access public
* @return array
*/
public function getDynamic($account = 'all', $period = 'all', $orderBy = 'date_desc', $pager = null, $productID = 'all', $projectID = 'all', $executionID = 'all', $date = '', $direction = 'next')
public function getDynamic($account = 'all', $period = 'all', $orderBy = 'date_desc', $limit = 50, $productID = 'all', $projectID = 'all', $executionID = 'all', $date = '', $direction = 'next')
{
$this->cleanActions();
/* Computer the begin and end date of a period. */
$beginAndEnd = $this->computeBeginAndEnd($period);
extract($beginAndEnd);
@@ -1050,34 +1088,32 @@ class actionModel extends model
if(!$this->app->user->admin)
{
$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(empty($authedProducts)) $authedProducts = '0';
if($productID == 'all') $grantedProducts = !empty($aclViews['product']) ? $this->app->user->view->products : '0';
if($projectID == 'all') $grantedProjects = !empty($aclViews['project']) ? $this->app->user->view->projects : '0';
if($executionID == 'all') $grantedExecutions = !empty($aclViews['execution']) ? $this->app->user->view->sprints : '0';
if($productID == 'all' and $projectID == 'all')
{
$productCondition = '';
foreach(explode(',', $authedProducts) as $product) $productCondition = empty($productCondition) ? "(execution = '0' and project = '0' and (product LIKE '%,$product,%'" : "$productCondition OR product LIKE '%,$product,%'";
foreach(explode(',', $grantedProducts) as $product) $productCondition = empty($productCondition) ? "(execution = '0' and project = '0' and (product LIKE '%,$product,%'" : "$productCondition OR product LIKE '%,$product,%'";
if(!empty($productCondition)) $productCondition .= '))';
$projectCondition = "(execution = '0' and project != '0' and project " . helper::dbIN($authedProjects) . ')';
$executionCondition = isset($authedExecutions) ? "(execution != 0 and execution " . helper::dbIN($authedExecutions) . ')' : "(execution != 0 and execution = '$executionID')";
$projectCondition = "(execution = '0' and project != '0' and project " . helper::dbIN($grantedProjects) . ')';
$executionCondition = isset($grantedExecutions) ? "(execution != 0 and execution " . helper::dbIN($grantedExecutions) . ')' : "(execution != 0 and execution = '$executionID')";
}
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')->fetchPairs($projectID) + array(0 => 0);
$authedExecutions = isset($authedExecutions) ? array_intersect(array_keys($executions), explode(',', $authedExecutions)) : array_keys($executions);
$grantedExecutions = isset($grantedExecutions) ? array_intersect(array_keys($executions), explode(',', $grantedExecutions)) : array_keys($executions);
$productCondition = '';
foreach(array_keys($products) as $product) $productCondition = empty($productCondition) ? "(execution = '0' and project = '0' and (product LIKE '%,$product,%'" : "$productCondition OR product LIKE '%,$product,%'";
if(!empty($productCondition)) $productCondition .= '))';
$projectCondition = "(execution = '0' and project = '$projectID')";
$executionCondition = "(execution != '0' and execution " . helper::dbIN($authedExecutions) . ')';
$executionCondition = "(execution != '0' and execution " . helper::dbIN($grantedExecutions) . ')';
}
elseif(is_numeric($productID) and $projectID == 'all')
{
@@ -1085,12 +1121,12 @@ class actionModel extends model
$projects = $this->product->getProjectPairsByProduct($productID);
$executions = $this->product->getExecutionPairsByProduct($productID) + array(0 => 0);
$authedProjects = array_intersect(array_keys($projects), explode(',', $authedProjects));
$authedExecutions = isset($authedExecutions) ? array_intersect(array_keys($executions), explode(',', $authedExecutions)) : array_keys($executions);
$grantedProjects = array_intersect(array_keys($projects), explode(',', $grantedProjects));
$grantedExecutions = isset($grantedExecutions) ? array_intersect(array_keys($executions), explode(',', $grantedExecutions)) : array_keys($executions);
$productCondition = "(execution = '0' and project = '0' and product like '%,$productID,%')";
$projectCondition = "(execution = '0' and project != '0' and project " . helper::dbIN($authedProjects) . ')';
$executionCondition = "(execution != '0' and execution " . helper::dbIN($authedExecutions) . ')';
$projectCondition = "(execution = '0' and project != '0' and project " . helper::dbIN($grantedProjects) . ')';
$executionCondition = "(execution != '0' and execution " . helper::dbIN($grantedExecutions) . ')';
}
$condition = "((product =',0,' or product = '0' or product=',,') AND project = '0' AND execution = '0')";
@@ -1113,46 +1149,58 @@ 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;
if(is_numeric($projectID))
{
$openedDate = $this->dao->select('openedDate')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetch('openedDate');
$beginDate = $openedDate > $beginDate ? $openedDate : $beginDate;
}
$efforts = $this->dao->select('id')->from(TABLE_EFFORT)->where($condition)->fetchPairs();
$efforts = !empty($efforts) ? implode(',', $efforts) : 0;
$condition = "(($condition) OR `objectType` IN ('doc', 'doclib'))";
$noMultipleExecutions = $this->dao->select('id')->from(TABLE_PROJECT)->where('multiple')->eq(0)->andWhere('type')->in('sprint,kanban')->fetchPairs('id', 'id');
$condition = "(`objectType` IN ('doc', 'doclib') OR ($condition)) AND `objectType` NOT IN ('program', 'effort', 'execution')";
if($noMultipleExecutions) $condition .= " OR (`objectID` NOT " . helper::dbIN($noMultipleExecutions) . " AND `objectType` = 'execution')";
$programCondition = empty($this->app->user->view->programs) ? '0' : $this->app->user->view->programs;
$condition .= " OR (`objectID` in ($programCondition) AND `objectType` = 'program')";
$efforts = $this->dao->select('id')->from(TABLE_EFFORT)
->where($condition)
->beginIF($period != 'all')
->beginIF(isset($begin))->andWhere('date')->gt($begin)->fi()
->beginIF(isset($end))->andWhere('date')->lt($end)->fi()
->fi()
->beginIF($beginDate)->andWhere('date')->ge($beginDate)->fi()
->fetchPairs();
$efforts = !empty($efforts) ? implode(',', $efforts) : 0;
$condition .= " OR (`objectID` in ($efforts) AND `objectType` = 'effort')";
$condition = "($condition)";
/* Get actions. */
$actions = $this->dao->select('*')->from(TABLE_ACTION)
$actionTable = in_array($period, $this->config->action->latestDateList) ? TABLE_ACTIONRECENT : TABLE_ACTION;
$actions = $this->dao->select('*')->from($actionTable)
->where('objectType')->notIN($this->config->action->ignoreObjectType4Dynamic)
->beginIF($this->config->vision == 'lite')->andWhere('objectType')->notin('product')->fi()
->beginIF($this->config->systemMode == 'light')->andWhere('objectType')->notin('program')->fi()
->andWhere('vision')->eq($this->config->vision)
->beginIF($period != 'all')->andWhere('date')->gt($begin)->fi()
->beginIF($period != 'all')->andWhere('date')->lt($end)->fi()
->beginIF($period != 'all')
->andWhere('date')->gt($begin)
->andWhere('date')->lt($end)
->fi()
->beginIF($date)->andWhere('date' . ($direction == 'next' ? '<' : '>') . "'{$date}'")->fi()
->beginIF($account != 'all')->andWhere('actor')->eq($account)->fi()
->beginIF($beginDate)->andWhere('date')->ge($beginDate)->fi()
->beginIF($account != 'all')->andWhere('actor')->eq($account)->fi()
->beginIF(is_numeric($productID))->andWhere('product')->like("%,$productID,%")->fi()
->andWhere('1=1', true)
->beginIF(is_numeric($projectID))->andWhere('project')->eq($projectID)->fi()
->beginIF(!empty($executions))->andWhere('execution')->in(array_keys($executions))->fi()
->beginIF(is_numeric($executionID))->andWhere('execution')->eq($executionID)->fi()
->markRight(1)
/* Types excluded from Lite. */
->beginIF($this->config->vision == 'lite')->andWhere('objectType')->notin('product')->fi()
->beginIF($this->config->systemMode == 'light')->andWhere('objectType')->notin('program')->fi()
->beginIF($productID == 'notzero')->andWhere('product')->gt(0)->andWhere('product')->notlike('%,0,%')->fi()
->beginIF($projectID == 'notzero')->andWhere('project')->gt(0)->fi()
->beginIF($executionID == 'notzero')->andWhere('execution')->gt(0)->fi()
->andWhere($condition)
->beginIF($actionCondition)->andWhere("($actionCondition)")->fi()
/* Filter out client login/logout actions. */
->andWhere('action')->notin('disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan,editmr,removemr')
->orderBy($orderBy)
->page($pager)
->limit($limit)
->fetchAll();
if(!$actions) return array();
@@ -1193,13 +1241,13 @@ class actionModel extends model
* @param array $executions
* @param int $queryID
* @param string $orderBy
* @param object $pager
* @param int $limit
* @param string $date
* @param string $direction
* @access public
* @return array
*/
public function getDynamicBySearch($products, $projects, $executions, $queryID, $orderBy = 'date_desc', $pager = null, $date = '', $direction = 'next')
public function getDynamicBySearch($products, $projects, $executions, $queryID, $orderBy = 'date_desc', $limit = 50, $date = '', $direction = 'next')
{
$query = $queryID ? $this->loadModel('search')->getQuery($queryID) : '';
@@ -1248,7 +1296,7 @@ class actionModel extends model
if($this->config->vision == 'lite') $actionQuery .= " AND objectType != 'product'";
$actionQuery .= " AND vision = '" . $this->config->vision . "'";
$actions = $this->getBySQL($actionQuery, $orderBy, $pager);
$actions = $this->getBySQL($actionQuery, $orderBy, $limit);
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'action');
if(!$actions) return array();
@@ -1260,11 +1308,11 @@ class actionModel extends model
*
* @param string $sql
* @param string $orderBy
* @param object $pager
* @param int $limit
* @access public
* @return array
*/
public function getBySQL($sql, $orderBy, $pager = null)
public function getBySQL($sql, $orderBy, $limit = 50)
{
$actionCondition = $this->getActionCondition();
if(is_array($actionCondition)) return array();
@@ -1273,7 +1321,7 @@ class actionModel extends model
->where($sql)
->beginIF(!empty($actionCondition))->andWhere("($actionCondition)")->fi()
->orderBy($orderBy)
->page($pager)
->limit($limit)
->fetchAll();
}
@@ -1304,6 +1352,17 @@ class actionModel extends model
$projectIdList = array();
foreach($relatedProjects as $objectType => $idList) $projectIdList += $idList;
/* If idList include ',*,' Format ',*,' to '*'. */
foreach($projectIdList as $key => $idList)
{
$idList = explode(',', $idList);
foreach($idList as $id) $projectIdList[] = $id;
unset($projectIdList[$key]);
}
if($projectIdList) $projectIdList = array_unique($projectIdList);
$shadowProducts = $this->dao->select('id')->from(TABLE_PRODUCT)->where('shadow')->eq(1)->fetchPairs();
$projectMultiples = $this->dao->select('id,type,multiple')->from(TABLE_PROJECT)->where('id')->in($projectIdList)->fetchAll('id');
$docList = $this->loadModel('doc')->getPrivDocs('', 0, 'all');
@@ -1424,7 +1483,7 @@ class actionModel extends model
$relatedProject = array();
if(strpos(",{$this->config->action->needGetProjectType},", ",{$objectType},") !== false)
{
$objectInfo = $this->dao->select("id, project, $field AS name")->from($table)->where('id')->in($objectIdList)->fetchAll();
$objectInfo = $this->dao->select("id, project, `$field` AS name")->from($table)->where('id')->in($objectIdList)->fetchAll();
if($objectType == 'gapanalysis') $users = $this->user->getPairs('noletter');
foreach($objectInfo as $object)
{
@@ -1434,7 +1493,7 @@ class actionModel extends model
}
elseif($objectType == 'project' or $objectType == 'execution')
{
$objectInfo = $this->dao->select("id, project, $field AS name")->from($table)->where('id')->in($objectIdList)->fetchAll();
$objectInfo = $this->dao->select("id, project, `$field` AS name")->from($table)->where('id')->in($objectIdList)->fetchAll();
foreach($objectInfo as $object)
{
$objectName[$object->id] = $object->name;
@@ -1467,7 +1526,7 @@ class actionModel extends model
elseif($objectType == 'stakeholder')
{
$objectName = $this->dao->select("t1.id, t2.realname")->from($table)->alias('t1')
->leftJoin(TABLE_USER)->alias('t2')->on("t1.{$field} = t2.account")
->leftJoin(TABLE_USER)->alias('t2')->on("t1.`$field` = t2.account")
->where('t1.id')->in($objectIdList)
->fetchPairs();
}
@@ -1479,11 +1538,11 @@ class actionModel extends model
}
elseif($objectType == 'privlang')
{
$objectName = $this->dao->select("objectID AS id, $field AS name")->from($table)->where('objectID')->in($objectIdList)->andWhere('objectType')->eq('priv')->fetchPairs();
$objectName = $this->dao->select("objectID AS id, `$field` AS name")->from($table)->where('objectID')->in($objectIdList)->andWhere('objectType')->eq('priv')->fetchPairs();
}
else
{
$objectName = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIdList)->fetchPairs();
$objectName = $this->dao->select("id, `$field` AS name")->from($table)->where('id')->in($objectIdList)->fetchPairs();
}
$objectNames[$objectType] = $objectName;
@@ -1544,7 +1603,7 @@ class actionModel extends model
}
}
if($this->config->edition == 'max' and $objectType == 'assetlib')
if(($this->config->edition == 'max' or $this->config->edition == 'ipd') and $objectType == 'assetlib')
{
$libType = $this->dao->select('type')->from(TABLE_ASSETLIB)->where('id')->eq($objectID)->fetch('type');
if(strpos('story,issue,risk,opportunity,practice,component', $libType) !== false) $actionObjectLabel = $this->lang->action->label->{$libType . 'assetlib'};
@@ -1588,7 +1647,7 @@ class actionModel extends model
if($objectDeleted) return $action;
}
if($this->config->edition == 'max'
if(($this->config->edition == 'max' or $this->config->edition == 'ipd')
and strpos($this->config->action->assetType, ",{$action->objectType},") !== false
and empty($action->project) and empty($action->product) and empty($action->execution))
{
@@ -1786,22 +1845,16 @@ class actionModel extends model
$period = strtolower($period);
if($period == 'all') return array('begin' => '1970-1-1', 'end' => '2109-1-1');
if($period == 'today') return array('begin' => $today, 'end' => $tomorrow);
if($period == 'yesterday') return array('begin' => $yesterday, 'end' => $today);
if($period == 'twodaysago') return array('begin' => $twoDaysAgo, 'end' => $yesterday);
if($period == 'latest3days')return array('begin' => $twoDaysAgo, 'end' => $tomorrow);
if($period == 'all') return array('begin' => '1970-1-1', 'end' => LONG_TIME);
if($period == 'today') return array('begin' => $today, 'end' => $tomorrow);
if($period == 'yesterday') return array('begin' => $yesterday, 'end' => $today);
if($period == 'twodaysago') return array('begin' => $twoDaysAgo, 'end' => $yesterday);
if($period == 'latest3days') return array('begin' => $twoDaysAgo, 'end' => $tomorrow);
if($period == 'lastweek') return date::getLastWeek();
if($period == 'thismonth') return date::getThisMonth();
if($period == 'lastmonth') return date::getLastMonth();
/* If the period is by week, add the end time to the end date. */
if($period == 'thisweek' or $period == 'lastweek')
{
$func = "get$period";
extract(date::$func());
return array('begin' => $begin, 'end' => $end . ' 23:59:59');
}
if($period == 'thismonth') return date::getThisMonth();
if($period == 'lastmonth') return date::getLastMonth();
return date::getThisWeek();
}
/**
@@ -1944,21 +1997,21 @@ class actionModel extends model
if($action->objectType == 'case')
{
$case = $this->dao->select('*')->from(TABLE_CASE)->where('id')->eq($action->objectID)->fetch();
if($case->scene)
$caseScene = $this->dao->select('scene')->from(TABLE_CASE)->where('id')->eq($action->objectID)->fetch('scene');
if($caseScene)
{
$scene = $this->dao->select('*')->from(VIEW_SCENECASE)->where('id')->eq($case->scene)->fetch();
$scene = $this->loadModel('testcase')->getSceneByID($caseScene);
if($scene->deleted) return print(js::error($this->lang->action->refusecase));
}
}
if($action->objectType == 'scene')
{
$scene = $this->dao->select('*')->from("zt_scene")->where('id')->eq($action->objectID)->fetch();
$scene = $this->loadModel('testcase')->getSceneByID($action->objectID);
if($scene->parent)
{
$scenerow = $this->dao->select('*')->from(VIEW_SCENECASE)->where('id')->eq($scene->parent)->fetch();
if($scenerow->deleted) return print(js::error($this->lang->action->refusescene));
$parentScene = $this->testcase->getSceneByID($scene->parent);
if($parentScene->deleted) return print(js::error($this->lang->action->refusescene));
}
}
@@ -1992,6 +2045,12 @@ class actionModel extends model
$this->dao->update(TABLE_DOCLIB)->set('deleted')->eq(0)->where($action->objectType)->eq($action->objectID)->exec();
}
if($action->objectType == 'demand')
{
$demand = $this->dao->select('*')->from(TABLE_DEMAND)->where('id')->eq($action->objectID)->fetch();
if($demand->parent) $this->loadModel('demand')->updateParentStatus($action->objectID, $demand->parent);
}
/* Revert productplan parent status. */
if($action->objectType == 'productplan') $this->loadModel('productplan')->changeParentField($action->objectID);
@@ -2080,7 +2139,8 @@ class actionModel extends model
if($dateGroup)
{
$lastDateActions = $this->dao->select('*')->from(TABLE_ACTION)->where($this->session->actionQueryCondition)->andWhere("(LEFT(`date`, 10) = '" . substr($action->originalDate, 0, 10) . "')")->orderBy($this->session->actionOrderBy)->fetchAll('id');
$lastDate = date(DT_DATE1, $timeStamp);
$lastDateActions = $this->dao->select('*')->from(TABLE_ACTION)->where('`date`')->ge($lastDate)->andWhere('`date`')->le("{$lastDate} 23:59:59")->andWhere($this->session->actionQueryCondition)->orderBy($this->session->actionOrderBy)->fetchAll('id');
if(count($dateGroup[$date]) < count($lastDateActions))
{
unset($dateGroup[$date]);
@@ -2124,11 +2184,13 @@ class actionModel extends model
$condition = $this->session->actionQueryCondition;
/* Remove date condition for direction. */
$condition = preg_replace("/AND +date[\<\>]'\d{4}\-\d{2}\-\d{2}'/", '', $condition);
$count = $this->dao->select('count(*) as count')->from(TABLE_ACTION)->where($condition)
->andWhere('date' . ($direction == 'next' ? '<' : '>') . "'{$date}'")
->fetch('count');
return $count > 0;
$condition = preg_replace("/AND +[`]?date[`]?[ ]*[\<\>][ |=]*'\d{4}\-\d{2}\-\d{2}'/", '', $condition);
$actions = $this->dao->select('id')->from(TABLE_ACTION)
->where('date' . ($direction == 'next' ? '<' : '>') . "'{$date}'")
->andWhere($condition)
->limit(1)
->fetch('id');
return !empty($actions);
}
/**
@@ -2340,4 +2402,32 @@ class actionModel extends model
$this->create($deletedAction->objectType, $deletedAction->objectID, 'undeleted');
}
}
/**
* Clear dynamic records older than one month.
*
* @access public
* @return void
*/
public function cleanActions()
{
$lastMonth = date('Y-m-d', strtotime('-1 month'));
$this->dao->delete()->from(TABLE_ACTIONRECENT)->where('date')->lt($lastMonth)->exec();
return !dao::isError();
}
/**
* Get dynamic count.
*
* @access public
* @return void
*/
public function getDynamicCount()
{
$condition = $this->session->actionQueryCondition;
$count = $this->dao->select('count(1) as count')->from(TABLE_ACTION)
->where($condition)
->fetch('count');
return $count;
}
}
+5
View File
@@ -122,6 +122,11 @@
$methodName = 'setSQL';
$params = "id={$action->objectID}";
}
if($module == 'deploystep')
{
$module = 'deploy';
$methodName = 'viewStep';
}
if($action->objectType == 'api')
{
$params = "libID=0&moduelID=0&apiID={$action->objectID}";
+4 -1
View File
@@ -32,11 +32,14 @@ class admin extends control
/**
* Index page.
*
* @access public
* @return void
*/
public function index()
{
set_time_limit(0);
$community = zget($this->config->global, 'community', '');
if(!$community or $community == 'na')
{
@@ -78,7 +81,7 @@ class admin extends control
*/
public function ajaxSetZentaoData()
{
if(helper::isIntranet()) return $this->send(array('result' => 'fail'));
if(helper::isIntranet()) return $this->send(array('result' => 'ignore'));
$hasInternet = $this->admin->checkInternet();
+17 -6
View File
@@ -39,10 +39,13 @@ $lang->admin->menuList->dev['name'] = $lang->admin->menuSetting['dev']['name'];
$lang->admin->menuList->dev['desc'] = $lang->admin->menuSetting['dev']['desc'];
$lang->admin->menuList->dev['order'] = 45;
$lang->admin->menuList->convert['name'] = $lang->admin->menuSetting['convert']['name'];
$lang->admin->menuList->convert['desc'] = $lang->admin->menuSetting['convert']['desc'];
$lang->admin->menuList->convert['link'] = 'convert|convertjira';
$lang->admin->menuList->convert['order'] = 50;
if($config->db->driver == 'mysql')
{
$lang->admin->menuList->convert['name'] = $lang->admin->menuSetting['convert']['name'];
$lang->admin->menuList->convert['desc'] = $lang->admin->menuSetting['convert']['desc'];
$lang->admin->menuList->convert['link'] = 'convert|convertjira';
$lang->admin->menuList->convert['order'] = 50;
}
$lang->admin->menuList->ai['name'] = $lang->admin->menuSetting['ai']['name'];
$lang->admin->menuList->ai['desc'] = $lang->admin->menuSetting['ai']['desc'];
@@ -190,7 +193,15 @@ $lang->admin->menuList->ai['menuOrder']['5'] = 'prompts';
// $lang->admin->menuList->ai['menuOrder']['10'] = 'conversations';
$lang->admin->menuList->ai['menuOrder']['15'] = 'models';
if($config->edition != 'max')
$lang->admin->menuList->ai['subMenu']['prompts'] = array('link' => "{$lang->admin->ai->prompt}|ai|prompts|", 'alias' => 'promptview,promptassignrole,promptselectdatasource,promptsetpurpose,promptsettargetform,promptfinalize,promptedit');
// $lang->admin->menuList->ai['subMenu']['conversations'] = array('link' => "{$lang->admin->ai->conversation}|ai|conversations|");
$lang->admin->menuList->ai['subMenu']['models'] = array('link' => "{$lang->admin->ai->model}|ai|models|", 'alias' => 'editmodel');
$lang->admin->menuList->ai['menuOrder']['5'] = 'prompts';
// $lang->admin->menuList->ai['menuOrder']['10'] = 'conversations';
$lang->admin->menuList->ai['menuOrder']['15'] = 'models';
if($config->edition != 'max' and $config->edition != 'ipd')
{
unset($lang->admin->menuList->model['subMenu']['scrum']);
unset($lang->admin->menuList->model['subMenu']['agileplus']);
@@ -208,7 +219,7 @@ if(!helper::hasFeature('waterfallplus'))
unset($lang->admin->menuList->model['subMenu']['waterfallplus']);
unset($lang->admin->menuList->model['menuOrder']['25']);
}
if($config->edition == 'max')
if($config->edition == 'max' or $config->edition == 'ipd')
{
if(!helper::hasFeature('scrum_auditplan') and !helper::hasFeature('scrum_process')) unset($lang->admin->menuList->model['subMenu']['scrum'], $lang->admin->menuList->model['menuOrder']['10']);
if(!helper::hasFeature('agileplus_auditplan') and !helper::hasFeature('agileplus_process')) unset($lang->admin->menuList->model['subMenu']['agileplus'], $lang->admin->menuList->model['menuOrder']['20']);
+4 -4
View File
@@ -701,10 +701,10 @@ class adminModel extends model
}
else
{
$news = json_decode($zentaoData['news']);
$publicclass = json_decode($zentaoData['publicclass']);
$plugins = json_decode($zentaoData['plugin']);
$patches = json_decode($zentaoData['patch']);
if(!empty($zentaoData['news'])) $news = json_decode($zentaoData['news']);
if(!empty($zentaoData['publicclass'])) $publicclass = json_decode($zentaoData['publicclass']);
if(!empty($zentaoData['plugin'])) $plugins = json_decode($zentaoData['plugin']);
if(!empty($zentaoData['patch'])) $patches = json_decode($zentaoData['patch']);
if(common::checkNotCN()) array_pop($plugins);
}
+1 -1
View File
@@ -139,7 +139,7 @@
</div>
<?php endforeach;?>
</div>
<?php if($config->edition != 'max'):?>
<?php if(!in_array($config->edition, array('max', 'ipd'))):?>
<div class="border-gray mb-16 radius-4">
<div class="h-40 pl-16 flex align-center justify-between">
<div class="panel-title"><?php echo $lang->admin->upgradeRecommend?></div>
+2 -2
View File
@@ -587,7 +587,7 @@ class api extends control
if($changes)
{
$actionID = $this->action->create('api', $apiID, 'edited');
$actionID = $this->action->create('api', $apiID, 'edited', '', '', '', false);
$this->action->logHistory($actionID, $changes);
}
@@ -630,7 +630,7 @@ class api extends control
$api = $this->api->create();
if($api === false) return $this->sendError(dao::getError());
$this->action->create('api', $api->id, 'Created');
$this->action->create('api', $api->id, 'Created', '', '', '', false);
if(isonlybody()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => 'true', 'callback' => "parentLocate({$api->id}, {$api->lib}, {$api->module})"));
return $this->sendSuccess(array('locate' => helper::createLink('api', 'index', "libID={$api->lib}&moduleID={$api->module}&apiID={$api->id}")));
+5
View File
@@ -69,6 +69,11 @@ class backup extends control
}
krsort($backups);
$diskSapce = $this->backup->checkDiskSpace($this->backupPath);
$alertTips = sprintf($this->lang->backup->insufficientDisk, round($diskSapce / (1024 * 1024 * 1024), 2));
$this->view->diskSapce = $diskSapce;
$this->view->alertTips = $alertTips;
$this->view->title = $this->lang->backup->common;
$this->view->position[] = $this->lang->backup->common;
$this->view->backups = $backups;
+43 -36
View File
@@ -2,46 +2,22 @@ $(function()
{
$('.backup').click(function()
{
var timeID = null;
$.ajax({
url: $(this).attr('data-link'),
success: function(data)
{
clearInterval(timeID);
$('#waitting .modal-body #message').append(data);
setTimeout(function(){return location.reload();}, 2000);
},
error: function(request, textstatus, error)
{
clearInterval(timeID);
if(textstatus == 'timeout') $('#waitting .modal-body #message').append("<p class='text-danger'>" + backupTimeout + '</p>');
setTimeout(function(){return location.reload();}, 2000);
}
});
$('#waitting .modal-body #backupType').html(backup);
$('#waitting').modal('show');
timeID = setInterval(function()
if(diskSapce)
{
$.get(createLink('backup', 'ajaxGetProgress'), function(data)
{
$('#waitting .modal-content #message').html(data);
});
}, 1000);
})
$('#spaceConfirm').modal('show', 'center');
}
else
{
backupData();
}
});
$('.rmPHPHeader').click(function()
{
$('#waitting .modal-body #backupType').html(rmPHPHeader);
$('#waitting .modal-content #message').hide();
$('#waitting').modal('show');
})
});
$('.restore').click(function()
{
@@ -64,8 +40,39 @@ $(function()
{
return location.reload();
}
})
});
return false;
})
})
});
});
function backupData()
{
var timeID = null;
$.ajax({
url: $('.backup').attr('data-link'),
success: function(data)
{
clearInterval(timeID);
$('#waitting .modal-body #message').append(data);
setTimeout(function(){return location.reload();}, 2000);
},
error: function(request, textstatus, error)
{
clearInterval(timeID);
if(textstatus == 'timeout') $('#waitting .modal-body #message').append("<p class='text-danger'>" + backupTimeout + '</p>');
setTimeout(function(){return location.reload();}, 2000);
}
});
$('#waitting .modal-body #backupType').html(backup);
$('#waitting').modal('show');
timeID = setInterval(function()
{
$.get(createLink('backup', 'ajaxGetProgress'), function(data)
{
$('#waitting .modal-content #message').html(data);
});
}, 1000);
}
+12 -9
View File
@@ -27,15 +27,18 @@ $lang->backup->settingDir = 'Backup Directory';
$lang->backup->settingList['nofile'] = 'Do not back up files or codes.';
$lang->backup->settingList['nosafe'] = 'Do not prevent downloading PHP file header.';
$lang->backup->waitting = '<span id="backupType"></span> In Arbeit. Bitte warten...';
$lang->backup->progressSQL = '<p>SQL backup: %s is backed up.</p>';
$lang->backup->progressAttach = '<p>SQL backup is completed.</p><p>Attachment backing up.</p>';
$lang->backup->progressCode = '<p>SQL backup is completed.</p><p>Attachment backup is completed.</p><p>Code backing up.</p>';
$lang->backup->confirmDelete = 'Möchten Sie das Backup löschen?';
$lang->backup->confirmRestore = 'Möchten Sie das Backup wiederherstellen?';
$lang->backup->holdDays = 'Behalten der letzen %s Tage der Backups';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Nur Dateien und Datenbanken können wiederhergestellt werden. Code kann manuell wieder hergestellt werden.';
$lang->backup->waitting = '<span id="backupType"></span> In Arbeit. Bitte warten...';
$lang->backup->progressSQL = '<p>SQL backup: %s is backed up.</p>';
$lang->backup->progressAttach = '<p>SQL backup is completed.</p><p>Attachment backing up.</p>';
$lang->backup->progressCode = '<p>SQL backup is completed.</p><p>Attachment backup is completed.</p><p>Code backing up.</p>';
$lang->backup->confirmDelete = 'Möchten Sie das Backup löschen?';
$lang->backup->confirmRestore = 'Möchten Sie das Backup wiederherstellen?';
$lang->backup->holdDays = 'Behalten der letzen %s Tage der Backups';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Nur Dateien und Datenbanken können wiederhergestellt werden. Code kann manuell wieder hergestellt werden.';
$lang->backup->insufficientDisk = 'Disk space less than%.2fG, it may cause insufficient backup space or affect the use, please process it and try again.';
$lang->backup->ongoBackup = 'ongoing backup';
$lang->backup->cancelBackup = 'cancel backup';
$lang->backup->success = new stdclass();
$lang->backup->success->backup = 'Erledigt!';
+12 -9
View File
@@ -27,15 +27,18 @@ $lang->backup->settingDir = 'Backup Directory';
$lang->backup->settingList['nofile'] = 'Do not back up files or codes.';
$lang->backup->settingList['nosafe'] = 'Do not prevent downloading PHP file header.';
$lang->backup->waitting = '<span id="backupType"></span> is ongoing. Please wait...';
$lang->backup->progressSQL = '<p>SQL backup: %s is backed up.</p>';
$lang->backup->progressAttach = '<p>SQL backup is completed.</p><p>Attachment backing up.</p>';
$lang->backup->progressCode = '<p>SQL backup is completed.</p><p>Attachment backup is completed.</p><p>Code backing up.</p>';
$lang->backup->confirmDelete = 'Do you want to delete the backup?';
$lang->backup->confirmRestore = 'Do you want to restore the backup?';
$lang->backup->holdDays = 'Hold last %s days of backup';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Only files and databases can be restored by clicking Restore. Code can be restored manually.';
$lang->backup->waitting = '<span id="backupType"></span> is ongoing. Please wait...';
$lang->backup->progressSQL = '<p>SQL backup: %s is backed up.</p>';
$lang->backup->progressAttach = '<p>SQL backup is completed.</p><p>Attachment backing up.</p>';
$lang->backup->progressCode = '<p>SQL backup is completed.</p><p>Attachment backup is completed.</p><p>Code backing up.</p>';
$lang->backup->confirmDelete = 'Do you want to delete the backup?';
$lang->backup->confirmRestore = 'Do you want to restore the backup?';
$lang->backup->holdDays = 'Hold last %s days of backup';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Only files and databases can be restored by clicking Restore. Code can be restored manually.';
$lang->backup->insufficientDisk = 'Disk space less than%.2fG, it may cause insufficient backup space or affect the use, please process it and try again.';
$lang->backup->ongoBackup = 'ongoing backup';
$lang->backup->cancelBackup = 'cancel backup';
$lang->backup->success = new stdclass();
$lang->backup->success->backup = 'Done!';
+12 -9
View File
@@ -27,15 +27,18 @@ $lang->backup->settingDir = 'Répertoire Backup';
$lang->backup->settingList['nofile'] = 'Ne pas archiver fichiers et codes.';
$lang->backup->settingList['nosafe'] = 'Ne pas prévenir du téléchargement par PHP file header.';
$lang->backup->waitting = '<span id="backupType"></span> est en cours. Patientez s´il vous plait...';
$lang->backup->progressSQL = '<p>SQL backup: %s est sauvegardé.</p>';
$lang->backup->progressAttach = '<p>SQL backup est terminé.</p><p>Les fichiers sont en cours de sauvegarde.</p>';
$lang->backup->progressCode = '<p>SQL backup est terminé.</p><p>Sauvegarde des fichiers terminée.</p><p>Sauvegarde du code en cours.</p>';
$lang->backup->confirmDelete = 'Voulez-vous supprimer la sauvegarde ?';
$lang->backup->confirmRestore = 'Voulez-vous restaurer la sauvegarde ?';
$lang->backup->holdDays = 'conserver les derniers %s jours de backup';
$lang->backup->copiedFail = 'Fichiers en échec de copie : ';
$lang->backup->restoreTip = 'Seulement les fichiers et les bases peuvent être restaurées en cliquant sur Restaurer. Le code doit être restauré manuellement.';
$lang->backup->waitting = '<span id="backupType"></span> est en cours. Patientez s´il vous plait...';
$lang->backup->progressSQL = '<p>SQL backup: %s est sauvegardé.</p>';
$lang->backup->progressAttach = '<p>SQL backup est terminé.</p><p>Les fichiers sont en cours de sauvegarde.</p>';
$lang->backup->progressCode = '<p>SQL backup est terminé.</p><p>Sauvegarde des fichiers terminée.</p><p>Sauvegarde du code en cours.</p>';
$lang->backup->confirmDelete = 'Voulez-vous supprimer la sauvegarde ?';
$lang->backup->confirmRestore = 'Voulez-vous restaurer la sauvegarde ?';
$lang->backup->holdDays = 'conserver les derniers %s jours de backup';
$lang->backup->copiedFail = 'Fichiers en échec de copie : ';
$lang->backup->restoreTip = 'Seulement les fichiers et les bases peuvent être restaurées en cliquant sur Restaurer. Le code doit être restauré manuellement.';
$lang->backup->insufficientDisk = 'Disk space less than%.2fG, it may cause insufficient backup space or affect the use, please process it and try again.';
$lang->backup->ongoBackup = 'ongoing backup';
$lang->backup->cancelBackup = 'cancel backup';
$lang->backup->success = new stdclass();
$lang->backup->success->backup = 'Terminé avec succès !';
+12 -9
View File
@@ -24,15 +24,18 @@ $lang->backup->settingDir = 'Thư mục sao lưu';
$lang->backup->settingList['nofile'] = 'Không sao lưu tập tin hoặc mã nguồn.';
$lang->backup->settingList['nosafe'] = 'Không ngăn tải xuống tập tin PHP.';
$lang->backup->waitting = '<span id="backupType"></span> đang diễn ra. Vui lòng đợi...';
$lang->backup->progressSQL = '<p>Sao lưu SQL: %s được sao lưu.</p>';
$lang->backup->progressAttach = '<p>Sao lưu SQL đã hoàn thành.</p><p>Sao lưu đính kèm: %s được sao lưu.</p>';
$lang->backup->progressCode = '<p>Sao lưu SQL đã hoàn thành.</p><p>Sao lưu đính kèm đã hoàn thành.</p><p>Sao lưu mã nguồn: %s được sao lưu.</p>';
$lang->backup->confirmDelete = 'Bạn có muốn xóa sao lưu này?';
$lang->backup->confirmRestore = 'Bạn có muốn khôi phục sao lưu này?';
$lang->backup->holdDays = 'Giữ ít nhất %s ngày sao lưu';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Chỉ tập tin và CSDL có thể được khôi phục bằng cách Click Khôi phục. Mã nguồn có thể khôi phục thủ công.';
$lang->backup->waitting = '<span id="backupType"></span> đang diễn ra. Vui lòng đợi...';
$lang->backup->progressSQL = '<p>Sao lưu SQL: %s được sao lưu.</p>';
$lang->backup->progressAttach = '<p>Sao lưu SQL đã hoàn thành.</p><p>Sao lưu đính kèm: %s được sao lưu.</p>';
$lang->backup->progressCode = '<p>Sao lưu SQL đã hoàn thành.</p><p>Sao lưu đính kèm đã hoàn thành.</p><p>Sao lưu mã nguồn: %s được sao lưu.</p>';
$lang->backup->confirmDelete = 'Bạn có muốn xóa sao lưu này?';
$lang->backup->confirmRestore = 'Bạn có muốn khôi phục sao lưu này?';
$lang->backup->holdDays = 'Giữ ít nhất %s ngày sao lưu';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Chỉ tập tin và CSDL có thể được khôi phục bằng cách Click Khôi phục. Mã nguồn có thể khôi phục thủ công.';
$lang->backup->insufficientDisk = 'Không gian đĩa nhỏ hơn%.2fG, Nó có thể gây ra không đủ dung lượng sao lưu hoặc ảnh hưởng đến việc sử dụng, vui lòng xử lý và thử lại.';
$lang->backup->ongoBackup = 'tiếp tục sao lưu';
$lang->backup->cancelBackup = 'hủy sao lưu';
$lang->backup->success = new stdclass();
$lang->backup->success->backup = 'Sao lưu hoàn thành!';
+12 -9
View File
@@ -27,15 +27,18 @@ $lang->backup->settingDir = '备份目录';
$lang->backup->settingList['nofile'] = '不备份附件和代码';
$lang->backup->settingList['nosafe'] = '不需要防下载PHP文件头';
$lang->backup->waitting = '<span id="backupType"></span>正在进行中,请稍候...';
$lang->backup->progressSQL = '<p>SQL备份中,已备份%s</p>';
$lang->backup->progressAttach = '<p>SQL备份完成</p><p>附件备份中,共有%s个文件,已经备份%s个</p>';
$lang->backup->progressCode = '<p>SQL备份完成</p><p>附件备份完成</p><p>代码备份中,共有%s个文件,已经备份%s个</p>';
$lang->backup->confirmDelete = '是否删除备份?';
$lang->backup->confirmRestore = '是否还原该备份?';
$lang->backup->holdDays = '备份保留最近 %s 天';
$lang->backup->copiedFail = '复制失败的文件:';
$lang->backup->restoreTip = '还原功能只还原附件和数据库,如果需要还原代码,可以手动还原。';
$lang->backup->waitting = '<span id="backupType"></span>正在进行中,请稍候...';
$lang->backup->progressSQL = '<p>SQL备份中,已备份%s</p>';
$lang->backup->progressAttach = '<p>SQL备份完成</p><p>附件备份中,共有%s个文件,已经备份%s个</p>';
$lang->backup->progressCode = '<p>SQL备份完成</p><p>附件备份完成</p><p>代码备份中,共有%s个文件,已经备份%s个</p>';
$lang->backup->confirmDelete = '是否删除备份?';
$lang->backup->confirmRestore = '是否还原该备份?';
$lang->backup->holdDays = '备份保留最近 %s 天';
$lang->backup->copiedFail = '复制失败的文件:';
$lang->backup->restoreTip = '还原功能只还原附件和数据库,如果需要还原代码,可以手动还原。';
$lang->backup->insufficientDisk = '磁盘空间小于%.2fG,可能会导致备份空间不足或影响使用,请处理后再试。';
$lang->backup->ongoBackup = '继续备份';
$lang->backup->cancelBackup = '取消备份';
$lang->backup->success = new stdclass();
$lang->backup->success->backup = '备份成功!';

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