InteractionSendMessageController.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. <?php
  2. namespace Controllers;
  3. use Libs\Logger;
  4. use Libs\Payload;
  5. use Libs\Roles;
  6. use Libs\Validator;
  7. use Models\IntegrationsModel;
  8. use Models\UnipileMessagesModel;
  9. use Models\UserModel;
  10. use Psr\Http\Message\ServerRequestInterface;
  11. use Services\UnipileClient;
  12. class InteractionSendMessageController
  13. {
  14. private UserModel $userModel;
  15. private IntegrationsModel $integrationsModel;
  16. private UnipileMessagesModel $messagesModel;
  17. private UnipileClient $unipileClient;
  18. public function __construct()
  19. {
  20. $this->userModel = new UserModel();
  21. $this->integrationsModel = new IntegrationsModel();
  22. $this->messagesModel = new UnipileMessagesModel();
  23. $this->unipileClient = new UnipileClient();
  24. }
  25. public function __invoke(ServerRequestInterface $request)
  26. {
  27. $userId = (int) ($request->getAttribute('user_id') ?? 0);
  28. $userEmail = (string) ($request->getAttribute('user_email') ?? '');
  29. $userRole = mb_strtolower(trim((string) ($request->getAttribute('user_role') ?? '')));
  30. $body = json_decode((string) $request->getBody(), true) ?: [];
  31. $conversationId = (int) ($body['conversation_id'] ?? 0);
  32. $text = trim((string) ($body['text'] ?? ''));
  33. if ($userId <= 0) {
  34. return Payload::fail('Unauthorized: Missing authenticated user', [], 'E_VALIDATE', 401);
  35. }
  36. $validator = (new Validator(['conversation_id' => $conversationId, 'text' => $text]))
  37. ->required('conversation_id')->intRange('conversation_id', 1)
  38. ->required('text')->maxLength('text', 4000);
  39. if ($validator->fails()) {
  40. return Payload::fail($validator->firstError(), [], 'E_VALIDATE', 400);
  41. }
  42. if (!$this->unipileClient->isConfigured()) {
  43. return Payload::fail('Unipile is not configured', [], 'E_GENERIC', 500);
  44. }
  45. try {
  46. $companyId = $this->userModel->getCompanyIdByUserId($userId);
  47. if ($companyId === null) {
  48. return Payload::fail('User not found', [], 'E_NOT_FOUND', 404);
  49. }
  50. $conversation = $this->messagesModel->getConversationForSending($companyId, $conversationId);
  51. if ($conversation === null) {
  52. return Payload::fail('Conversation not found', [], 'E_NOT_FOUND', 404);
  53. }
  54. if (!$this->canSend($companyId, $userEmail, $userRole, $conversation)) {
  55. return Payload::fail('Forbidden: insufficient permissions', [], 'E_FORBIDDEN', 403);
  56. }
  57. if (!(bool) ($conversation['integration_is_connected'] ?? false)) {
  58. return Payload::fail('Integration is not connected', [], 'E_VALIDATE', 400);
  59. }
  60. $chatId = (string) ($conversation['conversation_external_id'] ?? '');
  61. if ($chatId === '') {
  62. return Payload::fail('Conversation is missing external chat id', [], 'E_VALIDATE', 400);
  63. }
  64. $response = $this->unipileClient->sendTextMessage($chatId, $text);
  65. $message = $this->messagesModel->createOutboundLocalMessage($conversationId, $response, $text);
  66. $this->messagesModel->updateConversationAfterOutbound($conversationId, $text);
  67. return Payload::ok([
  68. 'message_id' => (int) ($message['message_id'] ?? 0),
  69. 'unipile' => $response,
  70. ]);
  71. } catch (\Throwable $e) {
  72. Logger::error('Failed to send WhatsApp message through Unipile', ['error' => $e->getMessage()]);
  73. return Payload::fail('Failed to send message', [], 'E_GENERIC', 500);
  74. }
  75. }
  76. private function canSend(int $companyId, string $userEmail, string $userRole, array $conversation): bool
  77. {
  78. if (in_array($userRole, [Roles::ADMIN, Roles::MANAGER], true)) {
  79. return true;
  80. }
  81. if ($userRole !== Roles::OPERATOR) {
  82. return false;
  83. }
  84. $operatorId = $this->integrationsModel->getOperatorIdByUserEmail($companyId, $userEmail);
  85. if ($operatorId <= 0) {
  86. return false;
  87. }
  88. return (int) ($conversation['operator_id'] ?? 0) === $operatorId;
  89. }
  90. }