| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- <?php
- namespace App\Http\Controllers;
- use App\Models\ChatMessage;
- use App\Models\Order;
- use App\Models\Reclamation;
- use App\Models\Role;
- use App\Models\User;
- use App\Services\FileService;
- use App\Services\NotificationService;
- use Illuminate\Http\RedirectResponse;
- use Illuminate\Http\Request;
- use Throwable;
- class ChatMessageController extends Controller
- {
- public function storeForOrder(
- Request $request,
- Order $order,
- FileService $fileService,
- NotificationService $notificationService,
- ): RedirectResponse {
- $this->ensureCanViewOrder($order);
- return $this->storeMessage(
- $request,
- $fileService,
- $notificationService,
- $order,
- null,
- 'chat/orders/' . $order->id,
- );
- }
- public function storeForReclamation(
- Request $request,
- Reclamation $reclamation,
- FileService $fileService,
- NotificationService $notificationService,
- ): RedirectResponse {
- $this->ensureCanViewReclamation($reclamation);
- return $this->storeMessage(
- $request,
- $fileService,
- $notificationService,
- null,
- $reclamation,
- 'chat/reclamations/' . $reclamation->id,
- );
- }
- private function storeMessage(
- Request $request,
- FileService $fileService,
- NotificationService $notificationService,
- ?Order $order,
- ?Reclamation $reclamation,
- string $filePath,
- ): RedirectResponse {
- $isPrivileged = hasRole(Role::ADMIN . ',' . Role::MANAGER);
- $validated = $request->validate([
- 'message' => 'nullable|string',
- 'notification_type' => 'nullable|string|in:none,responsibles,all,user',
- 'target_user_id' => 'nullable|integer|exists:users,id,deleted_at,NULL',
- 'target_user_ids' => 'nullable|array',
- 'target_user_ids.*' => 'integer|exists:users,id,deleted_at,NULL',
- 'attachments' => 'nullable|array|max:5',
- 'attachments.*' => 'file|max:10240',
- ]);
- $notificationType = $validated['notification_type'] ?? ChatMessage::NOTIFICATION_NONE;
- if (!$isPrivileged) {
- $notificationType = ChatMessage::NOTIFICATION_NONE;
- }
- $messageText = trim((string) ($validated['message'] ?? ''));
- $attachments = $request->file('attachments', []);
- if ($messageText === '' && empty($attachments)) {
- return redirect()->back()->with(['danger' => 'Нужно указать сообщение или добавить файл.']);
- }
- $recipientIds = [];
- $targetUserId = null;
- if ($notificationType === ChatMessage::NOTIFICATION_USER) {
- $targetUserId = (int) ($validated['target_user_id'] ?? 0);
- if ($targetUserId < 1) {
- return redirect()->back()->with(['danger' => 'Нужно выбрать пользователя для уведомления.']);
- }
- $recipientIds = [$targetUserId];
- }
- if (in_array($notificationType, [
- ChatMessage::NOTIFICATION_RESPONSIBLES,
- ChatMessage::NOTIFICATION_ALL,
- ], true)) {
- $recipientIds = $this->resolveTargetUserIds(
- $notificationType,
- $validated['target_user_ids'] ?? [],
- $order,
- $reclamation,
- (int) auth()->id(),
- );
- if (empty($recipientIds)) {
- return redirect()->back()->with(['danger' => 'Нужно выбрать хотя бы одного получателя уведомления.']);
- }
- }
- if (!in_array($notificationType, [ChatMessage::NOTIFICATION_USER], true)) {
- $targetUserId = null;
- }
- try {
- $chatMessage = ChatMessage::query()->create([
- 'order_id' => $order?->id,
- 'reclamation_id' => $reclamation?->id,
- 'user_id' => (int) auth()->id(),
- 'target_user_id' => $targetUserId,
- 'notification_type' => $notificationType,
- 'message' => $messageText !== '' ? $messageText : null,
- ]);
- if (!empty($recipientIds)) {
- $chatMessage->notifiedUsers()->syncWithoutDetaching($recipientIds);
- }
- $files = [];
- foreach ($attachments as $attachment) {
- $files[] = $fileService->saveUploadedFile($filePath, $attachment);
- }
- if (!empty($files)) {
- $chatMessage->files()->syncWithoutDetaching(collect($files)->pluck('id')->all());
- }
- if ($notificationType !== ChatMessage::NOTIFICATION_NONE) {
- $notificationService->notifyChatMessage($chatMessage->fresh([
- 'user',
- 'targetUser',
- 'files',
- 'order.user',
- 'order.brigadier',
- 'reclamation.order',
- 'reclamation.user',
- 'reclamation.brigadier',
- ]), $recipientIds);
- }
- } catch (Throwable $exception) {
- report($exception);
- return redirect()->back()->with(['error' => 'Не удалось отправить сообщение в чат.']);
- }
- return redirect()->back()->with(['success' => 'Сообщение отправлено.']);
- }
- private function ensureCanViewOrder(Order $order): void
- {
- if (hasRole(Role::BRIGADIER)) {
- $canView = (int) $order->brigadier_id === (int) auth()->id()
- && in_array((int) $order->order_status_id, Order::visibleStatusIdsForBrigadier(), true);
- if (!$canView) {
- abort(403);
- }
- }
- }
- private function ensureCanViewReclamation(Reclamation $reclamation): void
- {
- if (hasRole(Role::BRIGADIER)) {
- $canView = (int) $reclamation->brigadier_id === (int) auth()->id()
- && in_array((int) $reclamation->status_id, Reclamation::visibleStatusIdsForBrigadier(), true);
- if (!$canView) {
- abort(403);
- }
- }
- }
- private function resolveTargetUserIds(
- string $notificationType,
- array $targetUserIds,
- ?Order $order,
- ?Reclamation $reclamation,
- int $senderId,
- ): array {
- $selectedIds = array_values(array_unique(array_map(static fn ($id) => (int) $id, $targetUserIds)));
- $allowedIds = match ($notificationType) {
- ChatMessage::NOTIFICATION_RESPONSIBLES => $this->chatResponsibleRecipientIds($order, $reclamation),
- ChatMessage::NOTIFICATION_ALL => User::query()->pluck('id')->map(static fn ($id) => (int) $id)->all(),
- default => [],
- };
- $selectedIds = array_values(array_intersect($selectedIds, $allowedIds));
- return array_values(array_diff($selectedIds, [$senderId]));
- }
- private function chatResponsibleRecipientIds(?Order $order, ?Reclamation $reclamation): array
- {
- $adminIds = User::query()
- ->where('role', Role::ADMIN)
- ->pluck('id')
- ->map(static fn ($id) => (int) $id)
- ->all();
- if ($order) {
- return array_values(array_unique(array_filter(array_merge($adminIds, [
- $order->user_id ? (int) $order->user_id : null,
- $order->brigadier_id ? (int) $order->brigadier_id : null,
- ]))));
- }
- if ($reclamation) {
- return array_values(array_unique(array_filter(array_merge($adminIds, [
- $reclamation->user_id ? (int) $reclamation->user_id : null,
- $reclamation->brigadier_id ? (int) $reclamation->brigadier_id : null,
- ]))));
- }
- return $adminIds;
- }
- }
|