model.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <?php
  2. /**
  3. * The model file of gogs module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Chenqi <chenqi@cnezsoft.com>
  8. * @package gogs
  9. * @link https://www.zentao.net
  10. */
  11. class gogsModel extends model
  12. {
  13. /**
  14. * 获取请求地址信息。
  15. * Get gogs api base url by gogs id.
  16. *
  17. * @param int $gogsID
  18. * @access public
  19. * @return string
  20. */
  21. public function getApiRoot($gogsID)
  22. {
  23. $gogs = $this->fetchByID($gogsID);
  24. if(!$gogs || $gogs->type != 'gogs') return '';
  25. return rtrim($gogs->url, '/') . '/api/v1%s' . "?token={$gogs->token}";
  26. }
  27. /**
  28. * Gogs用户和禅道用户绑定。
  29. * Bind gogs user and zentao user.
  30. *
  31. * @param int $gogsID
  32. * @param array $users
  33. * @param array $gogsNames
  34. * @access public
  35. * @return array
  36. */
  37. public function bindUser($gogsID, $users, $gogsNames)
  38. {
  39. $repeatUsers = array();
  40. $userPairs = array();
  41. foreach($users as $openID => $account)
  42. {
  43. if(empty($account)) continue;
  44. if(in_array($account, $userPairs)) $repeatUsers[] = $account;
  45. $userPairs[$openID] = $account;
  46. }
  47. /* Check user repeat bind. */
  48. if($repeatUsers)
  49. {
  50. $userList = $this->loadModel('user')->getRealNameAndEmails($repeatUsers);
  51. dao::$errors = sprintf($this->lang->gogs->bindUserError, join(',', helper::arrayColumn($userList, 'realname')));
  52. return false;
  53. }
  54. $bindedUsers = $this->dao->select('openID,account')->from(TABLE_OAUTH)
  55. ->where('providerType')->eq('gogs')
  56. ->andWhere('providerID')->eq($gogsID)
  57. ->fetchPairs();
  58. $this->dao->delete()->from(TABLE_OAUTH)->where('providerType')->eq('gogs')->andWhere('providerID')->eq($gogsID)->exec();
  59. $this->loadModel('action');
  60. foreach($userPairs as $openID => $account)
  61. {
  62. /* If user binded user is change, delete it. */
  63. if(isset($bindedUsers[$openID]) && $bindedUsers[$openID] != $account) $this->action->create('gogsuser', $gogsID, 'unbind', '', $gogsNames[$openID]);
  64. /* Add zentao user and gogs user binded. */
  65. $user = new stdclass();
  66. $user->providerID = $gogsID;
  67. $user->providerType = 'gogs';
  68. $user->account = $account;
  69. $user->openID = $gogsNames[$openID];
  70. $this->dao->insert(TABLE_OAUTH)->data($user)->exec();
  71. $this->action->create('gogsuser', $gogsID, 'bind', '', $gogsNames[$openID]);
  72. }
  73. return !dao::isError();
  74. }
  75. /**
  76. * 检测token是否有效。
  77. * Check token access.
  78. *
  79. * @param string $url
  80. * @param string $token
  81. * @access public
  82. * @return void
  83. */
  84. public function checkTokenAccess($url = '', $token = '')
  85. {
  86. $apiRoot = rtrim($url, '/') . '/api/v1%s' . "?token={$token}";
  87. $url = sprintf($apiRoot, "/user");
  88. $user = json_decode(commonModel::http($url));
  89. if(empty($user) || isset($user->message)) return false;
  90. /* Check whether the token belongs to the administrator by edit user. */
  91. $editUserUrl = sprintf($apiRoot, "/admin/users/" . $user->username);
  92. $data = new stdclass();
  93. $data->login_name = $user->login;
  94. $data->email = $user->email;
  95. $result = commonModel::http($editUserUrl, $data, array(), array(), 'data', 'PATCH');
  96. $user = json_decode($result);
  97. if(empty($user)) return false;
  98. return true;
  99. }
  100. /**
  101. * 通过API获取Gogs项目信息。
  102. * Get project by api.
  103. *
  104. * @param int $gogsID
  105. * @param string $projectID
  106. * @access public
  107. * @return object|null
  108. */
  109. public function apiGetSingleProject($gogsID, $projectID)
  110. {
  111. $apiRoot = $this->getApiRoot($gogsID);
  112. if(!$apiRoot) return null;
  113. $url = sprintf($apiRoot, "/repos/$projectID");
  114. $project = json_decode(commonModel::http($url));
  115. if(isset($project->name))
  116. {
  117. $project->name_with_namespace = $project->full_name;
  118. $project->path_with_namespace = $project->full_name;
  119. $project->http_url_to_repo = $project->html_url;
  120. $project->name_with_namespace = $project->full_name;
  121. $gogs = $this->fetchByID($gogsID);
  122. $project->tokenCloneUrl = preg_replace('/(http(s)?:\/\/)/', '${1}' . $gogs->token . '@', $project->html_url);
  123. }
  124. return $project;
  125. }
  126. /**
  127. * 通过API获取Gogs项目列表。
  128. * Get projects by api.
  129. *
  130. * @param int $gogsID
  131. * @access public
  132. * @return array
  133. */
  134. public function apiGetProjects($gogsID)
  135. {
  136. $apiRoot = $this->getApiRoot($gogsID);
  137. if(!$apiRoot) return array();
  138. $url = sprintf($apiRoot, "/user");
  139. $user = json_decode(commonModel::http($url));
  140. if(!isset($user->username)) return array();
  141. $url = sprintf($apiRoot, "/users/{$user->username}/repos");
  142. $projects = array();
  143. $results = json_decode(commonModel::http($url));
  144. if(!is_array($results) || empty($results)) return array();
  145. if(!empty($results)) $projects = array_merge($projects, $results);
  146. return $projects;
  147. }
  148. /**
  149. * 通过API获取Gogs用户列表。
  150. * Get gogs user list.
  151. *
  152. * @param int $gogsID
  153. * @param bool $onlyLinked
  154. * @access public
  155. * @return array
  156. */
  157. public function apiGetUsers($gogsID, $onlyLinked = false)
  158. {
  159. $users = array();
  160. $apiRoot = $this->getApiRoot($gogsID, strtolower($this->app->rawMethod) != 'binduser');
  161. $page = 1;
  162. while(true)
  163. {
  164. $url = sprintf($apiRoot, "/admin/users") . "&page={$page}&limit=20";
  165. $result = json_decode(commonModel::http($url));
  166. if(empty($result->data)) break;
  167. $users = array_merge($users, $result->data);
  168. $page ++;
  169. }
  170. if(empty($users)) return array();
  171. /* Get linked users. */
  172. $linkedUsers = array();
  173. if($onlyLinked) $linkedUsers = $this->loadModel('pipeline')->getUserBindedPairs($gogsID, 'gogs', 'openID,account');
  174. $userList = array();
  175. foreach($users as $gogsUser)
  176. {
  177. if($onlyLinked and !isset($linkedUsers[$gogsUser->username])) continue;
  178. $user = new stdclass;
  179. $user->id = $gogsUser->id;
  180. $user->realname = $gogsUser->full_name ? $gogsUser->full_name : $gogsUser->username;
  181. $user->account = $gogsUser->username;
  182. $user->email = zget($gogsUser, 'email', '');
  183. $user->avatar = $gogsUser->avatar_url;
  184. $user->createdAt = zget($gogsUser, 'created', '');
  185. $user->lastActivityOn = zget($gogsUser, 'login', '');
  186. $userList[] = $user;
  187. }
  188. return $userList;
  189. }
  190. /**
  191. * 通过API获取Gogs项目分支列表。
  192. * Get project repository branches by api.
  193. *
  194. * @param int $gogsID
  195. * @param string $project
  196. * @access public
  197. * @return array
  198. */
  199. public function apiGetBranches($gogsID, $project)
  200. {
  201. $url = sprintf($this->getApiRoot($gogsID), "/repos/{$project}/branches");
  202. $branches = array();
  203. $page = 1;
  204. while(true)
  205. {
  206. $results = json_decode(commonModel::http($url . "&page={$page}&limit=50"));
  207. if(!is_array($results)) break;
  208. if(!empty($results)) $branches = array_merge($branches, $results);
  209. if(count($results) < 100) break;
  210. $page ++;
  211. }
  212. return $branches;
  213. }
  214. /**
  215. * 通过API获取Gogs项目分支信息。
  216. * Get single branch by API.
  217. *
  218. * @param int $gogsID
  219. * @param string $project
  220. * @param string $branchName
  221. * @access public
  222. * @return object|null
  223. */
  224. public function apiGetSingleBranch($gogsID, $project, $branchName)
  225. {
  226. if(empty($branchName)) return null;
  227. $url = sprintf($this->getApiRoot($gogsID), "/repos/$project/branches/$branchName");
  228. $branch = json_decode(commonModel::http($url));
  229. if(isset($branch->name))
  230. {
  231. $gogs = $this->fetchByID($gogsID);
  232. $branch->web_url = "{$gogs->url}/$project/src/$branchName";
  233. }
  234. return $branch;
  235. }
  236. /**
  237. * 通过API获取Gogs项目分支保护信息。
  238. * Get protect branches of one project.
  239. *
  240. * @param int $gogsID
  241. * @param string $project
  242. * @param string $keyword
  243. * @access public
  244. * @return array
  245. */
  246. public function apiGetBranchPrivs($gogsID, $project, $keyword = '')
  247. {
  248. $keyword = urlencode($keyword);
  249. $url = sprintf($this->getApiRoot($gogsID), "/repos/$project/branch_protections");
  250. $branches = json_decode(commonModel::http($url));
  251. if(!is_array($branches)) return array();
  252. $newBranches = array();
  253. foreach($branches as $branch)
  254. {
  255. $branch->name = $branch->Name;
  256. if(empty($keyword) || stristr($branch->name, $keyword)) $newBranches[] = $branch;
  257. }
  258. return $newBranches;
  259. }
  260. /**
  261. * 通过API删除Gogs分支。
  262. * Api delete branch.
  263. *
  264. * @param int $gogsID
  265. * @param string $project
  266. * @param string $branch
  267. * @access public
  268. * @return object|null
  269. */
  270. public function apiDeleteBranch($gogsID, $project, $branch)
  271. {
  272. if(empty($branch) || empty($project)) return null;
  273. $url = sprintf($this->getApiRoot($gogsID), "/repos/$project/branches/$branch");
  274. if(!$url) return null;
  275. return json_decode(commonModel::http($url, null, array(CURLOPT_CUSTOMREQUEST => 'DELETE')));
  276. }
  277. /**
  278. * API获取项目的合并请求列表。
  279. * Get Merge Requests by API.
  280. *
  281. * @param int $giteaID
  282. * @param string $project
  283. * @access public
  284. * @return array
  285. */
  286. public function apiGetMergeRequests($giteaID, $project)
  287. {
  288. $apiRoot = $this->getApiRoot($giteaID);
  289. if(!$apiRoot) return array();
  290. $apiPath = "/repos/{$project}/pulls";
  291. $url = sprintf($apiRoot, $apiPath);
  292. $mrList = json_decode(common::http($url));
  293. if(!is_array($mrList)) return array();
  294. foreach($mrList as $mr)
  295. {
  296. $mr->web_url = $mr->html_url;
  297. $mr->iid = $mr->id;
  298. $mr->state = $mr->state == 'open' ? 'opened' : $mr->state;
  299. if($mr->merged) $mr->state = 'merged';
  300. $mr->merge_status = $mr->mergeable ? 'can_be_merged' : 'cannot_be_merged';
  301. $mr->changes_count = empty($diff) ? 0 : 1;
  302. $mr->description = $mr->body;
  303. $mr->target_branch = $mr->base_branch;
  304. $mr->source_branch = $mr->head_branch;
  305. $mr->source_project_id = $project;
  306. $mr->target_project_id = $project;
  307. $mr->has_conflicts = empty($diff) ? true : false;
  308. $mr->is_draft = strpos($mr->title, 'Draft:') === 0;
  309. }
  310. return $mrList;
  311. }
  312. }