_sModule = 'bx_messenger'; $this->_oModule = BxDolModule::getInstance($this->_sModule); $this->_iProfileId = bx_get_logged_profile_id(); } public function serviceGetBlockMain() { $CNF = &$this->_oModule->_oConfig->CNF; $aMenuMain = []; if(($oMenuMain = BxTemplMenu::getObjectInstance($CNF['OBJECT_MENU_NAV_LEFT_MENU'])) !== false) $aMenuMain = $oMenuMain->getCodeAPI(); return [ bx_api_get_block('messenger_main_page', [ 'config' => [ 'permissions' => [ 'create_talk' => $this->_oModule->_oConfig->isAllowedAction(BX_MSG_ACTION_CREATE_TALKS, $this->_iProfileId) === true ? 1 : 0, 'send_message' => $this->_oModule->_oConfig->isAllowedAction(BX_MSG_ACTION_SEND_MESSAGE, $this->_iProfileId) === true ? 1 : 0, ] ], 'menu' => $aMenuMain, 'form' => ['data' => $this->serviceGetSendForm()], ], [ 'ext' => [ 'name' => $this->_sModule, 'params' => ($aParams = bx_get('params')) !== false ? $aParams : [], 'request' => ['url' => '/api.php?r=' . $this->_sModule . '/get_send_form/Services', 'immutable' => true] ] ]) ]; } public function serviceGetBlockContacts($mixedParams) { $aParams = bx_api_get_browse_params($mixedParams, true); $aBlock = BxDolPage::getBlockProcessing(); $sContentType = 'browse'; if(($sK = 'config_api') && $aBlock[$sK] && is_array($aBlock[$sK])) $sContentType = $aBlock[$sK]['content_type'] ?? $sContentType; $bBrowseSimple = $sContentType == 'browse_simple'; $aProfiles = !defined('BX_API_PAGE') || $bBrowseSimple ? $this->_oModule->_oTemplate->getContacts($this->_iProfileId, $aParams) : []; $aData = []; foreach($aProfiles as &$aProfile) if($aProfile['id'] != $this->_iProfileId) $aData[] = $this->_unitProfile($aProfile['id']); if(!$bBrowseSimple || $aData) $aData = [bx_api_get_block($sContentType, [ 'module' => $this->_sModule, 'unit' => 'mixed', 'request_url' => '/api.php?r=' . $this->_sModule . '/get_block_contacts/Services¶ms[]=', 'data' => $aData, 'params' => [ 'start' => isset($aParams['start']) ? $aParams['start'] : 0, 'per_page' => isset($aParams['per_page']) ? $aParams['per_page'] : 0 ] ])]; return $aData; } /* * Find convo (lot) related to logged in profile and context if the last one is provided. */ public function serviceFindConvo($sParams) { $aOptions = json_decode($sParams, true); $aParticipants = [$this->_iProfileId]; if(!empty($aOptions['context'])) $aParticipants[] = $aOptions['context']; $aLot = $this->_oModule->_oDb->getLotsByParticipantsList($aParticipants, BX_IM_TYPE_PRIVATE); if(empty($aLot) || !is_array($aLot)) return []; return ['lot' => $aLot]; } /** * Leave convo (lot) with defined ID */ public function serviceLeaveConvo($sParams) { $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; if(!$iLotId || !$this->_oModule->_oDb->isParticipant($iLotId, $this->_iProfileId)) return ['code' => 1, 'message' => _t('_bx_messenger_not_participant')]; if($this->_oModule->_oDb->isAuthor($iLotId, $this->_iProfileId)) return ['code' => 2, 'message' => _t('_bx_messenger_cant_leave')]; return ['code' => !$this->_oModule->_oDb->leaveLot($iLotId, $this->_iProfileId) ? 3 : 0]; } /** * Delete convo (lot) with defined ID */ public function serviceDeleteConvo($sParams) { $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; if(!$iLotId || !($this->_oModule->_oDb->isAuthor($iLotId, $this->_iProfileId) || ($this->_oModule->_oConfig->isAllowedAction(BX_MSG_ACTION_ADMINISTRATE_TALKS, $this->_iProfileId) === true))) return ['code' => 1, 'message' => _t('_bx_messenger_can_not_delete')]; return ['code' => !$this->_oModule->_oDb->deleteLot($iLotId) ? 2 : 0]; } /** * Remove all messages from convo (lot) with defined ID */ public function serviceClearConvo($sParams) { $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; if(!$iLotId || !$this->_isAllowedToManage($iLotId)) { return ['code' => 1, 'message' => _t('_bx_messenger_no_permissions')]; } return ['code' => $this->_oModule->_oDb->clearLot($iLotId) === false ? 2 : 0]; } /** * Search messages of convo (lot) with defined ID by their text, newest first, by pages */ public function serviceSearchConvoMessages($sParams) { $CNF = &$this->_oModule->_oConfig->CNF; $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; $sTerm = isset($aOptions['term']) ? trim((string)$aOptions['term']) : ''; $iStart = isset($aOptions['start']) ? max(0, (int)$aOptions['start']) : 0; $iPerPage = 20; if(!$iLotId || !$this->_iProfileId || !$this->_oModule->_oDb->getLotInfoById($iLotId)) { return ['code' => 1, 'message' => _t('_bx_messenger_not_found')]; } if(!$this->_oModule->_oDb->isParticipant($iLotId, $this->_iProfileId) && !$this->_isAdministrator()) { return ['code' => 2, 'message' => _t('_bx_messenger_not_participant')]; } $aResult = ['code' => 0, 'jots' => [], 'params' => ['start' => $iStart, 'per_page' => $iPerPage]]; if($sTerm === '') { return $aResult; } // LIKE wildcards in the term are searched as plain characters. $sTerm = addcslashes($sTerm, '%_\\'); $aJots = $this->_oModule->_oDb->findInHistory($iLotId, $sTerm, $iStart, $iPerPage, 'DESC', true); foreach($aJots as $aJot) { $aResult['jots'][] = [ 'id' => (int)$aJot['message_id'], 'message' => $aJot[$CNF['FIELD_MESSAGE']], 'added' => (int)$aJot['message_added'], 'author_data' => BxDolProfile::getData($aJot['message_author']), ]; } return $aResult; } /** * Save message (jot) with defined ID to the viewer's saved messages, or remove it from there */ public function serviceSaveJot($sParams) { $CNF = &$this->_oModule->_oConfig->CNF; $aOptions = json_decode($sParams, true); $iJotId = isset($aOptions['jot']) ? (int)$aOptions['jot'] : 0; if(!$iJotId || !$this->_iProfileId || !($aJotInfo = $this->_oModule->_oDb->getJotById($iJotId))) { return ['code' => 1, 'message' => _t('_bx_messenger_nothing_found')]; } if(!$this->_isAvailable($aJotInfo[$CNF['FIELD_MESSAGE_FK']])) { return ['code' => 2, 'message' => _t('_bx_messenger_not_participant')]; } $bSaved = $this->_oModule->_oDb->isJotSaved($iJotId, $this->_iProfileId); $mixedResult = $bSaved ? $this->_oModule->_oDb->deleteSavedJotItems($iJotId, $this->_iProfileId) : $this->_oModule->_oDb->saveJotItem($iJotId, $this->_iProfileId); if($mixedResult === false) { return ['code' => 3, 'message' => _t('_bx_messenger_nothing_has_been_saved')]; } return ['code' => 0, 'value' => (int)!$bSaved, 'title' => _t($bSaved ? '_bx_messenger_jot_menu_save' : '_bx_messenger_jot_menu_remove_save')]; } /** * Turn notifications of convo (lot) with defined ID on / off for the viewer */ public function serviceMuteConvo($sParams) { $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; if(!$iLotId || !$this->_iProfileId || !$this->_oModule->_oDb->getLotInfoById($iLotId) || !$this->_isAvailable($iLotId)) { return ['code' => 1, 'message' => _t('_bx_messenger_not_found')]; } $bMuted = (bool)$this->_oModule->_oDb->muteLot($iLotId, $this->_iProfileId); return ['code' => 0, 'value' => (int)$bMuted, 'title' => _t($bMuted ? '_bx_messenger_lots_menu_mute_info_on' : '_bx_messenger_lots_menu_mute_info_off')]; } /** * Mark convo (lot) with defined ID as important (star) / not important for the viewer */ public function serviceStarConvo($sParams) { $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; if(!$iLotId || !$this->_iProfileId || !$this->_oModule->_oDb->getLotInfoById($iLotId) || !$this->_isAvailable($iLotId)) { return ['code' => 1, 'message' => _t('_bx_messenger_not_found')]; } $bStarred = (bool)$this->_oModule->_oDb->starLot($iLotId, $this->_iProfileId); return ['code' => 0, 'value' => (int)$bStarred, 'title' => _t(!$bStarred ? '_bx_messenger_lots_menu_star_on' : '_bx_messenger_lots_menu_star_off')]; } /** * Get files attached to messages of convo (lot) with defined ID, newest first, by pages */ public function serviceGetConvoFiles($sParams) { $CNF = &$this->_oModule->_oConfig->CNF; $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; $iStart = isset($aOptions['start']) ? max(0, (int)$aOptions['start']) : 0; $iPerPage = (int)$CNF['PARAM_DEFAULT_TALK_FILES_NUM']; if(!$iLotId || !$this->_oModule->_oDb->getLotInfoById($iLotId)) { return ['code' => 1, 'message' => _t('_bx_messenger_not_found')]; } if(!$this->_iProfileId || !$this->_oModule->_oDb->isParticipant($iLotId, $this->_iProfileId)) { return ['code' => 2, 'message' => _t('_bx_messenger_not_participant')]; } $sStorage = $CNF['OBJECT_STORAGE']; $oStorage = new BxMessengerStorage($sStorage); // File URLs come from the storage engine object, BxMessengerStorage only checks types. $oStorageEngine = BxDolStorage::getObjectInstance($sStorage); $aFiles = []; foreach($this->_oModule->_oDb->getLotFiles($iLotId, $iStart, $iPerPage) as $aFile) { $iFileId = (int)$aFile[$CNF['FIELD_ST_ID']]; $bImage = $oStorage->isImageFile($aFile[$CNF['FIELD_ST_TYPE']]); $aFiles[] = [ 'id' => $iFileId, 'name' => $aFile[$CNF['FIELD_ST_NAME']], 'mime_type' => $aFile[$CNF['FIELD_ST_TYPE']], 'size' => isset($aFile['size']) ? (int)$aFile['size'] : 0, 'added' => (int)$aFile[$CNF['FIELD_ST_ADDED']], 'jot_id' => (int)$aFile[$CNF['FIELD_ST_JOT']], 'author_data' => BxDolProfile::getData($aFile[$CNF['FIELD_ST_AUTHOR']]), 'image' => $bImage ? bx_api_get_image($sStorage, $iFileId) : null, 'url' => $oStorageEngine ? $oStorageEngine->getFileUrlById($iFileId) : '', ]; } return [ 'code' => 0, 'files' => $aFiles, 'params' => [ 'start' => $iStart, 'per_page' => $iPerPage, 'total' => $this->_oModule->_oDb->getLotFilesCount($iLotId) ] ]; } /** * Get settings (allowed actions) of convo (lot) with defined ID */ public function serviceGetConvoSettings($sParams) { $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; if(!$iLotId || !$this->_oModule->_oDb->getLotInfoById($iLotId)) { return ['code' => 1, 'message' => _t('_bx_messenger_not_found')]; } if(!$this->_isAllowedToManage($iLotId)) { return ['code' => 2, 'message' => _t('_bx_messenger_lot_can_change_settings')]; } return array_merge(['code' => 0, 'title' => _t('_bx_messenger_lot_options_title')], $this->_oModule->_oTemplate->getLotSettingsOptions($iLotId)); } /** * Save settings (allowed actions) of convo (lot) with defined ID */ public function serviceSaveConvoSettings($sParams) { $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; if(!$iLotId || !$this->_oModule->_oDb->getLotInfoById($iLotId)) { return ['code' => 1, 'message' => _t('_bx_messenger_not_found')]; } if(!$this->_isAllowedToManage($iLotId)) { return ['code' => 2, 'message' => _t('_bx_messenger_lot_can_change_settings')]; } // Only known options can be saved. $aSettings = $this->_oModule->_oTemplate->getLotSettingsOptions($iLotId); $aValues = isset($aOptions['options']) && is_array($aOptions['options']) ? $aOptions['options'] : []; $aValues = array_values(array_intersect(array_column($aSettings['options'], 'key'), $aValues)); if($this->_oModule->_oDb->saveLotSettings($iLotId, $aValues) === false) { return ['code' => 3, 'message' => _t('_bx_messenger_nothing_has_been_saved')]; } return ['code' => 0, 'values' => $aValues]; } /** * Get convo (lot) info with defined ID */ public function serviceGetConvo($sParams) { $CNF = &$this->_oModule->_oConfig->CNF; $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; $aLotInfo = []; if(!$iLotId || !($aLotInfo = $this->_oModule->_oDb->getLotInfoById($iLotId))) return ['code' => 1, 'message' => _t('_bx_messenger_not_found')]; if(!$this->_isAvailable($iLotId)) return ['code' => 2, 'message' => _t('_bx_messenger_not_participant')]; $aPartList = $this->_oModule->_oDb->getParticipantsList($iLotId); if((int)$aLotInfo[$CNF['FIELD_TYPE']] === BX_IM_TYPE_BROADCAST) $aPartList = $this->_oModule->_oDb->getBroadcastParticipants($iLotId); return ['code' => 0, 'lot' => [ 'author_data' => BxDolProfile::getData($aLotInfo[$CNF['FIELD_AUTHOR']]), 'parts' => count($aPartList), 'files' => $this->_oModule->_oDb->getLotFilesCount($iLotId), 'messages' => $this->_oModule->_oDb->getJotsNumber($iLotId, 0), ]]; } /** * Get convo (lot) URL by recipient ID */ public function serviceGetConvoUrl($mixedParams) { $CNF = &$this->_oModule->_oConfig->CNF; $aOptions = is_array($mixedParams) ? $mixedParams : json_decode($mixedParams, true); $aParticipants = [$this->_iProfileId]; if(!empty($aOptions['recipient'])) $aParticipants[] = $aOptions['recipient']; $aLot = $this->_oModule->_oDb->findLotByParams([ $CNF['FIELD_PARTICIPANTS'] => $aParticipants, $CNF['FIELD_TYPE'] => BX_IM_TYPE_PRIVATE ]); if(empty($aLot) || !is_array($aLot)) { $aResult = $this->_oModule->saveParticipantsList($aParticipants); if(!isset($aResult['lot'])) return false; $aLot = $this->_oModule->_oDb->getLotInfoById($aResult['lot']); if(empty($aLot) || !is_array($aLot)) return false; } return bx_api_get_relative_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']) . '/inbox/' . $this->_normalizeConvoHash($aLot['hash'])); } public function serviceGetConvosList($sParams = '') { $aOptions = json_decode($sParams, true); $aData = $this->_oModule->serviceGetTalksList($aOptions); $aList = $aData['list']; if(isset($aData['code']) && !(int)$aData['code'] && !empty($aData['list'])) $aList = $this->_oModule->_oTemplate->getLotsPreview($this->_iProfileId, $aData['list']); $aResult = []; if(empty($aList)) return $aResult; $this->_prefetchStarredLots($aData['list']); foreach($aList as $iKey => $aItem) $aResult[] = $this->_unitLot($aData['list'][$iKey], $aItem); return $aResult; } public function serviceGetConvoMessages($sParams) { $aOptions = is_array($sParams) ? $sParams : json_decode($sParams, true); $CNF = &$this->_oModule->_oConfig->CNF; $iJot = isset($aOptions['jot']) ? (int)$aOptions['jot'] : 0; $iStart = isset($aOptions['start']) ? (int)$aOptions['start'] : 0; $iLotId = 0; if(isset($aOptions['lot']) && $aOptions['lot']) $iLotId = $this->_oModule->_oDb->getConvoByHash($aOptions['lot']); $sLoad = isset($aOptions['load']) ? $aOptions['load'] : 'prev'; $sArea = isset($aOptions['area_type']) ? $aOptions['area_type'] : 'index'; if ($iLotId && !$this->_isAvailable($iLotId)) return ['code' => 1, 'message' => _t('_bx_messenger_talk_is_not_allowed')]; $sUrl = isset($aOptions['url']) ? $aOptions['url'] : ''; if ($sUrl) $sUrl = $this->_oModule->getPreparedUrl($sUrl); $isFocused = (bool)bx_get('focus'); $iRequestedJot = (int)bx_get('req_jot'); $iLastViewedJot = (int)bx_get('last_viewed_jot'); $bUpdateHistory = true; $mixedContent = ''; $iUnreadJotsNumber = 0; $iLastUnreadJotId = 0; $bAttach = true; $bRemoveSeparator = false; $aParamsBrowse = []; switch ($sLoad) { case 'new': if (!$iJot) { $iJot = $this->_oModule->_oDb->getFirstUnreadJot($this->_iProfileId, $iLotId); if ($iJot) $iJot = $this->_oModule->_oDb->getPrevJot($iLotId, $iJot); else { $aLatestJot = $this->_oModule->_oDb->getLatestJot($iLotId); $iJot = !empty($aLatestJot) ? (int)$aLatestJot[$CNF['FIELD_MESSAGE_ID']] : 0; } } if ($iRequestedJot) { if ($this->_oModule->_oDb->getJotsNumber($iLotId, $iJot, $iRequestedJot) >= $CNF['MAX_JOTS_LOAD_HISTORY']) $bUpdateHistory = false; else if ($isFocused) $this->_oModule->_oDb->readMessage($iRequestedJot, $this->_iProfileId); } if ($iLastViewedJot && $bUpdateHistory && $isFocused) { $this->_oModule->_oDb->readMessage($iLastViewedJot, $this->_iProfileId); } case 'ids': $mixedContent = [$this->_oModule->_oDb->getJotById($iJot)]; break; case 'prev': $aCriteria = [ 'lot' => $iLotId, 'url' => $sUrl, 'start' => $iJot, 'load' => $sLoad, 'start' => $iStart, 'limit' => $CNF['MAX_JOTS_BY_DEFAULT'], 'area' => $sArea, ]; $iLastUnreadJotId = $iUnreadJotsNumber = 0; $aUnreadInfo = $this->_oModule->_oDb->getNewJots($this->_iProfileId, $iLotId); if (!empty($aUnreadInfo)) { $iLastUnreadJotId = (int)$aUnreadInfo[$CNF['FIELD_NEW_JOT']]; $iUnreadJotsNumber = (int)$aUnreadInfo[$CNF['FIELD_NEW_UNREAD']]; } $aParamsBrowse = array_merge($aParamsBrowse, [ 'start' => $iStart, 'limit' => $CNF['MAX_JOTS_BY_DEFAULT'], ]); $mixedContent = $this->_oModule->_oDb->getJotsByLotIdApi($aCriteria); /** * Mark as read (delete) notification for the lot while getting jots list. */ $this->_oModule->_oDb->markNotificationAsRead($this->_iProfileId, $iLotId); break; } $aResult = []; if (is_array($mixedContent) && $mixedContent){ $oMenu = BxTemplMenu::getObjectInstance($CNF['OBJECT_MENU_JOT_MENU']); $sStorage = $CNF['OBJECT_STORAGE']; $oStorage = new BxMessengerStorage($sStorage); // Messages of the page saved by the viewer, one query for the page. $aSavedJots = array_map('intval', $this->_oModule->_oDb->getSavedJotsByIds($this->_iProfileId, array_column($mixedContent, $CNF['FIELD_MESSAGE_ID']))); foreach($mixedContent as &$aJot) { $iJotId = $aJot[$CNF['FIELD_MESSAGE_ID']]; $this->_oModule->_oDb->readMessage($iJotId, $this->_iProfileId); $aFiles = []; if ($mixedFiles = $this->_oModule->_oDb->getJotFiles($iJotId)) foreach($mixedFiles as &$aFile) { if ($oStorage->isImageFile($aFile[$CNF['FIELD_ST_TYPE']])) $aFiles[] = bx_api_get_image($sStorage, (int)$aFile[$CNF['FIELD_ST_ID']]); } $aReactions = []; if(($oReactions = BxDolVote::getObjectInstance($CNF['OBJECT_JOTS_RVOTES'], $iJotId)) && $oReactions->isEnabled()) { $aReactionsOptions = []; $aReactions = $oReactions->getElementApi($aReactionsOptions); } $oMenu->setContentId($iJotId); $sReplyMessage = ''; if(($iReply = (int)$aJot['reply']) != 0) { $aReply = $this->_oModule->_oDb->getJotById($iReply); if(!empty($aReply) && is_array($aReply)) $sReplyMessage = $aReply[$CNF['FIELD_MESSAGE']]; } $aResult[] = array_merge($aJot, [ $CNF['FIELD_MESSAGE_FK'] => isset($aOptions['lot']) ? $aOptions['lot'] : '', $CNF['FIELD_MESSAGE'] => $aJot[$CNF['FIELD_MESSAGE']], 'author_data' => BxDolProfile::getData($aJot[$CNF['FIELD_MESSAGE_AUTHOR']]), 'reactions' => $aReactions, 'menu' => $oMenu->getCodeAPI(), 'files' => $aFiles, 'reply_message' => $sReplyMessage, 'saved' => in_array((int)$iJotId, $aSavedJots) ? 1 : 0 ]); } } return [ 'code' => 0, 'jots' => $aResult, 'params' => $aParamsBrowse, 'unread_jots' => $iUnreadJotsNumber, 'last_unread_jot' => $iLastUnreadJotId ]; } public function serviceGetSendForm($sParams = '') { if (!$this->_oModule->isLogged()) return ['code' => 1, 'msg' => _t('_bx_messenger_not_logged')]; $CNF = &$this->_oModule->_oConfig->CNF; $oForm = BxBaseFormView::getObjectInstance($CNF['OBJECT_API_FORM_NAME'], $CNF['OBJECT_API_FORM_NAME']); $aOptions = []; if ($sParams) $aOptions = json_decode($sParams, true); if (!empty($aOptions)){ if (isset($aOptions['action']) && $aOptions['action'] === 'edit' && isset($aOptions['id']) && (int)$aOptions['id']){ $aJotInfo = $this->_oModule->_oDb->getJotById((int)$aOptions['id']); if ($this->_isAvailable($aJotInfo[$CNF['FIELD_MESSAGE_FK']])){ $oForm->aInputs['message_id']['value'] = $aJotInfo[$CNF['FIELD_MESSAGE_ID']]; $oForm->aInputs['action']['value'] = 'edit'; $oForm->aInputs['message']['value'] = $aJotInfo[$CNF['FIELD_MESSAGE']]; } } } if ($oForm->isSubmittedAndValid()){ /* if (isset($aOptions['convo_id'])){ $oForm->aInputs['id']['value'] = $aOptions['convo_id']; } */ if (isset($aOptions['reply_id'])){ $oForm->aInputs['reply']['value'] = $aOptions['reply_id']; } $iLotId = 0 ; $mixedLotId = bx_get('id'); if (!$mixedLotId){ $mixedLotId = $oForm->aInputs['id']['value'] = $aOptions['convo_id']; } if ($mixedLotId) $iLotId = !is_numeric($mixedLotId) ? $this->_oModule->_oDb->getConvoByHash($mixedLotId) : (int)$mixedLotId; $aLotInfo = $this->_oModule->_oDb->getLotInfoById($iLotId); if (!empty($aLotInfo) && !$this->_isAvailable($iLotId)) return ['code' => 1, 'msg' => _t('_bx_messenger_not_participant')]; $sLotHash = $this->_normalizeConvoHash($aLotInfo['hash']); $aData = [ 'lot' => $iLotId, 'message' => bx_get('message') ]; /* if(($iReply = bx_get('reply')) !== false) $aData['reply'] = (int)$iReply;*/ if (isset($aOptions['reply_id'])){ $aData['reply'] = $aOptions['reply_id']; } if(($mixPayload = bx_get('payload')) !== false && !$aData['lot']) { if(!empty($mixPayload) && ($mixPayload = json_decode($mixPayload, true)) && is_array($mixPayload)) $aData = array_merge($aData, $mixPayload); if(isset($aData['participants']) && !in_array($this->_iProfileId, $aData['participants'])) $aData['participants'][] = $this->_iProfileId; } if(($mixedFiles = bx_get('files')) !== false && !empty($mixedFiles)) $aData['files'] = explode(',', $mixedFiles); $iMessageId = bx_get('message_id'); $sAction = bx_get('action'); if ($iMessageId && $sAction === 'edit') { $aJotInfo = $this->_oModule->_oDb->getJotById($iMessageId); if (empty($aJotInfo)) return ['code' => 1, 'msg' => _t('_Empty')]; if (!$this->_isAvailable($aJotInfo[$CNF['FIELD_MESSAGE_FK']])) return ['code' => 1, 'msg' => _t('_bx_messenger_not_participant')]; $sMessage = $this->_oModule->prepareMessageToDb($aData['message']); $mixedResult = $this->_oModule->_oDb->isAllowedToEditJot($iMessageId, $this->_iProfileId); if ($mixedResult !== true) return ['code' => 1, 'msg' => $mixedResult]; if (!empty($aData['files'])) { $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']); $aFilesNames = []; foreach($aData['files'] as &$iFileId) { $aFile = $oStorage->getFile($iFileId); if (empty($aFile)) continue; $aFilesNames[] = $aFile[$CNF['FIELD_ST_NAME']]; $this->_oModule->_oDb->updateFiles($iFileId, array( $CNF['FIELD_ST_JOT'] => $iMessageId, )); $oStorage->afterUploadCleanup($iFileId, $this->_iProfileId); } $aFilesData = []; if (!empty($aJotInfo[$CNF['FIELD_MESSAGE_AT']])) $aFilesData = @unserialize($aJotInfo[$CNF['FIELD_MESSAGE_AT']]); if (!empty($aFilesNames)) $aFilesData[BX_ATT_TYPE_FILES] = ( isset($aFilesData[BX_ATT_TYPE_FILES]) ? $aFilesData[BX_ATT_TYPE_FILES] : [] ) + $aFilesNames; $this->_oModule->_oDb->updateJot($iMessageId, $CNF['FIELD_MESSAGE_AT'], @serialize($aFilesData)); } if ($sMessage && $this->_oModule->_oDb->editJot($iMessageId, $this->_iProfileId, $sMessage)) { $this->_oModule->onUpdateJot($aJotInfo[$CNF['FIELD_MESSAGE_FK']], $iMessageId, $aJotInfo[$CNF['FIELD_MESSAGE_AUTHOR']]); $this->_pusherData('convo_' . $sLotHash, ['convo' => $iLotId, 'action' => 'edited', 'data' => $this->serviceGetConvoMessages([ 'load' => 'ids', 'lot' => $sLotHash, 'jot' => $iMessageId ])]); return ['code' => 0, 'jot_id' => $iMessageId]; } return ['code' => 1]; } $aResult = $this->_oModule->sendMessage($aData); $bResult = !empty($aResult) && is_array($aResult); // Socket broadcast lives in sendMessage() return $bResult ? array_merge($aResult, []) : ['msg' => $aResult]; } return $oForm->getCodeAPI(); } /* * Get participants list by lot ID. */ public function serviceGetPartsList($sParams) { $aOptions = json_decode($sParams, true); $iLotId = isset($aOptions['lot']) ? (int)$aOptions['lot'] : 0; if(!$iLotId || !($bAllowed = $this->_oModule->_oDb->isAuthor($iLotId, $this->_iProfileId) || $this->_oModule->_oConfig->isAllowedAction(BX_MSG_ACTION_ADMINISTRATE_TALKS, $this->_iProfileId) === true)) return ['code' => 1]; $aIds = $this->_oModule->_oDb->getParticipantsList($iLotId); if(empty($aIds) || !is_array($aIds)) return ['code' => 2]; $aResult = []; foreach($aIds as $iId) $aResult[] = BxDolProfile::getData($iId); return $aResult; } public function serviceSavePartsList($sParams) { $aOptions = json_decode($sParams, true); $aResult = ['code' => 1]; if (!$sParams || !isset($aOptions['parts'])) return $aResult; if(!in_array($this->_iProfileId, $aOptions['parts'])) $aOptions['parts'][] = $this->_iProfileId; $aResult = $this->_oModule->saveParticipantsList($aOptions['parts'], (isset($aOptions['id']) ? $aOptions['id'] : 0)); if(!isset($aResult['lot'])) return $aResult; $CNF = &$this->_oModule->_oConfig->CNF; $aLot = $this->_oModule->_oDb->getLotInfoById($aResult['lot']); $aItems = $this->_oModule->_oTemplate->getLotsPreview($this->_iProfileId, [$aLot]); if(!empty($aItems) && is_array($aItems)) $aResult = array_merge($aResult, [ 'convo' => $this->_unitLot($aLot, current($aItems)), 'lot' => $aLot[$CNF['FIELD_HASH']] ]); return $aResult; } public function serviceSearchUsers($sParams) { $aOptions = json_decode($sParams, true); if (!$sParams || !isset($aOptions['term'])) { return ['code' => 1]; } // Friends only mode: the module's own search among the viewer's friends. if ($this->_oModule->_oConfig->CNF['USE-FRIENDS-ONLY-MODE']) { return $this->_searchUsersByModule($sParams); } $sTerm = trim((string)$aOptions['term']); if ($sTerm === '') { return []; } $aExcept = isset($aOptions['except']) && is_array($aOptions['except']) ? array_map('intval', $aOptions['except']) : []; $iLimit = 10; // Names are searched in each profile module directly (its quick search fields), // so the result doesn't depend on the site's global search settings. $aProfileIds = []; $aModules = BxDolService::call('system', 'get_profiles_modules', [], 'TemplServiceProfiles'); foreach ((array)$aModules as $aModule) { if (!BxDolService::call($aModule['name'], 'act_as_profile') || !($oModule = BxDolModule::getInstance($aModule['name']))) { continue; } foreach ((array)$oModule->_oDb->searchByTerm($sTerm, $iLimit * 2) as $aRow) { if (!empty($aRow['profile_id'])) { $aProfileIds[] = (int)$aRow['profile_id']; } } } $aUsers = []; foreach (array_unique($aProfileIds) as $iProfileId) { if ($iProfileId == $this->_iProfileId || in_array($iProfileId, $aExcept)) { continue; } if (!($oProfile = BxDolProfile::getInstance($iProfileId)) || $oProfile->checkAllowedProfileContact() !== CHECK_ACTION_RESULT_ALLOWED) { continue; } $aUsers[] = BxDolProfile::getData($iProfileId); if (count($aUsers) >= $iLimit) { break; } } return $aUsers; } /** * Users search with the module's search (friends only mode). */ protected function _searchUsersByModule($sParams) { $aOptions = json_decode($sParams, true); $aResult = ['code' => 1]; $aUsers = []; if (!$sParams || !isset($aOptions['term'])) return $aResult; $aFoundProfile = $this->_oModule->searchProfiles($aOptions['term'], isset($aOptions['except']) ? $aOptions['except'] : []); if (!empty($aFoundProfile)) { foreach($aFoundProfile as &$aProfile) { if(!($oProfile = BxDolProfile::getInstanceByContentAndType($aProfile['id'], $aProfile['module'])) || $oProfile->checkAllowedProfileContact() !== CHECK_ACTION_RESULT_ALLOWED) continue; $aUsers[] = $aProfile['author_data']; } } return $aUsers; } public function serviceSearchLots($sParams) { $aOptions = json_decode($sParams, true); $sTerm = isset($aOptions['term']) ? $aOptions['term'] : ''; $iStarred = isset($aOptions['starred']) ? (int)$aOptions['starred'] : 0; // The list section the search runs in: the results stay inside it. $sGroup = isset($aOptions['group']) ? $aOptions['group'] : ''; $aSearchParams = [ 'term' => $sTerm, 'star' => (bool)$iStarred || $sGroup === BX_MSG_TALK_TYPE_FAVORITES, // The app searches talks by their titles and participants' names, not by messages. 'search_criteria' => [BX_SEARCH_CRITERIA_TITLES, BX_SEARCH_CRITERIA_PARTS] ]; if($sGroup === BX_MSG_TALK_TYPE_DIRECT) { $aSearchParams['type'] = BX_IM_TYPE_PRIVATE; } $aJots = []; $aLots = $this->_oModule->_oDb->getMyLots($this->_iProfileId, $aSearchParams, $aJots); if(empty($aLots) || !is_array($aLots)) { return []; } // Saved messages section: only talks with messages saved by the viewer. if($sGroup === BX_MSG_TALK_TYPE_SAVED) { $CNF = &$this->_oModule->_oConfig->CNF; $aSavedLotIds = array_flip($this->_oModule->_oDb->getSavedLotIds($this->_iProfileId)); $aLots = array_values(array_filter($aLots, function($aLot) use ($CNF, $aSavedLotIds) { return isset($aSavedLotIds[(int)$aLot[$CNF['FIELD_ID']]]); })); if(empty($aLots)) { return []; } } $aResult = [ 'lots' => [], 'search_list' => [] ]; $aItems = $this->_oModule->_oTemplate->getLotsPreview($this->_iProfileId, $aLots); $this->_prefetchStarredLots($aLots); foreach($aItems as $iKey => $aItem) $aResult['lots'][] = $this->_unitLot($aLots[$iKey], $aItem); if(!empty($aJots['jots_list']) && is_array($aJots['jots_list'])) { foreach($aJots['jots_list'] as $iJot => $iLot) { if(!isset($aResult['search_list'][$iLot])) $aResult['search_list'][$iLot] = [ 'id' => $iLot, 'jots' => [] ]; $aResult['search_list'][$iLot]['jots'][] = $iJot; } if(!empty($aResult['search_list'])) $aResult['search_list'] = array_values($aResult['search_list']); } return $aResult; } public function serviceRemoveJot($sParams = '') { $aOptions = json_decode($sParams, true); $iJotId = isset($aOptions['jot_id']) ? (int)$aOptions['jot_id'] : 0; $sLotHash = isset($aOptions['lot_id']) ? $aOptions['lot_id'] : 0; if(!$iJotId) return []; $iLotId = $this->_oModule->_oDb->getConvoByHash($sLotHash); $this->_pusherData('convo_' . $sLotHash, [ 'convo' => $iLotId, 'action' => 'deleted', 'data' => $iJotId ]); return $this->_oModule->serviceDeleteJot($iJotId, true); } protected function _unitProfile($iProfileId, $aParams = []) { $CNF = &$this->_oModule->_oConfig->CNF; $oProfile = BxDolProfile::getInstance($iProfileId); if(!$oProfile) return ''; $sModule = $oProfile->getModule(); $iContentId = $oProfile->getContentId(); $oModule = BxDolModule::getInstance($sModule); $aData = $oModule->_oDb->getContentInfoById($iContentId); $oPCNF = &$oModule->_oConfig->CNF; $aResult = [ 'id' => $iContentId, 'module' => $sModule, 'title' => $oProfile->getDisplayName(), 'url' => $this->serviceGetConvoUrl(['recipient' => $iProfileId]), 'image' => bx_api_get_image($oPCNF['OBJECT_STORAGE'], $aData[$oPCNF['FIELD_PICTURE']]), 'cover' => bx_api_get_image($oPCNF['OBJECT_STORAGE'], $aData[$oPCNF['FIELD_COVER']]) ]; $sKey = 'OBJECT_MENU_SNIPPET_META'; if(!empty($CNF[$sKey]) && ($oMetaMenu = BxDolMenu::getObjectInstance($CNF[$sKey], $oModule->_oTemplate)) !== false) { $oPrivacy = BxDolPrivacy::getObjectInstance($oPCNF['OBJECT_PRIVACY_VIEW']); $bPrivacy = $oPrivacy !== false; $bPublic = !$bPrivacy || $oPrivacy->check($iContentId) || $oPrivacy->isPartiallyVisible($aData[$CNF['FIELD_ALLOW_VIEW_TO']]); $oMetaMenu->setContentModule($sModule); $oMetaMenu->setContentId($iContentId); $oMetaMenu->setContentPublic($bPublic); $aResult['meta'] = $oMetaMenu->getCodeAPI(); } return $aResult; } protected function _unitLot($aLot, $aItem) { $CNF = &$this->_oModule->_oConfig->CNF; $aParticipants = []; if(!empty($aItem[$CNF['FIELD_PARTICIPANTS']])) { $aPartIds = explode(',', $aItem[$CNF['FIELD_PARTICIPANTS']]); foreach($aPartIds as $iPartId) { if(!$iPartId) continue; $aParticipants[] = BxDolProfile::getData($iPartId, ['with_online' => true]); } } $sImageUrl = $aItem['bx_if:user']['content']['icon']; if(!empty($sImageUrl) && is_array($sImageUrl)) $sImageUrl = !empty($sImageUrl['src']) ? $sImageUrl['src'] : ''; if($sImageUrl) $sImageUrl = bx_api_get_relative_url($sImageUrl); return [ 'author_data' => (int)$aItem[$CNF['FIELD_AUTHOR']] ? BxDolProfile::getData($aItem[$CNF['FIELD_AUTHOR']]) : [ 'id' => 0, 'display_type' => 'unit', 'display_name' => $aItem['bx_if:user']['content']['talk_type'], 'url' => $sImageUrl, 'url_avatar' => $sImageUrl, 'module' => isset($aItem['author_module']) ? $aItem['author_module'] : 'bx_pages', ], 'participants' => $aParticipants, 'title' => $aItem[$CNF['FIELD_TITLE']], 'message' => $aItem['bx_if:user']['content']['message'], 'date' => $aItem['bx_if:timer']['content']['time'], 'id' => $this->_normalizeConvoHash($aLot[$CNF['FIELD_HASH']]), 'id2' => $aItem[$CNF['FIELD_ID']], // Marked with a star (favorite) by the viewer. 'starred' => $this->_isStarredLot((int)$aItem[$CNF['FIELD_ID']]) ? 1 : 0, // Conversation actions (gear menu): the app requests the items on demand with system/get_menu. 'menu' => $this->_getLotMenuShort((int)$aItem[$CNF['FIELD_ID']]), 'unread' => $aItem['count'], 'total_messages' => $this->_oModule->_oDb->getJotsNumber($aItem[$CNF['FIELD_ID']], 0) ]; } protected function _pusherData($sAction, $aData = []) { $CNF = &$this->_oModule->_oConfig->CNF; $aData['user_id'] = $this->_iProfileId; if(!empty($aData['convo']) && ($aLotInfo = $this->_oModule->_oDb->getLotInfoById($aData['convo']))) $aData['id'] = $this->_normalizeConvoHash($aLotInfo[$CNF['FIELD_HASH']]); if(($oSockets = BxDolSockets::getInstance()) && $oSockets->isEnabled() && $sAction && !empty($aData)) $oSockets->sendEvent('bx', 'messenger', $sAction, $aData); } /** * Talks of a list marked with a star by the viewer, loaded with one query for the whole list. */ protected function _prefetchStarredLots($aLots) { $CNF = &$this->_oModule->_oConfig->CNF; $aLotIds = []; foreach((array)$aLots as $aLot) { if(!empty($aLot[$CNF['FIELD_ID']])) { $aLotIds[] = (int)$aLot[$CNF['FIELD_ID']]; } } $this->_aStarredLots = array_map('intval', $this->_oModule->_oDb->getStarredLots($this->_iProfileId, $aLotIds)); } protected function _isStarredLot($iLotId) { if($this->_aStarredLots !== null) { return in_array((int)$iLotId, $this->_aStarredLots); } return (bool)$this->_oModule->_oDb->isStarred($iLotId, $this->_iProfileId); } /** * Short code of the talk actions menu (object, title, params), items are loaded on demand. */ protected function _getLotMenuShort($iLotId) { if($this->_aLotMenuShort === null) { $CNF = &$this->_oModule->_oConfig->CNF; $oMenu = BxTemplMenu::getObjectInstance($CNF['OBJECT_MENU_TALK_INFO_MENU']); $this->_aLotMenuShort = $oMenu ? $oMenu->getShortCodeAPI() : []; } if(empty($this->_aLotMenuShort)) { return []; } return array_merge($this->_aLotMenuShort, ['params' => ['lot' => (int)$iLotId]]); } /** * Talk author or a member who can administrate talks. */ protected function _isAllowedToManage($iLotId) { return $this->_iProfileId && ($this->_oModule->_oDb->isAuthor($iLotId, $this->_iProfileId) || $this->_isAdministrator()); } /** * Member can administrate talks. Checked once per request: the ACL check counts the action. */ protected function _isAdministrator() { if($this->_bAdministrator === null) { $this->_bAdministrator = $this->_iProfileId && $this->_oModule->_oConfig->isAllowedAction(BX_MSG_ACTION_ADMINISTRATE_TALKS, $this->_iProfileId) === true; } return $this->_bAdministrator; } protected function _isAvailable($iLotId) { if(!$iLotId) return false; $CNF = &$this->_oModule->_oConfig->CNF; $aLotInfo = $this->_oModule->_oDb->getLotInfoById($iLotId); if(!empty($aLotInfo) && !$this->_oModule->_oDb->isParticipant($iLotId, $this->_iProfileId) && $aLotInfo[$CNF['FIELD_TYPE']] == BX_IM_TYPE_PRIVATE) return false; return true; } protected function _normalizeConvoHash($sHash) { return mb_strtolower($sHash); } public function log($mixedContents, $sSection = '', $sTitle = '') { if(is_array($mixedContents)) $mixedContents = var_export($mixedContents, true); else if(is_object($mixedContents)) $mixedContents = json_encode($mixedContents); if(empty($sSection)) $sSection = "Core"; $sTitle .= "\n"; bx_log($this->_sModule, ":\n[" . $sSection . "] " . $sTitle . $mixedContents); } /** * Service allows to get information about conference by room's uid * * @param $sUid * @param $iLimit * @return mixed */ public function serviceGetConferenceInfoByUid($sParams){ $aOptions = json_decode($sParams, true); $sUid = $aOptions['room_id'] ?? ''; if (!$sUid) return []; $iLimit = $aOptions['limit'] ?? 0; return $this->_oModule->_oDb->getVideoConferenceInfoByRoom($sUid, $iLimit); } } /** @} */