xgit simple git

nexus

nexus

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

api/reply.php

1 <?php
2 require_once __DIR__ . '/../includes/bootstrap.php';
3 if (!$USER) json_out(['error'=>'Not logged in'],401);
4 if ($_SERVER['REQUEST_METHOD']!=='POST') json_out(['error'=>'Method not allowed'],405);
5 if (!csrf_ok()) json_out(['error'=>'Invalid CSRF token'],403);
6 if ($USER['silenced']) json_out(['error'=>'You are silenced and cannot post'],403);
7 
8 // ── Rate limit check ─────────────────────────────────────────
9 $rl = rate_check((int)$USER['id'], 'post');
10 if (!$rl['ok']) {
11     $wait = (int)$rl['wait'];
12     json_out(['error'=>"You're posting too fast. Please wait {$wait} second".($wait!==1?'s':'').' before posting again.','rate_limited'=>true,'wait'=>$wait], 429);
13 }
14 
15 // ── Post captcha check ───────────────────────────────────────
16 if (post_captcha_enabled()) {
17     $cap = post('post_captcha');
18     if (!post_captcha_verify($cap)) {
19         json_out(['error'=>'Incorrect security answer.','captcha_failed'=>true], 403);
20     }
21 }
22 
23 $slug    = sanitise(post('slug'));
24 $content = sanitise(post('content'));
25 $replyTo = (int)post('reply_to');
26 
27 if (!$slug || !$content) json_out(['error'=>'Missing required fields'],400);
28 if (strlen($content) < 1)     json_out(['error'=>'Reply cannot be empty'],400);
29 if (strlen($content) > 20000) json_out(['error'=>'Post too long (max 20,000 chars)'],400);
30 
31 $topic = DB::row('SELECT * FROM topics WHERE slug=?', [$slug]);
32 if (!$topic) json_out(['error'=>'Topic not found'],404);
33 if ($topic['closed']) json_out(['error'=>'This topic is closed'],403);
34 $replyCat = DB::row('SELECT * FROM categories WHERE id=?',[$topic['category_id']]);
35 if (!can_reply_topic($replyCat ?? [])) json_out(['error'=>'No permission to reply in this category'],403);
36 
37 $last = DB::row('SELECT post_num FROM posts WHERE topic_id=? ORDER BY post_num DESC LIMIT 1',[$topic['id']]);
38 $num  = ($last ? (int)$last['post_num'] : 0) + 1;
39 
40 $pid = DB::insert(
41     'INSERT INTO posts (topic_id,user_id,content,post_num,reply_to) VALUES (?,?,?,?,?)',
42     [$topic['id'], $USER['id'], $content, $num, $replyTo ?: null]
43 );
44 
45 // Record rate limit event AFTER successful post
46 rate_record((int)$USER['id'], 'post');
47 
48 $now = DB::now();
49 DB::run("UPDATE topics SET last_post_at=$now,reply_count=reply_count+1 WHERE id=?",[$topic['id']]);
50 DB::run('UPDATE users SET post_count=post_count+1 WHERE id=?',[$USER['id']]);
51 DB::run('UPDATE categories SET post_count=post_count+1 WHERE id=?',[$topic['category_id']]);
52 
53 if ($topic['user_id'] !== $USER['id']) {
54     add_notification((int)$topic['user_id'],'reply',[
55         'slug'=>$topic['slug'],'title'=>$topic['title'],'from'=>$USER['username']
56     ]);
57 }
58 process_mentions($content, $pid, $topic['slug'], (int)$USER['id'], $USER['username']);
59 
60 $post = DB::row("
61     SELECT p.*,u.username,u.avatar,u.role,u.post_count,0 AS likes
62     FROM posts p JOIN users u ON u.id=p.user_id WHERE p.id=?
63 ",[$pid]);
64 
65 // Send new captcha if post captcha enabled
66 $newCaptcha = post_captcha_enabled() ? post_captcha_generate() : null;
67 
68 addon_hook('after_reply_saved', ['post_id'=>$pid,'topic_id'=>$topic['id'],'user_id'=>(int)$USER['id']]);
69 json_out(['ok'=>true,'post'=>$post,'new_captcha'=>$newCaptcha]);