Rev 738 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?phpdeclare(strict_types=1);namespace LeadersLinked\Controller;use Laminas\Db\Adapter\AdapterInterface;use Laminas\Mvc\Controller\AbstractActionController;use Laminas\Log\LoggerInterface;use Laminas\View\Model\ViewModel;use LeadersLinked\Library\Functions;use LeadersLinked\Mapper\UserMapper;use LeadersLinked\Model\User;use LeadersLinked\Mapper\UserBlockedMapper;use LeadersLinked\Mapper\ConversationMapper;use LeadersLinked\Mapper\MessageMapper;use LeadersLinked\Model\Conversation;use Laminas\View\Model\JsonModel;use LeadersLinked\Form\InMail\SendForm;use LeadersLinked\Model\Message;use LeadersLinked\Mapper\AbuseReportMapper;use LeadersLinked\Model\AbuseReport;use LeadersLinked\Library\Storage;class InMailController extends AbstractActionController{/*** @var \Laminas\Db\Adapter\AdapterInterface*/private $adapter;/**** @var \LeadersLinked\Cache\CacheInterface*/private $cache;/*** @var \Laminas\Log\LoggerInterface*/private $logger;/*** @var array*/private $config;/*** @var \Laminas\Mvc\I18n\Translator*/private $translator;/*** @param \Laminas\Db\Adapter\AdapterInterface $adapter* @param \LeadersLinked\Cache\CacheInterface $cache* @param \Laminas\Log\LoggerInterface LoggerInterface $logger* @param array $config* @param \Laminas\Mvc\I18n\Translator $translator*/public function __construct($adapter, $cache, $logger, $config, $translator){$this->adapter = $adapter;$this->cache = $cache;$this->logger = $logger;$this->config = $config;$this->translator = $translator;}public function indexAction(){$request = $this->getRequest();// Verificar que la petición sea GETif (!$request->isGet()) {return new JsonModel(['success' => false,'data' => 'ERROR_METHOD_NOT_ALLOWED']);}// Obtener el usuario actual autenticado$currentUserPlugin = $this->plugin('currentUserPlugin');$currentUser = $currentUserPlugin->getUser();// Obtener la fecha actual de la base de datos para cálculos de tiempo$userMapper = UserMapper::getInstance($this->adapter);$now = $userMapper->getDatebaseNow();// Obtener IDs de usuarios que el usuario actual ha bloqueado$userBlockedMapper = UserBlockedMapper::getInstance($this->adapter);$user_blocked_ids = $userBlockedMapper->fetchAllBlockedReturnIds($currentUser->id);// Obtener IDs de usuarios que han bloqueado al usuario actual$user_blocked_me_ids = $userBlockedMapper->fetchAllUserBlockMeReturnIds($currentUser->id);$storage = Storage::getInstance($this->config, $this->adapter);$conversationMapper = ConversationMapper::getInstance($this->adapter);$messageMapper = MessageMapper::getInstance($this->adapter);$conversations = [];$selected_user_id = 0;$uuid = $this->params()->fromRoute('id');if ($uuid) {$companyMapper = CompanyMapper::getInstance($this->adapter);$company = $companyMapper->fetchOneByUuid($uuid);if ($company) {$companyUserMapper = CompanyUserMapper::getInstance($this->adapter);$companyUser = $companyUserMapper->fetchOwnerByCompanyId($company->id);if(!in_array($companyUser->user_id, $user_blocked_ids) && !in_array($companyUser->id, $user_blocked_me_ids)) {$user = $userMapper->fetchOne($companyUser->user_id);$selected_user_id = $user->id;$conversation = $conversationMapper->fetchOneByUserId1AndUserId2($currentUser->id, $user->id);$timeElapsedString = '';if ($conversation) {$unread = $messageMapper->fetchCountUnreadMessagesByConversationIdAndReceiverId($conversation->id, $currentUser->id);$lastMessage = $messageMapper->fetchLastUnreadMessagesByConversationIdAndReceiverId($conversation->id, $currentUser->id);if ($lastMessage) {$timeElapsedString = $this->timeAgo($lastMessage, $now);}} else {$unread = 0;}array_push($conversations, ['uuid' => $company->uuid,'name' => $company->name,'last_message' => $timeElapsedString,'count_unread' => $unread,'selected' => 1,'image' => $storage->getCompanyImage($company),'profile' => $this->url()->fromRoute('company/view', ['id' => $company->uuid]),'messages_url' => $this->url()->fromRoute('inmail/messages',['uuid' => $company->uuid]),'save_url' => $this->url()->fromRoute('inmail/messages/send',['uuid' => $company->uuid]),'delete_url' => $this->url()->fromRoute('inmail/messages/delete',['uuid' => $company->uuid])]);}} else {$user = $userMapper->fetchOneByUuid($uuid);if ($user) {if(!in_array($user->id, $user_blocked_ids) && !in_array($user->id, $user_blocked_me_ids)) {$timeElapsedString = '';$selected_user_id = $user->id;$conversation = $conversationMapper->fetchOneByUserId1AndUserId2($currentUser->id, $user->id);if ($conversation) {$unread = $messageMapper->fetchCountUnreadMessagesByConversationIdAndReceiverId($conversation->id, $currentUser->id);$lastMessage = $messageMapper->fetchLastUnreadMessagesByConversationIdAndReceiverId($conversation->id, $currentUser->id);if ($lastMessage) {$timeElapsedString = $this->timeAgo($lastMessage, $now);}} else {$unread = 0;}array_push($conversations, ['uuid' => $user->uuid,'name' => trim($user->first_name . ' ' . $user->last_name),'image' => $storage->getUserImage($user),'profile' => $this->url()->fromRoute('profile/view', ['id' => $user->uuid]),'last_message' => $timeElapsedString,'count_unread' => $unread,'selected' => 1,'messages_url' => $this->url()->fromRoute('inmail/messages',['uuid' => $user->uuid]),'save_url' => $this->url()->fromRoute('inmail/messages/send',['uuid' => $user->uuid]),'delete_url' => $this->url()->fromRoute('inmail/messages/delete',['uuid' => $user->uuid]),]);}}}}$records = $conversationMapper->fetchAllByUserId($currentUser->id);foreach ($records as $record) {// Omitir conversaciones que ya fueron procesadas como seleccionadasif ($selected_user_id) {if ($record->sender_id == $currentUser->id && $record->receiver_id == $selected_user_id) {continue;}if ($record->receiver_id == $currentUser->id && $record->sender_id == $selected_user_id) {continue;}}if ($record->sender_id == $currentUser->id) {$user = $userMapper->fetchOne($record->receiver_id);}if ($record->receiver_id == $currentUser->id) {$user = $userMapper->fetchOne($record->sender_id);// Omitir usuarios bloqueadosif (in_array($user->id, $user_blocked_ids) || in_array($user->id, $user_blocked_me_ids)) {continue;}}$timeElapsedString = '';$unread = $messageMapper->fetchCountUnreadMessagesByConversationIdAndReceiverId($record->id,$currentUser->id);$lastMessage = $messageMapper->fetchLastMessagesByConversationIdAndReceiverId($record->id,$currentUser->id);if ($lastMessage) {$timeElapsedString = $this->timeAgo($lastMessage, $now);}array_push($conversations, ['uuid' => $user->uuid,'name' => trim($user->first_name . ' ' . $user->last_name),'image' => $storage->getUserImage($user),'profile' => $this->url()->fromRoute('profile/view', ['id' => $user->uuid]),'last_message' => $timeElapsedString,'count_unread' => $unread,'selected' => 0,'messages_url' => $this->url()->fromRoute('inmail/messages',['uuid' => $user->uuid]),'save_url' => $this->url()->fromRoute('inmail/messages/send',['uuid' => $user->uuid]),'delete_url' => $this->url()->fromRoute('inmail/messages/delete',['uuid' => $user->uuid])]);}// Ordenar por: seleccionados primero, luego por fecha del último mensajeusort($conversations, function ($a, $b) {if ($a['selected'] == $b['selected']) {if ($a['last_message'] == $b['last_message']) {return 0;} else {return $a['last_message'] < $b['last_message'] ? -1 : 1;}} else {return $a['selected'] < $b['selected'] ? -1 : 1;}});return new JsonModel(['success' => true,'data' => $conversations]);}public function getMessagesAction(){$request = $this->getRequest();if (!$request->isGet()) {return new JsonModel(['success' => false,'data' => 'ERROR_METHOD_NOT_ALLOWED']);}$page = (int) filter_var($this->params()->fromQuery('page'), FILTER_SANITIZE_NUMBER_INT);$uuid = $this->params()->fromRoute('uuid');if (!$uuid) {return new JsonModel(['success' => false,'data' => 'ERROR_PARAMETERS_ARE_INVALID']);}$currentUserPlugin = $this->plugin('currentUserPlugin');$currentUser = $currentUserPlugin->getUser();$userMapper = UserMapper::getInstance($this->adapter);$now = $userMapper->getDatebaseNow();$user = $userMapper->fetchOneByUuid($uuid);if (!$user) {return new JsonModel(['success' => false,'data' => 'ERROR_REQUEST_IS_INVALID']);}// Pre-calcular datos del usuario para evitar repetición$userData = $this->prepareUserData($user);$currentUserData = $this->prepareUserData($currentUser);$abuseReportMapper = AbuseReportMapper::getInstance($this->adapter);$abuse_report_message_ids = $abuseReportMapper->fetchAllDataByUserReportingIdAndTypeReturnIds($currentUser->id,AbuseReport::TYPE_INMAIL_MESSAGE);$conversationMapper = ConversationMapper::getInstance($this->adapter);$messageMapper = MessageMapper::getInstance($this->adapter);$conversation = $conversationMapper->fetchOneByUserId1AndUserId2($currentUser->id, $user->id);$messages = [];if ($conversation) {$paginator = $messageMapper->getAllMessagesPaginatorByConversationId($conversation->id, $page ? $page : 1, 10);$records = $paginator->getCurrentItems();foreach ($records as $record) {$timeElapsedString = $this->timeAgo($record->added_on, $now);$isOwnMessage = $record->sender_id == $currentUser->id;$isReported = in_array($record->id, $abuse_report_message_ids);if ($isOwnMessage) {$messages[] = $this->buildMessageData($record,$currentUserData,$userData,'right',$timeElapsedString,'' // No se puede reportar mensajes propios);} else {if ($isReported) {$messages[] = $this->buildReportedMessageData($record,$userData,$currentUserData,$timeElapsedString);} else {$url_abuse_report = $this->url()->fromRoute('helpers/abuse-report', ['type' => 'message','id' => $record->uuid], ['force_canonical' => true]);$messages[] = $this->buildMessageData($record,$userData,$currentUserData,'left',$timeElapsedString,$url_abuse_report);$messageMapper->markAsRead($record->id);}}}return new JsonModel(['success' => true,'data' => ['total' => ['count' => $paginator->getTotalItemCount(),'pages' => $paginator->getPages()->pageCount,],'current' => ['items' => $messages,'page' => $paginator->getCurrentPageNumber(),'count' => $paginator->getCurrentItemCount(),]]]);}return new JsonModel(['success' => true,'data' => ['total' => ['count' => 0,'pages' => 0,],'current' => ['items' => $messages,'page' => 1,'count' => 0,]]]);}/*** Prepara los datos del usuario para evitar repetición en la construcción de mensajes*/private function prepareUserData($user){$storage = Storage::getInstance($this->config, $this->adapter);return ['name' => trim($user->first_name . ' ' . $user->last_name),'image' => $storage->getUserImage($user),'profile_url' => $this->url()->fromRoute('profile/view', ['id' => $user->uuid])];}/*** Construye los datos de un mensaje normal** @param \LeadersLinked\Model\Message $record* @param array $senderData* @param array $receiverData* @param string $side* @param string $timeElapsedString* @param string $abuseReportUrl*/private function buildMessageData($record, $senderData, $receiverData, $side, $timeElapsedString, $abuseReportUrl){$storage = Storage::getInstance($this->config, $this->adapter);$path = $storage->getPathMessage();return ['uuid' => $record->uuid,'sender_name' => $senderData['name'],'sender_image' => $senderData['image_url'],'sender_profile' => $senderData['profile_url'],'receiver_name' => $receiverData['name'],'receiver_image' => $receiverData['image_url'],'receiver_profile' => $receiverData['profile_url'],'side' => $side,'message' => $record->message,'type' => $record->type,'filename_original' => $record->filename,'filename' => $storage->getGenericFile($path, $record->uuid, $record->filename),'date' => $timeElapsedString,'abuse_report_url' => $abuseReportUrl,];}/*** Construye los datos de un mensaje reportado*/private function buildReportedMessageData($record, $senderData, $receiverData, $timeElapsedString){return ['uuid' => $record->uuid,'sender_name' => $senderData['name'],'sender_image' => $senderData['image_url'],'sender_profile' => $senderData['profile_url'],'receiver_name' => $receiverData['name'],'receiver_image' => $receiverData['image_url'],'receiver_profile' => $receiverData['profile_url'],'side' => 'left','message' => 'LABEL_ABUSE_CONTENT_REPORTED','type' => Message::TYPE_TEXT,'filename' => '','date' => $timeElapsedString,'url_abuse_report' => '', // Ya no se puede reportar];}public function sendMessageAction(){// Verificar que la petición sea POST$request = $this->getRequest();if (!$request->isPost()) {return new JsonModel(['success' => false,'data' => 'ERROR_METHOD_NOT_ALLOWED']);}// Obtener el usuario actual$currentUserPlugin = $this->plugin('currentUserPlugin');$currentUser = $currentUserPlugin->getUser();// Obtener la fecha actual de la base de datos$userMapper = UserMapper::getInstance($this->adapter);$now = $userMapper->getDatebaseNow();// Validar el ID del destinatario$uuid = $this->params()->fromRoute('uuid');if (!$uuid) {return new JsonModel(['success' => false,'data' => 'ERROR_PARAMETERS_ARE_INVALID']);}// Buscar el usuario destinatario$user = $userMapper->fetchOneByUuidAndNetworkId($uuid, $currentUser->network_id);if (!$user) {return new JsonModel(['success' => false,'data' => 'ERROR_REQUEST_IS_INVALID']);}// Combinar datos POST y archivos$data = array_merge($request->getPost()->toArray(), $request->getFiles()->toArray());// Validar los datos del formulario$form = new SendForm();$form->setData($data);if (!$form->isValid()) {// Si el formulario no es válido, devolver los errores$messages = [];$form_messages = (array) $form->getMessages();foreach ($form_messages as $fieldname => $field_messages) {$messages[$fieldname] = array_values($field_messages);}return new JsonModel(['success' => false,'data' => $messages]);}// Obtener los datos validados$dataPost = (array) $form->getData();// Buscar o crear la conversación$conversationMapper = ConversationMapper::getInstance($this->adapter);$conversation = $conversationMapper->fetchOneByUserId1AndUserId2($currentUser->id, $user->id);if ($conversation) {// Actualizar estado de la conversación existente$conversation->receiver_status = Conversation::STATUS_NORMAL;$conversation->sender_status = Conversation::STATUS_NORMAL;if (!$conversationMapper->update($conversation)) {return new JsonModel(['success' => false,'data' => $conversationMapper->getError()]);}} else {// Crear nueva conversación$conversation = new Conversation();$conversation->sender_id = $currentUser->id;$conversation->sender_status = Conversation::STATUS_NORMAL;$conversation->receiver_id = $user->id;$conversation->receiver_status = Conversation::STATUS_NORMAL;if (!$conversationMapper->insert($conversation)) {return new JsonModel(['success' => false,'data' => $conversationMapper->getError()]);}}// Storage$storage = Storage::getInstance($this->config, $this->adapter);$storage->setFiles($request->getFiles()->toArray());$path = $storage->getPathMessage();// Determinar el tipo de archivo$type = Message::TYPE_TEXT;if($storage->setCurrentFilename('file')){$tmp_filename = $storage->getTmpFilename();$type = $storage->getFileType();}// Crear y guardar el mensaje$message = new Message();$message->conversation_id = $conversation->id;$message->read = Message::NO;$message->message = $type == Message::TYPE_TEXT ? $dataPost['message'] : '';$message->receiver_id = $user->id;$message->receiver_status = Message::STATUS_NORMAL;$message->sender_id = $currentUser->id;$message->sender_status = Message::STATUS_NORMAL;$message->type = $type;$messageMapper = MessageMapper::getInstance($this->adapter);if (!$messageMapper->insert($message)) {return new JsonModel(['success' => false,'data' => $messageMapper->getError()]);}$message = $messageMapper->fetchOne($message->id);// Procesar archivo adjunto si existeif ($tmp_filename) {$filename = 'inmail_message_' . $message->uuid . '.' . $storage->getExtension();$target_filename = $storage->composePathToFilename(Storage::TYPE_MESSAGE, $message->uuid, $filename);if (!$storage->uploadImageWithOutChangeSize($tmp_filename, $target_filename)) {return new JsonModel(['success' => false,'data' => 'ERROR_UPLOAD_FILE']);}$message->filename = $filename;if (!$messageMapper->update($message)) {return new JsonModel(['success' => false,'data' => $messageMapper->getError()]);}}// Actualizar última actividad del usuario$userMapper->updateLastActivity($currentUser->id);// Preparar datos para la respuesta$sender_image = $storage->getUserImage($currentUser);$receiver_image = $storage->getUserImage($user);$filename = $storage->getGenericFile($path, $message->uuid, $message->filename);$sender_profile = $this->url()->fromRoute('profile/view', ['id' => $currentUser->uuid]);$receiver_profile = $this->url()->fromRoute('profile/view', ['id' => $user->uuid]);// Devolver respuesta exitosa con datos del mensajereturn new JsonModel(['success' => true,'data' => ['sender_name' => trim($currentUser->first_name . ' ' . $currentUser->last_name),'sender_image' => $sender_image,'sender_profile' => $sender_profile,'receiver_name' => trim($user->first_name . ' ' . $user->last_name),'receiver_image' => $receiver_image,'receiver_profile' => $receiver_profile,'side' => 'right','message' => $message->message,'type' => $message->type,'filename' => $filename,'date' => $this->timeAgo($now, $now),]]);}private function timeAgo($timestamp, $now = ''){if ($now) {$datetime1 = \DateTime::createFromFormat('Y-m-d H:i:s', $now);} else {$now = date('Y-m-d H:i:s');$datetime1 = date_create($now);}$datetime2 = date_create($timestamp);$diff = date_diff($datetime1, $datetime2);$timemsg = '';if ($diff->y > 0) {$timemsg = $diff->y . ' ' . ($diff->y > 1 ? $this->translator->translate('LABEL_YEARS_SMALL') : $this->translator->translate('LABEL_YEAR_SMALL'));} else if ($diff->m > 0) {$timemsg = $diff->m . ' ' . ($diff->m > 1 ? $this->translator->translate('LABEL_MONTHS_SMALL') : $this->translator->translate('LABEL_MONTH_SMALL'));} else if ($diff->d > 0) {$timemsg = $diff->d . ' ' . ($diff->d > 1 ? $this->translator->translate('LABEL_DAYS_SMALL') : $this->translator->translate('LABEL_DAY_SMALL'));} else if ($diff->h > 0) {$timemsg = $diff->h . ' ' . ($diff->h > 1 ? $this->translator->translate('LABEL_HOURS_SMALL') : $this->translator->translate('LABEL_HOUR_SMALL'));} else if ($diff->i > 0) {$timemsg = $diff->i . ' ' . ($diff->i > 1 ? $this->translator->translate('LABEL_MINUTES_SMALL') : $this->translator->translate('LABEL_MINUTE_SMALL'));} else if ($diff->s > 0) {$timemsg = $diff->s . ' ' . ($diff->s > 1 ? $this->translator->translate('LABEL_SECONDS_SMALL') : $this->translator->translate('LABEL_SECOND_SMALL'));}if (!$timemsg) {$timemsg = $this->translator->translate('LABEL_NOW');} else {$timemsg = $this->translator->translate('LABEL_AGO_SMALL') . ' ' . $timemsg . '';}return $timemsg;}public function deleteMessageAction(){$request = $this->getRequest();if ($request->isPost()) {$currentUserPlugin = $this->plugin('currentUserPlugin');$currentUser = $currentUserPlugin->getUser();$uuid = $this->params()->fromRoute('uuid');if (!$uuid) {return new JsonModel(['success' => false,'data' => 'ERROR_PARAMETERS_ARE_INVALID']);}$userMapper = UserMapper::getInstance($this->adapter);$user = $userMapper->fetchOneByUuid($uuid);if (!$user) {return new JsonModel(['success' => false,'data' => 'ERROR_REQUEST_IS_INVALID']);}$conversationMapper = ConversationMapper::getInstance($this->adapter);$conversation = $conversationMapper->fetchOneByUserId1AndUserId2($currentUser->id, $user->id);if ($conversation) {if ($conversation->sender_id == $currentUser->id && $conversation->receiver_id == $user->id) {$conversation->sender_status = Conversation::STATUS_DELETED;if ($conversationMapper->update($conversation)) {$response = ['success' => true,'data' => 'LABEL_CONVERSATION_WAS_DELETED'];} else {$response = ['success' => false,'data' => $conversationMapper->getError()];}}if ($conversation->receiver_id == $currentUser->id && $conversation->sender_id == $user->id) {$conversation->receiver_status = Conversation::STATUS_DELETED;if ($conversationMapper->update($conversation)) {$response = ['success' => true,'data' => 'LABEL_CONVERSATION_WAS_DELETED'];} else {$response = ['success' => false,'data' => $conversationMapper->getError()];}}return new JsonModel($response);} else {$response = ['success' => false,'data' => 'ERROR_CONVERSATION_NOT_FOUND'];}return new JsonModel($response);} else {$response = ['success' => false,'data' => 'ERROR_METHOD_NOT_ALLOWED'];}return new JsonModel($response);}}