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
|
|
|
}
|