diff --git a/db/update16.0.beta1.sql b/db/update16.0.beta1.sql new file mode 100644 index 0000000000..6634ac2b81 --- /dev/null +++ b/db/update16.0.beta1.sql @@ -0,0 +1,7 @@ +ALTER TABLE `zt_task` ADD `repo` mediumint unsigned NOT NULL AFTER `activatedDate`; +ALTER TABLE `zt_task` ADD `entry` varchar(255) NOT NULL AFTER `repo`; +ALTER TABLE `zt_task` ADD `lines` varchar(10) NOT NULL AFTER `entry`; +ALTER TABLE `zt_task` ADD `v1` varchar(40) NOT NULL AFTER `lines`; +ALTER TABLE `zt_task` ADD `v2` varchar(40) NOT NULL AFTER `v1`; +ALTER TABLE `zt_task` ADD `mr` mediumint(8) unsigned NOT NULL AFTER `repo`; +ALTER TABLE `zt_bug` ADD `mr` mediumint(8) unsigned NOT NULL AFTER `repo`; diff --git a/module/gitlab/config.php b/module/gitlab/config.php index bd6760c7cc..d02cf70f27 100644 --- a/module/gitlab/config.php +++ b/module/gitlab/config.php @@ -8,6 +8,9 @@ $config->gitlab->edit->requiredFields = 'name,url,token'; $config->gitlab->createbranch = new stdclass; $config->gitlab->createbranch->requiredFields = 'branch,ref'; +$config->gitlab->createbranchpriv = new stdclass; +$config->gitlab->createbranchpriv->requiredFields = 'name'; + $config->gitlab->labelPattern = new stdclass; $config->gitlab->labelPattern->task = '/^zentao_task\/\d+$/'; $config->gitlab->labelPattern->bug = '/^zentao_bug\/\d+$/'; diff --git a/module/gitlab/control.php b/module/gitlab/control.php index 52eb02b5fa..5206321ea7 100644 --- a/module/gitlab/control.php +++ b/module/gitlab/control.php @@ -798,6 +798,138 @@ class gitlab extends control $this->display(); } + /** + * Browse gitlab protect branch. + * + * @param int $gitlabID + * @param int $projectID + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function browseBranchPriv($gitlabID, $projectID, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1) + { + $keyword = fixer::input('post')->setDefault('keyword', '')->get('keyword'); + $branches = $this->gitlab->apiGetBranchPrivs($gitlabID, $projectID, $keyword, $orderBy); + $project = $this->gitlab->apiGetSingleProject($gitlabID, $projectID); + + /* Pager. */ + $this->app->loadClass('pager', $static = true); + $recTotal = count($branches); + $pager = new pager($recTotal, $recPerPage, $pageID); + $branchList = array_chunk($branches, $pager->recPerPage); + + $this->view->keyword = $keyword; + $this->view->pager = $pager; + $this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->browseBranchPriv; + $this->view->levelLang = $this->lang->gitlab->branch->branchCreationLevelList; + $this->view->gitlabID = $gitlabID; + $this->view->projectID = $projectID; + $this->view->project = $project; + $this->view->orderBy = $orderBy; + $this->view->branchList = empty($branchList) ? $branchList: $branchList[$pageID - 1]; + $this->display(); + } + + /** + * Set a gitlab protect branch. + * + * @param int $gitlabID + * @param int $projectID + * @param string $branch + * @access public + * @return void + */ + public function createBranchPriv($gitlabID, $projectID, $branch = '') + { + if($_POST) + { + $this->gitlab->createBranchPriv($gitlabID, $projectID, $branch); + + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browseBranchPriv', "gitlabID=$gitlabID&projectID=$projectID"))); + } + + $branchPriv = new stdClass(); + $branchPriv->name = ''; + $branchPriv->mergeAccessLevel = 40; // Initialize data, and the operation authority is the maintainers by default. + $branchPriv->pushAccessLevel = 40; // Initialize data, and the operation authority is the maintainers by default. + + $gitlab = $this->gitlab->getByID($gitlabID); + $title = $this->lang->gitlab->createBranchPriv; + + if($branch) + { + $title = $this->lang->gitlab->editBranchPriv; + $branchPriv = $this->gitlab->apiGetSingleBranchPriv($gitlabID, $projectID, $branch); + $branchPriv->mergeAccessLevel = $this->gitlab->checkAccessLevel($branchPriv->merge_access_levels); + $branchPriv->pushAccessLevel = $this->gitlab->checkAccessLevel($branchPriv->push_access_levels); + } + + $gitlabBranches = $this->gitlab->apiGetBranches($gitlabID, $projectID); + $protectBranches = $this->gitlab->apiGetBranchPrivs($gitlabID, $projectID, '', 'name_asc'); + $protectNames = array_keys($protectBranches); + + $branches = array(); + foreach($gitlabBranches as $oneBranch) + { + if(!in_array($oneBranch->name, $protectNames) || $oneBranch->name == $branch) $branches[$oneBranch->name] = $oneBranch->name; + } + + $this->view->title = $this->lang->gitlab->common . $this->lang->colon . $title; + $this->view->pageTitle = $title; + $this->view->gitlab = $gitlab; + $this->view->gitlabID = $gitlabID; + $this->view->branch = $branch; + $this->view->projectID = $projectID; + $this->view->branches = $branches; + $this->view->branchPriv = $branchPriv; + $this->display(); + } + + /** + * Edit a gitlab branch protect. + * + * @param int $gitlabID + * @param int $projectID + * @param string $branch + * @access public + * @return void + */ + public function editBranchPriv($gitlabID, $projectID, $branch) + { + echo $this->fetch('gitlab', 'createBranchPriv', "gitlabID=$gitlabID&projectID=$projectID&branch=$branch"); + } + + /** + * Delete a gitlab protect branch. + * + * @param int $gitlabID + * @param int $projectID + * @param string $branch + * @param string $confirm + * @access public + * @return void + */ + public function deleteBranchPriv($gitlabID, $projectID, $branch, $confirm = 'no') + { + if($confirm != 'yes') die(js::confirm($this->lang->gitlab->branch->confirmDelete , inlink('deleteBranchPriv', "gitlabID=$gitlabID&projectID=$projectID&branch=$branch&confirm=yes"))); + + $reponse = $this->gitlab->apiDeleteBranchPriv($gitlabID, $projectID, $branch); + + /* 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('gitlabbranchPriv', $branch, 'deleted', '', $branch); + die(js::reload('parent')); + } + + die(js::alert($reponse->message)); + } + /** * Import gitlab issue to zentaopms. * diff --git a/module/gitlab/css/browsebranchpriv.css b/module/gitlab/css/browsebranchpriv.css new file mode 100644 index 0000000000..d86ca85e6a --- /dev/null +++ b/module/gitlab/css/browsebranchpriv.css @@ -0,0 +1,2 @@ +.text-c-counts > span {margin-left: 5px;} +#mainMenu .pull-left {margin-right: 15px;} diff --git a/module/gitlab/css/createbranchpriv.css b/module/gitlab/css/createbranchpriv.css new file mode 100644 index 0000000000..025aeb5e7f --- /dev/null +++ b/module/gitlab/css/createbranchpriv.css @@ -0,0 +1,2 @@ +.table-form>tbody>tr>th {width: 110px;} +.table-form {width: 50%;} diff --git a/module/gitlab/js/browsebranchpriv.js b/module/gitlab/js/browsebranchpriv.js new file mode 100644 index 0000000000..806b8bc4e1 --- /dev/null +++ b/module/gitlab/js/browsebranchpriv.js @@ -0,0 +1,23 @@ +$(document).ready(function() +{ + $('#branchSearch').click(function() + { + triggerSearch(); + }); + $('#keyword').keypress(function(event) + { + if(event.which == 13) triggerSearch(); + }) + +}); + +/** + * Trigger filtering function. + * + * @access public + * @return void + */ +function triggerSearch() +{ + $("#branchPrivForm").submit(); +} diff --git a/module/gitlab/js/managegroupmembers.js b/module/gitlab/js/managegroupmembers.js index 589e0ffc61..f67e13d81e 100644 --- a/module/gitlab/js/managegroupmembers.js +++ b/module/gitlab/js/managegroupmembers.js @@ -41,6 +41,6 @@ function addItem(obj) */ function deleteItem(obj) { - if($('#teamForm .table tbody').children().length < 2) return false; + if($('#teamForm .table-form tbody').children().length < 2) return false; $(obj).closest('tr').remove(); -} \ No newline at end of file +} diff --git a/module/gitlab/js/manageprojectmembers.js b/module/gitlab/js/manageprojectmembers.js index 589e0ffc61..f67e13d81e 100644 --- a/module/gitlab/js/manageprojectmembers.js +++ b/module/gitlab/js/manageprojectmembers.js @@ -41,6 +41,6 @@ function addItem(obj) */ function deleteItem(obj) { - if($('#teamForm .table tbody').children().length < 2) return false; + if($('#teamForm .table-form tbody').children().length < 2) return false; $(obj).closest('tr').remove(); -} \ No newline at end of file +} diff --git a/module/gitlab/lang/en.php b/module/gitlab/lang/en.php index e91ab12140..cf6809d55d 100644 --- a/module/gitlab/lang/en.php +++ b/module/gitlab/lang/en.php @@ -47,6 +47,10 @@ $lang->gitlab->deleteUser = 'Delete user'; $lang->gitlab->createBranch = 'Add branch'; $lang->gitlab->manageGroupMembers = 'Manage group member'; $lang->gitlab->createWebhook = 'Create Webhook'; +$lang->gitlab->browseBranchPriv = 'Protect branch'; +$lang->gitlab->createBranchPriv = 'Cerate branch protected'; +$lang->gitlab->editBranchPriv = 'Edit branch protected'; +$lang->gitlab->deleteBranchPriv = 'Delete branch protected'; $lang->gitlab->id = 'ID'; $lang->gitlab->name = "GitLab Name"; @@ -128,7 +132,7 @@ $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->bind = "Zentao user"; $lang->gitlab->user->avatar = "Avatar"; $lang->gitlab->user->skype = "Skype"; $lang->gitlab->user->linkedin = "Linkedin"; @@ -180,8 +184,19 @@ $lang->gitlab->group->memberExpiresAt = 'Expiration time $lang->gitlab->group->repeatError = "Group members cannot be added repeatedly"; $lang->gitlab->branch = new stdclass(); -$lang->gitlab->branch->name = 'Branch Name'; -$lang->gitlab->branch->from = 'Create from'; -$lang->gitlab->branch->create = 'Create'; -$lang->gitlab->branch->lastCommitter = 'Last Committer'; -$lang->gitlab->branch->lastCommittedDate = 'Last Committed Date'; +$lang->gitlab->branch->name = 'Branch Name'; +$lang->gitlab->branch->from = 'Create from'; +$lang->gitlab->branch->create = 'Create'; +$lang->gitlab->branch->lastCommitter = 'Last Committer'; +$lang->gitlab->branch->lastCommittedDate = 'Last Committed Date'; +$lang->gitlab->branch->accessLevel = "Branch protection list"; +$lang->gitlab->branch->mergeAllowed = "Merge Allowed"; +$lang->gitlab->branch->pushAllowed = "Push Allowed"; +$lang->gitlab->branch->placeholderSearch = "Branch name"; +$lang->gitlab->branch->placeholderSelect = "Branch name"; +$lang->gitlab->branch->confirmDelete = 'Branch will be writable for developers. Are you sure?'; +$lang->gitlab->branch->branchCreationLevelList[40] = "Maintainers"; +$lang->gitlab->branch->branchCreationLevelList[30] = "Developers + Maintainers"; +$lang->gitlab->branch->branchCreationLevelList[0] = "No one"; +$lang->gitlab->branch->emptyPrivNameError = "Branch cannot be empty."; +$lang->gitlab->branch->issetPrivNameError = "The protection branch already exists"; diff --git a/module/gitlab/lang/zh-cn.php b/module/gitlab/lang/zh-cn.php index 18e4da724c..3b58bb2bcf 100644 --- a/module/gitlab/lang/zh-cn.php +++ b/module/gitlab/lang/zh-cn.php @@ -47,6 +47,10 @@ $lang->gitlab->deleteUser = '删除用户'; $lang->gitlab->createBranch = '添加分支'; $lang->gitlab->manageGroupMembers = '群组成员管理'; $lang->gitlab->createWebhook = '创建Webhook'; +$lang->gitlab->browseBranchPriv = '分支保护管理'; +$lang->gitlab->createBranchPriv = '创建分支保护'; +$lang->gitlab->editBranchPriv = '编辑分支保护'; +$lang->gitlab->deleteBranchPriv = '删除分支保护'; $lang->gitlab->id = 'ID'; $lang->gitlab->name = "{$lang->gitlab->common}名称"; @@ -128,7 +132,7 @@ $lang->gitlab->user->projectsLimit = "限制项目"; $lang->gitlab->user->canCreateGroup = "可创建组"; $lang->gitlab->user->external = "外部人员"; $lang->gitlab->user->externalTip = "除非明确授予访问权限,否则外部用户无法查看内部或私有项目。另外,外部用户无法创建项目,群组或个人代码片段。"; -$lang->gitlab->user->bind = "绑定禅道用户"; +$lang->gitlab->user->bind = "禅道用户"; $lang->gitlab->user->avatar = "头像"; $lang->gitlab->user->skype = "Skype"; $lang->gitlab->user->linkedin = "Linkedin"; @@ -180,8 +184,19 @@ $lang->gitlab->group->memberExpiresAt = '过期时间'; $lang->gitlab->group->repeatError = "群组成员不能重复添加"; $lang->gitlab->branch = new stdclass(); -$lang->gitlab->branch->name = '分支名'; -$lang->gitlab->branch->from = '创建自'; -$lang->gitlab->branch->create = '创建'; -$lang->gitlab->branch->lastCommitter = '最后提交'; -$lang->gitlab->branch->lastCommittedDate = '最后修改时间'; +$lang->gitlab->branch->name = '分支名'; +$lang->gitlab->branch->from = '创建自'; +$lang->gitlab->branch->create = '创建'; +$lang->gitlab->branch->lastCommitter = '最后提交'; +$lang->gitlab->branch->lastCommittedDate = '最后修改时间'; +$lang->gitlab->branch->accessLevel = "分支保护列表"; +$lang->gitlab->branch->mergeAllowed = "允许合并到"; +$lang->gitlab->branch->pushAllowed = "允许推送到"; +$lang->gitlab->branch->placeholderSearch = "请输入分支名称"; +$lang->gitlab->branch->placeholderSelect = "请选择分支"; +$lang->gitlab->branch->confirmDelete = '确定删除分支保护?'; +$lang->gitlab->branch->branchCreationLevelList[40] = "维护者"; +$lang->gitlab->branch->branchCreationLevelList[30] = "开发者 + 维护者"; +$lang->gitlab->branch->branchCreationLevelList[0] = "禁止"; +$lang->gitlab->branch->emptyPrivNameError = "分支不能为空"; +$lang->gitlab->branch->issetPrivNameError = "已存在该保护分支"; diff --git a/module/gitlab/model.php b/module/gitlab/model.php index 6ca9804d8d..bb8d76d3bc 100644 --- a/module/gitlab/model.php +++ b/module/gitlab/model.php @@ -2332,4 +2332,134 @@ class gitlabModel extends model ->andWhere('path')->in($projectIDs) ->fetchPairs('path', 'product'); } + + /** + * Get protect branches of one project. + * + * @param int $gitlabID + * @param int $projectID + * @param string $keyword + * @param string $orderBy + * @access public + * @return array + */ + public function apiGetBranchPrivs($gitlabID, $projectID, $keyword = '', $orderBy = 'id_desc') + { + $keyword = urlencode($keyword); + $url = sprintf($this->getApiRoot($gitlabID), "/projects/$projectID/protected_branches"); + $branches = json_decode(commonModel::http($url)); + + /* Parse order string. */ + $order = explode('_', $orderBy); + + $newBranches = array(); + foreach($branches as $branch) + { + if(empty($keyword) || stristr($branch->name, $keyword)) $newBranches[$branch->{$order[0]}] = $branch; + } + + if($order[1] == 'asc') ksort($newBranches); + if($order[1] == 'desc') krsort($newBranches); + + return $newBranches; + } + + /** + * Get single protct branch by API. + * + * @param int $gitlabID + * @param int $projectID + * @param string $branch + * @access public + * @return object + */ + public function apiGetSingleBranchPriv($gitlabID, $projectID, $branch) + { + $url = sprintf($this->getApiRoot($gitlabID), "/projects/$projectID/protected_branches/$branch"); + return json_decode(commonModel::http($url)); + } + + /** + * Create gitlab potect branch. + * + * @param int $gitlabID + * @param int $projectID + * @param string $branch + * @access public + * @return bool + */ + public function createBranchPriv($gitlabID, $projectID, $branch = '') + { + $priv = fixer::input('post')->get(); + if(empty($priv->name)) dao::$errors['name'][] = $this->lang->gitlab->branch->emptyPrivNameError; + $singleBranch = $this->apiGetSingleBranchPriv($gitlabID, $projectID, $priv->name); + if(empty($branch) && !empty($singleBranch->id)) dao::$errors['name'][] = $this->lang->gitlab->branch->issetPrivNameError; + if(dao::isError()) return false; + if(!empty($branch) && !empty($singleBranch->id)) $this->apiDeleteBranchPriv($gitlabID, $projectID, $branch); + + $response = $this->apiCreateBranchPriv($gitlabID, $projectID, $priv); + + if(!empty($response->id)) + { + $action = empty($branch) ? 'created' : 'edited'; + $this->loadModel('action')->create('gitlabbranchpriv', $response->id, $action, '', $response->name); + return true; + } + + return $this->apiErrorHandling($response); + } + + /** + * Create a gitab protect branch by api. + * + * @param int $gitlabID + * @param int $projectID + * @param object $priv + * @access public + * @return object + */ + public function apiCreateBranchPriv($gitlabID, $projectID, $priv) + { + if(empty($priv->name)) return false; + $url = sprintf($this->getApiRoot($gitlabID), "/projects/" . $projectID . '/protected_branches'); + return json_decode(commonModel::http($url, $priv)); + } + + /** + * Delete a gitab protect branch by api. + * + * @param int $gitlabID + * @param int $projectID + * @param string $branch + * @access public + * @return object + */ + public function apiDeleteBranchPriv($gitlabID, $projectID, $branch) + { + $apiRoot = $this->getApiRoot($gitlabID); + $url = sprintf($apiRoot, "/projects/{$projectID}/protected_branches/{$branch}"); + return json_decode(commonModel::http($url, array(), $options = array(CURLOPT_CUSTOMREQUEST => 'DELETE'))); + } + + /** + * Check access level. + * + * @param array $accessLevels + * @access public + * @return int + */ + public function checkAccessLevel($accessLevels) + { + $noAccess = 0; + $developerAccess = 30; + $maintainerAccess = 40; + if(is_array($accessLevels)) + { + $levels = array(); + foreach($accessLevels as $level) $levels[] = (int)$level->access_level; + if(in_array($noAccess, $levels)) return $noAccess; + if(in_array($developerAccess, $levels)) return $developerAccess; + } + return $maintainerAccess; + } } diff --git a/module/gitlab/view/browse.html.php b/module/gitlab/view/browse.html.php index 7b12b003f1..07d3783305 100644 --- a/module/gitlab/view/browse.html.php +++ b/module/gitlab/view/browse.html.php @@ -50,7 +50,7 @@ common::printLink('gitlab', 'browseProject', "gitlabID=$id", " ", '',"title={$lang->gitlab->browseProject} class='btn btn-primary'"); common::printLink('gitlab', 'browseGroup', "gitlabID=$id", " ", '', "title={$lang->gitlab->browseGroup} class='btn btn-primary'"); common::printLink('gitlab', 'edit', "gitlabID=$id", " ", '',"title={$lang->gitlab->edit} class='btn btn-primary'"); - common::printLink('gitlab', 'browseUser', "gitlabID=$id", " ", '', "title={$lang->gitlab->browseUser} class='btn {$disabled}' ,'disabled'"); + common::printLink('gitlab', 'browseUser', "gitlabID=$id", " ", '', "title={$lang->gitlab->browseUser} class='btn {$disabled}' ,'disabled'"); common::printLink('gitlab', 'bindUser', "id=$id", " ", '', "title={$lang->gitlab->bindUser} class='btn {$disabled}' ,'disabled'"); if(common::hasPriv('gitlab', 'delete')) echo html::a($this->createLink('gitlab', 'delete', "gitlabID=$id"), '', 'hiddenwin', "title='{$lang->gitlab->delete}' class='btn'"); ?> diff --git a/module/gitlab/view/browsebranchpriv.html.php b/module/gitlab/view/browsebranchpriv.html.php new file mode 100644 index 0000000000..9ef6455f88 --- /dev/null +++ b/module/gitlab/view/browsebranchpriv.html.php @@ -0,0 +1,79 @@ + + * @package gitlab + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+ noData;?> + + createLink('gitlab', 'createBranchPriv', "gitlabID=$gitlabID&projectID=$projectID"), " " . $lang->gitlab->createBranchPriv, '', "class='btn btn-info'");?> + +
+