Optimizations + fix failing tests

This commit is contained in:
myrmidex 2025-08-06 20:01:28 +02:00
parent 5a142d2a3c
commit 4412974cfb
7 changed files with 81 additions and 31 deletions

View file

@ -17,14 +17,25 @@ class FeedsController extends BaseController
*/ */
public function index(Request $request): JsonResponse public function index(Request $request): JsonResponse
{ {
$feeds = Feed::orderBy('is_active', 'desc') $perPage = min($request->get('per_page', 15), 100);
->orderBy('name')
->get();
return $this->sendResponse( $feeds = Feed::with(['language'])
FeedResource::collection($feeds), ->withCount('articles')
'Feeds retrieved successfully.' ->orderBy('is_active', 'desc')
); ->orderBy('name')
->paginate($perPage);
return $this->sendResponse([
'feeds' => FeedResource::collection($feeds->items()),
'pagination' => [
'current_page' => $feeds->currentPage(),
'last_page' => $feeds->lastPage(),
'per_page' => $feeds->perPage(),
'total' => $feeds->total(),
'from' => $feeds->firstItem(),
'to' => $feeds->lastItem(),
]
], 'Feeds retrieved successfully.');
} }
/** /**

View file

@ -63,15 +63,14 @@ public function store(Request $request): JsonResponse
*/ */
public function show(Feed $feed, PlatformChannel $channel): JsonResponse public function show(Feed $feed, PlatformChannel $channel): JsonResponse
{ {
$route = Route::where('feed_id', $feed->id) $route = $this->findRoute($feed, $channel);
->where('platform_channel_id', $channel->id)
->with(['feed', 'platformChannel'])
->first();
if (!$route) { if (!$route) {
return $this->sendNotFound('Routing configuration not found.'); return $this->sendNotFound('Routing configuration not found.');
} }
$route->load(['feed', 'platformChannel']);
return $this->sendResponse( return $this->sendResponse(
new RouteResource($route), new RouteResource($route),
'Routing configuration retrieved successfully.' 'Routing configuration retrieved successfully.'
@ -84,9 +83,7 @@ public function show(Feed $feed, PlatformChannel $channel): JsonResponse
public function update(Request $request, Feed $feed, PlatformChannel $channel): JsonResponse public function update(Request $request, Feed $feed, PlatformChannel $channel): JsonResponse
{ {
try { try {
$route = Route::where('feed_id', $feed->id) $route = $this->findRoute($feed, $channel);
->where('platform_channel_id', $channel->id)
->first();
if (!$route) { if (!$route) {
return $this->sendNotFound('Routing configuration not found.'); return $this->sendNotFound('Routing configuration not found.');
@ -118,9 +115,7 @@ public function update(Request $request, Feed $feed, PlatformChannel $channel):
public function destroy(Feed $feed, PlatformChannel $channel): JsonResponse public function destroy(Feed $feed, PlatformChannel $channel): JsonResponse
{ {
try { try {
$route = Route::where('feed_id', $feed->id) $route = $this->findRoute($feed, $channel);
->where('platform_channel_id', $channel->id)
->first();
if (!$route) { if (!$route) {
return $this->sendNotFound('Routing configuration not found.'); return $this->sendNotFound('Routing configuration not found.');
@ -145,9 +140,7 @@ public function destroy(Feed $feed, PlatformChannel $channel): JsonResponse
public function toggle(Feed $feed, PlatformChannel $channel): JsonResponse public function toggle(Feed $feed, PlatformChannel $channel): JsonResponse
{ {
try { try {
$route = Route::where('feed_id', $feed->id) $route = $this->findRoute($feed, $channel);
->where('platform_channel_id', $channel->id)
->first();
if (!$route) { if (!$route) {
return $this->sendNotFound('Routing configuration not found.'); return $this->sendNotFound('Routing configuration not found.');
@ -168,4 +161,14 @@ public function toggle(Feed $feed, PlatformChannel $channel): JsonResponse
return $this->sendError('Failed to toggle routing configuration status: ' . $e->getMessage(), [], 500); return $this->sendError('Failed to toggle routing configuration status: ' . $e->getMessage(), [], 500);
} }
} }
/**
* Find a route by feed and channel
*/
private function findRoute(Feed $feed, PlatformChannel $channel): ?Route
{
return Route::where('feed_id', $feed->id)
->where('platform_channel_id', $channel->id)
->first();
}
} }

View file

@ -23,9 +23,10 @@ public function toArray(Request $request): array
'description' => $this->description, 'description' => $this->description,
'created_at' => $this->created_at->toISOString(), 'created_at' => $this->created_at->toISOString(),
'updated_at' => $this->updated_at->toISOString(), 'updated_at' => $this->updated_at->toISOString(),
'articles_count' => $this->when($request->routeIs('api.feeds.*'), function () { 'articles_count' => $this->when(
return $this->articles()->count(); $request->routeIs('api.feeds.*') && isset($this->articles_count),
}), $this->articles_count
),
]; ];
} }
} }

View file

@ -5,6 +5,7 @@
use App\Models\Article; use App\Models\Article;
use App\Models\ArticlePublication; use App\Models\ArticlePublication;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class DashboardStatsService class DashboardStatsService
{ {
@ -76,13 +77,35 @@ private function getDateRange(string $period): ?array
*/ */
public function getSystemStats(): array public function getSystemStats(): array
{ {
// Optimize with single queries using conditional aggregation
$feedStats = DB::table('feeds')
->selectRaw('
COUNT(*) as total_feeds,
SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) as active_feeds
')
->first();
$channelStats = DB::table('platform_channels')
->selectRaw('
COUNT(*) as total_channels,
SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) as active_channels
')
->first();
$routeStats = DB::table('routes')
->selectRaw('
COUNT(*) as total_routes,
SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) as active_routes
')
->first();
return [ return [
'total_feeds' => \App\Models\Feed::count(), 'total_feeds' => $feedStats->total_feeds,
'active_feeds' => \App\Models\Feed::where('is_active', true)->count(), 'active_feeds' => $feedStats->active_feeds,
'total_channels' => \App\Models\PlatformChannel::count(), 'total_channels' => $channelStats->total_channels,
'active_channels' => \App\Models\PlatformChannel::where('is_active', true)->count(), 'active_channels' => $channelStats->active_channels,
'total_routes' => \App\Models\Route::count(), 'total_routes' => $routeStats->total_routes,
'active_routes' => \App\Models\Route::where('is_active', true)->count(), 'active_routes' => $routeStats->active_routes,
]; ];
} }
} }

View file

@ -17,6 +17,12 @@ public function up(): void
$table->boolean('is_duplicate')->default(false); $table->boolean('is_duplicate')->default(false);
$table->timestamp('validated_at')->nullable(); $table->timestamp('validated_at')->nullable();
$table->timestamps(); $table->timestamps();
$table->index('url');
$table->index('is_valid');
$table->index('validated_at');
$table->index('created_at');
$table->index(['is_valid', 'created_at']);
}); });
} }

View file

@ -17,6 +17,9 @@ public function up(): void
->after('is_duplicate'); ->after('is_duplicate');
$table->timestamp('approved_at')->nullable()->after('approval_status'); $table->timestamp('approved_at')->nullable()->after('approval_status');
$table->string('approved_by')->nullable()->after('approved_at'); $table->string('approved_by')->nullable()->after('approved_at');
$table->index('approval_status');
$table->index(['is_valid', 'approval_status']);
}); });
} }

View file

@ -18,7 +18,10 @@ public function test_index_returns_successful_response(): void
$response->assertStatus(200) $response->assertStatus(200)
->assertJsonStructure([ ->assertJsonStructure([
'success', 'success',
'data', 'data' => [
'feeds',
'pagination'
],
'message' 'message'
]); ]);
} }
@ -32,7 +35,7 @@ public function test_index_returns_feeds_ordered_by_active_status_then_name(): v
$response = $this->getJson('/api/v1/feeds'); $response = $this->getJson('/api/v1/feeds');
$response->assertStatus(200); $response->assertStatus(200);
$feeds = $response->json('data'); $feeds = $response->json('data.feeds');
// First should be active feeds in alphabetical order // First should be active feeds in alphabetical order
$this->assertEquals('A Feed', $feeds[0]['name']); $this->assertEquals('A Feed', $feeds[0]['name']);