fix: Enable dynamic student/teacher contact discovery, dual REST/WebSocket persistence, and multi-path .env detection

This commit is contained in:
Hamza-Ayed
2026-08-27 03:47:45 +03:00
parent b11a4bd8c1
commit 7fd67756b4
4 changed files with 198 additions and 140 deletions
+55 -52
View File
@@ -11,71 +11,74 @@ use App\Core\Validator;
class ChatController
{
/**
* List all active conversations for the authenticated user (Student or Teacher)
* List all active conversations and available contacts (Student or Teacher)
* GET /api/chat/conversations
*/
public function getConversations(Request $request, Response $response): void
{
$userId = $request->user_id;
// Find all distinct other parties in conversations
$sql = "
SELECT
u.id as user_id,
u.uuid as user_uuid,
u.full_name as encrypted_name,
u.role as user_role,
tp.specialization,
m.last_message,
m.last_message_type,
m.last_message_at,
COALESCE(unread.unread_count, 0) as unread_count
FROM (
SELECT
CASE WHEN sender_id = ? THEN receiver_id ELSE sender_id END as other_user_id,
message as last_message,
message_type as last_message_type,
created_at as last_message_at,
ROW_NUMBER() OVER (
PARTITION BY (CASE WHEN sender_id = ? THEN receiver_id ELSE sender_id END)
ORDER BY created_at DESC
) as rn
FROM chat_messages
WHERE sender_id = ? OR receiver_id = ?
) m
JOIN users u ON u.id = m.other_user_id
LEFT JOIN teacher_profiles tp ON tp.user_id = u.id
LEFT JOIN (
SELECT sender_id, COUNT(*) as unread_count
FROM chat_messages
WHERE receiver_id = ? AND is_read = 0
GROUP BY sender_id
) unread ON unread.sender_id = u.id
WHERE m.rn = 1
ORDER BY m.last_message_at DESC
";
$userId = (int)$request->user_id;
$userRole = (string)($request->role ?? 'student');
// 1. Fetch users with conversation history
$activeConvs = [];
try {
$rows = Database::select($sql, [$userId, $userId, $userId, $userId, $userId]);
} catch (\Exception $e) {
// Fallback for MySQL setups without window functions
$rows = Database::select("
SELECT
u.id as user_id,
u.uuid as user_uuid,
u.full_name as encrypted_name,
u.role as user_role,
tp.specialization
tp.specialization,
m.message as last_message,
m.message_type as last_message_type,
m.created_at as last_message_at,
(SELECT COUNT(*) FROM chat_messages WHERE sender_id = u.id AND receiver_id = ? AND is_read = 0) as unread_count
FROM users u
LEFT JOIN teacher_profiles tp ON tp.user_id = u.id
WHERE u.id IN (
SELECT DISTINCT CASE WHEN sender_id = ? THEN receiver_id ELSE sender_id END
FROM chat_messages
WHERE sender_id = ? OR receiver_id = ?
JOIN chat_messages m ON m.id = (
SELECT MAX(id) FROM chat_messages
WHERE (sender_id = ? AND receiver_id = u.id) OR (sender_id = u.id AND receiver_id = ?)
)
", [$userId, $userId, $userId]);
WHERE u.id != ?
ORDER BY m.created_at DESC
", [$userId, $userId, $userId, $userId]);
$activeConvs = $rows ?: [];
} catch (\Exception $e) {
error_log("Active convs query note: " . $e->getMessage());
}
$existingUserIds = array_column($activeConvs, 'user_id');
$existingUserIds[] = $userId;
// 2. Fetch other users who haven't started a conversation yet
$targetRole = ($userRole === 'teacher' || $userRole === 'super_admin') ? 'student' : 'teacher';
$inPlaceholders = implode(',', array_fill(0, count($existingUserIds), '?'));
$otherUsers = [];
try {
$otherUsers = Database::select("
SELECT
u.id as user_id,
u.uuid as user_uuid,
u.full_name as encrypted_name,
u.role as user_role,
tp.specialization,
'' as last_message,
'text' as last_message_type,
NULL as last_message_at,
0 as unread_count
FROM users u
LEFT JOIN teacher_profiles tp ON tp.user_id = u.id
WHERE u.role = ? AND u.id NOT IN ({$inPlaceholders})
ORDER BY u.id DESC
LIMIT 50
", array_merge([$targetRole], $existingUserIds));
} catch (\Exception $e) {
error_log("Other users query note: " . $e->getMessage());
}
$allRows = array_merge($activeConvs, $otherUsers ?: []);
$conversations = array_map(function ($row) {
$rawName = (string)($row['encrypted_name'] ?? '');
$decryptedName = Security::decrypt($rawName) ?: $rawName;
@@ -83,15 +86,15 @@ class ChatController
return [
'user_id' => (int)$row['user_id'],
'user_uuid' => $row['user_uuid'] ?? '',
'full_name' => $decryptedName ?: ($row['user_role'] === 'teacher' ? 'أستاذ المادة' : 'طالب صَقِل'),
'full_name' => $decryptedName ?: ($row['user_role'] === 'teacher' ? 'الأستاذ حمزة الغويري' : 'طالب صَقِل'),
'role' => $row['user_role'] ?? 'student',
'specialization' => $row['specialization'] ?? null,
'last_message' => $row['last_message'] ?? '',
'specialization' => $row['specialization'] ?? ($row['user_role'] === 'teacher' ? 'الرياضيات العلمي' : null),
'last_message' => $row['last_message'] ?: ($row['user_role'] === 'teacher' ? 'متاح للإجابة عن استفساراتك' : 'طالب جديد — اضغط لبدء المحادثة'),
'last_message_type' => $row['last_message_type'] ?? 'text',
'last_message_at' => $row['last_message_at'] ?? null,
'unread_count' => (int)($row['unread_count'] ?? 0),
];
}, $rows);
}, $allRows);
$response->json([
'status' => 'success',