BxMessengerServices.php 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169
  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 Messenger Messenger
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. /**
  12. * For API only.
  13. */
  14. class BxMessengerServices extends BxDol
  15. {
  16. protected $_sModule;
  17. protected $_oModule;
  18. protected $_iProfileId;
  19. protected $_bAdministrator = null;
  20. protected $_aLotMenuShort = null;
  21. protected $_aStarredLots = null;
  22. public function __construct()
  23. {
  24. parent::__construct();
  25. $this->_sModule = 'bx_messenger';
  26. $this->_oModule = BxDolModule::getInstance($this->_sModule);
  27. $this->_iProfileId = bx_get_logged_profile_id();
  28. }
  29. public function serviceGetBlockMain()
  30. {
  31. $CNF = &$this->_oModule->_oConfig->CNF;
  32. $aMenuMain = [];
  33. if(($oMenuMain = BxTemplMenu::getObjectInstance($CNF['OBJECT_MENU_NAV_LEFT_MENU'])) !== false)
  34. $aMenuMain = $oMenuMain->getCodeAPI();
  35. return [
  36. bx_api_get_block('messenger_main_page', [
  37. 'config' => [
  38. 'permissions' => [
  39. 'create_talk' => $this->_oModule->_oConfig->isAllowedAction(BX_MSG_ACTION_CREATE_TALKS, $this->_iProfileId) === true ? 1 : 0,
  40. 'send_message' => $this->_oModule->_oConfig->isAllowedAction(BX_MSG_ACTION_SEND_MESSAGE, $this->_iProfileId) === true ? 1 : 0,
  41. ]
  42. ],
  43. 'menu' => $aMenuMain,
  44. 'form' => ['data' => $this->serviceGetSendForm()],
  45. ], [
  46. 'ext' => [
  47. 'name' => $this->_sModule,
  48. 'params' => ($aParams = bx_get('params')) !== false ? $aParams : [],
  49. 'request' => ['url' => '/api.php?r=' . $this->_sModule . '/get_send_form/Services', 'immutable' => true]
  50. ]
  51. ])
  52. ];
  53. }
  54. public function serviceGetBlockContacts($mixedParams)
  55. {
  56. $aParams = bx_api_get_browse_params($mixedParams, true);
  57. $aBlock = BxDolPage::getBlockProcessing();
  58. $sContentType = 'browse';
  59. if(($sK = 'config_api') && $aBlock[$sK] && is_array($aBlock[$sK]))
  60. $sContentType = $aBlock[$sK]['content_type'] ?? $sContentType;
  61. $bBrowseSimple = $sContentType == 'browse_simple';
  62. $aProfiles = !defined('BX_API_PAGE') || $bBrowseSimple ? $this->_oModule->_oTemplate->getContacts($this->_iProfileId, $aParams) : [];
  63. $aData = [];
  64. foreach($aProfiles as &$aProfile)
  65. if($aProfile['id'] != $this->_iProfileId)
  66. $aData[] = $this->_unitProfile($aProfile['id']);
  67. if(!$bBrowseSimple || $aData)
  68. $aData = [bx_api_get_block($sContentType, [
  69. 'module' => $this->_sModule,
  70. 'unit' => 'mixed',
  71. 'request_url' => '/api.php?r=' . $this->_sModule . '/get_block_contacts/Services&params[]=',
  72. 'data' => $aData,
  73. 'params' => [
  74. 'start' => isset($aParams['start']) ? $aParams['start'] : 0,
  75. 'per_page' => isset($aParams['per_page']) ? $aParams['per_page'] : 0
  76. ]
  77. ])];
  78. return $aData;
  79. }
  80. /*
  81. * Find convo (lot) related to logged in profile and context if the last one is provided.
  82. */
  83. public function serviceFindConvo($sParams)
  84. {
  85. $aOptions = json_decode($sParams, true);
  86. $aParticipants = [$this->_iProfileId];
  87. if(!empty($aOptions['context']))
  88. $aParticipants[] = $aOptions['context'];
  89. $aLot = $this->_oModule->_oDb->getLotsByParticipantsList($aParticipants, BX_IM_TYPE_PRIVATE);
  90. if(empty($aLot) || !is_array($aLot))
  91. return [];
  92. return ['lot' => $aLot];
  93. }
  94. /**
  95. * Leave convo (lot) with defined ID
  96. */
  97. public function serviceLeaveConvo($sParams)
  98. {
  99. $aOptions = json_decode($sParams, true);
  100. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  101. if(!$iLotId || !$this->_oModule->_oDb->isParticipant($iLotId, $this->_iProfileId))
  102. return ['code' => 1, 'message' => _t('_bx_messenger_not_participant')];
  103. if($this->_oModule->_oDb->isAuthor($iLotId, $this->_iProfileId))
  104. return ['code' => 2, 'message' => _t('_bx_messenger_cant_leave')];
  105. return ['code' => !$this->_oModule->_oDb->leaveLot($iLotId, $this->_iProfileId) ? 3 : 0];
  106. }
  107. /**
  108. * Delete convo (lot) with defined ID
  109. */
  110. public function serviceDeleteConvo($sParams)
  111. {
  112. $aOptions = json_decode($sParams, true);
  113. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  114. if(!$iLotId || !($this->_oModule->_oDb->isAuthor($iLotId, $this->_iProfileId) || ($this->_oModule->_oConfig->isAllowedAction(BX_MSG_ACTION_ADMINISTRATE_TALKS, $this->_iProfileId) === true)))
  115. return ['code' => 1, 'message' => _t('_bx_messenger_can_not_delete')];
  116. return ['code' => !$this->_oModule->_oDb->deleteLot($iLotId) ? 2 : 0];
  117. }
  118. /**
  119. * Remove all messages from convo (lot) with defined ID
  120. */
  121. public function serviceClearConvo($sParams)
  122. {
  123. $aOptions = json_decode($sParams, true);
  124. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  125. if(!$iLotId || !$this->_isAllowedToManage($iLotId)) {
  126. return ['code' => 1, 'message' => _t('_bx_messenger_no_permissions')];
  127. }
  128. return ['code' => $this->_oModule->_oDb->clearLot($iLotId) === false ? 2 : 0];
  129. }
  130. /**
  131. * Search messages of convo (lot) with defined ID by their text, newest first, by pages
  132. */
  133. public function serviceSearchConvoMessages($sParams)
  134. {
  135. $CNF = &$this->_oModule->_oConfig->CNF;
  136. $aOptions = json_decode($sParams, true);
  137. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  138. $sTerm = isset($aOptions['term']) ? trim((string)$aOptions['term']) : '';
  139. $iStart = isset($aOptions['start']) ? max(0, (int)$aOptions['start']) : 0;
  140. $iPerPage = 20;
  141. if(!$iLotId || !$this->_iProfileId || !$this->_oModule->_oDb->getLotInfoById($iLotId)) {
  142. return ['code' => 1, 'message' => _t('_bx_messenger_not_found')];
  143. }
  144. if(!$this->_oModule->_oDb->isParticipant($iLotId, $this->_iProfileId) && !$this->_isAdministrator()) {
  145. return ['code' => 2, 'message' => _t('_bx_messenger_not_participant')];
  146. }
  147. $aResult = ['code' => 0, 'jots' => [], 'params' => ['start' => $iStart, 'per_page' => $iPerPage]];
  148. if($sTerm === '') {
  149. return $aResult;
  150. }
  151. // LIKE wildcards in the term are searched as plain characters.
  152. $sTerm = addcslashes($sTerm, '%_\\');
  153. $aJots = $this->_oModule->_oDb->findInHistory($iLotId, $sTerm, $iStart, $iPerPage, 'DESC', true);
  154. foreach($aJots as $aJot) {
  155. $aResult['jots'][] = [
  156. 'id' => (int)$aJot['message_id'],
  157. 'message' => $aJot[$CNF['FIELD_MESSAGE']],
  158. 'added' => (int)$aJot['message_added'],
  159. 'author_data' => BxDolProfile::getData($aJot['message_author']),
  160. ];
  161. }
  162. return $aResult;
  163. }
  164. /**
  165. * Save message (jot) with defined ID to the viewer's saved messages, or remove it from there
  166. */
  167. public function serviceSaveJot($sParams)
  168. {
  169. $CNF = &$this->_oModule->_oConfig->CNF;
  170. $aOptions = json_decode($sParams, true);
  171. $iJotId = isset($aOptions['jot']) ? (int)$aOptions['jot'] : 0;
  172. if(!$iJotId || !$this->_iProfileId || !($aJotInfo = $this->_oModule->_oDb->getJotById($iJotId))) {
  173. return ['code' => 1, 'message' => _t('_bx_messenger_nothing_found')];
  174. }
  175. if(!$this->_isAvailable($aJotInfo[$CNF['FIELD_MESSAGE_FK']])) {
  176. return ['code' => 2, 'message' => _t('_bx_messenger_not_participant')];
  177. }
  178. $bSaved = $this->_oModule->_oDb->isJotSaved($iJotId, $this->_iProfileId);
  179. $mixedResult = $bSaved ? $this->_oModule->_oDb->deleteSavedJotItems($iJotId, $this->_iProfileId) : $this->_oModule->_oDb->saveJotItem($iJotId, $this->_iProfileId);
  180. if($mixedResult === false) {
  181. return ['code' => 3, 'message' => _t('_bx_messenger_nothing_has_been_saved')];
  182. }
  183. return ['code' => 0, 'value' => (int)!$bSaved, 'title' => _t($bSaved ? '_bx_messenger_jot_menu_save' : '_bx_messenger_jot_menu_remove_save')];
  184. }
  185. /**
  186. * Turn notifications of convo (lot) with defined ID on / off for the viewer
  187. */
  188. public function serviceMuteConvo($sParams)
  189. {
  190. $aOptions = json_decode($sParams, true);
  191. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  192. if(!$iLotId || !$this->_iProfileId || !$this->_oModule->_oDb->getLotInfoById($iLotId) || !$this->_isAvailable($iLotId)) {
  193. return ['code' => 1, 'message' => _t('_bx_messenger_not_found')];
  194. }
  195. $bMuted = (bool)$this->_oModule->_oDb->muteLot($iLotId, $this->_iProfileId);
  196. return ['code' => 0, 'value' => (int)$bMuted, 'title' => _t($bMuted ? '_bx_messenger_lots_menu_mute_info_on' : '_bx_messenger_lots_menu_mute_info_off')];
  197. }
  198. /**
  199. * Mark convo (lot) with defined ID as important (star) / not important for the viewer
  200. */
  201. public function serviceStarConvo($sParams)
  202. {
  203. $aOptions = json_decode($sParams, true);
  204. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  205. if(!$iLotId || !$this->_iProfileId || !$this->_oModule->_oDb->getLotInfoById($iLotId) || !$this->_isAvailable($iLotId)) {
  206. return ['code' => 1, 'message' => _t('_bx_messenger_not_found')];
  207. }
  208. $bStarred = (bool)$this->_oModule->_oDb->starLot($iLotId, $this->_iProfileId);
  209. return ['code' => 0, 'value' => (int)$bStarred, 'title' => _t(!$bStarred ? '_bx_messenger_lots_menu_star_on' : '_bx_messenger_lots_menu_star_off')];
  210. }
  211. /**
  212. * Get files attached to messages of convo (lot) with defined ID, newest first, by pages
  213. */
  214. public function serviceGetConvoFiles($sParams)
  215. {
  216. $CNF = &$this->_oModule->_oConfig->CNF;
  217. $aOptions = json_decode($sParams, true);
  218. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  219. $iStart = isset($aOptions['start']) ? max(0, (int)$aOptions['start']) : 0;
  220. $iPerPage = (int)$CNF['PARAM_DEFAULT_TALK_FILES_NUM'];
  221. if(!$iLotId || !$this->_oModule->_oDb->getLotInfoById($iLotId)) {
  222. return ['code' => 1, 'message' => _t('_bx_messenger_not_found')];
  223. }
  224. if(!$this->_iProfileId || !$this->_oModule->_oDb->isParticipant($iLotId, $this->_iProfileId)) {
  225. return ['code' => 2, 'message' => _t('_bx_messenger_not_participant')];
  226. }
  227. $sStorage = $CNF['OBJECT_STORAGE'];
  228. $oStorage = new BxMessengerStorage($sStorage);
  229. // File URLs come from the storage engine object, BxMessengerStorage only checks types.
  230. $oStorageEngine = BxDolStorage::getObjectInstance($sStorage);
  231. $aFiles = [];
  232. foreach($this->_oModule->_oDb->getLotFiles($iLotId, $iStart, $iPerPage) as $aFile) {
  233. $iFileId = (int)$aFile[$CNF['FIELD_ST_ID']];
  234. $bImage = $oStorage->isImageFile($aFile[$CNF['FIELD_ST_TYPE']]);
  235. $aFiles[] = [
  236. 'id' => $iFileId,
  237. 'name' => $aFile[$CNF['FIELD_ST_NAME']],
  238. 'mime_type' => $aFile[$CNF['FIELD_ST_TYPE']],
  239. 'size' => isset($aFile['size']) ? (int)$aFile['size'] : 0,
  240. 'added' => (int)$aFile[$CNF['FIELD_ST_ADDED']],
  241. 'jot_id' => (int)$aFile[$CNF['FIELD_ST_JOT']],
  242. 'author_data' => BxDolProfile::getData($aFile[$CNF['FIELD_ST_AUTHOR']]),
  243. 'image' => $bImage ? bx_api_get_image($sStorage, $iFileId) : null,
  244. 'url' => $oStorageEngine ? $oStorageEngine->getFileUrlById($iFileId) : '',
  245. ];
  246. }
  247. return [
  248. 'code' => 0,
  249. 'files' => $aFiles,
  250. 'params' => [
  251. 'start' => $iStart,
  252. 'per_page' => $iPerPage,
  253. 'total' => $this->_oModule->_oDb->getLotFilesCount($iLotId)
  254. ]
  255. ];
  256. }
  257. /**
  258. * Get settings (allowed actions) of convo (lot) with defined ID
  259. */
  260. public function serviceGetConvoSettings($sParams)
  261. {
  262. $aOptions = json_decode($sParams, true);
  263. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  264. if(!$iLotId || !$this->_oModule->_oDb->getLotInfoById($iLotId)) {
  265. return ['code' => 1, 'message' => _t('_bx_messenger_not_found')];
  266. }
  267. if(!$this->_isAllowedToManage($iLotId)) {
  268. return ['code' => 2, 'message' => _t('_bx_messenger_lot_can_change_settings')];
  269. }
  270. return array_merge(['code' => 0, 'title' => _t('_bx_messenger_lot_options_title')], $this->_oModule->_oTemplate->getLotSettingsOptions($iLotId));
  271. }
  272. /**
  273. * Save settings (allowed actions) of convo (lot) with defined ID
  274. */
  275. public function serviceSaveConvoSettings($sParams)
  276. {
  277. $aOptions = json_decode($sParams, true);
  278. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  279. if(!$iLotId || !$this->_oModule->_oDb->getLotInfoById($iLotId)) {
  280. return ['code' => 1, 'message' => _t('_bx_messenger_not_found')];
  281. }
  282. if(!$this->_isAllowedToManage($iLotId)) {
  283. return ['code' => 2, 'message' => _t('_bx_messenger_lot_can_change_settings')];
  284. }
  285. // Only known options can be saved.
  286. $aSettings = $this->_oModule->_oTemplate->getLotSettingsOptions($iLotId);
  287. $aValues = isset($aOptions['options']) && is_array($aOptions['options']) ? $aOptions['options'] : [];
  288. $aValues = array_values(array_intersect(array_column($aSettings['options'], 'key'), $aValues));
  289. if($this->_oModule->_oDb->saveLotSettings($iLotId, $aValues) === false) {
  290. return ['code' => 3, 'message' => _t('_bx_messenger_nothing_has_been_saved')];
  291. }
  292. return ['code' => 0, 'values' => $aValues];
  293. }
  294. /**
  295. * Get convo (lot) info with defined ID
  296. */
  297. public function serviceGetConvo($sParams)
  298. {
  299. $CNF = &$this->_oModule->_oConfig->CNF;
  300. $aOptions = json_decode($sParams, true);
  301. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  302. $aLotInfo = [];
  303. if(!$iLotId || !($aLotInfo = $this->_oModule->_oDb->getLotInfoById($iLotId)))
  304. return ['code' => 1, 'message' => _t('_bx_messenger_not_found')];
  305. if(!$this->_isAvailable($iLotId))
  306. return ['code' => 2, 'message' => _t('_bx_messenger_not_participant')];
  307. $aPartList = $this->_oModule->_oDb->getParticipantsList($iLotId);
  308. if((int)$aLotInfo[$CNF['FIELD_TYPE']] === BX_IM_TYPE_BROADCAST)
  309. $aPartList = $this->_oModule->_oDb->getBroadcastParticipants($iLotId);
  310. return ['code' => 0, 'lot' => [
  311. 'author_data' => BxDolProfile::getData($aLotInfo[$CNF['FIELD_AUTHOR']]),
  312. 'parts' => count($aPartList),
  313. 'files' => $this->_oModule->_oDb->getLotFilesCount($iLotId),
  314. 'messages' => $this->_oModule->_oDb->getJotsNumber($iLotId, 0),
  315. ]];
  316. }
  317. /**
  318. * Get convo (lot) URL by recipient ID
  319. */
  320. public function serviceGetConvoUrl($mixedParams)
  321. {
  322. $CNF = &$this->_oModule->_oConfig->CNF;
  323. $aOptions = is_array($mixedParams) ? $mixedParams : json_decode($mixedParams, true);
  324. $aParticipants = [$this->_iProfileId];
  325. if(!empty($aOptions['recipient']))
  326. $aParticipants[] = $aOptions['recipient'];
  327. $aLot = $this->_oModule->_oDb->findLotByParams([
  328. $CNF['FIELD_PARTICIPANTS'] => $aParticipants,
  329. $CNF['FIELD_TYPE'] => BX_IM_TYPE_PRIVATE
  330. ]);
  331. if(empty($aLot) || !is_array($aLot)) {
  332. $aResult = $this->_oModule->saveParticipantsList($aParticipants);
  333. if(!isset($aResult['lot']))
  334. return false;
  335. $aLot = $this->_oModule->_oDb->getLotInfoById($aResult['lot']);
  336. if(empty($aLot) || !is_array($aLot))
  337. return false;
  338. }
  339. return bx_api_get_relative_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']) . '/inbox/' . $this->_normalizeConvoHash($aLot['hash']));
  340. }
  341. public function serviceGetConvosList($sParams = '')
  342. {
  343. $aOptions = json_decode($sParams, true);
  344. $aData = $this->_oModule->serviceGetTalksList($aOptions);
  345. $aList = $aData['list'];
  346. if(isset($aData['code']) && !(int)$aData['code'] && !empty($aData['list']))
  347. $aList = $this->_oModule->_oTemplate->getLotsPreview($this->_iProfileId, $aData['list']);
  348. $aResult = [];
  349. if(empty($aList))
  350. return $aResult;
  351. $this->_prefetchStarredLots($aData['list']);
  352. foreach($aList as $iKey => $aItem)
  353. $aResult[] = $this->_unitLot($aData['list'][$iKey], $aItem);
  354. return $aResult;
  355. }
  356. public function serviceGetConvoMessages($sParams)
  357. {
  358. $aOptions = is_array($sParams) ? $sParams : json_decode($sParams, true);
  359. $CNF = &$this->_oModule->_oConfig->CNF;
  360. $iJot = isset($aOptions['jot']) ? (int)$aOptions['jot'] : 0;
  361. $iStart = isset($aOptions['start']) ? (int)$aOptions['start'] : 0;
  362. $iLotId = 0;
  363. if(isset($aOptions['lot']) && $aOptions['lot'])
  364. $iLotId = $this->_oModule->_oDb->getConvoByHash($aOptions['lot']);
  365. $sLoad = isset($aOptions['load']) ? $aOptions['load'] : 'prev';
  366. $sArea = isset($aOptions['area_type']) ? $aOptions['area_type'] : 'index';
  367. if ($iLotId && !$this->_isAvailable($iLotId))
  368. return ['code' => 1, 'message' => _t('_bx_messenger_talk_is_not_allowed')];
  369. $sUrl = isset($aOptions['url']) ? $aOptions['url'] : '';
  370. if ($sUrl)
  371. $sUrl = $this->_oModule->getPreparedUrl($sUrl);
  372. $isFocused = (bool)bx_get('focus');
  373. $iRequestedJot = (int)bx_get('req_jot');
  374. $iLastViewedJot = (int)bx_get('last_viewed_jot');
  375. $bUpdateHistory = true;
  376. $mixedContent = '';
  377. $iUnreadJotsNumber = 0;
  378. $iLastUnreadJotId = 0;
  379. $bAttach = true;
  380. $bRemoveSeparator = false;
  381. $aParamsBrowse = [];
  382. switch ($sLoad) {
  383. case 'new':
  384. if (!$iJot) {
  385. $iJot = $this->_oModule->_oDb->getFirstUnreadJot($this->_iProfileId, $iLotId);
  386. if ($iJot)
  387. $iJot = $this->_oModule->_oDb->getPrevJot($iLotId, $iJot);
  388. else {
  389. $aLatestJot = $this->_oModule->_oDb->getLatestJot($iLotId);
  390. $iJot = !empty($aLatestJot) ? (int)$aLatestJot[$CNF['FIELD_MESSAGE_ID']] : 0;
  391. }
  392. }
  393. if ($iRequestedJot) {
  394. if ($this->_oModule->_oDb->getJotsNumber($iLotId, $iJot, $iRequestedJot) >= $CNF['MAX_JOTS_LOAD_HISTORY'])
  395. $bUpdateHistory = false;
  396. else if ($isFocused)
  397. $this->_oModule->_oDb->readMessage($iRequestedJot, $this->_iProfileId);
  398. }
  399. if ($iLastViewedJot && $bUpdateHistory && $isFocused) {
  400. $this->_oModule->_oDb->readMessage($iLastViewedJot, $this->_iProfileId);
  401. }
  402. case 'ids':
  403. $mixedContent = [$this->_oModule->_oDb->getJotById($iJot)];
  404. break;
  405. case 'prev':
  406. $aCriteria = [
  407. 'lot' => $iLotId,
  408. 'url' => $sUrl,
  409. 'start' => $iJot,
  410. 'load' => $sLoad,
  411. 'start' => $iStart,
  412. 'limit' => $CNF['MAX_JOTS_BY_DEFAULT'],
  413. 'area' => $sArea,
  414. ];
  415. $iLastUnreadJotId = $iUnreadJotsNumber = 0;
  416. $aUnreadInfo = $this->_oModule->_oDb->getNewJots($this->_iProfileId, $iLotId);
  417. if (!empty($aUnreadInfo)) {
  418. $iLastUnreadJotId = (int)$aUnreadInfo[$CNF['FIELD_NEW_JOT']];
  419. $iUnreadJotsNumber = (int)$aUnreadInfo[$CNF['FIELD_NEW_UNREAD']];
  420. }
  421. $aParamsBrowse = array_merge($aParamsBrowse, [
  422. 'start' => $iStart,
  423. 'limit' => $CNF['MAX_JOTS_BY_DEFAULT'],
  424. ]);
  425. $mixedContent = $this->_oModule->_oDb->getJotsByLotIdApi($aCriteria);
  426. /**
  427. * Mark as read (delete) notification for the lot while getting jots list.
  428. */
  429. $this->_oModule->_oDb->markNotificationAsRead($this->_iProfileId, $iLotId);
  430. break;
  431. }
  432. $aResult = [];
  433. if (is_array($mixedContent) && $mixedContent){
  434. $oMenu = BxTemplMenu::getObjectInstance($CNF['OBJECT_MENU_JOT_MENU']);
  435. $sStorage = $CNF['OBJECT_STORAGE'];
  436. $oStorage = new BxMessengerStorage($sStorage);
  437. // Messages of the page saved by the viewer, one query for the page.
  438. $aSavedJots = array_map('intval', $this->_oModule->_oDb->getSavedJotsByIds($this->_iProfileId, array_column($mixedContent, $CNF['FIELD_MESSAGE_ID'])));
  439. foreach($mixedContent as &$aJot) {
  440. $iJotId = $aJot[$CNF['FIELD_MESSAGE_ID']];
  441. $this->_oModule->_oDb->readMessage($iJotId, $this->_iProfileId);
  442. $aFiles = [];
  443. if ($mixedFiles = $this->_oModule->_oDb->getJotFiles($iJotId))
  444. foreach($mixedFiles as &$aFile) {
  445. if ($oStorage->isImageFile($aFile[$CNF['FIELD_ST_TYPE']]))
  446. $aFiles[] = bx_api_get_image($sStorage, (int)$aFile[$CNF['FIELD_ST_ID']]);
  447. }
  448. $aReactions = [];
  449. if(($oReactions = BxDolVote::getObjectInstance($CNF['OBJECT_JOTS_RVOTES'], $iJotId)) && $oReactions->isEnabled()) {
  450. $aReactionsOptions = [];
  451. $aReactions = $oReactions->getElementApi($aReactionsOptions);
  452. }
  453. $oMenu->setContentId($iJotId);
  454. $sReplyMessage = '';
  455. if(($iReply = (int)$aJot['reply']) != 0) {
  456. $aReply = $this->_oModule->_oDb->getJotById($iReply);
  457. if(!empty($aReply) && is_array($aReply))
  458. $sReplyMessage = $aReply[$CNF['FIELD_MESSAGE']];
  459. }
  460. $aResult[] = array_merge($aJot, [
  461. $CNF['FIELD_MESSAGE_FK'] => isset($aOptions['lot']) ? $aOptions['lot'] : '',
  462. $CNF['FIELD_MESSAGE'] => $aJot[$CNF['FIELD_MESSAGE']],
  463. 'author_data' => BxDolProfile::getData($aJot[$CNF['FIELD_MESSAGE_AUTHOR']]),
  464. 'reactions' => $aReactions,
  465. 'menu' => $oMenu->getCodeAPI(),
  466. 'files' => $aFiles,
  467. 'reply_message' => $sReplyMessage,
  468. 'saved' => in_array((int)$iJotId, $aSavedJots) ? 1 : 0
  469. ]);
  470. }
  471. }
  472. return [
  473. 'code' => 0,
  474. 'jots' => $aResult,
  475. 'params' => $aParamsBrowse,
  476. 'unread_jots' => $iUnreadJotsNumber,
  477. 'last_unread_jot' => $iLastUnreadJotId
  478. ];
  479. }
  480. public function serviceGetSendForm($sParams = '')
  481. {
  482. if (!$this->_oModule->isLogged())
  483. return ['code' => 1, 'msg' => _t('_bx_messenger_not_logged')];
  484. $CNF = &$this->_oModule->_oConfig->CNF;
  485. $oForm = BxBaseFormView::getObjectInstance($CNF['OBJECT_API_FORM_NAME'], $CNF['OBJECT_API_FORM_NAME']);
  486. $aOptions = [];
  487. if ($sParams)
  488. $aOptions = json_decode($sParams, true);
  489. if (!empty($aOptions)){
  490. if (isset($aOptions['action']) && $aOptions['action'] === 'edit' && isset($aOptions['id']) && (int)$aOptions['id']){
  491. $aJotInfo = $this->_oModule->_oDb->getJotById((int)$aOptions['id']);
  492. if ($this->_isAvailable($aJotInfo[$CNF['FIELD_MESSAGE_FK']])){
  493. $oForm->aInputs['message_id']['value'] = $aJotInfo[$CNF['FIELD_MESSAGE_ID']];
  494. $oForm->aInputs['action']['value'] = 'edit';
  495. $oForm->aInputs['message']['value'] = $aJotInfo[$CNF['FIELD_MESSAGE']];
  496. }
  497. }
  498. }
  499. if ($oForm->isSubmittedAndValid()){
  500. /* if (isset($aOptions['convo_id'])){
  501. $oForm->aInputs['id']['value'] = $aOptions['convo_id'];
  502. } */
  503. if (isset($aOptions['reply_id'])){
  504. $oForm->aInputs['reply']['value'] = $aOptions['reply_id'];
  505. }
  506. $iLotId = 0 ;
  507. $mixedLotId = bx_get('id');
  508. if (!$mixedLotId){
  509. $mixedLotId = $oForm->aInputs['id']['value'] = $aOptions['convo_id'];
  510. }
  511. if ($mixedLotId)
  512. $iLotId = !is_numeric($mixedLotId) ? $this->_oModule->_oDb->getConvoByHash($mixedLotId) : (int)$mixedLotId;
  513. $aLotInfo = $this->_oModule->_oDb->getLotInfoById($iLotId);
  514. if (!empty($aLotInfo) && !$this->_isAvailable($iLotId))
  515. return ['code' => 1, 'msg' => _t('_bx_messenger_not_participant')];
  516. $sLotHash = $this->_normalizeConvoHash($aLotInfo['hash']);
  517. $aData = [
  518. 'lot' => $iLotId,
  519. 'message' => bx_get('message')
  520. ];
  521. /* if(($iReply = bx_get('reply')) !== false)
  522. $aData['reply'] = (int)$iReply;*/
  523. if (isset($aOptions['reply_id'])){
  524. $aData['reply'] = $aOptions['reply_id'];
  525. }
  526. if(($mixPayload = bx_get('payload')) !== false && !$aData['lot']) {
  527. if(!empty($mixPayload) && ($mixPayload = json_decode($mixPayload, true)) && is_array($mixPayload))
  528. $aData = array_merge($aData, $mixPayload);
  529. if(isset($aData['participants']) && !in_array($this->_iProfileId, $aData['participants']))
  530. $aData['participants'][] = $this->_iProfileId;
  531. }
  532. if(($mixedFiles = bx_get('files')) !== false && !empty($mixedFiles))
  533. $aData['files'] = explode(',', $mixedFiles);
  534. $iMessageId = bx_get('message_id');
  535. $sAction = bx_get('action');
  536. if ($iMessageId && $sAction === 'edit') {
  537. $aJotInfo = $this->_oModule->_oDb->getJotById($iMessageId);
  538. if (empty($aJotInfo))
  539. return ['code' => 1, 'msg' => _t('_Empty')];
  540. if (!$this->_isAvailable($aJotInfo[$CNF['FIELD_MESSAGE_FK']]))
  541. return ['code' => 1, 'msg' => _t('_bx_messenger_not_participant')];
  542. $sMessage = $this->_oModule->prepareMessageToDb($aData['message']);
  543. $mixedResult = $this->_oModule->_oDb->isAllowedToEditJot($iMessageId, $this->_iProfileId);
  544. if ($mixedResult !== true)
  545. return ['code' => 1, 'msg' => $mixedResult];
  546. if (!empty($aData['files'])) {
  547. $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
  548. $aFilesNames = [];
  549. foreach($aData['files'] as &$iFileId) {
  550. $aFile = $oStorage->getFile($iFileId);
  551. if (empty($aFile))
  552. continue;
  553. $aFilesNames[] = $aFile[$CNF['FIELD_ST_NAME']];
  554. $this->_oModule->_oDb->updateFiles($iFileId, array(
  555. $CNF['FIELD_ST_JOT'] => $iMessageId,
  556. ));
  557. $oStorage->afterUploadCleanup($iFileId, $this->_iProfileId);
  558. }
  559. $aFilesData = [];
  560. if (!empty($aJotInfo[$CNF['FIELD_MESSAGE_AT']]))
  561. $aFilesData = @unserialize($aJotInfo[$CNF['FIELD_MESSAGE_AT']]);
  562. if (!empty($aFilesNames))
  563. $aFilesData[BX_ATT_TYPE_FILES] = ( isset($aFilesData[BX_ATT_TYPE_FILES]) ? $aFilesData[BX_ATT_TYPE_FILES] : [] ) + $aFilesNames;
  564. $this->_oModule->_oDb->updateJot($iMessageId, $CNF['FIELD_MESSAGE_AT'], @serialize($aFilesData));
  565. }
  566. if ($sMessage && $this->_oModule->_oDb->editJot($iMessageId, $this->_iProfileId, $sMessage)) {
  567. $this->_oModule->onUpdateJot($aJotInfo[$CNF['FIELD_MESSAGE_FK']], $iMessageId, $aJotInfo[$CNF['FIELD_MESSAGE_AUTHOR']]);
  568. $this->_pusherData('convo_' . $sLotHash, ['convo' => $iLotId, 'action' => 'edited', 'data' => $this->serviceGetConvoMessages([
  569. 'load' => 'ids',
  570. 'lot' => $sLotHash,
  571. 'jot' => $iMessageId
  572. ])]);
  573. return ['code' => 0, 'jot_id' => $iMessageId];
  574. }
  575. return ['code' => 1];
  576. }
  577. $aResult = $this->_oModule->sendMessage($aData);
  578. $bResult = !empty($aResult) && is_array($aResult);
  579. // Socket broadcast lives in sendMessage()
  580. return $bResult ? array_merge($aResult, []) : ['msg' => $aResult];
  581. }
  582. return $oForm->getCodeAPI();
  583. }
  584. /*
  585. * Get participants list by lot ID.
  586. */
  587. public function serviceGetPartsList($sParams)
  588. {
  589. $aOptions = json_decode($sParams, true);
  590. $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0;
  591. if(!$iLotId || !($bAllowed = $this->_oModule->_oDb->isAuthor($iLotId, $this->_iProfileId) || $this->_oModule->_oConfig->isAllowedAction(BX_MSG_ACTION_ADMINISTRATE_TALKS, $this->_iProfileId) === true))
  592. return ['code' => 1];
  593. $aIds = $this->_oModule->_oDb->getParticipantsList($iLotId);
  594. if(empty($aIds) || !is_array($aIds))
  595. return ['code' => 2];
  596. $aResult = [];
  597. foreach($aIds as $iId)
  598. $aResult[] = BxDolProfile::getData($iId);
  599. return $aResult;
  600. }
  601. public function serviceSavePartsList($sParams)
  602. {
  603. $aOptions = json_decode($sParams, true);
  604. $aResult = ['code' => 1];
  605. if (!$sParams || !isset($aOptions['parts']))
  606. return $aResult;
  607. if(!in_array($this->_iProfileId, $aOptions['parts']))
  608. $aOptions['parts'][] = $this->_iProfileId;
  609. $aResult = $this->_oModule->saveParticipantsList($aOptions['parts'], (isset($aOptions['id']) ? $aOptions['id'] : 0));
  610. if(!isset($aResult['lot']))
  611. return $aResult;
  612. $CNF = &$this->_oModule->_oConfig->CNF;
  613. $aLot = $this->_oModule->_oDb->getLotInfoById($aResult['lot']);
  614. $aItems = $this->_oModule->_oTemplate->getLotsPreview($this->_iProfileId, [$aLot]);
  615. if(!empty($aItems) && is_array($aItems))
  616. $aResult = array_merge($aResult, [
  617. 'convo' => $this->_unitLot($aLot, current($aItems)),
  618. 'lot' => $aLot[$CNF['FIELD_HASH']]
  619. ]);
  620. return $aResult;
  621. }
  622. public function serviceSearchUsers($sParams)
  623. {
  624. $aOptions = json_decode($sParams, true);
  625. if (!$sParams || !isset($aOptions['term'])) {
  626. return ['code' => 1];
  627. }
  628. // Friends only mode: the module's own search among the viewer's friends.
  629. if ($this->_oModule->_oConfig->CNF['USE-FRIENDS-ONLY-MODE']) {
  630. return $this->_searchUsersByModule($sParams);
  631. }
  632. $sTerm = trim((string)$aOptions['term']);
  633. if ($sTerm === '') {
  634. return [];
  635. }
  636. $aExcept = isset($aOptions['except']) && is_array($aOptions['except']) ? array_map('intval', $aOptions['except']) : [];
  637. $iLimit = 10;
  638. // Names are searched in each profile module directly (its quick search fields),
  639. // so the result doesn't depend on the site's global search settings.
  640. $aProfileIds = [];
  641. $aModules = BxDolService::call('system', 'get_profiles_modules', [], 'TemplServiceProfiles');
  642. foreach ((array)$aModules as $aModule) {
  643. if (!BxDolService::call($aModule['name'], 'act_as_profile') || !($oModule = BxDolModule::getInstance($aModule['name']))) {
  644. continue;
  645. }
  646. foreach ((array)$oModule->_oDb->searchByTerm($sTerm, $iLimit * 2) as $aRow) {
  647. if (!empty($aRow['profile_id'])) {
  648. $aProfileIds[] = (int)$aRow['profile_id'];
  649. }
  650. }
  651. }
  652. $aUsers = [];
  653. foreach (array_unique($aProfileIds) as $iProfileId) {
  654. if ($iProfileId == $this->_iProfileId || in_array($iProfileId, $aExcept)) {
  655. continue;
  656. }
  657. if (!($oProfile = BxDolProfile::getInstance($iProfileId)) || $oProfile->checkAllowedProfileContact() !== CHECK_ACTION_RESULT_ALLOWED) {
  658. continue;
  659. }
  660. $aUsers[] = BxDolProfile::getData($iProfileId);
  661. if (count($aUsers) >= $iLimit) {
  662. break;
  663. }
  664. }
  665. return $aUsers;
  666. }
  667. /**
  668. * Users search with the module's search (friends only mode).
  669. */
  670. protected function _searchUsersByModule($sParams)
  671. {
  672. $aOptions = json_decode($sParams, true);
  673. $aResult = ['code' => 1];
  674. $aUsers = [];
  675. if (!$sParams || !isset($aOptions['term']))
  676. return $aResult;
  677. $aFoundProfile = $this->_oModule->searchProfiles($aOptions['term'], isset($aOptions['except']) ? $aOptions['except'] : []);
  678. if (!empty($aFoundProfile)) {
  679. foreach($aFoundProfile as &$aProfile) {
  680. if(!($oProfile = BxDolProfile::getInstanceByContentAndType($aProfile['id'], $aProfile['module'])) || $oProfile->checkAllowedProfileContact() !== CHECK_ACTION_RESULT_ALLOWED)
  681. continue;
  682. $aUsers[] = $aProfile['author_data'];
  683. }
  684. }
  685. return $aUsers;
  686. }
  687. public function serviceSearchLots($sParams)
  688. {
  689. $aOptions = json_decode($sParams, true);
  690. $sTerm = isset($aOptions['term']) ? $aOptions['term'] : '';
  691. $iStarred = isset($aOptions['starred']) ? (int)$aOptions['starred'] : 0;
  692. // The list section the search runs in: the results stay inside it.
  693. $sGroup = isset($aOptions['group']) ? $aOptions['group'] : '';
  694. $aSearchParams = [
  695. 'term' => $sTerm,
  696. 'star' => (bool)$iStarred || $sGroup === BX_MSG_TALK_TYPE_FAVORITES,
  697. // The app searches talks by their titles and participants' names, not by messages.
  698. 'search_criteria' => [BX_SEARCH_CRITERIA_TITLES, BX_SEARCH_CRITERIA_PARTS]
  699. ];
  700. if($sGroup === BX_MSG_TALK_TYPE_DIRECT) {
  701. $aSearchParams['type'] = BX_IM_TYPE_PRIVATE;
  702. }
  703. $aJots = [];
  704. $aLots = $this->_oModule->_oDb->getMyLots($this->_iProfileId, $aSearchParams, $aJots);
  705. if(empty($aLots) || !is_array($aLots)) {
  706. return [];
  707. }
  708. // Saved messages section: only talks with messages saved by the viewer.
  709. if($sGroup === BX_MSG_TALK_TYPE_SAVED) {
  710. $CNF = &$this->_oModule->_oConfig->CNF;
  711. $aSavedLotIds = array_flip($this->_oModule->_oDb->getSavedLotIds($this->_iProfileId));
  712. $aLots = array_values(array_filter($aLots, function($aLot) use ($CNF, $aSavedLotIds) {
  713. return isset($aSavedLotIds[(int)$aLot[$CNF['FIELD_ID']]]);
  714. }));
  715. if(empty($aLots)) {
  716. return [];
  717. }
  718. }
  719. $aResult = [
  720. 'lots' => [],
  721. 'search_list' => []
  722. ];
  723. $aItems = $this->_oModule->_oTemplate->getLotsPreview($this->_iProfileId, $aLots);
  724. $this->_prefetchStarredLots($aLots);
  725. foreach($aItems as $iKey => $aItem)
  726. $aResult['lots'][] = $this->_unitLot($aLots[$iKey], $aItem);
  727. if(!empty($aJots['jots_list']) && is_array($aJots['jots_list'])) {
  728. foreach($aJots['jots_list'] as $iJot => $iLot) {
  729. if(!isset($aResult['search_list'][$iLot]))
  730. $aResult['search_list'][$iLot] = [
  731. 'id' => $iLot,
  732. 'jots' => []
  733. ];
  734. $aResult['search_list'][$iLot]['jots'][] = $iJot;
  735. }
  736. if(!empty($aResult['search_list']))
  737. $aResult['search_list'] = array_values($aResult['search_list']);
  738. }
  739. return $aResult;
  740. }
  741. public function serviceRemoveJot($sParams = '')
  742. {
  743. $aOptions = json_decode($sParams, true);
  744. $iJotId = isset($aOptions['jot_id']) ? (int)$aOptions['jot_id'] : 0;
  745. $sLotHash = isset($aOptions['lot_id']) ? $aOptions['lot_id'] : 0;
  746. if(!$iJotId)
  747. return [];
  748. $iLotId = $this->_oModule->_oDb->getConvoByHash($sLotHash);
  749. $this->_pusherData('convo_' . $sLotHash, [
  750. 'convo' => $iLotId,
  751. 'action' => 'deleted',
  752. 'data' => $iJotId
  753. ]);
  754. return $this->_oModule->serviceDeleteJot($iJotId, true);
  755. }
  756. protected function _unitProfile($iProfileId, $aParams = [])
  757. {
  758. $CNF = &$this->_oModule->_oConfig->CNF;
  759. $oProfile = BxDolProfile::getInstance($iProfileId);
  760. if(!$oProfile)
  761. return '';
  762. $sModule = $oProfile->getModule();
  763. $iContentId = $oProfile->getContentId();
  764. $oModule = BxDolModule::getInstance($sModule);
  765. $aData = $oModule->_oDb->getContentInfoById($iContentId);
  766. $oPCNF = &$oModule->_oConfig->CNF;
  767. $aResult = [
  768. 'id' => $iContentId,
  769. 'module' => $sModule,
  770. 'title' => $oProfile->getDisplayName(),
  771. 'url' => $this->serviceGetConvoUrl(['recipient' => $iProfileId]),
  772. 'image' => bx_api_get_image($oPCNF['OBJECT_STORAGE'], $aData[$oPCNF['FIELD_PICTURE']]),
  773. 'cover' => bx_api_get_image($oPCNF['OBJECT_STORAGE'], $aData[$oPCNF['FIELD_COVER']])
  774. ];
  775. $sKey = 'OBJECT_MENU_SNIPPET_META';
  776. if(!empty($CNF[$sKey]) && ($oMetaMenu = BxDolMenu::getObjectInstance($CNF[$sKey], $oModule->_oTemplate)) !== false) {
  777. $oPrivacy = BxDolPrivacy::getObjectInstance($oPCNF['OBJECT_PRIVACY_VIEW']);
  778. $bPrivacy = $oPrivacy !== false;
  779. $bPublic = !$bPrivacy || $oPrivacy->check($iContentId) || $oPrivacy->isPartiallyVisible($aData[$CNF['FIELD_ALLOW_VIEW_TO']]);
  780. $oMetaMenu->setContentModule($sModule);
  781. $oMetaMenu->setContentId($iContentId);
  782. $oMetaMenu->setContentPublic($bPublic);
  783. $aResult['meta'] = $oMetaMenu->getCodeAPI();
  784. }
  785. return $aResult;
  786. }
  787. protected function _unitLot($aLot, $aItem)
  788. {
  789. $CNF = &$this->_oModule->_oConfig->CNF;
  790. $aParticipants = [];
  791. if(!empty($aItem[$CNF['FIELD_PARTICIPANTS']])) {
  792. $aPartIds = explode(',', $aItem[$CNF['FIELD_PARTICIPANTS']]);
  793. foreach($aPartIds as $iPartId) {
  794. if(!$iPartId)
  795. continue;
  796. $aParticipants[] = BxDolProfile::getData($iPartId, ['with_online' => true]);
  797. }
  798. }
  799. $sImageUrl = $aItem['bx_if:user']['content']['icon'];
  800. if(!empty($sImageUrl) && is_array($sImageUrl))
  801. $sImageUrl = !empty($sImageUrl['src']) ? $sImageUrl['src'] : '';
  802. if($sImageUrl)
  803. $sImageUrl = bx_api_get_relative_url($sImageUrl);
  804. return [
  805. 'author_data' => (int)$aItem[$CNF['FIELD_AUTHOR']] ? BxDolProfile::getData($aItem[$CNF['FIELD_AUTHOR']]) : [
  806. 'id' => 0,
  807. 'display_type' => 'unit',
  808. 'display_name' => $aItem['bx_if:user']['content']['talk_type'],
  809. 'url' => $sImageUrl,
  810. 'url_avatar' => $sImageUrl,
  811. 'module' => isset($aItem['author_module']) ? $aItem['author_module'] : 'bx_pages',
  812. ],
  813. 'participants' => $aParticipants,
  814. 'title' => $aItem[$CNF['FIELD_TITLE']],
  815. 'message' => $aItem['bx_if:user']['content']['message'],
  816. 'date' => $aItem['bx_if:timer']['content']['time'],
  817. 'id' => $this->_normalizeConvoHash($aLot[$CNF['FIELD_HASH']]),
  818. 'id2' => $aItem[$CNF['FIELD_ID']],
  819. // Marked with a star (favorite) by the viewer.
  820. 'starred' => $this->_isStarredLot((int)$aItem[$CNF['FIELD_ID']]) ? 1 : 0,
  821. // Conversation actions (gear menu): the app requests the items on demand with system/get_menu.
  822. 'menu' => $this->_getLotMenuShort((int)$aItem[$CNF['FIELD_ID']]),
  823. 'unread' => $aItem['count'],
  824. 'total_messages' => $this->_oModule->_oDb->getJotsNumber($aItem[$CNF['FIELD_ID']], 0)
  825. ];
  826. }
  827. protected function _pusherData($sAction, $aData = [])
  828. {
  829. $CNF = &$this->_oModule->_oConfig->CNF;
  830. $aData['user_id'] = $this->_iProfileId;
  831. if(!empty($aData['convo']) && ($aLotInfo = $this->_oModule->_oDb->getLotInfoById($aData['convo'])))
  832. $aData['id'] = $this->_normalizeConvoHash($aLotInfo[$CNF['FIELD_HASH']]);
  833. if(($oSockets = BxDolSockets::getInstance()) && $oSockets->isEnabled() && $sAction && !empty($aData))
  834. $oSockets->sendEvent('bx', 'messenger', $sAction, $aData);
  835. }
  836. /**
  837. * Talks of a list marked with a star by the viewer, loaded with one query for the whole list.
  838. */
  839. protected function _prefetchStarredLots($aLots)
  840. {
  841. $CNF = &$this->_oModule->_oConfig->CNF;
  842. $aLotIds = [];
  843. foreach((array)$aLots as $aLot) {
  844. if(!empty($aLot[$CNF['FIELD_ID']])) {
  845. $aLotIds[] = (int)$aLot[$CNF['FIELD_ID']];
  846. }
  847. }
  848. $this->_aStarredLots = array_map('intval', $this->_oModule->_oDb->getStarredLots($this->_iProfileId, $aLotIds));
  849. }
  850. protected function _isStarredLot($iLotId)
  851. {
  852. if($this->_aStarredLots !== null) {
  853. return in_array((int)$iLotId, $this->_aStarredLots);
  854. }
  855. return (bool)$this->_oModule->_oDb->isStarred($iLotId, $this->_iProfileId);
  856. }
  857. /**
  858. * Short code of the talk actions menu (object, title, params), items are loaded on demand.
  859. */
  860. protected function _getLotMenuShort($iLotId)
  861. {
  862. if($this->_aLotMenuShort === null) {
  863. $CNF = &$this->_oModule->_oConfig->CNF;
  864. $oMenu = BxTemplMenu::getObjectInstance($CNF['OBJECT_MENU_TALK_INFO_MENU']);
  865. $this->_aLotMenuShort = $oMenu ? $oMenu->getShortCodeAPI() : [];
  866. }
  867. if(empty($this->_aLotMenuShort)) {
  868. return [];
  869. }
  870. return array_merge($this->_aLotMenuShort, ['params' => ['lot' => (int)$iLotId]]);
  871. }
  872. /**
  873. * Talk author or a member who can administrate talks.
  874. */
  875. protected function _isAllowedToManage($iLotId)
  876. {
  877. return $this->_iProfileId && ($this->_oModule->_oDb->isAuthor($iLotId, $this->_iProfileId) || $this->_isAdministrator());
  878. }
  879. /**
  880. * Member can administrate talks. Checked once per request: the ACL check counts the action.
  881. */
  882. protected function _isAdministrator()
  883. {
  884. if($this->_bAdministrator === null) {
  885. $this->_bAdministrator = $this->_iProfileId && $this->_oModule->_oConfig->isAllowedAction(BX_MSG_ACTION_ADMINISTRATE_TALKS, $this->_iProfileId) === true;
  886. }
  887. return $this->_bAdministrator;
  888. }
  889. protected function _isAvailable($iLotId)
  890. {
  891. if(!$iLotId)
  892. return false;
  893. $CNF = &$this->_oModule->_oConfig->CNF;
  894. $aLotInfo = $this->_oModule->_oDb->getLotInfoById($iLotId);
  895. if(!empty($aLotInfo) && !$this->_oModule->_oDb->isParticipant($iLotId, $this->_iProfileId) && $aLotInfo[$CNF['FIELD_TYPE']] == BX_IM_TYPE_PRIVATE)
  896. return false;
  897. return true;
  898. }
  899. protected function _normalizeConvoHash($sHash)
  900. {
  901. return mb_strtolower($sHash);
  902. }
  903. public function log($mixedContents, $sSection = '', $sTitle = '')
  904. {
  905. if(is_array($mixedContents))
  906. $mixedContents = var_export($mixedContents, true);
  907. else if(is_object($mixedContents))
  908. $mixedContents = json_encode($mixedContents);
  909. if(empty($sSection))
  910. $sSection = "Core";
  911. $sTitle .= "\n";
  912. bx_log($this->_sModule, ":\n[" . $sSection . "] " . $sTitle . $mixedContents);
  913. }
  914. /**
  915. * Service allows to get information about conference by room's uid
  916. *
  917. * @param $sUid
  918. * @param $iLimit
  919. * @return mixed
  920. */
  921. public function serviceGetConferenceInfoByUid($sParams){
  922. $aOptions = json_decode($sParams, true);
  923. $sUid = $aOptions['room_id'] ?? '';
  924. if (!$sUid)
  925. return [];
  926. $iLimit = $aOptions['limit'] ?? 0;
  927. return $this->_oModule->_oDb->getVideoConferenceInfoByRoom($sUid, $iLimit);
  928. }
  929. }
  930. /** @} */