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

marscoin / martianrepublic / 23823524774

31 Mar 2026 11:03PM UTC coverage: 10.419%. Remained the same
23823524774

push

github

Martian Congress
refactor: A1 — split ApiController (1,147 lines) into 5 controllers

The god controller is dead. Long live focused controllers:

- FeedApiController (287 lines) — allPublic, allCitizen, allApplicants,
  allFeed, showCitizen, scitizen
- AuthApiController (260 lines) — marsAuth, checkAuth, wauth, token
- ForumApiController (205 lines) — threads, comments, categories
- ContentApiController (230 lines) — pinpic, pinvideo, pinjson (IPFS)
- UserManagementController (95 lines) — blockUser, deleteUser, eula

ApiController.php is now 18 lines (empty shell with migration notes).
All routes updated to array notation pointing to new controllers.
Zero method logic changed — pure structural refactor.

127 tests, 0 PHPStan errors, API endpoints verified.

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

31 of 637 new or added lines in 5 files covered. (4.87%)

599 of 5749 relevant lines covered (10.42%)

1.47 hits per line

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

14.55
/app/Http/Controllers/FeedApiController.php
1
<?php
2

3
namespace App\Http\Controllers;
4

5
use App\Models\Citizen;
6
use App\Models\CivicWallet;
7
use App\Models\Feed;
8
use App\Models\Profile;
9
use App\Models\User;
10
use Illuminate\Http\Request;
11
use Illuminate\Support\Facades\Auth;
12
use Illuminate\Support\Facades\Cache;
13
use Illuminate\Support\Facades\DB;
14

