Merge branch 'master' into 'sprint/175_sgm_fixbug'
# Conflicts: # module/execution/control.php # module/message/config.php
This commit is contained in:
@@ -15,6 +15,7 @@ test/data/sql/
|
||||
.gitkeep
|
||||
.bak
|
||||
.idea
|
||||
.vscode
|
||||
.gitignore
|
||||
.DS_Store
|
||||
vendor/
|
||||
|
||||
@@ -20,6 +20,8 @@ class bugEntry extends entry
|
||||
*/
|
||||
public function get($bugID)
|
||||
{
|
||||
$this->resetOpenApp($this->param('tab', 'product'));
|
||||
|
||||
$control = $this->loadController('bug', 'view');
|
||||
$control->view($bugID);
|
||||
|
||||
@@ -91,6 +93,11 @@ class bugEntry extends entry
|
||||
|
||||
$bug->actions = $this->loadModel('action')->processActionForAPI($data->data->actions, $data->data->users, $this->lang->bug);
|
||||
|
||||
$preAndNext = $data->data->preAndNext;
|
||||
$bug->preAndNext = array();
|
||||
$bug->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
|
||||
$bug->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
|
||||
|
||||
$this->send(200, $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool'));
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ class docEntry extends entry
|
||||
*/
|
||||
public function get($docID)
|
||||
{
|
||||
$this->resetOpenApp($this->param('tab', 'doc'));
|
||||
|
||||
$control = $this->loadController('doc', 'view');
|
||||
$control->view($docID);
|
||||
|
||||
@@ -44,6 +46,11 @@ class docEntry extends entry
|
||||
$doc->addedBy = zget($usersWithAvatar, $doc->addedBy);
|
||||
}
|
||||
|
||||
$preAndNext = $data->data->preAndNext;
|
||||
$doc->preAndNext = array();
|
||||
$doc->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
|
||||
$doc->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
|
||||
|
||||
$this->send(200, $this->format($doc, 'addedDate:time,assignedDate:date,editedDate:time'));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* The repo entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author xiawenlong <xiawenlong@cnezsoft.com>
|
||||
* @package repo
|
||||
* @version 1
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
class gitlabWebhookEntry extends baseEntry
|
||||
{
|
||||
|
||||
/**
|
||||
* Repo webhook.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$repoID= $this->param('repoID');
|
||||
if(empty($id)) return;
|
||||
|
||||
$this->loadModel('repo');
|
||||
|
||||
$repo = $this->repo->getRepoByID($repoID);
|
||||
if(empty($repo)) return;
|
||||
|
||||
$headers = getallheaders(); /* Fetch all HTTP request headers. */
|
||||
$event = isset($headers['X-Gitlab-Event']) ? $headers['X-Gitlab-Event'] : '';
|
||||
$token = isset($headers['X-Gitlab-Token']) ? $headers['X-Gitlab-Token'] : '';
|
||||
if(empty($event) || empty($token)) return;
|
||||
|
||||
$this->repo->handleWebhook($event, $token, $this->requestBody, $repo);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,7 +29,11 @@ class productplanEntry extends Entry
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $this->format($data->data->plan, 'begin:date,end:date,deleted:bool');
|
||||
$plan = $data->data->plan;
|
||||
$plan->stories = $data->data->planStories;
|
||||
$plan->bugs = $data->data->planBugs;
|
||||
|
||||
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
|
||||
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* The productplanlinkbug entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
class productplanLinkBugEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function post($planID)
|
||||
{
|
||||
$fields = 'bugs';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control = $this->loadController('productplan', 'linkBug');
|
||||
$control->linkBug($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'success')
|
||||
{
|
||||
$control = $this->loadController('productplan', 'view');
|
||||
$control->view($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $data->data->plan;
|
||||
$plan->stories = $data->data->planStories;
|
||||
$plan->bugs = $data->data->planBugs;
|
||||
|
||||
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
|
||||
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
|
||||
$this->sendError(400, array('message' => isset($data->message) ? $data->message : 'error'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* The productplanlinkstory entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
class productplanLinkStoryEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function post($planID)
|
||||
{
|
||||
$fields = 'stories';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control = $this->loadController('productplan', 'linkStory');
|
||||
$control->linkStory($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'success')
|
||||
{
|
||||
$control = $this->loadController('productplan', 'view');
|
||||
$control->view($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $data->data->plan;
|
||||
$plan->stories = $data->data->planStories;
|
||||
$plan->bugs = $data->data->planBugs;
|
||||
|
||||
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
|
||||
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
|
||||
$this->sendError(400, array('message' => isset($data->message) ? $data->message : 'error'));
|
||||
}
|
||||
}
|
||||
@@ -57,4 +57,34 @@ class productplansEntry extends entry
|
||||
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function post($productID = 0)
|
||||
{
|
||||
if(!$productID) $productID = $this->param('product', 0);
|
||||
if(!$productID) return $this->sendError(400, 'No product id.');
|
||||
|
||||
$fields = 'branch,begin,end,title,desc';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control = $this->loadController('productplan', 'create');
|
||||
$control->create($productID, $this->param('branch', 0), $this->param('parent', 0));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'success')
|
||||
{
|
||||
$plan = $this->loadModel('productplan')->getByID($data->id);
|
||||
$plan->stories = array();
|
||||
$plan->bugs = array();
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
|
||||
$this->sendError(400, array('message' => isset($data->message) ? $data->message : 'error'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* The productplanunlinkbug entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
class productplanUnlinkBugEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function post($planID)
|
||||
{
|
||||
$productplan = $this->loadModel('productplan');
|
||||
foreach($this->request('bugs', array()) as $bugID)
|
||||
{
|
||||
$productplan->unlinkBug($bugID, $planID);
|
||||
if(dao::isError()) return $this->sendError('error');
|
||||
}
|
||||
|
||||
$control = $this->loadController('productplan', 'view');
|
||||
$control->view($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $data->data->plan;
|
||||
$plan->stories = $data->data->planStories;
|
||||
$plan->bugs = $data->data->planBugs;
|
||||
|
||||
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
|
||||
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* The productplanunlinkstory entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
class productplanUnlinkStoryEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function post($planID)
|
||||
{
|
||||
$productplan = $this->loadModel('productplan');
|
||||
foreach($this->request('stories', array()) as $storyID)
|
||||
{
|
||||
$productplan->unlinkStory($storyID, $planID);
|
||||
if(dao::isError()) return $this->sendError('error');
|
||||
}
|
||||
|
||||
$control = $this->loadController('productplan', 'view');
|
||||
$control->view($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $data->data->plan;
|
||||
$plan->stories = $data->data->planStories;
|
||||
$plan->bugs = $data->data->planBugs;
|
||||
|
||||
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
|
||||
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ class projectCasesEntry extends entry
|
||||
if(!$projectID) $projectID = $this->param('project', 0);
|
||||
if(empty($projectID)) return $this->sendError(400, 'Need project id.');
|
||||
|
||||
$this->app->tab = 'project';
|
||||
$this->resetOpenApp('project');
|
||||
$this->app->session->set('project', $projectID, $this->app->tab);
|
||||
|
||||
$control = $this->loadController('project', 'testcase');
|
||||
|
||||
@@ -20,6 +20,8 @@ class storyEntry extends Entry
|
||||
*/
|
||||
public function get($storyID)
|
||||
{
|
||||
$this->resetOpenApp($this->param('tab', 'product'));
|
||||
|
||||
$control = $this->loadController('story', 'view');
|
||||
$control->view($storyID);
|
||||
|
||||
@@ -105,6 +107,11 @@ class storyEntry extends Entry
|
||||
|
||||
$story->actions = $this->loadModel('action')->processActionForAPI($data->data->actions, $data->data->users, $this->lang->story);
|
||||
|
||||
$preAndNext = $data->data->preAndNext;
|
||||
$story->preAndNext = array();
|
||||
$story->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
|
||||
$story->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
|
||||
|
||||
$this->send(200, $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time'));
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ class taskEntry extends Entry
|
||||
*/
|
||||
public function get($taskID)
|
||||
{
|
||||
$this->resetOpenApp($this->param('tab', 'execution'));
|
||||
|
||||
$control = $this->loadController('task', 'view');
|
||||
$control->view($taskID);
|
||||
|
||||
@@ -99,6 +101,11 @@ class taskEntry extends Entry
|
||||
|
||||
$task->actions = $this->loadModel('action')->processActionForAPI($data->data->actions, $data->data->users, $this->lang->task);
|
||||
|
||||
$preAndNext = $data->data->preAndNext;
|
||||
$task->preAndNext = array();
|
||||
$task->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
|
||||
$task->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
|
||||
|
||||
$this->send(200, $this->format($task, 'openedDate:time,assignedDate:time,realStarted:time,finishedDate:time,canceledDate:time,closedDate:time,lastEditedDate:time,deleted:bool'));
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,7 @@ $filter->search->index = new stdclass();
|
||||
$filter->gitlab->webhook = new stdclass();
|
||||
$filter->gitlab->importissue = new stdclass();
|
||||
$filter->mr->diff = new stdclass();
|
||||
$filter->mr->browse = new stdclass();
|
||||
$filter->ci->checkCompileStatus = new stdclass();
|
||||
$filter->execution->export = new stdclass();
|
||||
$filter->tree->browse = new stdclass();
|
||||
@@ -389,6 +390,9 @@ $filter->gitlab->importissue->get['repo'] = 'int';
|
||||
|
||||
$filter->mr->diff->cookie['arrange'] = 'reg::word';
|
||||
|
||||
$filter->mr->browse->get['mode'] = 'string';
|
||||
$filter->mr->browse->get['param'] = 'string';
|
||||
|
||||
$filter->ci->checkCompileStatus->get['gitlabOnly'] = 'string';
|
||||
|
||||
$filter->tree->browse->cookie['preProductID'] = 'int';
|
||||
|
||||
+9
-3
@@ -24,9 +24,13 @@ $routes['/products/:id'] = 'product';
|
||||
$routes['/productlines'] = 'productLines';
|
||||
$routes['/productlines/:id'] = 'productLine';
|
||||
|
||||
$routes['/productplans'] = 'productPlans';
|
||||
$routes['/products/:id/plans'] = 'productPlans';
|
||||
$routes['/productplans/:id'] = 'productPlan';
|
||||
$routes['/productplans'] = 'productPlans';
|
||||
$routes['/products/:id/plans'] = 'productPlans';
|
||||
$routes['/productplans/:id'] = 'productPlan';
|
||||
$routes['/productplans/:id/linkstory'] = 'productPlanLinkStory';
|
||||
$routes['/productplans/:id/unlinkstory'] = 'productPlanUnlinkStory';
|
||||
$routes['/productplans/:id/linkbug'] = 'productPlanLinkBug';
|
||||
$routes['/productplans/:id/unlinkbug'] = 'productPlanUnlinkBug';
|
||||
|
||||
$routes['/releases'] = 'releases';
|
||||
$routes['/products/:id/releases'] = 'releases';
|
||||
@@ -119,4 +123,6 @@ $routes['/z/folders/:id'] = 'zfolder';
|
||||
$routes['/z/files/:id'] = 'zfile';
|
||||
$routes['/z/files/:id/content'] = 'zfileContent';
|
||||
|
||||
$routes['/gitlab/webhook'] = 'gitlabWebhook';
|
||||
|
||||
$config->routes = $routes;
|
||||
|
||||
@@ -230,6 +230,7 @@ define('TABLE_PIPELINE', '`' . $config->db->prefix . 'pipeline`');
|
||||
define('TABLE_JOB', '`' . $config->db->prefix . 'job`');
|
||||
define('TABLE_COMPILE', '`' . $config->db->prefix . 'compile`');
|
||||
define('TABLE_MR', '`' . $config->db->prefix . 'mr`');
|
||||
define('TABLE_MRAPPROVAL', '`' . $config->db->prefix . 'mrapproval`');
|
||||
|
||||
define('TABLE_REPO', '`' . $config->db->prefix . 'repo`');
|
||||
define('TABLE_RELATION', '`' . $config->db->prefix . 'relation`');
|
||||
@@ -284,4 +285,4 @@ $config->newFeatures = array('introduction', 'tutorial', 'youngBlueTheme');
|
||||
/* Program privs.*/
|
||||
$config->programPriv = new stdclass();
|
||||
$config->programPriv->scrum = array('projectstory', 'projectrelease', 'project', 'build', 'bug', 'testcase', 'testreport', 'caselib', 'doc', 'repo', 'meeting', 'stakeholder');
|
||||
$config->programPriv->waterfall = array_merge($config->programPriv->scrum, array('workestimation', 'durationestimation', 'budget', 'programplan', 'review', 'reviewissue', 'weekly', 'milestone', 'design', 'issue', 'risk', 'opportunity', 'measrecord', 'auditplan', 'trainplan', 'gapanalysis', 'pssp'));
|
||||
$config->programPriv->waterfall = array_merge($config->programPriv->scrum, array('workestimation', 'durationestimation', 'budget', 'programplan', 'review', 'reviewissue', 'weekly', 'cm', 'milestone', 'design', 'issue', 'risk', 'opportunity', 'measrecord', 'auditplan', 'trainplan', 'gapanalysis', 'pssp', 'researchplan', 'researchreport'));
|
||||
|
||||
@@ -142,3 +142,13 @@ ADD `feedbackBy` varchar(100) NOT NULL AFTER `version`,
|
||||
ADD `notifyEmail` varchar(100) NOT NULL AFTER `feedbackBy`;
|
||||
|
||||
ALTER TABLE `zt_product` ADD `reviewer` varchar(255) NOT NULL AFTER `whitelist`;
|
||||
UPDATE `zt_testtask` SET `pri`=3 WHERE `pri`=0;
|
||||
|
||||
ALTER table zt_mr ADD `approver` varchar(255) NOT NULL,
|
||||
ADD `approvalStatus` char(30) NOT NULL,
|
||||
ADD `needApproved` enum('0','1') NOT NULL DEFAULT '0',
|
||||
ADD `needCI` enum('0','1') NOT NULL DEFAULT '0',
|
||||
ADD `repoID` mediumint(8) unsigned NOT NULL,
|
||||
ADD `jobID` mediumint(8) unsigned NOT NULL,
|
||||
ADD `compileID` mediumint(8) unsigned NOT NULL,
|
||||
ADD `compileStatus` char(30) NOT NULL;
|
||||
|
||||
@@ -731,6 +731,7 @@ CREATE TABLE IF NOT EXISTS `zt_mr` (
|
||||
`description` text NOT NULL,
|
||||
`assignee` varchar(255) NOT NULL,
|
||||
`reviewer` varchar(255) NOT NULL,
|
||||
`approver` varchar(255) NOT NULL,
|
||||
`createdBy` varchar(30) NOT NULL,
|
||||
`createdDate` datetime NOT NULL,
|
||||
`editedBy` varchar(30) NOT NULL,
|
||||
@@ -738,6 +739,23 @@ CREATE TABLE IF NOT EXISTS `zt_mr` (
|
||||
`deleted` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`status` char(30) NOT NULL,
|
||||
`mergeStatus` char(30) NOT NULL,
|
||||
`approvalStatus` char(30) NOT NULL,
|
||||
`needApproved` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`needCI` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`repoID` mediumint(8) unsigned NOT NULL,
|
||||
`jobID` mediumint(8) unsigned NOT NULL,
|
||||
`compileID` mediumint(8) unsigned NOT NULL,
|
||||
`compileStatus` char(30) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
-- DROP TABLE IF EXISTS `zt_mrapproval`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_mrapproval` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`mrID` mediumint(8) unsigned NOT NULL,
|
||||
`account` varchar(255) NOT NULL,
|
||||
`date` datetime NOT NULL,
|
||||
`action` char(30) NOT NULL,
|
||||
`comment` text NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
-- DROP TABLE IF EXISTS `zt_notify`;
|
||||
|
||||
@@ -576,43 +576,47 @@ class baseEntry
|
||||
{
|
||||
switch($type)
|
||||
{
|
||||
case 'time':
|
||||
$timeFormat = $this->param('timeFormat', 'utc');
|
||||
if($timeFormat == 'utc')
|
||||
{
|
||||
if(!$value or $value == '0000-00-00 00:00:00') return null;
|
||||
return gmdate("Y-m-d\TH:i:s\Z", strtotime($value));
|
||||
}
|
||||
return $value;
|
||||
case 'date':
|
||||
if(!$value or $value == '0000-00-00') return null;
|
||||
return $value;
|
||||
case 'bool':
|
||||
return !empty($value);
|
||||
case 'int':
|
||||
return (int) $value;
|
||||
case 'idList':
|
||||
$values = explode(',', $value);
|
||||
if(empty($values)) return array();
|
||||
case 'time':
|
||||
$timeFormat = $this->param('timeFormat', 'utc');
|
||||
if($timeFormat == 'utc')
|
||||
{
|
||||
if(!$value or $value == '0000-00-00 00:00:00') return null;
|
||||
return gmdate("Y-m-d\TH:i:s\Z", strtotime($value));
|
||||
}
|
||||
return $value;
|
||||
case 'date':
|
||||
if(!$value or $value == '0000-00-00') return null;
|
||||
return $value;
|
||||
case 'bool':
|
||||
return !empty($value);
|
||||
case 'int':
|
||||
return (int) $value;
|
||||
case 'idList':
|
||||
$values = explode(',', $value);
|
||||
if(empty($values)) return array();
|
||||
|
||||
$idList = array();
|
||||
foreach($values as $val)
|
||||
{
|
||||
if($val !== '') $idList[] = (int) $val;
|
||||
}
|
||||
return $idList;
|
||||
case 'stringList':
|
||||
$values = explode(',', $value);
|
||||
if(empty($values)) return array();
|
||||
$idList = array();
|
||||
foreach($values as $val)
|
||||
{
|
||||
if($val !== '') $idList[] = (int) $val;
|
||||
}
|
||||
return $idList;
|
||||
case 'stringList':
|
||||
$values = explode(',', $value);
|
||||
if(empty($values)) return array();
|
||||
|
||||
$stringList = array();
|
||||
foreach($values as $val)
|
||||
{
|
||||
if($val !== '') $stringList[] = $val;
|
||||
}
|
||||
return $stringList;
|
||||
default:
|
||||
return $value;
|
||||
$stringList = array();
|
||||
foreach($values as $val)
|
||||
{
|
||||
if($val !== '') $stringList[] = $val;
|
||||
}
|
||||
return $stringList;
|
||||
case 'array':
|
||||
$array = array();
|
||||
if(!empty($value)) foreach($value as $v) $array[] = $v;
|
||||
return $array;
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,4 +654,18 @@ class baseEntry
|
||||
$this->send(403, array('error' => 'Access not allowed'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset open app.
|
||||
*
|
||||
* @param string $tab
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function resetOpenApp($tab)
|
||||
{
|
||||
$_COOKIE['tab'] = $tab;
|
||||
$this->app->tab = $tab;
|
||||
$this->app->session->tab = $tab;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -928,6 +928,14 @@ class baseControl
|
||||
{
|
||||
if(!empty($data['message']))
|
||||
{
|
||||
if(is_string($data['message']))
|
||||
{
|
||||
echo js::alert($data['message']);
|
||||
$locate = isset($data['locate']) ? $data['locate'] : (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '');
|
||||
if (!empty($locate)) die(js::locate($locate));
|
||||
die(isset($data['message']) ? $data['message'] : 'fail');
|
||||
}
|
||||
|
||||
$message = json_decode(json_encode((array)$data['message']));
|
||||
foreach((array)$message as $item => $errors) $message->$item = implode(',', $errors);
|
||||
die(js::alert(strip_tags(implode('\n', (array)$message))));
|
||||
|
||||
@@ -517,7 +517,7 @@ class baseHelper
|
||||
* Get now time use the DT_DATETIME1 constant defined in the lang file.
|
||||
*
|
||||
* @access public
|
||||
* @return datetime now
|
||||
* @return string now
|
||||
*/
|
||||
static public function now()
|
||||
{
|
||||
@@ -529,7 +529,7 @@ class baseHelper
|
||||
* Get today according to the DT_DATE1 constant defined in the lang file.
|
||||
*
|
||||
* @access public
|
||||
* @return date today
|
||||
* @return string today
|
||||
*/
|
||||
static public function today()
|
||||
{
|
||||
@@ -541,7 +541,7 @@ class baseHelper
|
||||
* Get now time use the DT_TIME1 constant defined in the lang file.
|
||||
*
|
||||
* @access public
|
||||
* @return date today
|
||||
* @return string today
|
||||
*/
|
||||
static public function time()
|
||||
{
|
||||
@@ -748,10 +748,10 @@ class baseHelper
|
||||
* @param string $viewType
|
||||
* @return string the link string.
|
||||
*/
|
||||
function inLink($methodName = 'index', $vars = '', $viewType = '')
|
||||
function inLink($methodName = 'index', $vars = '', $viewType = '', $onlybody = false)
|
||||
{
|
||||
global $app;
|
||||
return helper::createLink($app->getModuleName(), $methodName, $vars, $viewType);
|
||||
return helper::createLink($app->getModuleName(), $methodName, $vars, $viewType, $onlybody);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -855,7 +855,7 @@ function getWebRoot($full = false)
|
||||
* @param mixed $valueWhenNone value when the key not exits.
|
||||
* @param mixed $valueWhenExists value when the key exits.
|
||||
* @access public
|
||||
* @return string
|
||||
* @return mixed
|
||||
*/
|
||||
function zget($var, $key, $valueWhenNone = false, $valueWhenExists = false)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,566 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the HTMLUP package.
|
||||
*
|
||||
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
|
||||
* <https://github.com/adhocore>
|
||||
*
|
||||
* Licensed under MIT license.
|
||||
*/
|
||||
|
||||
trait HtmlHelper
|
||||
{
|
||||
public function escape($input)
|
||||
{
|
||||
return \htmlspecialchars($input);
|
||||
}
|
||||
|
||||
public function h($level, $line)
|
||||
{
|
||||
if (\is_string($level)) {
|
||||
$level = \trim($level, '- ') === '' ? 2 : 1;
|
||||
}
|
||||
|
||||
if ($level < 7) {
|
||||
return "\n<h{$level}>" . \ltrim(\ltrim($line, '# ')) . "</h{$level}>";
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function hr($prevLine, $line)
|
||||
{
|
||||
if ($prevLine === '' && \preg_match(BlockElementParser::RE_MD_RULE, $line)) {
|
||||
return "\n<hr />";
|
||||
}
|
||||
}
|
||||
|
||||
public function codeStart($lang)
|
||||
{
|
||||
$lang = isset($lang[1])
|
||||
? ' class="language-' . $lang[1] . '"'
|
||||
: '';
|
||||
|
||||
return "\n<pre><code{$lang}>";
|
||||
}
|
||||
|
||||
public function codeLine($line, $isBlock, $indentLen = 4)
|
||||
{
|
||||
$code = "\n"; // @todo: donot use \n for first line
|
||||
$code .= $isBlock ? $line : \substr($line, $indentLen);
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
public function tableStart($line, $delim = '|')
|
||||
{
|
||||
$table = "<table>\n<thead>\n<tr>\n";
|
||||
|
||||
foreach (\explode($delim, \trim($line, $delim)) as $hdr) {
|
||||
$table .= '<th>' . \trim($hdr) . "</th>\n";
|
||||
}
|
||||
|
||||
$table .= "</tr>\n</thead>\n<tbody>\n";
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
public function tableRow($line, $colCount, $delim = '|')
|
||||
{
|
||||
$row = "<tr>\n";
|
||||
|
||||
foreach (\explode($delim, \trim($line, $delim)) as $i => $col) {
|
||||
if ($i > $colCount) {
|
||||
break;
|
||||
}
|
||||
|
||||
$col = \trim($col);
|
||||
$row .= "<td>{$col}</td>\n";
|
||||
}
|
||||
|
||||
$row .= "</tr>\n";
|
||||
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class BlockElementParser
|
||||
{
|
||||
use HtmlHelper;
|
||||
|
||||
const RE_MD_QUOTE = '~^\s*(>+)\s+~';
|
||||
const RE_RAW = '/^<\/?\w.*?\/?>/';
|
||||
const RE_MD_SETEXT = '~^\s*(={3,}|-{3,})\s*$~';
|
||||
const RE_MD_CODE = '/^```\s*([\w-]+)?/';
|
||||
const RE_MD_RULE = '~^(_{3,}|\*{3,}|\-{3,})$~';
|
||||
const RE_MD_TCOL = '~(\|\s*\:)?\s*\-{3,}\s*(\:\s*\|)?~';
|
||||
const RE_MD_OL = '/^\d+\. /';
|
||||
|
||||
protected $lines = [];
|
||||
protected $stackList = [];
|
||||
protected $stackBlock = [];
|
||||
protected $stackTable = [];
|
||||
|
||||
protected $pointer = -1;
|
||||
protected $listLevel = 0;
|
||||
protected $quoteLevel = 0;
|
||||
protected $indent = 0;
|
||||
protected $nextIndent = 0;
|
||||
protected $indentLen = 4;
|
||||
|
||||
protected $indentStr = ' ';
|
||||
protected $line = '';
|
||||
protected $trimmedLine = '';
|
||||
protected $prevLine = '';
|
||||
protected $trimmedPrevLine = '';
|
||||
protected $nextLine = '';
|
||||
protected $trimmedNextLine = '';
|
||||
protected $markup = '';
|
||||
|
||||
protected $inList = \false;
|
||||
protected $inQuote = \false;
|
||||
protected $inPara = \false;
|
||||
protected $inHtml = \false;
|
||||
protected $inTable = \false;
|
||||
|
||||
protected function parseBlockElements()
|
||||
{
|
||||
while (isset($this->lines[++$this->pointer])) {
|
||||
$this->init();
|
||||
|
||||
if ($this->flush() || $this->raw()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->quote();
|
||||
|
||||
if (($block = $this->isBlock()) || $this->inList) {
|
||||
$this->markup .= $block ? '' : $this->trimmedLine;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->table() || $this->paragraph();
|
||||
}
|
||||
}
|
||||
|
||||
protected function isBlock()
|
||||
{
|
||||
return $this->atx() || $this->setext() || $this->code() || $this->rule() || $this->listt();
|
||||
}
|
||||
|
||||
protected function atx()
|
||||
{
|
||||
if (\substr($this->trimmedLine, 0, 1) === '#') {
|
||||
$level = \strlen($this->trimmedLine) - \strlen(\ltrim($this->trimmedLine, '#'));
|
||||
$head = $this->h($level, $this->trimmedLine);
|
||||
|
||||
$this->markup .= $head;
|
||||
|
||||
return (bool) $head;
|
||||
}
|
||||
}
|
||||
|
||||
protected function setext()
|
||||
{
|
||||
if (\preg_match(static::RE_MD_SETEXT, $this->nextLine)) {
|
||||
$this->markup .= $this->h($this->nextLine, $this->trimmedLine);
|
||||
|
||||
$this->pointer++;
|
||||
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function code()
|
||||
{
|
||||
$isShifted = ($this->indent - $this->nextIndent) >= $this->indentLen;
|
||||
$codeBlock = \preg_match(static::RE_MD_CODE, $this->line, $codeMatch);
|
||||
|
||||
if ($codeBlock || (!$this->inList && !$this->inQuote && $isShifted)) {
|
||||
$this->markup .= $this->codeStart($codeMatch);
|
||||
|
||||
if (!$codeBlock) {
|
||||
$this->markup .= $this->escape(\substr($this->line, $this->indentLen));
|
||||
}
|
||||
|
||||
$this->codeInternal($codeBlock);
|
||||
|
||||
$this->pointer++;
|
||||
|
||||
$this->markup .= '</code></pre>';
|
||||
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
|
||||
private function codeInternal($codeBlock)
|
||||
{
|
||||
while (isset($this->lines[$this->pointer + 1])) {
|
||||
$this->line = $this->escape($this->lines[$this->pointer + 1]);
|
||||
|
||||
if (($codeBlock && \substr(\ltrim($this->line), 0, 3) !== '```')
|
||||
|| \strpos($this->line, $this->indentStr) === 0
|
||||
) {
|
||||
$this->markup .= $this->codeLine($this->line, $codeBlock, $this->indentLen);
|
||||
|
||||
$this->pointer++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function rule()
|
||||
{
|
||||
$this->markup .= $hr = $this->hr($this->trimmedPrevLine, $this->trimmedLine);
|
||||
|
||||
return (bool) $hr;
|
||||
}
|
||||
|
||||
protected function listt()
|
||||
{
|
||||
$isUl = \in_array(\substr($this->trimmedLine, 0, 2), ['- ', '* ', '+ ']);
|
||||
|
||||
if ($isUl || \preg_match(static::RE_MD_OL, $this->trimmedLine)) {
|
||||
$wrapper = $isUl ? 'ul' : 'ol';
|
||||
|
||||
if (!$this->inList) {
|
||||
$this->stackList[] = "</$wrapper>";
|
||||
|
||||
$this->markup .= "\n<$wrapper>\n";
|
||||
$this->inList = \true;
|
||||
|
||||
$this->listLevel++;
|
||||
}
|
||||
|
||||
$this->markup .= '<li>' . \ltrim($this->trimmedLine, '+-*0123456789. ');
|
||||
|
||||
$this->listInternal();
|
||||
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
|
||||
private function listInternal()
|
||||
{
|
||||
$isUl = \in_array(\substr($this->trimmedNextLine, 0, 2), ['- ', '* ', '+ ']);
|
||||
|
||||
if ($isUl || \preg_match(static::RE_MD_OL, $this->trimmedNextLine)) {
|
||||
$wrapper = $isUl ? 'ul' : 'ol';
|
||||
if ($this->nextIndent > $this->indent) {
|
||||
$this->stackList[] = "</li>\n";
|
||||
$this->stackList[] = "</$wrapper>";
|
||||
$this->markup .= "\n<$wrapper>\n";
|
||||
|
||||
$this->listLevel++;
|
||||
} else {
|
||||
$this->markup .= "</li>\n";
|
||||
}
|
||||
|
||||
if ($this->nextIndent < $this->indent) {
|
||||
$shift = \intval(($this->indent - $this->nextIndent) / $this->indentLen);
|
||||
|
||||
while ($shift--) {
|
||||
$this->markup .= \array_pop($this->stackList);
|
||||
|
||||
if ($this->listLevel > 2) {
|
||||
$this->markup .= \array_pop($this->stackList);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->markup .= "</li>\n";
|
||||
}
|
||||
}
|
||||
|
||||
protected function table()
|
||||
{
|
||||
static $headerCount = 0;
|
||||
|
||||
if (!$this->inTable) {
|
||||
$headerCount = \substr_count(\trim($this->trimmedLine, '|'), '|');
|
||||
|
||||
return $this->tableInternal($headerCount);
|
||||
}
|
||||
|
||||
$this->markup .= $this->tableRow($this->trimmedLine, $headerCount);
|
||||
|
||||
if (empty($this->trimmedNextLine)
|
||||
|| !\substr_count(\trim($this->trimmedNextLine, '|'), '|')
|
||||
) {
|
||||
$headerCount = 0;
|
||||
$this->inTable = \false;
|
||||
$this->stackTable[] = "</tbody>\n</table>";
|
||||
}
|
||||
|
||||
return \true;
|
||||
}
|
||||
|
||||
private function tableInternal($headerCount)
|
||||
{
|
||||
$columnCount = \preg_match_all(static::RE_MD_TCOL, \trim($this->trimmedNextLine, '|'));
|
||||
|
||||
if ($headerCount > 0 && $headerCount <= $columnCount) {
|
||||
$this->pointer++;
|
||||
|
||||
$this->inTable = \true;
|
||||
$this->markup .= $this->tableStart($this->trimmedLine);
|
||||
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SpanElementParser
|
||||
{
|
||||
use HtmlHelper;
|
||||
|
||||
const RE_URL = '~<(https?:[\/]{2}[^\s]+?)>~';
|
||||
const RE_EMAIL = '~<(\S+?@\S+?)>~';
|
||||
const RE_MD_IMG = '~!\[(.+?)\]\s*\((.+?)\s*(".+?")?\)~';
|
||||
const RE_MD_URL = '~\[(.+?)\]\s*\((.+?)\s*(".+?")?\)~';
|
||||
const RE_MD_FONT = '!(\*{1,2}|_{1,2}|`|~~)(.+?)\\1!';
|
||||
|
||||
public function parse($markup)
|
||||
{
|
||||
return $this->spans(
|
||||
$this->anchors(
|
||||
$this->links($markup)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function links($markup)
|
||||
{
|
||||
$markup = $this->emails($markup);
|
||||
|
||||
return \preg_replace(
|
||||
static::RE_URL,
|
||||
'<a href="$1">$1</a>',
|
||||
$markup
|
||||
);
|
||||
}
|
||||
|
||||
protected function emails($markup)
|
||||
{
|
||||
return \preg_replace(
|
||||
static::RE_EMAIL,
|
||||
'<a href="mailto:$1">$1</a>',
|
||||
$markup
|
||||
);
|
||||
}
|
||||
|
||||
protected function anchors($markup)
|
||||
{
|
||||
$markup = $this->images($markup);
|
||||
|
||||
return \preg_replace_callback(static::RE_MD_URL, function ($a) {
|
||||
$title = isset($a[3]) ? " title={$a[3]} " : '';
|
||||
|
||||
return "<a href=\"{$a[2]}\"{$title}>{$a[1]}</a>";
|
||||
}, $markup);
|
||||
}
|
||||
|
||||
protected function images($markup)
|
||||
{
|
||||
return \preg_replace_callback(static::RE_MD_IMG, function ($img) {
|
||||
$title = isset($img[3]) ? " title={$img[3]} " : '';
|
||||
$alt = $img[1] ? " alt=\"{$img[1]}\" " : '';
|
||||
|
||||
return "<img src=\"{$img[2]}\"{$title}{$alt}/>";
|
||||
}, $markup);
|
||||
}
|
||||
|
||||
protected function spans($markup)
|
||||
{
|
||||
// em/code/strong/del
|
||||
return \preg_replace_callback(static::RE_MD_FONT, function ($em) {
|
||||
switch (\substr($em[1], 0, 2)) {
|
||||
case '**':
|
||||
case '__':
|
||||
$tag = 'strong';
|
||||
break;
|
||||
|
||||
case '~~':
|
||||
$tag = 'del';
|
||||
break;
|
||||
|
||||
case $em[1] === '*':
|
||||
case $em[1] === '_':
|
||||
$tag = 'em';
|
||||
break;
|
||||
|
||||
default:
|
||||
$tag = 'code';
|
||||
$em[2] = $this->escape($em[2]);
|
||||
}
|
||||
|
||||
return "<$tag>{$em[2]}</$tag>";
|
||||
}, $markup);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HtmlUp - A **lightweight** && **fast** `markdown` to HTML Parser.
|
||||
*
|
||||
* Supports most of the markdown specs except deep nested elements.
|
||||
* Check readme.md for the details of its features && limitations.
|
||||
*
|
||||
* @author adhocore | Jitendra Adhikari <jiten.adhikary@gmail.com>
|
||||
* @copyright (c) 2014 Jitendra Adhikari
|
||||
*/
|
||||
class htmlup extends BlockElementParser
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $markdown
|
||||
* @param int $indentWidth
|
||||
*/
|
||||
public function __construct($markdown = \null, $indentWidth = 4)
|
||||
{
|
||||
$this->scan($markdown, $indentWidth);
|
||||
}
|
||||
|
||||
protected function scan($markdown, $indentWidth = 4)
|
||||
{
|
||||
if ('' === \trim($markdown)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->indentLen = $indentWidth == 2 ? 2 : 4;
|
||||
$this->indentStr = $indentWidth == 2 ? ' ' : ' ';
|
||||
|
||||
// Normalize whitespaces
|
||||
$markdown = \str_replace("\t", $this->indentStr, $markdown);
|
||||
$markdown = \str_replace(["\r\n", "\r"], "\n", $markdown);
|
||||
|
||||
$this->lines = \array_merge([''], \explode("\n", $markdown), ['']);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse markdown.
|
||||
*
|
||||
* @param string $markdown
|
||||
* @param int $indentWidth
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function parse($markdown = \null, $indentWidth = 4)
|
||||
{
|
||||
if (\null !== $markdown) {
|
||||
$this->reset(\true);
|
||||
|
||||
$this->scan($markdown, $indentWidth);
|
||||
}
|
||||
|
||||
if (empty($this->lines)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->parseBlockElements();
|
||||
|
||||
return (new SpanElementParser)->parse($this->markup);
|
||||
}
|
||||
|
||||
protected function init()
|
||||
{
|
||||
list($this->prevLine, $this->trimmedPrevLine) = [$this->line, $this->trimmedLine];
|
||||
|
||||
$this->line = $this->lines[$this->pointer];
|
||||
$this->trimmedLine = \trim($this->line);
|
||||
|
||||
$this->indent = \strlen($this->line) - \strlen(\ltrim($this->line));
|
||||
$this->nextLine = isset($this->lines[$this->pointer + 1])
|
||||
? $this->lines[$this->pointer + 1]
|
||||
: '';
|
||||
$this->trimmedNextLine = \trim($this->nextLine);
|
||||
$this->nextIndent = \strlen($this->nextLine) - \strlen(\ltrim($this->nextLine));
|
||||
}
|
||||
|
||||
protected function reset($all = \false)
|
||||
{
|
||||
$except = $all ? [] : \array_flip(['lines', 'pointer', 'markup', 'indentStr', 'indentLen']);
|
||||
|
||||
// Reset all current values.
|
||||
foreach (\get_class_vars(__CLASS__) as $prop => $value) {
|
||||
isset($except[$prop]) || $this->{$prop} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
protected function flush()
|
||||
{
|
||||
if ('' !== $this->trimmedLine) {
|
||||
return \false;
|
||||
}
|
||||
|
||||
while (!empty($this->stackList)) {
|
||||
$this->markup .= \array_pop($this->stackList);
|
||||
}
|
||||
|
||||
while (!empty($this->stackBlock)) {
|
||||
$this->markup .= \array_pop($this->stackBlock);
|
||||
}
|
||||
|
||||
while (!empty($this->stackTable)) {
|
||||
$this->markup .= \array_pop($this->stackTable);
|
||||
}
|
||||
|
||||
$this->markup .= "\n";
|
||||
|
||||
$this->reset(\false);
|
||||
|
||||
return \true;
|
||||
}
|
||||
|
||||
protected function raw()
|
||||
{
|
||||
if ($this->inHtml || \preg_match(static::RE_RAW, $this->trimmedLine)) {
|
||||
$this->markup .= "\n$this->line";
|
||||
if (!$this->inHtml && empty($this->lines[$this->pointer - 1])) {
|
||||
$this->inHtml = \true;
|
||||
}
|
||||
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function quote()
|
||||
{
|
||||
if (\preg_match(static::RE_MD_QUOTE, $this->line, $quoteMatch)) {
|
||||
$this->line = \substr($this->line, \strlen($quoteMatch[0]));
|
||||
$this->trimmedLine = \trim($this->line);
|
||||
|
||||
if (!$this->inQuote || $this->quoteLevel < \strlen($quoteMatch[1])) {
|
||||
$this->markup .= "\n<blockquote>";
|
||||
|
||||
$this->stackBlock[] = "\n</blockquote>";
|
||||
|
||||
$this->quoteLevel++;
|
||||
}
|
||||
|
||||
return $this->inQuote = \true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function paragraph()
|
||||
{
|
||||
$this->markup .= $this->inPara ? "\n<br />" : "\n<p>";
|
||||
$this->markup .= $this->trimmedLine;
|
||||
|
||||
if (empty($this->trimmedNextLine)) {
|
||||
$this->markup .= '</p>';
|
||||
$this->inPara = \false;
|
||||
} else {
|
||||
$this->inPara = \true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,8 @@ class gitlab
|
||||
* @param string $path
|
||||
* @param string $ref
|
||||
* @access public
|
||||
* @return array
|
||||
* @return object
|
||||
* @doc https://docs.gitlab.com/ee/api/repository_files.html
|
||||
*/
|
||||
public function files($path, $ref = 'master')
|
||||
{
|
||||
@@ -365,7 +366,7 @@ class gitlab
|
||||
*
|
||||
* @param string $cmd
|
||||
* @access public
|
||||
* @todo Exec commads by gitlab api.
|
||||
* @todo Exec commands by gitlab api.
|
||||
* @return array
|
||||
*/
|
||||
public function exec($cmd)
|
||||
@@ -535,10 +536,24 @@ class gitlab
|
||||
|
||||
if($version and $version != 'HEAD')
|
||||
{
|
||||
$committedDate = $this->getCommitedDate($version);
|
||||
/* Get since param. */
|
||||
if(substr($version, 0, 5) == 'since')
|
||||
{
|
||||
$since = true;
|
||||
$version = substr($version, 5);
|
||||
}
|
||||
|
||||
$committedDate = $this->getCommittedDate($version);
|
||||
if(!$committedDate) return array('commits' => array(), 'files' => array());
|
||||
|
||||
$params['until'] = $committedDate;
|
||||
if(!empty($since))
|
||||
{
|
||||
$params['since'] = $committedDate;
|
||||
}
|
||||
else
|
||||
{
|
||||
$params['until'] = $committedDate;
|
||||
}
|
||||
}
|
||||
|
||||
$list = $this->fetch($api, $params);
|
||||
@@ -566,7 +581,7 @@ class gitlab
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getCommitedDate($sha)
|
||||
public function getCommittedDate($sha)
|
||||
{
|
||||
if(!scm::checkRevision($sha)) return null;
|
||||
|
||||
@@ -594,8 +609,8 @@ class gitlab
|
||||
$param->path = urldecode($path);
|
||||
$param->ref_name = $this->branch;
|
||||
|
||||
$fromDate = $this->getCommitedDate($fromRevision);
|
||||
$toDate = $this->getCommitedDate($toRevision);
|
||||
$fromDate = $this->getCommittedDate($fromRevision);
|
||||
$toDate = $this->getCommittedDate($toRevision);
|
||||
|
||||
$since = '';
|
||||
$until = '';
|
||||
@@ -663,7 +678,7 @@ class gitlab
|
||||
* @param string $path
|
||||
* @param bool $recursive
|
||||
* @access public
|
||||
* @return void
|
||||
* @return mixed
|
||||
*/
|
||||
public function tree($path, $recursive = 1)
|
||||
{
|
||||
@@ -681,7 +696,7 @@ class gitlab
|
||||
*
|
||||
* @param string $api
|
||||
* @access public
|
||||
* @return void
|
||||
* @return mixed
|
||||
*/
|
||||
public function fetch($api, $params = array())
|
||||
{
|
||||
|
||||
@@ -32,6 +32,7 @@ $config->action->objectNameFields['budget'] = 'name';
|
||||
$config->action->objectNameFields['job'] = 'name';
|
||||
$config->action->objectNameFields['team'] = 'name';
|
||||
$config->action->objectNameFields['pipeline'] = 'name';
|
||||
$config->action->objectNameFields['mr'] = 'title';
|
||||
$config->action->objectNameFields['kanbancolumn'] = 'name';
|
||||
$config->action->objectNameFields['kanbanlane'] = 'name';
|
||||
|
||||
|
||||
+57
-38
@@ -76,44 +76,48 @@ $lang->action->periods['lastweek'] = $lang->action->dynamic->lastWeek;
|
||||
$lang->action->periods['thismonth'] = $lang->action->dynamic->thisMonth;
|
||||
$lang->action->periods['lastmonth'] = $lang->action->dynamic->lastMonth;
|
||||
|
||||
$lang->action->objectTypes['product'] = $lang->productCommon;
|
||||
$lang->action->objectTypes['branch'] = 'Branch';
|
||||
$lang->action->objectTypes['story'] = $lang->SRCommon;
|
||||
$lang->action->objectTypes['design'] = 'Design';
|
||||
$lang->action->objectTypes['productplan'] = 'Plan';
|
||||
$lang->action->objectTypes['release'] = 'Release';
|
||||
$lang->action->objectTypes['program'] = 'Program';
|
||||
$lang->action->objectTypes['project'] = 'Project';
|
||||
$lang->action->objectTypes['execution'] = $lang->executionCommon;
|
||||
$lang->action->objectTypes['task'] = 'Task';
|
||||
$lang->action->objectTypes['build'] = 'Build';
|
||||
$lang->action->objectTypes['job'] = 'Job';
|
||||
$lang->action->objectTypes['bug'] = 'Bug';
|
||||
$lang->action->objectTypes['case'] = 'Case';
|
||||
$lang->action->objectTypes['caseresult'] = 'Case Result';
|
||||
$lang->action->objectTypes['stepresult'] = 'Case Steps';
|
||||
$lang->action->objectTypes['caselib'] = 'Library';
|
||||
$lang->action->objectTypes['testsuite'] = 'Suite';
|
||||
$lang->action->objectTypes['testtask'] = 'Test Build';
|
||||
$lang->action->objectTypes['testreport'] = 'Report';
|
||||
$lang->action->objectTypes['doc'] = 'Document';
|
||||
$lang->action->objectTypes['api'] = 'Interface';
|
||||
$lang->action->objectTypes['doclib'] = 'Document Library';
|
||||
$lang->action->objectTypes['apistruct'] = 'API struct';
|
||||
$lang->action->objectTypes['todo'] = 'Todo';
|
||||
$lang->action->objectTypes['risk'] = 'Risk';
|
||||
$lang->action->objectTypes['issue'] = 'Issue';
|
||||
$lang->action->objectTypes['module'] = 'Module';
|
||||
$lang->action->objectTypes['user'] = 'User';
|
||||
$lang->action->objectTypes['stakeholder'] = 'Stakeholder';
|
||||
$lang->action->objectTypes['budget'] = 'Cost Estimate';
|
||||
$lang->action->objectTypes['entry'] = 'Entry';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['team'] = 'Team';
|
||||
$lang->action->objectTypes['whitelist'] = 'Whitelist';
|
||||
$lang->action->objectTypes['pipeline'] = 'GitLab';
|
||||
$lang->action->objectTypes['gitlab'] = 'GitLab';
|
||||
$lang->action->objectTypes['jenkins'] = 'Jenkins';
|
||||
$lang->action->objectTypes['product'] = $lang->productCommon;
|
||||
$lang->action->objectTypes['branch'] = 'Branch';
|
||||
$lang->action->objectTypes['story'] = $lang->SRCommon;
|
||||
$lang->action->objectTypes['design'] = 'Design';
|
||||
$lang->action->objectTypes['productplan'] = 'Plan';
|
||||
$lang->action->objectTypes['release'] = 'Release';
|
||||
$lang->action->objectTypes['program'] = 'Program';
|
||||
$lang->action->objectTypes['project'] = 'Project';
|
||||
$lang->action->objectTypes['execution'] = $lang->executionCommon;
|
||||
$lang->action->objectTypes['task'] = 'Task';
|
||||
$lang->action->objectTypes['build'] = 'Build';
|
||||
$lang->action->objectTypes['job'] = 'Job';
|
||||
$lang->action->objectTypes['bug'] = 'Bug';
|
||||
$lang->action->objectTypes['case'] = 'Case';
|
||||
$lang->action->objectTypes['caseresult'] = 'Case Result';
|
||||
$lang->action->objectTypes['stepresult'] = 'Case Steps';
|
||||
$lang->action->objectTypes['caselib'] = 'Library';
|
||||
$lang->action->objectTypes['testsuite'] = 'Suite';
|
||||
$lang->action->objectTypes['testtask'] = 'Test Build';
|
||||
$lang->action->objectTypes['testreport'] = 'Report';
|
||||
$lang->action->objectTypes['doc'] = 'Document';
|
||||
$lang->action->objectTypes['api'] = 'Interface';
|
||||
$lang->action->objectTypes['doclib'] = 'Document Library';
|
||||
$lang->action->objectTypes['apistruct'] = 'API struct';
|
||||
$lang->action->objectTypes['todo'] = 'Todo';
|
||||
$lang->action->objectTypes['risk'] = 'Risk';
|
||||
$lang->action->objectTypes['issue'] = 'Issue';
|
||||
$lang->action->objectTypes['module'] = 'Module';
|
||||
$lang->action->objectTypes['user'] = 'User';
|
||||
$lang->action->objectTypes['stakeholder'] = 'Stakeholder';
|
||||
$lang->action->objectTypes['budget'] = 'Cost Estimate';
|
||||
$lang->action->objectTypes['entry'] = 'Entry';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['team'] = 'Team';
|
||||
$lang->action->objectTypes['whitelist'] = 'Whitelist';
|
||||
$lang->action->objectTypes['pipeline'] = 'GitLab';
|
||||
$lang->action->objectTypes['gitlab'] = 'GitLab';
|
||||
$lang->action->objectTypes['jenkins'] = 'Jenkins';
|
||||
$lang->action->objectTypes['mr'] = 'Merge Request';
|
||||
$lang->action->objectTypes['gitlabproject'] = 'GitLab Project';
|
||||
$lang->action->objectTypes['gitlabuser'] = 'GitLab User';
|
||||
$lang->action->objectTypes['gitlabgroup'] = 'GitLab Group';
|
||||
|
||||
/* Used to describe operation history. */
|
||||
$lang->action->desc = new stdclass();
|
||||
@@ -287,6 +291,11 @@ $lang->action->label->syncprogram = 'start';
|
||||
$lang->action->label->syncproject = 'start';
|
||||
$lang->action->label->syncexecution = 'start';
|
||||
$lang->action->label->startProgram = '(The start of the project sets the status of the program as Ongoing)';
|
||||
$lang->action->label->createmr = 'MR Linked';
|
||||
$lang->action->label->mergedmr = 'MR Merged';
|
||||
$lang->action->label->reopen = 'Reopen';
|
||||
$lang->action->label->approve = 'Passed';
|
||||
$lang->action->label->reject = 'Rejected';
|
||||
|
||||
/* Dynamic information is grouped by object. */
|
||||
$lang->action->dynamicAction = new stdclass;
|
||||
@@ -694,3 +703,13 @@ $lang->action->apiTitle->reviewrejected = 'Review rejected';
|
||||
$lang->action->apiTitle->reviewclarified = 'Review clarified';
|
||||
$lang->action->apiTitle->commitsummary = 'Commit summary';
|
||||
$lang->action->apiTitle->updatetrainee = 'Update trainee';
|
||||
|
||||
/* Code Review in Repo or Merge Request module. */
|
||||
$lang->action->desc->repocreated = '$date, created and reviewed by <strong>$actor</strong>: $extra.' . "\n";
|
||||
$lang->action->label->repocreated = "create and review";
|
||||
$lang->action->dynamicAction->task['gitcommited'] = 'Git Commit';
|
||||
$lang->action->dynamicAction->bug['repocreated'] = $lang->action->label->repocreated;
|
||||
$lang->action->desc->createmr = '$extra';
|
||||
$lang->action->desc->mergedmr = '$date, <strong>$actor</strong> merged <a href="$extra">code</a>.';
|
||||
$lang->action->desc->approve = '$date, <strong>$actor</strong> approved.';
|
||||
$lang->action->desc->reject = '$date, <strong>$actor</strong> rejected.';
|
||||
|
||||
@@ -79,44 +79,48 @@ $lang->action->periods['lastweek'] = $lang->action->dynamic->lastWeek;
|
||||
$lang->action->periods['thismonth'] = $lang->action->dynamic->thisMonth;
|
||||
$lang->action->periods['lastmonth'] = $lang->action->dynamic->lastMonth;
|
||||
|
||||
$lang->action->objectTypes['product'] = $lang->productCommon;
|
||||
$lang->action->objectTypes['branch'] = '分支';
|
||||
$lang->action->objectTypes['story'] = $lang->SRCommon;
|
||||
$lang->action->objectTypes['design'] = '设计';
|
||||
$lang->action->objectTypes['productplan'] = '计划';
|
||||
$lang->action->objectTypes['release'] = '发布';
|
||||
$lang->action->objectTypes['program'] = '项目集';
|
||||
$lang->action->objectTypes['project'] = '项目';
|
||||
$lang->action->objectTypes['execution'] = $config->systemMode == 'new' ? '执行' : $lang->executionCommon;
|
||||
$lang->action->objectTypes['task'] = '任务';
|
||||
$lang->action->objectTypes['build'] = '版本';
|
||||
$lang->action->objectTypes['job'] = '构建';
|
||||
$lang->action->objectTypes['bug'] = 'Bug';
|
||||
$lang->action->objectTypes['case'] = '用例';
|
||||
$lang->action->objectTypes['caseresult'] = '用例结果';
|
||||
$lang->action->objectTypes['stepresult'] = '用例步骤';
|
||||
$lang->action->objectTypes['caselib'] = '用例库';
|
||||
$lang->action->objectTypes['testsuite'] = '套件';
|
||||
$lang->action->objectTypes['testtask'] = '测试单';
|
||||
$lang->action->objectTypes['testreport'] = '报告';
|
||||
$lang->action->objectTypes['doc'] = '文档';
|
||||
$lang->action->objectTypes['api'] = '接口';
|
||||
$lang->action->objectTypes['doclib'] = '文档库';
|
||||
$lang->action->objectTypes['apistruct'] = '数据结构';
|
||||
$lang->action->objectTypes['todo'] = '待办';
|
||||
$lang->action->objectTypes['risk'] = '风险';
|
||||
$lang->action->objectTypes['issue'] = '问题';
|
||||
$lang->action->objectTypes['module'] = '模块';
|
||||
$lang->action->objectTypes['user'] = '用户';
|
||||
$lang->action->objectTypes['stakeholder'] = '干系人';
|
||||
$lang->action->objectTypes['budget'] = '费用估算';
|
||||
$lang->action->objectTypes['entry'] = '应用';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['team'] = '团队';
|
||||
$lang->action->objectTypes['whitelist'] = '白名单';
|
||||
$lang->action->objectTypes['pipeline'] = 'GitLab';
|
||||
$lang->action->objectTypes['gitlab'] = 'GitLab';
|
||||
$lang->action->objectTypes['jenkins'] = 'Jenkins';
|
||||
$lang->action->objectTypes['product'] = $lang->productCommon;
|
||||
$lang->action->objectTypes['branch'] = '分支';
|
||||
$lang->action->objectTypes['story'] = $lang->SRCommon;
|
||||
$lang->action->objectTypes['design'] = '设计';
|
||||
$lang->action->objectTypes['productplan'] = '计划';
|
||||
$lang->action->objectTypes['release'] = '发布';
|
||||
$lang->action->objectTypes['program'] = '项目集';
|
||||
$lang->action->objectTypes['project'] = '项目';
|
||||
$lang->action->objectTypes['execution'] = $config->systemMode == 'new' ? '执行' : $lang->executionCommon;
|
||||
$lang->action->objectTypes['task'] = '任务';
|
||||
$lang->action->objectTypes['build'] = '版本';
|
||||
$lang->action->objectTypes['job'] = '构建';
|
||||
$lang->action->objectTypes['bug'] = 'Bug';
|
||||
$lang->action->objectTypes['case'] = '用例';
|
||||
$lang->action->objectTypes['caseresult'] = '用例结果';
|
||||
$lang->action->objectTypes['stepresult'] = '用例步骤';
|
||||
$lang->action->objectTypes['caselib'] = '用例库';
|
||||
$lang->action->objectTypes['testsuite'] = '套件';
|
||||
$lang->action->objectTypes['testtask'] = '测试单';
|
||||
$lang->action->objectTypes['testreport'] = '报告';
|
||||
$lang->action->objectTypes['doc'] = '文档';
|
||||
$lang->action->objectTypes['api'] = '接口';
|
||||
$lang->action->objectTypes['doclib'] = '文档库';
|
||||
$lang->action->objectTypes['apistruct'] = '数据结构';
|
||||
$lang->action->objectTypes['todo'] = '待办';
|
||||
$lang->action->objectTypes['risk'] = '风险';
|
||||
$lang->action->objectTypes['issue'] = '问题';
|
||||
$lang->action->objectTypes['module'] = '模块';
|
||||
$lang->action->objectTypes['user'] = '用户';
|
||||
$lang->action->objectTypes['stakeholder'] = '干系人';
|
||||
$lang->action->objectTypes['budget'] = '费用估算';
|
||||
$lang->action->objectTypes['entry'] = '应用';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['team'] = '团队';
|
||||
$lang->action->objectTypes['whitelist'] = '白名单';
|
||||
$lang->action->objectTypes['pipeline'] = 'GitLab';
|
||||
$lang->action->objectTypes['gitlab'] = 'GitLab';
|
||||
$lang->action->objectTypes['jenkins'] = 'Jenkins';
|
||||
$lang->action->objectTypes['mr'] = '合并请求';
|
||||
$lang->action->objectTypes['gitlabproject'] = 'GitLab项目';
|
||||
$lang->action->objectTypes['gitlabuser'] = 'GitLab用户';
|
||||
$lang->action->objectTypes['gitlabgroup'] = 'GitLab群组';
|
||||
|
||||
/* 用来描述操作历史记录。*/
|
||||
$lang->action->desc = new stdclass();
|
||||
@@ -290,6 +294,13 @@ $lang->action->label->syncprogram = '开始了';
|
||||
$lang->action->label->syncproject = '开始了';
|
||||
$lang->action->label->syncexecution = '开始了';
|
||||
$lang->action->label->startProgram = '(因项目开始而启动项目集)';
|
||||
$lang->action->label->createmr = 'MR关联了';
|
||||
$lang->action->label->mergedmr = 'MR合并了';
|
||||
$lang->action->label->compilepass = '构建成功';
|
||||
$lang->action->label->compilefail = '构建失败';
|
||||
$lang->action->label->reopen = '重新打开';
|
||||
$lang->action->label->approve = '通过了';
|
||||
$lang->action->label->reject = '拒绝了';
|
||||
|
||||
/* 动态信息按照对象分组 */
|
||||
$lang->action->dynamicAction = new stdclass();
|
||||
@@ -697,3 +708,13 @@ $lang->action->apiTitle->reviewrejected = '拒绝';
|
||||
$lang->action->apiTitle->reviewclarified = '有待明确';
|
||||
$lang->action->apiTitle->commitsummary = '提交培训总结';
|
||||
$lang->action->apiTitle->updatetrainee = '更新培训人员';
|
||||
|
||||
/* Code Review in Repo or Merge Request module. */
|
||||
$lang->action->desc->repocreated = '$date, 由 <strong>$actor</strong> 评审创建:$extra。' . "\n";
|
||||
$lang->action->label->repocreated = "创建评审";
|
||||
$lang->action->dynamicAction->task['gitcommited'] = 'git提交';
|
||||
$lang->action->dynamicAction->bug['repocreated'] = '创建代码评审';
|
||||
$lang->action->desc->createmr = '$extra';
|
||||
$lang->action->desc->mergedmr = '$date, 由 <strong>$actor</strong> 合并了 <a href="$extra">代码</a>。';
|
||||
$lang->action->desc->approve = '$date, 由 <strong>$actor</strong> 审核通过。';
|
||||
$lang->action->desc->reject = '$date, 由 <strong>$actor</strong> 拒绝。';
|
||||
|
||||
@@ -689,3 +689,9 @@ $lang->action->apiTitle->reviewrejected = '拒絶';
|
||||
$lang->action->apiTitle->reviewclarified = '有待明確';
|
||||
$lang->action->apiTitle->commitsummary = '提交培訓總結';
|
||||
$lang->action->apiTitle->updatetrainee = '更新培訓人員';
|
||||
|
||||
/* Code Review in Repo or Merge Request module. */
|
||||
$lang->action->desc->repocreated = '$date, 由 <strong>$actor</strong> 評審創建:$extra。' . "\n";
|
||||
$lang->action->label->repocreated = "創建評審";
|
||||
$lang->action->dynamicAction->task['gitcommited'] = 'git提交';
|
||||
$lang->action->dynamicAction->bug['repocreated'] = '創建代碼評審';
|
||||
|
||||
+13
-8
@@ -641,7 +641,7 @@ class actionModel extends model
|
||||
/**
|
||||
* Print actions of an object.
|
||||
*
|
||||
* @param array $action
|
||||
* @param object $action
|
||||
* @param string $desc
|
||||
* @access public
|
||||
* @return void
|
||||
@@ -945,9 +945,9 @@ class actionModel extends model
|
||||
/**
|
||||
* Transform the actions for display.
|
||||
*
|
||||
* @param int $actions
|
||||
* @param array $actions
|
||||
* @access public
|
||||
* @return void
|
||||
* @return object
|
||||
*/
|
||||
public function transformActions($actions)
|
||||
{
|
||||
@@ -988,6 +988,9 @@ class actionModel extends model
|
||||
/* If action type is login or logout, needn't link. */
|
||||
if($actionType == 'svncommited' or $actionType == 'gitcommited') $action->actor = zget($commiters, $action->actor);
|
||||
|
||||
/* Get gitlab objectname. */
|
||||
if(substr($objectType, 0,6) == 'gitlab') $action->objectName = $action->extra;
|
||||
|
||||
/* Other actions, create a link. */
|
||||
if(!$this->setObjectLink($action, $deptUsers))
|
||||
{
|
||||
@@ -1482,12 +1485,14 @@ class actionModel extends model
|
||||
{
|
||||
$dateGroup = array_reverse($dateGroup);
|
||||
}
|
||||
elseif($this->app->rawModule == 'company' and (($direction == 'next' and $orderBy == 'date_asc') or ($direction == 'pre' and $orderBy == 'date_desc')))
|
||||
elseif($this->app->rawModule == 'company')
|
||||
{
|
||||
$dateGroup = array_reverse($dateGroup);
|
||||
foreach($dateGroup as $key => $dateItem) $dateGroup[$key] = array_reverse($dateItem);
|
||||
if($direction == 'pre') $dateGroup = array_reverse($dateGroup);
|
||||
if(($direction == 'next' and $orderBy == 'date_asc') or ($direction == 'pre' and $orderBy == 'date_desc'))
|
||||
{
|
||||
foreach($dateGroup as $key => $dateItem) $dateGroup[$key] = array_reverse($dateItem);
|
||||
}
|
||||
}
|
||||
|
||||
return $dateGroup;
|
||||
}
|
||||
|
||||
@@ -1565,7 +1570,7 @@ class actionModel extends model
|
||||
/**
|
||||
* Print actions of an object for API(JIHU).
|
||||
*
|
||||
* @param array $action
|
||||
* @param object $action
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -510,4 +510,39 @@ class branchModel extends model
|
||||
|
||||
return $branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display of branch label.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $moduleID
|
||||
* @param int $executionID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function showBranch($productID, $moduleID = 0, $executionID = 0)
|
||||
{
|
||||
$this->loadModel('product');
|
||||
if(empty($productID) and empty($moduleID))
|
||||
{
|
||||
$productPairs = $this->product->getProductPairsByProject($executionID);
|
||||
if($this->app->tab != 'project') $productID = count($productPairs) == 1 ? key($productPairs) : 0;
|
||||
}
|
||||
elseif(empty($productID) and !empty($moduleID))
|
||||
{
|
||||
$module = $this->loadModel('tree')->getById($moduleID);
|
||||
$productID = $module->type != 'task' ? $module->root : 0;
|
||||
}
|
||||
|
||||
$product = $productID ? $this->product->getById($productID) : '';
|
||||
|
||||
if($product and $product->type != 'normal')
|
||||
{
|
||||
$this->app->loadLang('datatable');
|
||||
$this->lang->datatable->showBranch = sprintf($this->lang->datatable->showBranch, $this->lang->product->branchName[$product->type]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ foreach($branches as $branchID => $branch)
|
||||
|
||||
if($branchID == 'all' or empty($branchID) or $statusList[$branchID] == 'active')
|
||||
{
|
||||
$activeBranchesHtml .= html::a($linkHtml, $branch, '', "class='$selected' data-key='{$branchesPinyin[$branch]}' data-app='{$this->app->tab}'");
|
||||
$activeBranchesHtml .= html::a($linkHtml, $branch, '', "class='$selected' data-key='{$branchesPinyin[$branch]}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -202,13 +202,10 @@ class bug extends control
|
||||
|
||||
$showModule = !empty($this->config->datatable->bugBrowse->showModule) ? $this->config->datatable->bugBrowse->showModule : '';
|
||||
$productName = ($productID and isset($this->products[$productID])) ? $this->products[$productID] : $this->lang->product->allProduct;
|
||||
$product = $this->product->getById($productID);
|
||||
|
||||
$product = $this->product->getById($productID);
|
||||
if($product and $product->type != 'normal')
|
||||
{
|
||||
$this->app->loadLang('datatable');
|
||||
$this->lang->datatable->showBranch = sprintf($this->lang->datatable->showBranch, $this->lang->product->branchName[$product->type]);
|
||||
}
|
||||
/* Display of branch label. */
|
||||
$showBranch = $this->loadModel('branch')->showBranch($productID);
|
||||
|
||||
/* Set view. */
|
||||
$this->view->title = $productName . $this->lang->colon . $this->lang->bug->common;
|
||||
@@ -240,6 +237,7 @@ class bug extends control
|
||||
$this->view->setModule = true;
|
||||
$this->view->isProjectBug = ($productID and !$this->projectID) ? false : true;
|
||||
$this->view->modulePairs = $showModule ? $this->tree->getModulePairs($productID, 'bug', $showModule) : array();
|
||||
$this->view->showBranch = $showBranch;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -1080,7 +1078,7 @@ class bug extends control
|
||||
}
|
||||
}
|
||||
|
||||
$this->loadModel('my')->setMenu();
|
||||
$this->app->loadLang('my');
|
||||
$this->lang->task->menu = $this->lang->my->menu->work;
|
||||
$this->lang->my->menu->work['subModule'] = 'bug';
|
||||
|
||||
|
||||
@@ -204,6 +204,7 @@ function loadProductModules(productID)
|
||||
branch = $('#branch').val();
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
if(typeof(moduleID) == 'undefined') moduleID = 0;
|
||||
if(config.currentMethod == 'edit') moduleID = $('#module').val();
|
||||
link = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=bug&branch=' + branch + '&rootModuleID=0&returnType=html&fieldID=&needManage=true&extra=¤tModuleID=' + moduleID);
|
||||
$('#moduleIdBox').load(link, function()
|
||||
{
|
||||
@@ -626,7 +627,8 @@ function notice()
|
||||
*/
|
||||
function setBranchRelated(branchID, productID, num)
|
||||
{
|
||||
moduleLink = createLink('tree', 'ajaxGetModules', 'productID=' + productID + '&viewType=bug&branch=' + branchID + '&num=' + num);
|
||||
var currentModuleID = config.currentMethod == 'batchedit' ? $('#modules' + num).val() : 0;
|
||||
moduleLink = createLink('tree', 'ajaxGetModules', 'productID=' + productID + '&viewType=bug&branch=' + branchID + '&num=' + num + '¤tModuleID=' + currentModuleID);
|
||||
$.get(moduleLink, function(modules)
|
||||
{
|
||||
if(!modules) modules = '<select id="modules' + num + '" name="modules[' + num + ']" class="form-control"></select>';
|
||||
|
||||
@@ -570,7 +570,7 @@ class bugModel extends model
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->orderBy('id desc')
|
||||
->page($pager)
|
||||
->fetchAll();
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
<tbody>
|
||||
<tr valign='middle'>
|
||||
<th class='thWidth'><?php echo $lang->bug->product;?></th>
|
||||
<td><?php if(!common::printLink('product', 'browse', "productID=$bug->product", $product->name, '', "data-app='product'")) echo $product->name;?></td>
|
||||
<td><?php if(!common::printLink('product', 'view', "productID=$bug->product", $product->name, '', "data-app='product'")) echo $product->name;?></td>
|
||||
</tr>
|
||||
<?php if($product->type != 'normal'):?>
|
||||
<tr>
|
||||
|
||||
@@ -613,12 +613,14 @@ class build extends control
|
||||
$this->config->bug->search['style'] = 'simple';
|
||||
$this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairsForStory($build->product, $build->branch, 'skipParent');
|
||||
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($build->product, 'bug', 0, $build->branch);
|
||||
$this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($build->product, 0, 'id_desc', $this->session->project);
|
||||
$this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($build->product, $build->branch, 'id_desc', $this->session->project);
|
||||
$this->config->bug->search['params']['openedBuild']['values'] = $this->build->getProductBuildPairs($build->product, $branch = 0, $params = '');
|
||||
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
|
||||
|
||||
unset($this->config->bug->search['fields']['product']);
|
||||
unset($this->config->bug->search['params']['product']);
|
||||
unset($this->config->bug->search['fields']['project']);
|
||||
unset($this->config->bug->search['params']['project']);
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
unset($this->config->bug->search['fields']['branch']);
|
||||
@@ -626,9 +628,8 @@ class build extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
$branchPairs = $this->loadModel('branch')->getPairs($build->product, 'noempty');
|
||||
$branches = array('' => '') + array(BRANCH_MAIN => $this->lang->branch->main);
|
||||
if($build->branch) $branches += array($build->branch => $branchPairs[$build->branch]);
|
||||
$branchName = $this->loadModel('branch')->getById($build->branch);
|
||||
$branches = array('' => '', BRANCH_MAIN => $this->lang->branch->main, $build->branch => $branchName);
|
||||
|
||||
$this->config->bug->search['fields']['branch'] = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
$this->config->bug->search['params']['branch']['values'] = $branches;
|
||||
|
||||
@@ -31,6 +31,7 @@ $lang->build->id = 'ID';
|
||||
$lang->build->product = $lang->productCommon;
|
||||
$lang->build->project = 'Project';
|
||||
$lang->build->branch = 'Platform/Branch';
|
||||
$lang->build->branchName = '%s';
|
||||
$lang->build->execution = $lang->executionCommon;
|
||||
$lang->build->name = 'Name';
|
||||
$lang->build->date = 'Date';
|
||||
|
||||
@@ -31,6 +31,7 @@ $lang->build->id = 'ID';
|
||||
$lang->build->product = $lang->productCommon;
|
||||
$lang->build->project = '所属项目';
|
||||
$lang->build->branch = '平台/分支';
|
||||
$lang->build->branchName = '所属%s';
|
||||
$lang->build->execution = '所属' . $lang->executionCommon;
|
||||
$lang->build->name = '名称编号';
|
||||
$lang->build->date = '打包日期';
|
||||
|
||||
@@ -231,6 +231,7 @@ class caselib extends control
|
||||
$this->view->moduleName = $moduleID ? $this->tree->getById($moduleID)->name : $this->lang->tree->all;
|
||||
$this->view->param = $param;
|
||||
$this->view->setModule = true;
|
||||
$this->view->showBranch = false;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -156,6 +156,14 @@ class ciModel extends model
|
||||
|
||||
$this->dao->update(TABLE_COMPILE)->data($data)->where('id')->eq($compile->id)->exec();
|
||||
$this->dao->update(TABLE_JOB)->set('lastExec')->eq($now)->set('lastStatus')->eq($pipeline->status)->where('id')->eq($compile->job)->exec();
|
||||
|
||||
/* Send mr message by compile status. */
|
||||
$relateMR = $this->dao->select('*')->from(TABLE_MR)->where('compileID')->eq($compile->id)->fetch();
|
||||
if($relateMR)
|
||||
{
|
||||
if($data->status == 'success') $this->loadModel('action')->create('mr', $relateMR->id, 'compilePass');
|
||||
if($data->status == 'failed') $this->loadModel('action')->create('mr', $relateMR->id, 'compileFail');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -247,6 +247,7 @@ $lang->waterfall->menu->execution = array('link' => "{$lang->stage->common}|pr
|
||||
$lang->waterfall->menu->story = array('link' => "$lang->SRCommon|projectstory|story|project=%s", 'subModule' => 'projectstory,tree', 'exclude' => 'projectstory-track');
|
||||
$lang->waterfall->menu->design = array('link' => "{$lang->design->common}|design|browse|project=%s");
|
||||
$lang->waterfall->menu->qa = array('link' => "{$lang->qa->common}|project|bug|projectID=%s", 'subModule' => 'testcase,testtask,bug', 'alias' => 'bug,testtask,testcase');
|
||||
$lang->waterfall->menu->doc = array('link' => "{$lang->doc->common}|doc|tableContents|type=project&objectID=%s");
|
||||
$lang->waterfall->menu->devops = array('link' => "{$lang->repo->common}|repo|browse|repoID=0&branchID=&objectID=%s", 'subModule' => 'repo');
|
||||
$lang->waterfall->menu->build = array('link' => "{$lang->build->common}|project|build|project=%s");
|
||||
$lang->waterfall->menu->release = array('link' => "{$lang->release->common}|projectrelease|browse|project=%s", 'subModule' => 'projectrelease');
|
||||
|
||||
+91
-6
@@ -1845,13 +1845,18 @@ EOD;
|
||||
$typeOnlyCondition = $type . 'OnlyCondition';
|
||||
$queryCondition = $this->session->$queryCondition;
|
||||
|
||||
$preAndNextObject = new stdClass();
|
||||
$preAndNextObject->pre = '';
|
||||
$preAndNextObject->next = '';
|
||||
if(empty($queryCondition)) return $preAndNextObject;
|
||||
|
||||
$table = $this->config->objectTables[$type];
|
||||
$orderBy = $type . 'OrderBy';
|
||||
$orderBy = $this->session->$orderBy;
|
||||
if(empty($queryCondition) or $this->session->$typeOnlyCondition)
|
||||
if($this->session->$typeOnlyCondition)
|
||||
{
|
||||
$sql = $this->dao->select('*')->from($table)
|
||||
->beginIF($queryCondition != false)->where($queryCondition)->fi()
|
||||
->where($queryCondition)
|
||||
->beginIF($orderBy != false)->orderBy($orderBy)->fi()
|
||||
->get();
|
||||
}
|
||||
@@ -1879,10 +1884,6 @@ EOD;
|
||||
$existsObjectList = $this->session->$objectIdListKey;
|
||||
}
|
||||
|
||||
$preAndNextObject = new stdClass();
|
||||
$preAndNextObject->pre = '';
|
||||
$preAndNextObject->next = '';
|
||||
|
||||
$preObj = false;
|
||||
if(isset($existsObjectList['objectList']))
|
||||
{
|
||||
@@ -2613,6 +2614,90 @@ 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.
|
||||
* @static
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public static function httpWithHeader($url, $data = null, $options = array(), $headers = array())
|
||||
{
|
||||
global $lang, $app;
|
||||
if(!extension_loaded('curl')) return json_encode(array('result' => 'fail', 'message' => $lang->error->noCurlExt));
|
||||
|
||||
commonModel::$requestErrors = array();
|
||||
|
||||
if(!is_array($headers)) $headers = (array)$headers;
|
||||
$headers[] = "API-RemoteIP: " . zget($_SERVER, 'REMOTE_ADDR', '');
|
||||
|
||||
$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_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_IPRESOLVE, CURL_IPRESOLVE_V4);
|
||||
curl_setopt($curl, CURLOPT_HEADER, true);
|
||||
curl_setopt($curl, CURLINFO_HEADER_OUT, TRUE);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
|
||||
if(!empty($data))
|
||||
{
|
||||
if(is_object($data)) $data = (array) $data;
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
|
||||
}
|
||||
|
||||
if($options) curl_setopt_array($curl, $options);
|
||||
$response = curl_exec($curl);
|
||||
$errors = curl_error($curl);
|
||||
|
||||
$headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
|
||||
$headerString = substr($response, 0, $headerSize);
|
||||
$body = substr($response, $headerSize);
|
||||
|
||||
/* Parse header. */
|
||||
$header = explode("\n", $headerString);
|
||||
$newHeader = array();
|
||||
foreach($header as $item)
|
||||
{
|
||||
$field = explode(':', $item);
|
||||
if(count($field) < 2) continue;
|
||||
$headerkey = array_shift($field);
|
||||
$newHeader[$headerkey] = join('', $field);
|
||||
}
|
||||
curl_close($curl);
|
||||
|
||||
|
||||
$logFile = $app->getLogRoot() . 'saas.'. date('Ymd') . '.log.php';
|
||||
if(!file_exists($logFile)) file_put_contents($logFile, '<?php die(); ?' . '>');
|
||||
|
||||
$fh = @fopen($logFile, 'a');
|
||||
if($fh)
|
||||
{
|
||||
fwrite($fh, date('Ymd H:i:s') . ": " . $app->getURI() . "\n");
|
||||
fwrite($fh, "url: " . $url . "\n");
|
||||
if(!empty($data)) fwrite($fh, "data: " . print_r($data, true) . "\n");
|
||||
fwrite($fh, "results:" . print_r($response, true) . "\n");
|
||||
if(!empty($errors)) fwrite($fh, "errors: " . $errors . "\n");
|
||||
fclose($fh);
|
||||
}
|
||||
|
||||
if($errors) commonModel::$requestErrors[] = $errors;
|
||||
|
||||
return array('body' => $body, 'header' => $newHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Http.
|
||||
*
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
$(function()
|
||||
{
|
||||
<?php if(!empty($setModule)):?>
|
||||
$('#sidebar .cell .text-center:last').append("<a href='#showModuleModal' data-toggle='modal' class='btn btn-info btn-wide'><?php echo ($app->tab == 'product' or $app->tab == 'qa') ? $lang->datatable->displaySetting : $lang->datatable->moduleSetting;?></a><hr class='space-sm' />");
|
||||
$('#sidebar .cell .text-center:last').append("<a href='#showModuleModal' data-toggle='modal' class='btn btn-info btn-wide'><?php echo $lang->datatable->displaySetting;?></a><hr class='space-sm' />");
|
||||
<?php endif;?>
|
||||
|
||||
var addSettingButton = function()
|
||||
@@ -89,7 +89,7 @@ $(function()
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><i class="icon icon-close"></i></button>
|
||||
<h4 class="modal-title"><i class="icon-cog-outline"></i> <?php echo ($app->tab == 'product' or $app->tab == 'qa') ? $lang->datatable->displaySetting : $lang->datatable->moduleSetting;?></h4>
|
||||
<h4 class="modal-title"><i class="icon-cog-outline"></i> <?php echo $lang->datatable->displaySetting;?></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class='form-condensed' method='post' target='hiddenwin' action='<?php echo $this->createLink('datatable', 'ajaxSave')?>'>
|
||||
@@ -104,7 +104,7 @@ $(function()
|
||||
<td><?php echo html::radio('showAllModule', $lang->datatable->showAllModuleList, isset($config->execution->task->allModule) ? $config->execution->task->allModule : 0);?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<?php if(!empty($product) and $product->type != 'normal'):?>
|
||||
<?php if($showBranch):?>
|
||||
<tr>
|
||||
<td><?php echo $lang->datatable->showBranch;?></td>
|
||||
<td><?php echo html::radio('showBranch', $lang->datatable->showBranchList, isset($config->$currentModule->$currentMethod->showBranch) ? $config->$currentModule->$currentMethod->showBranch : 1);?></td>
|
||||
|
||||
@@ -5,66 +5,58 @@
|
||||
#kanbanList .panel-heading {padding: 10px;}
|
||||
#kanbanList .panel-body {padding: 0 10px 10px;}
|
||||
#kanbanList .kanban {min-height: 120px; overflow: visible;}
|
||||
#kanbanList .kanban-item {margin-top: 0; border-radius: 2px;}
|
||||
#kanbanList .kanban-item:hover {border: 1px solid #ccc;}
|
||||
#kanbanList .kanban-item + .kanban-item {margin-top: 10px;}
|
||||
#kanbanList .kanban-lane-items {padding: 10px; min-height: 38px;}
|
||||
#kanbanList .kanban-card {border-radius: 2px; padding: 10px;}
|
||||
#kanbanList .kanban-card:hover {border: 1px solid #ccc;}
|
||||
#kanbanList .kanban-header,
|
||||
#kanbanList .kanban-lane {border-bottom: none; margin-bottom: 0; min-height: 60px;}
|
||||
#kanbanList .kanban-lane {border-bottom: none; margin-bottom: 0;}
|
||||
#kanbanList .kanban-sub-lane {border-bottom: 0;}
|
||||
#kanbanList .kanban-lane {margin-top: 2px; min-height: 100px;}
|
||||
#kanbanList .kanban-lane.has-sub-lane {background-color: transparent;}
|
||||
#kanbanList .kanban-lane + .kanban-lane {border-top: 10px solid #fff;}
|
||||
#kanbanList .kanban-lane + .kanban-lane {margin-top: 10px;}
|
||||
#kanbanList .kanban-sub-lane + .kanban-sub-lane {margin-top: 2px;}
|
||||
#kanbanList .kanban-col + .kanban-col {border-left: 2px solid #fff;}
|
||||
#kanbanList .kanban-header-col {height: 72px; padding: 20px 5px;}
|
||||
#kanbanList .kanban-header-col > .title {margin: 0; line-height: 32px; height: 32px}
|
||||
#kanbanList .kanban-header-col > .title > .text {font-weight: bold; max-width: 200px; max-width: calc(100% - 50px);}
|
||||
#kanbanList .kanban-header-col > .title > .icon, #kanbanList .kanban-header-col > .title > .count {top: -11px}
|
||||
#kanbanList .kanban-header-col > .title > .text {max-width: 200px; max-width: calc(100% - 50px);}
|
||||
#kanbanList .kanban-header + .kanban-lane > .kanban-lane-name {margin-top: 0;}
|
||||
#kanbanList .kanban-header {position: relative;}
|
||||
#kanbanList .kanban-item.link-block {padding: 0;}
|
||||
#kanbanList .kanban-item.link-block > a {padding: 10px; display: block;}
|
||||
#kanbanList .kanban-item > .title {white-space: nowrap; overflow: hidden; text-overflow: clip;}
|
||||
#kanbanList .kanban-item.link-block > a {padding: 10px; display: block;}
|
||||
#kanbanList .kanban-item.has-progress {padding-right: 40px; position: relative;}
|
||||
#kanbanList .kanban-item.has-progress > .progress-pie {position: absolute; right: 7px; top: 7px}
|
||||
#kanbanList .kanban-item.has-left-border {border-left: 2px solid #838a9d;}
|
||||
#kanbanList .kanban-item.has-left-border.border-left-green {border-left-color: #0bd986;}
|
||||
#kanbanList .kanban-item.has-left-border.border-left-red {border-left-color: #ff5d5d;}
|
||||
#kanbanList .kanban-item.has-left-border.border-left-blue {border-left-color: #0991ff;}
|
||||
#kanbanList .kanban-item.link-block a {padding: 10px; display: block;}
|
||||
#kanbanList .kanban-card {display: grid;}
|
||||
#kanbanList .kanban-card > .title {white-space: nowrap; overflow: hidden; text-overflow: ellipsis;}
|
||||
#kanbanList .kanban-card.has-progress {padding-right: 40px; position: relative;}
|
||||
#kanbanList .kanban-card.has-progress > .progress-pie {position: absolute; right: 7px; top: 7px}
|
||||
#kanbanList .kanban-card.has-left-border {border-left: 2px solid #838a9d;}
|
||||
#kanbanList .kanban-card.has-left-border.border-left-green {border-left-color: #0bd986;}
|
||||
#kanbanList .kanban-card.has-left-border.border-left-red {border-left-color: #ff5d5d;}
|
||||
#kanbanList .kanban-card.has-left-border.border-left-blue {border-left-color: #0991ff;}
|
||||
#kanbanList .no-flex .kanban-lane > .kanban-sub-lanes[data-sub-lanes-count="1"] > .kanban-sub-lane {min-height: 90px;}
|
||||
#kanbanList .no-flex .kanban-lane > .kanban-sub-lanes[data-sub-lanes-count="2"] > .kanban-sub-lane {min-height: 45px;}
|
||||
|
||||
.kanban-affixed {padding-top: 72px;}
|
||||
.kanban-affixed > .kanban-header {position: fixed!important; top: 0; background: rgba(80,80,80,.9); color: #fff; z-index: 100;}
|
||||
|
||||
#kanbanList .kanban-header-col[data-type="doingProject"],
|
||||
#kanbanList .kanban-header-col[data-type="doingProject"] + .kanban-header-col[data-type="doingExecution"] {padding: 38px 10px 0;}
|
||||
#kanbanList .kanban-header-col[data-type="doingProject"]:after {content: attr(data-span-text); display: block; position: absolute; z-index: 10; left: 0; right: -100%; right: calc(-100% - 2px); top: 0; line-height: 36px; text-align: center; font-weight: bold; border-bottom: 2px solid #fff; background-color: #ededed;}
|
||||
#kanbanList .kanban-col[data-type="unclosedProduct"] .kanban-lane-items {height: 100%; display: flex; flex-direction: column; justify-content: center;}
|
||||
#kanbanList .kanban-item.kanban-item-span,
|
||||
#kanbanList .kanban-col[data-type="unclosedProduct"] .kanban-item {background-color: transparent; border: none; padding: 0; text-align: center; box-shadow: none!important;}
|
||||
#kanbanList .kanban-item.kanban-item-span:hover,
|
||||
#kanbanList .kanban-col[data-type="unclosedProduct"] .kanban-item:hover {box-shadow: none;}
|
||||
#kanbanList .kanban-item.kanban-item-span > .title,
|
||||
#kanbanList .kanban-col[data-type="unclosedProduct"] .kanban-item > .title {white-space: normal;}
|
||||
#kanbanList .kanban-col[data-type="unclosedProduct"] .kanban-item {padding: 0;}
|
||||
#kanbanList .kanban-col[data-type="unclosedProduct"] .kanban-lane-items {height: 100%; display: flex; flex-direction: column; justify-content: center; padding: 0; overflow: hidden;}
|
||||
#kanbanList .kanban-card.kanban-card-span,
|
||||
#kanbanList .kanban-col[data-type="unclosedProduct"] .kanban-card {background-color: transparent; border: none; padding: 0; text-align: center; box-shadow: none!important; margin: 0; height: auto!important;}
|
||||
#kanbanList .kanban-card.kanban-card-span:hover,
|
||||
#kanbanList .kanban-col[data-type="unclosedProduct"] .kanban-card:hover {box-shadow: none;}
|
||||
#kanbanList .kanban-card.kanban-card-span > .title,
|
||||
#kanbanList .kanban-col[data-type="unclosedProduct"] .kanban-card > .title {white-space: normal; line-height: 1;}
|
||||
|
||||
#kanbanList .kanban-col[data-type="normalRelease"] .kanban-item > .title {display: flex; flex-direction: row; flex-wrap: nowrap; align-items: center; height: 38px;}
|
||||
#kanbanList .kanban-col[data-type="normalRelease"] .kanban-item > .title > .text {display: block; white-space: nowrap; text-overflow: clip; overflow: hidden;}
|
||||
#kanbanList .kanban-col[data-type="normalRelease"] .kanban-item > .title.has-icon > .text {margin-right: 5px; max-width: calc(100% - 20px);}
|
||||
#kanbanList .no-flex .kanban-col[data-type="normalRelease"] .kanban-item > .title {display: block; height: 38px;}
|
||||
#kanbanList .no-flex .kanban-col[data-type="normalRelease"] .kanban-item > .title > .text {display: inline-block;}
|
||||
#kanbanList .no-flex .kanban-col[data-type="normalRelease"] .kanban-item > .title > .icon {position: relative; top: -5px}
|
||||
#kanbanList .kanban-col[data-type="normalRelease"] .kanban-card > .title {display: flex; flex-direction: row; flex-wrap: nowrap; align-items: center;}
|
||||
#kanbanList .kanban-col[data-type="normalRelease"] .kanban-card > .title > .text {display: block; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;}
|
||||
#kanbanList .kanban-col[data-type="normalRelease"] .kanban-card > .title.has-icon > .text {margin-right: 5px; max-width: calc(100% - 20px);}
|
||||
#kanbanList .no-flex .kanban-col[data-type="normalRelease"] .kanban-card > .title {display: block; height: 38px;}
|
||||
#kanbanList .no-flex .kanban-col[data-type="normalRelease"] .kanban-card > .title > .text {display: inline-block;}
|
||||
#kanbanList .no-flex .kanban-col[data-type="normalRelease"] .kanban-card > .title > .icon {position: relative; top: -5px}
|
||||
#kanbanList .kanban-affixed .kanban-header-col[data-type="doingProject"]:after {background-color: #606060;}
|
||||
|
||||
/* Show project and execution in one row */
|
||||
#kanbanList .kanban-lane-col[data-type="doingProject"] + .kanban-lane-col {border-left: none; box-shadow: inset 2px 0 0 #fff;}
|
||||
#kanbanList .kanban-lane-col[data-type="doingProject"] > .kanban-lane-items {padding: 0; overflow: visible; max-height: none!important;}
|
||||
#kanbanList .project-row {position: relative; width: 200%; width: calc(200% + 2px);}
|
||||
#kanbanList .project-row + .project-row {border-top: 2px solid #fff;}
|
||||
#kanbanList .kanban-lane-col[data-type="doingProject"] > .kanban-lane-items {padding: 0!important; overflow: visible; max-height: none!important;}
|
||||
#kanbanList .kanban-item-span {padding: 0!important;}
|
||||
#kanbanList .project-row {position: relative; width: 200%; width: calc(200% + 2px); height: 62px!important;}
|
||||
#kanbanList .kanban-item-span + .kanban-item-span > .project-row {border-top: 2px solid #fff;}
|
||||
#kanbanList .project-row > .project-col {float: left; width: 50%; padding: 10px;}
|
||||
#kanbanList .project-row > .project-col + .project-col {padding: 10px 9px 10px 11px;}
|
||||
#kanbanList .project-row > .execution-item {position: absolute!important; left: 100%; top: 0}
|
||||
</style>
|
||||
<script>
|
||||
@@ -102,7 +94,7 @@ function renderSpanItem(item, $item)
|
||||
$title = $('<div class="title" />').appendTo($item);
|
||||
}
|
||||
$title.text(item.name).attr('title', item.name);
|
||||
return $item.addClass('kanban-item-span');
|
||||
return $item.addClass('kanban-card-span');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,16 +300,17 @@ function renderReleaseItem(item, $item)
|
||||
*/
|
||||
function renderDoingProjectItem(item, $item)
|
||||
{
|
||||
$item.removeClass('kanban-item').addClass('project-row clearfix').empty();
|
||||
$item.closest('.kanban-item').addClass('kanban-item-span');
|
||||
$item.removeClass('kanban-card').addClass('project-row clearfix').empty();
|
||||
|
||||
var $projectCol = $('<div class="project-col"></div>').appendTo($item);
|
||||
var $projectItem = $('<div class="kanban-item project-item"></div>').appendTo($projectCol);
|
||||
var $projectItem = $('<div class="kanban-card project-item"></div>').appendTo($projectCol);
|
||||
renderProjectItem(item, $projectItem);
|
||||
|
||||
var $executionCol = $('<div class="project-col"></div>').appendTo($item);
|
||||
if(item.execution)
|
||||
{
|
||||
var $executionItem = $('<div class="kanban-item execution-item"></div>').appendTo($executionCol);
|
||||
var $executionItem = $('<div class="kanban-card execution-item"></div>').appendTo($executionCol);
|
||||
renderExecutionItem(item.execution, $executionItem);
|
||||
}
|
||||
|
||||
@@ -389,9 +382,7 @@ function affixKanbanHeader($kanbanBoard, affixed)
|
||||
$kanbanBoard.css('padding-top', affixed ? $header.outerHeight() : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update kanban affix state for all boards in page
|
||||
*/
|
||||
/** Update kanban affix state for all boards in page */
|
||||
function updateKanbanAffixState()
|
||||
{
|
||||
var $boards = $('.kanban-board');
|
||||
@@ -417,34 +408,36 @@ function updateKanbanAffixState()
|
||||
if($currentAffixedBoard) affixKanbanHeader($currentAffixedBoard, true);
|
||||
}
|
||||
|
||||
/** Try to update kanban affix state */
|
||||
function tryUpdateKanbanAffix()
|
||||
{
|
||||
if(window.updateKanbanAffixTimer) $.zui.clearAsap(window.updateKanbanAffixTimer);
|
||||
window.updateKanbanAffixTimer = $.zui.asap(function()
|
||||
{
|
||||
updateKanbanAffixState();
|
||||
window.updateKanbanAffixTimer = null;
|
||||
});
|
||||
}
|
||||
|
||||
/* Kanban color list for lane name */
|
||||
if(!window.kanbanColorList) window.kanbanColorList = ['#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761'];
|
||||
|
||||
/* Set default options to kanban component */
|
||||
$.extend($.fn.kanban.Constructor.DEFAULTS,
|
||||
{
|
||||
readonly: true,
|
||||
maxColHeight: 260,
|
||||
itemRender: renderKanbanItem,
|
||||
useFlex: false,
|
||||
showCount: true,
|
||||
showZeroCount: true,
|
||||
onRenderHeaderCol: function($col, col)
|
||||
readonly: true,
|
||||
maxColHeight: 260,
|
||||
itemRender: renderKanbanItem,
|
||||
showCount: true,
|
||||
showZeroCount: true,
|
||||
fluidBoardWidth: true,
|
||||
onRenderLaneName: function($name, lane, $kanban, columns, kanban)
|
||||
{
|
||||
if(col.type === 'doingProject' && window.doingText) $col.attr('data-span-text', window.doingText);
|
||||
var color = kanbanColorList[lane.$index % kanbanColorList.length];
|
||||
$name.css('background-color', color);
|
||||
},
|
||||
onRenderKanban: function($kanban, kanbanData)
|
||||
{
|
||||
$kanban.find('.kanban-lane').each(function(index)
|
||||
{
|
||||
var $lane = $(this);
|
||||
if ($lane.data('lane').color) return;
|
||||
|
||||
var $laneName = $lane.find('.kanban-lane-name');
|
||||
var color = kanbanColorList[index % kanbanColorList.length];
|
||||
$laneName.css('background-color', color);
|
||||
});
|
||||
|
||||
/* Update project count and execution count */
|
||||
var doingProjectCount = 0;
|
||||
var doingExecutionCount = 0;
|
||||
@@ -460,29 +453,13 @@ $.extend($.fn.kanban.Constructor.DEFAULTS,
|
||||
},
|
||||
onCreate: function(kanban)
|
||||
{
|
||||
kanban.$.on('scroll', updateKanbanAffixState);
|
||||
updateKanbanAffixState();
|
||||
kanban.$.on('scroll', tryUpdateKanbanAffix);
|
||||
tryUpdateKanbanAffix();
|
||||
}
|
||||
});
|
||||
|
||||
$(function()
|
||||
{
|
||||
/* Update kanban affix state on window resize or scroll */
|
||||
var updateTimer;
|
||||
var updateCallback = function()
|
||||
{
|
||||
updateKanbanAffixState();
|
||||
updateTimer = null;
|
||||
};
|
||||
$(window.kanbanAffixContainer || window).on('scroll resize', function(e)
|
||||
{
|
||||
if(updateTimer)
|
||||
{
|
||||
if(window.requestAnimationFrame) cancelAnimationFrame(updateTimer);
|
||||
else clearTimeout(updateTimer);
|
||||
}
|
||||
if(window.requestAnimationFrame) updateTimer = requestAnimationFrame(updateCallback);
|
||||
else updateTimer = setTimeout(updateCallback, 50);
|
||||
});
|
||||
$(window.kanbanAffixContainer || window).on('scroll resize', tryUpdateKanbanAffix);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
.dynamic.collapsed .timeline > li + li {display: none;}
|
||||
.dynamic.collapsed .dynamic-btn > .icon:before {content: '\f0d8';}
|
||||
|
||||
.c-project, .c-product, .c-execution {width: 140px !important; overflow: unset;}
|
||||
.c-user,.c-order {width: 100px !important; overflow: unset;}
|
||||
.c-project, .c-product, .c-execution {width: 110px !important; overflow: unset;}
|
||||
.c-user,.c-order {width: 90px !important; overflow: unset;}
|
||||
.c-date {width: 200px;}
|
||||
|
||||
@@ -30,3 +30,4 @@ $lang->compile->statusList['building'] = 'Building';
|
||||
$lang->compile->statusList['create_fail'] = 'Failed to create';
|
||||
$lang->compile->statusList['timeout'] = 'Timeout';
|
||||
$lang->compile->statusList['canceled'] = 'Canceled';
|
||||
$lang->compile->statusList['failed'] = 'Build failed';
|
||||
|
||||
@@ -30,3 +30,4 @@ $lang->compile->statusList['building'] = '构建中';
|
||||
$lang->compile->statusList['create_fail'] = '创建失败';
|
||||
$lang->compile->statusList['timeout'] = '执行超时';
|
||||
$lang->compile->statusList['canceled'] = '已取消';
|
||||
$lang->compile->statusList['failed'] = '构建失败';
|
||||
|
||||
@@ -23,6 +23,18 @@ class compileModel extends model
|
||||
return $this->dao->select('*')->from(TABLE_COMPILE)->where('id')->eq($buildID)->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get By Queue.
|
||||
*
|
||||
* @param int $queue
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getByQueue($queue)
|
||||
{
|
||||
return $this->dao->select('*')->from(TABLE_COMPILE)->where('queue')->eq($queue)->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get build list.
|
||||
*
|
||||
@@ -46,6 +58,22 @@ class compileModel extends model
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list by jobID.
|
||||
*
|
||||
* @param int $jobID
|
||||
* @return array
|
||||
*/
|
||||
public function getListByJobID($jobID)
|
||||
{
|
||||
return $this->dao->select('id, name, status')->from(TABLE_COMPILE)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere('job')->ne('0')
|
||||
->beginIF(!empty($jobID))->andWhere('job')->eq($jobID)->fi()
|
||||
->orderBy('id_desc')
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unexecuted list.
|
||||
*
|
||||
@@ -121,7 +149,7 @@ class compileModel extends model
|
||||
*/
|
||||
public function exec($compile)
|
||||
{
|
||||
$job = $this->dao->select('t1.id,t1.name,t1.repo,t1.pipeline,t2.name as jenkinsName,t2.url,t2.account,t2.token,t2.password')
|
||||
$job = $this->dao->select('t1.id,t1.name,t1.repo,t1.engine,t1.pipeline,t2.name as jenkinsName,t2.url,t2.account,t2.token,t2.password,t1.triggerType,t1.customParam,t1.server')
|
||||
->from(TABLE_JOB)->alias('t1')
|
||||
->leftJoin(TABLE_PIPELINE)->alias('t2')->on('t1.server=t2.id')
|
||||
->where('t1.id')->eq($compile->job)
|
||||
@@ -134,7 +162,7 @@ class compileModel extends model
|
||||
|
||||
if($job->triggerType == 'tag')
|
||||
{
|
||||
$lastTag = $this->getLastTagByRepo($repo);
|
||||
$lastTag = $this->loadModel('job')->getLastTagByRepo($repo, $job);
|
||||
if($lastTag)
|
||||
{
|
||||
$job->lastTag = $lastTag;
|
||||
|
||||
+97
-90
@@ -28,96 +28,103 @@ $lang->dev->fields['length'] = '长度';
|
||||
$lang->dev->fields['null'] = '是否可空';
|
||||
|
||||
$lang->dev->tableList = array();
|
||||
$lang->dev->tableList['action'] = '系统日志';
|
||||
$lang->dev->tableList['bug'] = 'Bug';
|
||||
$lang->dev->tableList['build'] = '版本';
|
||||
$lang->dev->tableList['burn'] = '燃尽图';
|
||||
$lang->dev->tableList['case'] = '测试用例';
|
||||
$lang->dev->tableList['casestep'] = '用例步骤';
|
||||
$lang->dev->tableList['company'] = '公司';
|
||||
$lang->dev->tableList['config'] = '配置';
|
||||
$lang->dev->tableList['custom'] = '自定义';
|
||||
$lang->dev->tableList['dept'] = '部门';
|
||||
$lang->dev->tableList['doc'] = '文档';
|
||||
$lang->dev->tableList['doclib'] = '文档库';
|
||||
$lang->dev->tableList['effort'] = '日志';
|
||||
$lang->dev->tableList['extension'] = '插件';
|
||||
$lang->dev->tableList['file'] = '附件';
|
||||
$lang->dev->tableList['group'] = '用户组';
|
||||
$lang->dev->tableList['grouppriv'] = '组权限';
|
||||
$lang->dev->tableList['history'] = '操作历史';
|
||||
$lang->dev->tableList['lang'] = '语言定义';
|
||||
$lang->dev->tableList['module'] = '模块';
|
||||
$lang->dev->tableList['program'] = '项目集';
|
||||
$lang->dev->tableList['product'] = $lang->productCommon;
|
||||
$lang->dev->tableList['productplan'] = $lang->productCommon . '计划';
|
||||
$lang->dev->tableList['project'] = '项目';
|
||||
$lang->dev->tableList['projectproduct'] = '项目' . $lang->productCommon;
|
||||
$lang->dev->tableList['projectstory'] = '项目' . $lang->SRCommon;
|
||||
$lang->dev->tableList['execution'] = $lang->executionCommon;
|
||||
$lang->dev->tableList['release'] = '发布';
|
||||
$lang->dev->tableList['story'] = $lang->SRCommon;
|
||||
$lang->dev->tableList['storyspec'] = "{$lang->SRCommon}描述";
|
||||
$lang->dev->tableList['task'] = '任务';
|
||||
$lang->dev->tableList['taskestimate'] = '任务预计';
|
||||
$lang->dev->tableList['team'] = '团队';
|
||||
$lang->dev->tableList['testresult'] = '测试结果';
|
||||
$lang->dev->tableList['testrun'] = '测试执行';
|
||||
$lang->dev->tableList['testtask'] = '测试单';
|
||||
$lang->dev->tableList['todo'] = '待办';
|
||||
$lang->dev->tableList['user'] = '用户';
|
||||
$lang->dev->tableList['usercontact'] = '用户联系人';
|
||||
$lang->dev->tableList['usergroup'] = '用户组';
|
||||
$lang->dev->tableList['userquery'] = '用户查询';
|
||||
$lang->dev->tableList['usertpl'] = '用户模板';
|
||||
$lang->dev->tableList['admin'] = '后台管理';
|
||||
$lang->dev->tableList['api'] = 'API接口';
|
||||
$lang->dev->tableList['backup'] = '备份';
|
||||
$lang->dev->tableList['common'] = '公有模块';
|
||||
$lang->dev->tableList['convert'] = '导入';
|
||||
$lang->dev->tableList['dev'] = '二次开发';
|
||||
$lang->dev->tableList['git'] = 'GIT';
|
||||
$lang->dev->tableList['index'] = '首页';
|
||||
$lang->dev->tableList['install'] = '安装';
|
||||
$lang->dev->tableList['mail'] = '邮箱';
|
||||
$lang->dev->tableList['misc'] = '杂项';
|
||||
$lang->dev->tableList['my'] = '我的地盘';
|
||||
$lang->dev->tableList['qa'] = '测试';
|
||||
$lang->dev->tableList['report'] = '统计';
|
||||
$lang->dev->tableList['search'] = '搜索';
|
||||
$lang->dev->tableList['sso'] = '单点登录';
|
||||
$lang->dev->tableList['svn'] = 'SVN';
|
||||
$lang->dev->tableList['testcase'] = '测试用例';
|
||||
$lang->dev->tableList['testreport'] = '测试报告';
|
||||
$lang->dev->tableList['testsuite'] = '测试套件';
|
||||
$lang->dev->tableList['caselib'] = '用例库';
|
||||
$lang->dev->tableList['tree'] = '模块关系';
|
||||
$lang->dev->tableList['upgrade'] = '更新';
|
||||
$lang->dev->tableList['cron'] = '定时任务';
|
||||
$lang->dev->tableList['datatable'] = '数据表格';
|
||||
$lang->dev->tableList['block'] = '区块';
|
||||
$lang->dev->tableList['branch'] = '平台/分支';
|
||||
$lang->dev->tableList['doccontent'] = '文档内容';
|
||||
$lang->dev->tableList['storystage'] = "{$lang->SRCommon}阶段";
|
||||
$lang->dev->tableList['tutorial'] = '新手教程';
|
||||
$lang->dev->tableList['suitecase'] = '套件用例';
|
||||
$lang->dev->tableList['score'] = '积分';
|
||||
$lang->dev->tableList['entry'] = '应用';
|
||||
$lang->dev->tableList['webhook'] = 'WebHook';
|
||||
$lang->dev->tableList['log'] = '接口日志';
|
||||
$lang->dev->tableList['message'] = '消息';
|
||||
$lang->dev->tableList['notify'] = '通知';
|
||||
$lang->dev->tableList['userview'] = '可访问权限';
|
||||
$lang->dev->tableList['repo'] = '代码';
|
||||
$lang->dev->tableList['repohistory'] = '版本历史';
|
||||
$lang->dev->tableList['repofiles'] = '代码文件';
|
||||
$lang->dev->tableList['repobranch'] = '代码分支';
|
||||
$lang->dev->tableList['ci'] = '持续集成';
|
||||
$lang->dev->tableList['compile'] = '构建';
|
||||
$lang->dev->tableList['jenkins'] = 'Jenkins';
|
||||
$lang->dev->tableList['job'] = '构建任务';
|
||||
$lang->dev->tableList['searchdict'] = '搜索字典';
|
||||
$lang->dev->tableList['searchindex'] = '搜索索引';
|
||||
$lang->dev->tableList['action'] = '系统日志';
|
||||
$lang->dev->tableList['bug'] = 'Bug';
|
||||
$lang->dev->tableList['build'] = '版本';
|
||||
$lang->dev->tableList['burn'] = '燃尽图';
|
||||
$lang->dev->tableList['case'] = '测试用例';
|
||||
$lang->dev->tableList['casestep'] = '用例步骤';
|
||||
$lang->dev->tableList['company'] = '公司';
|
||||
$lang->dev->tableList['config'] = '配置';
|
||||
$lang->dev->tableList['custom'] = '自定义';
|
||||
$lang->dev->tableList['dept'] = '部门';
|
||||
$lang->dev->tableList['doc'] = '文档';
|
||||
$lang->dev->tableList['doclib'] = '文档库';
|
||||
$lang->dev->tableList['effort'] = '日志';
|
||||
$lang->dev->tableList['extension'] = '插件';
|
||||
$lang->dev->tableList['file'] = '附件';
|
||||
$lang->dev->tableList['group'] = '用户组';
|
||||
$lang->dev->tableList['grouppriv'] = '组权限';
|
||||
$lang->dev->tableList['history'] = '操作历史';
|
||||
$lang->dev->tableList['lang'] = '语言定义';
|
||||
$lang->dev->tableList['module'] = '模块';
|
||||
$lang->dev->tableList['program'] = '项目集';
|
||||
$lang->dev->tableList['product'] = $lang->productCommon;
|
||||
$lang->dev->tableList['productplan'] = $lang->productCommon . '计划';
|
||||
$lang->dev->tableList['project'] = '项目';
|
||||
$lang->dev->tableList['projectproduct'] = '项目' . $lang->productCommon;
|
||||
$lang->dev->tableList['projectstory'] = '项目' . $lang->SRCommon;
|
||||
$lang->dev->tableList['execution'] = $lang->executionCommon;
|
||||
$lang->dev->tableList['release'] = '发布';
|
||||
$lang->dev->tableList['story'] = $lang->SRCommon;
|
||||
$lang->dev->tableList['storyspec'] = "{$lang->SRCommon}描述";
|
||||
$lang->dev->tableList['task'] = '任务';
|
||||
$lang->dev->tableList['taskestimate'] = '任务预计';
|
||||
$lang->dev->tableList['team'] = '团队';
|
||||
$lang->dev->tableList['testresult'] = '测试结果';
|
||||
$lang->dev->tableList['testrun'] = '测试执行';
|
||||
$lang->dev->tableList['testtask'] = '测试单';
|
||||
$lang->dev->tableList['todo'] = '待办';
|
||||
$lang->dev->tableList['user'] = '用户';
|
||||
$lang->dev->tableList['usercontact'] = '用户联系人';
|
||||
$lang->dev->tableList['usergroup'] = '用户组';
|
||||
$lang->dev->tableList['userquery'] = '用户查询';
|
||||
$lang->dev->tableList['usertpl'] = '用户模板';
|
||||
$lang->dev->tableList['admin'] = '后台管理';
|
||||
$lang->dev->tableList['api'] = 'API接口';
|
||||
$lang->dev->tableList['backup'] = '备份';
|
||||
$lang->dev->tableList['common'] = '公有模块';
|
||||
$lang->dev->tableList['convert'] = '导入';
|
||||
$lang->dev->tableList['dev'] = '二次开发';
|
||||
$lang->dev->tableList['git'] = 'GIT';
|
||||
$lang->dev->tableList['index'] = '首页';
|
||||
$lang->dev->tableList['install'] = '安装';
|
||||
$lang->dev->tableList['mail'] = '邮箱';
|
||||
$lang->dev->tableList['misc'] = '杂项';
|
||||
$lang->dev->tableList['my'] = '我的地盘';
|
||||
$lang->dev->tableList['qa'] = '测试';
|
||||
$lang->dev->tableList['report'] = '统计';
|
||||
$lang->dev->tableList['search'] = '搜索';
|
||||
$lang->dev->tableList['sso'] = '单点登录';
|
||||
$lang->dev->tableList['svn'] = 'SVN';
|
||||
$lang->dev->tableList['testcase'] = '测试用例';
|
||||
$lang->dev->tableList['testreport'] = '测试报告';
|
||||
$lang->dev->tableList['testsuite'] = '测试套件';
|
||||
$lang->dev->tableList['caselib'] = '用例库';
|
||||
$lang->dev->tableList['tree'] = '模块关系';
|
||||
$lang->dev->tableList['upgrade'] = '更新';
|
||||
$lang->dev->tableList['cron'] = '定时任务';
|
||||
$lang->dev->tableList['datatable'] = '数据表格';
|
||||
$lang->dev->tableList['block'] = '区块';
|
||||
$lang->dev->tableList['branch'] = '平台/分支';
|
||||
$lang->dev->tableList['doccontent'] = '文档内容';
|
||||
$lang->dev->tableList['storystage'] = "{$lang->SRCommon}阶段";
|
||||
$lang->dev->tableList['tutorial'] = '新手教程';
|
||||
$lang->dev->tableList['suitecase'] = '套件用例';
|
||||
$lang->dev->tableList['score'] = '积分';
|
||||
$lang->dev->tableList['entry'] = '应用';
|
||||
$lang->dev->tableList['webhook'] = 'WebHook';
|
||||
$lang->dev->tableList['log'] = '接口日志';
|
||||
$lang->dev->tableList['message'] = '消息';
|
||||
$lang->dev->tableList['notify'] = '通知';
|
||||
$lang->dev->tableList['userview'] = '可访问权限';
|
||||
$lang->dev->tableList['repo'] = '代码';
|
||||
$lang->dev->tableList['repohistory'] = '版本历史';
|
||||
$lang->dev->tableList['repofiles'] = '代码文件';
|
||||
$lang->dev->tableList['repobranch'] = '代码分支';
|
||||
$lang->dev->tableList['ci'] = '持续集成';
|
||||
$lang->dev->tableList['compile'] = '构建';
|
||||
$lang->dev->tableList['jenkins'] = 'Jenkins';
|
||||
$lang->dev->tableList['job'] = '构建任务';
|
||||
$lang->dev->tableList['searchdict'] = '搜索字典';
|
||||
$lang->dev->tableList['searchindex'] = '搜索索引';
|
||||
$lang->dev->tableList['kanbanlane'] = '看板泳道';
|
||||
$lang->dev->tableList['kanbancolumn'] = '看板列';
|
||||
$lang->dev->tableList['stakeholder'] = '干系人';
|
||||
$lang->dev->tableList['im_chat_message_index'] = 'im聊天消息';
|
||||
$lang->dev->tableList['im_message_backup'] = 'im消息备份';
|
||||
$lang->dev->tableList['im_message_index'] = 'im消息索引';
|
||||
$lang->dev->tableList['im_userdevice'] = 'im用户设备';
|
||||
|
||||
$lang->dev->groupList['my'] = '我的地盘';
|
||||
$lang->dev->groupList['program'] = '项目集';
|
||||
|
||||
@@ -385,7 +385,8 @@ class doc extends control
|
||||
|
||||
$link = $this->session->docList ? $this->session->docList : $this->createLink('doc', 'index');
|
||||
$doc = $this->doc->getById($docID);
|
||||
if(!empty($objectType) and $objectType != 'doc' and $doc->type != 'chapter')
|
||||
|
||||
if(!empty($objectType) and $objectType != 'doc' and $doc->type != 'chapter' and $doc->type != 'article')
|
||||
{
|
||||
$link = $this->createLink('doc', 'objectLibs', "type=$objectType&objectID=$objectID&libID=$libID&docID=$docID");
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
span.item>a {padding-left: 6px;}
|
||||
span.dotted-line+a {display: block;}
|
||||
#modules li.doc:before, .chapterNode:before, .independent:before {content: " "; width: 100%; border-bottom: 1px dashed #b5b9c5; position: absolute; top: 13px; right: 0; left: 30px;}
|
||||
.doc-title {display: inline-block !important; position: relative; padding-right: 10px;}
|
||||
.doc-title ,.item{display: inline-block !important; position: relative; padding-right: 10px; max-width:80%; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;}
|
||||
.tree li.has-list.open:before {content: unset;}
|
||||
#modules i.icon-file-text {color: #D0D2D6; font-size: 14px;}
|
||||
.tree li>a {max-width: 80%;}
|
||||
|
||||
@@ -44,7 +44,7 @@ if(empty($type)) $type = 'product';
|
||||
echo "<ul class='dropdown-menu pull-left'>";
|
||||
if($canManageMenu)
|
||||
{
|
||||
echo '<li>' . html::a($this->createLink('tree', 'browse', "rootID=$libID&view=doc", '', true), '<i class="icon-cog-outline"></i> ' . $this->lang->doc->manageType, '', "class='iframe'") . '</li>';
|
||||
echo '<li>' . html::a($this->createLink('tree', 'browse', "rootID=$libID&view=doc¤tModuleID=0&branch=0&from={$this->app->tab}", '', true), '<i class="icon-cog-outline"></i> ' . $this->lang->doc->manageType, '', "class='iframe'") . '</li>';
|
||||
echo "<li class='divider'></li>";
|
||||
}
|
||||
if($canEditLib) echo '<li>' . html::a($this->createLink('doc', 'editLib', "rootID=$libID"), '<i class="icon-edit"></i> ' . $lang->doc->editLib, '', "class='iframe'") . '</li>';
|
||||
@@ -112,7 +112,7 @@ if(empty($type)) $type = 'product';
|
||||
}
|
||||
else
|
||||
{
|
||||
common::printLink('tree', 'browse', "rootID=$libID&view=doc", $lang->doc->manageType, '', "class='btn btn-info btn-wide iframe'", '', true);
|
||||
common::printLink('tree', 'browse', "rootID=$libID&view=doc¤tModuleID=0&branch=0&from={$this->app->tab}", $lang->doc->manageType, '', "class='btn btn-info btn-wide iframe'", '', true);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -17,8 +17,12 @@ $app->loadLang('task');
|
||||
$config->execution->task = new stdclass();
|
||||
$config->execution->create = new stdclass();
|
||||
$config->execution->edit = new stdclass();
|
||||
$config->execution->create->requiredFields = 'name,code,begin,end';
|
||||
$config->execution->edit->requiredFields = 'name,code,begin,end';
|
||||
$config->execution->start = new stdclass();
|
||||
$config->execution->close = new stdclass();
|
||||
$config->execution->create->requiredFields = 'name,code,begin,end';
|
||||
$config->execution->edit->requiredFields = 'name,code,begin,end';
|
||||
$config->execution->start->requiredFields = 'realBegan';
|
||||
$config->execution->close->requiredFields = 'realEnd';
|
||||
|
||||
$config->execution->customBatchEditFields = 'days,type,teamname,status,desc,PO,QD,PM,RD';
|
||||
|
||||
@@ -44,7 +48,7 @@ $config->execution->search['fields']['desc'] = $lang->task->desc;
|
||||
$config->execution->search['fields']['assignedTo'] = $lang->task->assignedTo;
|
||||
$config->execution->search['fields']['pri'] = $lang->task->pri;
|
||||
|
||||
$config->execution->search['fields']['execution'] = $lang->task->execution;
|
||||
$config->execution->search['fields']['execution'] = $lang->task->execution;
|
||||
$config->execution->search['fields']['module'] = $lang->task->module;
|
||||
$config->execution->search['fields']['estimate'] = $lang->task->estimate;
|
||||
$config->execution->search['fields']['left'] = $lang->task->left;
|
||||
@@ -78,13 +82,13 @@ $config->execution->search['params']['desc'] = array('operator' => 'in
|
||||
$config->execution->search['params']['assignedTo'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
|
||||
$config->execution->search['params']['pri'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->task->priList);
|
||||
|
||||
$config->execution->search['params']['execution'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
$config->execution->search['params']['execution'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
$config->execution->search['params']['module'] = array('operator' => 'belong', 'control' => 'select', 'values' => '');
|
||||
$config->execution->search['params']['estimate'] = array('operator' => '=', 'control' => 'input', 'values' => '');
|
||||
$config->execution->search['params']['left'] = array('operator' => '=', 'control' => 'input', 'values' => '');
|
||||
$config->execution->search['params']['consumed'] = array('operator' => '=', 'control' => 'input', 'values' => '');
|
||||
$config->execution->search['params']['type'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->task->typeList);
|
||||
$config->execution->search['params']['fromBug'] = array('operator' => '=', 'control' => 'input', 'values' => $lang->task->typeList);
|
||||
$config->execution->search['params']['fromBug'] = array('operator' => '=', 'control' => 'input', 'values' => $lang->task->typeList);
|
||||
$config->execution->search['params']['closedReason'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->task->reasonList);
|
||||
|
||||
$config->execution->search['params']['openedBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
|
||||
|
||||
@@ -219,17 +219,10 @@ class execution extends control
|
||||
}
|
||||
|
||||
/* Get product. */
|
||||
if(empty($productID))
|
||||
{
|
||||
$productModule = $this->tree->getById($moduleID);
|
||||
if(!empty($productModule) and $productModule->type != 'task') $product = $this->product->getById($productModule->root);
|
||||
}
|
||||
if(empty($product)) $product = $this->product->getById($productID);
|
||||
$product = $this->product->getById($productID);
|
||||
|
||||
if(!empty($product) and $product->type != 'normal')
|
||||
{
|
||||
$this->lang->datatable->showBranch = sprintf($this->lang->datatable->showBranch, $this->lang->product->branchName[$product->type]);
|
||||
}
|
||||
/* Display of branch label. */
|
||||
$showBranch = $this->loadModel('branch')->showBranch($productID, $moduleID, $executionID);
|
||||
|
||||
/* Build the search form. */
|
||||
$actionURL = $this->createLink('execution', 'task', "executionID=$executionID&status=bySearch¶m=myQueryID");
|
||||
@@ -268,6 +261,7 @@ class execution extends control
|
||||
$this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products), 'noempty');
|
||||
$this->view->setModule = true;
|
||||
$this->view->canBeChanged = common::canModify('execution', $execution); // Determines whether an object is editable.
|
||||
$this->view->showBranch = $showBranch;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -609,7 +603,7 @@ class execution extends control
|
||||
if($this->session->importBugQuery == false) $this->session->set('importBugQuery', ' 1 = 1');
|
||||
}
|
||||
$bugQuery = str_replace("`product` = 'all'", "`product`" . helper::dbIN(array_keys($products)), $this->session->importBugQuery); // Search all execution.
|
||||
$bugs = $this->execution->getSearchBugs($products, $executionID, $bugQuery, $pager, 'id_desc');
|
||||
$bugs = $this->execution->getSearchBugs($products, $executionID, $bugQuery, $pager, 'id_desc');
|
||||
}
|
||||
|
||||
/* Build the search form. */
|
||||
@@ -662,8 +656,8 @@ class execution extends control
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->param = $param;
|
||||
$this->view->users = $users;
|
||||
$this->view->execution = $this->execution->getByID($executionID);
|
||||
$this->view->executionID = $executionID;
|
||||
$this->view->execution = $this->execution->getByID($executionID);
|
||||
$this->view->executionID = $executionID;
|
||||
$this->view->requiredFields = explode(',', $this->config->task->create->requiredFields);
|
||||
$this->display();
|
||||
}
|
||||
@@ -761,13 +755,22 @@ class execution extends control
|
||||
$users = $this->user->getPairs('noletter');
|
||||
|
||||
/* Build the search form. */
|
||||
$modules = array();
|
||||
$modules = array();
|
||||
$productModules = array();
|
||||
$executionModules = $this->loadModel('tree')->getTaskTreeModules($executionID, true);
|
||||
$products = $this->product->getProducts($executionID);
|
||||
foreach($products as $product)
|
||||
$products = $this->product->getProducts($executionID);
|
||||
if($productID)
|
||||
{
|
||||
$productModules = $this->tree->getOptionMenu($product->id);
|
||||
foreach($productModules as $moduleID => $moduleName)
|
||||
$product = $products[$productID];
|
||||
$productModules = $this->tree->getOptionMenu($productID, 'story', 0, $product->branches);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($products as $product) $productModules += $this->tree->getOptionMenu($product->id, 'story', 0, $product->branches);
|
||||
}
|
||||
foreach($productModules as $branchID => $moduleList)
|
||||
{
|
||||
foreach($moduleList as $moduleID => $moduleName)
|
||||
{
|
||||
if($moduleID and !isset($executionModules[$moduleID])) continue;
|
||||
$modules[$moduleID] = ((count($products) >= 2 and $moduleID) ? $product->name : '') . $moduleName;
|
||||
@@ -795,22 +798,8 @@ class execution extends control
|
||||
foreach($plans as $plan) $allPlans += $plan;
|
||||
}
|
||||
|
||||
if($this->cookie->storyModuleParam)
|
||||
{
|
||||
$module = $this->loadModel('tree')->getById($this->cookie->storyModuleParam);
|
||||
$this->view->module = $module;
|
||||
|
||||
$product = $this->product->getById($module->root);
|
||||
$this->lang->datatable->showBranch = sprintf($this->lang->datatable->showBranch, $this->lang->product->branchName[$product->type]);
|
||||
}
|
||||
|
||||
if($this->cookie->storyProductParam)
|
||||
{
|
||||
$product = $this->loadModel('product')->getById($this->cookie->storyProductParam);
|
||||
$this->view->product = $product;
|
||||
$this->lang->datatable->showBranch = sprintf($this->lang->datatable->showBranch, $this->lang->product->branchName[$product->type]);
|
||||
}
|
||||
|
||||
if($this->cookie->storyModuleParam) $this->view->module = $this->loadModel('tree')->getById($this->cookie->storyModuleParam);
|
||||
if($this->cookie->storyProductParam) $this->view->product = $this->loadModel('product')->getById($this->cookie->storyProductParam);
|
||||
if($this->cookie->storyBranchParam)
|
||||
{
|
||||
$branchID = $this->cookie->storyBranchParam;
|
||||
@@ -818,6 +807,9 @@ class execution extends control
|
||||
$this->view->branch = $this->loadModel('branch')->getById($branchID, $productID);
|
||||
}
|
||||
|
||||
/* Display of branch label. */
|
||||
$showBranch = $this->loadModel('branch')->showBranch($this->cookie->storyProductParam, $this->cookie->storyModuleParam, $executionID);
|
||||
|
||||
/* Get execution's product. */
|
||||
$productPairs = $this->loadModel('product')->getProductPairsByProject($executionID);
|
||||
|
||||
@@ -848,6 +840,7 @@ class execution extends control
|
||||
$this->view->setModule = true;
|
||||
$this->view->branchGroups = $branchGroups;
|
||||
$this->view->canBeChanged = common::canModify('execution', $execution); // Determines whether an object is editable.
|
||||
$this->view->showBranch = $showBranch;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -1038,6 +1031,16 @@ class execution extends control
|
||||
$type = strtolower($type);
|
||||
$queryID = ($type == 'bysearch') ? (int)$param : 0;
|
||||
$actionURL = $this->createLink('execution', 'build', "executionID=$executionID&type=bysearch&queryID=myQueryID");
|
||||
|
||||
$product = $param ? $this->loadModel('product')->getById($param) : '';
|
||||
if($product and $product->type != 'normal')
|
||||
{
|
||||
$this->loadModel('build');
|
||||
$this->loadModel('branch');
|
||||
$branches = array(BRANCH_MAIN => $this->lang->branch->main) + $this->branch->getPairs($product->id, '', $executionID);
|
||||
$this->config->build->search['fields']['branch'] = sprintf($this->lang->build->branchName, $this->lang->product->branchName[$product->type]);
|
||||
$this->config->build->search['params']['branch'] = array('operator' => '=', 'control' => 'select', 'values' => $branches);
|
||||
}
|
||||
$this->project->buildProjectBuildSearchForm($products, $queryID, $actionURL, 'execution');
|
||||
|
||||
/* Get builds. */
|
||||
@@ -1053,12 +1056,20 @@ class execution extends control
|
||||
/* Set execution builds. */
|
||||
$executionBuilds = array();
|
||||
$productList = $this->product->getProducts($executionID);
|
||||
$this->app->loadLang('branch');
|
||||
if(!empty($builds))
|
||||
{
|
||||
foreach($builds as $build)
|
||||
{
|
||||
/* If product is normal, unset branch name. */
|
||||
if(isset($productList[$build->product]) and $productList[$build->product]->type == 'normal') $build->branchName = '';
|
||||
if(isset($productList[$build->product]) and $productList[$build->product]->type == 'normal')
|
||||
{
|
||||
$build->branchName = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$build->branchName = isset($build->branchName) ? $build->branchName : $this->lang->branch->main;
|
||||
}
|
||||
$executionBuilds[$build->product][] = $build;
|
||||
}
|
||||
}
|
||||
@@ -1391,8 +1402,10 @@ class execution extends control
|
||||
}
|
||||
}
|
||||
|
||||
$isStage = false;
|
||||
if(!empty($project->model) and $project->model == 'waterfall')
|
||||
{
|
||||
$isStage = true;
|
||||
$this->lang->execution->type = str_replace($this->lang->executionCommon, $this->lang->project->stage, $this->lang->execution->type);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,5 @@
|
||||
#kanbanList .kanban-header-col {height: 32px!important; padding: 0!important;}
|
||||
#kanbanList .kanban-header-col > .title {padding: 0 5px!important;}
|
||||
#kanbanList .kanban-col[data-type="project"] .kanban-lane-items {height: 100%; display: flex; flex-direction: column; justify-content: center;}
|
||||
#kanbanList .kanban-lane-name {width: 5px; margin-right: 15px;}
|
||||
#kanbanList .kanban-lane-name > .text {display: none;}
|
||||
#kanbanList .kanban-item.link-block > a {cursor: move;}
|
||||
|
||||
@@ -2,20 +2,19 @@
|
||||
#main > .container {max-width: 1960px!important; padding: 0 10px}
|
||||
|
||||
.kanban + .kanban {margin-top: 15px}
|
||||
.kanban-item {position: relative;}
|
||||
.kanban-item > .title { display: block;white-space: nowrap; overflow: hidden; text-overflow: ellipsis}
|
||||
.kanban-item > .infos {position: relative; margin-top: 5px}
|
||||
.kanban-item > .infos > .info + .info {margin-left: 8px}
|
||||
.kanban-item > .infos > .info-id,
|
||||
.kanban-item > .infos > .info-deadline,
|
||||
.kanban-item > .infos > .info-estimate {font-size: 12px; position: relative; top: 2px}
|
||||
.kanban-item > .infos > .label-pri {min-width: 16px; line-height: 14px; height: 16px; padding: 0}
|
||||
.kanban-item > .infos > .label-severity {transform: scale(.75)}
|
||||
.kanban-item > .infos > .avatar {position: absolute; right: 0; top: 0}
|
||||
.kanban-item > .actions {position: absolute; top: 4px; right: 4px; opacity: 0;}
|
||||
.kanban-item:hover > .actions {opacity: 1;}
|
||||
.kanban-item > .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
|
||||
.kanban-item > .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
|
||||
.kanban-card > .title {display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis}
|
||||
.kanban-card > .infos {position: relative; margin-top: 5px}
|
||||
.kanban-card > .infos > .info + .info {margin-left: 8px}
|
||||
.kanban-card > .infos > .info-id,
|
||||
.kanban-card > .infos > .info-deadline,
|
||||
.kanban-card > .infos > .info-estimate {font-size: 12px; position: relative; top: 2px}
|
||||
.kanban-card > .infos > .label-pri {min-width: 16px; line-height: 14px; height: 16px; padding: 0}
|
||||
.kanban-card > .infos > .label-severity {transform: scale(.75)}
|
||||
.kanban-card > .infos > .avatar {position: absolute; right: 0; top: 0}
|
||||
.kanban-card > .actions {position: absolute; top: 4px; right: 4px; opacity: 0;}
|
||||
.kanban-card:hover > .actions {opacity: 1;}
|
||||
.kanban-card > .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
|
||||
.kanban-card > .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
|
||||
|
||||
.kanban-header-col > .actions {padding-top: 22px}
|
||||
.kanban-header-parent-col .kanban-header-col > .actions {padding-top: 6px; padding-right: 2px;}
|
||||
@@ -35,6 +34,20 @@
|
||||
#kanbans .kanban {min-height: initial;}
|
||||
#kanbans .kanban-lane {min-height: 150px;}
|
||||
#kanbans .kanban-affixed > .kanban-header {top: 100px;}
|
||||
#kanbans .kanban-card[data-scale-size="4"] {padding: 8px;}
|
||||
#kanbans .kanban-card[data-scale-size="3"] {padding: 3px 4px;}
|
||||
#kanbans .kanban-card[data-scale-size="3"] > .title {white-space: normal; max-height: 100%;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] {padding: 3px 4px;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .title {line-height: 18px; white-space: normal; max-height: 100%;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .title > .infos {display: inline-block; height: 18px; vertical-align: top;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .title > .infos > .info-pri {transform: scale(.8); vertical-align: top;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .title > .infos > .avatar {display: inline-block; transform: scale(.8); position: relative; top: -1px; vertical-align: top; margin-right: -1px;}
|
||||
|
||||
#kanbanScaleControl {width: 100px;}
|
||||
#kanbanScaleControl .input-group-addon {background: #fff; padding: 5px;}
|
||||
#kanbanScaleControl > .input-group-btn:first-child > .btn {border-radius: 16px 0 0 16px; border-right-color: transparent;}
|
||||
#kanbanScaleControl > .input-group-btn:last-child > .btn {border-radius: 0 16px 16px 0; border-left-color: transparent;}
|
||||
#kanbanScaleControl > .input-group-btn > .btn:hover {border-color: #b8bfce;}
|
||||
|
||||
#type_chosen .icon-kanban {padding-right: 10px; font-size: 15px;}
|
||||
|
||||
|
||||
@@ -184,9 +184,7 @@ function loadPlans(product, branchID)
|
||||
var branchID = typeof(branchID) == 'undefined' ? 0 : branchID;
|
||||
var index = $(product).attr('id').replace('products', '');
|
||||
|
||||
if(typeof(planID) == 'undefined') planID = 0;
|
||||
planID = $("select#plans" + productID).val() != '' ? $("select#plans" + productID).val() : planID;
|
||||
$.get(createLink('product', 'ajaxGetPlans', "productID=" + productID + '&branch=0,' + branchID + '&planID=' + planID + '&fieldID&needCreate=&expired=' + (config.currentMethod == 'create' ? 'unexpired' : '') + '¶m=skipParent'), function(data)
|
||||
$.get(createLink('product', 'ajaxGetPlans', "productID=" + productID + '&branch=0,' + branchID + '&planID=0&fieldID&needCreate=&expired=' + (config.currentMethod == 'create' ? 'unexpired' : '') + '¶m=skipParent'), function(data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
|
||||
@@ -157,8 +157,8 @@ $(function()
|
||||
|
||||
$('#kanban').kanban(
|
||||
{
|
||||
data: processKanbanData(),
|
||||
// noLaneName: true,
|
||||
data: processKanbanData(),
|
||||
laneNameWidth: 5,
|
||||
droppable:
|
||||
{
|
||||
selector: '.kanban-item:not(.kanban-item-span)',
|
||||
@@ -166,5 +166,6 @@ $(function()
|
||||
finish: handleFinishDrop,
|
||||
mouseButton: 'left'
|
||||
},
|
||||
virtualize: true
|
||||
});
|
||||
});
|
||||
|
||||
+195
-106
@@ -9,9 +9,10 @@ function changeView(view)
|
||||
* @param {String|{account: string, avatar: string}} user User account or user object
|
||||
* @returns {string}
|
||||
*/
|
||||
function renderUserAvatar(user, objectType, objectID)
|
||||
function renderUserAvatar(user, objectType, objectID, size)
|
||||
{
|
||||
var $noPrivAndNoAssigned = $('<div class="avatar has-text avatar-sm avatar-circle" title="' + noAssigned + '" style="background: #ccc"><i class="icon icon-account"></i></div>');
|
||||
var avatarSizeClass = 'avatar-' + (size || 'sm');
|
||||
var $noPrivAndNoAssigned = $('<div class="avatar has-text ' + avatarSizeClass + ' avatar-circle" title="' + noAssigned + '" style="background: #ccc"><i class="icon icon-person"></i></div>');
|
||||
if(objectType == 'task')
|
||||
{
|
||||
if(!priv.canAssignTask && !user) return $noPrivAndNoAssigned;
|
||||
@@ -28,17 +29,17 @@ function renderUserAvatar(user, objectType, objectID)
|
||||
var link = createLink('bug', 'assignto', 'id=' + objectID, '', true);
|
||||
}
|
||||
|
||||
if(!user) return $('<a class="avatar has-text avatar-sm avatar-circle iframe" title="' + noAssigned + '" style="background: #ccc" href="' + link + '"><i class="icon icon-account"></i></a>');
|
||||
if(!user) return $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + noAssigned + '" style="background: #ccc" href="' + link + '"><i class="icon icon-person"></i></a>');
|
||||
|
||||
if(typeof user === 'string') user = {account: user};
|
||||
if(!user.avatar && window.userList && window.userList[user.account]) user = window.userList[user.account];
|
||||
|
||||
var $noPrivAvatar = $('<div class="avatar has-text avatar-sm avatar-circle" />').avatar({user: user});
|
||||
var $noPrivAvatar = $('<div class="avatar has-text ' + avatarSizeClass + ' avatar-circle" />').avatar({user: user});
|
||||
if(objectType == 'task' && !priv.canAssignTask) return $noPrivAvatar;
|
||||
if(objectType == 'story' && !priv.canAssignStory) return $noPrivAvatar;
|
||||
if(objectType == 'bug' && !priv.canAssignBug) return $noPrivAvatar;
|
||||
|
||||
return $('<a class="avatar has-text avatar-sm avatar-circle iframe" href="' + link + '"/>').avatar({user: user});
|
||||
return $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" href="' + link + '"/>').avatar({user: user});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,43 +72,56 @@ function renderDeadline(deadline)
|
||||
*/
|
||||
function renderStoryItem(item, $item, col)
|
||||
{
|
||||
var $title = $item.find('.title');
|
||||
if(!$title.length)
|
||||
{
|
||||
$title = $('<a class="title iframe" data-width="95%"><i class="icon icon-lightbulb text-muted"></i> <span class="text"></span></a>')
|
||||
.attr('href', $.createLink('story', 'view', 'storyID=' + item.id, '', true));
|
||||
$title.appendTo($item);
|
||||
}
|
||||
$title.attr('title', item.title).find('.text').text(item.title);
|
||||
var scaleSize = window.kanbanScaleSize;
|
||||
if(+$item.attr('data-scale-size') !== scaleSize) $item.empty().attr('data-scale-size', scaleSize);
|
||||
|
||||
var $infos = $item.find('.infos');
|
||||
if(!$infos.length)
|
||||
if(scaleSize <= 3)
|
||||
{
|
||||
$infos = $('<div class="infos"></div>').appendTo($item);
|
||||
}
|
||||
$infos.html(
|
||||
[
|
||||
'<span class="info info-id text-muted">#' + item.id + '</span>',
|
||||
'<span class="info info-pri label-pri label-pri-' + item.pri + '" title="' + item.pri + '">' + item.pri + '</span>',
|
||||
item.estimate ? '<span class="info info-estimate text-muted">' + item.estimate + 'h</span>' : '',
|
||||
].join(''));
|
||||
$infos.append(renderUserAvatar(item.assignedTo, 'story', item.id));
|
||||
|
||||
var $actions = $item.find('.actions');
|
||||
if(!$actions.length && item.menus.length)
|
||||
{
|
||||
$actions = $([
|
||||
'<div class="actions">',
|
||||
'<a data-contextmenu="story" data-col="' + col.type + '">',
|
||||
'<i class="icon icon-ellipsis-v"></i>',
|
||||
'</a>',
|
||||
'</div>'
|
||||
].join('')).appendTo($item);
|
||||
var $title = $item.find('.title');
|
||||
if(!$title.length)
|
||||
{
|
||||
$title = $('<a class="title iframe" data-width="95%">' + (scaleSize <= 1 ? '<i class="icon icon-lightbulb text-muted"></i> ' : '') + '<span class="text"></span></a>')
|
||||
.attr('href', $.createLink('story', 'view', 'storyID=' + item.id, '', true));
|
||||
$title.appendTo($item);
|
||||
}
|
||||
$title.attr('title', item.title).find('.text').text(item.title);
|
||||
}
|
||||
|
||||
$item.attr('data-type', 'story').addClass('kanban-item-story');
|
||||
if(scaleSize <= 2)
|
||||
{
|
||||
var idHtml = scaleSize <= 1 ? ('<span class="info info-id text-muted">#' + item.id + '</span>') : '';
|
||||
var priHtml = '<span class="info info-pri label-pri label-pri-' + item.pri + '" title="' + item.pri + '">' + item.pri + '</span>';
|
||||
var hoursHtml = (item.estimate && scaleSize <= 1) ? ('<span class="info info-estimate text-muted">' + item.estimate + 'h</span>') : '';
|
||||
var avatarHtml = renderUserAvatar(item.assignedTo, 'story', item.id);
|
||||
var $infos = $item.find('.infos');
|
||||
if(!$infos.length) $infos = $('<div class="infos"></div>');
|
||||
$infos.html([idHtml, priHtml, hoursHtml].join(''));
|
||||
|
||||
return $item;
|
||||
$infos[scaleSize <= 1 ? 'append' : 'prepend'](avatarHtml);
|
||||
if(scaleSize <= 1) $infos.appendTo($item);
|
||||
else $infos.prependTo($item.find('.title'));
|
||||
}
|
||||
else if(scaleSize === 4)
|
||||
{
|
||||
$item.html(renderUserAvatar(item.assignedTo, 'story', item.id, 'md'));
|
||||
}
|
||||
|
||||
if(scaleSize <= 1)
|
||||
{
|
||||
var $actions = $item.find('.actions');
|
||||
if(!$actions.length && item.menus.length)
|
||||
{
|
||||
$actions = $([
|
||||
'<div class="actions">',
|
||||
'<a data-contextmenu="story" data-col="' + col.type + '">',
|
||||
'<i class="icon icon-ellipsis-v"></i>',
|
||||
'</a>',
|
||||
'</div>'
|
||||
].join('')).appendTo($item);
|
||||
}
|
||||
}
|
||||
|
||||
return $item.attr('data-type', 'story').addClass('kanban-item-story');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,44 +133,58 @@ function renderStoryItem(item, $item, col)
|
||||
*/
|
||||
function renderBugItem(item, $item, col)
|
||||
{
|
||||
var $title = $item.find('.title');
|
||||
if(!$title.length)
|
||||
{
|
||||
$title = $('<a class="title iframe" data-width="95%"><i class="icon icon-bug text-muted"></i> <span class="text"></span></a>')
|
||||
.attr('href', $.createLink('bug', 'view', 'bugID=' + item.id, '', true));
|
||||
$title.appendTo($item);
|
||||
}
|
||||
$title.attr('title', item.title).find('.text').text(item.title);
|
||||
var scaleSize = window.kanbanScaleSize;
|
||||
if(+$item.attr('data-scale-size') !== scaleSize) $item.empty().attr('data-scale-size', scaleSize);
|
||||
|
||||
var $infos = $item.find('.infos');
|
||||
if(!$infos.length)
|
||||
if(scaleSize <= 3)
|
||||
{
|
||||
$infos = $('<div class="infos"></div>').appendTo($item);
|
||||
}
|
||||
$infos.html(
|
||||
[
|
||||
'<span class="info info-id text-muted">#' + item.id + '</span>',
|
||||
'<span class="info info-severity label-severity" data-severity="' + item.severity + '" title="' + item.severity + '"></span>',
|
||||
'<span class="info info-pri label-pri label-pri-' + item.pri + '" title="' + item.pri + '">' + item.pri + '</span>',
|
||||
].join(''));
|
||||
if(item.deadline) $infos.append(renderDeadline(item.deadline));
|
||||
$infos.append(renderUserAvatar(item.assignedTo, 'bug', item.id));
|
||||
|
||||
var $actions = $item.find('.actions');
|
||||
if(!$actions.length && item.menus.length)
|
||||
{
|
||||
$actions = $([
|
||||
'<div class="actions">',
|
||||
'<a data-contextmenu="bug" data-col="' + col.type + '">',
|
||||
'<i class="icon icon-ellipsis-v"></i>',
|
||||
'</a>',
|
||||
'</div>'
|
||||
].join('')).appendTo($item);
|
||||
var $title = $item.find('.title');
|
||||
if(!$title.length)
|
||||
{
|
||||
$title = $('<a class="title iframe" data-width="95%">' + (scaleSize <= 1 ? '<i class="icon icon-bug text-muted"></i> ' : '') + '<span class="text"></span></a>')
|
||||
.attr('href', $.createLink('bug', 'view', 'bugID=' + item.id, '', true));
|
||||
$title.appendTo($item);
|
||||
}
|
||||
$title.attr('title', item.title).find('.text').text(item.title);
|
||||
}
|
||||
|
||||
$item.attr('data-type', 'bug').addClass('kanban-item-bug');
|
||||
if(scaleSize <= 2)
|
||||
{
|
||||
var idHtml = scaleSize <= 1 ? ('<span class="info info-id text-muted">#' + item.id + '</span>') : '';
|
||||
var severityHtml = scaleSize <= 1 ? ('<span class="info info-severity label-severity" data-severity="' + item.severity + '" title="' + item.severity + '"></span>') : '';
|
||||
var priHtml = '<span class="info info-pri label-pri label-pri-' + item.pri + '" title="' + item.pri + '">' + item.pri + '</span>';
|
||||
var avatarHtml = renderUserAvatar(item.assignedTo, 'bug', item.id);
|
||||
|
||||
return $item;
|
||||
var $infos = $item.find('.infos');
|
||||
if(!$infos.length) $infos = $('<div class="infos"></div>');
|
||||
$infos.html([idHtml, severityHtml, priHtml].join(''));
|
||||
if(item.deadline && scaleSize <= 1) $infos.append(renderDeadline(item.deadline));
|
||||
$infos[scaleSize <= 1 ? 'append' : 'prepend'](avatarHtml);
|
||||
|
||||
if(scaleSize <= 1) $infos.appendTo($item);
|
||||
else $infos.prependTo($item.find('.title'));
|
||||
}
|
||||
else if(scaleSize === 4)
|
||||
{
|
||||
$item.html(renderUserAvatar(item.assignedTo, 'bug', item.id, 'md'));
|
||||
}
|
||||
|
||||
if(scaleSize <= 1)
|
||||
{
|
||||
var $actions = $item.find('.actions');
|
||||
if(!$actions.length && item.menus.length)
|
||||
{
|
||||
$actions = $([
|
||||
'<div class="actions">',
|
||||
'<a data-contextmenu="bug" data-col="' + col.type + '">',
|
||||
'<i class="icon icon-ellipsis-v"></i>',
|
||||
'</a>',
|
||||
'</div>'
|
||||
].join('')).appendTo($item);
|
||||
}
|
||||
}
|
||||
|
||||
return $item.attr('data-type', 'bug').addClass('kanban-item-bug');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,39 +196,55 @@ function renderBugItem(item, $item, col)
|
||||
*/
|
||||
function renderTaskItem(item, $item, col)
|
||||
{
|
||||
var $title = $item.find('.title');
|
||||
if(!$title.length)
|
||||
{
|
||||
$title = $('<a class="title iframe" data-width="95%"><i class="icon icon-checked text-muted"></i> <span class="text"></span></a>')
|
||||
.attr('href', $.createLink('task', 'view', 'taskID=' + item.id, '', true));
|
||||
$title.appendTo($item);
|
||||
}
|
||||
$title.attr('title', item.name).find('.text').text(item.name);
|
||||
var scaleSize = window.kanbanScaleSize;
|
||||
if(+$item.attr('data-scale-size') !== scaleSize) $item.empty().attr('data-scale-size', scaleSize);
|
||||
|
||||
var $infos = $item.find('.infos');
|
||||
if(!$infos.length)
|
||||
if(scaleSize <= 3)
|
||||
{
|
||||
$infos = $('<div class="infos"></div>').appendTo($item);
|
||||
var $title = $item.find('.title');
|
||||
if(!$title.length)
|
||||
{
|
||||
$title = $('<a class="title iframe" data-width="95%">' + (scaleSize <= 1 ? '<i class="icon icon-checked text-muted"></i> ' : '') + '<span class="text"></span></a>')
|
||||
.attr('href', $.createLink('task', 'view', 'taskID=' + item.id, '', true));
|
||||
$title.appendTo($item);
|
||||
}
|
||||
$title.attr('title', item.name).find('.text').text(item.name);
|
||||
}
|
||||
$infos.html(
|
||||
[
|
||||
'<span class="info info-id text-muted">#' + item.id + '</span>',
|
||||
'<span class="info i nfo-pri label-pri label-pri-' + item.pri + '" title="' + item.pri + '">' + item.pri + '</span>',
|
||||
item.estimate ? '<span class="info info-estimate text-muted">' + item.estimate + 'h</span>' : '',
|
||||
].join(''));
|
||||
if(item.deadline) $infos.append(renderDeadline(item.deadline));
|
||||
$infos.append(renderUserAvatar(item.assignedTo, 'task', item.id));
|
||||
|
||||
var $actions = $item.find('.actions');
|
||||
if(!$actions.length && item.menus.length)
|
||||
if(scaleSize <= 2)
|
||||
{
|
||||
$actions = $([
|
||||
'<div class="actions">',
|
||||
'<a data-contextmenu="task" data-col="' + col.type + '">',
|
||||
'<i class="icon icon-ellipsis-v"></i>',
|
||||
'</a>',
|
||||
'</div>'
|
||||
].join('')).appendTo($item);
|
||||
var idHtml = scaleSize <= 1 ? ('<span class="info info-id text-muted">#' + item.id + '</span>') : '';
|
||||
var priHtml = '<span class="info info-pri label-pri label-pri-' + item.pri + '" title="' + item.pri + '">' + item.pri + '</span>';
|
||||
var hoursHtml = (item.estimate && scaleSize <= 1) ? ('<span class="info info-estimate text-muted">' + item.estimate + 'h</span>') : '';
|
||||
var avatarHtml = renderUserAvatar(item.assignedTo, 'task', item.id);
|
||||
|
||||
var $infos = $item.find('.infos');
|
||||
if(!$infos.length) $infos = $('<div class="infos"></div>');
|
||||
$infos.html([idHtml, priHtml, hoursHtml].join(''));
|
||||
if(item.deadline && scaleSize <= 1) $infos.append(renderDeadline(item.deadline));
|
||||
$infos[scaleSize <= 1 ? 'append' : 'prepend'](avatarHtml);
|
||||
|
||||
if(scaleSize <= 1) $infos.appendTo($item);
|
||||
else $infos.prependTo($item.find('.title'));
|
||||
}
|
||||
else if(scaleSize === 4)
|
||||
{
|
||||
$item.html(renderUserAvatar(item.assignedTo, 'task', item.id, 'md'));
|
||||
}
|
||||
|
||||
if(scaleSize <= 1)
|
||||
{
|
||||
var $actions = $item.find('.actions');
|
||||
if(!$actions.length && item.menus.length)
|
||||
{
|
||||
$actions = $([
|
||||
'<div class="actions">',
|
||||
'<a data-contextmenu="task" data-col="' + col.type + '">',
|
||||
'<i class="icon icon-ellipsis-v"></i>',
|
||||
'</a>',
|
||||
'</div>'
|
||||
].join('')).appendTo($item);
|
||||
}
|
||||
}
|
||||
|
||||
$item.attr('data-type', 'task').addClass('kanban-item-task');
|
||||
@@ -737,20 +781,57 @@ $.extend($.fn.kanban.Constructor.DEFAULTS,
|
||||
}
|
||||
});
|
||||
|
||||
/** Get card height */
|
||||
function getCardHeight()
|
||||
{
|
||||
return [59, 59, 62, 62, 47][window.kanbanScaleSize];
|
||||
}
|
||||
|
||||
/** Change kanban scale size */
|
||||
function changeKanbanScaleSize(newScaleSize)
|
||||
{
|
||||
var newScaleSize = Math.max(1, Math.min(4, newScaleSize));
|
||||
if(newScaleSize === window.kanbanScaleSize) return;
|
||||
|
||||
window.kanbanScaleSize = newScaleSize;
|
||||
$.zui.store.set('executionKanbanScaleSize', newScaleSize);
|
||||
$('#kanbanScaleSize').text(newScaleSize);
|
||||
$('#kanbanScaleControl .btn[data-type="+"]').attr('disabled', newScaleSize >= 4 ? 'disabled' : null);
|
||||
$('#kanbanScaleControl .btn[data-type="-"]').attr('disabled', newScaleSize <= 1 ? 'disabled' : null);
|
||||
|
||||
$('#kanbans').children('.kanban').each(function()
|
||||
{
|
||||
var kanban = $(this).data('zui.kanban');
|
||||
if(!kanban) return;
|
||||
kanban.setOptions({cardsPerRow: newScaleSize, cardHeight: getCardHeight()});
|
||||
});
|
||||
|
||||
return newScaleSize;
|
||||
}
|
||||
|
||||
/* Example code: */
|
||||
$(function()
|
||||
{
|
||||
$.cookie('isFullScreen', 0);
|
||||
|
||||
window.kanbanScaleSize = +$.zui.store.get('executionKanbanScaleSize', 1);
|
||||
$('#kanbanScaleSize').text(window.kanbanScaleSize);
|
||||
$('#kanbanScaleControl .btn[data-type="+"]').attr('disabled', window.kanbanScaleSize >= 4 ? 'disabled' : null);
|
||||
$('#kanbanScaleControl .btn[data-type="-"]').attr('disabled', window.kanbanScaleSize <= 1 ? 'disabled' : null);
|
||||
|
||||
/* Common options 用于初始化看板的通用选项 */
|
||||
var commonOptions =
|
||||
{
|
||||
maxColHeight: 'auto',
|
||||
minColWidth: 240,
|
||||
maxColWidth: 240,
|
||||
showCount: true,
|
||||
showZeroCount: true,
|
||||
fluidBoardWidth: true,
|
||||
maxColHeight: 'auto',
|
||||
minColWidth: 240,
|
||||
maxColWidth: 240,
|
||||
cardHeight: getCardHeight(),
|
||||
showCount: true,
|
||||
showZeroCount: true,
|
||||
fluidBoardWidth: false,
|
||||
cardsPerRow: window.kanbanScaleSize,
|
||||
virtualize: true,
|
||||
virtualRenderOptions: {container: '#kanbanContainer>.panel-body'},
|
||||
droppable:
|
||||
{
|
||||
target: findDropColumns,
|
||||
@@ -806,6 +887,12 @@ $(function()
|
||||
$.zui.ContextMenu.show(items, items.$options || {event: event});
|
||||
});
|
||||
|
||||
/* Make kanbanScaleControl works */
|
||||
$('#kanbanScaleControl').on('click', '.btn', function()
|
||||
{
|
||||
changeKanbanScaleSize(window.kanbanScaleSize + ($(this).data('type') === '+' ? 1 : -1));
|
||||
});
|
||||
|
||||
/* Resize kanban container on window resize */
|
||||
resizeKanbanContainer();
|
||||
$(window).on('resize', resizeKanbanContainer);
|
||||
@@ -823,18 +910,20 @@ $(function()
|
||||
{
|
||||
location.href = createLink('execution', 'importPlanStories', 'executionID=' + executionID + '&planID=' + planID + '&productID=0&fromMethod=kanban');
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$('#type_chosen .chosen-single span').prepend('<i class="icon-kanban"></i>');
|
||||
$('#group_chosen .chosen-single span').prepend(kanbanLang.laneGroup + ': ');
|
||||
|
||||
/* Ajax update kanban. */
|
||||
var lastUpdateData;
|
||||
setInterval(function()
|
||||
{
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy), function(data)
|
||||
{
|
||||
if(data)
|
||||
if(data && lastUpdateData !== lastUpdateData)
|
||||
{
|
||||
lastUpdateData = data;
|
||||
kanbanGroup = $.parseJSON(data);
|
||||
if(groupBy == 'default')
|
||||
{
|
||||
|
||||
@@ -28,8 +28,8 @@ $lang->execution->closedBy = 'ClosedBy';
|
||||
$lang->execution->closedDate = 'ClosedDate';
|
||||
$lang->execution->canceledBy = 'CanceledBy';
|
||||
$lang->execution->canceledDate = 'CanceledDate';
|
||||
$lang->execution->begin = 'Begin';
|
||||
$lang->execution->end = 'End';
|
||||
$lang->execution->begin = 'Planned Begin';
|
||||
$lang->execution->end = 'Planned End';
|
||||
$lang->execution->dateRange = 'Duration';
|
||||
$lang->execution->realBeganAB = 'Actual Begin';
|
||||
$lang->execution->realEndAB = 'Actual End';
|
||||
@@ -355,10 +355,7 @@ $lang->execution->unfinishedTask = "[%s] unfinished tasks. ";
|
||||
$lang->execution->unresolvedBug = "[%s] unresolved bugs. ";
|
||||
$lang->execution->projectNotEmpty = 'Project cannot be empty.';
|
||||
$lang->execution->confirmStoryToTask = $lang->SRCommon . '%s are converted to tasks in the current. Do you want to convert them anyways?';
|
||||
$lang->execution->realBeganNotEmpty = 'Actual Begin should not be empty.';
|
||||
$lang->execution->realBeganNotFuture = 'Actual Begin should be < = today.';
|
||||
$lang->execution->realEndNotEmpty = 'Actual End should not be empty.';
|
||||
$lang->execution->realEndNotFuture = 'Actual End should be < = today.';
|
||||
$lang->execution->ge = "『%s』should be >= actual begin『%s』.";
|
||||
|
||||
/* Statistics. */
|
||||
$lang->execution->charts = new stdclass();
|
||||
@@ -399,6 +396,7 @@ $lang->execution->bugList = "Bugs";
|
||||
$lang->execution->kanbanHideCols = 'Closed & Cancelled Columns';
|
||||
$lang->execution->kanbanShowOption = 'Unfold';
|
||||
$lang->execution->kanbanColsColor = 'Customize Column Color';
|
||||
$lang->execution->kanbanCardsUnit = 'X';
|
||||
|
||||
$lang->execution->kanbanViewList['all'] = 'All';
|
||||
$lang->execution->kanbanViewList['story'] = "{$lang->SRCommon}";
|
||||
|
||||
@@ -356,10 +356,7 @@ $lang->execution->unfinishedTask = "[%s]个未完成的任务,";
|
||||
$lang->execution->unresolvedBug = "[%s]个未解决的bug,";
|
||||
$lang->execution->projectNotEmpty = '所属项目不能为空。';
|
||||
$lang->execution->confirmStoryToTask = '%s' . $lang->SRCommon . '已经在当前' . $lang->execution->common . '中转了任务,请确认是否重复转任务。';
|
||||
$lang->execution->realBeganNotEmpty = "实际开始不能为空。";
|
||||
$lang->execution->realBeganNotFuture = "实际开始不能大于当前日期。";
|
||||
$lang->execution->realEndNotEmpty = "实际完成不能为空。";
|
||||
$lang->execution->realEndNotFuture = "实际完成不能大于当前日期。";
|
||||
$lang->execution->ge = "『%s』应当不小于实际开始时间『%s』。";
|
||||
|
||||
/* 统计。*/
|
||||
$lang->execution->charts = new stdclass();
|
||||
@@ -400,6 +397,7 @@ $lang->execution->bugList = "Bug列表";
|
||||
$lang->execution->kanbanHideCols = '看板隐藏已关闭、已取消列';
|
||||
$lang->execution->kanbanShowOption = '显示折叠信息';
|
||||
$lang->execution->kanbanColsColor = '看板列自定义颜色';
|
||||
$lang->execution->kanbanCardsUnit = '个';
|
||||
|
||||
$lang->execution->kanbanViewList['all'] = '综合看板';
|
||||
$lang->execution->kanbanViewList['story'] = "{$lang->SRCommon}看板";
|
||||
|
||||
+32
-27
@@ -608,6 +608,7 @@ class executionModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
$extendFields = $this->getFlowExtendFields();
|
||||
foreach($data->executionIDList as $executionID)
|
||||
{
|
||||
$executionName = $data->names[$executionID];
|
||||
@@ -644,6 +645,16 @@ class executionModel extends model
|
||||
if(isset($codeList[$executionCode])) dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->unique, $this->lang->project->code, $executionCode);
|
||||
$codeList[$executionCode] = $executionCode;
|
||||
}
|
||||
|
||||
foreach($extendFields as $extendField)
|
||||
{
|
||||
$executions[$executionID]->{$extendField->field} = $this->post->{$extendField->field}[$executionID];
|
||||
if(is_array($executions[$executionID]->{$extendField->field})) $executions[$executionID]->{$extendField->field} = join(',', $executions[$executionID]->{$extendField->field});
|
||||
|
||||
$executions[$executionID]->{$extendField->field} = htmlSpecialString($executions[$executionID]->{$extendField->field});
|
||||
$message = $this->checkFlowRule($extendField, $executions[$executionID]->{$extendField->field});
|
||||
if($message) die(js::alert($message));
|
||||
}
|
||||
}
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
@@ -715,21 +726,19 @@ class executionModel extends model
|
||||
->setDefault('status', 'doing')
|
||||
->setDefault('lastEditedBy', $this->app->user->account)
|
||||
->setDefault('lastEditedDate', $now)
|
||||
->remove('comment')->get();
|
||||
|
||||
if($execution->realBegan == '')
|
||||
{
|
||||
dao::$errors['realBegan'] = $this->lang->execution->realBeganNotEmpty;
|
||||
return false;
|
||||
}
|
||||
if($execution->realBegan > helper::today())
|
||||
{
|
||||
dao::$errors['realBegan'] = $this->lang->execution->realBeganNotFuture;
|
||||
return false;
|
||||
}
|
||||
->remove('comment')
|
||||
->get();
|
||||
|
||||
$this->dao->update(TABLE_EXECUTION)->data($execution)
|
||||
->autoCheck()
|
||||
->check($this->config->execution->start->requiredFields, 'notempty')
|
||||
->checkIF($execution->realBegan != '', 'realBegan', 'le', helper::today())
|
||||
->where('id')->eq((int)$executionID)
|
||||
->exec();
|
||||
|
||||
/* When it has multiple errors, only the first one is prompted */
|
||||
if(dao::isError() and count(dao::$errors['realBegan']) > 1) dao::$errors['realBegan'] = dao::$errors['realBegan'][0];
|
||||
|
||||
$this->dao->update(TABLE_EXECUTION)->data($execution)->autoCheck()->where('id')->eq((int)$executionID)->exec();
|
||||
|
||||
if(!dao::isError()) return common::createChanges($oldExecution, $execution);
|
||||
}
|
||||
|
||||
@@ -877,24 +886,20 @@ class executionModel extends model
|
||||
->setDefault('lastEditedDate', $now)
|
||||
->remove('comment')
|
||||
->get();
|
||||
|
||||
if($execution->realEnd == '')
|
||||
{
|
||||
dao::$errors['realEnd'] = $this->lang->execution->realEndNotEmpty;
|
||||
return false;
|
||||
}
|
||||
|
||||
if($execution->realEnd > helper::today())
|
||||
{
|
||||
dao::$errors['realEnd'] = $this->lang->execution->realEndNotFuture;
|
||||
return false;
|
||||
}
|
||||
$this->lang->error->ge = $this->lang->execution->ge;
|
||||
|
||||
$this->dao->update(TABLE_EXECUTION)->data($execution)
|
||||
->autoCheck()
|
||||
->check($this->config->execution->close->requiredFields,'notempty')
|
||||
->checkIF($execution->realEnd != '', 'realEnd', 'le', helper::today())
|
||||
->checkIF($execution->realEnd != '', 'realEnd', 'ge', $oldExecution->realBegan)
|
||||
->where('id')->eq((int)$executionID)
|
||||
->exec();
|
||||
|
||||
|
||||
/* When it has multiple errors, only the first one is prompted */
|
||||
if(dao::isError() and count(dao::$errors['realEnd']) > 1) dao::$errors['realEnd'] = dao::$errors['realEnd'][0];
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
$this->loadModel('score')->create('execution', 'close', $oldExecution);
|
||||
@@ -2957,7 +2962,7 @@ class executionModel extends model
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll();
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,6 +61,10 @@
|
||||
<th class='c-left text-right hours'><?php echo $lang->execution->totalLeft;?></th>
|
||||
<th class='c-progress'><?php echo $lang->execution->progress;?></th>
|
||||
<th class='c-burn'><?php echo $lang->execution->burn;?></th>
|
||||
<?php
|
||||
$extendFields = $this->execution->getFlowExtendFields();
|
||||
foreach($extendFields as $extendField) echo "<th rowspan='2'>{$extendField->name}</th>";
|
||||
?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class='sortable' id='executionTableList'>
|
||||
@@ -102,6 +106,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td id='spark-<?php echo $execution->id?>' class='sparkline text-left no-padding' values='<?php echo join(',', $execution->burns);?>'></td>
|
||||
<?php foreach($extendFields as $extendField) echo "<td>" . $this->loadModel('flow')->getFieldValue($extendField, $execution) . "</td>";?>
|
||||
</tr>
|
||||
<?php if(!empty($execution->children)):?>
|
||||
<?php $i = 0;?>
|
||||
@@ -140,6 +145,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td id='spark-<?php echo $child->id?>' class='sparkline text-left no-padding' values='<?php echo join(',', $child->burns);?>'></td>
|
||||
<?php foreach($extendFields as $extendField) echo "<td>" . $this->loadModel('flow')->getFieldValue($extendField, $child) . "</td>";?>
|
||||
</tr>
|
||||
<?php $i ++;?>
|
||||
<?php endforeach;?>
|
||||
|
||||
@@ -66,6 +66,10 @@
|
||||
<th class='c-desc <?php echo zget($visibleFields, 'desc', ' hidden') . zget($requiredFields, 'desc', '', ' required');?>'><?php echo $lang->execution->$desc;?></th>
|
||||
<th class='c-team-name <?php echo zget($visibleFields, 'teamname', ' hidden') . zget($requiredFields, 'teamname', '', ' required');?>'><?php echo $lang->execution->teamname;?></th>
|
||||
<th class='c-days<?php echo zget($visibleFields, 'days', ' hidden') . zget($requiredFields, 'days', '', ' required');?>'><?php echo $lang->execution->days;?></th>
|
||||
<?php
|
||||
$extendFields = $this->execution->getFlowExtendFields();
|
||||
foreach($extendFields as $extendField) echo "<th class='c-extend'>{$extendField->name}</th>";
|
||||
?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -110,6 +114,7 @@
|
||||
<span class='input-group-addon'><?php echo $lang->execution->day;?></span>
|
||||
</div>
|
||||
</td>
|
||||
<?php foreach($extendFields as $extendField) echo "<td" . (($extendField->control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->loadModel('flow')->getFieldControl($extendField, $executions[$executionID], $extendField->field . "[{$executionID}]") . "</td>";?>
|
||||
</tr>
|
||||
<?php
|
||||
if(isset($this->config->moreLinks["PMs[$executionID]"])) unset($this->config->moreLinks["PMs[$executionID]"]);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
$(function(){$(".preview").modalTrigger({width:1000, type:'iframe'});});
|
||||
var browseType = '<?php echo $browseType;?>';
|
||||
</script>
|
||||
<style>#importBugForm .bug-pri {overflow: visible;}</style>
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
<?php echo html::a(inlink('importBug', "executionID=$executionID"), "<span class='text'>{$lang->execution->importBug}</span>", '', "class='btn btn-link btn-active-text'");?>
|
||||
@@ -60,7 +61,7 @@ var browseType = '<?php echo $browseType;?>';
|
||||
<td><span class='label-pri <?php echo 'label-pri-' . $bug->pri;?>' title='<?php echo zget($lang->bug->priList, $bug->pri, $bug->pri)?>'><?php echo zget($lang->bug->priList, $bug->pri, $bug->pri)?></span></td>
|
||||
<td class='nobr'><?php common::printLink('bug', 'view', "bugID=$bug->id", $bug->title, '', "class='preview'", true, true);?></td>
|
||||
<td><span class='status-bug status-<?php echo $bug->status?>'><?php echo $this->processStatus('bug', $bug);?></span></td>
|
||||
<td style='overflow:visible'><?php echo html::select("pri[$bug->id]", $lang->task->priList, 3, "class='form-control chosen'");?></td>
|
||||
<td class='bug-pri'><?php echo html::select("pri[$bug->id]", $lang->task->priList, zget($lang->task->priList, $bug->pri ? $bug->pri : 3, 3), "class='form-control chosen'");?></td>
|
||||
<td style='overflow:visible'><?php echo html::select("assignedTo[$bug->id]", $users, zget($users, $bug->assignedTo, '', $bug->assignedTo), "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::input("estimate[$bug->id]", '', 'size=4 class="form-control"');?></td>
|
||||
<?php $deadline = ($bug->deadline > helper::today() and $bug->deadline > $execution->begin) ? $bug->deadline : '0000-00-00';?>
|
||||
|
||||
@@ -21,6 +21,17 @@
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<div class='input-group pull-left not-fix-input-group' id='kanbanScaleControl'>
|
||||
<span class='input-group-btn'>
|
||||
<button class='btn btn-icon' type='button' data-type='-'><i class='icon icon-minuse-solid-circle text-muted'></i></button>
|
||||
</span>
|
||||
<span class='input-group-addon'>
|
||||
<span id='kanbanScaleSize'>1</span><?php echo $lang->execution->kanbanCardsUnit; ?>
|
||||
</span>
|
||||
<span class='input-group-btn'>
|
||||
<button class='btn btn-icon' type='button' data-type='+'><i class='icon icon-plus-solid-circle text-muted'></i></button>
|
||||
</span>
|
||||
</div>
|
||||
<div class='btn-toolbar pull-right'>
|
||||
<?php
|
||||
$link = $this->createLink('task', 'export', "execution=$executionID&orderBy=$orderBy&type=kanban");
|
||||
@@ -52,7 +63,7 @@
|
||||
if(common::hasPriv('execution', 'printKanban')) echo '<li>' .html::a($this->createLink('execution', 'printKanban', "executionID=$executionID"), "<i class='icon-printer muted'></i> " . $lang->execution->printKanban, '', "class='iframe btn btn-link' id='printKanban' title='{$lang->execution->printKanban}' data-width='500'") . '</li>';
|
||||
echo '<li>' .html::a('javascript:fullScreen()', "<i class='icon-fullscreen muted'></i> " . $lang->execution->fullScreen, '', "class='btn btn-link' title='{$lang->execution->fullScreen}' data-width='500'") . '</li>';
|
||||
echo '</ul></div>';
|
||||
?>
|
||||
?>
|
||||
<?php
|
||||
$checkObject = new stdclass();
|
||||
$checkObject->execution = $executionID;
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<?php foreach($linkedBranches[$productID] as $branchID):?>
|
||||
<?php if(($execution->grade == 1 and in_array($productID, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches))) $attr = "disabled='disabled'";?>
|
||||
<?php if(($execution->grade == 1 and !(in_array($productID, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches)))) $attr = '';?>
|
||||
<?php $title = in_array($productID, $unmodifiableProducts) ? $lang->execution->notAllowRemoveProducts : $productName;?>
|
||||
<?php $title = (in_array($productID, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches)) ? $lang->execution->notAllowRemoveProducts : $productName;?>
|
||||
<?php $checked = 'checked';?>
|
||||
<div class='col-sm-4'>
|
||||
<div class='product <?php echo $checked . (isset($branchGroups[$productID]) ? ' has-branch' : '')?>'>
|
||||
|
||||
@@ -220,7 +220,7 @@
|
||||
<?php endif;?>
|
||||
<td class='c-pri'><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='c-name' title="<?php echo $story->title?>">
|
||||
<?php $showBranch = isset($this->config->execution->story->showBranch) ? $this->config->execution->story->showBranch : 1;?>
|
||||
<?php if($showBranch) $showBranch = isset($this->config->execution->story->showBranch) ? $this->config->execution->story->showBranch : 1;?>
|
||||
<?php if(isset($branchGroups[$story->product][$story->branch]) and $showBranch) echo "<span class='label label-outline label-badge'>" . $branchGroups[$story->product][$story->branch] . '</span>';?>
|
||||
<?php if(!empty($story->module) and isset($modulePairs[$story->module])) echo "<span class='label label-gray label-badge'>{$modulePairs[$story->module]}</span> ";?>
|
||||
<?php if($story->parent > 0) echo "<span class='label'>{$lang->story->childrenAB}</span>";?>
|
||||
|
||||
@@ -250,7 +250,7 @@ body {margin-bottom: 25px;}
|
||||
<tbody>
|
||||
<?php foreach($tasks as $task):?>
|
||||
<tr data-id='<?php echo $task->id;?>' data-status='<?php echo $task->status?>' data-estimate='<?php echo $task->estimate?>' data-consumed='<?php echo $task->consumed?>' data-left='<?php echo $task->left?>'>
|
||||
<?php foreach($customFields as $field) $this->task->printCell($field, $task, $users, $browseType, $branchGroups, $modulePairs, $useDatatable ? 'datatable' : 'table');?>
|
||||
<?php foreach($customFields as $field) $this->task->printCell($field, $task, $users, $browseType, $branchGroups, $modulePairs, $useDatatable ? 'datatable' : 'table', false, $showBranch);?>
|
||||
</tr>
|
||||
<?php if(!empty($task->children)):?>
|
||||
<?php $i = 0;?>
|
||||
@@ -258,7 +258,7 @@ body {margin-bottom: 25px;}
|
||||
<?php $class = $i == 0 ? ' table-child-top' : '';?>
|
||||
<?php $class .= ($i + 1 == count($task->children)) ? ' table-child-bottom' : '';?>
|
||||
<tr class='table-children<?php echo $class;?> parent-<?php echo $task->id;?>' data-id='<?php echo $child->id?>' data-status='<?php echo $child->status?>' data-estimate='<?php echo $child->estimate?>' data-consumed='<?php echo $child->consumed?>' data-left='<?php echo $child->left?>'>
|
||||
<?php foreach($customFields as $field) $this->task->printCell($field, $child, $users, $browseType, $branchGroups, $modulePairs, $useDatatable ? 'datatable' : 'table', true);?>
|
||||
<?php foreach($customFields as $field) $this->task->printCell($field, $child, $users, $browseType, $branchGroups, $modulePairs, $useDatatable ? 'datatable' : 'table', true, $showBranch);?>
|
||||
</tr>
|
||||
<?php $i ++;?>
|
||||
<?php endforeach;?>
|
||||
|
||||
@@ -115,7 +115,7 @@ class git extends control
|
||||
}
|
||||
foreach($logs as $log)
|
||||
{
|
||||
$parsedLogs[] = $this->convertLog($log);
|
||||
$parsedLogs[] = $this->git->convertLog($log);
|
||||
}
|
||||
|
||||
$this->loadModel('repo');
|
||||
|
||||
@@ -118,7 +118,7 @@ class gitModel extends model
|
||||
*/
|
||||
public function updateCommit($repo, $commentGroup, $printLog = true)
|
||||
{
|
||||
/* Load mudule and print log. */
|
||||
/* Load module and print log. */
|
||||
$this->loadModel('repo');
|
||||
if($printLog) $this->printLog("begin repo $repo->id");
|
||||
|
||||
@@ -146,7 +146,7 @@ class gitModel extends model
|
||||
}
|
||||
|
||||
$version = (int)$lastInDB->commit + 1;
|
||||
$logs = $this->repo->getUnsyncCommits($repo);
|
||||
$logs = $this->repo->getUnsyncedCommits($repo);
|
||||
$objects = array();
|
||||
if(!empty($logs))
|
||||
{
|
||||
@@ -198,7 +198,7 @@ class gitModel extends model
|
||||
* Set the repos.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
* @return mixed
|
||||
*/
|
||||
public function setRepos()
|
||||
{
|
||||
@@ -230,9 +230,9 @@ class gitModel extends model
|
||||
*/
|
||||
public function getRepos()
|
||||
{
|
||||
$repos = $this->setRepos();
|
||||
$this->setRepos();
|
||||
$repoPairs = array();
|
||||
foreach($repos as $repo) $repoPairs[] = $repo->path;
|
||||
foreach($this->repos as $repo) $repoPairs[] = $repo->path;
|
||||
|
||||
return $repoPairs;
|
||||
}
|
||||
@@ -284,7 +284,7 @@ class gitModel extends model
|
||||
*
|
||||
* @param object $repo
|
||||
* @access public
|
||||
* @return void
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRepoTags($repo)
|
||||
{
|
||||
|
||||
+601
-5
@@ -75,7 +75,7 @@ class gitlab extends control
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browse')));
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->create;
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->lblCreate;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -214,9 +214,9 @@ class gitlab extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function delete($id, $confim = 'no')
|
||||
public function delete($id, $confirm = 'no')
|
||||
{
|
||||
if($confim != 'yes') die(js::confirm($this->lang->gitlab->confirmDelete, inlink('delete', "id=$id&confirm=yes")));
|
||||
if($confirm != 'yes') die(js::confirm($this->lang->gitlab->confirmDelete, inlink('delete', "id=$id&confirm=yes")));
|
||||
|
||||
$oldGitLab = $this->gitlab->getByID($id);
|
||||
$this->loadModel('action');
|
||||
@@ -292,6 +292,426 @@ class gitlab extends control
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse gitlab group.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function browseGroup($gitlabID, $orderBy = 'name_asc')
|
||||
{
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->browseGroup;
|
||||
$this->view->gitlabID = $gitlabID;
|
||||
$this->view->gitlabGroupList = $this->gitlab->apiGetGroups($gitlabID, $orderBy);
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creat a gitlab group.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function createGroup($gitlabID)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
$this->gitlab->createGroup($gitlabID);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browseGroup', "gitlabID=$gitlabID")));
|
||||
}
|
||||
|
||||
$gitlab = $this->gitlab->getByID($gitlabID);
|
||||
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->group->create;
|
||||
$this->view->gitlab = $gitlab;
|
||||
$this->view->gitlabID = $gitlabID;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a gitlab group.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $userID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function editGroup($gitlabID, $groupID)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
$this->gitlab->editGroup($gitlabID);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browseGroup', "gitlabID=$gitlabID")));
|
||||
}
|
||||
|
||||
$gitlab = $this->gitlab->getByID($gitlabID);
|
||||
$group = $this->gitlab->apiGetSingleGroup($gitlabID, $groupID);
|
||||
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->group->edit;
|
||||
$this->view->gitlab = $gitlab;
|
||||
$this->view->group = $group;
|
||||
$this->view->gitlabID = $gitlabID;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gitlab group.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $groupID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function deleteGroup($gitlabID, $groupID, $confirm = 'no')
|
||||
{
|
||||
if($confirm != 'yes') die(js::confirm($this->lang->gitlab->group->confirmDelete , inlink('deleteGroup', "gitlabID=$gitlabID&groupID=$groupID&confirm=yes")));
|
||||
|
||||
$group = $this->gitlab->apiGetSingleGroup($gitlabID, $groupID);
|
||||
$reponse = $this->gitlab->apiDeleteGroup($gitlabID, $groupID);
|
||||
|
||||
/* If the status code beginning with 20 is returned or empty is returned, it is successful. */
|
||||
if(!$reponse or substr($reponse->message, 0, 2) == '20')
|
||||
{
|
||||
$this->loadModel('action')->create('gitlabgroup', $groupID, 'deleted', '', $group->name);
|
||||
die(js::reload('parent'));
|
||||
}
|
||||
|
||||
die(js::alert($reponse->message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage a gitlab group members.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $groupID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function manageGroupMembers($gitlabID, $groupID)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
$data = fixer::input('post')->get();
|
||||
|
||||
$ids = array_filter($data->ids);
|
||||
if(count($ids) != count(array_unique($ids))) return $this->send(array('result' => 'fail', 'message' => $this->lang->gitlab->group->repeatError));
|
||||
$newMembers = array();
|
||||
foreach($ids as $key => $id)
|
||||
{
|
||||
/* Check whether each member has selected accesslevel. */
|
||||
if(empty($data->levels[$key])) return $this->send(array('result' => 'fail', 'message' => $this->lang->gitlab->group->memberAccessLevel . $this->lang->gitlab->group->emptyError ));
|
||||
|
||||
$newMembers[$id] = (object)array('access_level'=>$data->levels[$key], 'expires_at'=>$data->expires[$key]);
|
||||
}
|
||||
|
||||
$currentMembers = $this->gitlab->apiGetGroupMembers($gitlabID, $groupID);
|
||||
|
||||
/* Get the updated,deleted data. */
|
||||
$addedMembers = $deletedMembers = $updatedMembers = array();
|
||||
foreach($currentMembers as $currentMember)
|
||||
{
|
||||
$memberID = $currentMember->id;
|
||||
if(empty($newMembers[$memberID]))
|
||||
{
|
||||
$deletedMembers[] = $memberID;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($newMembers[$memberID]->access_level != $currentMember->access_level or $newMembers[$memberID]->expires_at != $currentMember->expires_at)
|
||||
{
|
||||
$updatedData = new stdClass();
|
||||
$updatedData->user_id = $memberID;
|
||||
$updatedData->access_level = $newMembers[$memberID]->access_level;
|
||||
$updatedData->expires_at = $newMembers[$memberID]->expires_at;
|
||||
$updatedMembers[] = $updatedData;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Get the added data. */
|
||||
foreach($newMembers as $id => $newMember)
|
||||
{
|
||||
$exist = false;
|
||||
foreach($currentMembers as $currentMember)
|
||||
{
|
||||
if($currentMember->id == $id)
|
||||
{
|
||||
$exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if($exist == false)
|
||||
{
|
||||
$addedData = new stdClass();
|
||||
$addedData->user_id = $id;
|
||||
$addedData->access_level = $newMembers[$id]->access_level;
|
||||
$addedData->expires_at = $newMembers[$id]->expires_at;
|
||||
$addedMembers[] = $addedData;
|
||||
}
|
||||
}
|
||||
|
||||
foreach($addedMembers as $addedMember)
|
||||
{
|
||||
$this->gitlab->apiCreateGroupMember($gitlabID, $groupID, $addedMember);
|
||||
}
|
||||
|
||||
foreach($updatedMembers as $updatedMember)
|
||||
{
|
||||
$this->gitlab->apiUpdateGroupMember($gitlabID, $groupID, $updatedMember);
|
||||
}
|
||||
|
||||
foreach($deletedMembers as $deletedMemberID)
|
||||
{
|
||||
$this->gitlab->apiDeleteGroupMember($gitlabID, $groupID, $deletedMemberID);
|
||||
}
|
||||
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browseGroup', "gitlabID=$gitlabID")));
|
||||
}
|
||||
|
||||
/* Get gitlab users data. */
|
||||
$gitlabUserList = $this->gitlab->apiGetUsers($gitlabID, true);
|
||||
$gitlabUsers = array(''=>'');
|
||||
foreach($gitlabUserList as $gitlabUser)
|
||||
{
|
||||
$gitlabUsers[$gitlabUser->id] = $gitlabUser->realname;
|
||||
}
|
||||
|
||||
$accessLevels = $this->lang->gitlab->accessLevels;
|
||||
$currentMembers = $this->gitlab->apiGetGroupMembers($gitlabID, $groupID);
|
||||
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->group->manageMembers;
|
||||
$this->view->currentMembers = $currentMembers;
|
||||
$this->view->gitlabUsers = $gitlabUsers;
|
||||
$this->view->gitlabID = $gitlabID;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse gitlab user.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function browseUser($gitlabID, $orderBy = 'id_desc')
|
||||
{
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->browseUser;
|
||||
$this->view->gitlabID = $gitlabID;
|
||||
$this->view->gitlabUserList = $this->gitlab->apiGetUsers($gitlabID, false, $orderBy);
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creat a gitlab user.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function createUser($gitlabID)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
$this->gitlab->createUser($gitlabID);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browseUser', "gitlabID=$gitlabID")));
|
||||
}
|
||||
|
||||
$userPairs = $this->loadModel('user')->getPairs('noclosed|noletter');
|
||||
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->user->create;
|
||||
$this->view->userPairs = $userPairs;
|
||||
$this->view->gitlabID = $gitlabID;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a gitlab user.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $userID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function editUser($gitlabID, $userID)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
$this->gitlab->editUser($gitlabID);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browseUser', "gitlabID=$gitlabID")));
|
||||
}
|
||||
|
||||
$userPairs = $this->loadModel('user')->getPairs('noclosed|noletter');
|
||||
$user = $this->gitlab->apiGetSingleUser($gitlabID, $userID);
|
||||
$zentaoBindAccount = $this->dao->select('account')->from(TABLE_OAUTH)->where('providerType')->eq('gitlab')->andWhere('providerID')->eq($gitlabID)->andWhere('openID')->eq($user->id)->fetch('account');
|
||||
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->user->edit;
|
||||
$this->view->user = $user;
|
||||
$this->view->userPairs = $userPairs;
|
||||
$this->view->zentaoBindAccount = $zentaoBindAccount;
|
||||
$this->view->gitlabID = $gitlabID;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gitlab user.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $userID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function deleteUser($gitlabID, $userID, $confirm = 'no')
|
||||
{
|
||||
if($confirm != 'yes') die(js::confirm($this->lang->gitlab->user->confirmDelete , inlink('deleteUser', "gitlabID=$gitlabID&userID=$userID&confirm=yes")));
|
||||
|
||||
$user = $this->gitlab->apiGetSingleUser($gitlabID, $userID);
|
||||
$reponse = $this->gitlab->apiDeleteUser($gitlabID, $userID);
|
||||
|
||||
/* If the status code beginning with 20 is returned or empty is returned, it is successful. */
|
||||
if(!$reponse or substr($reponse->message, 0, 2) == '20')
|
||||
{
|
||||
$this->loadModel('action')->create('gitlabuser', $userID, 'deleted', '', $user->name);
|
||||
|
||||
/* Delete user bind. */
|
||||
$this->dao->delete()->from(TABLE_OAUTH)->where('providerType')->eq('gitlab')->andWhere('providerID')->eq($gitlabID)->andWhere('openID')->eq($userID)->exec();
|
||||
|
||||
die(js::reload('parent'));
|
||||
}
|
||||
|
||||
die(js::alert($reponse->message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse gitlab project.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param string $keyword
|
||||
* @param int $recTotal
|
||||
* @param int $recPerPage
|
||||
* @param int $pageID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function browseProject($gitlabID, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
|
||||
{
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
$keyword = fixer::input('post')->setDefault('keyword', '')->get('keyword'); // Fix bug#16741.
|
||||
|
||||
$result = $this->gitlab->apiGetProjectsPager($gitlabID, $keyword, $orderBy, $pager);
|
||||
|
||||
$gitlab = $this->gitlab->getByID($gitlabID);
|
||||
|
||||
$this->view->gitlab = $gitlab;
|
||||
$this->view->keyword = urldecode(urldecode($keyword));
|
||||
$this->view->pager = $result['pager'];
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->browseProject;
|
||||
$this->view->gitlabID = $gitlabID;
|
||||
$this->view->gitlabProjectList = $result['projects'];
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creat a gitlab project.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function createProject($gitlabID)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
$this->gitlab->createProject($gitlabID);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browseProject', "gitlabID=$gitlabID")));
|
||||
}
|
||||
|
||||
$gitlab = $this->gitlab->getByID($gitlabID);
|
||||
$user = $this->gitlab->apiGetCurrentUser($gitlab->url, $gitlab->token);
|
||||
|
||||
/* Get namespaces data */
|
||||
$namespacesList = $this->gitlab->apiGetNamespaces($gitlabID);
|
||||
$namespaces = array();
|
||||
foreach($namespacesList as $namespace)
|
||||
{
|
||||
if($namespace->kind == 'user' and $namespace->path == $user->username) $namespaces[$namespace->id] = $namespace->path;
|
||||
if($namespace->kind == 'group') $namespaces[$namespace->id] = $namespace->path;
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->project->create;
|
||||
$this->view->gitlab = $gitlab;
|
||||
$this->view->user = $user;
|
||||
$this->view->namespaces = $namespaces;
|
||||
$this->view->gitlabID = $gitlabID;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a gitlab project.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function editProject($gitlabID, $projectID)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
$this->gitlab->editProject($gitlabID);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browseProject', "gitlabID=$gitlabID")));
|
||||
}
|
||||
|
||||
$project = $this->gitlab->apiGetSingleProject($gitlabID, $projectID);
|
||||
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->project->edit;
|
||||
$this->view->project = $project;
|
||||
$this->view->gitlabID = $gitlabID;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gitlab project.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function deleteProject($gitlabID, $projectID, $confirm = 'no')
|
||||
{
|
||||
if($confirm != 'yes') die(js::confirm($this->lang->gitlab->project->confirmDelete , inlink('deleteProject', "gitlabID=$gitlabID&projectID=$projectID&confirm=yes")));
|
||||
|
||||
$project = $this->gitlab->apiGetSingleProject($gitlabID, $projectID);
|
||||
$reponse = $this->gitlab->apiDeleteProject($gitlabID, $projectID);
|
||||
|
||||
/* If the status code beginning with 20 is returned or empty is returned, it is successful. */
|
||||
if(!$reponse or substr($reponse->message, 0, 2) == '20')
|
||||
{
|
||||
$this->loadModel('action')->create('gitlabproject', $projectID, 'deleted', '', $project->name);
|
||||
die(js::reload('parent'));
|
||||
}
|
||||
|
||||
die(js::alert($reponse->message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Import gitlab issue to zentaopms.
|
||||
*
|
||||
@@ -307,8 +727,8 @@ class gitlab extends control
|
||||
$projectID = $repo->project;
|
||||
|
||||
$gitlab = $this->gitlab->getByID($gitlabID);
|
||||
$user = $this->gitlab->apiGetCurrentUser($gitlab->url, $gitlab->token);
|
||||
if(!isset($user->is_admin) or !$user->is_admin) die(js::alert($this->lang->gitlab->tokenLimit) . js::locate($this->createLink('gitlab', 'edit', array('gitlabID' => $gitlabID))));
|
||||
if($gitlab) $user = $this->gitlab->apiGetCurrentUser($gitlab->url, $gitlab->token);
|
||||
if(empty($user->is_admin)) die(js::alert($this->lang->gitlab->tokenLimit) . js::locate($this->createLink('gitlab', 'edit', array('gitlabID' => $gitlabID))));
|
||||
|
||||
|
||||
if($_POST)
|
||||
@@ -368,6 +788,7 @@ class gitlab extends control
|
||||
|
||||
/* 'not[iids]' option in gitlab API has a issue when iids is too long. */
|
||||
$gitlabIssues = $this->gitlab->apiGetIssues($gitlabID, $projectID, '&state=opened');
|
||||
if(!is_array($gitlabIssues)) $gitlabIssues = array();
|
||||
foreach($gitlabIssues as $index => $issue)
|
||||
{
|
||||
foreach($savedIssueIDList as $savedIssueID)
|
||||
@@ -395,6 +816,181 @@ class gitlab extends control
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Webhook by repoID.
|
||||
*
|
||||
* @param int $repoID
|
||||
* @param string $confirm
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function createWebhook($repoID, $confirm = 'no')
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
die(js::confirm($this->lang->gitlab->confirmAddWebhook, $this->createLink('gitlab', 'createWebhook', "repoID=$repoID&confirm=yes")));
|
||||
}
|
||||
else
|
||||
{
|
||||
$repo = $this->loadModel('repo')->getRepoByID($repoID);
|
||||
$res = $this->gitlab->addPushWebhook($repo);
|
||||
|
||||
if($res or is_array($res))
|
||||
{
|
||||
die(js::alert($this->lang->gitlab->addWebhookSuccess));
|
||||
}
|
||||
else
|
||||
{
|
||||
die(js::error($this->lang->gitlab->failCreateWebhook));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage a gitlab project members.
|
||||
*
|
||||
* @param int $repoID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function manageProjectMembers($repoID)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
$data = fixer::input('post')->get();
|
||||
|
||||
$accounts = array_filter($data->accounts);
|
||||
if(count($accounts) != count(array_unique($accounts))) return $this->send(array('result' => 'fail', 'message' => $this->lang->gitlab->group->repeatError));
|
||||
|
||||
$repo = $this->loadModel('repo')->getRepoByID($repoID);
|
||||
$users = $this->loadModel('user')->getPairs('noletter|noempty|nodeleted');
|
||||
$bindedUsers = $this->dao->select('account,openID')
|
||||
->from(TABLE_OAUTH)
|
||||
->where('providerType')->eq('gitlab')
|
||||
->andWhere('providerID')->eq($repo->gitlab)
|
||||
->fetchPairs();
|
||||
|
||||
if(empty($repo->acl))
|
||||
{
|
||||
$repo->acl = new stdClass();
|
||||
$repo->acl->users = array();
|
||||
}
|
||||
|
||||
$newGitlabMembers = array();
|
||||
foreach($accounts as $key => $account)
|
||||
{
|
||||
/* If the user has set permissions, check whether they are bound. */
|
||||
if(!empty($data->levels[$key]))
|
||||
{
|
||||
if(!isset($bindedUsers[$account])) return $this->send(array('result' => 'fail', 'message' => $users[$account] . ' ' . $this->lang->gitlab->project->notbindedError));
|
||||
$newGitlabMembers[$bindedUsers[$account]] = (object) array('access_level' => $data->levels[$key], 'expires_at' => $data->expires[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$gitlabCurrentMembers = $this->gitlab->apiGetProjectMembers($repo->gitlab, $repo->project);
|
||||
|
||||
$addedMembers = $updatedMembers = $deletedMembers = array();
|
||||
/* Get the updated data. */
|
||||
foreach($gitlabCurrentMembers as $gitlabCurrentMember)
|
||||
{
|
||||
$memberID = $gitlabCurrentMember->id;
|
||||
if(!isset($newGitlabMembers[$memberID])) continue;
|
||||
if($newGitlabMembers[$memberID]->access_level != $gitlabCurrentMember->access_level or $newGitlabMembers[$memberID]->expires_at != $gitlabCurrentMember->expires_at)
|
||||
{
|
||||
$updatedData = new stdClass();
|
||||
$updatedData->user_id = $memberID;
|
||||
$updatedData->access_level = $newGitlabMembers[$memberID]->access_level;
|
||||
$updatedData->expires_at = $newGitlabMembers[$memberID]->expires_at;
|
||||
$updatedMembers[] = $updatedData;
|
||||
}
|
||||
}
|
||||
/* Get the added data. */
|
||||
foreach($newGitlabMembers as $id => $newMember)
|
||||
{
|
||||
$exist = false;
|
||||
foreach($gitlabCurrentMembers as $gitlabCurrentMember)
|
||||
{
|
||||
if($gitlabCurrentMember->id == $id)
|
||||
{
|
||||
$exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if($exist == false)
|
||||
{
|
||||
$addedData = new stdClass();
|
||||
$addedData->user_id = $id;
|
||||
$addedData->access_level = $newGitlabMembers[$id]->access_level;
|
||||
$addedData->expires_at = $newGitlabMembers[$id]->expires_at;
|
||||
$addedMembers[] = $addedData;
|
||||
}
|
||||
}
|
||||
/* Get the deleted data. */
|
||||
$originalUsers = $repo->acl->users;
|
||||
foreach($originalUsers as $user)
|
||||
{
|
||||
if(!in_array($user, $accounts) and isset($bindedUsers[$user]))
|
||||
{
|
||||
$exist = false;
|
||||
foreach($gitlabCurrentMembers as $gitlabCurrentMember)
|
||||
{
|
||||
if($gitlabCurrentMember->id == $bindedUsers[$user])
|
||||
{
|
||||
$exist = true;
|
||||
$deletedMembers[] = $gitlabCurrentMember->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($addedMembers as $addedMember)
|
||||
{
|
||||
$this->gitlab->apiCreateProjectMember($repo->gitlab, $repo->project, $addedMember);
|
||||
}
|
||||
|
||||
foreach($updatedMembers as $updatedMember)
|
||||
{
|
||||
$this->gitlab->apiUpdateProjectMember($repo->gitlab, $repo->project, $updatedMember);
|
||||
}
|
||||
|
||||
foreach($deletedMembers as $deletedMemberID)
|
||||
{
|
||||
$this->gitlab->apiDeleteProjectMember($repo->gitlab, $repo->project, $deletedMemberID);
|
||||
}
|
||||
|
||||
$repo->acl->users = array_values($accounts);
|
||||
$this->dao->update(TABLE_REPO)->data(array('acl'=>json_encode($repo->acl)))->where('id')->eq($repoID)->exec();
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => helper::createLink('repo', 'maintain')));
|
||||
}
|
||||
|
||||
$repo = $this->loadModel('repo')->getRepoByID($repoID);
|
||||
$users = $this->loadModel('user')->getPairs('noletter|noempty|nodeleted|noclosed');
|
||||
$projectMembers = $this->gitlab->apiGetProjectMembers($repo->gitlab, $repo->project);
|
||||
|
||||
/* Get users accesslevel. */
|
||||
$userAccessData = array();
|
||||
$bindedUsers = $this->dao->select('openID,account')
|
||||
->from(TABLE_OAUTH)
|
||||
->where('providerType')->eq('gitlab')
|
||||
->andWhere('providerID')->eq($repo->gitlab)
|
||||
->fetchPairs();
|
||||
foreach($projectMembers as $projectMember)
|
||||
{
|
||||
if(isset($bindedUsers[$projectMember->id]))
|
||||
{
|
||||
$account = $bindedUsers[$projectMember->id];
|
||||
$userAccessData[$account] = $projectMember;
|
||||
}
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->manageProjectMembers;
|
||||
$this->view->userAccessData = $userAccessData;
|
||||
$this->view->users = $users;
|
||||
$this->view->repo = $repo;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Get executions by productID.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
.text-c-name > .avatar {vertical-align: middle;display: inline-block;margin-right: 5px;}
|
||||
.text-c-name > span {vertical-align: middle;}
|
||||
@@ -0,0 +1,2 @@
|
||||
.text-c-counts > span {margin-left: 5px;}
|
||||
#mainMenu .pull-left {margin-right: 15px;}
|
||||
@@ -0,0 +1 @@
|
||||
.table-form>tbody>tr>th {width: 110px;}
|
||||
@@ -0,0 +1,4 @@
|
||||
#avatarUpload {display: inline-block; width: 50px; height: 50px; position: relative;}
|
||||
#avatarUploadBtn {display: block; position: absolute; top: 0; left: 0; right: 0; bottom: 0;}
|
||||
#avatarUploadBtn {opacity: 0; color: #fff; border-radius: 50%; line-height: 50px;}
|
||||
#avatarUploadBtn:hover {opacity: 1; background-color: rgba(0,0,0,.5);}
|
||||
@@ -0,0 +1 @@
|
||||
.table-form>tbody>tr>th {width: 110px;}
|
||||
@@ -0,0 +1,4 @@
|
||||
#avatarUpload {display: inline-block; width: 50px; height: 50px; position: relative;}
|
||||
#avatarUploadBtn {display: block; position: absolute; top: 0; left: 0; right: 0; bottom: 0;}
|
||||
#avatarUploadBtn {opacity: 0; color: #fff; border-radius: 50%; line-height: 50px;}
|
||||
#avatarUploadBtn:hover {opacity: 1; background-color: rgba(0,0,0,.5);}
|
||||
@@ -0,0 +1,17 @@
|
||||
$(document).ready(function()
|
||||
{
|
||||
$('#projectSearch').click(function()
|
||||
{
|
||||
triggerSearch();
|
||||
});
|
||||
$('#keyword').keypress(function(event)
|
||||
{
|
||||
if(event.which == 13) triggerSearch();
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
function triggerSearch()
|
||||
{
|
||||
$("#gitlabprojectForm").submit();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* set avatar event
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setAvatar()
|
||||
{
|
||||
$('#avatarUploadBtn').on('click', function()
|
||||
{
|
||||
$('#files').click();
|
||||
});
|
||||
$("#files").change(function(){
|
||||
var files = this.files;
|
||||
if(!files.length) return;
|
||||
|
||||
$(".avatar img").attr("src", window.URL.createObjectURL(files[0]));
|
||||
$(".avatar").removeClass('hidden');
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
$("#name").bind("input propertychange", function(event){
|
||||
$("#path").val($(this).val().toLowerCase());
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
$(document).ready(function()
|
||||
{
|
||||
setAvatar();
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
$(document).ready(function()
|
||||
{
|
||||
setAvatar();
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Save team members.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function saveMembers()
|
||||
{
|
||||
$('#saveBtn').addClass('hidden');
|
||||
$('#submit').removeClass('hidden');
|
||||
$('#submit').click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item.
|
||||
*
|
||||
* @param object $obj
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function addItem(obj)
|
||||
{
|
||||
var item = $('#addItem').html().replace(/%i%/g, i);
|
||||
$(obj).closest('tr').after('<tr class="addedItem">' + item + '</tr>');
|
||||
var selects = $(obj).closest('tr').next('tr').find('select');
|
||||
selects.each(function()
|
||||
{
|
||||
$(this).trigger('liszt:updated');
|
||||
$(this).chosen();
|
||||
});
|
||||
$(obj).closest('tr').next('tr').find('.form-date').datetimepicker();
|
||||
i ++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete item.
|
||||
*
|
||||
* @param object $obj
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function deleteItem(obj)
|
||||
{
|
||||
if($('#teamForm .table tbody').children().length < 2) return false;
|
||||
$(obj).closest('tr').remove();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Save team members.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function saveMembers()
|
||||
{
|
||||
$('#saveBtn').addClass('hidden');
|
||||
$('#submit').removeClass('hidden');
|
||||
$('#submit').click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item.
|
||||
*
|
||||
* @param object $obj
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function addItem(obj)
|
||||
{
|
||||
var item = $('#addItem').html().replace(/%i%/g, i);
|
||||
$(obj).closest('tr').after('<tr class="addedItem">' + item + '</tr>');
|
||||
var selects = $(obj).closest('tr').next('tr').find('select');
|
||||
selects.each(function()
|
||||
{
|
||||
$(this).trigger('liszt:updated');
|
||||
$(this).chosen();
|
||||
});
|
||||
$(obj).closest('tr').next('tr').find('.form-date').datetimepicker();
|
||||
i ++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete item.
|
||||
*
|
||||
* @param object $obj
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function deleteItem(obj)
|
||||
{
|
||||
if($('#teamForm .table tbody').children().length < 2) return false;
|
||||
$(obj).closest('tr').remove();
|
||||
}
|
||||
+141
-25
@@ -1,28 +1,49 @@
|
||||
<?php
|
||||
$lang->gitlab = new stdclass;
|
||||
$lang->gitlab->common = 'GitLab';
|
||||
$lang->gitlab->browse = 'GitLab Browse';
|
||||
$lang->gitlab->create = 'Create GitLab';
|
||||
$lang->gitlab->edit = 'Edit GitLab';
|
||||
$lang->gitlab->view = 'View GitLab';
|
||||
$lang->gitlab->bindUser = 'Bind User';
|
||||
$lang->gitlab->webhook = 'webhook';
|
||||
$lang->gitlab->bindProduct = 'Import Product';
|
||||
$lang->gitlab->importIssue = 'Import Issue';
|
||||
$lang->gitlab->delete = 'Delete GitLab';
|
||||
$lang->gitlab->confirmDelete = 'Do you want to delete this GitLab server?';
|
||||
$lang->gitlab->gitlabAccount = 'GitLab Account';
|
||||
$lang->gitlab->zentaoAccount = 'Zentao Account';
|
||||
$lang->gitlab->bindingStatus = 'Binding Status';
|
||||
$lang->gitlab->binded = 'Binded';
|
||||
$lang->gitlab->serverFail = 'Connect to GitLab server failed, please check the GitLab server.';
|
||||
$lang->gitlab->common = 'GitLab';
|
||||
$lang->gitlab->browse = 'GitLab Browse';
|
||||
$lang->gitlab->search = 'Search';
|
||||
$lang->gitlab->create = 'Create GitLab';
|
||||
$lang->gitlab->edit = 'Edit GitLab';
|
||||
$lang->gitlab->view = 'View GitLab';
|
||||
$lang->gitlab->bindUser = 'Bind User';
|
||||
$lang->gitlab->webhook = 'webhook';
|
||||
$lang->gitlab->bindProduct = 'Import Product';
|
||||
$lang->gitlab->importIssue = 'Import Issue';
|
||||
$lang->gitlab->delete = 'Delete GitLab';
|
||||
$lang->gitlab->confirmDelete = 'Do you want to delete this GitLab server?';
|
||||
$lang->gitlab->gitlabAccount = 'GitLab Account';
|
||||
$lang->gitlab->zentaoAccount = 'Zentao Account';
|
||||
$lang->gitlab->bindingStatus = 'Binding Status';
|
||||
$lang->gitlab->binded = 'Binded';
|
||||
$lang->gitlab->serverFail = 'Connect to GitLab server failed, please check the GitLab server.';
|
||||
$lang->gitlab->lastUpdate = 'Last Update';
|
||||
$lang->gitlab->confirmAddWebhook = 'Are you sure about creating Webhook?';
|
||||
$lang->gitlab->addWebhookSuccess = 'Webhook created successfully';
|
||||
$lang->gitlab->failCreateWebhook = 'Failed to create Webhook, please view the log';
|
||||
$lang->gitlab->placeholderSearch = 'Project name';
|
||||
|
||||
$lang->gitlab->browseAction = 'GitLab List';
|
||||
$lang->gitlab->deleteAction = 'Delete GitLab';
|
||||
$lang->gitlab->gitlabProject = "GitLab Project";
|
||||
$lang->gitlab->gitlabIssue = "GitLab Issue";
|
||||
$lang->gitlab->zentaoProduct = 'Zentao Product';
|
||||
$lang->gitlab->objectType = 'Type'; // task, bug, story
|
||||
$lang->gitlab->browseAction = 'GitLab List';
|
||||
$lang->gitlab->deleteAction = 'Delete GitLab';
|
||||
$lang->gitlab->gitlabProject = "GitLab Project";
|
||||
$lang->gitlab->browseProject = "GitLab Project List";
|
||||
$lang->gitlab->browseUser = "User List";
|
||||
$lang->gitlab->browseGroup = "Group List";
|
||||
$lang->gitlab->gitlabIssue = "GitLab Issue";
|
||||
$lang->gitlab->zentaoProduct = 'Zentao Product';
|
||||
$lang->gitlab->objectType = 'Type'; // task, bug, story
|
||||
$lang->gitlab->manageProjectMembers = 'Manage project member';
|
||||
$lang->gitlab->createProject = 'Create Gitlab project';
|
||||
$lang->gitlab->editProject = 'Eidt Gitlab project';
|
||||
$lang->gitlab->deleteProject = 'Delete Gitlab project';
|
||||
$lang->gitlab->createGroup = 'Create group';
|
||||
$lang->gitlab->editGroup = 'Edit group';
|
||||
$lang->gitlab->deleteGroup = 'Delete group';
|
||||
$lang->gitlab->createUser = 'Create user';
|
||||
$lang->gitlab->editUser = 'Edit user';
|
||||
$lang->gitlab->deleteUser = 'Delete user';
|
||||
$lang->gitlab->manageGroupMembers = 'Manage group member';
|
||||
$lang->gitlab->createWebhook = 'Create Webhook';
|
||||
|
||||
$lang->gitlab->id = 'ID';
|
||||
$lang->gitlab->name = "GitLab Name";
|
||||
@@ -37,9 +58,10 @@ $lang->gitlab->tokenFirst = 'When the Token is not empty, the Token will be used
|
||||
$lang->gitlab->tips = 'When using a password, please disable the "Prevent cross-site request forgery" option in the GitLab global security settings.';
|
||||
|
||||
$lang->gitlab->placeholder = new stdclass;
|
||||
$lang->gitlab->placeholder->name = '';
|
||||
$lang->gitlab->placeholder->url = "Please fill in the access address of the GitLab Server homepage, as: https://gitlab.zentao.net.";
|
||||
$lang->gitlab->placeholder->token = "Please fill in the access token of an account with admin privileges.";
|
||||
$lang->gitlab->placeholder->name = '';
|
||||
$lang->gitlab->placeholder->url = "Please fill in the access address of the GitLab Server homepage, as: https://gitlab.zentao.net.";
|
||||
$lang->gitlab->placeholder->token = "Please fill in the access token of an account with admin privileges.";
|
||||
$lang->gitlab->placeholder->projectPath = "It should contain only letters, digits, underscore, hyphen and period. It should not start with hypen, or end with .git or .atom.";
|
||||
|
||||
$lang->gitlab->noImportableIssues = "There are currently no issues available for import.";
|
||||
$lang->gitlab->tokenError = "The current token is not admin rights.";
|
||||
@@ -48,3 +70,97 @@ $lang->gitlab->hostError = "Invalid GitLab service address.";
|
||||
$lang->gitlab->bindUserError = "Can not bind users repeatedly %s";
|
||||
$lang->gitlab->importIssueError = "The execution to which this issue belongs is not selected.";
|
||||
$lang->gitlab->importIssueWarn = "There is a problem of import failure, you can try to import again.";
|
||||
|
||||
$lang->gitlab->accessLevels[10] = 'Guest';
|
||||
$lang->gitlab->accessLevels[20] = 'Reporter';
|
||||
$lang->gitlab->accessLevels[30] = 'Developer';
|
||||
$lang->gitlab->accessLevels[40] = 'Maintainer';
|
||||
$lang->gitlab->accessLevels[50] = 'Owner';
|
||||
|
||||
$lang->gitlab->apiError[0] = 'internal is not allowed in a private group.';
|
||||
|
||||
$lang->gitlab->errorLang[0] = 'You cannot set Internal as its Visibility Level, if it is private in Gitlab.';
|
||||
|
||||
$lang->gitlab->project = new stdclass;
|
||||
$lang->gitlab->project->id = "Project ID";
|
||||
$lang->gitlab->project->name = "Project name";
|
||||
$lang->gitlab->project->create = "Create Gitlab project";
|
||||
$lang->gitlab->project->edit = "Edit Gitlab project";
|
||||
$lang->gitlab->project->url = "Project URL";
|
||||
$lang->gitlab->project->path = "Project slug";
|
||||
$lang->gitlab->project->description = "Project description";
|
||||
$lang->gitlab->project->visibility = "Visibility Level";
|
||||
$lang->gitlab->project->visibilityList['private'] = "Private(Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group)";
|
||||
$lang->gitlab->project->visibilityList['internal'] = "Internal(The project can be accessed by any logged in user except external users)";
|
||||
$lang->gitlab->project->visibilityList['public'] = "Public(The project can be accessed without any authentication)";
|
||||
$lang->gitlab->project->star = "Stars";
|
||||
$lang->gitlab->project->fork = "Forks";
|
||||
$lang->gitlab->project->mergeRequests = "Merge Requests";
|
||||
$lang->gitlab->project->issues = "Issues";
|
||||
$lang->gitlab->project->tagList = "Topics";
|
||||
$lang->gitlab->project->tagListTips = "Separate topics with commas.";
|
||||
$lang->gitlab->project->emptyNameError = "Project name cannot be empty.";
|
||||
$lang->gitlab->project->emptyPathError = "Project slug cannot be empty.";
|
||||
$lang->gitlab->project->confirmDelete = 'Do you want to delete this GitLab project?';
|
||||
$lang->gitlab->project->notbindedError = 'Gitlab user has not been bound, unable to modify permissions!';
|
||||
|
||||
$lang->gitlab->user = new stdclass;
|
||||
$lang->gitlab->user->id = "User ID";
|
||||
$lang->gitlab->user->name = "Name";
|
||||
$lang->gitlab->user->username = "Username";
|
||||
$lang->gitlab->user->email = "Email";
|
||||
$lang->gitlab->user->password = "Password";
|
||||
$lang->gitlab->user->passwordRepeat = "Repeat Password";
|
||||
$lang->gitlab->user->projectsLimit = "Projects limit";
|
||||
$lang->gitlab->user->canCreateGroup = "Can create group";
|
||||
$lang->gitlab->user->external = "External";
|
||||
$lang->gitlab->user->externalTip = "External users cannot see internal or private projects unless access is explicitly granted. Also, external users cannot create projects, groups, or personal snippets.";
|
||||
$lang->gitlab->user->bind = "Bind Zentao user";
|
||||
$lang->gitlab->user->avatar = "Avatar";
|
||||
$lang->gitlab->user->skype = "Skype";
|
||||
$lang->gitlab->user->linkedin = "Linkedin";
|
||||
$lang->gitlab->user->twitter = "Twitter";
|
||||
$lang->gitlab->user->websiteUrl = "Website url";
|
||||
$lang->gitlab->user->note = "Note";
|
||||
$lang->gitlab->user->createOn = "Created on";
|
||||
$lang->gitlab->user->lastActivity = "Last activity";
|
||||
$lang->gitlab->user->create = "Create Gitlab user";
|
||||
$lang->gitlab->user->edit = "Edit Gitlab user";
|
||||
$lang->gitlab->user->emptyError = "cannot be empty";
|
||||
$lang->gitlab->user->passwordError = "The second password is inconsistent!";
|
||||
$lang->gitlab->user->bindError = "The user has been bound!";
|
||||
$lang->gitlab->user->confirmDelete = 'Do you want to delete this GitLab user?';
|
||||
|
||||
$lang->gitlab->group = new stdclass;
|
||||
$lang->gitlab->group->id = "Group ID";
|
||||
$lang->gitlab->group->name = "Group name";
|
||||
$lang->gitlab->group->path = "Group URL";
|
||||
$lang->gitlab->group->pathTip = "Changing group URL can have unintended side effects.";
|
||||
$lang->gitlab->group->description = "Group description";
|
||||
$lang->gitlab->group->avatar = "Group avatar";
|
||||
$lang->gitlab->group->avatarTip = 'Max file size is 200 KB.';
|
||||
$lang->gitlab->group->visibility = "Visibility level";
|
||||
$lang->gitlab->group->visibilityList['private'] = "Private(The group and its projects can only be viewed by members)";
|
||||
$lang->gitlab->group->visibilityList['internal'] = "Internal(The group and any internal projects can be viewed by any logged in user except external users)";
|
||||
$lang->gitlab->group->visibilityList['public'] = "Public(The group and any public projects can be viewed without any authentication.)";
|
||||
$lang->gitlab->group->requestAccessEnabledTip = "Allow users to request access (if visibility is public or internal)";
|
||||
$lang->gitlab->group->lfsEnabled = 'Large File Storage';
|
||||
$lang->gitlab->group->lfsEnabledTip = "Allow projects within this group to use Git LFS(This setting can be overridden in each project)";
|
||||
$lang->gitlab->group->projectCreationLevel = "Allowed to create projects";
|
||||
$lang->gitlab->group->projectCreationLevelList['none'] = "No one";
|
||||
$lang->gitlab->group->projectCreationLevelList['maintainer'] = "Maintainers";
|
||||
$lang->gitlab->group->projectCreationLevelList['developer'] = "Developers + Maintainers";
|
||||
$lang->gitlab->group->subgroupCreationLevel = "Allowed to create projects";
|
||||
$lang->gitlab->group->subgroupCreationLevelList['owner'] = "Owners";
|
||||
$lang->gitlab->group->subgroupCreationLevelList['maintainer'] = "Maintainers";
|
||||
$lang->gitlab->group->create = "Create Group";
|
||||
$lang->gitlab->group->edit = "Edit Group";
|
||||
$lang->gitlab->group->createOn = "Created on";
|
||||
$lang->gitlab->group->members = "Group Members";
|
||||
$lang->gitlab->group->confirmDelete = 'Do you want to delete this GitLab group?';
|
||||
$lang->gitlab->group->emptyError = "cannot be empty";
|
||||
$lang->gitlab->group->manageMembers = 'Manage Group Members';
|
||||
$lang->gitlab->group->memberName = 'Account';
|
||||
$lang->gitlab->group->memberAccessLevel = 'Access Level';
|
||||
$lang->gitlab->group->memberExpiresAt = 'Expiration time';
|
||||
$lang->gitlab->group->repeatError = "Group members cannot be added repeatedly";
|
||||
|
||||
+143
-25
@@ -1,28 +1,49 @@
|
||||
<?php
|
||||
$lang->gitlab = new stdclass;
|
||||
$lang->gitlab->common = 'GitLab';
|
||||
$lang->gitlab->browse = '浏览GitLab';
|
||||
$lang->gitlab->create = '添加GitLab';
|
||||
$lang->gitlab->edit = '编辑GitLab';
|
||||
$lang->gitlab->view = '查看GitLab';
|
||||
$lang->gitlab->bindUser = '绑定用户';
|
||||
$lang->gitlab->webhook = 'webhook';
|
||||
$lang->gitlab->bindProduct = '关联产品';
|
||||
$lang->gitlab->importIssue = '关联issue';
|
||||
$lang->gitlab->delete = '删除GitLab';
|
||||
$lang->gitlab->confirmDelete = '确认删除该GitLab吗?';
|
||||
$lang->gitlab->gitlabAccount = 'GitLab用户';
|
||||
$lang->gitlab->zentaoAccount = '禅道用户';
|
||||
$lang->gitlab->bindingStatus = '绑定状态';
|
||||
$lang->gitlab->binded = '已绑定';
|
||||
$lang->gitlab->serverFail = '连接GitLab服务器异常,请检查GitLab服务器。';
|
||||
$lang->gitlab->common = 'GitLab';
|
||||
$lang->gitlab->browse = '浏览GitLab';
|
||||
$lang->gitlab->search = '搜索';
|
||||
$lang->gitlab->create = '添加GitLab';
|
||||
$lang->gitlab->edit = '编辑GitLab';
|
||||
$lang->gitlab->view = '查看GitLab';
|
||||
$lang->gitlab->bindUser = '绑定用户';
|
||||
$lang->gitlab->webhook = 'webhook';
|
||||
$lang->gitlab->bindProduct = '关联产品';
|
||||
$lang->gitlab->importIssue = '关联issue';
|
||||
$lang->gitlab->delete = '删除GitLab';
|
||||
$lang->gitlab->confirmDelete = '确认删除该GitLab吗?';
|
||||
$lang->gitlab->gitlabAccount = 'GitLab用户';
|
||||
$lang->gitlab->zentaoAccount = '禅道用户';
|
||||
$lang->gitlab->bindingStatus = '绑定状态';
|
||||
$lang->gitlab->binded = '已绑定';
|
||||
$lang->gitlab->serverFail = '连接GitLab服务器异常,请检查GitLab服务器。';
|
||||
$lang->gitlab->lastUpdate = '最后更新';
|
||||
$lang->gitlab->confirmAddWebhook = '您确定创建Webhook吗?';
|
||||
$lang->gitlab->addWebhookSuccess = 'webhook创建成功';
|
||||
$lang->gitlab->failCreateWebhook = 'Webhook创建失败,请查看日志';
|
||||
$lang->gitlab->placeholderSearch = '请输入项目名称';
|
||||
|
||||
$lang->gitlab->browseAction = 'GitLab列表';
|
||||
$lang->gitlab->deleteAction = '删除GitLab';
|
||||
$lang->gitlab->gitlabProject = "{$lang->gitlab->common}项目";
|
||||
$lang->gitlab->gitlabIssue = "{$lang->gitlab->common} issue";
|
||||
$lang->gitlab->zentaoProduct = '禅道产品';
|
||||
$lang->gitlab->objectType = '类型'; // task, bug, story
|
||||
$lang->gitlab->browseAction = 'GitLab列表';
|
||||
$lang->gitlab->deleteAction = '删除GitLab';
|
||||
$lang->gitlab->gitlabProject = "{$lang->gitlab->common}项目";
|
||||
$lang->gitlab->browseProject = "{$lang->gitlab->common}项目列表";
|
||||
$lang->gitlab->browseUser = "用户列表";
|
||||
$lang->gitlab->browseGroup = "群组列表";
|
||||
$lang->gitlab->gitlabIssue = "{$lang->gitlab->common} issue";
|
||||
$lang->gitlab->zentaoProduct = '禅道产品';
|
||||
$lang->gitlab->objectType = '类型'; // task, bug, story
|
||||
$lang->gitlab->manageProjectMembers = '项目成员管理';
|
||||
$lang->gitlab->createProject = '添加Gitlab项目';
|
||||
$lang->gitlab->editProject = '编辑Gitlab项目';
|
||||
$lang->gitlab->deleteProject = '删除Gitlab项目';
|
||||
$lang->gitlab->createGroup = '添加群组';
|
||||
$lang->gitlab->editGroup = '编辑群组';
|
||||
$lang->gitlab->deleteGroup = '删除群组';
|
||||
$lang->gitlab->createUser = '添加用户';
|
||||
$lang->gitlab->editUser = '编辑用户';
|
||||
$lang->gitlab->deleteUser = '删除用户';
|
||||
$lang->gitlab->manageGroupMembers = '群组成员管理';
|
||||
$lang->gitlab->createWebhook = '创建Webhook';
|
||||
|
||||
$lang->gitlab->id = 'ID';
|
||||
$lang->gitlab->name = "{$lang->gitlab->common}名称";
|
||||
@@ -37,9 +58,10 @@ $lang->gitlab->tokenFirst = 'Token不为空时,优先使用Token。';
|
||||
$lang->gitlab->tips = '使用密码时,请在GitLab全局安全设置中禁用"防止跨站点请求伪造"选项。';
|
||||
|
||||
$lang->gitlab->placeholder = new stdclass;
|
||||
$lang->gitlab->placeholder->name = '';
|
||||
$lang->gitlab->placeholder->url = "请填写Gitlab Server首页的访问地址,如:https://gitlab.zentao.net。";
|
||||
$lang->gitlab->placeholder->token = "请填写具有admin权限账户的access token";
|
||||
$lang->gitlab->placeholder->name = '';
|
||||
$lang->gitlab->placeholder->url = "请填写Gitlab Server首页的访问地址,如:https://gitlab.zentao.net。";
|
||||
$lang->gitlab->placeholder->token = "请填写具有admin权限账户的access token";
|
||||
$lang->gitlab->placeholder->projectPath = "项目标识串只能包含字母、数字、“_”、“-”和“.”。不能以“-”开头,以.git或者.atom结尾";
|
||||
|
||||
$lang->gitlab->noImportableIssues = "目前没有可供导入的issue。";
|
||||
$lang->gitlab->tokenError = "当前token非管理员权限。";
|
||||
@@ -48,3 +70,99 @@ $lang->gitlab->hostError = "无效的GitLab服务地址。";
|
||||
$lang->gitlab->bindUserError = "不能重复绑定用户 %s";
|
||||
$lang->gitlab->importIssueError = "未选择该issue所属的执行。";
|
||||
$lang->gitlab->importIssueWarn = "存在导入失败的issue,可再次尝试导入。";
|
||||
|
||||
$lang->gitlab->accessLevels[10] = 'Guest';
|
||||
$lang->gitlab->accessLevels[20] = 'Reporter';
|
||||
$lang->gitlab->accessLevels[30] = 'Developer';
|
||||
$lang->gitlab->accessLevels[40] = 'Maintainer';
|
||||
$lang->gitlab->accessLevels[50] = 'Owner';
|
||||
|
||||
$lang->gitlab->apiError[0] = 'internal is not allowed in a private group.';
|
||||
$lang->gitlab->apiError[1] = 'public is not allowed in a private group.';
|
||||
|
||||
$lang->gitlab->errorLang[0] = '私有分组的项目,可见性级别不能设为内部。';
|
||||
$lang->gitlab->errorLang[1] = '私有分组的项目,可见性级别不能设为公开。';
|
||||
|
||||
$lang->gitlab->project = new stdclass;
|
||||
$lang->gitlab->project->id = "项目ID";
|
||||
$lang->gitlab->project->name = "项目名称";
|
||||
$lang->gitlab->project->create = "添加Gitlab项目";
|
||||
$lang->gitlab->project->edit = "编辑Gitlab项目";
|
||||
$lang->gitlab->project->url = "项目 URL";
|
||||
$lang->gitlab->project->path = "项目标识串";
|
||||
$lang->gitlab->project->description = "项目描述";
|
||||
$lang->gitlab->project->visibility = "可见性级别";
|
||||
$lang->gitlab->project->visibilityList['private'] = "私有(项目访问必须明确授予每个用户。 如果此项目是在一个群组中,群组成员将会获得访问权限)";
|
||||
$lang->gitlab->project->visibilityList['internal'] = "内部(除外部用户外,任何登录用户均可访问该项目)";
|
||||
$lang->gitlab->project->visibilityList['public'] = "公开(该项目允许任何人访问)";
|
||||
$lang->gitlab->project->star = "星标";
|
||||
$lang->gitlab->project->fork = "派生";
|
||||
$lang->gitlab->project->mergeRequests = "合并请求";
|
||||
$lang->gitlab->project->issues = "议题";
|
||||
$lang->gitlab->project->tagList = "主题";
|
||||
$lang->gitlab->project->tagListTips = "用逗号分隔主题。";
|
||||
$lang->gitlab->project->emptyNameError = "项目名称不能为空";
|
||||
$lang->gitlab->project->emptyPathError = "项目标识串不能为空";
|
||||
$lang->gitlab->project->confirmDelete = '确认删除该GitLab项目吗?';
|
||||
$lang->gitlab->project->notbindedError = '还没绑定Gitlab用户,无法修改权限!';
|
||||
|
||||
$lang->gitlab->user = new stdclass;
|
||||
$lang->gitlab->user->id = "用户ID";
|
||||
$lang->gitlab->user->name = "名称";
|
||||
$lang->gitlab->user->username = "用户名";
|
||||
$lang->gitlab->user->email = "电子邮件";
|
||||
$lang->gitlab->user->password = "密码";
|
||||
$lang->gitlab->user->passwordRepeat = "重复密码";
|
||||
$lang->gitlab->user->projectsLimit = "限制项目";
|
||||
$lang->gitlab->user->canCreateGroup = "可创建组";
|
||||
$lang->gitlab->user->external = "外部人员";
|
||||
$lang->gitlab->user->externalTip = "除非明确授予访问权限,否则外部用户无法查看内部或私有项目。另外,外部用户无法创建项目,群组或个人代码片段。";
|
||||
$lang->gitlab->user->bind = "绑定禅道用户";
|
||||
$lang->gitlab->user->avatar = "头像";
|
||||
$lang->gitlab->user->skype = "Skype";
|
||||
$lang->gitlab->user->linkedin = "Linkedin";
|
||||
$lang->gitlab->user->twitter = "Twitter";
|
||||
$lang->gitlab->user->websiteUrl = "网站地址";
|
||||
$lang->gitlab->user->note = "备注";
|
||||
$lang->gitlab->user->createOn = "创建于";
|
||||
$lang->gitlab->user->lastActivity = "上次活动";
|
||||
$lang->gitlab->user->create = "添加Gitlab用户";
|
||||
$lang->gitlab->user->edit = "编辑Gitlab用户";
|
||||
$lang->gitlab->user->emptyError = "不能为空";
|
||||
$lang->gitlab->user->passwordError = "二次密码不一致!";
|
||||
$lang->gitlab->user->bindError = "该用户已经被绑定!";
|
||||
$lang->gitlab->user->confirmDelete = '确认删除该GitLab用户吗?';
|
||||
|
||||
$lang->gitlab->group = new stdclass;
|
||||
$lang->gitlab->group->id = "群组ID";
|
||||
$lang->gitlab->group->name = "群组名称";
|
||||
$lang->gitlab->group->path = "群组URL";
|
||||
$lang->gitlab->group->pathTip = "更改群组URL可能会有意想不到的副作用。";
|
||||
$lang->gitlab->group->description = "群组描述";
|
||||
$lang->gitlab->group->avatar = "群组头像";
|
||||
$lang->gitlab->group->avatarTip = '文件最大支持200k.';
|
||||
$lang->gitlab->group->visibility = "可见性级别";
|
||||
$lang->gitlab->group->visibilityList['private'] = "私有(群组及其项目只能由成员查看)";
|
||||
$lang->gitlab->group->visibilityList['internal'] = "内部(除外部用户外,任何登录用户均可查看该组和任何内部项目)";
|
||||
$lang->gitlab->group->visibilityList['public'] = "公开(群组和任何公共项目可以在没有任何身份验证的情况下查看)";
|
||||
$lang->gitlab->group->requestAccessEnabledTip = "允许用户请求访问(如果可见性是公开或内部的)";
|
||||
$lang->gitlab->group->lfsEnabled = '大文件存储';
|
||||
$lang->gitlab->group->lfsEnabledTip = "允许该组内的项目使用 Git LFS(可以在每个项目中覆盖此设置)";
|
||||
$lang->gitlab->group->projectCreationLevel = "创建项目权限";
|
||||
$lang->gitlab->group->projectCreationLevelList['noone'] = "禁止";
|
||||
$lang->gitlab->group->projectCreationLevelList['maintainer'] = "维护者";
|
||||
$lang->gitlab->group->projectCreationLevelList['developer'] = "开发者 + 维护者";
|
||||
$lang->gitlab->group->subgroupCreationLevel = "创建子群组权限";
|
||||
$lang->gitlab->group->subgroupCreationLevelList['owner'] = "所有者";
|
||||
$lang->gitlab->group->subgroupCreationLevelList['maintainer'] = "维护者";
|
||||
$lang->gitlab->group->create = "添加群组";
|
||||
$lang->gitlab->group->edit = "编辑群组";
|
||||
$lang->gitlab->group->createOn = "创建于";
|
||||
$lang->gitlab->group->members = "群组成员";
|
||||
$lang->gitlab->group->confirmDelete = '确认删除该GitLab群组吗?';
|
||||
$lang->gitlab->group->emptyError = "不能为空";
|
||||
$lang->gitlab->group->manageMembers = '群组成员管理';
|
||||
$lang->gitlab->group->memberName = '账号';
|
||||
$lang->gitlab->group->memberAccessLevel = '角色权限';
|
||||
$lang->gitlab->group->memberExpiresAt = '过期时间';
|
||||
$lang->gitlab->group->repeatError = "群组成员不能重复添加";
|
||||
|
||||
+791
-55
@@ -12,6 +12,9 @@
|
||||
|
||||
class gitlabModel extends model
|
||||
{
|
||||
|
||||
const HOOK_PUSH_EVENT = 'Push Hook';
|
||||
|
||||
/**
|
||||
* Get a gitlab by id.
|
||||
*
|
||||
@@ -112,6 +115,22 @@ class gitlabModel extends model
|
||||
->fetchPairs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get gitlab user id by zentao account.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getUserIDByZentaoAccount($gitlabID, $zentaoAccount)
|
||||
{
|
||||
return $this->dao->select('openID')->from(TABLE_OAUTH)
|
||||
->where('providerType')->eq('gitlab')
|
||||
->andWhere('providerID')->eq($gitlabID)
|
||||
->andWhere('account')->eq($zentaoAccount)
|
||||
->fetch('openID');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project pairs of one gitlab.
|
||||
*
|
||||
@@ -300,11 +319,17 @@ class gitlabModel extends model
|
||||
$refList = array();
|
||||
|
||||
$branches = $this->apiGetBranches($gitlabID, $projectID);
|
||||
foreach($branches as $branch) $refList[$branch->name] = "Branch::" . $branch->name;
|
||||
if(is_array($branches))
|
||||
{
|
||||
foreach($branches as $branch) $refList[$branch->name] = "Branch::" . $branch->name;
|
||||
}
|
||||
|
||||
$tags = $this->apiGetTags($gitlabID, $projectID);
|
||||
foreach($tags as $tag) $refList[$tag->name] = "Tag::" . $tag->name;
|
||||
|
||||
if(is_array($tags))
|
||||
{
|
||||
foreach($tags as $tag) $refList[$tag->name] = "Tag::" . $tag->name;
|
||||
}
|
||||
return $refList;
|
||||
|
||||
}
|
||||
@@ -393,7 +418,7 @@ class gitlabModel extends model
|
||||
/**
|
||||
* Get a list of to-do items by API.
|
||||
*
|
||||
* @docs https://docs.gitlab.com/ee/api/todos.html
|
||||
* @link https://docs.gitlab.com/ee/api/todos.html
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @param int $sudo
|
||||
@@ -426,19 +451,26 @@ class gitlabModel extends model
|
||||
* Get gitlab user list.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param bool $onlyLinked
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function apiGetUsers($gitlabID)
|
||||
public function apiGetUsers($gitlabID, $onlyLinked = false, $orderBy = 'id_desc')
|
||||
{
|
||||
/* GitLab API '/users' can only return 20 users per page in default, so we use a loop to fetch all users. */
|
||||
$page = 1;
|
||||
$response = array();
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
|
||||
/* Get order data. */
|
||||
$orders = explode('_', $orderBy);
|
||||
$sort = array_pop($orders);
|
||||
$order = join('_', $orders);
|
||||
|
||||
while(true)
|
||||
{
|
||||
/* Also use `per_page=20` to fetch users in API. Fetch active users only. */
|
||||
$url = sprintf($apiRoot, "/users") . "&page={$page}&per_page=20&active=true";
|
||||
$url = sprintf($apiRoot, "/users") . "&order_by={$order}&sort={$sort}&page={$page}&per_page=20&active=true";
|
||||
$result = json_decode(commonModel::http($url));
|
||||
if(!empty($result))
|
||||
{
|
||||
@@ -453,15 +485,23 @@ class gitlabModel extends model
|
||||
|
||||
if(!$response) return array();
|
||||
|
||||
/* Get linked users. */
|
||||
$linkedUsers = array();
|
||||
if($onlyLinked) $linkedUsers = $this->getUserIdAccountPairs($gitlabID);
|
||||
|
||||
$users = array();
|
||||
foreach($response as $gitlabUser)
|
||||
{
|
||||
$user = new stdclass;
|
||||
$user->id = $gitlabUser->id;
|
||||
$user->realname = $gitlabUser->name;
|
||||
$user->account = $gitlabUser->username;
|
||||
$user->email = $gitlabUser->email;
|
||||
$user->avatar = $gitlabUser->avatar_url;
|
||||
if($onlyLinked and !isset($linkedUsers[$gitlabUser->id])) continue;
|
||||
|
||||
$user = new stdclass;
|
||||
$user->id = $gitlabUser->id;
|
||||
$user->realname = $gitlabUser->name;
|
||||
$user->account = $gitlabUser->username;
|
||||
$user->email = $gitlabUser->email;
|
||||
$user->avatar = $gitlabUser->avatar_url;
|
||||
$user->createdAt = $gitlabUser->created_at;
|
||||
$user->lastActivityOn = $gitlabUser->last_activity_on;
|
||||
|
||||
$users[] = $user;
|
||||
}
|
||||
@@ -469,6 +509,127 @@ class gitlabModel extends model
|
||||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get group members of one gitlab.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $groupID
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiGetGroupMembers($gitlabID, $groupID)
|
||||
{
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/groups/$groupID/members/all");
|
||||
|
||||
$allResults = array();
|
||||
for($page = 1; true; $page++)
|
||||
{
|
||||
$results = json_decode(commonModel::http($url . "&&page={$page}&per_page=100"));
|
||||
if(!empty($results)) $allResults = array_merge($allResults, $results);
|
||||
if(count($results)<100) break;
|
||||
}
|
||||
|
||||
return $allResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get namespaces of one gitlab.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiGetNamespaces($gitlabID)
|
||||
{
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/namespaces");
|
||||
|
||||
$allResults = array();
|
||||
for($page = 1; true; $page++)
|
||||
{
|
||||
$results = json_decode(commonModel::http($url . "&&page={$page}&per_page=100"));
|
||||
if(!empty($results)) $allResults = array_merge($allResults, $results);
|
||||
if(count($results)<100) break;
|
||||
}
|
||||
|
||||
return $allResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get groups of one gitlab.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiGetGroups($gitlabID, $orderBy)
|
||||
{
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/groups");
|
||||
list($order, $sort) = explode('_', $orderBy);
|
||||
|
||||
$allResults = array();
|
||||
for($page = 1; true; $page++)
|
||||
{
|
||||
$results = json_decode(commonModel::http($url . "&statistics=true&order_by={$order}&sort={$sort}&page={$page}&per_page=100"));
|
||||
if(!empty($results)) $allResults = array_merge($allResults, $results);
|
||||
if(count($results)<100 or $page > 10) break;
|
||||
}
|
||||
|
||||
return $allResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a gitab group by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param object $group
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiCreateGroup($gitlabID, $group)
|
||||
{
|
||||
if(empty($group->name) or empty($group->path)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/groups");
|
||||
return json_decode(commonModel::http($url, $group));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get projects of one gitlab.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param string $keyword
|
||||
* @param string $orderBy
|
||||
* @param object $pager
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function apiGetProjectsPager($gitlabID, $keyword = '', $orderBy, $pager)
|
||||
{
|
||||
$gitlab = $this->getByID($gitlabID);
|
||||
if(!$gitlab) return array();
|
||||
|
||||
$host = rtrim($gitlab->url, '/');
|
||||
$host .= '/api/v4/projects';
|
||||
|
||||
/* Parse order string. */
|
||||
$order = explode('_', $orderBy);
|
||||
|
||||
$keyword = urlencode($keyword);
|
||||
$result = commonModel::httpWithHeader($host . "?private_token={$gitlab->token}&simple=true&&per_page={$pager->recPerPage}&order_by={$order[0]}&sort={$order[1]}&page={$pager->pageID}&search={$keyword}");
|
||||
|
||||
$header = $result['header'];
|
||||
$recTotal = $header['X-Total'];
|
||||
$recPerPage = $header['X-Per-Page'];
|
||||
$pager = pager::init($recTotal, $recPerPage, $pager->pageID);
|
||||
|
||||
return array('pager' => $pager, 'projects' => json_decode($result['body']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get projects of one gitlab.
|
||||
*
|
||||
@@ -488,13 +649,253 @@ class gitlabModel extends model
|
||||
for($page = 1; true; $page++)
|
||||
{
|
||||
$results = json_decode(commonModel::http($host . "?private_token={$gitlab->token}&simple=true&page={$page}&per_page=100"));
|
||||
if(empty($results) or $page > 10) break;
|
||||
$allResults = array_merge($allResults, $results);
|
||||
if(!empty($results)) $allResults = array_merge($allResults, $results);
|
||||
if(count($results)<100 or $page > 10) break;
|
||||
}
|
||||
|
||||
return $allResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a gitab project by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param object $project
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiCreateProject($gitlabID, $project)
|
||||
{
|
||||
if(empty($project->name) and empty($project->path)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/projects");
|
||||
return json_decode(commonModel::http($url, $project));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a gitab project member by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @param object $member
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiCreateProjectMember($gitlabID, $projectID, $member)
|
||||
{
|
||||
if(empty($member->user_id) or empty($member->access_level)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/projects/{$projectID}/members");
|
||||
return json_decode(commonModel::http($url, $member));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a gitab project member by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @param object $member
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiUpdateProjectMember($gitlabID, $projectID, $member)
|
||||
{
|
||||
if(empty($member->user_id) or empty($member->access_level)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/projects/{$projectID}/members/{$member->user_id}");
|
||||
return json_decode(commonModel::http($url, $member, $options = array(CURLOPT_CUSTOMREQUEST => 'PUT')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gitab project member by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $groupID
|
||||
* @param int $memberID
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiDeleteProjectMember($gitlabID, $groupID, $memberID)
|
||||
{
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/projects/{$groupID}/members/{$memberID}");
|
||||
return json_decode(commonModel::http($url, array(), $options = array(CURLOPT_CUSTOMREQUEST => 'DELETE')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a gitab group member by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $groupID
|
||||
* @param object $member
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiCreateGroupMember($gitlabID, $groupID, $member)
|
||||
{
|
||||
if(empty($member->user_id) or empty($member->access_level)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/groups/{$groupID}/members");
|
||||
return json_decode(commonModel::http($url, $member));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a gitab group member by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $groupID
|
||||
* @param object $member
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiUpdateGroupMember($gitlabID, $groupID, $member)
|
||||
{
|
||||
if(empty($member->user_id) or empty($member->access_level)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/groups/{$groupID}/members/{$member->user_id}");
|
||||
return json_decode(commonModel::http($url, $member, $options = array(CURLOPT_CUSTOMREQUEST => 'PUT')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gitab group member by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $groupID
|
||||
* @param int $memberID
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiDeleteGroupMember($gitlabID, $groupID, $memberID)
|
||||
{
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/groups/{$groupID}/members/{$memberID}");
|
||||
return json_decode(commonModel::http($url, array(), $options = array(CURLOPT_CUSTOMREQUEST => 'DELETE')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a gitab user by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param object $user
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiCreateUser($gitlabID, $user)
|
||||
{
|
||||
if(empty($user->name) or empty($user->username) or empty($user->email) or empty($user->password)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/users");
|
||||
return json_decode(commonModel::http($url, $user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a gitab user by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param object $user
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiUpdateUser($gitlabID, $user)
|
||||
{
|
||||
if(empty($user->id)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/users/{$user->id}");
|
||||
return json_decode(commonModel::http($url, $user, $options = array(CURLOPT_CUSTOMREQUEST => 'PUT')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a gitab group by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param object $group
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiUpdateGroup($gitlabID, $group)
|
||||
{
|
||||
if(empty($group->id)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/groups/{$group->id}");
|
||||
return json_decode(commonModel::http($url, $group, $options = array(CURLOPT_CUSTOMREQUEST => 'PUT')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gitab group by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $groupID
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiDeleteGroup($gitlabID, $groupID)
|
||||
{
|
||||
if(empty($groupID)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/groups/{$groupID}");
|
||||
return json_decode(commonModel::http($url, array(), $options = array(CURLOPT_CUSTOMREQUEST => 'DELETE')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a gitab project by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param object $project
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiUpdateProject($gitlabID, $project)
|
||||
{
|
||||
if(empty($project->id)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/projects/{$project->id}");
|
||||
return json_decode(commonModel::http($url, $project, $options = array(CURLOPT_CUSTOMREQUEST => 'PUT')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gitab project by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiDeleteProject($gitlabID, $projectID)
|
||||
{
|
||||
if(empty($projectID)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/projects/{$projectID}");
|
||||
return json_decode(commonModel::http($url, array(), $options = array(CURLOPT_CUSTOMREQUEST => 'DELETE')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gitab user by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $userID
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiDeleteUser($gitlabID, $userID)
|
||||
{
|
||||
if(empty($userID)) return false;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/users/{$userID}");
|
||||
return json_decode(commonModel::http($url, array(), $options = array(CURLOPT_CUSTOMREQUEST => 'DELETE')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get single project by API.
|
||||
*
|
||||
@@ -509,6 +910,34 @@ class gitlabModel extends model
|
||||
return json_decode(commonModel::http($url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get single user by API.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $userID
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiGetSingleUser($gitlabID, $userID)
|
||||
{
|
||||
$url = sprintf($this->getApiRoot($gitlabID), "/users/$userID");
|
||||
return json_decode(commonModel::http($url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get single group by API.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $groupID
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiGetSingleGroup($gitlabID, $groupID)
|
||||
{
|
||||
$url = sprintf($this->getApiRoot($gitlabID), "/groups/$groupID");
|
||||
return json_decode(commonModel::http($url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project users.
|
||||
*
|
||||
@@ -570,7 +999,7 @@ class gitlabModel extends model
|
||||
/**
|
||||
* Get Forks of a project by API.
|
||||
*
|
||||
* @docs https://docs.gitlab.com/ee/api/projects.html#list-forks-of-a-project
|
||||
* @link https://docs.gitlab.com/ee/api/projects.html#list-forks-of-a-project
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
@@ -603,15 +1032,16 @@ class gitlabModel extends model
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return array
|
||||
* @link https://docs.gitlab.com/ee/api/projects.html#list-project-hooks
|
||||
* @return mixed
|
||||
*/
|
||||
public function apiGetHooks($gitlabID, $projectID)
|
||||
{
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$apiPath = "/projects/{$projectID}/hooks";
|
||||
$url = sprintf($apiRoot, $apiPath);
|
||||
$response = json_decode(commonModel::http($url));
|
||||
return $response;
|
||||
|
||||
return json_decode(commonModel::http($url));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -621,15 +1051,16 @@ class gitlabModel extends model
|
||||
* @param int $projectID
|
||||
* @param int $hookID
|
||||
* @access public
|
||||
* @return object
|
||||
* @link https://docs.gitlab.com/ee/api/projects.html#get-project-hook
|
||||
* @return mixed
|
||||
*/
|
||||
public function apiGetHook($gitlabID, $projectID, $hookID)
|
||||
{
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$apiPath = "/projects/$projectID/hooks/$hookID)";
|
||||
$url = sprintf($apiRoot, $apiPath);
|
||||
$response = commonModel::http($url);
|
||||
return $response;
|
||||
|
||||
return json_decode(commonModel::http($url));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -637,29 +1068,24 @@ class gitlabModel extends model
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @param string $url
|
||||
* @param object $hook
|
||||
* @access public
|
||||
* @return object
|
||||
* @link https://docs.gitlab.com/ee/api/projects.html#add-project-hook
|
||||
* @return mixed
|
||||
*/
|
||||
public function apiCreateHook($gitlabID, $projectID, $url)
|
||||
public function apiCreateHook($gitlabID, $projectID, $hook)
|
||||
{
|
||||
if(!isset($hook->url)) return false;
|
||||
|
||||
$newHook = new stdclass;
|
||||
$newHook->enable_ssl_verification = "false"; /* Disable ssl verification for every hook. */
|
||||
|
||||
foreach($hook as $index => $item) $newHook->$index= $item;
|
||||
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/projects/{$projectID}/hooks");
|
||||
|
||||
$accessToken = $this->dao->select('private as accessToken')->from(TABLE_PIPELINE)
|
||||
->where('id')->eq($gitlabID)
|
||||
->fetch('accessToken');
|
||||
|
||||
$postData = new stdclass;
|
||||
$postData->enable_ssl_verification = "false";
|
||||
$postData->issues_events = "true";
|
||||
$postData->merge_requests_events = "true";
|
||||
$postData->push_events = "true";
|
||||
$postData->tag_push_events = "true";
|
||||
$postData->url = $url;
|
||||
$postData->token = $accessToken;
|
||||
|
||||
$url = sprintf($apiRoot, "/projects/{$projectID}/hooks");
|
||||
return commonModel::http($url, $postData);
|
||||
return json_decode(commonModel::http($url, $newHook));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -669,41 +1095,81 @@ class gitlabModel extends model
|
||||
* @param int $projectID
|
||||
* @param int $hookID
|
||||
* @access public
|
||||
* @return null|object
|
||||
* @link https://docs.gitlab.com/ee/api/projects.html#delete-project-hook
|
||||
* @return mixed
|
||||
*/
|
||||
public function apiDeleteHook($gitlabID, $projectID, $hookID)
|
||||
{
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
$url = sprintf($apiRoot, "/projects/{$projectID}/hooks/{$hookID}");
|
||||
|
||||
return commonModel::http($url, null, array(CURLOPT_CUSTOMREQUEST => 'delete'));
|
||||
return json_decode(commonModel::http($url, null, array(CURLOPT_CUSTOMREQUEST => 'delete')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add webhook with push and merge request events to GitLab project.
|
||||
*
|
||||
* @param object $repo
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function addPushWebhook($repo)
|
||||
{
|
||||
$hook = new stdClass;
|
||||
$hook->url = common::getSysURL() . '/api.php/v1/gitlab/webhook?repoID='. $repo->id;
|
||||
$hook->push_events = true;
|
||||
$hook->merge_requests_events = true;
|
||||
|
||||
/* Return an empty array if where is one existing webhook. */
|
||||
if($this->isWebhookExists($repo, $hook->url)) return array();
|
||||
|
||||
$result = $this->apiCreateHook($repo->gitlab, $repo->project, $hook);
|
||||
|
||||
if(!empty($result->id)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Webhook exists.
|
||||
*
|
||||
* @param object $repo
|
||||
* @param string $url
|
||||
* @return bool
|
||||
*/
|
||||
public function isWebhookExists($repo, $url = '')
|
||||
{
|
||||
$hookList = $this->apiGetHooks($repo->gitlab, $repo->project);
|
||||
foreach($hookList as $hook)
|
||||
{
|
||||
if($hook->url == $url) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update hook by api.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @param int $hookID
|
||||
* @param int $gitlabID
|
||||
* @param int $projectID
|
||||
* @param int $hookID
|
||||
* @param object $hook
|
||||
* @access public
|
||||
* @link https://docs.gitlab.com/ee/api/projects.html#edit-project-hook
|
||||
* @return object
|
||||
*/
|
||||
public function apiUpdateHook($gitlabID, $projectID, $hookID)
|
||||
public function apiUpdateHook($gitlabID, $projectID, $hookID, $hook)
|
||||
{
|
||||
$apiRoot = $this->getApiRoot($gitlabID);
|
||||
|
||||
$postData = new stdclass;
|
||||
$postData->enable_ssl_verification = "false";
|
||||
$postData->issues_events = "true";
|
||||
$postData->merge_requests_events = "true";
|
||||
$postData->push_events = "true";
|
||||
$postData->tag_push_events = "true";
|
||||
$postData->note_events = "true";
|
||||
$postData->url = $url;
|
||||
$postData->token = $token;
|
||||
if(!isset($hook->url)) return false;
|
||||
|
||||
$newHook = new stdclass;
|
||||
$newHook->enable_ssl_verification = "false"; /* Disable ssl verification for every hook. */
|
||||
|
||||
foreach($hook as $index => $item) $newHook->$index= $item;
|
||||
|
||||
$url = sprintf($apiRoot, "/projects/{$projectID}/hooks/{$hookID}");
|
||||
return commonModel::http($url, $postData, $options = array(CURLOPT_CUSTOMREQUEST => 'PUT'));
|
||||
return commonModel::http($url, $newHook, $options = array(CURLOPT_CUSTOMREQUEST => 'PUT'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1014,7 +1480,7 @@ class gitlabModel extends model
|
||||
$type = zget($body, 'object_kind', '');
|
||||
if(!$type or !is_callable(array($this, "webhookParse{$type}"))) return false;
|
||||
// fix php 8.0 bug. link: https://www.php.net/manual/zh/function.call-user-func-array.php#125953
|
||||
|
||||
|
||||
return call_user_func_array(array($this, "webhookParse{$type}"), array($body, $gitlabID));
|
||||
}
|
||||
|
||||
@@ -1551,4 +2017,274 @@ class gitlabModel extends model
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create gitlab project.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function createProject($gitlabID)
|
||||
{
|
||||
$project = fixer::input('post')->get();
|
||||
if(empty($project->name)) dao::$errors['name'][] = $this->lang->gitlab->project->emptyNameError;
|
||||
if(empty($project->path)) dao::$errors['path'][] = $this->lang->gitlab->project->emptyPathError;
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$reponse = $this->apiCreateProject($gitlabID, $project);
|
||||
|
||||
if(!empty($reponse->id))
|
||||
{
|
||||
$this->loadModel('action')->create('gitlabproject', $reponse->id, 'created', '', $reponse->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->apiErrorHandling($reponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit gitlab project.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function editProject($gitlabID)
|
||||
{
|
||||
$project = fixer::input('post')->get();
|
||||
if(empty($project->name)) dao::$errors['name'][] = $this->lang->gitlab->project->emptyNameError;
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$reponse = $this->apiUpdateProject($gitlabID, $project);
|
||||
|
||||
if(!empty($reponse->id))
|
||||
{
|
||||
$this->loadModel('action')->create('gitlabproject', $project->id, 'edited', '', $project->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->apiErrorHandling($reponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a gitlab user.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function createUser($gitlabID)
|
||||
{
|
||||
$user = fixer::input('post')->remove('avatar')->get();
|
||||
if(!empty($_FILES['avatar'])) $user->avatar = curl_file_create($_FILES['avatar']['tmp_name'], $_FILES['avatar']['type'], $_FILES['avatar']['name']);
|
||||
|
||||
if(empty($user->account)) dao::$errors['account'][] = $this->lang->gitlab->user->bind . $this->lang->gitlab->user->emptyError;
|
||||
if(empty($user->name)) dao::$errors['name'][] = $this->lang->gitlab->user->name . $this->lang->gitlab->user->emptyError;
|
||||
if(empty($user->username)) dao::$errors['username'][] = $this->lang->gitlab->user->username . $this->lang->gitlab->user->emptyError;
|
||||
if(empty($user->email)) dao::$errors['email'][] = $this->lang->gitlab->user->email . $this->lang->gitlab->user->emptyError;
|
||||
if(empty($user->password)) dao::$errors['password'][] = $this->lang->gitlab->user->password . $this->lang->gitlab->user->emptyError;
|
||||
if(dao::isError()) return false;
|
||||
if($user->password != $user->password_repeat)
|
||||
{
|
||||
dao::$errors[] = $this->lang->gitlab->user->passwordError;
|
||||
return false;
|
||||
}
|
||||
/* Check whether the user has been bind. */
|
||||
if($user->account)
|
||||
{
|
||||
$zentaoBindUser = $this->dao->select('account')->from(TABLE_OAUTH)->where('providerType')->eq('gitlab')->andWhere('providerID')->eq($gitlabID)->andWhere('account')->eq($user->account)->fetch();
|
||||
if($zentaoBindUser)
|
||||
{
|
||||
dao::$errors['account'][] = $this->lang->gitlab->user->bindError;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$reponse = $this->apiCreateUser($gitlabID, $user);
|
||||
|
||||
if(!empty($reponse->id))
|
||||
{
|
||||
$this->loadModel('action')->create('gitlabuser', $reponse->id, 'created', '', $reponse->name);
|
||||
|
||||
/* Bind user. */
|
||||
if($user->account)
|
||||
{
|
||||
$userBind = new stdclass;
|
||||
$userBind->providerID = $gitlabID;
|
||||
$userBind->providerType = 'gitlab';
|
||||
$userBind->account = $user->account;
|
||||
$userBind->openID = $reponse->id;
|
||||
$this->dao->insert(TABLE_OAUTH)->data($userBind)->exec();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->apiErrorHandling($reponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a gitlab user.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function editUser($gitlabID)
|
||||
{
|
||||
$user = fixer::input('post')
|
||||
->setDefault('can_create_group', 0)
|
||||
->setDefault('external', 0)
|
||||
->remove('username,avatar')
|
||||
->removeIF(!$this->post->password, 'password,password_repeat')
|
||||
->get();
|
||||
if(!empty($_FILES['avatar'])) $user->avatar = curl_file_create($_FILES['avatar']['tmp_name'], $_FILES['avatar']['type'], $_FILES['avatar']['name']);
|
||||
|
||||
if(empty($user->account)) dao::$errors['account'][] = $this->lang->gitlab->user->bind . $this->lang->gitlab->user->emptyError;
|
||||
if(empty($user->name)) dao::$errors['name'][] = $this->lang->gitlab->user->name . $this->lang->gitlab->user->emptyError;
|
||||
if(empty($user->email)) dao::$errors['email'][] = $this->lang->gitlab->user->email . $this->lang->gitlab->user->emptyError;
|
||||
if(dao::isError()) return false;
|
||||
if(!empty($user->password) and $user->password != $user->password_repeat)
|
||||
{
|
||||
dao::$errors[] = $this->lang->gitlab->user->passwordError;
|
||||
return false;
|
||||
}
|
||||
/* Check whether the user has been bind. */
|
||||
if($user->account)
|
||||
{
|
||||
$zentaoBindUser = $this->dao->select('account,openID')->from(TABLE_OAUTH)->where('providerType')->eq('gitlab')->andWhere('providerID')->eq($gitlabID)->andWhere('account')->eq($user->account)->fetch();
|
||||
$changeBind = (!$zentaoBindUser or $zentaoBindUser->openID != $user->id) ? true : false;
|
||||
if($zentaoBindUser && $changeBind)
|
||||
{
|
||||
dao::$errors['bind'][] = $this->lang->gitlab->user->bindError;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$reponse = $this->apiUpdateUser($gitlabID, $user);
|
||||
|
||||
if(!empty($reponse->id))
|
||||
{
|
||||
$this->loadModel('action')->create('gitlabuser', $reponse->id, 'edited', '', $reponse->name);
|
||||
|
||||
/* Delete old bind. */
|
||||
$this->dao->delete()->from(TABLE_OAUTH)->where('providerType')->eq('gitlab')->andWhere('providerID')->eq($gitlabID)->andWhere('openID')->eq($reponse->id)->andWhere('account')->ne($user->account)->exec();
|
||||
/* Bind user. */
|
||||
if($user->account && $changeBind)
|
||||
{
|
||||
$userBind = new stdclass;
|
||||
$userBind->providerID = $gitlabID;
|
||||
$userBind->providerType = 'gitlab';
|
||||
$userBind->account = $user->account;
|
||||
$userBind->openID = $reponse->id;
|
||||
$this->dao->replace(TABLE_OAUTH)->data($userBind)->exec();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->apiErrorHandling($reponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a gitlab group.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function createGroup($gitlabID)
|
||||
{
|
||||
$group = fixer::input('post')->setDefault('request_access_enabled,lfs_enabled', 0)->get();
|
||||
|
||||
if(empty($group->name)) dao::$errors['name'][] = $this->lang->gitlab->group->name . $this->lang->gitlab->group->emptyError;
|
||||
if(empty($group->path)) dao::$errors['path'][] = $this->lang->gitlab->group->path . $this->lang->gitlab->group->emptyError;
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$reponse = $this->apiCreateGroup($gitlabID, $group);
|
||||
|
||||
if(!empty($reponse->id))
|
||||
{
|
||||
$this->loadModel('action')->create('gitlabgroup', $reponse->id, 'created', '', $reponse->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->apiErrorHandling($reponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a gitlab group.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function editGroup($gitlabID)
|
||||
{
|
||||
$group = fixer::input('post')->remove('path')->setDefault('request_access_enabled,lfs_enabled', 0)->get();
|
||||
|
||||
if(empty($group->name)) dao::$errors['name'][] = $this->lang->gitlab->group->name . $this->lang->gitlab->group->emptyError;
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$reponse = $this->apiUpdateGroup($gitlabID, $group);
|
||||
|
||||
if(!empty($reponse->id))
|
||||
{
|
||||
$this->loadModel('action')->create('gitlabgroup', $reponse->id, 'edited', '', $reponse->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->apiErrorHandling($reponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Api error handling.
|
||||
*
|
||||
* @param object $reponse
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function apiErrorHandling($reponse)
|
||||
{
|
||||
if(!empty($reponse->error))
|
||||
{
|
||||
dao::$errors[] = $reponse->error;
|
||||
return false;
|
||||
}
|
||||
if(!empty($reponse->message))
|
||||
{
|
||||
if(is_string($reponse->message))
|
||||
{
|
||||
$errorKey = array_search($reponse->message, $this->lang->gitlab->apiError);
|
||||
dao::$errors[] = $errorKey === false ? $reponse->message : zget($this->lang->gitlab->errorLang, $errorKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($reponse->message as $field => $fieldErrors)
|
||||
{
|
||||
foreach($fieldErrors as $error)
|
||||
{
|
||||
$errorKey = array_search($error, $this->lang->gitlab->apiError);
|
||||
if($error) dao::$errors[$field][] = $errorKey === false ? $error : zget($this->lang->gitlab->errorLang, $errorKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!$reponse) dao::$errors[] = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get products which scm is GitLab by projects.
|
||||
*
|
||||
* @param array $projectIDs
|
||||
* @return array
|
||||
*/
|
||||
public function getProductsByProjects($projectIDs)
|
||||
{
|
||||
return $this->dao->select('path,product')->from(TABLE_REPO)->where('deleted')->eq('0')
|
||||
->andWhere('SCM')->eq('Gitlab')
|
||||
->andWhere('path')->in($projectIDs)
|
||||
->fetchPairs('path', 'product');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<?php echo $gitlabUser->account . " <" . $gitlabUser->email . ">";?>
|
||||
</td>
|
||||
<td><?php echo html::select("zentaoUsers[$gitlabUser->id]", $userPairs, $gitlabUser->zentaoAccount, "class='form-control select chosen'" );?></td>
|
||||
<td><?php echo isset($bindedUsers[$gitlabUser->account]) ? $lang->gitlab->binded : ""; ?></td>
|
||||
<td><?php echo isset($bindedUsers[$gitlabUser->zentaoAccount]) ? $lang->gitlab->binded : ""; ?></td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<th class='c-id'><?php common::printOrderLink('id', $orderBy, $vars, $lang->gitlab->id);?></th>
|
||||
<th class='c-name text-left'><?php common::printOrderLink('name', $orderBy, $vars, $lang->gitlab->name);?></th>
|
||||
<th class='text-left'><?php common::printOrderLink('url', $orderBy, $vars, $lang->gitlab->url);?></th>
|
||||
<th class='c-actions-3'><?php echo $lang->actions;?></th>
|
||||
<th class='c-actions-6'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -47,8 +47,11 @@
|
||||
<td class='c-actions text-left'>
|
||||
<?php
|
||||
$disabled = !empty($gitlab->isAdminToken) ? '' : 'disabled';
|
||||
common::printLink('gitlab', 'browseProject', "gitlabID=$id", "<i class='icon icon-list-box'></i> ", '',"title={$lang->gitlab->browseProject} class='btn btn-primary'");
|
||||
common::printLink('gitlab', 'browseGroup', "gitlabID=$id", "<i class='icon icon-groups'></i> ", '', "title={$lang->gitlab->browseGroup} class='btn btn-primary'");
|
||||
common::printLink('gitlab', 'edit', "gitlabID=$id", "<i class='icon icon-edit'></i> ", '',"title={$lang->gitlab->edit} class='btn btn-primary'");
|
||||
common::printLink('gitlab', 'bindUser', "id=$id", "<i class='icon icon-group'></i> ", '', "title={$lang->gitlab->bindUser} class='btn {$disabled}' ,'disabled'");
|
||||
common::printLink('gitlab', 'browseUser', "gitlabID=$id", "<i class='icon icon-persons'></i> ", '', "title={$lang->gitlab->browseUser} class='btn {$disabled}' ,'disabled'");
|
||||
common::printLink('gitlab', 'bindUser', "id=$id", "<i class='icon icon-link'></i> ", '', "title={$lang->gitlab->bindUser} class='btn {$disabled}' ,'disabled'");
|
||||
if(common::hasPriv('gitlab', 'delete')) echo html::a($this->createLink('gitlab', 'delete', "gitlabID=$id"), '<i class="icon-trash"></i>', 'hiddenwin', "title='{$lang->gitlab->delete}' class='btn'");
|
||||
?>
|
||||
</td>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* The browse view file of gitlab module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2017 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Gang Liu <liugang@cnezsoft.com>
|
||||
* @package gitlab
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<div class='pull-left'>
|
||||
<?php echo html::backButton('<i class="icon icon-back icon-sm"></i> ' . $lang->goback, '', 'btn btn-secondary');?>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-right">
|
||||
<?php if(common::hasPriv('gitlab', 'create')) common::printLink('gitlab', 'createGroup', "gitlabID=$gitlabID", "<i class='icon icon-plus'></i> " . $lang->gitlab->group->create, '', "class='btn btn-primary'");?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if(empty($gitlabGroupList)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->noData;?></span>
|
||||
<?php if(common::hasPriv('gitlab', 'create')):?>
|
||||
<?php echo html::a($this->createLink('gitlab', 'createGroup', "gitlabID=$gitlabID"), "<i class='icon icon-plus'></i> " . $lang->gitlab->group->create, '', "class='btn btn-info'");?>
|
||||
<?php endif;?>
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<div id='mainContent' class='main-row'>
|
||||
<form class='main-table' id='ajaxForm' method='post'>
|
||||
<table id='gitlabGroupList' class='table has-sort-head table-fixed'>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php $vars = "gitlabID=$gitlabID&orderBy=%s";?>
|
||||
<th class='c-id'><?php common::printOrderLink('id', $orderBy, $vars, $lang->gitlab->group->id);?></th>
|
||||
<th class='c-name text-left'><?php common::printOrderLink('name', $orderBy, $vars, $lang->gitlab->group->name);?></th>
|
||||
<th class='text-left'><?php common::printOrderLink('path', $orderBy, $vars, $lang->gitlab->group->path);?></th>
|
||||
<th class='text-left'><?php echo $lang->gitlab->group->createOn;?></th>
|
||||
<th class='c-actions-3'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($gitlabGroupList as $id => $gitlabGroup): ?>
|
||||
<tr class='text'>
|
||||
<td class='text-center'><?php echo $gitlabGroup->id;?></td>
|
||||
<td class='text-c-name' title='<?php echo $gitlabGroup->name;?>'>
|
||||
<?php echo html::avatar(substr($gitlabGroup->name, 0, 1), 20); ?>
|
||||
<span><?php echo $gitlabGroup->name;?></span>
|
||||
</td>
|
||||
<td class='text' title='<?php echo $gitlabGroup->path;?>'><?php echo $gitlabGroup->path;?></td>
|
||||
<td class='text' title='<?php echo substr($gitlabGroup->created_at, 0, 10);?>'><?php echo substr($gitlabGroup->created_at, 0, 10);?></td>
|
||||
<td class='c-actions text-left'>
|
||||
<?php
|
||||
common::printLink('gitlab', 'manageGroupMembers', "gitlabID=$gitlabID&groupID=$gitlabGroup->id", "<i class='icon icon-team'></i> ", '',"title={$lang->gitlab->group->manageMembers} class='btn btn-primary'");
|
||||
common::printLink('gitlab', 'editGroup', "gitlabID=$gitlabID&groupID=$gitlabGroup->id", "<i class='icon icon-edit'></i> ", '', "title={$lang->gitlab->group->edit} class='btn btn-primary'");
|
||||
if(common::hasPriv('gitlab', 'delete')) echo html::a($this->createLink('gitlab', 'deleteGroup', "gitlabID=$gitlabID&groupID=$gitlabGroup->id"), '<i class="icon-trash"></i>', 'hiddenwin', "title='{$lang->gitlab->deleteGroup}' class='btn'");
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* The browse view file of gitlab module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2017 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Gang Liu <liugang@cnezsoft.com>
|
||||
* @package gitlab
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php js::set('vars', "keyword=%s&orderBy=id_desc&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID=1")?>
|
||||
<?php js::set('gitlabID', $gitlabID)?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<div class='pull-left'>
|
||||
<?php echo html::backButton('<i class="icon icon-back icon-sm"></i> ' . $lang->goback, '', 'btn btn-secondary');?>
|
||||
</div>
|
||||
<div id="sidebarHeader">
|
||||
<div class="title"><?php echo $this->lang->gitlab->common . ':' . $gitlab->name; ?></div>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-left">
|
||||
<div>
|
||||
<form id='gitlabprojectForm' method='post'>
|
||||
<?php echo html::input('keyword', $keyword, "class='form-control' placeholder='{$lang->gitlab->placeholderSearch}' style='display: inline-block;width:auto;margin:0 10px'");?>
|
||||
<a id="projectSearch" class="btn btn-primary"><?php echo $lang->gitlab->search?></a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-right">
|
||||
<?php if(common::hasPriv('gitlab', 'createProject')) common::printLink('gitlab', 'createProject', "gitlabID=$gitlabID", "<i class='icon icon-plus'></i> " . $lang->gitlab->project->create, '', "class='btn btn-primary'");?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if(empty($gitlabProjectList)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->noData;?></span>
|
||||
<?php if(common::hasPriv('gitlab', 'createProject')):?>
|
||||
<?php echo html::a($this->createLink('gitlab', 'createProject', "gitlabID=$gitlabID"), "<i class='icon icon-plus'></i> " . $lang->gitlab->project->create, '', "class='btn btn-info'");?>
|
||||
<?php endif;?>
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<div id='mainContent' class='main-row'>
|
||||
<form class='main-table' id='ajaxForm' method='post'>
|
||||
<table id='gitlabProjectList' class='table has-sort-head table-fixed'>
|
||||
<?php $vars = "gitlabID={$gitlabID}&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class='c-id'><?php common::printOrderLink('id', $orderBy, $vars, $lang->gitlab->id);?></th>
|
||||
<th class='c-name text-left'><?php common::printOrderLink('name', $orderBy, $vars, $lang->gitlab->project->name);?></th>
|
||||
<th class='text-left'></th>
|
||||
<th class='text-left'><?php echo $lang->gitlab->lastUpdate;?></th>
|
||||
<th class='c-actions-4'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($gitlabProjectList as $id => $gitlabProject): ?>
|
||||
<tr class='text'>
|
||||
<td class='text-center'><?php echo $gitlabProject->id;?></td>
|
||||
<td class='text-c-name' title='<?php echo $gitlabProject->name;?>'><?php echo $gitlabProject->name_with_namespace;?></td>
|
||||
<td class='text text-c-counts'>
|
||||
<span title="<?php echo $lang->gitlab->project->star;?>"><i class="icon icon-star"></i> <?php echo $gitlabProject->star_count;?></span>
|
||||
<span title="<?php echo $lang->gitlab->project->fork;?>"><i class="icon icon-treemap"></i> <?php echo $gitlabProject->forks_count;?></span>
|
||||
</td>
|
||||
<td class='text' title='<?php echo substr($gitlabProject->last_activity_at, 0, 10);?>'><?php echo substr($gitlabProject->last_activity_at, 0, 10);?></td>
|
||||
<td class='c-actions text-left'>
|
||||
<?php
|
||||
common::printLink('gitlab', 'editProject', "gitlabID=$gitlabID&projectID=$gitlabProject->id", "<i class='icon icon-edit'></i> ", '', "title={$lang->gitlab->project->edit} class='btn btn-primary'");
|
||||
if(common::hasPriv('gitlab', 'delete')) echo html::a($this->createLink('gitlab', 'deleteProject', "gitlabID=$gitlabID&projectID=$gitlabProject->id"), '<i class="icon-trash"></i>', 'hiddenwin', "title='{$lang->gitlab->deleteProject}' class='btn'");
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if($gitlabProjectList):?>
|
||||
<div class='table-footer'><?php $pager->show('right', 'pagerjs');?></div>
|
||||
<?php endif;?>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* The browse view file of gitlab module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2017 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Gang Liu <liugang@cnezsoft.com>
|
||||
* @package gitlab
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<div class='pull-left'>
|
||||
<?php echo html::backButton('<i class="icon icon-back icon-sm"></i> ' . $lang->goback, '', 'btn btn-secondary');?>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-right">
|
||||
<?php common::printLink('gitlab', 'createUser', "gitlabID=$gitlabID", "<i class='icon icon-plus'></i> " . $lang->gitlab->user->create, '', "class='btn btn-primary'");?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if(empty($gitlabUserList)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->noData;?></span>
|
||||
<?php echo html::a($this->createLink('gitlab', 'createProject', "gitlabID=$gitlabID"), "<i class='icon icon-plus'></i> " . $lang->gitlab->user->create, '', "class='btn btn-info'");?>
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<div id='mainContent' class='main-row'>
|
||||
<form class='main-table' id='ajaxForm' method='post'>
|
||||
<table id='gitlabUserList' class='table has-sort-head table-borderless'>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php $vars = "gitlabID=$gitlabID&orderBy=%s";?>
|
||||
<th class='c-id'><?php common::printOrderLink('id', $orderBy, $vars, $lang->gitlab->user->id);?></th>
|
||||
<th class='c-name text-left w-60px'><?php common::printOrderLink('name', $orderBy, $vars, $lang->gitlab->user->name);?></th>
|
||||
<th class='c-name text-left'></th>
|
||||
<th class='text-left'><?php echo $lang->gitlab->user->createOn;?></th>
|
||||
<th class='text-left'><?php echo $lang->gitlab->user->lastActivity;?></th>
|
||||
<th class='c-actions-4'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($gitlabUserList as $id => $gitlabUser): ?>
|
||||
<tr>
|
||||
<td class='text-center'><?php echo $gitlabUser->id;?></td>
|
||||
<td class='w-60px'><?php echo html::image($gitlabUser->avatar, "height=40");?></td>
|
||||
<td class='text-left'>
|
||||
<strong><?php echo $gitlabUser->realname;?></strong>
|
||||
<?php echo $gitlabUser->account . " <" . $gitlabUser->email . ">";?>
|
||||
</td>
|
||||
<td class='text' title='<?php echo substr($gitlabUser->createdAt, 0, 10);?>'><?php echo substr($gitlabUser->createdAt, 0, 10);?></td>
|
||||
<td class='text' title='<?php echo substr($gitlabUser->lastActivityOn, 0, 10);?>'><?php echo substr($gitlabUser->lastActivityOn, 0, 10);?></td>
|
||||
<td class='c-actions text-left'>
|
||||
<?php
|
||||
common::printLink('gitlab', 'editUser', "gitlabID=$gitlabID&userID=$gitlabUser->id", "<i class='icon icon-edit'></i> ", '', "title={$lang->gitlab->user->edit} class='btn btn-primary'");
|
||||
if(common::hasPriv('gitlab', 'delete')) echo html::a($this->createLink('gitlab', 'deleteUser', "gitlabID=$gitlabID&userID=$gitlabUser->id"), '<i class="icon-trash"></i>', 'hiddenwin', "title='{$lang->gitlab->deleteUser}' class='btn'");
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* The create view file of gitlab module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2017 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Gang Liu <liugang@cnezsoft.com>
|
||||
* @package gitlab
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id='mainContent' class='main-row'>
|
||||
<div class='main-col main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $lang->gitlab->group->create;?></h2>
|
||||
</div>
|
||||
<form id='gitlabForm' method='post' class='form-ajax' enctype="multipart/form-data">
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->name;?></th>
|
||||
<td class='required'><?php echo html::input('name', '', "class='form-control' placeholder='{$lang->gitlab->group->name}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->path;?></th>
|
||||
<td class='required'>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon'><?php echo $gitlab->url . '/';?></span>
|
||||
<span><?php echo html::input('path', '', "class='form-control' placeholder='{$lang->gitlab->group->path}'");?></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->description;?></th>
|
||||
<td><?php echo html::textarea('description', '', "rows='4' class='form-control' placeholder='{$lang->gitlab->group->description}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->visibility;?></th>
|
||||
<td colspan='2'><?php echo nl2br(html::radio('visibility', $lang->gitlab->group->visibilityList, 'private', "", 'block'));?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td>
|
||||
<div class="checkbox-primary">
|
||||
<input type="checkbox" name='request_access_enabled' id="requestAccessEnabled" value='1' checked /><label for="external" class="no-margin"><?php echo $lang->gitlab->group->requestAccessEnabledTip; ?></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->lfsEnabled;?></th>
|
||||
<td colspan='2'>
|
||||
<div class="checkbox-primary">
|
||||
<input type="checkbox" name='lfs_enabled' id="lfsEnabled" value='1' checked /><label for="external" class="no-margin"><?php echo $lang->gitlab->group->lfsEnabledTip; ?></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->projectCreationLevel;?></th>
|
||||
<td><?php echo html::select('project_creation_level', $lang->gitlab->group->projectCreationLevelList, 'developer', "class='form-control'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->subgroupCreationLevel;?></th>
|
||||
<td><?php echo html::select('subgroup_creation_level', $lang->gitlab->group->subgroupCreationLevelList, 'maintainer', "class='form-control'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
<?php if(!isonlybody()) echo html::a(inlink('browseGroup', "gitlabID=$gitlabID"), $lang->goback, '', 'class="btn btn-wide"');?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* The create view file of gitlab module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2017 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Gang Liu <liugang@cnezsoft.com>
|
||||
* @package gitlab
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id='mainContent' class='main-row'>
|
||||
<div class='main-col main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $lang->gitlab->project->create;?></h2>
|
||||
</div>
|
||||
<form id='gitlabForm' method='post' class='form-ajax'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->project->name;?></th>
|
||||
<td class='required'><?php echo html::input('name', '', "class='form-control' placeholder='{$lang->gitlab->project->name}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->project->url;?></th>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<?php if(count($namespaces) < 2):?>
|
||||
<?php echo html::input('url', $gitlab->url . '/' . $user->username . '/', "class='form-control' disabled");?>
|
||||
<?php else:?>
|
||||
<span class='input-group-addon'><?php echo $gitlab->url . '/';?></span>
|
||||
<?php echo html::select('namespace_id', $namespaces, $user->username, "class='form-control'");?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->project->path;?></th>
|
||||
<td class='required'><?php echo html::input('path', '', "class='form-control' placeholder='{$lang->gitlab->placeholder->projectPath}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->project->description;?></th>
|
||||
<td><?php echo html::textarea('description', '', "rows='10' class='form-control' placeholder='{$lang->gitlab->project->description}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->project->visibility;?></th>
|
||||
<td colspan='2'><?php echo nl2br(html::radio('visibility', $lang->gitlab->project->visibilityList, 'private', "", 'block'));?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
<?php if(!isonlybody()) echo html::a(inlink('browseProject', "gitlabID=$gitlabID"), $lang->goback, '', 'class="btn btn-wide"');?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* The create view file of gitlab module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2017 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Gang Liu <liugang@cnezsoft.com>
|
||||
* @package gitlab
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id='mainContent' class='main-row'>
|
||||
<div class='main-col main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $lang->gitlab->user->create;?></h2>
|
||||
</div>
|
||||
<form id='gitlabForm' method='post' class='form-ajax' enctype="multipart/form-data">
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->bind;?></th>
|
||||
<td class='required'><?php echo html::select('account', $userPairs, '', "class='form-control chosen'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->name;?></th>
|
||||
<td class='required'><?php echo html::input('name', '', "class='form-control' placeholder='{$lang->gitlab->user->name}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->username;?></th>
|
||||
<td class='required'><?php echo html::input('username', '', "class='form-control' placeholder='{$lang->gitlab->user->username}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->email;?></th>
|
||||
<td class='required'><?php echo html::input('email', '', "class='form-control' placeholder='{$lang->gitlab->user->email}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->password;?></th>
|
||||
<td class='required'><?php echo html::password('password', '', "class='form-control' placeholder='{$lang->gitlab->user->password}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->passwordRepeat;?></th>
|
||||
<td class='required'><?php echo html::password('password_repeat', '', "class='form-control' placeholder='{$lang->gitlab->user->passwordRepeat}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr class="hidden">
|
||||
<th><?php echo $lang->gitlab->user->projectsLimit;?></th>
|
||||
<td><?php echo html::input('projects_limit', 100000, "class='form-control' placeholder='{$lang->gitlab->user->projectsLimit}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->canCreateGroup;?></th>
|
||||
<td>
|
||||
<div class="checkbox-primary">
|
||||
<input type="checkbox" name='can_create_group' id="canCreateGroup" value='1' checked /><label for="external" class="no-margin"> </label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->external;?></th>
|
||||
<td colspan='2'>
|
||||
<div class="checkbox-primary">
|
||||
<input type="checkbox" name='external' id="external" value='1'/><label for="external" class="no-margin"><?php echo $lang->gitlab->user->externalTip; ?></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if(function_exists('curl_file_create')):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->avatar;?></th>
|
||||
<td>
|
||||
<div id="avatarUpload" class="text-center">
|
||||
<?php echo html::avatar(array('avatar'=>' ', 'account'=>''), 50); ?>
|
||||
<input type="file" name="avatar" id="files" class="form-control hidden">
|
||||
<?php echo html::a('javascript:void(0);', '<i class="icon icon-pencil icon-2x"></i>', '', "class='btn-avatar' id='avatarUploadBtn' data-toggle='tooltip' data-container='body' data-placement='bottom' title='{$lang->gitlab->user->avatar}'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
<?php if(!isonlybody()) echo html::a(inlink('browseUser', "gitlabID=$gitlabID"), $lang->goback, '', 'class="btn btn-wide"');?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -21,16 +21,16 @@
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->name;?></th>
|
||||
<td class='required'><?php echo html::input('name', $gitlab->name, "class='form-control' placeholder='{$lang->gitlab->placeholder->name}'");?></td>
|
||||
<td class='required'><?php echo html::input('name', isset($gitlab->name) ? $gitlab->name : '', "class='form-control' placeholder='{$lang->gitlab->placeholder->name}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->url;?></th>
|
||||
<td class='required'><?php echo html::input('url', $gitlab->url, "class='form-control' placeholder='{$lang->gitlab->placeholder->url}'");?></td>
|
||||
<td class='required'><?php echo html::input('url', isset($gitlab->url) ? $gitlab->url : '', "class='form-control' placeholder='{$lang->gitlab->placeholder->url}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->token;?></th>
|
||||
<td><?php echo html::input('token', $gitlab->token, "class='form-control' placeholder='{$lang->gitlab->placeholder->token}'");?></td>
|
||||
<td><?php echo html::input('token', isset($gitlab->token) ? $gitlab->token : '', "class='form-control' placeholder='{$lang->gitlab->placeholder->token}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* The create view file of gitlab module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2017 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Gang Liu <liugang@cnezsoft.com>
|
||||
* @package gitlab
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id='mainContent' class='main-row'>
|
||||
<div class='main-col main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $lang->gitlab->group->edit;?></h2>
|
||||
</div>
|
||||
<form id='gitlabForm' method='post' class='form-ajax' enctype="multipart/form-data">
|
||||
<?php echo html::hidden('id', $group->id);?>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->name;?></th>
|
||||
<td class='required'><?php echo html::input('name', $group->name, "class='form-control' placeholder='{$lang->gitlab->group->name}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->path;?></th>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon'><?php echo $gitlab->url . '/';?></span>
|
||||
<span><?php echo html::input('path', $group->path, "readonly class='form-control' placeholder='{$lang->gitlab->group->path}'");?></span>
|
||||
</div>
|
||||
<div class="alert alert-warning hidden"><?php echo $lang->gitlab->group->pathTip;?></div>
|
||||
</td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->description;?></th>
|
||||
<td><?php echo html::textarea('description', $group->description, "rows='4' class='form-control' placeholder='{$lang->gitlab->group->description}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->visibility;?></th>
|
||||
<td colspan='2'><?php echo nl2br(html::radio('visibility', $lang->gitlab->group->visibilityList, $group->visibility, "", 'block'));?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td>
|
||||
<div class="checkbox-primary">
|
||||
<input type="checkbox" name='request_access_enabled' id="requestAccessEnabled" value='1' <?php if($group->request_access_enabled) echo 'checked';?> /><label for="external" class="no-margin"><?php echo $lang->gitlab->group->requestAccessEnabledTip; ?></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->lfsEnabled;?></th>
|
||||
<td colspan='2'>
|
||||
<div class="checkbox-primary">
|
||||
<input type="checkbox" name='lfs_enabled' id="lfsEnabled" value='1' <?php if($group->lfs_enabled) echo 'checked';?> /><label for="external" class="no-margin"><?php echo $lang->gitlab->group->lfsEnabledTip; ?></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->projectCreationLevel;?></th>
|
||||
<td><?php echo html::select('project_creation_level', $lang->gitlab->group->projectCreationLevelList, $group->project_creation_level, "class='form-control'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->group->subgroupCreationLevel;?></th>
|
||||
<td><?php echo html::select('subgroup_creation_level', $lang->gitlab->group->subgroupCreationLevelList, $group->subgroup_creation_level, "class='form-control'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
<?php if(!isonlybody()) echo html::a(inlink('browseGroup', "gitlabID=$gitlabID"), $lang->goback, '', 'class="btn btn-wide"');?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* The create view file of gitlab module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2017 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Gang Liu <liugang@cnezsoft.com>
|
||||
* @package gitlab
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id='mainContent' class='main-row'>
|
||||
<div class='main-col main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $lang->gitlab->project->edit;?></h2>
|
||||
</div>
|
||||
<form id='gitlabForm' method='post' class='form-ajax'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->project->id;?></th>
|
||||
<td><?php echo html::input('id', $project->id, "class='form-control' readonly placeholder='{$lang->gitlab->project->id}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->project->name;?></th>
|
||||
<td class='required'><?php echo html::input('name', $project->name, "class='form-control' placeholder='{$lang->gitlab->project->name}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->project->description;?></th>
|
||||
<td><?php echo html::textarea('description', $project->description, "rows='10' class='form-control' placeholder='{$lang->gitlab->project->description}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->project->visibility;?></th>
|
||||
<td colspan='2'><?php echo nl2br(html::radio('visibility', $lang->gitlab->project->visibilityList, $project->visibility, "", 'block'));?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
<?php if(!isonlybody()) echo html::a(inlink('browseProject', "gitlabID=$gitlabID"), $lang->goback, '', 'class="btn btn-wide"');?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* The create view file of gitlab module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2017 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Gang Liu <liugang@cnezsoft.com>
|
||||
* @package gitlab
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id='mainContent' class='main-row'>
|
||||
<div class='main-col main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $lang->gitlab->user->edit;?></h2>
|
||||
</div>
|
||||
<form id='gitlabForm' method='post' class='form-ajax' enctype="multipart/form-data">
|
||||
<?php echo html::hidden('id', $user->id);?>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->bind;?></th>
|
||||
<td class='required'><?php echo html::select('account', $userPairs, $zentaoBindAccount, "class='form-control chosen'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->name;?></th>
|
||||
<td class='required'><?php echo html::input('name', $user->name, "class='form-control' placeholder='{$lang->gitlab->user->name}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->username;?></th>
|
||||
<td><?php echo html::input('username', $user->username, "readonly class='form-control' placeholder='{$lang->gitlab->user->username}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->email;?></th>
|
||||
<td class='required'><?php echo html::input('email', $user->email, "class='form-control' placeholder='{$lang->gitlab->user->email}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->password;?></th>
|
||||
<td><?php echo html::password('password', '', "class='form-control' placeholder='{$lang->gitlab->user->password}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->passwordRepeat;?></th>
|
||||
<td><?php echo html::password('password_repeat', '', "class='form-control' placeholder='{$lang->gitlab->user->passwordRepeat}'");?></td>
|
||||
<td class="tips-git"></td>
|
||||
</tr>
|
||||
<tr class="hidden">
|
||||
<th><?php echo $lang->gitlab->user->projectsLimit;?></th>
|
||||
<td><?php echo html::input('projects_limit', $user->projects_limit, "class='form-control' placeholder='{$lang->gitlab->user->projectsLimit}'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->canCreateGroup;?></th>
|
||||
<td>
|
||||
<div class="checkbox-primary">
|
||||
<input type="checkbox" name='can_create_group' id="canCreateGroup" value='1' <?php if($user->can_create_group) echo 'checked';?> /><label for="external" class="no-margin"> </label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->external;?></th>
|
||||
<td colspan='2'>
|
||||
<div class="checkbox-primary">
|
||||
<input type="checkbox" name='external' id="external" value='1' <?php if($user->external) echo 'checked';?> /><label for="external" class="no-margin"><?php echo $lang->gitlab->user->externalTip; ?></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if(function_exists('curl_file_create')):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->gitlab->user->avatar;?></th>
|
||||
<td>
|
||||
<div id="avatarUpload" class="text-center">
|
||||
<?php echo html::avatar(array('avatar'=>$user->avatar_url, 'account'=>''), 50); ?>
|
||||
<input type="file" name="avatar" id="files" class="form-control hidden">
|
||||
<?php echo html::a('javascript:void(0);', '<i class="icon icon-pencil icon-2x"></i>', '', "class='btn-avatar' id='avatarUploadBtn' data-toggle='tooltip' data-container='body' data-placement='bottom' title='{$lang->gitlab->user->avatar}'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
<?php if(!isonlybody()) echo html::a(inlink('browseUser', "gitlabID=$gitlabID"), $lang->goback, '', 'class="btn btn-wide"');?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php js::set('oldAccountList', array_keys($currentMembers));?>
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
<span class='btn btn-link btn-active-text'>
|
||||
<?php echo html::a('###', "<span class='text'> {$lang->gitlab->group->manageMembers}</span>");?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<form class='main-form form-ajax' method='post' id='teamForm'>
|
||||
<table class='table table-form'>
|
||||
<thead>
|
||||
<tr class='text-center'>
|
||||
<th><?php echo $lang->gitlab->group->memberName;?></th>
|
||||
<th><?php echo $lang->gitlab->group->memberAccessLevel;?></th>
|
||||
<th class='c-date'><?php echo $lang->gitlab->group->memberExpiresAt;?></th>
|
||||
<th class="c-actions"><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $i = 0;?>
|
||||
<?php foreach($currentMembers as $member):?>
|
||||
<tr>
|
||||
<td><?php echo html::input("names[$i]", $member->name, "class='form-control' readonly");?></td>
|
||||
<td><?php echo html::select("levels[$i]", array(''=>'') + $this->lang->gitlab->accessLevels, $member->access_level, "class='form-control chosen'");?></td>
|
||||
<td>
|
||||
<?php echo html::input("expires[$i]", $member->expires_at, "class='form-control form-date'");?>
|
||||
<?php echo html::hidden("ids[$i]", $member->id);?>
|
||||
</td>
|
||||
<td class='c-actions text-center'>
|
||||
<?php echo html::a('javascript:;', "<i class='icon-plus'></i>", '', "onclick='addItem(this)' class='btn btn-link'");?>
|
||||
<?php echo html::a('javascript:;', "<i class='icon icon-close'></i>", '', "onclick='deleteItem(this)' class='btn btn-link'");?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php $i ++;?>
|
||||
<?php endforeach;?>
|
||||
|
||||
<?php for($j = 0; $j < 5; $j ++):?>
|
||||
<tr class='addedItem'>
|
||||
<td><?php echo html::select("ids[$i]", $gitlabUsers, '', "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::select("levels[$i]", array(''=>'') + $this->lang->gitlab->accessLevels, '', "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::input("expires[$i]", '', "class='form-control form-date'");?></td>
|
||||
<td class='c-actions text-center'>
|
||||
<?php echo html::a('javascript:;', "<i class='icon-plus'></i>", '', "onclick='addItem(this)' class='btn btn-link'");?>
|
||||
<?php echo html::a('javascript:;', "<i class='icon icon-close'></i>", '', "onclick='deleteItem(this)' class='btn btn-link'");?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php $i ++;?>
|
||||
<?php endfor;?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan='6' class='text-center form-actions'>
|
||||
<?php
|
||||
echo html::submitButton('', '', 'hidden btn btn-wide btn-primary');
|
||||
echo html::commonButton($lang->save, 'onclick="saveMembers()" id="saveBtn"', 'btn btn-wide btn-primary');
|
||||
|
||||
echo html::backButton();
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<?php js::set('i', $i);?>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<?php $i = '%i%';?>
|
||||
<table class='hidden'>
|
||||
<tr id='addItem' class='hidden'>
|
||||
<td><?php echo html::select("ids[]", $gitlabUsers, '', "class='form-control'");?></td>
|
||||
<td><?php echo html::select("levels[]", array(''=>'') + $this->lang->gitlab->accessLevels, '', "class='form-control'");?></td>
|
||||
<td><?php echo html::input("expires[$i]", '', "class='form-control form-date'");?></td>
|
||||
<td class='c-actions text-center'>
|
||||
<?php echo html::a('javascript:;', "<i class='icon-plus'></i>", '', "onclick='addItem(this)' class='btn btn-link'");?>
|
||||
<?php echo html::a('javascript:;', "<i class='icon icon-close'></i>", '', "onclick='deleteItem(this)' class='btn btn-link'");?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user