Merge branch 'master' of https://gitlab.zcorp.cc/easycorp/zentaopms into release/zentaopms_18.3

This commit is contained in:
tianshujie
2023-03-29 08:16:56 +08:00
9 changed files with 163 additions and 128 deletions
+55 -49
View File
@@ -136,7 +136,7 @@ class commonModel extends model
*
* @param object $execution
* @access public
* @return object $parentExecution
* @return object|false $parentExecution
*/
public function syncExecutionByChild($execution)
{
@@ -1474,15 +1474,20 @@ class commonModel extends model
echo "<li class='dropdown-submenu' id='downloadMobile'><a href='javascript:;'>" . $lang->downloadMobile . "</a><ul class='dropdown-menu pull-left''>";
/* Intranet users use local pictures. */
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://www.zentao.net/page/appqrcode.json');
curl_setopt($curl, CURLOPT_TIMEOUT_MS, 200);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, 200);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
$connected = curl_exec($curl);
curl_close($curl);
$connected = false;
if(extension_loaded('curl'))
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://www.zentao.net/page/appqrcode.json');
curl_setopt($curl, CURLOPT_TIMEOUT_MS, 200);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, 200);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
$connected = curl_exec($curl);
curl_close($curl);
}
if($connected)
{
echo "<li><div class='mobile-qrcode'><iframe src='https://www.zentao.net/page/appqrcode.html?v={$config->version}' frameborder='0' scrolling='no' seamless></iframe></div></li>";
@@ -1557,7 +1562,7 @@ class commonModel extends model
}
else
{
$orderBy = "" . trim($fieldName, '`') . "" . '_' . 'asc';
$orderBy = trim($fieldName, '`') . '_' . 'asc';
$className = 'header';
}
@@ -1569,10 +1574,9 @@ class commonModel extends model
}
/**
* Print link to a module's method.
*
* Print link to an modules' methd.
*
* Before printing, check the privilege first. If no privilege, return fasle. Else, print the link, return true.
* Before printing, check the privilege first. If no privilege, return false. Else, print the link, return true.
*
* @param string $module the module name
* @param string $method the method
@@ -1629,7 +1633,7 @@ class commonModel extends model
if(!commonModel::hasPriv('action', 'comment', $object)) return false;
echo html::commonButton('<i class="icon icon-chat-line"></i> ' . $lang->action->create, '', 'btn btn-link pull-right btn-comment');
echo <<<EOD
echo <<<EOF
<div class="modal fade modal-comment">
<div class="modal-dialog">
<div class="modal-content">
@@ -1658,7 +1662,7 @@ $(function()
if(\$body.hasClass('hide-modal-close')) \$body.removeClass('hide-modal-close');
});
</script>
EOD;
EOF;
}
/**
@@ -2143,9 +2147,9 @@ EOD;
* Get the previous and next object.
*
* @param string $type story|task|bug|case
* @param string $objectID
* @param int $objectID
* @access public
* @return void
* @return object
*/
public function getPreAndNextObject($type, $objectID)
{
@@ -2267,6 +2271,7 @@ EOD;
*
* @param string $sql
* @param string $objectType story|task|bug|testcase
* @param bool $onlyCondition
* @access public
* @return void
*/
@@ -2836,7 +2841,7 @@ EOD;
/**
* Check whether view type is tutorial
* @access public
* @return boolean
* @return bool
*/
public static function isTutorialMode()
{
@@ -3095,23 +3100,23 @@ EOD;
/**
* Response.
*
* @param string $code
* @param string $reasonPhrase
* @access public
* @return void
*/
public function response($code)
public function response($reasonPhrase)
{
$response = new stdclass();
if(isset($this->config->entry->errcode))
{
$response->errcode = $this->config->entry->errcode[$code];
$response->errmsg = urlencode($this->lang->entry->errmsg[$code]);
$response->errcode = $this->config->entry->errcode[$reasonPhrase];
$response->errmsg = urlencode($this->lang->entry->errmsg[$reasonPhrase]);
die(urldecode(json_encode($response)));
}
else
{
$response->error = $code;
$response->error = $reasonPhrase;
die(urldecode(json_encode($response)));
}
}
@@ -3120,10 +3125,10 @@ EOD;
/**
* Http response with header.
*
* @param string $url
* @param string|array $data
* @param array $options This is option and value pair, like CURLOPT_HEADER => true. Use curl_setopt function to set options.
* @param array $headers Set request headers.
* @param string $url
* @param string|array|object $data
* @param array $options This is option and value pair, like CURLOPT_HEADER => true. Use curl_setopt function to set options.
* @param array $headers Set request headers.
* @static
* @access public
* @return string
@@ -3140,16 +3145,16 @@ EOD;
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($curl, CURLOPT_USERAGENT, 'Sae T OAuth2 v0.1');
curl_setopt($curl, CURLOPT_USERAGENT, 'ZenTao PMS ' . $app->config->version);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_ENCODING, "");
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_ENCODING, '');
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLINFO_HEADER_OUT, TRUE);
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_URL, $url);
@@ -3175,8 +3180,8 @@ EOD;
{
$field = explode(':', $item);
if(count($field) < 2) continue;
$headerkey = array_shift($field);
$newHeader[$headerkey] = join('', $field);
$headerKey = array_shift($field);
$newHeader[$headerKey] = join('', $field);
}
curl_close($curl);
@@ -3240,17 +3245,17 @@ EOD;
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($curl, CURLOPT_USERAGENT, 'Sae T OAuth2 v0.1');
curl_setopt($curl, CURLOPT_USERAGENT, 'ZenTao PMS ' . $app->config->version);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_ENCODING, "");
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($curl, CURLOPT_HEADER, FALSE);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 2);
curl_setopt($curl, CURLINFO_HEADER_OUT, TRUE);
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_URL, $url);
@@ -3357,13 +3362,13 @@ EOD;
/**
* Get relations for two object.
*
* @param varchar $atype
* @param int $aid
* @param varchar $btype
* @param int $bid
* @param string $AType
* @param int $AID
* @param string $BType
* @param int $BID
*
* @access public
* @return string
* @return array
*/
public function getRelations($AType = '', $AID = 0, $BType = '', $BID = 0)
{
@@ -3386,7 +3391,7 @@ EOD;
* @param array $params
*
* @access public
* @return string
* @return void
*/
static public function setMenuVars($moduleName, $objectID, $params = array())
{
@@ -3463,8 +3468,9 @@ EOD;
}
}
/*
/**
* Replace the %s of one key of a menu by objectID or $params.
*
* @param object $menu
* @param int $objectID
* @param array $params
+5 -1
View File
@@ -67,7 +67,11 @@
if($execution->type == 'stage') $isClickable = $this->programplan->checkLeafStage($execution->id) ? true : false;
?>
<td title='<?php echo $execution->title;?>'>
<a href='javascript:void(0);' <?php echo $isClickable ? "onclick='locateView(\"execution\", $execution->id)'" : '';?>><?php echo $execution->name;?></a>
<?php if($isClickable):?>
<a href='javascript:void(0);' onclick="locateView('execution', <?php echo $execution->id;?>)"><?php echo $execution->name;?></a>
<?php else:?>
<?php echo $execution->name;?>
<?php endif;?>
</td>
<?php else:?>
<td title='<?php echo $execution->title;?>'><?php echo $execution->name;?></td>
+23 -39
View File
@@ -376,15 +376,7 @@ class personnelModel extends model
}
/* The number of hours per person. */
$userHours = array();
if($this->config->edition != 'open')
{
$userHours = $this->getUserEffortHours($userTasks);
}
else
{
$userHours = $this->getUserHours($userTasks);
}
$userHours = $this->getUserHours($userTasks);
foreach($userHours as $account => $hours)
{
@@ -395,33 +387,6 @@ class personnelModel extends model
return $invest;
}
/**
* Get user hours.
*
* @param object $userTasks
* @access public
* @return object
*/
public function getUserEffortHours($userTasks)
{
$accounts = array();
$taskIDList = array();
foreach($userTasks as $account => $taskID)
{
$accounts[] = $account;
$taskIDList = array_merge($taskIDList, $taskID);
}
$userHours = $this->dao->select('account, sum(`left`) as `left`, sum(consumed) as consumed')->from(TABLE_EFFORT)
->where('account')->in($accounts)
->andWhere('deleted')->eq(0)
->andWhere('objectType')->eq('task')
->andWhere('objectID')->in($taskIDList)
->groupBy('account')
->fetchAll('account');
return $userHours;
}
/**
* Get user hours.
*
@@ -439,12 +404,31 @@ class personnelModel extends model
$taskIDList = array_merge($taskIDList, $taskID);
}
$userHours = $this->dao->select('account, sum(`left`) as `left`, sum(consumed) as consumed')->from(TABLE_EFFORT)
$effortList = $this->dao->select('id, account, objectID , `left`, consumed')->from(TABLE_EFFORT)
->where('account')->in($accounts)
->andWhere('deleted')->eq(0)
->andWhere('objectID')->in($taskIDList)
->andWhere('objectType')->eq('task')
->groupBy('account')
->fetchAll('account');
->orderBy('id_asc')
->fetchGroup('account', 'id');
$userHours = array();
foreach($effortList as $account => $efforts)
{
$latestLeft = array();
$userHours[$account] = new stdclass();
$userHours[$account]->left = 0;
$userHours[$account]->consumed = 0;
foreach($efforts as $effort)
{
$latestLeft[$effort->objectID] = $effort->left;
$userHours[$account]->consumed += $effort->consumed;
}
$userHours[$account]->left = array_sum($latestLeft);
}
return $userHours;
}
+1 -1
View File
@@ -1871,7 +1871,7 @@ class repoModel extends model
$_POST['objectType'][1] = 'task';
$_POST['objectID'][1] = $taskID;
$_POST['work'][1] = str_replace('<br />', "\n", $action->comment);
if(is_dir($this->app->getModuleRoot() . 'effort'))
if($this->config->edition != 'open')
{
$this->loadModel('effort')->batchCreate();
}
-1
View File
@@ -237,7 +237,6 @@ class storyModel extends model
->setIF(!in_array($this->post->source, $this->config->story->feedbackSource), 'notifyEmail', '')
->setIF($executionID > 0, 'stage', 'projected')
->setIF($bugID > 0, 'fromBug', $bugID)
->setIF($this->post->assignedTo, 'assignedDate', helper::now())
->join('assignedTo', '')
->join('mailto', ',')
->stripTags($this->config->story->editor->create['id'], $this->config->allowedTags)
+4 -2
View File
@@ -59,7 +59,7 @@ foreach(explode(',', $config->story->create->requiredFields) as $field)
<?php if($branches and $type != 'story') echo html::select('branch', $branches, $branch, "onchange='loadBranch();' class='form-control chosen control-branch'");?>
</div>
</td>
<?php if(!((!$branches and $type == 'story') or $type == 'requirement')):?>
<?php if($branches and $type == 'story'):?>
<td colspan='2' id='assignedToBox' class="switchBranch">
<div class='input-group'>
<div class="input-group-addon assignedTo"><?php echo $lang->story->assignedTo;?></div>
@@ -128,7 +128,8 @@ foreach(explode(',', $config->story->create->requiredFields) as $field)
<i class="icon-exclamation-sign"></i> <?php echo $lang->story->notice->branch;?>
</td>
</tr>
<tr class='<?php if($branches) echo "hidden"; ?> switchBranch'>
<?php if(!$branches):?>
<tr class='switchBranch'>
<?php if(!$hiddenPlan):?>
<th class='planTh'><?php echo $lang->story->planAB;?></th>
<td colspan="2">
@@ -159,6 +160,7 @@ foreach(explode(',', $config->story->create->requiredFields) as $field)
</div>
</td>
</tr>
<?php endif;?>
<tr class='sourceBox <?php echo $hiddenSource;?>'>
<th><?php echo $lang->story->source;?></th>
<td colspan='2'>
+19 -7
View File
@@ -109,13 +109,14 @@ class personnelTest
}
/**
* getUserEffortHoursTest
* GetUserHoursTest
*
* @param mixed $projectID
* @param mixed $projectID
* @param array $accounts
* @access public
* @return void
*/
public function getUserEffortHoursTest($projectID)
public function getUserHoursTest($projectID, $accounts)
{
global $tester;
$projects = $tester->dao->select('id')->from(TABLE_PROJECT)->where('id')->in($projectID)->fetchall('id');
@@ -124,6 +125,17 @@ class personnelTest
->andWhere('deleted')->eq('0')
->fetchAll('id');
/* Initialize personnel related tasks. */
$invest = array();
foreach($accounts as $account)
{
$invest[$account]['createdTask'] = 0;
$invest[$account]['finishedTask'] = 0;
$invest[$account]['pendingTask'] = 0;
$invest[$account]['consumedTask'] = 0;
$invest[$account]['leftTask'] = 0;
}
$userTasks = array();
foreach($tasks as $task)
@@ -131,23 +143,23 @@ class personnelTest
if($task->openedBy && isset($invest[$task->openedBy]))
{
$invest[$task->openedBy]['createdTask'] += 1;
$userTasks[$task->openedBy][$task->id] = $task->id;
$userTasks[$task->openedBy][$task->id] = $task->id;
}
if($task->finishedBy && isset($invest[$task->finishedBy]))
{
$invest[$task->finishedBy]['finishedTask'] += 1;
$userTasks[$task->finishedBy][$task->id] = $task->id;
$userTasks[$task->finishedBy][$task->id] = $task->id;
}
if($task->assignedTo && $task->status == 'wait' && isset($invest[$task->assignedTo]))
{
$invest[$task->assignedTo]['pendingTask'] += 1;
$userTasks[$task->assignedTo][$task->id] = $task->id;
$userTasks[$task->assignedTo][$task->id] = $task->id;
}
}
$objects = $this->objectModel->getUserEffortHours($userTasks);
$objects = $this->objectModel->getUserHours($userTasks);
if(dao::isError()) return dao::getError();
@@ -1,28 +0,0 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
include dirname(dirname(dirname(__FILE__))) . '/class/personnel.class.php';
su('admin');
/**
title=测试 personnelModel->getUserEffortHours();
cid=1
pid=1
正常传入的情况 >> 0
传入不存在的情况 >> 0
*/
$personnel = new personnelTest('admin');
$projectID = array();
$projectID[0] = 11;
$projectID[1] = 11111;
$result1 = $personnel->getUserEffortHoursTest($projectID[0]);
$result2 = $personnel->getUserEffortHoursTest($projectID[1]);
r($result1) && p() && e('0'); //正常传入的情况
r($result2) && p() && e('0'); //传入不存在的情况
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
include dirname(dirname(dirname(__FILE__))) . '/class/personnel.class.php';
su('admin');
$project = zdTable('project');
$project->id->range('1-10');
$project->project->range('0,0,2{8}');
$project->type->range('program,project,sprint{8}');
$project->status->range('doing{3},wait{7}');
$project->vision->range('rnd');
$project->name->range('1-10')->prefix('Object');
$project->multiple->range('1');
$project->deleted->range('`0`');
$project->gen(10);
$task = zdTable('task');
$task->id->range('1');
$task->name->range('task1');
$task->project->range('2');
$task->type->range('dev');
$task->left->range('1');
$task->openedBy->range('admin');
$task->consumed->range('5');
$task->deleted->range('`0`');
$task->gen(1);
$effort = zdTable('effort');
$effort->id->range('1-2');
$effort->objectType->range('task');
$effort->objectID->range('1');
$effort->account->range('admin');
$effort->left->range('7,1');
$effort->consumed->range('2,3');
$effort->deleted->range('`0`');
$effort->gen(2);
/**
title=测试 personnelModel->getUserHours();
cid=1
pid=1
正常传入的情况 >> 1
传入不存在的情况 >> 0
*/
$personnel = new personnelTest('admin');
$result1 = $personnel->getUserHoursTest('2', array('admin'));
$result2 = $personnel->getUserHoursTest('100', array('admin'));
r($result1['admin']->left) && p() && e('1'); //正常传入的情况
r($result2) && p() && e('0'); //传入不存在的情况