diff --git a/api/v1/entries/projectissue.php b/api/v1/entries/productissue.php
similarity index 96%
rename from api/v1/entries/projectissue.php
rename to api/v1/entries/productissue.php
index 2e88f2bae9..1546897052 100644
--- a/api/v1/entries/projectissue.php
+++ b/api/v1/entries/productissue.php
@@ -1,18 +1,17 @@
loadModel('entry');
- $this->setParam('timeFormat', 'utc');
$idParams = explode('-', $issueID);
if(count($idParams) < 2) $this->sendError(400, 'The id of issue is wrong.');
diff --git a/api/v1/entries/projectissues.php b/api/v1/entries/productissues.php
similarity index 66%
rename from api/v1/entries/projectissues.php
rename to api/v1/entries/productissues.php
index 8665b880ff..a8c24b65c5 100644
--- a/api/v1/entries/projectissues.php
+++ b/api/v1/entries/productissues.php
@@ -1,19 +1,17 @@
sendError(400, 'The project_id is not supported');
-
- $this->setParam('timeFormat', 'utc');
+ if(!is_numeric($productID)) $this->sendError(400, 'The product_id is not supported');
$taskFields = 'id,status';
$taskStatus = array('' => '');
@@ -32,12 +30,14 @@ class projectIssuesEntry extends entry
$productID = (int)$productID;
$status = $this->param('status', '');
- $label = $this->param('label', '');
$search = $this->param('search', '');
$page = intval($this->param('page', 1));
$limit = intval($this->param('limit', 20));
$order = $this->param('order', 'openedDate_desc');
+ $labels = $this->param('labels', '');
+ $labels = $labels ? explode(',', $labels) : array();
+
$orderParams = explode('_', $order);
$order = $orderParams[0];
$sort = (isset($orderParams[1]) and strtolower($orderParams[1]) == 'asc') ? 'asc' : 'desc';
@@ -68,35 +68,75 @@ class projectIssuesEntry extends entry
$issues = array();
- $executions = $this->dao->select('project')->from(TABLE_PROJECTPRODUCT)->where('product')->eq($productID)->fetchPairs();
- $tasks = $this->dao->select($taskFields)->from(TABLE_TASK)->where('execution')->in(array_values($executions))
- ->beginIF($search)->andWhere('name')->like("%$search%")->fi()
- ->beginIF($label)->andWhere('type')->eq($label)->fi()
- ->beginIF($status)->andWhere('status')->in($taskStatus[$status])->fi()
- ->andWhere('deleted')->eq(0)
- ->fetchAll();
- foreach($tasks as $task) $issues[] = array('id' => $task->id, 'type' => 'task', 'order' => $task->$order, 'status' => $this->getKey($task->status, $taskStatus));
+ $storyFilter = array();
+ $bugFilter = array();
+ $taskFilter = array();
- $stories = $this->dao->select($storyFields)->from(TABLE_STORY)->where('product')->eq($productID)
- ->beginIF($search)->andWhere('title')->like("%$search%")->fi()
- ->beginIF($label)->andWhere('type')->eq($label)->fi()
- ->beginIF($status)->andWhere('status')->in($storyStatus[$status])->fi()
- ->andWhere('deleted')->eq(0)
- ->fetchAll();
- foreach($stories as $story)
+ if(empty($labels))
{
- $issues[] = array('id' => $story->id, 'type' => 'story', 'order' => $story->$order, 'status' => $this->getKey($story->status, $storyStatus));
+ $storyFilter[] = 'all';
+ $bugFilter[] = 'all';
+ $taskFilter[] = 'all';
+ }
+ else
+ {
+ $this->app->loadLang('story');
+ $this->app->loadLang('task');
+ $this->app->loadLang('bug');
+
+ $storyTypeMap = array_flip($this->app->lang->story->categoryList);
+ $taskTypeMap = array_flip($this->app->lang->task->typeList);
+ $bugTypeMap = array_flip($this->app->lang->bug->typeList);
+ foreach($labels as $label)
+ {
+ if($label == $this->app->lang->story->common) $storyFilter = array('all');
+ if(isset($storyTypeMap[$label]) and $storyFilter != array('all')) $storyFilter[] = $storyTypeMap[$label];
+
+ if($label == $this->app->lang->task->common) $taskFilter = array('all');
+ if(isset($taskTypeMap[$label]) and $taskFilter != array('all')) $taskFilter[] = $taskTypeMap[$label];
+
+ if($label == $this->app->lang->bug->common) $bugFilter = array('all');
+ if(isset($bugTypeMap[$label]) and $bugFilter != array('all')) $bugFilter[] = $bugTypeMap[$label];
+ }
+ }
+ $storyFilter = implode(',', $storyFilter);
+ $taskFilter = implode(',', $taskFilter);
+ $bugFilter = implode(',', $bugFilter);
+
+ $executions = $this->dao->select('project')->from(TABLE_PROJECTPRODUCT)->where('product')->eq($productID)->fetchPairs();
+ if($taskFilter)
+ {
+ $tasks = $this->dao->select($taskFields)->from(TABLE_TASK)->where('execution')->in(array_values($executions))
+ ->beginIF($search)->andWhere('name')->like("%$search%")->fi()
+ ->beginIF($status)->andWhere('status')->in($taskStatus[$status])->fi()
+ ->beginIF($taskFilter != 'all')->andWhere('type')->in($taskFilter)->fi()
+ ->andWhere('deleted')->eq(0)
+ ->fetchAll();
+ foreach($tasks as $task) $issues[] = array('id' => $task->id, 'type' => 'task', 'order' => $task->$order, 'status' => $this->getKey($task->status, $taskStatus));
}
- $bugs = $this->dao->select($bugFields)->from(TABLE_BUG)->where('product')->eq($productID)
- ->beginIF($search)->andWhere('title')->like("%$search%")->fi()
- ->beginIF($label)->andWhere('type')->eq($label)->fi()
- ->beginIF($status)->andWhere('status')->in($bugStatus[$status])->fi()
- ->andWhere('deleted')->eq(0)
- ->fetchAll();
- foreach($bugs as $bug)
+ if($storyFilter)
{
- $issues[] = array('id' => $bug->id, 'type' => 'bug', 'order' => $bug->$order, 'status' => $this->getKey($bug->status, $bugStatus));
+ $stories = $this->dao->select($storyFields)->from(TABLE_STORY)
+ ->where('product')->eq($productID)
+ ->beginIF($search)->andWhere('title')->like("%$search%")->fi()
+ ->beginIF($status)->andWhere('status')->in($storyStatus[$status])->fi()
+ ->beginIF($storyFilter != 'all')->andWhere('category')->in($storyFilter)->fi()
+ ->andWhere('deleted')->eq(0)
+ ->fetchAll();
+ foreach($stories as $story) $issues[] = array('id' => $story->id, 'type' => 'story', 'order' => $story->$order, 'status' => $this->getKey($story->status, $storyStatus));
+ }
+
+ if($bugFilter)
+ {
+ $bugs = $this->dao->select($bugFields)->from(TABLE_BUG)
+ ->where('product')->eq($productID)
+ ->beginIF($search)->andWhere('title')->like("%$search%")->fi()
+ ->beginIF($status)->andWhere('status')->in($bugStatus[$status])->fi()
+ ->beginIF($bugFilter != 'all')->andWhere('type')->in($bugFilter)->fi()
+ ->andWhere('deleted')->eq(0)
+ ->fetchAll();
+ foreach($bugs as $bug) $issues[] = array('id' => $bug->id, 'type' => 'bug', 'order' => $bug->$order, 'status' => $this->getKey($bug->status, $bugStatus));
}
array_multisort(array_column($issues, 'order'), $sort == 'asc' ? SORT_ASC : SORT_DESC, $issues);
@@ -118,8 +158,8 @@ class projectIssuesEntry extends entry
*/
public function processIssues($issues)
{
- $this->app->loadLang('task');
$this->app->loadLang('story');
+ $this->app->loadLang('task');
$this->app->loadLang('bug');
$this->loadModel('entry');
diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php
index d0d886679d..f0480dce7d 100644
--- a/api/v1/entries/projects.php
+++ b/api/v1/entries/projects.php
@@ -30,6 +30,7 @@ class projectsEntry extends entry
return $this->sendError(400, $data->message);
}
+ // TODO There is no handle for 401.
return $this->sendError(400, 'error');
}
diff --git a/config/routes.php b/config/routes.php
index 0dab867b89..a18c4c579f 100644
--- a/config/routes.php
+++ b/config/routes.php
@@ -38,7 +38,7 @@ $routes['/my'] = 'my';
$routes['/programs'] = 'programs';
$routes['/programs/:id'] = 'program';
-$routes['/issues/:issueID'] = 'projectIssue';
-$routes['/projects/:projectID/issues'] = 'projectIssues';
+$routes['/issues/:issueID'] = 'productIssue';
+$routes['/products/:productID/issues'] = 'productIssues';
$config->routes = $routes;
diff --git a/config/zentaopms.php b/config/zentaopms.php
index 0fbc294f6b..fe193d98ca 100644
--- a/config/zentaopms.php
+++ b/config/zentaopms.php
@@ -98,8 +98,8 @@ $config->hourPointCommonList['vi'][0] = 'giờ';
$config->hourPointCommonList['vi'][1] = 'điểm';
$config->hourPointCommonList['vi'][2] = 'function point';
-$config->manualUrl['home'] = 'https://www.zentao.net/book/zentaopmshelp.html?fullScreen=zentao&theme=' . $_COOKIE['theme'];
-$config->manualUrl['int'] = 'https://www.zentao.pm/book/zentaomanual/zentao-installation-11.html?fullScreen=zentao&theme=' . $_COOKIE['theme'];
+$config->manualUrl['home'] = 'https://www.zentao.net/book/zentaopmshelp.html?fullScreen=zentao';
+$config->manualUrl['int'] = 'https://www.zentao.pm/book/zentaomanual/zentao-installation-11.html?fullScreen=zentao';
/* Supported charsets. */
$config->charsets['zh-cn']['utf-8'] = 'UTF-8';
diff --git a/framework/api/entry.class.php b/framework/api/entry.class.php
index f48391751a..67cd73657b 100644
--- a/framework/api/entry.class.php
+++ b/framework/api/entry.class.php
@@ -496,7 +496,7 @@ class baseEntry
switch($type)
{
case 'time':
- $timeFormat = $this->param('timeFormat', '');
+ $timeFormat = $this->param('timeFormat', 'utc');
if($timeFormat == 'utc')
{
if(!$value or $value == '0000-00-00 00:00:00') return null;
diff --git a/module/action/model.php b/module/action/model.php
index bc601a6d23..718d885972 100755
--- a/module/action/model.php
+++ b/module/action/model.php
@@ -965,7 +965,7 @@ class actionModel extends model
$objectName = array();
$objectProject = array();
- if(strpos($this->config->action->needGetProjectType, $objectType) !== false)
+ if(strpos(",{$this->config->action->needGetProjectType},", ",{$objectType},") !== false)
{
$objectInfo = $this->dao->select("id, project, $field AS name")->from($table)->where('id')->in($objectIds)->fetchAll();
foreach($objectInfo as $object)
@@ -1128,7 +1128,7 @@ class actionModel extends model
elseif($action->objectType == 'team')
{
$action->objectLink = '';
- if($action->project) $action->objectLink = helper::createLink('project', 'manageMembers', 'projectID=' . $action->project);
+ if($action->project) $action->objectLink = helper::createLink('project', 'team', 'projectID=' . $action->project);
if($action->execution) $action->objectLink = helper::createLink('execution', 'team', 'executionID=' . $action->execution);
$action->objectLabel = zget($this->lang->action->objectTypes, $action->objectLabel);
}
diff --git a/module/common/lang/menu.php b/module/common/lang/menu.php
index 4cbb6a8d31..ce273b17eb 100644
--- a/module/common/lang/menu.php
+++ b/module/common/lang/menu.php
@@ -190,7 +190,7 @@ $lang->scrum->menu->devops = array('link' => "{$lang->repo->common}|repo|brow
$lang->scrum->menu->build = array('link' => "{$lang->build->common}|project|build|project=%s");
$lang->scrum->menu->release = array('link' => "{$lang->release->common}|projectrelease|browse|project=%s", 'subModule' => 'projectrelease');
$lang->scrum->menu->dynamic = array('link' => "$lang->dynamic|project|dynamic|project=%s");
-$lang->scrum->menu->settings = array('link' => "$lang->settings|project|view|project=%s", 'subModule' => 'stakeholder', 'alias' => 'edit,manageproducts,group,managemembers,manageview,managepriv,whitelist,addwhitelist');
+$lang->scrum->menu->settings = array('link' => "$lang->settings|project|view|project=%s", 'subModule' => 'stakeholder', 'alias' => 'edit,manageproducts,group,managemembers,manageview,managepriv,whitelist,addwhitelist,team');
$lang->scrum->dividerMenu = ',execution,programplan,doc,settings,';
@@ -218,7 +218,7 @@ $lang->scrum->menu->qa['subMenu']->testreport = array('link' => "{$lang->testrep
$lang->scrum->menu->settings['subMenu'] = new stdclass();
$lang->scrum->menu->settings['subMenu']->view = array('link' => "$lang->overview|project|view|project=%s", 'alias' => 'edit');
$lang->scrum->menu->settings['subMenu']->products = array('link' => "{$lang->product->common}|project|manageProducts|project=%s", 'alias' => 'manageproducts');
-$lang->scrum->menu->settings['subMenu']->members = array('link' => "{$lang->team->common}|project|manageMembers|project=%s", 'alias' => 'managemembers');
+$lang->scrum->menu->settings['subMenu']->members = array('link' => "{$lang->team->common}|project|team|project=%s", 'alias' => 'managemembers,team');
$lang->scrum->menu->settings['subMenu']->whitelist = array('link' => "{$lang->whitelist}|project|whitelist|project=%s", 'subModule' => 'personnel');
$lang->scrum->menu->settings['subMenu']->stakeholder = array('link' => "{$lang->stakeholder->common}|stakeholder|browse|project=%s", 'subModule' => 'stakeholder');
$lang->scrum->menu->settings['subMenu']->group = array('link' => "{$lang->priv}|project|group|project=%s", 'alias' => 'group,manageview,managepriv');
diff --git a/module/common/model.php b/module/common/model.php
index 7906e05691..d33a76a6fb 100644
--- a/module/common/model.php
+++ b/module/common/model.php
@@ -356,7 +356,7 @@ class commonModel extends model
echo "