From 5d00f2e69b8f0f4d7f3ae278d51d2561ab82d93e Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Sun, 20 Sep 2026 02:28:43 -0600 Subject: [PATCH] More dusting (cleanup + lint) --- app/Http/Controllers/SeasonalController.php | 249 -------------------- app/Models/Group.php | 2 +- routes/web-api.php | 3 - tests/Feature/SeasonalAggregationTest.php | 81 ------- 4 files changed, 1 insertion(+), 334 deletions(-) delete mode 100644 app/Http/Controllers/SeasonalController.php delete mode 100644 tests/Feature/SeasonalAggregationTest.php diff --git a/app/Http/Controllers/SeasonalController.php b/app/Http/Controllers/SeasonalController.php deleted file mode 100644 index 237581737..000000000 --- a/app/Http/Controllers/SeasonalController.php +++ /dev/null @@ -1,249 +0,0 @@ -middleware('auth'); - } - - public function yearInReview(): View - { - abort_if(now()->gt('2021-03-01 00:00:00'), 404); - abort_if(! db_is_mysql_maria(), 404); - - $profile = Auth::user()->profile; - - return view('account.yir', ['profile' => $profile]); - } - - public function getData(Request $request): JsonResponse - { - abort_if(now()->gt('2021-03-01 00:00:00'), 404); - abort_if(! db_is_mysql_maria(), 404); - - $uid = $request->user()->id; - $pid = $request->user()->profile_id; - $epoch = '2020-01-01 00:00:00'; - $epochStart = '2020-01-01 00:00:00'; - $epochEnd = '2020-12-31 23:59:59'; - - $siteKey = 'seasonal:my2020:shared'; - $siteTtl = now()->addMonths(3); - $userKey = 'seasonal:my2020:user:'.$uid; - $userTtl = now()->addMonths(3); - - $shared = Cache::remember($siteKey, $siteTtl, function () use ($epochStart, $epochEnd) { - return [ - 'average' => [ - 'posts' => round((float) DB::query()->fromSub( - Status::query() - ->whereNull('uri') - ->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album']) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->groupBy('profile_id') - ->selectRaw('count(*) as count'), - 'per_profile' - )->avg('count')), - - 'likes' => round((float) DB::query()->fromSub( - Like::query() - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->groupBy('profile_id') - ->selectRaw('count(*) as count'), - 'per_profile' - )->avg('count')), - ], - - 'popular' => [ - - 'hashtag' => StatusHashtag::selectRaw('*,count(hashtag_id) as count') - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->groupBy('hashtag_id') - ->orderByDesc('count') - ->take(1) - ->get() - ->map(function ($sh) { - return [ - 'name' => $sh->hashtag->name, - 'count' => $sh->count, - ]; - }) - ->first(), - - 'post' => Status::whereScope('public') - ->where('likes_count', '>', 1) - ->whereIsNsfw(false) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->orderByDesc('likes_count') - ->take(1) - ->get() - ->map(function ($status) { - return [ - 'id' => (string) $status->id, - 'username' => (string) $status->profile->username, - 'created_at' => $status->created_at->format('M d, Y'), - 'type' => $status->type, - 'url' => $status->url(), - 'thumb' => $status->thumb(), - 'likes_count' => $status->likes_count, - 'reblogs_count' => $status->reblogs_count, - 'reply_count' => $status->reply_count ?? 0, - ]; - }) - ->first(), - - 'places' => Status::selectRaw('*, count(place_id) as count') - ->whereNotNull('place_id') - ->having('count', '>', 1) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->groupBy('place_id') - ->orderByDesc('count') - ->take(1) - ->get() - ->map(function ($sh) { - return [ - 'name' => $sh->place->getName(), - 'url' => $sh->place->url(), - 'count' => $sh->count, - ]; - }) - ->first(), - ], - - ]; - }); - - $res = Cache::remember($userKey, $userTtl, function () use ($pid, $epochStart, $epochEnd, $request) { - return [ - 'account' => [ - 'user_id' => $request->user()->id, - 'created_at' => $request->user()->created_at->format('M d, Y'), - 'created_this_year' => $request->user()->created_at->gt('2020-01-01 00:00:00'), - 'created_months_ago' => $request->user()->created_at->diffInMonths(now()), - 'followers_this_year' => Follower::whereFollowingId($pid) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->count(), - 'followed_this_year' => Follower::whereProfileId($pid) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->count(), - 'most_popular' => Status::whereProfileId($pid) - ->where('likes_count', '>', 1) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->orderByDesc('likes_count') - ->take(1) - ->get() - ->map(function ($status) { - return [ - 'id' => (string) $status->id, - 'username' => (string) $status->profile->username, - 'created_at' => $status->created_at->format('M d, Y'), - 'type' => $status->type, - 'url' => $status->url(), - 'thumb' => $status->thumb(), - 'likes_count' => $status->likes_count, - 'reblogs_count' => $status->reblogs_count, - 'reply_count' => $status->reply_count ?? 0, - ]; - }) - ->first(), - 'posts_count' => Status::whereProfileId($pid) - ->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album']) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->count(), - 'likes_count' => Like::whereProfileId($pid) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->count(), - 'hashtag' => StatusHashtag::selectRaw('*, count(hashtag_id) as count') - ->whereProfileId($pid) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->groupBy('profile_id') - ->orderByDesc('count') - ->take(1) - ->get() - ->map(function ($sh) { - return [ - 'name' => $sh->hashtag->name, - 'count' => $sh->count, - ]; - }) - ->first(), - 'places' => Status::selectRaw('*, count(place_id) as count') - ->whereNotNull('place_id') - ->having('count', '>', 1) - ->whereProfileId($pid) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->groupBy('place_id') - ->orderByDesc('count') - ->take(1) - ->get() - ->map(function ($sh) { - return [ - 'name' => $sh->place->getName(), - 'url' => $sh->place->url(), - 'count' => $sh->count, - ]; - }) - ->first(), - 'places_total' => Status::whereProfileId($pid) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->whereNotNull('place_id') - ->count(), - ], - ]; - }); - - return response()->json(array_merge($res, $shared)); - } - - public function store(Request $request): JsonResponse - { - abort_if(now()->gt('2021-03-01 00:00:00'), 404); - abort_if(! db_is_mysql_maria(), 404); - - $user = $request->user(); - - $log = AccountLog::firstOrCreate([ - [ - 'item_type' => User::class, - 'item_id' => $user->id, - 'user_id' => $user->id, - 'action' => 'seasonal.my2020.view', - ], - [ - 'ip_address' => $request->ip(), - 'user_agent' => $request->userAgent(), - ], - ]); - - return response()->json(200); - } -} diff --git a/app/Models/Group.php b/app/Models/Group.php index e412d78b3..b14d53daf 100644 --- a/app/Models/Group.php +++ b/app/Models/Group.php @@ -126,7 +126,7 @@ class Group extends Model public function getMembershipType(): string { - return $this->is_private ? 'private' : ($this->is_local ? 'local' : 'all'); + return $this->is_private ? 'private' : ($this->local ? 'local' : 'all'); } public function selfRole($id = false) diff --git a/routes/web-api.php b/routes/web-api.php index 4a62656a1..615c16f5e 100644 --- a/routes/web-api.php +++ b/routes/web-api.php @@ -18,7 +18,6 @@ use App\Http\Controllers\PortfolioController; use App\Http\Controllers\ProfileSponsorController; use App\Http\Controllers\PublicApiController; use App\Http\Controllers\SearchController; -use App\Http\Controllers\SeasonalController; use App\Http\Controllers\SoftwareUpdateController; use App\Http\Controllers\SpaController; use App\Http\Controllers\StatusController; @@ -119,8 +118,6 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['localization'])->grou Route::get('discover/posts/trending', [DiscoverController::class, 'trendingApi']); Route::get('discover/posts/hashtags', [DiscoverController::class, 'trendingHashtags']); Route::get('discover/posts/places', [DiscoverController::class, 'trendingPlaces']); - Route::get('seasonal/yir', [SeasonalController::class, 'getData']); - Route::post('seasonal/yir', [SeasonalController::class, 'store']); Route::get('mutes', [AccountController::class, 'accountMutesV2']); Route::get('blocks', [AccountController::class, 'accountBlocksV2']); Route::get('filters', [AccountController::class, 'accountFiltersV2']); diff --git a/tests/Feature/SeasonalAggregationTest.php b/tests/Feature/SeasonalAggregationTest.php deleted file mode 100644 index 6df137e17..000000000 --- a/tests/Feature/SeasonalAggregationTest.php +++ /dev/null @@ -1,81 +0,0 @@ -pluck('count')->avg(). This verifies the SQL-side replacement: -| AVG over a subquery of per-profile counts returns the same value -| without materialising every group in memory. -| -*/ - -/** - * Mirrors the aggregation used in SeasonalController::getData for - * average posts per profile. - */ -function averagePostsPerProfile(string $epochStart, string $epochEnd): float -{ - return (float) DB::query()->fromSub( - Status::query() - ->whereNull('uri') - ->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album']) - ->where('created_at', '>', $epochStart) - ->where('created_at', '<', $epochEnd) - ->groupBy('profile_id') - ->selectRaw('count(*) as count'), - 'per_profile' - )->avg('count'); -} - -it('averages matching posts per profile in sql', function () { - $epochStart = '2020-01-01 00:00:00'; - $epochEnd = '2020-12-31 23:59:59'; - $inRange = '2020-06-01 12:00:00'; - - // Profile 1: 2 matching photos. Profile 2: 4 matching photos. - // Average per profile = 3. - Status::factory()->count(2)->photo()->create([ - 'profile_id' => 1001, - 'created_at' => $inRange, - ]); - Status::factory()->count(4)->photo()->create([ - 'profile_id' => 1002, - 'created_at' => $inRange, - ]); - - // Noise that must be excluded from the average: - // remote (uri set), wrong type, and out-of-range date. - Status::factory()->photo()->create([ - 'profile_id' => 1003, - 'uri' => 'https://remote.example/statuses/1', - 'created_at' => $inRange, - ]); - Status::factory()->create([ - 'profile_id' => 1003, - 'type' => 'text', - 'created_at' => $inRange, - ]); - Status::factory()->photo()->create([ - 'profile_id' => 1004, - 'created_at' => '2019-01-01 00:00:00', - ]); - - expect(averagePostsPerProfile($epochStart, $epochEnd))->toBe(3.0); -}); - -it('returns zero when no posts match', function () { - $average = averagePostsPerProfile('2020-01-01 00:00:00', '2020-12-31 23:59:59'); - - // No rows -> AVG returns null -> cast to 0.0 - expect($average)->toBe(0.0); -});