15
class FeedApiController extends Controller
16
{
17
    public function allPublic()
1✔
18
    {
19
        $perPage = 25;
1✔
20
        $cacheKey = 'all_public_cache'; // Define a unique cache key for this query
1✔
21
        $excludedUserIds = [6462, 7601]; // ID of the user you want to exclude, for example, a test account
1✔
22

23
        // Attempt to get cached data. If not available, the closure will be run to fetch and cache the data.
24
        $feeds = Cache::remember($cacheKey, 60, function () use ($perPage, $excludedUserIds) {
1✔
25
            $feeds = Feed::with(['user' => function ($query) use ($excludedUserIds) {
1✔
NEW
26
                $query->select('id', 'fullname', 'created_at')
×
NEW
27
                    ->where('id', '!=', $excludedUserIds); // Exclude the specific user by ID
×
28
            }, 'user.profile' => function ($query) {
1✔
NEW
29
                $query->select('userid', 'general_public', 'endorse_cnt', 'citizen', 'has_application');
×
30
            }, 'user.citizen' => function ($query) {
1✔
NEW
31
                $query->select('userid', 'avatar_link', 'liveness_link')
×
NEW
32
                    ->whereNotNull('avatar_link');
×
33
            }])
1✔
34
                ->joinSub(
1✔
35
                    Feed::selectRaw('max(id) as latest_id, userid')
1✔
36
                        ->where('tag', 'GP') // Ensure the tag is 'GP'
1✔
37
                        ->groupBy('userid'),
1✔
38
                    'latest_feeds',
1✔
39
                    function ($join) {
1✔
40
                        $join->on('feed.id', '=', 'latest_feeds.latest_id');
1✔
41
                    }
1✔
42
                )
1✔
43
                ->whereHas('user.profile', function ($query) {
1✔
44
                    $query->where('tag', 'GP');
1✔
45
                })
1✔
46
                ->whereHas('user', function ($query) use ($excludedUserIds) {
1✔
47
                    $query->whereNotIn('id', $excludedUserIds);
1✔
48
                })
1✔
49
                ->orderByDesc('id')
1✔
50
                ->take($perPage)
1✔
51
                ->distinct()
1✔
52
                ->get();
1✔
53

54
            return $feeds; // Directly return the fetched feeds
1✔
55
        });
1✔
56

57
        return response()->json($feeds);
1✔
58
    }
59

NEW
60
    public function allCitizen()
×
61
    {
NEW
62
        $perPage = 25;
×
NEW
63
        $cacheKey = 'all_citizens_cache';
×
NEW
64
        $excludedUserId = '';
×
65

NEW
66
        $feeds = Cache::remember($cacheKey, 60, function () use ($perPage, $excludedUserId) {
×
NEW
67
            return Feed::with([
×
NEW
68
                'user' => function ($query) use ($excludedUserId) {
×
NEW
69
                    $query->where('id', '!=', $excludedUserId)
×
NEW
70
                        ->select('id', 'fullname', 'created_at');
×
NEW
71
                },
×
NEW
72
                'user.profile' => function ($query) {
×
NEW
73
                    $query->select('userid', 'general_public', 'endorse_cnt', 'citizen', 'has_application');
×
NEW
74
                },
×
NEW
75
                'user.citizen' => function ($query) {
×
NEW
76
                    $query->select('userid', 'avatar_link', 'liveness_link')
×
NEW
77
                        ->whereNotNull('avatar_link'); // Ensure that avatar_link is not NULL
×
NEW
78
                },
×
NEW
79
            ])
×
NEW
80
                ->whereHas('user', function ($query) use ($excludedUserId) {  // Ensure user exists and is not excluded
×
NEW
81
                    $query->where('id', '!=', $excludedUserId);
×
NEW
82
                })
×
NEW
83
                ->whereHas('user.citizen', function ($query) {  // Ensure user has valid citizen data
×
NEW
84
                    $query->whereNotNull('avatar_link');
×
NEW
85
                })
×
NEW
86
                ->whereHas('user.profile', function ($query) {  // Additional filters for the profile
×
NEW
87
                    $query->where('tag', 'CT');
×
NEW
88
                })
×
NEW
89
                ->select('id', 'address', 'userid', 'tag', 'message', 'embedded_link', 'txid', 'blockid', 'mined', 'updated_at', 'created_at')  // Only select columns from the feed table
×
NEW
90
                ->orderByDesc('id')
×
NEW
91
                ->take($perPage)
×
NEW
92
                ->get();
×
NEW
93
        });
×
94

NEW
95
        return response()->json($feeds);
×
96
    }
97

NEW
98
    public function allApplicants()
×
99
    {
NEW
100
        $perPage = 25;
×
101

NEW
102
        $applicants = User::whereHas('profile', function ($query) {
×
NEW
103
            $query->where('has_application', 1);
×
NEW
104
        })
×
NEW
105
            ->where('id', '!=', 6462) // Exclude user with id 6462
×
NEW
106
            ->with(['profile', 'hdWallet' => function ($query) {
×
NEW
107
                $query->select('user_id', 'public_addr');
×
NEW
108
            }, 'citizen']) // Add citizen relationship
×
NEW
109
            ->orderByDesc('id')
×
NEW
110
            ->paginate($perPage, ['id', 'fullname']);
×
111

NEW
112
        $customResult = $applicants->getCollection()->transform(function ($user) {
×
NEW
113
            return [
×
NEW
114
                'userid' => $user->id,
×
NEW
115
                'fullname' => $user->fullname,
×
NEW
116
                'address' => $user->hdWallet ? $user->hdWallet->public_addr : null,
×
NEW
117
                'citizen' => $user->citizen, // Include citizen data
×
NEW
118
            ];
×
NEW
119
        });
×
120

NEW
121
        return response()->json([
×
NEW
122
            'current_page' => $applicants->currentPage(),
×
NEW
123
            'data' => $customResult,
×
NEW
124
            'total' => $applicants->total(),
×
NEW
125
            'per_page' => $applicants->perPage(),
×
NEW
126
            'last_page' => $applicants->lastPage(),
×
NEW
127
        ]);
×
128
    }
129

NEW
130
    public function allFeed(Request $request)
×
131
    {
NEW
132
        $perPage = 25;
×
NEW
133
        $page = $request->input('page', 1);
×
NEW
134
        $excludedUserIds = [6462, 7601];
×
NEW
135
        $cacheKey = 'all_feed_cache_'.$page;
×
136

NEW
137
        $feeds = Cache::remember($cacheKey, 60, function () use ($perPage, $excludedUserIds) {
×
NEW
138
            return Feed::with(['user' => function ($query) use ($excludedUserIds) {
×
NEW
139
                $query->select('id', 'fullname', 'created_at')
×
NEW
140
                    ->whereNotIn('id', $excludedUserIds);
×
NEW
141
            }, 'user.profile' => function ($query) {
×
NEW
142
                $query->select('userid', 'general_public', 'endorse_cnt', 'citizen', 'has_application');
×
NEW
143
            }, 'user.citizen' => function ($query) {
×
NEW
144
                $query->select('userid', 'avatar_link', 'liveness_link')
×
NEW
145
                    ->whereNotNull('avatar_link');
×
NEW
146
            }])
×
NEW
147
                ->whereHas('user', function ($query) use ($excludedUserIds) {
×
NEW
148
                    $query->whereNotIn('id', $excludedUserIds);
×
NEW
149
                })
×
NEW
150
                ->whereNotNull('mined')
×
NEW
151
                ->select(
×
NEW
152
                    'id',
×
NEW
153
                    'address',
×
NEW
154
                    'userid',
×
NEW
155
                    'tag',
×
NEW
156
                    'message',
×
NEW
157
                    'embedded_link',
×
NEW
158
                    'txid',
×
NEW
159
                    'blockid',
×
NEW
160
                    'mined',
×
NEW
161
                    'created_at',
×
NEW
162
                    'updated_at'
×
NEW
163
                )
×
NEW
164
                ->orderByDesc('mined')
×
NEW
165
                ->orderByDesc('id')
×
NEW
166
                ->paginate($perPage);
×
NEW
167
        });
×
168

NEW
169
        return $this->paginatedResponse($feeds);
×
170
    }
171

172
    // Helper method to format paginated responses consistently
NEW
173
    private function paginatedResponse($feeds)
×
174
    {
NEW
175
        return response()->json([
×
NEW
176
            'current_page' => $feeds->currentPage(),
×
NEW
177
            'data' => $feeds->items(),
×
NEW
178
            'first_page_url' => $feeds->url(1),
×
NEW
179
            'from' => $feeds->firstItem(),
×
NEW
180
            'last_page' => $feeds->lastPage(),
×
NEW
181
            'last_page_url' => $feeds->url($feeds->lastPage()),
×
NEW
182
            'next_page_url' => $feeds->nextPageUrl(),
×
NEW
183
            'path' => $feeds->path(),
×
NEW
184
            'per_page' => $feeds->perPage(),
×
NEW
185
            'prev_page_url' => $feeds->previousPageUrl(),
×
NEW
186
            'to' => $feeds->lastItem(),
×
NEW
187
            'total' => $feeds->total(),
×
NEW
188
        ]);
×
189
    }
190

NEW
191
    public function showCitizen(Request $request, $address)
×
192
    {
193
        // Look up the Martian user by public address
NEW
194
        $martianWallet = CivicWallet::where('public_addr', $address)->first();
×
195

NEW
196
        if (! $martianWallet) {
×
NEW
197
            return response()->json(['message' => 'Martian not found.'], 404);
×
198
        }
199

200
        // Attempt to fetch the user's profile and additional data
NEW
201
        $citizen = Citizen::where('public_address', $address)->first();
×
NEW
202
        $profile = Profile::where('userid', $martianWallet->user_id)->first();
×
NEW
203
        $feedItems = Feed::where('userid', $martianWallet->user_id)->whereNotNull('mined')->whereNotIn('tag', ['GP', 'CT'])->orderBy('created_at', 'desc')->get();
×
204

205
        // Fetch the latest 3 activities
NEW
206
        $activity = DB::table('feed')
×
NEW
207
            ->join('users', 'feed.userid', '=', 'users.id')
×
NEW
208
            ->join('profile', 'feed.userid', '=', 'profile.userid')
×
NEW
209
            ->select('profile.userid', 'users.fullname', 'feed.tag', 'feed.mined')
×
NEW
210
            ->where('feed.userid', $martianWallet->user_id)
×
NEW
211
            ->orderBy('feed.id', 'desc')
×
NEW
212
            ->get();
×
213

214
        // Construct response
NEW
215
        $response = [
×
NEW
216
            'citizen' => $citizen,
×
NEW
217
            'profile' => [
×
NEW
218
                'general_public' => $profile ? $profile->general_public : null,
×
NEW
219
                'isCitizen' => $profile ? $profile->citizen : null,
×
NEW
220
            ],
×
NEW
221
            'feedItems' => $feedItems,
×
NEW
222
            'activity' => $activity,
×
NEW
223
        ];
×
224

NEW
225
        return response()->json($response);
×
226
    }
227

228
    // token access
NEW
229
    public function scitizen(Request $request)
×
230
    {
231

NEW
232
        $uid = Auth::user()->id;
×
NEW
233
        $citcache = Citizen::where('userid', '=', $uid)->first();
×
NEW
234
        if (is_null($citcache)) {
×
NEW
235
            $citcache = new Citizen;
×
236
        }
NEW
237
        $citcache->userid = $uid;
×
238

NEW
239
        $firstname = $request->input('firstname');
×
NEW
240
        $lastname = $request->input('lastname');
×
NEW
241
        $shortbio = $request->input('shortbio');
×
NEW
242
        $displayname = $request->input('displayname');
×
243

NEW
244
        if (isset($firstname) && isset($lastname)) {
×
NEW
245
            $fullname = $firstname.' '.$lastname;
×
246

NEW
247
            $citcache->firstname = $firstname;
×
NEW
248
            $citcache->lastname = $lastname;
×
NEW
249
            $user = User::where('id', '=', $uid)->first();
×
NEW
250
            $user->fullname = $fullname;
×
NEW
251
            $user->save();
×
NEW
252
            $profile = Profile::where('userid', '=', $uid)->first();
×
NEW
253
            $profile->has_application = 1;
×
NEW
254
            $profile->save();
×
255
        }
NEW
256
        if (isset($shortbio)) {
×
NEW
257
            $citcache->shortbio = $shortbio;
×
NEW
258
            $profile = Profile::where('userid', '=', $uid)->first();
×
NEW
259
            $profile->has_application = 1;
×
NEW
260
            $profile->save();
×
261
        }
NEW
262
        if (isset($displayname)) {
×
NEW
263
            $citcache->displayname = $displayname;
×
NEW
264
            $profile = Profile::where('userid', '=', $uid)->first();
×
NEW
265
            $profile->has_application = 1;
×
NEW
266
            $profile->save();
×
267
        }
268

NEW
269
        $citcache->save();
×
270
        // Fetch profile data
NEW
271
        $profile = Profile::where('userid', '=', $uid)->first();
×
272

273
        // Merge citizen and profile data
NEW
274
        $response = [
×
NEW
275
            'citizen' => $citcache,
×
NEW
276
            'profile' => [
×
NEW
277
                'citizen' => $profile->citizen ?? null,
×
NEW
278
                'endorse_cnt' => $profile->endorse_cnt ?? null,
×
NEW
279
                'general_public' => $profile->general_public ?? null,
×
NEW
280
                'has_application' => $profile->has_application ?? null,
×
NEW
281
            ],
×
NEW
282
        ];
×
283

284
        // Return the merged data as a JSON response
NEW
285
        return response()->json($response);
×
286
    }
287
}
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