This commit is contained in:
tengfei
2017-12-18 16:16:06 +08:00
103 changed files with 1632 additions and 897 deletions
+5 -1
View File
@@ -39,7 +39,11 @@ echo %ztcli% > %baseDir%ztcli.bat
echo ztcli.bat ok
:: create backup.bat
SET backup= %phpcli% %baseDir%php\backup.php
if %requestType% == 'PATH_INFO' (
SET backup= %phpcli% %baseDir%ztcli "%pmsRoot%/backup-backup.html"
)else (
SET backup= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=backup&f=backup"
)
echo %backup% > %baseDir%backup.bat
echo backup.bat ok
+5 -1
View File
@@ -42,7 +42,11 @@ echo $ztcli > $basePath/ztcli.sh
echo "ztcli.sh ok"
# backup database
backup="$phpcli $basePath/php/backup.php"
if [ $requestType == 'PATH_INFO' ]; then
backup="$phpcli $basePath/ztcli '$pmsRoot/backup-backup.html'";
else
backup="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=backup&f=backup'";
fi
echo $backup > $basePath/backup.sh
echo "backup.sh ok"
-58
View File
@@ -1,58 +0,0 @@
<?php
/* Backup the db. */
error_reporting(E_ALL ^ E_NOTICE);
/* Include config.php and pclzip class. */
$pmsRoot = dirname(dirname(dirname(__FILE__)));
$myConfig = $pmsRoot . '/config/config.php';
$zipClass = $pmsRoot . '/lib/pclzip/pclzip.class.php';
$zdbClass = $pmsRoot . '/lib/zdb/zdb.class.php';
include $myConfig;
include $zipClass;
include $zdbClass;
/* Init the backupRoot and dest directory. */
$backupRoot = $pmsRoot . "/backup";
$destDir = $backupRoot . "/" . date('Ym');
if(!file_exists($backupRoot)) mkdir($backupRoot, 0777);
if(!file_exists($destDir)) mkdir($destDir, 0777);
/* Backup database. */
$dbRawFile = "db." . date('Ymd') . ".sql";
$dsn = "mysql:host={$config->db->host}; port={$config->db->port}; dbname={$config->db->name}";
$dbh = new PDO($dsn, $config->db->user, $config->db->password, array(PDO::ATTR_PERSISTENT => $config->db->persistant));
$dbh->exec("SET NAMES {$config->db->encoding}");
echo "Backuping database,";
$zdb = new zdb();
$return = $zdb->dump($dbRawFile);
if($return->result)
{
$dbZipFile = $destDir . "/" . str_replace("sql", "zip", $dbRawFile);
$archive = new pclzip($dbZipFile);
if($archive->create($dbRawFile))
{
unlink($dbRawFile);
echo " successfully saved to $dbZipFile\n";
}
else
{
die("Error : " . $archive->errorInfo(true));
}
}
else
{
echo "Failed to backup database!\n";
}
/* Backup the attachments. */
chdir(dirname(dirname(dirname(__FILE__))) . "/www");
if(!is_dir('data/upload')) die(" No files needed backup.\n");
echo "Backuping files,";
$attachFile = $destDir . "/" . "file." . date('Ymd', time()) . ".zip";
$archive = new pclzip($attachFile);
if($archive->create("data/upload", PCLZIP_OPT_REMOVE_PATH, "data")) die(" successfully saved to $attachFile\n");
die("Error : ".$archive->errorInfo(true));
+1 -1
View File
@@ -38,7 +38,7 @@ $config->langs['zh-tw'] = '繁體';
$config->langs['en'] = 'English';
/* 设备类型视图文件前缀。The prefix for view file for different device. */
$config->devicePrefix['mhtml'] = 'm.';
$config->devicePrefix['mhtml'] = '';
/* 默认值设置。Default settings. */
$config->default = new stdclass();
+5
View File
@@ -199,3 +199,8 @@ $filter->user->login->get['account'] = 'account';
$filter->user->login->get['lang'] = 'reg::lang';
$filter->user->login->get['password'] = 'reg::any';
$filter->user->edit->get['from'] = 'reg::word';
$filter->git->cat->get['repoUrl'] = 'reg::base64';
$filter->git->diff->get['repoUrl'] = 'reg::base64';
$filter->svn->cat->get['repoUrl'] = 'reg::base64';
$filter->svn->diff->get['repoUrl'] = 'reg::base64';
+1
View File
@@ -0,0 +1 @@
ALTER TABLE `zt_productplan` ADD `order` TEXT NOT NULL AFTER `end`;
+2 -1
View File
@@ -438,6 +438,7 @@ CREATE TABLE IF NOT EXISTS `zt_productplan` (
`desc` text NOT NULL,
`begin` date NOT NULL,
`end` date NOT NULL,
`order` text NOT NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `plan` (`product`,`end`)
@@ -916,7 +917,7 @@ INSERT INTO `zt_group` (`id`, `name`, `role`, `desc`) VALUES
(9, 'TOP', 'top', 'for top manager.'),
(10, 'OTHERS', 'others', 'for others.'),
(11, 'guest', 'guest', 'For guest'),
(12, 'limited', 'limited', 'For limited user');
(12, 'LIMITED', 'limited', 'For limited user');
INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(1, 'action', 'editComment'),
+17
View File
@@ -104,6 +104,23 @@ class action extends control
}
}
/**
* Comment.
*
* @param string $objectType
* @param int $objectID
* @access public
* @return void
*/
public function comment($objectType, $objectID)
{
$actionID = $this->action->create($objectType, $objectID, 'Commented', $this->post->comment);
$moduleName = $objectType == 'case' ? 'testcase' : $objectType;
$this->loadModel($moduleName)->sendmail($objectID, $actionID);
die(js::reload('parent'));
}
/**
* Edit comment of a action.
*
+1
View File
@@ -25,6 +25,7 @@ $lang->action->undelete = 'Restore';
$lang->action->hideOne = 'Hide';
$lang->action->hideAll = 'Hide All';
$lang->action->editComment = 'Edit';
$lang->action->comment = 'Comment';
$lang->action->trashTips = 'Note: Delete in ZenTao is logic.';
$lang->action->textDiff = 'Text Format';
+1
View File
@@ -25,6 +25,7 @@ $lang->action->undelete = '还原';
$lang->action->hideOne = '隐藏';
$lang->action->hideAll = '全部隐藏';
$lang->action->editComment = '修改备注';
$lang->action->comment = '备注';
$lang->action->trashTips = '提示:为了保证系统的完整性,禅道系统的删除都是标记删除。';
$lang->action->textDiff = '文本格式';
+1 -1
View File
@@ -6,7 +6,7 @@ $config->bug->longlife = 7;
$config->bug->create = new stdclass();
$config->bug->edit = new stdclass();
$config->bug->resolve = new stdclass();
$config->bug->create->requiredFields = 'title,openedBuild';
$config->bug->create->requiredFields = 'title,openedBuild,module';
$config->bug->edit->requiredFields = $config->bug->create->requiredFields;
$config->bug->resolve->requiredFields = 'resolution';
+106 -75
View File
@@ -15,7 +15,7 @@ class bug extends control
/**
* Construct function, load some modules auto.
*
*
* @access public
* @return void
*/
@@ -43,7 +43,7 @@ class bug extends control
/**
* The index page, locate to browse.
*
*
* @access public
* @return void
*/
@@ -54,15 +54,15 @@ class bug extends control
/**
* Browse bugs.
*
* @param int $productID
*
* @param int $productID
* @param string $branch
* @param string $browseType
* @param int $param
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @param string $browseType
* @param int $param
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
@@ -171,11 +171,11 @@ class bug extends control
/**
* The report page.
*
* @param int $productID
* @param string $browseType
*
* @param int $productID
* @param string $browseType
* @param int $branchID
* @param int $moduleID
* @param int $moduleID
* @access public
* @return void
*/
@@ -211,8 +211,8 @@ class bug extends control
/**
* Create a bug.
*
* @param int $productID
*
* @param int $productID
* @param string $extras others params, forexample, projectID=10,moduleID=10
* @access public
* @return void
@@ -328,6 +328,9 @@ class bug extends control
$projectMembers = $this->view->users;
}
$moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch);
if(empty($moduleOptionMenu)) die(js::locate(helper::createLink('tree', 'browse', "productID=$productID&view=story")));
/* Set custom. */
foreach(explode(',', $this->config->bug->list->customCreateFields) as $field) $customFields[$field] = $this->lang->bug->$field;
$this->view->customFields = $customFields;
@@ -339,7 +342,7 @@ class bug extends control
$this->view->productID = $productID;
$this->view->productName = $this->products[$productID];
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch);
$this->view->moduleOptionMenu = $moduleOptionMenu;
$this->view->stories = $stories;
$this->view->projects = $this->product->getProjectPairs($productID, $branch ? "0,$branch" : 0, $params = 'nodeleted');
$this->view->builds = $builds;
@@ -372,11 +375,11 @@ class bug extends control
}
/**
* Batch create.
*
* @param int $productID
* @param int $projectID
* @param int $moduleID
* Batch create.
*
* @param int $productID
* @param int $projectID
* @param int $moduleID
* @access public
* @return void
*/
@@ -453,8 +456,8 @@ class bug extends control
/**
* View a bug.
*
* @param int $bugID
*
* @param int $bugID
* @access public
* @return void
*/
@@ -481,7 +484,7 @@ class bug extends control
/* Get product info. */
$productID = $bug->product;
$productName = $this->products[$productID];
/* Header and positon. */
$this->view->title = "BUG #$bug->id $bug->title - " . $this->products[$productID];
$this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $productName);
@@ -503,8 +506,8 @@ class bug extends control
/**
* Edit a bug.
*
* @param int $bugID
*
* @param int $bugID
* @access public
* @return void
*/
@@ -625,11 +628,11 @@ class bug extends control
$this->bug->sendmail($bugID, $actionID);
$bug = $this->bug->getById($bugID);
if($bug->toTask != 0)
if($bug->toTask != 0)
{
foreach($changes as $change)
{
if($change['field'] == 'status')
if($change['field'] == 'status')
{
$confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask");
$cancelURL = $this->server->HTTP_REFERER;
@@ -727,7 +730,7 @@ class bug extends control
}
/**
* Update assign of bug.
* Update assign of bug.
*
* @param int $bugID
* @access public
@@ -763,6 +766,34 @@ class bug extends control
$this->display();
}
/**
* Batch change branch.
*
* @param int $branchID
* @access public
* @return void
*/
public function batchChangeBranch($branchID)
{
if($this->post->bugIDList)
{
$bugIDList = $this->post->bugIDList;
$bugIDList = array_unique($bugIDList);
unset($_POST['bugIDList']);
$allChanges = $this->bug->batchChangeBranch($bugIDList, $branchID);
if(dao::isError()) die(js::error(dao::getError()));
foreach($allChanges as $bugID => $changes)
{
$this->loadModel('action');
$actionID = $this->action->create('bug', $bugID, 'Edited');
$this->action->logHistory($actionID, $changes);
$this->bug->sendmail($bugID, $actionID);
}
}
$this->loadModel('score')->create('ajax', 'batchOther');
die(js::locate($this->session->bugList, 'parent'));
}
/**
* Batch change the module of bug.
*
@@ -792,9 +823,9 @@ class bug extends control
}
/**
* Batch update assign of bug.
*
* @param int $projectID
* Batch update assign of bug.
*
* @param int $projectID
* @access public
* @return void
*/
@@ -823,8 +854,8 @@ class bug extends control
/**
* confirm a bug.
*
* @param int $bugID
*
* @param int $bugID
* @access public
* @return void
*/
@@ -856,8 +887,8 @@ class bug extends control
}
/**
* Batch confirm bugs.
*
* Batch confirm bugs.
*
* @access public
* @return void
*/
@@ -875,11 +906,11 @@ class bug extends control
$this->loadModel('score')->create('ajax', 'batchOther');
die(js::locate($this->session->bugList, 'parent'));
}
/**
* Resolve a bug.
*
* @param int $bugID
*
* @param int $bugID
* @access public
* @return void
*/
@@ -896,7 +927,7 @@ class bug extends control
$this->bug->sendmail($bugID, $actionID);
$bug = $this->bug->getById($bugID);
if($bug->toTask != 0)
if($bug->toTask != 0)
{
/* If task is not finished, update it's status. */
$task = $this->task->getById($bug->toTask);
@@ -907,7 +938,7 @@ class bug extends control
$cancelURL = $this->createLink('bug', 'view', "bugID=$bugID");
die(js::confirm(sprintf($this->lang->bug->remindTask, $bug->toTask), $confirmURL, $cancelURL, 'parent', 'parent.parent'));
}
}
}
if(isonlybody()) die(js::closeModal('parent.parent'));
die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
}
@@ -936,9 +967,9 @@ class bug extends control
/**
* Batch resolve bugs.
*
* @param string $resolution
* @param string $resolvedBuild
*
* @param string $resolution
* @param string $resolvedBuild
* @access public
* @return void
*/
@@ -995,8 +1026,8 @@ class bug extends control
/**
* Close a bug.
*
* @param int $bugID
*
* @param int $bugID
* @access public
* @return void
*/
@@ -1113,8 +1144,8 @@ class bug extends control
}
/**
* Batch close bugs.
*
* Batch close bugs.
*
* @access public
* @return void
*/
@@ -1225,7 +1256,7 @@ class bug extends control
/**
* Save current template.
*
*
* @access public
* @return string
*/
@@ -1238,7 +1269,7 @@ class bug extends control
/**
* Build the user templates selection code.
*
*
* @access public
* @return void
*/
@@ -1250,8 +1281,8 @@ class bug extends control
/**
* Delete a user template.
*
* @param int $templateID
*
* @param int $templateID
* @access public
* @return void
*/
@@ -1263,8 +1294,8 @@ class bug extends control
/**
* AJAX: get bugs of a user in html select.
*
* @param string $account
*
* @param string $account
* @param string $id the id of the select control.
* @access public
* @return string
@@ -1280,9 +1311,9 @@ class bug extends control
/**
* AJAX: Get bug owner of a module.
*
* @param int $moduleID
* @param int $productID
*
* @param int $moduleID
* @param int $productID
* @access public
* @return string
*/
@@ -1294,32 +1325,32 @@ class bug extends control
/**
* AJAX: get team members of the project as assignedTo list.
*
* @param int $projectID
* @param string $selectedUser
*
* @param int $projectID
* @param string $selectedUser
* @access public
* @return string
*/
public function ajaxLoadAssignedTo($projectID, $selectedUser = '')
{
$projectMembers = $this->loadModel('project')->getTeamMemberPairs($projectID);
die(html::select('assignedTo', $projectMembers, $selectedUser, 'class="form-control"'));
}
/**
* AJAX: get team members of the latest project of a product as assignedTo list.
*
* @param int $productID
*
* @param int $productID
* x
* @param string $selectedUser
* @param string $selectedUser
* @access public
* @return string
*/
public function ajaxLoadProjectTeamMembers($productID, $selectedUser = '')
{
$latestProject = $this->product->getLatestProject($productID);
if(!empty($latestProject))
if(!empty($latestProject))
{
$projectMembers = $this->loadModel('project')->getTeamMemberPairs($latestProject->id, 'nodeleted');
}
@@ -1346,9 +1377,9 @@ class bug extends control
}
/**
* AJAX: get actions of a bug. for web app.
*
* @param int $bugID
* AJAX: get actions of a bug. for web app.
*
* @param int $bugID
* @access public
* @return void
*/
@@ -1359,10 +1390,10 @@ class bug extends control
}
/**
* Get data to export
*
* @param string $productID
* @param string $orderBy
* Get data to export
*
* @param string $productID
* @param string $orderBy
* @access public
* @return void
*/
@@ -1550,8 +1581,8 @@ class bug extends control
/**
* Ajax get bug by ID.
*
* @param int $bugID
*
* @param int $bugID
* @access public
* @return void
*/
+1 -1
View File
@@ -78,7 +78,7 @@ function loadBranch()
$('#taskIdBox').innerHTML = '<select id="task"></select>'; // Reset the task.
$('#task').chosen(defaultChosenOptions);
productID = $('#product').val();
loadProductModules(productID);
loadProductModules(productID);
loadProductProjects(productID);
loadProductBuilds(productID);
loadProductplans(productID);
+4 -4
View File
@@ -217,18 +217,18 @@ $lang->bug->browserList['other'] = 'Other';
$lang->bug->typeList[''] = '';
$lang->bug->typeList['codeerror'] = 'Code Error';
$lang->bug->typeList['interface'] = 'Interface Optimization';
$lang->bug->typeList['designchange'] = 'Design Change';
$lang->bug->typeList['newfeature'] = 'New Feature';
$lang->bug->typeList['designdefect'] = 'Design Defect';
$lang->bug->typeList['config'] = 'Configuration';
$lang->bug->typeList['install'] = 'Install/Deploy';
$lang->bug->typeList['security'] = 'Security';
$lang->bug->typeList['performance'] = 'Performance';
$lang->bug->typeList['standard'] = 'Standard';
$lang->bug->typeList['automation'] = 'Testing Script';
$lang->bug->typeList['trackthings'] = 'Issue Tracking';
$lang->bug->typeList['others'] = 'Other';
$lang->bug->statusList[''] = '';
$lang->bug->statusList['active'] = 'Active';
$lang->bug->statusList['resolved'] = 'Resolved';
+5 -4
View File
@@ -115,6 +115,7 @@ $lang->bug->byQuery = '搜索';
$lang->bug->needConfirm = '需求变动';
$lang->bug->allProduct = '所有' . $lang->productCommon;
$lang->bug->ditto = '同上';
$lang->bug->dittoNotice = '该bug与上一bug不属于同一产品!';
@@ -216,17 +217,17 @@ $lang->bug->browserList['other'] = '其他';
$lang->bug->typeList[''] = '';
$lang->bug->typeList['codeerror'] = '代码错误';
$lang->bug->typeList['interface'] = '界面优化';
$lang->bug->typeList['designchange'] = '设计变更';
$lang->bug->typeList['newfeature'] = '新增需求';
$lang->bug->typeList['designdefect'] = '设计缺陷';
$lang->bug->typeList['config'] = '配置相关';
$lang->bug->typeList['install'] = '安装部署';
$lang->bug->typeList['security'] = '安全相关';
$lang->bug->typeList['performance'] = '性能问题';
$lang->bug->typeList['standard'] = '标准规范';
$lang->bug->typeList['automation'] = '测试脚本';
$lang->bug->typeList['trackthings'] = '事务跟踪';
$lang->bug->typeList['others'] = '其他';
$lang->bug->typeList['designchange'] = '设计变更';
$lang->bug->typeList['newfeature'] = '新增需求';
$lang->bug->typeList['designdefect'] = '设计缺陷';
$lang->bug->typeList['trackthings'] = '事务跟踪';
$lang->bug->statusList[''] = '';
$lang->bug->statusList['active'] = '激活';
+34 -1
View File
@@ -113,7 +113,11 @@ class bugModel extends model
for($i = 0; $i < $batchNum; $i++)
{
if(!empty($data->title[$i]) and empty($data->openedBuilds[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->bug->openedBuild)));
if(!empty($data->title[$i]))
{
if(empty($data->modules[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->bug->module)));
if(empty($data->openedBuilds[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->bug->openedBuild)));
}
}
/* Get pairs(moduleID => moduleOwner) for bug. */
@@ -865,6 +869,35 @@ class bugModel extends model
$this->linkBugToBuild($bugID, $bug->resolvedBuild);
}
/**
* Batch change branch.
*
* @param array $bugIDList
* @param int $branchID
* @access public
* @return array
*/
public function batchChangeBranch($bugIDList, $branchID)
{
$now = helper::now();
$allChanges = array();
$oldBugs = $this->getByList($bugIDList);
foreach($bugIDList as $bugID)
{
$oldBug = $oldBugs[$bugID];
if($branchID == $oldBug->branch) continue;
$bug = new stdclass();
$bug->lastEditedBy = $this->app->user->account;
$bug->lastEditedDate = $now;
$bug->branch = $branchID;
$this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec();
if(!dao::isError()) $allChanges[$bugID] = common::createChanges($oldBug, $bug);
}
return $allChanges;
}
/**
* Batch change the module of bug.
*
+1 -1
View File
@@ -39,7 +39,7 @@ foreach(explode(',', $showFields) as $field)
<tr>
<th class='w-50px'> <?php echo $lang->idAB;?></th>
<th class='w-120px<?php echo zget($visibleFields, $product->type, ' hidden')?>'> <?php echo $lang->product->branch;?></th>
<th class='w-120px<?php echo zget($visibleFields, 'module', ' hidden')?>'> <?php echo $lang->bug->module;?></th>
<th class='w-120px<?php echo zget($visibleFields, 'module', ' hidden')?>'> <?php echo $lang->bug->module;?> <span class='required'></span></th>
<th class='w-130px<?php echo zget($visibleFields, 'project', ' hidden')?>'><?php echo $lang->bug->project;?></th>
<th><?php echo $lang->bug->openedBuild;?> <span class='required'></span></th>
<th><?php echo $lang->bug->title;?> <span class='required'></span></th>
+17
View File
@@ -237,6 +237,23 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow
$misc = common::hasPriv('bug', 'batchActivate') ? "onclick=\"setFormAction('$actionLink')\"" : $class;
if($misc) echo "<li>" . html::a('javascript:;', $lang->bug->activate, '', $misc) . "</li>";
if(common::hasPriv('bug', 'batchChangeBranch') and $this->session->currentProductType != 'normal')
{
$withSearch = count($branches) > 8;
echo "<li class='dropdown-submenu'>";
echo html::a('javascript:;', $lang->product->branchName[$this->session->currentProductType], '', "id='branchItem'");
echo "<div class='dropdown-menu" . ($withSearch ? ' with-search':'') . "'>";
echo "<ul class='dropdown-list'>";
foreach($branches as $branchID => $branchName)
{
$actionLink = $this->createLink('bug', 'batchChangeBranch', "branchID=$branchID");
echo "<li class='option' data-key='$branchID'>" . html::a('#', $branchName, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin')\"") . "</li>";
}
echo '</ul>';
if($withSearch) echo "<div class='menu-search'><div class='input-group input-group-sm'><input type='text' class='form-control' placeholder=''><span class='input-group-addon'><i class='icon-search'></i></span></div></div>";
echo '</div></li>';
}
if(common::hasPriv('bug', 'batchChangeModule'))
{
$withSearch = count($modules) > 8;
+1 -1
View File
@@ -89,7 +89,7 @@
<div class='actions'><?php if(!$bug->deleted) echo $actionLinks;?></div>
<fieldset id='commentBox' class='hide'>
<legend><?php echo $lang->comment;?></legend>
<form method='post' action='<?php echo inlink('edit', "bugID=$bug->id&comment=true")?>'>
<form method='post' action='<?php echo $this->createLink('action', 'comment', "objectType=bug&objectID=$bug->id")?>' target='hiddenwin'>
<div class="form-group"><?php echo html::textarea('comment', '',"rows='5' class='w-p100'");?></div>
<?php echo html::submitButton() . html::backButton();?>
</form>
+9 -4
View File
@@ -174,7 +174,7 @@ class build extends control
* @access public
* @return void
*/
public function view($buildID, $type = 'story', $link = 'false', $param = '')
public function view($buildID, $type = 'story', $link = 'false', $param = '', $orderBy = 'id_desc')
{
if($type == 'story')$this->session->set('storyList', $this->app->getURI(true));
if($type == 'bug') $this->session->set('bugList', $this->app->getURI(true));
@@ -189,7 +189,9 @@ class build extends control
$product = $this->loadModel('product')->getById($build->product);
if($product->type != 'normal') $this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
$bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($build->bugs)->andWhere('deleted')->eq(0)->fetchAll();
$bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($build->bugs)->andWhere('deleted')->eq(0)
->beginIF($type == 'bug')->orderBy($orderBy)->fi()
->fetchAll();
if($this->config->global->flow == 'onlyTest')
{
@@ -203,7 +205,9 @@ class build extends control
}
else
{
$stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($build->stories)->andWhere('deleted')->eq(0)->fetchAll('id');
$stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($build->stories)->andWhere('deleted')->eq(0)
->beginIF($type == 'story')->orderBy($orderBy)->fi()
->fetchAll('id');
$stages = $this->dao->select('*')->from(TABLE_STORYSTAGE)->where('story')->in($build->stories)->andWhere('branch')->eq($build->branch)->fetchPairs('story', 'stage');
foreach($stages as $storyID => $stage)$stories[$storyID]->stage = $stage;
@@ -214,7 +218,7 @@ class build extends control
$this->view->position[] = html::a($this->createLink('project', 'task', "projectID=$build->project"), $projects[$build->project]);
$this->view->position[] = $this->lang->build->view;
$this->view->stories = $stories;
$this->view->generatedBugs = $this->bug->getProjectBugs($build->project, $build->id, '', 0, 'status_desc,id_desc', null);
$this->view->generatedBugs = $this->bug->getProjectBugs($build->project, $build->id, '', 0, $type == 'newbug' ? $orderBy : 'status_desc,id_desc', null);
$this->view->bugs = $bugs;
$this->view->type = $type;
}
@@ -225,6 +229,7 @@ class build extends control
$this->view->actions = $this->loadModel('action')->getList('build', $buildID);
$this->view->link = $link;
$this->view->param = $param;
$this->view->orderBy = $orderBy;
$this->view->branchName = $build->productType == 'normal' ? '' : $this->loadModel('branch')->getById($build->branch);
$this->display();
}
+3
View File
@@ -10,5 +10,8 @@
.table-actions {padding-left: 5px;}
#buildInfo {border-top: 1px solid #ddd;}
#buildInfo > div {padding-top: 15px;}
#querybox form {margin: 0px !important;}
#moreOrLite {right: 0px !important;}
+4
View File
@@ -10,6 +10,10 @@
* @link http://www.zentao.net
*/
?>
<?php
$jsRoot = $this->app->getWebRoot() . "js/";
include '../../common/view/tablesorter.html.php';
?>
<div id='querybox' class='show'></div>
<div id='unlinkBugList'>
<form method='post' id='unlinkedBugsForm' target='hiddenwin' action='<?php echo $this->createLink('build', 'linkBug', "buildID={$build->id}&browseType=$browseType&param=$param");?>'>
+4
View File
@@ -10,6 +10,10 @@
* @link http://www.zentao.net
*/
?>
<?php
$jsRoot = $this->app->getWebRoot() . "js/";
include '../../common/view/tablesorter.html.php';
?>
<div id='querybox' class='show'></div>
<div id='unlinkStoryList'>
<form method='post' id='unlinkedStoriesForm' target='hiddenwin' action='<?php echo $this->createLink('build', 'linkStory', "buildID={$build->id}&browseType=$browseType&param=$param");?>'>
+83 -76
View File
@@ -79,9 +79,10 @@ tfoot tr td .table-actions .btn{display:none;}
<div class='tabs'>
<?php $countStories = count($stories); $countBugs = count($bugs); $countNewBugs = count($generatedBugs);?>
<ul class='nav nav-tabs'>
<li <?php if($type == 'story') echo "class='active'"?>><a href='#stories' data-toggle='tab'><?php echo html::icon($lang->icons['story'], 'green') . ' ' . $lang->build->stories;?></a></li>
<li <?php if($type == 'bug') echo "class='active'"?>><a href='#bugs' data-toggle='tab'><?php echo html::icon($lang->icons['bug'], 'green') . ' ' . $lang->build->bugs;?></a></li>
<li <?php if($type == 'newbug') echo "class='active'"?>><a href='#newBugs' data-toggle='tab'><?php echo html::icon($lang->icons['bug'], 'red') . ' ' . $lang->build->generatedBugs;?></a></li>
<li <?php if($type == 'story') echo "class='active'"?>><a href='#stories' data-toggle='tab'><?php echo html::icon($lang->icons['story'], 'green') . ' ' . $lang->build->stories;?></a></li>
<li <?php if($type == 'bug') echo "class='active'"?>><a href='#bugs' data-toggle='tab'><?php echo html::icon($lang->icons['bug'], 'green') . ' ' . $lang->build->bugs;?></a></li>
<li <?php if($type == 'newbug') echo "class='active'"?>><a href='#newBugs' data-toggle='tab'><?php echo html::icon($lang->icons['bug'], 'red') . ' ' . $lang->build->generatedBugs;?></a></li>
<li <?php if($type == 'buildInfo') echo "class='active'"?>><a href='#buildInfo' data-toggle='tab'><?php echo html::icon($lang->icons['plan'], 'blue') . ' ' . $lang->build->view;?></a></li>
</ul>
<div class='tab-content'>
<div class='tab-pane <?php if($type == 'story') echo 'active'?>' id='stories'>
@@ -91,16 +92,17 @@ tfoot tr td .table-actions .btn{display:none;}
<?php endif;?>
<form method='post' target='hiddenwin' action='<?php echo inlink('batchUnlinkStory', "buildID={$build->id}")?>' id='linkedStoriesForm'>
<table class='table table-hover table-condensed table-striped tablesorter table-fixed table-selectable' id='storyList'>
<?php $vars = "buildID={$build->id}&type=story&link=$link&param=$param&orderBy=%s";?>
<thead>
<tr>
<th class='w-id'><?php echo $lang->idAB;?></th>
<th class='w-pri'><?php echo $lang->priAB;?></th>
<th><?php echo $lang->story->title;?></th>
<th class='w-user'><?php echo $lang->openedByAB;?></th>
<th class='w-hour'><?php echo $lang->story->estimateAB;?></th>
<th class='w-hour'><?php echo $lang->statusAB;?></th>
<th class='w-100px'><?php echo $lang->story->stageAB;?></th>
<th class='w-50px'><?php echo $lang->actions;?></th>
<th class='w-id {sorter:false}'> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
<th class='w-pri {sorter:false}'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
<th class='text-left {sorter:false}'><?php common::printOrderLink('title', $orderBy, $vars, $lang->story->title);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='w-hour {sorter:false}'> <?php common::printOrderLink('estimate', $orderBy, $vars, $lang->story->estimateAB);?></th>
<th class='w-hour {sorter:false}'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
<th class='w-100px {sorter:false}'> <?php common::printOrderLink('stage', $orderBy, $vars, $lang->story->stageAB);?></th>
<th class='w-50px {sorter:false}'> <?php echo $lang->actions?></th>
</tr>
</thead>
<?php $canBatchUnlink = common::hasPriv('build', 'batchUnlinkStory');?>
@@ -150,16 +152,17 @@ tfoot tr td .table-actions .btn{display:none;}
<?php endif;?>
<form method='post' target='hiddenwin' action="<?php echo inLink('batchUnlinkBug', "build=$build->id");?>" id='linkedBugsForm'>
<table class='table table-hover table-condensed table-striped tablesorter table-fixed table-selectable' id='bugList'>
<?php $vars = "buildID={$build->id}&type=bug&link=$link&param=$param&orderBy=%s";?>
<thead>
<tr>
<th class='w-id'><?php echo $lang->idAB;?></th>
<th><?php echo $lang->bug->title;?></th>
<th class='w-100px'><?php echo $lang->bug->status;?></th>
<th class='w-user'><?php echo $lang->openedByAB;?></th>
<th class='w-date'><?php echo $lang->bug->openedDateAB;?></th>
<th class='w-user'><?php echo $lang->bug->resolvedByAB;?></th>
<th class='w-100px'><?php echo $lang->bug->resolvedDateAB;?></th>
<th class='w-50px'><?php echo $lang->actions;?></th>
<th class='w-id {sorter:false}'> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
<th class='text-left {sorter:false}'><?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
<th class='w-100px {sorter:false}'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='w-date {sorter:false}'> <?php common::printOrderLink('openedDate', $orderBy, $vars, $lang->bug->openedDateAB);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('resolvedBy', $orderBy, $vars, $lang->bug->resolvedByAB);?></th>
<th class='w-100px {sorter:false}'> <?php common::printOrderLink('resolvedDate', $orderBy, $vars, $lang->bug->resolvedDateAB);?></th>
<th class='w-50px {sorter:false}'> <?php echo $lang->actions?></th>
</tr>
</thead>
<?php $canBatchUnlink = common::hasPriv('build', 'batchUnlinkBug');?>
@@ -203,16 +206,18 @@ tfoot tr td .table-actions .btn{display:none;}
</div>
<div class='tab-pane <?php if($type == 'newbug') echo 'active'?>' id='newBugs'>
<table class='table table-hover table-condensed table-striped tablesorter table-fixed'>
<?php $vars = "buildID={$build->id}&type=newbug&link=$link&param=$param&orderBy=%s";?>
<thead>
<tr>
<th class='w-id'><?php echo $lang->idAB;?></th>
<th class='w-severity'><?php echo $lang->bug->severityAB;?></th>
<th><?php echo $lang->bug->title;?></th>
<th class='w-100px'><?php echo $lang->bug->status;?></th>
<th class='w-user'><?php echo $lang->openedByAB;?></th>
<th class='w-date'><?php echo $lang->bug->openedDateAB;?></th>
<th class='w-user'><?php echo $lang->bug->resolvedByAB;?></th>
<th class='w-100px'><?php echo $lang->bug->resolvedDateAB;?></th>
<th class='w-id {sorter:false}'> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
<th class='w-severity {sorter:false}'><?php common::printOrderLink('severity', $orderBy, $vars, $lang->bug->severityAB);?></th>
<th class='text-left {sorter:false}'> <?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
<th class='w-100px {sorter:false}'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='w-date {sorter:false}'> <?php common::printOrderLink('openedDate', $orderBy, $vars, $lang->bug->openedDateAB);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('resolvedBy', $orderBy, $vars, $lang->bug->resolvedByAB);?></th>
<th class='w-100px {sorter:false}'> <?php common::printOrderLink('resolvedDate', $orderBy, $vars, $lang->bug->resolvedDateAB);?></th>
<th class='w-50px {sorter:false}'> <?php echo $lang->actions?></th>
</tr>
</thead>
<?php foreach($generatedBugs as $bug):?>
@@ -239,60 +244,62 @@ tfoot tr td .table-actions .btn{display:none;}
</tfoot>
</table>
</div>
<div class='tab-pane <?php if($type == 'buildInfo') echo 'active'?>' id='buildInfo'>
<div class="row-table">
<div class='col-main'>
<fieldset>
<legend><?php echo $lang->build->basicInfo?></legend>
<table class='table table-data table-condensed table-borderless table-fixed'>
<tr>
<th class='w-80px'><?php echo $lang->build->product;?></th>
<td><?php echo $build->productName;?></td>
</tr>
<?php if($build->productType != 'normal'):?>
<tr>
<th><?php echo $lang->product->branch;?></th>
<td><?php echo $branchName;?></td>
</tr>
<?php endif;?>
<tr>
<th><?php echo $lang->build->name;?></th>
<td><?php echo $build->name;?></td>
</tr>
<tr>
<th><?php echo $lang->build->builder;?></th>
<td><?php echo $users[$build->builder];?></td>
</tr>
<tr>
<th><?php echo $lang->build->date;?></th>
<td><?php echo $build->date;?></td>
</tr>
<tr>
<th><?php echo $lang->build->scmPath;?></th>
<td style='word-break:break-all;'><?php echo html::a($build->scmPath, $build->scmPath, '_blank')?></td>
</tr>
<tr>
<th><?php echo $lang->build->filePath;?></th>
<td style='word-break:break-all;'><?php echo html::a($build->filePath, $build->filePath, '_blank');?></td>
</tr>
<?php if($this->config->global->flow != 'onlyTest'):?>
<tr>
<th><?php echo $lang->build->desc;?></th>
<td><div class='article-content'><?php echo $build->desc;?></div></td>
</tr>
<?php endif;?>
</table>
</fieldset>
<?php if($this->config->global->flow != 'onlyTest'):?>
<?php echo $this->fetch('file', 'printFiles', array('files' => $build->files, 'fieldset' => 'true'));?>
<?php endif;?>
</div>
<div class="col-side"><?php include '../../common/view/action.html.php';?></div>
</div>
</div>
</div>
</div>
<?php endif;?>
</div>
</div>
<div class='col-side'>
<div class='main-side main'>
<?php if($this->config->global->flow != 'onlyTest'):?>
<fieldset>
<legend><?php echo $lang->build->desc;?></legend>
<div class='article-content'><?php echo $build->desc;?></div>
</fieldset>
<?php endif;?>
<fieldset>
<legend><?php echo $lang->build->basicInfo?></legend>
<table class='table table-data table-condensed table-borderless table-fixed'>
<tr>
<th class='w-80px'><?php echo $lang->build->product;?></th>
<td><?php echo $build->productName;?></td>
</tr>
<?php if($build->productType != 'normal'):?>
<tr>
<th><?php echo $lang->product->branch;?></th>
<td><?php echo $branchName;?></td>
</tr>
<?php endif;?>
<tr>
<th><?php echo $lang->build->name;?></th>
<td><?php echo $build->name;?></td>
</tr>
<tr>
<th><?php echo $lang->build->builder;?></th>
<td><?php echo $users[$build->builder];?></td>
</tr>
<tr>
<th><?php echo $lang->build->date;?></th>
<td><?php echo $build->date;?></td>
</tr>
<tr>
<th><?php echo $lang->build->scmPath;?></th>
<td style='word-break:break-all;'><?php echo html::a($build->scmPath, $build->scmPath, '_blank')?></td>
</tr>
<tr>
<th><?php echo $lang->build->filePath;?></th>
<td style='word-break:break-all;'><?php echo html::a($build->filePath, $build->filePath, '_blank');?></td>
</tr>
</table>
</fieldset>
<?php if($this->config->global->flow != 'onlyTest'):?>
<?php echo $this->fetch('file', 'printFiles', array('files' => $build->files, 'fieldset' => 'true'));?>
<?php include '../../common/view/action.html.php';?>
<?php endif;?>
</div>
</div>
</div>
<?php if($this->config->global->flow != 'onlyTest'):?>
<?php js::set('param', helper::safe64Decode($param))?>
+100 -86
View File
@@ -48,7 +48,7 @@ class commonModel extends model
/**
* Set the commpany.
*
* First, search company by the http host. If not found, search by the default domain. Last, use the first as the default.
* First, search company by the http host. If not found, search by the default domain. Last, use the first as the default.
* After get the company, save it to session.
* @access public
* @return void
@@ -72,7 +72,7 @@ class commonModel extends model
/**
* Set the user info.
*
*
* @access public
* @return void
*/
@@ -99,7 +99,7 @@ class commonModel extends model
/**
* Load configs from database and save it to config->system and config->personal.
*
*
* @access public
* @return void
*/
@@ -170,9 +170,9 @@ class commonModel extends model
/**
* Deny access.
*
*
* @access public
* @return void
* @return mixed
*/
public function deny($module, $method)
{
@@ -207,7 +207,7 @@ class commonModel extends model
/**
* Print the run info.
*
*
* @param mixed $startTime the start time.
* @access public
* @return array the run info array.
@@ -223,7 +223,7 @@ class commonModel extends model
/**
* Print top bar.
*
*
* @static
* @access public
* @return void
@@ -293,8 +293,9 @@ class commonModel extends model
/**
* Create menu item link
*
* @param object $menuItemLink
* @param boolean $isTutorialMode
* @param object $menuItem
*
* @static
* @access public
* @return string
*/
@@ -321,6 +322,8 @@ class commonModel extends model
* Print the main menu.
*
* @param string $moduleName
* @param string $methodName
*
* @static
* @access public
* @return void
@@ -383,14 +386,14 @@ class commonModel extends model
if($config->global->flow == 'onlyTask') $searchObject = 'task';
}
echo "<div class='input-group input-group-sm' id='searchbox'>";
echo "<div class='input-group input-group-sm' id='searchbox'>";
echo "<div class='input-group-btn' id='typeSelector'>";
echo "<button type='button' class='btn dropdown-toggle' data-toggle='dropdown'><span id='searchTypeName'>" . $lang->searchObjects[$searchObject] . "</span> <span class='caret'></span></button>";
echo html::hidden('searchType', $searchObject);
echo "<ul class='dropdown-menu'>";
foreach ($lang->searchObjects as $key => $value)
{
echo "<li><a href='javascript:;' data-value='{$key}'>{$value}</a></li>";
echo "<li><a href='javascript:;' data-value='{$key}'>{$value}</a></li>";
}
echo '</ul></div>';
echo html::input('searchQuery', '', "onclick='this.value=\"\"' onkeydown='if(event.keyCode==13) shortcut()' class='form-control' placeholder='" . $lang->searchTips . "'");
@@ -400,8 +403,8 @@ class commonModel extends model
/**
* Print the module menu.
*
* @param string $moduleName
*
* @param string $moduleName
* @static
* @access public
* @return void
@@ -470,9 +473,9 @@ class commonModel extends model
/**
* Print the bread menu.
*
* @param string $moduleName
* @param string $position
*
* @param string $moduleName
* @param string $position
* @static
* @access public
* @return void
@@ -504,7 +507,7 @@ class commonModel extends model
/**
* Print the link for notify file.
*
*
* @static
* @access public
* @return void
@@ -519,8 +522,10 @@ class commonModel extends model
}
/**
* Print QR code Link.
*
* Print QR code Link.
*
* @param string $color
*
* @static
* @access public
* @return void
@@ -537,16 +542,16 @@ class commonModel extends model
/**
* Print the link contains orderBy field.
*
* This method will auto set the orderby param according the params. Fox example, if the order by is desc,
* This method will auto set the orderby param according the params. Fox example, if the order by is desc,
* will be changed to asc.
*
*
* @param string $fieldName the field name to sort by
* @param string $orderBy the order by string
* @param string $vars the vars to be passed
* @param string $label the label of the link
* @param string $module the module name
* @param string $method the method name
* @static
*
* @access public
* @return void
*/
@@ -583,17 +588,21 @@ class commonModel extends model
}
/**
*
* Print link to an modules' methd.
*
* Before printing, check the privilege first. If no privilege, return fasle. Else, print the link, return true.
*
* @param string $module the module name
* @param string $method the method
* @param string $vars vars to be passed
* @param string $label the label of the link
* @param string $target the target of the link
* @param string $misc others
* @param bool $newline
* @param string $module the module name
* @param string $method the method
* @param string $vars vars to be passed
* @param string $label the label of the link
* @param string $target the target of the link
* @param string $misc others
* @param bool $newline
* @param bool $onlyBody
* @param $object
*
* @static
* @access public
* @return bool
@@ -607,7 +616,7 @@ class commonModel extends model
/**
* Print icon of split line.
*
*
* @static
* @access public
* @return void
@@ -619,11 +628,13 @@ class commonModel extends model
/**
* Print icon of comment.
*
* @param string $module
*
* @param string $module
* @param $object
*
* @static
* @access public
* @return void
* @return mixed
*/
public static function printCommentIcon($module, $object = null)
{
@@ -631,7 +642,7 @@ class commonModel extends model
global $lang;
if(!commonModel::hasPriv($module, 'edit', $object)) return false;
if(!commonModel::hasPriv('action', 'comment', $object)) return false;
echo html::a('#commentBox', '<i class="icon-comment-alt"></i>', '', "title='$lang->comment' onclick='setComment()' class='btn'");
}
@@ -683,7 +694,7 @@ class commonModel extends model
$title = $method;
if($method == 'create' and $icon == 'copy') $method = 'copy';
if(isset($lang->$method) and is_string($lang->$method)) $title = $lang->$method;
if((isset($lang->$module->$method) or $app->loadLang($module)) and isset($lang->$module->$method))
if((isset($lang->$module->$method) or $app->loadLang($module)) and isset($lang->$module->$method))
{
$title = $method == 'report' ? $lang->$module->$method->common : $lang->$module->$method;
}
@@ -759,8 +770,11 @@ class commonModel extends model
/**
* Print backLink and preLink and nextLink.
*
* @param string $backLink
* @param object $preAndNext
* @param string $backLink
* @param object $preAndNext
* @param string $linkTemplate
*
* @static
* @access public
* @return void
*/
@@ -772,7 +786,7 @@ class commonModel extends model
$title = $lang->goback . $lang->backShortcutKey;
echo html::a($backLink, '<i class="icon-goback icon-level-up icon-large icon-rotate-270"></i>', '', "id='back' class='btn' title={$title}");
if(isset($preAndNext->pre) and $preAndNext->pre)
if(isset($preAndNext->pre) and $preAndNext->pre)
{
$id = (isset($_SESSION['testcaseOnlyCondition']) and !$_SESSION['testcaseOnlyCondition'] and $app->getModuleName() == 'testcase' and isset($preAndNext->pre->case)) ? 'case' : 'id';
$title = isset($preAndNext->pre->title) ? $preAndNext->pre->title : $preAndNext->pre->name;
@@ -780,7 +794,7 @@ class commonModel extends model
$link = $linkTemplate ? sprintf($linkTemplate, $preAndNext->pre->$id) : inLink('view', "ID={$preAndNext->pre->$id}");
echo html::a($link, '<i class="icon-pre icon-chevron-left"></i>', '', "id='pre' class='btn' title='{$title}'");
}
if(isset($preAndNext->next) and $preAndNext->next)
if(isset($preAndNext->next) and $preAndNext->next)
{
$id = (isset($_SESSION['testcaseOnlyCondition']) and !$_SESSION['testcaseOnlyCondition'] and $app->getModuleName() == 'testcase' and isset($preAndNext->next->case)) ? 'case' : 'id';
$title = isset($preAndNext->next->title) ? $preAndNext->next->title : $preAndNext->next->name;
@@ -792,7 +806,7 @@ class commonModel extends model
/**
* Create changes of one object.
*
*
* @param mixed $old the old object
* @param mixed $new the new object
* @static
@@ -818,10 +832,10 @@ class commonModel extends model
if($magicQuote) $value = stripslashes($value);
if(isset($old->$key) and $value != stripslashes($old->$key))
{
{
$diff = '';
if(substr_count($value, "\n") > 1 or
substr_count($old->$key, "\n") > 1 or
if(substr_count($value, "\n") > 1 or
substr_count($old->$key, "\n") > 1 or
strpos('name,title,desc,spec,steps,content,digest,verify,report', strtolower($key)) !== false)
{
$diff = commonModel::diff($old->$key, $value);
@@ -834,9 +848,9 @@ class commonModel extends model
/**
* Diff two string. (see phpt)
*
* @param string $text1
* @param string $text2
*
* @param string $text1
* @param string $text2
* @static
* @access public
* @return string
@@ -860,8 +874,8 @@ class commonModel extends model
/**
* Judge Suhosin Setting whether the actual size of post data is large than the setting size.
*
* @param int $countInputVars
*
* @param int $countInputVars
* @static
* @access public
* @return bool
@@ -885,9 +899,9 @@ class commonModel extends model
/**
* Get the previous and next object.
*
*
* @param string $type story|task|bug|case
* @param string $objectID
* @param string $objectID
* @access public
* @return void
*/
@@ -952,9 +966,9 @@ class commonModel extends model
/**
* Save one executed query.
*
* @param string $sql
* @param string $objectType story|task|bug|testcase
*
* @param string $sql
* @param string $objectType story|task|bug|testcase
* @access public
* @return void
*/
@@ -996,10 +1010,10 @@ class commonModel extends model
/**
* Remove duplicate for story, task, bug, case, doc.
*
*
* @param string $type e.g. story task bug case doc.
* @param array|object $data
* @param string $condition
* @param array|object $data
* @param string $condition
* @access public
* @return array
*/
@@ -1033,9 +1047,9 @@ class commonModel extends model
/**
* Append order by.
*
* @param string $orderBy
* @param string $append
*
* @param string $orderBy
* @param string $append
* @access public
* @return string
*/
@@ -1048,9 +1062,9 @@ class commonModel extends model
/**
* Check field exists
*
* @param string $table
* @param string $field
*
* @param string $table
* @param string $field
* @access public
* @return bool
*/
@@ -1071,7 +1085,7 @@ class commonModel extends model
/**
* Check upgrade's status file is ok or not.
*
*
* @access public
* @return void
*/
@@ -1092,7 +1106,7 @@ class commonModel extends model
/**
* Check the user has permission to access this method, if not, locate to the login page or deny page.
*
*
* @access public
* @return void
*/
@@ -1157,11 +1171,11 @@ class commonModel extends model
}
/**
* Check db priv.
*
* @param object $object
* @param string $module
* @param string $method
* Check db priv.
*
* @param object $object
* @param string $module
* @param string $method
* @static
* @access public
* @return void
@@ -1259,7 +1273,7 @@ class commonModel extends model
* we used %s as placeholder. These %s should be setted in one module.
*
* The items of one module's menu may be an string or array. For example, please see module/common/lang.
*
*
* @param string $object the menus of one module
* @param string $key the menu item to be replaced
* @param string $params the params passed to the menu item
@@ -1278,7 +1292,7 @@ class commonModel extends model
$menu->$key->link = vsprintf($menu->$key->link, $params);
$menu->$key = (array)$menu->$key;
}
else
else
{
$menu->$key = vsprintf($menu->$key, $params);
}
@@ -1300,7 +1314,7 @@ class commonModel extends model
/**
* Get the full url of the system.
*
*
* @access public
* @return string
*/
@@ -1323,8 +1337,8 @@ class commonModel extends model
/**
* Convert items to Pinyin.
*
* @param array $items
*
* @param array $items
* @static
* @access public
* @return array
@@ -1365,8 +1379,8 @@ class commonModel extends model
}
/**
* Check an entry.
*
* Check an entry.
*
* @access public
* @return void
*/
@@ -1394,9 +1408,9 @@ class commonModel extends model
}
/**
* Check token of an entry.
*
* @param string $key
* Check token of an entry.
*
* @param string $key
* @access public
* @return void
*/
@@ -1409,9 +1423,9 @@ class commonModel extends model
}
/**
* Response.
*
* @param int $code
* Response.
*
* @param int $code
* @access public
* @return void
*/
@@ -1425,10 +1439,10 @@ class commonModel extends model
}
/**
* Http.
*
* @param string $url
* @param string|array $data
* Http.
*
* @param string $url
* @param string|array $data
* @static
* @access public
* @return string
+1 -1
View File
@@ -13,7 +13,7 @@ if($extHookFiles) foreach($extHookFiles as $extHookFile) include $extHookFile;
?>
<?php if(empty($_GET['onlybody']) or $_GET['onlybody'] != 'yes'):?>
<?php $this->app->loadConfig('sso');?>
<?php
<?php
if(!empty($this->config->sso->redirect)) js::set('ssoRedirect', $this->config->sso->redirect);
?>
<header id='header'>
+4 -1
View File
@@ -159,6 +159,7 @@ class cron extends control
while(true)
{
dao::$cache = array();
/* When cron is null then die. */
if(empty($crons)) break;
if(empty($parsedCrons)) break;
@@ -170,10 +171,12 @@ class cron extends control
/* Run crons. */
$now = new datetime('now');
unset($_SESSION['company']);
unset($this->app->company);
$this->common->setCompany();
$this->common->loadConfigFromDB();
foreach($parsedCrons as $id => $cron)
{
$cronInfo = $this->cron->getById($id);
/* Skip empty and stop cron.*/
if(empty($cronInfo) or $cronInfo->status == 'stop') continue;
+1
View File
@@ -64,6 +64,7 @@ $lang->doc->manageType = 'Manage Category';
$lang->doc->editType = 'Edit';
$lang->doc->deleteType = 'Delete';
$lang->doc->addType = 'Add';
$lang->doc->childType = 'Child';
$lang->doc->libName = 'Name';
$lang->doc->libType = 'Category';
+1
View File
@@ -64,6 +64,7 @@ $lang->doc->manageType = '维护分类';
$lang->doc->editType = '编辑分类';
$lang->doc->deleteType = '删除分类';
$lang->doc->addType = '增加分类';
$lang->doc->childType = '子分类';
$lang->doc->libName = '文档库名称';
$lang->doc->libType = '文档库类型';
+1 -1
View File
@@ -133,7 +133,7 @@
<i class='icon icon-download'></i>
</a>
<div class='card-heading'>
<a href='<?php echo $this->createLink($file->objectType, 'view', "objectID=$file->objectID");?>'><?php echo $file->title . '.' . $file->extension . ' [' . strtoupper($file->objectType) . ' #' . $file->objectID . ']';?></a>
<a href='<?php echo $this->createLink($file->objectType, 'view', "objectID=$file->objectID");?>' title='<?php echo substr($file->addedDate, 0, 10)?>'><?php echo $file->title . '.' . $file->extension . ' [' . strtoupper($file->objectType) . ' #' . $file->objectID . ']';?></a>
<?php if(common::hasPriv('file', 'delete')): ?>
<a href='<?php echo $this->createLink('file', 'delete', "fileID=$file->id"); ?>' target='hiddenwin' title='<?php echo $lang->delete?>' class='delete pull-right'><i class='icon icon-remove'></i></a>
<?php endif?>
+1 -1
View File
@@ -126,7 +126,7 @@
<?php include '../../common/view/action.html.php';?>
<fieldset id='commentBox' class='hide'>
<legend><?php echo $lang->comment;?></legend>
<form method='post' action='<?php echo inlink('edit', "docID=$doc->id&comment=true")?>'>
<form method='post' action='<?php echo $this->createLink('action', 'comment', "objectType=doc&objectID=$doc->id")?>' target='hiddenwin'>
<div class="form-group"><?php echo html::textarea('comment', '',"style='width:100%;height:100px'");?></div>
<?php echo html::submitButton() . html::backButton();?>
</form>
+1
View File
@@ -46,6 +46,7 @@ $lang->extension->downloads = 'Downloads';
$lang->extension->compatible = 'Compatibility';
$lang->extension->grade = 'Score';
$lang->extension->depends = 'Dependent';
$lang->extension->expireDate = 'Expire';
$lang->extension->zentaoCompatible = 'Compatible Version';
$lang->extension->installedTime = 'Installed Time';
+1
View File
@@ -46,6 +46,7 @@ $lang->extension->downloads = '下载量';
$lang->extension->compatible = '兼容性';
$lang->extension->grade = '评分';
$lang->extension->depends = '依赖';
$lang->extension->expireDate = '到期日期';
$lang->extension->zentaoCompatible = '适用版本';
$lang->extension->installedTime = '安装时间';
+31
View File
@@ -886,4 +886,35 @@ class extensionModel extends model
if($type != 'between') return !$result;
return $result;
}
/**
* Get extension expire date.
*
* @param int $extension
* @access public
* @return void
*/
public function getExpireDate($extension)
{
$licencePath = $this->app->getConfigRoot() . 'license/';
$today = date('Y-m-d');
$expireDate = '';
$licenceOrderFile = $licencePath . 'order' . $extension->code . $extension->version . '.txt';
if(file_exists($licenceOrderFile))
{
$order = file_get_contents($licenceOrderFile);
$order = unserialize($order);
if($order->type != 'life')
{
$days = isset($order->days) ? $order->days : 0;
if($order->type == 'demo') $days = 31;
if($order->type == 'year') $days = 365;
$startDate = $order->paidDate != '0000-00-00 00:00:00' ? $order->paidDate : $order->createdDate;
if($days) $expireDate = date('Y-m-d', strtotime($startDate) + $days * 24 * 3600);
}
}
return $expireDate;
}
}
+2
View File
@@ -53,6 +53,8 @@
<?php
echo "{$lang->extension->version}: <i>{$extension->version}</i> ";
echo "{$lang->extension->author}: <i>{$extension->author}</i> ";
$expireDate = $this->extension->getExpireDate($extension);
if(!empty($expireDate)) echo "{$lang->extension->expireDate}: <i>{$expireDate}</i>";
?>
</div>
</div></div>
+4
View File
@@ -32,7 +32,9 @@ class git extends control
*/
public function diff($path, $revision)
{
if(isset($_GET['repoUrl'])) $path = $this->get->repoUrl;
$path = helper::safe64Decode($path);
$this->view->path = $path;
$this->view->revision = $revision;
$this->view->diff = $this->git->diff($path, $revision);
@@ -50,7 +52,9 @@ class git extends control
*/
public function cat($path, $revision)
{
if(isset($_GET['repoUrl'])) $path = $this->get->repoUrl;
$path = helper::safe64Decode($path);
$this->view->path = $path;
$this->view->revision = $revision;
$this->view->code = $this->git->cat($path, $revision);
+19 -3
View File
@@ -643,9 +643,8 @@ class gitModel extends model
{
foreach($actionFiles as $file)
{
$param = array('url' => helper::safe64Encode($repoRoot . $file), 'revision' => $log->revision);
$catLink = trim(html::a(helper::createLink('git', 'cat', $param, 'html'), 'view', '', "class='repolink'"));
$diffLink = trim(html::a(helper::createLink('git', 'diff', $param, 'html'), 'diff', '', "class='repolink'"));
$catLink = trim(html::a($this->buildURL('cat', $repoRoot . $file, $log->revision), 'view', '', "class='repolink'"));
$diffLink = trim(html::a($this->buildURL('diff', $repoRoot . $file, $log->revision), 'diff', '', "class='repolink'"));
$diff .= $action . " " . $file . " $catLink ";
$diff .= $action == 'M' ? "$diffLink\n" : "\n" ;
}
@@ -747,4 +746,21 @@ class gitModel extends model
{
echo helper::now() . " $log\n";
}
/**
* Build URL.
*
* @param string $methodName
* @param string $url
* @param int $revision
* @access public
* @return string
*/
public function buildURL($methodName, $url, $revision)
{
$buildedURL = helper::createLink('git', $methodName, "path=&revision=$revision", 'html');
$buildedURL .= strpos($buildedURL, '?') === false ? '?' : '&';
$buildedURL .= 'repoUrl=' . helper::safe64Encode($url);
return $buildedURL;
}
}
+1 -1
View File
@@ -11,7 +11,7 @@
*/
?>
<?php include '../../common/view/header.lite.html.php';?>
<?php $catLink = inlink('cat', 'url=' . helper::safe64Encode($path) . "&revision=$revision");?>
<?php $catLink = $this->git->buildURL('cat', $path, $revision);?>
<div class='box-title'><?php echo html::a($catLink, "$path@$revision");?></div>
<div class='box-content'><xmp><?php echo $diff;?></xmp></div>
<?php include '../../common/view/footer.lite.html.php';?>
+3
View File
@@ -1005,12 +1005,15 @@ $lang->resource->action->trash = 'trash';
$lang->resource->action->undelete = 'undelete';
$lang->resource->action->hideOne = 'hideOne';
$lang->resource->action->hideAll = 'hideAll';
$lang->resource->action->comment = 'comment';
$lang->resource->action->editComment = 'editComment';
$lang->action->methodOrder[5] = 'trash';
$lang->action->methodOrder[10] = 'undelete';
$lang->action->methodOrder[15] = 'hideOne';
$lang->action->methodOrder[20] = 'hideAll';
$lang->action->methodOrder[25] = 'comment';
$lang->action->methodOrder[30] = 'editComment';
$lang->resource->backup = new stdclass();
$lang->resource->backup->index = 'index';
-1
View File
@@ -422,7 +422,6 @@ class groupModel extends model
$action = strtolower($action);
if($action == 'manageview' and $group->role == 'limited') return false;
if($action == 'edit' and $group->role == 'limited') return false;
if($action == 'copy' and $group->role == 'limited') return false;
return true;
+22 -20
View File
@@ -126,26 +126,28 @@ $lang->install->account = 'Admin Account';
$lang->install->password = 'Admin Password';
$lang->install->errorEmptyPassword = 'Password should not be blank.';
$lang->install->groupList['ADMIN']['name'] = 'Admin';
$lang->install->groupList['ADMIN']['desc'] = 'System Administrator';
$lang->install->groupList['DEV']['name'] = 'Dev';
$lang->install->groupList['DEV']['desc'] = 'Dev Team';
$lang->install->groupList['QA']['name'] = 'QA';
$lang->install->groupList['QA']['desc'] = 'QA Team';
$lang->install->groupList['PM']['name'] = 'PM';
$lang->install->groupList['PM']['desc'] = 'for Project Manager';
$lang->install->groupList['PO']['name'] = 'PO';
$lang->install->groupList['PO']['desc'] = 'for Product Owner';
$lang->install->groupList['TD']['name'] = 'Dev Manager';
$lang->install->groupList['TD']['desc'] = 'for Dev Manager';
$lang->install->groupList['PD']['name'] = 'PD';
$lang->install->groupList['PD']['desc'] = 'for Product Director';
$lang->install->groupList['QD']['name'] = 'QD';
$lang->install->groupList['QD']['desc'] = 'for QA Director';
$lang->install->groupList['TOP']['name'] = 'Senior';
$lang->install->groupList['TOP']['desc'] = 'for Senior Manager';
$lang->install->groupList['OTHERS']['name'] = 'Other';
$lang->install->groupList['OTHERS']['desc'] = 'for Other';
$lang->install->groupList['ADMIN']['name'] = 'Admin';
$lang->install->groupList['ADMIN']['desc'] = 'System Administrator';
$lang->install->groupList['DEV']['name'] = 'Dev';
$lang->install->groupList['DEV']['desc'] = 'Dev Team';
$lang->install->groupList['QA']['name'] = 'QA';
$lang->install->groupList['QA']['desc'] = 'QA Team';
$lang->install->groupList['PM']['name'] = 'PM';
$lang->install->groupList['PM']['desc'] = 'for Project Manager';
$lang->install->groupList['PO']['name'] = 'PO';
$lang->install->groupList['PO']['desc'] = 'for Product Owner';
$lang->install->groupList['TD']['name'] = 'Dev Manager';
$lang->install->groupList['TD']['desc'] = 'for Dev Manager';
$lang->install->groupList['PD']['name'] = 'PD';
$lang->install->groupList['PD']['desc'] = 'for Product Director';
$lang->install->groupList['QD']['name'] = 'QD';
$lang->install->groupList['QD']['desc'] = 'for QA Director';
$lang->install->groupList['TOP']['name'] = 'Senior';
$lang->install->groupList['TOP']['desc'] = 'for Senior Manager';
$lang->install->groupList['OTHERS']['name'] = 'Other';
$lang->install->groupList['OTHERS']['desc'] = 'for Other';
$lang->install->groupList['LIMITED']['name'] = 'Limited User';
$lang->install->groupList['LIMITED']['desc'] = 'for Limited user (editing only content related to itself)';
$lang->install->cronList[''] = 'Monitor cron';
$lang->install->cronList['moduleName=project&methodName=computeburn'] = 'Update Burndown Chart';
+22 -20
View File
@@ -126,26 +126,28 @@ $lang->install->account = '管理员帐号';
$lang->install->password = '管理员密码';
$lang->install->errorEmptyPassword = '密码不能为空';
$lang->install->groupList['ADMIN']['name'] = '管理员';
$lang->install->groupList['ADMIN']['desc'] = '系统管理员';
$lang->install->groupList['DEV']['name'] = '研发';
$lang->install->groupList['DEV']['desc'] = '研发人员';
$lang->install->groupList['QA']['name'] = '测试';
$lang->install->groupList['QA']['desc'] = '测试人员';
$lang->install->groupList['PM']['name'] = '项目经理';
$lang->install->groupList['PM']['desc'] = '项目经理';
$lang->install->groupList['PO']['name'] = '产品经理';
$lang->install->groupList['PO']['desc'] = '产品经理';
$lang->install->groupList['TD']['name'] = '研发主管';
$lang->install->groupList['TD']['desc'] = '研发主管';
$lang->install->groupList['PD']['name'] = '产品主管';
$lang->install->groupList['PD']['desc'] = '产品主管';
$lang->install->groupList['QD']['name'] = '测试主管';
$lang->install->groupList['QD']['desc'] = '测试主管';
$lang->install->groupList['TOP']['name'] = '高层管理';
$lang->install->groupList['TOP']['desc'] = '高层管理';
$lang->install->groupList['OTHERS']['name'] = '其他';
$lang->install->groupList['OTHERS']['desc'] = '其他';
$lang->install->groupList['ADMIN']['name'] = '管理员';
$lang->install->groupList['ADMIN']['desc'] = '系统管理员';
$lang->install->groupList['DEV']['name'] = '研发';
$lang->install->groupList['DEV']['desc'] = '研发人员';
$lang->install->groupList['QA']['name'] = '测试';
$lang->install->groupList['QA']['desc'] = '测试人员';
$lang->install->groupList['PM']['name'] = '项目经理';
$lang->install->groupList['PM']['desc'] = '项目经理';
$lang->install->groupList['PO']['name'] = '产品经理';
$lang->install->groupList['PO']['desc'] = '产品经理';
$lang->install->groupList['TD']['name'] = '研发主管';
$lang->install->groupList['TD']['desc'] = '研发主管';
$lang->install->groupList['PD']['name'] = '产品主管';
$lang->install->groupList['PD']['desc'] = '产品主管';
$lang->install->groupList['QD']['name'] = '测试主管';
$lang->install->groupList['QD']['desc'] = '测试主管';
$lang->install->groupList['TOP']['name'] = '高层管理';
$lang->install->groupList['TOP']['desc'] = '高层管理';
$lang->install->groupList['OTHERS']['name'] = '其他';
$lang->install->groupList['OTHERS']['desc'] = '其他';
$lang->install->groupList['LIMITED']['name'] = '受限用户';
$lang->install->groupList['LIMITED']['desc'] = '受限用户分组(只能编辑与自己相关的内容)';
$lang->install->cronList[''] = '监控定时任务';
$lang->install->cronList['moduleName=project&methodName=computeburn'] = '更新燃尽图';
+11 -6
View File
@@ -55,21 +55,26 @@ class mail extends control
* @access public
* @return void
*/
public function detect()
public function detect($type = 'smtp')
{
if($_POST)
if($_POST or $type == 'gmail')
{
set_time_limit(30);
$error = '';
if($this->post->fromAddress == false) $error = sprintf($this->lang->error->notempty, $this->lang->mail->fromAddress);
if(!validater::checkEmail($this->post->fromAddress)) $error .= '\n' . sprintf($this->lang->error->email, $this->lang->mail->fromAddress);
if($type != 'gmail')
{
$error = '';
if($this->post->fromAddress == false) $error = sprintf($this->lang->error->notempty, $this->lang->mail->fromAddress);
if(!validater::checkEmail($this->post->fromAddress)) $error .= '\n' . sprintf($this->lang->error->email, $this->lang->mail->fromAddress);
if($error) die(js::alert($error));
if($error) die(js::alert($error));
}
if($type == 'gmail' and empty($_POST['fromAddress'])) $_POST['fromAddress'] = '@gmail.com';
echo "<script>setTimeout(function(){parent.location.href='" . inlink('edit') . "'}, 10000)</script>";
$mailConfig = $this->mail->autoDetect($this->post->fromAddress);
$mailConfig->fromAddress = $this->post->fromAddress;
$mailConfig->domain = common::getSysURL();
if($type == 'gmail') $mailConfig->fromAddress = '';
$this->session->set('mailConfig', $mailConfig);
die(js::locate(inlink('edit'), 'parent'));
+2 -1
View File
@@ -1,4 +1,5 @@
$(document).ready()
{
$('#password').focus();
$('#fromAddress').focus();
if($('#fromAddress').val() != '')$('#password').focus();
}
+1
View File
@@ -10,6 +10,7 @@ $lang->mail->resend = 'Resend';
$lang->mail->browse = 'Email List';
$lang->mail->delete = 'Delete Email';
$lang->mail->ztCloud = 'ZenTao CloudMail';
$lang->mail->gmail = 'GMAIL';
$lang->mail->sendCloud = 'Notice SendCloud';
$lang->mail->batchDelete = 'Batch Delete';
$lang->mail->sendcloudUser = 'Sync Contact';
+1
View File
@@ -10,6 +10,7 @@ $lang->mail->resend = '重发';
$lang->mail->browse = '邮件列表';
$lang->mail->delete = '删除邮件';
$lang->mail->ztCloud = '禅道云发信';
$lang->mail->gmail = 'GMAIL发信';
$lang->mail->sendCloud = 'Notice发信';
$lang->mail->batchDelete = '批量删除';
$lang->mail->sendcloudUser = '同步联系人';
+3
View File
@@ -24,6 +24,9 @@ include '../../common/view/header.html.php';
<?php if($this->app->getClientLang() != 'en' and common::hasPriv('mail', 'ztCloud')):?>
<?php echo html::a(inlink('ztCloud'), $lang->mail->ztCloud, '', "class='btn btn-sm w-120px'")?>
<?php endif;?>
<?php if($this->app->getClientLang() == 'en'):?>
<?php echo html::a(inlink('detect', 'type=gmail'), $lang->mail->gmail, '', "class='btn btn-sm w-120px'")?>
<?php endif;?>
<?php if(common::hasPriv('mail', 'detect')):?>
<?php echo html::a(inlink('detect'), $lang->mail->smtp, '', "class='btn btn-sm w-120px'")?>
<?php endif;?>
+25 -6
View File
@@ -406,18 +406,35 @@ class my extends control
if($this->post->mode == 'new')
{
$listID = $this->user->createContactList($this->post->newList, $this->post->users);
$this->user->setGlobalContacts($listID, isset($_POST['share']));
if(isonlybody()) die(js::closeModal('parent.parent', '', 'function(){parent.parent.ajaxGetContacts(\'#mailtoGroup\')}'));
die(js::locate(inlink('manageContacts', "listID=$listID"), 'parent'));
}
elseif($this->post->mode == 'edit')
{
$this->user->updateContactList($this->post->listID, $this->post->listName, $this->post->users);
$this->user->setGlobalContacts($this->post->listID, isset($_POST['share']));
die(js::locate(inlink('manageContacts', "listID={$this->post->listID}"), 'parent'));
}
}
$mode = empty($mode) ? 'edit' : $mode;
$lists = $this->user->getContactLists($this->app->user->account);
$mode = empty($mode) ? 'edit' : $mode;
$lists = $this->user->getContactLists($this->app->user->account);
$globalContacts = isset($this->config->my->global->globalContacts) ? $this->config->my->global->globalContacts : '';
$globalContacts = !empty($globalContacts) ? explode(',', $globalContacts) : array();
$myContacts = $this->user->getListByAccount($this->app->user->account);
$disabled = $globalContacts;
if(!empty($myContacts) && !empty($globalContacts))
{
foreach($globalContacts as $id)
{
if(in_array($id, array_keys($myContacts))) unset($disabled[array_search($id, $disabled)]);
}
}
$listID = $listID ? $listID : key($lists);
if(!$listID) $mode = 'new';
@@ -434,10 +451,12 @@ class my extends control
$this->view->list = $this->user->getContactListByID($listID);
}
$this->view->mode = $mode;
$this->view->lists = $lists;
$this->view->listID = $listID;
$this->view->users = $this->user->getPairs('noletter|noempty|noclosed|noclosed');
$this->view->mode = $mode;
$this->view->lists = $lists;
$this->view->listID = $listID;
$this->view->users = $this->user->getPairs('noletter|noempty|noclosed|noclosed');
$this->view->disabled = $disabled;
$this->view->globalContacts = $globalContacts;
$this->display();
}
-2
View File
@@ -1,3 +1 @@
body.body-modal {padding-bottom: 20px; min-height: 400px}
.list-group-item.active {color: #1A4F85}
+1
View File
@@ -17,6 +17,7 @@ $lang->my->changePassword = 'Edit Password';
$lang->my->unbind = 'Unbind Ranger';
$lang->my->manageContacts = 'Maintain Contact';
$lang->my->deleteContacts = 'Delete Contact';
$lang->my->shareContacts = 'Share List';
$lang->my->limited = 'Restricted operation (editing only content related to itself)';
$lang->my->score = 'My Score';
$lang->my->scoreRule = 'Score Rule';
+1
View File
@@ -17,6 +17,7 @@ $lang->my->changePassword = '修改密码';
$lang->my->unbind = '解除然之绑定';
$lang->my->manageContacts = '维护联系人';
$lang->my->deleteContacts = '删除联系人';
$lang->my->shareContacts = '共享联系人列表';
$lang->my->limited = '受限操作(只能编辑与自己相关的内容)';
$lang->my->score = '我的积分';
$lang->my->scoreRule = '积分规则';
+17 -3
View File
@@ -19,7 +19,8 @@
foreach($lists as $id => $listName)
{
$listClass = ($id == $listID) ? 'list-group-item active' : 'list-group-item';
echo html::a(inlink('managecontacts', "listID=$id&mode=edit"), $listName, '', "class='{$listClass}'");
$shareIcon = in_array($id, $globalContacts) ? '<i class="icon icon-share-sign"></i> ' : '';
echo html::a(inlink('managecontacts', "listID=$id&mode=edit"), $shareIcon . $listName, '', "class='{$listClass}'");
}
?>
</ul>
@@ -44,13 +45,14 @@
<td class='w-300px'>
<div class='required required-wrapper'></div>
<?php
if($mode == 'edit') $readonly = in_array($list->id, $disabled) ? ' readonly' : '';
if($mode == 'new')
{
echo html::input('newList', '', "class='form-control'");
}
else
{
echo html::input('listName', $list->listName, "class='form-control'");
echo html::input('listName', $list->listName, "$readonly class='form-control'");
echo html::hidden('listID', $list->id);
}
?>
@@ -67,11 +69,22 @@
}
else
{
echo html::select('users[]', $users, $list->userList, "multiple class='form-control chosen'");
echo html::select('users[]', $users, $list->userList, "multiple $readonly class='form-control chosen'");
}
?>
</td>
</tr>
<?php if(common::hasPriv('datatable', 'setGlobal')):?>
<tr>
<th></th>
<td colspan="2">
<label class="checkbox-inline">
<input type="checkbox" name="share" value="1" <?php if($mode != 'new' && in_array($list->id, $globalContacts)) echo 'checked';?>/> <?php echo $lang->my->shareContacts;?>
</label>
</td>
</tr>
<?php endif;?>
<?php if($mode == 'new' || !in_array($list->id, $disabled)):?>
<tr>
<td></td>
<td>
@@ -79,6 +92,7 @@
<?php if($mode == 'edit') echo html::a(inlink('deleteContacts', "listID=$listID"), $lang->delete, 'hiddenwin', "class='btn btn-danger'");?>
</td>
</tr>
<?php endif;?>
</table>
</div>
</div>
+41
View File
@@ -25,8 +25,49 @@ $(function()
setTimeout(function(){fixedTheadOfList('#storyList')}, 100);
if($('#storyList thead th.w-title').width() < 150) $('#storyList thead th.w-title').width(150);
$(document).on('click', "#storyList tbody tr", function(){showCheckedSummary();});
$(document).on('change', "#storyList :checkbox", function(){showCheckedSummary();});
$(document).on('click', "#datatable-storyList table tr", function(){showCheckedSummary();});
})
function showCheckedSummary()
{
var $summary = $('tfoot .table-actions .text:last');
if(!$summary.hasClass('readed'))
{
taskSummary = $summary.html();
$summary.addClass('readed');
}
var checkedTotal = 0;
var checkedEstimate = 0;
var checkedCase = 0;
$('[name^="storyIDList"]').each(function()
{
if($(this).prop('checked'))
{
checkedTotal += 1;
var taskID = $(this).val();
$tr = $("#storyList tbody tr[data-id='" + taskID + "']");
checkedEstimate += Number($tr.data('estimate'));
if(Number($tr.data('cases')) > 0) checkedCase += 1;
}
});
if(checkedTotal > 0)
{
rate = Math.round(checkedCase / checkedTotal * 10000) / 100 + '' + '%';
summary = checkedSummary.replace('%total%', checkedTotal)
.replace('%estimate%', checkedEstimate)
.replace('%rate%', rate)
$('tfoot .table-actions .text:last').html(summary);
}
else
{
$('tfoot .table-actions .text:last').html(taskSummary);
}
}
function setQueryBar(queryID, title)
{
$('#bysearchTab').before("<li id='QUERY" + queryID + "Tab' class='active'><a href='" + createLink('product', 'browse', "productID=" + productID + "&branch=" + branch + "&browseType=bysearch&param=" + queryID) + "'>" + title + "</a></li>");
+3 -2
View File
@@ -109,8 +109,9 @@ $lang->product->aclList['open'] = "Default (User with {$lang->productCommon}
$lang->product->aclList['private'] = "Private {$lang->productCommon} ({$lang->projectCommon} team members only)";
$lang->product->aclList['custom'] = 'Custom (Team members and Whitelist members have access to it.)';
$lang->product->storySummary = " <strong>%s</strong> Story(ies), <strong>%s</strong> hour(s) estimated, case coverage is <strong>%s</strong> on this page.";
$lang->product->noMatched = '"%s" cannot be found.' . $lang->productCommon;
$lang->product->storySummary = " <strong>%s</strong> Story(ies), <strong>%s</strong> hour(s) estimated, case coverage is <strong>%s</strong> on this page.";
$lang->product->checkedSummary = " <strong>%total%</strong> Checked, <strong>%estimate%</strong> hour(s) estimated, case coverage is <strong>%rate%</strong>.";
$lang->product->noMatched = '"%s" cannot be found.' . $lang->productCommon;
$lang->product->mySelects['assignedtome'] = $lang->product->assignedToMe;
$lang->product->mySelects['openedbyme'] = $lang->product->openedByMe;
+4 -3
View File
@@ -16,7 +16,7 @@ $lang->product->dynamic = "动态";
$lang->product->view = "{$lang->productCommon}概况";
$lang->product->edit = "编辑{$lang->productCommon}";
$lang->product->batchEdit = "批量编辑";
$lang->product->create = "新增{$lang->productCommon}";
$lang->product->create = "添加{$lang->productCommon}";
$lang->product->delete = "删除{$lang->productCommon}";
$lang->product->deleted = "已删除";
$lang->product->close = "关闭";
@@ -108,8 +108,9 @@ $lang->product->aclList['open'] = "默认设置(有{$lang->productCommon}视
$lang->product->aclList['private'] = "私有{$lang->productCommon}(只有{$lang->productCommon}相关负责人和{$lang->projectCommon}团队成员才能访问)";
$lang->product->aclList['custom'] = '自定义白名单(团队成员和白名单的成员可以访问)';
$lang->product->storySummary = "本页共 <strong>%s</strong> 个需求,预计 <strong>%s</strong> 个工时,用例覆盖率<strong>%s</strong>。";
$lang->product->noMatched = '找不到包含"%s"的' . $lang->productCommon;
$lang->product->storySummary = "本页共 <strong>%s</strong> 个需求,预计 <strong>%s</strong> 个工时,用例覆盖率<strong>%s</strong>。";
$lang->product->checkedSummary = "选中 <strong>%total%</strong> 个需求,预计 <strong>%estimate%</strong> 个工时,用例覆盖率<strong>%rate%</strong>。";
$lang->product->noMatched = '找不到包含"%s"的' . $lang->productCommon;
$lang->product->featureBar['browse']['unclosed'] = $lang->product->unclosed;
$lang->product->featureBar['browse']['unplan'] = $lang->product->unplan;
+61 -55
View File
@@ -14,11 +14,16 @@
class productModel extends model
{
/**
* Set menu.
*
* @param array $products
* @param int $productID
* @param string $extra
*
* Set menu.
*
* @param array $products
* @param int $productID
* @param int $branch
* @param int $module
* @param string $moduleType
* @param string $extra
*
* @access public
* @return void
*/
@@ -53,13 +58,14 @@ class productModel extends model
}
/**
* Create the select code of products.
*
* @param array $products
* @param int $productID
* @param string $currentModule
* @param string $currentMethod
* @param string $extra
* Create the select code of products.
*
* @param array $products
* @param int $productID
* @param string $currentModule
* @param string $currentMethod
* @param string $extra
*
* @access public
* @return string
*/
@@ -115,8 +121,8 @@ class productModel extends model
/**
* Save the product id user last visited to session.
*
* @param int $productID
*
* @param int $productID
* @param array $products
* @access public
* @return int
@@ -148,8 +154,8 @@ class productModel extends model
/**
* Check privilege.
*
* @param int $product
*
* @param int $product
* @access public
* @return bool
*/
@@ -157,7 +163,7 @@ class productModel extends model
{
/* Is admin? */
$account = ',' . $this->app->user->account . ',';
if($this->app->user->admin) return true;
if($this->app->user->admin) return true;
$acls = $this->app->user->rights['acls'];
if(!empty($acls['products']) and !in_array($product->id, $acls['products'])) return false;
@@ -172,8 +178,8 @@ class productModel extends model
/**
* Get product by id.
*
* @param int $productID
*
* @param int $productID
* @access public
* @return object
*/
@@ -188,8 +194,8 @@ class productModel extends model
/**
* Get by idList.
*
* @param array $productIDList
*
* @param array $productIDList
* @access public
* @return array
*/
@@ -200,9 +206,9 @@ class productModel extends model
/**
* Get products.
*
* @param string $status
* @param int $limit
*
* @param string $status
* @param int $limit
* @param int $line
* @access public
* @return array
@@ -227,9 +233,9 @@ class productModel extends model
}
/**
* Get product pairs.
*
* @param string $mode
* Get product pairs.
*
* @param string $mode
* @return array
*/
public function getPairs($mode = '')
@@ -273,7 +279,7 @@ class productModel extends model
/**
* Get grouped products.
*
*
* @access public
* @return void
*/
@@ -284,7 +290,7 @@ class productModel extends model
/**
* Create a product.
*
*
* @access public
* @return int
*/
@@ -325,8 +331,8 @@ class productModel extends model
/**
* Update a product.
*
* @param int $productID
*
* @param int $productID
* @access public
* @return array
*/
@@ -358,7 +364,7 @@ class productModel extends model
/**
* Batch update products.
*
*
* @access public
* @return void
*/
@@ -399,10 +405,10 @@ class productModel extends model
$this->fixOrder();
return $allChanges;
}
/**
* Close product.
*
*
* @param int $productID.
* @access public
* @return void
@@ -520,8 +526,8 @@ class productModel extends model
/**
* Get projects of a product in pairs.
*
* @param int $productID
*
* @param int $productID
* @param string $param all|nodeleted
* @access public
* @return array
@@ -549,8 +555,8 @@ class productModel extends model
/**
* Get roadmap of a proejct
*
* @param int $productID
*
* @param int $productID
* @access public
* @return array
*/
@@ -585,8 +591,8 @@ class productModel extends model
/**
* Get team members of a product from projects.
*
* @param object $product
*
* @param object $product
* @access public
* @return array
*/
@@ -624,9 +630,9 @@ class productModel extends model
}
/**
* Get product stat by id
*
* @param int $productID
* Get product stat by id
*
* @param int $productID
* @access public
* @return object|bool
*/
@@ -737,7 +743,7 @@ class productModel extends model
->where('deleted')->eq(0)
->andWhere('product')->in(array_keys($products))
->groupBy('product')
->fetchPairs();
->fetchPairs();
$unResolved = $this->dao->select('product,count(*) AS count')
->from(TABLE_BUG)
->where('status')->eq('active')
@@ -803,8 +809,8 @@ class productModel extends model
/**
* Get the summary of product's stories.
*
* @param array $stories
*
* @param array $stories
* @access public
* @return string.
*/
@@ -834,9 +840,9 @@ class productModel extends model
/**
* Judge an action is clickable or not.
*
* @param object $product
* @param string $action
*
* @param object $product
* @param string $action
* @access public
* @return void
*/
@@ -851,10 +857,10 @@ class productModel extends model
/**
* Create the link from module,method,extra
*
* @param string $module
* @param string $method
* @param mix $extra
*
* @param string $module
* @param string $method
* @param mix $extra
* @access public
* @return void
*/
@@ -903,7 +909,7 @@ class productModel extends model
/**
* Fix order.
*
*
* @access public
* @return void
*/
@@ -925,7 +931,7 @@ class productModel extends model
* get the latest project of the product.
*
* @param int $productID
* @access public
* @access public
* @return object
*/
public function getLatestProject($productID)
+2 -1
View File
@@ -141,7 +141,7 @@
</thead>
<tbody>
<?php foreach($stories as $story):?>
<tr class='text-center' data-id='<?php echo $story->id?>'>
<tr class='text-center' data-id='<?php echo $story->id?>' data-estimate='<?php echo $story->estimate?>' data-cases='<?php echo zget($storyCases, $story->id, 0);?>'>
<?php foreach($setting as $key => $value) $this->story->printCell($value, $story, $users, $branches, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table');?>
</tr>
<?php endforeach;?>
@@ -323,6 +323,7 @@
</table>
</form>
</div>
<?php js::set('checkedSummary', $lang->product->checkedSummary);?>
<script language='javascript'>
var moduleID = <?php echo $moduleID?>;
$('#module<?php echo $moduleID;?>').addClass('active');
+101 -37
View File
@@ -13,8 +13,10 @@ class productplan extends control
{
/**
* Common actions
*
* @param int $productID
*
* @param int $productID
* @param int $branch
*
* @access public
* @return void
*/
@@ -33,8 +35,10 @@ class productplan extends control
/**
* Create a plan.
*
* @param int $product
*
* @param string $product
* @param int $branch
*
* @access public
* @return void
*/
@@ -70,8 +74,9 @@ class productplan extends control
/**
* Edit a plan.
*
* @param int $planID
*
* @param int $planID
*
* @access public
* @return void
*/
@@ -99,8 +104,10 @@ class productplan extends control
/**
* Batch edit plan.
*
* @param int $productID
*
* @param int $productID
* @param int $branch
*
* @access public
* @return void
*/
@@ -130,11 +137,11 @@ class productplan extends control
}
die(js::locate('back'));
}
/**
* Delete a plan.
*
* @param int $planID
*
* @param int $planID
* @param string $confirm yes|no
* @access public
* @return void
@@ -171,11 +178,12 @@ class productplan extends control
/**
* Browse plans.
*
* @param int $product
* @param string $orderBy
*
* @param int $productID
* @param int $branch
* @param string $orderBy
* @param string $browseType
* @param int $recTotal
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
@@ -209,6 +217,9 @@ class productplan extends control
* @param int $planID
* @param string $type
* @param string $orderBy
* @param string $link
* @param string $param
*
* @access public
* @return void
*/
@@ -217,13 +228,39 @@ class productplan extends control
$this->session->set('storyList', $this->app->getURI(true) . '&type=' . 'story');
$this->session->set('bugList', $this->app->getURI(true) . '&type=' . 'bug');
$reSort = false;
if($type == 'story' && strpos($orderBy, 'order') !== false)
{
$orderBy = str_replace('order', 'id', $orderBy);
$reSort = true;
}
/* Append id for secend sort. */
$sort = $this->loadModel('common')->appendOrder($orderBy);
$plan = $this->productplan->getByID($planID, true);
if(!$plan) die(js::error($this->lang->notFound) . js::locate('back'));
$this->commonAction($plan->product, $plan->branch);
$products = $this->product->getPairs();
$products = $this->product->getPairs();
$planStories = $this->loadModel('story')->getPlanStories($planID, 'all', $type == 'story' ? $sort : 'id_desc');
if($reSort)
{
if(!empty($plan->order))
{
$stories = array();
$order = explode(',', $plan->order);
if(strpos($orderBy, 'asc') !== false) $order = array_reverse($order, true);
foreach($order as $id)
{
if(empty($id)) continue;
$stories[$id] = $planStories[$id];
}
$planStories = $stories;
unset($stories);
}
$orderBy = str_replace('id', 'order', $orderBy);
}
$this->loadModel('datatable');
$showModule = !empty($this->config->datatable->productBrowse->showModule) ? $this->config->datatable->productBrowse->showModule : '';
@@ -231,7 +268,7 @@ class productplan extends control
$this->view->title = "PLAN #$plan->id $plan->title/" . $products[$plan->product];
$this->view->position[] = $this->lang->productplan->view;
$this->view->planStories = $this->loadModel('story')->getPlanStories($planID, 'all', $type == 'story' ? $sort : 'id_desc');
$this->view->planStories = $planStories;
$this->view->planBugs = $this->loadModel('bug')->getPlanBugs($planID, 'all', $type == 'bug' ? $sort : 'id_desc');
$this->view->products = $products;
$this->view->summary = $this->product->summary($this->view->planStories);
@@ -248,10 +285,12 @@ class productplan extends control
}
/**
* Ajax: Get product plans.
*
* @param int $productID
* Ajax: Get product plans.
*
* @param int $productID
* @param int $branch
* @param string $number
*
* @access public
* @return void
*/
@@ -264,10 +303,28 @@ class productplan extends control
die(html::select($planName, $plans, '', "class='form-control'"));
}
/**
* Sort story for productplan.
*
* @param int $planID
*
* @access public
* @return bool
*/
public function ajaxStorySort($planID = 0)
{
if(empty($planID)) return true;
$this->dao->update(TABLE_PRODUCTPLAN)->set('`order`')->eq($this->post->storys)->where('id')->eq((int)$planID)->exec();
}
/**
* Link stories.
*
* @param int $planID
* @param int $planID
* @param string $browseType
* @param int $param
* @param string $orderBy
*
* @access public
* @return void
*/
@@ -340,9 +397,10 @@ class productplan extends control
}
/**
* Unlink story
*
* @param int $storyID
* Unlink story
*
* @param int $storyID
* @param int $planID
* @param string $confirm yes|no
* @access public
* @return void
@@ -377,9 +435,11 @@ class productplan extends control
}
/**
* Batch unlink story.
*
* @param string $confirm
* Batch unlink story.
*
* @param int $planID
* @param string $orderBy
*
* @access public
* @return void
*/
@@ -391,10 +451,12 @@ class productplan extends control
/**
* Link bugs.
*
* @param int $planID
* @param string $browseType
* @param int $param
*
* @param int $planID
* @param string $browseType
* @param int $param
* @param string $orderBy
*
* @access public
* @return void
*/
@@ -469,9 +531,9 @@ class productplan extends control
}
/**
* Unlink story
*
* @param int $bugID
* Unlink story
*
* @param int $bugID
* @param string $confirm yes|no
* @access public
* @return void
@@ -506,9 +568,11 @@ class productplan extends control
}
/**
* Batch unlink story.
*
* @param string $confirm
* Batch unlink story.
*
* @param $planID
* @param string $orderBy
*
* @access public
* @return void
*/
+6 -1
View File
@@ -40,4 +40,9 @@ $('#begin').on('change', function()
{
$("#end").val('');
$("input:radio[name='delta']").attr("checked",false);
});
});
$('#end').on('change', function()
{
$("input:radio[name='delta']").attr("checked", false);
});
+16 -1
View File
@@ -41,4 +41,19 @@ $(function()
$option.toggleClass('hide', $option.text().toString().toLowerCase().indexOf(val) < 0 && $option.data('key').toString().toLowerCase().indexOf(val) < 0);
});
});
})
$('#storyList').on('sort.sortable', function(e, data)
{
var list = '';
for(i = 0; i < data.list.length; i++) list += $(data.list[i]).attr('data-id') + ',';
console.log(list);
$.post(createLink('productplan', 'ajaxStorySort', 'planID=' + planID), {'storys' : list, 'orderBy' : orderBy}, function()
{
var $target = $(data.element[0]);
$target.hide();
$target.fadeIn(1000);
order = 'order_asc';
history.pushState({}, 0, createLink('productplan', 'view', "planID=" + planID + '&type=story&orderBy=' + order));
});
});
});
+1
View File
@@ -26,6 +26,7 @@ $lang->productplan->unlinkStory = "Unlink Story";
$lang->productplan->batchUnlinkStory = "Batch Unlink";
$lang->productplan->linkedStories = 'link Story';
$lang->productplan->unlinkedStories = 'UnLinkEd';
$lang->productplan->updateOrder = 'Ranking';
$lang->productplan->linkBug = "Link Bug";
$lang->productplan->unlinkBug = "Unlink Bug";
+1
View File
@@ -26,6 +26,7 @@ $lang->productplan->unlinkStory = "移除需求";
$lang->productplan->batchUnlinkStory = "批量移除需求";
$lang->productplan->linkedStories = '需求';
$lang->productplan->unlinkedStories = '未关联需求';
$lang->productplan->updateOrder = '排序';
$lang->productplan->linkBug = "关联Bug";
$lang->productplan->unlinkBug = "移除Bug";
+41 -22
View File
@@ -11,8 +11,10 @@
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/sortable.html.php';?>
<?php js::set('confirmUnlinkStory', $lang->productplan->confirmUnlinkStory)?>
<?php js::set('confirmUnlinkBug', $lang->productplan->confirmUnlinkBug)?>
<?php js::set('planID', $plan->id);?>
<div id='titlebar'>
<div class='heading'>
<span class='prefix'><?php echo html::icon($lang->icons['plan']);?> <strong><?php echo $plan->id;?></strong></span>
@@ -30,9 +32,23 @@
{
ob_start();
echo "<div class='btn-group'>";
echo "<div class='btn-group' id='createActionMenu'>";
common::printIcon('story', 'create', "productID=$plan->product&branch=$plan->branch&moduleID=0&storyID=0&projectID=0&bugID=0&planID=$plan->id", $plan, 'button', 'plus');
if(common::hasPriv('productplan', 'linkStory')) echo html::a(inlink('view', "planID=$plan->id&type=story&orderBy=id_desc&link=true"), '<i class="icon-link"></i> ' . $lang->productplan->linkStory, '', "class='btn'");
if(common::hasPriv('productplan', 'linkBug') and $config->global->flow != 'onlyStory') echo html::a(inlink('view', "planID=$plan->id&type=bug&orderBy=id_desc&link=true"), '<i class="icon-bug"></i> ' . $lang->productplan->linkBug, '', "class='btn'");
$batchMisc = common::hasPriv('story', 'batchCreate') ? '' : "disabled";
$batchLink = common::hasPriv('story', 'batchCreate') ? $this->createLink('story', 'batchCreate', "productID=$plan->product&branch=$plan->branch&moduleID=0&story=0&project=0&plan={$plan->id}") : '#';
echo "<button type='button' class='btn dropdown-toggle {$batchMisc}' data-toggle='dropdown'><span class='caret'></span></button>";
echo "<ul class='dropdown-menu pull-right'>";
echo "<li>" . html::a($batchLink, $lang->story->batchCreate, '', "class='$batchMisc'") . "</li>";
echo '</ul>';
echo '</div>';
if(common::hasPriv('productplan', 'linkStory'))
{
echo html::a(inlink('view', "planID=$plan->id&type=story&orderBy=id_desc&link=true"), '<i class="icon-link"></i> ' . $lang->productplan->linkStory, '', "class='btn'");
}
if(common::hasPriv('productplan', 'linkBug') and $config->global->flow != 'onlyStory')
{
echo html::a(inlink('view', "planID=$plan->id&type=bug&orderBy=id_desc&link=true"), '<i class="icon-bug"></i> ' . $lang->productplan->linkBug, '', "class='btn'");
}
echo '</div>';
echo "<div class='btn-group'>";
common::printIcon('productplan', 'edit', "planID=$plan->id", $plan);
@@ -60,6 +76,7 @@
<div class='tab-content'>
<div id='stories' class='tab-pane <?php if($type == 'story') echo 'active'?>'>
<?php if(common::hasPriv('productplan', 'linkStory')):?>
<?php $canOrder = common::hasPriv('project', 'storySort');?>
<div class='action'>
<?php echo html::a("javascript:showLink($plan->id, \"story\")", '<i class="icon-link"></i> ' . $lang->productplan->linkStory, '', "class='btn btn-sm btn-primary'");?>
</div>
@@ -70,21 +87,24 @@
<?php $vars = "planID={$plan->id}&type=story&orderBy=%s&link=$link&param=$param"; ?>
<thead>
<tr>
<th class='w-id {sorter:false}' > <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
<th class='w-pri {sorter:false}'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
<?php if($modulePairs):?>
<th class='w-150px text-left {sorter:false}'> <?php common::printOrderLink('module', $orderBy, $vars, $lang->story->module);?></th>
<th class='w-id {sorter:false}' > <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
<?php if($canOrder):?>
<th class='w-50px {sorter:false}'><?php common::printOrderLink('order', $orderBy, $vars, $lang->productplan->updateOrder);?></th>
<?php endif;?>
<th class='text-left {sorter:false}'> <?php common::printOrderLink('title', $orderBy, $vars, $lang->story->title);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('assignedTo', $orderBy, $vars, $lang->assignedToAB);?></th>
<th class='w-60px {sorter:false}'> <?php common::printOrderLink('estimate', $orderBy, $vars, $lang->story->estimateAB);?></th>
<th class='w-status {sorter:false}'><?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
<th class='w-80px {sorter:false}'> <?php common::printOrderLink('stage', $orderBy, $vars, $lang->story->stageAB);?></th>
<th class='w-50px {sorter:false}'> <?php echo $lang->actions?></th>
<th class='w-pri {sorter:false}'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
<?php if($modulePairs):?>
<th class='w-150px text-left {sorter:false}'><?php common::printOrderLink('module', $orderBy, $vars, $lang->story->module);?></th>
<?php endif;?>
<th class='text-left {sorter:false}'><?php common::printOrderLink('title', $orderBy, $vars, $lang->story->title);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('assignedTo', $orderBy, $vars, $lang->assignedToAB);?></th>
<th class='w-60px {sorter:false}'> <?php common::printOrderLink('estimate', $orderBy, $vars, $lang->story->estimateAB);?></th>
<th class='w-status {sorter:false}'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
<th class='w-80px {sorter:false}'> <?php common::printOrderLink('stage', $orderBy, $vars, $lang->story->stageAB);?></th>
<th class='w-50px {sorter:false}'> <?php echo $lang->actions?></th>
</tr>
</thead>
<tbody>
<tbody class='sortable'>
<?php
$totalEstimate = 0.0;
$canBatchUnlink = common::hasPriv('productPlan', 'batchUnlinkStory');
@@ -95,17 +115,16 @@
$viewLink = $this->createLink('story', 'view', "storyID=$story->id");
$totalEstimate += $story->estimate;
?>
<tr class='text-center'>
<tr class='text-center' data-id='<?php echo $story->id;?>'>
<td class='cell-id'>
<?php if($canBatchUnlink or $canBatchChangePlan):?>
<input type='checkbox' name='storyIDList[]' value='<?php echo $story->id;?>'/>
<input type='checkbox' name='storyIDList[]' value='<?php echo $story->id;?>'/>
<?php endif;?>
<?php echo html::a($viewLink, sprintf("%03d", $story->id));?>
</td>
<?php if($canOrder):?><td class='sort-handler'><i class='icon-move'></i></td><?php endif;?>
<td><span class='<?php echo 'pri' . zget($lang->story->priList, $story->pri, $story->pri)?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri);?></span></td>
<?php if($modulePairs):?>
<td class='text-left nobr'><?php if(!empty($story->module)) echo $modulePairs[$story->module];?></td>
<?php endif;?>
<?php if($modulePairs):?><td class='text-left nobr'><?php if(!empty($story->module)) echo $modulePairs[$story->module];?></td><?php endif;?>
<td class='text-left nobr' title='<?php echo $story->title?>'><?php echo html::a($viewLink , $story->title);?></td>
<td><?php echo zget($users, $story->openedBy);?></td>
<td><?php echo zget($users, $story->assignedTo);?></td>
@@ -126,7 +145,7 @@
</tbody>
<tfoot>
<tr>
<td colspan='9'>
<td colspan='<?php echo $canOrder ? 11 : 10;?>'>
<div class='table-actions clearfix'>
<?php if(count($planStories)):?>
<?php echo html::selectButton();?>
@@ -332,7 +351,7 @@
<tr class='text-center'>
<td class='cell-id'>
<?php if($canBatchUnlink):?>
<input type='checkbox' name='unlinkBugs[]' value='<?php echo $bug->id;?>'/>
<input type='checkbox' name='unlinkBugs[]' value='<?php echo $bug->id;?>'/>
<?php endif;?>
<?php echo html::a($this->createLink('bug', 'view', "bugID=$bug->id"), sprintf("%03d", $bug->id));?>
</td>
@@ -357,7 +376,7 @@
<tr>
<td colspan='7'>
<div class='table-actions clearfix'>
<?php
<?php
if(count($planBugs) and $canBatchUnlink)
{
echo html::selectButton();
+6 -2
View File
@@ -857,6 +857,9 @@ class project extends control
/**
* Create a project.
*
* @param string $projectID
* @param string $copyProjectID
*
* @access public
* @return void
*/
@@ -1305,8 +1308,8 @@ class project extends control
public function tree($projectID, $type = '')
{
$this->project->setMenu($this->projects, $projectID);
$project = $this->loadModel('project')->getById($projectID);
$tree = $this->project->getProjectTree($projectID);
$project = $this->loadModel('project')->getById($projectID);
$tree = $this->project->getProjectTree($projectID);
/* Save to session. */
$uri = $this->app->getURI(true);
@@ -1946,6 +1949,7 @@ class project extends control
*/
public function tips($projectID)
{
$this->view->project = $this->project->getById($projectID);
$this->view->projectID = $projectID;
$this->display('project', 'tips');
}
+8 -5
View File
@@ -163,12 +163,15 @@ function loadBranch(){}
/* Auto compute the work days. */
$(function()
{
if(typeof(replaceID) != 'undefined') setModal4List('iframe', replaceID, function($list)
if(typeof(replaceID) != 'undefined')
{
$list.find('.progress-pie:visible').progressPie();
var datatable = $list.data('zui.datatable');
if(datatable) datatable.$datatable.find('.progress-pie:visible').progressPie();
});
setModal4List('iframe', replaceID, function($list)
{
$list.find('.progress-pie:visible').progressPie();
var datatable = $list.data('zui.datatable');
if(datatable) datatable.$datatable.find('.progress-pie:visible').progressPie();
});
}
$(".date").bind('dateSelected', function()
{
computeWorkDays(this.id);
+4
View File
@@ -19,6 +19,10 @@ $(function()
$("#days").val('');
$("input:radio[name='delta']").attr("checked",false);
});
$('#end').on('change', function()
{
$("input:radio[name='delta']").attr("checked", false);
})
});
function showTypeTips()
+39
View File
@@ -21,4 +21,43 @@ $(function()
$('#module' + moduleID).addClass('active');
$('#product' + productID).addClass('active');
$(document).on('click', "#storyList tbody tr", function(){showCheckedSummary();});
$(document).on('change', "#storyList :checkbox", function(){showCheckedSummary();});
});
function showCheckedSummary()
{
var $summary = $('tfoot .table-actions .text:last');
if(!$summary.hasClass('readed'))
{
taskSummary = $summary.html();
$summary.addClass('readed');
}
var checkedTotal = 0;
var checkedEstimate = 0;
var checkedCase = 0;
$('[name^="storyIDList"]').each(function()
{
if($(this).prop('checked'))
{
checkedTotal += 1;
var taskID = $(this).val();
$tr = $("#storyList tbody tr[data-id='" + taskID + "']");
checkedEstimate += Number($tr.data('estimate'));
if(Number($tr.data('cases')) > 0) checkedCase += 1;
}
});
if(checkedTotal > 0)
{
rate = Math.round(checkedCase / checkedTotal * 10000) / 100 + '' + '%';
summary = checkedSummary.replace('%total%', checkedTotal)
.replace('%estimate%', checkedEstimate)
.replace('%rate%', rate)
$('tfoot .table-actions .text:last').html(summary);
}
else
{
$('tfoot .table-actions .text:last').html(taskSummary);
}
}
+48
View File
@@ -22,6 +22,10 @@ $(function()
});
if($('#taskList thead th.w-name').width() < 150) $('#taskList thead th.w-name').width(150);
$(document).on('click', "#taskList tbody tr", function(){showCheckedSummary();});
$(document).on('change', "#taskList :checkbox", function(){showCheckedSummary();});
$(document).on('click', "#datatable-taskList table tr", function(){showCheckedSummary();});
});
function setQueryBar(queryID, title)
@@ -30,5 +34,49 @@ function setQueryBar(queryID, title)
$tagTab.before("<li id='QUERY" + queryID + "Tab' class='active'><a href='" + createLink('project', 'task', "projectID=" + projectID + "&browseType=bysearch&param=" + queryID) + "'>" + title + "</a></li>");
}
function showCheckedSummary()
{
var $summary = $('tfoot .table-actions .text:last');
if(!$summary.hasClass('readed'))
{
taskSummary = $summary.html();
$summary.addClass('readed');
}
var checkedTotal = 0;
var checkedWait = 0;
var checkedDoing = 0;
var checkedEstimate = 0;
var checkedConsumed = 0;
var checkedLeft = 0;
$('[name^="taskIDList"]').each(function()
{
if($(this).prop('checked'))
{
checkedTotal += 1;
var taskID = $(this).val();
$tr = $("#taskList tbody tr[data-id='" + taskID + "']");
if($tr.data('status') == 'wait') checkedWait += 1;
if($tr.data('status') == 'doing') checkedDoing += 1;
checkedEstimate += Number($tr.data('estimate'));
checkedConsumed += Number($tr.data('consumed'));
checkedLeft += Number($tr.data('left'));
}
});
if(checkedTotal > 0)
{
summary = checkedSummary.replace('%total%', checkedTotal).replace('%wait%', checkedWait)
.replace('%doing%', checkedDoing)
.replace('%estimate%', checkedEstimate)
.replace('%consumed%', checkedConsumed)
.replace('%left%', checkedLeft);
$('tfoot .table-actions .text:last').html(summary);
}
else
{
$('tfoot .table-actions .text:last').html(taskSummary);
}
}
$('#module' + moduleID).addClass('active');
$('#product' + productID).addClass('active');
+1
View File
@@ -180,6 +180,7 @@ $lang->project->beginAndEnd = 'Time Frame';
$lang->project->lblStats = 'Hour Report';
$lang->project->stats = '<strong>%s</strong> Hour(s) available, <strong>%s</strong> Hour(s) Estimated, <strong>%s</strong> Hour(s) Consumed, <strong>%s</strong> Hour(s) Remained.';
$lang->project->taskSummary = " <strong>%s</strong> Tasks on this page, <strong>%s</strong> Wait, <strong>%s</strong> Doing. <strong>%s</strong> Hour(s) Estimated, <strong>%s</strong> Hour(s) Consumed, <strong>%s</strong> Hour(s) Remained.";
$lang->project->checkedSummary = " <strong>%total%</strong> Checked, <strong>%wait%</strong> Wait, <strong>%doing%</strong> Doing, <strong>%estimate%</strong> Hour(s) Estimated, <strong>%consumed%</strong> Hour(s) Consumed, <strong>%left%</strong> Hour(s) Remained.";
$lang->project->memberHours = "%s has <strong>%s</strong> Hour(s) available ";
$lang->project->groupSummary = "<strong>%s</strong> Tasks in this group, Wait <strong>%s</strong>, Doing <strong>%s</strong>. <strong>%s</strong> Hour(s) Estimated , <strong>%s</strong> Hour(s) Consumed, <strong>%s</strong> Hour(s) Remained.";
$lang->project->groupSummaryAB = "Total Tasks <strong>%s</strong>, Wait <strong>%s</strong>, Doing <strong>%s</strong>.<br /> <strong>%s</strong> Hour(s) Estimated, <strong>%s</strong> Hour(s) Consumed,<strong>%s</strong> Hour(s) Remained.";
+3 -2
View File
@@ -42,7 +42,7 @@ $lang->project->progress = '进度';
$lang->project->hours = '预计 %s 消耗 %s 剩余 %s';
$lang->project->viewBug = '查看bug';
$lang->project->noProduct = "无{$lang->productCommon}{$lang->projectCommon}";
$lang->project->createStory = "新增需求";
$lang->project->createStory = "添加需求";
$lang->project->all = '所有';
$lang->project->undone = '未完成';
$lang->project->unclosed = '未关闭';
@@ -180,6 +180,7 @@ $lang->project->beginAndEnd = '起止时间';
$lang->project->lblStats = '工时统计';
$lang->project->stats = '可用工时<strong>%s</strong>工时,总共预计<strong>%s</strong>工时,已经消耗<strong>%s</strong>工时,预计剩余<strong>%s</strong>工时';
$lang->project->taskSummary = "本页共 <strong>%s</strong> 个任务,未开始 <strong>%s</strong>,进行中 <strong>%s</strong>,总预计<strong>%s</strong>工时,已消耗<strong>%s</strong>工时,剩余<strong>%s</strong>工时。";
$lang->project->checkedSummary = "选中 <strong>%total%</strong> 个任务,未开始 <strong>%wait%</strong>,进行中 <strong>%doing%</strong>,总预计<strong>%estimate%</strong>工时,已消耗<strong>%consumed%</strong>工时,剩余<strong>%left%</strong>工时。";
$lang->project->memberHours = "%s共有 <strong>%s</strong> 个可用工时,";
$lang->project->groupSummary = "本组共 <strong>%s</strong> 个任务,未开始 <strong>%s</strong>,进行中 <strong>%s</strong>,总预计<strong>%s</strong>工时,已消耗<strong>%s</strong>工时,剩余<strong>%s</strong>工时。";
$lang->project->groupSummaryAB = "总任务<strong>%s</strong> ,未开始<strong>%s</strong>,进行中<strong>%s</strong>。<br />总预计<strong>%s</strong>,已消耗<strong>%s</strong>,剩余<strong>%s</strong>。";
@@ -214,7 +215,7 @@ $lang->project->tips = '提示';
$lang->project->afterInfo = "{$lang->projectCommon}添加成功,您现在可以进行以下操作:";
$lang->project->setTeam = '设置团队';
$lang->project->linkStory = '关联需求';
$lang->project->createTask = '添加任务';
$lang->project->createTask = '创建任务';
$lang->project->goback = "返回任务列表";
$lang->project->noweekend = '去除周末';
$lang->project->withweekend = '显示周末';
+7 -5
View File
@@ -1423,13 +1423,15 @@ class projectModel extends model
* @access public
* @return void
*/
public function linkStory($projectID)
public function linkStory($projectID, $stories = array())
{
if($this->post->stories == false) return false;
if(empty($stories)) $stories = $this->post->stories;
if(empty($stories)) return false;
$this->loadModel('action');
$versions = $this->loadModel('story')->getVersions($this->post->stories);
$versions = $this->loadModel('story')->getVersions($stories);
$lastOrder = (int)$this->dao->select('*')->from(TABLE_PROJECTSTORY)->where('project')->eq($projectID)->orderBy('order_desc')->limit(1)->fetch('order');
foreach($this->post->stories as $key => $storyID)
foreach($stories as $key => $storyID)
{
$productID = (int)$this->post->products[$storyID];
$data = new stdclass();
@@ -2239,7 +2241,7 @@ class projectModel extends model
*/
public function getPrevKanban($projectID)
{
$prevKanbans = $this->loadModel('setting')->getItem("ower=null&module=project&section=kanban&key=project$projectID");
$prevKanbans = $this->loadModel('setting')->getItem("owner=null&module=project&section=kanban&key=project$projectID");
return json_decode($prevKanbans, true);
}
+18 -3
View File
@@ -27,7 +27,21 @@
common::printIcon('story', 'export', "productID=$productID&orderBy=id_desc", '', 'button', '', '', 'export');
$this->lang->story->create = $this->lang->project->createStory;
if($productID and !$this->loadModel('story')->checkForceReview()) common::printIcon('story', 'create', "productID=$productID&branch=&moduleID=0&story=0&project=$project->id");
if($productID and !$this->loadModel('story')->checkForceReview())
{
echo "<div class='btn-group' id='createActionMenu'>";
common::printIcon('story', 'create', "productID=$productID&branch=0&moduleID=0&story=0&project=$project->id");
$misc = common::hasPriv('story', 'batchCreate') ? '' : "disabled";
$link = common::hasPriv('story', 'batchCreate') ? $this->createLink('story', 'batchCreate', "productID=$productID&branch=0&moduleID=0&story=0&project=$project->id") : '#';
echo "<button type='button' class='btn dropdown-toggle {$misc}' data-toggle='dropdown'>";
echo "<span class='caret'></span>";
echo '</button>';
echo "<ul class='dropdown-menu pull-right'>";
echo "<li>" . html::a($link, $lang->story->batchCreate, '', "class='$misc'") . "</li>";
echo '</ul>';
echo '</div>';
}
if(commonModel::isTutorialMode())
{
@@ -58,7 +72,7 @@
<div class='main'>
<script>setTreeBox();</script>
<form method='post' id='projectStoryForm'>
<?php $canOrder = common::hasPriv('project', 'storySort');?>
<?php $canOrder = common::hasPriv('project', 'storySort');?>
<table class='table tablesorter table-condensed table-fixed table-selectable' id='storyList'>
<thead>
<tr class='colhead'>
@@ -91,7 +105,7 @@
$storyLink = $this->createLink('story', 'view', "storyID=$story->id&version=$story->version&from=project&param=$project->id");
$totalEstimate += $story->estimate;
?>
<tr class='text-center' id="story<?php echo $story->id;?>" data-id='<?php echo $story->id;?>' data-order='<?php echo $story->order ?>'>
<tr class='text-center' id="story<?php echo $story->id;?>" data-id='<?php echo $story->id;?>' data-order='<?php echo $story->order ?>' data-estimate='<?php echo $story->estimate?>' data-cases='<?php echo zget($storyCases, $story->id, 0)?>'>
<td class='cell-id'>
<?php if($canBatchEdit or $canBatchClose):?>
<input type='checkbox' name='storyIDList[<?php echo $story->id;?>]' value='<?php echo $story->id;?>' />
@@ -218,6 +232,7 @@
</table>
</form>
</div>
<?php js::set('checkedSummary', $lang->product->checkedSummary);?>
<?php js::set('projectID', $project->id);?>
<?php js::set('orderBy', $orderBy)?>
<?php include '../../common/view/footer.html.php';?>
+12 -4
View File
@@ -49,8 +49,15 @@ js::set('browseType', $browseType);
if($useDatatable) include '../../common/view/datatable.html.php';
$customFields = $this->datatable->getSetting('project');
$widths = $this->datatable->setFixedFieldWidth($customFields);
$columns = 0;
if($project->type == 'ops')
{
foreach($customFields as $id => $customField)
{
if($customField->id == 'story') unset($customFields[$id]);
}
}
$widths = $this->datatable->setFixedFieldWidth($customFields);
$columns = 0;
?>
<table class='table table-condensed table-hover table-striped tablesorter table-fixed <?php echo ($useDatatable ? 'datatable' : 'table-selectable');?> table-selectable' id='taskList' data-checkable='true' data-fixed-left-width='<?php echo $widths['leftWidth']?>' data-fixed-right-width='<?php echo $widths['rightWidth']?>' data-custom-menu='true' data-checkbox-name='taskIDList[]'>
<thead>
@@ -69,14 +76,14 @@ js::set('browseType', $browseType);
</thead>
<tbody>
<?php foreach($tasks as $task):?>
<tr class='text-center' data-id='<?php echo $task->id;?>'>
<tr class='text-center' data-id='<?php echo $task->id;?>' data-status='<?php echo $task->status?>' data-estimate='<?php echo $task->estimate?>' data-consumed='<?php echo $task->consumed?>' data-left='<?php echo $task->left?>'>
<?php foreach($customFields as $field) $this->task->printCell($field, $task, $users, $browseType, $branchGroups, $modulePairs, $useDatatable ? 'datatable' : 'table');?>
</tr>
<?php if(!empty($task->children)):?>
<?php foreach($task->children as $key => $child):?>
<?php $class = $key == 0 ? ' table-child-top' : '';?>
<?php $class .= ($key + 1 == count($task->children)) ? ' table-child-bottom' : '';?>
<tr class='text-center table-children<?php echo $class;?> parent-<?php echo $task->id;?>' data-id='<?php echo $child->id?>'>
<tr class='text-center table-children<?php echo $class;?> parent-<?php echo $task->id;?>' data-id='<?php echo $child->id?>' data-status='<?php echo $task->status?>' data-estimate='<?php echo $task->estimate?>' data-consumed='<?php echo $task->consumed?>' data-left='<?php echo $task->left?>'>
<?php foreach($customFields as $field) $this->task->printCell($field, $child, $users, $browseType, $branchGroups, $modulePairs, $useDatatable ? 'datatable' : 'table', true);?>
</tr>
<?php endforeach;?>
@@ -166,6 +173,7 @@ js::set('browseType', $browseType);
</table>
</form>
</div>
<?php js::set('checkedSummary', $lang->project->checkedSummary);?>
<?php js::set('replaceID', 'taskList')?>
<script>
$('#project<?php echo $projectID;?>').addClass('active')
+2
View File
@@ -28,6 +28,7 @@
foreach(customModel::getFeatureMenu('project', 'task') as $menuItem)
{
if($project->type == 'ops' && $menuItem->name == 'needconfirm') continue;
if(isset($menuItem->hidden)) continue;
$menuType = $menuItem->name;
if(strpos($menuType, 'QUERY') === 0)
@@ -73,6 +74,7 @@
foreach ($lang->project->groups as $key => $value)
{
if($key == '') continue;
if($project->type == 'ops' && $key == 'story') continue;
echo '<li' . ($key == $groupBy ? " class='active'" : '') . '>';
common::printLink('project', 'groupTask', "project=$projectID&groupBy=$key", $value);
}
+1 -1
View File
@@ -2,7 +2,7 @@
<h6><?php echo $lang->project->afterInfo;?></h6>
<div class='pdb-20'>
<?php echo html::a($this->createLink('project', 'team', "projectID=$projectID"), $lang->project->setTeam, '', "class='btn'");?>
<?php if($this->config->global->flow != 'onlyTask') echo html::a($this->createLink('project', 'linkstory', "projectID=$projectID"), $lang->project->linkStory, '', "class='btn'");?>
<?php if($this->config->global->flow != 'onlyTask' && $project->type != 'ops') echo html::a($this->createLink('project', 'linkstory', "projectID=$projectID"), $lang->project->linkStory, '', "class='btn'");?>
<?php echo html::a($this->createLink('task', 'create', "project=$projectID"), $lang->project->createTask, '', "class='btn'");?>
<?php echo html::a($this->createLink('project', 'task', "projectID=$projectID"), $lang->project->goback, '', "class='btn'");?>
</div>
+11 -4
View File
@@ -126,7 +126,7 @@ class release extends control
* @access public
* @return void
*/
public function view($releaseID, $type = 'story', $link = 'false', $param = '')
public function view($releaseID, $type = 'story', $link = 'false', $param = '', $orderBy = 'id_desc')
{
if($type == 'story') $this->session->set('storyList', $this->app->getURI(true));
if($type == 'bug' or $type == 'leftBug') $this->session->set('bugList', $this->app->getURI(true));
@@ -137,15 +137,21 @@ class release extends control
$release = $this->release->getById((int)$releaseID, true);
if(!$release) die(js::error($this->lang->notFound) . js::locate('back'));
$stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($release->stories)->andWhere('deleted')->eq(0)->fetchAll('id');
$stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($release->stories)->andWhere('deleted')->eq(0)
->beginIF($type == 'story')->orderBy($orderBy)->fi()
->fetchAll('id');
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'story');
$stages = $this->dao->select('*')->from(TABLE_STORYSTAGE)->where('story')->in($release->stories)->andWhere('branch')->eq($release->branch)->fetchPairs('story', 'stage');
foreach($stages as $storyID => $stage)$stories[$storyID]->stage = $stage;
$bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($release->bugs)->andWhere('deleted')->eq(0)->fetchAll();
$bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($release->bugs)->andWhere('deleted')->eq(0)
->beginIF($type == 'bug')->orderBy($orderBy)->fi()
->fetchAll();
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'linkedBug');
$leftBugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($release->leftBugs)->andWhere('deleted')->eq(0)->fetchAll();
$leftBugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($release->leftBugs)->andWhere('deleted')->eq(0)
->beginIF($type == 'leftBug')->orderBy($orderBy)->fi()
->fetchAll();
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'leftBugs');
$this->commonAction($release->product);
@@ -162,6 +168,7 @@ class release extends control
$this->view->type = $type;
$this->view->link = $link;
$this->view->param = $param;
$this->view->orderBy = $orderBy;
$this->view->branchName = $release->productType == 'normal' ? '' : $this->loadModel('branch')->getById($release->branch);
$this->display();
}
+4
View File
@@ -10,6 +10,10 @@
* @link http://www.zentao.net
*/
?>
<?php
$jsRoot = $this->app->getWebRoot() . "js/";
include '../../common/view/tablesorter.html.php';
?>
<div id='querybox' class='show'></div>
<?php
$releaseBugs = $type == 'bug' ? $release->bugs : $release->leftBugs;
+4
View File
@@ -10,6 +10,10 @@
* @link http://www.zentao.net
*/
?>
<?php
$jsRoot = $this->app->getWebRoot() . "js/";
include '../../common/view/tablesorter.html.php';
?>
<div id='querybox' class='show'></div>
<div id='unlinkStoryList'>
<form method='post' target='hiddenwin' id='unlinkedStoriesForm' action='<?php echo $this->createLink('release', 'linkStory', "releaseID=$release->id&browseType=$browseType&param=$param")?>'>
+26 -23
View File
@@ -82,16 +82,17 @@
<?php endif;?>
<form method='post' target='hiddenwin' action="<?php echo inLink('batchUnlinkStory', "release=$release->id");?>" id='linkedStoriesForm'>
<table class='table table-hover table-condensed table-striped tablesorter table-fixed table-selectable' id='storyList'>
<?php $vars = "releaseID={$release->id}&type=story&link=$link&param=$param&orderBy=%s";?>
<thead>
<tr>
<th class='w-id'><?php echo $lang->idAB;?></th>
<th class='w-pri'><?php echo $lang->priAB;?></th>
<th class="text-left"><?php echo $lang->story->title;?></th>
<th class='w-user'><?php echo $lang->openedByAB;?></th>
<th class='w-hour'><?php echo $lang->story->estimateAB;?></th>
<th class='w-hour'><?php echo $lang->statusAB;?></th>
<th class='w-100px'><?php echo $lang->story->stageAB;?></th>
<th class='w-50px'><?php echo $lang->actions;?></th>
<th class='w-id {sorter:false}'> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
<th class='w-pri {sorter:false}'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
<th class="text-left {sorter:false}"><?php common::printOrderLink('title', $orderBy, $vars, $lang->story->title);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='w-hour {sorter:false}'> <?php common::printOrderLink('estimate', $orderBy, $vars, $lang->story->estimateAB);?></th>
<th class='w-hour {sorter:false}'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
<th class='w-100px {sorter:false}'> <?php common::printOrderLink('stage', $orderBy, $vars, $lang->story->stageAB);?></th>
<th class='w-50px {sorter:false}'> <?php echo $lang->actions?></th>
</tr>
</thead>
<?php $canBatchUnlink = common::hasPriv('release', 'batchUnlinkStory');?>
@@ -141,16 +142,17 @@
<?php endif;?>
<form method='post' target='hiddenwin' action="<?php echo inLink('batchUnlinkBug', "releaseID=$release->id");?>" id='linkedBugsForm'>
<table class='table table-hover table-condensed table-striped tablesorter table-fixed table-selectable' id='bugList'>
<?php $vars = "releaseID={$release->id}&type=bug&link=$link&param=$param&orderBy=%s";?>
<thead>
<tr>
<th class='w-id'><?php echo $lang->idAB;?></th>
<th><?php echo $lang->bug->title;?></th>
<th class='w-100px'><?php echo $lang->bug->status;?></th>
<th class='w-user'><?php echo $lang->openedByAB;?></th>
<th class='w-date'><?php echo $lang->bug->openedDateAB;?></th>
<th class='w-user'><?php echo $lang->bug->resolvedByAB;?></th>
<th class='w-100px'><?php echo $lang->bug->resolvedDateAB;?></th>
<th class='w-50px'><?php echo $lang->actions;?></th>
<th class='w-id {sorter:false}'> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
<th class='text-left {sorter:false}'><?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
<th class='w-100px {sorter:false}'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='w-date {sorter:false}'> <?php common::printOrderLink('openedDate', $orderBy, $vars, $lang->bug->openedDateAB);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('resolvedBy', $orderBy, $vars, $lang->bug->resolvedByAB);?></th>
<th class='w-100px {sorter:false}'> <?php common::printOrderLink('resolvedDate', $orderBy, $vars, $lang->bug->resolvedDateAB);?></th>
<th class='w-50px {sorter:false}'> <?php echo $lang->actions;?></th>
</tr>
</thead>
<?php $canBatchUnlink = common::hasPriv('release', 'batchUnlinkBug');?>
@@ -200,15 +202,16 @@
<?php endif;?>
<form method='post' target='hiddenwin' action="<?php echo inLink('batchUnlinkBug', "releaseID=$release->id&type=leftBug");?>" id='linkedBugsForm'>
<table class='table table-hover table-condensed table-striped tablesorter table-fixed table-selectable' id='leftBugList'>
<?php $vars = "releaseID={$release->id}&type=leftBug&link=$link&param=$param&orderBy=%s";?>
<thead>
<tr>
<th class='w-id'><?php echo $lang->idAB;?></th>
<th class='w-severity'><?php echo $lang->bug->severityAB;?></th>
<th><?php echo $lang->bug->title;?></th>
<th class='w-100px'><?php echo $lang->bug->status;?></th>
<th class='w-user'><?php echo $lang->openedByAB;?></th>
<th class='w-150px'><?php echo $lang->bug->openedDateAB;?></th>
<th class='w-50px'><?php echo $lang->actions;?></th>
<th class='w-id {sorter:false}'> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
<th class='w-severity {sorter:false}'><?php common::printOrderLink('severity', $orderBy, $vars, $lang->bug->severityAB);?></th>
<th class='text-left {sorter:false}'> <?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
<th class='w-100px {sorter:false}'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
<th class='w-user {sorter:false}'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='w-150px {sorter:false}'> <?php common::printOrderLink('openedDate', $orderBy, $vars, $lang->bug->openedDateAB);?></th>
<th class='w-50px {sorter:false}'> <?php echo $lang->actions;?></th>
</tr>
</thead>
<?php $canBatchUnlink = common::hasPriv('release', 'batchUnlinkBug');?>
+19 -18
View File
@@ -56,11 +56,11 @@ include '../../common/view/chosen.html.php';
.outer > #querybox {margin: -20px -20px 20px; border-top: none; border-bottom: 1px solid #ddd}
#searchform input.date::-webkit-input-placeholder{color: #000000; opacity: 1;}
#searchform input.date::-moz-placeholder{color: #000000; opacity: 1;}
#searchform input.date::-moz-placeholder{color: #000000; opacity: 1;}
#searchform input.date:-ms-input-placeholder{color: #000000; opacity: 1;}
</style>
<script language='Javascript'>
var dtOptions =
var dtOptions =
{
language: '<?php echo $this->app->getClientLang();?>',
weekStart: 1,
@@ -97,8 +97,8 @@ var actionURL = '<?php echo $actionURL;?>';
/**
* Set date field
*
* @param string $query
*
* @param string $query
* @return void
*/
function setDateField(query, fieldNO)
@@ -160,9 +160,9 @@ function setDateField(query, fieldNO)
/**
* When the value of the fields select changed, set the operator and value of the new field.
*
* @param string $obj
* @param int $fieldNO
*
* @param string $obj
* @param int $fieldNO
* @access public
* @return void
*/
@@ -177,7 +177,7 @@ function setField(obj, fieldNO, moduleparams)
if(typeof(params[fieldName]['class']) != undefined && params[fieldName]['class'] == 'date')
{
setDateField($(obj).closest('form').find("#value" + fieldNO), fieldNO);
$(obj).closest('form').find("#value" + fieldNO).addClass('date'); // Shortcut the width of the datepicker to make sure align with others.
$(obj).closest('form').find("#value" + fieldNO).addClass('date'); // Shortcut the width of the datepicker to make sure align with others.
var groupItems = <?php echo $config->search->groupItems?>;
var maxNO = 2 * groupItems;
var nextNO = fieldNO > groupItems ? fieldNO - groupItems + 1 : fieldNO + groupItems;
@@ -207,7 +207,7 @@ function setField(obj, fieldNO, moduleparams)
/**
* Reset forms.
*
*
* @access public
* @return void
*/
@@ -216,12 +216,13 @@ function resetForm(obj)
for(i = 1; i <= groupItems * 2; i ++)
{
$(obj).closest('form').find('#value' + i).val('').trigger('chosen:updated');
$(obj).closest('form').find('#dateValue' + i).val('').attr('placeholder','');
}
}
/**
* Show more fields.
*
*
* @access public
* @return void
*/
@@ -241,7 +242,7 @@ function showmore(obj)
/**
* Show lite search form.
*
*
* @access public
* @return void
*/
@@ -261,8 +262,8 @@ function showlite(obj)
/**
* loadQueries.
*
* @param queryID $queryID
*
* @param queryID $queryID
* @access public
* @return void
*/
@@ -273,8 +274,8 @@ function loadQueries(queryID)
/**
* Execute a query.
*
* @param int $queryID
*
* @param int $queryID
* @access public
* @return void
*/
@@ -286,7 +287,7 @@ function executeQuery(queryID)
/**
* Delete a query.
*
*
* @access public
* @return void
*/
@@ -383,7 +384,7 @@ foreach($fieldParams as $fieldName => $param)
/* Print value. */
echo "<td id='valueBox$fieldNO' style='overflow:visible'>";
if($param['control'] == 'select') echo html::select("value$fieldNO", $param['values'], $formSession["value$fieldNO"], "class='form-control searchSelect chosen'");
if($param['control'] == 'input')
if($param['control'] == 'input')
{
$fieldName = $formSession["field$fieldNO"];
$fieldValue = $formSession["value$fieldNO"];
@@ -467,7 +468,7 @@ foreach($fieldParams as $fieldName => $param)
?>
</table>
</td>
<td class='<?php echo $style == 'simple' ? 'w-80px' : 'w-160px';?>'>
<td class='<?php echo $style == 'simple' ? 'w-80px' : 'w-160px';?>'>
<?php
echo html::hidden('module', $module);
echo html::hidden('actionURL', $actionURL);
+1 -1
View File
@@ -13,7 +13,7 @@ $config->story->edit = new stdclass();
$config->story->change = new stdclass();
$config->story->close = new stdclass();
$config->story->review = new stdclass();
$config->story->create->requiredFields = 'title';
$config->story->create->requiredFields = 'title,module';
$config->story->change->requiredFields = 'title';
$config->story->close->requiredFields = 'closedReason';
$config->story->review->requiredFields = 'assignedTo,reviewedBy';
+10 -3
View File
@@ -102,6 +102,7 @@ class story extends control
$users = $this->user->getPairs('pdfirst|noclosed|nodeleted');
$moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch);
if(empty($moduleOptionMenu)) die(js::locate(helper::createLink('tree', 'browse', "productID=$productID&view=story")));
/* Set menu. */
$this->product->setMenu($products, $product->id, $branch);
@@ -194,22 +195,28 @@ class story extends control
* Create a batch stories.
*
* @param int $productID
* @param int $branch
* @param int $moduleID
* @param int $storyID
* @param int $project
* @param int $plan
* @access public
* @return void
*/
public function batchCreate($productID = 0, $branch = 0, $moduleID = 0, $storyID = 0)
public function batchCreate($productID = 0, $branch = 0, $moduleID = 0, $storyID = 0, $project = 0, $plan = 0)
{
if(!empty($_POST))
{
$mails = $this->story->batchCreate($productID, $branch);
if(dao::isError()) die(js::error(dao::getError()));
$stories = array();
foreach($mails as $mail)
{
$stories[] = $mail->storyID;
if($mail->actionID) $this->story->sendmail($mail->storyID, $mail->actionID);
}
if($project) $this->loadModel('project')->linkStory($project, $stories);
/* If storyID not equal zero, subdivide this story to child stories and close it. */
if($storyID)
@@ -236,7 +243,7 @@ class story extends control
$this->product->setMenu($products, $product->id, $branch);
/* Init vars. */
$planID = 0;
$planID = $plan;
$pri = 0;
$estimate = '';
$title = '';
@@ -672,7 +679,7 @@ class story extends control
$this->story->review($storyID);
if(dao::isError()) die(js::error(dao::getError()));
$result = $this->post->result;
if($this->post->closedReason != '' and strpos('done,postponed,subdivided', $this->post->closedReason) === false) $result = 'pass';
if($this->post->closedReason != '' and strpos('done,postponed,subdivided,willnotdo', $this->post->closedReason) === false) $result = 'pass';
$actionID = $this->action->create('story', $storyID, 'Reviewed', $this->post->comment, ucfirst($result));
$this->story->sendmail($storyID, $actionID);
if($this->post->result == 'reject')
+1 -1
View File
@@ -73,7 +73,7 @@ $lang->story->lastEditedBy = 'Last Edited By';
$lang->story->lastEditedDate = 'Last Edited On';
$lang->story->closedBy = 'Closed By';
$lang->story->closedDate = 'Closed On';
$lang->story->closedReason = 'Close Reason';
$lang->story->closedReason = 'Reason';
$lang->story->rejectedReason = 'Reject Reason';
$lang->story->reviewedBy = 'Reviewer';
$lang->story->reviewedDate = 'Review on';
+190 -185
View File
@@ -15,9 +15,9 @@ class storyModel extends model
{
/**
* Get a story by id.
*
* @param int $storyID
* @param int $version
*
* @param int $storyID
* @param int $version
* @param bool $setImgSize
* @access public
* @return object|bool
@@ -67,8 +67,8 @@ class storyModel extends model
/**
* Get stories by idList.
*
* @param int|array|string $storyIDList
*
* @param int|array|string $storyIDList
* @access public
* @return array
*/
@@ -84,8 +84,8 @@ class storyModel extends model
/**
* Get story specs.
*
* @param array $storyIdList
*
* @param array $storyIdList
* @access public
* @return array
*/
@@ -98,9 +98,9 @@ class storyModel extends model
}
/**
* Get affected things.
*
* @param object $story
* Get affected things.
*
* @param object $story
* @access public
* @return object
*/
@@ -135,7 +135,7 @@ class storyModel extends model
/**
* Create a story.
*
*
* @access public
* @return int|bool the id of the created story or false when error.
*/
@@ -184,7 +184,7 @@ class storyModel extends model
$data->verify = $story->verify;
$this->dao->insert(TABLE_STORYSPEC)->data($data)->exec();
if($projectID != 0 and $story->status != 'draft')
if($projectID != 0 and $story->status != 'draft')
{
$lastOrder = (int)$this->dao->select('*')->from(TABLE_PROJECTSTORY)->where('project')->eq($projectID)->orderBy('order_desc')->limit(1)->fetch('order');
$this->dao->insert(TABLE_PROJECTSTORY)
@@ -209,7 +209,7 @@ class storyModel extends model
$bug->assignedTo = 'closed';
$bug->assignedDate = $now;
$this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec();
$this->loadModel('action')->create('bug', $bugID, 'ToStory', '', $storyID);
$this->action->create('bug', $bugID, 'Closed');
@@ -218,13 +218,13 @@ class storyModel extends model
->where('objectType')->eq('bug')
->andWhere('objectID')->eq($bugID)
->fetchAll();
if(!empty($files))
{
if(!empty($files))
{
foreach($files as $file)
{
$file->objectType = 'story';
$file->objectID = $storyID;
unset($file->id);
$file->objectID = $storyID;
unset($file->id);
$this->dao->insert(TABLE_FILE)->data($file)->exec();
}
}
@@ -238,7 +238,7 @@ class storyModel extends model
/**
* Create a batch stories.
*
*
* @access public
* @return int|bool the id of the created story or false when error.
*/
@@ -258,6 +258,7 @@ class storyModel extends model
$plan = 0;
$pri = 0;
$source = '';
for($i = 0; $i < $batchNum; $i++)
{
$module = $stories->module[$i] == 'ditto' ? $module : $stories->module[$i];
@@ -268,6 +269,8 @@ class storyModel extends model
$stories->plan[$i] = $plan;
$stories->pri[$i] = (int)$pri;
$stories->source[$i] = $source;
if(!empty($stories->title[$i]) && empty($stories->module[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->story->module)));
}
if(isset($stories->uploadImage)) $this->loadModel('file');
@@ -296,7 +299,7 @@ class storyModel extends model
$this->dao->insert(TABLE_STORY)->data($data)->autoCheck()
->batchCheck($this->config->story->create->requiredFields, 'notempty')
->exec();
if(dao::isError())
if(dao::isError())
{
echo js::error(dao::getError());
die(js::reload('parent'));
@@ -324,8 +327,8 @@ class storyModel extends model
if(rename($realPath, $this->file->savePath . $this->file->getSaveName($file['pathname'])))
{
$file['addedBy'] = $this->app->user->account;
$file['addedDate'] = $now;
$file['addedBy'] = $this->app->user->account;
$file['addedDate'] = $now;
$file['objectType'] = 'story';
$file['objectID'] = $storyID;
if(in_array($file['extension'], $this->config->file->imageExtensions))
@@ -356,7 +359,7 @@ class storyModel extends model
/* Remove upload image file and session. */
if(!empty($stories->uploadImage) and $this->session->storyImagesFile)
{
$classFile = $this->app->loadClass('zfile');
$classFile = $this->app->loadClass('zfile');
$file = current($_SESSION['storyImagesFile']);
$realPath = dirname($file['realpath']);
if(is_dir($realPath)) $classFile->removeDir($realPath);
@@ -368,8 +371,8 @@ class storyModel extends model
/**
* Change a story.
*
* @param int $storyID
*
* @param int $storyID
* @access public
* @return array the change of the story.
*/
@@ -444,8 +447,8 @@ class storyModel extends model
/**
* Update a story.
*
* @param int $storyID
*
* @param int $storyID
* @access public
* @return array the changes of the story.
*/
@@ -476,7 +479,7 @@ class storyModel extends model
->join('mailto', ',')
->remove('linkStories,childStories,files,labels,comment')
->get();
if(is_array($story->plan)) $story->plan = trim(join(',', $story->plan), ',');
if(isset($story->plan) and is_array($story->plan)) $story->plan = trim(join(',', $story->plan), ',');
if(empty($_POST['product'])) $story->branch = $oldStory->branch;
$this->dao->update(TABLE_STORY)
@@ -510,7 +513,7 @@ class storyModel extends model
/**
* Batch update stories.
*
*
* @access public
* @return array.
*/
@@ -536,9 +539,9 @@ class storyModel extends model
if($data->modules[$storyID] == 'ditto') $data->modules[$storyID] = isset($prev['module']) ? $prev['module'] : 0;
if($data->plans[$storyID] == 'ditto') $data->plans[$storyID] = isset($prev['plan']) ? $prev['plan'] : 0;
if($data->sources[$storyID] == 'ditto') $data->sources[$storyID] = isset($prev['source']) ? $prev['source'] : '';
if(isset($data->stages[$storyID]) and ($data->stages[$storyID] == 'ditto')) $data->stages[$storyID] = isset($prev['stage']) ? $prev['stage'] : '';
if(isset($data->closedBys[$storyID]) and ($data->closedBys[$storyID] == 'ditto')) $data->closedBys[$storyID] = isset($prev['closedBy']) ? $prev['closedBy'] : '';
if(isset($data->closedReasons[$storyID]) and ($data->closedReasons[$storyID] == 'ditto')) $data->closedReasons[$storyID] = isset($prev['closedReason']) ? $prev['closedReason'] : '';
if(isset($data->stages[$storyID]) and ($data->stages[$storyID] == 'ditto')) $data->stages[$storyID] = isset($prev['stage']) ? $prev['stage'] : '';
if(isset($data->closedBys[$storyID]) and ($data->closedBys[$storyID] == 'ditto')) $data->closedBys[$storyID] = isset($prev['closedBy']) ? $prev['closedBy'] : '';
if(isset($data->closedReasons[$storyID]) and ($data->closedReasons[$storyID] == 'ditto')) $data->closedReasons[$storyID] = isset($prev['closedReason']) ? $prev['closedReason'] : '';
$prev['pri'] = $data->pris[$storyID];
$prev['branch'] = isset($data->branches[$storyID]) ? $data->branches[$storyID] : 0;
@@ -608,7 +611,7 @@ class storyModel extends model
$this->dao->insert(TABLE_STORYSPEC)->data($data)->exec();
}
if(!dao::isError())
if(!dao::isError())
{
if($story->closedReason == 'done') $this->loadModel('score')->create('story', 'close');
$allChanges[$storyID] = common::createChanges($oldStory, $story);
@@ -625,8 +628,8 @@ class storyModel extends model
/**
* Review a story.
*
* @param int $storyID
*
* @param int $storyID
* @access public
* @return bool
*/
@@ -686,8 +689,8 @@ class storyModel extends model
/**
* Batch review stories.
*
* @param array $storyIDList
*
* @param array $storyIDList
* @access public
* @return array
*/
@@ -730,10 +733,10 @@ class storyModel extends model
}
/**
* Subdivide story
*
* @param int $storyID
* @param array $stories
* Subdivide story
*
* @param int $storyID
* @param array $stories
* @access public
* @return int
*/
@@ -773,8 +776,8 @@ class storyModel extends model
/**
* Close a story.
*
* @param int $storyID
*
* @param int $storyID
* @access public
* @return bool
*/
@@ -795,7 +798,7 @@ class storyModel extends model
->add('closedBy', $this->app->user->account)
->add('assignedTo', 'closed')
->add('assignedDate', $now)
->add('status', 'closed')
->add('status', 'closed')
->removeIF($this->post->closedReason != 'duplicate', 'duplicateStory')
->removeIF($this->post->closedReason != 'subdivided', 'childStories')
->setIF($this->post->closedReason == 'done', 'stage', 'released')
@@ -814,7 +817,7 @@ class storyModel extends model
/**
* Batch close story.
*
*
* @access public
* @return void
*/
@@ -864,7 +867,7 @@ class storyModel extends model
->checkIF($story->closedReason == 'duplicate', 'duplicateStory', 'notempty')
->where('id')->eq($storyID)->exec();
if(!dao::isError())
if(!dao::isError())
{
$allChanges[$storyID] = common::createChanges($oldStory, $story);
}
@@ -909,11 +912,11 @@ class storyModel extends model
/**
* Batch change the plan of story.
*
* @param array $storyIDList
* @param int $planID
*
* @param array $storyIDList
* @param int $planID
* @access public
* @return array
* @return array
*/
public function batchChangePlan($storyIDList, $planID, $oldPlanID = 0)
{
@@ -949,9 +952,9 @@ class storyModel extends model
/**
* Batch change branch.
*
* @param array $storyIDList
* @param int $branchID
*
* @param array $storyIDList
* @param int $branchID
* @access public
* @return void
*/
@@ -977,8 +980,10 @@ class storyModel extends model
/**
* Batch change the stage of story.
*
* @param string $stage
*
* @param $storyIDList
* @param $stage
*
* @access public
* @return array
*/
@@ -1008,7 +1013,7 @@ class storyModel extends model
/**
* Batch assign to.
*
*
* @access public
* @return array
*/
@@ -1038,8 +1043,8 @@ class storyModel extends model
/**
* Activate a story.
*
* @param int $storyID
*
* @param int $storyID
* @access public
* @return bool
*/
@@ -1066,8 +1071,8 @@ class storyModel extends model
/**
* Set stage of a story.
*
* @param int $storyID
*
* @param int $storyID
* @access public
* @return bool
*/
@@ -1159,11 +1164,11 @@ class storyModel extends model
}
/**
* Judge stage according to the devel and test tasks' status.
*
* Judge stage according to the devel and test tasks' status.
*
* 1. one doing devel task, all test tasks waiting, set stage as developing.
* 2. all devel tasks done, all test tasks waiting, set stage as developed.
* 3. one test task doing, set stage as testing.
* 3. one test task doing, set stage as testing.
* 4. all test tasks done, still some devel tasks not done(wait, doing), set stage as testing.
* 5. all test tasks done, all devel tasks done, set stage as tested.
*/
@@ -1172,7 +1177,7 @@ class storyModel extends model
$stage = 'projected';
$testTasks = isset($branchTestTasks[$branch]) ? $branchTestTasks[$branch] : 0;
$develTasks = isset($branchDevelTasks[$branch]) ? $branchDevelTasks[$branch] : 0;
if($statusList['devel']['doing'] > 0 and $statusList['test']['wait'] == $testTasks) $stage = 'developing';
if($statusList['devel']['doing'] > 0 and $statusList['test']['wait'] == $testTasks) $stage = 'developing';
if($statusList['devel']['done'] == $develTasks and $develTasks > 0 and $statusList['test']['wait'] == $testTasks) $stage = 'developed';
if($statusList['test']['doing'] > 0) $stage = 'testing';
if(($statusList['devel']['wait'] > 0 or $statusList['devel']['doing'] > 0) and $statusList['test']['done'] == $testTasks and $testTasks > 0) $stage = 'testing';
@@ -1302,7 +1307,7 @@ class storyModel extends model
/**
* Get stories list of a product.
*
*
* @param int $productID
* @param array|string $moduleIdList
* @param string $status
@@ -1334,12 +1339,12 @@ class storyModel extends model
/**
* Get stories pairs of a product.
*
* @param int $productID
* @param array|string $moduleIdList
* @param string $status
* @param string $order
* @param int $limit
*
* @param int $productID
* @param array|string $moduleIdList
* @param string $status
* @param string $order
* @param int $limit
* @access public
* @return array
*/
@@ -1362,11 +1367,11 @@ class storyModel extends model
/**
* Get stories by assignedTo.
*
* @param int $productID
* @param string $account
* @param string $orderBy
* @param object $pager
*
* @param int $productID
* @param string $account
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
@@ -1377,11 +1382,11 @@ class storyModel extends model
/**
* Get stories by openedBy.
*
* @param int $productID
* @param string $account
* @param string $orderBy
* @param object $pager
*
* @param int $productID
* @param string $account
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
@@ -1392,11 +1397,11 @@ class storyModel extends model
/**
* Get stories by reviewedBy.
*
* @param int $productID
* @param string $account
* @param string $orderBy
* @param object $pager
*
* @param int $productID
* @param string $account
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
@@ -1407,11 +1412,11 @@ class storyModel extends model
/**
* Get stories by closedBy.
*
* @param int $productID
* @param string $account
* @param string $orderBy
* @param object $pager
*
* @param int $productID
* @param string $account
* @param string $orderBy
* @param object $pager
* @return array
*/
public function getByClosedBy($productID, $branch, $modules, $account, $orderBy, $pager)
@@ -1421,11 +1426,11 @@ class storyModel extends model
/**
* Get stories by status.
*
* @param int $productID
* @param string $orderBy
* @param object $pager
* @param string $status
*
* @param int $productID
* @param string $orderBy
* @param object $pager
* @param string $status
* @access public
* @return array
*/
@@ -1453,12 +1458,12 @@ class storyModel extends model
/**
* Get stories by a field.
*
* @param int $productID
* @param string $fieldName
* @param mixed $fieldValue
* @param string $orderBy
* @param object $pager
*
* @param int $productID
* @param string $fieldName
* @param mixed $fieldValue
* @param string $orderBy
* @param object $pager
* @param string $operator equal|include
* @access public
* @return array
@@ -1481,10 +1486,10 @@ class storyModel extends model
/**
* Get to be closed stories.
*
* @param int $productID
* @param string $orderBy
* @param string $pager
*
* @param int $productID
* @param string $orderBy
* @param string $pager
* @access public
* @return array
*/
@@ -1519,7 +1524,7 @@ class storyModel extends model
{
if($projectID != '')
{
$products = $this->loadModel('project')->getProducts($projectID);
$products = $this->loadModel('project')->getProducts($projectID);
}
else
{
@@ -1549,7 +1554,7 @@ class storyModel extends model
foreach($products as $product) $branches[$product->branch] = $product->branch;
unset($branches[0]);
$branches = join(',', $branches);
if($branches) $storyQuery .= " AND `branch`" . helper::dbIN("0,$branches");
if($branches) $storyQuery .= " AND `branch`" . helper::dbIN("0,$branches");
if($this->app->moduleName == 'release' or $this->app->moduleName == 'build')
{
$storyQuery .= " AND `status` NOT IN ('draft')";// Fix bug #990.
@@ -1572,11 +1577,11 @@ class storyModel extends model
/**
* Get stories by a sql.
*
* @param int $productID
* @param string $sql
* @param string $orderBy
* @param object $pager
*
* @param int $productID
* @param string $sql
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
@@ -1611,12 +1616,12 @@ class storyModel extends model
}
return $stories;
}
/**
* Get stories list of a project.
*
* @param int $projectID
* @param string $orderBy
*
* @param int $projectID
* @param string $orderBy
* @access public
* @return array
*/
@@ -1693,9 +1698,9 @@ class storyModel extends model
/**
* Get stories pairs of a project.
*
* @param int $projectID
* @param int $productID
*
* @param int $projectID
* @param int $productID
* @param array|string $moduleIdList
* @param string $type
* @access public
@@ -1763,11 +1768,11 @@ class storyModel extends model
/**
* Get stories of a user.
*
* @param string $account
* @param string $type the query type
* @param string $orderBy
* @param object $pager
*
* @param string $account
* @param string $type the query type
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
@@ -1785,19 +1790,19 @@ class storyModel extends model
->orderBy($orderBy)
->page($pager)
->fetchAll();
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'story');
$productIdList = array();
foreach($stories as $story) $productIdList[$story->product] = $story->product;
return $this->mergePlanTitle($productIdList, $stories);
}
/**
* Get story pairs of a user.
*
* @param string $account
* @param string $limit
*
* @param string $account
* @param string $limit
* @access public
* @return array
*/
@@ -1811,11 +1816,11 @@ class storyModel extends model
->limit($limit)
->fetchAll();
}
/**
* Get doing projects' members of a story.
*
* @param int $storyID
*
* @param int $storyID
* @access public
* @return array
*/
@@ -1832,8 +1837,8 @@ class storyModel extends model
/**
* Get version of a story.
*
* @param int $storyID
*
* @param int $storyID
* @access public
* @return int
*/
@@ -1844,7 +1849,7 @@ class storyModel extends model
/**
* Get versions of some stories.
*
*
* @param array|string story id list
* @access public
* @return array
@@ -1856,8 +1861,8 @@ class storyModel extends model
/**
* Get zero case.
*
* @param int $productID
*
* @param int $productID
* @access public
* @return array
*/
@@ -1876,8 +1881,8 @@ class storyModel extends model
/**
* Batch get story stage.
*
* @param array $stories
*
* @param array $stories
* @access public
* @return array
*/
@@ -1890,8 +1895,8 @@ class storyModel extends model
/**
* Check need confirm.
*
* @param array $dataList
*
* @param array $dataList
* @access public
* @return array
*/
@@ -1919,9 +1924,9 @@ class storyModel extends model
}
/**
* Format stories
*
* @param array $stories
* Format stories
*
* @param array $stories
* @param string $type
* @param int $limit
* @access public
@@ -1960,8 +1965,8 @@ class storyModel extends model
/**
* Extract accounts from some stories.
*
* @param array $stories
*
* @param array $stories
* @access public
* @return array
*/
@@ -1980,8 +1985,8 @@ class storyModel extends model
/**
* Extract accounts from a story.
*
* @param object $story
*
* @param object $story
* @access public
* @return array
*/
@@ -1997,8 +2002,8 @@ class storyModel extends model
/**
* Merge the default chart settings and the settings of current chart.
*
* @param string $chartType
*
* @param string $chartType
* @access public
* @return void
*/
@@ -2016,7 +2021,7 @@ class storyModel extends model
}
/**
* Get report data of storys per product
* Get report data of storys per product
*
* @access public
* @return array
@@ -2070,7 +2075,7 @@ class storyModel extends model
}
/**
* Get report data of storys per source
* Get report data of storys per source
*
* @access public
* @return array
@@ -2087,8 +2092,8 @@ class storyModel extends model
}
/**
* Get report data of storys per plan
*
* Get report data of storys per plan
*
* @access public
* @return array
*/
@@ -2104,8 +2109,8 @@ class storyModel extends model
}
/**
* Get report data of storys per status
*
* Get report data of storys per status
*
* @access public
* @return array
*/
@@ -2120,8 +2125,8 @@ class storyModel extends model
}
/**
* Get report data of storys per stage
*
* Get report data of storys per stage
*
* @access public
* @return array
*/
@@ -2136,8 +2141,8 @@ class storyModel extends model
}
/**
* Get report data of storys per pri
*
* Get report data of storys per pri
*
* @access public
* @return array
*/
@@ -2152,8 +2157,8 @@ class storyModel extends model
}
/**
* Get report data of storys per estimate
*
* Get report data of storys per estimate
*
* @access public
* @return array
*/
@@ -2165,8 +2170,8 @@ class storyModel extends model
}
/**
* Get report data of storys per openedBy
*
* Get report data of storys per openedBy
*
* @access public
* @return array
*/
@@ -2182,8 +2187,8 @@ class storyModel extends model
}
/**
* Get report data of storys per assignedTo
*
* Get report data of storys per assignedTo
*
* @access public
* @return array
*/
@@ -2199,8 +2204,8 @@ class storyModel extends model
}
/**
* Get report data of storys per closedReason
*
* Get report data of storys per closedReason
*
* @access public
* @return array
*/
@@ -2215,8 +2220,8 @@ class storyModel extends model
}
/**
* Get report data of storys per change
*
* Get report data of storys per change
*
* @access public
* @return array
*/
@@ -2228,9 +2233,9 @@ class storyModel extends model
}
/**
* Get kanban group data.
*
* @param array $stories
* Get kanban group data.
*
* @param array $stories
* @access public
* @return array
*/
@@ -2244,9 +2249,9 @@ class storyModel extends model
/**
* Adjust the action clickable.
*
* @param object $story
* @param string $action
*
* @param object $story
* @param string $action
* @access public
* @return void
*/
@@ -2264,9 +2269,9 @@ class storyModel extends model
/**
* Merge plan title.
*
* @param int|array $productID
* @param array $stories
*
* @param int|array $productID
* @param array $stories
* @access public
* @return array
*/
@@ -2455,7 +2460,7 @@ class storyModel extends model
/**
* Set report condition.
*
*
* @access public
* @return string
*/
@@ -2475,7 +2480,7 @@ class storyModel extends model
/**
* Check force review for user.
*
*
* @access public
* @return bool
*/
@@ -2488,10 +2493,10 @@ class storyModel extends model
}
/**
* Send mail
*
* @param int $storyID
* @param int $actionID
* Send mail
*
* @param int $storyID
* @param int $actionID
* @access public
* @return void
*/
+3 -3
View File
@@ -40,7 +40,7 @@ if($this->story->checkForceReview()) unset($visibleFields['review']);
<tr class='text-center'>
<th class='w-30px'><?php echo $lang->idAB;?></th>
<th class='w-120px<?php echo zget($visibleFields, $product->type, ' hidden')?>'><?php echo $lang->product->branch;?></th>
<th class='w-p15<?php echo zget($visibleFields, 'module', ' hidden')?>'><?php echo $lang->story->module;?></th>
<th class='w-p15<?php echo zget($visibleFields, 'module', ' hidden')?>'><?php echo $lang->story->module;?> <span class='required'></span></th>
<th class='w-p15<?php echo zget($visibleFields, 'plan', ' hidden')?>'><?php echo $lang->story->plan;?></th>
<th <?php if(count($visibleFields) >= 9) echo "class='w-150px'"?>><?php echo $lang->story->title;?> <span class='required'></span></th>
<th class='w-p15<?php echo zget($visibleFields, 'spec', ' hidden')?>'><?php echo $lang->story->spec;?></th>
@@ -56,7 +56,7 @@ if($this->story->checkForceReview()) unset($visibleFields['review']);
<?php if(!empty($titles)):?>
<?php foreach($titles as $storyTitle => $fileName):?>
<?php $moduleID = $i == 0 ? $moduleID : 'ditto';?>
<?php $planID = $i == 0 ? '' : 'ditto';?>
<?php $planID = $i == 0 ? $planID : 'ditto';?>
<?php $pri = $i == 0 ? '' : 'ditto';?>
<?php $source = $i == 0 ? '' : 'ditto';?>
<tr class='text-center'>
@@ -88,7 +88,7 @@ if($this->story->checkForceReview()) unset($visibleFields['review']);
<?php $nextStart = $i;?>
<?php for($i = $nextStart; $i < $config->story->batchCreate; $i++):?>
<?php $moduleID = $i - $nextStart == 0 ? $moduleID : 'ditto';?>
<?php $planID = $i - $nextStart == 0 ? '' : 'ditto';?>
<?php $planID = $i - $nextStart == 0 ? $planID : 'ditto';?>
<?php $pri = $i - $nextStart == 0 ? '' : 'ditto';?>
<?php $source = $i - $nextStart == 0 ? '' : 'ditto';?>
<tr class='text-center'>
+1 -1
View File
@@ -116,7 +116,7 @@
</div>
<fieldset id='commentBox' class='hide'>
<legend><?php echo $lang->comment;?></legend>
<form method='post' action='<?php echo inlink('edit', "storyID=$story->id")?>'>
<form method='post' action='<?php echo $this->createLink('action', 'comment', "objectType=story&objectID=$story->id")?>' target='hiddenwin'>
<div class="form-group"><?php echo html::textarea('comment', '',"rows='5' class='w-p100'");?></div>
<?php echo html::submitButton() . html::backButton();?>
</form>
+4
View File
@@ -32,7 +32,9 @@ class svn extends control
*/
public function diff($url, $revision)
{
if(isset($_GET['repoUrl'])) $url = $this->get->repoUrl;
$url = helper::safe64Decode($url);
$this->view->url = $url;
$this->view->revision = $revision;
$this->view->diff = $this->svn->diff($url, $revision);
@@ -50,7 +52,9 @@ class svn extends control
*/
public function cat($url, $revision)
{
if(isset($_GET['repoUrl'])) $url = $this->get->repoUrl;
$url = helper::safe64Decode($url);
$this->view->url = $url;
$this->view->revision = $revision;
$this->view->code = $this->svn->cat($url, $revision);
+20 -3
View File
@@ -611,9 +611,8 @@ class svnModel extends model
{
foreach($actionFiles as $file)
{
$param = array('url' => helper::safe64Encode($repoRoot . $file), 'revision' => $log->revision);
$catLink = trim(html::a(helper::createLink('svn', 'cat', $param, 'html'), 'view', '', "class='repolink'"));
$diffLink = trim(html::a(helper::createLink('svn', 'diff', $param, 'html'), 'diff', '', "class='repolink'"));
$catLink = trim(html::a($this->buildURL('cat', $repoRoot . $file, $log->revision), 'view', '', "class='repolink'"));
$diffLink = trim(html::a($this->buildURL('diff', $repoRoot . $file, $log->revision), 'diff', '', "class='repolink'"));
$diff .= $action . " " . $file . " $catLink ";
$diff .= $action == 'M' ? "$diffLink\n" : "\n" ;
}
@@ -715,4 +714,22 @@ class svnModel extends model
{
echo helper::now() . " $log\n";
}
/**
* Build URL.
*
* @param string $methodName
* @param string $url
* @param int $revision
* @access public
* @return string
*/
public function buildURL($methodName, $url, $revision)
{
$buildedURL = helper::createLink('svn', $methodName, "url=&revision=$revision", 'html');
$buildedURL .= strpos($buildedURL, '?') === false ? '?' : '&';
$buildedURL .= 'repoUrl=' . helper::safe64Encode($url);
return $buildedURL;
}
}
+1 -1
View File
@@ -11,7 +11,7 @@
*/
?>
<?php include '../../common/view/header.lite.html.php';?>
<?php $catLink = inlink('cat', 'url=' . helper::safe64Encode($url) . "&revision=$revision");?>
<?php $catLink = $this->svn->buildURL('cat', $url, $revision);?>
<div class='box-title'><?php echo html::a($catLink, "$url@$revision");?></div>
<div class='box-content'><xmp><?php echo $diff;?></xmp></div>
<?php include '../../common/view/footer.lite.html.php';?>
+9 -4
View File
@@ -152,6 +152,8 @@ class task extends control
/* Set Custom*/
foreach(explode(',', $this->config->task->customCreateFields) as $field) $customFields[$field] = $this->lang->task->$field;
if($project->type == 'ops') unset($customFields['story']);
$this->view->customFields = $customFields;
$this->view->showFields = $this->config->task->custom->createFields;
@@ -1172,14 +1174,17 @@ class task extends control
*/
public function export($projectID, $orderBy)
{
$project = $this->project->getById($projectID);
$allExportFields = $this->config->task->exportFields;
if($project->type == 'ops') $allExportFields = str_replace(' story,', '', $allExportFields);
if($_POST)
{
$this->loadModel('file');
$taskLang = $this->lang->task;
$taskConfig = $this->config->task;
$taskLang = $this->lang->task;
/* Create field lists. */
$fields = $this->post->exportFields ? $this->post->exportFields : explode(',', $taskConfig->exportFields);
$fields = $this->post->exportFields ? $this->post->exportFields : explode(',', $allExportFields);
foreach($fields as $key => $fieldName)
{
$fieldName = trim($fieldName);
@@ -1286,7 +1291,7 @@ class task extends control
$this->fetch('file', 'export2' . $this->post->fileType, $_POST);
}
$this->view->allExportFields = $this->config->task->exportFields;
$this->view->allExportFields = $allExportFields;
$this->view->customExport = true;
$this->display();
}
+1 -1
View File
@@ -16,7 +16,7 @@
<div class='heading'>
<span class='prefix'><?php echo html::icon($lang->icons['task']);?></span>
<strong><small class='text-muted'><?php echo html::icon($lang->icons['batchCreate']);?></small> <?php echo $lang->task->batchCreate;?></strong>
<span><small><a href='javascript:toggleZeroTaskStory();' id='zeroTaskStory'><?php echo $lang->story->zeroTask;?><i class='icon icon-remove'></i></a></small></span>
<?php if($project->type != 'ops'):?><span><small><a href='javascript:toggleZeroTaskStory();' id='zeroTaskStory'><?php echo $lang->story->zeroTask;?><i class='icon icon-remove'></i></a></small></span><?php endif;?>
<div class='actions'>
<?php echo html::commonButton($lang->pasteText, "data-toggle='myModal'", 'btn btn-primary')?>
<button type="button" class="btn btn-default" data-toggle="customModal"><i class='icon icon-cog'></i> </button>
+1 -1
View File
@@ -156,7 +156,7 @@
<div class='actions'> <?php if(!$task->deleted) echo $actionLinks;?></div>
<fieldset id='commentBox' class='hide'>
<legend><?php echo $lang->comment;?></legend>
<form method='post' action='<?php echo inlink('edit', "taskID=$task->id&comment=true")?>'>
<form method='post' action='<?php echo $this->createLink('action', 'comment', "objectType=task&objectID=$task->id")?>' target='hiddenwin'>
<div class="form-group"><?php echo html::textarea('comment', '',"rows='5' class='w-p100'");?></div>
<?php echo html::submitButton() . html::backButton();?>
</form>
+137 -111
View File
@@ -15,7 +15,7 @@ class testcase extends control
/**
* Construct function, load product, tree, user auto.
*
*
* @access public
* @return void
*/
@@ -31,7 +31,7 @@ class testcase extends control
/**
* Index page.
*
*
* @access public
* @return void
*/
@@ -61,8 +61,8 @@ class testcase extends control
$browseType = strtolower($browseType);
/* Set browseType, productID, moduleID and queryID. */
$productID = $this->product->saveState($productID, $this->products);
$branch = ($branch === '') ? (int)$this->cookie->preBranch : (int)$branch;
$productID = $this->product->saveState($productID, $this->products);
$branch = ($branch === '') ? (int)$this->cookie->preBranch : (int)$branch;
setcookie('preProductID', $productID, $this->config->cookieLife, $this->config->webRoot);
setcookie('preBranch', (int)$branch, $this->config->cookieLife, $this->config->webRoot);
@@ -75,9 +75,9 @@ class testcase extends control
if($browseType == 'bysuite') setcookie('caseSuite', (int)$param, $this->config->cookieLife, $this->config->webRoot);
if($browseType != 'bymodule') $this->session->set('caseBrowseType', $browseType);
$moduleID = ($browseType == 'bymodule') ? (int)$param : ($browseType == 'bysearch' ? 0 : ($this->cookie->caseModule ? $this->cookie->caseModule : 0));
$suiteID = ($browseType == 'bysuite') ? (int)$param : ($browseType == 'bymodule' ? ($this->cookie->caseSuite ? $this->cookie->caseSuite : 0) : 0);
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
$moduleID = ($browseType == 'bymodule') ? (int)$param : ($browseType == 'bysearch' ? 0 : ($this->cookie->caseModule ? $this->cookie->caseModule : 0));
$suiteID = ($browseType == 'bysuite') ? (int)$param : ($browseType == 'bymodule' ? ($this->cookie->caseSuite ? $this->cookie->caseSuite : 0) : 0);
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
/* Set menu, save session. */
$this->testcase->setMenu($this->products, $productID, $branch, $moduleID, $suiteID);
@@ -93,7 +93,7 @@ class testcase extends control
/* Load pager. */
$this->app->loadClass('pager', $static = true);
$pager = pager::init($recTotal, $recPerPage, $pageID);
$sort = $this->loadModel('common')->appendOrder($orderBy);
$sort = $this->loadModel('common')->appendOrder($orderBy);
/* Get test cases. */
$cases = $this->testcase->getTestCases($productID, $branch, $browseType, $browseType == 'bysearch' ? $queryID : $suiteID, $moduleID, $sort, $pager);
@@ -141,9 +141,9 @@ class testcase extends control
/**
* Group case.
*
* @param int $productID
* @param string $groupBy
*
* @param int $productID
* @param string $groupBy
* @access public
* @return void
*/
@@ -173,21 +173,21 @@ class testcase extends control
}
}
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->common;
$this->view->position[] = html::a($this->createLink('testcase', 'groupTask', "productID=$productID&groupBy=$groupBy"), $this->products[$productID]);
$this->view->position[] = $this->lang->testcase->common;
$this->view->productID = $productID;
$this->view->productName = $this->products[$productID];
$this->view->users = $this->user->getPairs('noletter');
$this->view->browseType = 'group';
$this->view->groupBy = $groupBy;
$this->view->orderBy = $groupBy;
$this->view->groupByList = $groupByList;
$this->view->cases = $groupCases;
$this->view->suiteList = $this->loadModel('testsuite')->getSuites($productID);
$this->view->suiteID = 0;
$this->view->moduleID = 0;
$this->view->branch = $branch;
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->common;
$this->view->position[] = html::a($this->createLink('testcase', 'groupTask', "productID=$productID&groupBy=$groupBy"), $this->products[$productID]);
$this->view->position[] = $this->lang->testcase->common;
$this->view->productID = $productID;
$this->view->productName = $this->products[$productID];
$this->view->users = $this->user->getPairs('noletter');
$this->view->browseType = 'group';
$this->view->groupBy = $groupBy;
$this->view->orderBy = $groupBy;
$this->view->groupByList = $groupByList;
$this->view->cases = $groupCases;
$this->view->suiteList = $this->loadModel('testsuite')->getSuites($productID);
$this->view->suiteID = 0;
$this->view->moduleID = 0;
$this->view->branch = $branch;
$this->display();
}
@@ -286,13 +286,13 @@ class testcase extends control
/* If bugID large than 0, use this bug as template. */
if($bugID > 0)
{
$bug = $this->loadModel('bug')->getById($bugID);
$type = $bug->type;
$pri = $bug->pri ? $bug->pri : $bug->severity;
$storyID = $bug->story;
$caseTitle= $bug->title;
$keywords = $bug->keywords;
$steps = $this->testcase->createStepsFromBug($bug->steps);
$bug = $this->loadModel('bug')->getById($bugID);
$type = $bug->type;
$pri = $bug->pri ? $bug->pri : $bug->severity;
$storyID = $bug->story;
$caseTitle = $bug->title;
$keywords = $bug->keywords;
$steps = $this->testcase->createStepsFromBug($bug->steps);
}
/* Padding the steps to the default steps count. */
@@ -428,9 +428,9 @@ class testcase extends control
/**
* Create bug.
*
* @param int $productID
* @param string $extras
*
* @param int $productID
* @param string $extras
* @access public
* @return void
*/
@@ -453,20 +453,20 @@ class testcase extends control
if(!$case) die(js::error($this->lang->notFound) . js::locate('back', 'parent'));
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->createBug;
$this->view->runID = $runID;
$this->view->case = $case;
$this->view->caseID = $caseID;
$this->view->version = $version;
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->createBug;
$this->view->runID = $runID;
$this->view->case = $case;
$this->view->caseID = $caseID;
$this->view->version = $version;
$this->display();
}
/**
* View a test case.
*
* @param int $caseID
* @param int $version
* @param string $from
*
* @param int $caseID
* @param int $version
* @param string $from
* @access public
* @return void
*/
@@ -527,8 +527,8 @@ class testcase extends control
/**
* Edit a case.
*
* @param int $caseID
*
* @param int $caseID
* @access public
* @return void
*/
@@ -586,9 +586,9 @@ class testcase extends control
}
else
{
$productID = $case->product;
$title = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->edit;
$position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]);
$productID = $case->product;
$title = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->edit;
$position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]);
/* Set menu. */
$this->testcase->setMenu($this->products, $productID, $case->branch);
@@ -615,21 +615,21 @@ class testcase extends control
$position[] = $this->lang->testcase->common;
$position[] = $this->lang->testcase->edit;
$this->view->title = $title;
$this->view->position = $position;
$this->view->currentModuleID = $case->module;
$this->view->users = $this->user->getPairs('noletter');
$this->view->case = $case;
$this->view->actions = $this->loadModel('action')->getList('case', $caseID);
$this->view->isLibCase = $isLibCase;
$this->view->title = $title;
$this->view->position = $position;
$this->view->currentModuleID = $case->module;
$this->view->users = $this->user->getPairs('noletter');
$this->view->case = $case;
$this->view->actions = $this->loadModel('action')->getList('case', $caseID);
$this->view->isLibCase = $isLibCase;
$this->display();
}
/**
* Batch edit case.
*
* @param int $productID
*
* @param int $productID
* @access public
* @return void
*/
@@ -728,7 +728,8 @@ class testcase extends control
if($showSuhosinInfo) $this->view->suhosinInfo = extension_loaded('suhosin') ? sprintf($this->lang->suhosinInfo, $countInputVars) : sprintf($this->lang->maxVarsInfo, $countInputVars);
$this->loadModel('story');
$this->view->stories = $this->story->getProductStoryPairs($productID, $branch);
$stories = $this->story->getProductStoryPairs($productID, $branch);
$this->view->stories = array('' => '', 'ditto' => $this->lang->testcase->ditto) + $stories;
/* Set custom. */
foreach(explode(',', $this->config->testcase->customBatchEditFields) as $field) $customFields[$field] = $this->lang->testcase->$field;
@@ -750,8 +751,8 @@ class testcase extends control
/**
* Review case.
*
* @param int $caseID
*
* @param int $caseID
* @access public
* @return void
*/
@@ -761,7 +762,7 @@ class testcase extends control
{
$this->testcase->review($caseID);
if(dao::isError()) die(js::error(dao::getError()));
$result = $this->post->result;
$result = $this->post->result;
$this->loadModel('action')->create('case', $caseID, 'Reviewed', $this->post->comment, ucfirst($result));
die(js::reload('parent.parent'));
}
@@ -774,8 +775,8 @@ class testcase extends control
/**
* Batch review case.
*
* @param string $result
*
* @param string $result
* @access public
* @return void
*/
@@ -791,8 +792,8 @@ class testcase extends control
/**
* Delete a test case
*
* @param int $caseID
*
* @param int $caseID
* @param string $confirm yes|noe
* @access public
* @return void
@@ -828,8 +829,8 @@ class testcase extends control
/**
* Batch delete cases.
*
* @param int $productID
*
* @param int $productID
* @access public
* @return void
*/
@@ -842,6 +843,33 @@ class testcase extends control
die(js::locate($this->session->caseList));
}
/**
* Batch change branch.
*
* @param int $branchID
* @access public
* @return void
*/
public function batchChangeBranch($branchID)
{
if($this->post->caseIDList)
{
$caseIDList = $this->post->caseIDList;
$caseIDList = array_unique($caseIDList);
unset($_POST['caseIDList']);
$allChanges = $this->testcase->batchChangeBranch($caseIDList, $branchID);
if(dao::isError()) die(js::error(dao::getError()));
foreach($allChanges as $caseID => $changes)
{
$this->loadModel('action');
$actionID = $this->action->create('case', $caseID, 'Edited');
$this->action->logHistory($actionID, $changes);
}
}
die(js::locate($this->session->caseList, 'parent'));
}
/**
* Batch change the module of case.
*
@@ -871,8 +899,8 @@ class testcase extends control
/**
* Batch review case.
*
* @param string $result
*
* @param string $result
* @access public
* @return void
*/
@@ -973,9 +1001,9 @@ class testcase extends control
}
/**
* Confirm testcase changed.
*
* @param int $caseID
* Confirm testcase changed.
*
* @param int $caseID
* @access public
* @return void
*/
@@ -988,8 +1016,8 @@ class testcase extends control
/**
* Confirm story changes.
*
* @param int $caseID
*
* @param int $caseID
* @access public
* @return void
*/
@@ -1003,8 +1031,8 @@ class testcase extends control
/**
* Batch ctory change cases.
*
* @param int $productID
*
* @param int $productID
* @access public
* @return void
*/
@@ -1018,11 +1046,11 @@ class testcase extends control
}
/**
* export
*
* @param int $productID
* @param string $orderBy
* @param int $taskID
* export
*
* @param int $productID
* @param string $orderBy
* @param int $taskID
* @access public
* @return void
*/
@@ -1090,8 +1118,6 @@ class testcase extends control
foreach($cases as $case)
{
$case->title = htmlspecialchars_decode($case->title);
$relatedModuleIdList[$case->module] = $case->module;
$relatedStoryIdList[$case->story] = $case->story;
$relatedCaseIdList[$case->linkCase] = $case->linkCase;
@@ -1134,8 +1160,8 @@ class testcase extends control
}
if($step->version != $case->version) continue;
$sign = (in_array($this->post->fileType, array('html', 'xml'))) ? '<br />' : "\n";
$case->stepDesc .= $stepId . ". " . htmlspecialchars_decode($step->desc) . $sign;
$case->stepExpect .= $stepId . ". " . htmlspecialchars_decode($step->expect) . $sign;
$case->stepDesc .= $stepId . ". " . $step->desc . $sign;
$case->stepExpect .= $stepId . ". " . $step->expect . $sign;
$childId ++;
}
}
@@ -1196,9 +1222,9 @@ class testcase extends control
}
/**
* Export templet
*
* @param int $productID
* Export templet
*
* @param int $productID
* @access public
* @return void
*/
@@ -1220,8 +1246,8 @@ class testcase extends control
$fields['stage'] = $this->lang->testcase->stage;
$fields[''] = '';
$fields['typeValue'] = $this->lang->testcase->lblTypeValue;
$fields['stageValue'] = $this->lang->testcase->lblStageValue;
$fields['typeValue'] = $this->lang->testcase->lblTypeValue;
$fields['stageValue'] = $this->lang->testcase->lblStageValue;
if($product->type != 'normal') $fields['branchValue'] = $this->lang->product->branchName[$product->type];
$branches = $this->loadModel('branch')->getPairs($productID);
@@ -1257,9 +1283,9 @@ class testcase extends control
}
/**
* Import csv
*
* @param int $productID
* Import csv
*
* @param int $productID
* @access public
* @return void
*/
@@ -1324,14 +1350,14 @@ class testcase extends control
/**
* Import case from lib.
*
* @param int $productID
* @param int $branch
* @param int $libID
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
*
* @param int $productID
* @param int $branch
* @param int $libID
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
@@ -1395,8 +1421,8 @@ class testcase extends control
/**
* Show import data
*
* @param int $productID
*
* @param int $productID
* @access public
* @return void
*/
@@ -1419,7 +1445,7 @@ class testcase extends control
$fields = array_flip($fields);
$rows = $this->loadModel('file')->parseCSV($file);
$header = array();
$header = array();
foreach($rows[0] as $i => $rowValue)
{
if(empty($rowValue)) break;
@@ -1451,7 +1477,7 @@ class testcase extends control
{
$id = trim(substr($cellValue, strrpos($cellValue,'(#') + 2), ')');
$case->$field = $id;
}
}
}
elseif(in_array($field, $caseConfig->export->listFields))
{
@@ -1568,10 +1594,10 @@ class testcase extends control
/**
* Case bugs.
*
* @param int $runID
* @param int $caseID
* @param int $version
*
* @param int $runID
* @param int $caseID
* @param int $version
* @access public
* @return void
*/
+36 -2
View File
@@ -541,13 +541,15 @@ class testcaseModel extends model
else
{
/* Compare every step. */
$i = 0;
foreach($oldCase->steps as $key => $oldStep)
{
if(trim($oldStep->desc) != trim($steps[$key]['desc']) or trim($oldStep->expect) != $steps[$key]['expect'])
if(trim($oldStep->desc) != trim($steps[$i]['desc']) or trim($oldStep->expect) != $steps[$i]['expect'])
{
$stepChanged = true;
break;
}
$i++;
}
}
$version = $stepChanged ? $oldCase->version + 1 : $oldCase->version;
@@ -762,13 +764,15 @@ class testcaseModel extends model
if($data->pris[$caseID] == 'ditto') $data->pris[$caseID] = isset($prev['pri']) ? $prev['pri'] : 3;
if($data->branches[$caseID] == 'ditto') $data->branches[$caseID] = isset($prev['branch']) ? $prev['branch'] : 0;
if($data->modules[$caseID] == 'ditto') $data->modules[$caseID] = isset($prev['module']) ? $prev['module'] : 0;
if($data->stories[$caseID] == 'ditto') $data->stories[$caseID] = isset($prev['story']) ? $prev['story'] : 0;
if($data->types[$caseID] == 'ditto') $data->types[$caseID] = isset($prev['type']) ? $prev['type'] : '';
if($data->stories[$caseID] == '') $data->stories[$caseID] = 0;
$prev['pri'] = $data->pris[$caseID];
$prev['type'] = $data->types[$caseID];
$prev['story'] = $data->stories[$caseID];
$prev['branch'] = $data->branches[$caseID];
$prev['module'] = $data->modules[$caseID];
$prev['type'] = $data->types[$caseID];
}
/* Initialize cases from the post data.*/
@@ -817,6 +821,36 @@ class testcaseModel extends model
return $allChanges;
}
/**
* Batch change branch.
*
* @param array $caseIDList
* @param int $branchID
* @access public
* @return array
*/
public function batchChangeBranch($caseIDList, $branchID)
{
$now = helper::now();
$allChanges = array();
$oldCases = $this->getByList($caseIDList);
foreach($caseIDList as $caseID)
{
$oldCase = $oldCases[$caseID];
if($branchID == $oldCase->branch) continue;
$case = new stdclass();
$case->lastEditedBy = $this->app->user->account;
$case->lastEditedDate = $now;
$case->branch = $branchID;
$this->dao->update(TABLE_CASE)->data($case)->autoCheck()->where('id')->eq((int)$caseID)->exec();
if(!dao::isError()) $allChanges[$caseID] = common::createChanges($oldCase, $case);
}
return $allChanges;
}
/**
* Batch change the module of case.
*
+17
View File
@@ -128,6 +128,23 @@ js::set('branch', $branch);
$misc = common::hasPriv('testtask', 'batchRun') ? "onclick=\"setFormAction('$actionLink')\"" : $class;
echo "<li>" . html::a('#', $lang->testtask->runCase, '', $misc) . "</li>";
if(common::hasPriv('testcase', 'batchChangeBranch') and $this->session->currentProductType != 'normal')
{
$withSearch = count($branches) > 8;
echo "<li class='dropdown-submenu'>";
echo html::a('javascript:;', $lang->product->branchName[$this->session->currentProductType], '', "id='branchItem'");
echo "<div class='dropdown-menu" . ($withSearch ? ' with-search':'') . "'>";
echo "<ul class='dropdown-list'>";
foreach($branches as $branchID => $branchName)
{
$actionLink = $this->createLink('testcase', 'batchChangeBranch', "branchID=$branchID");
echo "<li class='option' data-key='$branchID'>" . html::a('#', $branchName, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin')\"") . "</li>";
}
echo '</ul>';
if($withSearch) echo "<div class='menu-search'><div class='input-group input-group-sm'><input type='text' class='form-control' placeholder=''><span class='input-group-addon'><i class='icon-search'></i></span></div></div>";
echo '</div></li>';
}
if(common::hasPriv('testcase', 'batchChangeModule'))
{
$withSearch = count($modules) > 8;
+1 -1
View File
@@ -119,7 +119,7 @@
<div class='actions'><?php echo $actionLinks;?></div>
<fieldset id='commentBox' class='hide'>
<legend><?php echo $lang->comment;?></legend>
<form method='post' action='<?php echo inlink('edit', "caseID=$case->id&comment=true")?>'>
<form method='post' action='<?php echo $this->createLink('action', 'comment', "objectType=case&objectID=$case->id")?>' target='hiddenwin'>
<div class="form-group"><?php echo html::textarea('comment', '',"rows='5' class='w-p100'");?></div>
<?php echo html::submitButton() . html::backButton();?>
</form>
+1 -1
View File
@@ -112,7 +112,7 @@ class treeModel extends model
ksort($treeMenu);
$topMenu = @array_shift($treeMenu);
$topMenu = explode("\n", trim($topMenu));
$lastMenu[] = '/';
$lastMenu[] = in_array($type, array('bug', 'story')) ? '' : '/';
foreach($topMenu as $menu)
{
if(!strpos($menu, '|')) continue;
+1 -1
View File
@@ -182,7 +182,7 @@ $(function()
{
linkTemplate: '<?php echo helper::createLink('tree', 'browse', "rootID=$rootID&viewType=$viewType&moduleID={0}&branch={1}"); ?>',
title: '<?php echo $viewType == 'line' ? '': $lang->tree->child ?>',
template: '<a href="javascript:;"><?php echo $viewType == 'line' ? '': $lang->tree->child?></a>'
template: '<a href="javascript:;"><?php echo $viewType == 'line' ? '': (strpos($viewType, 'doc') !== false ? $lang->doc->childType : $lang->tree->child)?></a>'
}
},
action: function(event)
+1 -1
View File
@@ -39,7 +39,7 @@ $lang->tutorial->tasks['createAccount']['nav'] = array('module' => 'user', 'met
$lang->tutorial->tasks['createAccount']['desc'] = "<p>在系统创建一个新的用户帐号:</p><ul><li data-target='nav'>打开 <span class='task-nav'>组织 <i class='icon icon-angle-right'></i> 用户 <i class='icon icon-angle-right'></i> 添加用户</span> 页面;</li><li data-target='form'>在添加用户表单中填写新用户信息;</li><li data-target='submit'>保存用户信息。</li></ul>";
$lang->tutorial->tasks['createProduct'] = array('title' => '创建产品');
$lang->tutorial->tasks['createProduct']['nav'] = array('module' => 'product', 'method' => 'create', 'menu' => 'create', 'form' => '#dataform', 'submit' => '#submit', 'targetPageName' => '新增产品');
$lang->tutorial->tasks['createProduct']['nav'] = array('module' => 'product', 'method' => 'create', 'menu' => 'create', 'form' => '#dataform', 'submit' => '#submit', 'targetPageName' => '添加产品');
$lang->tutorial->tasks['createProduct']['desc'] = "<p>在系统创建一个新的产品:</p><ul><li data-target='nav'>打开 <span class='task-nav'>产品 <i class='icon icon-angle-right'></i> 添加产品</span> 页面;</li><li data-target='form'>在表单中填写要创建的产品信息;</li><li data-target='submit'>保存产品信息。</li></ul>";
$lang->tutorial->tasks['createStory'] = array('title' => '创建需求');
+37
View File
@@ -1901,4 +1901,41 @@ class upgradeModel extends model
return true;
}
/**
* Change limited name.
*
* @access public
* @return bool
*/
public function changeLimitedName()
{
$this->app->loadLang('install');
$this->dao->update(TABLE_GROUP)->set('name')->eq($this->lang->install->groupList['LIMITED']['name'])
->set('desc')->eq($this->lang->install->groupList['LIMITED']['desc'])
->where('role')->eq('limited')
->exec();
return true;
}
/**
* Adjust Priv for 9.7
*
* @access public
* @return bool
*/
public function adjustPriv9_7()
{
$groups = $this->dao->select('*')->from(TABLE_GROUPPRIV)->where('method')->eq('edit')->andWhere('module')->in('story,task,bug,testcase')->fetchPairs('group', 'group');
foreach($groups as $groupID)
{
$groupPriv = new stdclass();
$groupPriv->group = $groupID;
$groupPriv->module = 'action';
$groupPriv->method = 'comment';
$this->dao->replace(TABLE_GROUPPRIV)->data($groupPriv)->exec();
}
return true;
}
}

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