| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- <?php
- /**
- * The model file of gitea module of ZenTaoPMS.
- *
- * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
- * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Chenqi <chenqi@cnezsoft.com>
- * @package gitea
- * @link https://www.zentao.net
- */
- class giteaModel extends model
- {
- const HOOK_PUSH_EVENT = 'Push Hook';
- /* Gitlab access level. */
- public $noAccess = 0;
- public $developerAccess = 30;
- public $maintainerAccess = 40;
- /**
- * 获取Gitea请求地址信息。
- * Get gitea api base url by gitea id.
- *
- * @param int $giteaID
- * @param bool $sudo
- * @access public
- * @return string
- */
- public function getApiRoot($giteaID, $sudo = true)
- {
- $gitea = $this->fetchByID($giteaID);
- if(!$gitea || $gitea->type != 'gitea') return '';
- $sudoParam = '';
- if($sudo && !$this->app->user->admin)
- {
- $openID = $this->loadModel('pipeline')->getOpenIdByAccount($giteaID, 'gitea', $this->app->user->account);
- if($openID) $sudoParam = "&sudo={$openID}";
- }
- return rtrim($gitea->url, '/') . '/api/v1%s' . "?token={$gitea->token}" . $sudoParam;
- }
- /**
- * Gitea用户和禅道用户绑定。
- * Bind gitea user and zentao user.
- *
- * @param int $giteaID
- * @param array $users
- * @param array $giteaNames
- * @access public
- * @return bool
- */
- public function bindUser($giteaID, $users, $giteaNames)
- {
- $repeatUsers = array();
- $userPairs = array();
- foreach($users as $openID => $account)
- {
- if(empty($account)) continue;
- if(in_array($account, $userPairs)) $repeatUsers[] = $account;
- $userPairs[$openID] = $account;
- }
- /* Check user repeat bind. */
- if($repeatUsers)
- {
- $userList = $this->loadModel('user')->getRealNameAndEmails($repeatUsers);
- dao::$errors = sprintf($this->lang->gitea->bindUserError, join(',', helper::arrayColumn($userList, 'realname')));
- return false;
- }
- $bindedUsers = $this->dao->select('openID,account')->from(TABLE_OAUTH)
- ->where('providerType')->eq('gitea')
- ->andWhere('providerID')->eq($giteaID)
- ->fetchPairs();
- $this->dao->delete()->from(TABLE_OAUTH)->where('providerType')->eq('gitea')->andWhere('providerID')->eq($giteaID)->exec();
- $this->loadModel('action');
- foreach($userPairs as $openID => $account)
- {
- /* If user binded user is change, delete it. */
- if(isset($bindedUsers[$openID]) && $bindedUsers[$openID] != $account) $this->action->create('giteauser', $giteaID, 'unbind', '', $giteaNames[$openID]);
- /* Add zentao user and gitea user binded. */
- $user = new stdclass();
- $user->providerID = $giteaID;
- $user->providerType = 'gitea';
- $user->account = $account;
- $user->openID = $giteaNames[$openID];
- $this->dao->insert(TABLE_OAUTH)->data($user)->exec();
- $this->action->create('giteauser', $giteaID, 'bind', '', $giteaNames[$openID]);
- }
- return !dao::isError();
- }
- /**
- * 解析翻译接口返回的错误信息。
- * Api error handling.
- *
- * @param object $response
- * @access public
- * @return bool
- */
- public function apiErrorHandling($response)
- {
- if(!empty($response->error))
- {
- dao::$errors[] = $response->error;
- return false;
- }
- if(empty($response->message))
- {
- dao::$errors[] = 'error';
- return false;
- }
- $errorMsg = array();
- if(is_string($response->message)) $errorMsg[] = $response->message;
- if(is_array($response->message))
- {
- foreach($response->message as $fieldErrors)
- {
- if(is_string($fieldErrors)) $fieldErrors = array($fieldErrors);
- foreach($fieldErrors as $error) $errorMsg[] = $error;
- }
- }
- foreach($errorMsg as $error) $this->parseApiError($error);
- return false;
- }
- /**
- * 解析api返回的错误信息。
- * Parse api error.
- *
- * @param string $message
- * @access public
- * @return void
- */
- public function parseApiError($message)
- {
- $errorKey = array_search($message, $this->lang->gitea->apiError);
- if($errorKey === false)
- {
- dao::$errors[] = $message;
- }
- else
- {
- $field = $this->lang->gitea->errorKey[$errorKey];
- dao::$errors[$field] = zget($this->lang->gitea->errorLang, $errorKey);
- }
- }
- /**
- * 检测token是否有效。
- * Check token access.
- *
- * @param string $url
- * @param string $token
- * @access public
- * @return bool
- */
- public function checkTokenAccess($url = '', $token = '')
- {
- $apiRoot = rtrim($url, '/') . '/api/v1%s' . "?token={$token}";
- $url = sprintf($apiRoot, "/admin/users") . "&limit=1";
- $users = json_decode(commonModel::http($url));
- if(empty($users)) return false;
- if(isset($users->message) || isset($users->error)) return false;
- return true;
- }
- /**
- * 通过API获取Gitea项目信息。
- * Get project by api.
- *
- * @param int $giteaID
- * @param string $projectID
- * @access public
- * @return object|null
- */
- public function apiGetSingleProject($giteaID, $projectID)
- {
- $apiRoot = $this->getApiRoot($giteaID);
- if(!$apiRoot) return null;
- $url = sprintf($apiRoot, "/repos/$projectID");
- $project = json_decode(commonModel::http($url));
- if(isset($project->name))
- {
- $project->name_with_namespace = $project->full_name;
- $project->path_with_namespace = $project->full_name;
- $project->http_url_to_repo = $project->html_url;
- $project->name_with_namespace = $project->full_name;
- $gitea = $this->fetchByID($giteaID);
- $oauth = "oauth2:{$gitea->token}@";
- $project->tokenCloneUrl = preg_replace('/(http(s)?:\/\/)/', "\$1$oauth", $project->html_url);
- $project->tokenCloneUrl = str_replace(array('https://', 'http://'), strstr($url, ':', true) . '://', $project->tokenCloneUrl);
- }
- return $project;
- }
- /**
- * 通过API获取Gitea项目列表。
- * Get projects by api.
- *
- * @param int $giteaID
- * @param bool $sudo
- * @access public
- * @return array
- */
- public function apiGetProjects($giteaID, $sudo = true)
- {
- $apiRoot = $this->getApiRoot($giteaID, $sudo);
- if(!$apiRoot) return array();
- $url = sprintf($apiRoot, "/repos/search");
- $page = 1;
- $projects = array();
- while(true)
- {
- $results = json_decode(commonModel::http($url . "&page={$page}&limit=50"));
- if(empty($results->data) || !is_array($results->data)) break;
- $projects = array_merge($projects, $results->data);
- if(count($results->data) < 50) break;
- $page ++;
- }
- return $projects;
- }
- /**
- * 通过api获取组列表。
- * Get groups by api.
- *
- * @param int $giteaID
- * @param bool $sudo
- * @access public
- * @return array
- */
- public function apiGetGroups($giteaID, $sudo = true)
- {
- $apiRoot = $this->getApiRoot($giteaID, $sudo);
- if(!$apiRoot) return array();
- $url = sprintf($apiRoot, "/orgs");
- $allResults = array();
- for($page = 1; true; $page++)
- {
- $results = json_decode(commonModel::http($url . "&page={$page}&limit=50"));
- if(empty($results) || isset($results->message)) break;
- $allResults = array_merge($allResults, $results);
- if(count($results) < 50) break;
- }
- return $allResults;
- }
- /**
- * 通过API获取Gitea用户列表。
- * Get gitea user list.
- *
- * @param int $giteaID
- * @param bool $onlyLinked
- * @access public
- * @return array
- */
- public function apiGetUsers($giteaID, $onlyLinked = false)
- {
- $apiRoot = $this->getApiRoot($giteaID, strtolower($this->app->rawMethod) != 'binduser');
- if(empty($apiRoot)) return array();
- $page = 1;
- $users = array();
- while(true)
- {
- $url = sprintf($apiRoot, "/users/search") . "&page={$page}&limit=50";
- $result = json_decode(commonModel::http($url));
- if(empty($result->data)) break;
- $users = array_merge($users, $result->data);
- $page ++;
- }
- if(empty($users)) return array();
- /* Get linked users. */
- $linkedUsers = array();
- if($onlyLinked) $linkedUsers = $this->loadModel('pipeline')->getUserBindedPairs($giteaID, 'gitea', 'openID,account');
- $userList = array();
- foreach($users as $giteaUser)
- {
- if($onlyLinked && !isset($linkedUsers[$giteaUser->username])) continue;
- $user = new stdclass();
- $user->id = $giteaUser->id;
- $user->realname = $giteaUser->full_name ? $giteaUser->full_name : $giteaUser->username;
- $user->account = $giteaUser->username;
- $user->email = zget($giteaUser, 'email', '');
- $user->avatar = $giteaUser->avatar_url;
- $user->createdAt = zget($giteaUser, 'created', '');
- $user->lastActivityOn = zget($giteaUser, 'last_login', '');
- $userList[] = $user;
- }
- return $userList;
- }
- /**
- * 通过API获取Gitea项目分支列表。
- * Get project repository branches by api.
- *
- * @param int $giteaID
- * @param string $project
- * @access public
- * @return array
- */
- public function apiGetBranches($giteaID, $project)
- {
- $url = sprintf($this->getApiRoot($giteaID), "/repos/{$project}/branches");
- $branches = array();
- for($page = 1; true; $page++)
- {
- $results = json_decode(commonModel::http($url . "&page={$page}&limit=50"));
- if(!is_array($results)) break;
- if(!empty($results)) $branches = array_merge($branches, $results);
- if(count($results) < 100) break;
- }
- return $branches;
- }
- /**
- * 通过API获取Gitea项目分支信息。
- * Get single branch by API.
- *
- * @param int $giteaID
- * @param string $project
- * @param string $branchName
- * @access public
- * @return object|null
- */
- public function apiGetSingleBranch($giteaID, $project, $branchName)
- {
- if(empty($branchName)) return null;
- $url = sprintf($this->getApiRoot($giteaID), "/repos/$project/branches/$branchName");
- $branch = json_decode(commonModel::http($url));
- if(isset($branch->name))
- {
- $gitea = $this->fetchByID($giteaID);
- $branch->web_url = "{$gitea->url}/$project/src/branch/$branchName";
- }
- return $branch;
- }
- /**
- * 通过API获取Gitea项目分支保护信息。
- * Get protect branches of one project.
- *
- * @param int $giteaID
- * @param string $project
- * @param string $keyword
- * @access public
- * @return array|null
- */
- public function apiGetBranchPrivs($giteaID, $project, $keyword = '')
- {
- $url = sprintf($this->getApiRoot($giteaID), "/repos/$project/branch_protections");
- $branches = json_decode(commonModel::http($url));
- if(!is_array($branches)) return array();
- $keyword = urlencode($keyword);
- $newBranches = array();
- foreach($branches as $branch)
- {
- $branch->name = $branch->branch_name;
- if(empty($keyword) || stristr($branch->name, $keyword)) $newBranches[] = $branch;
- }
- return $newBranches;
- }
- /**
- * API获取项目的合并请求列表。
- * Get Merge Requests by API.
- *
- * @param int $giteaID
- * @param string $project
- * @access public
- * @return array
- */
- public function apiGetMergeRequests($giteaID, $project)
- {
- $apiRoot = $this->getApiRoot($giteaID, false);
- if(!$apiRoot) return array();
- $apiPath = "/repos/{$project}/pulls";
- $url = sprintf($apiRoot, $apiPath);
- $mrList = json_decode(common::http($url));
- if(!is_array($mrList)) return array();
- foreach($mrList as $mr)
- {
- $mr->web_url = $mr->url;
- $mr->iid = $mr->number;
- $mr->state = $mr->state == 'open' ? 'opened' : $mr->state;
- if($mr->merged) $mr->state = 'merged';
- $mr->merge_status = $mr->mergeable ? 'can_be_merged' : 'cannot_be_merged';
- $mr->description = $mr->body;
- $mr->target_branch = $mr->base->ref;
- $mr->source_branch = $mr->head->ref;
- $mr->source_project_id = $project;
- $mr->target_project_id = $project;
- $mr->has_conflicts = !$mr->mergeable;
- $mr->is_draft = strpos($mr->title, 'Draft:') === 0;
- }
- return $mrList;
- }
- }
|