Merge branch 'master' into 'apiext'

# Conflicts:
#   config/routes.php
This commit is contained in:
王怡栋
2021-12-17 09:58:59 +00:00
1367 changed files with 112946 additions and 46874 deletions
+3 -1
View File
@@ -3,6 +3,7 @@ config/my.php
www/data/
www/install.php
www/upgrade.php
www/checklist.php
www/ok.txt
tools/*
release/*
@@ -15,6 +16,7 @@ test/data/sql/
.gitkeep
.bak
.idea
.vscode
.gitignore
.DS_Store
vendor/
@@ -22,6 +24,6 @@ docker
.docker-sync
composer.lock
.editorconfig
CodeSniffer.conf
test/runtime/*
test/www
+1 -1
View File
@@ -1 +1 @@
15.7
16.0.beta1
+57 -4
View File
@@ -9,7 +9,7 @@
* @version 1
* @link http://www.zentao.net
*/
class bugEntry extends entry
class bugEntry extends entry
{
/**
* GET method.
@@ -20,12 +20,64 @@ class bugEntry extends entry
*/
public function get($bugID)
{
$this->resetOpenApp($this->param('tab', 'product'));
$control = $this->loadController('bug', 'view');
$control->view($bugID);
$data = $this->getData();
$bug = $data->data->bug;
$this->send(200, $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool'));
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);
$bug = $data->data->bug;
/* Set product name */
$bug->productName = $data->data->product->name;
/* Set module title */
$moduleTitle = '';
if(empty($bug->module)) $moduleTitle = '/';
if($bug->module)
{
$modulePath = $data->data->modulePath;
foreach($modulePath as $key => $module)
{
$moduleTitle .= $module->name;
if(isset($modulePath[$key + 1])) $moduleTitle .= '/';
}
}
$bug->moduleTitle = $moduleTitle;
$openedBuilds = array();
foreach(explode(',', $bug->openedBuild) as $buildID)
{
if(empty($buildID)) continue;
$openedBuild = new stdclass();
$openedBuild->id = $buildID;
$openedBuild->title = zget($data->data->builds, $buildID, '');
$openedBuilds[] = $openedBuild;
}
$bug->openedBuild = $openedBuilds;
if($bug->resolvedBuild)
{
$resolvedBuild = new stdclass();
$resolvedBuild->id = $bug->resolvedBuild;
$resolvedBuild->title = zget($data->data->builds, $bug->resolvedBuild, '');
$bug->resolvedBuild = $resolvedBuild;
}
$bug->actions = $this->loadModel('action')->processActionForAPI($data->data->actions, $data->data->users, $this->lang->bug);
$preAndNext = $data->data->preAndNext;
$bug->preAndNext = array();
$bug->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
$bug->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
$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'));
}
/**
@@ -42,6 +94,7 @@ class bugEntry extends entry
/* Set $_POST variables. */
$fields = 'title,project,execution,openedBuild,assignedTo,pri,severity,type,story,resolvedBy,closedBy,resolution,product,plan,task';
$this->batchSetPost($fields, $oldBug);
$this->setPost('notifyEmail', implode(',', $this->request('notifyEmail', array())));
$control = $this->loadController('bug', 'edit');
$control->edit($bugID);
@@ -52,7 +105,7 @@ class bugEntry extends entry
if(!isset($data->status)) return $this->sendError(400, 'error');
$bug = $this->bug->getByID($bugID);
$this->send(200, $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool'));
$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'));
}
/**
+32 -34
View File
@@ -9,42 +9,22 @@
* @version 1
* @link http://www.zentao.net
*/
class bugsEntry extends entry
class bugsEntry extends entry
{
/**
* GET method.
*
* @param int $productID
* @param int $projectID
* @param int $executionID
* @access public
* @return void
*/
public function get($productID = 0, $projectID = 0, $executionID = 0)
public function get($productID = 0)
{
if(!$productID) $productID = $this->param('product', 0);
if(!$projectID) $projectID = $this->param('project', 0);
if(!$executionID) $executionID = $this->param('execution', 0);
if(empty($productID)) $productID = $this->param('product', 0);
if(empty($productID)) return $this->sendError(400, 'Need product id.');
if($projectID)
{
$control = $this->loadController('project', 'bug');
$control->bug($projectID, $productID, $this->param('order', 'status,id_desc'), $this->param('build', 0), $this->param('status', 'all'), 0, $this->param('limit', 20), $this->param('page', 1));
}
elseif($executionID)
{
$control = $this->loadController('execution', 'bug');
$control->bug($executionID, $productID, $this->param('order', 'status,id_desc'), $this->param('build', 0), $this->param('status', 'all'), 0, $this->param('limit', 20), $this->param('page', 1));
}
elseif($productID)
{
$control = $this->loadController('bug', 'browse');
$control->browse($productID, $this->param('branch', ''), $this->param('status', ''), 0, $this->param('order', ''), 0, $this->param('limit', 20), $this->param('page', 1));
}
else
{
return $this->sendError(400, 'Need product or project or execution id.');
}
$control = $this->loadController('bug', 'browse');
$control->browse($productID, $this->param('branch', 'all'), $this->param('status', ''), 0, $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
@@ -55,16 +35,33 @@ class bugsEntry extends entry
$result = array();
foreach($bugs as $bug)
{
$result[] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool');
$status = array('code' => $bug->status, 'name' => $this->lang->bug->statusList[$bug->status]);
if($bug->status == 'active' and $bug->confirmed) $status = array('code' => 'confirmed', 'name' => $this->lang->bug->labelConfirmed);
if($bug->resolution == 'postponed') $status = array('code' => 'postponed', 'name' => $this->lang->bug->labelPostponed);
if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs);
$bug->status = $status['code'];
$bug->statusName = $status['name'];
$result[$bug->id] = $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(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => $result));
$storyChangeds = $this->dao->select('t1.id')->from(TABLE_BUG)->alias('t1')
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id')
->where('t1.id')->in(array_keys($result))
->andWhere('t1.story')->ne('0')
->andWhere('t1.storyVersion != t2.version')
->fetchPairs('id', 'id');
foreach($storyChangeds as $bugID)
{
$status = array('code' => 'storyChanged', 'name' => $this->lang->bug->changed);
$result[$bugID]->status = $status['code'];
$result[$bugID]->statusName = $status['name'];
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => array_values($result)));
}
if(isset($data->status) and $data->status == 'fail')
{
return $this->sendError(400, $data->message);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
@@ -86,18 +83,19 @@ class bugsEntry extends entry
$this->batchSetPost($fields);
$this->setPost('product', $productID);
$this->setPost('notifyEmail', implode(',', $this->request('notifyEmail', array())));
$control = $this->loadController('bug', 'create');
$this->requireFields('title,pri,severity,type,openedBuild');
$control->create($productID);
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
$bug = $this->loadModel('bug')->getByID($data->id);
$this->send(200, $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time'));
$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'));
}
}
+3 -6
View File
@@ -24,13 +24,10 @@ class buildEntry extends Entry
$control->view($buildID);
$data = $this->getData();
if(isset($data->status) and $data->status == 'success') return $this->send(200, $this->format($data->data->build, 'stories:idList,bugs:idList,deleted:bool'));
if(isset($data->status) and $data->status == 'success') return $this->send(200, $this->format($data->data->build, 'builder:user,stories:idList,bugs:idList,deleted:bool'));
/* Exception handling. */
if(isset($data->status) and $data->status == 'fail')
{
return isset($data->code) and $data->code == 404 ? $this->send404() : $this->sendError(400, $data->message);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$this->sendError(400, 'error');
}
@@ -58,7 +55,7 @@ class buildEntry extends Entry
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$build = $this->build->getByID($buildID);
$this->send(200, $build);
$this->send(200, $this->format($build, 'builder:user,stories:idList,bugs:idList,deleted:bool'));
}
/**
+7 -9
View File
@@ -20,25 +20,23 @@ class buildsEntry extends entry
*/
public function get($projectID = 0)
{
if(!$projectID) $projectID = $this->param('project', 0);
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));
$control->build($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');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$result = array();
foreach($data->data->projectBuilds as $productID => $builds)
{
foreach($builds as $build)
{
$result[] = $this->format($build, 'bugs:idList,stories:idList,deleted:bool');
}
foreach($builds as $build) $result[] = $this->format($build, 'bugs:idList,stories:idList,builder:user,deleted:bool');
}
return $this->send(200, $result);
return $this->send(200, array('total' => count($result), 'builds' => $result));
}
/**
@@ -61,7 +59,7 @@ class buildsEntry extends entry
$control = $this->loadController('build', 'create');
$this->requireFields('execution,product,name,builder,date');
$control->create(0,0,$projectID);
$control->create(0, 0, $projectID);
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
+3
View File
@@ -36,6 +36,9 @@ class configEntry extends baseEntry
case 'timezone':
$config['value'] = $this->config->timezone;
break;
case 'systemMode':
$config['value'] = $this->config->systemMode;
break;
default:
$this->sendError(400, 'No configuration.');
return;
+5 -4
View File
@@ -21,10 +21,11 @@ class configsEntry extends baseEntry
{
$configs = array();
$configs[] = array('key' => 'language', 'value' => $this->config->default->lang);
$configs[] = array('key' => 'version', 'value' => $this->config->version);
$configs[] = array('key' => 'charset', 'value' => $this->config->charset);
$configs[] = array('key' => 'timezone', 'value' => $this->config->timezone);
$configs[] = array('key' => 'language', 'value' => $this->config->default->lang);
$configs[] = array('key' => 'version', 'value' => $this->config->version);
$configs[] = array('key' => 'charset', 'value' => $this->config->charset);
$configs[] = array('key' => 'timezone', 'value' => $this->config->timezone);
$configs[] = array('key' => 'systemMode', 'value' => $this->config->systemMode);
$this->send(200, $configs);
}
+88
View File
@@ -0,0 +1,88 @@
<?php
/**
* The doc entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class docEntry extends entry
{
/**
* GET method.
*
* @param int $docID
* @access public
* @return void
*/
public function get($docID)
{
$this->resetOpenApp($this->param('tab', 'doc'));
$control = $this->loadController('doc', 'view');
$control->view($docID);
$data = $this->getData();
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);
$doc = $data->data->doc;
unset($doc->draft);
if(!empty($doc->files)) $doc->files = array_values((array)$doc->files);
/* Set lib name */
$doc->libName = $data->data->lib->name;
$preAndNext = $data->data->preAndNext;
$doc->preAndNext = array();
$doc->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
$doc->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
$this->send(200, $this->format($doc, 'addedBy:user,addedDate:time,assignedTo:user,assignedDate:date,editedBy:user,editedDate:time,mailto:userList'));
}
/**
* PUT method.
*
* @param int $storyID
* @access public
* @return void
*/
public function put($storyID)
{
$oldStory = $this->loadModel('story')->getByID($storyID);
/* Set $_POST variables. */
$fields = 'type';
$this->batchSetPost($fields, $oldStory);
$this->setPost('parent', 0);
$control = $this->loadController('story', 'edit');
$control->edit($storyID);
$this->getData();
$story = $this->story->getByID($storyID);
$this->sendSuccess(200, $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time,deleted:bool'));
}
/**
* DELETE method.
*
* @param int $storyID
* @access public
* @return void
*/
public function delete($storyID)
{
$control = $this->loadController('story', 'delete');
$control->delete($storyID, 'yes');
$this->getData();
$this->sendSuccess(200, 'success');
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
* The doclibs entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class doclibsEntry extends Entry
{
/**
* GET method.
*
* @access public
* @return void
*/
public function get()
{
$type = $this->param('type', 0);
$objectID = $this->param('objectID', 0);
$libs = $this->loadModel('doc')->getLibs($type, $this->param('extra', ''), $this->param('appendLibs', ''), $objectID);
$result = array();
foreach($libs as $libID => $libName)
{
$lib = new stdclass();
$lib->id = $libID;
$lib->name = $libName;
$result[] = $lib;
}
krsort($result);
return $this->send(200, array('libs' => array_values($result)));
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
* The docs entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class docsEntry extends Entry
{
/**
* GET method.
*
* @access public
* @return void
*/
public function get($libID = 0)
{
if(empty($libID)) $libID = $this->param('lib', 0);
if(empty($libID)) return $this->sendError(400, 'Need lib id.');
$docTree = $this->loadModel('doc')->getDocTree($libID);
foreach($docTree as $i => $module)
{
if(empty($module->id))
{
unset($docTree[$i]);
foreach($module->children as $doc) $docTree[] = $doc;
}
}
return $this->send(200, array('docs' => array_values($docTree)));
}
}
+35 -5
View File
@@ -27,14 +27,36 @@ class executionEntry extends Entry
$data = $this->getData();
if(!$data or !isset($data->status)) return $this->send400('error');
if(isset($data->status) and $data->status == 'fail')
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$execution = $this->format($data->data->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');
$execution->progress = ($execution->totalConsumed + $execution->totalLeft) ? round($execution->totalConsumed / ($execution->totalConsumed + $execution->totalLeft) * 100, 1) : 0;
$execution->teamMembers = array_values((array)$data->data->teamMembers);
$execution->products = array();
foreach($data->data->products as $productID => $executionProduct)
{
return isset($data->code) and $data->code == 404 ? $this->send404() : $this->sendError(400, $data->message);
$product = new stdclass();
$product->id = $executionProduct->id;
$product->name = $executionProduct->name;
$product->plans = array();
foreach($executionProduct->plans as $planID)
{
$plan = new stdclass();
$plan->id = $planID;
$plan->name = $data->data->planGroups->{$productID}->{$planID};
$product->plans[] = $plan;
}
$execution->products[] = $product;
}
$execution = $this->format($data->data->execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool');
$this->loadModel('testcase');
$execution->caseReview = ($this->config->testcase->needReview or !empty($this->config->testcase->forceReview));
if(!$fields) $this->send(200, $execution);
$users = $data->data->users;
/* Set other fields. */
$fields = explode(',', strtolower($fields));
foreach($fields as $field)
@@ -63,6 +85,14 @@ class executionEntry extends Entry
$execution->stories = array_values($stories);
break;
case 'actions':
$actions = $data->data->actions;
$execution->actions = $this->loadModel('action')->processActionForAPI($actions, $users, $this->lang->execution);
break;
case "dynamics":
$dynamics = $data->data->dynamics;
$execution->dynamics = $this->loadModel('action')->processDynamicForAPI($dynamics);
break;
}
}
@@ -81,7 +111,7 @@ class executionEntry extends Entry
$oldExecution = $this->loadModel('execution')->getByID($executionID);
/* Set $_POST variables. */
$fields = 'project,code,name,begin,end,lifetime,desc,days,acl';
$fields = 'project,code,name,begin,end,lifetime,desc,days,acl,status';
$this->batchSetPost($fields, $oldExecution);
$this->setPost('whitelist', $this->request('whitelist', explode(',', $oldExecution->whitelist)));
@@ -94,7 +124,7 @@ class executionEntry extends Entry
if(!isset($data->result)) return $this->sendError(400, 'error');
$execution = $this->execution->getByID($executionID);
$this->send(200, $this->format($execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'));
$this->send(200, $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'));
}
/**
+68
View File
@@ -0,0 +1,68 @@
<?php
/**
* The execution bugs entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class executionBugsEntry extends entry
{
/**
* GET method.
*
* @param int $executionID
* @access public
* @return void
*/
public function get($executionID = 0)
{
if(!$executionID) $executionID = $this->param('execution', 0);
if(empty($executionID)) return $this->sendError(400, 'Need execution id.');
$control = $this->loadController('execution', 'bug');
$control->bug($executionID, $this->param('product', 0), $this->param('order', 'status,id_desc'), $this->param('build', 0), $this->param('status', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$bugs = $data->data->bugs;
$pager = $data->data->pager;
$result = array();
foreach($bugs as $bug)
{
$status = array('code' => $bug->status, 'name' => $this->lang->bug->statusList[$bug->status]);
if($bug->status == 'active' and $bug->confirmed) $status = array('code' => 'confirmed', 'name' => $this->lang->bug->labelConfirmed);
if($bug->resolution == 'postponed') $status = array('code' => 'postponed', 'name' => $this->lang->bug->labelPostponed);
if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs);
$bug->status = $status['code'];
$bug->statusName = $status['name'];
$result[$bug->id] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool');
}
$storyChangeds = $this->dao->select('t1.id')->from(TABLE_BUG)->alias('t1')
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id')
->where('t1.id')->in(array_keys($result))
->andWhere('t1.story')->ne('0')
->andWhere('t1.storyVersion != t2.version')
->fetchPairs('id', 'id');
foreach($storyChangeds as $bugID)
{
$status = array('code' => 'storyChanged', 'name' => $this->lang->bug->changed);
$result[$bugID]->status = $status['code'];
$result[$bugID]->statusName = $status['name'];
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => array_values($result)));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
}
+41
View File
@@ -0,0 +1,41 @@
<?php
/**
* The execution builds entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class executionBuildsEntry extends entry
{
/**
* GET method.
*
* @param int $executionID
* @access public
* @return void
*/
public function get($executionID = 0)
{
if(empty($executionID)) $executionID = $this->param('execution', 0);
if(empty($executionID)) return $this->sendError(400, "Need execution id.");
$control = $this->loadController('execution', 'build');
$control->build($executionID, $this->param('status', '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');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$result = array();
foreach($data->data->executionBuilds as $builds)
{
foreach($builds as $build) $result[] = $this->format($build, 'builder:user,bugs:idList,stories:idList,deleted:bool');
}
return $this->send(200, array('total' => count($result), 'builds' => $result));
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
/**
* The execution cases entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class executionCasesEntry extends entry
{
/**
* GET method.
*
* @param int $executionID
* @access public
* @return void
*/
public function get($executionID = 0)
{
if(!$executionID) $executionID = $this->param('execution', 0);
if(empty($executionID)) return $this->sendError(400, 'Need execution id.');
$control = $this->loadController('execution', 'testcase');
$control->testcase($executionID, $this->param('status', 'all'), $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$cases = $data->data->cases;
$pager = $data->data->pager;
$result = array();
foreach($cases as $case)
{
$case->statusName = 'name' => $this->lang->testcase->statusList[$case->status];
$result[] = $this->format($case, 'openedDate:time,reviewedDate:date,lastEditedDate:time,lastRunDate:time');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'cases' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
}
+101 -24
View File
@@ -21,25 +21,54 @@ class executionsEntry extends entry
public function get($projectID = 0)
{
$appendFields = $this->param('fields', '');
$withProject = $this->param('withProject', '');
if(strpos(strtolower(",{$appendFields},"), ',dropmenu,') !== false) return $this->getDropMenu();
$control = $this->loadController('execution', 'all');
$control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
if($projectID)
{
$pager = $data->data->pager;
$result = array();
foreach($data->data->executionStats as $execution)
{
$execution = $this->filterFields($execution, 'id,name,project,code,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields);
$result[] = $this->format($execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'executions' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
$control = $this->loadController('project', 'execution');
$control->execution($this->param('status', 'undone'), $projectID, $this->param('order', 'id_desc'), $this->param('product', 0), 0, $this->param('limit', 20), $this->param('page', 1));
return $this->sendError(400, 'error');
/* Response */
$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);
$executions = $data->data->executionStats;
$pager = $data->data->pager;
$projects = $data->data->projects;
}
else
{
$control = $this->loadController('execution', 'all');
$control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, 0, $this->param('limit', 20), $this->param('page', 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(400, $data->message);
$executions = $data->data->executionStats;
$pager = $data->data->pager;
$projects = $data->data->projects;
}
$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,' . $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');
}
$data = array();
$data['page'] = $pager->pageID;
$data['total'] = $pager->recTotal;
$data['limit'] = $pager->recPerPage;
$data['executions'] = $result;
if(!empty($withProject)) $data['projects'] = $projects;
return $this->send(200, $data);
}
/**
@@ -55,15 +84,17 @@ class executionsEntry extends entry
$this->batchSetPost($fields);
$projectID = $this->param('project', $projectID);
$this->setPost('project', $projectID);
$this->setPost('acl', $this->request('acl', 'private'));
$this->setPost('project', $projectID);
$this->setPost('acl', $this->request('acl', 'private'));
$this->setPost('PO', $this->request('PO', ''));
$this->setPost('PM', $this->request('PM', ''));
$this->setPost('QD', $this->request('QD', ''));
$this->setPost('RD', $this->request('RD', ''));
$this->setPost('whitelist', $this->request('whitelist', array()));
$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');
$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->create($projectID);
$data = $this->getData();
@@ -71,6 +102,52 @@ class executionsEntry extends entry
$execution = $this->loadModel('execution')->getByID($data->id);
$this->send(201, $this->format($execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'));
$this->send(201, $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'));
}
/**
* Get drop menu.
*
* @access public
* @return void
*/
public function getDropMenu()
{
$control = $this->loadController('execution', 'ajaxGetDropMenu');
$control->ajaxGetDropMenu($this->request('executionID', 0), $this->request('module', 'execution'), $this->request('method', 'task'), $this->request('extra', ''));
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$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($projectExecutions as $execution)
{
if(helper::diffDate(date('Y-m-d'), $execution->end) > 0) $execution->delay = true;
$teams = $execution->teams;
$execution = $this->filterFields($execution, 'id,project,model,type,name,code,status,PM,delay');
$projectName = zget($projects, $execution->project, '');
if($projectName) $execution->name = $projectName . '/' . $execution->name;
if($execution->status == 'closed')
{
$dropMenu['closed'][] = $execution;
}
elseif($execution->status != 'done' and $execution->status != 'closed' and ($execution->PM == $account or isset($teams->$account)))
{
$dropMenu['involved'][] = $execution;
}
else
{
$dropMenu['other'][] = $execution;
}
}
}
$this->send(200, $dropMenu);
}
}
@@ -9,7 +9,7 @@
* @version 1
* @link http://www.zentao.net
*/
class executionStoriesEntry extends entry
class executionStoriesEntry extends entry
{
/**
* GET method.
@@ -20,8 +20,11 @@ class executionStoriesEntry extends entry
*/
public function get($executionID)
{
if(empty($executionID)) $this->param('execution', 0);
if(empty($executionID)) return $this->sendError(400, 'Need execution id.');
$control = $this->loadController('execution', 'story');
$control->story($executionID, $this->param('order', ''), $this->param('type', 'all'), 0, $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
$control->story($executionID, $this->param('order', 'id_desc'), $this->param('status', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
@@ -31,15 +34,12 @@ class executionStoriesEntry extends entry
$result = array();
foreach($stories as $story)
{
$result[] = $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time');
$result[] = $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(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'executionStories' => $result));
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result));
}
if(isset($data->status) and $data->status == 'fail')
{
return $this->sendError(400, $data->message);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
+17
View File
@@ -11,6 +11,23 @@
*/
class fileEntry extends Entry
{
/**
* GET method.
*
* @access public
* @return void
*/
public function get($fileID)
{
$control = $this->loadController('file', 'download');
$control->download($fileID);
$data = $this->getData();
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);
$this->send(200, $data);
}
/**
* PUT method.
*
+1 -4
View File
@@ -27,10 +27,7 @@ class filesEntry extends Entry
$data = $this->getData();
if(!$data or !isset($data->status)) return $this->send400('error');
if(isset($data->status) and $data->status == 'error')
{
return isset($data->code) and $data->code == 404 ? $this->send404() : $this->sendError(400, $data->message);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$this->send(200, array('id' => $data->id));
}
+39
View File
@@ -0,0 +1,39 @@
<?php
/**
* The repo entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author xiawenlong <xiawenlong@cnezsoft.com>
* @package repo
* @version 1
* @link http://www.zentao.net
*/
class gitlabWebhookEntry extends baseEntry
{
/**
* Repo webhook.
*
* @access public
* @return void
*/
public function post()
{
$repoID= $this->param('repoID');
if(empty($id)) return;
$this->loadModel('repo');
$repo = $this->repo->getRepoByID($repoID);
if(empty($repo)) return;
$headers = getallheaders(); /* Fetch all HTTP request headers. */
$event = isset($headers['X-Gitlab-Event']) ? $headers['X-Gitlab-Event'] : '';
$token = isset($headers['X-Gitlab-Token']) ? $headers['X-Gitlab-Token'] : '';
if(empty($event) || empty($token)) return;
$this->repo->handleWebhook($event, $token, $this->requestBody, $repo);
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ class issueEntry extends Entry
$data = $this->getData();
if(!$data or (isset($data->message) and $data->message == '404 Not found')) return $this->send404();
if(isset($data->status) and $data->status == 'success') return $this->send(200, $this->format($data->data->issue, 'createdDate:time,editedDate:time,assignedDate:time'));
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$this->sendError(400, 'error');
}
+1 -1
View File
@@ -28,7 +28,7 @@ class issuesEntry extends entry
$data = $this->getData();
if(!isset($data->status)) return $this->sendError(400, 'error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$pager = $data->data->pager;
$result = array();
+80
View File
@@ -0,0 +1,80 @@
<?php
/**
* The meetings entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class meetingsEntry extends entry
{
/**
* GET method.
*
* @param int $projectID
* @access public
* @return void
*/
public function get($projectID = 0)
{
if(empty($projectID)) $projectID = $this->param('project', 0);
if(empty($projectID)) return $this->sendError(400, 'Need project id.');
$project = $this->loadModel('project')->getByID($projectID);
if(!$project) return $this->send404();
/* Get meetings by project. */
$control = $this->loadController('meeting', 'browse');
$control->browse($projectID, $this->param('status', 'all'), '', $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(!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);
$pager = $data->data->pager;
$result = array();
foreach($data->data->meetings as $risk)
{
$result[] = $this->format($risk, 'createdDate:time,editedDate:time');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'meetings' => $result));
}
/**
* POST method.
*
* @param int $projectID
* @access public
* @return void
*/
public function post($projectID = 0)
{
$project = $this->loadModel('project')->getByID($projectID);
if(!$project) return $this->send404();
$fields = 'source,name,category,strategy,status,impact,probability,rate,identifiedDate,plannedClosedDate,actualClosedDate,resolvedBy,assignedTo,prevention,remedy,resolution';
$this->batchSetPost($fields);
$this->setPost('impact', $this->request('impact', 3));
$this->setPost('probability', $this->request('probability', 3));
$this->setPost('rate', $this->request('rate', 9));
$this->setPost('pri', 'middle');
$control = $this->loadController('risk', 'create');
$this->requireFields('name');
$control->create($projectID);
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
$risk = $this->loadModel('risk')->getByID($data->id);
$this->send(201, $this->format($risk, 'createdDate:time,editedDate:time'));
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
/**
* The ping entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class pingEntry extends entry
{
/**
* GET method.
*
* @access public
* @return void
*/
public function get()
{
$this->send(200, array('token' => session_id(), 'tokenLife' => ini_get('session.gc_maxlifetime')));
}
}
+31 -7
View File
@@ -27,16 +27,17 @@ class productEntry extends Entry
$data = $this->getData();
if(!$data or !isset($data->status)) return $this->send400('error');
if(isset($data->status) and $data->status == 'fail')
{
return isset($data->code) and $data->code == 404 ? $this->send404() : $this->sendError(400, $data->message);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$product = $this->format($data->data->product, 'createdDate:time,whitelist:userList,createdBy:user,PO:user,RD:user,QD:user,feedback:user');
$this->loadModel('testcase');
$product->caseReview = ($this->config->testcase->needReview or !empty($this->config->testcase->forceReview));
$product = $this->format($data->data->product, 'createdDate:time');
if(!$fields) return $this->send(200, $product);
/* Set other fields. */
$fields = explode(',', $fields);
$fields = explode(',', strtolower($fields));
foreach($fields as $field)
{
switch($field)
@@ -50,6 +51,29 @@ class productEntry extends Entry
$product->modules = $data->data->tree;
}
break;
case 'actions':
$product->addComment = common::hasPriv('action', 'comment') ? true : false;
$actions = $data->data->actions;
$product->actions = $this->loadModel('action')->processActionForAPI($actions, $users, $this->lang->product);
break;
case 'lastexecution':
$execution = $this->dao->select('t2.id,t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
->where('t2.deleted')->eq(0)
->andWhere('t1.product')->eq($productID)
->andWhere('t2.type')->in('sprint,stage')
->orderBy('t2.id desc')
->limit(1)
->fetch();
if($execution)
{
$workhour = $this->loadModel('project')->computerProgress(array($execution->id => $execution));
if(isset($workhour[$execution->id])) $execution->progress = $workhour[$execution->id]->progress;
}
$product->lastExecution = $execution;
break;
}
}
@@ -78,7 +102,7 @@ class productEntry extends Entry
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$product = $this->product->getByID($productID);
$this->send(200, array('product' => $this->format($product, 'createdDate:time')));
$this->send(200, $this->format($product, 'createdDate:time'));
}
/**
+19 -7
View File
@@ -27,12 +27,13 @@ class productplanEntry extends Entry
$data = $this->getData();
if(!$data or !isset($data->status)) return $this->send400('error');
if(isset($data->status) and $data->status == 'fail')
{
return isset($data->code) and $data->code == 404 ? $this->send404() : $this->sendError(400, $data->message);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$plan = $this->format($data->data->plan, 'begin:date,end:date,deleted:bool');
$plan = $data->data->plan;
$plan->stories = $data->data->planStories;
$plan->bugs = $data->data->planBugs;
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
return $this->send(200, $plan);
}
@@ -58,8 +59,19 @@ class productplanEntry extends Entry
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$plan = $this->productplan->getByID($planID);
$this->sendSuccess(200, $this->format($plan, 'begin:date,end:date'));
/* Get plan info. */
$control = $this->loadController('productplan', 'view');
$control->view($planID);
$data = $this->getData();
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);
$plan = $data->data->plan;
$plan->stories = $data->data->planStories;
$plan->bugs = $data->data->planBugs;
$this->send(200, $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array'));
}
/**
+50
View File
@@ -0,0 +1,50 @@
<?php
/**
* The productplanlinkbugs entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class productplanLinkBugsEntry extends entry
{
/**
* POST method.
*
* @param int $planID
* @access public
* @return void
*/
public function post($planID)
{
$fields = 'bugs';
$this->batchSetPost($fields);
$control = $this->loadController('productplan', 'linkBug');
$control->linkBug($planID);
$data = $this->getData();
if(isset($data->result) and $data->result == 'success')
{
$control = $this->loadController('productplan', 'view');
$control->view($planID);
$data = $this->getData();
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);
$plan = $data->data->plan;
$plan->stories = $data->data->planStories;
$plan->bugs = $data->data->planBugs;
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
return $this->send(200, $plan);
}
$this->sendError(400, array('message' => isset($data->message) ? $data->message : 'error'));
}
}
+50
View File
@@ -0,0 +1,50 @@
<?php
/**
* The productplanlinkstories entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class productplanLinkStoriesEntry extends entry
{
/**
* POST method.
*
* @param int $planID
* @access public
* @return void
*/
public function post($planID)
{
$fields = 'stories';
$this->batchSetPost($fields);
$control = $this->loadController('productplan', 'linkStory');
$control->linkStory($planID);
$data = $this->getData();
if(isset($data->result) and $data->result == 'success')
{
$control = $this->loadController('productplan', 'view');
$control->view($planID);
$data = $this->getData();
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);
$plan = $data->data->plan;
$plan->stories = $data->data->planStories;
$plan->bugs = $data->data->planBugs;
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
return $this->send(200, $plan);
}
$this->sendError(400, array('message' => isset($data->message) ? $data->message : 'error'));
}
}
+52 -3
View File
@@ -32,13 +32,62 @@ class productplansEntry extends entry
{
$result = array();
$plans = $data->data->plans;
foreach($plans as $plan) $result[] = $plan;
$pager = $data->data->pager;
return $this->send(200, array('plans' => $result));
foreach($plans as $plan)
{
if($plan->parent > 0 and isset($result[$plan->parent]))
{
$parentPlan = $result[$plan->parent];
if(!isset($parentPlan->children) or !is_array($parentPlan->children)) $parentPlan->children = array();
$parentPlan->children[] = $plan;
$result[$plan->parent] = $parentPlan;
}
else
{
$result[$plan->id] = $this->format($plan, 'begin:date,end:date,deleted:bool,project:int');
}
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'plans' => array_values($result)));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
/**
* POST method.
*
* @param int $productID
* @access public
* @return void
*/
public function post($productID = 0)
{
if(!$productID) $productID = $this->param('product', 0);
if(!$productID) return $this->sendError(400, 'No product id.');
$fields = 'branch,begin,end,title,desc';
$this->batchSetPost($fields);
$this->setPost('product', $productID);
$this->setPost('parent', $this->request('parent', 0));
$this->setPost('branch', $this->request('branch', 0));
$control = $this->loadController('productplan', 'create');
$control->create($productID, $this->param('branch', 0), $this->param('parent', 0));
$data = $this->getData();
if(isset($data->result) and $data->result == 'success')
{
$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'));
}
$this->sendError(400, array('message' => isset($data->message) ? $data->message : 'error'));
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
/**
* The productplanunlinkbugs entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class productplanUnlinkBugsEntry extends entry
{
/**
* POST method.
*
* @param int $planID
* @access public
* @return void
*/
public function post($planID)
{
$productplan = $this->loadModel('productplan');
foreach($this->request('bugs', array()) as $bugID)
{
$productplan->unlinkBug($bugID, $planID);
if(dao::isError()) return $this->sendError('error');
}
$control = $this->loadController('productplan', 'view');
$control->view($planID);
$data = $this->getData();
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);
$plan = $data->data->plan;
$plan->stories = $data->data->planStories;
$plan->bugs = $data->data->planBugs;
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
return $this->send(200, $plan);
}
}
@@ -0,0 +1,45 @@
<?php
/**
* The productplanunlinkstories entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class productplanUnlinkStoriesEntry extends entry
{
/**
* POST method.
*
* @param int $planID
* @access public
* @return void
*/
public function post($planID)
{
$productplan = $this->loadModel('productplan');
foreach($this->request('stories', array()) as $storyID)
{
$productplan->unlinkStory($storyID, $planID);
if(dao::isError()) return $this->sendError('error');
}
$control = $this->loadController('productplan', 'view');
$control->view($planID);
$data = $this->getData();
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);
$plan = $data->data->plan;
$plan->stories = $data->data->planStories;
$plan->bugs = $data->data->planBugs;
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
return $this->send(200, $plan);
}
}
+128
View File
@@ -0,0 +1,128 @@
<?php
/**
* The product projects entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class productProjectsEntry extends entry
{
/**
* GET method.
*
* @param int $productID
* @access public
* @return void
*/
public function get($productID = 0)
{
if(empty($productID)) $productID = $this->param('product', 0);
if(empty($productID)) return $this->sendError('400', "Need product id");
$appendFields = $this->param('fields', '');
$control = $this->loadController('product', 'project');
$control->project($this->param('status', 'all'), $productID, $this->param('branch', 0), $this->param('involved', 0), $this->param('order', 'order_desc'));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$result = array();
foreach($data->data->projectStats as $project)
{
foreach($project->hours as $field => $value) $project->$field = $value;
$project = $this->filterFields($project, 'id,name,code,model,type,budget,budgetUnit,parent,begin,end,status,openedBy,openedDate,PM,delay,progress,' . $appendFields);
$result[] = $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time');
}
$data = array();
$data['total'] = count($result);
$data['projects'] = $result;
$withUser = $this->param('withUser', '');
if(!empty($withUser)) $data['users'] = $users;
return $this->send(200, $data);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
// TODO There is no handle for 401.
return $this->sendError(400, 'error');
}
/**
* POST method.
*
* @access public
* @return void
*/
public function post()
{
$fields = 'name,begin,end,products';
$this->batchSetPost($fields);
$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()));
$this->setPost('PM', $this->request('PM', ''));
$this->setPost('model', $this->request('model', 'scrum'));
$control = $this->loadController('project', 'create');
$this->requireFields('name,code,begin,end,products');
$control->create($this->request('model', 'scrum'));
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
if(!isset($data->result)) return $this->sendError(400, 'error');
$project = $this->loadModel('project')->getByID($data->id);
$this->send(201, $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'));
}
/**
* Get drop menu.
*
* @access public
* @return void
*/
public function getDropMenu()
{
$control = $this->loadController('project', 'ajaxGetDropMenu');
$control->ajaxGetDropMenu($this->request('projectID', 0), $this->request('module', 'project'), $this->request('method', 'browse'));
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array());
foreach($data->data->projects as $programID => $projects)
{
foreach($projects as $project)
{
if(helper::diffDate(date('Y-m-d'), $project->end) > 0) $project->delay = true;
$project = $this->filterFields($project, 'id,model,type,name,code,parent,status,PM,delay');
if($project->status == 'closed')
{
$dropMenu['closed'][] = $project;
}
elseif($project->PM == $this->app->user->account)
{
$dropMenu['owner'][] = $project;
}
else
{
$dropMenu['other'][] = $project;
}
}
}
$this->send(200, $dropMenu);
}
}
+163 -19
View File
@@ -20,23 +20,24 @@ class productsEntry extends entry
*/
public function get($programID = 0)
{
$fields = $this->param('fields', '');
if(strpos(strtolower(",{$fields},"), ',dropmenu,') !== false) return $this->getDropMenu();
if(!$programID) $programID = $this->param('program', 0);
$mergeChildren = $this->param('mergeChildren', '');
if($programID)
{
$control = $this->loadController('program', 'product');
$control->product($programID, $this->param('status', 'all'), $this->param('order', 'order_asc'), 0, 10000);
$control->product($programID, $this->param('status', 'all'), $this->param('order', 'order_asc'), 0, $this->param('limit', '20'), $this->param('page', '1'));
/* Response */
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$result = array();
$products = $data->data->products;
foreach($products as $product) $result[] = $this->format($product, 'createdDate:time');
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);
$products = $data->data->products;
return $this->send(200, array('products' => $result));
}
}
else
{
@@ -45,19 +46,51 @@ class productsEntry extends entry
/* Response */
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$result = array();
$products = $data->data->productStats;
foreach($products as $product) $result[] = $this->format($product, 'createdDate:time');
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
return $this->send(200, array('products' => $result));
}
$products = $data->data->productStats;
if($mergeChildren) $products = $data->data->productStructure;
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
$result = array();
if($mergeChildren)
{
$programs = $this->mergeChildren($products);
return $this->send(200, $programs);
}
else
{
$accounts = array();
foreach($products as $product)
{
$accounts[$product->PO] = $product->PO;
$accounts[$product->QD] = $product->QD;
$accounts[$product->RD] = $product->RD;
$accounts[$product->createdBy] = $product->createdBy;
if(isset($product->feedback)) $accounts[$product->feedback] = $product->feedback;
if(!empty($product->mailto))
{
foreach(explode(',', $product->mailto) as $account)
{
$account = trim($account);
if(empty($account)) continue;
$accounts[$account] = $account;
}
}
return $this->sendError(400, 'error');
$result[] = $this->format($product, 'createdDate:time,whitelist:userList,createdBy:user,PO:user,RD:user,QD:user');
}
$data = array();
$data['total'] = count($result);
$data['products'] = $result;
$withUser = $this->param('withUser', '');
if(!empty($withUser)) $data['users'] = $this->loadModel('user')->getListByAccounts($accounts, 'account');
return $this->send(200, $data);
}
}
/**
@@ -80,12 +113,123 @@ class productsEntry extends entry
$control->create($this->request('program', 0));
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
if(isset($data->result) and $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
/* Response */
$product = $this->loadModel('product')->getByID($data->id);
$product = $this->format($product, 'createdDate:time,whitelist:[]string');
$product = $this->format($product, 'createdDate:time,whitelist:userList,createdBy:user,PO:user,RD:user,QD:user');
$this->send(200, $product);
}
/**
* Get dropmenu.
*
* @access public
* @return void
*/
public function getDropMenu()
{
$control = $this->loadController('product', 'ajaxGetDropMenu');
$control->ajaxGetDropMenu($this->request('productID', 0), $this->request('module', 'product'), $this->request('method', 'browse'), $this->request('extra', ''), $this->request('from', ''));
$data = $this->getData();
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array());
foreach($data->data->products as $programID => $products)
{
foreach($products as $product)
{
$product = $this->filterFields($product, 'id,program,name,code,status,PO');
if($product->status == 'closed')
{
$dropMenu['closed'][] = $product;
}
elseif($product->PO == $this->app->user->account)
{
$dropMenu['owner'][] = $product;
}
else
{
$dropMenu['other'][] = $product;
}
}
}
$this->send(200, $dropMenu);
}
/**
* Merge children products.
*
* @param array $products
* @access public
* @return void
*/
public function mergeChildren($products)
{
$programs = array();
foreach($products as $programID => $program)
{
$programs[$programID] = new stdclass();
if(!empty($programID))
{
$programs[$programID]->id = $programID;
$programs[$programID]->name = $program->programName;
$programs[$programID]->type = 'program';
}
$unclosedTotal = 0;
foreach($program as $field => $value)
{
if(!isset($programs[$programID]->children)) $programs[$programID]->children = array();
if(isset($value->products))
{
$lineID = $field;
if(empty($lineID))
{
foreach($value->products as $product)
{
unset($product->desc);
$programs[$programID]->children[$product->id] = $product;
if($product->status != 'closed') $unclosedTotal += 1;
}
}
else
{
$line = new stdclass();
$line->id = $lineID;
$line->name = $value->lineName;
$line->type = 'line';
$line->children = array();
foreach($value->products as $product)
{
unset($product->desc);
$line->children[$product->id] = $product;
if($product->status != 'closed') $unclosedTotal += 1;
}
if(isset($line->children)) $line->children = array_values($line->children);
$programs[$programID]->children[$lineID] = $line;
}
if(isset($programs[$programID]->children)) $programs[$programID]->children = array_values($programs[$programID]->children);
$programs[$programID]->unclosedTotal = $unclosedTotal;
}
}
}
$topProducts = array();
if(isset($programs[0]))
{
$topProducts = $programs[0]->children;
unset($programs[0]);
}
$programs = array_values($programs);
foreach($topProducts as $product) $programs[] = $product;
return $programs;
}
}
+56
View File
@@ -11,4 +11,60 @@
*/
class programEntry extends Entry
{
/**
* GET method.
*
* @param int $programID
* @access public
* @return void
*/
public function get($programID)
{
$program = $this->loadModel('program')->getByID($programID);
if(!$program) return $this->send404();
$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'));
}
/**
* PUT method.
*
* @param int $programID
* @access public
* @return void
*/
public function put($programID)
{
$oldProgram = $this->loadModel('program')->getByID($programID);
/* Set $_POST variables. */
$fields = 'name,PM,budget,budgetUnit,desc,parent,begin,end,realBegan,realEnd,acl,whitelist';
$this->batchSetPost($fields, $oldProgram);
$this->setPost('parent', $this->request('parent', 0));
$control = $this->loadController('program', 'edit');
$control->edit($programID);
$this->getData();
$program = $this->program->getByID($programID);
$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'));
}
/**
* DELETE method.
*
* @param int $programID
* @access public
* @return void
*/
public function delete($programID)
{
$control = $this->loadController('program', 'delete');
$control->delete(0, $programID, 'true');
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$this->sendSuccess(200, 'success');
}
}
+94 -10
View File
@@ -9,7 +9,7 @@
* @version 1
* @link http://www.zentao.net
*/
class ProgramsEntry extends Entry
class programsEntry extends Entry
{
/**
* GET method.
@@ -19,25 +19,109 @@ class ProgramsEntry extends Entry
*/
public function get()
{
$_COOKIE['showClosed'] = $this->param('showClosed', 0);
$mergeChildren = $this->param('mergeChildren', 0);
$this->config->systemMode = 'new';
$fields = $this->param('fields', '');
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'));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
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)
{
$programs = $data->data->programs;
$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)
{
$result[] = $this->format($program, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool');
unset($program->desc);
$program->end = $program->end == LONG_TIME ? $this->lang->program->longTime : $program->end;
$programBudget = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')) ? round((float)$program->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$program->budget, 2);
$program->labelBudget = $program->budget != 0 ? zget($this->lang->project->currencySymbol, $program->budgetUnit) . ' ' . $programBudget : $this->lang->project->future;
if(empty($program->parent)) $result[$program->id] = $program;
if(isset($programs->{$program->parent}))
{
$parentProgram = $programs->{$program->parent};
if(!isset($parentProgram->children)) $parentProgram->children = array();
$parentProgram->children[] = $program;
}
}
else
{
$result[] = $program;
}
return $this->send(200, array('programs' => $result));
}
if(isset($data->status) and $data->status == 'fail')
return $this->send(200, array('programs' => array_values($result)));
}
/**
* POST method.
*
* @access public
* @return void
*/
public function post()
{
$fields = 'name,PM,budget,budgetUnit,desc,begin,end';
$this->batchSetPost($fields);
$this->setPost('acl', $this->request('acl', 'open'));
$this->setPost('whitelist', $this->request('whitelist', array()));
$control = $this->loadController('program', 'create');
$this->requireFields('name,begin,end');
$control->create($this->request('parent', 0));
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$program = $this->loadModel('program')->getByID($data->id);
$this->send(201, $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'));
}
/**
* Get drop menu.
*
* @access public
* @return void
*/
public function getDropMenu()
{
$programs = $this->dao->select('id,name,parent,path,grade,`order`')->from(TABLE_PROJECT)
->where('deleted')->eq('0')
->andWhere('type')->eq('program')
->andWhere('id')->in($this->app->user->view->programs)
->beginIF(empty($_COOKIE['showClosed']))->andWhere('status')->ne('closed')->fi()
->orderBy('grade desc, `order`')
->fetchAll('id');
$dropMenu = array();
foreach($programs as $programID => $program)
{
return $this->sendError(400, $data->message);
if(empty($program->parent))
{
$dropMenu[] = $program;
}
elseif(isset($programs[$program->parent]))
{
if(!isset($programs[$program->parent]->children)) $programs[$program->parent]->children = array();
$programs[$program->parent]->children[] = $program;
}
}
return $this->sendError(400, 'error');
$this->send(200, $dropMenu);
}
}
+59 -11
View File
@@ -20,20 +20,68 @@ class projectEntry extends entry
*/
public function get($projectID)
{
$fields = strtolower($this->param('fields'));
$control = $this->loadController('project', 'view');
$control->view($projectID);
$data = $this->getData();
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
if(isset($data->status) and $data->status == 'success') return $this->send(200, $this->format($data->data->project, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'));
if(isset($data->status) and $data->status == 'fail')
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);
$project = $this->format($data->data->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');
$this->loadModel('testcase');
$project->caseReview = ($this->config->testcase->needReview or !empty($this->config->testcase->forceReview));
if(empty($fields)) return $this->send(200, $project);
/* Set other fields. */
$fields = explode(',', $fields);
foreach($fields as $field)
{
if(isset($data->code) and $data->code == 404) $this->send404();
return $this->sendError(400, $data->message);
switch($field)
{
case 'team':
$teams = array();
$accounts = array();
foreach($data->data->teamMembers as $account => $team)
{
$team = $this->filterFields($team, "account,role,join,realname");
$teams[$account] = $team;
$accounts[$account] = $account;
}
$users = $this->loadModel('user')->getListByAccounts($accounts, 'account');
foreach($teams as $account => $team)
{
$user = zget($users, $account, '');
$team->avatar = $user->avatar;
}
$project->teams = $teams;
break;
case "stat":
$project->stat = $data->data->statData;
break;
case "workhour":
$workhour = $data->data->workhour;
$workhour->progress = ($workhour->totalConsumed + $workhour->totalLeft) ? floor($workhour->totalConsumed / ($workhour->totalConsumed + $workhour->totalLeft) * 1000) / 1000 * 100 : 0;
$project->workhour = $workhour;
break;
case "actions":
$actions = $data->data->actions;
$project->actions = $this->loadModel('action')->processActionForAPI($actions, (array)$data->data->users, $this->lang->project);
break;
case "dynamics":
$dynamics = $data->data->dynamics;
$project->dynamics = $this->loadModel('action')->processDynamicForAPI($dynamics);
break;
}
}
$this->sendError(400, 'error');
return $this->send(200, $project);
}
/**
@@ -46,7 +94,7 @@ class projectEntry extends entry
public function put($projectID)
{
$oldProject = $this->loadModel('project')->getByID($projectID);
$linkedProducts = $this->project->getProducts($projectID);
$linkedProducts = $this->loadModel('product')->getProducts($projectID);
/* Set $_POST variables. */
$fields = 'name,begin,end,acl,parent,desc,PM,whitelist';
@@ -56,8 +104,8 @@ class projectEntry extends entry
$plans = array();
foreach($linkedProducts as $product)
{
$products[] = $product->id;
$plans[] = $product->plan;
$products[] = $product->id;
foreach($product->plans as $planID) $plans[] = $planID;
}
$this->setPost('products', $products);
$this->setPost('plans', $plans);
@@ -66,11 +114,11 @@ class projectEntry extends entry
$control->edit($projectID);
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(!isset($data->result)) return $this->sendError(400, 'error');
$project = $this->project->getByID($projectID);
$this->send(200, $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'));
$this->send(200, $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'));
}
/**
+68
View File
@@ -0,0 +1,68 @@
<?php
/**
* The project bugs entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class projectBugsEntry extends entry
{
/**
* GET method.
*
* @param int $projectID
* @access public
* @return void
*/
public function get($projectID = 0)
{
if(empty($projectID)) $projectID = $this->param('project', 0);
if(empty($projectID)) return $this->sendError(400, 'Need project id.');
$control = $this->loadController('project', 'bug');
$control->bug($projectID, $this->param('product', 0), $this->param('order', 'status,id_desc'), $this->param('build', 0), $this->param('status', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$bugs = $data->data->bugs;
$pager = $data->data->pager;
$result = array();
foreach($bugs as $bug)
{
$status = array('code' => $bug->status, 'name' => $this->lang->bug->statusList[$bug->status]);
if($bug->status == 'active' and $bug->confirmed) $status = array('code' => 'confirmed', 'name' => $this->lang->bug->labelConfirmed);
if($bug->resolution == 'postponed') $status = array('code' => 'postponed', 'name' => $this->lang->bug->labelPostponed);
if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs);
$bug->status = $status['code'];
$bug->statusName = $status['name'];
$result[$bug->id] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool');
}
$storyChangeds = $this->dao->select('t1.id')->from(TABLE_BUG)->alias('t1')
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id')
->where('t1.id')->in(array_keys($result))
->andWhere('t1.story')->ne('0')
->andWhere('t1.storyVersion != t2.version')
->fetchPairs('id', 'id');
foreach($storyChangeds as $bugID)
{
$status = array('code' => 'storyChanged', 'name' => $this->lang->bug->changed);
$result[$bugID]->status = $status['code'];
$result[$bugID]->statusName = $status['name'];
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => array_values($result)));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
}
+51
View File
@@ -0,0 +1,51 @@
<?php
/**
* The project cases entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class projectCasesEntry extends entry
{
/**
* GET method.
*
* @param int $projectID
* @access public
* @return void
*/
public function get($projectID = 0)
{
if(!$projectID) $projectID = $this->param('project', 0);
if(empty($projectID)) return $this->sendError(400, 'Need project id.');
$this->resetOpenApp('project');
$this->app->session->set('project', $projectID, $this->app->tab);
$control = $this->loadController('project', 'testcase');
$control->testcase($projectID, $this->param('product', 0), $this->param('branch', 0), $this->param('status', 'all'), 0, $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$cases = $data->data->cases;
$pager = $data->data->pager;
$result = array();
foreach($cases as $case)
{
$case->statusName = $this->lang->testcase->statusList[$case->status];
$result[] = $this->format($case, 'openedDate:time,reviewedDate:date,lastEditedDate:time,lastRunDate:time');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'cases' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
}
+21 -2
View File
@@ -9,7 +9,7 @@
* @version 1
* @link http://www.zentao.net
*/
class projectreleasesEntry extends entry
class projectReleasesEntry extends entry
{
/**
* GET method.
@@ -20,7 +20,26 @@ class projectreleasesEntry extends entry
*/
public function get($projectID = 0)
{
$this->fetch('releases', 'get', array('productID' => 0, 'projectID' => $projectID));
if(empty($projectID)) $projectID = $this->param('project');
if(empty($projectID)) return $this->sendError(400, 'Need project id.');
$control = $this->loadController('projectrelease', 'browse');
$control->browse($projectID, $this->param('execution', 0), $this->param('status', 'all'), $this->param('order', 't1.date_desc'));
/* Response */
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$result = array();
$releases = $data->data->releases;
foreach($releases as $release) $result[] = $this->format($release, 'deleted:bool,date:date,mailto:userList');
return $this->send(200, array('total' => count($result), 'releases' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
/**
+73 -10
View File
@@ -22,26 +22,50 @@ class projectsEntry extends entry
{
if(!$programID) $programID = $this->param('program', 0);
$appendFields = $this->param('fields', '');
if(stripos(strtolower(",{$appendFields},"), ',dropmenu,') !== false) return $this->getDropMenu();
$control = $this->loadController('project', 'browse');
$control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
$_COOKIE['involved'] = $this->param('involved', 0);
$this->config->systemMode = 'new';
if($programID)
{
$control = $this->loadController('program', 'project');
$control->project($programID, $this->param('status', 'all'), $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
}
else
{
$control = $this->loadController('project', 'browse');
$control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
}
if(isset($data->status) and $data->status == 'success')
{
$pager = $data->data->pager;
$users = $data->data->users;
$result = array();
foreach($data->data->projectStats as $project)
{
$project = $this->filterFields($project, 'id,name,code,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields);
$result[] = $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time');
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');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => (int)$pager->recPerPage, 'projects' => $result));
$data = array();
$data['page'] = $pager->pageID;
$data['total'] = $pager->recTotal;
$data['limit'] = (int)$pager->recPerPage;
$data['projects'] = $result;
$withUser = $this->param('withUser', '');
if(!empty($withUser)) $data['users'] = $users;
return $this->send(200, $data);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
// TODO There is no handle for 401.
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
@@ -74,6 +98,45 @@ class projectsEntry extends entry
$project = $this->loadModel('project')->getByID($data->id);
$this->send(201, $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'));
$this->send(201, $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'));
}
/**
* Get drop menu.
*
* @access public
* @return void
*/
public function getDropMenu()
{
$control = $this->loadController('project', 'ajaxGetDropMenu');
$control->ajaxGetDropMenu($this->request('projectID', 0), $this->request('module', 'project'), $this->request('method', 'browse'));
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array());
foreach($data->data->projects as $programID => $projects)
{
foreach($projects as $project)
{
if(helper::diffDate(date('Y-m-d'), $project->end) > 0) $project->delay = true;
$project = $this->filterFields($project, 'id,model,type,name,code,parent,status,PM,delay');
if($project->status == 'closed')
{
$dropMenu['closed'][] = $project;
}
elseif($project->PM == $this->app->user->account)
{
$dropMenu['owner'][] = $project;
}
else
{
$dropMenu['other'][] = $project;
}
}
}
$this->send(200, $dropMenu);
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
/**
* The project entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package project
* @version 1
* @link http://www.zentao.net
*/
class projectStoriesEntry extends entry
{
/**
* GET method.
*
* @param int $projectID
* @access public
* @return void
*/
public function get($projectID)
{
if(!$projectID) $projectID = $this->param('project');
if(!$projectID) return $this->sendError(400, 'Need product id.');
$control = $this->loadController('projectstory', 'story');
$control->story($projectID, $this->param('product', 0), $this->param('branch', ''), $this->param('status', 'unclosed'), 0, 'story', $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$stories = $data->data->stories;
$pager = $data->data->pager;
$result = array();
foreach($stories as $story)
{
$result[] = $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(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
}
+1 -4
View File
@@ -25,10 +25,7 @@ class releaseEntry extends Entry
$data = $this->getData();
if(!$data or !isset($data->status)) return $this->send400('error');
if(isset($data->status) and $data->status == 'fail')
{
return isset($data->code) and $data->code == 404 ? $this->send404() : $this->sendError(400, $data->message);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$release = $this->format($data->data->release, 'date:date,deleted:bool');
+8 -19
View File
@@ -15,26 +15,16 @@ class releasesEntry extends entry
* GET method.
*
* @param int $productID
* @param int $projectID
* @access public
* @return void
*/
public function get($productID = 0, $projectID = 0)
public function get($productID = 0)
{
if(!$productID) $productID = $this->param('product');
if(!$projectID) $projectID = $this->param('project');
if(!$productID and !$projectID) return $this->sendError(400, 'Need product or project id.');
if(empty($productID)) $productID = $this->param('product');
if(empty($productID)) return $this->sendError(400, 'Need product id.');
if($projectID)
{
$control = $this->loadController('projectrelease', 'browse');
$control->browse($projectID, 0, $this->param('status', 'all'));
}
else
{
$control = $this->loadController('release', 'browse');
$control->browse($productID, $this->param('branch', 0), $this->param('status', 'all'));
}
$control = $this->loadController('release', 'browse');
$control->browse($productID, $this->param('branch', 0), $this->param('status', 'all'), $this->param('order', 't1.date_desc'));
/* Response */
$data = $this->getData();
@@ -42,13 +32,12 @@ class releasesEntry extends entry
{
$result = array();
$releases = $data->data->releases;
foreach($releases as $release) $result[] = $this->format($release, 'deleted:bool,date:date');
foreach($releases as $release) $result[] = $this->format($release, 'deleted:bool,date:date,mailto:userList');
return $this->send(200, array('releases' => $result));
return $this->send(200, array('total' => count($result), 'releases' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
}
+1
View File
@@ -278,6 +278,7 @@ class reportsEntry extends entry
{
$product->storyStat = array();
foreach(array_keys($storyStatusList) as $storyStatus) $product->storyStat[$storyStatus] = isset($productStoryStat[$productID][$storyStatus]) ? $productStoryStat[$productID][$storyStatus] : 0;
$product->progress = $product->storyStat['closed'] == 0 ? 0 : round($product->storyStat['closed'] / array_sum($product->storyStat) * 100, 1);
}
foreach(array_keys($productStatusList) as $status)
+40
View File
@@ -0,0 +1,40 @@
<?php
/**
* The repos entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class reposEntry extends entry
{
/**
* GET method.
*
* @access public
* @return void
*/
public function get()
{
$control = $this->loadController('repo', 'maintain');
$control->maintain(0, $this->param('order', 'id_desc'), 0, $this->param('limit', 100), $this->param('page', 1));
/* Response */
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
{
$result = array();
$pager = $data->data->pager;
$repos = $data->data->repoList;
foreach($repos as $repo) $result[] = $this->format($repo, 'deleted:bool,lastSync:datetime,synced:bool,product:idList');
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'repos' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ class riskEntry extends Entry
$data = $this->getData();
if(!$data or (isset($data->message) and $data->message == '404 Not found')) return $this->send404();
if(isset($data->status) and $data->status == 'success') return $this->send(200, $this->format($data->data->risk, 'createdDate:time,editedDate:time'));
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$this->sendError(400, 'error');
}
+1 -1
View File
@@ -39,7 +39,7 @@ class risksEntry extends entry
}
if(!isset($data->status)) return $this->sendError(400, 'error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$pager = $data->data->pager;
$result = array();
+132
View File
@@ -0,0 +1,132 @@
<?php
/**
* The stakeholder entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package entries
* @version 1
* @link http://www.zentao.net
*/
class stakeholdersEntry extends entry
{
/**
* GET method.
*
* @param int $programID
* @access public
* @return void
*/
public function get($programID = 0)
{
if(!$programID) $programID = $this->param('program', 0);
if($programID)
{
$control = $this->loadController('program', 'stakeholder');
$control->stakeholder($programID, $this->param('order', 't1.id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
}
if(isset($data->status) and $data->status == 'success')
{
$this->app->loadLang('stakeholder');
$pager = $data->data->pager;
$users = $data->data->users;
$result = array();
foreach($data->data->stakeholders as $stakeholder)
{
$stakeholder->roleName = zget($this->lang->user->roleList, $stakeholder->role, '');
$stakeholder->typeName = zget($this->lang->stakeholder->fromList, $stakeholder->from, '');
$result[] = $stakeholder;
}
$data = array();
$data['page'] = $pager->pageID;
$data['total'] = $pager->recTotal;
$data['limit'] = (int)$pager->recPerPage;
$data['stakeholders'] = $result;
$withUser = $this->param('withUser', '');
if(!empty($withUser)) $data['users'] = $users;
return $this->send(200, $data);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
/**
* POST method.
*
* @access public
* @return void
*/
public function post()
{
$fields = 'name,begin,end,products';
$this->batchSetPost($fields);
$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()));
$this->setPost('PM', $this->request('PM', ''));
$this->setPost('model', $this->request('model', 'scrum'));
$control = $this->loadController('project', 'create');
$this->requireFields('name,code,begin,end,products');
$control->create($this->request('model', 'scrum'));
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
if(!isset($data->result)) return $this->sendError(400, 'error');
$project = $this->loadModel('project')->getByID($data->id);
$this->send(201, $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'));
}
/**
* Get drop menu.
*
* @access public
* @return void
*/
public function getDropMenu()
{
$control = $this->loadController('project', 'ajaxGetDropMenu');
$control->ajaxGetDropMenu($this->request('projectID', 0), $this->request('module', 'project'), $this->request('method', 'browse'));
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array());
foreach($data->data->projects as $programID => $projects)
{
foreach($projects as $project)
{
if(helper::diffDate(date('Y-m-d'), $project->end) > 0) $project->delay = true;
$project = $this->filterFields($project, 'id,model,type,name,code,parent,status,PM,delay');
if($project->status == 'closed')
{
$dropMenu['closed'][] = $project;
}
elseif($project->PM == $this->app->user->account)
{
$dropMenu['owner'][] = $project;
}
else
{
$dropMenu['other'][] = $project;
}
}
}
$this->send(200, $dropMenu);
}
}
+20 -37
View File
@@ -9,53 +9,36 @@
* @version 1
* @link http://www.zentao.net
*/
class storiesEntry extends entry
class storiesEntry extends entry
{
/**
* GET method.
*
* @param int $productID
* @param int $projectID
* @access public
* @return void
*/
public function get($productID = 0, $projectID = 0)
public function get($productID = 0)
{
if(!$productID) $productID = $this->param('product');
if(!$projectID) $projectID = $this->param('project');
if(!$productID and !$projectID) return $this->sendError(400, 'Need product or project id.');
if(!$productID) return $this->sendError(400, 'Need product id.');
if($projectID)
{
$control = $this->loadController('projectstory', 'story');
$control->story($projectID, $productID, $this->param('branch', 0), $this->param('type', ''), 0, 'story', $this->param('order', ''), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
}
else
{
$control = $this->loadController('product', 'browse');
$control->browse($productID, $this->param('branch', 0), $this->param('type', ''), 0, 'story', $this->param('order', ''), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
}
$control = $this->loadController('product', 'browse');
$control->browse($productID, $this->param('branch', ''), $this->param('status', 'unclosed'), 0, $this->param('type', 'story'), $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
if(isset($data->status) and $data->status == 'success')
{
$stories = $data->data->stories;
$pager = $data->data->pager;
$result = array();
foreach($stories as $story)
{
$result[] = $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time,deleted:bool');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result));
}
$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);
if(isset($data->status) and $data->status == 'fail')
$stories = $data->data->stories;
$pager = $data->data->pager;
$result = array();
foreach($stories as $story)
{
return $this->sendError(400, $data->message);
if(isset($story->children)) $story->children = array_values((array)$story->children);
$result[] = $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->sendError(400, 'error');
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result));
}
/**
@@ -75,7 +58,8 @@ class storiesEntry extends entry
$this->batchSetPost($fields);
/* If reviewer is not post, set needNotReview. */
if(empty($this->request('reviewer'))) $this->setPost('needNotReview', 1);
$reviewer = $this->request('reviewer');
if(empty($reviewer)) $this->setPost('needNotReview', 1);
$this->setPost('product', $productID);
$this->setPost('type', $this->param('type', 'story'));
@@ -83,13 +67,12 @@ class storiesEntry extends entry
$this->requireFields('title,spec,pri,category');
$control->create($productID);
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
$story = $this->loadModel('story')->getByID($data->id);
$this->send(200, $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time,deleted:bool'));
$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'));
}
}
+58 -3
View File
@@ -20,12 +20,67 @@ class storyEntry extends Entry
*/
public function get($storyID)
{
$this->resetOpenApp($this->param('tab', 'product'));
$control = $this->loadController('story', 'view');
$control->view($storyID);
$data = $this->getData();
$data = $this->getData();
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);
$story = $data->data->story;
$this->send(200, $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time'));
if(!empty($story->children)) $story->children = array_values((array)$story->children);
if(isset($story->planTitle)) $story->planTitle = array_values((array)$story->planTitle);
if($story->parent > 0) $story->parentPri = $this->dao->select('pri')->from(TABLE_STORY)->where('id')->eq($story->parent)->fetch('pri');
/* Set product name */
$story->productName = $data->data->product->name;
/* Set module title */
$moduleTitle = '';
if(empty($story->module)) $moduleTitle = '/';
if($story->module)
{
$modulePath = $data->data->modulePath;
foreach($modulePath as $key => $module)
{
$moduleTitle .= $module->name;
if(isset($modulePath[$key + 1])) $moduleTitle .= '/';
}
}
$story->moduleTitle = $moduleTitle;
$storyTasks = array();
foreach($story->tasks as $executionTasks)
{
foreach($executionTasks as $task)
{
if(!isset($data->data->executions->{$task->execution})) continue;
$storyTasks[] = $this->filterFields($task, 'id,name,type');
}
}
$story->tasks = $storyTasks;
$story->bugs = array();
foreach($data->data->bugs as $bug) $story->bugs[] = $this->filterFields($bug, 'id,title');
$story->cases = array();
foreach($data->data->cases as $case) $story->cases[] = $this->filterFields($case, 'id,title');
$story->requirements = array();
foreach($data->data->relations as $relation) $story->requirements[] = $this->filterFields($relation, 'id,title');
$story->actions = $this->loadModel('action')->processActionForAPI($data->data->actions, $data->data->users, $this->lang->story);
$preAndNext = $data->data->preAndNext;
$story->preAndNext = array();
$story->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
$story->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
$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'));
}
/**
@@ -49,7 +104,7 @@ class storyEntry extends Entry
$this->getData();
$story = $this->story->getByID($storyID);
$this->sendSuccess(200, $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time,deleted:bool'));
$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
@@ -35,12 +35,13 @@ class storyChangeEntry extends Entry
}
$control = $this->loadController('story', 'change');
$this->requireFields('title,spec');
$this->requireFields('title,spec,verify');
$control->change($storyID);
$data = $this->getData();
if($data->status == 'fail') return $this->sendError(400, $data->message);
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);
$story = $this->loadModel('story')->getByID($storyID);
+32
View File
@@ -39,6 +39,38 @@ class tabsEntry extends baseEntry
$menus[] = $menu;
}
}
elseif($moduleName == 'product')
{
$this->app->loadLang('product');
$tabs = array('story', 'plan', 'project', 'release', 'requirement', 'doc', 'view');
foreach($tabs as $menuKey)
{
if($menuKey == 'requirement' and empty($this->config->URAndSR)) continue;
if(isset($this->lang->product->menu->$menuKey))
{
list($label, $module, $method) = explode('|', $this->lang->product->menu->$menuKey['link']);
if(!common::hasPriv($module, $method)) continue;
}
else
{
if(!common::hasPriv('product', $menuKey)) continue;
}
$label = zget($this->lang->product, $menuKey, '');
if($menuKey == 'view') $label = $this->lang->overview;
if($menuKey == 'doc') $label = $this->lang->doc->common;
if($menuKey == 'project') $label = $this->lang->project->common;
if($menuKey == 'story') $label = $this->lang->createObjects['story'];
if($menuKey == 'requirement') $label = $this->lang->URCommon;
$menu = new stdclass();
$menu->code = $menuKey;
$menu->name = $label;
$menus[] = $menu;
}
}
$this->send(200, array('tabs' => $menus));
}
+61 -6
View File
@@ -20,19 +20,74 @@ class taskEntry extends Entry
*/
public function get($taskID)
{
$this->resetOpenApp($this->param('tab', 'execution'));
$control = $this->loadController('task', 'view');
$control->view($taskID);
$data = $this->getData();
if(!$data or !isset($data->status)) return $this->send400('error');
if(isset($data->status) and $data->status == 'fail')
{
return isset($data->code) and $data->code == 404 ? $this->send404() : $this->sendError(400, $data->message);
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$task = $data->data->task;
$this->send(200, $this->format($task, 'openedDate:time,assignedDate:time,realStarted:time,finishedDate:time,canceledDate:time,closedDate:time,lastEditedDate:time,deleted:bool'));
if(!empty($task->children)) $task->children = array_values((array)$task->children);
if($task->parent > 0) $task->parentPri = $this->dao->select('pri')->from(TABLE_TASK)->where('id')->eq($task->parent)->fetch('pri');
/* Set execution name */
$task->executionName = $data->data->execution->name;
/* Set module title */
$moduleTitle = '';
if(empty($task->module)) $moduleTitle = '/';
if($task->module)
{
$modulePath = $data->data->modulePath;
foreach($modulePath as $key => $module)
{
$moduleTitle .= $module->name;
if(isset($modulePath[$key + 1])) $moduleTitle .= '/';
}
}
$task->moduleTitle = $moduleTitle;
$queryAccounts = array();
if($task->assignedTo) $queryAccounts[$task->assignedTo] = $task->assignedTo;
if(!empty($task->team))
{
foreach($task->team as $account => $team) $queryAccounts[$account] = $account;
}
$usersWithAvatar = $this->loadModel('user')->getListByAccounts($queryAccounts, 'account');
if(!empty($task->team))
{
$teams = array();
foreach($task->team as $account => $team)
{
$user = zget($usersWithAvatar, $account, '');
$team->realname = $user ? $user->realname : $account;
$team->avatar = $user ? $user->avatar : '';
$team->estimate = round($team->estimate, 1);
$team->consumed = round($team->consumed, 1);
$team->left = round($team->left, 1);
$allHours = $team->consumed + $team->left;
$team->progress = empty($allHours) ? 0 : round($team->consumed / $allHours * 100, 1);
$teams[] = $team;
}
$task->team = $teams;
}
$task->actions = $this->loadModel('action')->processActionForAPI($data->data->actions, $data->data->users, $this->lang->task);
$preAndNext = $data->data->preAndNext;
$task->preAndNext = array();
$task->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
$task->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
$this->send(200, $this->format($task, 'deadline:date,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,realStarted:time,finishedBy:user,finishedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,lastEditedBy:user,lastEditedDate:time,deleted:bool,mailto:userList'));
}
/**
@@ -55,7 +110,7 @@ class taskEntry extends Entry
$this->getData();
$task = $this->task->getByID($taskID);
$this->send(200, $this->format($task, 'openedDate:time,assignedDate:time,realStarted:time,finishedDate:time,canceledDate:time,closedDate:time,lastEditedDate:time'));
$this->send(200, $this->format($task, 'deadline:date,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,realStarted:time,finishedBy:user,finishedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,lastEditedBy:user,lastEditedDate:time,deleted:bool,mailto:userList'));
}
/**
+3 -2
View File
@@ -29,9 +29,10 @@ class taskAssignToEntry extends Entry
$this->requireFields('assignedTo');
$control->assignTo($task->execution, $taskID);
$data = $this->getData();
if($data->result == 'fail') return $this->sendError(400, $data->message);
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);
$task = $this->loadModel('task')->getByID($taskID);
+3 -2
View File
@@ -34,9 +34,10 @@ class taskFinishEntry extends Entry
$control = $this->loadController('task', 'finish');
$this->requireFields('assignedTo,currentConsumed,realStarted,finishedDate');
$control->finish($taskID);
$data = $this->getData();
if($data->result == 'fail') return $this->sendError(400, $data->message);
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);
$task = $this->loadModel('task')->getByID($taskID);
+5 -5
View File
@@ -31,7 +31,7 @@ class tasksEntry extends entry
{
/* Get tasks by execution. */
$control = $this->loadController('execution', 'task');
$control->task($executionID, $this->param('status', 'all'), 0, $this->param('order', ''), $this->param('total', 0), $this->param('limit', 100), $this->param('page', 1));
$control->task($executionID, $this->param('status', 'all'), 0, $this->param('order', 'id_desc'), 0, $this->param('limit', 100), $this->param('page', 1));
$data = $this->getData();
}
@@ -42,13 +42,13 @@ class tasksEntry extends entry
$result = array();
foreach($tasks as $task)
{
$result[] = $this->format($task, 'openedDate:time,assignedDate:time,realStarted:time,finishedDate:time,canceledDate:time,closedDate:time,lastEditedDate:time,deleted:bool');
if(isset($task->children)) $task->children = array_values((array)$task->children);
$result[] = $this->format($task, 'deadline:date,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,realStarted:time,finishedBy:user,finishedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,lastEditedBy:user,lastEditedDate:time,deleted:bool,mailto:userList');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'tasks' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
@@ -77,6 +77,6 @@ class tasksEntry extends entry
$task = $this->loadModel('task')->getByID($data->id);
$this->send(201, $this->format($task, 'openedDate:time,assignedDate:time,realStarted:time,finishedDate:time,canceledDate:time,closedDate:time,lastEditedDate:time'));
$this->send(201, $this->format($task, 'deadline:date,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,realStarted:time,finishedBy:user,finishedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,lastEditedBy:user,lastEditedDate:time,deleted:bool,mailto:userList'));
}
}
+3 -2
View File
@@ -28,9 +28,10 @@ class taskStartEntry extends Entry
$control = $this->loadController('task', 'start');
$this->requireFields('left');
$control->start($taskID);
$data = $this->getData();
if($data->result == 'fail') return $this->sendError(400, $data->message);
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);
$task = $this->loadModel('task')->getByID($taskID);
+43 -3
View File
@@ -9,7 +9,7 @@
* @version 1
* @link http://www.zentao.net
*/
class testcaseEntry extends entry
class testcaseEntry extends entry
{
/**
* GET method.
@@ -25,13 +25,53 @@ class testcaseEntry extends entry
$data = $this->getData();
if(!$data or (isset($data->message) and $data->message == '404 Not found')) return $this->send404();
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(!isset($data->case)) $this->sendError(400, 'error');
$case = $data->case;
$case->steps = (isset($case->steps) and !empty($case->steps)) ? array_values(get_object_vars($case->steps)) : array();
$this->send(200, $this->format($case, 'openedDate:time,lastEditedDate:time,lastRunDate:time,scriptedDate:date,reviewedDate:date,deleted:bool'));
$this->send(200, $this->format($case, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,lastRunDate:time,scriptedDate:date,reviewedBy:user,reviewedDate:date,steps:array,deleted:bool'));
}
/**
* PUT method.
*
* @param int $caseID
* @access public
* @return void
*/
public function put($caseID)
{
$oldCase = $this->loadModel('testcase')->getByID($caseID);
/* Set $_POST variables. */
$fields = 'title,pri,story,type,stage,product,module,branch,precondition';
$this->batchSetPost($fields, $oldCase);
/* Set steps and expects. */
if(isset($this->requestBody->steps))
{
$steps = array();
$expects = array();
$stepType = array();
foreach($this->requestBody->steps as $step)
{
$steps[] = $step->desc;
$expects[] = $step->expect;
$stepType[] = 'item';
}
$this->setPost('steps', $steps);
$this->setPost('expects', $expects);
$this->setPost('stepType', $stepType);
}
$control = $this->loadController('testcase', 'edit');
$control->edit($caseID);
$this->getData();
$case = $this->testcase->getByID($caseID);
$this->send(200, $this->format($case, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,lastRunDate:time,scriptedDate:date,reviewedBy:user,reviewedDate:date,steps:array,deleted:bool'));
}
/**
+9 -21
View File
@@ -15,28 +15,16 @@ class testcasesEntry extends entry
* GET method.
*
* @param int $productID
* @param int $projectID
* @param int $executionID
* @access public
* @return void
*/
public function get($productID = 0, $projectID = 0, $executionID = 0)
public function get($productID = 0)
{
if(!$productID) $productID = $this->param('product', 0);
if(!$projectID) $projectID = $this->param('project', 0);
if(!$executionID) $executionID = $this->param('execution', 0);
if(!$productID and !$projectID and !$executionID) return $this->sendError(400, 'Need product or project or execution id.');
if(empty($productID)) $productID = $this->param('product', 0);
if(empty($productID)) return $this->sendError(400, 'Need product id.');
if($executionID)
{
$control = $this->loadController('execution', 'testcase');
$control->testcase($executionID, $this->param('status', 'all'), $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
}
else
{
$control = $this->loadController('testcase', 'browse');
$control->browse($productID, $this->param('branch', ''), $this->param('status', 'all'), 0, $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1), $projectID);
}
$control = $this->loadController('testcase', 'browse');
$control->browse($productID, $this->param('branch', ''), $this->param('status', 'all'), 0, $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
@@ -47,14 +35,14 @@ class testcasesEntry extends entry
$result = array();
foreach($cases as $case)
{
$result[] = $this->format($case, 'openedDate:time,lastEditedDate:time,lastRunDate:time,scriptedDate:date,reviewedDate:date,deleted:bool');
$case->statusName = $this->lang->testcase->statusList[$case->status];
$result[] = $this->format($case, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,lastRunDate:time,scriptedDate:date,reviewedBy:user,reviewedDate:date,deleted:bool');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'testcases' => $result));
}
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
return $this->sendError(400, 'error');
}
@@ -104,6 +92,6 @@ class testcasesEntry extends entry
$case = $this->loadModel('testcase')->getByID($data->id);
$case->steps = (isset($case->steps) and !empty($case->steps)) ? array_values($case->steps) : array();
$this->send(200, $this->format($case, 'openedDate:time,lastEditedDate:time,lastRunDate:time,scriptedDate:date,reviewedDate:date,deleted:bool'));
$this->send(200, $this->format($case, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,lastRunDate:time,scriptedDate:date,reviewedBy:user,reviewedDate:date,deleted:bool'));
}
}
+3 -3
View File
@@ -9,7 +9,7 @@
* @version 1
* @link http://www.zentao.net
*/
class testtaskEntry extends entry
class testtaskEntry extends entry
{
/**
* GET method.
@@ -24,12 +24,12 @@ class testtaskEntry extends entry
$control->view($testtaskID);
$data = $this->getData();
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(!isset($data->data->task)) $this->sendError(400, 'error');
$testtask = $data->data->task;
$this->send(200, $this->format($testtask, 'realFinishedDate:time'));
$this->send(200, $this->format($testtask, 'begin:date,end:date,mailto:userList,owner:user,realFinishedDate:time'));
}
/**
+2 -2
View File
@@ -29,13 +29,13 @@ class testtasksEntry extends entry
$data = $this->getData();
if(!isset($data->status)) return $this->sendError(400, 'error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$pager = $data->data->pager;
$result = array();
foreach($data->data->tasks as $testtask)
{
$result[] = $this->format($testtask, 'realFinishedDate:time');
$result[] = $this->format($testtask, 'begin:date,end:date,mailto:userList,owner:user,realFinishedDate:time');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'testtasks' => $result));
+5 -4
View File
@@ -9,7 +9,7 @@
* @version 1
* @link http://www.zentao.net
*/
class todoEntry extends entry
class todoEntry extends entry
{
/**
* GET method.
@@ -25,7 +25,8 @@ class todoEntry extends entry
$data = $this->getData();
if(!$data or (isset($data->message) and $data->message == '404 Not found')) return $this->send404();
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
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);
$todo = $data->data->todo;
$this->send(200, $this->format($todo, 'assignedDate:time,finishedDate:time,closedDate:time'));
@@ -45,7 +46,7 @@ class todoEntry extends entry
/* Set $_POST variables. */
$fields = 'date,type,name,pri,desc,status,begin,end,private';
$this->batchSetPost($fields, $oldTodo);
$this->setPost('idvalue', 0);
$this->setPost('date', $this->request('date', date("Y-m-d", strtotime($oldTodo->date))));
$this->setPost('begin', $this->request('begin') ? str_replace(':', '', $this->request('begin')) : $oldTodo->begin);
@@ -57,7 +58,7 @@ class todoEntry extends entry
$data = $this->getData();
if(!isset($data->status)) return $this->sendError(400, 'error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$todo = $this->todo->getByID($todoID);
$this->send(200, $this->format($todo, 'assignedDate:time,finishedDate:time,closedDate:time'));
+2 -1
View File
@@ -24,7 +24,8 @@ class todoActivateEntry extends Entry
$control->activate($todoID);
$data = $this->getData();
if($data->status == 'fail') return $this->sendError(400, $data->message);
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);
$todo = $this->loadModel('todo')->getByID($todoID);
$this->send(200, $this->format($todo, 'assignedDate:time,finishedDate:time,closedDate:time'));
+2 -1
View File
@@ -24,7 +24,8 @@ class todoFinishEntry extends Entry
$control->finish($todoID);
$data = $this->getData();
if($data->status == 'fail') return $this->sendError(400, $data->message);
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);
$todo = $this->loadModel('todo')->getByID($todoID);
$this->send(200, $this->format($todo, 'assignedDate:time,finishedDate:time,closedDate:time'));
+1 -1
View File
@@ -24,7 +24,7 @@ class todosEntry extends entry
$data = $this->getData();
if(!isset($data->status)) return $this->sendError(400, 'error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$pager = $data->data->pager;
$result = array();
+103 -9
View File
@@ -14,7 +14,7 @@ class userEntry extends Entry
/**
* GET method.
*
* @param int $userID
* @param int|string $userID
* @access public
* @return void
*/
@@ -23,6 +23,13 @@ class userEntry extends Entry
/* Get my info defaultly. */
if(!$userID) return $this->getInfo($this->param('fields', ''));
if(!is_numeric($userID))
{
$user = $this->loadModel('user')->getById($userID, 'account');
if(!$user) return $this->send404();
$userID = $user->id;
}
/* Get user by id. */
$control = $this->loadController('user', 'profile');
$control->profile($userID);
@@ -71,7 +78,7 @@ class userEntry extends Entry
$products = $this->my->getProducts('ownbyme');
if($products)
{
$info->product['total'] = $products->allCount;
$info->product['total'] = $products->unclosedCount;
$info->product['products'] = $products->products;
}
break;
@@ -95,6 +102,41 @@ class userEntry extends Entry
$info->project['projects'] = $projects->projects;
}
break;
case 'lastproject':
$info->lastProject = array('total' => 0, 'projects' => array());
$control = $this->loadController('project', 'ajaxGetDropMenu');
$control->ajaxGetDropMenu(0, 'project', 'index');
$data = $this->getData();
if($data->status == 'success')
{
$myProjects['owner'] = array();
$myProjects['other'] = array();
foreach($data->data->projects as $programID => $programProjects)
{
foreach($programProjects as $project)
{
if($project->status == 'closed') continue;
$project = $this->filterFields($project, 'id,model,type,name,code,parent,status,PM');
if($project->PM == $this->app->user->account)
{
$myProjects['owner'][] = $project;
}
else
{
$myProjects['other'][] = $project;
}
}
}
$lastProjects = array_merge($myProjects['owner'], $myProjects['other']);
$lastProjects = array_slice($lastProjects, 0, 3);
$info->lastProject['total'] = count($lastProjects);
$info->lastProject['projects'] = $lastProjects;
}
break;
case 'execution':
$info->execution = array('total' => 0, 'executions' => array());
if(!common::hasPriv('my', 'execution')) break;
@@ -109,6 +151,41 @@ class userEntry extends Entry
$info->execution['executions'] = array_values((array)$data->data->executions);
}
break;
case 'lastexecution':
$info->lastExecution = array('total' => 0, 'executions' => array());
$control = $this->loadController('execution', 'ajaxGetDropMenu');
$control->ajaxGetDropMenu(0, 'execution', 'browse', '');
$data = $this->getData();
$account = $this->app->user->account;
if($data->status == 'success')
{
$myExecutions['owner'] = array();
$myExecutions['other'] = array();
foreach($data->data->executions as $projectID => $projectExecutions)
{
foreach($projectExecutions as $execution)
{
if($execution->status == 'done' or $execution->status == 'closed') continue;
if($execution->PM == $account or isset($execution->teams->$account))
{
$myExecutions['owner'][] = $this->filterFields($execution, 'id,model,type,name,code,parent,status,PM');
}
else
{
$myExecutions['other'][] = $this->filterFields($execution, 'id,model,type,name,code,parent,status,PM');
}
}
}
$lastExecutions = array_merge($myExecutions['owner'], $myExecutions['other']);
$lastExecutions = array_slice($lastExecutions, 0, 3);
$info->lastExecution['total'] = count($lastExecutions);
$info->lastExecution['executions'] = $lastExecutions;
}
break;
case 'actions':
$info->actions = $this->my->getActions();
break;
@@ -144,7 +221,8 @@ class userEntry extends Entry
if($bug->status == 'active' and $bug->confirmed) $status = array('code' => 'confirmed', 'name' => $this->lang->bug->labelConfirmed);
if($bug->resolution == 'postponed') $status = array('code' => 'postponed', 'name' => $this->lang->bug->labelPostponed);
if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs);
$bug->status = $status;
$bug->status = $status['code'];
$bug->statusName = $status['name'];
$bugs[$bug->id] = $bug;
}
@@ -154,11 +232,12 @@ class userEntry extends Entry
->where('t1.id')->in(array_keys($bugs))
->andWhere('t1.story')->ne('0')
->andWhere('t1.storyVersion != t2.version')
->fetchAll();
->fetchPairs('id', 'id');
foreach($storyChangeds as $bugID)
{
$status = array('code' => 'storyChanged', 'name' => $this->lang->bug->storyChanged);
$bugs[$bugID]->status = $status;
$status = array('code' => 'storyChanged', 'name' => $this->lang->bug->changed);
$bugs[$bugID]->status = $status['code'];
$bugs[$bugID]->statusName = $status['name'];
}
$info->bug['total'] = $data->data->pager->recTotal;
@@ -194,7 +273,7 @@ class userEntry extends Entry
$stories = array();
foreach($data->data->stories as $story)
{
$story->status = array('code' => $story->status, 'name' => $this->lang->story->statusList[$story->status]);
$story->statusName = $this->lang->story->statusList[$story->status];
$stories[$story->id] = $story;
}
@@ -279,17 +358,25 @@ class userEntry extends Entry
/**
* PUT method.
*
* @param int $userID
* @param int|string $userID
* @access public
* @return void
*/
public function put($userID)
{
if(!is_numeric($userID))
{
$user = $this->loadModel('user')->getById($userID, 'account');
if(!$user) return $this->send404();
$userID = $user->id;
}
$oldUser = $this->loadModel('user')->getByID($userID, 'id');
/* Set $_POST variables. */
$fields = 'dept,realname,email,commiter,gender';
$this->batchSetPost($fields, $oldUser);
$this->setPost('account', $oldUser->account);
if($this->request('gender') and !in_array($this->request('gender'), array('f', 'm'))) return $this->sendError(400, "The value of gendar must be 'f' or 'm'");
@@ -310,12 +397,19 @@ class userEntry extends Entry
/**
* DELETE method.
*
* @param int $userID
* @param int|string $userID
* @access public
* @return void
*/
public function delete($userID)
{
if(!is_numeric($userID))
{
$user = $this->loadModel('user')->getById($userID, 'account');
if(!$user) return $this->send404();
$userID = $user->id;
}
$this->setPost('verifyPassword', md5($this->app->user->password . $this->app->session->rand));
$control = $this->loadController('user', 'delete');
+1 -1
View File
@@ -73,7 +73,7 @@ class usersEntry extends entry
$control->create();
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
$user = $this->loadModel('user')->getByID($data->id, 'id');
+42
View File
@@ -0,0 +1,42 @@
<?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';
/**
* Gen api data
*
* @param string $fileName
* @param array $data
* @access public
* @return void
*/
function genData($fileName, $data)
{
global $app;
$dataRoot = $app->getAppRoot() . 'db' . DS . 'api' . DS;
$file = fopen($dataRoot . $fileName, 'w');
fwrite($file, serialize($data));
fclose($file);
}
/* Gen demo data to db/api. */
$app = router::createApp('pms', dirname(dirname(dirname(__FILE__))), 'router');
$dao = $app->loadClass('dao');
$structs = $dao->select('*')->from(TABLE_APISTRUCT)->fetchAll();;
$structSpecs = $dao->select('*')->from(TABLE_APISTRUCT_SPEC)->fetchAll();
$apis = $dao->select('*')->from(TABLE_API)->fetchAll();
$apiSpecs = $dao->select('*')->from(TABLE_API_SPEC)->fetchAll();
$modules = $dao->select('*')->from(TABLE_MODULE)->where('type')->eq('api')->fetchAll();
genData('apistruct', $structs);
genData('apistruct_spec', $structSpecs);
genData('api', $apis);
genData('apispec', $apiSpecs);
genData('module', $modules);
+1 -1
View File
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
if(!function_exists('getWebRoot')){function getWebRoot(){}}
/* 基本设置。Basic settings. */
$config->version = '15.7'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->version = '16.0.beta1'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
$config->timezone = 'Asia/Shanghai'; // 时区设置。 The time zone setting, for more see http://www.php.net/manual/en/timezones.php.
+36 -15
View File
@@ -63,6 +63,7 @@ $filter->search = new stdclass();
$filter->gitlab = new stdclass();
$filter->mr = new stdclass();
$filter->ci = new stdclass();
$filter->tree = new stdclass();
$filter->block->default = new stdclass();
$filter->block->main = new stdclass();
@@ -78,6 +79,7 @@ $filter->doc->create = new stdclass();
$filter->doc->browse = new stdclass();
$filter->doc->alllibs = new stdclass();
$filter->doc->objectlibs = new stdclass();
$filter->doc->tablecontents = new stdclass();
$filter->doc->showfiles = new stdclass();
$filter->doc->default = new stdclass();
$filter->api->index = new stdClass();
@@ -92,6 +94,8 @@ $filter->product->default = new stdclass();
$filter->product->index = new stdclass();
$filter->product->export = new stdclass();
$filter->product->project = new stdclass();
$filter->product->roadmap = new stdclass();
$filter->product->dynamic = new stdclass();
$filter->branch->default = new stdclass();
$filter->program->default = new stdclass();
$filter->program->pgmproject = new stdclass();
@@ -112,6 +116,7 @@ $filter->qa->default = new stdclass();
$filter->story->create = new stdclass();
$filter->story->export = new stdclass();
$filter->story->batchcreate = new stdclass();
$filter->story->track = new stdclass();
$filter->sso->getbindusers = new stdclass();
$filter->sso->gettodolist = new stdclass();
$filter->sso->getuserpairs = new stdclass();
@@ -146,8 +151,10 @@ $filter->search->index = new stdclass();
$filter->gitlab->webhook = new stdclass();
$filter->gitlab->importissue = new stdclass();
$filter->mr->diff = new stdclass();
$filter->mr->browse = new stdclass();
$filter->ci->checkCompileStatus = new stdclass();
$filter->execution->export = new stdclass();
$filter->tree->browse = new stdclass();
$filter->my->work->cookie['pagerMyTask'] = 'int';
$filter->my->work->cookie['pagerMyRequirement'] = 'int';
@@ -164,16 +171,16 @@ $filter->my->contribute->cookie['pagerMyTestcase'] = 'int';
$filter->my->contribute->cookie['pagerMyTesttask'] = 'int';
$filter->my->contribute->cookie['pagerMyDoc'] = 'int';
$filter->bug->batchcreate->cookie['preBranch'] = 'int';
$filter->bug->batchcreate->cookie['preBranch'] = 'reg::word';
$filter->bug->browse->cookie['bugModule'] = 'int';
$filter->bug->browse->cookie['bugBranch'] = 'int';
$filter->bug->browse->cookie['treeBranch'] = 'int';
$filter->bug->browse->cookie['preBranch'] = 'int';
$filter->bug->browse->cookie['treeBranch'] = 'reg::word';
$filter->bug->browse->cookie['preBranch'] = 'reg::word';
$filter->bug->browse->cookie['qaBugOrder'] = 'reg::orderBy';
$filter->bug->browse->cookie['windowWidth'] = 'int';
$filter->bug->default->cookie['lastProduct'] = 'int';
$filter->bug->default->cookie['preProductID'] = 'int';
$filter->bug->create->cookie['preBranch'] = 'int';
$filter->bug->create->cookie['preBranch'] = 'reg::word';
$filter->bug->create->cookie['lastBugModule'] = 'int';
$filter->bug->export->cookie['checkedItem'] = 'reg::checked';
@@ -183,9 +190,13 @@ $filter->doc->create->cookie['lastDocModule'] = 'int';
$filter->doc->browse->cookie['browseType'] = 'reg::browseType';
$filter->doc->alllibs->cookie['browseType'] = 'reg::browseType';
$filter->doc->objectlibs->cookie['browseType'] = 'reg::browseType';
$filter->doc->objectlibs->cookie['preProductID'] = 'int';
$filter->doc->objectlibs->cookie['preBranch'] = 'reg::word';
$filter->doc->default->cookie['from'] = 'code';
$filter->doc->default->cookie['product'] = 'int';
$filter->doc->showfiles->cookie['docFilesViewType'] = 'code';
$filter->doc->tablecontents->cookie['preProductID'] = 'int';
$filter->doc->tablecontents->cookie['preBranch'] = 'reg::word';
$filter->api->index->get['libID'] = 'int';
$filter->api->index->get['module'] = 'int';
$filter->api->index->get['apiID'] = 'int';
@@ -197,24 +208,26 @@ $filter->api->edit->get['libID'] = 'int';
$filter->api->edit->get['module'] = 'int';
$filter->api->edit->get['apiID'] = 'int';
$filter->file->download->cookie[$config->sessionVar] = 'code';
$filter->mail->ztcloud->cookie['ztCloudLicense'] = 'equal::yes';
$filter->product->browse->cookie['preBranch'] = 'int';
$filter->product->browse->cookie['preBranch'] = 'reg::word';
$filter->product->browse->cookie['preProductID'] = 'int';
$filter->product->browse->cookie['productStoryOrder'] = 'reg::orderBy';
$filter->product->browse->cookie['storyModule'] = 'int';
$filter->product->browse->cookie['storyBranch'] = 'int';
$filter->product->browse->cookie['treeBranch'] = 'int';
$filter->product->browse->cookie['treeBranch'] = 'reg::word';
$filter->product->default->cookie['lastProduct'] = 'int';
$filter->product->default->cookie['preProductID'] = 'int';
$filter->product->index->cookie['preBranch'] = 'int';
$filter->product->index->cookie['preBranch'] = 'reg::word';
$filter->product->export->cookie['checkedItem'] = 'reg::checked';
$filter->product->project->cookie['involved'] = 'code';
$filter->product->project->cookie['preBranch'] = 'reg::word';
$filter->product->roadmap->cookie['preBranch'] = 'reg::word';
$filter->product->dynamic->cookie['preBranch'] = 'reg::word';
$filter->branch->default->cookie['preBranch'] = 'int';
$filter->branch->default->cookie['preBranch'] = 'reg::word';
$filter->program->default->cookie['lastPGM'] = 'int';
$filter->program->default->cookie['lastPRJ'] = 'int';
@@ -245,12 +258,14 @@ $filter->projectstory->story->cookie['storyModuleParam'] = 'int';
$filter->projectstory->story->cookie['pagerProductBrowse'] = 'int';
$filter->qa->default->cookie['lastProduct'] = 'int';
$filter->qa->default->cookie['preBranch'] = 'int';
$filter->qa->default->cookie['preBranch'] = 'reg::word';
$filter->qa->default->cookie['preProductID'] = 'int';
$filter->story->create->cookie['lastStoryModule'] = 'int';
$filter->story->batchcreate->cookie['preProductID'] = 'int';
$filter->story->export->cookie['checkedItem'] = 'reg::checked';
$filter->story->track->cookie['preBranch'] = 'reg::word';
$filter->story->track->cookie['preProductID'] = 'int';
$filter->task->create->cookie['lastTaskModule'] = 'int';
$filter->task->export->cookie['checkedItem'] = 'reg::checked';
@@ -264,12 +279,12 @@ $filter->execution->export->cookie['checkedItem'] = 'reg::checked';
$filter->testcase->browse->cookie['caseModule'] = 'int';
$filter->testcase->browse->cookie['caseSuite'] = 'int';
$filter->testcase->browse->cookie['preBranch'] = 'int';
$filter->testcase->browse->cookie['preBranch'] = 'reg::word';
$filter->testcase->create->cookie['lastCaseModule'] = 'int';
$filter->testcase->default->cookie['lastProduct'] = 'int';
$filter->testcase->default->cookie['preProductID'] = 'int';
$filter->testcase->export->cookie['checkedItem'] = 'reg::checked';
$filter->testcase->groupcase->cookie['preBranch'] = 'int';
$filter->testcase->groupcase->cookie['preBranch'] = 'reg::word';
$filter->testreport->default->cookie['lastProduct'] = 'int';
$filter->testreport->default->cookie['lastProject'] = 'int';
@@ -282,7 +297,7 @@ $filter->testsuite->default->cookie['preProductID'] = 'int';
$filter->testsuite->library->cookie['libCaseModule'] = 'int';
$filter->testsuite->library->cookie['preCaseLibID'] = 'int';
$filter->testtask->browse->cookie['preBranch'] = 'int';
$filter->testtask->browse->cookie['preBranch'] = 'reg::word';
$filter->testtask->cases->cookie['preTaskID'] = 'int';
$filter->testtask->cases->cookie['taskCaseModule'] = 'int';
$filter->testtask->default->cookie['lastProduct'] = 'int';
@@ -356,8 +371,8 @@ $filter->repo->diff->cookie['repoPairs'] = 'array';
$filter->repo->view->cookie['repoPairs'] = 'array';
$filter->repo->ajaxsynccommit->cookie['syncBranch'] = 'reg::any';
$filter->webhook->bind->get['selectedDepts'] = 'reg::checked';
$filter->webhook->bind->cookie['selectedDepts'] = 'reg::checked';
$filter->webhook->bind->get['selectedDepts'] = 'reg::any';
$filter->webhook->bind->cookie['selectedDepts'] = 'reg::any';
$filter->search->index->get['words'] = 'reg::any';
$filter->search->index->get['type'] = 'code';
@@ -375,4 +390,10 @@ $filter->gitlab->importissue->get['repo'] = 'int';
$filter->mr->diff->cookie['arrange'] = 'reg::word';
$filter->mr->browse->get['mode'] = 'string';
$filter->mr->browse->get['param'] = 'string';
$filter->ci->checkCompileStatus->get['gitlabOnly'] = 'string';
$filter->tree->browse->cookie['preProductID'] = 'int';
$filter->tree->browse->cookie['preBranch'] = 'reg::word';
+59 -31
View File
@@ -4,10 +4,12 @@
*/
$routes = array();
$routes['/tokens'] = 'tokens';
$routes['/langs'] = 'langs';
$routes['/views'] = 'views';
$routes['/groups'] = 'groups';
$routes['/tokens'] = 'tokens';
$routes['/langs'] = 'langs';
$routes['/views'] = 'views';
$routes['/groups'] = 'groups';
$routes['/ping'] = 'ping';
$routes['/comments'] = 'comments';
$routes['/tabs/:module'] = 'tabs';
@@ -24,39 +26,47 @@ $routes['/products/:id'] = 'product';
$routes['/productlines'] = 'productLines';
$routes['/productlines/:id'] = 'productLine';
$routes['/productplans'] = 'productPlans';
$routes['/products/:id/plans'] = 'productPlans';
$routes['/productplans/:id'] = 'productPlan';
$routes['/productplans'] = 'productPlans';
$routes['/products/:id/plans'] = 'productPlans';
$routes['/productplans/:id'] = 'productPlan';
$routes['/productplans/:id/linkstories'] = 'productPlanLinkStories';
$routes['/productplans/:id/unlinkstories'] = 'productPlanUnlinkStories';
$routes['/productplans/:id/linkbugs'] = 'productPlanLinkBugs';
$routes['/productplans/:id/unlinkbugs'] = 'productPlanUnlinkBugs';
$routes['/releases'] = 'releases';
$routes['/product/:id/releases'] = 'releases';
$routes['/projects/:id/releases'] = 'projectreleases';
$routes['/products/:id/releases'] = 'releases';
$routes['/projects/:id/releases'] = 'projectReleases';
$routes['/releases/:id'] = 'release';
$routes['/stories'] = 'stories';
$routes['/products/:id/stories'] = 'stories';
$routes['/projects/:id/stories'] = 'projectStories';
$routes['/executions/:id/stories'] = 'executionStories';
$routes['/stories/:id'] = 'story';
$routes['/stories/:id/change'] = 'storyChange';
$routes['/products/:id/bugs'] = 'bugs';
$routes['/bugs'] = 'bugs';
$routes['/bugs/:id'] = 'bug';
$routes['/products/:id/bugs'] = 'bugs';
$routes['/projects/:id/bugs'] = 'projectBugs';
$routes['/executions/:id/bugs'] = 'executionBugs';
$routes['/bugs'] = 'bugs';
$routes['/bugs/:id'] = 'bug';
$routes['/programs/:id/projects'] = 'projects';
$routes['/products/:id/projects'] = 'productProjects';
$routes['/projects'] = 'projects';
$routes['/projects/:id'] = 'project';
$routes['/projects/:project/executions'] = 'executions';
$routes['/executions'] = 'executions';
$routes['/executions/:id'] = 'execution';
$routes['/projects/:id/executions'] = 'executions';
$routes['/executions'] = 'executions';
$routes['/executions/:id'] = 'execution';
$routes['/executions/:execution/tasks'] = 'tasks';
$routes['/tasks'] = 'tasks';
$routes['/tasks/:id'] = 'task';
$routes['/tasks/:id/assignto'] = 'taskAssignTo';
$routes['/tasks/:id/start'] = 'taskStart';
$routes['/tasks/:id/finish'] = 'taskFinish';
$routes['/executions/:id/tasks'] = 'tasks';
$routes['/tasks'] = 'tasks';
$routes['/tasks/:id'] = 'task';
$routes['/tasks/:id/assignto'] = 'taskAssignTo';
$routes['/tasks/:id/start'] = 'taskStart';
$routes['/tasks/:id/finish'] = 'taskFinish';
$routes['/users'] = 'users';
$routes['/users/:id'] = 'user';
@@ -65,23 +75,28 @@ $routes['/user'] = 'user';
$routes['/programs'] = 'programs';
$routes['/programs/:id'] = 'program';
$routes['/products/:productID/issues'] = 'productIssues';
$routes['/projects/:projectID/issues'] = 'issues';
$routes['/issues'] = 'issues';
$routes['/issues/:issueID'] = 'issue';
$routes['/programs/:id/stakeholders'] = 'stakeholders';
$routes['/products/:id/issues'] = 'productIssues';
$routes['/projects/:id/issues'] = 'issues';
$routes['/issues'] = 'issues';
$routes['/issues/:id'] = 'issue';
$routes['/todos'] = 'todos';
$routes['/todos/:id'] = 'todo';
$routes['/todos/:id/finish'] = 'todoFinish';
$routes['/todos/:id/activate'] = 'todoActivate';
$routes['/projects/:projectID/builds'] = 'builds';
$routes['/builds'] = 'builds';
$routes['/builds/:id'] = 'build';
$routes['/projects/:id/builds'] = 'builds';
$routes['/executions/:id/builds'] = 'executionBuilds';
$routes['/builds'] = 'builds';
$routes['/builds/:id'] = 'build';
$routes['/products/:id/testcases'] = 'testcases';
$routes['/testcases'] = 'testcases';
$routes['/testcases/:id'] = 'testcase';
$routes['/products/:id/testcases'] = 'testcases';
$routes['/projects/:id/testcases'] = 'projectCases';
$routes['/executions/:id/testcases'] = 'executionCases';
$routes['/testcases'] = 'testcases';
$routes['/testcases/:id'] = 'testcase';
$routes['/projects/:projectID/testtasks'] = 'testtasks';
$routes['/testtasks'] = 'testtasks';
@@ -91,9 +106,20 @@ $routes['/projects/:projectID/risks'] = 'risks';
$routes['/risks'] = 'risks';
$routes['/risks/:id'] = 'risk';
$routes['/projects/:id/meetings'] = 'meetings';
$routes['/meetings'] = 'meetings';
$routes['/meetings/:id'] = 'meeting';
$routes['/departments'] = 'departments';
$routes['/departments/:id'] = 'department';
$routes['/doclibs'] = 'doclibs';
$routes['/doclibs/:id'] = 'docs';
$routes['/docs'] = 'docs';
$routes['/docs/:id'] = 'doc';
$routes['/repos'] = 'repos';
$routes['/reports'] = 'reports';
$routes['/z/folders'] = 'zfolders';
@@ -101,4 +127,6 @@ $routes['/z/folders/:id'] = 'zfolder';
$routes['/z/files/:id'] = 'zfile';
$routes['/z/files/:id/content'] = 'zfileContent';
$routes['/gitlab/webhook'] = 'gitlabWebhook';
$config->routes = $routes;
+52 -39
View File
@@ -142,6 +142,9 @@ $config->openMethods[] = 'my.changepassword';
$config->openMethods[] = 'my.profile';
$config->openMethods[] = 'my.settutorialconfig';
$config->openMethods[] = 'doc.selectlibtype';
$config->openMethods[] = 'sso.getfeishusso';
$config->openMethods[] = 'sso.feishuauthen';
$config->openMethods[] = 'sso.feishulogin';
/* Define the tables. */
define('TABLE_COMPANY', '`' . $config->db->prefix . 'company`');
@@ -167,6 +170,7 @@ define('TABLE_USERTPL', '`' . $config->db->prefix . 'usertpl`');
define('TABLE_PRODUCT', '`' . $config->db->prefix . 'product`');
define('TABLE_BRANCH', '`' . $config->db->prefix . 'branch`');
define('TABLE_EXPECT', '`' . $config->db->prefix . 'expect`');
define('TABLE_STAGE', '`' . $config->db->prefix . 'stage`');
define('TABLE_STAKEHOLDER', '`' . $config->db->prefix . 'stakeholder`');
define('TABLE_STORY', '`' . $config->db->prefix . 'story`');
define('TABLE_STORYSPEC', '`' . $config->db->prefix . 'storyspec`');
@@ -192,6 +196,8 @@ define('TABLE_BURN', '`' . $config->db->prefix . 'burn`');
define('TABLE_BUILD', '`' . $config->db->prefix . 'build`');
define('TABLE_ACL', '`' . $config->db->prefix . 'acl`');
define('TABLE_DESIGN', '`' . $config->db->prefix . 'design`');
define('TABLE_DESIGNSPEC', '`' . $config->db->prefix . 'designspec`');
define('TABLE_DOCLIB', '`' . $config->db->prefix . 'doclib`');
define('TABLE_DOC', '`' . $config->db->prefix . 'doc`');
define('TABLE_API', '`' . $config->db->prefix . 'api`');
@@ -203,6 +209,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_FILE', '`' . $config->db->prefix . 'file`');
define('TABLE_HOLIDAY', '`' . $config->db->prefix . 'holiday`');
define('TABLE_HISTORY', '`' . $config->db->prefix . 'history`');
define('TABLE_EXTENSION', '`' . $config->db->prefix . 'extension`');
define('TABLE_CRON', '`' . $config->db->prefix . 'cron`');
@@ -213,6 +220,7 @@ define('TABLE_SUITECASE', '`' . $config->db->prefix . 'suitecase`');
define('TABLE_TESTREPORT', '`' . $config->db->prefix . 'testreport`');
define('TABLE_ENTRY', '`' . $config->db->prefix . 'entry`');
define('TABLE_WEEKLYREPORT', '`' . $config->db->prefix . 'weeklyreport`');
define('TABLE_WEBHOOK', '`' . $config->db->prefix . 'webhook`');
define('TABLE_LOG', '`' . $config->db->prefix . 'log`');
define('TABLE_SCORE', '`' . $config->db->prefix . 'score`');
@@ -222,54 +230,59 @@ define('TABLE_PIPELINE', '`' . $config->db->prefix . 'pipeline`');
define('TABLE_JOB', '`' . $config->db->prefix . 'job`');
define('TABLE_COMPILE', '`' . $config->db->prefix . 'compile`');
define('TABLE_MR', '`' . $config->db->prefix . 'mr`');
define('TABLE_MRAPPROVAL', '`' . $config->db->prefix . 'mrapproval`');
define('TABLE_REPO', '`' . $config->db->prefix . 'repo`');
define('TABLE_RELATION', '`' . $config->db->prefix . 'relation`');
define('TABLE_REPOHISTORY', '`' . $config->db->prefix . 'repohistory`');
define('TABLE_REPOFILES', '`' . $config->db->prefix . 'repofiles`');
define('TABLE_REPOBRANCH', '`' . $config->db->prefix . 'repobranch`');
define('TABLE_REPO', '`' . $config->db->prefix . 'repo`');
define('TABLE_RELATION', '`' . $config->db->prefix . 'relation`');
define('TABLE_REPOHISTORY', '`' . $config->db->prefix . 'repohistory`');
define('TABLE_REPOFILES', '`' . $config->db->prefix . 'repofiles`');
define('TABLE_REPOBRANCH', '`' . $config->db->prefix . 'repobranch`');
define('TABLE_KANBANLANE', '`' . $config->db->prefix . 'kanbanlane`');
define('TABLE_KANBANCOLUMN', '`' . $config->db->prefix . 'kanbancolumn`');
if(!defined('TABLE_LANG')) define('TABLE_LANG', '`' . $config->db->prefix . 'lang`');
if(!defined('TABLE_PROJECTSPEC')) define('TABLE_PROJECTSPEC', '`' . $config->db->prefix . 'projectspec`');
if(!defined('TABLE_SEARCHINDEX')) define('TABLE_SEARCHINDEX', $config->db->prefix . 'searchindex');
if(!defined('TABLE_SEARCHDICT')) define('TABLE_SEARCHDICT', $config->db->prefix . 'searchdict');
$config->objectTables['product'] = TABLE_PRODUCT;
$config->objectTables['productplan'] = TABLE_PRODUCTPLAN;
$config->objectTables['story'] = TABLE_STORY;
$config->objectTables['requirement'] = TABLE_STORY;
$config->objectTables['release'] = TABLE_RELEASE;
$config->objectTables['program'] = TABLE_PROJECT;
$config->objectTables['project'] = TABLE_PROJECT;
$config->objectTables['execution'] = TABLE_PROJECT;
$config->objectTables['task'] = TABLE_TASK;
$config->objectTables['build'] = TABLE_BUILD;
$config->objectTables['bug'] = TABLE_BUG;
$config->objectTables['case'] = TABLE_CASE;
$config->objectTables['testcase'] = TABLE_CASE;
$config->objectTables['testtask'] = TABLE_TESTTASK;
$config->objectTables['testsuite'] = TABLE_TESTSUITE;
$config->objectTables['testreport'] = TABLE_TESTREPORT;
$config->objectTables['user'] = TABLE_USER;
$config->objectTables['api'] = TABLE_API;
$config->objectTables['doc'] = TABLE_DOC;
$config->objectTables['doclib'] = TABLE_DOCLIB;
$config->objectTables['todo'] = TABLE_TODO;
$config->objectTables['custom'] = TABLE_LANG;
$config->objectTables['branch'] = TABLE_BRANCH;
$config->objectTables['module'] = TABLE_MODULE;
$config->objectTables['caselib'] = TABLE_TESTSUITE;
$config->objectTables['entry'] = TABLE_ENTRY;
$config->objectTables['webhook'] = TABLE_WEBHOOK;
$config->objectTables['stakeholder'] = TABLE_STAKEHOLDER;
$config->objectTables['job'] = TABLE_JOB;
$config->objectTables['team'] = TABLE_TEAM;
$config->objectTables['pipeline'] = TABLE_PIPELINE;
$config->objectTables['mr'] = TABLE_MR;
$config->objectTables['product'] = TABLE_PRODUCT;
$config->objectTables['productplan'] = TABLE_PRODUCTPLAN;
$config->objectTables['story'] = TABLE_STORY;
$config->objectTables['requirement'] = TABLE_STORY;
$config->objectTables['release'] = TABLE_RELEASE;
$config->objectTables['program'] = TABLE_PROJECT;
$config->objectTables['project'] = TABLE_PROJECT;
$config->objectTables['execution'] = TABLE_PROJECT;
$config->objectTables['task'] = TABLE_TASK;
$config->objectTables['build'] = TABLE_BUILD;
$config->objectTables['bug'] = TABLE_BUG;
$config->objectTables['case'] = TABLE_CASE;
$config->objectTables['testcase'] = TABLE_CASE;
$config->objectTables['testtask'] = TABLE_TESTTASK;
$config->objectTables['testsuite'] = TABLE_TESTSUITE;
$config->objectTables['testreport'] = TABLE_TESTREPORT;
$config->objectTables['user'] = TABLE_USER;
$config->objectTables['api'] = TABLE_API;
$config->objectTables['doc'] = TABLE_DOC;
$config->objectTables['doclib'] = TABLE_DOCLIB;
$config->objectTables['todo'] = TABLE_TODO;
$config->objectTables['custom'] = TABLE_LANG;
$config->objectTables['branch'] = TABLE_BRANCH;
$config->objectTables['module'] = TABLE_MODULE;
$config->objectTables['caselib'] = TABLE_TESTSUITE;
$config->objectTables['entry'] = TABLE_ENTRY;
$config->objectTables['webhook'] = TABLE_WEBHOOK;
$config->objectTables['stakeholder'] = TABLE_STAKEHOLDER;
$config->objectTables['job'] = TABLE_JOB;
$config->objectTables['team'] = TABLE_TEAM;
$config->objectTables['pipeline'] = TABLE_PIPELINE;
$config->objectTables['mr'] = TABLE_MR;
$config->objectTables['kanbancolumn'] = TABLE_KANBANCOLUMN;
$config->objectTables['kanbanlane'] = TABLE_KANBANLANE;
$config->newFeatures = array('introduction', 'tutorial', 'youngBlueTheme');
/* Program privs.*/
$config->programPriv = new stdclass();
$config->programPriv->scrum = array('product', 'story', 'productplan', 'release', 'projectrelease', 'project', 'task', 'build', 'qa', 'bug', 'testcase', 'testsuite', 'testreport', 'caselib', 'doc', 'report', 'repo', 'svn', 'git', 'search', 'tree', 'file', 'jenkins', 'gitlab', 'job', 'ci', 'branch');
$config->programPriv->waterfall = $config->programPriv->scrum + array('workestimation', 'durationestimation', 'budget', 'programplan', 'review', 'reviewissue', 'weekly', 'milestone', 'design', 'issue', 'risk', 'auditplan', 'nc', 'cm', 'pssp');
$config->programPriv->scrum = array('projectstory', 'projectrelease', 'project', 'build', 'bug', 'testcase', 'testreport', 'caselib', 'doc', 'repo', 'meeting', 'stakeholder');
$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'));
+3195
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
a:3:{i:0;O:8:"stdClass":12:{s:2:"id";s:1:"1";s:3:"lib";s:1:"6";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:7:"version";s:1:"2";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2021-12-02 16:53:45";s:8:"editedBy";s:5:"admin";s:10:"editedDate";s:19:"2021-12-02 16:54:24";s:7:"deleted";s:1:"0";}i:1;O:8:"stdClass":12:{s:2:"id";s:1:"2";s:3:"lib";s:2:"45";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:7:"version";s:1:"2";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"0000-00-00 00:00:00";s:8:"editedBy";s:5:"admin";s:10:"editedDate";s:19:"2021-12-02 16:54:24";s:7:"deleted";s:1:"0";}i:2;O:8:"stdClass":12:{s:2:"id";s:1:"3";s:3:"lib";s:2:"46";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:7:"version";s:1:"2";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2021-12-07 10:14:42";s:8:"editedBy";s:5:"admin";s:10:"editedDate";s:19:"2021-12-02 16:54:24";s:7:"deleted";s:1:"0";}}
+1
View File
@@ -0,0 +1 @@
a:4:{i:0;O:8:"stdClass":8:{s:2:"id";s:1:"1";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"version";s:1:"1";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2021-12-02 16:53:45";}i:1;O:8:"stdClass":8:{s:2:"id";s:1:"2";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"version";s:1:"2";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2021-12-02 16:54:24";}i:2;O:8:"stdClass":8:{s:2:"id";s:1:"3";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"version";s:1:"1";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2021-12-07 10:14:42";}i:3;O:8:"stdClass":8:{s:2:"id";s:1:"4";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"version";s:1:"2";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2021-12-07 10:14:42";}}
+1
View File
@@ -0,0 +1 @@
a:14:{i:0;O:8:"stdClass":13:{s:2:"id";s:2:"16";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:5:"Token";s:6:"parent";s:1:"0";s:4:"path";s:4:",16,";s:5:"grade";s:1:"1";s:5:"order";s:2:"10";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:1;O:8:"stdClass":13:{s:2:"id";s:2:"17";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:9:"项目集";s:6:"parent";s:1:"0";s:4:"path";s:4:",17,";s:5:"grade";s:1:"1";s:5:"order";s:2:"30";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:2;O:8:"stdClass":13:{s:2:"id";s:2:"18";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:6:"产品";s:6:"parent";s:1:"0";s:4:"path";s:4:",18,";s:5:"grade";s:1:"1";s:5:"order";s:2:"40";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:3;O:8:"stdClass":13:{s:2:"id";s:2:"19";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:6:"项目";s:6:"parent";s:1:"0";s:4:"path";s:4:",19,";s:5:"grade";s:1:"1";s:5:"order";s:2:"80";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:4;O:8:"stdClass":13:{s:2:"id";s:2:"20";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:6:"执行";s:6:"parent";s:1:"0";s:4:"path";s:4:",20,";s:5:"grade";s:1:"1";s:5:"order";s:3:"100";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:5;O:8:"stdClass":13:{s:2:"id";s:2:"33";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:6:"需求";s:6:"parent";s:1:"0";s:4:"path";s:4:",33,";s:5:"grade";s:1:"1";s:5:"order";s:2:"70";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:6;O:8:"stdClass":13:{s:2:"id";s:2:"34";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:6:"任务";s:6:"parent";s:1:"0";s:4:"path";s:4:",34,";s:5:"grade";s:1:"1";s:5:"order";s:3:"110";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:7;O:8:"stdClass":13:{s:2:"id";s:2:"35";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:3:"Bug";s:6:"parent";s:1:"0";s:4:"path";s:4:",35,";s:5:"grade";s:1:"1";s:5:"order";s:3:"120";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:8;O:8:"stdClass":13:{s:2:"id";s:2:"36";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:6:"用例";s:6:"parent";s:1:"0";s:4:"path";s:4:",36,";s:5:"grade";s:1:"1";s:5:"order";s:3:"130";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:9;O:8:"stdClass":13:{s:2:"id";s:2:"37";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:12:"产品计划";s:6:"parent";s:1:"0";s:4:"path";s:4:",37,";s:5:"grade";s:1:"1";s:5:"order";s:2:"50";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:10;O:8:"stdClass":13:{s:2:"id";s:2:"38";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:6:"发布";s:6:"parent";s:1:"0";s:4:"path";s:4:",38,";s:5:"grade";s:1:"1";s:5:"order";s:2:"60";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:11;O:8:"stdClass":13:{s:2:"id";s:2:"39";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:9:"测试单";s:6:"parent";s:1:"0";s:4:"path";s:4:",39,";s:5:"grade";s:1:"1";s:5:"order";s:3:"140";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:12;O:8:"stdClass":13:{s:2:"id";s:2:"40";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:6:"版本";s:6:"parent";s:1:"0";s:4:"path";s:4:",40,";s:5:"grade";s:1:"1";s:5:"order";s:2:"90";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:13;O:8:"stdClass":13:{s:2:"id";s:2:"41";s:4:"root";s:1:"6";s:6:"branch";s:1:"0";s:4:"name";s:6:"用户";s:6:"parent";s:1:"0";s:4:"path";s:4:",41,";s:5:"grade";s:1:"1";s:5:"order";s:2:"20";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+166
View File
@@ -0,0 +1,166 @@
ALTER TABLE `zt_branch` ADD `default` enum ('0', '1') NOT NULL DEFAULT '0' AFTER `name`;
ALTER TABLE `zt_branch` ADD `status` enum ('active', 'closed') NOT NULL DEFAULT 'active' AFTER `default`;
ALTER TABLE `zt_branch` ADD `desc` varchar(255) NOT NULL AFTER `status`;
ALTER TABLE `zt_branch` ADD `createdDate` date NOT NULL AFTER `desc`;
ALTER TABLE `zt_branch` ADD `closedDate` date NOT NULL AFTER `createdDate`;
ALTER TABLE `zt_projectstory` ADD `branch` mediumint(8) NOT NULL AFTER `product`;
ALTER TABLE `zt_projectproduct` ADD PRIMARY KEY `project_product_branch` (`project`, `product`, `branch`), DROP INDEX `PRIMARY`;
ALTER TABLE `zt_apistruct` CHANGE COLUMN `editEdBy` `editedBy` varchar(30) NOT NULL DEFAULT 0;
-- DROP TABLE IF EXISTS `zt_kanbanlane`;
CREATE TABLE IF NOT EXISTS `zt_kanbanlane` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`execution` mediumint(8) NOT NULL DEFAULT '0',
`type` char(30) NOT NULL,
`groupby` char(30) NOT NULL,
`extra` char(30) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
`color` char(30) NOT NULL,
`order` smallint(6) NOT NULL DEFAULT '0',
`lastEditedTime` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_kanbancolumn`;
CREATE TABLE IF NOT EXISTS `zt_kanbancolumn` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`lane` mediumint(8) NOT NULL DEFAULT '0',
`parent` mediumint(8) NOT NULL DEFAULT '0',
`type` char(30) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
`color` char(30) NOT NULL,
`limit` smallint(6) NOT NULL DEFAULT '-1',
`order` mediumint(8) NOT NULL DEFAULT '0',
`cards` text NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_stage`;
CREATE TABLE IF NOT EXISTS `zt_stage` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`percent` varchar(255) NOT NULL,
`type` varchar(255) NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL,
`editedDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_design`;
CREATE TABLE IF NOT EXISTS `zt_design` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`project` varchar(255) NOT NULL,
`product` varchar(255) NOT NULL,
`commit` text NOT NULL,
`commitedBy` varchar(30) NOT NULL,
`execution` mediumint(8) unsigned NOT NULL DEFAULT '0',
`name` varchar(255) NOT NULL,
`status` varchar(30) NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL,
`editedDate` datetime NOT NULL,
`assignedTo` varchar(30) NOT NULL,
`assignedBy` varchar(30) NOT NULL,
`assignedDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
`story` char(30) NOT NULL,
`desc` text NOT NULL,
`version` smallint(6) NOT NULL,
`type` char(30) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_designspec`;
CREATE TABLE IF NOT EXISTS `zt_designspec` (
`design` mediumint(8) NOT NULL,
`version` smallint(6) NOT NULL,
`name` varchar(255) NOT NULL,
`desc` text NOT NULL,
`files` varchar(255) NOT NULL,
UNIQUE KEY `design` (`design`,`version`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_weeklyreport`;
CREATE TABLE IF NOT EXISTS `zt_weeklyreport`(
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`project` mediumint(8) unsigned NOT NULL,
`weekStart` date NOT NULL,
`pv` float(9,2) NOT NULL,
`ev` float(9,2) NOT NULL,
`ac` float(9,2) NOT NULL,
`sv` float(9,2) NOT NULL,
`cv` float(9,2) NOT NULL,
`staff` smallint(5) unsigned NOT NULL,
`progress` varchar(255) NOT NULL,
`workload` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `week` (`project`,`weekStart`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_holiday`;
CREATE TABLE IF NOT EXISTS `zt_holiday` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL DEFAULT '',
`type` enum('holiday', 'working') NOT NULL DEFAULT 'holiday',
`desc` text NOT NULL,
`year` char(4) NOT NULL,
`begin` date NOT NULL,
`end` date NOT NULL,
PRIMARY KEY (`id`),
KEY `year` (`year`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_mrapproval`;
CREATE TABLE IF NOT EXISTS `zt_mrapproval` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`mrID` mediumint(8) unsigned NOT NULL,
`account` varchar(255) NOT NULL,
`date` datetime NOT NULL,
`action` char(30) NOT NULL,
`comment` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
REPLACE INTO `zt_stage` (`name`,`percent`,`type`,`createdBy`,`createdDate`,`editedBy`,`editedDate`,`deleted`) VALUES
('需求','10','request','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
('设计','10','design','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
('开发','50','dev','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
('测试','15','qa','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
('发布','10','release','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
('总结评审','5','review','admin','2020-02-08 21:08:45','admin','2020-02-12 13:50:27','0');
INSERT INTO `zt_lang` (`lang`, `module`, `section`, `key`, `value`, `system`) VALUES
('all','stage','typeList','request','需求', '1'),
('all','stage','typeList','design','设计', '1'),
('all','stage','typeList','dev','开发', '1'),
('all','stage','typeList','qa','测试', '1'),
('all','stage','typeList','release','发布', '1'),
('all','stage','typeList','review','总结评审','1'),
('all','stage','typeList','other','其他','1');
ALTER TABLE `zt_bug`
ADD `feedbackBy` varchar(100) NOT NULL AFTER `activatedDate`,
ADD `notifyEmail` varchar(100) NOT NULL AFTER `feedbackBy`;
ALTER TABLE `zt_story`
ADD `feedbackBy` varchar(100) NOT NULL AFTER `version`,
ADD `notifyEmail` varchar(100) NOT NULL AFTER `feedbackBy`;
ALTER TABLE `zt_product` ADD `reviewer` varchar(255) NOT NULL AFTER `whitelist`;
UPDATE `zt_testtask` SET `pri`=3 WHERE `pri`=0;
ALTER table zt_mr ADD `approver` varchar(255) NOT NULL,
ADD `approvalStatus` char(30) NOT NULL,
ADD `needApproved` enum('0','1') NOT NULL DEFAULT '0',
ADD `needCI` enum('0','1') NOT NULL DEFAULT '0',
ADD `repoID` mediumint(8) unsigned NOT NULL,
ADD `jobID` mediumint(8) unsigned NOT NULL,
ADD `compileID` mediumint(8) unsigned NOT NULL,
ADD `compileStatus` char(30) NOT NULL;
+9
View File
@@ -0,0 +1,9 @@
ALTER TABLE `zt_task` ADD `repo` mediumint unsigned NOT NULL AFTER `activatedDate`;
ALTER TABLE `zt_task` ADD `entry` varchar(255) NOT NULL AFTER `repo`;
ALTER TABLE `zt_task` ADD `lines` varchar(10) NOT NULL AFTER `entry`;
ALTER TABLE `zt_task` ADD `v1` varchar(40) NOT NULL AFTER `lines`;
ALTER TABLE `zt_task` ADD `v2` varchar(40) NOT NULL AFTER `v1`;
ALTER TABLE `zt_task` ADD `mr` mediumint(8) unsigned NOT NULL AFTER `repo`;
ALTER TABLE `zt_bug` ADD `mr` mediumint(8) unsigned NOT NULL AFTER `repo`;
UPDATE `zt_grouppriv` SET `method`='addReview' where `module`='mr' and `method`='addBug';
+236 -87
View File
@@ -30,99 +30,94 @@ CREATE TABLE IF NOT EXISTS `zt_action` (
KEY `objectID` (`objectID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_api_lib_release`;
CREATE TABLE `zt_api_lib_release`
(
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`lib` int UNSIGNED NOT NULL DEFAULT 0,
`desc` varchar(255) NOT NULL DEFAULT '',
`version` varchar(255) NOT NULL DEFAULT '',
`snap` mediumtext NOT NULL,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NOT NULL,
PRIMARY KEY (`id`)
CREATE TABLE `zt_api_lib_release` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`lib` int UNSIGNED NOT NULL DEFAULT 0,
`desc` varchar(255) NOT NULL DEFAULT '',
`version` varchar(255) NOT NULL DEFAULT '',
`snap` mediumtext NOT NULL,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_api`;
CREATE TABLE `zt_api`
(
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`product` varchar(255) NOT NULL DEFAULT '',
`lib` int UNSIGNED NOT NULL DEFAULT 0,
`module` int UNSIGNED NOT NULL DEFAULT 0,
`title` varchar(100) NOT NULL DEFAULT '',
`path` varchar(255) NOT NULL DEFAULT '',
`protocol` varchar(10) NOT NULL DEFAULT '',
`method` varchar(10) NOT NULL DEFAULT '',
`requestType` varchar(100) NOT NULL DEFAULT '',
`responseType` varchar(100) NOT NULL DEFAULT '',
`status` varchar(20) NOT NULL DEFAULT '',
`owner` varchar(30) NOT NULl DEFAULT 0,
`desc` text NULL,
`version` smallint UNSIGNED NOT NULL DEFAULT 0,
`params` text NULL,
`paramsExample` text NUll,
`responseExample` text NUll,
`response` text NULL,
`commonParams` text NULL,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL DEFAULT 0,
`editedDate` datetime NOT NULL,
`deleted` enum ('0', '1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
CREATE TABLE `zt_api` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`product` varchar(255) NOT NULL DEFAULT '',
`lib` int UNSIGNED NOT NULL DEFAULT 0,
`module` int UNSIGNED NOT NULL DEFAULT 0,
`title` varchar(100) NOT NULL DEFAULT '',
`path` varchar(255) NOT NULL DEFAULT '',
`protocol` varchar(10) NOT NULL DEFAULT '',
`method` varchar(10) NOT NULL DEFAULT '',
`requestType` varchar(100) NOT NULL DEFAULT '',
`responseType` varchar(100) NOT NULL DEFAULT '',
`status` varchar(20) NOT NULL DEFAULT '',
`owner` varchar(30) NOT NULl DEFAULT 0,
`desc` text NULL,
`version` smallint UNSIGNED NOT NULL DEFAULT 0,
`params` text NULL,
`paramsExample` text NUll,
`responseExample` text NUll,
`response` text NULL,
`commonParams` text NULL,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL DEFAULT 0,
`editedDate` datetime NOT NULL,
`deleted` enum ('0', '1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_apispec`;
CREATE TABLE `zt_apispec`
(
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`doc` int UNSIGNED NOT NULL DEFAULT 0,
`module` int UNSIGNED NOT NULL DEFAULT 0,
`title` varchar(100) NOT NULL DEFAULT '',
`path` varchar(255) NOT NULL DEFAULT '',
`protocol` varchar(10) NOT NULL DEFAULT '',
`method` varchar(10) NOT NULL DEFAULT '',
`requestType` varchar(100) NOT NULL DEFAULT '',
`responseType` varchar(100) NOT NULL DEFAULT '',
`status` varchar(20) NOT NULL DEFAULT '',
`owner` varchar(255) NOT NULl DEFAULT 0,
`desc` text NULL,
`version` smallint UNSIGNED NOT NULL DEFAULT 0,
`params` text NULL,
`paramsExample` text NUll,
`responseExample` text NUll,
`response` text NULL,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NULL,
PRIMARY KEY (`id`)
CREATE TABLE `zt_apispec` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`doc` int UNSIGNED NOT NULL DEFAULT 0,
`module` int UNSIGNED NOT NULL DEFAULT 0,
`title` varchar(100) NOT NULL DEFAULT '',
`path` varchar(255) NOT NULL DEFAULT '',
`protocol` varchar(10) NOT NULL DEFAULT '',
`method` varchar(10) NOT NULL DEFAULT '',
`requestType` varchar(100) NOT NULL DEFAULT '',
`responseType` varchar(100) NOT NULL DEFAULT '',
`status` varchar(20) NOT NULL DEFAULT '',
`owner` varchar(255) NOT NULl DEFAULT 0,
`desc` text NULL,
`version` smallint UNSIGNED NOT NULL DEFAULT 0,
`params` text NULL,
`paramsExample` text NUll,
`responseExample` text NUll,
`response` text NULL,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_apistruct`;
CREATE TABLE `zt_apistruct`
(
`id` int unsigned NOT NULL AUTO_INCREMENT,
`lib` int UNSIGNED NOT NULL DEFAULT 0,
`name` varchar(30) NOT NULL DEFAULT '',
`type` varchar(50) NOT NULL DEFAULT '',
`desc` varchar(255) NOT NULL DEFAULT '',
`version` smallint unsigned NOT NULL DEFAULT 0,
`attribute` text NULL,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NOT NULL,
`editEdBy` varchar(30) NOT NULL DEFAULT 0,
`editedDate` datetime NOT NULL,
`deleted` enum ('0', '1') NOT NULL DEFAULT '0',
primary key (`id`)
CREATE TABLE `zt_apistruct` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`lib` int UNSIGNED NOT NULL DEFAULT 0,
`name` varchar(30) NOT NULL DEFAULT '',
`type` varchar(50) NOT NULL DEFAULT '',
`desc` varchar(255) NOT NULL DEFAULT '',
`version` smallint unsigned NOT NULL DEFAULT 0,
`attribute` text NULL,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL DEFAULT 0,
`editedDate` datetime NOT NULL,
`deleted` enum ('0', '1') NOT NULL DEFAULT '0',
primary key (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_apistruct_spec`;
CREATE TABLE `zt_apistruct_spec`
(
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`type` varchar(50) NOT NULL DEFAULT '',
`desc` varchar(255) NOT NULL DEFAULT '',
`attribute` text NULL,
`version` smallint unsigned NOT NULL DEFAULT 0,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NOT NULL,
primary key (`id`)
CREATE TABLE `zt_apistruct_spec` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`type` varchar(50) NOT NULL DEFAULT '',
`desc` varchar(255) NOT NULL DEFAULT '',
`attribute` text NULL,
`version` smallint unsigned NOT NULL DEFAULT 0,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NOT NULL,
primary key (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_block`;
CREATE TABLE IF NOT EXISTS `zt_block` (
@@ -147,6 +142,11 @@ CREATE TABLE IF NOT EXISTS `zt_branch` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`product` mediumint(8) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
`default` enum ('0', '1') NOT NULL DEFAULT '0',
`status` enum ('active', 'closed') NOT NULL DEFAULT 'active',
`desc` varchar(255) NOT NULL,
`createdDate` date NOT NULL,
`closedDate` date NOT NULL,
`order` smallint unsigned NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
@@ -182,6 +182,8 @@ CREATE TABLE IF NOT EXISTS `zt_bug` (
`confirmed` tinyint(1) NOT NULL default '0',
`activatedCount` smallint(6) NOT NULL,
`activatedDate` datetime NOT NULL,
`feedbackBy` varchar(100) NOT NULL,
`notifyEmail` varchar(100) NOT NULL,
`mailto` text,
`openedBy` varchar(30) NOT NULL default '',
`openedDate` datetime NOT NULL,
@@ -201,6 +203,7 @@ CREATE TABLE IF NOT EXISTS `zt_bug` (
`caseVersion` smallint(6) NOT NULL DEFAULT '1',
`result` mediumint(8) unsigned NOT NULL,
`repo` mediumint(8) unsigned NOT NULL,
`mr` mediumint(8) unsigned NOT NULL,
`entry` varchar(255) NOT NULL,
`lines` varchar(10) NOT NULL,
`v1` varchar(40) NOT NULL,
@@ -393,6 +396,39 @@ CREATE TABLE IF NOT EXISTS `zt_dept` (
KEY `parent` (`parent`),
KEY `path` (`path`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_design`;
CREATE TABLE IF NOT EXISTS `zt_design` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`project` varchar(255) NOT NULL,
`product` varchar(255) NOT NULL,
`commit` text NOT NULL,
`commitedBy` varchar(30) NOT NULL,
`execution` mediumint(8) unsigned NOT NULL DEFAULT '0',
`name` varchar(255) NOT NULL,
`status` varchar(30) NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL,
`editedDate` datetime NOT NULL,
`assignedTo` varchar(30) NOT NULL,
`assignedBy` varchar(30) NOT NULL,
`assignedDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
`story` char(30) NOT NULL,
`desc` text NOT NULL,
`version` smallint(6) NOT NULL,
`type` char(30) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_designspec`;
CREATE TABLE IF NOT EXISTS `zt_designspec` (
`design` mediumint(8) NOT NULL,
`version` smallint(6) NOT NULL,
`name` varchar(255) NOT NULL,
`desc` text NOT NULL,
`files` varchar(255) NOT NULL,
UNIQUE KEY `design` (`design`,`version`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_doc`;
CREATE TABLE IF NOT EXISTS `zt_doc` (
`id` mediumint(8) unsigned NOT NULL auto_increment,
@@ -558,6 +594,19 @@ CREATE TABLE IF NOT EXISTS `zt_grouppriv` (
`method` char(30) NOT NULL default '',
UNIQUE KEY `group` (`group`,`module`,`method`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_holiday`;
CREATE TABLE IF NOT EXISTS `zt_holiday` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL DEFAULT '',
`type` enum('holiday', 'working') NOT NULL DEFAULT 'holiday',
`desc` text NOT NULL,
`year` char(4) NOT NULL,
`begin` date NOT NULL,
`end` date NOT NULL,
PRIMARY KEY (`id`),
KEY `year` (`year`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_history`;
CREATE TABLE IF NOT EXISTS `zt_history` (
`id` mediumint(8) unsigned NOT NULL auto_increment,
@@ -595,6 +644,34 @@ CREATE TABLE IF NOT EXISTS `zt_job` (
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_kanbanlane`;
CREATE TABLE IF NOT EXISTS `zt_kanbanlane` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`execution` mediumint(8) NOT NULL DEFAULT '0',
`type` char(30) NOT NULL,
`groupby` char(30) NOT NULL,
`extra` char(30) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
`color` char(30) NOT NULL,
`order` smallint(6) NOT NULL DEFAULT '0',
`lastEditedTime` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_kanbancolumn`;
CREATE TABLE IF NOT EXISTS `zt_kanbancolumn` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`lane` mediumint(8) NOT NULL DEFAULT '0',
`parent` mediumint(8) NOT NULL DEFAULT '0',
`type` char(30) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
`color` char(30) NOT NULL,
`limit` smallint(6) NOT NULL DEFAULT '-1',
`order` mediumint(8) NOT NULL DEFAULT '0',
`cards` text NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_lang`;
CREATE TABLE IF NOT EXISTS `zt_lang` (
`id` mediumint(8) unsigned NOT NULL auto_increment,
@@ -655,6 +732,7 @@ CREATE TABLE IF NOT EXISTS `zt_mr` (
`description` text NOT NULL,
`assignee` varchar(255) NOT NULL,
`reviewer` varchar(255) NOT NULL,
`approver` varchar(255) NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL,
@@ -662,6 +740,23 @@ CREATE TABLE IF NOT EXISTS `zt_mr` (
`deleted` enum('0','1') NOT NULL DEFAULT '0',
`status` char(30) NOT NULL,
`mergeStatus` char(30) NOT NULL,
`approvalStatus` char(30) NOT NULL,
`needApproved` enum('0','1') NOT NULL DEFAULT '0',
`needCI` enum('0','1') NOT NULL DEFAULT '0',
`repoID` mediumint(8) unsigned NOT NULL,
`jobID` mediumint(8) unsigned NOT NULL,
`compileID` mediumint(8) unsigned NOT NULL,
`compileStatus` char(30) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_mrapproval`;
CREATE TABLE IF NOT EXISTS `zt_mrapproval` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`mrID` mediumint(8) unsigned NOT NULL,
`account` varchar(255) NOT NULL,
`date` datetime NOT NULL,
`action` char(30) NOT NULL,
`comment` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_notify`;
@@ -733,6 +828,7 @@ CREATE TABLE IF NOT EXISTS `zt_product` (
`RD` varchar(30) NOT NULL,
`acl` enum('open','private','custom') NOT NULL default 'open',
`whitelist` text NOT NULL,
`reviewer` varchar(255) NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`createdVersion` varchar(20) NOT NULL,
@@ -832,7 +928,7 @@ CREATE TABLE IF NOT EXISTS `zt_projectproduct` (
`product` mediumint(8) unsigned NOT NULL,
`branch` mediumint(8) unsigned NOT NULL,
`plan` mediumint(8) unsigned NOT NULL,
PRIMARY KEY (`project`,`product`)
PRIMARY KEY (`project`, `product`, `branch`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_projectspec`;
CREATE TABLE IF NOT EXISTS `zt_projectspec` (
@@ -848,6 +944,7 @@ CREATE TABLE IF NOT EXISTS `zt_projectspec` (
CREATE TABLE IF NOT EXISTS `zt_projectstory` (
`project` mediumint(8) unsigned NOT NULL default '0',
`product` mediumint(8) unsigned NOT NULL,
`branch` mediumint(8) unsigned NOT NULL,
`story` mediumint(8) unsigned NOT NULL default '0',
`version` smallint(6) NOT NULL default '1',
`order` smallint(6) unsigned NOT NULL,
@@ -989,6 +1086,19 @@ CREATE TABLE IF NOT EXISTS `zt_searchindex` (
FULLTEXT KEY `content` (`content`),
FULLTEXT KEY `title` (`title`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_stage`;
CREATE TABLE IF NOT EXISTS `zt_stage` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`percent` varchar(255) NOT NULL,
`type` varchar(255) NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL,
`editedDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_stakeholder`;
CREATE TABLE IF NOT EXISTS `zt_stakeholder` (
`id` mediumint(8) NOT NULL AUTO_INCREMENT PRIMARY KEY,
@@ -1043,6 +1153,8 @@ CREATE TABLE IF NOT EXISTS `zt_story` (
`linkStories` varchar(255) NOT NULL,
`duplicateStory` mediumint(8) unsigned NOT NULL,
`version` smallint(6) NOT NULL default '1',
`feedbackBy` varchar(100) NOT NULL,
`notifyEmail` varchar(100) NOT NULL,
`URChanged` enum('0','1') NOT NULL DEFAULT '0',
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`),
@@ -1139,6 +1251,12 @@ CREATE TABLE IF NOT EXISTS `zt_task` (
`lastEditedBy` varchar(30) NOT NULL,
`lastEditedDate` datetime NOT NULL,
`activatedDate` date NOT NULL,
`repo` mediumint(8) unsigned NOT NULL,
`mr` mediumint(8) unsigned NOT NULL,
`entry` varchar(255) NOT NULL,
`lines` varchar(10) NOT NULL,
`v1` varchar(40) NOT NULL,
`v2` varchar(40) NOT NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `execution` (`execution`),
@@ -1409,6 +1527,22 @@ CREATE TABLE IF NOT EXISTS `zt_userview` (
`sprints` mediumtext NOT NULL,
UNIQUE KEY `account` (`account`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_weeklyreport`;
CREATE TABLE IF NOT EXISTS `zt_weeklyreport`(
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`project` mediumint(8) unsigned NOT NULL,
`weekStart` date NOT NULL,
`pv` float(9,2) NOT NULL,
`ev` float(9,2) NOT NULL,
`ac` float(9,2) NOT NULL,
`sv` float(9,2) NOT NULL,
`cv` float(9,2) NOT NULL,
`staff` smallint(5) unsigned NOT NULL,
`progress` varchar(255) NOT NULL,
`workload` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `week` (`project`,`weekStart`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_webhook`;
CREATE TABLE IF NOT EXISTS `zt_webhook` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
@@ -5695,7 +5829,22 @@ REPLACE INTO `zt_lang` (`lang`, `module`, `section`, `key`, `value`, `system`) V
('zh-cn', 'custom', 'URSRList', '3', '{\"SRName\":\"\\u8f6f\\u9700\",\"URName\":\"\\u7528\\u9700\"}', '1'),('zh-cn', 'custom', 'URSRList', '4', '{\"SRName\":\"\\u6545\\u4e8b\",\"URName\":\"\\u53f2\\u8bd7\"}', '1'),
('zh-cn', 'custom', 'URSRList', '5', '{\"SRName\":\"\\u9700\\u6c42\",\"URName\":\"\\u7528\\u6237\\u9700\\u6c42\"}', '1'),
('en', 'custom', 'URSRList', '1', '{\"SRName\":\"Story\",\"URName\":\"Epic\"}', '0'),
('en', 'custom', 'URSRList', '2', '{\"SRName\":\"Software Requirement\",\"URName\":\"User Requirement\"}', '0');
('en', 'custom', 'URSRList', '2', '{\"SRName\":\"Software Requirement\",\"URName\":\"User Requirement\"}', '0'),
('all','stage','typeList','request','需求', '1'),
('all','stage','typeList','design','设计', '1'),
('all','stage','typeList','dev','开发', '1'),
('all','stage','typeList','qa','测试', '1'),
('all','stage','typeList','release','发布', '1'),
('all','stage','typeList','review','总结评审','1'),
('all','stage','typeList','other','其他','1');
REPLACE INTO `zt_stage` (`name`,`percent`,`type`,`createdBy`,`createdDate`,`editedBy`,`editedDate`,`deleted`) VALUES
('需求','10','request','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
('设计','10','design','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
('开发','50','dev','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
('测试','15','qa','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
('发布','10','release','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
('总结评审','5','review','admin','2020-02-08 21:08:45','admin','2020-02-12 13:50:27','0');
INSERT INTO `zt_config` (`owner`, `module`, `section`, `key`, `value`) VALUES ('system', 'custom', '', 'hourPoint', '0');
INSERT INTO `zt_config` (`owner`, `module`, `section`, `key`, `value`) VALUES ('system', 'common', '', 'CRProduct', '1');
+230
View File
@@ -1,3 +1,233 @@
2021-12-06 16.0.beat1
完成的需求
14005 能够按照平台分支浏览用户需求
14429 父需求支持变更
14761 选择某一个分支之后点击其他菜单希望能够保持分支下拉菜单状态
14771 启用多分支功能后增加分支字样显示的控制
14772 需求修改所属分支时如果有冲突给出提示
14778 分支设置默认分支功能
14877 根据分支提示上次版本计划名称
15134 员工负载表增加备注说明
15470 看板可以设置一个单元格里面卡片的排列方式
15478 我的地盘bug列表增加确认字段
25665 梳理项目和执行关联产品分支的逻辑
25666 可以将某一个分支关闭
25667 将所有分支概念改为主干并处理历史数据
25670 多分支产品浏览需求的时候将所有和主干区分开
25673 分支增加排序功能
27484 文档库右侧目录增加文件的浮动操作菜单
27485 文档库右侧目录增加目录的浮动操作菜单
27486 wiki目录中,当鼠标悬浮到文章名称时展示文章快捷操作
27487 wiki目录中,鼠标悬浮到具体章节时展示章节的快捷操作
27927 执行看板默认只显示一屏滚动时再往下加载
28098 需求批量转任务时对已经转换过任务的需求进行提示
28131 待处理任务列表中子任务名称前显示父任务
28138 员工负载表中增加项目名称信息
28147 统计列表中具备横向滚动条的列表可以直接展示出来
28153 Bug创建表中优化执行查询条件
28235 关闭项目时增加实际完成日期的记录
28236 项目工时统计中增加实际开始和实际完成的信息
28237 执行启动时增加实际开始日期的记录
28238 关闭执行时增加实际完成日期的记录
28239 执行工时统计中增加实际开始和实际完成的信息
28310 未开始的项目
28466 测试Bug列表中增加按所属项目的搜索条件
28509 项目概况中增加项目代号的显示
28510 项目列表中增加项目代号字段显示
28719 项目看板中看板列显示数量汇总
28727 计划创建迭代时选择项目点击下一步后自动关闭选择弹窗
28809 执行看板中进行中项目排序规则调整
28810 执行看板中已关闭的执行只展示最近2期数据
28811 执行看板中执行支持拖动调整看板列和状态
28811 执行看板中执行支持拖动调整看板列和状态
28812 项目看板中调整项目集和项目的排序规则
28813 项目看板中已关闭的项目只展示最近2个数据
28814 项目看板中项目支持拖动调整看板列和状态
28814 项目看板中项目支持拖动调整看板列和状态
28815 产品看板中看板列显示数量汇总
28816 产品看板中调整项目集和产品的排序规则
28817 项目集看板中调整项目集和产品的排序规则
28818 项目集看板中看板列显示数量汇总
28819 调整项目集/产品/项目/执行重名规则
28833 创建执行页面可以直接维护相关负责人信息
28834 项目的分组权限中移除无用的模块和方法
28835 关联多个产品的项目也可以选择归并方式
28904 优化项目列表“我参与的”筛选结果 结
28928 可以设置哪些人不需要提醒
28929 编辑bug修改状态时如果未修改成功希望有错误提示
28931 调整分支管理功能
28932 实现分支的批量操作
28941 重新登陆系统后产品下拉菜单应当保持上次选中的产品名称
28944 在开源版中增加瀑布模型的相关功能
28959 老版本升级新版本数据归并的时候,可以修改项目、执行名称。
28960 调整产品列表页面的宽度展示比例
28965 实现分支的新增/编辑操作
28970 需求列表批量选中希望可以通过shift快捷键操作
28972 产品列表左侧的模块设置调整为显示设置
28973 提交Bug时分支与影响版本要跟着联动
28974 产品列表批量调整计划时在计划名称前显示分支信息
28993 创建或者编辑用例时调整所属需求的查询逻辑
29000 产品列表中调整字段显示宽度
29002 动态支持按正序/倒序切换排序
29030 已挂起的项目/执行下面的任务不在待办/待处理的任务中展示
29059 多分支产品批量创建需求时分支字段设为默认项
29069 组织团队成员任务列表增加优先级排序功能
29074 用户下拉菜单中增加人员的头像/部门/职位信息
29108 提交/编辑软件需求页面中增加反馈者和通知邮箱信息
29109 提交/编辑Bug页面中增加反馈者和通知邮箱信息
29116 创建/编辑发布信息的通知人员中增加反馈者
29127 计划的Bug列表中增加批量编辑和调整计划功能
29131 产品概况中增加评审人员的设置
29134 看板页面的刷新不要抖动用更加平滑的方式呈现
29141 启用多分支功能后要用例增加分支字样显示的控制
29142 启用多分支功能后要Bug增加分支字样显示的控制
29143 批量创建需求/BUG/用例时所属模块选择同上,需要检测上一行数据的所属分支和当前行的所属分支是否一致
29144 所有分支下批量编辑需求/BUG/用例,所属模块数据默认为所有分支的模块时,需要处理分支与模块不一致的问题
29145 项目和执行关联了产品的多个分支及计划时调整概况页面显示方式
29147 产品下软件需求列表需求名称前显示主干的分支名
29156 启用多分支功能后项目需求列表增加是否显示分支名
29157 启用多分支功能后执行需求列表增加是否显示分支名
29158 启用多分支功能后执行任务列表增加是否显示分支名
29166 需求调整分支时,需求所属模块为主干的不用清空所属模块
29167 Bug调整分支时所属模块为主干的不用清空所属模块
29168 用例调整分支时所属模块为主干的不用清空所属模块
29173 项目关联产品计划时不允许关联父计划
29174 执行关联产品计划时不允许关联父计划
29182 分支下拉菜单中显示已关闭的分支状态
29192 归并数据遇到重名数据时可修改重名的数据
29193 调整发布中消息通知的触发方式
29218 分支的状态全部为关闭时才能调整产品类型为正常
29234 梳理分支逻辑
29438 在执行1下创建测试用例在执行2用例列表中也能看到
修复的BUG
6917 用例转bug编号会变化
6978 多分支产品bug搜索影响版本不太清晰
11290 邮件列表中主题字段内容部分遮挡
12023 产品下分支页面建议优化
13756 提bug页面没有正常显示所属产品分支的控件
14101 青春蓝-引导页国际版配图为中文
15665 维护目录和版本管理前的icon图标一样
15675 版本下解决又激活的bug,重新解决的时候,应该带有之前版本信息
15675 版本下解决又激活的bug,重新解决的时候,应该带有之前版本信息
15686 创建项目填充数据后,再选择项目集数据被清空
15687 自定义任务优先级展示问题
15688 新建用例,模块和需求对应错误
15689 测试单的报表百分比换行
15690 切换产品后,新建用例未显示在用例列表中
15691 套件的用例列表右上角的操作按钮样式不一致
15693 卡片展示项目时,项目状态显示不正确
15694 执行下创建用例,可以选择产品所有的模块和需求
15695 建用例,有默认所属模块可选择所有需求
15737 统计视图无法通过权限控制取消
15780 更改项目集的父项目集时,下面的产品线不能变更到顶层项目集
15781 项目创建版本时选择不到产品分支
15798 报告导出之后不展示饼状图
15826 后台评审流程开启后产品中批量创建研发需求没有默认需要评审
15828 项目集列表中删除顶级项目,跳转错误
16000 执行测试用例下用例标题换行显示
16018 项目-测试-BUG界面提交BUG不显示多分支/平台
16130 项目下创建测试用例时相关需求列出的数据不对
16139 设为分支为默认分支icon没有显示完全
16257 创建执行的时候已经关闭的项目仍然可以选择
16302 项目软件需求下搜索下拉列中所属分支显示为%s
16527 批量编辑用例时,列出了所有分支
16567 多分支产品的任务名称前主干分支名称显示其他分支名称不显示
16570 经典模式多分支产品批量提bug时标题未填写点击保存没做提示
16573 经典模式多分支产品批量创建用例未填写用例标题保存直接跳转列表没做提示
16574 关联产品页面已关联产品可以下拉选择其他未关联的分支
16582 分支1版本可以关联其他分支需求
16583 批量编辑测试用例分支显示错误导致无法选择模块
16584 执行版本不能按照所属分支搜索
16585 主干版本前未显示主干标识
16587 需求编辑页面所处阶段处分支展示方式建议优化
16588 项目/执行下显示了未关联的分支需求
16589 多分支产品测试用例列表用例类型展示有遮挡
16591 批量编辑研发需求修改分支后再修改回去计划没有随之联动
16592 多分支产品项目的研发需求模块展示不对
16593 测试下Bug页面中左侧模块树默认高亮了主干
16603 项目列表中项目名称显示不全
16605 项目的用例下显示了所有的分支
16608 编辑模块页面选择分支后上级模块列出的还是主干模块
16609 导出用例的模板显示了所有分支
16612 用例模板没显示分支下的模块
16616 导入用例分支下拉列表显示了所有分支
16620 研发需求变动列表一条用例显示多次
16621 搜索用例时,所属分支列出了所有分支
16622 产品下研发需求页搜索的所属模块下拉只列出了主干下的模块
16623 多分支产品关闭的分支在项目关联产品的时候仍然显示
16624 产品详情页中左上角产品下拉菜单中无当前产品选项
16626 测试套件中不显示其他分支模块只显示主干模块
16631 套件的用例名称前不显示主干
16637 测试单关联用例列表,用例列表显示分支标识
16639 测试用例详情页指派给用户显示数字
16640 测试单的优先级显示为0
16641 地盘待处理下用例批量编辑页面相关研发需求未带出
16643 地盘下批量编辑任务页面“贡献”菜单位置显示不对
16645 创建Gitlab动态没有链接地址
16646 文档的产品库中产品显示错误
16647 测试单生成报告提示没有关联的非Trunk测试单
16648 项目列表中项目名称完全折叠隐藏
16650 多分支产品测试套件详情所属模块只展示主干模块
16653 发布可以关联所有分支的需求
16676 地盘待处理下批量执行用例页面有代码报错
16680 产品库创建文档时所属文档库下拉无法选择其他产品库
16681 导入用例库测试用例分支和模块不对应
16682 地盘贡献下复制用例页面有代码报错
16683 测试单关联测试用例不能选择主干
16684 套件中用例标题的主干分支不显示
16685 测试单关联测试用例分支=空搜索到的数据为主干的测试用例
16689 测试单用例列表不显示测试用例相关模块
16690 产品下需求批量编辑页面计划显示不对
16692 项目下软件需求批量编辑页面分支显示不对
16694 提交测试的测试单不应该受左上角选择分支影响
16697 测试单关联测试用例选择所属分支应该只能选择版本关联的分支
16700 项目创建发布选择版本后产品分支会消失
16708 批量编辑多分支产品的研发需求报错
16713 产品需求模块中主干模块直接显示不用增加层级
2021-11-02 15.7.1
修复的BUG
15835 创建产品选择产品线选中样式不对
15793 编辑项目集实际开始日期应置空
15792 子计划的开始结束时间没有根据父计划做约束
15790 无关联项目时,计划创建迭代跳转页面不正确
15784 执行测试下提Bug返回的页面不对
15778 产品线取消所属项目集后产品列表页面显示错误
15776 添加产品 无法选中 产品线
15755 地盘下执行列表中“指派给我”含义不明确
15754 批量提Bug时不填写必填项[影响版本]也可以保存成功
15753 内网中批量新建质量保证计划三级导航菜单未高亮
15746 文档大纲只能显示第一个字影响使用
15745 执行-提醒-模块和动作顺序颠倒了
15744 后台-通知-设置,权限的英文描述不需要为过去式
15743 产品-需求-没有创建权限的用户点击导出时下拉菜单溢出
15742 产品-设置页面英文单词换行
15741 修改接口文档后历史记录可以优化一下,对于用户来说看不懂修改了哪里
15739 接口库中接口的添加时间会随更新时间改动
15737 统计视图无法通过权限控制取消
15729 项目团队成员维护新增字段行没有搜索功能
15728 取消备注权限后,还可以通过编辑添加备注
15723 点击左侧导航栏有时跳转页面不正确
15719 评审阶段的需求,点击搜索后,不可以评审,但可以变更
15718 需求导入excel时如果取消勾选“不需要评审”则导入的需求状态为草稿且无法激活
15716 测试报告中项目目标建议给出提示或说明
15715 细分子任务弹窗时无任务研发需求
15712 项目下研发需求还会显示细分需求按钮
15710 在产品A下添加测试用例选择产品B不显示相关联研发需求
15708 经典模式下变更需求页标签名称不对
15705 组织-动态搜索条件设置 所属产品=全部产品 后,搜索不出数据
15702 接口多层级字段,去掉多个L符号
15672 点击删除版本按钮后没有弹出访问受限提示弹窗
15668 编辑名称为空的接口时显示错误
15667 创建接口的时候可以为一个空格
15664 不能进行目录维护时,优化一下左侧提示文案
15660 接口库名称可以重名
15659 接口库中多级目录时创建接口显示不明确
15657 数据结构列表操作栏的title显示为接口
15467 管理流程字样显示问题
15287 批量编辑任务,指派给closed,任务状态未关闭
14559 项目下拉中所有产品和产品列表文案需统一
2021-10-18 15.7
修复的BUG
14487 无用php记录太多拉低禅道整体性能
+88 -25
View File
@@ -275,6 +275,7 @@ class baseEntry
global $app;
$app->setModuleName($moduleName);
$app->setMethodName($methodName);
$app->viewType = 'json';
/* Check user permission. */
$this->checkPriv();
@@ -546,6 +547,23 @@ class baseEntry
return $filtered;
}
/**
* Format user.
*
* @param string $account
* @param array $users
* @access public
* @return array
*/
public function formatUser($account, $users)
{
$user = array();
$user['account'] = $account;
$user['realname'] = zget($users, $account);
return $user;
}
/**
* 类型转换.
* Typecasting.
@@ -559,31 +577,62 @@ class baseEntry
{
switch($type)
{
case 'time':
$timeFormat = $this->param('timeFormat', 'utc');
if($timeFormat == 'utc')
{
if(!$value or $value == '0000-00-00 00:00:00') return null;
return gmdate("Y-m-d\TH:i:s\Z", strtotime($value));
}
return $value;
case 'date':
if(!$value or $value == '0000-00-00') return null;
return $value;
case 'bool':
return boolval($value) ? true : false;
case 'idList':
$values = explode(',', $value);
if(empty($values)) return array();
case 'time':
$timeFormat = $this->param('timeFormat', 'utc');
if($timeFormat == 'utc')
{
if(!$value or $value == '0000-00-00 00:00:00') return null;
return gmdate("Y-m-d\TH:i:s\Z", strtotime($value));
}
return $value;
case 'date':
if(!$value or $value == '0000-00-00') return null;
return $value;
case 'bool':
return !empty($value);
case 'int':
return (int) $value;
case 'idList':
$values = explode(',', $value);
if(empty($values)) return array();
$idList = array();
foreach($values as $val)
{
if($val !== '') $idList[] = (int) $val;
}
return $idList;
default:
return $value;
$idList = array();
foreach($values as $val)
{
if($val !== '') $idList[] = (int) $val;
}
return $idList;
case 'stringList':
$values = explode(',', $value);
if(empty($values)) return array();
$stringList = array();
foreach($values as $val)
{
if($val !== '') $stringList[] = $val;
}
return $stringList;
case 'array':
$array = array();
if(!empty($value)) foreach($value as $v) $array[] = $v;
return $array;
case 'user':
if(empty($value)) return null;
if(empty($this->users)) $this->users = $this->dao->select('id,account,avatar,realname')->from(TABLE_USER)->fetchAll('account');
return zget($this->users, $value, null);
case 'userList':
$values = explode(',', $value);
if(empty($values)) return array();
$userList = array();
foreach($values as $val)
{
$val = $this->cast($val, 'user');
if($val) $userList[] = $val;
}
return $userList;
default:
return $value;
}
}
@@ -616,9 +665,23 @@ class baseEntry
{
$module = $this->app->getModuleName();
$method = $this->app->getMethodName();
if($module and $method and !commonModel::hasPriv($module, $method))
if($module and $method and !$this->loadModel('common')->isOpenMethod($module, $method) and !commonModel::hasPriv($module, $method))
{
$this->send(403, array('error' => 'Access not allowed'));
}
}
/**
* Reset open app.
*
* @param string $tab
* @access public
* @return void
*/
public function resetOpenApp($tab)
{
$_COOKIE['tab'] = $tab;
$this->app->tab = $tab;
$this->app->session->tab = $tab;
}
}
+7 -16
View File
@@ -82,22 +82,13 @@ class api extends router
$this->httpMethod = strtolower($_SERVER['REQUEST_METHOD']);
if(!empty($_SERVER['PATH_INFO']))
{
$this->path = rtrim($_SERVER['PATH_INFO'], '/');
}
else
{
$this->path = rtrim((strpos($_SERVER['REQUEST_URI'], '?') > 0 ? strstr($_SERVER['REQUEST_URI'], '?', true) : $_SERVER['REQUEST_URI']), '/');
}
$fileName = ltrim(substr($_SERVER['SCRIPT_FILENAME'], strlen($_SERVER['DOCUMENT_ROOT'])), '/');
$this->path = substr(ltrim($_SERVER['REQUEST_URI'], '/'), strlen($fileName) + 1);
if(strpos($this->path, '?') > 0) $this->path = strstr($this->path, '?', true);
$dir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/');
if($dir != '' and strpos($this->path, $dir) === 0) $this->path = substr($this->path, strlen($dir));
$subPos = strpos($this->path, '/', 1);
$this->version = $subPos ? substr($this->path, 1, $subPos - 1) : '';
$this->path = $subPos ? substr($this->path, $subPos) : $this->path;
$subPos = $this->path ? strpos($this->path, '/') : false;
$this->version = $subPos !== false ? substr($this->path, 0, $subPos) : '';
$this->path = $subPos !== false ? substr($this->path, $subPos) : '';
$this->loadApiLang();
}
@@ -230,7 +221,7 @@ class api extends router
public function loadApiLang()
{
global $lang;
include($this->appRoot . "api/$this->version/lang/$this->clientLang.php");
if($this->version) include($this->appRoot . "api/$this->version/lang/$this->clientLang.php");
}
/**
+9 -4
View File
@@ -927,6 +927,14 @@ class baseControl
{
if(!empty($data['message']))
{
if(is_string($data['message']))
{
echo js::alert($data['message']);
$locate = isset($data['locate']) ? $data['locate'] : (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '');
if (!empty($locate)) die(js::locate($locate));
die(isset($data['message']) ? $data['message'] : 'fail');
}
$message = json_decode(json_encode((array)$data['message']));
foreach((array)$message as $item => $errors) $message->$item = implode(',', $errors);
die(js::alert(strip_tags(implode('\n', (array)$message))));
@@ -944,10 +952,7 @@ class baseControl
*/
public function sendError($error)
{
$this->send([
'result' => 'fail',
'message' => $error,
]);
$this->send(array('result' => 'fail', 'message' => $error));
}
/**
+27 -7
View File
@@ -504,7 +504,12 @@ class baseHelper
*/
static public function diffDate($date1, $date2)
{
return round((strtotime($date1) - strtotime($date2)) / 86400, 0);
/* Get the timestamp in the current operating system. */
$date1 = new DateTime($date1);
$date2 = new DateTime($date2);
$date1 = date_format($date1, "U");
$date2 = date_format($date2, "U");
return round(($date1 - $date2) / 86400, 0);
}
/**
@@ -512,7 +517,7 @@ class baseHelper
* Get now time use the DT_DATETIME1 constant defined in the lang file.
*
* @access public
* @return datetime now
* @return string now
*/
static public function now()
{
@@ -524,7 +529,7 @@ class baseHelper
* Get today according to the DT_DATE1 constant defined in the lang file.
*
* @access public
* @return date today
* @return string today
*/
static public function today()
{
@@ -536,7 +541,7 @@ class baseHelper
* Get now time use the DT_TIME1 constant defined in the lang file.
*
* @access public
* @return date today
* @return string today
*/
static public function time()
{
@@ -743,10 +748,10 @@ class baseHelper
* @param string $viewType
* @return string the link string.
*/
function inLink($methodName = 'index', $vars = '', $viewType = '')
function inLink($methodName = 'index', $vars = '', $viewType = '', $onlybody = false)
{
global $app;
return helper::createLink($app->getModuleName(), $methodName, $vars, $viewType);
return helper::createLink($app->getModuleName(), $methodName, $vars, $viewType, $onlybody);
}
/**
@@ -850,7 +855,7 @@ function getWebRoot($full = false)
* @param mixed $valueWhenNone value when the key not exits.
* @param mixed $valueWhenExists value when the key exits.
* @access public
* @return string
* @return mixed
*/
function zget($var, $key, $valueWhenNone = false, $valueWhenExists = false)
{
@@ -882,3 +887,18 @@ function isHttps()
if(!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') return true;
return false;
}
/**
* Compatibility for htmlspecialchars.
*
* @param string $string
* @param int $flags
* @param string $encoding
* @access public
* @return string
*/
function htmlSpecialString($string, $flags = '', $encoding = 'UTF-8')
{
if(!$flags) $flags = defined('ENT_SUBSTITUTE') ? ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 : ENT_QUOTES;
return htmlspecialchars($string, $flags, $encoding);
}
+2 -1
View File
@@ -2250,6 +2250,7 @@ class baseRouter
$view->methodVar = $this->config->methodVar;
$view->viewVar = $this->config->viewVar;
$view->sessionVar = $this->config->sessionVar;
$view->systemMode = $this->config->systemMode;
$this->session->set('random', mt_rand(0, 10000));
$view->sessionName = session_name();
@@ -2420,7 +2421,7 @@ class baseRouter
public function triggerError($message, $file, $line, $exit = false)
{
/* 设置错误信息(Set the error info) */
$message = htmlspecialchars($message);
$message = htmlSpecialString($message);
if(preg_match('/[^\x00-\x80]/', $message)) $message = helper::convertEncoding($message, 'gbk');
/* Only show error when debug is open. */
+6 -1
View File
@@ -117,7 +117,12 @@ class router extends baseRouter
unset($lang->{$moduleName}->{$section});
if(isset($nullKey))$lang->{$moduleName}->{$section}[$nullKey] = $nullValue;
foreach($fields as $key => $value) $lang->{$moduleName}->{$section}[$key] = $value;
foreach($fields as $key => $value)
{
if(!isset($lang->{$moduleName})) $lang->{$moduleName} = new stdclass();
if(!isset($lang->{$moduleName}->{$section})) $lang->{$moduleName}->{$section} = array();
$lang->{$moduleName}->{$section}[$key] = $value;
}
unset($nullKey);
unset($nullValue);
}
+194 -177
View File
@@ -17,8 +17,8 @@ class ztclient
public $session;
/**
* The construce function.
*
* The construce function.
*
* @param string $zentaoRoot the zentao root url
* @param string $account the login account
* @param string $password the passwod
@@ -43,8 +43,8 @@ class ztclient
}
/**
* Get the settings through getconfig api from remote.
*
* Get the settings through getconfig api from remote.
*
* @access private
* @return object
*/
@@ -58,7 +58,7 @@ class ztclient
/**
* Set the session api.
*
*
* @access private
* @return string the session api url.
*/
@@ -69,7 +69,7 @@ class ztclient
/**
* Set the login api.
*
*
* @access private
* @return string the login api url.
*/
@@ -80,8 +80,8 @@ class ztclient
/**
* Set the method api.
*
* @param string $module the module name
*
* @param string $module the module name
* @param string $method the methhod name
* @param string $vars the vars to passwd
* @access private
@@ -110,8 +110,8 @@ class ztclient
/**
* Set the method api.
*
* @param string $module the module name
*
* @param string $module the module name
* @param string $method the methhod name
* @param string $vars the vars to passed
* @access private
@@ -138,8 +138,8 @@ class ztclient
}
/**
* Start session
*
* Start session
*
* @access public
* @return void
*/
@@ -151,7 +151,7 @@ class ztclient
/**
* Login.
*
*
* @access public
* @return void
*/
@@ -164,9 +164,9 @@ class ztclient
}
/**
* Fetch one method of a module's control.
*
* @param string $module the module name
* Fetch one method of a module's control.
*
* @param string $module the module name
* @param string $method the methhod name
* @param string $vars the vars to passwd
* @access public
@@ -178,9 +178,9 @@ class ztclient
}
/**
* Fetch one method of a module's model.
*
* @param string $module the module name
* Fetch one method of a module's model.
*
* @param string $module the module name
* @param string $method the methhod name
* @param string $vars the vars to passwd
* @access public
@@ -192,9 +192,9 @@ class ztclient
}
/**
* Get a api and check it.
*
* @param string $url
* Get a api and check it.
*
* @param string $url
* @access private
* @return bool
*/
@@ -209,9 +209,9 @@ class ztclient
}
/**
* Fetch one method of a module's control.
*
* @param string $module the module name
* Fetch one method of a module's control.
*
* @param string $module the module name
* @param string $method the methhod name
* @param array $vars the vars to passwd
* @access public
@@ -224,8 +224,8 @@ class ztclient
/**
* Post.
*
* @param string $url
*
* @param string $url
* @access private
* @return bool
*/
@@ -241,8 +241,8 @@ class ztclient
/**
* Append session param to the url.
*
* @param string $url
*
* @param string $url
* @access private
* @return string
*/
@@ -288,7 +288,7 @@ http://snoopy.sourceforge.net/
class Snoopy
{
/**** Public variables ****/
/* user definable vars */
var $host = "www.php.net"; // host name we are connecting to
@@ -297,7 +297,7 @@ class Snoopy
var $proxy_port = ""; // proxy port to use
var $proxy_user = ""; // proxy user to use
var $proxy_pass = ""; // proxy password to use
var $agent = "Snoopy v1.2.4"; // agent we masquerade as
var $referer = ""; // referer info to pass
var $cookies = array(); // array of cookies to pass
@@ -315,15 +315,15 @@ class Snoopy
var $passcookies = true; // pass set cookies back through redirects
// NOTE: this currently does not respect
// dates, domains or paths.
var $user = ""; // user for http authentication
var $pass = ""; // password for http authentication
// http accept types
var $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*";
var $results = ""; // where the content is put
var $error = ""; // error messages sent here
var $response_code = ""; // response code returned from server
var $headers = array(); // headers returned from server sent here
@@ -349,11 +349,11 @@ class Snoopy
// library functions built into php,
// as these functions are not stable
// as of this Snoopy release.
/**** Private variables ****/
/**** Private variables ****/
var $_maxlinelen = 4096; // max line length (headers)
var $_httpmethod = "GET"; // default http request method
var $_httpversion = "HTTP/1.0"; // default http request version
var $_submit_method = "POST"; // default submit method
@@ -363,7 +363,7 @@ class Snoopy
var $_redirectdepth = 0; // increments on an http redirect
var $_frameurls = array(); // frame src urls
var $_framedepth = 0; // increments on frame depth
var $_isproxy = false; // set if using a proxy server
var $_fp_timeout = 30; // timeout for socket connection
@@ -378,7 +378,7 @@ class Snoopy
function fetch($URI)
{
//preg_match("|^([^:]+)://([^:/]+)(:[\d]+)*(.*)|",$URI,$URI_PARTS);
$URI_PARTS = parse_url($URI);
if (!empty($URI_PARTS["user"]))
@@ -389,7 +389,7 @@ class Snoopy
$URI_PARTS["query"] = '';
if (empty($URI_PARTS["path"]))
$URI_PARTS["path"] = '';
switch(strtolower($URI_PARTS["scheme"]))
{
case "http":
@@ -409,7 +409,7 @@ class Snoopy
// no proxy, send only the path
$this->_httprequest($path, $fp, $URI, $this->_httpmethod);
}
$this->_disconnect($fp);
if($this->_redirectaddr)
@@ -432,8 +432,8 @@ class Snoopy
{
$frameurls = $this->_frameurls;
$this->_frameurls = array();
while(list(,$frameurl) = each($frameurls))
foreach($frameurls as $frameurl))
{
if($this->_framedepth < $this->maxframes)
{
@@ -441,15 +441,17 @@ class Snoopy
$this->_framedepth++;
}
else
{
break;
}
}
}
}
}
else
{
return false;
}
return true;
return true;
break;
case "https":
if(!$this->curl_path)
@@ -493,7 +495,7 @@ class Snoopy
$frameurls = $this->_frameurls;
$this->_frameurls = array();
while(list(,$frameurl) = each($frameurls))
foreach($frameurls as $frameurl)
{
if($this->_framedepth < $this->maxframes)
{
@@ -501,17 +503,19 @@ class Snoopy
$this->_framedepth++;
}
else
{
break;
}
}
}
return true;
}
return true;
break;
default:
// not a valid protocol
$this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n';
return false;
break;
}
}
return true;
}
@@ -529,9 +533,9 @@ class Snoopy
function submit($URI, $formvars="", $formfiles="")
{
unset($postdata);
$postdata = $this->_prepare_post_body($formvars, $formfiles);
$URI_PARTS = parse_url($URI);
if (!empty($URI_PARTS["user"]))
$this->user = $URI_PARTS["user"];
@@ -561,17 +565,17 @@ class Snoopy
// no proxy, send only the path
$this->_httprequest($path, $fp, $URI, $this->_submit_method, $this->_submit_type, $postdata);
}
$this->_disconnect($fp);
if($this->_redirectaddr)
{
/* url was redirected, check if we've hit the max depth */
if($this->maxredirs > $this->_redirectdepth)
{
{
if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr))
$this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]);
$this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]);
// only follow redirect if it's on this site, or offsiteok is true
if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok)
{
@@ -590,9 +594,9 @@ class Snoopy
{
$frameurls = $this->_frameurls;
$this->_frameurls = array();
while(list(,$frameurl) = each($frameurls))
{
foreach($frameurls as $frameurl)
{
if($this->_framedepth < $this->maxframes)
{
$this->fetch($frameurl);
@@ -601,14 +605,14 @@ class Snoopy
else
break;
}
}
}
}
else
{
return false;
}
return true;
return true;
break;
case "https":
if(!$this->curl_path)
@@ -635,9 +639,9 @@ class Snoopy
{
/* url was redirected, check if we've hit the max depth */
if($this->maxredirs > $this->_redirectdepth)
{
{
if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr))
$this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]);
$this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]);
// only follow redirect if it's on this site, or offsiteok is true
if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok)
@@ -658,8 +662,8 @@ class Snoopy
$frameurls = $this->_frameurls;
$this->_frameurls = array();
while(list(,$frameurl) = each($frameurls))
{
foreach($frameurls as $frameurl)
{
if($this->_framedepth < $this->maxframes)
{
$this->fetch($frameurl);
@@ -668,16 +672,16 @@ class Snoopy
else
break;
}
}
return true;
}
return true;
break;
default:
// not a valid protocol
$this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n';
return false;
break;
}
}
return true;
}
@@ -691,7 +695,7 @@ class Snoopy
function fetchlinks($URI)
{
if ($this->fetch($URI))
{
{
if($this->lastredirectaddr)
$URI = $this->lastredirectaddr;
if(is_array($this->results))
@@ -719,9 +723,9 @@ class Snoopy
function fetchform($URI)
{
if ($this->fetch($URI))
{
{
if(is_array($this->results))
{
@@ -730,14 +734,14 @@ class Snoopy
}
else
$this->results = $this->_stripform($this->results);
return true;
}
else
return false;
}
/*======================================================================*\
Function: fetchtext
Purpose: fetch the text from a web page, stripping the links
@@ -748,7 +752,7 @@ class Snoopy
function fetchtext($URI)
{
if($this->fetch($URI))
{
{
if(is_array($this->results))
{
for($x=0;$x<count($this->results);$x++)
@@ -772,7 +776,7 @@ class Snoopy
function submitlinks($URI, $formvars="", $formfiles="")
{
if($this->submit($URI,$formvars, $formfiles))
{
{
if($this->lastredirectaddr)
$URI = $this->lastredirectaddr;
if(is_array($this->results))
@@ -806,7 +810,7 @@ class Snoopy
function submittext($URI, $formvars = "", $formfiles = "")
{
if($this->submit($URI,$formvars, $formfiles))
{
{
if($this->lastredirectaddr)
$URI = $this->lastredirectaddr;
if(is_array($this->results))
@@ -830,7 +834,7 @@ class Snoopy
return false;
}
/*======================================================================*\
Function: set_submit_multipart
@@ -842,7 +846,7 @@ class Snoopy
$this->_submit_type = "multipart/form-data";
}
/*======================================================================*\
Function: set_submit_normal
Purpose: Set the form submission content type to
@@ -853,14 +857,14 @@ class Snoopy
$this->_submit_type = "application/x-www-form-urlencoded";
}
/*======================================================================*\
Private functions
\*======================================================================*/
/*======================================================================*\
Function: _striplinks
Purpose: strip the hyperlinks from an html document
@@ -869,28 +873,28 @@ class Snoopy
\*======================================================================*/
function _striplinks($document)
{
{
preg_match_all("'<\s*a\s.*?href\s*=\s* # find <a href=
([\"\'])? # find single or double quote
(?(1) (.*?)\\1 | ([^\s\>]+)) # if quote found, match up to next matching
# quote, otherwise match up to next space
'isx",$document,$links);
// catenate the non-empty matches from the conditional subpattern
while(list($key,$val) = each($links[2]))
foreach($links[2] as $key => $val)
{
if(!empty($val))
$match[] = $val;
}
while(list($key,$val) = each($links[3]))
}
foreach($links[3] as $key => $val)
{
if(!empty($val))
$match[] = $val;
}
}
// return the links
return $match;
}
@@ -903,18 +907,18 @@ class Snoopy
\*======================================================================*/
function _stripform($document)
{
{
preg_match_all("'<\/?(FORM|INPUT|SELECT|TEXTAREA|(OPTION))[^<>]*>(?(2)(.*(?=<\/?(option|select)[^<>]*>[\r\n]*)|(?=[\r\n]*))|(?=[\r\n]*))'Usi",$document,$elements);
// catenate the matches
$match = implode("\r\n",$elements[0]);
// return the links
return $match;
}
/*======================================================================*\
Function: _striptext
Purpose: strip the text from an html document
@@ -924,11 +928,11 @@ class Snoopy
function _striptext($document)
{
// I didn't use preg eval (//e) since that is only available in PHP 4.0.
// so, list your entities one by one here. I included some of the
// more common ones.
$search = array("'<script[^>]*?>.*?</script>'si", // strip out javascript
"'<[\/\!]*?[^<>]*?>'si", // strip out html tags
"'([\r\n])[\s]+'", // strip out white space
@@ -977,9 +981,9 @@ class Snoopy
"?",
"?",
);
$text = preg_replace($search,$replace,$document);
return $text;
}
@@ -993,7 +997,7 @@ class Snoopy
function _expandlinks($links,$URI)
{
preg_match("/^[^\?]+/",$URI,$match);
$match = preg_replace("|/[^\/\.]+\.[^\/\.]+$|","",$match[0]);
@@ -1001,21 +1005,21 @@ class Snoopy
$match_part = parse_url($match);
$match_root =
$match_part["scheme"]."://".$match_part["host"];
$search = array( "|^http://".preg_quote($this->host)."|i",
"|^(\/)|i",
"|^(?!http://)(?!mailto:)|i",
"|/\./|",
"|/[^\/]+/\.\./|"
);
$replace = array( "",
$match_root."/",
$match."/",
"/",
"/"
);
);
$expandedLinks = preg_replace($search,$replace,$links);
return $expandedLinks;
@@ -1028,19 +1032,19 @@ class Snoopy
$fp the current open file pointer
$URI the full URI
$body body contents to send if any (POST)
Output:
Output:
\*======================================================================*/
function _httprequest($url,$fp,$URI,$http_method,$content_type="",$body="")
{
$cookie_headers = '';
if($this->passcookies && $this->_redirectaddr)
$this->setcookies();
$URI_PARTS = parse_url($URI);
if(empty($url))
$url = "/";
$headers = $http_method." ".$url." ".$this->_httpversion."\r\n";
$headers = $http_method." ".$url." ".$this->_httpversion."\r\n";
if(!empty($this->agent))
$headers .= "User-Agent: ".$this->agent."\r\n";
if(!empty($this->host) && !isset($this->rawheaders['Host'])) {
@@ -1054,10 +1058,10 @@ class Snoopy
if(!empty($this->referer))
$headers .= "Referer: ".$this->referer."\r\n";
if(!empty($this->cookies))
{
{
if(!is_array($this->cookies))
$this->cookies = (array)$this->cookies;
reset($this->cookies);
if ( count($this->cookies) > 0 ) {
$cookie_headers .= 'Cookie: ';
@@ -1065,14 +1069,18 @@ class Snoopy
$cookie_headers .= $cookieKey."=".urlencode($cookieVal)."; ";
}
$headers .= substr($cookie_headers,0,-2) . "\r\n";
}
}
}
if(!empty($this->rawheaders))
{
if(!is_array($this->rawheaders))
{
$this->rawheaders = (array)$this->rawheaders;
while(list($headerKey,$headerVal) = each($this->rawheaders))
}
foreach($this->rawheaders as $headerKey => $headerVal)
{
$headers .= $headerKey.": ".$headerVal."\r\n";
}
}
if(!empty($content_type)) {
$headers .= "Content-type: $content_type";
@@ -1080,28 +1088,28 @@ class Snoopy
$headers .= "; boundary=".$this->_mime_boundary;
$headers .= "\r\n";
}
if(!empty($body))
if(!empty($body))
$headers .= "Content-length: ".strlen($body)."\r\n";
if(!empty($this->user) || !empty($this->pass))
if(!empty($this->user) || !empty($this->pass))
$headers .= "Authorization: Basic ".base64_encode($this->user.":".$this->pass)."\r\n";
//add proxy auth headers
if(!empty($this->proxy_user))
if(!empty($this->proxy_user))
$headers .= 'Proxy-Authorization: ' . 'Basic ' . base64_encode($this->proxy_user . ':' . $this->proxy_pass)."\r\n";
$headers .= "\r\n";
// set the read timeout if needed
if ($this->read_timeout > 0)
socket_set_timeout($fp, $this->read_timeout);
$this->timed_out = false;
fwrite($fp,$headers.$body,strlen($headers.$body));
$this->_redirectaddr = false;
unset($this->headers);
while($currentHeader = fgets($fp,$this->_maxlinelen))
{
if ($this->read_timeout > 0 && $this->_check_timeout($fp))
@@ -1109,10 +1117,10 @@ class Snoopy
$this->status=-100;
return false;
}
if($currentHeader == "\r\n")
break;
// if a header begins with Location: or URI:, set the redirect
if(preg_match("/^(Location:|URI:)/i",$currentHeader))
{
@@ -1132,16 +1140,16 @@ class Snoopy
else
$this->_redirectaddr = $matches[2];
}
if(preg_match("|^HTTP/|",$currentHeader))
{
if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$currentHeader, $status))
{
$this->status= $status[1];
}
}
$this->response_code = $currentHeader;
}
$this->headers[] = $currentHeader;
}
@@ -1159,13 +1167,13 @@ class Snoopy
$this->status=-100;
return false;
}
// check if there is a a redirect meta tag
if(preg_match("'<meta[\s]*http-equiv[^>]*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match))
{
$this->_redirectaddr = $this->_expandlinks($match[1],$URI);
$this->_redirectaddr = $this->_expandlinks($match[1],$URI);
}
// have we hit our frame depth and is there frame src to fetch?
@@ -1181,7 +1189,7 @@ class Snoopy
// no framed content
else
$this->results = $results;
return true;
}
@@ -1191,21 +1199,21 @@ class Snoopy
Input: $url the url to fetch
$URI the full URI
$body body contents to send if any (POST)
Output:
Output:
\*======================================================================*/
function _httpsrequest($url,$URI,$http_method,$content_type="",$body="")
{
{
if($this->passcookies && $this->_redirectaddr)
$this->setcookies();
$headers = array();
$headers = array();
$URI_PARTS = parse_url($URI);
if(empty($url))
$url = "/";
// GET ... header not needed for curl
//$headers[] = $http_method." ".$url." ".$this->_httpversion;
//$headers[] = $http_method." ".$url." ".$this->_httpversion;
if(!empty($this->agent))
$headers[] = "User-Agent: ".$this->agent;
if(!empty($this->host))
@@ -1218,10 +1226,10 @@ class Snoopy
if(!empty($this->referer))
$headers[] = "Referer: ".$this->referer;
if(!empty($this->cookies))
{
{
if(!is_array($this->cookies))
$this->cookies = (array)$this->cookies;
reset($this->cookies);
if ( count($this->cookies) > 0 ) {
$cookie_str = 'Cookie: ';
@@ -1234,9 +1242,13 @@ class Snoopy
if(!empty($this->rawheaders))
{
if(!is_array($this->rawheaders))
{
$this->rawheaders = (array)$this->rawheaders;
while(list($headerKey,$headerVal) = each($this->rawheaders))
}
foreach($this->rawheaders as $headerKey => $headerVal)
{
$headers[] = $headerKey.": ".$headerVal;
}
}
if(!empty($content_type)) {
if ($content_type == "multipart/form-data")
@@ -1244,43 +1256,43 @@ class Snoopy
else
$headers[] = "Content-type: $content_type";
}
if(!empty($body))
if(!empty($body))
$headers[] = "Content-length: ".strlen($body);
if(!empty($this->user) || !empty($this->pass))
if(!empty($this->user) || !empty($this->pass))
$headers[] = "Authorization: BASIC ".base64_encode($this->user.":".$this->pass);
for($curr_header = 0; $curr_header < count($headers); $curr_header++) {
$safer_header = strtr( $headers[$curr_header], "\"", " " );
$cmdline_params .= " -H \"".$safer_header."\"";
}
if(!empty($body))
$cmdline_params .= " -d \"$body\"";
if($this->read_timeout > 0)
$cmdline_params .= " -m ".$this->read_timeout;
$headerfile = tempnam($temp_dir, "sno");
exec($this->curl_path." -k -D \"$headerfile\"".$cmdline_params." \"".escapeshellcmd($URI)."\"",$results,$return);
if($return)
{
$this->error = "Error: cURL could not retrieve the document, error $return.";
return false;
}
$results = implode("\r\n",$results);
$result_headers = file("$headerfile");
$this->_redirectaddr = false;
unset($this->headers);
for($currentHeader = 0; $currentHeader < count($result_headers); $currentHeader++)
{
// if a header begins with Location: or URI:, set the redirect
if(preg_match("/^(Location: |URI: )/i",$result_headers[$currentHeader]))
{
@@ -1300,7 +1312,7 @@ class Snoopy
else
$this->_redirectaddr = $matches[2];
}
if(preg_match("|^HTTP/|",$result_headers[$currentHeader]))
$this->response_code = $result_headers[$currentHeader];
@@ -1308,10 +1320,10 @@ class Snoopy
}
// check if there is a a redirect meta tag
if(preg_match("'<meta[\s]*http-equiv[^>]*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match))
{
$this->_redirectaddr = $this->_expandlinks($match[1],$URI);
$this->_redirectaddr = $this->_expandlinks($match[1],$URI);
}
// have we hit our frame depth and is there frame src to fetch?
@@ -1329,7 +1341,7 @@ class Snoopy
$this->results = $results;
unlink("$headerfile");
return true;
}
@@ -1337,7 +1349,7 @@ class Snoopy
Function: setcookies()
Purpose: set cookies for a redirection
\*======================================================================*/
function setcookies()
{
for($x=0; $x<count($this->headers); $x++)
@@ -1347,7 +1359,7 @@ class Snoopy
}
}
/*======================================================================*\
Function: _check_timeout
Purpose: checks whether timeout has occurred
@@ -1371,13 +1383,13 @@ class Snoopy
Purpose: make a socket connection
Input: $fp file pointer
\*======================================================================*/
function _connect(&$fp)
{
if(!empty($this->proxy_host) && !empty($this->proxy_port))
{
$this->_isproxy = true;
$host = $this->proxy_host;
$port = $this->proxy_port;
}
@@ -1386,9 +1398,9 @@ class Snoopy
$host = $this->host;
$port = $this->port;
}
$this->status = 0;
if($fp = fsockopen(
$host,
$port,
@@ -1424,13 +1436,13 @@ class Snoopy
Purpose: disconnect a socket connection
Input: $fp file pointer
\*======================================================================*/
function _disconnect($fp)
{
return(fclose($fp));
}
/*======================================================================*\
Function: _prepare_post_body
Purpose: Prepare post body according to encoding type
@@ -1438,7 +1450,7 @@ class Snoopy
$formfiles - form upload files
Output: post body
\*======================================================================*/
function _prepare_post_body($formvars, $formfiles)
{
settype($formvars, "array");
@@ -1447,27 +1459,32 @@ class Snoopy
if (count($formvars) == 0 && count($formfiles) == 0)
return;
switch ($this->_submit_type) {
case "application/x-www-form-urlencoded":
reset($formvars);
while(list($key,$val) = each($formvars)) {
foreach($formvars as $key => $val)
{
if (is_array($val) || is_object($val)) {
while (list($cur_key, $cur_val) = each($val)) {
foreach($val as $cur_key => $cur_val)
{
$postdata .= urlencode($key)."[]=".urlencode($cur_val)."&";
}
} else
{
$postdata .= urlencode($key)."=".urlencode($val)."&";
}
}
break;
case "multipart/form-data":
$this->_mime_boundary = "Snoopy".md5(uniqid(microtime()));
reset($formvars);
while(list($key,$val) = each($formvars)) {
foreach($formvars as $key => $val)
{
if (is_array($val) || is_object($val)) {
while (list($cur_key, $cur_val) = each($val)) {
foreach($val as $cur_key => $cur_val) {
$postdata .= "--".$this->_mime_boundary."\r\n";
$postdata .= "Content-Disposition: form-data; name=\"$key\[\]\"\r\n\r\n";
$postdata .= "$cur_val\r\n";
@@ -1478,11 +1495,11 @@ class Snoopy
$postdata .= "$val\r\n";
}
}
reset($formfiles);
while (list($field_name, $file_names) = each($formfiles)) {
foreach($formfiles as $field_name => $file_names) {
settype($file_names, "array");
while (list(, $file_name) = each($file_names)) {
foreach($file_names as $file_name) {
if (!is_readable($file_name)) continue;
$fp = fopen($file_name, "r");
+2 -4
View File
@@ -108,8 +108,6 @@ class baseHTML
*/
static public function a($href = '', $title = '', $misc = '', $newline = true)
{
global $config;
if(strlen(trim($title)) == 0) $title = $href;
$newline = $newline ? "\n" : '';
@@ -491,7 +489,7 @@ class baseHTML
$gobackLink = "<a href='javascript:history.go(-1)' class='btn btn-back $class' $misc>{$label}</a>";
$tab = $_COOKIE['tab'];
$referer = isset($_SERVER['HTTP_REFERER']) ? strtolower($_SERVER['HTTP_REFERER']) : '';
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
$refererParts = parse_url($referer);
if($config->requestType == 'PATH_INFO' and empty($refererParts)) return $gobackLink;
@@ -504,7 +502,7 @@ class baseHTML
$gobackLink = isset($gobackList[$tab]) ? $gobackList[$tab] : '';
/* If the link of the referer is not the link of the current page or the link of the index, the cookie and gobackLink will be updated. */
if(!preg_match("/(m=|\/)(index|search|$currentModule)(&f=|-)(index|buildquery|$currentMethod)(&|-|\.)?/", $refererLink))
if(!preg_match("/(m=|\/)(index|search|$currentModule)(&f=|-)(index|buildquery|$currentMethod)(&|-|\.)?/", strtolower($refererLink)))
{
$gobackList[$tab] = $referer;
$gobackLink = $referer;
+1 -1
View File
@@ -136,7 +136,7 @@ class dingapi
$node['id'] = $deptID;
$node['pId'] = $parentID;
$node['name'] = $deptName;
if($parentID == 0) $node['open'] = true;
$node['open'] = true;
$tree[] = $node;
}
+54 -3
View File
@@ -52,17 +52,23 @@ class feishuapi
* @access public
* @return array
*/
public function getAllUsers()
public function getAllUsers($selectedDepts = '')
{
$selectedDepts = trim($selectedDepts);
if(empty($selectedDepts)) return array('result' => 'fail', 'message' => 'nodept');
set_time_limit(0);
$users = array();
$depts = $this->getDepts();
$depts = explode(',', $selectedDepts);
$depts = array_flip($depts);
unset($depts[1]);
if(empty($depts)) return array('result' => 'fail', 'message' => 'nodept');
/* Get users by dept. */
foreach($depts as $deptID => $count)
{
if($deptID and empty($count)) continue;
if(empty($deptID)) continue;
$pageToken = '';
while(true)
@@ -138,6 +144,46 @@ class feishuapi
return $depts;
}
/**
* Get department tree structure.
*
* @access public
* @return array
*/
public function getDeptTree()
{
$depts = array('result' => 'success', 'data' => array());
/* Gets the enterprise name. */
$response = $this->queryAPI($this->apiUrl . "tenant/v2/tenant/query", '', array(CURLOPT_CUSTOMREQUEST => "GET"));
$company = array('id' => '1', 'pId' => '0', 'name' => $response->data->tenant->name, 'open' => 1);
$data = array($company);
/* Get depts by parent dept. */
$pageToken = '';
while(true)
{
$response = $this->queryAPI($this->apiUrl . "contact/v3/departments?parent_department_id=0" . ($pageToken ? "&page_token={$pageToken}" : '') . "&fetch_child=true", '', array(CURLOPT_CUSTOMREQUEST => "GET"));
if(isset($response->data->items))
{
foreach($response->data->items as $key => $dept)
{
$key ++;
$data[$key]['id'] = $dept->open_department_id;
$data[$key]['pId'] = empty($dept->parent_department_id) ? 1 : $dept->parent_department_id;
$data[$key]['name'] = $dept->name;
$data[$key]['open'] = 1;
}
}
if(!isset($response->data->page_token)) break;
$pageToken = $response->data->page_token;
}
$depts['data'] = $data;
return $depts;
}
/**
* Send message
*
@@ -179,6 +225,11 @@ class feishuapi
if(empty($response)) $this->errors = $errors;
if(isset($response->code)) $this->errors[$response->code] = "Errcode:{$response->code}, Errmsg:{$response->msg}";
if(!empty($this->errors))
{
echo js::error(array_shift($this->errors));
die(js::locate(helper::createLink('webhook', 'browse')));
}
return false;
}
+16 -2
View File
@@ -229,7 +229,7 @@ class html extends baseHTML
/**
* Create user avatar.
*
* @param string|object|array $user User object or user avatar url or user account
* @param string|object|array $user User object or user account
* @param string|int $size Avatar size, can be a number or preset sizes: "xs", "sm", "", "lg", "xl", default is ""
* @param string $className Avatar element class name, default is "avatar-circle"
* @param string $attrib Extra attributes on avatar element
@@ -248,7 +248,6 @@ class html extends baseHTML
if(is_string($user))
{
$userObj->account = $user;
if(strlen($user) > 1) $userObj->avatar = $user;
$user = $userObj;
}
elseif(is_array($user))
@@ -316,6 +315,21 @@ class html extends baseHTML
{
return html::avatar($user, 'lg', $className, $attrib, $tag);
}
/**
* Create a progress ring.
*
* @param int progress Progress value, 0 ~ 100
* @static
* @access public
* @return string
*/
static public function ring($progress)
{
$progressVal = max(0, min(100, round($progress)));
$ringPosition = ceil($progressVal / 2) * 24;
return "<div class='ring' style='background-position-x: -{$ringPosition}px'><span>{$progressVal}</span></div>";
}
}
/**
+566
View File
@@ -0,0 +1,566 @@
<?php
/*
* This file is part of the HTMLUP package.
*
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
* <https://github.com/adhocore>
*
* Licensed under MIT license.
*/
trait HtmlHelper
{
public function escape($input)
{
return \htmlspecialchars($input);
}
public function h($level, $line)
{
if (\is_string($level)) {
$level = \trim($level, '- ') === '' ? 2 : 1;
}
if ($level < 7) {
return "\n<h{$level}>" . \ltrim(\ltrim($line, '# ')) . "</h{$level}>";
}
return '';
}
public function hr($prevLine, $line)
{
if ($prevLine === '' && \preg_match(BlockElementParser::RE_MD_RULE, $line)) {
return "\n<hr />";
}
}
public function codeStart($lang)
{
$lang = isset($lang[1])
? ' class="language-' . $lang[1] . '"'
: '';
return "\n<pre><code{$lang}>";
}
public function codeLine($line, $isBlock, $indentLen = 4)
{
$code = "\n"; // @todo: donot use \n for first line
$code .= $isBlock ? $line : \substr($line, $indentLen);
return $code;
}
public function tableStart($line, $delim = '|')
{
$table = "<table>\n<thead>\n<tr>\n";
foreach (\explode($delim, \trim($line, $delim)) as $hdr) {
$table .= '<th>' . \trim($hdr) . "</th>\n";
}
$table .= "</tr>\n</thead>\n<tbody>\n";
return $table;
}
public function tableRow($line, $colCount, $delim = '|')
{
$row = "<tr>\n";
foreach (\explode($delim, \trim($line, $delim)) as $i => $col) {
if ($i > $colCount) {
break;
}
$col = \trim($col);
$row .= "<td>{$col}</td>\n";
}
$row .= "</tr>\n";
return $row;
}
}
abstract class BlockElementParser
{
use HtmlHelper;
const RE_MD_QUOTE = '~^\s*(>+)\s+~';
const RE_RAW = '/^<\/?\w.*?\/?>/';
const RE_MD_SETEXT = '~^\s*(={3,}|-{3,})\s*$~';
const RE_MD_CODE = '/^```\s*([\w-]+)?/';
const RE_MD_RULE = '~^(_{3,}|\*{3,}|\-{3,})$~';
const RE_MD_TCOL = '~(\|\s*\:)?\s*\-{3,}\s*(\:\s*\|)?~';
const RE_MD_OL = '/^\d+\. /';
protected $lines = [];
protected $stackList = [];
protected $stackBlock = [];
protected $stackTable = [];
protected $pointer = -1;
protected $listLevel = 0;
protected $quoteLevel = 0;
protected $indent = 0;
protected $nextIndent = 0;
protected $indentLen = 4;
protected $indentStr = ' ';
protected $line = '';
protected $trimmedLine = '';
protected $prevLine = '';
protected $trimmedPrevLine = '';
protected $nextLine = '';
protected $trimmedNextLine = '';
protected $markup = '';
protected $inList = \false;
protected $inQuote = \false;
protected $inPara = \false;
protected $inHtml = \false;
protected $inTable = \false;
protected function parseBlockElements()
{
while (isset($this->lines[++$this->pointer])) {
$this->init();
if ($this->flush() || $this->raw()) {
continue;
}
$this->quote();
if (($block = $this->isBlock()) || $this->inList) {
$this->markup .= $block ? '' : $this->trimmedLine;
continue;
}
$this->table() || $this->paragraph();
}
}
protected function isBlock()
{
return $this->atx() || $this->setext() || $this->code() || $this->rule() || $this->listt();
}
protected function atx()
{
if (\substr($this->trimmedLine, 0, 1) === '#') {
$level = \strlen($this->trimmedLine) - \strlen(\ltrim($this->trimmedLine, '#'));
$head = $this->h($level, $this->trimmedLine);
$this->markup .= $head;
return (bool) $head;
}
}
protected function setext()
{
if (\preg_match(static::RE_MD_SETEXT, $this->nextLine)) {
$this->markup .= $this->h($this->nextLine, $this->trimmedLine);
$this->pointer++;
return \true;
}
}
protected function code()
{
$isShifted = ($this->indent - $this->nextIndent) >= $this->indentLen;
$codeBlock = \preg_match(static::RE_MD_CODE, $this->line, $codeMatch);
if ($codeBlock || (!$this->inList && !$this->inQuote && $isShifted)) {
$this->markup .= $this->codeStart($codeMatch);
if (!$codeBlock) {
$this->markup .= $this->escape(\substr($this->line, $this->indentLen));
}
$this->codeInternal($codeBlock);
$this->pointer++;
$this->markup .= '</code></pre>';
return \true;
}
}
private function codeInternal($codeBlock)
{
while (isset($this->lines[$this->pointer + 1])) {
$this->line = $this->escape($this->lines[$this->pointer + 1]);
if (($codeBlock && \substr(\ltrim($this->line), 0, 3) !== '```')
|| \strpos($this->line, $this->indentStr) === 0
) {
$this->markup .= $this->codeLine($this->line, $codeBlock, $this->indentLen);
$this->pointer++;
continue;
}
break;
}
}
protected function rule()
{
$this->markup .= $hr = $this->hr($this->trimmedPrevLine, $this->trimmedLine);
return (bool) $hr;
}
protected function listt()
{
$isUl = \in_array(\substr($this->trimmedLine, 0, 2), ['- ', '* ', '+ ']);
if ($isUl || \preg_match(static::RE_MD_OL, $this->trimmedLine)) {
$wrapper = $isUl ? 'ul' : 'ol';
if (!$this->inList) {
$this->stackList[] = "</$wrapper>";
$this->markup .= "\n<$wrapper>\n";
$this->inList = \true;
$this->listLevel++;
}
$this->markup .= '<li>' . \ltrim($this->trimmedLine, '+-*0123456789. ');
$this->listInternal();
return \true;
}
}
private function listInternal()
{
$isUl = \in_array(\substr($this->trimmedNextLine, 0, 2), ['- ', '* ', '+ ']);
if ($isUl || \preg_match(static::RE_MD_OL, $this->trimmedNextLine)) {
$wrapper = $isUl ? 'ul' : 'ol';
if ($this->nextIndent > $this->indent) {
$this->stackList[] = "</li>\n";
$this->stackList[] = "</$wrapper>";
$this->markup .= "\n<$wrapper>\n";
$this->listLevel++;
} else {
$this->markup .= "</li>\n";
}
if ($this->nextIndent < $this->indent) {
$shift = \intval(($this->indent - $this->nextIndent) / $this->indentLen);
while ($shift--) {
$this->markup .= \array_pop($this->stackList);
if ($this->listLevel > 2) {
$this->markup .= \array_pop($this->stackList);
}
}
}
} else {
$this->markup .= "</li>\n";
}
}
protected function table()
{
static $headerCount = 0;
if (!$this->inTable) {
$headerCount = \substr_count(\trim($this->trimmedLine, '|'), '|');
return $this->tableInternal($headerCount);
}
$this->markup .= $this->tableRow($this->trimmedLine, $headerCount);
if (empty($this->trimmedNextLine)
|| !\substr_count(\trim($this->trimmedNextLine, '|'), '|')
) {
$headerCount = 0;
$this->inTable = \false;
$this->stackTable[] = "</tbody>\n</table>";
}
return \true;
}
private function tableInternal($headerCount)
{
$columnCount = \preg_match_all(static::RE_MD_TCOL, \trim($this->trimmedNextLine, '|'));
if ($headerCount > 0 && $headerCount <= $columnCount) {
$this->pointer++;
$this->inTable = \true;
$this->markup .= $this->tableStart($this->trimmedLine);
return \true;
}
}
}
class SpanElementParser
{
use HtmlHelper;
const RE_URL = '~<(https?:[\/]{2}[^\s]+?)>~';
const RE_EMAIL = '~<(\S+?@\S+?)>~';
const RE_MD_IMG = '~!\[(.+?)\]\s*\((.+?)\s*(".+?")?\)~';
const RE_MD_URL = '~\[(.+?)\]\s*\((.+?)\s*(".+?")?\)~';
const RE_MD_FONT = '!(\*{1,2}|_{1,2}|`|~~)(.+?)\\1!';
public function parse($markup)
{
return $this->spans(
$this->anchors(
$this->links($markup)
)
);
}
protected function links($markup)
{
$markup = $this->emails($markup);
return \preg_replace(
static::RE_URL,
'<a href="$1">$1</a>',
$markup
);
}
protected function emails($markup)
{
return \preg_replace(
static::RE_EMAIL,
'<a href="mailto:$1">$1</a>',
$markup
);
}
protected function anchors($markup)
{
$markup = $this->images($markup);
return \preg_replace_callback(static::RE_MD_URL, function ($a) {
$title = isset($a[3]) ? " title={$a[3]} " : '';
return "<a href=\"{$a[2]}\"{$title}>{$a[1]}</a>";
}, $markup);
}
protected function images($markup)
{
return \preg_replace_callback(static::RE_MD_IMG, function ($img) {
$title = isset($img[3]) ? " title={$img[3]} " : '';
$alt = $img[1] ? " alt=\"{$img[1]}\" " : '';
return "<img src=\"{$img[2]}\"{$title}{$alt}/>";
}, $markup);
}
protected function spans($markup)
{
// em/code/strong/del
return \preg_replace_callback(static::RE_MD_FONT, function ($em) {
switch (\substr($em[1], 0, 2)) {
case '**':
case '__':
$tag = 'strong';
break;
case '~~':
$tag = 'del';
break;
case $em[1] === '*':
case $em[1] === '_':
$tag = 'em';
break;
default:
$tag = 'code';
$em[2] = $this->escape($em[2]);
}
return "<$tag>{$em[2]}</$tag>";
}, $markup);
}
}
/**
* HtmlUp - A **lightweight** && **fast** `markdown` to HTML Parser.
*
* Supports most of the markdown specs except deep nested elements.
* Check readme.md for the details of its features && limitations.
*
* @author adhocore | Jitendra Adhikari <jiten.adhikary@gmail.com>
* @copyright (c) 2014 Jitendra Adhikari
*/
class htmlup extends BlockElementParser
{
/**
* Constructor.
*
* @param string $markdown
* @param int $indentWidth
*/
public function __construct($markdown = \null, $indentWidth = 4)
{
$this->scan($markdown, $indentWidth);
}
protected function scan($markdown, $indentWidth = 4)
{
if ('' === \trim($markdown)) {
return;
}
$this->indentLen = $indentWidth == 2 ? 2 : 4;
$this->indentStr = $indentWidth == 2 ? ' ' : ' ';
// Normalize whitespaces
$markdown = \str_replace("\t", $this->indentStr, $markdown);
$markdown = \str_replace(["\r\n", "\r"], "\n", $markdown);
$this->lines = \array_merge([''], \explode("\n", $markdown), ['']);
}
public function __toString()
{
return $this->parse();
}
/**
* Parse markdown.
*
* @param string $markdown
* @param int $indentWidth
*
* @return string
*/
public function parse($markdown = \null, $indentWidth = 4)
{
if (\null !== $markdown) {
$this->reset(\true);
$this->scan($markdown, $indentWidth);
}
if (empty($this->lines)) {
return '';
}
$this->parseBlockElements();
return (new SpanElementParser)->parse($this->markup);
}
protected function init()
{
list($this->prevLine, $this->trimmedPrevLine) = [$this->line, $this->trimmedLine];
$this->line = $this->lines[$this->pointer];
$this->trimmedLine = \trim($this->line);
$this->indent = \strlen($this->line) - \strlen(\ltrim($this->line));
$this->nextLine = isset($this->lines[$this->pointer + 1])
? $this->lines[$this->pointer + 1]
: '';
$this->trimmedNextLine = \trim($this->nextLine);
$this->nextIndent = \strlen($this->nextLine) - \strlen(\ltrim($this->nextLine));
}
protected function reset($all = \false)
{
$except = $all ? [] : \array_flip(['lines', 'pointer', 'markup', 'indentStr', 'indentLen']);
// Reset all current values.
foreach (\get_class_vars(__CLASS__) as $prop => $value) {
isset($except[$prop]) || $this->{$prop} = $value;
}
}
protected function flush()
{
if ('' !== $this->trimmedLine) {
return \false;
}
while (!empty($this->stackList)) {
$this->markup .= \array_pop($this->stackList);
}
while (!empty($this->stackBlock)) {
$this->markup .= \array_pop($this->stackBlock);
}
while (!empty($this->stackTable)) {
$this->markup .= \array_pop($this->stackTable);
}
$this->markup .= "\n";
$this->reset(\false);
return \true;
}
protected function raw()
{
if ($this->inHtml || \preg_match(static::RE_RAW, $this->trimmedLine)) {
$this->markup .= "\n$this->line";
if (!$this->inHtml && empty($this->lines[$this->pointer - 1])) {
$this->inHtml = \true;
}
return \true;
}
}
protected function quote()
{
if (\preg_match(static::RE_MD_QUOTE, $this->line, $quoteMatch)) {
$this->line = \substr($this->line, \strlen($quoteMatch[0]));
$this->trimmedLine = \trim($this->line);
if (!$this->inQuote || $this->quoteLevel < \strlen($quoteMatch[1])) {
$this->markup .= "\n<blockquote>";
$this->stackBlock[] = "\n</blockquote>";
$this->quoteLevel++;
}
return $this->inQuote = \true;
}
}
protected function paragraph()
{
$this->markup .= $this->inPara ? "\n<br />" : "\n<p>";
$this->markup .= $this->trimmedLine;
if (empty($this->trimmedNextLine)) {
$this->markup .= '</p>';
$this->inPara = \false;
} else {
$this->inPara = \true;
}
}
}
-29
View File
@@ -1,29 +0,0 @@
Software License Agreement (BSD License)
Copyright (c) 2015, SegmentFault
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name of schillmania.com nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission from schillmania.com.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013-2018 Emanuil Rusev, erusev.com
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
<?php
/**
* This is a stub include that automatically configures the include path.
*/
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() );
require_once 'HTMLPurifier/Bootstrap.php';
require_once 'HTMLPurifier.autoload.php';
// vim: et sw=4 sts=4

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