• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

marscoin / martianrepublic / 24432853959

15 Apr 2026 02:12AM UTC coverage: 10.995% (-0.009%) from 11.004%
24432853959

push

github

novalis78
Include citizen avatar and display data in forum API responses

Add LEFT JOIN to citizen table for both thread listing and comment
fetching. Adds avatar_link, displayname, and is_citizen fields to the
JSON responses. Existing consumers (web UI) are unaffected — extra
fields are ignored if not used. Mobile app can now render avatars and
citizen badges directly from these endpoints without extra lookups.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

0 of 5 new or added lines in 1 file covered. (0.0%)

664 of 6039 relevant lines covered (11.0%)

1.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/app/Http/Controllers/ForumApiController.php
1
<?php
2

3
namespace App\Http\Controllers;
4

5
use App\Models\Post;
6
use App\Models\Thread;
7
use Illuminate\Http\Request;
8
use Illuminate\Support\Facades\Auth;
9
use Illuminate\Support\Facades\DB;
10

11
class ForumApiController extends Controller
12
{
13
    public function getThreadsByCategory($categoryId)
×
14
    {
15
        $threads = $this->fetchThreads($categoryId);
×
16

17
        return response()->json(['threads' => $threads]);
×
18
    }
19

20
    public function getThreadComments($threadId)
×
21
    {
22
        // Assume $threadId is passed correctly to the function
23
        $comments = $this->fetchCommentsByThread($threadId);
×
24

25
        return response()->json(['comments' => $comments]);
×
26
    }
27

28
    public function getAllCategoriesWithThreads()
×
29
    {
30
        $userId = Auth::id();
×
31

32
        $categories = DB::table('forum_categories')->get();
×
33

34
        // Fetch all threads in a single query instead of N+1
35
        $threads = DB::table('forum_threads')
×
36
            ->leftJoin('users', 'forum_threads.author_id', '=', 'users.id')
×
37
            ->leftJoin('profile', 'users.id', '=', 'profile.userid')
×
38
            ->leftJoin('user_blocks as ub', function ($join) use ($userId) {
×
39
                $join->on('forum_threads.author_id', '=', 'ub.blocked_user_id')
×
40
                    ->where('ub.user_id', '=', $userId);
×
41
            })
×
42
            ->select(
×
43
                'forum_threads.id',
×
44
                'forum_threads.category_id',
×
45
                'forum_threads.title',
×
46
                'forum_threads.created_at',
×
47
                'forum_threads.reply_count',
×
48
                'users.fullname as author_name',
×
49
                DB::raw('IF(ub.blocked_user_id IS NOT NULL, true, false) as is_blocked')
×
50
            )
×
51
            ->orderBy('forum_threads.created_at', 'desc')
×
52
            ->get()
×
53
            ->groupBy('category_id');
×
54

55
        foreach ($categories as $category) {
×
56
            $category->threads = $threads->get($category->id, collect());
×
57
        }
58

59
        return response()->json(['categories' => $categories]);
×
60
    }
61

62
    public function createThread(Request $request)
×
63
    {
64
        $request->validate([
×
65
            'category_id' => 'required|exists:forum_categories,id',
×
66
            'title' => 'required|string|max:255',
×
67
            'content' => 'required|string',
×
68
        ]);
×
69

70
        $thread = new Thread;
×
71
        $thread->category_id = $request->category_id;
×
72
        $thread->author_id = Auth::id();
×
73
        $thread->title = $request->title;
×
74
        $thread->save();
×
75

76
        $post = new Post;
×
77
        $post->thread_id = $thread->id;
×
78
        $post->author_id = Auth::id();
×
79
        $post->content = $request->content;
×
80
        $post->save();
×
81

82
        $thread->first_post_id = $post->id;
×
83
        $thread->last_post_id = $post->id;
×
84
        $thread->reply_count = 0;
×
85
        $thread->save();
×
86

87
        return response()->json([
×
88
            'message' => 'Thread created successfully',
×
89
            'thread_id' => $thread->id,
×
90
            'post_id' => $post->id,
×
91
        ], 201);
×
92
    }
93

94
    public function createComment(Request $request, $threadId)
×
95
    {
96
        $request->validate([
×
97
            'content' => 'required|string',
×
98
            'post_id' => 'nullable|exists:forum_posts,id',
×
99
        ]);
×
100

101
        $thread = Thread::findOrFail($threadId);
×
102

103
        $post = new Post;
×
104
        $post->thread_id = $threadId;
×
105
        $post->author_id = Auth::id();
×
106
        $post->content = $request->content;
×
107
        $post->post_id = $request->post_id; // This will be null for top-level comments
×
108
        $post->save();
×
109

110
        $thread->last_post_id = $post->id;
×
111
        $thread->reply_count += 1;
×
112
        $thread->save();
×
113

114
        return response()->json([
×
115
            'message' => 'Comment created successfully',
×
116
            'post_id' => $post->id,
×
117
        ], 201);
×
118
    }
119

120
    private function fetchThreads($categoryId)
×
121
    {
122
        $userId = Auth::id();
×
123

124
        $threads = DB::table('forum_threads')
×
125
            ->where('forum_threads.category_id', $categoryId)
×
126
            ->leftJoin('users', 'forum_threads.author_id', '=', 'users.id')
×
127
            ->leftJoin('profile', 'users.id', '=', 'profile.userid')
×
NEW
128
            ->leftJoin('citizen', 'users.id', '=', 'citizen.userid')
×
129
            ->leftJoin('user_blocks as ub', function ($join) use ($userId) {
×
130
                $join->on('forum_threads.author_id', '=', 'ub.blocked_user_id')
×
131
                    ->where('ub.user_id', '=', $userId);
×
132
            })
×
133
            ->select(
×
134
                'forum_threads.id',
×
NEW
135
                'forum_threads.author_id',
×
136
                'forum_threads.title',
×
137
                'forum_threads.created_at',
×
138
                'forum_threads.reply_count',
×
139
                'users.fullname as author_name',
×
NEW
140
                'citizen.avatar_link',
×
NEW
141
                'citizen.displayname',
×
NEW
142
                'profile.citizen as is_citizen',
×
143
                DB::raw('IF(ub.blocked_user_id IS NOT NULL, true, false) as is_blocked')
×
144
            )
×
145
            ->orderBy('forum_threads.created_at', 'desc')
×
146
            ->get();
×
147

148
        return $threads;
×
149
    }
150

151
    private function fetchCommentsByThread($threadId)
×
152
    {
153
        $userId = Auth::id();
×
154

155
        $query = '
×
156
            WITH RECURSIVE CommentTree AS (
157
                SELECT
158
                    p.id,
159
                    p.thread_id,
160
                    p.author_id,
161
                    p.content,
162
                    p.post_id as pid,
163
                    p.created_at,
164
                    CHAR_LENGTH(p.content) as char_length_sum
165
                FROM
166
                    forum_posts p
167
                WHERE
168
                    p.thread_id = ? AND p.post_id IS NULL
169

170
                UNION ALL
171

172
                SELECT
173
                    p.id,
174
                    p.thread_id,
175
                    p.author_id,
176
                    p.content,
177
                    p.post_id,
178
                    p.created_at,
179
                    ct.char_length_sum + CHAR_LENGTH(p.content)
180
                FROM
181
                    forum_posts p
182
                INNER JOIN
183
                    CommentTree ct ON p.post_id = ct.id
184
            )
185
            SELECT
186
                ct.id,
187
                ct.thread_id,
188
                ct.author_id,
189
                u.fullname,
190
                c.avatar_link,
191
                c.displayname,
192
                pr.citizen as is_citizen,
193
                ct.content,
194
                ct.created_at,
195
                ct.pid,
196
                CHAR_LENGTH(ct.content) as char_length_sum,
197
                IF(ub.blocked_user_id IS NOT NULL, true, false) as is_blocked
198
            FROM
199
                CommentTree ct
200
            LEFT JOIN users u ON ct.author_id = u.id
201
            LEFT JOIN profile pr ON ct.author_id = pr.userid
202
            LEFT JOIN citizen c ON ct.author_id = c.userid
203
            LEFT JOIN user_blocks ub ON ub.blocked_user_id = ct.author_id AND ub.user_id = ?
204
            ORDER BY
205
                ct.pid ASC,
206
                ct.created_at ASC;
207
        ';
×
208

209
        $comments = DB::select($query, [$threadId, $userId]);
×
210
        $commentsCollection = collect($comments);
×
211

212
        return response()->json(['comments' => $commentsCollection]);
×
213
    }
214
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc