Merge branch 'master' of git@github.com:easysoft/zentaopms
This commit is contained in:
@@ -89,6 +89,7 @@ $lang->action->desc->editestimate = '$date, <strong>$actor</strong> edited wor
|
||||
$lang->action->desc->deleteestimate = '$date, <strong>$actor</strong> deleted working hours';
|
||||
$lang->action->desc->canceled = '$date, canceled by <strong>$actor</strong>.';
|
||||
$lang->action->desc->svncommited = '$date, <strong>$actor</strong> commited to svn,revision is <strong>#$extra</strong>.' . "\n";
|
||||
$lang->action->desc->gitcommited = '$date, <strong>$actor</strong> commited to git,revision is <strong>#$extra</strong>.' . "\n";
|
||||
$lang->action->desc->finished = '$date, finished by <strong>$actor</strong>.';
|
||||
$lang->action->desc->diff1 = 'changed <strong><i>%s</i></strong>, old is "%s", new is "%s".<br />';
|
||||
$lang->action->desc->diff2 = 'changed <strong><i>%s</i></strong>, the diff is:' . "\n" . "<blockquote>%s</blockquote>" . "\n<div class='hidden'>%s</div>";
|
||||
@@ -119,6 +120,7 @@ $lang->action->label->tostory = 'converted to story';
|
||||
$lang->action->label->frombug = 'converted from bug';
|
||||
$lang->action->label->totask = 'converted to task';
|
||||
$lang->action->label->svncommited = 'commited code';
|
||||
$lang->action->label->gitcommited = 'commited code';
|
||||
$lang->action->label->linked2plan = 'link to plan';
|
||||
$lang->action->label->unlinkedfromplan = 'unlink from plan';
|
||||
$lang->action->label->marked = 'edited';
|
||||
@@ -191,6 +193,7 @@ $lang->action->search->label['tostory'] = $lang->action->label->tost
|
||||
$lang->action->search->label['frombug'] = $lang->action->label->frombug;
|
||||
$lang->action->search->label['totask'] = $lang->action->label->totask;
|
||||
$lang->action->search->label['svncommited'] = $lang->action->label->svncommited;
|
||||
$lang->action->search->label['gitcommited'] = $lang->action->label->gitcommited;
|
||||
$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan;
|
||||
$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan;
|
||||
$lang->action->search->label['linked2project'] = $lang->action->label->linked2project;
|
||||
|
||||
@@ -89,6 +89,7 @@ $lang->action->desc->editestimate = '$date, 由 <strong>$actor</strong> 编辑
|
||||
$lang->action->desc->deleteestimate = '$date, 由 <strong>$actor</strong> 删除工时。';
|
||||
$lang->action->desc->canceled = '$date, 由 <strong>$actor</strong> 取消。' . "\n";
|
||||
$lang->action->desc->svncommited = '$date, 由 <strong>$actor</strong> 提交代码,版本为<strong>#$extra</strong>。' . "\n";
|
||||
$lang->action->desc->gitcommited = '$date, 由 <strong>$actor</strong> 提交代码,版本为<strong>#$extra</strong>。' . "\n";
|
||||
$lang->action->desc->finished = '$date, 由 <strong>$actor</strong> 完成。' . "\n";
|
||||
$lang->action->desc->diff1 = '修改了 <strong><i>%s</i></strong>,旧值为 "%s",新值为 "%s"。<br />' . "\n";
|
||||
$lang->action->desc->diff2 = '修改了 <strong><i>%s</i></strong>,区别为:' . "\n" . "<blockquote>%s</blockquote>" . "\n<div class='hidden'>%s</div>";
|
||||
@@ -119,6 +120,7 @@ $lang->action->label->tostory = '转需求';
|
||||
$lang->action->label->frombug = '转需求';
|
||||
$lang->action->label->totask = '转任务';
|
||||
$lang->action->label->svncommited = '提交代码';
|
||||
$lang->action->label->gitcommited = '提交代码';
|
||||
$lang->action->label->linked2plan = '关联计划';
|
||||
$lang->action->label->unlinkedfromplan = '移除计划';
|
||||
$lang->action->label->marked = '编辑了';
|
||||
@@ -191,6 +193,7 @@ $lang->action->search->label['tostory'] = $lang->action->label->tost
|
||||
$lang->action->search->label['frombug'] = $lang->action->label->frombug;
|
||||
$lang->action->search->label['totask'] = $lang->action->label->totask;
|
||||
$lang->action->search->label['svncommited'] = $lang->action->label->svncommited;
|
||||
$lang->action->search->label['gitcommited'] = $lang->action->label->gitcommited;
|
||||
$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan;
|
||||
$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan;
|
||||
$lang->action->search->label['linked2project'] = $lang->action->label->linked2project;
|
||||
|
||||
@@ -39,7 +39,7 @@ class actionModel extends model
|
||||
$action->actor = $actor ? $actor : $this->app->user->account;
|
||||
$action->action = strtolower($actionType);
|
||||
$action->date = helper::now();
|
||||
$action->comment = $comment;
|
||||
$action->comment = ltrim($comment, "<br />");
|
||||
$action->extra = $extra;
|
||||
|
||||
/* Get product and project for this object. */
|
||||
@@ -193,6 +193,7 @@ class actionModel extends model
|
||||
foreach($actions as $actionID => $action)
|
||||
{
|
||||
if(strtolower($action->action) == 'svncommited' and isset($commiters[$action->actor])) $action->actor = $commiters[$action->actor];
|
||||
if(strtolower($action->action) == 'gitcommited' and isset($commiters[$action->actor])) $action->actor = $commiters[$action->actor];
|
||||
$action->history = isset($histories[$actionID]) ? $histories[$actionID] : array();
|
||||
$actions[$actionID] = $action;
|
||||
}
|
||||
@@ -605,7 +606,7 @@ class actionModel extends model
|
||||
if($history->diff != '')
|
||||
{
|
||||
$history->diff = str_replace(array('<ins>', '</ins>', '<del>', '</del>'), array('[ins]', '[/ins]', '[del]', '[/del]'), $history->diff);
|
||||
$history->diff = $history->field != 'subversion' ? htmlspecialchars($history->diff) : $history->diff; // Keep the diff link.
|
||||
$history->diff = ($history->field != 'subversion' and $history->field != 'git') ? htmlspecialchars($history->diff) : $history->diff; // Keep the diff link.
|
||||
$history->diff = str_replace(array('[ins]', '[/ins]', '[del]', '[/del]'), array('<ins>', '</ins>', '<del>', '</del>'), $history->diff);
|
||||
$history->diff = nl2br($history->diff);
|
||||
$history->noTagDiff = preg_replace('/<\/?([a-z][a-z0-9]*)[^\/]*\/?>/Ui', '', $history->diff);
|
||||
|
||||
@@ -1312,7 +1312,7 @@ class bugModel extends model
|
||||
{
|
||||
$products = array_keys($this->loadModel('product')->getPrivProducts());
|
||||
$bugQuery = str_replace($allProduct, '1', $this->session->bugQuery);
|
||||
$bugQuery = $bugQuery . ' AND `product`' . helper::dbIN(array_keys($products));
|
||||
$bugQuery = $bugQuery . ' AND `product`' . helper::dbIN($products);
|
||||
}
|
||||
$bugQuery = $this->loadModel('search')->replaceDynamic($bugQuery);
|
||||
$bugs = $this->dao->select('*')->from(TABLE_BUG)->where($bugQuery)
|
||||
|
||||
@@ -26,7 +26,7 @@ js::set('page', 'assignedto');
|
||||
</tr>
|
||||
<tr>
|
||||
<td class='rowhead'><?php echo $lang->bug->mailto;?></td>
|
||||
<td><?php echo html::select('mailto[]', $users, str_replace(' ', '', $bug->mailto), 'class="text-1" multiple');?></td>
|
||||
<td><?php echo html::select('mailto[]', $users, str_replace(' ', '', $bug->mailto), 'class="w-p98" multiple');?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class='rowhead'><?php echo $lang->comment;?></td>
|
||||
|
||||
@@ -72,7 +72,7 @@ js::set('customed', $customed);
|
||||
}
|
||||
?>
|
||||
|
||||
<div class='treeSlider'><span> </span></div>
|
||||
<div class='treeSlider' id='bugTree'><span> </span></div>
|
||||
<form method='post'>
|
||||
<table class='cont-lt1'>
|
||||
<tr valign='top'>
|
||||
|
||||
@@ -30,7 +30,7 @@ js::set('page', 'confirmbug');
|
||||
</tr>
|
||||
<tr>
|
||||
<td class='rowhead'><?php echo $lang->bug->mailto;?></td>
|
||||
<td><?php echo html::select('mailto[]', $users, str_replace(' ' , '', $bug->mailto), 'class="text-1" multiple');?></td>
|
||||
<td><?php echo html::select('mailto[]', $users, str_replace(' ' , '', $bug->mailto), 'class="w-p98" multiple');?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class='rowhead'><?php echo $lang->comment;?></td>
|
||||
|
||||
@@ -619,7 +619,7 @@ class commonModel extends model
|
||||
}
|
||||
else
|
||||
{
|
||||
$objects = $this->dbh->query($queryCondition . "OR id=$objectID ORDER BY $orderBy")->fetchAll();
|
||||
$objects = $this->dbh->query($queryCondition . " ORDER BY $orderBy")->fetchAll();
|
||||
}
|
||||
|
||||
$tmpObjectIDs = array();
|
||||
@@ -683,9 +683,6 @@ class commonModel extends model
|
||||
$orderBy = explode('limit', $orderBy[1]);
|
||||
$orderBy = str_replace('t1.', '', $orderBy[0]);
|
||||
|
||||
/* Fix bug #448. I don't know why too. */
|
||||
if($orderBy == 'yes') $orderBy = '';
|
||||
|
||||
$this->session->set($objectType . 'OrderBy', $orderBy);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
<?php if($extView = $this->getExtViewFile(__FILE__)){include $extView; return helper::cd();}?>
|
||||
<?php
|
||||
if($config->debug)
|
||||
{
|
||||
css::import($defaultTheme . 'dropmenu.css');
|
||||
js::import($jsRoot . 'jquery/dropmenu/dropmenu.js');
|
||||
}
|
||||
css::import($defaultTheme . 'dropmenu.css');
|
||||
js::import($jsRoot . 'jquery/dropmenu/dropmenu.js');
|
||||
?>
|
||||
|
||||
@@ -44,7 +44,7 @@ $(document).ready(function()
|
||||
|
||||
KindEditor.ready(function(K)
|
||||
{
|
||||
keEditor = K.create('#' + editorID,
|
||||
editor = K.create('#' + editorID,
|
||||
{
|
||||
items:editorTool,
|
||||
filterMode:true,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* encodings: 提交日志的编码,比如GBK,可以用逗号连接起来的多个。
|
||||
* client: Git客户端执行文件的路径,windows下面是git.exe的路径,linux下面比如/usr/bin/git
|
||||
* repos可以是多个,需要设定某一个库的访问路径。
|
||||
*
|
||||
* encodeings: the encoding of the comment,can be a list.
|
||||
* client: the git client binary path. Unser windows, find the path of git.exe. Under linux, try /usr/bin/git
|
||||
* Can set multi repos, ervery one should set the path.
|
||||
*
|
||||
* 例子:
|
||||
* $config->git->client = '/usr/bin/git'; // c:\git\git.exe
|
||||
* $config->git->repos['pms']['path'] = '/home/user/repo/pms'; // c:\repo\pms
|
||||
*
|
||||
*/
|
||||
$config->git = new stdClass();
|
||||
$config->git->encodings = 'utf-8, gbk';
|
||||
$config->git->client = '/usr/bin/git';
|
||||
|
||||
$i = 1;
|
||||
$config->git->repos[$i]['path'] = '/home/z/pms';
|
||||
|
||||
/*
|
||||
$i ++;
|
||||
$config->git->repos[$i]['path'] = '';
|
||||
*/
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* The control file of git currentModule of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2013 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
|
||||
* @license LGPL (http://www.gnu.org/licenses/lgpl.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package git
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
class git extends control
|
||||
{
|
||||
/**
|
||||
* Sync git.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->git->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Diff a file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $revision
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function diff($path, $revision)
|
||||
{
|
||||
$path = helper::safe64Decode($path);
|
||||
$this->view->url = $path;
|
||||
$this->view->revision = $revision;
|
||||
$this->view->diff = $this->git->diff($path, $revision);
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cat a file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $revision
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function cat($path, $revision)
|
||||
{
|
||||
$path = helper::safe64Decode($path);
|
||||
$this->view->path = $path;
|
||||
$this->view->revision = $revision;
|
||||
$this->view->code = $this->git->cat($path, $revision);
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync from the syncer by api.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function apiSync()
|
||||
{
|
||||
if($this->post->logs)
|
||||
{
|
||||
$repoRoot = $this->post->repoRoot;
|
||||
$list = json_decode($this->post->logs);
|
||||
|
||||
$logs = array();
|
||||
$i = 0;
|
||||
foreach($list as $line)
|
||||
{
|
||||
if(!$line)
|
||||
{
|
||||
$i++;
|
||||
continue;
|
||||
}
|
||||
$logs[$i][] = $line;
|
||||
}
|
||||
foreach($logs as $log)
|
||||
{
|
||||
$parsedLogs[] = $this->convertLog($log);
|
||||
}
|
||||
|
||||
$parsedObjects = array('stories' => array(), 'tasks' => array(), 'bugs' => array());
|
||||
foreach($parsedLogs as $log)
|
||||
{
|
||||
$objects = $this->git->parseComment($log->msg);
|
||||
if($objects)
|
||||
{
|
||||
$this->git->saveAction2PMS($objects, $log, $repoRoot);
|
||||
if($objects['stories']) $parsedObjects['stories'] = array_merge($parsedObjects['stories'], $objects['stories']);
|
||||
if($objects['tasks']) $parsedObjects['tasks' ] = array_merge($parsedObjects['tasks'], $objects['tasks']);
|
||||
if($objects['bugs']) $parsedObjects['bugs'] = array_merge($parsedObjects['bugs'], $objects['bugs']);
|
||||
}
|
||||
}
|
||||
$parsedObjects['stories'] = array_unique($parsedObjects['stories']);
|
||||
$parsedObjects['tasks'] = array_unique($parsedObjects['tasks']);
|
||||
$parsedObjects['bugs'] = array_unique($parsedObjects['bugs']);
|
||||
$this->view->parsedObjects = $parsedObjects;
|
||||
$this->display();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* The git module zh-cn file of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2013 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
|
||||
* @license LGPL (http://www.gnu.org/licenses/lgpl.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package git
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
/* Methods. */
|
||||
$lang->git = new stdclass();
|
||||
$lang->git->common = 'Git';
|
||||
$lang->git->cat = 'View code';
|
||||
$lang->git->diff = 'Diff code';
|
||||
$lang->git->apiSync = 'API: sync git log';
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* The git module zh-cn file of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2013 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
|
||||
* @license LGPL (http://www.gnu.org/licenses/lgpl.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package git
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
/* 方法列表。*/
|
||||
$lang->git = new stdclass();
|
||||
$lang->git->common = 'Git';
|
||||
$lang->git->cat = '查看源代码';
|
||||
$lang->git->diff = '比较源代码';
|
||||
$lang->git->apiSync = '接口:同步git日志';
|
||||
@@ -0,0 +1,661 @@
|
||||
<?php
|
||||
/**
|
||||
* The model file of git module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2013 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
|
||||
* @license LGPL (http://www.gnu.org/licenses/lgpl.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package git
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php
|
||||
class gitModel extends model
|
||||
{
|
||||
/**
|
||||
* The git binary client.
|
||||
*
|
||||
* @var int
|
||||
* @access public
|
||||
*/
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* Repos.
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
public $repos = array();
|
||||
|
||||
/**
|
||||
* The log root.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $logRoot = '';
|
||||
|
||||
/**
|
||||
* The restart file.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $restartFile = '';
|
||||
|
||||
/**
|
||||
* The root path of a repo
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $repoRoot = '';
|
||||
|
||||
/**
|
||||
* Users
|
||||
*
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
public $users = array();
|
||||
|
||||
/**
|
||||
* Construct function.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->loadModel('action');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->setRepos();
|
||||
$this->setLogRoot();
|
||||
$this->setRestartFile();
|
||||
|
||||
foreach($this->repos as $name => $repo)
|
||||
{
|
||||
$this->printLog("begin repo $name");
|
||||
$repo = (object)$repo;
|
||||
$repo->name = $name;
|
||||
$this->setRepo($repo);
|
||||
|
||||
$savedRevision = $this->getSavedRevision();
|
||||
$this->printLog("start from revision $savedRevision");
|
||||
$logs = $this->getRepoLogs($repo, $savedRevision);
|
||||
$this->printLog("get " . count($logs) . " logs");
|
||||
|
||||
$this->printLog('begin parsing logs');
|
||||
$latestRevision = $logs[0]->revision;
|
||||
foreach($logs as $log)
|
||||
{
|
||||
$this->printLog("parsing log {$log->revision}");
|
||||
if($log->revision == $savedRevision)
|
||||
{
|
||||
$this->printLog("{$log->revision} alread parsed, ommit it");
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->printLog("comment is\n----------\n" . trim($log->msg) . "\n----------");
|
||||
$objects = $this->parseComment($log->msg);
|
||||
if($objects)
|
||||
{
|
||||
$this->printLog('extract' .
|
||||
' story:' . join(' ', $objects['stories']) .
|
||||
' task:' . join(' ', $objects['tasks']) .
|
||||
' bug:' . join(',', $objects['bugs']));
|
||||
|
||||
$this->saveAction2PMS($objects, $log);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->printLog('no objects found' . "\n");
|
||||
}
|
||||
}
|
||||
|
||||
$this->saveLastRevision($latestRevision);
|
||||
$this->printLog("save revision $latestRevision");
|
||||
$this->deleteRestartFile();
|
||||
$this->printLog("\n\nrepo $name finished");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the log root.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setLogRoot()
|
||||
{
|
||||
$this->logRoot = $this->app->getTmpRoot() . 'git/';
|
||||
if(!is_dir($this->logRoot)) mkdir($this->logRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the restart file.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setRestartFile()
|
||||
{
|
||||
$this->restartFile = dirname(__FILE__) . '/restart';
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the restart file.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function deleteRestartFile()
|
||||
{
|
||||
if(is_file($this->restartFile)) unlink($this->restartFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the repos.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setRepos()
|
||||
{
|
||||
if(!$this->config->git->repos) die("You must set one git repo.\n");
|
||||
$this->repos = $this->config->git->repos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set repo.
|
||||
*
|
||||
* @param object $repo
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setRepo($repo)
|
||||
{
|
||||
$this->setClient($repo);
|
||||
$this->setLogFile($repo->name);
|
||||
$this->setRepoRoot($repo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the git binary client of a repo.
|
||||
*
|
||||
* @param object $repo
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setClient($repo)
|
||||
{
|
||||
if($this->config->git->client == '') die("You must set the git client file.\n");
|
||||
$this->client = $this->config->git->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the log file of a repo.
|
||||
*
|
||||
* @param string $repoName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setLogFile($repoName)
|
||||
{
|
||||
$this->logFile = $this->logRoot . $repoName;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the root path of a repo.
|
||||
*
|
||||
* @param object $repo
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setRepoRoot($repo)
|
||||
{
|
||||
$this->repoRoot = $repo->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repo logs.
|
||||
*
|
||||
* @param object $repo
|
||||
* @param int $fromRevision
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getRepoLogs($repo, $fromRevision)
|
||||
{
|
||||
$parsedLogs = array();
|
||||
|
||||
/* The git log command. */
|
||||
if($fromRevision)
|
||||
{
|
||||
$cmd = "cd $this->repoRoot; $this->client log --stat $fromRevision..HEAD --pretty=format:%an*_*%cd*_*%H*_*%s";
|
||||
}
|
||||
else
|
||||
{
|
||||
$cmd = "cd $this->repoRoot; $this->client log --stat --pretty=format:%an*_*%cd*_*%H*_*%s";
|
||||
}
|
||||
exec($cmd, $list, $return);
|
||||
|
||||
if(!$list and $return) die("Some error occers: \nThe command is $cmd\n");
|
||||
if(!$list and !$return) exit;
|
||||
|
||||
/* Process logs. */
|
||||
$logs = array();
|
||||
$i = 0;
|
||||
|
||||
foreach($list as $line)
|
||||
{
|
||||
if(!$line)
|
||||
{
|
||||
$i++;
|
||||
continue;
|
||||
}
|
||||
$logs[$i][] = $line;
|
||||
}
|
||||
foreach($logs as $log)
|
||||
{
|
||||
$parsedLogs[] = $this->convertLog($log);
|
||||
}
|
||||
return $parsedLogs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert log from xml format to object.
|
||||
*
|
||||
* @param object $log
|
||||
* @access public
|
||||
* @return ojbect
|
||||
*/
|
||||
public function convertLog($log)
|
||||
{
|
||||
|
||||
list($account, $date, $hash, $comment) = explode('*_*', $log[0]);
|
||||
$parsedLog = new stdClass();
|
||||
$parsedLog->author = $account;
|
||||
$parsedLog->revision = $hash;
|
||||
$parsedLog->msg = $comment;
|
||||
$parsedLog->date = date('Y-m-d H:i:s', strtotime($date));
|
||||
$parsedLog->files = array();
|
||||
|
||||
unset($log[0]);
|
||||
foreach($log as $change)
|
||||
{
|
||||
if(strpos($change, '|') === false) continue;
|
||||
list($entry, $modify) = explode('|', $change);
|
||||
$entry = '/' . trim($entry);
|
||||
$parsedLog->files['M'][] = $entry;
|
||||
}
|
||||
|
||||
return $parsedLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the comment of git, extract object id list from it.
|
||||
*
|
||||
* @param string $comment
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function parseComment($comment)
|
||||
{
|
||||
$stories = array();
|
||||
$tasks = array();
|
||||
$bugs = array();
|
||||
|
||||
// bug|story|task(case insensitive) + some space + #|:|:(Chinese) + id lists(maybe join with space or ,)
|
||||
// $comment = "bug # 1,2,3,4 Bug:1 2 3 4 5 story:9999,1234566 story:456,1234566";
|
||||
$commonReg = "(?:\s){0,}(?:#|:|:){0,}([0-9, ]{1,})";
|
||||
$taskReg = '/task' . $commonReg . '/i';
|
||||
$storyReg = '/story' . $commonReg . '/i';
|
||||
$bugReg = '/bug' . $commonReg . '/i';
|
||||
|
||||
if(preg_match_all($storyReg, $comment, $result)) $stories = join(' ', $result[1]);
|
||||
if(preg_match_all($taskReg, $comment, $result)) $tasks = join(' ', $result[1]);
|
||||
if(preg_match_all($bugReg, $comment, $result)) $bugs = join(' ', $result[1]);
|
||||
|
||||
if($stories) $stories = array_unique(explode(' ', str_replace(',', ' ', $stories)));
|
||||
if($tasks) $tasks = array_unique(explode(' ', str_replace(',', ' ', $tasks)));
|
||||
if($bugs) $bugs = array_unique(explode(' ', str_replace(',', ' ', $bugs)));
|
||||
|
||||
if(!$stories and !$tasks and !$bugs) return array();
|
||||
return array('stories' => $stories, 'tasks' => $tasks, 'bugs' => $bugs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the comment to uft-8.
|
||||
*
|
||||
* @param string $comment
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function iconvComment($comment)
|
||||
{
|
||||
/* Get encodings. */
|
||||
$encodings = str_replace(' ', '', trim($comment));
|
||||
if($encodings == '') return $comment;
|
||||
$encodings = explode(',', $encodings);
|
||||
|
||||
/* Try convert. */
|
||||
foreach($encodings as $encoding)
|
||||
{
|
||||
$result = @iconv($encoding, 'utf-8', $comment);
|
||||
if($result) return $result;
|
||||
}
|
||||
|
||||
return $comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diff a url.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $revision
|
||||
* @access public
|
||||
* @return string|bool
|
||||
*/
|
||||
public function diff($path, $revision)
|
||||
{
|
||||
$repo = $this->getRepoByURL($path);
|
||||
if(!$repo) return false;
|
||||
|
||||
$this->setClient($repo);
|
||||
putenv('LC_CTYPE=en_US.UTF-8');
|
||||
|
||||
$path = str_replace('%2F', '/', urlencode($path));
|
||||
$path = str_replace('%3A', ':', $path);
|
||||
|
||||
$cmd = "cd $repo->path;$this->client diff $revision^ $revision $path";
|
||||
$diff = `$cmd`;
|
||||
return $diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cat a url.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $revision
|
||||
* @access public
|
||||
* @return string|bool
|
||||
*/
|
||||
public function cat($path, $revision)
|
||||
{
|
||||
$repo = $this->getRepoByURL($path);
|
||||
if(!$repo) return false;
|
||||
|
||||
$this->setClient($repo);
|
||||
|
||||
putenv('LC_CTYPE=en_US.UTF-8');
|
||||
|
||||
$path = str_replace('%2F', '/', urlencode($path));
|
||||
$path = str_replace('%3A', ':', $path);
|
||||
|
||||
$subPath = substr($path, strlen($repo->path) + 1);
|
||||
$cmd = "cd $repo->path;$this->client show $revision:$subPath";
|
||||
$code = `$cmd`;
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repo by url.
|
||||
*
|
||||
* @param string $url
|
||||
* @access public
|
||||
* @return object|bool
|
||||
*/
|
||||
public function getRepoByURL($url)
|
||||
{
|
||||
foreach($this->config->git->repos as $repo) if(strpos($url, $repo['path']) !== false) return (object)$repo;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save action to pms.
|
||||
*
|
||||
* @param array $objects
|
||||
* @param object $log
|
||||
* @param string $repoRoot
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function saveAction2PMS($objects, $log, $repoRoot = '')
|
||||
{
|
||||
$action = new stdclass();
|
||||
$action->actor = $log->author;
|
||||
$action->action = 'gitcommited';
|
||||
$action->date = $log->date;
|
||||
$action->comment = $this->iconvComment($log->msg);
|
||||
$action->extra = substr($log->revision, 0, 10);
|
||||
|
||||
$changes = $this->createActionChanges($log, $repoRoot);
|
||||
|
||||
if($objects['stories'])
|
||||
{
|
||||
$products = $this->getStoryProducts($objects['stories']);
|
||||
foreach($objects['stories'] as $storyID)
|
||||
{
|
||||
$storyID = (int)$storyID;
|
||||
if(!isset($products[$storyID])) continue;
|
||||
|
||||
$action->objectType = 'story';
|
||||
$action->objectID = $storyID;
|
||||
$action->product = $products[$storyID];
|
||||
$action->project = 0;
|
||||
|
||||
$this->saveRecord($action, $changes);
|
||||
}
|
||||
}
|
||||
|
||||
if($objects['tasks'])
|
||||
{
|
||||
$productsAndProjects = $this->getTaskProductsAndProjects($objects['tasks']);
|
||||
foreach($objects['tasks'] as $taskID)
|
||||
{
|
||||
$taskID = (int)$taskID;
|
||||
if(!isset($productsAndProjects[$taskID])) continue;
|
||||
|
||||
$action->objectType = 'task';
|
||||
$action->objectID = $taskID;
|
||||
$action->product = $productsAndProjects[$taskID]['product'];
|
||||
$action->project = $productsAndProjects[$taskID]['project'];
|
||||
|
||||
$this->saveRecord($action, $changes);
|
||||
}
|
||||
}
|
||||
|
||||
if($objects['bugs'])
|
||||
{
|
||||
$productsAndProjects = $this->getBugProductsAndProjects($objects['bugs']);
|
||||
|
||||
foreach($objects['bugs'] as $bugID)
|
||||
{
|
||||
$bugID = (int)$bugID;
|
||||
if(!isset($productsAndProjects[$bugID])) continue;
|
||||
|
||||
$action->objectType = 'bug';
|
||||
$action->objectID = $bugID;
|
||||
$action->product = $productsAndProjects[$bugID]->product;
|
||||
$action->project = $productsAndProjects[$bugID]->project;
|
||||
|
||||
$this->saveRecord($action, $changes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an action to pms.
|
||||
*
|
||||
* @param object $action
|
||||
* @param object $log
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function saveRecord($action, $changes)
|
||||
{
|
||||
$record = $this->dao->select('*')->from(TABLE_ACTION)
|
||||
->where('objectType')->eq($action->objectType)
|
||||
->andWhere('objectID')->eq($action->objectID)
|
||||
->andWhere('extra')->eq($action->extra)
|
||||
->andWhere('action')->eq('gitcommited')
|
||||
->fetch();
|
||||
if($record)
|
||||
{
|
||||
$this->dao->update(TABLE_ACTION)->data($action)->where('id')->eq($record->id)->exec();
|
||||
if($changes)
|
||||
{
|
||||
$historyID = $this->dao->findByAction($record->id)->from(TABLE_HISTORY)->fetch('id');
|
||||
$this->dao->update(TABLE_HISTORY)->data($changes)->where('id')->eq($historyID)->exec();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->dao->insert(TABLE_ACTION)->data($action)->autoCheck()->exec();
|
||||
if($changes)
|
||||
{
|
||||
$actionID = $this->dao->lastInsertID();
|
||||
$this->action->logHistory($actionID, array($changes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create changes for action from a log.
|
||||
*
|
||||
* @param object $log
|
||||
* @param string $repoRoot
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function createActionChanges($log, $repoRoot)
|
||||
{
|
||||
if(!$log->files) return array();
|
||||
$diff = '';
|
||||
|
||||
$oldSelf = $this->server->PHP_SELF;
|
||||
$this->server->set('PHP_SELF', $this->config->webRoot);
|
||||
|
||||
if(!$repoRoot) $repoRoot = $this->repoRoot;
|
||||
|
||||
foreach($log->files as $action => $actionFiles)
|
||||
{
|
||||
foreach($actionFiles as $file)
|
||||
{
|
||||
$param = array('url' => helper::safe64Encode($repoRoot . $file), 'revision' => $log->revision);
|
||||
$catLink = trim(html::a(helper::createLink('git', 'cat', $param, 'html'), 'view', '', "class='gitlink'"));
|
||||
$diffLink = trim(html::a(helper::createLink('git', 'diff', $param, 'html'), 'diff', '', "class='gitlink'"));
|
||||
$diff .= $action . " " . $file . " $catLink ";
|
||||
$diff .= $action == 'M' ? "$diffLink\n" : "\n" ;
|
||||
}
|
||||
}
|
||||
$changes->field = 'git';
|
||||
$changes->old = '';
|
||||
$changes->new = '';
|
||||
$changes->diff = trim($diff);
|
||||
|
||||
$this->server->set('PHP_SELF', $oldSelf);
|
||||
return (array)$changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get products of stories.
|
||||
*
|
||||
* @param array $stories
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getStoryProducts($stories)
|
||||
{
|
||||
return $this->dao->select('id, product')->from(TABLE_STORY)->where('id')->in($stories)->fetchPairs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get products and projects of tasks.
|
||||
*
|
||||
* @param array $tasks
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getTaskProductsAndProjects($tasks)
|
||||
{
|
||||
$records = array();
|
||||
$products = $this->dao->select('t1.id, t2.product')
|
||||
->from(TABLE_TASK)->alias('t1')
|
||||
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id')
|
||||
->where('t1.id')->in($tasks)->fetchPairs();
|
||||
|
||||
$projects = $this->dao->select('id, project')->from(TABLE_TASK)->where('id')->in($tasks)->fetchPairs();
|
||||
|
||||
foreach($projects as $taskID => $projectID)
|
||||
{
|
||||
$record = array();
|
||||
$record['project'] = $projectID;
|
||||
$record['product'] = isset($products[$taskID]) ? $products[$taskID] : 0;
|
||||
$records[$taskID] = $record;
|
||||
}
|
||||
return $records;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get products and projects of bugs.
|
||||
*
|
||||
* @param array $bugs
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getBugProductsAndProjects($bugs)
|
||||
{
|
||||
return $this->dao->select('id, project, product')->from(TABLE_BUG)->where('id')->in($bugs)->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the saved revision.
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getSavedRevision()
|
||||
{
|
||||
if(!file_exists($this->logFile)) return 0;
|
||||
if(file_exists($this->restartFile)) return 0;
|
||||
return trim(file_get_contents($this->logFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the last revision.
|
||||
*
|
||||
* @param int $revision
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function saveLastRevision($revision)
|
||||
{
|
||||
file_put_contents($this->logFile, $revision);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pring log.
|
||||
*
|
||||
* @param sting $log
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function printLog($log)
|
||||
{
|
||||
echo helper::now() . " $log\n";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* The cat view file of git module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2013 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
|
||||
* @license LGPL (http://www.gnu.org/licenses/lgpl.html)
|
||||
* @author Congzhi Chen <congzhi@cnezsoft.com>
|
||||
* @package file
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.lite.html.php';?>
|
||||
<div class='box-title'><?php echo "$path@$revision";?></div>
|
||||
<div class='box-content'><xmp><?php echo $code;?></xmp></div>
|
||||
<?php include '../../common/view/footer.lite.html.php';?>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* The diff view file of git module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2013 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
|
||||
* @license LGPL (http://www.gnu.org/licenses/lgpl.html)
|
||||
* @author Congzhi Chen <congzhi@cnezsoft.com>
|
||||
* @package file
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.lite.html.php';?>
|
||||
<?php $catLink = inlink('cat', 'url=' . helper::safe64Encode($path) . "&revision=$revision");?>
|
||||
<div class='box-title'><?php echo html::a($catLink, "$path@$revision");?></div>
|
||||
<div class='box-content'><xmp><?php echo $diff;?></xmp></div>
|
||||
<?php include '../../common/view/footer.lite.html.php';?>
|
||||
@@ -46,13 +46,14 @@ $lang->moduleOrder[125] = 'action';
|
||||
|
||||
$lang->moduleOrder[130] = 'mail';
|
||||
$lang->moduleOrder[135] = 'svn';
|
||||
$lang->moduleOrder[140] = 'search';
|
||||
$lang->moduleOrder[145] = 'tree';
|
||||
$lang->moduleOrder[150] = 'api';
|
||||
$lang->moduleOrder[155] = 'file';
|
||||
$lang->moduleOrder[160] = 'misc';
|
||||
$lang->moduleOrder[165] = 'sso';
|
||||
$lang->moduleOrder[170] = 'webapp';
|
||||
$lang->moduleOrder[140] = 'git';
|
||||
$lang->moduleOrder[145] = 'search';
|
||||
$lang->moduleOrder[150] = 'tree';
|
||||
$lang->moduleOrder[155] = 'api';
|
||||
$lang->moduleOrder[160] = 'file';
|
||||
$lang->moduleOrder[165] = 'misc';
|
||||
$lang->moduleOrder[170] = 'sso';
|
||||
$lang->moduleOrder[175] = 'webapp';
|
||||
|
||||
$lang->resource = new stdclass();
|
||||
|
||||
@@ -513,6 +514,16 @@ $lang->svn->methodOrder[5] = 'diff';
|
||||
$lang->svn->methodOrder[10] = 'cat';
|
||||
$lang->svn->methodOrder[15] = 'apiSync';
|
||||
|
||||
/* Git. */
|
||||
$lang->resource->git = new stdclass();
|
||||
$lang->resource->git->diff = 'diff';
|
||||
$lang->resource->git->cat = 'cat';
|
||||
$lang->resource->git->apiSync = 'apiSync';
|
||||
|
||||
$lang->git->methodOrder[5] = 'diff';
|
||||
$lang->git->methodOrder[10] = 'cat';
|
||||
$lang->git->methodOrder[15] = 'apiSync';
|
||||
|
||||
/* Company. */
|
||||
$lang->resource->company = new stdclass();
|
||||
$lang->resource->company->index = 'index';
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
</div>
|
||||
|
||||
<div id='querybox' class='<?php if($browseType !='bysearch') echo 'hidden';?>'></div>
|
||||
<div class='treeSlider'><span> </span></div>
|
||||
<div class='treeSlider' id='storyTree'><span> </span></div>
|
||||
<form method='post' id='productStoryForm'>
|
||||
<table class='cont-lt1'>
|
||||
<tr valign='top'>
|
||||
@@ -153,7 +153,7 @@
|
||||
<?php
|
||||
$class = "class='disabled'";
|
||||
|
||||
$canBatchClose = common::hasPriv('story', 'batchClose') and strtolower($browseType) != 'closedbyme' and strtolower($browseType) != 'closedstory';
|
||||
$canBatchClose = common::hasPriv('story', 'batchClose') && strtolower($browseType) != 'closedbyme' && strtolower($browseType) != 'closedstory';
|
||||
$actionLink = $this->createLink('story', 'batchClose', "productID=$productID&projectID=0");
|
||||
$misc = $canBatchClose ? "onclick=setFormAction('$actionLink')" : $class;
|
||||
echo "<li>" . html::a('#', $lang->close, '', $misc) . "</li>";
|
||||
|
||||
@@ -43,6 +43,7 @@ $lang->productplan->desc = 'Desc';
|
||||
$lang->productplan->begin = 'Begin';
|
||||
$lang->productplan->end = 'End';
|
||||
|
||||
$lang->productplan->endList[7] = 'One Weeks';
|
||||
$lang->productplan->endList[14] = 'Two Weeks';
|
||||
$lang->productplan->endList[31] = 'One Month';
|
||||
$lang->productplan->endList[62] = 'Two Months';
|
||||
|
||||
@@ -43,6 +43,7 @@ $lang->productplan->desc = '描述';
|
||||
$lang->productplan->begin = '开始日期';
|
||||
$lang->productplan->end = '结束日期';
|
||||
|
||||
$lang->productplan->endList[7] = '一星期';
|
||||
$lang->productplan->endList[14] = '两星期';
|
||||
$lang->productplan->endList[31] = '一个月';
|
||||
$lang->productplan->endList[62] = '两个月';
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
var browseType = '<?php echo $browseType;?>';
|
||||
</script>
|
||||
<div id='querybox' class='<?php if($browseType != 'bysearch') echo 'hidden';?>'></div>
|
||||
<div class='treeSlider'><span> </span></div>
|
||||
<div class='treeSlider' id='taskTree'><span> </span></div>
|
||||
<form method='post' id='projectTaskForm'>
|
||||
<table class='cont-lt2'>
|
||||
<tr valign='top'>
|
||||
|
||||
@@ -87,14 +87,14 @@ class releaseModel extends model
|
||||
$buildID = $this->dao->lastInsertID();
|
||||
}
|
||||
|
||||
$release = fixer::input('post')
|
||||
->stripTags('name')
|
||||
->add('product', (int)$productID)
|
||||
->join('stories', ',')
|
||||
->join('bugs', ',')
|
||||
->remove('allchecker')
|
||||
->setIF($this->post->build ==false, 'build', $buildID)
|
||||
->get();
|
||||
$release = fixer::input('post')
|
||||
->stripTags('name')
|
||||
->add('product', (int)$productID)
|
||||
->join('stories', ',')
|
||||
->join('bugs', ',')
|
||||
->setIF($this->post->build == false, 'build', $buildID)
|
||||
->remove('allchecker')
|
||||
->get();
|
||||
|
||||
$this->dao->insert(TABLE_RELEASE)->data($release)->autoCheck()->batchCheck($this->config->release->create->requiredFields, 'notempty')->check('name','unique')->exec();
|
||||
$releaseID = $this->dao->lastInsertID();
|
||||
|
||||
@@ -644,7 +644,7 @@ class story extends control
|
||||
*/
|
||||
public function batchClose($productID = 0, $projectID = 0)
|
||||
{
|
||||
if($this->post->closedReasons)
|
||||
if($this->post->comments)
|
||||
{
|
||||
$allChanges = $this->story->batchClose();
|
||||
|
||||
@@ -1035,6 +1035,7 @@ class story extends control
|
||||
if(isset($storyLang->statusList[$story->status])) $story->status = $storyLang->statusList[$story->status];
|
||||
if(isset($storyLang->stageList[$story->stage])) $story->stage = $storyLang->stageList[$story->stage];
|
||||
if(isset($storyLang->reasonList[$story->closedReason])) $story->closedReason = $storyLang->reasonList[$story->closedReason];
|
||||
if(isset($storyLang->sourceList[$story->source])) $story->source = $storyLang->sourceList[$story->source];
|
||||
|
||||
if(isset($users[$story->openedBy])) $story->openedBy = $users[$story->openedBy];
|
||||
if(isset($users[$story->assignedTo])) $story->assignedTo = $users[$story->assignedTo];
|
||||
|
||||
+40
-41
@@ -579,51 +579,49 @@ class storyModel extends model
|
||||
|
||||
/* Adjust whether the post data is complete, if not, remove the last element of $storyIDList. */
|
||||
if($this->session->showSuhosinInfo) array_pop($storyIDList);
|
||||
if(!empty($storyIDList))
|
||||
foreach($storyIDList as $storyID)
|
||||
{
|
||||
foreach($storyIDList as $storyID)
|
||||
$oldStory = $this->getById($storyID);
|
||||
if(!$oldStory->status == 'closed') continue;
|
||||
|
||||
$story->lastEditedBy = $this->app->user->account;
|
||||
$story->lastEditedDate = $now;
|
||||
$story->closedBy = $this->app->user->account;
|
||||
$story->closedDate = $now;
|
||||
$story->assignedTo = 'closed';
|
||||
$story->assignedDate = $now;
|
||||
$story->status = 'closed';
|
||||
|
||||
$story->closedReason = $this->post->closedReasons[$storyID];
|
||||
$story->duplicateStory = $this->post->duplicateStoryIDList[$storyID] ? $this->post->duplicateStoryIDList[$storyID] : $oldStory->duplicateStory;
|
||||
$story->childStories = $this->post->childStoriesIDList[$storyID] ? $this->post->childStoriesIDList[$storyID] : $oldStory->childStories;
|
||||
|
||||
if($story->closedReason == 'done') $story->stage = 'released';
|
||||
if($story->closedReason != 'done') $story->plan = 0;
|
||||
|
||||
$stories[$storyID] = $story;
|
||||
unset($story);
|
||||
}
|
||||
|
||||
foreach($stories as $storyID => $story)
|
||||
{
|
||||
if(!$story->closedReason) continue;
|
||||
|
||||
$oldStory = $this->getById($storyID);
|
||||
|
||||
$this->dao->update(TABLE_STORY)->data($story)
|
||||
->autoCheck()
|
||||
->checkIF($story->closedReason == 'duplicate', 'duplicateStory', 'notempty')
|
||||
->checkIF($story->closedReason == 'subdivided', 'childStories', 'notempty')
|
||||
->where('id')->eq($storyID)->exec();
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
$oldStory = $this->getById($storyID);
|
||||
|
||||
$story->lastEditedBy = $this->app->user->account;
|
||||
$story->lastEditedDate = $now;
|
||||
$story->closedBy = $this->app->user->account;
|
||||
$story->closedDate = $now;
|
||||
$story->assignedTo = 'closed';
|
||||
$story->assignedDate = $now;
|
||||
$story->status = 'closed';
|
||||
|
||||
$story->closedReason = $this->post->closedReasons[$storyID];
|
||||
$story->duplicateStory = $this->post->duplicateStoryIDList[$storyID] ? $this->post->duplicateStoryIDList[$storyID] : $oldStory->duplicateStory;
|
||||
$story->childStories = $this->post->childStoriesIDList[$storyID] ? $this->post->childStoriesIDList[$storyID] : $oldStory->childStories;
|
||||
|
||||
if($story->closedReason == 'done') $story->stage = 'released';
|
||||
if($story->closedReason != 'done') $story->plan = 0;
|
||||
|
||||
$stories[$storyID] = $story;
|
||||
unset($story);
|
||||
$allChanges[$storyID] = common::createChanges($oldStory, $story);
|
||||
}
|
||||
|
||||
foreach($stories as $storyID => $story)
|
||||
else
|
||||
{
|
||||
if(!$story->closedReason) continue;
|
||||
|
||||
$oldStory = $this->getById($storyID);
|
||||
|
||||
$this->dao->update(TABLE_STORY)->data($story)
|
||||
->autoCheck()
|
||||
->checkIF($story->closedReason == 'duplicate', 'duplicateStory', 'notempty')
|
||||
->checkIF($story->closedReason == 'subdivided', 'childStories', 'notempty')
|
||||
->where('id')->eq($storyID)->exec();
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
$allChanges[$storyID] = common::createChanges($oldStory, $story);
|
||||
}
|
||||
else
|
||||
{
|
||||
die(js::error('story#' . $storyID . dao::getError(true)));
|
||||
}
|
||||
die(js::error('story#' . $storyID . dao::getError(true)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -991,6 +989,7 @@ class storyModel extends model
|
||||
$queryProductID = 'all';
|
||||
}
|
||||
$storyQuery = $storyQuery . ' AND `product`' . helper::dbIN(array_keys($products));
|
||||
if($projectID != '') $storyQuery .= " AND `status` != 'draft'";
|
||||
$storyQuery = $this->loadModel('search')->replaceDynamic($storyQuery);
|
||||
|
||||
return $this->getBySQL($queryProductID, $storyQuery, $orderBy, $pager);
|
||||
|
||||
@@ -936,6 +936,7 @@ class task extends control
|
||||
/* Get related objects title or names. */
|
||||
$relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs();
|
||||
$relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('task')->andWhere('objectID')->in(@array_keys($tasks))->fetchGroup('objectID');
|
||||
$relatedModules = $this->loadModel('tree')->getTaskOptionMenu($projectID);
|
||||
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
@@ -954,6 +955,7 @@ class task extends control
|
||||
if(isset($taskLang->priList[$task->pri])) $task->pri = $taskLang->priList[$task->pri];
|
||||
if(isset($taskLang->statusList[$task->status])) $task->status = $taskLang->statusList[$task->status];
|
||||
if(isset($taskLang->reasonList[$task->closedReason])) $task->closedReason = $taskLang->reasonList[$task->closedReason];
|
||||
if(isset($relatedModules[$task->module])) $task->module = $relatedModules[$task->module];
|
||||
|
||||
if(isset($users[$task->openedBy])) $task->openedBy = $users[$task->openedBy];
|
||||
if(isset($users[$task->assignedTo])) $task->assignedTo = $users[$task->assignedTo];
|
||||
|
||||
@@ -149,6 +149,7 @@ $lang->task->error->consumedNumber = '"Consumed" must be number';
|
||||
$lang->task->error->consumedSmall = '"Consumed" must be more than consumed before';
|
||||
$lang->task->error->consumedThisTime = 'Please input "hours"';
|
||||
$lang->task->error->left = 'Please input "left"';
|
||||
$lang->task->error->work = '"Comment" must be less than 255 characters';
|
||||
|
||||
/* Report. */
|
||||
$lang->task->report = new stdclass();
|
||||
|
||||
@@ -149,6 +149,7 @@ $lang->task->error->consumedNumber = '"已经消耗"必须为数字';
|
||||
$lang->task->error->consumedSmall = '"已经消耗"必须大于之前消耗';
|
||||
$lang->task->error->consumedThisTime = '请填写"工时"';
|
||||
$lang->task->error->left = '请填写"剩余"';
|
||||
$lang->task->error->work = '"备注"必须小于255个字符';
|
||||
|
||||
/* 统计报表。*/
|
||||
$lang->task->report = new stdclass();
|
||||
|
||||
@@ -387,9 +387,9 @@ class taskModel extends model
|
||||
$now = helper::now();
|
||||
$task = fixer::input('post')
|
||||
->setDefault('assignedTo', $this->app->user->account)
|
||||
->setDefault('assignedDate', $now)
|
||||
->setDefault('lastEditedBy', $this->app->user->account)
|
||||
->setDefault('lastEditedDate', $now)
|
||||
->setIF($oldTask->assignedTo != $this->app->user->account, 'assignedDate', $now)
|
||||
->remove('comment')->get();
|
||||
if($this->post->left == 0)
|
||||
{
|
||||
@@ -440,6 +440,7 @@ class taskModel extends model
|
||||
{
|
||||
if(!$record->consumed[$id]) die(js::alert($this->lang->task->error->consumedThisTime));
|
||||
if($record->left[$id] === '') die(js::alert($this->lang->task->error->left));
|
||||
if(strlen($record->work[$id]) > 255) die(js::alert($this->lang->task->error->work));
|
||||
$estimates[$id] = new stdclass();
|
||||
$estimates[$id]->date = $record->dates[$id];
|
||||
$estimates[$id]->task = $taskID;
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
<th class='rowhead'><?php echo $lang->task->assignedTo;?></th>
|
||||
<td><?php echo html::select('assignedTo[]', $members, $task->assignedTo, 'class=select-3');?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class='rowhead'><?php echo $lang->task->type;?></th>
|
||||
<td><?php echo html::select('type', $lang->task->typeList, $task->type, 'class=select-3 onchange="setOwners(this.value)"');?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class='rowhead'><?php echo $lang->task->story;?></th>
|
||||
<td>
|
||||
@@ -65,10 +69,6 @@
|
||||
<th class='rowhead'><?php echo $lang->task->deadline;?></th>
|
||||
<td><?php echo html::input('deadline', $task->deadline, "class='text-3 date'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class='rowhead'><?php echo $lang->task->type;?></th>
|
||||
<td><?php echo html::select('type', $lang->task->typeList, $task->type, 'class=select-3 onchange="setOwners(this.value)"');?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class='rowhead'><?php echo $lang->task->mailto;?></th>
|
||||
<td>
|
||||
|
||||
@@ -115,7 +115,8 @@ class testcase extends control
|
||||
|
||||
$queryProductID = $productID;
|
||||
$allProduct = "`product` = 'all'";
|
||||
$caseQuery = $this->session->testcaseQuery;
|
||||
|
||||
$caseQuery = '(' . $this->session->testcaseQuery;
|
||||
if(strpos($this->session->testcaseQuery, $allProduct) !== false)
|
||||
{
|
||||
$products = array_keys($this->loadModel('product')->getPrivProducts());
|
||||
@@ -123,6 +124,7 @@ class testcase extends control
|
||||
$caseQuery = $caseQuery . ' AND `product`' . helper::dbIN(array_keys($products));
|
||||
$queryProductID = 'all';
|
||||
}
|
||||
$caseQuery .= ')';
|
||||
|
||||
$caseQuery = $this->loadModel('search')->replaceDynamic($caseQuery);
|
||||
$this->view->cases = $this->dao->select('*')->from(TABLE_CASE)->where($caseQuery)
|
||||
@@ -814,8 +816,6 @@ class testcase extends control
|
||||
$endField = $field;
|
||||
$caseData = array();
|
||||
$stepData = array();
|
||||
$hasEdit = false;
|
||||
$hasNew = false;
|
||||
while($csv)
|
||||
{
|
||||
$case = new stdclass();
|
||||
@@ -889,15 +889,6 @@ class testcase extends control
|
||||
$csv = substr($csv, $pos + strlen($delimiter));
|
||||
}
|
||||
|
||||
if(!empty($case->id))
|
||||
{
|
||||
$hasEdit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$hasNew = true;
|
||||
}
|
||||
|
||||
$caseData[$row] = $case;
|
||||
unset($case);
|
||||
$row++;
|
||||
@@ -919,8 +910,6 @@ class testcase extends control
|
||||
$this->view->stepData = $stepData;
|
||||
$this->view->productID = $productID;
|
||||
$this->view->product = $this->products[$productID];
|
||||
$this->view->hasEdit = $hasEdit;
|
||||
$this->view->hasNew = $hasNew;
|
||||
$this->display();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,10 +106,7 @@ function createRow()
|
||||
{
|
||||
if(newRowID == 0) newRowID = $('.stepID').size();
|
||||
newRowID ++;
|
||||
var lblDelete = '<?php echo $lang->testcase->deleteStep;?>';
|
||||
var lblBefore = '<?php echo $lang->testcase->insertBefore;?>';
|
||||
var lblAfter = '<?php echo $lang->testcase->insertAfter;?>';
|
||||
var newRow = "<tr class='a-center' id='row" + newRowID + "'>";
|
||||
var newRow = "<tr class='a-center' id='row" + newRowID + "'>";
|
||||
newRow += "<th class='stepID'></th>";
|
||||
newRow += "<td class='w-p50'><textarea name='steps[]' rows=3 class='w-p100'></textarea></td>";
|
||||
newRow += "<td><textarea name='expects[]' rows=3 class='w-p100'></textarea></td>";
|
||||
|
||||
@@ -69,8 +69,7 @@ $lang->testcase->export = "Export data";
|
||||
$lang->testcase->confirmChange = 'Confirm case change';
|
||||
$lang->testcase->confirmStoryChange = 'Confirm story change';
|
||||
|
||||
$lang->testcase->editHaved = 'Modify existing case';
|
||||
$lang->testcase->addNew = 'Add new case';
|
||||
$lang->testcase->new = 'New';
|
||||
|
||||
$lang->testcase->num = 'The number of cases';
|
||||
|
||||
|
||||
@@ -69,8 +69,7 @@ $lang->testcase->export = "导出数据";
|
||||
$lang->testcase->confirmChange = '确认用例变动';
|
||||
$lang->testcase->confirmStoryChange = '确认需求变动';
|
||||
|
||||
$lang->testcase->editHaved = '修改已有用例';
|
||||
$lang->testcase->addNew = '添加新用例';
|
||||
$lang->testcase->new = '新增';
|
||||
|
||||
$lang->testcase->num = '导入用例个数:';
|
||||
|
||||
|
||||
@@ -538,5 +538,8 @@ class testcaseModel extends model
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unlink($this->session->importFile);
|
||||
unset($_SESSION['importFile']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ js::set('confirmDelete', $lang->testcase->confirmDelete);
|
||||
</div>
|
||||
|
||||
<div id='querybox' class='<?php if($browseType != 'bysearch') echo 'hidden';?>'></div>
|
||||
<div class='treeSlider'><span> </span></div>
|
||||
<div class='treeSlider' id='testcaseTree'><span> </span></div>
|
||||
<form id='batchForm' method='post'>
|
||||
<table class='cont-lt1'>
|
||||
<tr valign='top'>
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/form.html.php';?>
|
||||
<?php include '../../common/view/chosen.html.php';?>
|
||||
<?php js::set('lblDelete', $lang->testcase->deleteStep);?>
|
||||
<?php js::set('lblBefore', $lang->testcase->insertBefore);?>
|
||||
<?php js::set('lblAfter', $lang->testcase->insertAfter);?>
|
||||
<form method='post' enctype='multipart/form-data' id='dataform' class='ajaxForm'>
|
||||
<table class='table-1'>
|
||||
<caption><?php echo $lang->testcase->create;?></caption>
|
||||
|
||||
@@ -11,13 +11,12 @@ function setDownloading()
|
||||
|
||||
function closeWindow()
|
||||
{
|
||||
if($.cookie('downloading') == 1 || i >= 30)
|
||||
if($.cookie('downloading') == 1)
|
||||
{
|
||||
parent.$.fn.colorbox.close();
|
||||
$.cookie('downloading', null);
|
||||
clearInterval(time);
|
||||
}
|
||||
i ++;
|
||||
}
|
||||
</script>
|
||||
<form method='post' target='hiddenwin' onsubmit='setDownloading();'>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<style>
|
||||
.affix {position:fixed; top:0px; width:95.6%;z-index:10000;}
|
||||
</style>
|
||||
<form target='hiddenwin' method='post'>
|
||||
<?php if($hasEdit):?>
|
||||
<table class='table-1'>
|
||||
<caption class='caption-tl'><?php echo $lang->testcase->editHaved?></caption>
|
||||
<tr class='colhead'>
|
||||
<th><?php echo $lang->testcase->id?></th>
|
||||
<th><?php echo $lang->testcase->title?></th>
|
||||
@@ -24,13 +25,24 @@
|
||||
</th>
|
||||
</tr>
|
||||
<?php foreach($caseData as $key => $case):?>
|
||||
<?php if(empty($case->id)) continue?>
|
||||
<tr valign='top' align='center'>
|
||||
<td><?php echo $case->id . html::hidden("id[$key]", $case->id) . html::hidden("product[$key]", $productID)?></td>
|
||||
<td>
|
||||
<?php
|
||||
if(isset($case->id))
|
||||
{
|
||||
echo $case->id . html::hidden("id[$key]", $case->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $key . " <sub class='gray' style='vertical-align:sub;'>{$lang->testcase->new}</sub>";
|
||||
}
|
||||
echo html::hidden("product[$key]", $productID);
|
||||
?>
|
||||
</td>
|
||||
<td><?php echo html::input("title[$key]", $case->title, "class='text-1' style='margin-top:2px'")?></td>
|
||||
<td><?php echo html::select("module[$key]", $modules, isset($case->module) ? $case->module : $cases[$case->id]->module, "class='select-2'")?></td>
|
||||
<td><?php echo html::select("story[$key]", $stories, isset($case->story) ? $case->story : $cases[$case->id]->story, "class='select-2'")?></td>
|
||||
<td><?php echo html::select("pri[$key]", $lang->testcase->priList, isset($case->pri) ? $case->pri : $cases[$case->id]->pri)?></td>
|
||||
<td><?php echo html::select("module[$key]", $modules, isset($case->module) ? $case->module : (isset($case->id) ? $cases[$case->id]->module : ''), "class='select-2'")?></td>
|
||||
<td><?php echo html::select("story[$key]", $stories, isset($case->story) ? $case->story : (isset($case->id) ? $cases[$case->id]->story : ''), "class='select-2'")?></td>
|
||||
<td><?php echo html::select("pri[$key]", $lang->testcase->priList, isset($case->pri) ? $case->pri : (isset($case->id) ? $cases[$case->id]->pri : ''))?></td>
|
||||
<td><?php echo html::select("type[$key]", $lang->testcase->typeList, $case->type)?></td>
|
||||
<td><?php echo html::select("status[$key]", $lang->testcase->statusList, isset($case->status) ? $case->status : '')?></td>
|
||||
<td><?php echo html::input("frequency[$key]", isset($case->frequency) ? $case->frequency : 1, "size='2'")?></td>
|
||||
@@ -52,58 +64,30 @@
|
||||
<?php unset($caseData[$key]);?>
|
||||
<?php endforeach;?>
|
||||
</table>
|
||||
<?php endif;?>
|
||||
<?php if($hasNew):?>
|
||||
<table class='table-1'>
|
||||
<caption class='caption-tl'><?php echo $lang->testcase->addNew?></caption>
|
||||
<tr class='colhead'>
|
||||
<th><?php echo $lang->testcase->importID?></th>
|
||||
<th><?php echo $lang->testcase->title?></th>
|
||||
<th><?php echo $lang->testcase->module?></th>
|
||||
<th><?php echo $lang->testcase->story?></th>
|
||||
<th><?php echo $lang->testcase->pri?></th>
|
||||
<th><?php echo $lang->testcase->type?></th>
|
||||
<th><?php echo $lang->testcase->status?></th>
|
||||
<th><?php echo $lang->testcase->frequency?></th>
|
||||
<th><?php echo $lang->testcase->stage?></th>
|
||||
<th><?php echo $lang->testcase->precondition?></th>
|
||||
<th><?php echo $lang->testcase->steps?>
|
||||
<table class='table-1'>
|
||||
<tr>
|
||||
<th><?php echo $lang->testcase->stepDesc?></th>
|
||||
<th><?php echo $lang->testcase->stepExpect?></th>
|
||||
</tr>
|
||||
</table>
|
||||
</th>
|
||||
</tr>
|
||||
<?php foreach($caseData as $key => $case):?>
|
||||
<tr valign='top' align='center'>
|
||||
<td><?php echo $key + 1?></td>
|
||||
<td><?php echo html::input("title[$key]", $case->title, "class='text-1' style='margin-top:2px'")?></td>
|
||||
<td><?php echo html::select("module[$key]", $modules, isset($case->module) ? $case->module : '', "class='select-2'") . html::hidden("product[$key]", $productID)?></td>
|
||||
<td><?php echo html::select("story[$key]", $stories, isset($case->story) ? $case->story : '', "class='select-2'")?></td>
|
||||
<td><?php echo html::select("pri[$key]", $lang->testcase->priList, isset($case->pri) ? $case->pri : '')?></td>
|
||||
<td><?php echo html::select("type[$key]", $lang->testcase->typeList, $case->type)?></td>
|
||||
<td><?php echo html::select("status[$key]", $lang->testcase->statusList, isset($case->status) ? $case->status : 'normal')?></td>
|
||||
<td><?php echo html::input("frequency[$key]", isset($case->frequency) ? $case->frequency : 1, "size='2'")?></td>
|
||||
<td><?php echo html::select("stage[$key][]", $lang->testcase->stageList, isset($case->stage) ? $case->stage : '', "multiple='multiple'")?></td>
|
||||
<td><?php echo html::textarea("precondition[$key]", isset($case->precondition) ? $case->precondition : "", "style='margin-top:2px; height:69px'")?></td>
|
||||
<td>
|
||||
<?php if(isset($stepData[$key]['desc'])):?>
|
||||
<table class='table-1'>
|
||||
<?php foreach($stepData[$key]['desc'] as $id => $desc):?>
|
||||
<tr>
|
||||
<td><?php echo html::textarea("desc[$key][$id]", $desc)?></td>
|
||||
<td><?php echo html::textarea("expect[$key][$id]", isset($stepData[$key]['expect'][$id]) ? $stepData[$key]['expect'][$id] : '')?></td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</table>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</table>
|
||||
<?php endif;?>
|
||||
<p><?php echo html::submitButton() . html::backButton()?></p>
|
||||
</form>
|
||||
<script>
|
||||
$(function(){affix('.colhead')})
|
||||
function affix(obj)
|
||||
{
|
||||
var fixH = $(obj).offset().top;
|
||||
var first = true;
|
||||
$(window).scroll(function()
|
||||
{
|
||||
var scroH = $(this).scrollTop();
|
||||
if(scroH>=fixH && first)
|
||||
{
|
||||
$(obj).parent().parent().before("<table id='headerClone'></table>");
|
||||
$('#headerClone').append($(obj).clone()).addClass('affix');
|
||||
$('.table-1 ' + obj + ' th').each(function(i){$('#headerClone ' + obj + ' th').eq(i).width($(this).width())});
|
||||
first = false;
|
||||
}
|
||||
else if(scroH<fixH)
|
||||
{
|
||||
$("#headerClone").remove();
|
||||
first = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -303,7 +303,7 @@ class tree extends control
|
||||
*/
|
||||
public function ajaxGetOptionMenu($rootID, $viewType = 'story', $rootModuleID = 0, $returnType = 'html', $needManage = false)
|
||||
{
|
||||
if($viewType = 'task')
|
||||
if($viewType == 'task')
|
||||
{
|
||||
$optionMenu = $this->tree->getTaskOptionMenu($rootID);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ $lang->user->dept = '所属部门';
|
||||
$lang->user->account = '用户名';
|
||||
$lang->user->password = '密码';
|
||||
$lang->user->password2 = '请重复密码';
|
||||
$lang->user->role = '角色';
|
||||
$lang->user->role = '职位';
|
||||
$lang->user->group = '分组';
|
||||
$lang->user->realname = '真实姓名';
|
||||
$lang->user->nickname = '昵称';
|
||||
@@ -124,7 +124,7 @@ $lang->user->loginWithDemoUser = '使用demo账号登录:';
|
||||
$lang->user->placeholder = new stdclass();
|
||||
$lang->user->placeholder->account = '英文、数字和下划线的组合,三位以上';
|
||||
$lang->user->placeholder->password1 = '六位以上';
|
||||
$lang->user->placeholder->role = '角色影响内容和用户列表的顺序。';
|
||||
$lang->user->placeholder->role = '职位影响内容和用户列表的顺序。';
|
||||
$lang->user->placeholder->group = '分组决定用户的权限列表。';
|
||||
$lang->user->placeholder->join = '入职日期';
|
||||
$lang->user->placeholder->commiter = '版本控制系统(subversion)中的帐号';
|
||||
@@ -135,7 +135,7 @@ $lang->user->error->accountDupl = "ID %s,该用户名已经存在";
|
||||
$lang->user->error->realname = "ID %s,必须填写真实姓名";
|
||||
$lang->user->error->password = "ID %s,密码必须六位以上";
|
||||
$lang->user->error->mail = "ID %s,请填写正确的邮箱地址";
|
||||
$lang->user->error->role = "ID %s,角色不能为空";
|
||||
$lang->user->error->role = "ID %s,职位不能为空";
|
||||
|
||||
$lang->user->contacts = new stdclass();
|
||||
$lang->user->contacts->common = '联系人';
|
||||
|
||||
@@ -115,7 +115,14 @@ class userModel extends model
|
||||
if(!$rawCommiters) return array();
|
||||
|
||||
$commiters = array();
|
||||
foreach($rawCommiters as $commiter) $commiters[$commiter->commiter] = $commiter->realname ? $commiter->realname : $commiter->account;
|
||||
foreach($rawCommiters as $commiter)
|
||||
{
|
||||
$userCommiters = explode(',', $commiter->commiter);
|
||||
foreach($userCommiters as $userCommiter)
|
||||
{
|
||||
$commiters[$userCommiter] = $commiter->realname ? $commiter->realname : $commiter->account;
|
||||
}
|
||||
}
|
||||
|
||||
return $commiters;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ $jsFiles[] = $jqueryRoot . 'datepicker/date.js';
|
||||
$jsFiles[] = $jqueryRoot . 'datepicker/min.js';
|
||||
$jsFiles[] = $jqueryRoot . 'alert/min.js';
|
||||
$jsFiles[] = $jqueryRoot . 'colorize/min.js';
|
||||
$jsFiles[] = $jqueryRoot . 'dropmenu/dropmenu.js';
|
||||
|
||||
/* Combine these js files. */
|
||||
$allJSFile = $jsRoot . 'all.js';
|
||||
@@ -71,7 +70,6 @@ foreach($langs as $lang)
|
||||
$cssCode .= file_get_contents($themeRoot . 'default/treeview.css');
|
||||
$cssCode .= file_get_contents($themeRoot . 'default/datepicker.css');
|
||||
$cssCode .= file_get_contents($themeRoot . 'default/alert.css');
|
||||
$cssCode .= file_get_contents($themeRoot . 'default/dropmenu.css');
|
||||
|
||||
/* Css file for current lang and current them. */
|
||||
$cssCode .= file_get_contents($themeRoot . "lang/$lang.css");
|
||||
|
||||
Vendored
+4
-1
@@ -13,8 +13,11 @@ $.extend(
|
||||
{
|
||||
$.enableForm(formID);
|
||||
|
||||
/* try parse to json when response is json's string. */
|
||||
try{if(typeof(response) == 'string') response = JSON.parse(response);}catch(e){}
|
||||
|
||||
/* The response is not an object, some error occers, alert it. */
|
||||
if($.type(response) != 'object')
|
||||
if(typeof(response) != 'object')
|
||||
{
|
||||
if(response) return alert(response);
|
||||
return alert('No response.');
|
||||
|
||||
+41
-10
@@ -285,6 +285,39 @@ function toggleHelpLink()
|
||||
if($.cookie('help') == 'on') return $.cookie('help', 'off', {expires:config.cookieLife, path:config.webRoot});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide tree box
|
||||
*
|
||||
* @param string $treeType
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function hideTreeBox(treeType)
|
||||
{
|
||||
$.cookie(treeType, 'hide', {expires:config.cookieLife, path:config.webRoot});
|
||||
$('.side').hide();
|
||||
$('.divider').hide();
|
||||
$('.treeSlider span').css("border-right", "0 none");
|
||||
$('.treeSlider span').css("border-left", "4px solid #000000");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Show tree box
|
||||
*
|
||||
* @param string $treeType
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function showTreeBox(treeType)
|
||||
{
|
||||
$.cookie(treeType, 'show', {expires:config.cookieLife, path:config.webRoot});
|
||||
$('.side').show();
|
||||
$('.divider').show();
|
||||
$('.treeSlider span').css("border-right", "4px solid #000000");
|
||||
$('.treeSlider span').css("border-left", "0 none");
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle tree menu.
|
||||
|
||||
@@ -293,23 +326,21 @@ function toggleHelpLink()
|
||||
*/
|
||||
function toggleTreeBox()
|
||||
{
|
||||
var treeSliderH = 50;
|
||||
$('.treeSlider').height(treeSliderH);
|
||||
var treeType = $('.treeSlider').attr('id');
|
||||
if(typeof treeType == 'undefined') return;
|
||||
if($.cookie(treeType) == 'hide') hideTreeBox(treeType);
|
||||
|
||||
$('.treeSlider').toggle
|
||||
(
|
||||
function()
|
||||
{
|
||||
$('.side').hide()
|
||||
$('.divider').hide()
|
||||
$('.treeSlider span').css("border-right", "0 none");
|
||||
$('.treeSlider span').css("border-left", "4px solid #000000");
|
||||
if($.cookie(treeType) == 'hide') return showTreeBox(treeType);
|
||||
hideTreeBox(treeType);
|
||||
},
|
||||
function()
|
||||
{
|
||||
$('.side').show()
|
||||
$('.divider').show()
|
||||
$('.treeSlider span').css("border-right", "4px solid #000000");
|
||||
$('.treeSlider span').css("border-left", "0 none");
|
||||
if($.cookie(treeType) == 'show') return hideTreeBox(treeType);
|
||||
showTreeBox(treeType);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -358,6 +358,7 @@ table.tablesorter thead tr .headerSortDown {background-image: url(./images/table
|
||||
border-left:none;
|
||||
cursor: pointer;
|
||||
width: 8px;
|
||||
height: 50px;
|
||||
left: 16px;
|
||||
border-radius:0px 10px 10px 0px
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user