Merge branch 'master' into 'sprint/32_zhouxin_fixbugs'
# Conflicts: # module/project/config.php
This commit is contained in:
@@ -296,5 +296,5 @@ $config->newFeatures = array('introduction', 'tutorial', 'youngBlueTheme');
|
||||
|
||||
/* Program privs.*/
|
||||
$config->programPriv = new stdclass();
|
||||
$config->programPriv->scrum = array('projectstory', 'projectrelease', 'project', 'build', 'bug', 'testcase', 'testreport', 'caselib', 'doc', 'repo', 'meeting', 'stakeholder');
|
||||
$config->programPriv->scrum = array('projectstory', 'projectrelease', 'project', 'build', 'bug', 'testcase', 'testreport', 'doc', 'repo', 'meeting', 'stakeholder', 'testtask');
|
||||
$config->programPriv->waterfall = array_merge($config->programPriv->scrum, array('workestimation', 'durationestimation', 'budget', 'programplan', 'review', 'reviewissue', 'weekly', 'cm', 'milestone', 'design', 'issue', 'risk', 'opportunity', 'measrecord', 'auditplan', 'trainplan', 'gapanalysis', 'pssp', 'researchplan', 'researchreport'));
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ REPLACE INTO `zt_stage` (`name`,`percent`,`type`,`createdBy`,`createdDate`,`edit
|
||||
('发布','10','release','admin','2020-02-08 21:08:30','admin','2020-02-12 13:50:27','0'),
|
||||
('总结评审','5','review','admin','2020-02-08 21:08:45','admin','2020-02-12 13:50:27','0');
|
||||
|
||||
INSERT INTO `zt_lang` (`lang`, `module`, `section`, `key`, `value`, `system`) VALUES
|
||||
REPLACE INTO `zt_lang` (`lang`, `module`, `section`, `key`, `value`, `system`) VALUES
|
||||
('all','stage','typeList','request','需求', '1'),
|
||||
('all','stage','typeList','design','设计', '1'),
|
||||
('all','stage','typeList','dev','开发', '1'),
|
||||
|
||||
@@ -557,7 +557,7 @@ class baseHelper
|
||||
*/
|
||||
static public function isZeroDate($date)
|
||||
{
|
||||
return substr($date, 0, 4) == '0000';
|
||||
return (empty($date) or substr($date, 0, 4) == '0000');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -404,6 +404,7 @@ class control extends baseControl
|
||||
foreach(explode(',', $requiredFields) as $requiredField)
|
||||
{
|
||||
if(empty($requiredField)) continue;
|
||||
if(!isset($fields[$requiredField])) continue;
|
||||
if(isset($_POST[$requiredField]) and $_POST[$requiredField] === '')
|
||||
{
|
||||
$message[$requiredField][] = sprintf($this->lang->error->notempty, $fields[$requiredField]->name);
|
||||
|
||||
@@ -55,4 +55,4 @@ $config->action->majorList['execution'] = array('opened', 'edited');
|
||||
|
||||
$config->action->needGetProjectType = 'build,task,bug,case,testcase,caselib,testtask,testsuite,testreport,doc,issue,release,risk,design,opportunity,trainplan,gapanalysis,researchplan,researchreport,';
|
||||
$config->action->needGetRelateField = ',story,productplan,release,task,build,bug,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,kanbanlane,kanbancolumn,';
|
||||
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,';
|
||||
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,execution,project,';
|
||||
|
||||
@@ -60,7 +60,7 @@ class action extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
$trashes = $this->action->getTrashes($type, $sort, $pager);
|
||||
|
||||
/* Title and position. */
|
||||
|
||||
@@ -53,6 +53,7 @@ $lang->action->confirmHideAll = 'Do you want to hide all the records?';
|
||||
$lang->action->needEdit = '%s that you want to restore. Please edit it.';
|
||||
$lang->action->historyEdit = 'The history EditBy cannot be empty.';
|
||||
$lang->action->noDynamic = 'No dynamics. ';
|
||||
$lang->action->undeletedTips = 'This data did not participate in the merging process during the version upgrade process, so restore is not supported.';
|
||||
|
||||
$lang->action->history = new stdclass();
|
||||
$lang->action->history->action = 'Link';
|
||||
|
||||
@@ -53,6 +53,7 @@ $lang->action->confirmHideAll = '您确定要全部隐藏这些记录吗?';
|
||||
$lang->action->needEdit = '要还原%s的名称或代号已经存在,请编辑更改。';
|
||||
$lang->action->historyEdit = '历史记录编辑不能为空。';
|
||||
$lang->action->noDynamic = '暂时没有动态。';
|
||||
$lang->action->undeletedTips = '该数据在版本升级过程中未参与数据归并流程,不支持还原。';
|
||||
|
||||
$lang->action->history = new stdclass();
|
||||
$lang->action->history->action = '关联日志';
|
||||
|
||||
@@ -1429,6 +1429,13 @@ class actionModel extends model
|
||||
{
|
||||
$action = $this->getById($actionID);
|
||||
if($action->action != 'deleted') return;
|
||||
|
||||
if($this->config->systemMode == 'new' and $action->objectType == 'execution')
|
||||
{
|
||||
$execution = $this->dao->select('*')->from(TABLE_EXECUTION)->where('id')->eq($action->objectID)->fetch();
|
||||
if($execution->deleted and empty($execution->project)) return print(js::error($this->lang->action->undeletedTips));
|
||||
}
|
||||
|
||||
if($action->objectType == 'product')
|
||||
{
|
||||
$product = $this->dao->select('id,name,code,acl')->from(TABLE_PRODUCT)->where('id')->eq($action->objectID)->fetch();
|
||||
|
||||
@@ -99,7 +99,7 @@ class api extends control
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
$releases = $this->api->getReleaseByQuery($libID, $pager, $sort);
|
||||
|
||||
$this->view->releases = $releases;
|
||||
@@ -185,7 +185,7 @@ class api extends control
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$structs = $this->api->getStructByQuery($libID, $pager, $sort);
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<th><?php echo $lang->block->totalStory . ':';?></th>
|
||||
<td><?php echo $totalData[$projectID]->allStories;?></td>
|
||||
<th><?php echo $lang->block->totalPeople . ':';?></th>
|
||||
<td><?php echo $totalData[$projectID]->teamCount ? html::a($this->createLink('project', 'manageMembers', 'projectID=' . $projectID), $totalData[$projectID]->teamCount) : 0;?></td>
|
||||
<td><?php echo $totalData[$projectID]->teamCount ? html::a($this->createLink('project', 'team', 'projectID=' . $projectID), $totalData[$projectID]->teamCount) : 0;?></td>
|
||||
<th><?php echo $lang->block->estimatedHours . ':';?></th>
|
||||
<td><?php echo $totalData[$projectID]->estimate . $lang->execution->workHour;?></td>
|
||||
<th><?php echo $lang->block->totalBug. ':';?></th>
|
||||
|
||||
@@ -189,6 +189,11 @@ $config->bug->datatable->fieldList['type']['fixed'] = 'no';
|
||||
$config->bug->datatable->fieldList['type']['width'] = '90';
|
||||
$config->bug->datatable->fieldList['type']['required'] = 'no';
|
||||
|
||||
$config->bug->datatable->fieldList['project']['title'] = 'project';
|
||||
$config->bug->datatable->fieldList['project']['fixed'] = 'no';
|
||||
$config->bug->datatable->fieldList['project']['width'] = '120';
|
||||
$config->bug->datatable->fieldList['project']['required'] = 'no';
|
||||
|
||||
$config->bug->datatable->fieldList['execution']['title'] = 'execution';
|
||||
$config->bug->datatable->fieldList['execution']['fixed'] = 'no';
|
||||
$config->bug->datatable->fieldList['execution']['width'] = '120';
|
||||
|
||||
@@ -148,7 +148,7 @@ class bug extends control
|
||||
setcookie('qaBugOrder', $orderBy, 0, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
@@ -238,6 +238,7 @@ class bug extends control
|
||||
$this->view->isProjectBug = ($productID and !$this->projectID) ? false : true;
|
||||
$this->view->modulePairs = $showModule ? $this->tree->getModulePairs($productID, 'bug', $showModule) : array();
|
||||
$this->view->showBranch = $showBranch;
|
||||
$this->view->projectPairs = $this->loadModel('project')->getPairsByProgram();
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -548,7 +549,7 @@ class bug extends control
|
||||
if($user) $productMembers[$assignedTo] = $user->realname;
|
||||
}
|
||||
|
||||
$moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch === 'all' ? 0 : $branch);
|
||||
$moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, ($branch === 'all' or !isset($branches[$branch])) ? 0 : $branch);
|
||||
if(empty($moduleOptionMenu)) die(js::locate(helper::createLink('tree', 'browse', "productID=$productID&view=story")));
|
||||
|
||||
/* Get products and projects. */
|
||||
|
||||
+38
-28
@@ -2697,7 +2697,7 @@ class bugModel extends model
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function printCell($col, $bug, $users, $builds, $branches, $modulePairs, $executions = array(), $plans = array(), $stories = array(), $tasks = array(), $mode = 'datatable')
|
||||
public function printCell($col, $bug, $users, $builds, $branches, $modulePairs, $executions = array(), $plans = array(), $stories = array(), $tasks = array(), $mode = 'datatable', $projectPairs = array())
|
||||
{
|
||||
/* Check the product is closed. */
|
||||
$canBeChanged = common::canBeChanged('bug', $bug);
|
||||
@@ -2732,35 +2732,42 @@ class bugModel extends model
|
||||
{
|
||||
$class = "c-$id";
|
||||
$title = '';
|
||||
if($id == 'id') $class .= ' cell-id';
|
||||
if($id == 'status')
|
||||
switch($id)
|
||||
{
|
||||
$class .= ' bug-' . $bug->status;
|
||||
$title = "title='" . $this->processStatus('bug', $bug) . "'";
|
||||
}
|
||||
if($id == 'confirmed')
|
||||
{
|
||||
$class .= ' text-center';
|
||||
}
|
||||
if($id == 'title')
|
||||
{
|
||||
$class .= ' text-left';
|
||||
$title = "title='{$bug->title}'";
|
||||
}
|
||||
if($id == 'type')
|
||||
{
|
||||
$title = "title='" . zget($this->lang->bug->typeList, $bug->type) . "'";
|
||||
}
|
||||
if($id == 'assignedTo')
|
||||
{
|
||||
$class .= ' has-btn text-left';
|
||||
if($bug->assignedTo == $account) $class .= ' red';
|
||||
}
|
||||
if($id == 'resolvedBy')
|
||||
{
|
||||
$class .= ' c-user';
|
||||
$title = "title='" . zget($users, $bug->resolvedBy) . "'";
|
||||
case 'id':
|
||||
$class .= ' cell-id';
|
||||
break;
|
||||
case 'status':
|
||||
$class .= ' bug-' . $bug->status;
|
||||
$title = "title='" . $this->processStatus('bug', $bug) . "'";
|
||||
break;
|
||||
case 'confirmed':
|
||||
$class .= ' text-center';
|
||||
break;
|
||||
case 'title':
|
||||
$class .= ' text-left';
|
||||
$title = "title='{$bug->title}'";
|
||||
break;
|
||||
case 'type':
|
||||
$title = "title='" . zget($this->lang->bug->typeList, $bug->type) . "'";
|
||||
break;
|
||||
case 'assignedTo':
|
||||
$class .= ' has-btn text-left';
|
||||
if($bug->assignedTo == $account) $class .= ' red';
|
||||
break;
|
||||
case 'resolvedBy':
|
||||
$class .= ' c-user';
|
||||
$title = "title='" . zget($users, $bug->resolvedBy) . "'";
|
||||
break;
|
||||
case 'project':
|
||||
$title = "title='" . zget($projectPairs, $bug->project, '') . "'";
|
||||
break;
|
||||
case 'resolvedBuild':
|
||||
$class .= ' text-ellipsis';
|
||||
$title = "title='" . $bug->resolvedBuild . "'";
|
||||
break;
|
||||
}
|
||||
|
||||
if($id == 'deadline' && isset($bug->delay) && $bug->status == 'active') $class .= ' delayed';
|
||||
if(strpos(',type,execution,story,plan,task,openedBuild,', ",{$id},") !== false) $class .= ' text-ellipsis';
|
||||
|
||||
@@ -2809,6 +2816,9 @@ class bugModel extends model
|
||||
case 'branch':
|
||||
echo zget($branches, $bug->branch, '');
|
||||
break;
|
||||
case 'project':
|
||||
echo zget($projectPairs, $bug->project, '');
|
||||
break;
|
||||
case 'execution':
|
||||
echo zget($executions, $bug->execution, '');
|
||||
break;
|
||||
|
||||
@@ -306,7 +306,7 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow
|
||||
}
|
||||
}?>
|
||||
<?php else:?>
|
||||
<?php foreach($setting as $value) $this->bug->printCell($value, $bug, $users, $builds, $branchOption, $modulePairs, $executions, $plans, $stories, $tasks, $useDatatable ? 'datatable' : 'table');?>
|
||||
<?php foreach($setting as $value) $this->bug->printCell($value, $bug, $users, $builds, $branchOption, $modulePairs, $executions, $plans, $stories, $tasks, $useDatatable ? 'datatable' : 'table', $projectPairs);?>
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
|
||||
@@ -289,7 +289,7 @@
|
||||
<td>
|
||||
<?php
|
||||
if($bug->story) echo html::a($this->createLink('story', 'view', "storyID=$bug->story", '', true), "#$bug->story $bug->storyTitle", '', "class='iframe' data-width='80%'");
|
||||
if($bug->storyStatus == 'active' and $bug->latestStoryVersion > $bug->storyVersion)
|
||||
if($bug->storyStatus == 'active' and $bug->latestStoryVersion > $bug->storyVersion and common::hasPriv('bug', 'confirmStoryChange'))
|
||||
{
|
||||
echo "(<span class='warning'>{$lang->story->changed}</span> ";
|
||||
echo html::a($this->createLink('bug', 'confirmStoryChange', "bugID=$bug->id"), $lang->confirm, 'hiddenwin');
|
||||
|
||||
@@ -203,7 +203,7 @@ class caselib extends control
|
||||
$this->caselib->buildSearchForm($libID, $libraries, $queryID, $actionURL);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* save session .*/
|
||||
$cases = $this->caselib->getLibCases($libID, $browseType, $queryID, $moduleID, $sort, $pager);
|
||||
|
||||
@@ -2022,7 +2022,7 @@ EOD;
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function appendOrder($orderBy, $append = 'id')
|
||||
public static function appendOrder($orderBy, $append = 'id')
|
||||
{
|
||||
if(empty($orderBy)) return $append;
|
||||
|
||||
|
||||
@@ -1,24 +1 @@
|
||||
<?php if($extView = $this->getExtViewFile(__FILE__)){include $extView; return helper::cd();}?>
|
||||
<?php if($config->debug):?>
|
||||
<?php css::import($jsRoot . 'zui/picker/zui.picker.min.css'); ?>
|
||||
<?php js::import($jsRoot . 'zui/picker/zui.picker.min.js'); ?>
|
||||
<?php endif;?>
|
||||
<style>
|
||||
.picker-single .picker-selection-remove{z-index: 1000;}
|
||||
.picker-selection-single:after, .picker-multi.picker-focus .picker-selections:before{font-family: ZentaoIcon !important; content: '\f0d7' !important;}
|
||||
</style>
|
||||
<script>
|
||||
var chooseUsersToMail = '<?php echo $lang->chooseUsersToMail;?>';
|
||||
if($.fn.picker)
|
||||
{
|
||||
$(document).ready(function()
|
||||
{
|
||||
$(".picker-select[data-pickertype!='remote']").picker({chosenMode: true});
|
||||
$("[data-pickertype='remote']").each(function()
|
||||
{
|
||||
var pickerremote = $(this).attr('data-pickerremote');
|
||||
$(this).picker({chosenMode: true, remote: pickerremote});
|
||||
})
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -63,7 +63,7 @@ class company extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Build the search form. */
|
||||
$queryID = $type == 'bydept' ? 0 : (int)$param;
|
||||
@@ -205,7 +205,7 @@ class company extends control
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$order = $direction == 'next' ? 'date_desc' : 'date_asc';
|
||||
$sort = $this->loadModel('common')->appendOrder($order);
|
||||
$sort = common::appendOrder($order);
|
||||
|
||||
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
|
||||
$date = empty($date) ? '' : date('Y-m-d', $date);
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<?php $tab = '';?>
|
||||
<?php if($action->objectType == 'meeting') $tab = $action->project ? "data-app='project'" : "data-app='my'";?>
|
||||
<?php
|
||||
if((isset($config->maxVersion) and strpos(",{$config->action->assetType},", ",{$action->objectType},") !== false) or empty($action->objectName))
|
||||
if(empty($action->objectName))
|
||||
{
|
||||
echo '#' . $action->objectID;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
$(function()
|
||||
{
|
||||
$('#modeTab').addClass('btn-active-text');
|
||||
$('[name=mode]').change(function()
|
||||
{
|
||||
$(this).val() == 'new' ? $('#changeModeTips').removeClass('hidden') : $('#changeModeTips').addClass('hidden');
|
||||
});
|
||||
})
|
||||
|
||||
@@ -220,6 +220,7 @@ $lang->custom->menuTip = 'Click to show/hide the menu. Drag to switch d
|
||||
$lang->custom->saveFail = 'Failed to save!';
|
||||
$lang->custom->page = ' Page';
|
||||
$lang->custom->changeClassicTip = 'The Program module will be hidden, if you switch to the classic mode.';
|
||||
$lang->custom->changeModeTips = 'Historical deleted data does not participate in the data merging process. After switching the mode, it will not support restoration. Please know.';
|
||||
|
||||
$lang->custom->scoreStatus[1] = 'On';
|
||||
$lang->custom->scoreStatus[0] = 'Off';
|
||||
|
||||
@@ -220,6 +220,7 @@ $lang->custom->menuTip = '点击显示或隐藏导航条目,拖拽来
|
||||
$lang->custom->saveFail = '保存失败!';
|
||||
$lang->custom->page = '页面';
|
||||
$lang->custom->changeClassicTip = '切换为老版本的习惯后,系统将取消项目集功能。';
|
||||
$lang->custom->changeModeTips = '历史删除数据不参与数据归并流程,切换模式后将不支持还原,请知悉';
|
||||
|
||||
$lang->custom->scoreStatus[1] = '开启';
|
||||
$lang->custom->scoreStatus[0] = '关闭';
|
||||
|
||||
@@ -32,12 +32,12 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><?php if($changedMode != 'yes') echo html::submitButton($lang->custom->switch);?></td>
|
||||
<td>
|
||||
<?php if($changedMode != 'yes') echo html::submitButton($lang->custom->switch);?>
|
||||
<div id='changeModeTips' class='text-danger hidden'><?php echo $lang->custom->changeModeTips;?></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
$('#modeTab').addClass('btn-active-text');
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
+32
-1
@@ -92,7 +92,7 @@ class doc extends control
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
if($browseType == 'collectedbyme')
|
||||
{
|
||||
@@ -778,6 +778,37 @@ class doc extends control
|
||||
$this->doc->saveDraft($docID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax get doclib whitelist.
|
||||
*
|
||||
* @param int $doclibID
|
||||
* @param string $acl open|custom|private
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function ajaxGetWhitelist($doclibID, $acl)
|
||||
{
|
||||
$doclib = $this->doc->getLibById($doclibID);
|
||||
$users = $this->user->getPairs('noletter|noempty|noclosed');
|
||||
|
||||
if($doclib->acl != 'custom' and !empty($doclib->project) and $acl == 'custom')
|
||||
{
|
||||
$project = $this->loadModel('project')->getById($doclib->project);
|
||||
|
||||
$userList = array();
|
||||
$projectTeams = $this->loadModel('user')->getTeamMemberPairs($doclib->project);
|
||||
$stakeholders = $this->loadModel('stakeholder')->getStakeHolderPairs($doclib->project);
|
||||
foreach($stakeholders as $stakeholder) $userList[$stakeholder] = $users[$stakeholder];
|
||||
|
||||
$userList += $projectTeams;
|
||||
$whitelist = implode(',', array_keys($userList)) . $project->whitelist . ',' .$project->PM . ',' . $doclib->users;
|
||||
|
||||
return print(html::select('users[]', $users, $whitelist, "class='form-control chosen' multiple"));
|
||||
}
|
||||
|
||||
return print(html::select('users[]', $users, $doclib->users, "class='form-control chosen' multiple"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show files.
|
||||
*
|
||||
|
||||
@@ -24,16 +24,36 @@ function toggleAcl(acl, type)
|
||||
if(acl == 'custom')
|
||||
{
|
||||
$('#whiteListBox').removeClass('hidden');
|
||||
$('#groupWhiteListBox').removeClass('hidden');
|
||||
}
|
||||
else if(acl == 'private')
|
||||
{
|
||||
$('#whiteListBox').removeClass('hidden');
|
||||
$('#groupWhiteListBox').addClass('hidden');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#whiteListBox').addClass('hidden');
|
||||
}
|
||||
|
||||
if(type == 'lib')
|
||||
{
|
||||
var libType = $('input[name="type"]:checked').val();
|
||||
var notice = typeof(noticeAcl[libType][acl]) != 'undefined' ? noticeAcl[libType][acl] : '';
|
||||
$('#noticeAcl').html(notice);
|
||||
|
||||
if(libType == 'custom' && acl == 'private') $('#whiteListBox').addClass('hidden');
|
||||
|
||||
if(libType == 'project' && typeof(doclibID) != 'undefined')
|
||||
{
|
||||
link = createLink('doc', 'ajaxGetWhitelist', 'doclibID=' + doclibID + '&acl=' + acl);
|
||||
$.get(link, function(users)
|
||||
{
|
||||
$('#users').replaceWith(users);
|
||||
$('#users_chosen').remove();
|
||||
$('#users').chosen();
|
||||
})
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -206,7 +206,9 @@ $lang->doc->selectLibType = 'Please select a type of doc library.';
|
||||
$lang->doc->noticeAcl['lib']['product']['default'] = 'Users who can access the selected product can access it.';
|
||||
$lang->doc->noticeAcl['lib']['product']['custom'] = 'Users who can access the selected product or users in the whiltelist can access it.';
|
||||
$lang->doc->noticeAcl['lib']['project']['default'] = 'Users who can access the selected project can access it.';
|
||||
$lang->doc->noticeAcl['lib']['project']['custom'] = 'Users who can access the selected project or users in the whiltelist can access it.';
|
||||
$lang->doc->noticeAcl['lib']['project']['open'] = 'Users who can access the selected project can access it.';
|
||||
$lang->doc->noticeAcl['lib']['project']['private'] = 'Users who can access the selected project or users in the whiltelist can access it.';
|
||||
$lang->doc->noticeAcl['lib']['project']['custom'] = 'Users in the whiltelist can access it.';
|
||||
$lang->doc->noticeAcl['lib']['execution']['default'] = "Users who can access the selected {$lang->executionCommon} can access it.";
|
||||
$lang->doc->noticeAcl['lib']['execution']['custom'] = "Users who can access the selected {$lang->executionCommon} or users in the whiltelist can access it.";
|
||||
$lang->doc->noticeAcl['lib']['custom']['open'] = 'All users can access it.';
|
||||
|
||||
@@ -206,7 +206,9 @@ $lang->doc->selectLibType = '请选择文档库类型';
|
||||
$lang->doc->noticeAcl['lib']['product']['default'] = '有所选产品访问权限的用户可以访问。';
|
||||
$lang->doc->noticeAcl['lib']['product']['custom'] = '有所选产品访问权限或白名单里的用户可以访问。';
|
||||
$lang->doc->noticeAcl['lib']['project']['default'] = "有所选项目访问权限的用户可以访问。";
|
||||
$lang->doc->noticeAcl['lib']['project']['custom'] = "有所选项目访问权限或白名单里的用户可以访问。";
|
||||
$lang->doc->noticeAcl['lib']['project']['open'] = "有所选项目访问权限的用户可以访问。";
|
||||
$lang->doc->noticeAcl['lib']['project']['private'] = "有所选项目访问权限或白名单里的用户可以访问。";
|
||||
$lang->doc->noticeAcl['lib']['project']['custom'] = "白名单的用户可以访问。";
|
||||
$lang->doc->noticeAcl['lib']['execution']['default'] = "有所选{$lang->executionCommon}访问权限的用户可以访问。";
|
||||
$lang->doc->noticeAcl['lib']['execution']['custom'] = "有所选{$lang->executionCommon}访问权限或白名单里的用户可以访问。";
|
||||
$lang->doc->noticeAcl['lib']['custom']['open'] = '所有人都可以访问。';
|
||||
|
||||
+47
-17
@@ -177,8 +177,7 @@ class docModel extends model
|
||||
$lib->project = $execution->project;
|
||||
}
|
||||
|
||||
if($lib->acl == 'private') $lib->users = $this->app->user->account;
|
||||
if($lib->acl == 'custom')
|
||||
if($lib->acl == 'custom' or $lib->acl == 'private')
|
||||
{
|
||||
$trimedUsers = ',' . trim($lib->users, ',') . ',';
|
||||
if(strpos($trimedUsers, ',' . $this->app->user->account . ',') === false) $lib->users .= ',' . $this->app->user->account;
|
||||
@@ -254,10 +253,20 @@ class docModel extends model
|
||||
->join('groups', ',')
|
||||
->join('users', ',')
|
||||
->get();
|
||||
if($lib->acl == 'private')
|
||||
|
||||
if($oldLib->type == 'project' or $oldLib->type == 'custom')
|
||||
{
|
||||
$libCreatedBy = $this->dao->select('*')->from(TABLE_ACTION)->where('objectType')->eq('doclib')->andWhere('objectID')->eq($libID)->andWhere('action')->eq('created')->fetch('actor');
|
||||
$lib->users = $libCreatedBy ? $libCreatedBy : $this->app->user->account;
|
||||
|
||||
if($oldLib->type == 'custom')
|
||||
{
|
||||
if($lib->acl == 'private') $lib->users = $libCreatedBy ? $libCreatedBy : $this->app->user->account;
|
||||
}
|
||||
else
|
||||
{
|
||||
$openedBy = $this->dao->findById($oldLib->project)->from(TABLE_PROJECT)->fetch('openedBy');
|
||||
if($lib->acl == 'private' and $lib->acl == 'custom') $lib->users .= ',' . $libCreatedBy ? $libCreatedBy : $openedBy;
|
||||
}
|
||||
}
|
||||
|
||||
$lib->name = trim($lib->name); //Temporary treatment: Code for bug #15528.
|
||||
@@ -906,11 +915,17 @@ class docModel extends model
|
||||
if(isset($object->addedBy) and $object->addedBy == $this->app->user->account) return true;
|
||||
if(isset($object->users) and strpos(",{$object->users},", $account) !== false) return true;
|
||||
|
||||
if($object->project and $object->main)
|
||||
if($object->project and $object->acl == 'private')
|
||||
{
|
||||
$stakeHolders = array();
|
||||
$project = $this->loadModel('project')->getById($object->project);
|
||||
$projectTeams = $this->loadModel('user')->getTeamMemberPairs($object->project);
|
||||
$authorizedUsers = $this->user->getProjectAuthedUsers($project, '', $projectTeams, array_flip(explode(",", $project->whitelist)));
|
||||
$stakeHolderList = $this->loadModel('stakeholder')->getStakeHolderPairs($object->project);
|
||||
foreach($stakeHolderList as $stakeHolder) $stakeHolders[$stakeHolder] = $stakeHolder;
|
||||
|
||||
$authorizedUsers = $this->user->getProjectAuthedUsers($project, $stakeHolders, $projectTeams, array_flip(explode(",", $project->whitelist)));
|
||||
|
||||
if(strpos(",{$object->users},", $account) !== false) return true;
|
||||
if(array_key_exists($this->app->user->account, array_filter($authorizedUsers))) return true;
|
||||
}
|
||||
|
||||
@@ -1318,6 +1333,15 @@ class docModel extends model
|
||||
/* Sort project. */
|
||||
$orderedProjects = array();
|
||||
|
||||
/* 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},%")
|
||||
->fetchPairs();
|
||||
}
|
||||
|
||||
$objects = $this->dao->select('*')->from(TABLE_PROJECT)
|
||||
->where('type')->eq('project')
|
||||
->andWhere('deleted')->eq(0)
|
||||
@@ -1905,28 +1929,34 @@ class docModel extends model
|
||||
*/
|
||||
public function buildCreateButton4Doc($objectType, $objectID, $libID)
|
||||
{
|
||||
if(!common::hasPriv('doc', 'create') and !common::hasPriv('doc', 'createLib')) return '';
|
||||
|
||||
if($objectType == 'book')
|
||||
{
|
||||
$html = html::a(helper::createLink('doc', 'createLib', "type=$objectType&objectID=$objectID"), '<i class="icon icon-plus"></i> ' . $this->lang->doc->createBook, '', 'class="btn btn-secondary iframe"');
|
||||
}
|
||||
elseif($libID)
|
||||
{
|
||||
$html = "<div class='dropdown' id='createDropdown'>";
|
||||
$html = "<div class='dropdown' id='createDropdown'>";
|
||||
$html .= "<button class='btn btn-primary' type='button' data-toggle='dropdown'><i class='icon icon-plus'></i> " . $this->lang->doc->createAB . " <span class='caret'></span></button>";
|
||||
$html .= "<ul class='dropdown-menu pull-right'>";
|
||||
foreach($this->lang->doc->typeList as $typeKey => $typeName)
|
||||
|
||||
if(common::hasPriv('doc', 'create'))
|
||||
{
|
||||
$class = strpos($this->config->doc->officeTypes, $typeKey) !== false ? 'iframe' : '';
|
||||
$icon = zget($this->config->doc->iconList, $typeKey);
|
||||
$html .= "<li>";
|
||||
$html .= html::a(helper::createLink('doc', 'create', "objectType=$objectType&objectID=$objectID&libID=$libID&moduleID=0&type=$typeKey", '', $class ? true : false), "<i class='icon-$icon icon'></i> " . $typeName, '', "class='$class' data-app='{$this->app->tab}'");
|
||||
$html .= "</li>";
|
||||
if($typeKey == 'url') $html .= '<li class="divider"></li>';
|
||||
foreach($this->lang->doc->typeList as $typeKey => $typeName)
|
||||
{
|
||||
$class = strpos($this->config->doc->officeTypes, $typeKey) !== false ? 'iframe' : '';
|
||||
$icon = zget($this->config->doc->iconList, $typeKey);
|
||||
$html .= "<li>";
|
||||
$html .= html::a(helper::createLink('doc', 'create', "objectType=$objectType&objectID=$objectID&libID=$libID&moduleID=0&type=$typeKey", '', $class ? true : false), "<i class='icon-$icon icon'></i> " . $typeName, '', "class='$class' data-app='{$this->app->tab}'");
|
||||
$html .= "</li>";
|
||||
if($typeKey == 'url') $html .= '<li class="divider"></li>';
|
||||
}
|
||||
}
|
||||
|
||||
if(common::hasPriv('doc', 'createLib'))
|
||||
{
|
||||
$html .= '<li class="divider"></li>';
|
||||
if(common::hasPriv('doc', 'create')) $html .= '<li class="divider"></li>';
|
||||
$html .= '<li>' . html::a(helper::createLink('doc', 'createLib', "type=$objectType&objectID=$objectID"), "<i class='icon-doc-lib icon'></i> " . $this->lang->doc->createLib, '', "class='iframe' data-width='70%'") . '</li>';
|
||||
}
|
||||
$html .= "</ul></div>";
|
||||
@@ -2579,8 +2609,8 @@ EOT;
|
||||
$tab = strpos(',doc,product,project,execution,', ",{$this->app->tab},") !== false ? $this->app->tab : 'doc';
|
||||
if($tab != 'doc') $this->loadModel($tab)->setMenu($objectID);
|
||||
|
||||
$this->lang->TRActions = $this->buildCollectButton4Doc();
|
||||
$this->lang->TRActions .= common::hasPriv('doc', 'create') ? $this->buildCreateButton4Doc($type, $objectID, $libID) : '';
|
||||
$this->lang->TRActions = $this->buildCollectButton4Doc();
|
||||
$this->lang->TRActions .= $this->buildCreateButton4Doc($type, $objectID, $libID);
|
||||
|
||||
return array($libs, $libID, $object, $objectID);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<tr id='whiteListBox' class='hidden'>
|
||||
<th><?php echo $lang->doc->whiteList;?></th>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<div id='groupWhiteListBox' class='input-group'>
|
||||
<span class='input-group-addon groups-addon'><?php echo $lang->doclib->group?></span>
|
||||
<?php echo html::select('groups[]', $groups, '', "class='form-control chosen' multiple")?>
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
?>
|
||||
<?php include '../../common/view/header.lite.html.php';?>
|
||||
<?php include '../../common/view/chosen.html.php';?>
|
||||
<?php js::set('doclibID', $lib->id);?>
|
||||
<?php if($lib->type == 'product'):?>
|
||||
<style> .chosen-container .chosen-results {max-height: 180px;}</style>
|
||||
<?php else:?>
|
||||
@@ -63,7 +64,7 @@
|
||||
<tr id='whiteListBox' class='hidden'>
|
||||
<th><?php echo $lang->doc->whiteList?></th>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<div id='groupWhiteListBox' class='input-group'>
|
||||
<span class='input-group-addon groups-addon'><?php echo $lang->doclib->group?></span>
|
||||
<?php echo html::select('groups[]', $groups, $lib->groups, "class='form-control chosen' multiple")?>
|
||||
</div>
|
||||
|
||||
@@ -175,7 +175,7 @@ class execution extends control
|
||||
setcookie('executionTaskOrder', $orderBy, 0, $this->config->webRoot, '', false, true);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Header and position. */
|
||||
$this->view->title = $execution->name . $this->lang->colon . $this->lang->execution->task;
|
||||
@@ -268,7 +268,7 @@ class execution extends control
|
||||
/* Get tasks and group them. */
|
||||
if(empty($groupBy))$groupBy = 'story';
|
||||
if(($groupBy == 'story') and ($execution->type == 'ops'))$groupBy = 'status';
|
||||
$sort = $this->loadModel('common')->appendOrder($groupBy);
|
||||
$sort = common::appendOrder($groupBy);
|
||||
$tasks = $this->loadModel('task')->getExecutionTasks($executionID, $productID = 0, $status = 'all', $modules = 0, $sort);
|
||||
$groupBy = str_replace('`', '', $groupBy);
|
||||
$taskLang = $this->lang->task;
|
||||
@@ -730,7 +730,7 @@ class execution extends control
|
||||
setcookie('executionStoryOrder', $orderBy, 0, $this->config->webRoot, '', false, true);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$queryID = ($type == 'bysearch') ? $param : 0;
|
||||
$execution = $this->commonAction($executionID);
|
||||
@@ -885,7 +885,7 @@ class execution extends control
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
if($this->app->getViewType() == 'xhtml') $recPerPage = 10;
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
$bugs = $this->bug->getExecutionBugs($executionID, $productID, $build, $type, $param, $sort, '', $pager);
|
||||
$bugs = $this->bug->checkDelayedBugs($bugs);
|
||||
$users = $this->user->getPairs('noletter');
|
||||
@@ -1972,13 +1972,10 @@ class execution extends control
|
||||
foreach($plans as $plan) $allPlans += $plan;
|
||||
}
|
||||
|
||||
$userList = array();
|
||||
$avatarPairs = $this->dao->select('account, avatar')->from(TABLE_USER)->where('deleted')->eq(0)->fetchPairs();
|
||||
foreach($avatarPairs as $account => $avatar)
|
||||
{
|
||||
if(!$avatar) continue;
|
||||
$userList[$account]['avatar'] = $avatar;
|
||||
}
|
||||
$userList = $this->dao->select('account, realname name, avatar')->from(TABLE_USER)->where('deleted')->eq(0)->fetchAll('account');
|
||||
$userList['closed']['account'] = 'Closed';
|
||||
$userList['closed']['name'] = 'Closed';
|
||||
$userList['closed']['avatar'] = '';
|
||||
|
||||
$this->view->title = $this->lang->execution->kanban;
|
||||
$this->view->position[] = html::a($this->createLink('execution', 'browse', "executionID=$executionID"), $execution->name);
|
||||
@@ -2743,7 +2740,7 @@ class execution extends control
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$orderBy = $direction == 'next' ? 'date_desc' : 'date_asc';
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Set the menu. If the executionID = 0, use the indexMenu instead. */
|
||||
$this->execution->setMenu($executionID);
|
||||
|
||||
@@ -39,7 +39,7 @@ function renderUserAvatar(user, objectType, objectID, size)
|
||||
if(objectType == 'story' && !priv.canAssignStory) return $noPrivAvatar;
|
||||
if(objectType == 'bug' && !priv.canAssignBug) return $noPrivAvatar;
|
||||
|
||||
return $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" href="' + link + '"/>').avatar({user: user});
|
||||
return $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + user.name + '" href="' + link + '"/>').avatar({user: user});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -329,7 +329,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, teams, teamMembers')
|
||||
->remove('products, workDays, delta, branch, uid, plans, teams, teamMembers, contactListMenu')
|
||||
->get();
|
||||
|
||||
/* Check the workload format and total. */
|
||||
@@ -487,7 +487,7 @@ class executionModel extends model
|
||||
->setDefault('team', $this->post->name)
|
||||
->join('whitelist', ',')
|
||||
->stripTags($this->config->execution->editor->edit['id'], $this->config->allowedTags)
|
||||
->remove('products, branch, uid, plans, syncStories')
|
||||
->remove('products, branch, uid, plans, syncStories, contactListMenu')
|
||||
->get();
|
||||
|
||||
if($this->config->systemMode == 'new' and (empty($execution->project) or $execution->project == $oldExecution->project)) $this->checkBeginAndEndDate($oldExecution->project, $execution->begin, $execution->end);
|
||||
@@ -1324,7 +1324,7 @@ class executionModel extends model
|
||||
$module = 'execution';
|
||||
$method = 'testcase';
|
||||
}
|
||||
if($module == 'testtask' and ($method == 'view' || $method == 'create' || $method == 'edit'))
|
||||
if($module == 'testtask' and ($method == 'view' || $method == 'create' || $method == 'edit' || $method == 'linkcase'))
|
||||
{
|
||||
$module = 'execution';
|
||||
$method = 'testtask';
|
||||
|
||||
@@ -227,9 +227,12 @@
|
||||
</tr>
|
||||
<tr class="hidden" id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $users, $whitelist, 'class="form-control chosen" multiple');?></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td colspan='2'>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('whitelist[]', $users, $whitelist, 'class="form-control chosen" multiple');?>
|
||||
<?php echo $this->fetch('my', 'buildContactLists', "dropdownName='whitelist'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='4' class='text-center form-actions'>
|
||||
|
||||
@@ -191,8 +191,12 @@
|
||||
</tr>
|
||||
<tr class="<?php if($execution->acl == 'open') echo 'hidden';?>" id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $users, $execution->whitelist, 'class="form-control chosen" multiple');?></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('whitelist[]', $users, $execution->whitelist, 'class="form-control chosen" multiple');?>
|
||||
<?php echo $this->fetch('my', 'buildContactLists', "dropdownName='whitelist'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td colspan='3' class='text-center form-actions'><?php echo html::submitButton() . ' ' . html::backButton();?></td></tr>
|
||||
</table>
|
||||
|
||||
+23
-9
@@ -2510,12 +2510,20 @@ class gitlabModel extends model
|
||||
public function createBranchPriv($gitlabID, $projectID, $branch = '')
|
||||
{
|
||||
$priv = fixer::input('post')->get();
|
||||
if(empty($priv->name)) dao::$errors['name'][] = $this->lang->gitlab->branch->emptyPrivNameError;
|
||||
$singleBranch = $this->apiGetSingleBranchPriv($gitlabID, $projectID, $priv->name);
|
||||
if(empty($branch) && !empty($singleBranch->id)) dao::$errors['name'][] = $this->lang->gitlab->branch->issetPrivNameError;
|
||||
if(dao::isError()) return false;
|
||||
if(!empty($branch) && !empty($singleBranch->id)) $this->apiDeleteBranchPriv($gitlabID, $projectID, $branch);
|
||||
if(empty($priv->name))
|
||||
{
|
||||
dao::$errors['name'][] = $this->lang->gitlab->branch->emptyPrivNameError;
|
||||
return false;
|
||||
}
|
||||
|
||||
$singleBranch = $this->apiGetSingleBranchPriv($gitlabID, $projectID, $priv->name);
|
||||
if(empty($branch) && !empty($singleBranch->id))
|
||||
{
|
||||
dao::$errors['name'][] = $this->lang->gitlab->branch->issetPrivNameError;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!empty($branch) && !empty($singleBranch->id)) $this->apiDeleteBranchPriv($gitlabID, $projectID, $branch);
|
||||
$response = $this->apiCreateBranchPriv($gitlabID, $projectID, $priv);
|
||||
|
||||
if(!empty($response->id))
|
||||
@@ -2575,12 +2583,18 @@ class gitlabModel extends model
|
||||
public function createTagPriv($gitlabID, $projectID, $tag = '')
|
||||
{
|
||||
$priv = fixer::input('post')->get();
|
||||
if(empty($priv->name)) dao::$errors['name'][] = $this->lang->gitlab->tag->emptyPrivNameError;
|
||||
if(dao::isError()) return false;
|
||||
if(empty($priv->name))
|
||||
{
|
||||
dao::$errors['name'][] = $this->lang->gitlab->tag->emptyPrivNameError;
|
||||
return false;
|
||||
}
|
||||
|
||||
$singleTag = $this->apiGetSingleTagPriv($gitlabID, $projectID, $priv->name);
|
||||
if(empty($tag) && !empty($singleTag->id)) dao::$errors['name'][] = $this->lang->gitlab->tag->issetPrivNameError;
|
||||
if(dao::isError()) return false;
|
||||
if(empty($tag) && !empty($singleTag->id))
|
||||
{
|
||||
dao::$errors['name'][] = $this->lang->gitlab->tag->issetPrivNameError;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!empty($tag) && !empty($singleTag->name)) $this->apiDeleteTagPriv($gitlabID, $projectID, $tag);
|
||||
$response = $this->apiCreateTagPriv($gitlabID, $projectID, $priv);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<tr>
|
||||
<th></th>
|
||||
<td class='text-center form-actions'>
|
||||
<?php echo html::submitButton($lang->gitlab->branch->create);?>
|
||||
<?php echo html::submitButton();?>
|
||||
<?php $backLink = $this->session->gitlabBranchList ? $this->session->gitlabBranchList : inlink('browseBranch', "gitlibID=$gitlabID&projectID=$projectID");?>
|
||||
<?php if(!isonlybody()) echo html::a($backLink, $lang->goback, '', 'class="btn btn-wide"');?>
|
||||
</td>
|
||||
|
||||
@@ -25,10 +25,12 @@
|
||||
<th><?php echo $lang->group->desc;?></th>
|
||||
<td><?php echo html::textarea('desc', '', "rows=5 class=form-control");?></td>
|
||||
</tr>
|
||||
<?php if($this->app->tab != 'project'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->group->limited;?></th>
|
||||
<td><?php echo html::checkbox('limited', '');?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<td colspan='2' class='text-center'><?php echo html::submitButton();?></td>
|
||||
</tr>
|
||||
|
||||
@@ -591,7 +591,7 @@ class kanbanModel extends model
|
||||
$lane->order = $laneOrder;
|
||||
$lane->items = $planList;
|
||||
|
||||
$lanes[] = $lane;
|
||||
$lanes[] = $lane;
|
||||
$laneOrder ++;
|
||||
$colorIndex ++;
|
||||
if($colorIndex == count($this->config->productplan->laneColorList)) $colorIndex = 0;
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
$userCount = count($assignedToList);
|
||||
?>
|
||||
<?php if($userCount > 0):?>
|
||||
<div class='users pull-right' title="<?php echo $members;?>">
|
||||
<div class='users pull-right' title="<?php echo trim($members, ',');?>">
|
||||
<?php
|
||||
foreach($assignedToList as $account)
|
||||
{
|
||||
|
||||
@@ -105,7 +105,7 @@ $lang->mr->apiError->createMR = "Failed to create a merge request through API. R
|
||||
$lang->mr->apiError->sudo = "Unable to operate with the GitLab account bound to the current user. Reason: %s";
|
||||
|
||||
$lang->mr->createFailedFromAPI = "Failed to create Merge Request.";
|
||||
$lang->mr->hasSameOpenedMR = "There are duplicate and unclosed merge requests.";
|
||||
$lang->mr->hasSameOpenedMR = "There are duplicate and unclosed merge requests: ID%u";
|
||||
$lang->mr->accessGitlabFailed = "Unable to connect to the GitLab server.";
|
||||
$lang->mr->reopenSuccess = "The merge request was reopened.";
|
||||
$lang->mr->closeSuccess = "Merge request closed.";
|
||||
|
||||
@@ -105,7 +105,7 @@ $lang->mr->apiError->createMR = "通过API创建合并请求失败,失败原
|
||||
$lang->mr->apiError->sudo = "无法以当前用户绑定的GitLab账户进行操作,失败原因:%s";
|
||||
|
||||
$lang->mr->createFailedFromAPI = "创建合并请求失败。";
|
||||
$lang->mr->hasSameOpenedMR = "存在重复并且未关闭的合并请求。";
|
||||
$lang->mr->hasSameOpenedMR = "存在重复并且未关闭的合并请求: ID%u";
|
||||
$lang->mr->accessGitlabFailed = "当前无法连接到GitLab服务器。";
|
||||
$lang->mr->reopenSuccess = "已重新打开合并请求。";
|
||||
$lang->mr->closeSuccess = "已关闭合并请求。";
|
||||
|
||||
+6
-5
@@ -275,7 +275,7 @@ class mrModel extends model
|
||||
{
|
||||
$pipeline = $this->loadModel('job')->exec($MR->jobID);
|
||||
|
||||
if(!empty($pipeline->queue) && $MR->jobID != $oldMR->jobID)
|
||||
if(!empty($pipeline->queue))
|
||||
{
|
||||
$compile = $this->loadModel('compile')->getByQueue($pipeline->queue);
|
||||
$MR->compileID = $compile->id;
|
||||
@@ -1462,7 +1462,7 @@ class mrModel extends model
|
||||
{
|
||||
if(empty($sourceProject) or empty($sourceBranch) or empty($targetProject) or empty($targetBranch)) return array('result' => 'success');
|
||||
|
||||
$dbOpenedCount = $this->dao->select('count(*) as count')->from(TABLE_MR)
|
||||
$dbOpenedID = $this->dao->select('id')->from(TABLE_MR)
|
||||
->where('gitlabID')->eq($gitlabID)
|
||||
->andWhere('sourceProject')->eq($sourceProject)
|
||||
->andWhere('sourceBranch')->eq($sourceBranch)
|
||||
@@ -1470,10 +1470,11 @@ class mrModel extends model
|
||||
->andWhere('targetBranch')->eq($targetBranch)
|
||||
->andWhere('status')->eq('opened')
|
||||
->andWhere('deleted')->eq('0')
|
||||
->fetch('count');
|
||||
if($dbOpenedCount > 0) return array('result' => 'fail', 'message' => $this->lang->mr->hasSameOpenedMR);
|
||||
->fetch('id');
|
||||
if(!empty($dbOpenedID)) return array('result' => 'fail', 'message' => sprintf($this->lang->mr->hasSameOpenedMR, $dbOpenedID));
|
||||
|
||||
if($this->apiGetSameOpened($gitlabID, $sourceProject, $sourceBranch, $targetProject, $targetBranch)) return array('result' => 'fail', 'message' => $this->lang->mr->hasSameOpenedMR);
|
||||
$mr = $this->apiGetSameOpened($gitlabID, $sourceProject, $sourceBranch, $targetProject, $targetBranch);
|
||||
if($mr) return array('result' => 'fail', 'message' => sprintf($this->lang->mr->errorLang[2], $mr->iid));
|
||||
return array('result' => 'success');
|
||||
}
|
||||
|
||||
|
||||
+132
-11
@@ -86,9 +86,128 @@ class my extends control
|
||||
*/
|
||||
public function work($mode = 'task', $type = 'assignedTo', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
|
||||
{
|
||||
$this->showWorkCount($orderBy, $recTotal, $recPerPage, $pageID);
|
||||
|
||||
echo $this->fetch('my', $mode, "type=$type&orderBy=$orderBy&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID");
|
||||
}
|
||||
|
||||
/**
|
||||
* Show to-do work count.
|
||||
*
|
||||
* @param string $orderBy
|
||||
* @param int $recTotal
|
||||
* @param int $recPerPage
|
||||
* @param int $pageID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function showWorkCount($orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
|
||||
{
|
||||
$this->loadModel('task');
|
||||
$this->loadModel('story');
|
||||
$this->loadModel('bug');
|
||||
$this->loadModel('testcase');
|
||||
$this->loadModel('testtask');
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
if($this->app->getViewType() == 'mhtml') $recPerPage = 10;
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Get the number of tasks assigned to me. */
|
||||
$tasks = $this->task->getUserTasks($this->app->user->account, 'assignedTo', 0, $pager);
|
||||
$taskCount = $pager->recTotal;
|
||||
|
||||
/* Get the number of stories assigned to me. */
|
||||
$assignedToStories = $this->story->getUserStories($this->app->user->account, 'assignedTo', $orderBy, $pager, 'story', false);
|
||||
$assignedToStoryCount = $pager->recTotal;
|
||||
$reviewByStories = $this->story->getUserStories($this->app->user->account, 'reviewBy', $orderBy, $pager, 'story', false);
|
||||
$reviewByStoryCount = $pager->recTotal;
|
||||
$storyCount = $assignedToStoryCount + $reviewByStoryCount;
|
||||
|
||||
$requirementCount = 0;
|
||||
$isOpenedURAndSR = $this->config->URAndSR;
|
||||
if($isOpenedURAndSR)
|
||||
{
|
||||
/* Get the number of requirements assigned to me. */
|
||||
$assignedRequirements = $this->story->getUserStories($this->app->user->account, 'assignedTo', $orderBy, $pager, 'requirement');
|
||||
$assignedRequirementCount = $pager->recTotal;
|
||||
$reviewByRequirements = $this->story->getUserStories($this->app->user->account, 'reviewBy', $orderBy, $pager, 'requirement');
|
||||
$reviewByRequirementCount = $pager->recTotal;
|
||||
$requirementCount = $assignedRequirementCount + $reviewByRequirementCount;
|
||||
}
|
||||
|
||||
/* Get the number of bugs assigned to me. */
|
||||
$bugs = $this->bug->getUserBugs($this->app->user->account, 'assignedTo', $orderBy, 0, $pager);
|
||||
$bugCount = $pager->recTotal;
|
||||
|
||||
/* Get the number of testcases assigned to me. */
|
||||
$cases = $this->testcase->getByAssignedTo($this->app->user->account, $orderBy, $pager, 'skip');
|
||||
$caseCount = $pager->recTotal;
|
||||
|
||||
/* Get the number of testtasks assigned to me. */
|
||||
$testTasks = $this->testtask->getByUser($this->app->user->account, $pager, $orderBy, 'assignedTo');
|
||||
$testTaskCount = $pager->recTotal;
|
||||
|
||||
$issueCount = 0;
|
||||
$riskCount = 0;
|
||||
$reviewCount = 0;
|
||||
$ncCount = 0;
|
||||
$meetingCount = 0;
|
||||
$isMaxVersion = isset($this->config->maxVersion) ? 1 : 0;
|
||||
if($isMaxVersion)
|
||||
{
|
||||
|
||||
$this->loadModel('issue');
|
||||
$this->loadModel('risk');
|
||||
$this->loadModel('review');
|
||||
$this->loadModel('meeting');
|
||||
|
||||
/* Get the number of issues assigned to me. */
|
||||
$issues = $this->issue->getUserIssues('assignedTo', $this->app->user->account, $orderBy, $pager);
|
||||
$issueCount = $pager->recTotal;
|
||||
|
||||
/* Get the number of risks assigned to me. */
|
||||
$risks = $this->risk->getUserRisks('assignedTo', $this->app->user->account, $orderBy, $pager);
|
||||
$riskCount = $pager->recTotal;
|
||||
|
||||
/* Get the number of reviews assigned to me. */
|
||||
$reviewList = $this->review->getUserReviews('wait', $orderBy, $pager);
|
||||
$reviewCount = $pager->recTotal;
|
||||
|
||||
/* Get the number of nc assigned to me. */
|
||||
$ncList = $this->my->getNcList('assignedToMe', $orderBy, $pager);
|
||||
$ncCount = $pager->recTotal;
|
||||
|
||||
/* Get the number of meetings assigned to me. */
|
||||
$meetings = $this->meeting->getListByUser('futureMeeting', $orderBy, 0, $pager);
|
||||
$meetingCount = $pager->recTotal;
|
||||
}
|
||||
|
||||
echo <<<EOF
|
||||
<script>
|
||||
var taskCount = $taskCount;
|
||||
var storyCount = $storyCount;
|
||||
var bugCount = $bugCount;
|
||||
var caseCount = $caseCount;
|
||||
var testTaskCount = $testTaskCount;
|
||||
|
||||
var isOpenedURAndSR = $isOpenedURAndSR;
|
||||
if(isOpenedURAndSR !== 0) var requirementCount = $requirementCount;
|
||||
|
||||
var isMaxVersion = $isMaxVersion;
|
||||
if(isMaxVersion !== 0)
|
||||
{
|
||||
var issueCount = $issueCount;
|
||||
var riskCount = $riskCount;
|
||||
var reviewCount = $reviewCount;
|
||||
var ncCount = $ncCount;
|
||||
var meetingCount = $meetingCount;
|
||||
}
|
||||
</script>
|
||||
EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* My contribute view.
|
||||
*
|
||||
@@ -145,7 +264,7 @@ class my extends control
|
||||
$this->view->position[] = $this->lang->my->todo;
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$todos = $this->loadModel('todo')->getList($type, $account, $status, 0, $pager, $sort);
|
||||
$tasks = $this->loadModel('task')->getUserSuspendedTasks($account);
|
||||
@@ -198,7 +317,7 @@ class my extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$stories = $this->loadModel('story')->getUserStories($this->app->user->account, $type, $sort, $pager, 'story', false);
|
||||
if(!empty($stories)) $stories = $this->story->mergeReviewer($stories);
|
||||
@@ -242,7 +361,7 @@ class my extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$stories = $this->loadModel('story')->getUserStories($this->app->user->account, $type, $sort, $pager, 'requirement');
|
||||
if(!empty($stories)) $stories = $this->story->mergeReviewer($stories);
|
||||
@@ -286,7 +405,7 @@ class my extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Get tasks. */
|
||||
$tasks = $this->loadModel('task')->getUserTasks($this->app->user->account, $type, 0, $pager, $sort);
|
||||
@@ -361,7 +480,7 @@ class my extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
$bugs = $this->loadModel('bug')->getUserBugs($this->app->user->account, $type, $sort, 0, $pager);
|
||||
$bugs = $this->bug->checkDelayedBugs($bugs);
|
||||
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'bug', false);
|
||||
@@ -413,7 +532,7 @@ class my extends control
|
||||
$this->app->loadLang('testcase');
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->testTask;
|
||||
$this->view->position[] = $this->lang->my->testTask;
|
||||
@@ -456,7 +575,7 @@ class my extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$cases = array();
|
||||
if($type == 'assigntome')
|
||||
@@ -505,7 +624,7 @@ class my extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$docs = $this->doc->getDocsByBrowseType($type, 0, 0, $sort, $pager);
|
||||
|
||||
@@ -791,7 +910,7 @@ class my extends control
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Get users by dept. */
|
||||
$user = $this->loadModel('user')->getById($this->app->user->account, 'account');
|
||||
@@ -968,12 +1087,14 @@ class my extends control
|
||||
/**
|
||||
* Build contact lists.
|
||||
*
|
||||
* @param dropdownName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function buildContactLists()
|
||||
public function buildContactLists($dropdownName = 'mailto')
|
||||
{
|
||||
$this->view->contactLists = $this->user->getContactLists($this->app->user->account, 'withnote');
|
||||
$this->view->dropdownName = $dropdownName;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -1086,7 +1207,7 @@ class my extends control
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$orderBy = $direction == 'next' ? 'date_desc' : 'date_asc';
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* The header and position. */
|
||||
$this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->dynamic;
|
||||
|
||||
+21
-2
@@ -3,9 +3,28 @@ $(function()
|
||||
if(typeof mode === 'string')
|
||||
{
|
||||
$('#subNavbar li[data-id=' + mode + ']').addClass('active');
|
||||
if(typeof rawMethod === 'string' && rawMethod == 'work') $('#subNavbar li[data-id=' + mode + '] a').append('<span class="label label-light label-badge">' + total + '</span>');
|
||||
if(typeof rawMethod === 'string' && rawMethod == 'work')
|
||||
{
|
||||
$("#subNavbar li[data-id='task'] a").append('<span class="label label-light label-badge">' + taskCount + '</span>');
|
||||
$("#subNavbar li[data-id='story'] a").append('<span class="label label-light label-badge">' + storyCount + '</span>');
|
||||
$("#subNavbar li[data-id='bug'] a").append('<span class="label label-light label-badge">' + bugCount + '</span>');
|
||||
$("#subNavbar li[data-id='testcase'] a").append('<span class="label label-light label-badge">' + caseCount + '</span>');
|
||||
$("#subNavbar li[data-id='testtask'] a").append('<span class="label label-light label-badge">' + testTaskCount + '</span>');
|
||||
|
||||
if(isOpenedURAndSR !== 0) $("#subNavbar li[data-id='requirement'] a").append('<span class="label label-light label-badge">' + requirementCount + '</span>');
|
||||
|
||||
if(isMaxVersion !== 0)
|
||||
{
|
||||
$("#subNavbar li[data-id='issue'] a").append('<span class="label label-light label-badge">' + issueCount + '</span>');
|
||||
$("#subNavbar li[data-id='risk'] a").append('<span class="label label-light label-badge">' + riskCount + '</span>');
|
||||
$("#subNavbar li[data-id='audit'] a").append('<span class="label label-light label-badge">' + reviewCount + '</span>');
|
||||
$("#subNavbar li[data-id='nc'] a").append('<span class="label label-light label-badge">' + ncCount + '</span>');
|
||||
$("#subNavbar li[data-id='myMeeting'] a").append('<span class="label label-light label-badge">' + meetingCount + '</span>');
|
||||
}
|
||||
}
|
||||
}
|
||||
var $scp = $('[data-id="changePassword"] a');
|
||||
|
||||
var $scp = $('[data-id="changePassword"] a');
|
||||
if($scp.length > 0)
|
||||
{
|
||||
var sign = config.requestType == 'GET' ? '&' : '?';
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<?php
|
||||
if($contactLists)
|
||||
{
|
||||
echo html::select('contactListMenu', $contactLists, '', "class='form-control chosen' onchange=\"setMailto('mailto', this.value)\"");
|
||||
echo html::select('contactListMenu', $contactLists, '', "class='form-control chosen' onchange=\"setMailto('$dropdownName', this.value)\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -28,7 +28,7 @@ else
|
||||
<style>
|
||||
#contactListMenu_chosen {width: 100px !important;}
|
||||
#contactListMenu + .chosen-container {min-width: 100px;}
|
||||
td > #mailto + .chosen-container .chosen-choices {border-radius: 2px 2px 0 0;}
|
||||
td > #mailto + .chosen-container + #contactListMenu + .chosen-container > .chosen-single {border-radius: 0 0 2px 2px; border-top-width: 0; padding-top: 6px;}
|
||||
td > <?php echo "#" . $dropdownName;?> + .chosen-container .chosen-choices {border-radius: 2px 2px 0 0;}
|
||||
td > <?php echo "#" . $dropdownName;?> + .chosen-container + #contactListMenu + .chosen-container > .chosen-single {border-radius: 0 0 2px 2px; border-top-width: 0; padding-top: 6px;}
|
||||
#contactListMenu + .chosen-container.chosen-container-active > .chosen-single {border-top-width: 1px !important; padding-top: 5px !important;}
|
||||
</style>
|
||||
|
||||
@@ -214,7 +214,7 @@ class product extends control
|
||||
setcookie('productStoryOrder', $orderBy, 0, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
@@ -843,7 +843,7 @@ class product extends control
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$orderBy = $direction == 'next' ? 'date_desc' : 'date_asc';
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
|
||||
@@ -577,7 +577,7 @@ class productModel extends model
|
||||
->stripTags($this->config->product->editor->create['id'], $this->config->allowedTags)
|
||||
->join('whitelist', ',')
|
||||
->join('reviewer', ',')
|
||||
->remove('uid,newLine,lineName')
|
||||
->remove('uid,newLine,lineName,contactListMenu')
|
||||
->get();
|
||||
|
||||
if(!empty($_POST['lineName']))
|
||||
@@ -653,7 +653,7 @@ class productModel extends model
|
||||
->join('whitelist', ',')
|
||||
->join('reviewer', ',')
|
||||
->stripTags($this->config->product->editor->edit['id'], $this->config->allowedTags)
|
||||
->remove('uid,changeProjects')
|
||||
->remove('uid,changeProjects,contactListMenu')
|
||||
->get();
|
||||
|
||||
if($this->config->systemMode == 'new')
|
||||
|
||||
@@ -599,7 +599,7 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('plan', $productPlans[$productID], '', "class='form-control chosen' id='plan'");?>
|
||||
<?php echo html::select('plan', zget($productPlans, $productID, ''), '', "class='form-control chosen' id='plan'");?>
|
||||
<span class='input-group-btn'><?php echo html::commonButton($lang->execution->linkStory, "id='toTaskButton'", 'btn btn-primary');?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -104,8 +104,12 @@
|
||||
</tr>
|
||||
<tr id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $users, '', 'class="form-control chosen" multiple');?></td>
|
||||
<td></td>
|
||||
<td colspan='2'>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('whitelist[]', $users, '', 'class="form-control chosen" multiple');?>
|
||||
<?php echo $this->fetch('my', 'buildContactLists', "dropdownName='whitelist'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='3' class='text-center form-actions'>
|
||||
|
||||
@@ -87,8 +87,12 @@
|
||||
</tr>
|
||||
<tr class="<?php if($product->acl == 'open') echo 'hidden';?>" id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $users, $product->whitelist, 'class="form-control chosen" multiple');?></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('whitelist[]', $users, $product->whitelist, 'class="form-control chosen" multiple');?>
|
||||
<?php echo $this->fetch('my', 'buildContactLists', "dropdownName='whitelist'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='3' class='text-center form-actions'>
|
||||
|
||||
@@ -66,7 +66,7 @@ class productplan extends control
|
||||
|
||||
$this->executeHooks($planID);
|
||||
|
||||
if($parent > 0) $this->productplan->updateParentStatus($parent, 'opened');
|
||||
if($parent > 0) $this->productplan->updateParentStatus($parent);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $planID));
|
||||
@@ -248,7 +248,7 @@ class productplan extends control
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
$this->session->set('productPlanList', $this->app->getURI(true), 'product');
|
||||
|
||||
$viewType = $this->cookie->viewType ? $this->cookie->viewType : 'list';
|
||||
@@ -280,9 +280,9 @@ class productplan extends control
|
||||
|
||||
foreach($branches as $id => $name)
|
||||
{
|
||||
$plans = isset($planGroup[$product->id][$id]) ? array_filter($planGroup[$product->id][$id]) : array();
|
||||
$plans = isset($planGroup[$product->id][$id]) ? array_filter($planGroup[$product->id][$id]) : array();
|
||||
$branchPairs[$id] = $name . ' ' . count($plans);
|
||||
$planCount += count($plans);
|
||||
$planCount += count($plans);
|
||||
}
|
||||
|
||||
$this->view->branches = array('all' => $this->lang->productplan->allAB . ' ' . $planCount) + $branchPairs;
|
||||
@@ -344,7 +344,7 @@ class productplan extends control
|
||||
if($this->app->getViewType() == 'xhtml') $recPerPage = 10;
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$this->commonAction($plan->product, $plan->branch);
|
||||
$products = $this->product->getProductPairsByProject($this->session->project);
|
||||
|
||||
@@ -29,5 +29,5 @@ ol, ul {padding-left: 20px;}
|
||||
#mainMenu .icon-checked, #mainMenu .icon-off, #mainMenu .icon-play, #mainMenu .icon-magic {margin-right: 3px;}
|
||||
|
||||
#mainMenu .page-title {display: flex;}
|
||||
#mainMenu .btn-toolbar .page-title .label { top: 9px; margin-right: 10px; height: 16px;}
|
||||
#mainMenu .btn-toolbar .page-title .label {top: 9px; margin-right: 10px; height: 16px;}
|
||||
#mainMenu .btn-toolbar .page-title .text {max-width: 434px; overflow: hidden; white-space:nowrap; margin-right: 6px;}
|
||||
|
||||
@@ -33,12 +33,8 @@ function setPlanStatus(planID, status)
|
||||
if(status != 'wait')
|
||||
{
|
||||
$('#future' + planID).closest('div').addClass('hidden');
|
||||
|
||||
$("input[name='begin[" + planID + "]']").closest('td').addClass('required');
|
||||
$("input[name='end[" + planID + "]']").closest('td').addClass('required');
|
||||
$("input[name='begin[" + planID + "]']").removeAttr('disabled');
|
||||
$("input[name='end[" + planID + "]']").removeAttr('disabled');
|
||||
|
||||
$('.form-date').datetimepicker('update');
|
||||
}
|
||||
else
|
||||
@@ -46,15 +42,12 @@ function setPlanStatus(planID, status)
|
||||
var isFuture = $('#future' + planID).prop('checked');
|
||||
|
||||
$('#future' + planID).closest('div').removeClass('hidden');
|
||||
$("input[name='begin[" + planID + "]']").closest('td').removeClass('required');
|
||||
$("input[name='end[" + planID + "]']").closest('td').removeClass('required');
|
||||
|
||||
if(isFuture)
|
||||
{
|
||||
$("input[name='begin[" + planID + "]']").attr('disabled', 'disabled');
|
||||
$("input[name='end[" + planID + "]']").attr('disabled', 'disabled');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,18 +56,18 @@ $(function()
|
||||
$('#branch_chosen .chosen-single span').prepend('<i class="icon-delay"></i>');
|
||||
$('#kanban').kanban(
|
||||
{
|
||||
data: kanbanData,
|
||||
minColWidth: 290,
|
||||
maxColWidth: 290,
|
||||
maxColHeight: 460,
|
||||
minColHeight: 190,
|
||||
cardHeight: 80,
|
||||
itemRender: renderKanbanItem,
|
||||
virtualize: true,
|
||||
data: kanbanData,
|
||||
minColWidth: 290,
|
||||
maxColWidth: 290,
|
||||
maxColHeight: 460,
|
||||
minColHeight: 190,
|
||||
cardHeight: 80,
|
||||
itemRender: renderKanbanItem,
|
||||
virtualize: true,
|
||||
droppable:
|
||||
{
|
||||
target: findDropColumns,
|
||||
finish: handleFinishDrop,
|
||||
target: findDropColumns,
|
||||
finish: handleFinishDrop,
|
||||
mouseButton: 'left'
|
||||
}
|
||||
});
|
||||
@@ -77,7 +77,7 @@ $(function()
|
||||
$.zui.ContextMenu.hide();
|
||||
});
|
||||
|
||||
/* Init contextmenu */
|
||||
/* Init contextmenu. */
|
||||
$('#kanban').on('click', '[data-contextmenu]', function(event)
|
||||
{
|
||||
var $trigger = $(this);
|
||||
@@ -86,30 +86,27 @@ $(function()
|
||||
if(!menuCreator) return;
|
||||
|
||||
var options = $.extend({event: event, $trigger: $trigger}, $trigger.data());
|
||||
var items = menuCreator(options);
|
||||
var items = menuCreator(options);
|
||||
if(!items || !items.length) return;
|
||||
|
||||
$.zui.ContextMenu.show(items, items.$options || {event: event});
|
||||
});
|
||||
}
|
||||
|
||||
/* Hide contextmenu when page scroll */
|
||||
/* Hide contextmenu when page scroll. */
|
||||
$(window).on('scroll', function()
|
||||
{
|
||||
$.zui.ContextMenu.hide();
|
||||
});
|
||||
});
|
||||
|
||||
/* Define menu creators */
|
||||
window.menuCreators =
|
||||
{
|
||||
card: createCardMenu
|
||||
};
|
||||
/* Define menu creators. */
|
||||
window.menuCreators = {card: createCardMenu};
|
||||
|
||||
/**
|
||||
* Create card menu.
|
||||
*
|
||||
* @param object $options
|
||||
* @param object options
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -194,11 +191,14 @@ $(document).on('click', 'td.content .more', function(e)
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Find drop columns
|
||||
* @param {JQuery} $element Drag element
|
||||
* @param {JQuery} $root Dnd root element
|
||||
*/
|
||||
/**
|
||||
* Find drop columns.
|
||||
*
|
||||
* @param object $element Drag element
|
||||
* @param object $root Dnd root element
|
||||
* @access public
|
||||
* @return object|bool
|
||||
*/
|
||||
function findDropColumns($element, $root)
|
||||
{
|
||||
var $col = $element.closest('.kanban-col');
|
||||
@@ -216,42 +216,46 @@ function findDropColumns($element, $root)
|
||||
if(colRules === true) return true;
|
||||
|
||||
var $newCol = $(this);
|
||||
var newCol = $newCol.data();
|
||||
var newCol = $newCol.data();
|
||||
if(newCol.id === col.id) return false;
|
||||
|
||||
var $newLane = $newCol.closest('.kanban-lane');
|
||||
var newLane = $newLane.data('lane');
|
||||
var newLane = $newLane.data('lane');
|
||||
return colRules.indexOf(newCol.type) > -1 && newLane.id === lane.id;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle finish drop task
|
||||
* @param {Object} event Event object
|
||||
* @returns {void}
|
||||
* Handle finish drop card.
|
||||
*
|
||||
* @param object event
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function handleFinishDrop(event)
|
||||
{
|
||||
var $card = $(event.element); // The drag card
|
||||
var $card = $(event.element); // The drag card.
|
||||
var $dragCol = $card.closest('.kanban-lane-col');
|
||||
var $dropCol = $(event.target);
|
||||
|
||||
/* Get d-n-d(drag and drop) infos 获取拖放操作相关信息 */
|
||||
var card = $card.data('item');
|
||||
/* Get d-n-d(drag and drop) infos. */
|
||||
var card = $card.data('item');
|
||||
var fromColType = $dragCol.data('type');
|
||||
var toColType = $dropCol.data('type');
|
||||
var kanbanID = $card.closest('.kanban').data('id');
|
||||
var toColType = $dropCol.data('type');
|
||||
var kanbanID = $card.closest('.kanban').data('id');
|
||||
|
||||
changeCardColType(card, fromColType, toColType, kanbanID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change column type for a card
|
||||
|
||||
* @param {Object} card Card object
|
||||
* @param {String} fromColType The column type before change
|
||||
* @param {String} toColType The column type after change
|
||||
* @param {String} kanbanID Kanban ID
|
||||
* Change column type for a card.
|
||||
*
|
||||
* @param object card
|
||||
* @param string fromColType The column type before change
|
||||
* @param string toColType The column type after change
|
||||
* @param int kanbanID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function changeCardColType(card, fromColType, toColType, kanbanID)
|
||||
{
|
||||
@@ -303,7 +307,12 @@ function changeCardColType(card, fromColType, toColType, kanbanID)
|
||||
}
|
||||
|
||||
/**
|
||||
* The function for rendering kanban item
|
||||
* The function for rendering kanban item.
|
||||
*
|
||||
* @param object item
|
||||
* @param object $item
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function renderKanbanItem(item, $item)
|
||||
{
|
||||
@@ -387,10 +396,10 @@ function renderKanbanItem(item, $item)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get planID
|
||||
* Get planID.
|
||||
*
|
||||
* @param object $obj
|
||||
* @param int $branch
|
||||
* @param object obj
|
||||
* @param int branch
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
@@ -428,9 +437,9 @@ if(!window.kanbanDropRules)
|
||||
{
|
||||
window.kanbanDropRules =
|
||||
{
|
||||
wait: ['doing'],
|
||||
doing: ['done'],
|
||||
done: ['doing', 'closed'],
|
||||
wait: ['doing'],
|
||||
doing: ['done'],
|
||||
done: ['doing', 'closed'],
|
||||
closed: ['doing']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,8 +72,6 @@ function setPlanStatus()
|
||||
{
|
||||
$('#checkBox').closest('div').addClass('hidden');
|
||||
$('#future').val(0);
|
||||
$('#begin').closest('td').addClass('required');
|
||||
$('#end').closest('td').addClass('required');
|
||||
$('#begin').removeAttr('disabled');
|
||||
$('#end').parents('tr').show();
|
||||
}
|
||||
@@ -82,12 +80,10 @@ function setPlanStatus()
|
||||
var isFuture = $('#future').prop('checked');
|
||||
|
||||
$('#checkBox').closest('div').removeClass('hidden');
|
||||
$('#begin').closest('td').removeClass('required');
|
||||
$('#end').closest('td').removeClass('required');
|
||||
if(isFuture)
|
||||
{
|
||||
$('#begin').attr('disabled', 'disabled');
|
||||
$('#end').val('').parents('tr').hide();
|
||||
$('#end').parents('tr').hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,20 +111,20 @@ $lang->productplan->endList[93] = '3 Months';
|
||||
$lang->productplan->endList[186] = '6 Months';
|
||||
$lang->productplan->endList[365] = '1 Year';
|
||||
|
||||
$lang->productplan->errorNoTitle = 'ID %s title should not be empty.';
|
||||
$lang->productplan->errorNoBegin = 'ID %s begin time should not be empty.';
|
||||
$lang->productplan->errorNoEnd = 'ID %s end time should not be empty.';
|
||||
$lang->productplan->beginGeEnd = 'ID %s begin time should not be >= end time.';
|
||||
$lang->productplan->beginLetterParent = "The start date of the parent plan: %s, the start date cannot be less than the start date of the parent plan.";
|
||||
$lang->productplan->endGreaterParent = "The completion date of the parent plan: %s, the completion date cannot be greater than the completion date of the parent plan.";
|
||||
$lang->productplan->beginGreaterChild = "The start date of the child plan: %s, the start date cannot be greater than the start date of the child plan.";
|
||||
$lang->productplan->endLetterChild = "The completion date of the child plan: %s, the completion date cannot be less than the completion date of the child plan.";
|
||||
$lang->productplan->noLinkedProject = "The current product has not been linked with a project. Please enter the list of the product to link or create a project.";
|
||||
$lang->productplan->enterProjectList = "Enter the list of the product";
|
||||
$lang->productplan->beginGreaterChildTip = "The start date of the parent plan[%s]: %s, cannot be greater than the start date of the child plan: %s.";
|
||||
$lang->productplan->endLetterChildTip = "The completion date of the parent plan[%s]: %s, cannot be less than the completion date of the child plan: %s.", ;
|
||||
$lang->productplan->beginLetterParentTip = "The start date of the child plan[%s]: %s, cannot be less than the start date of the parent plan: %s.";
|
||||
$lang->productplan->endGreaterParentTip = "The completion date of the child plan[%s]: %s, cannot be greater than the completion date of the parent plan: %s.";
|
||||
$lang->productplan->errorNoTitle = 'ID %s title should not be empty.';
|
||||
$lang->productplan->errorNoBegin = 'ID %s begin time should not be empty.';
|
||||
$lang->productplan->errorNoEnd = 'ID %s end time should not be empty.';
|
||||
$lang->productplan->beginGeEnd = 'ID %s begin time should not be >= end time.';
|
||||
$lang->productplan->beginLetterParent = "The start date of the parent plan: %s, the start date cannot be less than the start date of the parent plan.";
|
||||
$lang->productplan->endGreaterParent = "The completion date of the parent plan: %s, the completion date cannot be greater than the completion date of the parent plan.";
|
||||
$lang->productplan->beginGreaterChild = "The start date of the child plan: %s, the start date cannot be greater than the start date of the child plan.";
|
||||
$lang->productplan->endLetterChild = "The completion date of the child plan: %s, the completion date cannot be less than the completion date of the child plan.";
|
||||
$lang->productplan->noLinkedProject = "The current product has not been linked with a project. Please enter the list of the product to link or create a project.";
|
||||
$lang->productplan->enterProjectList = "Enter the list of the product";
|
||||
$lang->productplan->beginGreaterChildTip = "The start date of the parent plan[%s]: %s, cannot be greater than the start date of the child plan: %s.";
|
||||
$lang->productplan->endLetterChildTip = "The completion date of the parent plan[%s]: %s, cannot be less than the completion date of the child plan: %s.", ;
|
||||
$lang->productplan->beginLetterParentTip = "The start date of the child plan[%s]: %s, cannot be less than the start date of the parent plan: %s.";
|
||||
$lang->productplan->endGreaterParentTip = "The completion date of the child plan[%s]: %s, cannot be greater than the completion date of the parent plan: %s.";
|
||||
|
||||
$lang->productplan->featureBar['browse']['all'] = 'All';
|
||||
$lang->productplan->featureBar['browse']['wait'] = 'Waiting';
|
||||
|
||||
@@ -111,20 +111,20 @@ $lang->productplan->endList[93] = '三个月';
|
||||
$lang->productplan->endList[186] = '半年';
|
||||
$lang->productplan->endList[365] = '一年';
|
||||
|
||||
$lang->productplan->errorNoTitle = 'ID %s 标题不能为空';
|
||||
$lang->productplan->errorNoBegin = 'ID %s 开始时间不能为空';
|
||||
$lang->productplan->errorNoEnd = 'ID %s 结束时间不能为空';
|
||||
$lang->productplan->beginGeEnd = 'ID %s 开始时间不能大于结束时间';
|
||||
$lang->productplan->beginLetterParent = "父计划的开始日期:%s,开始日期不能小于父计划的开始日期";
|
||||
$lang->productplan->endGreaterParent = "父计划的完成日期:%s,完成日期不能大于父计划的完成日期";
|
||||
$lang->productplan->beginGreaterChild = "子计划的开始日期:%s,开始日期不能大于子计划的开始日期";
|
||||
$lang->productplan->endLetterChild = "子计划的完成日期:%s,完成日期不能小于子计划的完成日期";
|
||||
$lang->productplan->noLinkedProject = "当前产品还未关联项目,请进入产品的项目列表关联或创建一个项目";
|
||||
$lang->productplan->enterProjectList = "进入产品的项目列表";
|
||||
$lang->productplan->beginGreaterChildTip = "父计划[%s]的开始日期:%s,不能大于子计划的开始日期: %s";
|
||||
$lang->productplan->endLetterChildTip = "父计划[%s]的完成日期:%s,不能小于子计划的完成日期: %s";
|
||||
$lang->productplan->beginLetterParentTip = "子计划[%s]的开始日期:%s,不能小于父计划的开始日期: %s";
|
||||
$lang->productplan->endGreaterParentTip = "子计划[%s]的完成日期:%s,不能大于父计划的完成日期: %s";
|
||||
$lang->productplan->errorNoTitle = 'ID %s 标题不能为空';
|
||||
$lang->productplan->errorNoBegin = 'ID %s 开始时间不能为空';
|
||||
$lang->productplan->errorNoEnd = 'ID %s 结束时间不能为空';
|
||||
$lang->productplan->beginGeEnd = 'ID %s 开始时间不能大于结束时间';
|
||||
$lang->productplan->beginLetterParent = "父计划的开始日期:%s,开始日期不能小于父计划的开始日期";
|
||||
$lang->productplan->endGreaterParent = "父计划的完成日期:%s,完成日期不能大于父计划的完成日期";
|
||||
$lang->productplan->beginGreaterChild = "子计划的开始日期:%s,开始日期不能大于子计划的开始日期";
|
||||
$lang->productplan->endLetterChild = "子计划的完成日期:%s,完成日期不能小于子计划的完成日期";
|
||||
$lang->productplan->noLinkedProject = "当前产品还未关联项目,请进入产品的项目列表关联或创建一个项目";
|
||||
$lang->productplan->enterProjectList = "进入产品的项目列表";
|
||||
$lang->productplan->beginGreaterChildTip = "父计划[%s]的开始日期:%s,不能大于子计划的开始日期: %s";
|
||||
$lang->productplan->endLetterChildTip = "父计划[%s]的完成日期:%s,不能小于子计划的完成日期: %s";
|
||||
$lang->productplan->beginLetterParentTip = "子计划[%s]的开始日期:%s,不能小于父计划的开始日期: %s";
|
||||
$lang->productplan->endGreaterParentTip = "子计划[%s]的完成日期:%s,不能大于父计划的完成日期: %s";
|
||||
|
||||
$lang->productplan->featureBar['browse']['all'] = '所有';
|
||||
$lang->productplan->featureBar['browse']['wait'] = '未开始';
|
||||
|
||||
@@ -401,7 +401,7 @@ class productplanModel extends model
|
||||
}
|
||||
if($plan->parentEnd != $this->config->productplan->future)
|
||||
{
|
||||
if($plan->end !==$this->config->productplan->future and $plan->end > $plan->parentEnd) dao::$errors['end'] = sprintf($this->lang->productplan->endGreaterParent, $plan->parentEnd);
|
||||
if($plan->end !== $this->config->productplan->future and $plan->end > $plan->parentEnd) dao::$errors['end'] = sprintf($this->lang->productplan->endGreaterParent, $plan->parentEnd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,7 +454,7 @@ class productplanModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a plan
|
||||
* Update a plan.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
@@ -464,21 +464,21 @@ class productplanModel extends model
|
||||
{
|
||||
$oldPlan = $this->dao->findByID((int)$planID)->from(TABLE_PRODUCTPLAN)->fetch();
|
||||
$plan = fixer::input('post')->stripTags($this->config->productplan->editor->edit['id'], $this->config->allowedTags)
|
||||
->setIF($this->post->future || empty($_POST['begin']), 'begin', $this->config->productplan->future)
|
||||
->setIF($this->post->future || empty($_POST['end']), 'end', $this->config->productplan->future)
|
||||
->setIF($this->post->future or empty($_POST['begin']), 'begin', $this->config->productplan->future)
|
||||
->setIF($this->post->future or empty($_POST['end']), 'end', $this->config->productplan->future)
|
||||
->remove('delta,uid,future')
|
||||
->get();
|
||||
|
||||
if($oldPlan->parent > 0)
|
||||
{
|
||||
$parentPlan = $this->getByID($oldPlan->parent);
|
||||
if($parentPlan->begin != $this->config->productplan->future)
|
||||
if($parentPlan->begin !== $this->config->productplan->future)
|
||||
{
|
||||
if($plan->begin < $parentPlan->begin) dao::$errors['begin'] = sprintf($this->lang->productplan->beginLetterParent, $parentPlan->begin);
|
||||
}
|
||||
if($parentPlan->end != $this->config->productplan->future)
|
||||
if($parentPlan->end !== $this->config->productplan->future)
|
||||
{
|
||||
if($plan->end !==$this->config->productplan->future and $plan->end > $parentPlan->end) dao::$errors['end'] = sprintf($this->lang->productplan->endGreaterParent, $parentPlan->end);
|
||||
if($plan->end !== $this->config->productplan->future and $plan->end > $parentPlan->end) dao::$errors['end'] = sprintf($this->lang->productplan->endGreaterParent, $parentPlan->end);
|
||||
}
|
||||
}
|
||||
elseif($oldPlan->parent == -1 and $plan->begin != $this->config->productplan->future)
|
||||
@@ -496,25 +496,18 @@ class productplanModel extends model
|
||||
if($maxEnd > $plan->end and $maxEnd != $this->config->productplan->future) dao::$errors['end'] = sprintf($this->lang->productplan->endLetterChildTip, $planID, $plan->end, $maxEnd);
|
||||
}
|
||||
|
||||
$requiredFields = $oldPlan->status == 'wait' ? $this->config->productplan->edit->requiredFields : 'title, begin, end';
|
||||
if($plan->status != 'wait' and $plan->begin == $this->config->productplan->future)
|
||||
{
|
||||
dao::$errors['begin'] = sprintf($this->lang->error->notempty, $this->lang->productplan->begin);
|
||||
}
|
||||
if($plan->status != 'wait' and $plan->end == $this->config->productplan->future)
|
||||
{
|
||||
dao::$errors['end'] = sprintf($this->lang->error->notempty, $this->lang->productplan->end);
|
||||
}
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$plan = $this->loadModel('file')->processImgURL($plan, $this->config->productplan->editor->edit['id'], $this->post->uid);
|
||||
$this->dao->update(TABLE_PRODUCTPLAN)
|
||||
->data($plan)
|
||||
->autoCheck()
|
||||
->batchCheck($requiredFields, 'notempty')
|
||||
->batchCheck($this->config->productplan->edit->requiredFields, 'notempty')
|
||||
->checkIF(!$this->post->future && !empty($_POST['begin']) && !empty($_POST['end']), 'end', 'ge', $plan->begin)
|
||||
->where('id')->eq((int)$planID)
|
||||
->exec();
|
||||
if(dao::isError()) return false;
|
||||
|
||||
if($oldPlan->parent > 0) $this->updateParentStatus($oldPlan->parent);
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
@@ -525,10 +518,10 @@ class productplanModel extends model
|
||||
|
||||
/**
|
||||
* Start a plan.
|
||||
*
|
||||
* @param int $planID
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return array
|
||||
* @return array
|
||||
*/
|
||||
public function start($planID)
|
||||
{
|
||||
@@ -554,7 +547,7 @@ class productplanModel extends model
|
||||
|
||||
if(dao::isError()) return false;
|
||||
|
||||
if($oldPlan->parent > 0) $this->updateParentStatus($oldPlan->parent, 'started');
|
||||
if($oldPlan->parent > 0) $this->updateParentStatus($oldPlan->parent);
|
||||
$this->file->updateObjectID($this->post->uid, $planID, 'productplan');
|
||||
|
||||
return common::createChanges($oldPlan, $plan);
|
||||
@@ -567,7 +560,7 @@ class productplanModel extends model
|
||||
* @param string $status doing|done|closed
|
||||
* @param string $action started|finished|closed|activated
|
||||
* @access public
|
||||
* @return array
|
||||
* @return bool
|
||||
*/
|
||||
public function updateStatus($planID, $status = '', $action = '')
|
||||
{
|
||||
@@ -584,7 +577,7 @@ class productplanModel extends model
|
||||
$actionID = $this->loadModel('action')->create('productplan', $planID, $action);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
if($oldPlan->parent > 0) $this->updateParentStatus($oldPlan->parent, $action);
|
||||
if($oldPlan->parent > 0) $this->updateParentStatus($oldPlan->parent);
|
||||
|
||||
return !dao::isError();
|
||||
}
|
||||
@@ -593,64 +586,48 @@ class productplanModel extends model
|
||||
* Update a parent plan's status.
|
||||
*
|
||||
* @param int $parentID
|
||||
* @param string $action started|finished|closed|activated
|
||||
* @access public
|
||||
* @return void
|
||||
* @return bool
|
||||
*/
|
||||
public function updateParentStatus($parentID, $action)
|
||||
public function updateParentStatus($parentID)
|
||||
{
|
||||
$parent = $this->getByID($parentID);
|
||||
$childStatus = $this->dao->select('status')->from(TABLE_PRODUCTPLAN)->where('parent')->eq($parentID)->andWhere('deleted')->eq(0)->fetchPairs();
|
||||
|
||||
switch($action)
|
||||
if(count($childStatus) == 1 and isset($childStatus['wait']))
|
||||
{
|
||||
case 'opened':
|
||||
if($parent->status == 'done' or $parent->status == 'closed')
|
||||
{
|
||||
$parentStatus = 'doing';
|
||||
$parentAction = 'createchild';
|
||||
}
|
||||
|
||||
break;
|
||||
case 'started':
|
||||
if($parent->status != 'doing')
|
||||
{
|
||||
$parentStatus = 'doing';
|
||||
$parentAction = $parent->status != 'doing' ? 'startedbychild' : '';
|
||||
}
|
||||
|
||||
break;
|
||||
case 'finished':
|
||||
if(isset($childStatus['wait']) or isset($childStatus['doing'])) break;
|
||||
|
||||
if($parent->status != 'done')
|
||||
{
|
||||
$parentStatus = 'done';
|
||||
$parentAction = 'finishedbychild';
|
||||
}
|
||||
|
||||
break;
|
||||
case 'closed':
|
||||
if(count($childStatus) == 1 and $parent->status != 'closed')
|
||||
{
|
||||
$parentAction = 'closedbychild';
|
||||
$parentStatus = 'closed';
|
||||
}
|
||||
|
||||
break;
|
||||
case 'activated':
|
||||
if($parent->status != 'doing')
|
||||
{
|
||||
$parentStatus = 'doing';
|
||||
$parentAction = $parent->status != 'doing' ? 'activatedbychild' : '';
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
elseif(count($childStatus) == 1 and isset($childStatus['closed']))
|
||||
{
|
||||
if($parent->status != 'closed')
|
||||
{
|
||||
$parentStatus = 'closed';
|
||||
$parentAction = 'closedbychild';
|
||||
}
|
||||
}
|
||||
elseif(!isset($childStatus['wait']) and !isset($childStatus['doing']))
|
||||
{
|
||||
if($parent->status != 'done')
|
||||
{
|
||||
$parentStatus = 'done';
|
||||
$parentAction = 'finishedbychild';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($parent->status != 'doing')
|
||||
{
|
||||
$parentStatus = 'doing';
|
||||
$parentAction = $this->app->rawMethod == 'create' ? 'createchild' : 'activatedbychild';
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($parentStatus)) $this->dao->update(TABLE_PRODUCTPLAN)->set('status')->eq($parentStatus)->where('id')->eq($parentID)->exec();
|
||||
if(!empty($parentAction)) $this->loadModel('action')->create('productplan', $parentID, $parentAction, '', $parentAction);
|
||||
|
||||
if(isset($parentStatus))
|
||||
{
|
||||
$this->dao->update(TABLE_PRODUCTPLAN)->set('status')->eq($parentStatus)->where('id')->eq($parentID)->exec();
|
||||
$this->loadModel('action')->create('productplan', $parentID, $parentAction, '', $parentAction);
|
||||
}
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
@@ -684,21 +661,13 @@ class productplanModel extends model
|
||||
$plan->begin = isset($data->begin[$planID]) ? $data->begin[$planID] : '';
|
||||
$plan->end = isset($data->end[$planID]) ? $data->end[$planID] : '';
|
||||
$plan->status = isset($data->status[$planID]) ? $data->status[$planID] : $oldPlans[$planID]->status;
|
||||
$plan->parent = $oldPlans[$planID]->parent;
|
||||
|
||||
if(empty($plan->title)) die(js::alter(sprintf($this->lang->productplan->errorNoTitle, $planID)));
|
||||
if($plan->begin > $plan->end and !empty($plan->end)) die(js::alert(sprintf($this->lang->productplan->beginGeEnd, $planID)));
|
||||
|
||||
if(!$isFuture and $plan->status != 'wait')
|
||||
{
|
||||
if($plan->begin == '') die(js::alert(sprintf($this->lang->productplan->errorNoBegin, $planID)));
|
||||
if($plan->end == '') die(js::alert(sprintf($this->lang->productplan->errorNoEnd, $planID)));
|
||||
if($plan->begin > $plan->end) die(js::alert(sprintf($this->lang->productplan->beginGeEnd, $planID)));
|
||||
}
|
||||
|
||||
if($plan->begin == '' or $plan->end == '')
|
||||
{
|
||||
$plan->begin = $this->config->productplan->future;
|
||||
$plan->end = $this->config->productplan->future;
|
||||
}
|
||||
if($plan->begin == '') $plan->begin = $this->config->productplan->future;
|
||||
if($plan->end == '') $plan->end = $this->config->productplan->future;
|
||||
|
||||
foreach($extendFields as $extendField)
|
||||
{
|
||||
@@ -714,12 +683,13 @@ class productplanModel extends model
|
||||
}
|
||||
|
||||
$changes = array();
|
||||
$parents = array();
|
||||
foreach($plans as $planID => $plan)
|
||||
{
|
||||
/*Determine whether the begin and end dates of the parent plan and the child plan are correct. */
|
||||
if($oldPlans[$planID]->parent > 0)
|
||||
$parentID = $oldPlans[$planID]->parent;
|
||||
/* Determine whether the begin and end dates of the parent plan and the child plan are correct. */
|
||||
if($parentID > 0)
|
||||
{
|
||||
$parentID = $oldPlans[$planID]->parent;
|
||||
$parent = isset($plans[$parentID]) ? $plans[$parentID] : $this->getByID($parentID);
|
||||
if($parent->begin != $this->config->productplan->future and $plan->begin != $this->config->productplan->future and $plan->begin < $parent->begin)
|
||||
{
|
||||
@@ -730,7 +700,7 @@ class productplanModel extends model
|
||||
die(js::alert(sprintf($this->lang->productplan->endGreaterParentTip, $planID, $plan->end, $parent->end)));
|
||||
}
|
||||
}
|
||||
elseif($oldPlans[$planID]->parent == -1 and $plan->begin != $this->config->productplan->future)
|
||||
elseif($parentID == -1 and $plan->begin != $this->config->productplan->future)
|
||||
{
|
||||
$childPlans = $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('parent')->eq($planID)->andWhere('deleted')->eq(0)->fetchAll('id');
|
||||
$minBegin = $plan->begin;
|
||||
@@ -748,12 +718,15 @@ class productplanModel extends model
|
||||
$change = common::createChanges($oldPlans[$planID], $plan);
|
||||
if($change)
|
||||
{
|
||||
if($parentID > 0 and !isset($parents[$parentID])) $parents[$parentID] = $parentID;
|
||||
$this->dao->update(TABLE_PRODUCTPLAN)->data($plan)->autoCheck()->where('id')->eq($planID)->exec();
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
$changes[$planID] = $change;
|
||||
}
|
||||
}
|
||||
|
||||
foreach($parents as $parent) $this->updateParentStatus($parent);
|
||||
|
||||
return $changes;
|
||||
}
|
||||
|
||||
@@ -999,7 +972,7 @@ class productplanModel extends model
|
||||
*/
|
||||
public static function isClickable($plan, $action)
|
||||
{
|
||||
$action = strtolower($action);
|
||||
$action = strtolower($action);
|
||||
$clickable = commonModel::hasPriv('productplan', $action);
|
||||
if(!$clickable) return false;
|
||||
|
||||
|
||||
@@ -38,28 +38,28 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($plans as $plan):?>
|
||||
<?php $isChecked = ($plan->begin == '2030-01-01' || $plan->end == '2030-01-01') ? 'checked="checked"' : '';?>
|
||||
<?php $isChecked = ($plan->begin == '2030-01-01' or $plan->end == '2030-01-01') ? 'checked="checked"' : '';?>
|
||||
<tr>
|
||||
<td class='text-center'><?php echo $plan->id . html::hidden("id[$plan->id]", $plan->id);?></td>
|
||||
<?php if($product->type != 'normal'):?>
|
||||
<td class='text-left'>
|
||||
<?php $disabled = $plan->parent == '-1' ? "disabled='disabled'" : '';?>
|
||||
<?php $disabled = $plan->parent != -1 ? "disabled='disabled'" : '';?>
|
||||
<?php echo html::select("branch[$plan->id]", $plan->parent == '-1' ? '' : $branchTagOption, $plan->branch, "onchange='getConflictStories($plan->id, this.value); 'class='form-control chosen' $disabled");?>
|
||||
</td>
|
||||
<?php endif;?>
|
||||
<td title='<?php echo $plan->title?>'><?php echo html::input("title[$plan->id]", $plan->title, "class='form-control'")?></td>
|
||||
<?php if($plan->parent != -1):?>
|
||||
<td><?php echo html::select("status[$plan->id]", array_slice($lang->productplan->statusList,($plan->status == 'wait' ? 0 : 1)), $plan->status, "class='form-control chosen' onchange='setPlanStatus($plan->id, this.value)'");?></td>
|
||||
<td><?php echo html::select("status[$plan->id]", array_slice($lang->productplan->statusList,($plan->status == 'wait' ? 0 : 1)), $plan->status, "class='form-control chosen' onchange='setPlanStatus($plan->id, this.value, $plan->parent)'");?></td>
|
||||
<?php else:?>
|
||||
<td><?php echo html::select("status[$plan->id]", array_slice($lang->productplan->statusList,($plan->status == 'wait' ? 0 : 1)), $plan->status, "class='form-control chosen' disabled onchange='setPlanStatus($plan->id, this.value)'");?></td>
|
||||
<td><?php echo html::select("status[$plan->id]", array_slice($lang->productplan->statusList,($plan->status == 'wait' ? 0 : 1)), $plan->status, "class='form-control chosen' disabled onchange='setPlanStatus($plan->id, this.value, $plan->parent)'");?></td>
|
||||
<?php endif;?>
|
||||
<?php $required = $plan->status != 'wait' ? 'required' : '' ;?>
|
||||
<?php $disabled = ($plan->begin == '2030-01-01' || $plan->end == '2030-01-01') ? 'disabled="disabled"' : '';?>
|
||||
<?php $disabled = (($plan->begin == '2030-01-01' or $plan->end == '2030-01-01') and $plan->status == 'wait') ? 'disabled="disabled"' : '';?>
|
||||
<?php if($plan->parent == -1 and ($plan->begin == '2030-01-01' or $plan->end == '2030-01-01')) $disabled = 'disabled="disabled"';?>
|
||||
<?php if($plan->begin == '2030-01-01') $plan->begin = '';?>
|
||||
<?php if($plan->end == '2030-01-01') $plan->end = '';?>
|
||||
<td class=<?php echo $required;?>><?php echo html::input("begin[$plan->id]", $plan->begin, "class='form-control form-date' $disabled");?></td>
|
||||
<td class=<?php echo $required;?>><?php echo html::input("end[$plan->id]", $plan->end, "class='form-control form-date' $disabled");?></td>
|
||||
<?php $hidden = ($plan->status != 'wait') ? 'hidden' : '';?>
|
||||
<td><?php echo html::input("begin[$plan->id]", $plan->begin, "class='form-control form-date' $disabled");?></td>
|
||||
<td><?php echo html::input("end[$plan->id]", $plan->end, "class='form-control form-date' $disabled");?></td>
|
||||
<?php $hidden = ($plan->status != 'wait' and $plan->parent != -1) ? 'hidden' : '';?>
|
||||
<td><div class='checkbox-primary <?php echo $hidden;?>'><input type='checkbox' id="future<?php echo $plan->id; ?>" name='future[<?php echo $plan->id; ?>]' <?php echo $isChecked;?> onclick="changeDate(<?php echo $plan->id;?>);"/><label for='future<?php echo $plan->id; ?>'><?php echo $lang->productplan->future;?></label></div></td>
|
||||
<?php foreach($extendFields as $extendField) echo "<td" . (($extendField->control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->loadModel('flow')->getFieldControl($extendField, $plan, $extendField->field . "[{$plan->id}]") . "</td>";?>
|
||||
</tr>
|
||||
|
||||
@@ -47,11 +47,10 @@
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
<tr>
|
||||
<?php $required = $plan->status != 'wait' ? 'required' : '' ;?>
|
||||
<?php $hidden = $plan->status != 'wait' ? 'hidden' : '';?>
|
||||
<?php $checked = $plan->begin == '2030-01-01' || $plan->end == '2030-01-01' ? "checked='checked'" : '';?>
|
||||
<?php $hidden = $plan->status != 'wait' ? 'hidden' : '';?>
|
||||
<?php $checked = $plan->begin == '2030-01-01' || $plan->end == '2030-01-01' ? "checked='checked'" : '';?>
|
||||
<th><?php echo $lang->productplan->begin;?></th>
|
||||
<td><?php echo html::input('begin', $plan->begin != '2030-01-01' ? formatTime($plan->begin) : '', "class='form-control form-date' $required");?></td>
|
||||
<td><?php echo html::input('begin', $plan->begin != '2030-01-01' ? formatTime($plan->begin) : '', "class='form-control form-date'");?></td>
|
||||
<td>
|
||||
<?php if($plan->status == 'wait'):?>
|
||||
<div class='checkbox-primary <?php echo $hidden;?>' id='checkBox'>
|
||||
@@ -63,7 +62,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->end;?></th>
|
||||
<td><?php echo html::input('end', $plan->end != '2030-01-01' ? formatTime($plan->end) : '', "class='form-control form-date' $required");?></td>
|
||||
<td><?php echo html::input('end', $plan->end != '2030-01-01' ? formatTime($plan->end) : '', "class='form-control form-date'");?></td>
|
||||
<?php $deltaValue = $plan->end == '2030-01-01' ? 0 : (strtotime($plan->end) - strtotime($plan->begin)) / 3600 / 24 + 1;?>
|
||||
<td colspan='2'><?php echo html::radio('delta', $lang->productplan->endList , $deltaValue, "onclick='computeEndDate(this.value)'");?></td>
|
||||
</tr>
|
||||
|
||||
@@ -593,7 +593,7 @@ class programModel extends model
|
||||
->add('type', 'program')
|
||||
->join('whitelist', ',')
|
||||
->stripTags($this->config->program->editor->create['id'], $this->config->allowedTags)
|
||||
->remove('delta,future')
|
||||
->remove('delta,future,contactListMenu')
|
||||
->get();
|
||||
|
||||
if($program->parent)
|
||||
@@ -678,7 +678,7 @@ class programModel extends model
|
||||
->setIF(!isset($this->post->budgetUnit), 'budgetUnit', $oldProgram->budgetUnit)
|
||||
->join('whitelist', ',')
|
||||
->stripTags($this->config->program->editor->edit['id'], $this->config->allowedTags)
|
||||
->remove('uid,delta,future,syncPRJUnit,exchangeRate')
|
||||
->remove('uid,delta,future,syncPRJUnit,exchangeRate,contactListMenu')
|
||||
->get();
|
||||
|
||||
$program = $this->loadModel('file')->processImgURL($program, $this->config->program->editor->edit['id'], $this->post->uid);
|
||||
|
||||
@@ -114,9 +114,12 @@
|
||||
</tr>
|
||||
<tr id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $users, '', 'class="form-control chosen" multiple');?></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td colspan='2'>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('whitelist[]', $users, '', 'class="form-control chosen" multiple');?>
|
||||
<?php echo $this->fetch('my', 'buildContactLists', "dropdownName='whitelist'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='4' class='text-center form-actions'>
|
||||
|
||||
@@ -99,9 +99,12 @@
|
||||
</tr>
|
||||
<tr class="<?php if($program->acl == 'open') echo 'hidden';?>" id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $users, $program->whitelist, 'class="form-control chosen" multiple');?></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('whitelist[]', $users, $program->whitelist, 'class="form-control chosen" multiple');?>
|
||||
<?php echo $this->fetch('my', 'buildContactLists', "dropdownName='whitelist'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='4' class='text-center form-actions'>
|
||||
|
||||
@@ -88,7 +88,7 @@ class programplan extends control
|
||||
|
||||
if($type == 'lists')
|
||||
{
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
$this->loadModel('datatable');
|
||||
$plans = $this->programplan->getPlans($projectID, $this->productID, $sort);
|
||||
}
|
||||
|
||||
@@ -125,14 +125,19 @@ $config->project->datatable->fieldList['actions']['width'] = '180';
|
||||
$config->project->datatable->fieldList['actions']['required'] = 'yes';
|
||||
$config->project->datatable->fieldList['actions']['pri'] = '1';
|
||||
|
||||
$config->project->removePriv['project'] = array('index', 'browse', 'kanban', 'create', 'batchEdit', 'qa', 'updateOrder', 'createGuide', 'programTitle');
|
||||
$config->project->removePriv['bug'] = array('batchChangePlan');
|
||||
$config->project->removePriv['doc'] = array('catalog', 'index');
|
||||
$config->project->removePriv['auditplan'] = array('delete');
|
||||
|
||||
$config->project->checkList = new stdclass();
|
||||
$config->project->checkList->scrum = array('bug', 'execution', 'build', 'doc', 'release', 'testtask', 'case');
|
||||
$config->project->checkList->waterfall = array('execution', 'design', 'doc', 'bug', 'case', 'build', 'release', 'testtask');
|
||||
$config->project->maxCheckList = new stdclass();
|
||||
$config->project->maxCheckList->scrum = array('bug', 'execution', 'build', 'doc', 'release', 'testtask', 'case', 'issue', 'risk');
|
||||
$config->project->maxCheckList->waterfall = array('execution', 'design', 'doc', 'bug', 'case', 'build', 'release', 'testtask', 'review', 'build', 'researchplan', 'issue', 'risk', 'opportunity', 'auditplan', 'gapanalysis', 'meeting');
|
||||
|
||||
$config->project->removePriv['project'] = array('index', 'browse', 'kanban', 'create', 'batchEdit', 'qa', 'updateOrder', 'createGuide', 'programTitle', 'export');
|
||||
$config->project->removePriv['bug'] = array('browse', 'batchChangePlan', 'batchCreate', 'batchEdit', 'batchConfirm', 'batchResolve', 'batchClose', 'batchActivate', 'report', 'batchChangeModule', 'batchChangeBranch');
|
||||
$config->project->removePriv['testcase'] = array('browse', 'batchChangeModule', 'batchChangeBranch');
|
||||
$config->project->removePriv['testtask'] = array('browse', 'view', 'start', 'activate', 'block', 'close');
|
||||
$config->project->removePriv['doc'] = array('catalog', 'index');
|
||||
$config->project->removePriv['repo'] = array('edit', 'delete', 'maintain', 'setRules');
|
||||
$config->project->removePriv['testreport'] = array('browse');
|
||||
$config->project->removePriv['auditplan'] = array('delete');
|
||||
if(!isset($config->maxVersion)) $config->project->removePriv['stakeholder'] = array('issue', 'viewIssue', 'userIssue');
|
||||
@@ -808,7 +808,7 @@ class project extends control
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$orderBy = $direction == 'next' ? 'date_desc' : 'date_asc';
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Set the pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
@@ -925,7 +925,7 @@ class project extends control
|
||||
/* Load pager and get bugs, user. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
$bugs = $this->bug->getProjectBugs($projectID, $productID, $build, $type, $param, $sort, '', $pager);
|
||||
$users = $this->user->getPairs('noletter');
|
||||
|
||||
@@ -1321,6 +1321,7 @@ class project extends control
|
||||
$users = $this->user->getPairs('noclosed|nodeleted|devfirst|nofeedback');
|
||||
$roles = $this->user->getUserRoles(array_keys($users));
|
||||
$deptUsers = $dept === '' ? array() : $this->dept->getDeptUserPairs($dept);
|
||||
$userInfos = $this->user->getUserDisplayInfos(array_keys($users), $dept);
|
||||
|
||||
$currentMembers = $this->project->getTeamMembers($projectID);
|
||||
$members2Import = $this->project->getMembers2Import($copyProjectID, array_keys($currentMembers));
|
||||
@@ -1331,6 +1332,7 @@ class project extends control
|
||||
$this->view->project = $project;
|
||||
$this->view->users = $users;
|
||||
$this->view->deptUsers = $deptUsers;
|
||||
$this->view->userInfos = $userInfos;
|
||||
$this->view->roles = $roles;
|
||||
$this->view->dept = $dept;
|
||||
$this->view->depts = array('' => '') + $this->dept->getOptionMenu();
|
||||
|
||||
@@ -36,7 +36,7 @@ function saveMembers()
|
||||
$('#submit').removeClass('hidden');
|
||||
if(result) $('#removeExecution').val('yes');
|
||||
$('#submit').click();
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,9 +50,7 @@ function saveMembers()
|
||||
*/
|
||||
function setRole(account, roleID)
|
||||
{
|
||||
role = roles[account]; // get role according the account.
|
||||
roleOBJ = $(document.getElementById('roles[' + roleID + ']')); // get role object.
|
||||
roleOBJ.val(role) // set the role.
|
||||
$('#roles\\[' + roleID + '\\]').val(roles[account]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,11 +63,11 @@ function setRole(account, roleID)
|
||||
function addItem(obj)
|
||||
{
|
||||
var item = $('#addItem').html().replace(/%i%/g, i);
|
||||
$(obj).closest('tr').after('<tr class="addedItem">' + item + '</tr>');
|
||||
var accounts = $(obj).closest('tr').next('tr').find('select:first');
|
||||
accounts.trigger('liszt:updated');
|
||||
accounts.chosen();
|
||||
i ++;
|
||||
var $tr = $('<tr class="addedItem">' + item + '</tr>').insertAfter($(obj).closest('tr'));
|
||||
$tr.find('select:first')
|
||||
.trigger('liszt:updated')
|
||||
.picker({type: 'user'});
|
||||
i++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -772,7 +772,7 @@ class projectModel extends model
|
||||
->add('type', 'project')
|
||||
->join('whitelist', ',')
|
||||
->stripTags($this->config->project->editor->create['id'], $this->config->allowedTags)
|
||||
->remove('products,branch,plans,delta,newProduct,productName,future')
|
||||
->remove('products,branch,plans,delta,newProduct,productName,future,contactListMenu')
|
||||
->get();
|
||||
|
||||
$linkedProductsCount = 0;
|
||||
@@ -874,9 +874,24 @@ class projectModel extends model
|
||||
|
||||
/* Create doc lib. */
|
||||
$this->app->loadLang('doc');
|
||||
$authorizedUsers = array();
|
||||
|
||||
$authorizedUsers = $project->whitelist . ',' . $project->PM . ',' . $project->openedBy . ',';
|
||||
$authorizedUsers = array_unique(explode(',', trim($authorizedUsers, ',')));
|
||||
if($project->parent and $project->acl == 'program')
|
||||
{
|
||||
$stakeHolders = $this->loadModel('stakeholder')->getStakeHolderPairs($project->parent);
|
||||
foreach($stakeHolders as $stakeHolder) $authorizedUsers[$stakeHolder] = $stakeHolder;
|
||||
|
||||
foreach(explode(',', $project->whitelist) as $white)
|
||||
{
|
||||
if(empty($white)) continue;
|
||||
$authorizedUsers[$white] = $white;
|
||||
}
|
||||
|
||||
$authorizedUsers[$project->PM] = $project->PM;
|
||||
$authorizedUsers[$project->openedBy] = $project->openedBy;
|
||||
$authorizedUsers[$program->PM] = $program->PM;
|
||||
$authorizedUsers[$program->openedBy] = $program->openedBy;
|
||||
}
|
||||
|
||||
$lib = new stdclass();
|
||||
$lib->project = $projectID;
|
||||
@@ -884,7 +899,7 @@ class projectModel extends model
|
||||
$lib->type = 'project';
|
||||
$lib->main = '1';
|
||||
$lib->acl = $project->acl != 'program' ? $project->acl : 'custom';
|
||||
if($project->acl == 'private') $lib->users = ',' . implode(',', $authorizedUsers) . ',';
|
||||
$lib->users = ',' . implode(',', array_filter($authorizedUsers)) . ',';
|
||||
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
|
||||
|
||||
$this->updateProducts($projectID);
|
||||
@@ -985,7 +1000,7 @@ class projectModel extends model
|
||||
->setIF($this->post->budget != 0, 'budget', round($this->post->budget, 2))
|
||||
->join('whitelist', ',')
|
||||
->stripTags($this->config->project->editor->edit['id'], $this->config->allowedTags)
|
||||
->remove('products,branch,plans,delta,future')
|
||||
->remove('products,branch,plans,delta,future,contactListMenu')
|
||||
->get();
|
||||
|
||||
if($project->parent)
|
||||
@@ -2079,8 +2094,8 @@ class projectModel extends model
|
||||
$this->lang->switcherMenu = $this->getSwitcher($objectID, $this->app->rawModule, $this->app->rawMethod);
|
||||
|
||||
/* Reset project priv. */
|
||||
$moduleName = $this->app->getModuleName();
|
||||
$methodName = $this->app->getMethodName();
|
||||
$moduleName = $this->app->rawModule;
|
||||
$methodName = $this->app->rawMethod;
|
||||
|
||||
$this->loadModel('common')->resetProjectPriv($objectID);
|
||||
if(!$this->common->isOpenMethod($moduleName, $methodName) and !commonModel::hasPriv($moduleName, $methodName)) $this->common->deny($moduleName, $methodName, false);
|
||||
|
||||
@@ -159,9 +159,12 @@
|
||||
</tr>
|
||||
<tr class="hidden" id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $users, '', 'class="form-control chosen" multiple');?></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td colspan='2'>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('whitelist[]', $users, '', 'class="form-control chosen" multiple');?>
|
||||
<?php echo $this->fetch('my', 'buildContactLists', "dropdownName='whitelist'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->auth;?></th>
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
<script>
|
||||
$('.createButton').on('click', function()
|
||||
{
|
||||
$('#guideDialog').modal('hide');
|
||||
window.location.reload();
|
||||
$.closeModal();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -176,9 +176,12 @@
|
||||
</tr>
|
||||
<tr class="<?php if($project->acl == 'open') echo 'hidden';?>" id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $users, $project->whitelist, 'class="form-control chosen" multiple');?></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('whitelist[]', $users, $project->whitelist, 'class="form-control chosen" multiple');?>
|
||||
<?php echo $this->fetch('my', 'buildContactLists', "dropdownName='whitelist'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->auth;?></th>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<?php js::set('projectID', $project->id);?>
|
||||
<?php js::set('roles', $roles);?>
|
||||
<?php js::set('deptID', $dept);?>
|
||||
<?php js::set('pickerUsers', $userInfos);?>
|
||||
<?php js::set('copyProjectID', $copyProjectID);?>
|
||||
<?php js::set('oldAccountList', array_keys($currentMembers));?>
|
||||
<?php js::set('unlinkExecutionMembers', $lang->project->unlinkExecutionMembers);?>
|
||||
@@ -75,7 +76,7 @@
|
||||
<?php foreach($members2Import as $member2Import):?>
|
||||
<?php if(!isset($users[$member2Import->account])) continue;?>
|
||||
<tr class='addedItem'>
|
||||
<td><?php echo html::select("accounts[$i]", $users, $member2Import->account, "class='form-control chosen' onchange='setRole(this.value, $i)'");?></td>
|
||||
<td><?php echo html::select("accounts[$i]", $users, $member2Import->account, "class='form-control user-picker' onchange='setRole(this.value, $i)'");?></td>
|
||||
<td><?php echo html::input("roles[$i]", $member2Import->role, "class='form-control'");?></td>
|
||||
<td><?php echo html::input("days[$i]", $project->days, "class='form-control'");?></td>
|
||||
<td><?php echo html::input("hours[$i]", $member2Import->hours, "class='form-control'");?></td>
|
||||
@@ -91,7 +92,7 @@
|
||||
|
||||
<?php for($j = 0; $j < 5; $j ++):?>
|
||||
<tr class='addedItem'>
|
||||
<td><?php echo html::select("accounts[$i]", $users, '', "class='form-control chosen' onchange='setRole(this.value, $i)'");?></td>
|
||||
<td><?php echo html::select("accounts[$i]", $users, '', "class='form-control user-picker' onchange='setRole(this.value, $i)'");?></td>
|
||||
<td><?php echo html::input("roles[$i]", '', "class='form-control'");?></td>
|
||||
<td><?php echo html::input("days[$i]", $project->days, "class='form-control'");?></td>
|
||||
<td><?php echo html::input("hours[$i]", $config->execution->defaultWorkhours, "class='form-control'");?></td>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<?php js::set('confirmDelete', $lang->stakeholder->confirmDelete);?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<div class="btn-toolbar pull-left">
|
||||
<?php echo html::a($this->createLink('stakeholder', 'browse', 'browseType=all'), '<span class="text">' . $lang->stakeholder->browse . '</span>', '', 'class="btn btn-link btn-active-text"');?>
|
||||
<?php echo html::a($this->createLink('stakeholder', 'browse', "projectID=$projectID"), '<span class="text">' . $lang->stakeholder->browse . '</span>', '', 'class="btn btn-link btn-active-text"');?>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-right">
|
||||
<?php if(common::hasPriv('stakeholder', 'batchcreate') and common::hasPriv('stakeholder', 'create')):?>
|
||||
|
||||
@@ -1766,7 +1766,7 @@ class story extends control
|
||||
}
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$this->view->title = $this->lang->story->zeroCase;
|
||||
$this->view->position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $products[$productID]);
|
||||
|
||||
@@ -2473,8 +2473,9 @@ class storyModel extends model
|
||||
*/
|
||||
public function getBySearch($productID, $branch = '', $queryID = 0, $orderBy = '', $executionID = '', $type = 'story', $excludeStories = '', $pager = null)
|
||||
{
|
||||
$this->loadModel('product');
|
||||
$executionID = empty($executionID) ? 0 : $executionID;
|
||||
$products = $this->loadModel('product')->getProducts($executionID);
|
||||
$products = empty($executionID) ? $this->product->getList() : $this->product->getProducts($executionID);
|
||||
|
||||
$query = $queryID ? $this->loadModel('search')->getQuery($queryID) : '';
|
||||
|
||||
@@ -2734,7 +2735,7 @@ class storyModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getExecutionStoryPairs($executionID = 0, $productID = 0, $branch = 0, $moduleIdList = 0, $type = 'full', $status = 'all')
|
||||
public function getExecutionStoryPairs($executionID = 0, $productID = 0, $branch = 'all', $moduleIdList = 0, $type = 'full', $status = 'all')
|
||||
{
|
||||
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getExecutionStoryPairs();
|
||||
$stories = $this->dao->select('t2.id, t2.title, t2.module, t2.pri, t2.estimate, t3.name AS product')
|
||||
@@ -4469,7 +4470,7 @@ class storyModel extends model
|
||||
public function sortStoriesOfPlan($planID, $sortIDList, $orderBy = 'id_desc', $pageID = 1, $recPerPage = 100)
|
||||
{
|
||||
/* Append id for secend sort. */
|
||||
$orderBy = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$orderBy = common::appendOrder($orderBy);
|
||||
|
||||
/* Get all stories by plan. */
|
||||
$stories = $this->getPlanStories($planID, 'all', $orderBy);
|
||||
|
||||
@@ -481,8 +481,9 @@
|
||||
{
|
||||
if(!isset($executions[$task->execution])) continue;
|
||||
$executionName = $executions[$task->execution];
|
||||
$taskInfo = $task->id . ' <span class="label label-success label-outline">' . $this->lang->task->statusList[$task->status] . '</span> ' . $task->name;
|
||||
$class = isonlybody() ? 'showinonlybody' : 'iframe';
|
||||
echo "<li title='$task->name'>" . html::a($this->createLink('task', 'view', "taskID=$task->id", '', true), "[T]$task->id $task->name", '', "class=$class data-width='80%'");
|
||||
echo "<li title='$task->name'>" . html::a($this->createLink('task', 'view', "taskID=$task->id", '', true), $taskInfo, '', "class=$class data-width='80%'");
|
||||
echo html::a($this->createLink('execution', 'browse', "executionID=$task->execution"), $executionName, '', "class='text-muted'") . '</li>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1481,7 +1481,7 @@ class task extends control
|
||||
$taskLang = $this->lang->task;
|
||||
|
||||
/* Create field lists. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
$fields = $this->post->exportFields ? $this->post->exportFields : explode(',', $allExportFields);
|
||||
foreach($fields as $key => $fieldName)
|
||||
{
|
||||
|
||||
@@ -137,7 +137,7 @@ class testcase extends control
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Get test cases. */
|
||||
$cases = $this->testcase->getTestCases($productID, $branch, $browseType, $browseType == 'bysearch' ? $queryID : $suiteID, $moduleID, $sort, $pager);
|
||||
@@ -480,7 +480,7 @@ class testcase extends control
|
||||
$this->view->executionID = $executionID;
|
||||
$this->view->productInfo = $productInfo;
|
||||
$this->view->productName = $this->products[$productID];
|
||||
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0, $branch === 'all' ? 0 : $branch);
|
||||
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0, ($branch === 'all' or !isset($branches[$branch])) ? 0 : $branch);
|
||||
$this->view->currentModuleID = $currentModuleID;
|
||||
$this->view->gobackLink = (isset($output['from']) and $output['from'] == 'global') ? $this->createLink('testcase', 'browse', "productID=$productID") : '';
|
||||
$this->view->stories = $stories;
|
||||
|
||||
@@ -70,25 +70,27 @@ $lang->testreport->bugStageList['generated'] = 'Generated Bugs';
|
||||
$lang->testreport->bugStageList['legacy'] = 'Legacy Bugs';
|
||||
$lang->testreport->bugStageList['resolved'] = 'Resolved Bugs';
|
||||
|
||||
$lang->testreport->caseSummary = 'Total <strong>%s</strong> cases. <strong>%s</strong> cases run. <strong>%s</strong> results generated. <strong>%s</strong> cases failed.';
|
||||
$lang->testreport->buildSummary = 'Tested <strong>%s</strong> builds.';
|
||||
$lang->testreport->confirmDelete = 'Do you want to delete this report?';
|
||||
$lang->testreport->moreNotice = 'More features can be extended with reference to the ZenTao extension manual, or you can contact us at renee@easysoft.ltd for customization.';
|
||||
$lang->testreport->exportNotice = "Exported By <a href='https://www.zentao.net' target='_blank' style='color:grey'>ZenTao</a>";
|
||||
$lang->testreport->noReport = "No report has been generated. Please check it later.";
|
||||
$lang->testreport->foundBugTip = "Bugs found in this build period and the affected build is in this test period.";
|
||||
$lang->testreport->legacyBugTip = "Active bugs, or bugs that are not resolved in the test period.";
|
||||
$lang->testreport->fromCaseBugTip = "Bugs found from the running of cases in the test period.";
|
||||
$lang->testreport->errorTrunk = "You cannot create a Testing report for the trunk. Please modify the linked build!";
|
||||
$lang->testreport->noTestTask = "No test requests for this {$lang->productCommon}, so no reports can be generated. Please go to {$lang->productCommon} which has test requests and then generate the report.";
|
||||
$lang->testreport->noObjectID = "No test request or {$lang->executionCommon} is selected, so no report can be generated.";
|
||||
$lang->testreport->moreProduct = "Testing reports can only be generated for the same {$lang->productCommon}.";
|
||||
$lang->testreport->hiddenCase = "Hide %s use cases";
|
||||
$lang->testreport->goalTip = "Descriptive information about the {$lang->execution->common} of this build";
|
||||
$lang->testreport->caseSummary = 'Total <strong>%s</strong> cases. <strong>%s</strong> cases run. <strong>%s</strong> results generated. <strong>%s</strong> cases failed.';
|
||||
$lang->testreport->buildSummary = 'Tested <strong>%s</strong> builds.';
|
||||
$lang->testreport->confirmDelete = 'Do you want to delete this report?';
|
||||
$lang->testreport->moreNotice = 'More features can be extended with reference to the ZenTao extension manual, or you can contact us at renee@easysoft.ltd for customization.';
|
||||
$lang->testreport->exportNotice = "Exported By <a href='https://www.zentao.net' target='_blank' style='color:grey'>ZenTao</a>";
|
||||
$lang->testreport->noReport = "No report has been generated. Please check it later.";
|
||||
$lang->testreport->foundBugTip = "Bugs found in this build period and the affected build is in this test period.";
|
||||
$lang->testreport->legacyBugTip = "Active bugs, or bugs that are not resolved in the test period.";
|
||||
$lang->testreport->activatedBugTip = "Reactive bugs in the test period.";
|
||||
$lang->testreport->fromCaseBugTip = "Bugs found from the running of cases in the test period.";
|
||||
$lang->testreport->errorTrunk = "You cannot create a Testing report for the trunk. Please modify the linked build!";
|
||||
$lang->testreport->noTestTask = "No test requests for this {$lang->productCommon}, so no reports can be generated. Please go to {$lang->productCommon} which has test requests and then generate the report.";
|
||||
$lang->testreport->noObjectID = "No test request or {$lang->executionCommon} is selected, so no report can be generated.";
|
||||
$lang->testreport->moreProduct = "Testing reports can only be generated for the same {$lang->productCommon}.";
|
||||
$lang->testreport->hiddenCase = "Hide %s use cases";
|
||||
$lang->testreport->goalTip = "Descriptive information about the {$lang->execution->common} of this build";
|
||||
|
||||
$lang->testreport->bugSummary = <<<EOD
|
||||
Total <strong>%s</strong> Bugs reported <a data-toggle='tooltip' class='text-warning' title='{$lang->testreport->foundBugTip}'><i class='icon-help'></i></a>,
|
||||
<strong>%s</strong> Bugs remained unresolved <a data-toggle='tooltip' class='text-warning' title='{$lang->testreport->legacyBugTip}'><i class='icon-help'></i></a>,
|
||||
<strong>%s</strong> Bugs reactivated <a data-toggle='tooltip' class='text-warning' title='{$lang->testreport->activatedBugTip}'><i class='icon-help'></i></a>,
|
||||
<strong>%s</strong> Bugs found from the running of cases<a data-toggle='tooltip' class='text-warning' title='{$lang->testreport->fromCaseBugTip}'><i class='icon-help'></i></a>.
|
||||
Bug Effective Rate <a data-toggle='tooltip' class='text-warning' title='Resolution is resolved or delayed / status is resolved or closed'><i class='icon-help'></i></a>: <strong>%s</strong>,Bugs-reported-from-cases rate<a data-toggle='tooltip' class='text-warning' title='Bugs created from cases / bugs'><i class='icon-help'></i></a>: <strong>%s</strong>
|
||||
EOD;
|
||||
|
||||
@@ -70,25 +70,27 @@ $lang->testreport->bugStageList['generated'] = '产生的Bug';
|
||||
$lang->testreport->bugStageList['legacy'] = '遗留的Bug';
|
||||
$lang->testreport->bugStageList['resolved'] = '解决的Bug';
|
||||
|
||||
$lang->testreport->caseSummary = '共有<strong>%s</strong>个用例,共执行<strong>%s</strong>个用例,产生了<strong>%s</strong>个结果,失败的用例有<strong>%s</strong>个。';
|
||||
$lang->testreport->buildSummary = '共测试了<strong>%s</strong>个版本。';
|
||||
$lang->testreport->confirmDelete = '是否删除该报告?';
|
||||
$lang->testreport->moreNotice = '更多功能可以参考禅道扩展机制进行扩展,也可以联系我们进行定制。';
|
||||
$lang->testreport->exportNotice = "由<a href='https://www.zentao.net' target='_blank' style='color:grey'>禅道项目管理软件</a>导出";
|
||||
$lang->testreport->noReport = "暂无报告,请选择测试单生成测试报告。";
|
||||
$lang->testreport->foundBugTip = "影响版本在测试轮次内,并且创建时间在测试时间范围内产生的Bug数。";
|
||||
$lang->testreport->legacyBugTip = "Bug状态是激活,或Bug的解决时间在测试结束时间之后。";
|
||||
$lang->testreport->fromCaseBugTip = "测试时间范围内,用例执行失败后创建的Bug。";
|
||||
$lang->testreport->errorTrunk = "主干版本不能创建测试报告,请修改关联版本!";
|
||||
$lang->testreport->noTestTask = "该{$lang->productCommon}下还没有关联非Trunk的测试单,不能创建报告。请先创建测试单,再创建。";
|
||||
$lang->testreport->noObjectID = "没有选定测试单或{$lang->executionCommon},无法创建测试报告!";
|
||||
$lang->testreport->moreProduct = "只能对同一个{$lang->productCommon}生成测试报告。";
|
||||
$lang->testreport->hiddenCase = "隐藏 %s 个用例";
|
||||
$lang->testreport->goalTip = "该版本所属{$lang->execution->common}的描述信息";
|
||||
$lang->testreport->caseSummary = '共有<strong>%s</strong>个用例,共执行<strong>%s</strong>个用例,产生了<strong>%s</strong>个结果,失败的用例有<strong>%s</strong>个。';
|
||||
$lang->testreport->buildSummary = '共测试了<strong>%s</strong>个版本。';
|
||||
$lang->testreport->confirmDelete = '是否删除该报告?';
|
||||
$lang->testreport->moreNotice = '更多功能可以参考禅道扩展机制进行扩展,也可以联系我们进行定制。';
|
||||
$lang->testreport->exportNotice = "由<a href='https://www.zentao.net' target='_blank' style='color:grey'>禅道项目管理软件</a>导出";
|
||||
$lang->testreport->noReport = "暂无报告,请选择测试单生成测试报告。";
|
||||
$lang->testreport->foundBugTip = "影响版本在测试轮次内,并且创建时间在测试时间范围内产生的Bug数。";
|
||||
$lang->testreport->legacyBugTip = "Bug状态是激活,或Bug的解决时间在测试结束时间之后。";
|
||||
$lang->testreport->activatedBugTip = "在测试单时间范围内被激活的Bug数量。";
|
||||
$lang->testreport->fromCaseBugTip = "测试时间范围内,用例执行失败后创建的Bug。";
|
||||
$lang->testreport->errorTrunk = "主干版本不能创建测试报告,请修改关联版本!";
|
||||
$lang->testreport->noTestTask = "该{$lang->productCommon}下还没有关联非Trunk的测试单,不能创建报告。请先创建测试单,再创建。";
|
||||
$lang->testreport->noObjectID = "没有选定测试单或{$lang->executionCommon},无法创建测试报告!";
|
||||
$lang->testreport->moreProduct = "只能对同一个{$lang->productCommon}生成测试报告。";
|
||||
$lang->testreport->hiddenCase = "隐藏 %s 个用例";
|
||||
$lang->testreport->goalTip = "该版本所属{$lang->execution->common}的描述信息";
|
||||
|
||||
$lang->testreport->bugSummary = <<<EOD
|
||||
共发现<strong>%s</strong>个Bug <a data-toggle='tooltip' class='text-warning' title='{$lang->testreport->foundBugTip}'><i class='icon-help'></i></a>,
|
||||
遗留<strong>%s</strong>个Bug <a data-toggle='tooltip' class='text-warning' title='{$lang->testreport->legacyBugTip}'><i class='icon-help'></i></a>。
|
||||
重新激活<strong>%s</strong>个Bug <a data-toggle='tooltip' class='text-warning' title='{$lang->testreport->activatedBugTip}'><i class='icon-help'></i></a>。
|
||||
用例执行产生<strong>%s</strong>个Bug <a data-toggle='tooltip' class='text-warning' title='{$lang->testreport->fromCaseBugTip}'><i class='icon-help'></i></a>。
|
||||
有效Bug率(方案为已解决或延期 / 状态为已解决或已关闭):<strong>%s</strong>,用例发现Bug率(用例创建的Bug / 发现Bug数):<strong>%s</strong>
|
||||
EOD;
|
||||
|
||||
@@ -141,6 +141,7 @@ class testreportModel extends model
|
||||
$resolvedBugs = $this->dao->select('*')->from(TABLE_BUG)->where('product')->in($productIdList)->andWhere('resolvedDate')->ge($begin)->andWhere('resolvedDate')->le("$end 23:59:59")->andWhere('deleted')->eq(0)->fetchAll();
|
||||
$foundBugs = array();
|
||||
$legacyBugs = array();
|
||||
$activatedBugs = array();
|
||||
$byCaseNum = 0;
|
||||
$buildIdList = array_keys($builds);
|
||||
$taskIdList = array_keys($tasks);
|
||||
@@ -168,6 +169,48 @@ class testreportModel extends model
|
||||
$handleGroups['resolved'][$date] = 0;
|
||||
}
|
||||
|
||||
$buildBugs = array();
|
||||
$allBugs = $this->dao->select('*')->from(TABLE_BUG)->where('product')->in($productIdList)->andWhere('deleted')->eq(0)->fetchAll('id');
|
||||
|
||||
foreach($allBugs as $bug)
|
||||
{
|
||||
if(!empty(array_intersect(explode(',', $bug->openedBuild), $buildIdList))) $buildBugs[$bug->id] = $bug;
|
||||
}
|
||||
|
||||
/* Get bug reactivated actions during the testreport. */
|
||||
$actions = $this->dao->select('*')->from(TABLE_ACTION)
|
||||
->where('objectType')->eq('bug')
|
||||
->andWhere('action')->eq('activated')
|
||||
->andWhere('date')->ge($begin)
|
||||
->andWhere('date')->le($end . ' 23:59:59')
|
||||
->andWhere('objectID')->in(array_keys($buildBugs))
|
||||
->fetchGroup('objectID', 'id');
|
||||
|
||||
$actionIdList = array();
|
||||
foreach($actions as $bugID => $action) $actionIdList = array_merge($actionIdList, array_keys($action));
|
||||
|
||||
$histories = $this->loadModel('action')->getHistory($actionIdList);
|
||||
foreach($actions as $bugID => $actionList)
|
||||
{
|
||||
foreach($actionList as $actionID => $action)
|
||||
{
|
||||
$action->history = zget($histories, $actionID, array());
|
||||
}
|
||||
}
|
||||
|
||||
foreach($buildBugs as $bug)
|
||||
{
|
||||
$bugActions = zget($actions, $bug->id, array());
|
||||
foreach($bugActions as $action)
|
||||
{
|
||||
foreach($action->history as $history)
|
||||
{
|
||||
if($history->field == 'openedBuild' and !in_array($history->new, $buildIdList)) continue;
|
||||
$activatedBugs[$bug->id] = $bug;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the resolved bug data. */
|
||||
foreach($resolvedBugs as $bug)
|
||||
{
|
||||
@@ -216,6 +259,7 @@ class testreportModel extends model
|
||||
}
|
||||
|
||||
$resolvedBugs = 0;
|
||||
$this->loadModel('action');
|
||||
foreach($foundBugs as $bug)
|
||||
{
|
||||
$severityGroups[$bug->severity] = isset($severityGroups[$bug->severity]) ? $severityGroups[$bug->severity] + 1 : 1;
|
||||
@@ -231,6 +275,7 @@ class testreportModel extends model
|
||||
|
||||
$bugInfo['foundBugs'] = count($foundBugs);
|
||||
$bugInfo['legacyBugs'] = $legacyBugs;
|
||||
$bugInfo['activatedBugs'] = $activatedBugs;
|
||||
$bugInfo['countBugByTask'] = $byCaseNum;
|
||||
$bugInfo['bugConfirmedRate'] = empty($resolvedBugs) ? 0 : round((zget($resolutionGroups, 'fixed', 0) + zget($resolutionGroups, 'postponed', 0)) / $resolvedBugs * 100, 2);
|
||||
$bugInfo['bugCreateByCaseRate'] = empty($byCaseNum) ? 0 : round($byCaseNum / count($foundBugs) * 100, 2);
|
||||
|
||||
@@ -83,8 +83,8 @@
|
||||
<?php
|
||||
echo '<div>' . $storySummary . '</div>';
|
||||
echo '<div>' . sprintf($lang->testreport->buildSummary, empty($builds) ? 1 : count($builds)) . $caseSummary . '</div>';
|
||||
echo '<div>' . sprintf($lang->testreport->bugSummary, $bugInfo['foundBugs'], count($legacyBugs), $bugInfo['countBugByTask'], $bugInfo['bugConfirmedRate'] . '%', $bugInfo['bugCreateByCaseRate'] . '%') . '</div>';
|
||||
unset($bugInfo['countBugByTask']); unset($bugInfo['bugConfirmedRate']); unset($bugInfo['bugCreateByCaseRate']); unset($bugInfo['foundBugs']);
|
||||
echo '<div>' . sprintf($lang->testreport->bugSummary, $bugInfo['foundBugs'], count($legacyBugs), count($bugInfo['activatedBugs']), $bugInfo['countBugByTask'], $bugInfo['bugConfirmedRate'] . '%', $bugInfo['bugCreateByCaseRate'] . '%') . '</div>';
|
||||
unset($bugInfo['countBugByTask']); unset($bugInfo['bugConfirmedRate']); unset($bugInfo['bugCreateByCaseRate']); unset($bugInfo['foundBugs']); unset($bugInfo['activatedBugs']);
|
||||
?>
|
||||
</td>
|
||||
<td></td>
|
||||
|
||||
@@ -71,8 +71,8 @@
|
||||
<?php
|
||||
echo '<p>' . $storySummary . '</p>';
|
||||
echo '<p>' . sprintf($lang->testreport->buildSummary, empty($builds) ? 1 : count($builds)) . $caseSummary . '</p>';
|
||||
echo '<p>' . sprintf($lang->testreport->bugSummary, $bugInfo['foundBugs'], count($legacyBugs), $bugInfo['countBugByTask'], $bugInfo['bugConfirmedRate'] . '%', $bugInfo['bugCreateByCaseRate'] . '%') . '</p>';
|
||||
unset($bugInfo['countBugByTask']); unset($bugInfo['bugConfirmedRate']); unset($bugInfo['bugCreateByCaseRate']); unset($bugInfo['foundBugs']);
|
||||
echo '<p>' . sprintf($lang->testreport->bugSummary, $bugInfo['foundBugs'], count($legacyBugs), count($bugInfo['activatedBugs']), $bugInfo['countBugByTask'], $bugInfo['bugConfirmedRate'] . '%', $bugInfo['bugCreateByCaseRate'] . '%') . '</p>';
|
||||
unset($bugInfo['countBugByTask']); unset($bugInfo['bugConfirmedRate']); unset($bugInfo['bugCreateByCaseRate']); unset($bugInfo['foundBugs']); unset($bugInfo['activatedBugs']);
|
||||
?>
|
||||
</td>
|
||||
<td></td>
|
||||
|
||||
@@ -78,8 +78,8 @@
|
||||
<?php
|
||||
echo '<p>' . $storySummary . '</p>';
|
||||
echo '<p>' . sprintf($lang->testreport->buildSummary, empty($builds) ? 1 : count($builds)) . $caseSummary . '</p>';
|
||||
echo '<p>' . sprintf($lang->testreport->bugSummary, $bugInfo['foundBugs'], count($legacyBugs), $bugInfo['countBugByTask'], $bugInfo['bugConfirmedRate'] . '%', $bugInfo['bugCreateByCaseRate'] . '%') . '</p>';
|
||||
unset($bugInfo['countBugByTask']); unset($bugInfo['bugConfirmedRate']); unset($bugInfo['bugCreateByCaseRate']); unset($bugInfo['foundBugs']);
|
||||
echo '<p>' . sprintf($lang->testreport->bugSummary, $bugInfo['foundBugs'], count($legacyBugs), count($bugInfo['activatedBugs']), $bugInfo['countBugByTask'], $bugInfo['bugConfirmedRate'] . '%', $bugInfo['bugCreateByCaseRate'] . '%') . '</p>';
|
||||
unset($bugInfo['countBugByTask']); unset($bugInfo['bugConfirmedRate']); unset($bugInfo['bugCreateByCaseRate']); unset($bugInfo['foundBugs']); unset($bugInfo['activatedBugs']);
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -71,7 +71,7 @@ class testsuite extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$suites = $this->testsuite->getSuites($productID, $sort, $pager);
|
||||
if(empty($suites) and $pageID > 1)
|
||||
@@ -169,7 +169,7 @@ class testsuite extends control
|
||||
$this->session->set('caseList', $this->app->getURI(true), 'qa');
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
|
||||
@@ -106,7 +106,7 @@ class testtask extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Get tasks. */
|
||||
$tasks = $this->testtask->getProductTasks($productID, $branch, $sort, $pager, $scopeAndStatus, $beginTime, $endTime);
|
||||
@@ -178,7 +178,7 @@ class testtask extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->common;
|
||||
$this->view->position[] = html::a($this->createLink('testtask', 'browseUnits', "productID=$productID"), $this->products[$productID]);
|
||||
@@ -503,7 +503,7 @@ class testtask extends control
|
||||
}
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy, 't2.id');
|
||||
$sort = common::appendOrder($orderBy, 't2.id');
|
||||
|
||||
/* Get test cases. */
|
||||
$runs = $this->testtask->getTaskCases($productID, $browseType, $queryID, $moduleID, $sort, $pager, $task);
|
||||
@@ -1314,6 +1314,8 @@ class testtask extends control
|
||||
*/
|
||||
public function results($runID, $caseID = 0, $version = 0)
|
||||
{
|
||||
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($this->session->project);
|
||||
|
||||
if($runID)
|
||||
{
|
||||
$case = $this->testtask->getRunById($runID)->case;
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
<?php endif; endif; $childId++;?>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
<?php if($result->caseResult == 'fail'):?>
|
||||
<?php if($result->caseResult == 'fail' and common::hasPriv('testcase', 'createBug')):?>
|
||||
<tr>
|
||||
<td></td><td></td><td></td><td></td><td></td><td></td>
|
||||
<td><?php echo html::commonButton($lang->testcase->createBug, "onclick='createBug(this)'", "btn btn-primary createBtn");?></td>
|
||||
|
||||
@@ -243,7 +243,7 @@ class treeModel extends model
|
||||
{
|
||||
/* If createdVersion <= 4.1, go to getOptionMenu(). */
|
||||
$products = $this->loadModel('product')->getProductPairsByProject($rootID);
|
||||
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products));
|
||||
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products), 'noclosed');
|
||||
|
||||
if(!$this->isMergeModule($rootID, 'task') or !$products) return $this->getOptionMenu($rootID, 'task', $startModule);
|
||||
|
||||
@@ -277,10 +277,12 @@ class treeModel extends model
|
||||
{
|
||||
foreach($rootModules as $id => $rootModule)
|
||||
{
|
||||
$activeBranch = isset($branchGroups[$id]) ? array_keys($branchGroups[$id]) : array();
|
||||
if($type == 'product')
|
||||
{
|
||||
$modules = $this->dao->select('*')->from(TABLE_MODULE)->where("((root = '" . (int)$rootID . "' and type = 'task' and parent != 0) OR (root = $id and type = 'story'))")
|
||||
->beginIF($startModulePath)->andWhere('path')->like($startModulePath)->fi()
|
||||
->beginIF(!empty($activeBranch))->andWhere('branch')->in($activeBranch)->fi()
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy('grade desc, branch, `order`, type')
|
||||
->fetchAll('id');
|
||||
|
||||
@@ -395,7 +395,7 @@ class upgrade extends control
|
||||
$data->project = $_POST['projectType'] == 'execution' ? $projectList : $projectList[$projectProduct->project];
|
||||
$data->product = $projectProduct->product;
|
||||
$data->plan = $projectProduct->plan;
|
||||
$data->branch = $projectProduct->branch;
|
||||
$data->branch = $projectProduct->branch;
|
||||
|
||||
$this->dao->replace(TABLE_PROJECTPRODUCT)->data($data)->exec();
|
||||
}
|
||||
@@ -406,7 +406,7 @@ class upgrade extends control
|
||||
|
||||
/* Get no merged product and project count. */
|
||||
$noMergedProductCount = $this->dao->select('count(*) as count')->from(TABLE_PRODUCT)->where('program')->eq(0)->fetch('count');
|
||||
$noMergedSprintCount = $this->dao->select('count(*) as count')->from(TABLE_PROJECT)->where('grade')->eq(0)->andWhere('path')->eq('')->andWhere('type')->ne('program')->fetch('count');
|
||||
$noMergedSprintCount = $this->dao->select('count(*) as count')->from(TABLE_PROJECT)->where('grade')->eq(0)->andWhere('path')->eq('')->andWhere('type')->ne('program')->andWhere('deleted')->eq(0)->fetch('count');
|
||||
|
||||
/* When all products and projects merged then finish and locate afterExec page. */
|
||||
if(empty($noMergedProductCount) and empty($noMergedSprintCount))
|
||||
@@ -443,6 +443,7 @@ class upgrade extends control
|
||||
$noMergedSprints = $this->dao->select('t1.*')->from(TABLE_PROJECT)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id=t2.project')
|
||||
->where('t1.project')->eq(0)
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->andWhere('t1.type')->eq('sprint')
|
||||
->andWhere('t2.product')->in(array_keys($noMergedProducts))
|
||||
->orderBy('t1.id_desc')
|
||||
@@ -487,6 +488,7 @@ class upgrade extends control
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')
|
||||
->where('t2.model')->eq('')
|
||||
->andWhere('t2.project')->eq(0)
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->andWhere('t2.type')->eq('sprint')
|
||||
->fetchAll('id');
|
||||
|
||||
@@ -531,7 +533,13 @@ class upgrade extends control
|
||||
/* Get no merged projects than is not linked product. */
|
||||
if($type == 'sprint')
|
||||
{
|
||||
$noMergedSprints = $this->dao->select('*')->from(TABLE_PROJECT)->where('parent')->eq(0)->andWhere('path')->eq('')->orderBy('id_desc')->fetchAll('id');
|
||||
$noMergedSprints = $this->dao->select('*')->from(TABLE_PROJECT)
|
||||
->where('parent')->eq(0)
|
||||
->andWhere('path')->eq('')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy('id_desc')
|
||||
->fetchAll('id');
|
||||
|
||||
$projectProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)->where('project')->in(array_keys($noMergedSprints))->fetchGroup('project', 'product');
|
||||
foreach($projectProducts as $sprintID => $products) unset($noMergedSprints[$sprintID]);
|
||||
|
||||
@@ -543,8 +551,16 @@ class upgrade extends control
|
||||
/* Get no merged projects that link more then two products. */
|
||||
if($type == 'moreLink')
|
||||
{
|
||||
$noMergedSprints = $this->dao->select('*')->from(TABLE_PROJECT)->where('parent')->eq(0)->andWhere('path')->eq('')->orderBy('id_desc')->fetchAll('id');
|
||||
$projectProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)->where('project')->in(array_keys($noMergedSprints))->fetchGroup('project', 'product');
|
||||
$noMergedSprints = $this->dao->select('*')->from(TABLE_PROJECT)
|
||||
->where('parent')->eq(0)
|
||||
->andWhere('path')->eq('')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy('id_desc')
|
||||
->fetchAll('id');
|
||||
|
||||
$projectProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)
|
||||
->where('project')->in(array_keys($noMergedSprints))
|
||||
->fetchGroup('project', 'product');
|
||||
|
||||
$productPairs = array();
|
||||
foreach($projectProducts as $sprintID => $products)
|
||||
@@ -591,7 +607,7 @@ class upgrade extends control
|
||||
* Rename object in upgrade.
|
||||
*
|
||||
* @param string $type project|product|execution
|
||||
* @param string $duplicateList
|
||||
* @param string $duplicateList
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#selectedModeTips {padding-top: 10px}
|
||||
#upgradeTips {padding-bottom: 10px;}
|
||||
@@ -126,6 +126,7 @@ $lang->upgrade->mergeRepoTips = "Merge the selected version library under t
|
||||
$lang->upgrade->needBuild4Add = 'Full text retrieval has been added in this upgrade. Need create index. Please go [Admin->System->BuildIndex] page to build index.';
|
||||
$lang->upgrade->errorEngineInnodb = 'Your MySQL does not support InnoDB data table engine. Please modify it to MyISAM and try again.';
|
||||
$lang->upgrade->duplicateProject = "Project name in the same program cannot be duplicate. Please adjust the duplicate names.";
|
||||
$lang->upgrade->upgradeTips = "Historically deleted data cannot be upgraded, and restoration is not supported after the upgrade. Please be aware.";
|
||||
|
||||
$lang->upgrade->projectType['project'] = "Upgrade the historical {$lang->projectCommon} as a project";
|
||||
$lang->upgrade->projectType['execution'] = "Upgrade the historical {$lang->projectCommon} as an execution";
|
||||
|
||||
@@ -126,6 +126,7 @@ $lang->upgrade->mergeRepoTips = "将选中的版本库归并到所选产品
|
||||
$lang->upgrade->needBuild4Add = '本次升级需要创建索引。请到 [后台->系统->重建索引] 页面,重新创建索引。';
|
||||
$lang->upgrade->errorEngineInnodb = '您当前的数据库不支持使用InnoDB数据表引擎,请修改为MyISAM后重试。';
|
||||
$lang->upgrade->duplicateProject = "同一个项目集内项目名称不能重复,请调整重名的项目名称";
|
||||
$lang->upgrade->upgradeTips = "历史删除数据不参与升级,升级后将不支持还原,请知悉";
|
||||
|
||||
$lang->upgrade->projectType['project'] = "把历史的{$lang->projectCommon}作为项目升级";
|
||||
$lang->upgrade->projectType['execution'] = "把历史的{$lang->projectCommon}作为执行升级";
|
||||
|
||||
@@ -39,12 +39,12 @@
|
||||
<?php echo $lang->upgrade->to15Desc;?>
|
||||
<?php $systemMode = isset($lang->upgrade->to15Mode['classic']) ? 'classic' : 'new';?>
|
||||
<?php echo html::radio('mode', $lang->upgrade->to15Mode, $systemMode);?>
|
||||
<p> </p>
|
||||
<div id='selectedModeTips' class='text-info'><?php echo $lang->upgrade->selectedModeTips[$systemMode];?></div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class='panel-footer text-center'>
|
||||
<div id='upgradeTips' class='text-danger hidden'><?php echo $lang->upgrade->upgradeTips;?></div>
|
||||
<?php echo html::submitButton($lang->upgrade->start . (strpos($this->app->getClientLang(), 'zh') === false ? ' ' : '') . $lang->upgrade->common);?>
|
||||
</div>
|
||||
</form>
|
||||
@@ -57,6 +57,7 @@ $(function()
|
||||
$('[name=mode]').change(function()
|
||||
{
|
||||
$('#selectedModeTips').html(selectedModeTips[$(this).val()]);
|
||||
$(this).val() == 'new' ? $('#upgradeTips').removeClass('hidden') : $('#upgradeTips').addClass('hidden');
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -74,7 +74,7 @@ class user extends control
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
/* Get user, totos. */
|
||||
$account = $user->account;
|
||||
@@ -259,7 +259,7 @@ class user extends control
|
||||
$this->app->loadLang('testcase');
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$this->view->title = $this->lang->user->common . $this->lang->colon . $this->lang->user->testTask;
|
||||
$this->view->position[] = $this->lang->user->testTask;
|
||||
@@ -301,7 +301,7 @@ class user extends control
|
||||
$users = $this->loadModel('dept')->getDeptUserPairs($this->app->user->dept, 'id');
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
|
||||
$cases = array();
|
||||
if($type == 'case2Him')
|
||||
@@ -1097,7 +1097,7 @@ class user extends control
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$orderBy = $direction == 'next' ? 'date_desc' : 'date_asc';
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
$sort = common::appendOrder($orderBy);
|
||||
$date = empty($date) ? '' : date('Y-m-d', $date);
|
||||
|
||||
$actions = $this->loadModel('action')->getDynamic($account, $period, $sort, $pager, 'all', 'all', 'all', $date, $direction);
|
||||
@@ -1165,19 +1165,20 @@ class user extends control
|
||||
* AJAX: get users from a contact list.
|
||||
*
|
||||
* @param int $contactListID
|
||||
* @param string $dropdownName
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function ajaxGetContactUsers($contactListID)
|
||||
public function ajaxGetContactUsers($contactListID, $dropdownName = 'mailto')
|
||||
{
|
||||
$list = $contactListID ? $this->user->getContactListByID($contactListID) : '';
|
||||
|
||||
$users = $this->user->getPairs('devfirst|nodeleted', $list ? $list->userList : '', $this->config->maxCount);
|
||||
if(isset($this->config->user->moreLink)) $this->config->moreLinks['mailto[]'] = $this->config->user->moreLink;
|
||||
if(isset($this->config->user->moreLink)) $this->config->moreLinks[$dropdownName . "[]"] = $this->config->user->moreLink;
|
||||
|
||||
if(!$contactListID) return print(html::select('mailto[]', $users, '', "class='form-control chosen' multiple data-placeholder='{$this->lang->chooseUsersToMail}'"));
|
||||
if(!$contactListID) return print(html::select($dropdownName . "[]", $users, '', "class='form-control chosen' multiple data-placeholder='{$this->lang->chooseUsersToMail}'"));
|
||||
|
||||
return print(html::select('mailto[]', $users, $list->userList, "class='form-control chosen' multiple data-placeholder='{$this->lang->chooseUsersToMail}'"));
|
||||
return print(html::select($dropdownName . "[]", $users, $list->userList, "class='form-control chosen' multiple data-placeholder='{$this->lang->chooseUsersToMail}'"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -205,6 +205,39 @@ class userModel extends model
|
||||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get users info list for displaying
|
||||
*
|
||||
* @param array $accounts
|
||||
* @param int $deptID
|
||||
* @param string $type
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getUserDisplayInfos($accounts, $deptID = 0, $type = 'inside')
|
||||
{
|
||||
$users = $this->dao->select('account, realname, avatar, dept, role')->from(TABLE_USER)
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF($accounts)->andWhere('type')->eq($type)->fi()
|
||||
->beginIF($accounts)->andWhere('account')->in($accounts)->fi()
|
||||
->fetchAll('account');
|
||||
|
||||
$depts = $this->loadModel('dept')->getDeptPairs($deptID);
|
||||
|
||||
$infos = array();
|
||||
foreach($users as $info)
|
||||
{
|
||||
$info->roleName = zget($this->lang->user->roleList, $info->role, '');
|
||||
if(isset($depts[$info->dept])) $info->deptName = $depts[$info->dept];
|
||||
if(empty($info->avatar)) unset($info->avatar);
|
||||
if(empty($info->realname)) unset($info->realname);
|
||||
if(empty($info->role)) unset($info->role);
|
||||
if(empty($info->roleName)) unset($info->roleName);
|
||||
$infos[$info->account] = $info;
|
||||
}
|
||||
return $infos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user info by ID.
|
||||
*
|
||||
|
||||
@@ -16,7 +16,6 @@ $jsFiles[] = $jqueryRoot . 'lib.js';
|
||||
$jsFiles[] = $jqueryRoot . 'tablesorter/min.js';
|
||||
$jsFiles[] = $jqueryRoot . 'tablesorter/metadata.js';
|
||||
$jsFiles[] = $jsRoot . 'zui/min.js';
|
||||
$jsFiles[] = $jsRoot . 'zui/picker/zui.picker.min.js';
|
||||
$jsFiles[] = $jsRoot . 'my.full.js';
|
||||
|
||||
/* Combine these js files. */
|
||||
@@ -58,7 +57,6 @@ $themes = array_keys($lang->themes);
|
||||
|
||||
/* Create css files for every them and every lang. */
|
||||
$zuiCode = str_replace(array('/*!', '../fonts'), array('/*', '../zui/fonts'), file_get_contents($themeRoot . 'zui/css/min.css'));
|
||||
$zuiCode .= "\n" . str_replace('/*!', '/*', file_get_contents($jsRoot . 'zui/picker/zui.picker.min.css')) . "\n";
|
||||
foreach($langs as $lang)
|
||||
{
|
||||
foreach($themes as $theme)
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ function showMoreImage(obj)
|
||||
*/
|
||||
function setMailto(mailto, contactListID)
|
||||
{
|
||||
link = createLink('user', 'ajaxGetContactUsers', 'listID=' + contactListID);
|
||||
link = createLink('user', 'ajaxGetContactUsers', 'listID=' + contactListID + '&dropdownName=' + mailto);
|
||||
$.get(link, function(users)
|
||||
{
|
||||
$('#' + mailto).replaceWith(users);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user