defaults($opts, [ 'template' => '', # Ключ уведомления 'templateData' => [], # Данные шаблона для уведомления 'minusWords' => true, # Выполнять проверку на минус-слова ]); $template = $opts['template']; $templateData = $opts['templateData']; $return = $this->app->filter('internalmail.model.sendMessage.before', false, [ 'authorID' => &$authorID, 'recipientID' => &$recipientID, 'message' => &$message, 'messageData' => &$messageData, 'template' => &$template, 'templateData' => &$templateData, ]); if ($return !== false) { return $return; } if (! $this->isAdminPanel()) { $limit = $this->app->filter('internalmail.model.sendMessage.limit', config::sysAdmin('internalmail.contacts.limit', 0, TYPE_UINT)); if ($limit > 0) { $sent = $this->newMessagesSentToday($authorID); if ($sent >= $limit) { $messages = $this->messagesSent($authorID, $recipientID); if ($messages == 0) { $this->errors->set(_t('internalmail', 'Unfortunately, you cannot send a message to this user, because today you have already used the limit of new contacts.')); return 0; } } } if ($opts['minusWords']) { $minusWord = ''; if ($this->controller->spamMinusWordsSearch(['text' => $message, 'word' => &$minusWord])) { $this->errors->set(_t('internalmail', 'There is a forbidden word "[word]" in your message', [ 'word' => $minusWord, ])); return 0; } } } if (isset($messageData['attach']) && is_array($messageData['attach'])) { $messageData['attach'] = json_encode($messageData['attach'], JSON_UNESCAPED_UNICODE); } $message = nl2br($message); $messageCreated = $this->db->now(); $messageData = array_merge([ 'author' => $authorID, 'recipient' => $recipientID, 'message' => $message, 'is_new' => 1, 'created' => $messageCreated, ], $messageData); $messageID = $this->db->insert(static::TABLE_INTERNALMAIL, $messageData); if (!empty($messageID)) { $this->updateContact($authorID, $recipientID, $messageData['company_id'] ?? 0, $messageID, $messageCreated, false); $this->updateContact($recipientID, $authorID, $messageData['company_id'] ?? 0, $messageID, $messageCreated, true); $this->updateNewMessagesCounter($recipientID); NewMessage::dispatch($messageID, $authorID, $recipientID); # уведомление о новом сообщении if ($template !== false) { $userData = Users::model()->userDataEnotify($recipientID, Users::ENOTIFY_INTERNALMAIL); if ($userData) { if ($template === '') { $template = 'internalmail_new_message'; } $loginAuto = Users::loginAutoHash($userData); $templateData = array_merge([ 'name' => $userData['name'], 'email' => $userData['email'], 'user_id' => $recipientID, 'link' => $this->controller->url('account.messages', ['alogin' => $loginAuto]), 'message' => tpl::truncate(strip_tags($message), 250), 'item_id' => $messageData['item_id'] ?? 0, 'company_id' => $messageData['company_id'] ?? 0, ], $templateData); if (!empty($messageData['item_id'])) { $itemData = Listings::model()->itemData($messageData['item_id'], ['id','title','link']); if (!empty($itemData)) { $templateData['item_title'] = $itemData['title']; $templateData['item_link'] = $itemData['link'] . '?alogin=' . $loginAuto; } } $this->app->sendMailTemplate($templateData, $template, $userData['email'], false, '', '', $userData['lang']); } } # обновляем счетчик сообщений объявления if (!empty($itemID)) { Listings::model()->itemSave($itemID, [ 'messages_total = messages_total + 1', 'messages_new = messages_new + 1', ]); } return $messageID; } return 0; } /** * Очистка текста сообщения * @param string $message текст сообщения * @param int $maxLength максимально допустимое кол-во символов или 0 - без ограничений * @param bool|array $activateLinks подсветка ссылок * @return string очищенный текст */ public function cleanMessage(string $message, int $maxLength = 4000, $activateLinks = true): string { $message = htmlspecialchars($message); $message = $this->input->cleanTextPlain($message, $maxLength, $activateLinks); # антимат $message = TextParser::antimat($message); # дополнительная обработка $message = $this->app->filter('internalmail.message.validate', $message); return $message; } /** * Помечаем все сообщения переписки как "прочитанные" * @param int $userID ID текущего пользователя * @param int $interlocutorID ID собеседника * @param int $companyId ID компании / 0 / -1 (все) * @param bool $updateNewCounter обновлять счетчик кол-ва новых сообщений * @return int кол-во помеченных сообщений */ public function setMessagesReaded($userID, $interlocutorID, $companyId, bool $updateNewCounter = true): int { # сообщения $updateCond = [ 'recipient' => $userID, 'author' => $interlocutorID, 'is_new' => 1, ]; if ($companyId >= 0) { $updateCond['company_id'] = $companyId; } $updated = $this->db->update(static::TABLE_INTERNALMAIL, [ 'is_new' => 0, 'readed' => $this->db->now(), ], $updateCond); # контакты $updateCond = [ 'user_id' => $userID, 'interlocutor_id' => $interlocutorID, ]; if ($companyId >= 0) { $updateCond['company_id'] = $companyId; } $this->db->update(static::TABLE_INTERNALMAIL_CONTACTS, [ 'messages_new' => 0 ], $updateCond); # счетчик новых сообщений if ($updateNewCounter && !empty($updated)) { $this->updateNewMessagesCounter($userID); } return $updated; } /** * Переключатели сообщения * @param int $messageID ID сообщения * @param string $field переключаемое поле * @return mixed|void */ public function messageToggle(int $messageID, string $field) { switch ($field) { case 'blocked': { # Заблокировано return $this->toggleInt(static::TABLE_INTERNALMAIL, $messageID, $field); } } } /** * Обновляем данные контакта * @param int $userID ID пользователя * @param int $interlocutorID ID собеседника * @param int $companyId ID компании или 0 * @param int $messageID ID последнего сообщения * @param string $messageCreated дата создания последнего сообщения * @param bool $messageIsNew является ли сообщение новым (обновляем контакт получателя) * @return bool */ protected function updateContact($userID, $interlocutorID, $companyId, int $messageID, string $messageCreated, bool $messageIsNew): bool { # обновляем существующий контакт $data = [ 'last_message_id' => $messageID, 'last_message_date' => $messageCreated, 'messages_total = messages_total + 1', ]; if ($messageIsNew) { $data[] = 'messages_new = messages_new + 1'; } $res = $this->db->update(static::TABLE_INTERNALMAIL_CONTACTS, $data, [ 'user_id' => $userID, 'interlocutor_id' => $interlocutorID, 'company_id' => $companyId, ]); if (empty($res)) { # создаем контакт $res = $this->db->insert(static::TABLE_INTERNALMAIL_CONTACTS, [ 'user_id' => $userID, 'interlocutor_id' => $interlocutorID, 'company_id' => $companyId, 'last_message_id' => $messageID, 'last_message_date' => $messageCreated, 'messages_total' => 1, 'messages_new' => ($messageIsNew ? 1 : 0), ], false); } return !empty($res); } /** * Перемещаем собеседника в папку * @param int $userID ID пользователя (кто перемещает) * @param int $interlocutorID ID пользователя собеседника (кого перемещает) * @param int $companyId ID компании участвующей в переписке или 0 * @param int $folderID ID папки (куда перемещает) * @param bool $toggle true - удалять из папки, если собеседник уже в ней находится * @return int */ public function interlocutorToFolder($userID, $interlocutorID, $companyId, int $folderID, bool $toggle = true): int { if (empty($userID) || empty($interlocutorID) || $folderID <= 0) { return 0; } $exists = $this->db->one_data( 'SELECT interlocutor_id FROM ' . static::TABLE_INTERNALMAIL_FOLDERS_USERS . ' WHERE user_id = :userID AND interlocutor_id = :interlocutorID AND company_id = :companyID AND folder_id = :folderID', [ ':userID' => $userID, ':interlocutorID' => $interlocutorID, ':companyID' => $companyId, ':folderID' => $folderID, ] ); if ($exists) { if (!$toggle) { return 1; } $this->db->delete(static::TABLE_INTERNALMAIL_FOLDERS_USERS, [ 'user_id' => $userID, 'interlocutor_id' => $interlocutorID, 'company_id' => $companyId, 'folder_id' => $folderID, ]); return 0; } else { $this->db->insert(static::TABLE_INTERNALMAIL_FOLDERS_USERS, [ 'user_id' => $userID, 'interlocutor_id' => $interlocutorID, 'company_id' => $companyId, 'folder_id' => $folderID, ], false); return 1; } } /** * Получаем список папок, в которых находится собеседник * @param int $userID ID текущего пользователя * @param array $interlocutorsID ID собеседников * @param bool $useCompanyID задействовать company_id * @return array */ public function getInterlocutorFolders($userID, array $interlocutorsID, bool $useCompanyID = false): array { if (empty($interlocutorsID)) { return []; } $interlocutorsID = array_map('intval', $interlocutorsID); $folders = $this->db->select( 'SELECT folder_id as f, interlocutor_id as id, company_id as company FROM ' . static::TABLE_INTERNALMAIL_FOLDERS_USERS . ' WHERE user_id = :userID AND interlocutor_id IN(' . join(',', $interlocutorsID) . ')' . (!$useCompanyID ? ' AND company_id = 0' : ''), [':userID' => $userID] ); if (empty($folders)) { return []; } $result = []; foreach ($folders as $v) { if ($useCompanyID) { $result[$v['id']][$v['company']][] = $v['f']; } else { $result[$v['id']][] = $v['f']; } } return $result; } /** * Проверяет добавлен ли пользователь собеседником в папку * @param int $userID ID проверяющего * @param int $interlocutorID ID собеседника * @param int $companyId ID компании или 0 * @param int $folderID ID папки * @return bool */ public function isUserInFolder($userID, $interlocutorID, $companyId, int $folderID): bool { if (empty($interlocutorID) || $folderID <= 0) { return false; } return (bool)$this->db->one_data( 'SELECT COUNT(*) FROM ' . static::TABLE_INTERNALMAIL_FOLDERS_USERS . ' WHERE user_id = :interlocutorID AND interlocutor_id = :userID AND company_id = :companyID AND folder_id = :folder', [ ':interlocutorID' => $interlocutorID, ':companyID' => $companyId, ':userID' => $userID, ':folder' => $folderID, ] ); } /** * Создание/обновление папки пользователя * @param int $userID ID пользователя * @param int $folderID ID папки (обновляем) или 0 (создаем) * @param array $data данные * @return bool|int ID созданной папки */ public function userFolderSave($userID, int $folderID, array $data = []) { if ($folderID > 0) { if (empty($userID) || empty($data)) { return false; } $res = $this->db->update(static::TABLE_INTERNALMAIL_FOLDERS, $data, [ 'id' => $folderID, 'user_id' => $userID, ]); return !empty($res); } else { if (empty($userID) || empty($data)) { return 0; } $data['user_id'] = $userID; return $this->db->insert(static::TABLE_INTERNALMAIL_FOLDERS, $data); } } /** * Формирование ленты сообщений пользователей (spy - adm) * @param int $userID ID отправителя или 0 (все лента) * @param bool $countOnly только подсчет кол-ва * @param string $sqlLimit лимит выборки * @return array|int */ public function getMessagesSpyLenta($userID, bool $countOnly = false, string $sqlLimit = '') { $filter = []; if ($userID) { $filter[':from'] = ['I.author = :from', ':from' => $userID]; } $filter = $this->prepareFilter($filter); if ($countOnly) { return (int)$this->db->one_data('SELECT COUNT(*) FROM ' . static::TABLE_INTERNALMAIL . ' I ' . $filter['where'], $filter['bind']); } $data = $this->db->select( 'SELECT I.id, I.created, I.message, I.is_new, I.company_id, I.blocked, U1.user_id as from_id, U1.name as from_name, U1.login as from_login, U1.avatar as from_avatar, U1.sex as from_sex, U2.user_id as to_id, U2.name as to_name, U2.login as to_login, U2.avatar as to_avatar, U2.sex as to_sex FROM ' . static::TABLE_INTERNALMAIL . ' I INNER JOIN ' . Users::TABLE_USERS . ' U1 ON U1.user_id = I.author INNER JOIN ' . Users::TABLE_USERS . ' U2 ON U2.user_id = I.recipient ' . $filter['where'] . ' ORDER BY I.created DESC ' . $sqlLimit, $filter['bind'] ); if (empty($data)) { $data = []; } return $data; } /** * Получаем сообщения переписки * @param int $userID ID пользователя, просматривающего свои сообщения * @param int $interlocutorID ID собеседника * @param int $companyId ID компании или 0 * @param bool $countOnly только считаем кол-во * @param string|array $opts * @return array|int */ public function getConversationMessages($userID, $interlocutorID, $companyId, bool $countOnly = false, $opts = '') { if (! empty($opts) && is_string($opts)) { $opts = ['limit' => $opts]; } if (! is_array($opts)) { $opts = []; } $opts = $this->defaults($opts, [ 'limit' => '', 'order' => 'M.created ' . ($this->isAdminPanel() ? 'DESC' : 'ASC'), 'filter' => [], ]); $filter = $opts['filter']; $filter[':a'] = [ '((M.author=:userID AND M.recipient=:interlocutorID) OR (M.author=:interlocutorID AND M.recipient=:userID))', ':userID' => $userID, ':interlocutorID' => $interlocutorID, ]; $filter['company_id'] = $companyId; $filter = $this->prepareFilter($filter, 'M'); if ($countOnly) { return $this->db->one_data('SELECT COUNT(M.id) FROM ' . static::TABLE_INTERNALMAIL . ' M ' . $filter['where'], $filter['bind']); } return $this->db->select( 'SELECT M.*, DATE(M.created) as created_date, (M.author=:userID) as my, (M.recipient=:userID AND M.is_new) as new FROM ' . static::TABLE_INTERNALMAIL . ' M ' . $filter['where'] . ' ORDER BY ' . $opts['order'] . ' ' . $opts['limit'], $filter['bind'] ); } /** * Получаем список контактов пользователя (frontend) * @param int $userID ID пользователя, просматривающего свои переписки * @param int $companyId ID компании / 0 / -1 * @param int $folderID ID папки * @param string $filterMessages строка поиска (фильтр по сообщениям в переписке) * @param bool $countOnly только считаем кол-во * @param string $sqlLimit * @return array|int */ public function getContactsListingFront($userID, $companyId, int $folderID = 0, string $filterMessages = '', bool $countOnly = false, string $sqlLimit = '') { $bind = [':userID' => $userID]; $filterCompany = false; if ($companyId && in_array($folderID, [static::FOLDER_FOR_COMPANY, static::FOLDER_FOR_USER])) { if ($folderID == static::FOLDER_FOR_COMPANY) { $filterCompany = 'company_id = :companyID'; } else { if ($folderID == static::FOLDER_FOR_USER) { $filterCompany = 'company_id != :companyID'; } } $folderID = static::FOLDER_ALL; $bind[':companyID'] = $companyId; } else { if (!bff::businessEnabled()) { $filterCompany = 'company_id = 0'; } } if ($folderID > 0) { $bind[':folderID'] = $folderID; } if (mb_strlen($filterMessages) > 2) { if (preg_match('/item:([\d]+)/', $filterMessages, $matches) && !empty($matches[1])) { $itemID = intval($matches[1]); if ($itemID > 0) { $bind[':itemID'] = $itemID; $filterMessages = ' AND M.item_id = :itemID'; } } else { $filterMessages = ' AND ' . $this->db->prepareFulltextQuery($filterMessages, 'message,attach'); } } else { $filterMessages = ''; } if ($countOnly) { if (!empty($filterMessages)) { return $this->db->one_data( 'SELECT COUNT(U.user_id) FROM ' . static::TABLE_INTERNALMAIL . ' M, ' . Users::TABLE_USERS . ' U ' . ($folderID > 0 ? ', ' . static::TABLE_INTERNALMAIL_FOLDERS_USERS . ' F ' : '') . ' WHERE ( M.author = :userID OR M.recipient = :userID ) AND U.user_id = (CASE WHEN (M.author = :userID) THEN M.recipient ELSE M.author END) ' . ($folderID > 0 ? ' AND F.user_id = :userID AND F.company_id = M.company_id AND F.interlocutor_id = U.user_id AND F.folder_id = :folderID ' : '') . ' ' . ($filterCompany ? ' AND M.' . $filterCompany : '') . $filterMessages, $bind ); } else { return $this->db->one_data( 'SELECT COUNT(C.interlocutor_id) FROM ' . static::TABLE_INTERNALMAIL_CONTACTS . ' C ' . ($folderID > 0 ? ' INNER JOIN ' . static::TABLE_INTERNALMAIL_FOLDERS_USERS . ' F ON F.user_id = C.user_id AND F.company_id = C.company_id AND F.interlocutor_id = C.interlocutor_id AND F.folder_id = :folderID ' : '') . ' WHERE C.user_id = :userID ' . ($filterCompany ? ' AND C.' . $filterCompany : ''), $bind ); } } if (!empty($filterMessages)) { $interlocutorsID = $this->db->select( 'SELECT U.user_id, M.company_id FROM ' . static::TABLE_INTERNALMAIL . ' M, ' . Users::TABLE_USERS . ' U ' . ($folderID > 0 ? ', ' . static::TABLE_INTERNALMAIL_FOLDERS_USERS . ' F ' : '') . ' WHERE ( M.author = :userID OR M.recipient = :userID ) AND U.user_id = (CASE WHEN (M.author = :userID) THEN M.recipient ELSE M.author END) ' . ($folderID > 0 ? ' AND F.user_id = :userID AND F.interlocutor_id = U.user_id AND F.company_id = M.company_id AND F.folder_id = :folderID ' : '') . ' ' . ($filterCompany ? ' AND M.' . $filterCompany : '') . ' ' . $filterMessages . ' GROUP BY U.user_id, M.company_id', $bind ); if (empty($interlocutorsID)) { return []; } $interlocutorsCondition = []; foreach ($interlocutorsID as $v) { $interlocutorsCondition[] = '(C.interlocutor_id = ' . $v['user_id'] . ' AND C.company_id = ' . $v['company_id'] . ')'; } foreach ([':folderID', ':itemID'] as $k) { if (isset($bind[$k])) { unset($bind[$k]); } } $contactsList = $this->db->select_key( 'SELECT I.user_id, I.name, I.login, I.avatar, IST.last_activity, I.sex, I.activated, C.messages_total AS msgs_total, C.messages_new AS msgs_new, C.last_message_id AS msgs_last_id, C.last_message_date AS msgs_last_created, C.company_id FROM ' . static::TABLE_INTERNALMAIL_CONTACTS . ' C, ' . Users::TABLE_USERS . ' I, ' . Users::TABLE_USERS_STAT . ' IST WHERE C.user_id = :userID ' . ($filterCompany ? ' AND C.' . $filterCompany : '') . ' AND (' . join(' OR ', $interlocutorsCondition) . ') AND C.interlocutor_id = I.user_id AND IST.user_id = I.user_id ORDER BY C.last_message_date DESC' . $sqlLimit, 'msgs_last_id', $bind ); } else { $contactsList = $this->db->select_key( 'SELECT I.user_id, I.name, I.login, I.avatar, IST.last_activity, I.sex, I.activated, C.messages_total AS msgs_total, C.messages_new AS msgs_new, C.last_message_id AS msgs_last_id, C.last_message_date AS msgs_last_created, C.company_id FROM ' . static::TABLE_INTERNALMAIL_CONTACTS . ' C INNER JOIN ' . Users::TABLE_USERS . ' I ON C.interlocutor_id = I.user_id INNER JOIN ' . Users::TABLE_USERS_STAT . ' IST ON I.user_id = IST.user_id ' . ($folderID > 0 ? ' INNER JOIN ' . static::TABLE_INTERNALMAIL_FOLDERS_USERS . ' F ON F.user_id = C.user_id AND F.company_id = C.company_id AND F.interlocutor_id = I.user_id AND F.folder_id = :folderID ' : '') . ' WHERE C.user_id = :userID ' . ($filterCompany ? ' AND C.' . $filterCompany : '') . ' ORDER BY C.last_message_date DESC' . $sqlLimit, 'msgs_last_id', $bind ); } if (empty($contactsList)) { return []; } $lastMessagesID = []; $usersID = []; foreach ($contactsList as &$v) { $v['folders'] = []; $usersID[] = $v['user_id']; $lastMessagesID[] = $v['msgs_last_id']; unset($v['msgs_last_id'], $v['msgs_last_created']); } unset($v); # связь собеседников с папками if ($folderID !== -1) { $usersFolders = $this->getInterlocutorFolders($userID, $usersID, true); foreach ($contactsList as &$v) { if (isset($usersFolders[$v['user_id']][$v['company_id']])) { $v['folders'] = $usersFolders[$v['user_id']][$v['company_id']]; } } unset($v); } # компании if (bff::businessEnabled()) { $myCompanyID = User::companyID(); $companiesID = []; foreach ($contactsList as &$v) { if ($v['company_id'] && $v['company_id'] != $myCompanyID) { $companiesID[] = $v['company_id']; } } unset($v); if (!empty($companiesID)) { $companiesData = Business::model()->companiesDataToMessages($companiesID); $companyLogo = Business::logo(); foreach ($contactsList as &$v) { if ($v['company_id'] && isset($companiesData[$v['company_id']])) { $company = & $companiesData[$v['company_id']]; $company['logo'] = $companyLogo->url($company['id'], $company['logo'], $companyLogo::szSmall, false, true); $v['company'] = $company; } } unset($v); } } # данные о последних сообщениях в контактах $lastMessagesData = $this->db->select( 'SELECT id, author, recipient, company_id, item_id, created, readed, is_new, message, blocked FROM ' . static::TABLE_INTERNALMAIL . ' WHERE id IN (' . join(',', $lastMessagesID) . ')' ); if (!empty($lastMessagesData)) { $itemsID = []; foreach ($lastMessagesData as $v) { $contactsList[$v['id']]['message'] = $v; if ($v['item_id'] > 0) { $itemsID[$v['id']] = $v['item_id']; } } # данные о прикрепленных объявлениях (Listings) if (!empty($itemsID)) { $itemsData = Listings::model()->itemsDataByFilter( ['id' => array_unique($itemsID)], ['id','user_id','title','link'], ['context' => 'internalmail-contacts-listing-front'] ); if (! empty($itemsData)) { foreach ($itemsID as $k_id => $item_id) { if (isset($itemsData[$item_id])) { $contactsList[$k_id]['item'] = $itemsData[$item_id]; } } } } } unset($lastMessagesID); return $contactsList; } /** * Получаем контакты пользователя (admin-панель) * @param int $userID ID пользователя, просматривающего свои переписки * @param int $companyId ID компании * @param int $folderID ID папки * @param bool $countOnly только считаем кол-во * @param string $sqlLimit * @return array|int */ public function getContactsListingAdm($userID, $companyId, int $folderID, bool $countOnly = false, string $sqlLimit = '') { $bind = [':userID' => $userID]; if ($folderID > 0) { $bind[':folderID'] = $folderID; } $companyFilter = false; if (!empty($companyId)) { $bind[':companyID'] = $companyId; $companyFilter = 'company_id = :companyID'; } if ($countOnly) { return $this->db->one_data( 'SELECT COUNT(C.interlocutor_id) FROM ' . static::TABLE_INTERNALMAIL_CONTACTS . ' C ' . ($folderID > 0 ? ' INNER JOIN ' . static::TABLE_INTERNALMAIL_FOLDERS_USERS . ' F ON F.user_id = C.user_id AND F.company_id = C.company_id AND F.interlocutor_id = C.interlocutor_id AND F.folder_id = :folderID ' : '') . ' WHERE C.user_id = :userID' . ($companyFilter ? ' AND C.' . $companyFilter : ''), $bind ); } $contactsList = $this->db->select_key( 'SELECT I.user_id, I.name, I.email, I.login, I.admin, I.avatar, I.sex, I.activated, C.messages_total AS msgs_total, C.messages_new AS msgs_new, C.last_message_id AS msgs_last_id, C.last_message_date AS msgs_last_created, C.company_id FROM ' . static::TABLE_INTERNALMAIL_CONTACTS . ' C INNER JOIN ' . Users::TABLE_USERS . ' I ON C.interlocutor_id = I.user_id ' . ($folderID > 0 ? ' INNER JOIN ' . static::TABLE_INTERNALMAIL_FOLDERS_USERS . ' F ON F.user_id = C.user_id AND F.company_id = C.company_id AND F.interlocutor_id = I.user_id AND F.folder_id = :folderID ' : '') . ' WHERE C.user_id = :userID' . ($companyFilter ? ' AND C.' . $companyFilter : '') . ' ORDER BY C.last_message_date DESC ' . $sqlLimit, 'msgs_last_id', $bind ); if (empty($contactsList)) { return []; } $lastMessagesID = []; $usersID = []; foreach ($contactsList as &$v) { $v['folders'] = []; $usersID[] = $v['user_id']; $lastMessagesID[] = $v['msgs_last_id']; } unset($v); # получаем связь собеседников с папками if ($folderID !== -1) { $usersFolders = $this->getInterlocutorFolders($userID, $usersID, true); foreach ($contactsList as &$v) { if (isset($usersFolders[$v['user_id']][$v['company_id']])) { $v['folders'] = $usersFolders[$v['user_id']][$v['company_id']]; } } unset($v); } # получаем данные о последних сообщениях в переписках $lastMessagesData = $this->db->select( 'SELECT id, author, recipient, company_id, created, readed, is_new, message FROM ' . static::TABLE_INTERNALMAIL . ' WHERE id IN (' . join(',', $lastMessagesID) . ')' ); if (! empty($lastMessagesData)) { foreach ($lastMessagesData as $v) { $contactsList[$v['id']]['lastmsg'] = $v; } } unset($lastMessagesID, $lastMessagesData); return $contactsList; } /** * Возвращает кол-во новых сообщений * @param int|array $filter ID пользователя просматривающего свои сообщения или array - фильтр сообщений * @return int */ public function getNewMessagesCount($filter): int { if (! is_array($filter)) { $filter = ['recipient' => $filter]; } $filter['is_new'] = 1; return $this->db->select_rows_count(static::TABLE_INTERNALMAIL, $filter); } /** * Обновляем счетчик новых сообщений пользователя * @param int $userID ID пользователя * @return int текущее значение счетчика */ protected function updateNewMessagesCounter($userID): int { $newMessagesCount = $this->getNewMessagesCount($userID); Users::model()->userCounterSave($userID, 'internalmail_new', $newMessagesCount, false); return $newMessagesCount; } /** * Формирование списка получателей по email адресу (admin) * @param string $searchQuery первые символы email адреса * @param int $currentUserID ID текущего пользователя * @param int $limit максимальное кол-во совпадений * @return array */ public function suggestInterlocutors(string $searchQuery, int $currentUserID, int $limit = 10): array { /** * получаем список подходящих по email'у собеседников, исключая: * - текущего пользователя * - запретивших им писать (im_noreply=1) * - заблокированных пользователей */ return $this->db->select( 'SELECT U.user_id as id, U.email FROM ' . Users::TABLE_USERS . ' U WHERE U.user_id != :userID AND U.email LIKE (:q) ' . ( ! $this->isAdminPanel() ? ' AND U.im_noreply = 0 ' : '') . ' ORDER BY U.email' . $this->db->prepareLimit(0, ($limit > 0 ? $limit : 10)), [ ':q' => $searchQuery . '%', ':userID' => $currentUserID, ] ); } /** * Удаление связи сообщений с объявлениями * @param array $itemsID ID объявлений * @return int кол-во удаленных связей */ public function unlinkMessagesItemsID(array $itemsID = []): int { if ($itemsID) { return (int)$this->db->update( static::TABLE_INTERNALMAIL, ['item_id' => 0], ['item_id' => $itemsID] ); } return 0; } /** * Блокировка всех сообщений пользователя * @param int $userID ID пользователя * @return int кол-во заблокированных сообщений */ public function blockUserMessages($userID): int { if (!empty($userID)) { return (int)$this->db->update( static::TABLE_INTERNALMAIL, ['blocked' => 1], ['author' => $userID, 'blocked' => 0] ); } return 0; } /** * Количество новых сообщений отправленных пользователем сегодня * @param int $userID ID пользователя * @return int */ public function newMessagesSentToday($userID): int { $today = $this->db->select_one_column( 'SELECT recipient FROM ' . static::TABLE_INTERNALMAIL . ' WHERE author = :user AND created >= :from AND created <= :to GROUP BY recipient', [ ':user' => $userID, ':from' => date('Y-m-d 00:00:00'), ':to' => date('Y-m-d 23:59:59'), ] ); if (empty($today)) { return 0; } $latest = $this->db->select_one_column( 'SELECT recipient FROM ' . static::TABLE_INTERNALMAIL . ' WHERE author = :user AND ' . $this->db->prepareIN('recipient', $today) . ' AND created < :from GROUP BY recipient', [ ':user' => $userID, ':from' => date('Y-m-d 00:00:00'), ] ); $today = array_diff($today, $latest); return count($today); } /** * Кол-во отправленных сообщений * @param int $authorID * @param int $recipientID * @return int */ public function messagesSent($authorID, $recipientID): int { return $this->db->select_rows_count(static::TABLE_INTERNALMAIL, [ 'author' => $authorID, 'recipient' => $recipientID, ]); } /** * Список сообщений по фильтру * @param array $filter * @param array $fields * @param array $opts * @return int|mixed */ public function messagesByFilter(array $filter, array $fields, array $opts = []) { $opts = $this->defaults($opts, [ 'oneArray' => true, 'group' => '', 'order' => '', ]); $filter = $this->prepareFilter($filter); if (empty($fields)) { return (int)$this->db->one_data('SELECT COUNT(*) FROM ' . static::TABLE_INTERNALMAIL . $filter['where'], $filter['bind']); } else { if ($opts['oneArray']) { return $this->db->one_array( 'SELECT ' . join(',', $fields) . ' FROM ' . static::TABLE_INTERNALMAIL . $filter['where'] . ' LIMIT 1', $filter['bind'] ); } else { return $this->db->select( 'SELECT ' . join(',', $fields) . ' FROM ' . static::TABLE_INTERNALMAIL . $filter['where'] . ( ! empty($opts['group']) ? ' GROUP BY ' . $opts['group'] : '') . ( ! empty($opts['order']) ? ' ORDER BY ' . $opts['order'] : ''), $filter['bind'] ); } } } /** * Метод обрабатывающий ситуацию с удалением пользователя * @param int $userID ID пользователя * @param array $options доп. параметры удаления * @return void */ public function onUserDeleted($userID, array $options = []) { if (empty($userID)) { return; } $users = []; $filter = [ 'is_new' => 1, 'author' => $userID, ]; $data = $this->messagesByFilter($filter, ['recipient'], ['oneArray' => false, 'group' => 'recipient']); foreach ($data as $v) { if (! in_array($v['recipient'], $users)) { $users[] = $v['recipient']; } } $this->db->delete(static::TABLE_INTERNALMAIL, ['author' => $userID]); $this->db->delete(static::TABLE_INTERNALMAIL, ['recipient' => $userID]); $this->db->delete(static::TABLE_INTERNALMAIL_CONTACTS, ['user_id' => $userID]); $this->db->delete(static::TABLE_INTERNALMAIL_CONTACTS, ['interlocutor_id' => $userID]); $this->db->delete(static::TABLE_INTERNALMAIL_FOLDERS, ['user_id' => $userID]); $this->db->delete(static::TABLE_INTERNALMAIL_FOLDERS_USERS, ['user_id' => $userID]); $this->db->delete(static::TABLE_INTERNALMAIL_FOLDERS_USERS, ['interlocutor_id' => $userID]); if (! empty($users)) { foreach ($users as $v) { $this->updateNewMessagesCounter($v); } } } }