add projet
This commit is contained in:
+413
@@ -0,0 +1,413 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Configuration;
|
||||
use App\Models\Message;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class MessagingController extends BaseApiController
|
||||
{
|
||||
protected Message $message;
|
||||
protected User $user;
|
||||
protected Configuration $config;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->message = model(Message::class);
|
||||
$this->user = model(User::class);
|
||||
$this->config = model(Configuration::class);
|
||||
}
|
||||
|
||||
public function conversations()
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
if (!$user) {
|
||||
return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$userId = (int) $user->id;
|
||||
|
||||
$sql = <<<'SQL'
|
||||
SELECT
|
||||
CASE WHEN sender_id = ? THEN recipient_id ELSE sender_id END AS other_user_id,
|
||||
MAX(sent_datetime) AS last_message_time,
|
||||
SUM(CASE WHEN recipient_id = ? AND read_status = 0 THEN 1 ELSE 0 END) AS unread_count,
|
||||
(
|
||||
SELECT m2.message
|
||||
FROM messages m2
|
||||
WHERE (m2.sender_id = ? AND m2.recipient_id = CASE WHEN m1.sender_id = ? THEN m1.recipient_id ELSE m1.sender_id END)
|
||||
OR (m2.recipient_id = ? AND m2.sender_id = CASE WHEN m1.sender_id = ? THEN m1.recipient_id ELSE m1.sender_id END)
|
||||
ORDER BY m2.sent_datetime DESC
|
||||
LIMIT 1
|
||||
) AS last_message
|
||||
FROM messages m1
|
||||
WHERE (sender_id = ? OR recipient_id = ?)
|
||||
AND (subject = '' OR subject IS NULL OR subject = 'chat')
|
||||
GROUP BY other_user_id
|
||||
ORDER BY last_message_time DESC
|
||||
SQL;
|
||||
|
||||
$rows = DB::select($sql, array_fill(0, 8, $userId));
|
||||
|
||||
$conversations = [];
|
||||
foreach ($rows as $row) {
|
||||
$otherUser = $this->user->find($row->other_user_id);
|
||||
if (!$otherUser) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$conversations[] = [
|
||||
'user_id' => $row->other_user_id,
|
||||
'user_name' => trim(($otherUser['firstname'] ?? '') . ' ' . ($otherUser['lastname'] ?? '')),
|
||||
'user_initials' => strtoupper(($otherUser['firstname'][0] ?? '') . ($otherUser['lastname'][0] ?? '')),
|
||||
'last_message' => $row->last_message ?? '',
|
||||
'last_message_time'=> $row->last_message_time ?? null,
|
||||
'unread_count' => (int) ($row->unread_count ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
return $this->success($conversations, 'Conversations retrieved successfully');
|
||||
}
|
||||
|
||||
public function conversation($userId = null)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
if (!$user) {
|
||||
return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if (!$userId) {
|
||||
return $this->error('User ID is required', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$currentUserId = (int) $user->id;
|
||||
$otherUserId = (int) $userId;
|
||||
|
||||
$otherUser = $this->user->find($otherUserId);
|
||||
if (!$otherUser) {
|
||||
return $this->error('User not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$page = max(1, (int) ($this->request->getGet('page') ?? 1));
|
||||
$perPage = min(100, max(1, (int) ($this->request->getGet('per_page') ?? 50)));
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
$baseQuery = DB::table('messages')
|
||||
->where(function ($query) use ($currentUserId, $otherUserId) {
|
||||
$query->where('sender_id', $currentUserId)
|
||||
->where('recipient_id', $otherUserId);
|
||||
})
|
||||
->orWhere(function ($query) use ($currentUserId, $otherUserId) {
|
||||
$query->where('sender_id', $otherUserId)
|
||||
->where('recipient_id', $currentUserId);
|
||||
})
|
||||
->whereRaw("(subject = '' OR subject IS NULL OR subject = 'chat')")
|
||||
->orderBy('sent_datetime', 'ASC');
|
||||
|
||||
$total = (clone $baseQuery)->count();
|
||||
$messages = (clone $baseQuery)->offset($offset)->limit($perPage)->get();
|
||||
|
||||
foreach ($messages as $message) {
|
||||
if ($message->recipient_id === $currentUserId && ((int) $message->read_status) === 0) {
|
||||
$this->message->update($message->id, [
|
||||
'read_status' => 1,
|
||||
'read_datetime'=> Carbon::now('UTC')->format('Y-m-d H:i:s'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$enriched = [];
|
||||
foreach ($messages as $msg) {
|
||||
$enriched[] = [
|
||||
'id' => $msg->id,
|
||||
'sender_id' => $msg->sender_id,
|
||||
'recipient_id' => $msg->recipient_id,
|
||||
'message' => $msg->message,
|
||||
'sent_datetime' => $msg->sent_datetime,
|
||||
'read_status' => $msg->read_status,
|
||||
'read_datetime' => $msg->read_datetime,
|
||||
'attachment' => $msg->attachment ?? null,
|
||||
'is_sender' => $msg->sender_id === $currentUserId,
|
||||
];
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'messages' => $enriched,
|
||||
'other_user' => [
|
||||
'id' => $otherUser['id'],
|
||||
'name' => trim(($otherUser['firstname'] ?? '') . ' ' . ($otherUser['lastname'] ?? '')),
|
||||
'initials' => strtoupper(($otherUser['firstname'][0] ?? '') . ($otherUser['lastname'][0] ?? '')),
|
||||
],
|
||||
'pagination' => [
|
||||
'current_page' => $page,
|
||||
'per_page' => $perPage,
|
||||
'total' => $total,
|
||||
'total_pages' => (int) ceil($total / $perPage),
|
||||
],
|
||||
];
|
||||
|
||||
return $this->success($payload, 'Messages retrieved successfully');
|
||||
}
|
||||
|
||||
public function send()
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
if (!$user) {
|
||||
return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$payload = $this->payloadData();
|
||||
if (empty($payload)) {
|
||||
return $this->error('Invalid request data', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'recipient_id' => 'required|integer',
|
||||
'message' => 'required|max_length[5000]',
|
||||
];
|
||||
|
||||
$errors = $this->validateRequest($payload, $rules);
|
||||
if (!empty($errors)) {
|
||||
return $this->respondValidationError($errors);
|
||||
}
|
||||
|
||||
$recipientId = (int) $payload['recipient_id'];
|
||||
if ($recipientId === (int) $user->id) {
|
||||
return $this->error('Cannot send message to yourself', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$recipient = $this->user->find($recipientId);
|
||||
if (!$recipient) {
|
||||
return $this->error('Recipient not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$schoolYear = $this->config->getConfig('school_year') ?? date('Y');
|
||||
$semester = $this->config->getConfig('semester') ?? 'Fall';
|
||||
|
||||
$maxMessageNumber = $this->message->newQuery()
|
||||
->selectRaw('COALESCE(MAX(message_number), 0) AS message_number')
|
||||
->first();
|
||||
|
||||
$messageNumber = (int) ($maxMessageNumber->message_number ?? $maxMessageNumber['message_number'] ?? 0) + 1;
|
||||
|
||||
$messageData = [
|
||||
'sender_id' => (int) $user->id,
|
||||
'recipient_id' => $recipientId,
|
||||
'subject' => 'chat',
|
||||
'message' => $payload['message'],
|
||||
'sent_datetime' => Carbon::now('UTC')->format('Y-m-d H:i:s'),
|
||||
'read_status' => 0,
|
||||
'message_number'=> $messageNumber,
|
||||
'priority' => 'normal',
|
||||
'status' => 'sent',
|
||||
'semester' => $semester,
|
||||
'school_year' => $schoolYear,
|
||||
'attachment' => $payload['attachment'] ?? null,
|
||||
];
|
||||
|
||||
try {
|
||||
$message = $this->message->create($messageData);
|
||||
return $this->success([
|
||||
'id' => $message->id,
|
||||
'sender_id' => $message->sender_id,
|
||||
'recipient_id' => $message->recipient_id,
|
||||
'message' => $message->message,
|
||||
'sent_datetime' => $message->sent_datetime,
|
||||
'read_status' => $message->read_status,
|
||||
'attachment' => $message->attachment,
|
||||
'is_sender' => true,
|
||||
], 'Message sent successfully', Response::HTTP_CREATED);
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Message send error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to send message', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public function markRead()
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
if (!$user) {
|
||||
return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$payload = $this->payloadData();
|
||||
if (empty($payload)) {
|
||||
return $this->error('Invalid request data', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$currentUserId = (int) $user->id;
|
||||
|
||||
try {
|
||||
if (!empty($payload['message_ids']) && is_array($payload['message_ids'])) {
|
||||
$messageIds = array_map('intval', $payload['message_ids']);
|
||||
$updated = $this->message->newQuery()
|
||||
->whereIn('id', $messageIds)
|
||||
->where('recipient_id', $currentUserId)
|
||||
->where('read_status', 0)
|
||||
->update([
|
||||
'read_status' => 1,
|
||||
'read_datetime'=> Carbon::now('UTC')->format('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
return $this->success([
|
||||
'updated_count' => $updated,
|
||||
], 'Messages marked as read');
|
||||
}
|
||||
|
||||
if (isset($payload['user_id'])) {
|
||||
$senderId = (int) $payload['user_id'];
|
||||
$updated = $this->message->newQuery()
|
||||
->where('sender_id', $senderId)
|
||||
->where('recipient_id', $currentUserId)
|
||||
->where('read_status', 0)
|
||||
->update([
|
||||
'read_status' => 1,
|
||||
'read_datetime'=> Carbon::now('UTC')->format('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
return $this->success([
|
||||
'updated_count' => $updated,
|
||||
], 'Messages marked as read');
|
||||
}
|
||||
|
||||
return $this->error('Either message_ids or user_id is required', Response::HTTP_BAD_REQUEST);
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Mark read error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to mark messages as read', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public function unreadCount()
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
if (!$user) {
|
||||
return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
try {
|
||||
$count = $this->message->newQuery()
|
||||
->where('recipient_id', (int) $user->id)
|
||||
->where('read_status', 0)
|
||||
->whereRaw("(subject = '' OR subject IS NULL OR subject = 'chat')")
|
||||
->count();
|
||||
|
||||
return $this->success([
|
||||
'unread_count' => $count,
|
||||
], 'Unread count retrieved successfully');
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Unread count error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to get unread count', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public function searchUsers()
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
if (!$user) {
|
||||
return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$query = trim((string) ($this->request->getGet('q') ?? ''));
|
||||
if (strlen($query) < 2) {
|
||||
return $this->error('Search query must be at least 2 characters', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$limit = min(20, max(1, (int) ($this->request->getGet('limit') ?? 10)));
|
||||
|
||||
try {
|
||||
$users = $this->user->newQuery()
|
||||
->where(function ($q) use ($query) {
|
||||
$q->where('firstname', 'LIKE', "%{$query}%")
|
||||
->orWhere('lastname', 'LIKE', "%{$query}%")
|
||||
->orWhere('email', 'LIKE', "%{$query}%");
|
||||
})
|
||||
->where('id', '!=', (int) $user->id)
|
||||
->where('status', 'active')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$results = [];
|
||||
foreach ($users as $u) {
|
||||
$results[] = [
|
||||
'id' => $u->id,
|
||||
'name' => trim(($u->firstname ?? '') . ' ' . ($u->lastname ?? '')),
|
||||
'initials' => strtoupper(($u->firstname[0] ?? '') . ($u->lastname[0] ?? '')),
|
||||
'email' => $u->email ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
return $this->success($results, 'Users retrieved successfully');
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Search users error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to search users', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteMessage($id = null)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
if (!$user) {
|
||||
return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if (!$id) {
|
||||
return $this->error('Message ID is required', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$message = $this->message->find($id);
|
||||
if (!$message) {
|
||||
return $this->error('Message not found', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($message->sender_id !== (int) $user->id && $message->recipient_id !== (int) $user->id) {
|
||||
return $this->error('Unauthorized to delete this message', Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
$this->message->update($id, [
|
||||
'status' => 'deleted',
|
||||
]);
|
||||
|
||||
return $this->success(null, 'Message deleted successfully');
|
||||
}
|
||||
|
||||
public function deleteConversation($userId = null)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
if (!$user) {
|
||||
return $this->respondError('Authentication required', Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if (!$userId) {
|
||||
return $this->error('User ID is required', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$currentUserId = (int) $user->id;
|
||||
$otherUserId = (int) $userId;
|
||||
|
||||
try {
|
||||
$updated = $this->message->newQuery()
|
||||
->where(function ($query) use ($currentUserId, $otherUserId) {
|
||||
$query->where('sender_id', $currentUserId)
|
||||
->where('recipient_id', $otherUserId);
|
||||
})
|
||||
->orWhere(function ($query) use ($currentUserId, $otherUserId) {
|
||||
$query->where('sender_id', $otherUserId)
|
||||
->where('recipient_id', $currentUserId);
|
||||
})
|
||||
->whereRaw("(subject = '' OR subject IS NULL OR subject = 'chat')")
|
||||
->update(['status' => 'deleted']);
|
||||
|
||||
return $this->success([
|
||||
'deleted_count' => $updated,
|
||||
], 'Conversation deleted successfully');
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Delete conversation error: ' . $e->getMessage());
|
||||
return $this->respondError('Failed to delete conversation', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user