2023-05-16 10:47:08 +08:00

584 lines
18 KiB
PHP

<?php
/**
* The model file of gogs module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 禅道软件(青岛)有限公司(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 product
* @version $Id: $
* @link http://www.zentao.net
*/
class gogsModel extends model
{
/**
* Get a gogs by id.
*
* @param int $id
* @access public
* @return object
*/
public function getByID($id)
{
return $this->loadModel('pipeline')->getByID($id);
}
/**
* Get gogs list.
*
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
public function getList($orderBy = 'id_desc', $pager = null)
{
$gogsList = $this->loadModel('pipeline')->getList('gogs', $orderBy, $pager);
return $gogsList;
}
/**
* Get gogs pairs.
*
* @access public
* @return array
*/
public function getPairs()
{
return $this->loadModel('pipeline')->getPairs('gogs');
}
/**
* Get gogs api base url by gogs id.
*
* @param int $gogsID
* @access public
* @return string
*/
public function getApiRoot($gogsID)
{
$gogs = $this->getByID($gogsID);
if(!$gogs) return '';
return rtrim($gogs->url, '/') . '/api/v1%s' . "?token={$gogs->token}";
}
/**
* Create a gogs.
*
* @access public
* @return bool
*/
public function create()
{
return $this->loadModel('pipeline')->create('gogs');
}
/**
* Update a gogs.
*
* @param int $id
* @access public
* @return bool
*/
public function update($id)
{
return $this->loadModel('pipeline')->update($id);
}
/**
* Bind users.
*
* @param int $gogsID
* @access public
* @return array
*/
public function bindUser($gogsID)
{
$userPairs = $this->loadModel('user')->getPairs('noclosed|noletter');
$users = $this->post->zentaoUsers;
$gogsNames = $this->post->gogsUserNames;
$accountList = array();
$repeatUsers = array();
foreach($users as $openID => $user)
{
if(empty($user)) continue;
if(isset($accountList[$user])) $repeatUsers[] = zget($userPairs, $user);
$accountList[$user] = $openID;
}
if(count($repeatUsers))
{
dao::$errors[] = sprintf($this->lang->gogs->bindUserError, join(',', $repeatUsers));
return false;
}
$user = new stdclass;
$user->providerID = $gogsID;
$user->providerType = 'gogs';
$oldUsers = $this->dao->select('*')->from(TABLE_OAUTH)->where('providerType')->eq($user->providerType)->andWhere('providerID')->eq($user->providerID)->fetchAll('openID');
foreach($users as $openID => $account)
{
$existAccount = isset($oldUsers[$openID]) ? $oldUsers[$openID] : '';
if($existAccount and $existAccount->account != $account)
{
$this->dao->delete()
->from(TABLE_OAUTH)
->where('openID')->eq($openID)
->andWhere('providerType')->eq($user->providerType)
->andWhere('providerID')->eq($user->providerID)
->exec();
$this->loadModel('action')->create('gogsuser', $gogsID, 'unbind', '', sprintf($this->lang->gogs->bindDynamic, $gogsNames[$openID], $zentaoUsers[$existAccount->account]->realname));
}
if(!$existAccount or $existAccount->account != $account)
{
if(!$account) continue;
$user->account = $account;
$user->openID = $openID;
$this->dao->insert(TABLE_OAUTH)->data($user)->exec();
$this->loadModel('action')->create('gogsuser', $gogsID, 'bind', '', sprintf($this->lang->gogs->bindDynamic, $gogsNames[$openID], $zentaoUsers[$account]->realname));
}
}
}
/**
* 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))
{
if(is_string($response->message))
{
$errorKey = array_search($response->message, $this->lang->gogs->apiError);
dao::$errors[] = $errorKey === false ? $response->message : zget($this->lang->gogs->errorLang, $errorKey);
}
else
{
foreach($response->message as $field => $fieldErrors)
{
if(is_string($fieldErrors))
{
$errorKey = array_search($fieldErrors, $this->lang->gogs->apiError);
if($fieldErrors) dao::$errors[$field][] = $errorKey === false ? $fieldErrors : zget($this->lang->gogs->errorLang, $errorKey);
}
else
{
foreach($fieldErrors as $error)
{
$errorKey = array_search($error, $this->lang->gogs->apiError);
if($error) dao::$errors[$field][] = $errorKey === false ? $error : zget($this->lang->gogs->errorLang, $errorKey);
}
}
}
}
}
if(!$response) dao::$errors[] = false;
return false;
}
/**
* Check token access.
*
* @param string $url
* @param string $token
* @access public
* @return void
*/
public function checkTokenAccess($url = '', $token = '')
{
$apiRoot = rtrim($url, '/') . '/api/v1%s' . "?token={$token}";
$url = sprintf($apiRoot, "/user");
$httpData = commonModel::httpWithHeader($url);
$user = json_decode($httpData['body']);
if(empty($httpData['header'])) return false;
if(empty($user)) return null;
/* Check whether the token belongs to the administrator by edit user. */
$editUserUrl = sprintf($apiRoot, "/admin/users/" . $user->username);
$data = new stdclass();
$data->login_name = $user->login;
$data->email = $user->email;
$result = commonModel::http($editUserUrl, $data, array(), array(), 'data', 'PATCH');
$user = json_decode($result);
if(empty($user)) return null;
return true;
}
/**
* Get Gogs id list by user account.
*
* @param string $account
* @access public
* @return array
*/
public function getGogsListByAccount($account = '')
{
if(!$account) $account = $this->app->user->account;
return $this->dao->select('providerID,openID')->from(TABLE_OAUTH)
->where('providerType')->eq('gogs')
->andWhere('account')->eq($account)
->fetchPairs('providerID');
}
/**
* Get zentao account gogs user id pairs of one gogs.
*
* @param int $gogsID
* @access public
* @return array
*/
public function getUserAccountIdPairs($gogsID, $fields = 'account,openID')
{
return $this->dao->select($fields)->from(TABLE_OAUTH)
->where('providerType')->eq('gogs')
->andWhere('providerID')->eq($gogsID)
->fetchPairs();
}
/**
* Get gogs user id by zentao account.
*
* @param int $gogsID
* @param string $zentaoAccount
* @access public
* @return array
*/
public function getUserIDByZentaoAccount($gogsID, $zentaoAccount)
{
return $this->dao->select('openID')->from(TABLE_OAUTH)
->where('providerType')->eq('gogs')
->andWhere('providerID')->eq($gogsID)
->andWhere('account')->eq($zentaoAccount)
->fetch('openID');
}
/**
* Get matched gogs users.
*
* @param int $gogsID
* @param array $gogsUsers
* @param array $zentaoUsers
* @access public
* @return array
*/
public function getMatchedUsers($gogsID, $gogsUsers, $zentaoUsers)
{
$matches = new stdclass;
foreach($gogsUsers as $gogsUser)
{
foreach($zentaoUsers as $zentaoUser)
{
if($gogsUser->account == $zentaoUser->account) $matches->accounts[$gogsUser->account][] = $zentaoUser->account;
if($gogsUser->realname == $zentaoUser->realname) $matches->names[$gogsUser->realname][] = $zentaoUser->account;
if($gogsUser->email == $zentaoUser->email) $matches->emails[$gogsUser->email][] = $zentaoUser->account;
}
}
$bindedUsers = $this->getUserAccountIdPairs($gogsID, 'openID,account');
$matchedUsers = array();
foreach($gogsUsers as $gogsUser)
{
if(isset($bindedUsers[$gogsUser->account]))
{
$gogsUser->zentaoAccount = $bindedUsers[$gogsUser->account];
$matchedUsers[] = $gogsUser;
continue;
}
$matchedZentaoUsers = array();
if(isset($matches->accounts[$gogsUser->account])) $matchedZentaoUsers = array_merge($matchedZentaoUsers, $matches->accounts[$gogsUser->account]);
if(isset($matches->emails[$gogsUser->email])) $matchedZentaoUsers = array_merge($matchedZentaoUsers, $matches->emails[$gogsUser->email]);
if(isset($matches->names[$gogsUser->realname])) $matchedZentaoUsers = array_merge($matchedZentaoUsers, $matches->names[$gogsUser->realname]);
$matchedZentaoUsers = array_unique($matchedZentaoUsers);
if(count($matchedZentaoUsers) == 1)
{
$gogsUser->zentaoAccount = current($matchedZentaoUsers);
$matchedUsers[] = $gogsUser;
}
}
return $matchedUsers;
}
/**
* Get project by api.
*
* @param int $gogsID
* @param int $projectID
* @access public
* @return void
*/
public function apiGetSingleProject($gogsID, $projectID)
{
$apiRoot = $this->getApiRoot($gogsID);
if(!$apiRoot) return array();
$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;
$gogs = $this->getByID($gogsID);
$oauth = "{$gogs->token}@";
$project->tokenCloneUrl = preg_replace('/(http(s)?:\/\/)/', "\$1$oauth", $project->html_url);
}
return $project;
}
/**
* Get projects by api.
*
* @param int $gogsID
* @access public
* @return array
*/
public function apiGetProjects($gogsID)
{
$apiRoot = $this->getApiRoot($gogsID);
if(!$apiRoot) return array();
$user = $this->apiGetAdminer($gogsID);
if(!$user) return array();
$url = sprintf($apiRoot, "/users/{$user->username}/repos");
$allResults = array();
for($page = 1; true; $page++)
{
$results = json_decode(commonModel::http($url . "&page={$page}&limit=50"));
if(!is_array($results)) break;
if(!empty($results)) $allResults = array_merge($allResults, $results);
if(count($results) < 50) break;
}
return $allResults;
}
/**
* Api get adminer.
*
* @param int $gogsID
* @access public
* @return void
*/
public function apiGetAdminer($gogsID)
{
$apiRoot = $this->getApiRoot($gogsID);
if(!$apiRoot) return array();
$url = sprintf($apiRoot, "/user");
$user = json_decode(commonModel::http($url));
return isset($user->username) ? $user : null;
}
/**
* Get gogs user list.
*
* @param int $gogsID
* @param bool $onlyLinked
* @access public
* @return array
*/
public function apiGetUsers($gogsID, $onlyLinked = false)
{
$response = array();
$apiRoot = $this->getApiRoot($gogsID);
for($page = 1; true; $page++)
{
$url = sprintf($apiRoot, "/admin/users") . "&page={$page}&limit=20";
$result = json_decode(commonModel::http($url));
if(empty($result->data)) break;
$response = array_merge($response, $result->data);
$page += 1;
}
if(empty($response)) return array();
/* Get linked users. */
$linkedUsers = array();
if($onlyLinked) $linkedUsers = $this->getUserAccountIdPairs($gogsID, 'openID,account');
$users = array();
foreach($response as $gogsUser)
{
if($onlyLinked and !isset($linkedUsers[$gogsUser->id])) continue;
$user = new stdclass;
$user->id = $gogsUser->id;
$user->realname = $gogsUser->full_name ? $gogsUser->full_name : $gogsUser->username;
$user->account = $gogsUser->username;
$user->email = zget($gogsUser, 'email', '');
$user->avatar = $gogsUser->avatar_url;
$user->createdAt = zget($gogsUser, 'created', '');
$user->lastActivityOn = zget($gogsUser, 'login', '');
$users[] = $user;
}
return $users;
}
/**
* Get project repository branches by api.
*
* @param int $gogsID
* @param string $project
* @access public
* @return object
*/
public function apiGetBranches($gogsID, $project, $pager = null)
{
$url = sprintf($this->getApiRoot($gogsID), "/repos/{$project}/branches");
$allResults = array();
for($page = 1; true; $page++)
{
$results = json_decode(commonModel::http($url . "&page={$page}&limit=50"));
if(!is_array($results)) break;
if(!empty($results)) $allResults = array_merge($allResults, $results);
if(count($results) < 100) break;
}
return $allResults;
}
/**
* Get upstream project by API.
*
* @param int $gogsID
* @param string $project
* @access public
* @return void
*/
public function apiGetUpstream($gogsID, $project)
{
$currentProject = $this->apiGetSingleProject($gogsID, $project);
if(isset($currentProject->parent->full_name)) return $currentProject->parent->full_name;
return array();
}
/**
* Get branches.
*
* @param int $gogsID
* @param string $project
* @access public
* @return array
*/
public function getBranches($gogsID, $project)
{
$rawBranches = $this->apiGetBranches($gogsID, $project);
$branches = array();
foreach($rawBranches as $branch) $branches[] = $branch->name;
return $branches;
}
/**
* Get gogs user id and realname pairs of one gogs.
*
* @param int $gogsID
* @access public
* @return array
*/
public function getUserIdRealnamePairs($gogsID)
{
return $this->dao->select('oauth.openID as openID,user.realname as realname')
->from(TABLE_OAUTH)->alias('oauth')
->leftJoin(TABLE_USER)->alias('user')
->on("oauth.account = user.account")
->where('providerType')->eq('gogs')
->andWhere('providerID')->eq($gogsID)
->fetchPairs();
}
/**
* Get single branch by API.
*
* @param int $gogsID
* @param string $project
* @param string $branchName
* @access public
* @return object
*/
public function apiGetSingleBranch($gogsID, $project, $branchName)
{
$url = sprintf($this->getApiRoot($gogsID), "/repos/$project/branches/$branchName");
$branch = json_decode(commonModel::http($url));
if($branch)
{
$gogs = $this->getByID($gogsID);
$branch->web_url = "{$gogs->url}/$project/src/$branchName";
}
return $branch;
}
/**
* Get protect branches of one project.
*
* @param int $gogsID
* @param string $project
* @param string $keyword
* @access public
* @return array
*/
public function apiGetBranchPrivs($gogsID, $project, $keyword = '')
{
$keyword = urlencode($keyword);
$url = sprintf($this->getApiRoot($gogsID), "/repos/$project/branch_protections");
$branches = json_decode(commonModel::http($url));
if(!is_array($branches)) return array();
$newBranches = array();
foreach($branches as $branch)
{
$branch->name = $branch->Name;
if(empty($keyword) || stristr($branch->name, $keyword)) $newBranches[] = $branch;
}
return $newBranches;
}
/**
* Api delete branch.
*
* @param int $gogsID
* @param string $project
* @param string $branch
* @access public
* @return void
*/
public function apiDeleteBranch($gogsID, $project, $branch)
{
$url = sprintf($this->getApiRoot($gogsID), "/repos/$project/branches/$branch");
return json_decode(commonModel::http($url, null, array(CURLOPT_CUSTOMREQUEST => 'DELETE')));
}
}