fedi-feed-router/backend/app/Http/Controllers/Api/V1/PlatformChannelsController.php

381 lines
15 KiB
PHP
Raw Normal View History

2025-08-02 15:20:09 +02:00
<?php
namespace App\Http\Controllers\Api\V1;
2025-08-15 16:39:18 +02:00
use Domains\Platform\Resources\PlatformChannelResource;
use Domains\Platform\Models\PlatformChannel;
use Domains\Platform\Models\PlatformAccount;
2025-08-16 11:34:52 +02:00
use Domains\Platform\Models\PlatformInstance;
2025-08-16 09:00:46 +02:00
use Domains\Platform\Services\ChannelLanguageDetectionService;
2025-08-16 11:34:52 +02:00
use Domains\Platform\Api\Lemmy\LemmyApiService;
2025-08-16 09:00:46 +02:00
use Domains\Platform\Exceptions\ChannelException;
2025-08-02 15:20:09 +02:00
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
2025-08-16 11:34:52 +02:00
use Illuminate\Support\Facades\Cache;
2025-08-02 15:20:09 +02:00
class PlatformChannelsController extends BaseController
{
/**
* Display a listing of platform channels
*/
public function index(): JsonResponse
{
2025-08-10 01:26:56 +02:00
$channels = PlatformChannel::with(['platformInstance', 'platformAccounts'])
2025-08-02 15:20:09 +02:00
->orderBy('is_active', 'desc')
->orderBy('name')
->get();
return $this->sendResponse(
PlatformChannelResource::collection($channels),
'Platform channels retrieved successfully.'
);
}
/**
* Store a newly created platform channel
*/
public function store(Request $request): JsonResponse
{
try {
$validated = $request->validate([
'platform_instance_id' => 'required|exists:platform_instances,id',
'channel_id' => 'required|string|max:255',
'name' => 'required|string|max:255',
'display_name' => 'nullable|string|max:255',
'description' => 'nullable|string',
'is_active' => 'boolean',
]);
$validated['is_active'] = $validated['is_active'] ?? true;
2025-08-12 01:53:59 +02:00
// Get the platform instance to check for active accounts
2025-08-15 16:39:18 +02:00
$platformInstance = \Domains\Platform\Models\PlatformInstance::findOrFail($validated['platform_instance_id']);
2025-08-12 01:53:59 +02:00
// Check if there are active platform accounts for this instance
$activeAccounts = PlatformAccount::where('instance_url', $platformInstance->url)
->where('is_active', true)
->get();
if ($activeAccounts->isEmpty()) {
return $this->sendError(
'Cannot create channel: No active platform accounts found for this instance. Please create a platform account first.',
[],
422
);
}
2025-08-16 09:00:46 +02:00
// Detect and validate channel languages
$languageDetectionService = app(ChannelLanguageDetectionService::class);
try {
$languageInfo = $languageDetectionService->detectChannelLanguages(
$validated['name'],
$validated['platform_instance_id']
);
// Add detected language to validated data
$validated['language_id'] = $languageInfo['language_id'];
} catch (ChannelException $e) {
return $this->sendError($e->getMessage(), [], 422);
}
2025-08-02 15:20:09 +02:00
$channel = PlatformChannel::create($validated);
2025-08-12 01:53:59 +02:00
// Automatically attach the first active account to the channel
$firstAccount = $activeAccounts->first();
$channel->platformAccounts()->attach($firstAccount->id, [
'is_active' => true,
'priority' => 1,
'created_at' => now(),
'updated_at' => now(),
]);
2025-08-16 09:00:46 +02:00
$responseMessage = 'Platform channel created successfully and linked to platform account!';
// Add information about language detection if fallback was used
if (isset($languageInfo['fallback_used']) && $languageInfo['fallback_used']) {
$responseMessage .= ' Note: Used default language due to detection issue.';
}
2025-08-02 15:20:09 +02:00
return $this->sendResponse(
2025-08-16 09:00:46 +02:00
new PlatformChannelResource($channel->load(['platformInstance', 'platformAccounts', 'language'])),
$responseMessage,
2025-08-02 15:20:09 +02:00
201
);
} catch (ValidationException $e) {
return $this->sendValidationError($e->errors());
} catch (\Exception $e) {
return $this->sendError('Failed to create platform channel: ' . $e->getMessage(), [], 500);
}
}
/**
* Display the specified platform channel
*/
2025-08-05 21:53:49 +02:00
public function show(PlatformChannel $platformChannel): JsonResponse
2025-08-02 15:20:09 +02:00
{
return $this->sendResponse(
2025-08-05 21:53:49 +02:00
new PlatformChannelResource($platformChannel->load('platformInstance')),
2025-08-02 15:20:09 +02:00
'Platform channel retrieved successfully.'
);
}
/**
* Update the specified platform channel
*/
2025-08-05 21:53:49 +02:00
public function update(Request $request, PlatformChannel $platformChannel): JsonResponse
2025-08-02 15:20:09 +02:00
{
try {
$validated = $request->validate([
'name' => 'required|string|max:255',
'display_name' => 'nullable|string|max:255',
'description' => 'nullable|string',
'is_active' => 'boolean',
]);
2025-08-05 21:53:49 +02:00
$platformChannel->update($validated);
2025-08-02 15:20:09 +02:00
return $this->sendResponse(
2025-08-05 21:53:49 +02:00
new PlatformChannelResource($platformChannel->fresh(['platformInstance'])),
2025-08-02 15:20:09 +02:00
'Platform channel updated successfully!'
);
} catch (ValidationException $e) {
return $this->sendValidationError($e->errors());
} catch (\Exception $e) {
return $this->sendError('Failed to update platform channel: ' . $e->getMessage(), [], 500);
}
}
/**
* Remove the specified platform channel
*/
2025-08-05 21:53:49 +02:00
public function destroy(PlatformChannel $platformChannel): JsonResponse
2025-08-02 15:20:09 +02:00
{
try {
2025-08-05 21:53:49 +02:00
$platformChannel->delete();
2025-08-02 15:20:09 +02:00
return $this->sendResponse(
null,
'Platform channel deleted successfully!'
);
} catch (\Exception $e) {
return $this->sendError('Failed to delete platform channel: ' . $e->getMessage(), [], 500);
}
}
/**
* Toggle platform channel active status
*/
public function toggle(PlatformChannel $channel): JsonResponse
{
try {
$newStatus = !$channel->is_active;
$channel->update(['is_active' => $newStatus]);
$status = $newStatus ? 'activated' : 'deactivated';
return $this->sendResponse(
2025-08-10 01:26:56 +02:00
new PlatformChannelResource($channel->fresh(['platformInstance', 'platformAccounts'])),
2025-08-02 15:20:09 +02:00
"Platform channel {$status} successfully!"
);
} catch (\Exception $e) {
return $this->sendError('Failed to toggle platform channel status: ' . $e->getMessage(), [], 500);
}
}
2025-08-10 01:26:56 +02:00
/**
* Attach a platform account to a channel
*/
public function attachAccount(PlatformChannel $channel, Request $request): JsonResponse
{
try {
$validated = $request->validate([
'platform_account_id' => 'required|exists:platform_accounts,id',
'is_active' => 'boolean',
'priority' => 'nullable|integer|min:1|max:100',
]);
$platformAccount = PlatformAccount::findOrFail($validated['platform_account_id']);
// Check if account is already attached
if ($channel->platformAccounts()->where('platform_account_id', $platformAccount->id)->exists()) {
return $this->sendError('Platform account is already attached to this channel.', [], 422);
}
$channel->platformAccounts()->attach($platformAccount->id, [
'is_active' => $validated['is_active'] ?? true,
'priority' => $validated['priority'] ?? 1,
'created_at' => now(),
'updated_at' => now(),
]);
return $this->sendResponse(
new PlatformChannelResource($channel->fresh(['platformInstance', 'platformAccounts'])),
'Platform account attached to channel successfully!'
);
} catch (ValidationException $e) {
return $this->sendValidationError($e->errors());
} catch (\Exception $e) {
return $this->sendError('Failed to attach platform account: ' . $e->getMessage(), [], 500);
}
}
/**
* Detach a platform account from a channel
*/
public function detachAccount(PlatformChannel $channel, PlatformAccount $account): JsonResponse
{
try {
if (!$channel->platformAccounts()->where('platform_account_id', $account->id)->exists()) {
return $this->sendError('Platform account is not attached to this channel.', [], 422);
}
$channel->platformAccounts()->detach($account->id);
return $this->sendResponse(
new PlatformChannelResource($channel->fresh(['platformInstance', 'platformAccounts'])),
'Platform account detached from channel successfully!'
);
} catch (\Exception $e) {
return $this->sendError('Failed to detach platform account: ' . $e->getMessage(), [], 500);
}
}
/**
* Update platform account-channel relationship settings
*/
public function updateAccountRelation(PlatformChannel $channel, PlatformAccount $account, Request $request): JsonResponse
{
try {
$validated = $request->validate([
'is_active' => 'boolean',
'priority' => 'nullable|integer|min:1|max:100',
]);
if (!$channel->platformAccounts()->where('platform_account_id', $account->id)->exists()) {
return $this->sendError('Platform account is not attached to this channel.', [], 422);
}
$channel->platformAccounts()->updateExistingPivot($account->id, [
'is_active' => $validated['is_active'] ?? true,
'priority' => $validated['priority'] ?? 1,
'updated_at' => now(),
]);
return $this->sendResponse(
new PlatformChannelResource($channel->fresh(['platformInstance', 'platformAccounts'])),
'Platform account-channel relationship updated successfully!'
);
} catch (ValidationException $e) {
return $this->sendValidationError($e->errors());
} catch (\Exception $e) {
return $this->sendError('Failed to update platform account relationship: ' . $e->getMessage(), [], 500);
}
}
2025-08-16 11:34:52 +02:00
/**
* Get available communities for a platform instance
*/
public function getCommunities(Request $request): JsonResponse
{
try {
$validated = $request->validate([
'platform_instance_id' => 'required|exists:platform_instances,id',
'type' => 'sometimes|string|in:Local,All,Subscribed',
'sort' => 'sometimes|string|in:Hot,Active,New,TopDay,TopWeek,TopMonth,TopYear,TopAll',
'limit' => 'sometimes|integer|min:1|max:100',
'page' => 'sometimes|integer|min:1',
'show_nsfw' => 'sometimes|boolean',
]);
$platformInstance = PlatformInstance::findOrFail($validated['platform_instance_id']);
// Check if there are active platform accounts for this instance to get auth token
$activeAccount = PlatformAccount::where('instance_url', $platformInstance->url)
->where('is_active', true)
->first();
if (!$activeAccount) {
return $this->sendError(
'Cannot fetch communities: No active platform accounts found for this instance. Please create a platform account first.',
[],
422
);
}
// Create cache key based on instance and parameters
$cacheKey = sprintf(
'communities:%s:%s:%s:%d:%d:%s',
$platformInstance->id,
$validated['type'] ?? 'Local',
$validated['sort'] ?? 'Active',
$validated['limit'] ?? 50,
$validated['page'] ?? 1,
$validated['show_nsfw'] ?? false ? '1' : '0'
);
// Try to get communities from cache first (cache for 10 minutes)
$communities = Cache::remember($cacheKey, 600, function () use ($platformInstance, $activeAccount, $validated) {
$apiService = app(LemmyApiService::class, ['instance' => $platformInstance->url]);
return $apiService->listCommunities(
$activeAccount->settings['api_token'] ?? null,
$validated['type'] ?? 'Local',
$validated['sort'] ?? 'Active',
$validated['limit'] ?? 50,
$validated['page'] ?? 1,
$validated['show_nsfw'] ?? false
);
});
// Transform the response to include only relevant data and add helpful fields
$transformedCommunities = collect($communities['communities'] ?? [])->map(function ($item) {
$community = $item['community'] ?? [];
return [
'id' => $community['id'] ?? null,
'name' => $community['name'] ?? null,
'title' => $community['title'] ?? null,
'description' => $community['description'] ?? null,
'nsfw' => $community['nsfw'] ?? false,
'local' => $community['local'] ?? false,
'subscribers' => $item['counts']['subscribers'] ?? 0,
'posts' => $item['counts']['posts'] ?? 0,
'display_text' => sprintf(
'%s (%s subscribers)',
$community['title'] ?? $community['name'] ?? 'Unknown',
number_format($item['counts']['subscribers'] ?? 0)
),
];
});
return $this->sendResponse([
'communities' => $transformedCommunities,
'total' => $transformedCommunities->count(),
'platform_instance' => [
'id' => $platformInstance->id,
'name' => $platformInstance->name,
'url' => $platformInstance->url,
],
'parameters' => [
'type' => $validated['type'] ?? 'Local',
'sort' => $validated['sort'] ?? 'Active',
'limit' => $validated['limit'] ?? 50,
'page' => $validated['page'] ?? 1,
'show_nsfw' => $validated['show_nsfw'] ?? false,
]
], 'Communities retrieved successfully.');
} catch (ValidationException $e) {
return $this->sendValidationError($e->errors());
} catch (\Exception $e) {
// Clear cache on error to prevent serving stale data
if (isset($cacheKey)) {
Cache::forget($cacheKey);
}
return $this->sendError('Failed to fetch communities: ' . $e->getMessage(), [], 500);
}
}
2025-08-02 15:20:09 +02:00
}