xgit simple git

nexus

nexus

clone git clone https://kb.hax.al/nexus

api/chat.php


1<?php
2/**
3 * Live chat API for private messages.
4 * Actions: send, poll, delete, conversations
5 */
6require_once __DIR__ . '/../includes/bootstrap.php';
7must_login();
8if (!csrf_ok()) json_out(['error' => 'CSRF'], 403);
9 
10$action = post('action');
11$uid    = (int)$USER['id'];
12 
13/* ── Helper: build conversation_id ───────────────────── */
14function conv_id(int $a, int $b): string {
15    return min($a,$b) . '-' . max($a,$b);
16}
17 
18/* ── Send a message ──────────────────────────────────── */
19if ($action === 'send') {
20    $toId   = (int)post('to_id');
21    $body   = sanitise(post('body'));
22 
23    if (!$toId || $toId === $uid) json_out(['error' => 'Invalid recipient'], 400);
24    if (!$body)                   json_out(['error' => 'Message is empty'], 400);
25    if (mb_strlen($body) > 2000)  json_out(['error' => 'Message too long (max 2000)'], 400);
26 
27    $other = DB::row('SELECT id,username FROM users WHERE id=? AND suspended=0', [$toId]);
28    if (!$other) json_out(['error' => 'User not found'], 404);
29 
30    $convId = conv_id($uid, $toId);
31 
32    $msgId = DB::insert(
33        'INSERT INTO messages (sender_id,receiver_id,subject,body,conversation_id) VALUES (?,?,?,?,?)',
34        [$uid, $toId, '', $body, $convId]
35    );
36 
37    // Notify recipient
38    add_notification($toId, 'message', [
39        'from'    => $USER['username'],
40        'from_id' => $uid,
41        'subject' => mb_substr($body, 0, 60) . (mb_strlen($body) > 60 ? '…' : ''),
42    ]);
43 
44    // Return the new message row for live append
45    $msg = DB::row(
46        'SELECT m.*, u.username AS sender_name, u.avatar AS sender_av
47         FROM messages m JOIN users u ON u.id=m.sender_id
48         WHERE m.id=?', [$msgId]
49    );
50    json_out(['ok' => true, 'message' => $msg]);
51}
52 
53/* ── Poll: fetch new messages since a given id ───────── */
54if ($action === 'poll') {
55    $otherId  = (int)post('other_id');
56    $sinceId  = (int)post('since_id');
57    if (!$otherId) json_out(['error' => 'Missing other_id'], 400);
58 
59    $convId = conv_id($uid, $otherId);
60    $msgs   = DB::rows(
61        'SELECT m.*, u.username AS sender_name, u.avatar AS sender_av
62         FROM messages m JOIN users u ON u.id=m.sender_id
63         WHERE m.conversation_id=? AND m.id>?
64         ORDER BY m.id ASC LIMIT 50',
65        [$convId, $sinceId]
66    );
67 
68    // Mark messages from other user as read
69    if ($msgs) {
70        $now = DB::now();
71        DB::run(
72            "UPDATE messages SET is_read=1
73             WHERE conversation_id=? AND receiver_id=? AND `is_read`=0",
74            [$convId, $uid]
75        );
76    }
77 
78    json_out(['ok' => true, 'messages' => $msgs]);
79}
80 
81/* ── Load full conversation ──────────────────────────── */
82if ($action === 'load') {
83    $otherId = (int)post('other_id');
84    $before  = (int)post('before_id'); // for pagination
85    if (!$otherId) json_out(['error' => 'Missing other_id'], 400);
86 
87    $convId = conv_id($uid, $otherId);
88    $params = [$convId];
89    $where  = '';
90    if ($before) {
91        $where   = ' AND m.id < ?';
92        $params[] = $before;
93    }
94 
95    $msgs = DB::rows(
96        "SELECT m.*, u.username AS sender_name, u.avatar AS sender_av
97         FROM messages m JOIN users u ON u.id=m.sender_id
98         WHERE m.conversation_id=? $where
99         ORDER BY m.id DESC LIMIT 40",
100        $params
101    );
102    $msgs = array_reverse($msgs); // oldest first
103 
104    // Mark as read
105    DB::run(
106        "UPDATE messages SET `is_read`=1
107         WHERE conversation_id=? AND receiver_id=? AND `is_read`=0",
108        [$convId, $uid]
109    );
110 
111    $other = DB::row('SELECT id,username,avatar,role,karma,last_seen FROM users WHERE id=?', [$otherId]);
112    json_out(['ok' => true, 'messages' => $msgs, 'other' => $other]);
113}
114 
115/* ── List conversations ──────────────────────────────── */
116if ($action === 'conversations') {
117    $convs = DB::rows(
118        "SELECT m.*,
119                u.username AS other_name, u.avatar AS other_av,
120                (SELECT COUNT(*) FROM messages m2
121                 WHERE m2.conversation_id=m.conversation_id
122                   AND m2.receiver_id=? AND m2.is_read=0) AS unread_count
123         FROM messages m
124         JOIN users u ON u.id = CASE WHEN m.sender_id=? THEN m.receiver_id ELSE m.sender_id END
125         WHERE m.conversation_id IN (
126             SELECT conversation_id FROM messages
127             WHERE sender_id=? OR receiver_id=?
128         )
129         AND m.id IN (
130             SELECT MAX(id) FROM messages
131             WHERE sender_id=? OR receiver_id=?
132             GROUP BY conversation_id
133         )
134         ORDER BY m.created_at DESC",
135        [$uid, $uid, $uid, $uid, $uid, $uid]
136    );
137    json_out(['ok' => true, 'conversations' => $convs]);
138}
139 
140/* ── Delete a message ────────────────────────────────── */
141if ($action === 'delete') {
142    $msgId = (int)post('msg_id');
143    $msg   = DB::row('SELECT * FROM messages WHERE id=?', [$msgId]);
144    if (!$msg) json_out(['error' => 'Not found'], 404);
145    if ($msg['sender_id'] !== $uid && $msg['receiver_id'] !== $uid) json_out(['error' => 'Forbidden'], 403);
146 
147    if ($msg['sender_id'] === $uid)
148        DB::run('UPDATE messages SET deleted_by_sender=1 WHERE id=?', [$msgId]);
149    else
150        DB::run('UPDATE messages SET deleted_by_receiver=1 WHERE id=?', [$msgId]);
151 
152    json_out(['ok' => true]);
153}
154 
155json_out(['error' => 'Unknown action'], 400);