fedi-feed-router/app/Livewire/Channels.php

149 lines
5 KiB
PHP
Raw Normal View History

<?php
namespace App\Livewire;
use App\Actions\CreateChannelAction;
use App\Models\Language;
use App\Models\PlatformAccount;
use App\Models\PlatformChannel;
use App\Models\PlatformInstance;
use Illuminate\Contracts\View\View;
use Illuminate\Database\UniqueConstraintViolationException;
use Illuminate\Validation\Rule;
use Livewire\Component;
use RuntimeException;
class Channels extends Component
{
public ?int $managingChannelId = null;
public bool $showCreateModal = false;
public string $newName = '';
public ?int $newPlatformInstanceId = null;
public ?int $newLanguageId = null;
public string $newDescription = '';
public function toggle(int $channelId): void
{
$channel = PlatformChannel::findOrFail($channelId);
$channel->is_active = ! $channel->is_active;
$channel->save();
}
public function openCreateModal(): void
{
$this->reset(['newName', 'newPlatformInstanceId', 'newLanguageId', 'newDescription']);
$this->resetErrorBag();
$this->showCreateModal = true;
}
public function closeCreateModal(): void
{
$this->showCreateModal = false;
}
public function createChannel(CreateChannelAction $action): void
{
$this->validate([
// name doubles as the Lemmy community slug (used verbatim as channel_id for
// community lookup at publish time), so it must be lowercase slug format.
'newName' => [
'required',
'string',
'max:255',
'regex:/^[a-z0-9_]+$/',
Rule::unique('platform_channels', 'name')
->where('platform_instance_id', $this->newPlatformInstanceId),
],
'newPlatformInstanceId' => 'required|integer|exists:platform_instances,id',
'newLanguageId' => 'nullable|integer|exists:languages,id',
], [
'newName.regex' => 'The name must be a valid community slug (lowercase letters, numbers, and underscores only).',
'newName.unique' => 'A channel with this name already exists for this instance.',
]);
try {
$action->execute(
$this->newName,
$this->newPlatformInstanceId,
$this->newLanguageId,
// Blade textarea binds an empty string when blank; the action expects null for "no description".
$this->newDescription !== '' ? $this->newDescription : null,
);
} catch (UniqueConstraintViolationException $e) {
// Unreachable via this form (the unique rule above catches duplicates first),
// but the (platform_instance_id, channel_id) index can still fire if channel_id
// ever drifts from name. Surface it as a field error instead of a 500.
$this->addError('newName', 'A channel with this name already exists for this instance.');
return;
} catch (RuntimeException $e) {
$this->addError('newPlatformInstanceId', $e->getMessage());
return;
}
$this->closeCreateModal();
}
public function openAccountModal(int $channelId): void
{
$this->managingChannelId = $channelId;
}
public function closeAccountModal(): void
{
$this->managingChannelId = null;
}
public function attachAccount(int $accountId): void
{
if (! $this->managingChannelId) {
return;
}
$channel = PlatformChannel::findOrFail($this->managingChannelId);
if (! $channel->platformAccounts()->where('platform_account_id', $accountId)->exists()) {
$channel->platformAccounts()->attach($accountId, [
'is_active' => true,
'priority' => 1,
'created_at' => now(),
'updated_at' => now(),
]);
}
}
public function detachAccount(int $channelId, int $accountId): void
{
$channel = PlatformChannel::findOrFail($channelId);
$channel->platformAccounts()->detach($accountId);
}
public function render(): View
{
$channels = PlatformChannel::with(['platformInstance', 'platformAccounts'])->orderBy('name')->get();
$allAccounts = PlatformAccount::where('is_active', true)->get();
$managingChannel = $this->managingChannelId
? PlatformChannel::with('platformAccounts')->find($this->managingChannelId)
: null;
$availableAccounts = $managingChannel
? $allAccounts->filter(fn ($account) => ! $managingChannel->platformAccounts->contains('id', $account->id))
: collect();
return view('livewire.channels', [
'channels' => $channels,
'managingChannel' => $managingChannel,
'availableAccounts' => $availableAccounts,
'platformInstances' => PlatformInstance::where('is_active', true)->orderBy('name')->get(),
'languages' => Language::where('is_active', true)->orderBy('name')->get(),
])->layout('layouts.app');
}
}