Merge branch 'master' of https://gitlab.zcorp.cc/easycorp/zentaopms into tanghucheng_task

This commit is contained in:
tanghucheng
2022-08-10 08:26:32 +08:00
954 changed files with 4113 additions and 2010 deletions
+10
View File
@@ -3191,9 +3191,19 @@ class bugModel extends model
$class .= ' c-user';
$title = "title='" . zget($users, $bug->resolvedBy) . "'";
break;
case 'openedBy':
$class .= ' c-user';
$title = "title='" . zget($users, $bug->openedBy) . "'";
break;
case 'project':
$title = "title='" . zget($projectPairs, $bug->project, '') . "'";
break;
case 'plan':
$title = "title='" . zget($plans, $bug->plan) . "'";
break;
case 'execution':
$title = "title='" . zget($executions, $bug->execution) . "'";
break;
case 'resolvedBuild':
$class .= ' text-ellipsis';
$title = "title='" . $bug->resolvedBuild . "'";
+1 -1
View File
@@ -320,7 +320,7 @@ $lang->execution->menu->task = array('link' => "{$lang->task->common}|execut
$lang->execution->menu->kanban = array('link' => "$lang->executionKanban|execution|taskkanban|executionID=%s");
$lang->execution->menu->burn = array('link' => "$lang->burn|execution|burn|executionID=%s");
$lang->execution->menu->view = array('link' => "$lang->view|execution|grouptask|executionID=%s", 'alias' => 'grouptask,tree,taskeffort,gantt,calendar,relation,maintainrelation');
$lang->execution->menu->story = array('link' => "$lang->SRCommon|execution|story|executionID=%s", 'subModule' => 'story', 'alias' => 'batchcreate,linkstory,storykanban');
$lang->execution->menu->story = array('link' => "$lang->SRCommon|execution|story|executionID=%s", 'subModule' => 'story', 'alias' => 'batchcreate,linkstory,storykanban,batchtotask');
$lang->execution->menu->qa = array('link' => "{$lang->qa->common}|execution|bug|executionID=%s", 'subModule' => 'bug,testcase,testtask,testreport', 'alias' => 'qa,bug,testcase,testtask,testreport');
$lang->execution->menu->devops = array('link' => "{$lang->repo->common}|repo|browse|repoID=0&branchID=&objectID=%s", 'subModule' => 'repo');
$lang->execution->menu->doc = array('link' => "{$lang->doc->common}|doc|tableContents|type=execution&objectID=%s", 'subModule' => 'doc');
+3 -3
View File
@@ -188,14 +188,14 @@ $config->execution->datatable->fieldList['id']['fixed'] = 'left';
$config->execution->datatable->fieldList['id']['width'] = '70';
$config->execution->datatable->fieldList['id']['required'] = 'yes';
$config->execution->datatable->fieldList['name']['title'] = 'name';
$config->execution->datatable->fieldList['name']['title'] = 'execName';
$config->execution->datatable->fieldList['name']['fixed'] = 'left';
$config->execution->datatable->fieldList['name']['width'] = 'auto';
$config->execution->datatable->fieldList['name']['required'] = 'yes';
if(!isset($config->setCode) or $config->setCode == 1)
{
$config->execution->datatable->fieldList['code']['title'] = 'code';
$config->execution->datatable->fieldList['code']['title'] = 'execCode';
$config->execution->datatable->fieldList['code']['fixed'] = 'no';
$config->execution->datatable->fieldList['code']['width'] = '95';
$config->execution->datatable->fieldList['code']['required'] = 'no';
@@ -211,7 +211,7 @@ $config->execution->datatable->fieldList['PM']['fixed'] = 'no';
$config->execution->datatable->fieldList['PM']['width'] = '70';
$config->execution->datatable->fieldList['PM']['required'] = 'no';
$config->execution->datatable->fieldList['status']['title'] = 'status';
$config->execution->datatable->fieldList['status']['title'] = 'execStatus';
$config->execution->datatable->fieldList['status']['fixed'] = 'no';
$config->execution->datatable->fieldList['status']['width'] = '100';
$config->execution->datatable->fieldList['status']['required'] = 'no';
+7 -4
View File
@@ -1058,7 +1058,7 @@ class execution extends control
$this->view->builds = $this->build->getBuildPairs($productID);
$this->view->branchOption = $branchOption;
$this->view->branchTagOption = $branchTagOption;
$this->view->plans = $this->loadModel('productplan')->getPairs($productID);
$this->view->plans = $this->loadModel('productplan')->getPairs($productID ? $productID : array_keys($products));
$this->view->stories = $storyList;
$this->view->tasks = $taskList;
$this->view->projectPairs = $this->loadModel('project')->getPairsByProgram();
@@ -1384,6 +1384,9 @@ class execution extends control
$this->loadModel('kanban');
$this->app->loadClass('date');
$minDate = !helper::isZeroDate($execution->openedDate) ? $execution->openedDate : $execution->begin;
$maxDate = !helper::isZeroDate($execution->closedDate) ? $execution->closedDate : helper::today();
if(!empty($_POST))
{
$begin = htmlspecialchars($this->post->begin, ENT_QUOTES);
@@ -1424,6 +1427,8 @@ class execution extends control
$this->view->chartData = $chartData;
$this->view->begin = $begin;
$this->view->end = $end;
$this->view->minDate = $minDate;
$this->view->maxDate = $maxDate;
$this->display();
}
@@ -2290,9 +2295,7 @@ class execution extends control
{
$this->app->loadClass('date');
$begin = date('Y-m-d', strtotime('-13 days'));
$begin = (helper::isZeroDate($execution->begin) or helper::diffDate($begin, $execution->begin) > 0) ? $begin : $execution->begin;
$end = helper::today();
list($begin, $end) = $this->execution->getBeginEnd4CFD($execution);
$dateList = date::getDateList($begin, $end, 'Y-m-d', 'noweekend');
$chartData = $this->execution->buildCFDData($executionID, $dateList, 'task');
if(isset($chartData['line'])) $chartData['line'] = array_reverse($chartData['line']);
+1
View File
@@ -28,6 +28,7 @@ td.flex span.project-type-label {min-width: 40px;}
.has-child > span {margin-right: 5px;}
.c-name > .text-ellipsis {text-overflow: clip;}
.c-code, .c-project {overflow: hidden; white-space: nowrap;}
th.c-status {text-align: center}
.c-project{text-overflow: unset !important;}
canvas {height: 28px;}
+2 -2
View File
@@ -137,7 +137,7 @@ $(function()
location.href = createLink('execution', 'cfd', 'executionID=' + executionID + '&type=' + type + '&withWeekend=' + withWeekend + '&begin=' + begin + '&end=' + end);
});
$("#end, #begin").datetimepicker('setEndDate', today);
$("#end, #begin").datetimepicker('setStartDate', executionBegin);
$("#end, #begin").datetimepicker('setEndDate', maxDate);
$("#end, #begin").datetimepicker('setStartDate', minDate);
$('.datetimepicker-days table tfoot').append('<tr><th colspan="7">' + dateRangeTip + '</th></tr>');
});
+21 -1
View File
@@ -32,7 +32,7 @@ $(function()
})
/* Get checked stories. */
$('#batchToTaskButton').on('click', function()
$(document).on('click', '#batchToTaskButton', function()
{
storyIdList = '';
linedTaskIdList = '';
@@ -53,6 +53,26 @@ $(function()
$('#submit').click(function()
{
var taskType = $('#type').val();
var hourPoint = $('#hourPointValue').val();
if(taskType.length == 0)
{
alert(typeNotEmpty);
return false;
}
if(hourPoint == 0)
{
alert(hourPointNotEmpty);
return false;
}
else if(typeof(hourPoint) != 'undefined' && (isNaN(hourPoint) || hourPoint < 0))
{
alert(hourPointNotError);
return false;
}
hourPoint = typeof(hourPoint) == 'undefined' ? 0 : hourPoint;
if(linedTaskIdList)
{
confirmStoryToTask = confirmStoryToTask.replace('%s', linedTaskIdList);
+1
View File
@@ -154,6 +154,7 @@ $lang->execution->putoff = 'Zurückstellen';
$lang->execution->suspend = 'Aussetzen';
$lang->execution->close = 'Schließen';
$lang->execution->export = 'Export';
$lang->execution->next = "Next";
$lang->execution->endList[7] = '1 Woche';
$lang->execution->endList[14] = '2 Wochen';
+1
View File
@@ -154,6 +154,7 @@ $lang->execution->putoff = 'Delay';
$lang->execution->suspend = 'Suspend';
$lang->execution->close = 'Close';
$lang->execution->export = 'Export';
$lang->execution->next = "Next";
$lang->execution->endList[7] = '1 Week';
$lang->execution->endList[14] = '2 Weeks';
+1
View File
@@ -154,6 +154,7 @@ $lang->execution->putoff = 'Ajourner';
$lang->execution->suspend = 'Suspendre';
$lang->execution->close = 'Fermer';
$lang->execution->export = 'Exporter';
$lang->execution->next = "Suivant";
$lang->execution->endList[7] = '1 Semaine';
$lang->execution->endList[14] = '2 Semaines';
+1
View File
@@ -154,6 +154,7 @@ $lang->execution->putoff = "延期";
$lang->execution->suspend = "挂起";
$lang->execution->close = "关闭";
$lang->execution->export = "导出";
$lang->execution->next = "下一步";
$lang->execution->endList[7] = '一星期';
$lang->execution->endList[14] = '两星期';
+3 -19
View File
@@ -3179,24 +3179,8 @@ class executionModel extends model
*/
public function getBeginEnd4CFD($execution)
{
$begin = $execution->begin;
$end = $execution->end;
if(helper::today() < $execution->begin)
{
$begin = helper::today();
$end = helper::today();
}
elseif((helper::today() >= $execution->begin) and (helper::today() <= $execution->end))
{
$begin = (date('Y-m-d', strtotime('-13 days')) < $execution->begin) ? $execution->begin : date('Y-m-d', strtotime('-13 days'));
$end = helper::today();
}
elseif((helper::today() > $execution->end))
{
$begin = date('Y-m-d', strtotime('-13 days', strtotime($execution->end))) > $execution->begin ? date('Y-m-d', strtotime('-13 days', strtotime($execution->end))) : $execution->begin;
$end = $execution->end;
}
$end = (!helper::isZeroDate($execution->closedDate) and date('Y-m-d', strtotime($execution->closedDate)) < helper::today()) ? date('Y-m-d', strtotime($execution->closedDate)) : helper::today();
$begin = (!helper::isZeroDate($execution->openedDate) and date('Y-m-d', strtotime($execution->openedDate)) > date('Y-m-d', strtotime('-13 days', strtotime($end)))) ? date('Y-m-d', strtotime($execution->openedDate)) : date('Y-m-d', strtotime('-13 days', strtotime($end)));
return array($begin, $end);
}
@@ -4385,7 +4369,7 @@ class executionModel extends model
}
echo empty($execution->children) ? html::a(helper::createLink('execution', 'view', "executionID=$execution->id"), $execution->name) : $execution->name;
echo '<td>' . zget($users, $execution->PM) . '</td>';
echo "<td class='status-{$execution->status}'>" . zget($this->lang->project->statusList, $execution->status) . '</td>';
echo "<td class='status-{$execution->status} text-center'>" . zget($this->lang->project->statusList, $execution->status) . '</td>';
echo '<td>' . html::ring($execution->hours->progress) . '</td>';
echo helper::isZeroDate($execution->begin) ? '<td></td>' : '<td>' . $execution->begin . '</td>';
if(!helper::isZeroDate($execution->end))
+2 -2
View File
@@ -20,8 +20,8 @@
<?php js::set('YUnit', $lang->execution->count); ?>
<?php js::set('XUnit', $lang->execution->burnXUnit); ?>
<?php js::set('dateRangeTip', $lang->execution->charts->cfd->dateRangeTip); ?>
<?php js::set('today', date(DT_DATE1)); ?>
<?php js::set('executionBegin', $execution->begin); ?>
<?php js::set('minDate', $minDate); ?>
<?php js::set('maxDate', $maxDate); ?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php
+7 -3
View File
@@ -18,8 +18,12 @@
<?php js::set('productID', $this->cookie->storyProductParam);?>
<?php js::set('branchID', str_replace(',', '_', $this->cookie->storyBranchParam));?>
<?php js::set('executionID', $execution->id);?>
<?php js::set('projectID', $execution->project);?>
<?php js::set('confirmUnlinkStory', $lang->execution->confirmUnlinkStory)?>
<?php js::set('typeError', sprintf($this->lang->error->notempty, $this->lang->task->type))?>
<?php js::set('typeNotEmpty', sprintf($this->lang->error->notempty, $this->lang->task->type));?>
<?php js::set('hourPointNotEmpty', sprintf($this->lang->error->notempty, $this->lang->story->convertRelations));?>
<?php js::set('hourPointNotError', sprintf($this->lang->story->float, $this->lang->story->convertRelations));?>
<?php js::set('workingHourError', sprintf($this->lang->error->notempty, $this->lang->workingHour))?>
<?php js::set('linkedTaskStories', $linkedTaskStories);?>
<?php js::set('confirmStoryToTask', $lang->execution->confirmStoryToTask);?>
@@ -318,7 +322,7 @@
<h4 class="modal-title"><?php echo $lang->story->batchToTask;?></h4>
</div>
<div class="modal-body">
<form method='post' class='form-ajax' action='<?php echo $this->createLink('story', 'batchToTask', "executionID=$execution->id");?>'>
<form method='post' class='not-watch' action='<?php echo $this->createLink('story', 'batchToTask', "executionID=$execution->id&projectID=$execution->project");?>'>
<table class='table table-form'>
<tr>
<th class="<?php echo strpos($this->app->getClientLang(), 'zh') === false ? 'w-140px' : 'w-80px';?>"><?php echo $lang->task->type?></th>
@@ -328,7 +332,7 @@
<?php if($lang->hourCommon !== $lang->workingHour):?>
<tr>
<th><?php echo $lang->story->one . $lang->hourCommon?></th>
<td><div class='input-group'><span class='input-group-addon'><?php echo "=";?></span><?php echo html::input('hourPointValue', '', "class='form-control' required");?> <span class='input-group-addon'><?php echo $lang->workingHour;?></span></div></td>
<td><div class='input-group'><span class='input-group-addon'><?php echo "≈";?></span><?php echo html::input('hourPointValue', '', "class='form-control' required");?> <span class='input-group-addon'><?php echo $lang->workingHour;?></span></div></td>
<td></td>
</tr>
<?php endif;?>
@@ -342,7 +346,7 @@
<tr>
<td colspan='3' class='text-center'>
<?php echo html::hidden('storyIdList', '');?>
<?php echo html::submitButton($lang->story->toTask, '', 'btn btn-primary');?>
<?php echo html::submitButton($lang->execution->next, '', 'btn btn-primary');?>
</td>
</tr>
</table>
Regular → Executable
+6
View File
@@ -127,6 +127,12 @@ class file extends control
return print("<html><head><meta charset='utf-8'></head><body>{$this->lang->file->fileNotFound}</body></html>");
}
if(!$this->file->checkPriv($file))
{
echo(js::alert($this->lang->file->accessDenied));
return print(js::locate(helper::createLink('my', 'index')));
}
/* Judge the mode, down or open. */
$mode = 'down';
$fileTypes = 'txt|jpg|jpeg|gif|png|bmp|xml|html';
Regular → Executable
+1
View File
@@ -56,6 +56,7 @@ $lang->file->uploadImagesExplain = 'Hinweis: Beim Upload von .jpg, .jpeg, .gif,
$lang->file->saveAndNext = 'Save and Next';
$lang->file->importPager = 'Total: <strong>%s</strong>. Page <strong>%s</strong> of <strong>%s</strong>';
$lang->file->importSummary = "Import <strong id='allCount'>%s</strong> items You can <strong>%s</strong> items/page, so you have to import <strong id='times'>%s</strong> times.";
$lang->file->accessDenied = 'Access denied to this file!';
$lang->file->errorNotExists = "<span class='text-red'>'%s' wurde nicht gefunden.</span>";
$lang->file->errorCanNotWrite = "<span class='text-red'>'%s' ist nicht beschreibbar. Bitte passen Sie die Berechtigungen an. Befehl <span class='code'>sudo chmod -R 777 '%s'</span></span> in Linux.";
Regular → Executable
+1
View File
@@ -56,6 +56,7 @@ $lang->file->uploadImagesExplain = 'Note: upload .jpg, .jpeg, .gif, or .png imag
$lang->file->saveAndNext = 'Save and Next';
$lang->file->importPager = 'Total: <strong>%s</strong>. Page <strong>%s</strong> of <strong>%s</strong>';
$lang->file->importSummary = "Import <strong id='allCount'>%s</strong> items You can <strong>%s</strong> items/page, so you have to import <strong id='times'>%s</strong> times.";
$lang->file->accessDenied = 'Access denied to this file!';
$lang->file->errorNotExists = "<span class='text-red'>'%s' is not found.</span>";
$lang->file->errorCanNotWrite = "<span class='text-red'>'%s' is not writable. Please change its permission. Enter <span class='code'>sudo chmod -R 777 '%s'</span></span> in Linux.";
Regular → Executable
+1
View File
@@ -56,6 +56,7 @@ $lang->file->uploadImagesExplain = "Note : Chargez images au format .jpg, .jpeg,
$lang->file->saveAndNext = 'Enregistrer et poursuivre';
$lang->file->importPager = 'Total: <strong>%s</strong>. Page <strong>%s</strong> de <strong>%s</strong>';
$lang->file->importSummary = "Import <strong id='allCount'>%s</strong> items Vous pouvez avoir <strong>%s</strong> items/page, vous devez donc importer <strong id='times'>%s</strong> fois.";
$lang->file->accessDenied = 'Access denied to this file!';
$lang->file->errorNotExists = "<span class='text-red'>'%s' non trouvé.</span>";
$lang->file->errorCanNotWrite = "<span class='text-red'>'%s' non inscriptible. Changez les permissions. Entrez la commande <span class='code'>sudo chmod -R 777 '%s'</span></span> sous Linux.";
Regular → Executable
+1
View File
@@ -51,6 +51,7 @@ $lang->file->uploadImagesExplain = 'Ghi chú: upload .jpg, .jpeg, .gif, or .png
$lang->file->saveAndNext = 'Save and Next';
$lang->file->importPager = 'Total: <strong>%s</strong>. Page <strong>%s</strong> of <strong>%s</strong>';
$lang->file->importSummary = "Import <strong id='allCount'>%s</strong> items You can <strong>%s</strong> items/page, so you have to import <strong id='times'>%s</strong> times.";
$lang->file->accessDenied = 'Access denied to this file!';
$lang->file->errorNotExists = "<span class='text-red'>'%s' không là found.</span>";
$lang->file->errorCanNotWrite = "<span class='text-red'>'%s' không thể ghi. Vui lòng change its permission. Enter <span class='code'>sudo chmod -R 777 '%s'</span></span> in Linux.";
Regular → Executable
+1
View File
@@ -56,6 +56,7 @@ $lang->file->uploadImagesExplain = '注:请上传"jpg, jpeg, gif, png"格式
$lang->file->saveAndNext = '保存并跳转下一页';
$lang->file->importPager = '共有<strong>%s</strong>条记录,当前第<strong>%s</strong>页,共有<strong>%s</strong>页';
$lang->file->importSummary = "本次导入共有<strong id='allCount'>%s</strong>条记录,每页导入%s条,需要导入<strong id='times'>%s</strong>次";
$lang->file->accessDenied = '您无权下载该附件!';
$lang->file->errorNotExists = "<span class='text-red'>文件夹 '%s' 不存在</span>";
$lang->file->errorCanNotWrite = "<span class='text-red'>文件夹 '%s' 不可写,请改变文件夹的权限。在linux中输入指令: <span class='code'>sudo chmod -R 777 %s</span></span>";
Regular → Executable
View File
Regular → Executable
+52
View File
@@ -525,6 +525,58 @@ class fileModel extends model
}
}
/**
* Check file priv.
*
* @param int $file
* @access public
* @return bool
*/
public function checkPriv($file)
{
if($this->app->user->admin) return true;
$objectType = $file->objectType;
$objectID = $file->objectID;
$projectObjects = array('design', 'issue', 'risk');
$productObjects = array('story', 'bug', 'testcase', 'productplan');
$executionObjects = array('task', 'build');
$table = $this->config->objectTables[$objectType];
if(!$table) return true;
if(in_array($objectType, $projectObjects))
{
$projectID = $this->dao->findByID($objectID)->from($table)->fetch('project');
}
elseif(in_array($objectType, $productObjects))
{
$productID = $this->dao->findByID($objectID)->from($table)->fetch('product');
}
elseif(in_array($objectType, $executionObjects))
{
$executionID = $this->dao->findByID($objectID)->from($table)->fetch('execution');
}
elseif($objectType == 'doc')
{
$doc = $this->dao->findById($objectID)->from(TABLE_DOC)->fetch();
return $this->loadModel('doc')->checkPrivDoc($doc);
}
elseif($objectType == 'feedback')
{
$productID = $this->dao->findById($objectID)->from(TABLE_FEEDBACK)->fetch();
$grantProducts = $this->loadModel('feedback')->getGrantProducts();
return in_array($productID, array_keys($grantProducts));
}
if(isset($projectID) and strpos(",{$this->app->user->view->projects},", ",$projectID,") === false) return false;
if(isset($productID) and strpos(",{$this->app->user->view->products},", ",$productID,") === false) return false;
if(isset($executionID) and strpos(",{$this->app->user->view->sprints},", ",$executionID,") === false) return false;
return true;
}
/**
* Compress image to config configured size.
*
+3 -3
View File
@@ -1240,9 +1240,9 @@ EOF;
if(!empty($_POST))
{
$this->user->updatePassword($this->app->user->id);
if(dao::isError()) return print(js::error(dao::getError()));
if(isonlybody()) return print(js::closeModal('parent.parent', 'this'));
return print(js::locate($this->createLink('my', 'index'), 'parent.parent'));
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(isonlybody()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess,locate => $this->createLink('my', 'index')));
}
$this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->changePassword;
+1
View File
@@ -0,0 +1 @@
#mainContent table > tbody > tr > td > div.text-danger.help-text {word-break: break-all;}
+2 -1
View File
@@ -1 +1,2 @@
.c-hours, .c-progress {width: 80px !important;}
.c-hours, .c-progress {width: 80px !important;}
th.c-status {padding-right: 8px !important;}
+1
View File
@@ -14,6 +14,7 @@ $(document).ready(function()
var password1 = $('input#password1').val().trim();
var passwordStrength = computePasswordStrength(password1);
var rand = $('input#verifyRand').val();
if(!password1Encrypted) $("#passwordLength").val(password1.length);
if($("form input[name=passwordStrength]").length == 0) $('#submit').after("<input type='hidden' name='passwordStrength' value='0' />");
$("form input[name=passwordStrength]").val(passwordStrength);
+1
View File
@@ -13,6 +13,7 @@ $(document).ready(function()
var password = $('input#verifyPassword').val();
var password1 = $('input#password1').val();
var passwordStrength = computePasswordStrength(password1);
if(!password1Encrypted) $("#passwordLength").val(password1.length);
if($("form input[name=passwordStrength]").length == 0) $('#submit').after("<input type='hidden' name='passwordStrength' value='0' />");
$("form input[name=passwordStrength]").val(passwordStrength);
+6 -3
View File
@@ -21,7 +21,7 @@
<div class='main-header'>
<h2><i class='icon-key'></i> <?php echo $lang->my->changePassword;?></h2>
</div>
<form method='post' target='hiddenwin'>
<form method='post' class='form-ajax'>
<table align='center' class='table table-form w-320px'>
<tr>
<th class='rowhead thWidth'><?php echo $lang->user->account;?></th>
@@ -35,7 +35,7 @@
<th><?php echo $lang->user->newPassword;?></th>
<td>
<span class='input-group'>
<?php echo html::password('password1', '', "class='form-control' onmouseup='checkPassword(this.value)' onkeyup='checkPassword(this.value)' placeholder='" . (!empty($config->safe->mode) ? $lang->user->placeholder->passwordStrength[$config->safe->mode] : '') . "'");?>
<?php echo html::password('password1', '', "class='form-control' onmouseup='checkPassword(this.value)' onkeyup='checkPassword(this.value)' placeholder='" . zget($lang->user->placeholder->passwordStrength, $config->safe->mode, '') . "'");?>
<span class='input-group-addon' id='passwordStrength'></span>
</span>
</td>
@@ -45,7 +45,10 @@
<td><?php echo html::password('password2', '', "class='form-control'");?></td>
</tr>
<tr>
<td colspan='2' class='text-center form-actions'><?php echo html::submitButton();?></td>
<td colspan='2' class='text-center form-actions'>
<?php echo html::hidden('passwordLength', 0);?>
<?php echo html::submitButton();?>
</td>
</tr>
</table>
<?php if(!empty($this->app->user->modifyPasswordReason)):?>
+1 -1
View File
@@ -84,7 +84,7 @@
</tr>
</table>
<?php echo html::select('visions[]', $this->user->getVisionList(), $user->visions, "class='form-control chosen' multiple");?>
<div class='text-center form-actions'><?php echo html::submitButton() . html::backButton();?></div>
<div class='text-center form-actions'><?php echo html::hidden('passwordLength', 0) . html::submitButton() . html::backButton();?></div>
</form>
<?php echo html::hidden('verifyRand', $rand);?>
</div>
+4 -4
View File
@@ -39,7 +39,7 @@
<?php endif;?>
<th class='c-date'><?php echo $lang->execution->begin;?></th>
<th class='c-date'><?php echo $lang->execution->end;?></th>
<th class='c-status'><?php echo $lang->statusAB;?></th>
<th class='c-status text-center'><?php echo $lang->statusAB;?></th>
<th class='c-user'><?php echo $lang->team->role;?></th>
<th class='c-date'><?php echo $lang->team->join;?></th>
<th class='c-hours'><?php echo $lang->my->hours;?></th>
@@ -53,13 +53,13 @@
<tr class='text-left'>
<td><?php echo html::a($link, sprintf('%03d', $execution->id));?></td>
<td class='c-name text-left'>
<?php if($config->systemMode == 'new'):?>
<?php if($config->systemMode == 'new'):?>
<?php
if($execution->type === 'stage') echo "<span class='project-type-label label label-outline label-warning'>{$lang->project->stage}</span> ";
if($execution->type === 'sprint') echo "<span class='project-type-label label label-outline label-info'>{$lang->executionCommon}</span> ";
if($execution->type === 'kanban') echo "<span class='project-type-label label label-outline label-info'>{$lang->execution->kanban}</span> ";
?>
<?php endif;?>
<?php endif;?>
<?php echo html::a($link, $execution->name, '', "title='$execution->name'");?>
</td>
<?php if($config->systemMode == 'new'):?>
@@ -69,7 +69,7 @@
<?php endif;?>
<td><?php echo $execution->begin;?></td>
<td><?php echo $execution->end;?></td>
<td class="c-status">
<td class="c-status text-center">
<?php if(isset($execution->delay)):?>
<span class="status-project status-delayed" title='<?php echo $lang->execution->delayed;?>'><?php echo $lang->execution->delayed;?></span>
<?php else:?>
+23
View File
@@ -0,0 +1,23 @@
<?php
$lang->port = new stdclass();
$lang->port->reservedWord['id'] = 'ID';
$lang->port->reservedWord['type'] = 'Type';
$lang->port->reservedWord['project'] = 'Project';
$lang->port->reservedWord['execution'] = 'Execution';
$lang->port->reservedWord['product'] = 'Project';
$lang->port->reservedWord['code'] = 'CODE';
$lang->port->reservedWord['name'] = 'Name';
$lang->port->reservedWord['title'] = 'Title';
$lang->port->importCase = 'Import EXCEL';
$lang->port->importNotice = 'Notice: Importing data is risky! Make sure to complete the following steps in sequence before merging.';
$lang->port->noRequire = 'Row %s has“%s ”which is a required field and it should not be blank.';
$lang->port->exportTemplate = 'Export Template';
$lang->port->import = 'Import';
$lang->port->id = 'ID';
$lang->port->new = 'New';
$lang->port->num = 'Count:';
$lang->port->children = 'Child';
+23
View File
@@ -0,0 +1,23 @@
<?php
$lang->port = new stdclass();
$lang->port->reservedWord['id'] = 'ID';
$lang->port->reservedWord['type'] = 'Type';
$lang->port->reservedWord['project'] = 'Project';
$lang->port->reservedWord['execution'] = 'Execution';
$lang->port->reservedWord['product'] = 'Project';
$lang->port->reservedWord['code'] = 'CODE';
$lang->port->reservedWord['name'] = 'Name';
$lang->port->reservedWord['title'] = 'Title';
$lang->port->importCase = 'Import EXCEL';
$lang->port->importNotice = 'Notice: Importing data is risky! Make sure to complete the following steps in sequence before merging.';
$lang->port->noRequire = 'Row %s has“%s ”which is a required field and it should not be blank.';
$lang->port->exportTemplate = 'Export Template';
$lang->port->import = 'Import';
$lang->port->id = 'ID';
$lang->port->new = 'New';
$lang->port->num = 'Count:';
$lang->port->children = 'Child';
+23
View File
@@ -0,0 +1,23 @@
<?php
$lang->port = new stdclass();
$lang->port->reservedWord['id'] = 'ID';
$lang->port->reservedWord['type'] = 'Type';
$lang->port->reservedWord['project'] = 'Project';
$lang->port->reservedWord['execution'] = 'Execution';
$lang->port->reservedWord['product'] = 'Project';
$lang->port->reservedWord['code'] = 'CODE';
$lang->port->reservedWord['name'] = 'Name';
$lang->port->reservedWord['title'] = 'Title';
$lang->port->importCase = 'Import EXCEL';
$lang->port->importNotice = 'Notice: Importing data is risky! Make sure to complete the following steps in sequence before merging.';
$lang->port->noRequire = 'Row %s has“%s ”which is a required field and it should not be blank.';
$lang->port->exportTemplate = 'Export Template';
$lang->port->import = 'Import';
$lang->port->id = 'ID';
$lang->port->new = 'New';
$lang->port->num = 'Count:';
$lang->port->children = 'Child';
-1
View File
@@ -9,7 +9,6 @@ $lang->port->reservedWord['product'] = '所属产品';
$lang->port->reservedWord['code'] = '代号';
$lang->port->reservedWord['name'] = '名称';
$lang->port->reservedWord['title'] = '标题';
$lang->port->reservedWord['asdawdadw'] = '测试字段';
$lang->port->importCase = '导入EXCEL';
$lang->port->importNotice = '请先导出模板,按照模板格式填写数据后再导入。';
+1
View File
@@ -16,3 +16,4 @@ tbody.sortable > tr > td.sort-handler {color: #3c4353 !important;}
div.checkbox-primary + span.table-nest-icon {margin-left:0px !important;}
#checkAll + label.hover:after {border-width: 0px;}
.c-budget {padding-right:16px !important;}
+1 -1
View File
@@ -80,7 +80,7 @@
<?php endif;?>
</td>
<?php $programBudget = $this->loadModel('project')->getBudgetWithUnit($program->budget);?>
<td class='text-right'><?php echo $program->budget != 0 ? zget($lang->project->currencySymbol, $program->budgetUnit) . ' ' . $programBudget : $lang->project->future;?></td>
<td class='text-right c-budget'><?php echo $program->budget != 0 ? zget($lang->project->currencySymbol, $program->budgetUnit) . ' ' . $programBudget : $lang->project->future;?></td>
<td><?php echo $program->begin;?></td>
<td><?php echo $program->end == LONG_TIME ? $lang->program->longTime : $program->end;?></td>
<td>
+1 -1
View File
@@ -1183,7 +1183,7 @@ class project extends control
$this->view->branchOption = $branchOption;
$this->view->branchTagOption = $branchTagOption;
$this->view->executions = $executions;
$this->view->plans = $this->loadModel('productplan')->getPairs($productID);
$this->view->plans = $this->loadModel('productplan')->getPairs($productID ? $productID : array_keys($products));
$this->view->stories = $storyList;
$this->view->tasks = $taskList;
$this->view->projectPairs = $this->project->getPairsByProgram();
+1 -1
View File
@@ -2029,7 +2029,7 @@ class projectModel extends model
echo $project->end;
break;
case 'status':
echo "<span class='status-task status-{$project->status}'> " . zget($this->lang->project->statusList, $project->status) . "</span>";
echo "<span class='status-task text-center status-{$project->status}'> " . zget($this->lang->project->statusList, $project->status) . "</span>";
break;
case 'budget':
echo $budgetTitle;
+1 -1
View File
@@ -72,7 +72,7 @@
<?php echo $lang->nameAB;?>
</th>
<th class='c-user'><?php echo $lang->execution->owner;?></th>
<th class='c-status'><?php echo $lang->project->status;?></th>
<th class='c-status text-center'><?php echo $lang->project->status;?></th>
<th class='c-hours'><?php echo $lang->project->progress;?></th>
<th class='c-date'><?php echo $lang->programplan->begin;?></th>
<th class='c-date'><?php echo $lang->programplan->end;?></th>
+3 -3
View File
@@ -32,7 +32,7 @@
<th class='c-user'><?php echo $lang->openedByAB;?></th>
<th class='c-user'><?php echo $lang->assignedToAB;?></th>
<th class='c-estimate text-right'><?php echo $lang->story->estimateAB;?></th>
<th class='c-status'><?php echo $lang->statusAB;?></th>
<th class='c-status text-center'><?php echo $lang->statusAB;?></th>
<th class='c-stage'><?php echo $lang->story->stageAB;?></th>
</tr>
</thead>
@@ -50,14 +50,14 @@
<td><span class='label-pri <?php echo 'label-pri-' . $story->pri;?>' title='<?php echo zget($lang->story->priList, $story->pri)?>'><?php echo zget($lang->story->priList, $story->pri)?></span></td>
<td class='text-left nobr c-name' title='<?php echo $story->title?>'>
<?php
if($story->parent > 0) echo "<span class='label'>{$lang->story->childrenAB}</span>";
if($story->parent > 0) echo "<span class='label label-badge label-light' title='{$lang->story->childrenAB}'>{$lang->story->childrenAB}</span>";
echo html::a($this->createLink('story', 'view', "storyID=$story->id", '', true), $story->title, '', "data-toggle='modal' data-type='iframe' data-width='90%'");
?>
</td>
<td><?php echo zget($users, $story->openedBy);?></td>
<td><?php echo zget($users, $story->assignedTo);?></td>
<td class='text-right' title="<?php echo $story->estimate . ' ' . $lang->hourCommon;?>"><?php echo $story->estimate . $config->hourUnit;?></td>
<td><span class='status-story status-<?php echo $story->status?>'><?php echo $this->processStatus('story', $story);?></span></td>
<td class='text-center'><span class='status-story status-<?php echo $story->status?>'><?php echo $this->processStatus('story', $story);?></span></td>
<td><?php echo zget($lang->story->stageList, $story->stage);?></td>
</tr>
<?php $unlinkedCount++;?>
+4 -4
View File
@@ -75,7 +75,7 @@
<th class="text-left"><?php common::printOrderLink('title', $orderBy, $vars, $lang->story->title);?></th>
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='w-80px text-right'><?php common::printOrderLink('estimate', $orderBy, $vars, $lang->story->estimateAB);?></th>
<th class='w-90px'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
<th class='w-90px text-center'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
<th class='w-100px'><?php common::printOrderLink('stage', $orderBy, $vars, $lang->story->stageAB);?></th>
<th class='c-actions-1'><?php echo $lang->actions?></th>
</tr>
@@ -96,13 +96,13 @@
<td><span class='label-pri <?php echo 'label-pri-' . $story->pri;?>' title='<?php echo zget($lang->story->priList, $story->pri, $story->pri);?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri);?></span></td>
<td class='text-left nobr' title='<?php echo $story->title?>'>
<?php
if($story->parent > 0) echo "<span class='label'>{$lang->story->childrenAB}</span>";
if($story->parent > 0) echo "<span class='label label-badge label-light' title='{$lang->story->childrenAB}'>{$lang->story->childrenAB}</span>";
echo html::a($storyLink,$story->title, '', "class='preview'");
?>
</td>
<td><?php echo zget($users, $story->openedBy);?></td>
<td class='text-right' title="<?php echo $story->estimate . ' ' . $lang->hourCommon;?>"><?php echo $story->estimate . $config->hourUnit;?></td>
<td>
<td class='text-center'>
<span class='status-story status-<?php echo $story->status;?>'><?php echo $this->processStatus('story', $story);?></span>
</td>
<td><?php echo $lang->story->stageList[$story->stage];?></td>
@@ -196,7 +196,7 @@
<td><?php echo zget($users, $bug->openedBy);?></td>
<td><?php echo substr($bug->openedDate, 5, 11)?></td>
<td><?php echo zget($users, $bug->resolvedBy);?></td>
<td><?php echo substr($bug->resolvedDate, 5, 11)?></td>
<td><?php echo helper::isZeroDate($bug->resolvedDate) ? '' : substr($bug->resolvedDate, 5, 11);?></td>
<td class='c-actions'>
<?php
if(common::hasPriv('release', 'unlinkBug') and $canBeChanged)
+30 -12
View File
@@ -1730,29 +1730,47 @@ class story extends control
* Batch stories convert to tasks.
*
* @param int $executionID
* @param int $projectID
* @access public
* @return void
*/
public function batchToTask($executionID = 0)
public function batchToTask($executionID = 0, $projectID = 0)
{
if(!empty($_POST))
if(!empty($_POST['name']))
{
$response['result'] = 'success';
$response['message'] = $this->lang->story->successToTask;
$tasks = $this->story->batchToTask($executionID, $this->session->project);
if(dao::isError())
{
$response['result'] = 'fail';
$response['message'] = dao::getError();
return $this->send($response);
}
$tasks = $this->story->batchToTask($executionID, $projectID);
if(dao::isError()) return print(js::error(dao::getError()));
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'idList' => $tasks));
$response['locate'] = $this->createLink('execution', 'task', "executionID=$executionID");
return $this->send($response);
return print(js::locate($this->createLink('execution', 'task', "executionID=$executionID"), 'parent'));
}
if(!$this->post->storyIdList) return print(js::locate($this->session->storyList, 'parent'));
$stories = $this->story->getByList($_POST['storyIdList']);
$storyGroup = array();
foreach($stories as $story)
{
if(strpos('draft,closed', $story->status) !== false) continue;
if(isset($storyGroup[$story->module])) continue;
$storyGroup[$story->module] = $this->story->getExecutionStoryPairs($executionID, 0, 'all', $story->module, 'short', 'active');
}
$this->view->title = $this->lang->story->batchToTask;
$this->view->executionID = $executionID;
$this->view->syncFields = empty($_POST['fields']) ? array() : $_POST['fields'];
$this->view->hourPointValue = empty($_POST['hourPointValue']) ? 0 : $_POST['hourPointValue'];
$this->view->taskType = empty($_POST['type']) ? '' : $_POST['type'];
$this->view->stories = $stories;
$this->view->storyGroup = $storyGroup;
$this->view->modules = $this->loadModel('tree')->getTaskOptionMenu($executionID, 0, 0, 'allModule');
$this->view->members = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution', 'nodeleted');
$this->view->storyTasks = $this->loadModel('task')->getStoryTaskCounts(array_keys($stories), $executionID);
$this->display();
}
/**
+22
View File
@@ -0,0 +1,22 @@
.chosen-container[id^="story"] {width: 200px; max-width: 150px;}
select[id^="story"] + .picker-single {width: 130px; max-width: 130px;}
#mainContent .main-header h2 {max-width: 300px;}
#batchToTaskForm .input-group,
#batchToTaskForm .input-group .form-control {position: static;}
#batchToTaskForm .input-group .colorpicker {z-index: 2;}
#batchToTaskForm .input-group .colorpicker.open {z-index: 5;}
.main-header .pull-left {max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
.chosen-results > li.has-task,
.chosen-results > li.has-new-task {position: relative; color: #388E3C;}
.chosen-results > li.has-task.highlighted,
.chosen-results > li.has-new-task.highlighted {color: #fff;}
.c-id {width: 30px;}
.c-name, .c-desc {width: 150px;}
.c-story {width: 200px;}
.c-assigned {width: 130px;}
.c-date {width: 120px;}
.c-pri {width: 80px;}
.c-actions {width: 60px;}
+304
View File
@@ -0,0 +1,304 @@
$(document).on('change', "[name^='estStarted'], [name^='deadline']", function()
{
toggleCheck($(this));
});
/**
* Set story related.
*
* @param int $num
* @access public
* @return void
*/
function setStoryRelated(num)
{
setPreview(num);
}
/**
* Toggle checkbox.
*
* @param object $obj
* @access public
* @return void
*/
function toggleCheck(obj)
{
var $this = $(obj);
var date = $this.val();
var $ditto = $this.closest('div').find("input[type='checkBox']");
if(date == '')
{
$ditto.attr('checked', true);
$ditto.closest('.input-group-addon').show();
}
else
{
$ditto.removeAttr('checked');
$ditto.closest('.input-group-addon').hide();
}
}
/**
* Set stories.
*
* @param int $moduleID
* @param int $executionID
* @param int $num
* @access public
* @return void
*/
function setStories(moduleID, executionID, num)
{
var link = createLink('story', 'ajaxGetExecutionStories', 'executionID=' + executionID + '&productID=0&branch=all&moduleID=' + moduleID + '&storyID=0&num=' + num + '&type=short');
$.get(link, function(stories)
{
var storyID = $('#story' + num).val();
if(!stories) stories = '<select id="story' + num + '" name="story[' + num + ']" class="form-control"></select>';
$('#story' + num).replaceWith(stories);
if(num != 0 && (moduleID == 0 || moduleID == 'ditto')) $('#story' + num).append("<option value='ditto'>" + ditto + "</option>");
$('#story' + num).val(storyID);
var chosenWidth = $("#story" + num + "_chosen").css('max-width');
$("#story" + num + "_chosen").remove();
$("#story" + num).next('.picker').remove();
$("#story" + num).chosen();
$("#story" + num + "_chosen").width(chosenWidth).css('max-width', chosenWidth);
});
}
/**
* Copy story title.
*
* @param int $num
* @access public
* @return void
*/
function copyStoryTitle(num)
{
var $story = $('#story' + num);
var storyTitle = $story.find('option:selected').text();
var storyValue = $story.find('option:selected').val();
var begin = parseInt($story.closest('tr').children('.c-id').text()) - 2;
if(storyValue === 'ditto')
{
for(var i = begin; i >= 0; i--)
{
var selectedValue = $('#tableBody tbody > tr').eq(i).find('select[name^="story"]').val();
var selectedTitle = $('#tableBody tbody > tr').eq(i).find('select[name^="story"]').find('option:selected').text();
if(selectedValue !== 'ditto')
{
storyTitle = selectedTitle;
break;
}
}
}
var startPosition = storyTitle.indexOf(':') + 1;
var endPosition = storyTitle.lastIndexOf('[');
storyTitle = storyTitle.substr(startPosition, endPosition - startPosition);
$('#name\\[' + num + '\\]').val(storyTitle);
}
/**
* Set preview.
*
* @param int $num
* @access public
* @return void
*/
function setPreview(num)
{
var storyID = $('#story' + num).val();
if(storyID != 0 && storyID != 'ditto')
{
storyLink = createLink('story', 'view', "storyID=" + storyID, '', true);
$('#preview' + num).removeAttr('disabled');
$('#preview' + num).modalTrigger({type:'iframe'});
$('#preview' + num).css('pointer-events', 'auto');
$('#preview' + num).attr('href', storyLink);
}
else
{
storyLink = '#';
$('#preview' + num).attr('disabled', true);
$('#preview' + num).css('pointer-events', 'none');
$('#preview' + num).attr('href', storyLink);
}
}
/**
* Mark story task.
*
* @access public
* @return void
*/
function markStoryTask()
{
$('select[name^="story"]').each(function()
{
var $select = $(this);
$select.find('option').each(function()
{
var $option = $(this);
var value = $option.attr('value');
var tasksCount = storyTasks[value];
$option.attr('data-data', value).toggleClass('has-task', !!(tasksCount && tasksCount !== '0'));
});
$select.trigger("chosen:updated");
});
var getStoriesHasTask = function()
{
var storiesHasTask = {};
$('#tableBody tbody>tr').each(function()
{
var $tr = $(this);
if ($tr.find('input[name^="name"]').val())
{
storiesHasTask[$tr.find('select[name^="story"]').val()] = true;
}
});
return storiesHasTask;
};
$('#batchToTaskForm').on('chosen:showing_dropdown', 'select[name^="story"],.chosen-with-drop', function()
{
var storiesHasTask = getStoriesHasTask();
var $container = $(this).closest('td').find('.chosen-container');
setTimeout(function()
{
$container.find('.chosen-results>li').each(function()
{
var $li = $(this);
$li.toggleClass('has-new-task', !!storiesHasTask[$li.data('data')]);
});
}, 100);
});
}
$(document).on('chosen:showing_dropdown', 'select[name^="story"],.chosen-with-drop', function()
{
var select = $(this).closest('td').find('select');
if($(select).val() == 'ditto')
{
var index = $(select).closest('td').index();
var row = $(select).closest('tr').index();
var table = $(select).closest('tr').parent();
var value = '';
for(i = row - 1; i >= 0; i--)
{
value = $(table).find('tr').eq(i).find('td').eq(index).find('select').val();
if(value != 'ditto') break;
}
$(select).val(value);
$(select).trigger("chosen:updated");
$(select).trigger("change");
}
})
$(document).on('mousedown', 'select', function()
{
if($(this).val() == 'ditto')
{
var index = $(this).closest('td').index();
var row = $(this).closest('tr').index();
var table = $(this).closest('tr').parent();
var value = '';
for(i = row - 1; i >= 0; i--)
{
value = $(table).find('tr').eq(i).find('td').eq(index).find('select').val();
if(value != 'ditto') break;
}
$(this).val(value);
}
})
$(function()
{
$('.chosen-container[id^=module]').width(chosenWidth);
$('.chosen-container[id^=module]').css('max-width', chosenWidth);
var chosenWidth = $('#story1_chosen').width();
$('.chosen-container[id^=story]').width(chosenWidth);
$('.chosen-container[id^=story]').css('max-width', chosenWidth);
markStoryTask();
$(document).keydown(function(event)
{
if(event.ctrlKey && event.keyCode == 38)
{
event.stopPropagation();
event.preventDefault();
selectFocusJump('up');
}
else if(event.ctrlKey && event.keyCode == 40)
{
event.stopPropagation();
event.preventDefault();
selectFocusJump('down');
}
else if(event.keyCode == 38)
{
inputFocusJump('up');
}
else if(event.keyCode == 40)
{
inputFocusJump('down');
}
});
});
/**
* Add row.
*
* @param object $obj
* @access public
* @return void
*/
function addRow(obj)
{
var row = $('#addRow').html().replace(/%i%/g, rowIndex + 1);
$('<tr class="addedRow">' + row + '</tr>').insertAfter($(obj).closest('tr'));
var $beginRow = $row = $(obj).closest('tr').next();
$row.find(".form-date").datepicker();
$row.find("input[name^=color]").colorPicker();
$row.find('div[id$=_chosen]').remove();
$row.find('.picker').remove();
$row.find('.chosen').chosen();
var begin = parseInt($(obj).parent().siblings('.c-id').text()) + 1;
var count = $('#tableBody tbody > tr').length;
for(var i = begin; i <= count; i++)
{
$beginRow.children('.c-id').text(i);
$beginRow = $beginRow.next();
}
rowIndex ++;
}
/**
* Delete row.
*
* @param object $obj
* @access public
* @return void
*/
function deleteRow(obj)
{
var $beginRow = $(obj).closest('tr').next();
var begin = parseInt($(obj).parent().siblings('.c-id').text());
var count = $('#tableBody tbody > tr').length;
for(var i = begin; i <= count; i++)
{
$beginRow.children('.c-id').text(i);
$beginRow = $beginRow.next();
}
$(obj).closest('tr').remove();
}
+2 -1
View File
@@ -84,9 +84,10 @@ $lang->story->reportAction = "Story Report";
$lang->story->skipStory = '%s is a parent story. It cannot be closed.';
$lang->story->closedStory = 'Story %s is closed and will not be closed.';
$lang->story->batchToTaskTips = "This action will create a task with the same name as the selected {$lang->SRCommon} and link {$lang->SRCommon} to the task. The closed {$lang->SRCommon} will not be converted into tasks.";
$lang->story->batchToTaskTips = "The closed {$lang->SRCommon} will not be converted into tasks.";
$lang->story->successToTask = "Converted to task.";
$lang->story->storyRound = '%s time estimation';
$lang->story->float = "『%s』should be positive number, decimals included.";
$lang->story->id = 'ID';
$lang->story->parent = 'Parent';
+2 -1
View File
@@ -84,9 +84,10 @@ $lang->story->reportAction = "Report";
$lang->story->skipStory = '%s is a parent story. It cannot be closed.';
$lang->story->closedStory = 'Story %s is closed and will not be closed.';
$lang->story->batchToTaskTips = "This action will create a task with the same name as the selected {$lang->SRCommon} and link {$lang->SRCommon} to the task. The closed {$lang->SRCommon} will not be converted into tasks.";
$lang->story->batchToTaskTips = "The closed {$lang->SRCommon} will not be converted into tasks.";
$lang->story->successToTask = "Converted to task.";
$lang->story->storyRound = '%s time estimation';
$lang->story->float = "『%s』should have positive number, or decimals.";
$lang->story->id = 'ID';
$lang->story->parent = 'Parent';
+2 -1
View File
@@ -84,9 +84,10 @@ $lang->story->reportAction = "Rapport de Story";
$lang->story->skipStory = '%s is a parent story. It cannot be closed.';
$lang->story->closedStory = 'Story %s is closed and will not be closed.';
$lang->story->batchToTaskTips = "This action will create a task with the same name as the selected {$lang->SRCommon} and link {$lang->SRCommon} to the task. The closed {$lang->SRCommon} will not be converted into tasks.";
$lang->story->batchToTaskTips = "The closed {$lang->SRCommon} will not be converted into tasks.";
$lang->story->successToTask = "Converted to task.";
$lang->story->storyRound = '%s time estimation';
$lang->story->float = "『 %s 』doit avoir des nombres positifs ou décimaux.";
$lang->story->id = 'ID';
$lang->story->parent = 'Parent';
+2 -1
View File
@@ -84,9 +84,10 @@ $lang->story->reportAction = "统计报表";
$lang->story->skipStory = '需求:%s 为父需求,将不会被关闭。';
$lang->story->closedStory = '需求:%s 已关闭,将不会被关闭。';
$lang->story->batchToTaskTips = "此操作会创建与所选{$lang->SRCommon}同名的任务,并将{$lang->SRCommon}关联到任务中,已关闭的需求不会转为任务。";
$lang->story->batchToTaskTips = "已关闭的需求不会转为任务。";
$lang->story->successToTask = '批量转任务成功';
$lang->story->storyRound = '第 %s 轮估算';
$lang->story->float = "『%s』应当是正数,可以是小数。";
$lang->story->id = '编号';
$lang->story->parent = '父需求';
+138 -46
View File
@@ -2020,72 +2020,159 @@ class storyModel extends model
{
/* load Module and get the data from the post and get the current time. */
$this->loadModel('action');
$data = fixer::input('post')->get();
$now = helper::now();
$this->loadModel('task');
/* Judgment of required items. */
if(empty($data->type))
{
dao::$errors['type'] = sprintf($this->lang->error->notempty, $this->lang->task->type);
}
$now = helper::now();
$account = $this->app->user->account;
$tasks = fixer::input('post')
->remove('syncFields')
->get();
if(isset($data->hourPointValue) and empty($data->hourPointValue))
{
dao::$errors['hourPointValue'] = sprintf($this->lang->error->notempty, $this->lang->story->convertRelations);
}
elseif(isset($data->hourPointValue) and !is_numeric($data->hourPointValue))
{
dao::$errors['hourPointValue'] = sprintf($this->lang->error->float, $this->lang->story->convertRelations);
}
if(dao::isError()) return false;
if(!empty($_POST['syncFields'])) $stories = empty($tasks->story) ? array() : $this->getByList($tasks->story);
/* Create tasks. */
$tasks = array();
$stories = empty($data->storyIdList) ? array() : $this->getByList($data->storyIdList);
foreach($stories as $story)
$preStory = 0;
$storyIDs = array();
$taskNames = array();
foreach($tasks->story as $key => $storyID)
{
if(strpos('draft,closed', $story->status) !== false) continue;
$tasks->name[$key] = trim($tasks->name[$key]);
if(empty($tasks->name[$key])) continue;
if($tasks->type[$key] == 'affair') continue;
if($tasks->type[$key] == 'ditto' and isset($tasks->type[$key - 1]) and $tasks->type[$key - 1] == 'affair') continue;
$task = new stdclass();
$task->execution = $executionID;
$task->project = $projectID ? $projectID : 0;
$task->name = $story->title;
$task->story = $story->id;
$task->type = $data->type;
$task->estimate = isset($data->hourPointValue) ? ($story->estimate * $data->hourPointValue) : $story->estimate;
$task->left = $task->estimate;
$task->openedBy = $this->app->user->account;
$task->openedDate = $now;
$task->storyVersion = $story->version;
if($storyID == 'ditto') $storyID = $preStory;
$preStory = $storyID;
if(isset($data->fields))
if(!isset($tasks->story[$key - 1]) and $key > 1 and !empty($tasks->name[$key - 1]))
{
foreach($data->fields as $field)
{
$task->$field = $story->$field;
if($field == 'assignedTo') $task->assignedDate = $now;
if($field == 'spec')
{
unset($task->$field);
$task->desc = $story->$field;
}
}
$storyIDs[] = 0;
$taskNames[] = $tasks->name[$key - 1];
}
$inNames = in_array($tasks->name[$key], $taskNames);
if(!$inNames or ($inNames && !in_array($storyID, $storyIDs)))
{
$storyIDs[] = $storyID;
$taskNames[] = $tasks->name[$key];
}
else
{
dao::$errors['message'][] = sprintf($this->lang->duplicate, $this->lang->task->common) . ' ' . $tasks->name[$key];
return false;
}
}
$story = 0;
$module = 0;
$type = '';
$assignedTo = '';
$estStarted = '0000-00-00';
$deadline = '0000-00-00';
$data = array();
$requiredFields = "," . $this->config->task->create->requiredFields . ",";
foreach($tasks->name as $i => $task)
{
$module = (!isset($tasks->module[$i]) or $tasks->module[$i] == 'ditto') ? $module : $tasks->module[$i];
$story = (!isset($tasks->story[$i]) or $tasks->story[$i] == 'ditto') ? $story : $tasks->story[$i];
$type = (!isset($tasks->type[$i]) or $tasks->type[$i] == 'ditto') ? $type : $tasks->type[$i];
$assignedTo = (!isset($tasks->assignedTo[$i]) or $tasks->assignedTo[$i] == 'ditto') ? $assignedTo : $tasks->assignedTo[$i];
$estStarted = (!isset($tasks->estStarted[$i]) or isset($tasks->estStartedDitto[$i])) ? $estStarted : $tasks->estStarted[$i];
$deadline = (!isset($tasks->deadline[$i]) or isset($tasks->deadlineDitto[$i])) ? $deadline : $tasks->deadline[$i];
if(empty($tasks->name[$i])) continue;
$data[$i] = new stdclass();
$data[$i]->story = (int)$story;
$data[$i]->type = $type;
$data[$i]->module = (int)$module;
$data[$i]->assignedTo = $assignedTo;
$data[$i]->color = $tasks->color[$i];
$data[$i]->name = $tasks->name[$i];
$data[$i]->pri = $tasks->pri[$i];
$data[$i]->estimate = $tasks->estimate[$i];
$data[$i]->left = $tasks->estimate[$i];
$data[$i]->project = $this->config->systemMode == 'new' ? $projectID : 0;
$data[$i]->execution = $executionID;
$data[$i]->estStarted = $estStarted;
$data[$i]->deadline = $deadline;
$data[$i]->status = 'wait';
$data[$i]->openedBy = $account;
$data[$i]->openedDate = $now;
$data[$i]->vision = 'rnd';
if($story)
{
$data[$i]->storyVersion = $stories[$story]->version;
if(strpos(",{$_POST['syncFields']},", ',spec,') !== false) $data[$i]->desc = $stories[$story]->spec;
if(strpos(",{$_POST['syncFields']},", 'mailto') !== false) $data[$i]->mailto = $stories[$story]->mailto;
}
if($assignedTo) $data[$i]->assignedDate = $now;
if(strpos($requiredFields, ',estStarted,') !== false and empty($estStarted)) $data[$i]->estStarted = '';
if(strpos($requiredFields, ',deadline,') !== false and empty($deadline)) $data[$i]->deadline = '';
}
/* check data. */
foreach($data as $i => $task)
{
if(!helper::isZeroDate($task->deadline) and $task->deadline < $task->estStarted)
{
dao::$errors['message'][] = $this->lang->task->error->deadlineSmall;
return false;
}
if($task->estimate and !preg_match("/^[0-9]+(.[0-9]{1,3})?$/", $task->estimate))
{
dao::$errors['message'][] = $this->lang->task->error->estimateNumber;
return false;
}
foreach(explode(',', $requiredFields) as $field)
{
$field = trim($field);
if(empty($field)) continue;
if(!isset($task->$field)) continue;
if(!empty($task->$field)) continue;
if($field == 'estimate' and strlen(trim($task->estimate)) != 0) continue;
dao::$errors['message'][] = sprintf($this->lang->error->notempty, $this->lang->task->$field);
return false;
}
if($task->estimate) $task->estimate = (float)$task->estimate;
}
$taskIdList = array();
foreach($data as $i => $task)
{
$task->version = 1;
$this->dao->insert(TABLE_TASK)->data($task)
->autoCheck()
->checkIF($task->estimate != '', 'estimate', 'float')
->exec();
if(dao::isError()) return false;
$taskID = $this->dao->lastInsertID();
$tasks[] = $taskID;
$taskID = $this->dao->lastInsertID();
$taskIdList[] = $taskID;
$taskSpec = new stdClass();
$taskSpec->task = $taskID;
$taskSpec->version = $task->version;
$taskSpec->name = $task->name;
$taskSpec->estStarted = $task->estStarted;
$taskSpec->deadline = $task->deadline;
$this->dao->insert(TABLE_TASKSPEC)->data($taskSpec)->autoCheck()->exec();
if(dao::isError()) return false;
if($task->story) $this->setStage($task->story);
$this->action->create('task', $taskID, 'Opened', '');
}
$this->loadModel('kanban')->updateLane($executionID, 'task');
return $tasks;
return $taskIdList;
}
/**
@@ -4422,6 +4509,11 @@ class storyModel extends model
{
$title = $story->feedbackBy;
}
elseif($id =='version')
{
$title = $story->version;
$class = 'text-center';
}
elseif($id == 'notifyEmail')
{
$title = $story->notifyEmail;
+202
View File
@@ -0,0 +1,202 @@
<?php
/**
* The batch to task view of story module of ZenTaoPMS.
*
* @copyright Copyright 2009-2022 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Shujie Tian <tianshujie@easycorp.ltd>
* @package story
* @version $Id$
* @link https://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/datepicker.html.php';?>
<?php js::set('ditto', $lang->task->ditto);?>
<?php js::set('storyTasks', $storyTasks);?>
<?php js::set('storyType', 'story');?>
<?php js::set('storyCount', count($stories));?>
<?php
$requiredFields = array();
foreach(explode(',', $config->task->create->requiredFields) as $field)
{
if($field) $requiredFields[$field] = '';
}
?>
<div id="mainContent" class="main-content fade">
<div class="main-header clearfix">
<h2 class="pull-left"><?php echo $lang->story->batchToTask;?></h2>
</div>
<form method='post' class='batch-actions-form' target='hiddenwin' enctype='multipart/form-data' id="batchToTaskForm">
<div class="table-responsive">
<table class="table table-form" id="tableBody">
<thead>
<tr>
<th class='c-id'><?php echo $lang->idAB;?></th>
<th class='c-module<?php echo zget($requiredFields, 'module', '', ' required');?>'><?php echo $lang->task->module?></th>
<th class='c-story<?php echo zget($requiredFields, 'story', '', ' required');?>'><?php echo $lang->task->story;?></th>
<th class='c-name required has-btn'><?php echo $lang->task->name;?></span></th>
<th class='c-type required'><?php echo $lang->typeAB;?></span></th>
<th class='c-assigned<?php echo zget($requiredFields, 'assignedTo', '', ' required');?>'><?php echo $lang->task->assignedTo;?></th>
<th class='c-estimate<?php echo zget($requiredFields, 'estimate', '', ' required');?>'><?php echo $lang->task->estimateAB;?></th>
<th class='c-date<?php echo zget($requiredFields, 'estStarted', '', ' required');?>'><?php echo $lang->task->estStarted;?></th>
<th class='c-date<?php echo zget($requiredFields, 'deadline', '', ' required');?>'><?php echo $lang->task->deadline;?></th>
<th class='c-pri<?php echo zget($requiredFields, 'pri', '', ' required');?>'><?php echo $lang->task->pri;?></th>
<th class='c-actions'><?php echo $lang->actions;?></th>
</tr>
</thead>
<tbody>
<?php $i = 1;?>
<?php foreach($stories as $storyID => $story):?>
<?php
if(strpos('draft,closed', $story->status) !== false) continue;
$currentStory = $storyID;
$pri = 3;
$storyPairs = zget($storyGroup, $story->module, array());
$estimate = $hourPointValue ? $story->estimate * $hourPointValue : $story->estimate;
if($i == 1)
{
$moduleID = 0;
$type = $assignedTo = '';
}
else
{
$type = $assignedTo = $moduleID = 'ditto';
$storyPairs['ditto'] = $lang->task->ditto;
$members['ditto'] = $lang->task->ditto;
$modules['ditto'] = $lang->task->ditto;
$lang->task->typeList['ditto'] = $lang->task->ditto;
}
if(in_array('module', $syncFields)) $moduleID = $story->module;
if(in_array('pri', $syncFields)) $pri = $story->pri;
if(in_array('assignedTo', $syncFields)) $assignedTo = $story->assignedTo ? $story->assignedTo : $assignedTo;
?>
<tr>
<td class='text-left c-id'><?php echo $i;?></td>
<td style='overflow:visible'>
<?php echo html::select("module[$i]", $modules, $moduleID, "class='form-control chosen' onchange='setStories(this.value, $executionID, $i)'")?>
</td>
<td style='overflow: visible'>
<div class='input-group'>
<?php echo html::select("story[$i]", $storyPairs, $currentStory, "class='form-control chosen' onchange='setStoryRelated($i)'");?>
<span class='input-group-btn'>
<a id='preview<?php echo $i;?>' href="<?php echo $this->createLink('story', 'view', "storyID=$currentStory", '', true)?>" class='btn iframe btn-link btn-icon btn-copy' data-width='80%' title='<?php echo $lang->preview;?>'><i class='icon-eye'></i></a>
<a href='javascript:copyStoryTitle(<?php echo $i;?>)' class='btn btn-link btn-icon btn-copy' title='<?php echo $lang->task->copyStoryTitle; ?>'><i class='icon-arrow-right'></i></a>
</span>
</div>
</td>
<td style='overflow:visible'>
<div class="input-control has-icon-right">
<?php echo html::input("name[$i]", $story->title, "class='form-control title-import'");?>
<div class="colorpicker">
<button type="button" class="btn btn-link dropdown-toggle" data-toggle="dropdown"><span class="cp-title"></span><span class="color-bar"></span><i class="ic"></i></button>
<ul class="dropdown-menu clearfix pull-right">
<li class="heading"><?php echo $lang->task->colorTag;?><i class="icon icon-close"></i></li>
</ul>
<?php echo html::hidden("color[$i]", '', "data-provide='colorpicker' data-icon='color' data-wrapper='input-control-icon-right' data-update-color='#name\\[$i\\]'");?>
</div>
</div>
</td>
<td><?php echo html::select("type[$i]", $lang->task->typeList, $taskType, 'class=form-control');?></td>
<td style='overflow:visible'><?php echo html::select("assignedTo[$i]", $members, $assignedTo, "class='form-control chosen'");?></td>
<td><?php echo html::input("estimate[$i]", $estimate, "class='form-control text-center'");?></td>
<td>
<div class='input-group'>
<?php
echo html::input("estStarted[$i]", '', "class='form-control text-center form-date' onkeyup='toggleCheck(this)'");
if($i != 1) echo "<span class='input-group-addon estStartedBox'><input type='checkbox' name='estStartedDitto[$i]' id='estStartedDitto$i' " . ($i > 1 ? "checked" : '') . " /> {$lang->task->ditto}</span>";
?>
</div>
</td>
<td>
<div class='input-group'>
<?php
echo html::input("deadline[$i]", '', "class='form-control text-center form-date' onkeyup='toggleCheck(this)'");
if($i != 1) echo "<span class='input-group-addon deadlineBox'><input type='checkbox' name='deadlineDitto[$i]' id='deadlineDitto$i' " . ($i > 1 ? "checked" : '') . " /> {$lang->task->ditto}</span>";
?>
</div>
</td>
<td><?php echo html::select("pri[$i]", (array)$lang->task->priList, $pri, 'class=form-control');?></td>
<td class='c-actions text-left'>
<a href='javascript:;' onclick='addRow(this)' class='btn btn-link'><i class='icon-plus'></i></a>
<?php if($i > 1):?>
<a href='javascript:;' onclick='deleteRow(this)' class='btn btn-link'><i class='icon icon-close'></i></a>
<?php endif;?>
</td>
</tr>
<?php $i ++;?>
<?php endforeach;?>
</tbody>
<tfoot>
<tr>
<td colspan='11' class='text-center form-actions'>
<?php echo html::hidden('syncFields', implode(',', $syncFields));?>
<?php echo html::submitButton();?>
<?php echo html::backButton();?>
</td>
</tr>
</tfoot>
</table>
</div>
</form>
</div>
<?php js::set('rowIndex', -- $i);?>
<div>
<?php $i = '%i%';?>
<table class='hidden'>
<tr id='addRow' class='hidden'>
<td class='text-left c-id'><?php echo $i;?></td>
<td style='overflow:visible'>
<?php echo html::select("module[$i]", $modules, 'ditto', "class='form-control chosen' onchange='setStories(this.value, $executionID, $i)'")?>
</td>
<td style='overflow: visible'>
<div class='input-group'>
<?php echo html::select("story[$i]", $storyPairs, 'ditto', "class='form-control chosen' onchange='setStoryRelated($i)'");?>
<span class='input-group-btn'>
<a id='preview<?php echo $i;?>' href='#' class='btn iframe btn-link btn-icon btn-copy' style='pointer-events:none' data-width='80%' disabled='disabled' title='<?php echo $lang->preview; ?>'><i class='icon-eye'></i></a>
<a href='javascript:copyStoryTitle(<?php echo $i;?>)' class='btn btn-link btn-icon btn-copy' title='<?php echo $lang->task->copyStoryTitle; ?>'><i class='icon-arrow-right'></i></a>
</span>
</div>
</td>
<td style='overflow:visible'>
<div class="input-control has-icon-right">
<?php echo html::input("name[$i]", '', "class='form-control title-import'");?>
<div class="colorpicker">
<button type="button" class="btn btn-link dropdown-toggle" data-toggle="dropdown"><span class="cp-title"></span><span class="color-bar"></span><i class="ic"></i></button>
<ul class="dropdown-menu clearfix pull-right">
<li class="heading"><?php echo $lang->task->colorTag;?><i class="icon icon-close"></i></li>
</ul>
<?php echo html::hidden("color[$i]", '', "data-provide='colorpicker' data-icon='color' data-wrapper='input-control-icon-right' data-update-color='#name\\[$i\\]'");?>
</div>
</div>
</td>
<td><?php echo html::select("type[$i]", $lang->task->typeList, 'ditto', 'class=form-control');?></td>
<td style='overflow:visible'><?php echo html::select("assignedTo[$i]", $members, 'ditto', "class='form-control chosen'");?></td>
<td><?php echo html::input("estimate[$i]", '', "class='form-control text-center'");?></td>
<td>
<div class='input-group'>
<?php
echo html::input("estStarted[$i]", '', "class='form-control text-center form-date' onkeyup='toggleCheck(this)'");
echo "<span class='input-group-addon estStartedBox'><input type='checkbox' name='estStartedDitto[$i]' id='estStartedDitto$i' checked/> {$lang->task->ditto}</span>";
?>
</div>
</td>
<td>
<div class='input-group'>
<?php
echo html::input("deadline[$i]", '', "class='form-control text-center form-date' onkeyup='toggleCheck(this)'");
echo "<span class='input-group-addon deadlineBox'><input type='checkbox' name='deadlineDitto[$i]' id='deadlineDitto$i' checked/> {$lang->task->ditto}</span>";
?>
</div>
</td>
<td><?php echo html::select("pri[$i]", (array)$lang->task->priList, $pri, 'class=form-control');?></td>
<td class='c-actions text-left'>
<a href='javascript:;' onclick='addRow(this)' class='btn btn-link'><i class='icon-plus'></i></a>
<a href='javascript:;' onclick='deleteRow(this)' class='btn btn-link'><i class='icon icon-close'></i></a>
</td>
</tr>
</table>
</div>
<?php include '../../common/view/footer.html.php';?>
+3 -2
View File
@@ -128,7 +128,8 @@ function setStoryRelated(num)
*/
function setPreview(num)
{
var storyID = $('#story' + num).val();
var storyID = $('#story' + num).val();
var storyLink = '#';
if(storyID != 0 && storyID != 'ditto')
{
var link = createLink('story', 'ajaxGetInfo', 'storyID=' + storyID);
@@ -148,6 +149,7 @@ function setPreview(num)
var concat = storyLink.indexOf('?') >= 0 ? '&' : '?';
storyLink = storyLink + concat + 'onlybody=yes';
}
$('#preview' + num).removeAttr('disabled');
$('#preview' + num).modalTrigger({type:'iframe'});
$('#preview' + num).css('pointer-events', 'auto');
@@ -155,7 +157,6 @@ function setPreview(num)
}
else
{
storyLink = '#';
$('#preview' + num).attr('disabled', true);
$('#preview' + num).css('pointer-events', 'none');
$('#preview' + num).attr('href', storyLink);
+1 -1
View File
@@ -3804,7 +3804,7 @@ class taskModel extends model
$list = "<tr $trAttrs class='$trClass $showmore'>";
$list .= '<td>';
if($task->parent > 0) $list .= '<span class="label label-badge label-light" title="' . $this->lang->task->children . '">' . $this->lang->task->childrenAB . '</span> ';
$list .= html::a(helper::createLink('task', 'view', "id=$task->id"), $task->name, '', "data-app='project'");
$list .= common::hasPriv('task', 'view') ? html::a(helper::createLink('task', 'view', "id=$task->id"), $task->name, '', "style='color: $task->color'", "data-app='project'") : "<span style='color:$task->color'>$task->name</span>";
$list .= '</td>';
$list .= '<td>' . zget($users, $task->assignedTo, '') . '</td>';
$list .= "<td class='status-{$task->status}'>" . $this->processStatus('task', $task) . '</td>';
+1 -1
View File
@@ -118,7 +118,7 @@ $colspan = count($visibleFields) + 3;
<tr>
<td class='text-left c-id'><?php echo $i;?></td>
<td class="<?php echo zget($visibleFields, 'module', 'hidden')?> moduleBox" style='overflow:visible'>
<?php echo html::select("module[$i]", $modules, $moduleID, "class='form-control chosen' onchange='setStories(this.value, $execution->id)'")?>
<?php echo html::select("module[$i]", $modules, $moduleID, "class='form-control chosen' onchange='setStories(this.value, $execution->id, $i)'")?>
<?php echo html::hidden("parent[$i]", $parent);?>
</td>
<?php if($execution->lifetime != 'ops' and $execution->attribute != 'request' and $execution->attribute != 'review'):?>
+5 -5
View File
@@ -1068,15 +1068,14 @@ class user extends control
if($_POST)
{
if($needCreateFile) return print(js::reload('parent'));
if($needCreateFile) return $this->send(array('result' => 'success', 'locate' => 'reload'));
$result = $this->user->resetPassword();
if(dao::isError()) return print(js::error(dao::getError()));
if(!$result) return print(js::alert($this->lang->user->resetFail));
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(!$result) return $this->send(array('result' => 'fail', 'message' => $this->lang->user->resetFail));
echo js::alert($this->lang->user->resetSuccess);
$referer = helper::safe64Encode($this->createLink('index', 'index'));
return print(js::locate(inlink('logout', 'referer=' . $referer), 'parent'));
return $this->send(array('result' => 'success', 'message' => $this->lang->user->resetSuccess, 'locate' => $this->createLink('user', 'logout', 'referer=' . $referer)));
}
/* Remove the real path for security reason. */
@@ -1174,6 +1173,7 @@ class user extends control
$this->view->title = $this->lang->user->resetPWD;
$this->view->expired = $expired;
$this->view->user = empty($user) ? '' : $user;
$this->view->rand = $this->user->updateSessionRandom();
$this->display();
}
+2
View File
@@ -3,3 +3,5 @@
.w-enVerifyPassword {width: 150px !important;}
.c-id {width: 70px;}
.c-hours {width: 110px;}
#mainContent table > tbody > tr > td > div.text-danger.help-text {word-break: break-all;}
+1
View File
@@ -1,2 +1,3 @@
.alert-info > h5 > span {color: red;}
.btn-back {margin-left: 25px;}
.table tbody > tr > td div.text-danger.help-text {word-break: break-all;}
+1
View File
@@ -13,3 +13,4 @@ body {background: #1183fb linear-gradient(-90deg, #0a48d1 0%, #1183fb 100%); bac
#resetPanel .form-group .input-group.required:after {top: 6px;}
#resetPanel .form-actions > .btn-wide {min-width: 45%;}
#resetPanel .form-actions > a.btn-wide {margin-right: 0px;}
#resetForm .form-group div.text-danger.help-text {word-break: break-all;}
+2 -1
View File
@@ -92,11 +92,12 @@ $(function()
$('#password2').change(function(){password2Encrypted = false});
$('#submit').click(function()
{
if(!password1Encrypted && !password2Encrypted)
if(!password1Encrypted || !password2Encrypted)
{
var password1 = $('#password1').val();
var password2 = $('#password2').val();
var passwordStrength = computePasswordStrength(password1);
if(!password1Encrypted) $("#passwordLength").val(password1.length);
if($("form input[name=passwordStrength]").length == 0) $('#submit').after("<input type='hidden' name='passwordStrength' value='0' />");
$("form input[name=passwordStrength]").val(passwordStrength);
+2 -1
View File
@@ -6,11 +6,12 @@ $(function()
$('#password2').change(function(){password2Encrypted = false});
$('#submit').click(function()
{
if(!password1Encrypted && !password2Encrypted)
if(!password1Encrypted || !password2Encrypted)
{
var password1 = $('#password1').val().trim();
var password2 = $('#password2').val().trim();
var passwordStrength = computePasswordStrength(password1);
if(!password1Encrypted) $("#passwordLength").val(password1.length);
if($("form input[name=passwordStrength]").length == 0) $('#submit').after("<input type='hidden' name='passwordStrength' value='0' />");
$("form input[name=passwordStrength]").val(passwordStrength);
+21 -4
View File
@@ -1,10 +1,27 @@
$(document).ready(function()
{
var password1Encrypted = false
var password2Encrypted = false
$('#password1').change(function(){password1Encrypted = false});
$('#password2').change(function(){password2Encrypted = false});
$('form #submit').click(function()
{
var password = $('#password1').val().trim();
var passwordStrength = computePasswordStrength(password);
if(!password1Encrypted || !password2Encrypted)
{
var password1 = $('#password1').val().trim();
var password2 = $('#password2').val().trim();
var passwordStrength = computePasswordStrength(password1);
$('form').prepend("<input type='hidden' name='passwordStrength' value=" + passwordStrength + "/>");
});
if($("form input[name=passwordStrength]").length == 0) $('#submit').after("<input type='hidden' name='passwordStrength' value='0' />");
$("form input[name=passwordStrength]").val(passwordStrength);
var rand = $('input#verifyRand').val();
if(password1 && !password1Encrypted) $('#password1').val(md5(password1) + rand);
if(password2 && !password2Encrypted) $('#password2').val(md5(password2) + rand);
password1Encrypted = true;
password2Encrypted = true;
$('form').prepend("<input type='hidden' name='passwordStrength' value='" + passwordStrength + "'>");
$('form').prepend("<input type='hidden' name='passwordLength' value='" + password1.length + "'>");
}
})
});
+19 -5
View File
@@ -10,13 +10,27 @@ $(function()
}, 1000);
}
$('#password1').attr('id', 'password');
var password1Encrypted = false
var password2Encrypted = false
$('#password1').change(function(){password1Encrypted = false});
$('#password2').change(function(){password2Encrypted = false});
$('#submit').click(function()
{
var password1 = $('#password').val();
var passwordStrength = computePasswordStrength(password1);
if(!password1Encrypted || !password2Encrypted)
{
var password1 = $('#password1').val().trim();
var password2 = $('#password2').val().trim();
var passwordStrength = computePasswordStrength(password1);
if(!password1Encrypted) $("#passwordLength").val(password1.length);
$("form input[id=passwordStrength]").val(passwordStrength);
if($("form input[name=passwordStrength]").length == 0) $('#submit').after("<input type='hidden' name='passwordStrength' value='0' />");
$("form input[name=passwordStrength]").val(passwordStrength);
var rand = $('input#verifyRand').val();
if(password1 && !password1Encrypted) $('#password1').val(md5(password1) + rand);
if(password2 && !password2Encrypted) $('#password2').val(md5(password2) + rand);
password1Encrypted = true;
password2Encrypted = true;
}
})
})
+5
View File
@@ -224,9 +224,14 @@ $lang->user->placeholder->loginAccount = 'Enter your account';
$lang->user->placeholder->loginUrl = 'Enter your ZenTao address';
$lang->user->placeholder->email = 'Enter your email';
$lang->user->placeholder->passwordStrength[0] = '≥6 letters.';
$lang->user->placeholder->passwordStrength[1] = 'Buchstaben und Ziffern. Mindestens 6 Zeichen';
$lang->user->placeholder->passwordStrength[2] = 'Buchstaben, Ziffern und Sonderzeichen. Mindestens 10 Zeichen';
$lang->user->placeholder->passwordStrengthCheck[0] = 'The password should be ≥ 6 letters.';
$lang->user->placeholder->passwordStrengthCheck[1] = 'The password should be ≥ 6 letters, combination of uppercase, lowercase letters and numbers.';
$lang->user->placeholder->passwordStrengthCheck[2] = 'The password should be ≥ 10 letters, combination of uppercase, lowercase letters, numbers, and special symbols.';
$lang->user->error = new stdclass();
$lang->user->error->account = "ID %s,Konto muss Buchstaben, Unterstriche oder Ziffern enthalten. Mindestens 3 Zeichen.";
$lang->user->error->accountDupl = "ID %s,Konto wurde genutzt.";
+5
View File
@@ -224,9 +224,14 @@ $lang->user->placeholder->loginAccount = 'Enter your account';
$lang->user->placeholder->loginUrl = 'Enter your ZenTao address';
$lang->user->placeholder->email = 'Enter your email';
$lang->user->placeholder->passwordStrength[0] = '≥6 letters.';
$lang->user->placeholder->passwordStrength[1] = '>= 6 letters and numbers';
$lang->user->placeholder->passwordStrength[2] = '>= 10 letters, numbers and special characters';
$lang->user->placeholder->passwordStrengthCheck[0] = 'The password should be ≥ 6 letters.';
$lang->user->placeholder->passwordStrengthCheck[1] = 'The password should be ≥ 6 letters, combination of uppercase, lowercase letters and numbers.';
$lang->user->placeholder->passwordStrengthCheck[2] = 'The password should be ≥ 10 letters, combination of uppercase, lowercase letters, numbers, and special symbols.';
$lang->user->error = new stdclass();
$lang->user->error->account = "ID %s,account must be >= 3 letters, underline or numbers";
$lang->user->error->accountDupl = "ID %s,account is used.";
+5
View File
@@ -224,9 +224,14 @@ $lang->user->placeholder->loginAccount = 'Enter your account';
$lang->user->placeholder->loginUrl = 'Enter your ZenTao address';
$lang->user->placeholder->email = 'Enter your email';
$lang->user->placeholder->passwordStrength[0] = 'Le mot de passe doit ≥ 6 caractè res.';
$lang->user->placeholder->passwordStrength[1] = '>= 6 lettres et chiffres';
$lang->user->placeholder->passwordStrength[2] = '>= 10 lettres, chiffres et caractères spéciaux';
$lang->user->placeholder->passwordStrengthCheck[0] = 'Le mot de passe doit ≥ 6 caractères.';
$lang->user->placeholder->passwordStrengthCheck[1] = 'Le mot de passe doit ≥ 6 caractères, combinaison de lettres majuscules, minuscules et de chiffres.';
$lang->user->placeholder->passwordStrengthCheck[2] = 'Le mot de passe doit ≥ 10 caractères, combinaison de lettres majuscules, minuscules, de chiffres et de symboles spéciaux.';
$lang->user->error = new stdclass();
$lang->user->error->account = "ID %s,compte doit être >= 3 lettres, souligné ou chiffres";
$lang->user->error->accountDupl = "ID %s,compte déjà utilisé par quelqu'un d'autre.";
+7 -2
View File
@@ -224,8 +224,13 @@ $lang->user->placeholder->loginAccount = '请输入用户名';
$lang->user->placeholder->loginUrl = '请输入禅道系统网址';
$lang->user->placeholder->email = '请输入邮箱';
$lang->user->placeholder->passwordStrength[1] = '6位以上,包含大小写字母,数字。';
$lang->user->placeholder->passwordStrength[2] = '10位以上,包含大小写字母,数字,特殊字符。';
$lang->user->placeholder->passwordStrength[0] = '密码必须6位及以上。';
$lang->user->placeholder->passwordStrength[1] = '6位及以上,包含大小写字母,数字。';
$lang->user->placeholder->passwordStrength[2] = '10位及以上,包含大小写字母,数字,特殊字符。';
$lang->user->placeholder->passwordStrengthCheck[0] = '密码须6位及以上。';
$lang->user->placeholder->passwordStrengthCheck[1] = '密码必须6位及以上,且包含大小写字母、数字。';
$lang->user->placeholder->passwordStrengthCheck[2] = '密码必须10位及以上,且包含大小写字母、数字、特殊符号。';
$lang->user->error = new stdclass();
$lang->user->error->account = "【ID %s】的用户名应该为:三位以上的英文、数字或下划线的组合";
+27 -19
View File
@@ -320,7 +320,7 @@ class userModel extends model
->setIF($this->post->password1 == false, 'password', '')
->setIF($this->post->email != false, 'email', trim($this->post->email))
->join('visions', ',')
->remove('new, group, password1, password2, verifyPassword, passwordStrength')
->remove('new, group, password1, password2, verifyPassword, passwordStrength,passwordLength')
->get();
if(empty($_POST['verifyPassword']) or $this->post->verifyPassword != md5($this->app->user->password . $this->session->rand))
@@ -544,7 +544,7 @@ class userModel extends model
->setIF($this->post->password1 != false, 'password', substr($this->post->password1, 0, 32))
->setIF($this->post->email != false, 'email', trim($this->post->email))
->join('visions', ',')
->remove('new, password1, password2, groups,verifyPassword, passwordStrength')
->remove('new, password1, password2, groups,verifyPassword, passwordStrength,passwordLength')
->get();
if(empty($_POST['verifyPassword']) or $this->post->verifyPassword != md5($this->app->user->password . $this->session->rand))
@@ -786,7 +786,7 @@ class userModel extends model
$user = fixer::input('post')
->setIF($this->post->password1 != false, 'password', substr($this->post->password1, 0, 32))
->remove('account, password1, password2, originalPassword, passwordStrength')
->remove('account, password1, password2, originalPassword, passwordStrength,passwordLength')
->get();
if(empty($_POST['originalPassword']) or $this->post->originalPassword != md5($this->app->user->password . $this->session->rand))
@@ -800,6 +800,7 @@ class userModel extends model
$this->app->user->modifyPassword = false;
if(!dao::isError())
{
if(!empty($this->app->user->modifyPasswordReason)) $this->app->user->modifyPasswordReason = '';
$this->loadModel('score')->create('user', 'changePassword', $this->computePasswordStrength($this->post->password1));
}
}
@@ -818,7 +819,7 @@ class userModel extends model
$user = $this->getById($this->post->account);
if(!$user) return false;
$password = md5($this->post->password1);
$password = substr($this->post->password1, 0, 32);
$this->dao->update(TABLE_USER)->set('password')->eq($password)->autoCheck()->where('account')->eq($this->post->account)->exec();
return !dao::isError();
}
@@ -833,17 +834,28 @@ class userModel extends model
{
$_POST['password1'] = trim($_POST['password1']);
$_POST['password2'] = trim($_POST['password2']);
if(!$canNoPassword and empty($_POST['password1'])) dao::$errors['password'][] = sprintf($this->lang->error->notempty, $this->lang->user->password);
if(!$canNoPassword and empty($_POST['password1'])) dao::$errors['password1'][] = sprintf($this->lang->error->notempty, $this->lang->user->password) . '<br/>';
if($this->post->password1 != false)
{
if($this->post->password1 != $this->post->password2) dao::$errors['password'][] = $this->lang->error->passwordsame;
if(!validater::checkReg($this->post->password1, '|(.){6,}|')) dao::$errors['password'][] = $this->lang->error->passwordrule;
if(isset($this->config->safe->mode) and ($this->post->passwordStrength < $this->config->safe->mode)) dao::$errors['password1'][] = zget($this->lang->user->placeholder->passwordStrengthCheck, $this->config->safe->mode, $this->lang->user->weakPassword) . '<br/>';
if(isset($_POST['passwordLength']) and $this->post->passwordLength < 6 and empty(dao::$errors['password1'])) dao::$errors['password1'][] = zget($this->lang->user->placeholder->passwordStrengthCheck, 0, $this->lang->user->weakPassword) . '<br/>';
if($this->post->password1 != $this->post->password2) dao::$errors['password1'][] = $this->lang->error->passwordsame . '<br/>';
if(isset($this->config->safe->mode) and ($this->post->passwordStrength < $this->config->safe->mode)) dao::$errors['password'] = zget($this->lang->user->placeholder->passwordStrength, $this->config->safe->mode, $this->lang->user->weakPassword);
if(!empty($this->config->safe->changeWeak))
{
if(!isset($this->config->safe->weak)) $this->app->loadConfig('admin');
if(strpos(",{$this->config->safe->weak},", ",{$this->post->password1},") !== false) dao::$errors['password1'][] = sprintf($this->lang->user->errorWeak, $this->config->safe->weak);
if(strpos(",{$this->config->safe->weak},", ",{$this->post->password1},") !== false) dao::$errors['password1'] = sprintf($this->lang->user->errorWeak, $this->config->safe->weak);
$weaks = array();
foreach(explode(',', $this->config->safe->weak) as $weak)
{
$weak = md5(trim($weak));
$weaks[$weak] = $weak;
}
if(isset($weaks[substr($this->post->password1, 0, 32)])) dao::$errors['password1'] = sprintf($this->lang->user->errorWeak, $this->config->safe->weak);
}
}
return !dao::isError();
@@ -1656,7 +1668,6 @@ class userModel extends model
$strength = 0;
$length = strlen($password);
$uniqueChars = '';
$complexity = array();
$chars = str_split($password);
foreach($chars as $letter)
@@ -1664,7 +1675,7 @@ class userModel extends model
$asc = ord($letter);
if($asc >= 48 && $asc <= 57)
{
$complexity[2] = 2;
$complexity[0] = 1;
}
elseif($asc >= 65 && $asc <= 90)
{
@@ -1672,20 +1683,17 @@ class userModel extends model
}
elseif($asc >= 97 && $asc <= 122)
{
$complexity[0] = 1;
$complexity[2] = 4;
}
else
{
$complexity[3] = 3;
$complexity[3] = 8;
}
if(strpos($uniqueChars, $letter) === false) $uniqueChars .= $letter;
}
if(strlen($uniqueChars) > 4)$strength += strlen($uniqueChars) - 4;
$strength += array_sum($complexity) + (2 * (count($complexity) - 1));
if($length < 6 and $strength >= 10) $strength = 9;
$sumComplexity = array_sum($complexity);
$strength = $strength > 29 ? 29 : $strength;
$strength = floor($strength / 10);
if(($sumComplexity == 7 or $sumComplexity == 15) and $length >= 6) $strength = 1;
if($sumComplexity == 15 and $length >= 10) $strength = 2;
return $strength;
}
+2 -1
View File
@@ -13,7 +13,7 @@
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/datepicker.html.php';?>
<?php js::import($jsRoot . 'md5.js');?>
<?php if(!empty($config->safe->mode)) $lang->user->placeholder->password1 = $lang->user->placeholder->passwordStrength[$config->safe->mode]?>
<?php $lang->user->placeholder->password1 = zget($lang->user->placeholder->passwordStrength, $config->safe->mode, '');?>
<?php js::set('holders', $lang->user->placeholder);?>
<?php js::set('roleGroup', $roleGroup);?>
<?php
@@ -110,6 +110,7 @@ $showVisionList = count($visionList) > 1;
<th></th>
<td class='text-center form-actions'>
<?php if(!$showVisionList) echo html::hidden("visions[]", $this->config->vision);?>
<?php echo html::hidden('passwordLength', 0);?>
<?php echo html::submitButton();?>
<?php echo html::a($this->createLink('company', 'browse'), $lang->goback, '', "class='btn btn-wide'")?>
</td>
+2 -1
View File
@@ -71,7 +71,7 @@
<td>
<input type='password' style="display:none"> <!-- Disable input password by browser automatically. -->
<span class='input-group'>
<?php echo html::password('password1', '', "class='form-control disabled-ie-placeholder' onmouseup='checkPassword(this.value)' onkeyup='checkPassword(this.value)' placeholder='" . (!empty($config->safe->mode) ? $lang->user->placeholder->passwordStrength[$config->safe->mode] : '') . "'");?>
<?php echo html::password('password1', '', "class='form-control disabled-ie-placeholder' onmouseup='checkPassword(this.value)' onkeyup='checkPassword(this.value)' placeholder='" . zget($lang->user->placeholder->passwordStrength, $config->safe->mode, '') . "'");?>
<span class='input-group-addon' id='passwordStrength'></span>
</span>
</td>
@@ -117,6 +117,7 @@
</tr>
<tr>
<td colspan='2' class='text-center form-actions'>
<?php echo html::hidden('passwordLength', 0);?>
<?php echo html::submitButton();?>
<?php echo html::backButton();?>
</td>
+2 -1
View File
@@ -11,6 +11,7 @@
*/
?>
<?php include '../../common/view/header.lite.html.php';?>
<?php js::import($jsRoot . 'md5.js');?>
<?php if($needCreateFile):?>
<div class='container mw-700px' style='margin-top:100px;'>
<div class='panel panel-default'>
@@ -34,7 +35,7 @@
<div class='panel-heading'>
<strong><?php echo $lang->user->resetPassword?></strong>
</div>
<form method='post' target='hiddenwin'>
<form method='post' class='form-ajax'>
<table class='table table-form'>
<tr>
<th><?php echo $lang->user->account?></th>
+4 -1
View File
@@ -10,6 +10,7 @@
*/
include '../../common/view/header.lite.html.php';
?>
<?php js::import($jsRoot . 'md5.js');?>
<?php js::set('expired', $expired);?>
<?php if($expired):?>
<style>body {background: none;}</style>
@@ -28,7 +29,7 @@ include '../../common/view/header.lite.html.php';
<div class='form-group'>
<label for='password1'><?php echo $lang->user->password;?></label>
<span class='input-group'>
<?php echo html::password('password1', '', "class='form-control' required placeholder='{$lang->user->placeholder->loginPassword}' onmouseup='checkPassword(this.value)' onkeyup='checkPassword(this.value)'");?>
<?php echo html::password('password1', '', "class='form-control' required placeholder='" . zget($lang->user->placeholder->loginPassword, $config->safe->mode, '') . "' onmouseup='checkPassword(this.value)' onkeyup='checkPassword(this.value)'");?>
<span class='input-group-addon' id='passwordStrength'></span>
</span>
</div>
@@ -41,6 +42,7 @@ include '../../common/view/header.lite.html.php';
<?php
echo html::hidden('account', $user->account);
echo html::hidden('passwordStrength', '');
echo html::hidden('passwordLength', 0);
echo html::submitButton($lang->user->submit);
echo html::a(inlink('login'), $lang->goback, '', 'class="btn btn-wide"');
?>
@@ -49,6 +51,7 @@ include '../../common/view/header.lite.html.php';
</tbody>
</table>
</form>
<?php echo html::hidden('verifyRand', $rand);?>
</div>
</div>
</div>
+1 -1
View File
@@ -8,7 +8,7 @@ INSERT INTO `zt_config` (`id`, `vision`, `owner`, `module`, `section`, `key`, `v
(6, 'rnd', 'system', 'project', '', 'unitList', 'CNY,USD'),
(7, 'rnd', 'system', 'project', '', 'defaultCurrency', 'CNY'),
(8, 'rnd', 'system', 'story', '', 'reviewRules', 'allpass'),
(10, 'rnd', 'system', 'common', 'global', 'version', '17.0.beta1'),
(10, '', 'system', 'common', 'global', 'version', '17.4'),
(11, 'rnd', 'system', 'common', 'global', 'sn', 'c8aa3269e181f2b9258ce96625de1497'),
(12, 'rnd', 'system', 'common', 'global', 'flow', 'full'),
(13, 'rnd', 'system', 'common', 'safe', 'mode', '1'),
+3 -1
View File
@@ -81,6 +81,8 @@ class db
$dbUsed = $this->getUsedDbList();
$lastDB = 0;
if(!empty($dbUsed)) $lastDB = max($dbUsed);
/* If all db is used. */
if($lastDB == $this->config->test->dbNum)
{
shell_exec("> $this->dbLogFile");
@@ -139,7 +141,7 @@ class db
*/
function initDB()
{
for($i = 1; $i < 11; $i++)
for($i = 1; $i <= $this->config->test->dbNum; $i++)
{
$this->dao->query('DROP DATABASE ' . $this->config->test->dbPrefix . $i);
$this->dao->query('CREATE DATABASE ' . $this->config->test->dbPrefix . $i);
+2 -1
View File
@@ -2,6 +2,7 @@
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
include dirname(dirname(dirname(__FILE__))) . '/class/action.class.php';
$db->switchDB();
su('admin');
/**
@@ -34,4 +35,4 @@ r($action->createTest($objectTypeList[3], $objectIDList[0], $actionTypeList[3]))
r($action->createTest($objectTypeList[4], $objectIDList[0], $actionTypeList[4], $comment)) && p('objectType,objectId,action,comment') && e('story,,comments,测试备注'); // 测试创建story 1 comment动态
r($action->createTest($objectTypeList[4], $objectIDList[0], $actionTypeList[4])) && p() && e(''); // 测试创建story 1 comment动态 不填写备注
r($action->createTest($objectTypeList[2], $objectIDList[0], $actionTypeList[5], '', '', $actor)) && p() && e('0'); // 测试创建游客 logout动态
system("./ztest init");
$db->restoreDB();
+7 -5
View File
@@ -10,10 +10,12 @@ title=测试 actionModel->getTrashes();
cid=1
pid=1
查询type all id desc排序的回收站信息 >> testsuite,,这是测试套件名称87;story,,软件需求48
查询type all id desc排序的回收站信息 >> story,,软件需求48;testsuite,,这是测试套件名称87
查询type hidden id asc排序的回收站信息 >> testcase,,这个是测试用例9
查询type hidden id asc排序的回收站信息 >> testcase,,这个是测试用例9
查询objectType all type all id desc排序的回收站信息 >> testsuite,,这是测试套件名称87;story,,软件需求48
查询objectType all type all id desc排序的回收站信息 >> story,,软件需求48;testsuite,,这是测试套件名称87
查询objectType all type hidden id asc排序的回收站信息 >> testcase,,这个是测试用例9
查询objectType all type hidden id asc排序的回收站信息 >> testcase,,这个是测试用例9
查询objectType story type all id asc排序的回收站信息 >> story,,软件需求48
查询objectType testcase hidden id asc排序的回收站信息 >> testcase,,这个是测试用例9
*/
@@ -29,4 +31,4 @@ r($action->getTrashesTest($objectTypeList[0], $typeList[0], $orderBy[1], $pager)
r($action->getTrashesTest($objectTypeList[0], $typeList[1], $orderBy[0], $pager)) && p('0:objectType,objectId,objectName') && e('testcase,,这个是测试用例9'); // 查询objectType all type hidden id asc排序的回收站信息
r($action->getTrashesTest($objectTypeList[0], $typeList[1], $orderBy[1], $pager)) && p('0:objectType,objectId,objectName') && e('testcase,,这个是测试用例9'); // 查询objectType all type hidden id asc排序的回收站信息
r($action->getTrashesTest($objectTypeList[1], $typeList[0], $orderBy[0], $pager)) && p('0:objectType,objectId,objectName') && e('story,,软件需求48'); // 查询objectType story type all id asc排序的回收站信息
r($action->getTrashesTest($objectTypeList[2], $typeList[1], $orderBy[0], $pager)) && p('0:objectType,objectId,objectName') && e('testcase,,这个是测试用例9'); // 查询objectType testcase hidden id asc排序的回收站信息
r($action->getTrashesTest($objectTypeList[2], $typeList[1], $orderBy[0], $pager)) && p('0:objectType,objectId,objectName') && e('testcase,,这个是测试用例9'); // 查询objectType testcase hidden id asc排序的回收站信息
+4 -1
View File
@@ -10,6 +10,9 @@ title=测试 actionModel->getTrashObjectTypes();
cid=1
pid=1
查询type all 的对象类型列表 >> story
查询type all 的对象类型列表 >> testcase
*/
$typeList = array('all', 'hidden');
@@ -17,4 +20,4 @@ $typeList = array('all', 'hidden');
$action = new actionTest();
r($action->getTrashObjectTypesTest($typeList[0])) && p('story:objectType') && e('story'); // 查询type all 的对象类型列表
r($action->getTrashObjectTypesTest($typeList[1])) && p('testcase:objectType') && e('testcase'); // 查询type all 的对象类型列表
r($action->getTrashObjectTypesTest($typeList[1])) && p('testcase:objectType') && e('testcase'); // 查询type all 的对象类型列表
+2 -1
View File
@@ -2,6 +2,7 @@
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
include dirname(dirname(dirname(__FILE__))) . '/class/action.class.php';
$db->switchDB();
su('admin');
/**
@@ -17,4 +18,4 @@ pid=1
$action = new actionTest();
r($action->hideAllTest()) && p('0:extra;1:extra;2:extra') && e('2;2;2'); // 隐藏回收站全部信息
system("./ztest init");
$db->restoreDB();
+2 -1
View File
@@ -2,6 +2,7 @@
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
include dirname(dirname(dirname(__FILE__))) . '/class/action.class.php';
$db->switchDB();
su('admin');
/**
@@ -24,4 +25,4 @@ r($action->hideOneTest($actionIDList[0])) && p('extra') && e('2'); // 隐藏acti
r($action->hideOneTest($actionIDList[1])) && p('extra') && e('2'); // 隐藏action 87
r($action->hideOneTest($actionIDList[2])) && p('extra') && e('2'); // 隐藏已隐藏action 9
r($action->hideOneTest($actionIDList[3])) && p('extra') && e('1'); // 隐藏非删除action 1
system("./ztest init");
$db->restoreDB();
+2 -1
View File
@@ -2,6 +2,7 @@
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
include dirname(dirname(dirname(__FILE__))) . '/class/action.class.php';
$db->switchDB();
su('admin');
/**
@@ -34,4 +35,4 @@ r($action->logHistoryTest($actionIDList[1], $changes2)) && p('0:field,old,new')
r($action->logHistoryTest($actionIDList[2], $changes3)) && p('0:field,old,new') && e('name,name1,name2'); // 测试新增actionID 10003 历史记录
r($action->logHistoryTest($actionIDList[3], $changes4)) && p('0:field,old,new') && e('code,code1,code2'); // 测试新增actionID 10004 历史记录
r($action->logHistoryTest($actionIDList[4], $changes5)) && p('0:field,old,new') && e('assignedTo,test2,test1'); // 测试新增actionID 10005 历史记录
system("./ztest init");
$db->restoreDB();
+2 -1
View File
@@ -2,6 +2,7 @@
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
include dirname(dirname(dirname(__FILE__))) . '/class/action.class.php';
$db->switchDB();
su('admin');
/**
@@ -28,4 +29,4 @@ r($action->readTest($objectType[1], $objectID[1])) && p('0:objectType,objectID,r
r($action->readTest($objectType[2], $objectID[2])) && p('0:objectType,objectID,read') && e('productplan,3,1'); // 测试对action 3 进行阅读操作
r($action->readTest($objectType[3], $objectID[3])) && p('0:objectType,objectID,read') && e('release,4,1'); // 测试对action 4 进行阅读操作
r($action->readTest($objectType[4], $objectID[4])) && p('0:objectType,objectID,read') && e('project,5,1'); // 测试对action 5 进行阅读操作
system("./ztest init");
$db->restoreDB();
+2 -1
View File
@@ -2,6 +2,7 @@
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
include dirname(dirname(dirname(__FILE__))) . '/class/action.class.php';
$db->switchDB();
su('admin');
/**
@@ -24,4 +25,4 @@ r($action->undeleteTest($actionIDList[0])) && p('extra') && e('0'); // 测试还
r($action->undeleteTest($actionIDList[1])) && p('extra') && e('0'); // 测试还原action 87
r($action->undeleteTest($actionIDList[2])) && p('extra') && e('0'); // 测试还原action 9
r($action->undeleteTest($actionIDList[3])) && p('extra') && e('1'); // 测试还原未删除action 1
system("./ztest init");
$db->restoreDB();
+2 -1
View File
@@ -2,6 +2,7 @@
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
include dirname(dirname(dirname(__FILE__))) . '/class/action.class.php';
$db->switchDB();
su('admin');
/**
@@ -27,4 +28,4 @@ r($action->updateCommentTest($actionIDList[1], $commentList[1])) && p('comment')
r($action->updateCommentTest($actionIDList[2], $commentList[2])) && p('comment') && e('备注3'); // 测试更新action 3的备注
r($action->updateCommentTest($actionIDList[3], $commentList[3])) && p('comment') && e('备注4'); // 测试更新action 4的备注
r($action->updateCommentTest($actionIDList[4], $commentList[4])) && p('comment') && e('备注5'); // 测试更新action 5的备注
system("./ztest init");
$db->restoreDB();
Regular → Executable
+6 -1
View File
@@ -10,6 +10,11 @@ title=测试 apiModel->create();
cid=1
pid=1
测试创建api >> 910
测试没有lib创建api >> 『API Library』should not be blank.
测试没有title创建api >> 『Name』should not be blank.
测试没有path创建api >> 『Request Path』should not be blank.
*/
$api = new apiTest();
@@ -46,4 +51,4 @@ $emptyPathApi['path'] = '';
r($api->createTest($normalApi)) && p('lib') && e('910'); //测试创建api
r($api->createTest($emptyLibApi)) && p('lib:0') && e('『API Library』should not be blank.'); //测试没有lib创建api
r($api->createTest($emptyTitleApi)) && p('title:0') && e('『Name』should not be blank.'); //测试没有title创建api
r($api->createTest($emptyPathApi)) && p('path:0') && e('『Request Path』should not be blank.'); //测试没有path创建api
r($api->createTest($emptyPathApi)) && p('path:0') && e('『Request Path』should not be blank.'); //测试没有path创建api
Regular → Executable
+4 -1
View File
@@ -10,6 +10,9 @@ title=测试 apiModel->createStruct();
cid=1
pid=1
创建数据结构 >> struct
创建没有结构名的数据结构 >> 『Name』should not be blank.
*/
global $tester;
@@ -32,4 +35,4 @@ $normalStruct->addedBy = $tester->app->user->account;
$normalStruct->addedDate = helper::now();
r($api->createStructTest($normalStruct)) && p('name') && e('struct'); //创建数据结构
r($api->createStructTest($emptyNameStruct)) && p('name:0') && e('『Name』should not be blank.'); //创建没有结构名的数据结构
r($api->createStructTest($emptyNameStruct)) && p('name:0') && e('『Name』should not be blank.'); //创建没有结构名的数据结构
Regular → Executable
+3 -1
View File
@@ -10,6 +10,8 @@ title=测试 apiModel->deleteRelease();
cid=1
pid=1
删除一个创建的发布 >> 0
*/
global $tester;
@@ -24,4 +26,4 @@ $normalRelease->addedDate = helper::now();
$release = $api->publishLibTest($normalRelease, false);
r($api->deleteReleaseTest($release->id, $release->lib)) && p('') && e('0'); //删除一个创建的发布
r($api->deleteReleaseTest($release->id, $release->lib)) && p('') && e('0'); //删除一个创建的发布
+3 -1
View File
@@ -10,6 +10,8 @@ title=测试 apiModel->getApiListByRelease();
cid=1
pid=1
创建api后创建发布,使用发布查找api >> 910
*/
global $tester;
@@ -44,4 +46,4 @@ $normalRelease->addedDate = helper::now();
$apiInfo = $api->createTest($normalApi, false);
$release = $api->publishLibTest($normalRelease, false);
r($api->getApiListByReleaseTest($release)) && p('0:lib') && e('910'); //创建api后创建发布,使用发布查找api
r($api->getApiListByReleaseTest($release)) && p('0:lib') && e('910'); //创建api后创建发布,使用发布查找api
Regular → Executable
+3 -1
View File
@@ -10,6 +10,8 @@ title=测试 apiModel->getLibById();
cid=1
pid=1
获取刚创建的api >> 910
*/
$api = new apiTest();
@@ -35,4 +37,4 @@ $data = array(
$normalApi = $data;
$apiInfo = $api->createTest($normalApi, false);
r($api->getLibByIdTest($apiInfo->id)) && p('lib') && e('910'); //获取刚创建的api
r($api->getLibByIdTest($apiInfo->id)) && p('lib') && e('910'); //获取刚创建的api
+6 -1
View File
@@ -10,6 +10,11 @@ title=测试 apiModel->getListByModuleId();
cid=1
pid=1
通过正常的libID、moduleID、releaseID查询api信息 >> 获取token
通过正常的libID、moduleID,不传releaseID,查询api信息 >> 获取我的个人信息
通过正常的libID,不传moduleID、releaseID查询api信息 >> 获取token
通过不存在的libID,moduleID,releaseID查询api信息 >> 0
*/
$api = new apiTest();
@@ -17,4 +22,4 @@ $api = new apiTest();
r($api->getListByModuleIdTest(1, 1, 1)) && p('title') && e('获取token'); //通过正常的libID、moduleID、releaseID查询api信息
r($api->getListByModuleIdTest(1, 1, 0)) && p('title') && e('获取我的个人信息'); //通过正常的libID、moduleID,不传releaseID,查询api信息
r($api->getListByModuleIdTest(1, 0, 0)) && p('title') && e('获取token'); //通过正常的libID,不传moduleID、releaseID查询api信息
r($api->getListByModuleIdTest(0, 0, 0)) && p('title') && e('0'); //通过不存在的libID,moduleID,releaseID查询api信息
r($api->getListByModuleIdTest(0, 0, 0)) && p('title') && e('0'); //通过不存在的libID,moduleID,releaseID查询api信息
Regular → Executable
+3 -1
View File
@@ -10,6 +10,8 @@ title=测试 apiModel->getRelease();
cid=1
pid=1
获取刚创建的发布 >> Version1
*/
global $tester;
@@ -23,4 +25,4 @@ $normalRelease->addedBy = $tester->app->user->account;
$normalRelease->addedDate = helper::now();
$release = $api->publishLibTest($normalRelease, false);
r($api->getReleaseTest($release->lib)) && p('version') && e('Version1'); //获取刚创建的发布
r($api->getReleaseTest($release->lib)) && p('version') && e('Version1'); //获取刚创建的发布
+3 -1
View File
@@ -10,6 +10,8 @@ title=测试 apiModel->getReleaseListByApi();
cid=1
pid=1
获取刚插入的发布信息 >> 910
*/
global $tester;
@@ -23,4 +25,4 @@ $normalRelease->addedBy = $tester->app->user->account;
$normalRelease->addedDate = helper::now();
$release = $api->publishLibTest($normalRelease, false);
r($api->getReleaseListByApiTest($release->lib, $release->id)) && p("{$release->id}:lib") && e('910'); //获取刚插入的发布信息
r($api->getReleaseListByApiTest($release->lib, $release->id)) && p("{$release->id}:lib") && e('910'); //获取刚插入的发布信息
Regular → Executable
+3 -1
View File
@@ -10,6 +10,8 @@ title=测试 apiModel->getStructByID();
cid=1
pid=1
获取刚创建的数据结构 >> struct
*/
global $tester;
@@ -24,4 +26,4 @@ $normalStruct->addedBy = $tester->app->user->account;
$normalStruct->addedDate = helper::now();
$struct = $api->createStructTest($normalStruct, false);
r($api->getStructByIDTest($struct->id)) && p('name') && e('struct'); //获取刚创建的数据结构
r($api->getStructByIDTest($struct->id)) && p('name') && e('struct'); //获取刚创建的数据结构
+3 -1
View File
@@ -10,6 +10,8 @@ title=测试 apiModel->getStructListByLibID();
cid=1
pid=1
用libID获取刚插入的数据结构 >> 910
*/
global $tester;
@@ -26,4 +28,4 @@ $normalStruct->addedDate = helper::now();
$struct = $api->createStructTest($normalStruct, false);
r($api->getStructListByLibIDTest($normalStruct->lib)) && p('0:lib') && e('910'); //用libID获取刚插入的数据结构
r($api->getStructListByLibIDTest($normalStruct->lib)) && p('0:lib') && e('910'); //用libID获取刚插入的数据结构
+3 -1
View File
@@ -10,6 +10,8 @@ title=测试 apiModel->getStructListByRelease();
cid=1
pid=1
创建api后创建发布,使用发布查找api >> 910
*/
global $tester;
@@ -45,4 +47,4 @@ $apiInfo = $api->createTest($normalApi, false);
$release = $api->publishLibTest($normalRelease, false);
r($api->getStructListByReleaseTest($release->lib)) && p('') && e('');
//r($api->getApiListByReleaseTest($release)) && p('0:lib') && e('910'); //创建api后创建发布,使用发布查找api
//r($api->getApiListByReleaseTest($release)) && p('0:lib') && e('910'); //创建api后创建发布,使用发布查找api
Regular → Executable
+4 -1
View File
@@ -10,6 +10,9 @@ title=测试 apiModel->publishLib();
cid=1
pid=1
没有版本名的发布 >> 『Version』should not be blank.
正常的发布 >> Version1
*/
global $tester;
@@ -30,4 +33,4 @@ $normalRelease->addedBy = $tester->app->user->account;
$normalRelease->addedDate = helper::now();
r($api->publishLibTest($emptyBuildRelease)) && p('version:0') && e('『Version』should not be blank.'); //没有版本名的发布
r($api->publishLibTest($normalRelease)) && p('version') && e('Version1'); //正常的发布
r($api->publishLibTest($normalRelease)) && p('version') && e('Version1'); //正常的发布
Regular → Executable
+3 -2
View File
@@ -10,6 +10,8 @@ title=测试 apiModel->update();
cid=1
pid=1
修改一个刚创建的api >> edittestapi
*/
$api = new apiTest();
@@ -50,10 +52,9 @@ $editData = array(
'responseExample' => ''
);
$normalApi = $data;
$editApi = $editData;
$apiInfo = $api->createTest($normalApi, false);
r($api->updateTest($apiInfo->id, $editApi)) && p('0:new') && e('edittestapi'); //修改一个刚创建的api
r($api->updateTest($apiInfo->id, $editApi)) && p('0:new') && e('edittestapi'); //修改一个刚创建的api
Regular → Executable
+4 -1
View File
@@ -10,6 +10,9 @@ title=测试 apiModel->updateStruct();
cid=1
pid=1
正常的修改 >> editStruct
没有名称的修改 >> 『Name』should not be blank.
*/
global $tester;
@@ -37,4 +40,4 @@ $emptyNameEditStruct['name'] = '';
$struct = $api->createStructTest($normalStruct, false);
r($api->updateStructTest($struct->id, $normalEditStruct, false)) && p('0:new') && e('editStruct'); //正常的修改
r($api->updateStructTest($struct->id, $emptyNameEditStruct)) && p('name:0') && e('『Name』should not be blank.'); //没有名称的修改
r($api->updateStructTest($struct->id, $emptyNameEditStruct)) && p('name:0') && e('『Name』should not be blank.'); //没有名称的修改
+3 -2
View File
@@ -10,11 +10,12 @@ title=测试 blockModel->getQaStatisticParams();
cid=1
pid=1
测试name >> 类型
测试control >> select
*/
$block = new blockTest();
r($block->getQaStatisticParamsTest()) && p('type:name') && e('类型'); //测试name
r($block->getQaStatisticParamsTest()) && p('type:control') && e('select');//测试control
r($block->getQaStatisticParamsTest()) && p('type:control') && e('select');//测试control
+2 -2
View File
@@ -10,10 +10,10 @@ title=测试 blockModel->getReleaseParams();
cid=1
pid=1
测试name >> 数量,20,input
*/
$block = new blockTest();
r($block->getReleaseParamsTest()) && p('name,default,control') && e('数量,20,input'); //测试name
r($block->getReleaseParamsTest()) && p('name,default,control') && e('数量,20,input'); //测试name
+6 -2
View File
@@ -10,7 +10,11 @@ title=测试 blockModel->getScrumListParams();
cid=1
pid=1
测试name和select >> 类型,select
测试options >> 未完成
测试options >> 进行中
测试options >> 全部
测试options >> 我参与
*/
@@ -20,4 +24,4 @@ r($block->getScrumListParamsTest()) && p('name,control') && e('类型,select
r($block->getScrumListParamsTest()) && p('options:undone') && e('未完成'); //测试options
r($block->getScrumListParamsTest()) && p('options:doing') && e('进行中'); //测试options
r($block->getScrumListParamsTest()) && p('options:all') && e('全部'); //测试options
r($block->getScrumListParamsTest()) && p('options:involved') && e('我参与'); //测试options
r($block->getScrumListParamsTest()) && p('options:involved') && e('我参与'); //测试options
+1 -1
View File
@@ -16,4 +16,4 @@ pid=1
$block = new blockTest();
r($block->getScrumProductParamsTest()) && p('count:name;count:default;count:control') && e('数量;20;input'); // 测试获取产品区块的参数
r($block->getScrumProductParamsTest()) && p('count:name;count:default;count:control') && e('数量;20;input'); // 测试获取产品区块的参数
+1 -1
View File
@@ -16,4 +16,4 @@ pid=1
$block = new blockTest();
r($block->getScrumRoadMapParamsTest()) && p() && e('0'); // 测试获取产品路线图区块的参数
r($block->getScrumRoadMapParamsTest()) && p() && e('0'); // 测试获取产品路线图区块的参数

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