BxOAuthAPI.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  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 OAuth2 OAuth2 server
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. use OAuth2\Response;
  12. class BxOAuthAPI extends BxDol
  13. {
  14. protected $_oModule;
  15. protected $_oDb;
  16. public $aAction2Scope = array (
  17. 'me' => 'basic,market,service,api',
  18. 'user' => 'basic,market,service,api',
  19. 'friends' => 'basic,market,service,api',
  20. 'service' => 'service',
  21. 'market' => 'market',
  22. 'api' => 'api',
  23. );
  24. public $aExceptionsAPI = array ('output', 'errorOutput', 'isPublicAPI');
  25. function __construct($oModule)
  26. {
  27. $this->_oModule = $oModule;
  28. $this->_oDb = $oModule->_oDb;
  29. }
  30. /**
  31. * @page private_api API Private
  32. * @section private_api_me /m/oauth2/api/me
  33. *
  34. * Provides information about current profile.
  35. *
  36. * **Scopes:**
  37. * `basic`, `service`, `market`
  38. *
  39. * **HTTP Method:**
  40. * `GET`
  41. *
  42. * **Request header:**
  43. * @code
  44. * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
  45. * @endcode
  46. *
  47. * **Response (success):**
  48. * @code
  49. * {
  50. * "id":"123",
  51. * "type":"bx_organizations",
  52. * "email":"test@example.com",
  53. * "role":"1",
  54. * "name":"Test",
  55. * "profile_display_name":"Test",
  56. * "profile_link":"http:\/\/example.com\/path-to-una\/page\/view-organization-profile?id=12",
  57. * "picture":"http:\/\/example.com\/path-to-una\/image_transcoder.php?o=bx_organizations_picture&h=36&dpx=1&t=1496247306"
  58. * }
  59. * @endcode
  60. *
  61. * **Response (error):**
  62. * @code
  63. * {
  64. * "error":"short error description here",
  65. * "error_description":"long error description here"
  66. * }
  67. * @endcode
  68. *
  69. */
  70. function me($aToken)
  71. {
  72. if (!($oProfile = BxDolProfile::getInstance($aToken['user_id']))) {
  73. $this->errorOutput('404', 'not_found', 'Profile was not found');
  74. return;
  75. }
  76. $aClient = $this->_oDb->getClientsBy(array('type' => 'client_id', 'client_id' => $aToken['client_id']));
  77. $aProfile = $this->_prepareProfileArray($oProfile, false);
  78. $aProfile['owner'] = (int)$aProfile['id'] == (int)$aClient['user_id'];
  79. $this->output($aProfile);
  80. }
  81. /**
  82. * @page private_api API Private
  83. * @section private_api_user /m/oauth2/api/user
  84. *
  85. * Provides information about particular profile profile.
  86. *
  87. * **Parameters:**
  88. * - `id` - profile ID
  89. *
  90. * Everything else is equivalent to @ref private_api_me
  91. */
  92. function user($aToken)
  93. {
  94. $iProfileId = (int)bx_get('id');
  95. if ($iProfileId == $aToken['user_id']) {
  96. $this->me($aToken);
  97. return;
  98. }
  99. if (!($oProfile = $this->_getProfileWithAccessChecking($iProfileId)))
  100. return;
  101. if (!($oProfile = BxDolProfile::getInstance($aToken['user_id'])))
  102. return;
  103. $this->output($this->_prepareProfileArray($oProfile, !isAdmin($oProfile->getAccountId())));
  104. }
  105. /**
  106. * @page private_api API Private
  107. * @section private_api_friends /m/oauth2/api/friends
  108. *
  109. * Get list of friends.
  110. *
  111. * **Scopes:**
  112. * `basic`, `service`, `market`
  113. *
  114. * **HTTP Method:**
  115. * `GET`
  116. *
  117. * **Parameters:**
  118. * - `id` - profile ID
  119. *
  120. * **Request header:**
  121. * @code
  122. * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
  123. * @endcode
  124. *
  125. * **Response (success):**
  126. * @code
  127. * {
  128. * "user_id":30,
  129. * "friends":[
  130. * "24",
  131. * "29",
  132. * "51"
  133. * ]
  134. * }
  135. * @endcode
  136. *
  137. * **Response (error):**
  138. * @code
  139. * {
  140. * "error":"short error description here",
  141. * "error_description":"long error description here"
  142. * }
  143. * @endcode
  144. *
  145. */
  146. function friends($aToken)
  147. {
  148. $iProfileId = (int)bx_get('id');
  149. if (!($oProfile = $this->_getProfileWithAccessChecking($iProfileId)))
  150. return;
  151. if (!($oConn = BxDolConnection::getObjectInstance('sys_profiles_friends'))) {
  152. $this->errorOutput(405, 'not_supported', 'Friends lists aren\'t supported');
  153. return false;
  154. }
  155. $this->output(array(
  156. 'user_id' => $iProfileId,
  157. 'friends' => $oConn->getConnectedContent($iProfileId, true),
  158. ));
  159. }
  160. /**
  161. * @page private_api API Private
  162. * @section private_api_market /m/oauth2/api/market
  163. *
  164. * Market service call.
  165. *
  166. * **Scopes:**
  167. * `market`, `service`
  168. *
  169. * Everything is equivalent to @ref private_api_service, only module name parameter can be ommited
  170. */
  171. function market($aToken)
  172. {
  173. $_GET['key'] = $_POST['key'] = $aToken['client_id'];
  174. $_GET['module'] = $_POST['module'] = 'bx_market_api';
  175. $this->service($aToken);
  176. }
  177. /**
  178. * @page public_api API Public
  179. * @section public_api_com /m/oauth2/api/com
  180. *
  181. * API service call (com is for command).
  182. * The call should be look this:
  183. * `/m/oauth2/api/com/[metod-name-here]`
  184. *
  185. * **Scopes:**
  186. * `api`
  187. *
  188. * Everything is equivalent to @ref private_api_service,
  189. * only module name parameter can be ommited and
  190. * method is passed as method parameter instead of GET/POST variable
  191. */
  192. function com($sMethod, $aToken, $bPublic)
  193. {
  194. $_GET['key'] = $_POST['key'] = (isset($aToken['client_id']) ? $aToken['client_id'] : '');
  195. if (!isset($_GET['module']) && !isset($_POST['module']))
  196. $_GET['module'] = $_POST['module'] = 'bx_api';
  197. $_GET['method'] = $_POST['method'] = $sMethod;
  198. $this->service($aToken, $bPublic, true);
  199. }
  200. function isPublicAPI($sModule, $sMethod, $sClass = false)
  201. {
  202. return $this->_isAPI($sModule, $sMethod, $sClass, 'is_public_service');
  203. }
  204. function isSafeAPI($sModule, $sMethod, $sClass = false)
  205. {
  206. return $this->_isAPI($sModule, $sMethod, $sClass, 'is_safe_service');
  207. }
  208. protected function _isAPI($sModule, $sMethod, $sClass = false, $sCheckMethod = 'is_safe_service')
  209. {
  210. if (!$sClass)
  211. $sClass = 'Module';
  212. if (!BxDolRequest::serviceExists($sModule, $sMethod, $sClass))
  213. return false;
  214. if (!BxDolRequest::serviceExists($sModule, $sCheckMethod, 'system' == $sModule ? 'TemplServices' : $sClass))
  215. return false;
  216. return BxDolService::call($sModule, $sCheckMethod, array($sMethod), 'system' == $sModule ? 'TemplServices' : $sClass);
  217. }
  218. /**
  219. * @page private_api API Private
  220. * @section private_api_service /m/oauth2/api/service
  221. *
  222. * Perform system call.
  223. * For a list of avalibale service calls and their parameters refer to @ref service page.
  224. *
  225. * URL should look like this in case of service API call:
  226. * @code
  227. * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params[]=1&params[]=abc&class=custom_class_name_or_remove_it_if_main_module_class
  228. * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params=serialized_string_of_params
  229. * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params=json_string_of_params
  230. * @endcode
  231. *
  232. * **Scopes:**
  233. * `service`
  234. *
  235. * **HTTP Method:**
  236. * `GET`, `POST`
  237. *
  238. * **Parameters:**
  239. * - `module` - module name to perform service call in
  240. * - `method` - service call method
  241. * - `params` - parameters array
  242. * - `class` - custom module name if different from main module class
  243. *
  244. * **Request header:**
  245. * @code
  246. * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
  247. * @endcode
  248. *
  249. * **Response (success):**
  250. * Depends on particular service call
  251. *
  252. * **Response (error):**
  253. * Error responce is described in particular service method.
  254. * In case of general error (for example when service call isn't found, or error with token), the format is following:
  255. * @code
  256. * {
  257. * "error":"short error description here",
  258. * "error_description":"long error description here"
  259. * }
  260. * @endcode
  261. *
  262. */
  263. function service($aToken, $bPublic = false, $bOutputResultOnly = false)
  264. {
  265. if (!$bPublic && !($oProfile = BxDolProfile::getInstance($aToken['user_id']))) {
  266. $this->errorOutput('404', 'not_found', 'Profile was not found');
  267. return;
  268. }
  269. if (!$bPublic) {
  270. bx_login($oProfile->getAccountId(), false);
  271. check_logged();
  272. }
  273. $sModule = bx_get('module');
  274. $sMethod = bx_get('method');
  275. if (!($aParams = bx_get('params')))
  276. $aParams = array();
  277. elseif (is_string($aParams) && preg_match('/^a:[\d+]:\{/', $aParams))
  278. $aParams = @unserialize($aParams);
  279. elseif (is_string($aParams) && preg_match('/^\[.*\]$/', $aParams))
  280. $aParams = @json_decode($aParams);
  281. if (!is_array($aParams))
  282. $aParams = array($aParams);
  283. if (!($sClass = bx_get('class')))
  284. $sClass = 'Module';
  285. if (!BxDolRequest::serviceExists($sModule, $sMethod, $sClass)) {
  286. $this->errorOutput(404, 'not_found', 'Service was not found');
  287. return false;
  288. }
  289. $mixedRet = BxDolService::call($sModule, $sMethod, $aParams, $sClass);
  290. if (is_array($mixedRet) && isset($mixedRet['error']) && isset($mixedRet['code'])) {
  291. $this->errorOutput($mixedRet['code'], $mixedRet['error'], isset($mixedRet['desc']) ? $mixedRet['desc'] : $mixedRet['error']);
  292. return false;
  293. }
  294. $this->output($bOutputResultOnly ? $mixedRet : array(
  295. 'module' => $sModule,
  296. 'method' => $sMethod,
  297. 'data' => $mixedRet,
  298. ));
  299. }
  300. function errorOutput($iHttpCode, $sError, $sErrorDesc)
  301. {
  302. $oReponse = new Response();
  303. $oReponse->setError($iHttpCode, $sError, $sErrorDesc);
  304. $oReponse->send();
  305. }
  306. function output($a)
  307. {
  308. $oReponse = new Response();
  309. $oReponse->setParameters($a);
  310. $oReponse->send();
  311. }
  312. protected function _getProfileWithAccessChecking ($iProfileId)
  313. {
  314. if (!$oProfile = BxDolProfile::getInstance($iProfileId)) {
  315. $this->errorOutput('404', 'not_found', 'Profile was not found');
  316. return false;
  317. }
  318. /*
  319. // TODO: check visibility
  320. if (!bx_check_profile_visibility($iProfileId, $aToken['user_id'], true)) {
  321. $this->errorOutput(403, 'access_denied', 'You have no rights to view this user info');
  322. return false;
  323. }
  324. */
  325. return $oProfile;
  326. }
  327. protected function _prepareProfileArray ($oProfile, $bPublicFieldsOnly = true)
  328. {
  329. $oAccount = $oProfile->getAccountObject();
  330. $aProfileInfo = $oProfile->getInfo();
  331. $aAccountInfo = $oAccount->getInfo();
  332. if ($bPublicFieldsOnly) {
  333. $aProfileInfo = array(
  334. 'id' => $aProfileInfo['id'],
  335. );
  336. }
  337. else {
  338. unset($aProfileInfo['account_id']);
  339. unset($aProfileInfo['content_id']);
  340. unset($aProfileInfo['status']);
  341. // --- account's profiles info
  342. $aProfileInfo['email'] = $oAccount->getEmail();
  343. // ---- returns all accounts profiles React Jot
  344. $aProfiles = $oAccount->getProfiles();
  345. foreach($aProfiles as &$aProfile) {
  346. $oSubProfile = BxDolProfile::getInstance($aProfile['id']);
  347. $aProfileInfo['profiles'][$aProfile['id']] = array(
  348. 'name' => $oSubProfile->getDisplayName(),
  349. 'profile_link' => $oSubProfile->getUrl(),
  350. 'picture' => $oSubProfile->getThumb(),
  351. 'id' => $aProfile['id']
  352. );
  353. }
  354. // TODO: fetch extended info from profile module
  355. }
  356. $aProfileInfo['role'] = $aAccountInfo['role'];
  357. $aProfileInfo['name'] = $oAccount->getDisplayName();
  358. $aProfileInfo['profile_display_name'] = $oProfile->getDisplayName();
  359. $aProfileInfo['profile_link'] = $oProfile->getUrl();
  360. $aProfileInfo['picture'] = $oProfile->getPicture();
  361. $aProfileInfo['avatar'] = $oProfile->getAvatar();
  362. // ---- additional profile's fields for React Jot
  363. $aProfileInfo['cover'] = $oProfile->getCover();
  364. $aProfileInfo['followers'] = (int)BxDolConnection::getObjectInstance('sys_profiles_subscriptions')->getConnectedInitiatorsCount($aProfileInfo['id']);
  365. $aProfileInfo['following'] = (int)BxDolConnection::getObjectInstance('sys_profiles_subscriptions')->getConnectedContentCount($aProfileInfo['id']);
  366. $aProfileInfo['friends'] = (int)BxDolConnection::getObjectInstance('sys_profiles_friends')->getConnectedContentCount($aProfileInfo['id'], true);
  367. return $aProfileInfo;
  368. }
  369. }
  370. /** @} */