fedi-feed-router/app/Http/Controllers/RoutingController.php

169 lines
5 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Feed;
use App\Models\FeedPlatformChannel;
use App\Models\PlatformChannel;
use App\Services\RoutingValidationService;
use App\Exceptions\RoutingMismatchException;
use Illuminate\Http\Request;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
class RoutingController extends Controller
{
public function index(): View
{
$feeds = Feed::with(['channels.platformInstance'])
->where('is_active', true)
->orderBy('name')
->get();
$channels = PlatformChannel::with(['platformInstance', 'feeds'])
->where('is_active', true)
->orderBy('name')
->get();
return view('pages.routing.index', compact('feeds', 'channels'));
}
public function create(): View
{
$feeds = Feed::where('is_active', true)
->orderBy('name')
->get();
$channels = PlatformChannel::with('platformInstance')
->where('is_active', true)
->orderBy('name')
->get();
return view('pages.routing.create', compact('feeds', 'channels'));
}
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'feed_id' => 'required|exists:feeds,id',
'channel_ids' => 'required|array|min:1',
'channel_ids.*' => 'exists:platform_channels,id',
'priority' => 'integer|min:0|max:100',
'filters' => 'nullable|string'
]);
$feed = Feed::findOrFail($validated['feed_id']);
$channels = PlatformChannel::findMany($validated['channel_ids']);
$priority = $validated['priority'] ?? 0;
try {
app(RoutingValidationService::class)->validateLanguageCompatibility($feed, $channels);
} catch (RoutingMismatchException $e) {
return redirect()->back()
->withInput()
->withErrors(['language' => $e->getMessage()]);
}
$filters = $this->parseJsonFilters($validated['filters'] ?? null);
// Attach channels to feed
$syncData = [];
foreach ($validated['channel_ids'] as $channelId) {
$syncData[$channelId] = [
'is_active' => true,
'priority' => $priority,
'filters' => $filters,
'created_at' => now(),
'updated_at' => now()
];
}
$feed->channels()->syncWithoutDetaching($syncData);
return redirect()->route('routing.index')
->with('success', 'Feed routing created successfully!');
}
public function edit(Feed $feed, PlatformChannel $channel): View
{
$routing = $feed->channels()
->wherePivot('platform_channel_id', $channel->id)
->first();
if (! $routing) {
abort(404, 'Routing not found');
}
return view('pages.routing.edit', compact('feed', 'channel', 'routing'));
}
public function update(Request $request, Feed $feed, PlatformChannel $channel): RedirectResponse
{
$validated = $request->validate([
'is_active' => 'boolean',
'priority' => 'integer|min:0|max:100',
'filters' => 'nullable|string'
]);
$filters = $this->parseJsonFilters($validated['filters'] ?? null);
$feed->channels()->updateExistingPivot($channel->id, [
'is_active' => $validated['is_active'] ?? true,
'priority' => $validated['priority'] ?? 0,
'filters' => $filters,
'updated_at' => now()
]);
return redirect()->route('routing.index')
->with('success', 'Routing updated successfully!');
}
public function destroy(Feed $feed, PlatformChannel $channel): RedirectResponse
{
$feed->channels()->detach($channel->id);
return redirect()->route('routing.index')
->with('success', 'Routing deleted successfully!');
}
public function toggle(Request $request, Feed $feed, PlatformChannel $channel): RedirectResponse
{
$routing = FeedPlatformChannel::where('feed_id', $feed->id)
->where('platform_channel_id', $channel->id)
->first();
if (! $routing) {
abort(404, 'Routing not found');
}
$newStatus = ! $routing->is_active;
$feed->channels()->updateExistingPivot($channel->id, [
'is_active' => $newStatus,
'updated_at' => now()
]);
$status = $newStatus ? 'activated' : 'deactivated';
return redirect()->route('routing.index')
->with('success', "Routing {$status} successfully!");
}
/**
* @return array<string, mixed>|null
*/
private function parseJsonFilters(?string $json): ?array
{
if (empty($json)) {
return null;
}
$decoded = json_decode($json, true);
if (json_last_error() === JSON_ERROR_NONE) {
return $decoded;
}
return null;
}
}