This commit is contained in:
holan20180123
2021-08-11 17:00:14 +08:00
39 changed files with 511 additions and 155 deletions
@@ -1,18 +1,17 @@
<?php
/**
* 禅道API的project issues资源类
* 禅道API的product issue资源类
* 版本V1
* 目前适用于Gitlab
*
* The project issues entry point of zentaopms
* The product issue entry point of zentaopms
* Version 1
*/
class projectIssueEntry extends entry
class productIssueEntry extends entry
{
public function get($issueID)
{
$this->loadModel('entry');
$this->setParam('timeFormat', 'utc');
$idParams = explode('-', $issueID);
if(count($idParams) < 2) $this->sendError(400, 'The id of issue is wrong.');
@@ -1,19 +1,17 @@
<?php
/**
* 禅道API的project issues资源类
* 禅道API的product issues资源类
* 版本V1
* 目前适用于Gitlab
*
* The project issues entry point of zentaopms
* The product issues entry point of zentaopms
* Version 1
*/
class projectIssuesEntry extends entry
class productIssuesEntry extends entry
{
public function get($productID)
{
if(!is_numeric($productID)) $this->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');
+1
View File
@@ -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');
}
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -98,8 +98,8 @@ $config->hourPointCommonList['vi'][0] = 'giờ';
$config->hourPointCommonList['vi'][1] = 'điểm';
$config->hourPointCommonList['vi'][2] = 'function point';
$config->manualUrl['home'] = 'https://www.zentao.net/book/zentaopmshelp.html?fullScreen=zentao&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';
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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);
}
+2 -2
View File
@@ -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');
+1 -1
View File
@@ -356,7 +356,7 @@ class commonModel extends model
echo "<ul class='dropdown-menu pull-left'>";
//if($config->global->flow == 'full' && !commonModel::isTutorialMode() and $app->user->account != 'guest') echo '<li>' . html::a(helper::createLink('tutorial', 'start'), $lang->noviceTutorial, '', "class='iframe' data-class-name='modal-inverse' data-width='800' data-headerless='true' data-backdrop='true' data-keyboard='true'") . "</li>";
$manualUrl = (!empty($config->isINT)) ? $config->manualUrl['int'] : $config->manualUrl['home'];
$manualUrl = ((!empty($config->isINT)) ? $config->manualUrl['int'] : $config->manualUrl['home']) . '&theme=' . $_COOKIE['theme'];
echo '<li>' . html::a($manualUrl, $lang->manual, '', "class='open-in-app' id='helpLink' data-app='help'") . '</li>';
echo '<li>' . html::a(helper::createLink('misc', 'changeLog'), $lang->changeLog, '', "class='iframe' data-width='800' data-headerless='true' data-backdrop='true' data-keyboard='true'") . '</li>';
+23
View File
@@ -1340,6 +1340,7 @@ class execution extends control
$this->view->name = $name;
$this->view->code = $code;
$this->view->team = $team;
$this->view->teams = array(0 => '') + $this->execution->getTeamPairsByProject((int)$projectID);
$this->view->allProjects = array(0 => '') + $this->project->getPairsByModel();
$this->view->executionID = $executionID;
$this->view->productID = $productID;
@@ -2635,6 +2636,28 @@ class execution extends control
}
}
/**
* AJAX: get team members by projectID/executionID.
*
* @param int $objectID
* @access public
* @return string
*/
public function ajaxGetTeamMembers($objectID)
{
$type = 'execution';
if($this->config->systemMode == 'new')
{
$type = $this->dao->findById($objectID)->from(TABLE_PROJECT)->fetch('type');
$type = $type == 'project' ? $type : 'execution';
}
$users = $this->loadModel('user')->getPairs('nodeleted|noclosed');
$members = $this->user->getTeamMemberPairs($objectID, $type);
die(html::select('teamMembers[]', $users, array_keys($members), "class='form-control chosen' multiple"));
}
/**
* When create a execution, help the user.
*
+12
View File
@@ -42,6 +42,18 @@ $(function()
};
adjustMainCol();
$(window).on('resize', adjustMainCol);
$('#teams').change(function()
{
var objectID = $(this).val();
$.get(createLink('execution', 'ajaxGetTeamMembers', 'objectID=' + objectID), function(data)
{
$('#teamMembers').parent().html(data);
$('#teamMembers').chosen();
});
})
$('#teams').change();
});
function showLifeTimeTips()
+3
View File
@@ -100,6 +100,9 @@ $lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . '
$lang->execution->noTeam = 'No team members at the moment';
$lang->execution->or = ' or ';
if($this->config->systemMode == 'new') $lang->execution->copyTeamTip = "select Project/{$lang->execution->common} to copy its members";
if($this->config->systemMode == 'classic') $lang->execution->copyTeamTip = "select Project/{$lang->executionCommon} to copy its members";
$lang->execution->start = 'Start';
$lang->execution->activate = 'Aktivieren';
$lang->execution->putoff = 'Zurückstellen';
+3
View File
@@ -101,6 +101,9 @@ $lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . '
$lang->execution->noTeam = 'No team members at the moment';
$lang->execution->or = ' or ';
if($this->config->systemMode == 'new') $lang->execution->copyTeamTip = "select Project/{$lang->execution->common} to copy its members";
if($this->config->systemMode == 'classic') $lang->execution->copyTeamTip = "select Project/{$lang->executionCommon} to copy its members";
$lang->execution->start = 'Start';
$lang->execution->activate = 'Activate';
$lang->execution->putoff = 'Delay';
+3
View File
@@ -100,6 +100,9 @@ $lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . '
$lang->execution->noTeam = 'No team members at the moment';
$lang->execution->or = ' or ';
if($this->config->systemMode == 'new') $lang->execution->copyTeamTip = "select Project/{$lang->execution->common} to copy its members";
if($this->config->systemMode == 'classic') $lang->execution->copyTeamTip = "select Project/{$lang->executionCommon} to copy its members";
$lang->execution->start = 'Démarrer';
$lang->execution->activate = 'Activer';
$lang->execution->putoff = 'Ajourner';
+3
View File
@@ -101,6 +101,9 @@ $lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . '
$lang->execution->noTeam = 'No team members at the moment';
$lang->execution->or = ' or ';
if($this->config->systemMode == 'new') $lang->execution->copyTeamTip = "select Project/{$lang->execution->common} to copy its members";
if($this->config->systemMode == 'classic') $lang->execution->copyTeamTip = "select Project/{$lang->executionCommon} to copy its members";
$lang->execution->start = 'Bắt đầu';
$lang->execution->activate = 'Kích hoạt';
$lang->execution->putoff = 'Tạm ngưng';
+3
View File
@@ -101,6 +101,9 @@ $lang->execution->copyNoExecution = '没有可用的' . $lang->executionCommon .
$lang->execution->noTeam = '暂时没有团队成员';
$lang->execution->or = '或';
if($this->config->systemMode == 'new') $lang->execution->copyTeamTip = "可以选择复制项目或{$lang->execution->common}团队的成员";
if($this->config->systemMode == 'classic') $lang->execution->copyTeamTip = "可以选择复制{$lang->executionCommon}团队的成员";
$lang->execution->start = "开始";
$lang->execution->activate = "激活";
$lang->execution->putoff = "延期";
+58 -25
View File
@@ -325,7 +325,7 @@ class executionModel extends model
->join('whitelist', ',')
->add('type', $type)
->stripTags($this->config->execution->editor->create['id'], $this->config->allowedTags)
->remove('products, workDays, delta, branch, uid, plans')
->remove('products, workDays, delta, branch, uid, plans, teams, teamMembers')
->get();
/* Check the workload format and total. */
@@ -368,6 +368,7 @@ class executionModel extends model
$executionID = $this->dao->lastInsertId();
$today = helper::today();
$creatorExists = false;
$teamMembers = array();
/* Save order. */
$this->dao->update(TABLE_EXECUTION)->set('`order`')->eq($executionID * 5)->where('id')->eq($executionID)->exec();
@@ -376,39 +377,42 @@ class executionModel extends model
/* Update the path. */
if($this->config->systemMode == 'new') $this->setTreePath($executionID);
/* Copy team of execution. */
if($copyExecutionID != '')
/* Set team of execution. */
$members = isset($_POST['teamMembers']) ? $_POST['teamMembers'] : array();
$roles = $this->loadModel('user')->getUserRoles(array_keys($members));
foreach($members as $account)
{
$members = $this->dao->select('*')->from(TABLE_TEAM)->where('root')->eq($copyExecutionID)->andWhere('type')->eq('execution')->fetchAll();
foreach($members as $member)
{
unset($member->id);
$member->root = $executionID;
$member->join = $today;
$member->days = $sprint->days;
$member->type = 'execution';
$this->dao->insert(TABLE_TEAM)->data($member)->exec();
if($member->account == $this->app->user->account) $creatorExists = true;
}
}
if(empty($account)) continue;
/* Add the creator to team. */
if($copyExecutionID == '' or !$creatorExists)
{
$this->app->loadLang('user');
$member = new stdclass();
$member = new stdClass();
$member->root = $executionID;
$member->account = $this->app->user->account;
$member->role = zget($this->lang->user->roleList, $this->app->user->role, '');
$member->join = $today;
$member->type = 'execution';
$member->account = $account;
$member->role = zget($roles, $account, '');
$member->join = $today;
$member->days = $sprint->days;
$member->hours = $this->config->execution->defaultWorkhours;
$this->dao->insert(TABLE_TEAM)->data($member)->exec();
if($this->config->systemMode == 'new') $this->addProjectMembers($sprint->project, array($member));
if($member->account == $this->app->user->account) $creatorExists = true;
$teamMembers[$account] = $member;
}
if(!$creatorExists)
{
$member = new stdClass();
$member->root = $executionID;
$member->type = 'execution';
$member->account = $this->app->user->account;
$member->role = zget($this->lang->user->roleList, $this->app->user->role, '');
$member->join = $today;
$member->days = $sprint->days;
$member->hours = $this->config->execution->defaultWorkhours;
$this->dao->insert(TABLE_TEAM)->data($member)->exec();
$teamMembers[$member->account] = $member;
}
if($this->config->systemMode == 'new') $this->addProjectMembers($sprint->project, $teamMembers);
/* Create doc lib. */
$this->app->loadLang('doc');
$lib = new stdclass();
@@ -2439,6 +2443,35 @@ class executionModel extends model
->fetchAll('account');
}
/**
* Get the project and execution the team through the projectID.
*
* @param int $projectID
* @access public
* @return array
*/
public function getTeamPairsByProject($projectID = 0)
{
$teams = $this->dao->select('id,team,type')->from(TABLE_PROJECT)
->where('deleted')->eq(0)
->andWhere('project')->eq($projectID)
->orWhere('id')->eq($projectID)
->fetchAll('id');
if(empty($teams)) return array();
$teamPairs = array();
foreach($teams as $id => $team)
{
if(empty($team->team)) continue;
$object = $team->type == 'project' ? $this->lang->project->common . '-' : $this->lang->execution->common . '-';
$teamPairs[$id] = $object . $team->team;
}
return $teamPairs;
}
/**
* Manage team members.
*
+16 -7
View File
@@ -50,13 +50,13 @@
<tr>
<th class='w-120px'><?php echo $lang->execution->project;?></th>
<td class="col-main"><?php echo html::select("project", $allProjects, $projectID, "class='form-control chosen' required onchange='refreshPage(this.value)'");?></td>
<td></td><td></td>
<td colspan='2'></td>
</tr>
<?php endif;?>
<tr>
<th class='w-120px'><?php echo (($from == 'execution') and ($config->systemMode == 'new')) ? $lang->execution->execName : $lang->execution->name;?></th>
<td class="col-main"><?php echo html::input('name', $name, "class='form-control' required");?></td>
<td></td><td></td>
<td colspan='2'></td>
</tr>
<tr>
<th><?php echo (($from == 'execution') and ($config->systemMode == 'new')) ? $lang->execution->execCode : $lang->execution->code;?></th>
@@ -82,13 +82,9 @@
</div>
</td><td></td><td></td>
</tr>
<tr>
<th><?php echo $lang->execution->teamname;?></th>
<td><?php echo html::input('team', $team, "class='form-control'");?></td><td></td><td></td>
</tr>
<tr>
<th><?php echo (($from == 'execution') and ($config->systemMode == 'new')) ? $lang->execution->execType : $lang->execution->type;?></th>
<td><?php echo html::select('lifetime', $lang->execution->lifeTimeList, '', "class='form-control' onchange='showLifeTimeTips()'"); ?></td>
<td><?php echo html::select('lifetime', $lang->execution->lifeTimeList, '', "class='form-control chosen' onchange='showLifeTimeTips()'"); ?></td>
<td class='muted' colspan='2'><div id='lifeTimeTips'><?php echo $lang->execution->typeDesc;?></div></td>
</tr>
<tr class='hide'>
@@ -144,6 +140,19 @@
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->execution->teamname;?></th>
<td><?php echo html::input('team', $team, "class='form-control'");?></td>
<td colspan='2'></td>
</tr>
<tr>
<th><?php echo $lang->execution->copyTeam;?></th>
<td><?php echo html::select('teams', $teams, $copyExecutionID, "class='form-control chosen' data-placeholder='{$lang->execution->copyTeamTip}'"); ?></td>
</tr>
<tr>
<th><?php echo $lang->execution->team;?></th>
<td colspan='3'><?php echo html::select('teamMembers[]', $users, '', "class='form-control chosen' multiple"); ?></td>
</tr>
<tr>
<th><?php echo (($from == 'execution') and ($config->systemMode == 'new')) ? $lang->execution->execDesc : $lang->execution->desc;?></th>
<td colspan='3'>
+4
View File
@@ -237,6 +237,8 @@ if($config->systemMode == 'new')
$lang->resource->project->export = 'export';
$lang->resource->project->createGuide = 'createGuide';
$lang->resource->project->updateOrder = 'updateOrder';
$lang->resource->project->team = 'teamAction';
$lang->resource->project->unlinkMember = 'unlinkMember';
$lang->project->methodOrder[0] = 'index';
$lang->project->methodOrder[5] = 'browse';
@@ -275,6 +277,8 @@ if($config->systemMode == 'new')
$lang->project->methodOrder[170] = 'export';
$lang->project->methodOrder[175] = 'createGuide';
$lang->project->methodOrder[180] = 'updateOrder';
$lang->project->methodOrder[185] = 'team';
$lang->project->methodOrder[190] = 'unlinkMember';
$lang->resource->projectbuild = new stdclass();
$lang->resource->projectbuild->browse = 'browse';
+5 -11
View File
@@ -124,6 +124,7 @@ class myModel extends model
$info->todo->dynamic = new stdclass();
if(common::hasPriv('todo', 'view'))
{
$this->app->loadClass('date');
$todos = $this->dao->select('*')->from(TABLE_TODO)
->where('assignedTo')->eq($this->app->user->account)
->andWhere('cycle')->eq(0)
@@ -134,12 +135,6 @@ class myModel extends model
->fetchAll();
foreach($todos as $key => $todo)
{
if($todo->status == 'done' and $todo->finishedBy == $this->app->user->account)
{
unset($todos[$key]);
continue;
}
$todo->begin = date::formatTime($todo->begin);
$todo->end = date::formatTime($todo->end);
}
@@ -182,10 +177,9 @@ class myModel extends model
->orWhere('participant')->in($this->app->user->account)
->markRight(1)
->orderBy('id_desc')
->limit(3)
->fetchAll();
$info->meeting->total = (int) $this->dao->select('count(*) AS count')->from(TABLE_MEETING)->where('assignedTo')->eq($this->app->user->account)->andWhere('status')->ne('closed')->andWhere('deleted')->eq(0)->fetch('count');
$info->meeting->dynamic = $meetings;
$info->meeting->total = count($meetings);
$info->meeting->dynamic = array_slice($meetings, 0, 3);
}
/* My issues. */
@@ -278,8 +272,8 @@ class myModel extends model
}
$info->dynamic = $actions;
/* User info. */
$info->participateProjectCount = count($info->projects);
/* Some count. */
$info->joinProjectCount = count($info->projects);
$info->createdDocs = $this->dao->select('count(*) AS count')->from(TABLE_DOC)->where('addedBy')->eq($this->app->user->account)->andWhere('deleted')->eq('0')->fetch('count');
return $info;
+60
View File
@@ -1106,6 +1106,66 @@ class project extends control
$this->display();
}
/**
* Browse team of a project.
*
* @param int $projectID
* @access public
* @return void
*/
public function team($projectID = 0)
{
$this->app->loadLang('execution');
$this->project->setMenu($projectID);
$project = $this->project->getById($projectID);
$this->view->title = $project->name . $this->lang->colon . $this->lang->project->team;
$this->view->projectID = $projectID;
$this->view->teamMembers = $this->project->getTeamMembers($projectID);
$this->view->deptUsers = $this->loadModel('dept')->getDeptUserPairs($this->app->user->dept, 'useid');
$this->view->canBeChanged = common::canModify('project', $project);
$this->display();
}
/**
* Unlink a memeber.
*
* @param int $projectID
* @param int $userID
* @param string $confirm yes|no
* @access public
* @return void
*/
public function unlinkMember($projectID, $userID, $confirm = 'no')
{
if($confirm == 'no') die(js::confirm($this->lang->project->confirmUnlinkMember, $this->inlink('unlinkMember', "projectID=$projectID&userID=$userID&confirm=yes")));
$user = $this->loadModel('user')->getById($userID, 'id');
$account = $user->account;
$this->project->unlinkMember($projectID, $account);
if(!dao::isError()) $this->loadModel('action')->create('team', $projectID, 'managedTeam');
/* if ajax request, send result. */
if($this->server->ajax)
{
if(dao::isError())
{
$response['result'] = 'fail';
$response['message'] = dao::getError();
}
else
{
$response['result'] = 'success';
$response['message'] = '';
}
return $this->send($response);
}
die(js::locate($this->inlink('team', "projectID=$projectID"), 'parent'));
}
/**
* Manage project members.
*
+4
View File
@@ -0,0 +1,4 @@
function checkUserDept(userID)
{
alert(noAccess);
}
+18 -15
View File
@@ -52,6 +52,7 @@ $lang->project->unlinkedProducts = "Unlinked {$lang->productCommon}s";
$lang->project->testreport = 'Test Report';
$lang->project->selectProgram = 'Program filtering';
$lang->project->teamMember = 'Team Member';
$lang->project->unlinkMember = 'Remove Member';
/* Fields. */
$lang->project->common = 'Project';
@@ -77,6 +78,7 @@ $lang->project->closedDate = 'ClosedDate';
$lang->project->canceledBy = 'CanceledBy';
$lang->project->canceledDate = 'CanceledDate';
$lang->project->team = 'Team';
$lang->project->teamAction = 'Team List';
$lang->project->order = 'Rank';
$lang->project->budget = 'Budget';
$lang->project->budgetUnit = 'Budget Unit';
@@ -231,18 +233,19 @@ $lang->project->programTitle['0'] = 'Hidden';
$lang->project->programTitle['base'] = 'Base-level project only';
$lang->project->programTitle['end'] = 'End-level project only';
$lang->project->accessDenied = 'Access denied to this project';
$lang->project->chooseProgramType = 'Select management type';
$lang->project->scrumTitle = 'Agile Development Management';
$lang->project->cannotCreateChild = 'The project has contents, so you cannot add a child project. You can create a parent project for this one and then add a child project for the parent project.';
$lang->project->hasChildren = 'This project has a child project, so it cannot be deleted.';
$lang->project->confirmDelete = 'Do you want to delete this project?';
$lang->project->cannotChangeToCat = "The project has contents, so you cannot it to a parent project.";
$lang->project->cannotCancelCat = "There are child projects of this project. You cannot cancel the parent project mark.";
$lang->project->parentBeginEnd = "The begin and end date of the parent project: %s ~ %s";
$lang->project->parentBudget = "The budget of the parent project: ";
$lang->project->beginLetterParent = "The begin date of the parent project: %s. It cannot be < the begin date of its parent project.";
$lang->project->endGreaterParent = "The end date of the parent project: %s. It cannot be > the end date of its parent project.";
$lang->project->beginGreateChild = "The minimum start date of the project set: %s. The start date of the project cannot be less than the minimum start date of the project set.";
$lang->project->endLetterChild = "The maximum finish date for the project set: %s. The completion date of a project cannot be greater than the maximum completion date of the project set.";
$lang->project->childLongTime = "There are long-term projects in the child project, and the parent project should also be a long-term project.";
$lang->project->accessDenied = 'Access denied to this project';
$lang->project->chooseProgramType = 'Select management type';
$lang->project->scrumTitle = 'Agile Development Management';
$lang->project->cannotCreateChild = 'The project has contents, so you cannot add a child project. You can create a parent project for this one and then add a child project for the parent project.';
$lang->project->hasChildren = 'This project has a child project, so it cannot be deleted.';
$lang->project->confirmDelete = 'Do you want to delete this project?';
$lang->project->cannotChangeToCat = "The project has contents, so you cannot it to a parent project.";
$lang->project->cannotCancelCat = "There are child projects of this project. You cannot cancel the parent project mark.";
$lang->project->parentBeginEnd = "The begin and end date of the parent project: %s ~ %s";
$lang->project->parentBudget = "The budget of the parent project: ";
$lang->project->beginLetterParent = "The begin date of the parent project: %s. It cannot be < the begin date of its parent project.";
$lang->project->endGreaterParent = "The end date of the parent project: %s. It cannot be > the end date of its parent project.";
$lang->project->beginGreateChild = "The minimum start date of the project set: %s. The start date of the project cannot be less than the minimum start date of the project set.";
$lang->project->endLetterChild = "The maximum finish date for the project set: %s. The completion date of a project cannot be greater than the maximum completion date of the project set.";
$lang->project->childLongTime = "There are long-term projects in the child project, and the parent project should also be a long-term project.";
$lang->project->confirmUnlinkMember = "Do you want to remove this user from project?";
+19 -16
View File
@@ -22,7 +22,7 @@ $lang->project->editGroup = '项目编辑分组';
$lang->project->copyGroup = '项目复制分组';
$lang->project->manageView = '项目维护视野';
$lang->project->managePriv = '项目维护权限';
$lang->project->manageMembers = '项目团队';
$lang->project->manageMembers = '团队管理';
$lang->project->export = '导出';
$lang->project->addProduct = '新建产品';
$lang->project->manageGroupMember = '维护分组用户';
@@ -52,6 +52,7 @@ $lang->project->unlinkedProducts = '未关联';
$lang->project->testreport = '测试报告';
$lang->project->selectProgram = '项目集筛选';
$lang->project->teamMember = '团队成员';
$lang->project->unlinkMember = '移除成员';
/* Fields. */
$lang->project->common = '项目';
@@ -77,6 +78,7 @@ $lang->project->closedDate = '关闭日期';
$lang->project->canceledBy = '由谁取消';
$lang->project->canceledDate = '取消日期';
$lang->project->team = '团队';
$lang->project->teamAction = '团队列表';
$lang->project->order = '排序';
$lang->project->budget = '预算';
$lang->project->budgetUnit = '预算单位';
@@ -231,18 +233,19 @@ $lang->project->programTitle['0'] = '不显示';
$lang->project->programTitle['base'] = '只显示一级项目集';
$lang->project->programTitle['end'] = '只显示最后一级项目集';
$lang->project->accessDenied = '您无权访问该项目!';
$lang->project->chooseProgramType = '选择项目管理方式';
$lang->project->scrumTitle = '敏捷开发全流程项目管理';
$lang->project->cannotCreateChild = '该项目已经有实际的内容,无法直接添加子项目。您可以为当前项目创建一个父项目,然后在新的父项目下面添加子项目。';
$lang->project->hasChildren = '该项目有子项目存在,不能删除。';
$lang->project->confirmDelete = "您确定删除项目[%s]吗?";
$lang->project->cannotChangeToCat = "该项目已经有实际的内容,无法修改为父项目";
$lang->project->cannotCancelCat = "该项目下已经有子项目,无法取消父项目标记";
$lang->project->parentBeginEnd = "父项目起止时间:%s ~ %s";
$lang->project->parentBudget = "父项目预算:";
$lang->project->beginLetterParent = "父项目的开始日期:%s,开始日期不能小于父项目的开始日期";
$lang->project->endGreaterParent = "父项目的完成日期:%s,完成日期不能大于父项目的完成日期";
$lang->project->beginGreateChild = "项目集的最小开始日期:%s,项目的开始日期不能小于项目集的最小开始日期";
$lang->project->endLetterChild = "项目集的最大完成日期:%s,项目的完成日期不能大于项目集的最大完成日期";
$lang->project->childLongTime = "子项目中有长期项目,父项目也应该是长期项目";
$lang->project->accessDenied = '您无权访问该项目!';
$lang->project->chooseProgramType = '选择项目管理方式';
$lang->project->scrumTitle = '敏捷开发全流程项目管理';
$lang->project->cannotCreateChild = '该项目已经有实际的内容,无法直接添加子项目。您可以为当前项目创建一个父项目,然后在新的父项目下面添加子项目。';
$lang->project->hasChildren = '该项目有子项目存在,不能删除。';
$lang->project->confirmDelete = "您确定删除项目[%s]吗?";
$lang->project->cannotChangeToCat = "该项目已经有实际的内容,无法修改为父项目";
$lang->project->cannotCancelCat = "该项目下已经有子项目,无法取消父项目标记";
$lang->project->parentBeginEnd = "父项目起止时间:%s ~ %s";
$lang->project->parentBudget = "父项目预算:";
$lang->project->beginLetterParent = "父项目的开始日期:%s,开始日期不能小于父项目的开始日期";
$lang->project->endGreaterParent = "父项目的完成日期:%s,完成日期不能大于父项目的完成日期";
$lang->project->beginGreateChild = "项目集的最小开始日期:%s,项目的开始日期不能小于项目集的最小开始日期";
$lang->project->endLetterChild = "项目集的最大完成日期:%s,项目的完成日期不能大于项目集的最大完成日期";
$lang->project->childLongTime = "子项目中有长期项目,父项目也应该是长期项目";
$lang->project->confirmUnlinkMember = "您确定从该项目中移除该用户吗?";
+19 -16
View File
@@ -22,7 +22,7 @@ $lang->project->editGroup = '項目編輯分組';
$lang->project->copyGroup = '項目複製分組';
$lang->project->manageView = '項目維護視野';
$lang->project->managePriv = '項目維護權限';
$lang->project->manageMembers = '項目團隊';
$lang->project->manageMembers = '團隊管理';
$lang->project->export = '導出';
$lang->project->addProduct = '新建產品';
$lang->project->manageGroupMember = '維護分組用戶';
@@ -52,6 +52,7 @@ $lang->project->unlinkedProducts = '未關聯';
$lang->project->testreport = '測試報告';
$lang->project->selectProgram = '項目集篩選';
$lang->project->teamMember = '團隊成員';
$lang->project->unlinkMember = '移除成員';
/* Fields. */
$lang->project->common = '項目';
@@ -77,6 +78,7 @@ $lang->project->closedDate = '關閉日期';
$lang->project->canceledBy = '由誰取消';
$lang->project->canceledDate = '取消日期';
$lang->project->team = '團隊';
$lang->project->teamAction = '團隊清單';
$lang->project->order = '排序';
$lang->project->budget = '預算';
$lang->project->budgetUnit = '預算單位';
@@ -231,18 +233,19 @@ $lang->project->programTitle['0'] = '不顯示';
$lang->project->programTitle['base'] = '只顯示一級項目集';
$lang->project->programTitle['end'] = '只顯示最後一級項目集';
$lang->project->accessDenied = '您無權訪問該項目!';
$lang->project->chooseProgramType = '選擇項目管理方式';
$lang->project->scrumTitle = '敏捷開發全流程項目管理';
$lang->project->cannotCreateChild = '該項目已經有實際的內容,無法直接添加子項目。您可以為當前項目創建一個父項目,然後在新的父項目下面添加子項目。';
$lang->project->hasChildren = '該項目有子項目存在,不能刪除。';
$lang->project->confirmDelete = "您確定刪除項目[%s]嗎?";
$lang->project->cannotChangeToCat = "該項目已經有實際的內容,無法修改為父項目";
$lang->project->cannotCancelCat = "該項目下已經有子項目,無法取消父項目標記";
$lang->project->parentBeginEnd = "父項目起止時間:%s ~ %s";
$lang->project->parentBudget = "父項目預算:";
$lang->project->beginLetterParent = "父項目的開始日期:%s,開始日期不能小於父項目的開始日期";
$lang->project->endGreaterParent = "父項目的完成日期:%s,完成日期不能大於父項目的完成日期";
$lang->project->beginGreateChild = "項目集的最小開始日期:%s,項目的開始日期不能小於項目集的最小開始日期";
$lang->project->endLetterChild = "項目集的最大完成日期:%s,項目的完成日期不能大於項目集的最大完成日期";
$lang->project->childLongTime = "子項目中有長期項目,父項目也應該是長期項目";
$lang->project->accessDenied = '您無權訪問該項目!';
$lang->project->chooseProgramType = '選擇項目管理方式';
$lang->project->scrumTitle = '敏捷開發全流程項目管理';
$lang->project->cannotCreateChild = '該項目已經有實際的內容,無法直接添加子項目。您可以為當前項目創建一個父項目,然後在新的父項目下面添加子項目。';
$lang->project->hasChildren = '該項目有子項目存在,不能刪除。';
$lang->project->confirmDelete = "您確定刪除項目[%s]嗎?";
$lang->project->cannotChangeToCat = "該項目已經有實際的內容,無法修改為父項目";
$lang->project->cannotCancelCat = "該項目下已經有子項目,無法取消父項目標記";
$lang->project->parentBeginEnd = "父項目起止時間:%s ~ %s";
$lang->project->parentBudget = "父項目預算:";
$lang->project->beginLetterParent = "父項目的開始日期:%s,開始日期不能小於父項目的開始日期";
$lang->project->endGreaterParent = "父項目的完成日期:%s,完成日期不能大於父項目的完成日期";
$lang->project->beginGreateChild = "項目集的最小開始日期:%s,項目的開始日期不能小於項目集的最小開始日期";
$lang->project->endLetterChild = "項目集的最大完成日期:%s,項目的完成日期不能大於項目集的最大完成日期";
$lang->project->childLongTime = "子項目中有長期項目,父項目也應該是長期項目";
$lang->project->confirmUnlinkMember = "您確定從該項目中移除該用戶嗎?";
+19
View File
@@ -1256,6 +1256,25 @@ class projectModel extends model
}
}
/**
* Unlink a member.
*
* @param int $projectID
* @param string $account
* @access public
* @return void
*/
public function unlinkMember($projectID, $account)
{
$this->dao->delete()->from(TABLE_TEAM)->where('root')->eq((int)$projectID)->andWhere('type')->eq('project')->andWhere('account')->eq($account)->exec();
$this->loadModel('user');
$this->user->updateUserView($projectID, 'project', array($account));
$linkedProducts = $this->loadModel('product')->getProductPairsByProject($projectID);
if(!empty($linkedProducts)) $this->user->updateUserView(array_keys($linkedProducts), 'product', array($account));
}
/**
* Manage team members.
*
+110
View File
@@ -0,0 +1,110 @@
<?php
/**
* The team view file of project module 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 Qiyu Xie
* @package project
* @version $Id: team.html.php 4143 2021-08-11 11:01:06Z $
* @link https://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php js::set('confirmUnlinkMember', $lang->project->confirmUnlinkMember)?>
<?php js::set('noAccess', $lang->user->error->noAccess)?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<span class='btn btn-link btn-active-text'><span class='text'><?php echo $lang->project->teamMember;?></span></span>
</div>
<div class='btn-toolbar pull-right'>
<?php
if($canBeChanged)
{
if(commonModel::isTutorialMode())
{
$wizardParams = helper::safe64Encode("projectID=$projectID");
echo html::a($this->createLink('tutorial', 'wizard', "module=project&method=manageMembers&params=$wizardParams"), "<i class='icon icon-persons'></i> " . $lang->project->manageMembers, '', "class='btn btn-primary manage-team-btn'");
}
else
{
if(!empty($app->user->admin) or empty($app->user->rights['rights']['my']['limited'])) common::printLink('project', 'manageMembers', "projectID=$projectID", "<i class='icon icon-persons'></i> " . $lang->project->manageMembers, '', "class='btn btn-primary manage-team-btn'");
}
}
?>
</div>
</div>
<div id='mainContent'>
<?php if(empty($teamMembers)):?>
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $lang->execution->noMembers;?></span>
<?php if((!empty($app->user->admin) or empty($app->user->rights['rights']['my']['limited'])) && common::hasPriv('project', 'manageMembers')):?>
<?php echo html::a($this->createLink('project', 'manageMembers', "projectID=$projectID"), "<i class='icon icon-persons'></i> " . $lang->project->manageMembers, '', "class='btn btn-info'");?>
<?php endif;?>
</p>
</div>
<?php else:?>
<form class='main-table'>
<table class='table' id='memberList'>
<thead>
<tr>
<th><?php echo $lang->team->account;?></th>
<th><?php echo $lang->team->role;?></th>
<th><?php echo $lang->team->join;?></th>
<th><?php echo $lang->team->days;?></th>
<th><?php echo $lang->team->hours;?></th>
<th><?php echo $lang->team->totalHours;?></th>
<th class='w-100px text-center'><?php echo $lang->team->limited;?></th>
<?php if($canBeChanged):?>
<th class='c-actions-1 w-80px text-center'><?php echo $lang->actions;?></th>
<?php endif;?>
</tr>
</thead>
<tbody>
<?php $totalHours = 0;?>
<?php foreach($teamMembers as $member):?>
<tr>
<td>
<?php
if(common::hasPriv('user', 'view'))
{
$link = isset($deptUsers[$member->userID]) ? $this->createLink('user', 'view', "userID={$member->userID}") : "javascript:checkUserDept();";
echo html::a($link, $member->realname, '', 'data-app="system"');
}
else
{
echo $member->realname;
}
$memberHours = $member->days * $member->hours;
$totalHours += $memberHours;
?>
</td>
<td title='<?php echo $member->role;?>'><?php echo $member->role;?></td>
<td><?php echo $member->join;?></td>
<td><?php echo $member->days . $lang->execution->day;?></td>
<td><?php echo $member->hours . $lang->execution->workHour;?></td>
<td><?php echo $memberHours . $lang->execution->workHour;?></td>
<td class="text-center"><?php echo $lang->team->limitedList[$member->limited];?></td>
<?php if($canBeChanged):?>
<td class='c-actions text-center'>
<?php
if (common::hasPriv('project', 'unlinkMember', $member))
{
$unlinkURL = $this->createLink('project', 'unlinkMember', "projectID=$projectID&userID=$member->userID&confirm=yes");
echo html::a("javascript:ajaxDelete(\"$unlinkURL\", \"mainContent\", confirmUnlinkMember)", '<i class="icon-green-project-unlinkMember icon-unlink"></i>', '', "class='btn' title='{$lang->project->unlinkMember}'");
}
?>
</td>
<?php endif;?>
</tr>
<?php endforeach;?>
</tbody>
</table>
<div class='table-footer'>
<div class='table-statistic'><?php echo $lang->team->totalHours . ':' . "<strong>$totalHours{$lang->execution->workHour}</strong>";?></div>
</div>
</form>
<?php endif;?>
</div>
<?php include '../../common/view/footer.html.php';?>
+1 -3
View File
@@ -44,13 +44,11 @@ class projectreleaseModel extends model
* Get list of releases.
*
* @param int $projectID
* @param int $productID
* @param int $branch
* @param string $type
* @access public
* @return array
*/
public function getList($projectID, $productID, $branch = 0, $type = 'all')
public function getList($projectID, $type = 'all')
{
return $this->dao->select('t1.*, t2.name as productName, t3.id as buildID, t3.name as buildName, t3.execution, t4.name as executionName')
->from(TABLE_RELEASE)->alias('t1')
+1 -1
View File
@@ -701,7 +701,7 @@ class searchModel extends model
if(empty($savedDict)) $savedDict = $this->dao->select("`key`")->from(TABLE_SEARCHDICT)->fetchPairs('key', 'key');
foreach($dict as $key => $value)
{
if(!is_numeric($key) or empty($value) or strlen($key) != 5) continue;
if(!is_numeric($key) or empty($value) or strlen($key) != 5 or $key < 0) continue;
if(isset($savedDict[$key])) continue;
$this->dao->insert(TABLE_SEARCHDICT)->data(array('key' => $key, 'value' => $value))->exec();
+14
View File
@@ -5,4 +5,18 @@ $(function()
{
if(reviewedReviewer.indexOf($(this).find('span').text()) != -1) $(this).css('pointer-events', 'none');
})
$('#reviewer').change(function()
{
if($('#reviewer_chosen .search-choice').length === 1)
{
alert(reviewerNotEmpty);
$('#reviewer').val(reviewers);
$('#reviewer').trigger('chosen:updated');
}
else
{
reviewers = $('#reviewer').val();
}
})
})
+2 -1
View File
@@ -388,7 +388,8 @@ $lang->story->chosen = new stdClass();
$lang->story->chosen->reviewedBy = 'Prüfer wählen';
$lang->story->notice = new stdClass();
$lang->story->notice->closed = 'Die ausgewählten Storys wurden bereits geschlossen!';
$lang->story->notice->closed = 'Die ausgewählten Storys wurden bereits geschlossen!';
$lang->story->notice->reviewerNotEmpty = 'This requirement needs to be reviewed, and the reviewedby is required.';
$lang->story->convertToTask = new stdClass();
$lang->story->convertToTask->fieldList = array();
+2 -1
View File
@@ -389,7 +389,8 @@ $lang->story->chosen = new stdClass();
$lang->story->chosen->reviewedBy = 'Choose ReviewedBy';
$lang->story->notice = new stdClass();
$lang->story->notice->closed = 'Story that you select is closed!';
$lang->story->notice->closed = 'Story that you select is closed!';
$lang->story->notice->reviewerNotEmpty = 'This requirement needs to be reviewed, and the reviewedby is required.';
$lang->story->convertToTask = new stdClass();
$lang->story->convertToTask->fieldList = array();
+2 -1
View File
@@ -388,7 +388,8 @@ $lang->story->chosen = new stdClass();
$lang->story->chosen->reviewedBy = 'Choisir valideur';
$lang->story->notice = new stdClass();
$lang->story->notice->closed = 'La Story que vous avez sélectionnée est malheureusement fermée !';
$lang->story->notice->closed = 'La Story que vous avez sélectionnée est malheureusement fermée !';
$lang->story->notice->reviewerNotEmpty = 'This requirement needs to be reviewed, and the reviewedby is required.';
$lang->story->convertToTask = new stdClass();
$lang->story->convertToTask->fieldList = array();
+2 -1
View File
@@ -388,7 +388,8 @@ $lang->story->chosen = new stdClass();
$lang->story->chosen->reviewedBy = 'Chọn xét duyệt bởi';
$lang->story->notice = new stdClass();
$lang->story->notice->closed = 'Câu chuyện mà bạn chọn đã đóng!';
$lang->story->notice->closed = 'Câu chuyện mà bạn chọn đã đóng!';
$lang->story->notice->reviewerNotEmpty = 'This requirement needs to be reviewed, and the reviewedby is required.';
$lang->story->convertToTask = new stdClass();
$lang->story->convertToTask->fieldList = array();
+2 -1
View File
@@ -389,7 +389,8 @@ $lang->story->chosen = new stdClass();
$lang->story->chosen->reviewedBy = '选择评审人...';
$lang->story->notice = new stdClass();
$lang->story->notice->closed = "您选择的{$lang->SRCommon}已经被关闭了!";
$lang->story->notice->closed = "您选择的{$lang->SRCommon}已经被关闭了!";
$lang->story->notice->reviewerNotEmpty = '该需求需要评审,评审人员不能为空。';
$lang->story->convertToTask = new stdClass();
$lang->story->convertToTask->fieldList = array();
+2 -1
View File
@@ -389,7 +389,8 @@ $lang->story->chosen = new stdClass();
$lang->story->chosen->reviewedBy = '選擇評審人...';
$lang->story->notice = new stdClass();
$lang->story->notice->closed = "您選擇的{$lang->SRCommon}已經被關閉了!";
$lang->story->notice->closed = "您選擇的{$lang->SRCommon}已經被關閉了!";
$lang->story->notice->reviewerNotEmpty = '該需求需要評審,評審人員不能為空。';
$lang->story->convertToTask = new stdClass();
$lang->story->convertToTask->fieldList = array();
+11 -7
View File
@@ -793,8 +793,9 @@ class storyModel extends model
if(isset($_POST['reviewer']))
{
$_POST['reviewer'] = array_filter($_POST['reviewer']);
$oldReviewer = $this->getReviewerPairs($storyID, $oldStory->version);
$_POST['reviewer'] = array_filter($_POST['reviewer']);
$oldReviewer = $this->getReviewerPairs($storyID, $oldStory->version);
$oldStory->reviewers = implode(',', array_keys($oldReviewer));
/* Update story reviewer. */
$this->dao->delete()->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->andWhere('reviewer')->notin(implode(',', $_POST['reviewer']))->exec();
@@ -810,8 +811,9 @@ class storyModel extends model
}
/* Update the story status by review rules. */
$reviewerList = $this->getReviewerPairs($storyID, $oldStory->version);
$reviewedBy = explode(',', trim($oldStory->reviewedBy, ','));
$reviewerList = $this->getReviewerPairs($storyID, $oldStory->version);
$story->reviewers = implode(',', array_keys($reviewerList));
$reviewedBy = explode(',', trim($oldStory->reviewedBy, ','));
if(!array_diff(array_keys($reviewerList), $reviewedBy))
{
$status = $this->setStatusByReviewRules($reviewerList);
@@ -830,7 +832,7 @@ class storyModel extends model
}
$this->dao->update(TABLE_STORY)
->data($story)
->data($story, 'reviewers')
->autoCheck()
->checkIF(isset($story->closedBy), 'closedReason', 'notempty')
->checkIF(isset($story->closedReason) and $story->closedReason == 'done', 'stage', 'notempty')
@@ -4006,7 +4008,6 @@ class storyModel extends model
{
$stories = $this->getProductStories($productID, 0, 0, 'all', 'story', 'id_desc', true, $excludeStories);
}
if($stories) $pager->recTotal += count($stories);
}
else
{
@@ -4041,6 +4042,7 @@ class storyModel extends model
}
$tracks['noRequirement'] = $stories;
$pager->recTotal += 1;
}
return $tracks;
@@ -4151,6 +4153,7 @@ class storyModel extends model
$data = new stdclass();
$data->AType = 'requirement';
$data->BType = 'story';
$data->product = $story->product;
$data->relation = 'subdivideinto';
$data->AID = $isStory ? $id : $storyID;
$data->BID = $isStory ? $storyID : $id;
@@ -4162,6 +4165,7 @@ class storyModel extends model
$data->AType = 'story';
$data->BType = 'requirement';
$data->relation = 'subdividedfrom';
$data->product = $story->product;
$data->AID = $isStory ? $storyID : $id;
$data->BID = $isStory ? $id : $storyID;
$data->AVersion = $isStory ? $story->version : $requirement->version;
@@ -4482,7 +4486,7 @@ class storyModel extends model
* @param string $result
* @param string $reason
* @access public
* @return int
* @return int|string
*/
public function recordReviewAction($story, $result = '', $reason = '')
{
+3 -1
View File
@@ -17,6 +17,8 @@
<?php js::set('rawModule', $this->app->rawModule);?>
<?php js::set('reviewedReviewer', $reviewedReviewer);?>
<?php js::set('storyModule', $lang->story->module);?>
<?php js::set('reviewers', explode(',', $reviewers));?>
<?php js::set('reviewerNotEmpty', $lang->story->notice->reviewerNotEmpty);?>
<div class='main-content' id='mainContent'>
<form method='post' enctype='multipart/form-data' target='hiddenwin' id='dataform'>
<div class='main-header'>
@@ -209,7 +211,7 @@
<?php if($isShowReviewer):?>
<tr>
<th><?php echo $lang->story->reviewers;?></th>
<td><?php echo html::select('reviewer[]', $users, $reviewers, 'class="form-control chosen" multiple')?></td>
<td><?php echo html::select('reviewer[]', array('' => '') + $users, $reviewers, 'class="form-control chosen" multiple')?></td>
</tr>
<?php endif;?>
<?php if($story->status == 'closed'):?>
+1 -1
View File
@@ -1090,7 +1090,7 @@ class task extends control
if(isonlybody()) die(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
if(defined('RUN_MODE') && RUN_MODE == 'api')
{
die(array('status' => 'success', 'data' => $taskID));
return $this->send(array('status' => 'success', 'data' => $taskID));
}
else
{