This commit is contained in:
zhujinyong
2022-01-19 08:33:08 +08:00
76 changed files with 3627 additions and 180 deletions
File diff suppressed because it is too large Load Diff
+1
View File
@@ -29,6 +29,7 @@
30043 实现执行看板设置泳道高度功能
30053 实现研发看板设置泳道高度功能
30068 通用看板中默认的模版横向不要有滚动条
2022-01-11 16.1
46672 实现计划卡片的更多设置功能
46671 计划看板中实现卡片的排序功能
+14 -6
View File
@@ -352,14 +352,18 @@ class actionModel extends model
}
elseif($actionName == 'linked2execution')
{
$name = $this->dao->select('name')->from(TABLE_PROJECT)->where('id')->eq($action->extra)->fetch('name');
if($name) $action->extra = common::hasPriv('execution', 'view') ? html::a(helper::createLink('execution', 'view', "executionID=$action->execution"), $name) : $name;
$execution = $this->dao->select('name,type')->from(TABLE_PROJECT)->where('id')->eq($action->extra)->fetch();
$name = $execution->name;
$method = $execution->type == 'kanban' ? 'kanban' : 'view';
if($name) $action->extra = common::hasPriv('execution', $method) ? html::a(helper::createLink('execution', $method, "executionID=$action->execution"), $name) : $name;
}
elseif($actionName == 'linked2project')
{
$name = $this->dao->select('name')->from(TABLE_PROJECT)->where('id')->eq($action->extra)->fetch('name');
$project = $this->dao->select('name,model')->from(TABLE_PROJECT)->where('id')->eq($action->extra)->fetch();
$productID = trim($action->product, ',');
if($name) $action->extra = common::hasPriv('project', 'view') ? html::a(helper::createLink('project', 'view', "projectID=$action->project"), $name) : $name;
$name = $project->name;
$method = $project->model == 'kanban' ? 'index' : 'view';
if($name) $action->extra = common::hasPriv('project', $method) ? html::a(helper::createLink('project', $method, "projectID=$action->project"), $name) : $name;
}
elseif($actionName == 'linked2plan')
{
@@ -1034,12 +1038,16 @@ class actionModel extends model
{
$action->objectName .= $this->lang->action->label->startProgram;
}
if($action->objectType == 'branch' and $action->action == 'mergedbranch')
elseif($action->objectType == 'branch' and $action->action == 'mergedbranch')
{
if($action->objectID == 0) $action->objectName = $this->lang->branch->main;
$action->objectName = '"' . $action->extra . ' "' . $this->lang->action->to . ' "' . $action->objectName . '"';
}
elseif($action->objectType == 'user')
{
$user = $this->dao->select('id,realname')->from(TABLE_USER)->where('id')->eq($action->objectID)->fetch();
if($user) $action->objectName = $user->realname;
}
$projectID = isset($relatedProjects[$action->objectType][$action->objectID]) ? $relatedProjects[$action->objectType][$action->objectID] : 0;
+3 -1
View File
@@ -428,7 +428,7 @@ class bug extends control
setcookie('bugModule', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
$location = $this->createLink('bug', 'browse', "productID={$this->post->product}&branch=$branch&browseType=byModule&param={$this->post->module}&orderBy=id_desc");
}
if($this->app->getViewType() == 'xhtml') $location = $this->createLink('bug', 'view', "bugID=$bugID");
if($this->app->getViewType() == 'xhtml') $location = $this->createLink('bug', 'view', "bugID=$bugID", 'html');
$response['locate'] = $location;
return $this->send($response);
}
@@ -599,6 +599,8 @@ class bug extends control
/* Get executions. */
$executions = array(0 => '');
if(isset($projects[$projectID]) or $this->config->systemMode == 'classic') $executions += $this->product->getExecutionPairsByProduct($productID, $branch ? "0,$branch" : 0, 'id_desc', $projectID);
$execution = $executionID ? $this->loadModel('execution')->getByID($executionID) : '';
$executions = isset($executions[$executionID]) ? $executions : $executions + array($executionID => $execution->name);
/* Set custom. */
foreach(explode(',', $this->config->bug->list->customCreateFields) as $field) $customFields[$field] = $this->lang->bug->$field;
+2 -2
View File
@@ -121,8 +121,8 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow
}
else
{
$branch = $branch != 'all' ? $branch : 0;
$createBugLink = $this->createLink('bug', 'create', "productID=$productID&branch=$branch&extra=moduleID=$moduleID");
$selectedBranch = $branch != 'all' ? $branch : 0;
$createBugLink = $this->createLink('bug', 'create', "productID=$productID&branch=$selectedBranch&extra=moduleID=$moduleID");
}
$batchCreateLink = $this->createLink('bug', 'batchCreate', "productID=$productID&branch=$branch&executionID=0&moduleID=$moduleID");
+1 -1
View File
@@ -532,7 +532,7 @@ class commonModel extends model
{
$params = "programID=0&copyProjectID=0&extra=from=global";
$createMethod = 'createGuide';
$attr = 'data-toggle="modal" data-target="#guideDialog"';
$attr = 'data-toggle="modal"';
}
else
{
+1 -1
View File
@@ -309,7 +309,7 @@ class doc extends control
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $docID));
$objectID = zget($lib, $lib->type, '');
$params = "type={$lib->type}&objectID=$objectID&libID={$lib->id}&docID=" . $docResult['id'];
$link = isonlybody() ? 'parent' : $this->createLink('doc', 'objectLibs', $params);
$link = isonlybody() ? 'parent' : $this->createLink('doc', 'objectLibs', $params, 'html');
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $link));
}
+3 -3
View File
@@ -1335,9 +1335,9 @@ class docModel extends model
/* Project permissions for DocLib whitelist. */
if($this->app->tab == 'doc')
{
$myObjects = $this->dao->select('t2.id, t2.name')->from(TABLE_DOCLIB)->alias('t1')
->leftjoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')
->where("CONCAT(',', t1.users, ',')")->like("%,{$this->app->user->account},%")
$myObjects = $this->dao->select('t1.id, t1.name')->from(TABLE_PROJECT)->alias('t1')
->leftjoin(TABLE_DOCLIB)->alias('t2')->on('t2.project=t1.id')
->where("CONCAT(',', t2.users, ',')")->like("%,{$this->app->user->account},%")
->fetchPairs();
}
+9 -7
View File
@@ -123,12 +123,13 @@ class execution extends control
/* Set browse type. */
$browseType = strtolower($status);
/* Get products by execution. */
$execution = $this->commonAction($executionID, $status);
$execution = $this->commonAction($executionID, $status);
$executionID = $execution->id;
if($execution->type == 'kanban') $this->locate($this->createLink('execution', 'kanban', "executionID=$executionID"));
$executionID = $execution->id;
$products = $this->product->getProductPairsByProject($executionID);
/* Get products by execution. */
$products = $this->product->getProductPairsByProject($executionID);
setcookie('preExecutionID', $executionID, $this->config->cookieLife, $this->config->webRoot, '', false, true);
/* Save the recently five executions visited in the cookie. */
@@ -1978,11 +1979,12 @@ class execution extends control
$userList = array();
$users = $this->loadModel('user')->getPairs('noletter|nodeleted');
$avatarPairs = $this->dao->select('account, avatar')->from(TABLE_USER)->where('deleted')->eq(0)->fetchPairs();
$avatarPairs = $this->user->getAvatarPairs();
foreach($avatarPairs as $account => $avatar)
{
if(!$avatar) continue;
$userList[$account]['avatar'] = $avatar;
if(!isset($users[$account])) continue;
$userList[$account]['realname'] = $users[$account];
$userList[$account]['avatar'] = $avatar;
}
/* Get execution's product. */
+3 -1
View File
@@ -59,7 +59,7 @@
.region .kanban-item {position: relative}
.kanban-card {height: auto !important; padding: 8px 14px !important}
.kanban-card {height: auto !important; padding: 8px 14px !important; min-height: 60px;}
.cardcolor {width:40px; height: 14px; float: left; margin-left: 5px; margin-right: 5px; margin-top: 2px; border-radius: 2px;}
#cardcolormenu {padding:2px 2px; width: 100px;}
@@ -103,3 +103,5 @@
#kanban .kanban-card[data-scale-size="2"] > .infos {display: inline-block; height: 18px; vertical-align: top; margin: 0;}
#kanban .kanban-card[data-scale-size="2"] > .infos > .info-pri {transform: scale(.8); vertical-align: top;}
#kanban .kanban-card[data-scale-size="2"] > .infos > .avatar {display: inline-block; transform: scale(.8); position: relative; top: -2px; vertical-align: top; margin-right: -1px;}
#mainMenu .divider {margin: 10px}
+11 -4
View File
@@ -299,6 +299,7 @@ function findDropColumns($element, $root)
{
if(!colRules) return false;
if(colRules === true) return true;
if($.cookie('isFullScreen') == 1) return false;
var $newCol = $(this);
var newCol = $newCol.data();
@@ -338,7 +339,7 @@ function renderUserAvatar(user, objectType, objectID, size)
if(!user) return $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + noAssigned + '" style="background: #ccc" href="' + link + '" data-toggle="modal" data-width="80%"><i class="icon icon-person"></i></a>');
if(typeof user === 'string') user = {account: user};
if(!user.avatar && window.users && window.users[user.account]) user = {avatar: users[user.account].avatar, account: user.account, realname: users[user.account]};
if(!user.avatar && window.userList && window.userList[user.account]) user = {avatar: userList[user.account].avatar, account: user.account, realname: userList[user.account].realname};
var $noPrivAvatar = $('<div class="avatar has-text ' + avatarSizeClass + ' avatar-circle" />').avatar({user: user});
if(objectType == 'task' && !priv.canAssignTask) return $noPrivAvatar;
@@ -605,11 +606,18 @@ function renderCount($count, count, column)
function renderHeaderCol($column, column, $header, kanbanData)
{
if(groupBy != 'default') return;
/* Render group header. */
var privs = kanbanData.actions;
var columnPrivs = kanbanData.columns[0].actions;
var $actions = $column.children('.actions');
if(column.parent == -1)
{
$column.append('<div class="actions"></div>');
$actions = $column.children('.actions');
}
if(privs.includes('sortGroup'))
{
var groups = regions[column.region].groups;
@@ -786,7 +794,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
}
else if(toColType == 'developing')
{
if((fromColType == 'pause' || fromColType == 'cancel' || fromColType == 'closed' || fromColType == 'developed') && priv.canActivateTask)
if((fromColType == 'pause' || fromColType == 'canceled' || fromColType == 'closed' || fromColType == 'developed') && priv.canActivateTask)
{
var link = createLink('task', 'activate', 'taskID=' + objectID + '&extra=fromColID=' + fromColID + ',toColID=' + toColID + ',fromLaneID=' + fromLaneID + ',toLaneID=' + toLaneID, '', true);
showIframe = true;
@@ -860,7 +868,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
}
}
if(moveCard)
if(moveCard || (fromLaneID != toLaneID && fromColID == toColID))
{
var link = createLink('kanban', 'ajaxMoveCard', 'cardID=' + objectID + '&fromColID=' + fromColID + '&toColID=' + toColID + '&fromLaneID=' + fromLaneID + '&toLaneID=' + toLaneID + '&execitionID=' + executionID + '&browseType=' + browseType + '&groupBy=' + groupBy + '&regionID=' + regionID + '&orderBy=' + orderBy );
$.ajax(
@@ -964,7 +972,6 @@ function initKanban($kanban)
displayCards: displayCards,
createColumnText: kanbanLang.createColumn,
addItemText: '',
cardHeight: getCardHeight(),
cardsPerRow: window.kanbanScaleSize,
onAction: handleKanbanAction,
onRenderLaneName: renderLaneName,
+9 -8
View File
@@ -470,7 +470,7 @@ if(!window.kanbanDropRules)
task:
{
'wait': ['developing', 'developed', 'canceled', 'closed'],
'developing': ['developed', 'pause'],
'developing': ['developed', 'pause', 'canceled'],
'developed': ['canceled', 'closed'],
'pause': ['developing'],
'canceled': ['developing'],
@@ -499,6 +499,7 @@ function findDropColumns($element, $root)
{
if(!colRules) return false;
if(colRules === true) return true;
if($.cookie('isFullScreen') == 1) return false;
var $newCol = $(this);
var newCol = $newCol.data();
@@ -553,7 +554,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
}
else if(toColType == 'developing')
{
if((fromColType == 'pause' || fromColType == 'cancel' || fromColType == 'closed' || fromColType == 'developed') && priv.canActivateTask)
if((fromColType == 'pause' || fromColType == 'canceled' || fromColType == 'closed' || fromColType == 'developed') && priv.canActivateTask)
{
var link = createLink('task', 'activate', 'taskID=' + objectID, '', true);
showIframe = true;
@@ -761,8 +762,8 @@ function createColumnMenu(options)
var kanbanID = options.kanban;
var items = [];
if(priv.canEditName) items.push({label: executionLang.editName, url: $.createLink('kanban', 'setColumn', 'col=' + col.columnID + '&executionID=' + executionID + '&from=execution'), className: 'iframe', attrs: {'data-width': '500px'}})
if(priv.canSetWIP) items.push({label: executionLang.setWIP, url: $.createLink('kanban', 'setWIP', 'col=' + col.columnID + '&executionID=' + executionID + '&from=execution'), className: 'iframe', attrs: {'data-width': '500px'}})
if(priv.canEditName) items.push({label: executionLang.editName, url: $.createLink('kanban', 'setColumn', 'col=' + col.id + '&executionID=' + executionID + '&from=execution'), className: 'iframe', attrs: {'data-width': '500px'}})
if(priv.canSetWIP) items.push({label: executionLang.setWIP, url: $.createLink('kanban', 'setWIP', 'col=' + col.id + '&executionID=' + executionID + '&from=execution'), className: 'iframe', attrs: {'data-width': '500px'}})
//if(priv.canSortCards) items.push({label: executionLang.sortColumn, items: ['按ID倒序', '按ID顺序'], className: 'iframe', onClick: handleSortColCards})
return items;
}
@@ -786,13 +787,13 @@ function createColumnCreateMenu(options)
}
else if(col.laneType == 'bug')
{
if(priv.canCreateBug) items.push({label: bugLang.create, url: $.createLink('bug', 'create', 'productID=0&moduleID=0&extra=executionID=' + executionID, '', true), className: 'iframe'});
if(priv.canBatchCreateBug) items.push({label: bugLang.batchCreate, url: $.createLink('bug', 'batchcreate', 'productID=' + productID + '&moduleID=0&executionID=' + executionID, '', true), className: 'iframe'});
if(priv.canCreateBug) items.push({label: bugLang.create, url: $.createLink('bug', 'create', 'productID=0&moduleID=0&extra=executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-width': '80%'}});
if(priv.canBatchCreateBug) items.push({label: bugLang.batchCreate, url: $.createLink('bug', 'batchcreate', 'productID=' + productID + '&moduleID=0&executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-width': '90%'}});
}
else
{
if(priv.canCreateTask) items.push({label: taskLang.create, url: $.createLink('task', 'create', 'executionID=' + executionID, '', true), className: 'iframe'});
if(priv.canBatchCreateTask) items.push({label: taskLang.batchCreate, url: $.createLink('task', 'batchcreate', 'executionID=' + executionID, '', true), className: 'iframe'});
if(priv.canCreateTask) items.push({label: taskLang.create, url: $.createLink('task', 'create', 'executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-width': '80%'}});
if(priv.canBatchCreateTask) items.push({label: taskLang.batchCreate, url: $.createLink('task', 'batchcreate', 'executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-width': '80%'}});
}
return items;
}
+8 -4
View File
@@ -63,6 +63,13 @@ class executionModel extends model
*/
public function setMenu($executionID, $buildID = 0, $extra = '')
{
$execution = $this->getByID($executionID);
if($execution and $execution->type == 'kanban')
{
$this->lang->execution->menu = new stdclass();
$this->lang->execution->accessDenied = str_replace($this->lang->executionCommon, $this->lang->execution->kanban, $this->lang->execution->accessDenied);
}
if(!$this->app->user->admin and strpos(",{$this->app->user->view->sprints},", ",$executionID,") === false and !defined('TUTORIAL') and $executionID != 0) die(js::error($this->lang->execution->accessDenied) . js::locate('back'));
$executions = $this->getPairs(0, 'all', 'nocode');
@@ -71,9 +78,6 @@ class executionModel extends model
$this->session->set('execution', $executionID);
/* Unset story, bug, build and testtask if type is ops. */
$execution = $this->getByID($executionID);
if($execution and $execution->type == 'kanban') $this->lang->execution->menu = new stdclass();
if($execution and $execution->type == 'stage' and $this->config->systemMode == 'new')
{
global $lang;
@@ -523,7 +527,7 @@ class executionModel extends model
->limit(1)
->exec();
if($oldExecution->type == 'kanban') $this->dao->delete()->from(TABLE_TEAM)->where('root')->eq((int)$executionID)->andWhere('type')->eq('execution')->exec();
if($oldExecution->type == 'kanban') $this->dao->delete()->from(TABLE_TEAM)->where('root')->eq((int)$executionID)->andWhere('type')->eq('execution')->andWhere('account')->ne($oldExecution->openedBy)->exec();
/* Get team and language item. */
$this->lang->execution->team = $this->lang->execution->teamname;
+4
View File
@@ -175,6 +175,7 @@
</div>
</td>
</tr>
<?php if(empty($project) or $project->model != 'kanban'):?>
<tr>
<th><?php echo $lang->execution->teamname;?></th>
<td><?php echo html::input('team', $team, "class='form-control'");?></td>
@@ -184,6 +185,7 @@
<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>
<?php endif;?>
<tr>
<th rowspan='2'><?php echo $lang->execution->owner;?></th>
<td>
@@ -213,10 +215,12 @@
</div>
</td>
</tr>
<?php if(empty($project) or $project->model != 'kanban'):?>
<tr>
<th><?php echo $lang->execution->team;?></th>
<td colspan='3'><?php echo html::select('teamMembers[]', $users, '', "class='form-control chosen' multiple"); ?></td>
</tr>
<?php endif;?>
<tr>
<th><?php echo (($from == 'execution') and ($config->systemMode == 'new')) ? $lang->execution->execDesc : $lang->execution->desc;?></th>
<td colspan='3'>
+1 -1
View File
@@ -189,7 +189,7 @@ js::set('hasTaskButton', $hasTaskButton);
</div>
<?php else:?>
<div class='panel' id='kanbanContainer'>
<div class='panel-body'>
<div class='panel-body region'>
<div id='kanbans' class='kanban'></div>
</div>
</div>
+2 -9
View File
@@ -955,17 +955,10 @@ class kanban extends control
*/
public function setColumn($columnID, $executionID = 0, $from = 'kanban')
{
$column = $this->kanban->getColumnById($columnID);
$column = $this->kanban->getColumnByID($columnID);
if($_POST)
{
/* Check lane column name is unique. */
$exist = $this->kanban->getColumnByName($this->post->name, $column->lane);
if($exist and $exist->id != $columnID and $from != 'kanban')
{
return $this->sendError($this->lang->kanban->noColumnUniqueName);
}
$changes = $this->kanban->updateLaneColumn($columnID, $column);
if(dao::isError()) return $this->sendError(dao::getError());
if($changes)
@@ -1072,7 +1065,7 @@ class kanban extends control
->andWhere('`column`')->eq($toColID)
->exec();
$kanbanGroup = $regionID == 0 ? $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy) : $this->kanban->getRDKanban($executionID, $browseType, $orderBy, $groupBy, $regionID);
$kanbanGroup = $regionID == 0 ? $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy) : $this->kanban->getRDKanban($executionID, $browseType, $orderBy, $regionID, $groupBy);
die(json_encode($kanbanGroup));
}
+1 -1
View File
@@ -718,7 +718,7 @@ function createCardMenu(options)
{
if(moveColumns[i].parent > 0) parentColumns.push(moveColumns[i].parent);
if(moveColumns[i].id == card.column || $.inArray(moveColumns[i].id, parentColumns) >= 0) continue;
moveCardItems.push({label: moveColumns[i].name, onClick: function(){moveCard(card.id, moveColumns[i].id, card.lane, card.kanban, card.region);}});
moveCardItems.push({label: moveColumns[i].name, onClick: function(){moveCard(card.id, card.column, moveColumns[i].id, card.lane, card.lane, card.kanban, card.region);}});
}
moveCardItems = moveCardItems.reverse();
items.push({label: kanbanLang.moveCard, icon: 'move', items: moveCardItems});
-2
View File
@@ -140,7 +140,6 @@ $lang->kanban->laneColor = 'Lane Color';
$lang->kanban->setColumn = 'Column Settings';
$lang->kanban->columnName = 'Column Name';
$lang->kanban->columnColor = 'Column Color';
$lang->kanban->noColumnUniqueName = 'The Kanban column name already exists.';
$lang->kanban->moveUp = 'Swimlane Up';
$lang->kanban->moveDown = 'Swimlane Down';
$lang->kanban->laneMove = 'Swimlane Move';
@@ -263,7 +262,6 @@ $lang->kanbanlane->heightTypeList['custom'] = 'Custom (Customize lane height bas
$lang->kanbanlane->error = new stdclass();
$lang->kanbanlane->error->mustBeInt = 'The number of cards must be a positive integer greater than 2.';
$lang->kanbanregion = new stdclass();
$lang->kanbanregion->name = 'Region Name';
$lang->kanbanregion->default = 'Default Region';
-1
View File
@@ -140,7 +140,6 @@ $lang->kanban->laneColor = '泳道颜色';
$lang->kanban->setColumn = '看板列设置';
$lang->kanban->columnName = '看板列名称';
$lang->kanban->columnColor = '看板列颜色';
$lang->kanban->noColumnUniqueName = '看板列名称已存在';
$lang->kanban->moveUp = '泳道上移';
$lang->kanban->moveDown = '泳道下移';
$lang->kanban->laneMove = '泳道移动';
+36 -42
View File
@@ -333,17 +333,16 @@ class kanbanModel extends model
public function splitColumn($columnID)
{
$this->loadModel('action');
$data = fixer::input('post')->get();
$column = $this->getColumnByID($columnID);
$maxOrder = $this->dao->select('MAX(`order`) AS maxOrder')->from(TABLE_KANBANCOLUMN)->where('`group`')->eq($column->group)->fetch('maxOrder');
$order = $maxOrder ? $maxOrder + 1 : 1;
$sumChildLimit = $this->dao->select('SUM(`limit`) AS sumChildLimit')->from(TABLE_KANBANCOLUMN)->where('parent')->eq($columnID)->fetch('sumChildLimit');
$data = fixer::input('post')->get();
$column = $this->getColumnByID($columnID);
$maxOrder = $this->dao->select('MAX(`order`) AS maxOrder')->from(TABLE_KANBANCOLUMN)->where('`group`')->eq($column->group)->fetch('maxOrder');
$order = $maxOrder ? $maxOrder + 1 : 1;
$sumChildLimit = $this->dao->select('SUM(`limit`) AS sumChildLimit')->from(TABLE_KANBANCOLUMN)->where('parent')->eq($columnID)->fetch('sumChildLimit');
$childrenColumn = array();
$childrenColumn = array();
foreach($data->name as $i => $name)
{
$childColumn = new stdclass();
$childColumn->lane = $column->lane;
$childColumn->parent = $column->id;
$childColumn->region = $column->region;
$childColumn->group = $column->group;
@@ -386,9 +385,22 @@ class kanbanModel extends model
if(!dao::isError())
{
$childColumnID = $this->dao->lastInsertID();
if($i == 1) $this->dao->update(TABLE_KANBANCARD)->set('`column`')->eq($childColumnID)->where('`column`')->eq($columnID)->exec();
$this->dao->update(TABLE_KANBANCOLUMN)->set('type')->eq("column{$childColumnID}")->where('id')->eq($childColumnID)->exec();
$this->action->create('kanbanColumn', $childColumnID, 'created');
$cellList = $this->dao->select('*')->from(TABLE_KANBANCELL)->where('`column`')->eq($column->id)->fetchAll();
foreach($cellList as $cell)
{
$newCell = new stdclass();
$newCell->kanban = $cell->kanban;
$newCell->lane = $cell->lane;
$newCell->column = $childColumnID;
$newCell->type = 'common';
$newCell->cards = $i == 1 ? $cell->cards : '';
$this->dao->insert(TABLE_KANBANCELL)->data($newCell)->exec();
$this->dao->update(TABLE_KANBANCELL)->set('cards')->eq('')->where('id')->eq($cell->id)->exec();
}
}
}
@@ -836,6 +848,7 @@ class kanbanModel extends model
->andWhere("INSTR(t2.cards, CONCAT(',',t1.id,','))")->gt(0)
->andWhere('archived')->eq(0)
->andWhere('t2.kanban')->eq($kanbanID)
->andWhere('t2.type')->eq('common')
//->orderBy('`order` asc')
->fetchAll('id');
@@ -938,7 +951,7 @@ class kanbanModel extends model
->fetchgroup('lane', 'column');
/* Get group objects. */
if($browseType == 'all' or $browseType == 'story') $objectGroup['story'] = $this->loadModel('story')->getExecutionStories($executionID);
if($browseType == 'all' or $browseType == 'story') $objectGroup['story'] = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, 't1.`order`_desc', 'allStory');
if($browseType == 'all' or $browseType == 'bug') $objectGroup['bug'] = $this->loadModel('bug')->getExecutionBugs($executionID);
if($browseType == 'all' or $browseType == 'task') $objectGroup['task'] = $this->loadModel('execution')->getKanbanTasks($executionID, "id");
@@ -1017,7 +1030,7 @@ class kanbanModel extends model
->fetchGroup('lane', 'id');
/* Get group objects. */
if($browseType == 'all' or $browseType == 'story') $objectGroup['story'] = $this->loadModel('story')->getExecutionStories($executionID);
if($browseType == 'all' or $browseType == 'story') $objectGroup['story'] = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, 't1.`order`_desc', 'allStory');
if($browseType == 'all' or $browseType == 'bug') $objectGroup['bug'] = $this->loadModel('bug')->getExecutionBugs($executionID);
if($browseType == 'all' or $browseType == 'task') $objectGroup['task'] = $this->loadModel('execution')->getKanbanTasks($executionID, "id");
@@ -1116,7 +1129,8 @@ class kanbanModel extends model
public function getKanban4Group($executionID, $browseType, $groupBy)
{
/* Get card data. */
if($browseType == 'story') $cardList = $this->loadModel('story')->getExecutionStories($executionID);
$cardList = array();
if($browseType == 'story') $cardList = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, 't1.`order`_desc', 'allStory');
if($browseType == 'bug') $cardList = $this->loadModel('bug')->getExecutionBugs($executionID);
if($browseType == 'task') $cardList = $this->loadModel('execution')->getKanbanTasks($executionID, "id");
@@ -2083,19 +2097,16 @@ class kanbanModel extends model
$execution = $this->loadModel('execution')->getByID($executionID);
if($execution->type == 'kanban')
{
$regionIdList = $this->dao->select('id')->from(TABLE_KANBANREGION)
->where('deleted')->eq(0)
->andWhere('kanban')->eq($executionID)
->fetchPairs();
$lanes = $this->dao->select('t1.*')->from(TABLE_KANBANLANE)->alias('t1')
->leftJoin(TABLE_KANBANCELL)->alias('t2')->on('t1.id=t2.lane')
$lanes = $this->dao->select('t2.*')->from(TABLE_KANBANREGION)->alias('t1')
->leftJoin(TABLE_KANBANLANE)->alias('t2')->on('t1.id=t2.region')
->leftJoin(TABLE_KANBANCELL)->alias('t3')->on('t2.id=t3.lane')
->where('t1.deleted')->eq(0)
->andWhere('t1.execution')->eq($executionID)
->andWhere('t1.type')->eq($laneType)
->andWhere('t1.region')->in($regionIdList)
->beginIF(!empty($cardID))->andWhere('t2.cards')->like("%,$cardID,%")->fi()
->orderBy('t1.`order` asc')
->andWhere('t2.deleted')->eq(0)
->andWhere('t1.kanban')->eq($executionID)
->andWhere('t2.execution')->eq($executionID)
->andWhere('t2.type')->eq($laneType)
->beginIF(!empty($cardID))->andWhere('t3.cards')->like("%,$cardID,%")->fi()
->orderBy('t1.`order` asc, t2.`order` asc')
->fetchAll('id');
if(count($lanes) > 1) $lanes = array_slice($lanes, 0, 1);
@@ -2147,7 +2158,7 @@ class kanbanModel extends model
if($laneType == 'story')
{
$stories = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, 't1.`order`_desc', 'byModule', 0, 'story', $otherCardList);
$stories = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, 't1.`order`_desc', 'allStory', 0, 'story', $otherCardList);
foreach($stories as $storyID => $story)
{
foreach($this->config->kanban->storyColumnStageList as $colType => $stage)
@@ -2791,7 +2802,7 @@ class kanbanModel extends model
public function getColumnByID($columnID)
{
$column = $this->dao->select('t1.*, t2.type as laneType')->from(TABLE_KANBANCOLUMN)->alias('t1')
->leftjoin(TABLE_KANBANLANE)->alias('t2')->on('t1.group=t2.id')
->leftjoin(TABLE_KANBANCELL)->alias('t2')->on('t1.id=t2.column')
->where('t1.id')->eq($columnID)
->fetch();
@@ -2800,23 +2811,6 @@ class kanbanModel extends model
return $column;
}
/**
* Get Column by column name.
*
* @param string $name
* @param int $laneID
* @access public
* @return object
*/
public function getColumnByName($name, $laneID)
{
return $this->dao->select('*')
->from(TABLE_KANBANCOLUMN)
->where('name')->eq($name)
->andWhere('lane')->eq($laneID)
->fetch();
}
/**
* Get columns by object id.
*
@@ -22,6 +22,7 @@
#archivedCards .kanban-item > .info > .user {position: absolute; right: 0; top: 0}
#archivedCards .card-actions {position: relative; padding: 15px 10px; padding-top: 0px;}
#archivedCards .card-actions > .btn {display: block;}
[lang^='en'] #archivedCards .card-actions > .btn {width: 55px;}
#archivedCards .card-actions > .btn + .btn {margin-top: 10px;}
#archivedCards .info > .time {background-color: rgba(0, 0, 0, 0.15);}
#archivedCards .info > .users > span {display: inline-block; color: transparent; width: 2px; height: 2px; background-color: #8990a2; position:sticky; top: 3px; margin: 0 7px; border-radius: 50%; line-height: 32px;}
+1 -1
View File
@@ -356,7 +356,7 @@ class productModel extends model
->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->products)->fi()
->beginIF(strpos($status, 'noclosed') !== false)->andWhere('t2.status')->ne('closed')->fi()
->orderBy($orderBy . 't2.order asc')
->fetchAll();
->fetchAll('id');
$products = array();
foreach($projectProducts as $product)
+1 -1
View File
@@ -18,7 +18,7 @@ td.c-branch {overflow: hidden; text-align: left !important; text-overflow: ellip
.c-title {width: 160px;}
.c-branch {width: 100px;}
.c-story, .c-status {width: 80px;}
.c-execution {width: 50px !important;}
.c-execution {width: 100px !important;}
.c-bug, .c-hour {width: 60px;}
.plan-name {position: relative; display: flex; align-items: center;}
+1 -1
View File
@@ -155,8 +155,8 @@ $lang->project->etc = " , etc";
$lang->project->product = 'Product';
$lang->project->branch = 'Branch';
$lang->project->plan = 'Plan';
$lang->project->kanban = 'Kanban';
$lang->project->createKanban = 'Create Kanban';
$lang->project->kanban = 'Kanban';
/* Project Kanban. */
$lang->project->typeList = array();
+8 -2
View File
@@ -43,7 +43,11 @@
<div class='panel' data-url='<?php echo $this->createLink('execution', 'kanban', "kanbanID=$kanbanID");?>'>
<div class='panel-heading'>
<div class='kanban-name'>
<?php if($kanban->end < helper::today() and $kanban->status != 'done' and $kanban->status != 'closed' and $kanban->status != 'suspended'):?>
<span class="label label-doing"><?php echo $lang->project->statusList['delay'];?></span>
<?php else:?>
<span class="label label-<?php echo $kanban->status;?>"><?php echo zget($lang->execution->statusList, $kanban->status);?></span>
<?php endif;?>
<strong title='<?php echo $kanban->name;?>'><?php echo $kanban->name;?></strong>
</div>
<?php
@@ -86,14 +90,16 @@
<div class='kanban-members pull-left'>
<?php $count = 0;?>
<?php foreach($members as $member):?>
<?php if($count > 1) break;?>
<?php if($count > 2) break;?>
<?php $count ++;?>
<div title="<?php echo $member->realname;?>">
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$member->account], 'account' => $member->account)); ?>
</div>
<?php endforeach;?>
<?php if(count($members) > 3):?>
<?php if(count($members) > 4):?>
<?php echo '<span>…</span>';?>
<?php endif;?>
<?php if(count($members) > 3):?>
<?php $lastMember = end($members);?>
<div title="<?php echo $lastMember->realname;?>">
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$lastMember->account], 'account' => $lastMember->account)); ?>
+4 -14
View File
@@ -105,19 +105,7 @@ class story extends control
$storyID = $storyResult['id'];
$productID = $this->post->product ? $this->post->product : $productID;
$execution = $this->dao->findById((int)$objectID)->from(TABLE_EXECUTION)->fetch();
if(!empty($execution) and $execution->type == 'kanban')
{
if(isset($output['laneID']) and isset($output['columnID']))
{
$this->loadModel('kanban')->addKanbanCell($objectID, $output['laneID'], $output['columnID'], 'story', $storyID);
}
else
{
$this->loadModel('kanban')->updateLane($objectID, 'story');
}
}
if($storyResult['status'] == 'exists')
{
$response['message'] = sprintf($this->lang->duplicate, $this->lang->story->common);
@@ -194,7 +182,7 @@ class story extends control
$param = $execution->type == 'project' ? "projectID=$objectID&productID=$productID" : "executionID=$objectID&orderBy=id_desc&browseType=unclosed";
$response['locate'] = $this->createLink($moduleName, 'story', $param);
}
if($this->app->getViewType() == 'xhtml') $response['locate'] = $this->createLink('story', 'view', "storyID=$storyID");
if($this->app->getViewType() == 'xhtml') $response['locate'] = $this->createLink('story', 'view', "storyID=$storyID", 'html');
return $this->send($response);
}
@@ -795,7 +783,9 @@ class story extends control
$product = $this->product->getByID($productID);
$branchProduct = $product->type == 'normal' ? false : true;
$modules = array($productID => $this->tree->getOptionMenu($productID, 'story', 0, array_keys($branches)));
$modulePairs = $this->tree->getOptionMenu($productID, 'story', 0, array_keys($branches));
$branchModules = $branchProduct ? $modulePairs : array('0' => $modulePairs);
$modules = array($productID => $branchModules);
$plans = array($productID => $this->productplan->getBranchPlanPairs($productID, '', true));
$products = array($productID => $product);
$branchTagOption = array($productID => $branchTagOption);
+18 -3
View File
@@ -1845,7 +1845,7 @@ class storyModel extends model
$task = new stdclass();
$task->execution = $executionID;
$task->project = $projectID;
$task->project = $projectID ? $projectID : 0;
$task->name = $story->title;
$task->story = $story->id;
$task->type = $data->type;
@@ -1983,6 +1983,8 @@ class storyModel extends model
*/
public function setStage($storyID)
{
$this->loadModel('kanban');
$storyID = (int)$storyID;
$account = $this->app->user->account;
@@ -2014,7 +2016,11 @@ class storyModel extends model
{
$this->dao->update(TABLE_STORY)->set('stage')->eq('closed')->where('id')->eq($storyID)->exec();
foreach($stages as $branch => $stage) $this->dao->replace(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('closed')->exec();
foreach($executions as $execution => $branch) $this->dao->replace(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('closed')->exec();
foreach($executions as $execution => $branch)
{
$this->dao->replace(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('closed')->exec();
$this->kanban->updateLane($execution, 'story', $storyID);
}
return false;
}
@@ -2075,7 +2081,7 @@ class storyModel extends model
/* Get current stage and set as default value. */
$currentStage = $story->stage;
$stage = $currentStage;
$stage = $currentStage;
/* Cycle all tasks, get counts of every type and every status. */
$branchStatusList = array();
@@ -2167,6 +2173,15 @@ class storyModel extends model
$this->dao->update(TABLE_STORY)->set('stage')->eq(current($stages))->where('id')->eq($storyID)->exec();
}
$currentStory = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch();
if($story->stage != $currentStory->stage)
{
foreach($executions as $executionID => $branch)
{
$this->kanban->updateLane($executionID, 'story', $storyID);
}
}
return;
}
+1 -1
View File
@@ -151,7 +151,7 @@ class task extends control
/* Locate the browser. */
if($this->app->getViewType() == 'xhtml')
{
$taskLink = $this->createLink('task', 'view', "taskID=$taskID");
$taskLink = $this->createLink('task', 'view', "taskID=$taskID", 'html');
$response['locate'] = $taskLink;
return $this->send($response);
}
+2 -1
View File
@@ -458,7 +458,7 @@ class taskModel extends model
if(!empty($changes)) $this->action->logHistory($actionID, $changes);
}
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($kanbanID, 'task');
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($executionID, 'task');
return $mails;
}
@@ -1609,6 +1609,7 @@ class taskModel extends model
if($task->parent > 0) $this->updateParentStatus($task->id);
if($task->story) $this->loadModel('story')->setStage($task->story);
if(isset($data->status) and $task->status != $data->status) $this->loadModel('kanban')->updateLane($task->execution, 'task', $taskID);
if($task->status == 'done' and !dao::isError()) $this->loadModel('score')->create('task', 'finish', $taskID);
return $changes;
+3 -1
View File
@@ -207,7 +207,8 @@ js::set('suiteID', $suiteID);
</div>
</div>
<?php endif;?>
<?php if($canBatchChangeModule and !empty($productID) and $branch !== 'all'):?>
<?php if($canBatchChangeModule and !empty($productID)):?>
<?php if($product->type == 'normal' or ($product->type != 'normal' and $branch !== 'all')):?>
<div class="btn-group dropup">
<button data-toggle="dropdown" type="button" class="btn"><?php echo $lang->story->moduleAB;?> <span class="caret"></span></button>
<?php $withSearch = count($modules) > 6;?>
@@ -235,6 +236,7 @@ js::set('suiteID', $suiteID);
</div>
</div>
<?php endif;?>
<?php endif;?>
</div>
<div class="table-statistic"><?php echo $summary;?></div>
<?php $pager->show('right', 'pagerjs');?>
+1 -1
View File
@@ -69,7 +69,7 @@ class todo extends control
}
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $todoID));
if($this->viewType == 'xhtml') die(js::locate($this->createLink('todo', 'view', "todoID=$todoID"), 'parent'));
if($this->viewType == 'xhtml') die(js::locate($this->createLink('todo', 'view', "todoID=$todoID", 'html'), 'parent'));
if(isonlybody()) die(js::closeModal('parent.parent'));
die(js::locate($this->createLink('my', 'todo', "type=all&userID=&status=all&orderBy=id_desc"), 'parent'));
}
+30 -26
View File
@@ -130,32 +130,35 @@ class tutorialModel extends model
public function getProject()
{
$project = new stdclass();
$project->id = 2;
$project->project = 0;
$project->model = 'scrum';
$project->type = 'project';
$project->name = 'Test Project';
$project->code = '';
$project->lifetime = '';
$project->begin = date('Y-m-d', strtotime('-7 days'));
$project->end = date('Y-m-d', strtotime('+7 days'));
$project->realBegan = '';
$project->realEnd = '';
$project->days = 10;
$project->status = 'wait';
$project->pri = '1';
$project->desc = '';
$project->goal = '';
$project->acl = 'open';
$project->parent = 0;
$project->path = ',2,';
$project->grade = 1;
$project->PM = $this->app->user->account;
$project->PO = $this->app->user->account;
$project->QD = $this->app->user->account;
$project->RD = $this->app->user->account;
$project->budget = 0;
$project->deleted = '0';
$project->id = 2;
$project->project = 0;
$project->model = 'scrum';
$project->type = 'project';
$project->name = 'Test Project';
$project->code = '';
$project->lifetime = '';
$project->begin = date('Y-m-d', strtotime('-7 days'));
$project->end = date('Y-m-d', strtotime('+7 days'));
$project->realBegan = '';
$project->realEnd = '';
$project->days = 10;
$project->status = 'wait';
$project->pri = '1';
$project->desc = '';
$project->goal = '';
$project->acl = 'open';
$project->parent = 0;
$project->path = ',2,';
$project->grade = 1;
$project->PM = $this->app->user->account;
$project->PO = $this->app->user->account;
$project->QD = $this->app->user->account;
$project->RD = $this->app->user->account;
$project->openedBy = $this->app->user->account;
$project->whitelist = '';
$project->budget = 0;
$project->displayCards = 0;
$project->deleted = '0';
return $project;
}
@@ -291,6 +294,7 @@ class tutorialModel extends model
$execution->totalLeft = 0;
$execution->totalHours = 0;
$execution->totalEstimate = 0;
$execution->displayCards = 0;
return $execution;
}
+1 -1
View File
@@ -5401,7 +5401,7 @@ class upgradeModel extends model
$cell->kanban = $key[0];
$cell->lane = $key[1];
$cell->column = $key[2];
$cell->type = 'card';
$cell->type = 'common';
$cell->cards = $cards;
$this->dao->insert(TABLE_KANBANCELL)->data($cell)->exec();
+2 -2
View File
@@ -79,11 +79,11 @@ function p($keys = '', $delimiter = ',')
if(empty($_result)) return print(">> 0\n");
if(is_array($_result) and isset($_result['code']) and $_result['code'] == 'fail') return print(">> " . (string) $_result['message'] . "\n");
/* Print $_result. */
if(!$keys or !is_array($_result) and !is_object($_result)) return print(">> " . (string) $_result . "\n");
if(is_array($_result) and isset($_result['code']) and $_result['code'] == 'fail') return print(">> " . (string) $_result['message'] . "\n");
$parts = explode(';', $keys);
$values = array();
foreach($parts as $part)
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
su('admin');
/**
title=测试productModel->create();
cid=1
pid=1
*/
$config = new stdClass();
$config->createFields->product = array('program' => '', 'name' => '', 'code' => '', 'PO' => '', 'QD' => '', 'RD' => '', 'type' => 'normal', 'status' => 'normal', 'desc' => '', 'acl' => 'private');
function createObject($module = '', $param = array())
{
global $config;
foreach($config->createFields->$module as $field => $defaultValue) $_POST[$field] = $defaultValue;
foreach($param as $key => $value) $_POST[$key] = $value;
global $tester;
$objectModel = $tester->loadModel($module);
$objectID = $objectModel->create();
unset($_POST);
if(dao::isError())
{
return dao::getError();
}
else
{
$object = $objectModel->getByID($objectID);
return $object;
}
}
$create1 = array('name' => 'case1', 'code' => 'testcase1');
$create2 = array('name' => 'case2');
$create3 = array('name' => 'case1', 'code' => 'testcase1');
$create4 = array('code' => 'testcase1');
$create5 = array('name' => 'case3', 'code' => 'testcase3');
$create6 = array('program' => '3', 'name' => 'case4', 'code' => 'testcase4');
$create7 = array('program' => '4', 'name' => 'case5', 'code' => 'testcase5', 'type' => 'branch', 'status' => 'closed');
r(createObject('product', $create1)) && p('name') && e('case1'); // 测试正常的创建
r(createObject('product', $create2)) && p('code:0') && e('『code』不能为空。'); // 测试不填产品代号的情况
r(createObject('product', $create3)) && p('code:0') && e('『code』已经有『testcase1』这条记录了。如果您确定该记录已删除,请到后台-系统-数据-回收站还原。'); // 测试创建重复的产品
r(createObject('product', $create4)) && p('name:0') && e('『name』不能为空。'); // 测试不填产品名称的情况
r(createObject('product', $create5)) && p('name,code') && e('case3,testcase3'); // 测试传入name和code
r(createObject('product', $create6)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code
r(createObject('product', $create7)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status
system("./ztest init");
+91
View File
@@ -0,0 +1,91 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=productModel->getList();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->product = $tester->loadModel('product');
}
public function getAllProducts($programID)
{
return $this->product->getList($programID);
}
public function getAllProductsCount($programID)
{
return count($this->getAllProducts($programID));
}
public function getNoclosedProducts($programID)
{
return $this->product->getList($programID, 'noclosed');
}
public function getNoclosedProductsCount($programID)
{
return count($this->getNoclosedProducts($programID));
}
public function getClosedProducts($programID)
{
return $this->product->getList($programID, 'closed');
}
public function getClosedProductsCount($programID)
{
return count($this->getClosedProducts($programID));
}
public function getInvolvedProducts($programID)
{
return $this->product->getList($programID, 'involved');
}
public function getInvolvedProductsCount($programID)
{
return count($this->getInvolvedProducts($programID));
}
public function getProductsByLine($programID, $line = 0)
{
return $this->product->getList($programID, 'all', 0, $line);
}
public function countProductsByLine($programID, $line = 0)
{
return count($this->getProductsByLine($programID, $line));
}
public function getProductList($programID, $status = 'all', $line = 0)
{
return $this->product->getList($programID, $status, 0, $line);
}
public function getProductCount($programID, $status = 'all', $line = 0)
{
return count($this->getProductList($programID, $status, $line));
}
}
$adminTester = new Tester('admin');
r($adminTester->getAllProductsCount(1)) && p() && e('9'); // 返回项目集1下的产品数量
r($adminTester->getAllProductsCount(0)) && p() && e('100'); // 测试传入programID=0的情况
r($adminTester->getAllProductsCount(11)) && p() && e('0'); // 传入不存在的项目集
r($adminTester->getNoclosedProductsCount(1)) && p() && e('5'); // 返回项目集1下的未关闭的产品数量
r($adminTester->getNoclosedProductsCount(0)) && p() && e('60'); // 获取所有的未关闭的产品数量
r($adminTester->getClosedProductsCount(1)) && p() && e('4'); // 返回项目集1下的关闭了的产品数量
r($adminTester->getClosedProductsCount(0)) && p() && e('40'); // 返回所有的未关闭的产品数量
r($adminTester->getInvolvedProductsCount(1)) && p() && e('0'); // 返回项目集1下的与当前用户有关系的产品数量
r($adminTester->countProductsByLine(1, 1)) && p() && e('9'); // 返回项目集1下产品线1的产品数量
r($adminTester->countProductsByLine(1, 2)) && p() && e('0'); // 返回项目集1下产品线2的产品数量
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试productModel->getPairs();
cid=1
pid=1
*/
class Tester
{
public function __construct($user, $orderBy = 'id_desc')
{
global $tester;
su($user);
$this->product = $tester->loadModel('product');
$this->config = new stdclass();
$this->config->product->orderBy = $orderBy;
}
public function getProductPairs($programID)
{
$pairs = $this->product->getPairs('', $programID);
if($pairs == array()) return '没有数据';
return $pairs;
}
public function getProductPairsCount($programID)
{
$pairsCount = count($this->getProductPairs($programID));
if($pairsCount == '没有数据') return '0';
return $pairsCount;
}
public function getAllPairs($programID)
{
$pairs = $this->product->getPairs('all', $programID);
if($pairs == array()) return '没有数据';
return $pairs;
}
public function getAllPairsCount($programID)
{
$pairsCount = count($this->getAllPairs($programID));
if($pairsCount == '没有数据') return '0';
return $pairsCount;
}
public function getNoclosedPairs($programID)
{
$pairs = $this->product->getPairs('noclosed', $programID);
if($pairs == array()) return '没有数据';
return $pairs;
}
public function getNoclosedPairsCount($programID)
{
$pairsCount = count($this->getNoclosedPairs($programID));
if($pairsCount == '没有数据') return '0';
return $pairsCount;
}
public function getProductPairsByOrder($programID, $mode = '', $orderBy = 'id_desc')
{
$this->config->product->orderBy = $orderBy;
$pairs = $this->product->getPairs($mode, $programID);
return checkOrder($pairs, $orderBy);
}
}
$tester = new Tester('admin');
r($tester->getProductPairs(10)) && p('11') && e('正常产品11'); // 测试项目集10下的11号产品
r($tester->getProductPairs(10)) && p('55') && e('多分支产品55'); // 测试项目集10下的55号产品
r($tester->getProductPairs(10)) && p('99') && e('多平台产品99'); // 测试项目集10下的99号产品
r($tester->getProductPairs(11)) && p() && e('没有数据'); // 测试不存在的项目集
r($tester->getProductPairsCount(0)) && p() && e('100'); // 返回所有产品的数量
r($tester->getProductPairsCount(10)) && p() && e('9'); // 返回项目集10下的所有产品
r($tester->getNoclosedPairs(5)) && p('6') && e('正常产品6'); // 测试项目集10下的未关闭产品5
r($tester->getNoclosedPairsCount(10)) && p() && e('5'); // 返回项目集10下的未关闭产品的数量
r($tester->getProductPairsByOrder(10, '', 'program_desc')) && p() && e('1'); // 测试顺序program_desc
r($tester->getProductPairsByOrder(11, '', 'program_asc')) && p() && e('1'); // 测试顺序program_asc
r($tester->getProductPairsByOrder(11, '', 'type_desc')) && p() && e('1'); // 测试顺序type_desc
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php'; su('admin');
/**
title=测试productModel->update();
cid=1
pid=1
*/
function updateObject($module, $objectID, $param = array())
{
global $tester;
$objectModel = $tester->loadModel($module);
$object = $objectModel->getById($objectID);
foreach($object as $field => $value)
{
if(in_array($field, array_keys($param)))
{
$_POST[$field] = $param[$field];
}
else
{
$_POST[$field] = $value;
}
}
$change = $objectModel->update($objectID);
if($change == array()) $change = '没有数据更新';
unset($_POST);
if(dao::isError())
{
return dao::getError();
}
else
{
return $change;
}
}
$case1 = array('name' => 'john');
$case2 = array('code' => 'newcode1');
$case3 = array('name' => 'jack', 'code' => 'newcode2');
$case4 = array('name' => 'jack');
$case5 = array('code' => 'newcode2');
$case6 = array('name' => 'jack');
$case7 = array('code' => 'newcode2');
r(updateObject('product', 2, $case1)) && p('0:field,old,new') && e('name,正常产品2,john'); // 测试更新产品名称
r(updateObject('product', 2, $case2)) && p('0:field,old,new') && e('code,code2,newcode1'); // 测试更新产品代号
r(updateObject('product', 2, $case3)) && p('0:field,old,new;1:field,old,new') && e('name,john,jack;code,newcode1,newcode2'); // 测试更新产品名称和代号
r(updateObject('product', 2, $case4)) && p() && e('没有数据更新'); // 测试不更改产品名称
r(updateObject('product', 2, $case5)) && p() && e('没有数据更新'); // 测试不更改产品代号
r(updateObject('product', 13, $case6)) && p('name:0') && e('『产品名称』已经有『jack』这条记录了。如果您确定该记录已删除,请到后台-系统-数据-回收站还原。'); // 测试同一项目集下产品名称不能重复
r(updateObject('product', 13, $case7)) && p('code:0') && e('『产品代号』已经有『newcode2』这条记录了。如果您确定该记录已删除,请到后台-系统-数据-回收站还原。'); // 测试同一项目集下产品代号不能重复
system("./ztest init");
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::create();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
function create($data)
{
global $app;
$_POST = '';
$_POST = $data;
$programID = $this->program->create();
if(dao::isError()) return array('message' => dao::getError());
$program = $this->program->getById($programID);
$app->dbh->query("DELETE FROM ". TABLE_PROGRAM ." where name = '" . $data['name']. "'");
return $program;
}
function createData($status)
{
$data = array(
'parent' => 0,
'name' => '测试新增项目集一',
'budget' => '',
'budgetUnit' => 'CNY',
'begin' => '2022-01-12',
'end' => '2022-02-12',
'desc' => '测试项目集描述',
'acl' => 'private'
);
switch($status)
{
case '1': // 创建新项目集
break;
case '2': // 项目集名称为空时
$data['name'] = '';
break;
case '3': // 项目集的开始时间为空
$data['begin'] = '';
break;
case '4': // 项目集的完成时间为空
$data['end'] = '';
break;
case '5': // 项目集的计划完成时间大于计划开始时间
$data['end'] = '2022-01-10';
break;
case '6': // 项目集的完成日期大于父项目集的完成日期
$data['parent'] = '1';
$data['begin'] = '2018-01-01';
$data['end'] = '2022-02-10';
break;
default:
}
return $this->create($data);
}
}
$t = new Tester('admin');
r($t->createData(1)) && p('name') && e('测试新增项目集一'); // 创建新项目集
r($t->createData(2)) && p('message[name]:0') && e('『项目集名称』不能为空。'); // 项目集名称为空时
r($t->createData(3)) && p('message[begin]:0') && e('『计划开始』不能为空。'); // 项目集的开始时间为空
r($t->createData(4)) && p('message[end]:0') && e('『计划完成』不能为空。'); // 项目集的完成时间为空
r($t->createData(5)) && p('message[end]:0') && e('『计划完成』应当大于『2022-01-12』。'); // 项目集的计划完成时间大于计划开始时间
r($t->createData(6)) && p('message:begin;message:end') && e('父项目集的开始日期:2019-01-01,开始日期不能小于父项目集的开始日期;父项目集的完成日期:2019-01-01,完成日期不能大于父项目集的完成日期'); // 项目集的完成日期大于父项目集的完成日期
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::createStakeholder();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function createStakeholder($programID)
{
$_POST['accounts'] = array('dev1', 'dev2');
$stakeHolder = $this->program->createStakeholder($programID);
return $this->program->getStakeholdersByPrograms($programID);
}
}
$t = new Tester('admin');
/*CreateStakeholder($programID). */
r($t->createStakeholder(1)) && p('0:account;1:account') && e('dev2;dev1'); // 创建id=1的项目集的干系人dev1,dev2并查看。
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getBudgetLeft();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getBudgetLeft($programID)
{
$program = $this->program->getById(1);
return $this->program->getBudgetLeft($program);
}
}
$t = new Tester('admin');
/* GetBudgetLeft($program). */
r($t->getBudgetLeft(1)) && p() && e('0'); // 查看父项目集id=1的预算剩余
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getBudgetUnitList();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getBudgetUnitList()
{
global $app;
$app->loadConfig('project');
$app->loadLang('project');
return $this->program->getBudgetUnitList();
}
}
$t = new Tester('admin');
/* GetBudgetUnitList(). */
r($t->getBudgetUnitList()) && p('CNY;USD') && e('人民币;美元'); //获取货币类型列表
+28 -4
View File
@@ -8,9 +8,33 @@ title=测试 programModel::getById();
cid=1
pid=1
通过id字段获取存在的项目集 >> 测试项目集1
*/
$program = $tester->loadModel('program');
r($program->getById(1)) && p('name') && e('测试项目集1'); // 通过id字段获取存在的项目集
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getById($programID)
{
if(empty($this->program->getById($programID)))
{
return array('code' => 'fail', 'message' => 'Not Found');
}
else
{
return $this->program->getById($programID);
}
}
}
$t = new Tester('admin');
/* GetById($programID). */
r($t->getById(1)) && p('name') && e('项目集1'); // 通过id字段获取id=1的项目集并验证它的name。
r($t->getById(1000)) && p('message') && e('Not Found'); // 通过id字段获取id=1000的项目集并验证它的name。
+42
View File
@@ -0,0 +1,42 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel:: getChildren();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getChildren($programID)
{
$programInfo = $this->program->getChildren($programID);
if(empty($programInfo))
{
return array('code' => 'fail' , 'message' => 'Not Found');
}
else
{
return $programInfo;
}
}
}
$t = new Tester('admin');
/* GetChildren($programID). */
r($t->getChildren(1)) && p() && e('9'); // 通过id查找id=1的子项目集个数
r($t->getChildren(220)) && p() && e('5'); // 通过id查找id=220的子项目集个数
r($t->getChildren(221)) && p('message') && e('Not Found'); // 通过id查找id=221的子项目集个数
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getInvolvedPrograms();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getInvolvedPrograms($account)
{
return $this->program->getInvolvedPrograms($account);
}
}
$t = new Tester('admin');
/* GetInvolvedPrograms($account). */
r($t->getInvolvedPrograms('admin')) && p('122') && e('122'); // 查看用户admin可以看到的项目和执行id列表
r($t->getInvolvedPrograms('test2')) && p('1;122') && e('1;122'); // 查看用户test2可以看到的项目和执行id列表
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
su('admin');
/**
title=测试 programModel::getKanbanGroup();
cid=1
pid=1
*/
$program = $tester->loadModel('program');
$result = 'Not Found';
r($program->getKanbanGroup()) && p() && e('');
if(empty($program->getKanbanGroup()['my'])) r($result) && p() && e($result); // 获取我的看板组
if(empty($program->getKanbanGroup()['other'])) r($result) && p() && e($result); // 获取其他看板组
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getList();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getListByStatus($status)
{
$this->program->cookie->showClosed = ture;
$programs = $this->program->getList($status);
if(!$programs) return 0;
foreach($programs as $program)
{
if($program->status != $status and $status != 'all') return 0;
}
return count($programs);
}
public function getListByOrder($orderBy)
{
$programs = $this->program->getList('all', $orderBy);
return checkOrder($programs, $orderBy);
}
}
$t = new Tester('admin');
/* GetList($status). */
r($t->getListByStatus('all')) && p() && e('100'); // 查看所有项目和项目集的个数
r($t->getListByStatus('wait')) && p() && e('34'); // 查看所有'wait'的项目和项目集的个数
r($t->getListByStatus('doing')) && p() && e('44'); // 查看所有'doing'的项目和项目集的个数
r($t->getListByStatus('suspended')) && p() && e('11'); // 查看所有'suspended'的项目和项目集的个数
r($t->getListByStatus('closed')) && p() && e('11'); // 查看所有'closed'的项目和项目集的个数
/* GetList('all', $orderBy). */
r($t->getListByOrder('name_desc')) && p() && e(1); // 按照项目和项目集名称倒序获取项目列表
r($t->getListByOrder('id_asc')) && p() && e(1); // 按照ID正序获取项目和项目集列表
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getPairs();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getPairs()
{
$programs = $this->program->getPairs();
if(!$programs) return 0;
return $programs;
}
public function getCount()
{
return count($this->program->getPairs());
}
}
$t = new Tester('admin');
/* Count().*/
r($t->getCount()) && p() && e('10'); // 获取项目集个数
/* GetPairs().*/
r($t->getPairs()) && p('1') && e('项目集1'); // 获取项目集id/name 的关联数组
r($t->getPairs()) && p('9') && e('项目集9'); // 获取项目集id/name 的关联数组
r($t->getPairs()) && p('11') && e(''); // 获取不存在的项目集id/name 的关联数组
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getPairsByList();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getPairsByList($programIDList = '')
{
if(empty($this->program->getPairsByList($programIDList)))
{
return array('code' => 'fail', 'message' => 'Not Found');
}
else
{
return $this->program->getPairsByList($programIDList);
}
}
}
$t = new Tester('admin');
/* GetPairsByList($programIDList). */
r($t->getPairsByList('1')) && p('1') && e('项目集1'); // 通过字符串'1'获取项目集名称
r($t->getPairsByList('1,2,3')) && p('1,2,3') && e('项目集1,项目集2,项目集3'); // 通过字符串'1,2,3'获取项目集名称
r($t->getPairsByList(array(1))) && p('1') && e('项目集1');//通过数组array(1)获取项目集名称
r($t->getPairsByList(array(1,2,3))) && p('1,2,3') && e('项目集1,项目集2,项目集3');//通过数组array(1,2,3)获取项目集名称
r($t->getPairsByList()) && p('message') && e('Not Found');// 通过id为空获取项目集名称
r($t->getPairsByList('0')) && p('message') && e('Not Found');// 通过id=0获取项目集名称
r($t->getPairsByList('11')) && p('message') && e('Not Found');// 通过id=11获取项目集名称
+40
View File
@@ -0,0 +1,40 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getParentPairs();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su(%$user);
$this->program = $tester->loadModel('program');
}
public function getParentPairs()
{
return $this->program->getParentPairs();
}
public function getCount()
{
return count($this->program->getParentPairs());
}
}
$t = new Tester('admin');
/* Count(). */
r($t->getCount()) && p() && e('11'); //
/* GetParentPairs(). */
r($t->getParentPairs()) && p('1') && e(''); // 获取父项目集的id/name关联数组
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getParentPM();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getParentPM($programIdList)
{
return $this->program->getParentPM($programIdList);
}
}
$t = new Tester('admin');
/* GetParentPM($programIdList). */
r($t->getParentPM('1')) && p() && e('0'); //
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getProductPairs();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getProductPairsByID($programID = 0)
{
$program = $this->program->getByID($programID);
if(empty($program)) return array('message' => 'Not Found');
return $this->program->getProductPairs($programID, 'assign', 'all');
}
public function getProductPairsByMod($mode = 'assign')
{
return $this->program->getProductPairs(1, $mode, 'noclosed');
}
public function getProductPairsByStatus($status = 'all')
{
return $this->program->getProductPairs(1, 'assign', $status);
}
public function getCount($programID = 0, $mode = 'assign', $status = 'all')
{
return count($this->program->getProductPairs($programID, $mode, $status));
}
}
$t = new Tester('admin');
/* GetProductPairs($programID). */
r($t->getProductPairsByID('1')) && p('23') && e('已关闭的正常产品23'); //根据项目或项目集ID获取关联产品详情
r($t->getProductPairsByID('1000')) && p('message') && e('Not Found'); //获取不存在的项目或项目集
/* GetProductPairs('all', $mode, 'noclosed'). */
r($t->getProductPairsByMod('all')) && p('1') && e('正常产品1'); // 根据项目或项目集指派情况获取关联产品详情
/* GetProductPairs('all', 'assign', $status). */
r($t->getProductPairsByStatus('all')) && p('100') && e('多平台产品100'); //根据项目或项目集状态获取关联产品详情
/* Count().*/
r($t->getCount('1', 'assign', 'all')) && p() && e('10'); //查看ID=1,有指派,所有状态的关联产品数量
r($t->getCount('1', 'assign', 'noclosed')) && p() && e('6'); //查看ID=1,有指派,未关闭的关联产品数量
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModee::getProgressList();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getProgressList()
{
return $this->program->getProgressList();
}
public function getCount()
{
return count($this->program->getProgressList());
}
}
$t = new Tester('admin');
/* Count(). */
r($t->getCount()) && p() && e('100'); // 获取项目和项目集的个数
/* GetProgressList(). */
r($t->getProgressList()) && p('1') && e('0'); // 获取id=1的项目的进度
r($t->getProgressList()) && p('11') && e('0'); // 获取id=11的项目集的进度
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getProjectList();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
$this->config->systemMode = 'new';
}
public function getListByProgramID($programID = 0)
{
return count($this->program->getProjectList($programID));
}
public function getListByStatus($browseType = 'all')
{
$projects = $this->program->getProjectList('0', $browseType);
if(!$projects) return 0;
foreach($projects as $project)
{
if($project->status != $browseType and $browseType != 'all' and $browseType != 'undone') return 0;
if($browseType == 'undone' and ($project->status != ('wait' or 'doing'))) return 0;
}
return count($projects);
}
public function getListByOrder($orderBy = 'id_desc')
{
$projects = $this->program->getProjectList('0', 'all', '0', $orderBy);
return checkOrder($projects, $orderBy);
}
public function getListAddProgramTitle($programTitle = 0)
{
return $this->program->getProjectList('0', 'all', '0', 'id_desc', '', $programTitle);
}
public function getListByInvolved($involved = 0, $count = '')
{
$projects = $this->program->getProjectList('0', 'all', '0', 'id_desc', '', '0', $involved);
if($count == 'count') return count($projects);
return $projects;
}
}
$t = new Tester('admin');
/* GetProjectList($programID). */
r($t->getListByProgramID(0)) && p() && e('90'); // 查看当前项目集下所有项目的个数
/* GetProjectList(0, $browseType). */
r($t->getListByStatus('doing')) && p() && e('44'); // 查看当前项目集下所有状态为进行中的项目的个数
/* GetProjectList(0, 'all', 0, $orderBy). */
r($t->getListByOrder('name_desc')) && p() && e('1'); // 根据name倒序查看所有项目
r($t->getListByOrder('id_desc')) && p() && e('1'); // 根据id倒序查看所有项目的个数
/* GetProjectList(0, 'all', 0, 'id_desc', '', $programTitle). */
r($t->getListAddProgramTitle(0)) && p('11:name') && e('项目1'); // 查看所有项目(包含所属项目集名称)
/* GetProjectList(0, 'all', 0, 'id_desc', '', 0, $involved). */
r($t->getListByInvolved(1)) && p('11:name') && e('项目1'); // 查看当前用户参与的项目
r($t->getListByInvolved(1, 'count')) && p() && e('1'); // 查看当前用户参与的项目的个数
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getProjectStats();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getStatsByProgramID($programID = 0)
{
return count($this->program->getProjectStats($programID));
}
public function getStatsByStatus($browseType = 'all')
{
$projects = $this->program->getProjectStats('0', $browseType);
if(!$projects) return 0;
foreach($projects as $project)
{
if($project->status != $browseType and $browseType != 'all' and $browseType != 'undone') return 0;
if($browseType == 'undone' and ($project->status != ('wait' or 'doing'))) return 0;
}
return count($projects);
}
public function getStatsByOrder($orderBy = 'id_desc')
{
$projects = $this->program->getProjectStats('0', 'all', '0', $orderBy);
return checkOrder($projects, $orderBy);
}
public function getStatsAddProgramTitle($programTitle = 0)
{
return $this->program->getProjectStats('0', 'all', '0', 'id_desc', '', $programTitle);
}
public function getStatsByInvolved($involved = 0, $count = '')
{
$projects = $this->program->getProjectStats('0', 'all', '0', 'id_desc', '', '0', $involved);
if($count == 'count') return count($projects);
return $projects;
}
}
$t = new Tester('admin');
/* GetProjectStats($programID). */
r($t->getStatsByProgramID(0)) && p() && e('68'); // 查看当前项目集下所有未开始和进行中的项目的个数
/* GetProjectStats(0, $browseType). */
r($t->getStatsByStatus('doing')) && p() && e('44'); // 查看当前项目集下所有状态为进行中的项目的个数
/* GetProjectStats(0, 'all', 0, $orderBy). */
r($t->getStatsByOrder('name_desc')) && p() && e('1'); // 根据name倒序查看所有项目
r($t->getStatsByOrder('id_desc')) && p() && e('1'); // 根据id倒序查看所有项目的个数
/* GetProjectStats(0, 'all', 0, 'id_desc', '', $programTitle). */
r($t->getStatsAddProgramTitle(0)) && p('11:name') && e('项目1'); // 查看所有项目(包含所属项目集名称)
/* GetProjectStats(0, 'all', 0, 'id_desc', '', 0, $involved). */
r($t->getStatsByInvolved(1)) && p('11:name') && e('项目1'); // 查看当前用户参与的项目
r($t->getStatsByInvolved(1, 'count')) && p() && e('1'); // 查看当前用户参与的项目的个数
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getStakeholders();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getByID($programID = 0)
{
$stakeholders = $this->program->getStakeholders($programID);
return $stakeholders;
}
public function getByOrder($orderBy = 'id_desc')
{
$stakeholders = $this->program->getStakeholders(2, $orderBy);
return checkOrder($stakeholders, $orderBy);
}
public function getCount($programID = 0)
{
$stakeholders = $this->program->getStakeholders($programID);
return count($stakeholders);
}
}
$t = new Tester('admin');
/* GetStakeholders($programID). */
r($t->getByID(2)) && p() && e('0'); // 查看项目集2的干系人信息
/* GetStakeholders('2', $orderBy). */
r($t->getByOrder('id_desc')) && p() && e('1'); // 根据干系人id倒序排序
r($t->getByOrder('id_asc')) && p() && e('1'); // 根据干系人id正序排序
/* Count(). */
r($t->getCount(2)) && p() && e('0'); // 查看项目集2的干系人个数
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getStakeholdersByPrograms();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getByPrograms($programIdList = 0)
{
$stakeHolders = $this->program->getStakeholdersByPrograms($programIdList);
return $stakeHolders;
}
public function getCount($programIdList = 0)
{
$stakeHolders = $this->program->getStakeholdersByPrograms($programIdList);
return count($stakeHolders);
}
}
$t = new Tester('admin');
/* GetStakeholdersByPrograms($programIdList). */
r($t->getByPrograms('2')) && p() && e('0'); // 获取项目集2的干系人名单
r($t->getByPrograms('2,3')) && p() && e('0'); // 获取项目集2和项目集3的干系人名单
/* Count(). */
r($t->getCount('2')) && p() && e('0'); // 获取项目集2的干系人个数
r($t->getCount('2,3')) && p() && e('0'); // 获取项目集2和项目集3的干系人个数
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getTeamMemberPairs();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getById($programID)
{
if(empty($this->program->getTeamMemberPairs($programID)))
{
return array('code' => 'fail', 'message' => 'Not Found');
}
else
{
return $this->program->getTeamMemberPairs($programID);
}
}
public function getCount($programID)
{
return count($this->program->getTeamMemberPairs($programID));
}
}
$t = new Tester('admin');
/* GetTeamMemberPairs($programID). */
r($t->getById(1)) && p('user89') && e('U:测试89'); //获取项目集下所有团队成员
r($t->getCount(1)) && p() && e('181'); // 获取项目集下所有团队成员
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
su('dev1');
/**
title=测试 programModel::getTopByID();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getById($programID = 0)
{
if(empty($this->program->getTopById($programID)))
{
return array('code' => 'fail', 'message' => 'Not Found');
}
else
{
return $this->program->getByTopId($programID);
}
}
}
$t = new Tester('admin');
/* GetTopById($programID). */
r($t->getByID(1)) && p('message') && e('Not Found'); // 获取项目集1最上级的项目集id
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::getTopPairs();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getTopPairs($count = '')
{
if($count == 'count') return count($this->program->getTopPairs());
return $this->program->getTopPairs();
}
}
$t = new Tester('admin');
/* getTopPairs(). */
r($t->getTopPairs()) && p('1') && e('项目集1'); // 查看id=1的父项目集
/* Count(). */
r($t->getTopPairs('count')) && p() && e('10'); // 查看父项目集的个数
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::hasUnfinished();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function getUnfinished($programID)
{
$program = $this->program->getById($programID);
return $this->program->hasUnfinished($program);
}
}
$t = new Tester('admin');
/* HasUnfinished($program). */
r($t->getUnfinished(1)) && p() && e('88'); // 获取项目集1下未完成的项目和项目集
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::processNode();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
}
$t = new Tester('admin');
$program = $tester->loadModel('program');
r($program->processNode(1, 0, 1, 1)) && p() && e(''); //
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::setTreePath();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
public function setTreePath($programID)
{
$programPath = $this->program->setTreePath($programID);
if($programPath)
{
return $this->program->getById($programID);
}
else
{
return 0;
}
}
}
$t = new Tester('admin');
/* SetTreePath($programID). */
r($t->setTreePath(12)) && p('path') && e('12,'); // 查找id=11的项目集的path
r($t->setTreePath(1000)) && p('path') && e('0'); // 查找不存在的id=1000的项目集的path
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 programModel::update($programID);
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->program = $tester->loadModel('program');
}
function update($programID, $data)
{
global $app;
$_POST = $data;
$result = $this->program->update(10);
if(dao::isError()) return array('message' => dao::getError());
$app->dbh->query("UPDATE " . TABLE_PROGRAM . " SET name = '" . $result[0]['old']. "' where id = '" . $programID . "'");
return $result;
}
function updateProgram($programID, $status = 0)
{
$data = array(
'parent' => '0',
'name' => '测试更新项目集十',
'begin' => '2020-10-10',
'end' => '2020-10-11',
'acl' => 'private',
'budget' => '100',
'budgetUnit' => 'CNY'
);
switch($status)
{
case '1': // 项目集名称已经存在时
$data['name'] = '项目集1';
break;
case '2': // 当计划开始为空时更新项目集信息
$data['begin'] = '';
break;
case '3': // 当计划完成为空时更新项目集信息
$data['end'] = '';
break;
case '4': // 当计划完成小于计划开始时
$data['end'] = '2020-01-01';
break;
case '5': // 项目集开始时间小于父项目集时
$data['parent'] = '9';
$data['begin'] = '2019-01-01';
break;
default: // 更新id为10的项目集信息
}
return $this->update($programID, $data);
}
}
$t = new Tester('admin');
r($t->updateProgram(10)) && p('0:new') && e('测试更新项目集十');// 更新id为10的项目集信息
r($t->updateProgram(10, 2)) && p('message[begin]:0') && e('『计划开始』不能为空。');// 当计划开始为空时更新项目集信息
r($t->updateProgram(10, 3)) && p('message[end]:0') && e('『计划完成』不能为空。');// 当计划完成为空时更新项目集信息
r($t->updateProgram(10, 4)) && p('message[end]:0') && e('『计划完成』应当大于『2020-10-10』。');// 当计划完成小于计划开始时
r($t->updateProgram(10, 1)) && p('message[name]:0') && e('『项目集名称』已经有『项目集1』这条记录了。如果您确定该记录已删除,请到后台-系统-数据-回收站还原。');// 项目集名称已经存在时
r($t->updateProgram(10, 5)) && p('message:begin;message:end') && e('父项目集的开始日期:2019-09-09,开始日期不能小于父项目集的开始日期;父项目集的完成日期:2019-09-09,完成日期不能大于父项目集的完成日期');// 项目集开始时间小于父项目集时
+88 -6
View File
@@ -10,13 +10,95 @@ pid=1
*/
$project = $tester->loadModel('project');
class Tester
{
public function __construct($user)
{
global $tester;
r($project->getByID(11)) && p('code,type') && e('project1,project'); // 获取ID等于11的项目
su($user);
$this->project = $tester->loadModel('project');
}
$result = empty($project->getByID(0)) ? 'No Data!' : '';
r($result) && p() && e('No Data!'); // 获取ID等于0的项目
/**
* Get project by ID.
*
* @param int $projectID
* @access public
* @return object
*/
public function getProjectByID($projectID)
{
return $this->project->getByID($projectID);
}
r($project->getByID(1, 'program')) && p('name,type') && e('项目集1,program'); // 获取ID等于0的项目集
/**
* Get program by ID.
*
* @param int $programID
* @access public
* @return object
*/
public function getProgramByID($programID)
{
return $this->project->getByID($programID, 'program');
}
r($project->getByID(101, 'sprint')) && p('name,type') && e('迭代1,sprint'); // 获取ID等于101的迭代
/**
* Get sprint by ID.
*
* @param int $sprintID
* @access public
* @return object
*/
public function getSprintByID($sprintID)
{
return $this->project->getByID($sprintID, 'sprint');
}
/**
* Get stage by ID.
*
* @param int $stageID
* @access public
* @return object
*/
public function getStageByID($stageID)
{
return $this->project->getByID($stageID, 'stage');
}
/**
* Get Kanban by ID,
*
* @param int $kanbanID
* @access public
* @return void
*/
public function getKanbanByID($kanbanID)
{
return $this->project->getByID($kanbanID, 'kanban');
}
}
$t = new Tester('admin');
/* Get project by ID. */
r($t->getProjectByID(11)) && p('code,type') && e('project1,project'); //获取ID等于11的项目
r($t->getProjectByID(0)) && p('code,type') && e('0'); //获取不存在的项目
/* Get program by ID. */
r($t->getProgramByID(1)) && p('code,type') && e('program1,program'); //获取ID等于1的项目集
r($t->getProgramByID(0)) && p('code,type') && e('0'); //获取不存在的项目集
/* Get sprint by ID. */
r($t->getSprintByID(101)) && p('code,type') && e('project1,sprint'); //获取ID等于101的冲刺
r($t->getSprintByID(0)) && p('code,type') && e('0'); //获取不存在的冲刺
/* Get stage by ID. */
r($t->getStageByID(131)) && p('code,type') && e('project31,stage'); //获取ID等于131的阶段
r($t->getStageByID(0)) && p('code,type') && e('0'); //获取不存在的阶段
/* Get Kanban by ID. */
r($t->getKanbanByID(161)) && p('code,type') && e('project61,kanban'); //获取ID等于161的阶段
r($t->getKanbanByID(0)) && p('code,type') && e('0'); //获取不存在的看板
+3 -3
View File
@@ -23,9 +23,9 @@ class Tester
/**
* Check projectList get from getByIdList.
*
* @param array $projectIdList
* @param int $count
*
* @param array $projectIdList
* @param int $count
* @access public
* @return array
*/
+54 -6
View File
@@ -2,6 +2,14 @@
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 projectModel::getOverviewList;
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
@@ -12,23 +20,62 @@ class Tester
$this->project = $tester->loadModel('project');
}
/**
* Get project by status.
*
* @param string $status
* @access public
* @return int
*/
public function getBystatus($status)
{
$projects = $this->project->getOverviewList('byStatus', $status);
if(!$projects) return 0;
if(!$projects)
{
$result = array();
$result['code'] = 'fail';
$result['message'] = 'No data.';
return $result;
}
if($status == 'undone') $status = 'wait,doing,suspended';
foreach($projects as $project)
{
if($project->status != $status) return 0;
if(strpos(",$status,", $project->status) === false)
{
$result = array();
$result['code'] = 'fail';
$result['message'] = 'Error data.';
return $result;
}
}
return count($projects);
}
/**
* Get project list by order.
*
* @param string $orderBy
* @access public
* @return void
*/
public function getListByOrder($orderBy)
{
$projects = $this->project->getOverviewList('byStatus', 'wait', $orderBy);
return checkOrder($projects, $orderBy);
}
/**
* Get project by ID.
*
* @param int $projectID
* @access public
* @return void
*/
public function getByID($projectID)
{
return $this->project->getOverviewList('byID', $projectID);
@@ -38,12 +85,13 @@ class Tester
$t = new Tester('admin');
/* GetOverviewList('byStatus'). */
r($t->getByStatus('wait')) && p('') && e('15'); // 获取未开始的项目
r($t->getByStatus('wait')) && p() && e('15'); // 获取未开始的项目
r($t->getByStatus('undone')) && p() && e('15'); // 获取状态不为done和closed的项目
/* GetOverviewList('byID', $id). */
r($t->getByID(11)) && p('11:id') && e('11'); // 根据项目ID获取项目详情
r($t->getByID(10000)) && p('id') && e(''); // 获取不存在的项目
r($t->getByID(10000)) && p('id') && e('0'); // 获取不存在的项目
/* GetOverviewList('byStatus', 'wait', $orderBy). */
r($t->getListByOrder('id_asc')) && p() && e('true'); // 按照ID正序获取项目列表
r($t->getListByOrder('name_desc')) && p() && e('true'); // 按照项目名称倒序获取项目列表
r($t->getListByOrder('id_asc')) && p() && e('1'); //按照ID正序获取项目列表
r($t->getListByOrder('name_desc')) && p() && e('1'); // 按照项目名称倒序获取项目列表
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 projectModel::getPairsByIdList;
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->project = $tester->loadModel('project');
}
/**
* Get project pairs by ID list.
*
* @param array $IDList
* @access public
* @return int
*/
public function getByIdList($IDList)
{
$projects = $this->project->getPairsByIdList($IDList);
if(empty($projects))
{
$result = array();
$result['code'] = 'fail';
$result['message'] = 'No data.';
return $result;
}
foreach($projects as $projectID => $projectName)
{
if(!empty($IDList) and !in_array($projectID, $IDList))
{
$result = array();
$result['code'] = 'fail';
$result['message'] = 'Error Data.';
return $result;
}
}
return count($projects);
}
}
$t = new Tester('admin');
r($t->getByIdList(array(0,11,12,13))) && p() && e('3'); //查找ID为0、11、12、13的项目
r($t->getByIdList(array())) && p() && e('90'); //查找所有项目
+93
View File
@@ -0,0 +1,93 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 projectModel::getPairsByProgram;
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->project = $tester->loadModel('project');
}
/**
* Get project pairs by programID.
*
* @param int $programID
* @access public
* @return int
*/
public function getByProgram($programID)
{
$projects = $this->project->getPairsByProgram($programID);
if(empty($projects))
{
$result = array();
$result['code'] = 'fail';
$result['message'] = 'No data.';
return $result;
}
return count($projects);
}
/**
* Get project pairs by status.
*
* @param string $status
* @access public
* @return int
*/
public function getByStatus($status)
{
$projects = $this->project->getPairsByProgram(2, $status);
if(empty($projects))
{
$result = array();
$result['code'] = 'fail';
$result['message'] = 'No data.';
return $result;
}
return count($projects);
}
/**
* Get project list by order.
*
* @param string $orderBy
* @access public
* @return int
*/
public function getListByOrder($orderBy)
{
$projects = $this->project->getPairsByProgram(3, 'doing', $orderBy);
return checkOrder($projects, $orderBy);
}
}
$t = new Tester('admin');
/* Get project list by program ID. */
r($t->getByProgram('')) && p() && e('90'); //查找管理员可查看的所有项目
r($t->getByProgram(0)) && p() && e('No data.'); //查找独立项目
r($t->getByProgram(1)) && p() && e('9'); //查找管理员可查看的所属项目集ID为1的项目
/* Get project list by status. */
r($t->getByStatus('wait')) && p() && e('3'); //查找管理员可查看的所属项目集ID为1且状态为wait的项目
r($t->getByStatus('noclosed')) && p() && e('7'); //查找管理员可查看的所属项目集ID为1且状态不为closed的项目
/* Get project list by order. */
r($t->getListByOrder('id_desc')) && p() && e('1'); //按照ID降序排序查找项目
+13
View File
@@ -0,0 +1,13 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 projectModel::getProjectsConsumed;
cid=1
pid=1
*/
$project = $tester->loadModel('project');
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 projectModel::checkHasContent;
cid=1
pid=1
*/
$project = $tester->loadModel('project');
+2 -4
View File
@@ -12,7 +12,5 @@ pid=1
$project = $tester->loadModel('project');
$result = empty($project->getSwitcher(11, 'project', 'browse')) ? 'Return!' : '';
r($result) && p() && e('Return'); // 获取项目下拉菜单,项目列表页面没有项目下拉菜单
r($project->getSwitcher(11, 'project', 'execution')) && p() && e("<span class='text'>项目1</span>"); // 获取项目ID为11的迭代列表页面的项目下拉菜单,查看是否包含项目ID为11的名称
r($project->getSwitcher(11, 'project', 'browse')) && p() && e('0'); //获取项目下拉菜单,项目列表页面没有项目下拉菜单
r($project->getSwitcher(11, 'project', 'execution')) && p() && e("<span class='text'>项目1</span>"); //获取项目ID为11的迭代列表页面的项目下拉菜单,查看是否包含项目ID为11的名称
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试 projectModel::getTotalBugByProject;
cid=1
pid=1
*/
+4
View File
@@ -17,24 +17,28 @@ $doingProject = $projectModel->getByID(13);
$suspendProject = $projectModel->getByID(17);
$closedProject = $projectModel->getByID(18);
/* Check wait project. */
r($projectModel->isClickable($waitProject, 'start')) && p() && e('1'); // 检查未开始项目的开始按钮
r($projectModel->isClickable($waitProject, 'finish')) && p() && e('1'); // 检查未开始项目的完成按钮
r($projectModel->isClickable($waitProject, 'close')) && p() && e('1'); // 检查未开始项目的关闭按钮
r($projectModel->isClickable($waitProject, 'suspend')) && p() && e('1'); // 检查未开始项目的暂停按钮
r($projectModel->isClickable($waitProject, 'activate')) && p() && e('0'); // 检查未开始项目的激活按钮
/* Check doing project. */
r($projectModel->isClickable($doingProject, 'start')) && p() && e('0'); //检查进行中项目的开始按钮
r($projectModel->isClickable($doingProject, 'finish')) && p() && e('1'); //检查进行中项目的完成按钮
r($projectModel->isClickable($doingProject, 'close')) && p() && e('1'); //检查进行中项目的关闭按钮
r($projectModel->isClickable($doingProject, 'suspend')) && p() && e('1'); //检查进行中项目的暂停按钮
r($projectModel->isClickable($doingProject, 'activate')) && p() && e('0'); //检查进行中项目的激活按钮
/* Check suspend project. */
r($projectModel->isClickable($suspendProject, 'start')) && p() && e('1'); //检查已暂停项目的开始按钮
r($projectModel->isClickable($suspendProject, 'finish')) && p() && e('0'); //检查已暂停项目的完成按钮
r($projectModel->isClickable($suspendProject, 'close')) && p() && e('1'); //检查已暂停项目的关闭按钮
r($projectModel->isClickable($suspendProject, 'suspend')) && p() && e('0'); //检查已暂停项目的暂停按钮
r($projectModel->isClickable($suspendProject, 'activate')) && p() && e('0'); //检查已暂停项目的激活按钮
/* Check closed project. */
r($projectModel->isClickable($closedProject, 'start')) && p() && e('0'); //检查已关闭项目的开始按钮
r($projectModel->isClickable($closedProject, 'finish')) && p() && e('0'); //检查已关闭项目的完成按钮
r($projectModel->isClickable($closedProject, 'close')) && p() && e('0'); //检查已关闭项目的关闭按钮
+3
View File
@@ -19,6 +19,9 @@ switch($argv[1])
case 'control':
ztfRun('control');
break;
case 'program':
ztfRun('model/program');
break;
case 'model':
ztfRun('model');
break;
@@ -25,17 +25,16 @@ class xuanxuanIm extends imModel
$products = empty($products) ? array() : array_keys($products);
$executions = empty($executions) ? array() : array_keys($executions);
$libIdList = array_keys($this->loadModel('doc')->getLibs('all'));
$productID = isset($products[0]) ? $products[0] : 1;
$executionID = isset($executions[0]) ? $executions[0] : 1;
$productID = isset($products[0]) ? $products[0] : 0;
$executionID = isset($executions[0]) ? $executions[0] : 0;
$libID = isset($libIdList[0]) ? $libIdList[0] : 1;
$actions = new stdclass();
if(common::hasPriv('bug', 'create') and !empty($products)) $actions->createBug = array('title' => $this->lang->im->createBug, 'url' => $baseURL . str_replace('/x.php', '/index.php', helper::createLink('bug', 'create', "product=$productID", 'xhtml')), 'height' => "600px", 'width' => "1200px");
if(common::hasPriv('story', 'create') and !empty($products)) $actions->createStory = array('title' => $this->lang->im->createStory, 'url' => $baseURL . str_replace('/x.php', '/index.php', helper::createLink('story', 'create', "product=$productID", 'xhtml')), 'height' => "600px", 'width' => "1200px");
if(common::hasPriv('task', 'create') and !empty($executions))$actions->createTask = array('title' => $this->lang->im->createTask, 'url' => $baseURL . str_replace('/x.php', '/index.php', helper::createLink('task', 'create', "execution=$executionID", 'xhtml')), 'height' => "600px", 'width' => "1200px");
if(common::hasPriv('doc', 'create') and !empty($libIdList)) $actions->createDoc = array('title' => $this->lang->im->createDoc, 'url' => $baseURL . str_replace('/x.php', '/index.php', helper::createLink('doc', 'create', "objectType=&objectID=0&libID=0", 'xhtml')), 'height' => "600px", 'width' => "1200px");
if(common::hasPriv('todo', 'create')) $actions->createTodo = array('title' => $this->lang->im->createTodo, 'url' => $baseURL . str_replace('/x.php', '/index.php', helper::createLink('todo', 'create', '', 'xhtml')), 'height' => "600px", 'width' => "1200px");
if(common::hasPriv('bug', 'create')) $actions->createBug = array('title' => $this->lang->im->createBug, 'url' => $baseURL . str_replace('/x.php', '/index.php', helper::createLink('bug', 'create', "product=$productID", 'xhtml')), 'height' => "600px", 'width' => "1200px");
if(common::hasPriv('story', 'create')) $actions->createStory = array('title' => $this->lang->im->createStory, 'url' => $baseURL . str_replace('/x.php', '/index.php', helper::createLink('story', 'create', "product=$productID", 'xhtml')), 'height' => "600px", 'width' => "1200px");
if(common::hasPriv('task', 'create')) $actions->createTask = array('title' => $this->lang->im->createTask, 'url' => $baseURL . str_replace('/x.php', '/index.php', helper::createLink('task', 'create', "execution=$executionID", 'xhtml')), 'height' => "600px", 'width' => "1200px");
if(common::hasPriv('doc', 'create')) $actions->createDoc = array('title' => $this->lang->im->createDoc, 'url' => $baseURL . str_replace('/x.php', '/index.php', helper::createLink('doc', 'create', "objectType=&objectID=0&libID=0", 'xhtml')), 'height' => "600px", 'width' => "1200px");
if(common::hasPriv('todo', 'create')) $actions->createTodo = array('title' => $this->lang->im->createTodo, 'url' => $baseURL . str_replace('/x.php', '/index.php', helper::createLink('todo', 'create', '', 'xhtml')), 'height' => "600px", 'width' => "1200px");
$urls = array();
foreach($this->config->im->cards as $moduleName => $methods)
{