BxGitHubModule.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup GitHub GitHub
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. define('BX_GITHUB_AUTHORIZE_APP', 'app');
  12. define('BX_GITHUB_AUTHORIZE_PAT', 'pat');
  13. class BxGitHubModule extends BxBaseModGeneralModule
  14. {
  15. protected $_iLoggedId;
  16. protected $_oApi;
  17. public function __construct($aModule)
  18. {
  19. parent::__construct($aModule);
  20. $this->_oConfig->init($this->_oDb);
  21. $this->_iLoggedId = bx_get_logged_profile_id();
  22. $this->_oApi = $this->getObjectApi();
  23. /*
  24. * Below authorization using profile ID only is used
  25. * when "Personal Access Token" authorization is enabled.
  26. */
  27. if($this->_iLoggedId && ($sAccessToken = $this->getAccessToken($this->_iLoggedId)) !== false)
  28. $this->_oApi->init($sAccessToken);
  29. }
  30. /**
  31. * ACTION METHODS
  32. */
  33. public function actionAuthorize($iAppId)
  34. {
  35. $CNF = &$this->_oConfig->CNF;
  36. if(($oApp = $this->getObjectApp($iAppId)) !== false && ($sCode = bx_get('code')) !== false) {
  37. $aAccessToken = $oApp->getAccessToken($sCode);
  38. if($aAccessToken !== false) {
  39. $this->_oDb->insertAuthorization($this->_iLoggedId, $iAppId, $aAccessToken);
  40. header('Location: ' . BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink($CNF['URL_SETTINGS']));
  41. exit;
  42. }
  43. }
  44. return $this->_oTemplate->displayErrorOccured();
  45. }
  46. /**
  47. * SERVICE METHODS
  48. */
  49. public function serviceGetOptionsAuthorize()
  50. {
  51. $aResult = [];
  52. foreach(['pat', 'app'] as $sItem)
  53. $aResult[] = [
  54. 'key' => $sItem,
  55. 'value' => _t('_bx_github_option_authorize_' . $sItem)
  56. ];
  57. return $aResult;
  58. }
  59. public function serviceGetApps($iProfileId)
  60. {
  61. if(!$this->_oConfig->isAuthorizeByApp())
  62. return false;
  63. if(!$iProfileId)
  64. return [];
  65. return $this->_oDb->getApps(['sample' => 'profile_id', 'profile_id' => $iProfileId]);
  66. }
  67. public function serviceRefreshAccessToken($iAppId, $iProfileId = 0)
  68. {
  69. if(!$this->_oConfig->isAuthorizeByApp())
  70. return false;
  71. if(!$iProfileId && !($iProfileId = $this->_iLoggedId))
  72. return false;
  73. return $this->refreshAccessToken($iProfileId, $iAppId);
  74. }
  75. public function serviceGetBlockAuthorize($iAppId, $iProfileId = 0)
  76. {
  77. if(!$this->_oConfig->isAuthorizeByApp())
  78. return '';
  79. if(!$iProfileId && !($iProfileId = $this->_iLoggedId))
  80. return '';
  81. return $this->_oTemplate->getBlockAuthorize($iAppId, $iProfileId);
  82. }
  83. public function serviceGetBlockApps($iProfileId = 0)
  84. {
  85. $CNF = &$this->_oConfig->CNF;
  86. if(!$iProfileId || ($iProfileId != $this->_iLoggedId && !$this->_isAdministrator()))
  87. $iProfileId = $this->_iLoggedId;
  88. if(!$iProfileId)
  89. return MsgBox(_t('_sys_txt_access_denied'));
  90. if(($mixedCheck = $this->checkAllowedAddApp($iProfileId)) !== CHECK_ACTION_RESULT_ALLOWED)
  91. return MsgBox($mixedCheck);
  92. $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_APPS']);
  93. if(!$oGrid)
  94. return $this->_bIsApi ? [] : '';
  95. $oGrid->setProfileId($iProfileId);
  96. if($this->_bIsApi)
  97. return [
  98. bx_api_get_block('grid', $oGrid->getCodeAPI())
  99. ];
  100. return $oGrid->getCode();
  101. }
  102. public function serviceGetBlockAuthorizations($iProfileId = 0)
  103. {
  104. $CNF = &$this->_oConfig->CNF;
  105. if(!$iProfileId || ($iProfileId != $this->_iLoggedId && !$this->_isAdministrator()))
  106. $iProfileId = $this->_iLoggedId;
  107. if(!$iProfileId)
  108. return MsgBox(_t('_sys_txt_access_denied'));
  109. $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_AUTHORIZATIONS']);
  110. if(!$oGrid)
  111. return $this->_bIsApi ? [] : '';
  112. $oGrid->setProfileId($iProfileId);
  113. if($this->_bIsApi)
  114. return [
  115. bx_api_get_block('grid', $oGrid->getCodeAPI())
  116. ];
  117. return $oGrid->getCode();
  118. }
  119. public function serviceGetBlockSettings($iProfileId = 0)
  120. {
  121. if(!$iProfileId || ($iProfileId != $this->_iLoggedId && !$this->_isAdministrator()))
  122. $iProfileId = $this->_iLoggedId;
  123. if(!$iProfileId)
  124. return MsgBox(_t('_sys_txt_access_denied'));
  125. return $this->_oTemplate->getBlockSettingsClient($iProfileId);
  126. }
  127. public function serviceGetRepositories($sUsername, $mixedAuth)
  128. {
  129. $this->_authenticate($mixedAuth);
  130. return $this->_oApi->getRepositories($sUsername);
  131. }
  132. public function serviceGetIssues($sUsername, $sRepository, $mixedAuth, $sState = 'open')
  133. {
  134. $this->_authenticate($mixedAuth);
  135. return $this->_oApi->getIssues($sUsername, $sRepository, $sState);
  136. }
  137. public function serviceGetIssue($sUsername, $sRepository, $mixedAuth, $iIssue)
  138. {
  139. $this->_authenticate($mixedAuth);
  140. return $this->_oApi->getIssue($sUsername, $sRepository, $iIssue);
  141. }
  142. public function serviceCreateIssue($sUsername, $sRepository, $mixedAuth, $sTitle, $sText = '', $aParams = [])
  143. {
  144. $this->_authenticate($mixedAuth);
  145. return $this->_oApi->createIssue($sUsername, $sRepository, $sTitle, $sText, $aParams);
  146. }
  147. public function serviceUpdateIssue($sUsername, $sRepository, $mixedAuth, $iIssue, $aParams)
  148. {
  149. $this->_authenticate($mixedAuth);
  150. return $this->_oApi->updateIssue($sUsername, $sRepository, $iIssue, $aParams);
  151. }
  152. public function serviceCloseIssue($sUsername, $sRepository, $mixedAuth, $iIssue)
  153. {
  154. $this->_authenticate($mixedAuth);
  155. return $this->_oApi->updateIssue($sUsername, $sRepository, $iIssue, ['state' => 'closed']);
  156. }
  157. public function serviceReopenIssue($sUsername, $sRepository, $mixedAuth, $iIssue)
  158. {
  159. $this->_authenticate($mixedAuth);
  160. return $this->_oApi->updateIssue($sUsername, $sRepository, $iIssue, ['state' => 'open']);
  161. }
  162. public function serviceCreateLabel($sUsername, $sRepository, $mixedAuth, $mixedLabel)
  163. {
  164. $this->_authenticate($mixedAuth);
  165. return $this->_oApi->createLabel($sUsername, $sRepository, $mixedLabel);
  166. }
  167. public function serviceAddLabel($sUsername, $sRepository, $mixedAuth, $iIssue, $mixedLabel)
  168. {
  169. $this->_authenticate($mixedAuth);
  170. return $this->_oApi->addLabel($sUsername, $sRepository, $iIssue, $mixedLabel);
  171. }
  172. /*
  173. * COMMON METHODS
  174. */
  175. public function getObjectApi()
  176. {
  177. bx_import('Api', $this->_aModule);
  178. return new BxGitHubApi($this);
  179. }
  180. public function getObjectApp($iAppId)
  181. {
  182. bx_import('App', $this->_aModule);
  183. $oApp = new BxGitHubApp($this);
  184. return $oApp->init($iAppId) ? $oApp : false;
  185. }
  186. public function getAccessToken($iProfileId, $iAppId = 0)
  187. {
  188. $sToken = '';
  189. if($this->_oConfig->isAuthorizeByApp()) {
  190. if(!$iAppId)
  191. return false;
  192. $aAuthorization = $this->_oDb->getAuthorization($iProfileId, $iAppId);
  193. if($aAuthorization === false)
  194. return false;
  195. if(($iExpiresIn = (int)$aAuthorization['at_expires_in']) != 0 && ((int)$aAuthorization['changed'] + $iExpiresIn) < time()) {
  196. $this->refreshAccessToken($iProfileId, $iAppId, $aAuthorization['refresh_token']);
  197. $aAuthorization = $this->_oDb->getAuthorization($iProfileId, $iAppId);
  198. if($aAuthorization === false)
  199. return false;
  200. }
  201. $sToken = $aAuthorization['access_token'];
  202. }
  203. else {
  204. $aSettings = $this->_oDb->getSettings(['sample' => 'profile_id', 'profile_id' => $iProfileId]);
  205. if(empty($aSettings) || !is_array($aSettings) || empty($aSettings['pat']))
  206. return false;
  207. $sToken = $aSettings['pat'];
  208. }
  209. return $sToken;
  210. }
  211. public function refreshAccessToken($iProfileId, $iAppId, $sRefreshToken = '')
  212. {
  213. $oApp = $this->getObjectApp($iAppId);
  214. if(!$oApp)
  215. return false;
  216. if(!$sRefreshToken) {
  217. $aAuthorization = $this->_oDb->getAuthorizations([
  218. 'sample' => 'profile_app_ids',
  219. 'profile_id' => $iProfileId,
  220. 'app_id' => $iAppId
  221. ]);
  222. if(!$aAuthorization || !is_array($aAuthorization) || empty($aAuthorization['refresh_token']))
  223. return false;
  224. $sRefreshToken = $aAuthorization['refresh_token'];
  225. }
  226. $aAccessToken = $oApp->refreshAccessToken($sRefreshToken);
  227. if(!$aAccessToken)
  228. return false;
  229. return $this->_oDb->insertAuthorization($iProfileId, $iAppId, $aAccessToken) !== false;
  230. }
  231. /**
  232. * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
  233. */
  234. public function checkAllowedAddApp($iProfileId, $isPerformAction = false)
  235. {
  236. $aCheck = checkActionModule($iProfileId, 'add app', $this->getName(), $isPerformAction);
  237. return $aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED ? $aCheck[CHECK_ACTION_MESSAGE] : CHECK_ACTION_RESULT_ALLOWED;
  238. }
  239. public function log($sContents, $iLevel = BX_LOG_DEBUG)
  240. {
  241. $CNF = &$this->_oConfig->CNF;
  242. if (is_array($sContents))
  243. $sContents = var_export($sContents, true);
  244. else if (is_object($sContents))
  245. $sContents = json_encode($sContents);
  246. bx_log($CNF['OBJECT_LOG_API'], $sContents, $iLevel);
  247. }
  248. protected function _authenticate($mixedAuth)
  249. {
  250. if(!$mixedAuth)
  251. return;
  252. $iProfileId = $iAppId = 0;
  253. if(is_array($mixedAuth) && ($iAuthParams = count($mixedAuth)))
  254. if($iAuthParams == 2)
  255. list($iProfileId, $iAppId) = $mixedAuth;
  256. else
  257. $iProfileId = (int)reset($mixedAuth);
  258. else
  259. $iProfileId = (int)$mixedAuth;
  260. if(($iProfileId && $iProfileId != $this->_iLoggedId) || $iAppId) {
  261. $sAccessToken = $this->getAccessToken($iProfileId, $iAppId);
  262. if($sAccessToken !== false)
  263. $this->_oApi->init($sAccessToken);
  264. }
  265. }
  266. }
  267. /** @} */