mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 01:24:46 +02:00
clean: remove discord thread features (#1191)
This commit is contained in:
@@ -1,72 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Discord;
|
||||
|
||||
use App\Actions\ActionResult;
|
||||
use App\Enums\Actions\ActionStatus;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Wiki\Anime;
|
||||
use Exception;
|
||||
use Illuminate\Http\Client\PendingRequest;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class DiscordThreadAction
|
||||
{
|
||||
/**
|
||||
* Get the HTTP client for Discord API.
|
||||
*/
|
||||
public static function getHttp(): PendingRequest
|
||||
{
|
||||
return Http::withHeaders(['x-api-key' => Config::get('services.discord.api_key')])
|
||||
->baseUrl(Config::get('services.discord.api_url'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $fields
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(Anime $anime, array $fields): ActionResult
|
||||
{
|
||||
try {
|
||||
$response = static::getHttp()
|
||||
->acceptJson()
|
||||
->post('/thread', ['name' => Arr::get($fields, 'name'), 'slug' => $anime->slug])
|
||||
->throw()
|
||||
->json();
|
||||
|
||||
if (Arr::has($response, 'id')) {
|
||||
DiscordThread::query()->create([
|
||||
DiscordThread::ATTRIBUTE_NAME => Arr::get($response, 'name'),
|
||||
DiscordThread::ATTRIBUTE_ID => intval(Arr::get($response, 'id')),
|
||||
DiscordThread::ATTRIBUTE_ANIME => $anime->getKey(),
|
||||
]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return new ActionResult(ActionStatus::PASSED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the thread by ID.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function get(string $id): array
|
||||
{
|
||||
return static::getHttp()
|
||||
->acceptJson()
|
||||
->get('/thread', ['id' => $id])
|
||||
->throw()
|
||||
->json();
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,23 @@ use App\Actions\ActionResult;
|
||||
use App\Enums\Actions\ActionStatus;
|
||||
use App\Enums\Actions\Models\Wiki\Video\DiscordNotificationType;
|
||||
use App\Models\Wiki\Video;
|
||||
use Illuminate\Http\Client\PendingRequest;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class DiscordVideoNotificationAction
|
||||
{
|
||||
/**
|
||||
* Get the HTTP client for Discord API.
|
||||
*/
|
||||
public static function getHttp(): PendingRequest
|
||||
{
|
||||
return Http::withHeaders(['x-api-key' => Config::get('services.discord.api_key')])
|
||||
->baseUrl(Config::get('services.discord.api_url'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, Video> $videos
|
||||
* @param array<string, mixed> $fields
|
||||
@@ -22,37 +33,10 @@ class DiscordVideoNotificationAction
|
||||
{
|
||||
$type = Arr::get($fields, DiscordNotificationType::getFieldKey());
|
||||
|
||||
$newVideos = [];
|
||||
|
||||
foreach ($videos as $video) {
|
||||
$video
|
||||
->load([
|
||||
'animethemeentries.animetheme.anime.discordthread',
|
||||
]);
|
||||
|
||||
$anime = $video->animethemeentries->first()->animetheme->anime;
|
||||
|
||||
if ($anime->discordthread === null) {
|
||||
if (Str::length($anime->name) >= 100) {
|
||||
$anime->name = Str::limit($anime->name, 96, '...');
|
||||
}
|
||||
|
||||
$threadAction = new DiscordThreadAction();
|
||||
|
||||
$threadAction->handle($anime, ['name' => $anime->getName()]);
|
||||
$anime->load('discordthread');
|
||||
}
|
||||
|
||||
$newVideos[] = [
|
||||
'threadId' => $anime->discordthread->getKey(),
|
||||
'videoId' => $video->getKey(),
|
||||
];
|
||||
}
|
||||
|
||||
DiscordThreadAction::getHttp()
|
||||
static::getHttp()
|
||||
->post('/notification', [
|
||||
'type' => $type->value,
|
||||
'videos' => $newVideos,
|
||||
'videos' => $videos->map(fn (Video $video): array => ['videoId' => $video->getKey()])->toArray(),
|
||||
])
|
||||
->throw();
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Storage\Admin\Dump;
|
||||
|
||||
use App\Concerns\Repositories\Admin\ReconcilesDumpRepositories;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DumpDiscordAction extends DumpAction
|
||||
{
|
||||
use ReconcilesDumpRepositories;
|
||||
|
||||
final public const string FILENAME_PREFIX = 'animethemes-db-dump-discord-';
|
||||
|
||||
/**
|
||||
* The list of tables to include in the dump.
|
||||
*/
|
||||
public static function allowedTables(): array
|
||||
{
|
||||
return [
|
||||
DiscordThread::TABLE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The temporary path for the database dump.
|
||||
* Note: The dumper library does not support writing to disk, so we have to write to the local filesystem first.
|
||||
* Pattern: "animethemes-db-dump-discord-{milliseconds from epoch}.sql".
|
||||
*/
|
||||
protected function getDumpFile(): string
|
||||
{
|
||||
$filesystem = Storage::disk('local');
|
||||
|
||||
return Str::of($filesystem->path(''))
|
||||
->append(DumpDiscordAction::FILENAME_PREFIX)
|
||||
->append(strval(Date::now()->valueOf()))
|
||||
->append('.sql')
|
||||
->__toString();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands\Storage\Admin;
|
||||
|
||||
use App\Actions\Storage\Admin\Dump\DumpDiscordAction;
|
||||
use Illuminate\Console\Attributes\Description;
|
||||
use Illuminate\Console\Attributes\Signature;
|
||||
|
||||
#[Signature(
|
||||
'db:dump-discord
|
||||
{--comments : Write additional information in the MySQL dump such as program version, server version and host}
|
||||
{--data-only : Dump only the data without the schema in PostgreSQL dump}
|
||||
{--default-character-set=utf8 : Specify default character set in MySQL dump}
|
||||
{--extended-insert : Use multiple-row insert syntax in MySQL dump}
|
||||
{--inserts : Dump data as INSERT commands rather than COPY in PostgreSQL dump}
|
||||
{--lock-tables : Lock all tables before dumping them to MySQL dump}
|
||||
{--no-create-info : Turn off CREATE TABLE statements in MySQL dump}
|
||||
{--quick : Retrieve rows for a table from the server one row at a time in MySQL dump}
|
||||
{--set-gtid-purged=AUTO : Add SET GTID_PURGED to output in MySQL dump}
|
||||
{--single-transaction=true : Issue a BEGIN SQL statement before dumping data from server for MySQL dump}
|
||||
{--skip-column-statistics : Turn off ANALYZE table statements in the MySQL dump}
|
||||
{--skip-comments : Do not write additional information in the MySQL dump}
|
||||
{--skip-extended-insert : Turn off extended-insert in MySQL dump}
|
||||
{--skip-lock-tables : Turn off locking tables before dumping to MySQL dump}
|
||||
{--skip-quick : Do not retrieve rows for a table from the server one row at a time in MySQL dump}'
|
||||
)]
|
||||
#[Description('Produces sanitized database dump, targeting discord-related tables for seeding purposes')]
|
||||
class DiscordDumpCommand extends DumpCommand
|
||||
{
|
||||
protected function action(): DumpDiscordAction
|
||||
{
|
||||
return new DumpDiscordAction($this->options());
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ use App\Console\Commands\Repositories\Storage\Admin\DumpReconcileCommand;
|
||||
use App\Console\Commands\Storage\Admin\AdminDumpCommand;
|
||||
use App\Console\Commands\Storage\Admin\AuthDumpCommand;
|
||||
use App\Console\Commands\Storage\Admin\ContentDumpCommand;
|
||||
use App\Console\Commands\Storage\Admin\DiscordDumpCommand;
|
||||
use App\Console\Commands\Storage\Admin\DocumentDumpCommand;
|
||||
use App\Console\Commands\Storage\Admin\DumpPruneCommand;
|
||||
use App\Console\Commands\Storage\Admin\ListDumpCommand;
|
||||
@@ -61,12 +60,6 @@ class Kernel extends ConsoleKernel
|
||||
->storeOutput()
|
||||
->weeklyOn(Schedule::MONDAY);
|
||||
|
||||
$schedule->command(DiscordDumpCommand::class)
|
||||
->withoutOverlapping()
|
||||
->runInBackground()
|
||||
->storeOutput()
|
||||
->weeklyOn(Schedule::MONDAY);
|
||||
|
||||
$schedule->command(DocumentDumpCommand::class)
|
||||
->withoutOverlapping()
|
||||
->runInBackground()
|
||||
|
||||
@@ -8,7 +8,6 @@ class ServiceConstants
|
||||
{
|
||||
final public const string ADMIN_DISCORD_CHANNEL_QUALIFIED = 'services.discord.admin_discord_channel';
|
||||
final public const string DB_UPDATES_DISCORD_CHANNEL_QUALIFIED = 'services.discord.db_updates_discord_channel';
|
||||
final public const string SUBMISSIONS_DISCORD_CHANNEL_QUALIFIED = 'services.discord.submissions_discord_channel';
|
||||
|
||||
final public const string OPENAI_BEARER_TOKEN = 'services.openai.token';
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Events\Discord\DiscordThread;
|
||||
|
||||
use App\Events\Base\Admin\AdminDeletedEvent;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
|
||||
/**
|
||||
* @extends AdminDeletedEvent<DiscordThread>
|
||||
*/
|
||||
class DiscordThreadDeleted extends AdminDeletedEvent {}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Events\Discord\DiscordThread;
|
||||
|
||||
use App\Events\Base\Admin\AdminUpdatedEvent;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
|
||||
/**
|
||||
* @extends AdminUpdatedEvent<DiscordThread>
|
||||
*/
|
||||
class DiscordThreadUpdated extends AdminUpdatedEvent
|
||||
{
|
||||
public function __construct(DiscordThread $thread)
|
||||
{
|
||||
parent::__construct($thread);
|
||||
$this->initializeEmbedFields($thread);
|
||||
}
|
||||
}
|
||||
@@ -20,13 +20,10 @@ class AnimeDeleting extends BaseEvent implements CascadesDeletesEvent
|
||||
public function cascadeDeletes(): void
|
||||
{
|
||||
$anime = $this->getModel()->load([
|
||||
'discordthread',
|
||||
Anime::RELATION_SYNONYMS,
|
||||
Anime::RELATION_VIDEOS,
|
||||
]);
|
||||
|
||||
$anime->discordthread?->delete();
|
||||
|
||||
$anime->synonyms->each(function (Synonym $synonym): void {
|
||||
Synonym::withoutEvents(function () use ($synonym): void {
|
||||
$synonym->unsearchable();
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Actions\Models\Wiki\Anime;
|
||||
|
||||
use App\Actions\Discord\DiscordThreadAction as DiscordThreadActionAction;
|
||||
use App\Filament\Actions\BaseAction;
|
||||
use App\Filament\Components\Fields\TextInput;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Wiki\Anime;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class DiscordThreadAction extends BaseAction
|
||||
{
|
||||
public static function getDefaultName(): ?string
|
||||
{
|
||||
return 'discord-thread';
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->label(__('filament.actions.anime.discord_thread.name'));
|
||||
$this->icon(Heroicon::OutlinedChatBubbleLeftRight);
|
||||
|
||||
$this->visible(Gate::allows('create', DiscordThread::class));
|
||||
|
||||
$this->fillForm(fn (Anime $record): array => ['name' => $record->getName()]);
|
||||
|
||||
$this->action(function (Anime $record, array $data): void {
|
||||
$result = new DiscordThreadActionAction()->handle($record, $data);
|
||||
|
||||
if ($result->hasFailed()) {
|
||||
$this->failedLog($result->getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function getSchema(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextInput::make('name')
|
||||
->label(__('filament.actions.discord.thread.name'))
|
||||
->helperText(__('filament.actions.discord.thread.help'))
|
||||
->required()
|
||||
->maxlength(100),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ use App\Actions\Discord\DiscordVideoNotificationAction as DiscordVideoNotificati
|
||||
use App\Enums\Actions\Models\Wiki\Video\DiscordNotificationType;
|
||||
use App\Filament\BulkActions\BaseBulkAction;
|
||||
use App\Filament\Components\Fields\Select;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Wiki\Video;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Enums\Width;
|
||||
@@ -32,7 +31,7 @@ class VideoDiscordNotificationBulkAction extends BaseBulkAction
|
||||
$this->label(__('filament.bulk_actions.discord.notification.name'));
|
||||
$this->icon(Heroicon::OutlinedBell);
|
||||
|
||||
$this->visible(Gate::allows('create', DiscordThread::class));
|
||||
$this->visible(Gate::allows('create', Video::class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Discord\DiscordThread\Pages;
|
||||
|
||||
use App\Filament\Resources\Base\BaseListResources;
|
||||
use App\Filament\Resources\Discord\DiscordThreadResource;
|
||||
|
||||
class ListDiscordThreads extends BaseListResources
|
||||
{
|
||||
protected static string $resource = DiscordThreadResource::class;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Discord\DiscordThread\Pages;
|
||||
|
||||
use App\Filament\Resources\Base\BaseViewResource;
|
||||
use App\Filament\Resources\Discord\DiscordThreadResource;
|
||||
|
||||
class ViewDiscordThread extends BaseViewResource
|
||||
{
|
||||
protected static string $resource = DiscordThreadResource::class;
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Resources\Discord;
|
||||
|
||||
use App\Actions\Discord\DiscordThreadAction;
|
||||
use App\Enums\Filament\NavigationGroup;
|
||||
use App\Filament\Components\Columns\BelongsToColumn;
|
||||
use App\Filament\Components\Columns\TextColumn;
|
||||
use App\Filament\Components\Fields\BelongsTo;
|
||||
use App\Filament\Components\Fields\TextInput;
|
||||
use App\Filament\Components\Filters\DateFilter;
|
||||
use App\Filament\Components\Infolist\BelongsToEntry;
|
||||
use App\Filament\Components\Infolist\TextEntry;
|
||||
use App\Filament\Resources\BaseResource;
|
||||
use App\Filament\Resources\Discord\DiscordThread\Pages\ListDiscordThreads;
|
||||
use App\Filament\Resources\Discord\DiscordThread\Pages\ViewDiscordThread;
|
||||
use App\Filament\Resources\Wiki\AnimeResource;
|
||||
use App\Models\BaseModel;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use Filament\Resources\RelationManagers\RelationGroup;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Utilities\Set;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class DiscordThreadResource extends BaseResource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<Model>|null
|
||||
*/
|
||||
protected static ?string $model = DiscordThread::class;
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return __('filament.resources.singularLabel.discord_thread');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return __('filament.resources.label.discord_threads');
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): NavigationGroup
|
||||
{
|
||||
return NavigationGroup::DISCORD;
|
||||
}
|
||||
|
||||
public static function getNavigationIcon(): Heroicon
|
||||
{
|
||||
return Heroicon::OutlinedChatBubbleLeftRight;
|
||||
}
|
||||
|
||||
public static function getRecordTitleAttribute(): string
|
||||
{
|
||||
return DiscordThread::ATTRIBUTE_NAME;
|
||||
}
|
||||
|
||||
public static function getRecordSlug(): string
|
||||
{
|
||||
return 'discord-thread';
|
||||
}
|
||||
|
||||
public static function getEloquentQuery(): Builder
|
||||
{
|
||||
$query = parent::getEloquentQuery();
|
||||
|
||||
// Necessary to prevent lazy loading when loading related resources
|
||||
return $query->with([DiscordThread::RELATION_ANIME]);
|
||||
}
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
TextInput::make(DiscordThread::ATTRIBUTE_ID)
|
||||
->label(__('filament.fields.discord_thread.id.name'))
|
||||
->helperText(__('filament.fields.discord_thread.id.help'))
|
||||
->disabledOn(['edit'])
|
||||
->formatStateUsing(fn ($state): string => strval($state))
|
||||
->required()
|
||||
->live()
|
||||
->afterStateUpdated(fn (Set $set, string $state): mixed => $set(DiscordThread::ATTRIBUTE_NAME, Arr::get(new DiscordThreadAction()->get($state), 'thread.name'))),
|
||||
|
||||
TextInput::make(DiscordThread::ATTRIBUTE_NAME)
|
||||
->label(__('filament.fields.discord_thread.name.name'))
|
||||
->helperText(__('filament.fields.discord_thread.name.help'))
|
||||
->required(),
|
||||
|
||||
BelongsTo::make(DiscordThread::ATTRIBUTE_ANIME)
|
||||
->resource(AnimeResource::class)
|
||||
->required(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return parent::table($table)
|
||||
->columns([
|
||||
TextColumn::make(DiscordThread::ATTRIBUTE_ID)
|
||||
->label(__('filament.fields.discord_thread.id.name')),
|
||||
|
||||
TextColumn::make(DiscordThread::ATTRIBUTE_NAME)
|
||||
->label(__('filament.fields.discord_thread.name.name'))
|
||||
->copyableWithMessage()
|
||||
->searchable(),
|
||||
|
||||
BelongsToColumn::make(DiscordThread::RELATION_ANIME, AnimeResource::class),
|
||||
])
|
||||
->defaultSort(BaseModel::CREATED_AT, 'desc');
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Section::make(static::getRecordTitle($schema->getRecord()))
|
||||
->schema([
|
||||
TextEntry::make(DiscordThread::ATTRIBUTE_ID)
|
||||
->label(__('filament.fields.discord_thread.id.name')),
|
||||
|
||||
TextEntry::make(DiscordThread::ATTRIBUTE_NAME)
|
||||
->label(__('filament.fields.discord_thread.name.name')),
|
||||
|
||||
BelongsToEntry::make(DiscordThread::RELATION_ANIME, AnimeResource::class),
|
||||
])
|
||||
->columns(3),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, RelationGroup|class-string<\Filament\Resources\RelationManagers\RelationManager>>
|
||||
*/
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
RelationGroup::make(static::getModelLabel(), [
|
||||
...parent::getBaseRelations(),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Filament\Tables\Filters\BaseFilter[]
|
||||
*/
|
||||
public static function getFilters(): array
|
||||
{
|
||||
return [
|
||||
DateFilter::make(BaseModel::ATTRIBUTE_CREATED_AT)
|
||||
->label(__('filament.fields.base.created_at')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, \Filament\Resources\Pages\PageRegistration>
|
||||
*/
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListDiscordThreads::route('/'),
|
||||
'view' => ViewDiscordThread::route('/{record:thread_id}'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ use App\Enums\Models\Wiki\AnimeSeason;
|
||||
use App\Enums\Models\Wiki\ResourceSite;
|
||||
use App\Filament\Actions\Models\Wiki\Anime\AttachAnimeResourceAction;
|
||||
use App\Filament\Actions\Models\Wiki\Anime\BackfillAnimeAction;
|
||||
use App\Filament\Actions\Models\Wiki\Anime\DiscordThreadAction;
|
||||
use App\Filament\Components\Columns\TextColumn;
|
||||
use App\Filament\Components\Fields\Select;
|
||||
use App\Filament\Components\Fields\Slug;
|
||||
@@ -260,8 +259,6 @@ class AnimeResource extends BaseResource
|
||||
];
|
||||
|
||||
return [
|
||||
DiscordThreadAction::make(),
|
||||
|
||||
BackfillAnimeAction::make(),
|
||||
|
||||
AttachAnimeResourceAction::make(),
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models\Discord;
|
||||
|
||||
use App\Events\Discord\DiscordThread\DiscordThreadDeleted;
|
||||
use App\Events\Discord\DiscordThread\DiscordThreadUpdated;
|
||||
use App\Models\BaseModel;
|
||||
use App\Models\Wiki\Anime;
|
||||
use App\Observers\Discord\DiscordThreadObserver;
|
||||
use Database\Factories\Discord\DiscordThreadFactory;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Attributes\Table;
|
||||
use Illuminate\Database\Eloquent\Attributes\WithoutIncrementing;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* @property Anime $anime
|
||||
* @property int $anime_id
|
||||
* @property string $thread_id
|
||||
* @property string $name
|
||||
*
|
||||
* @method static DiscordThreadFactory factory(...$parameters)
|
||||
*/
|
||||
#[ObservedBy(DiscordThreadObserver::class)]
|
||||
#[Table(DiscordThread::TABLE, DiscordThread::ATTRIBUTE_ID, 'string')]
|
||||
#[WithoutIncrementing]
|
||||
class DiscordThread extends BaseModel
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
final public const string TABLE = 'discord_threads';
|
||||
|
||||
final public const string ATTRIBUTE_ANIME = 'anime_id';
|
||||
final public const string ATTRIBUTE_ID = 'thread_id';
|
||||
final public const string ATTRIBUTE_NAME = 'name';
|
||||
|
||||
final public const string RELATION_ANIME = 'anime';
|
||||
|
||||
/**
|
||||
* The event map for the model.
|
||||
*
|
||||
* Allows for object-based events for native Eloquent events.
|
||||
*
|
||||
* @var array<string, class-string>
|
||||
*/
|
||||
protected $dispatchesEvents = [
|
||||
'deleted' => DiscordThreadDeleted::class,
|
||||
'updated' => DiscordThreadUpdated::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
DiscordThread::ATTRIBUTE_ANIME,
|
||||
DiscordThread::ATTRIBUTE_ID,
|
||||
DiscordThread::ATTRIBUTE_NAME,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
DiscordThread::ATTRIBUTE_ANIME => 'int',
|
||||
DiscordThread::ATTRIBUTE_NAME => 'string',
|
||||
];
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getSubtitle(): string
|
||||
{
|
||||
return $this->anime->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Anime, $this>
|
||||
*/
|
||||
public function anime(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Anime::class, DiscordThread::ATTRIBUTE_ANIME);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ use App\Events\Wiki\Anime\AnimeUpdated;
|
||||
use App\Http\Resources\Pivot\Wiki\Resource\AnimeSeriesJsonResource;
|
||||
use App\Http\Resources\Pivot\Wiki\Resource\AnimeStudioJsonResource;
|
||||
use App\Models\BaseModel;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\Wiki\Anime\AnimeSynonym;
|
||||
use App\Models\Wiki\Anime\AnimeTheme;
|
||||
@@ -41,7 +40,6 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -53,7 +51,6 @@ use RuntimeException;
|
||||
/**
|
||||
* @property int $anime_id
|
||||
* @property Collection<int, AnimeTheme> $animethemes
|
||||
* @property DiscordThread|null $discordthread
|
||||
* @property Collection<int, ExternalEntry> $externalentries
|
||||
* @property AnimeFormat|null $format
|
||||
* @property Collection<int, Image> $images
|
||||
@@ -218,14 +215,6 @@ class Anime extends BaseModel implements Auditable, HasImages, HasResources, Has
|
||||
return $this->morphMany(Synonym::class, Synonym::RELATION_SYNONYMABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HasOne<DiscordThread, $this>
|
||||
*/
|
||||
public function discordthread(): HasOne
|
||||
{
|
||||
return $this->hasOne(DiscordThread::class, DiscordThread::ATTRIBUTE_ANIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsToMany<Series, $this, AnimeSeries>
|
||||
*/
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Observers\Discord;
|
||||
|
||||
use App\Actions\Discord\DiscordThreadAction;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use Illuminate\Contracts\Events\ShouldHandleEventsAfterCommit;
|
||||
|
||||
class DiscordThreadObserver implements ShouldHandleEventsAfterCommit
|
||||
{
|
||||
/**
|
||||
* Handle the DiscordThread "updated" event.
|
||||
*/
|
||||
public function updated(DiscordThread $thread): void
|
||||
{
|
||||
DiscordThreadAction::getHttp()
|
||||
->put('/thread', $thread->toArray())
|
||||
->throw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the DiscordThread "deleted" event.
|
||||
*/
|
||||
public function deleted(DiscordThread $thread): void
|
||||
{
|
||||
DiscordThreadAction::getHttp()
|
||||
->delete('/thread', ['id' => $thread->getKey()])
|
||||
->throw();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Policies\Discord;
|
||||
|
||||
use App\Policies\BasePolicy;
|
||||
|
||||
class DiscordThreadPolicy extends BasePolicy {}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories\Discord;
|
||||
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use Illuminate\Database\Eloquent\Factories\Attributes\UseModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @method DiscordThread createOne($attributes = [])
|
||||
* @method DiscordThread makeOne($attributes = [])
|
||||
*
|
||||
* @extends Factory<DiscordThread>
|
||||
*/
|
||||
#[UseModel(DiscordThread::class)]
|
||||
class DiscordThreadFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
DiscordThread::ATTRIBUTE_NAME => fake()->words(3, true),
|
||||
DiscordThread::ATTRIBUTE_ID => fake()->words(3, true),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('discord_threads')) {
|
||||
Schema::create('discord_threads', function (Blueprint $table) {
|
||||
$table->timestamps(6);
|
||||
$table->string('thread_id')->primary();
|
||||
$table->string('name');
|
||||
|
||||
$table->unsignedBigInteger('anime_id');
|
||||
$table->foreign('anime_id')->references('anime_id')->on('anime');
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -16,7 +16,6 @@ use App\Models\Auth\Prohibition;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Auth\Sanction;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Document\Page;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
@@ -69,9 +68,6 @@ class PermissionSeeder extends Seeder
|
||||
$this->registerResource(Sanction::class, CrudPermission::cases());
|
||||
$this->registerResource(User::class, $extendedCrudPermissions);
|
||||
|
||||
// Discord Resources
|
||||
$this->registerResource(DiscordThread::class, CrudPermission::cases());
|
||||
|
||||
// List Resources
|
||||
$this->registerResource(ExternalEntry::class, CrudPermission::cases());
|
||||
$this->registerResource(ExternalProfile::class, CrudPermission::cases());
|
||||
|
||||
@@ -17,7 +17,6 @@ use App\Models\Auth\Prohibition;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Auth\Sanction;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Document\Page;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
@@ -77,9 +76,6 @@ class AdminSeeder extends RoleSeeder
|
||||
$this->configureResource($role, Sanction::class, CrudPermission::cases());
|
||||
$this->configureResource($role, User::class, $extendedCrudPermissions);
|
||||
|
||||
// Discord Resources
|
||||
$this->configureResource($role, DiscordThread::class, CrudPermission::cases());
|
||||
|
||||
// List Resources
|
||||
$this->configureResource($role, ExternalEntry::class, CrudPermission::cases());
|
||||
$this->configureResource($role, ExternalProfile::class, CrudPermission::cases());
|
||||
|
||||
@@ -9,7 +9,6 @@ use App\Enums\Auth\ExtendedCrudPermission;
|
||||
use App\Enums\Auth\Role as RoleEnum;
|
||||
use App\Enums\Auth\SpecialPermission;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Document\Page;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
@@ -54,9 +53,6 @@ class ContentModeratorRoleSeeder extends RoleSeeder
|
||||
ExtendedCrudPermission::cases(),
|
||||
);
|
||||
|
||||
// Discord Resources
|
||||
$this->configureResource($role, DiscordThread::class, [CrudPermission::VIEW]);
|
||||
|
||||
// List Resources
|
||||
$this->configureResource($role, ExternalEntry::class, [CrudPermission::VIEW]);
|
||||
$this->configureResource($role, ExternalProfile::class, CrudPermission::cases());
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\Role as RoleEnum;
|
||||
use App\Enums\Auth\SpecialPermission;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Document\Page;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
@@ -48,9 +47,6 @@ class ContributorRoleSeeder extends RoleSeeder
|
||||
/** @var Role $role */
|
||||
$role = Role::findOrCreate($roleEnum->value);
|
||||
|
||||
// Discord Resources
|
||||
$this->configureResource($role, DiscordThread::class, [CrudPermission::VIEW]);
|
||||
|
||||
// List Resources
|
||||
$this->configureResource($role, ExternalEntry::class, [CrudPermission::VIEW]);
|
||||
$this->configureResource($role, ExternalProfile::class, CrudPermission::cases());
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\Role as RoleEnum;
|
||||
use App\Enums\Auth\SpecialPermission;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Document\Page;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
@@ -48,9 +47,6 @@ class DeveloperRoleSeeder extends RoleSeeder
|
||||
/** @var Role $role */
|
||||
$role = Role::findOrCreate($roleEnum->value);
|
||||
|
||||
// Discord Resources
|
||||
$this->configureResource($role, DiscordThread::class, [CrudPermission::VIEW]);
|
||||
|
||||
// List Resources
|
||||
$this->configureResource($role, ExternalEntry::class, [CrudPermission::VIEW]);
|
||||
$this->configureResource($role, ExternalProfile::class, CrudPermission::cases());
|
||||
|
||||
@@ -9,7 +9,6 @@ use App\Enums\Auth\ExtendedCrudPermission;
|
||||
use App\Enums\Auth\Role as RoleEnum;
|
||||
use App\Enums\Auth\SpecialPermission;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Document\Page;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
@@ -54,9 +53,6 @@ class EncoderRoleSeeder extends RoleSeeder
|
||||
ExtendedCrudPermission::cases(),
|
||||
);
|
||||
|
||||
// Discord Resources
|
||||
$this->configureResource($role, DiscordThread::class, [CrudPermission::CREATE, CrudPermission::UPDATE, CrudPermission::VIEW]);
|
||||
|
||||
// List Resources
|
||||
$this->configureResource($role, ExternalEntry::class, [CrudPermission::VIEW]);
|
||||
$this->configureResource($role, ExternalProfile::class, CrudPermission::cases());
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\Role as RoleEnum;
|
||||
use App\Enums\Auth\SpecialPermission;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Document\Page;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
@@ -48,9 +47,6 @@ class PanelViewerRoleSeeder extends RoleSeeder
|
||||
/** @var Role $role */
|
||||
$role = Role::findOrCreate($roleEnum->value);
|
||||
|
||||
// Discord Resources
|
||||
$this->configureResource($role, DiscordThread::class, [CrudPermission::VIEW]);
|
||||
|
||||
// List Resources
|
||||
$this->configureResource($role, ExternalEntry::class, [CrudPermission::VIEW]);
|
||||
$this->configureResource($role, ExternalProfile::class, CrudPermission::cases());
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\Role as RoleEnum;
|
||||
use App\Enums\Auth\SpecialPermission;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Document\Page;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
@@ -48,9 +47,6 @@ class PatronRoleSeeder extends RoleSeeder
|
||||
/** @var Role $role */
|
||||
$role = Role::findOrCreate($roleEnum->value);
|
||||
|
||||
// Discord Resources
|
||||
$this->configureResource($role, DiscordThread::class, [CrudPermission::VIEW]);
|
||||
|
||||
// List Resources
|
||||
$this->configureResource($role, ExternalEntry::class, [CrudPermission::VIEW]);
|
||||
$this->configureResource($role, ExternalProfile::class, CrudPermission::cases());
|
||||
|
||||
@@ -71,9 +71,6 @@ return [
|
||||
],
|
||||
'name' => 'Backfill Anime',
|
||||
],
|
||||
'discord_thread' => [
|
||||
'name' => 'Create Discord Thread',
|
||||
],
|
||||
],
|
||||
'audio' => [
|
||||
'delete' => [
|
||||
@@ -100,12 +97,6 @@ return [
|
||||
'restore' => 'Restore',
|
||||
'view' => 'View',
|
||||
],
|
||||
'discord' => [
|
||||
'thread' => [
|
||||
'name' => 'Name',
|
||||
'help' => 'The name of the thread to be created. Use the default name or a shorter synonym if it exceeds 100 characters.',
|
||||
],
|
||||
],
|
||||
'dump' => [
|
||||
'dump' => [
|
||||
'confirmButtonText' => 'Dump',
|
||||
@@ -691,16 +682,6 @@ return [
|
||||
'timestamps' => 'Timestamps',
|
||||
'updated_at' => 'Updated At',
|
||||
],
|
||||
'discord_thread' => [
|
||||
'id' => [
|
||||
'help' => 'The thread ID on Discord',
|
||||
'name' => 'Thread ID',
|
||||
],
|
||||
'name' => [
|
||||
'help' => 'The name of the thread on Discord',
|
||||
'name' => 'Name',
|
||||
],
|
||||
],
|
||||
'dump' => [
|
||||
'path' => 'Path',
|
||||
'public' => 'Public',
|
||||
@@ -1041,7 +1022,6 @@ return [
|
||||
'announcements' => 'Announcements',
|
||||
'artists' => 'Artists',
|
||||
'audios' => 'Audios',
|
||||
'discord_threads' => 'Threads',
|
||||
'dumps' => 'Dumps',
|
||||
'external_entries' => 'External Entries',
|
||||
'external_profiles' => 'External Profiles',
|
||||
@@ -1078,7 +1058,6 @@ return [
|
||||
'announcement' => 'Announcement',
|
||||
'artist' => 'Artist',
|
||||
'audio' => 'Audio',
|
||||
'discord_thread' => 'Thread',
|
||||
'dump' => 'Dump',
|
||||
'external_entry' => 'External Entry',
|
||||
'external_profile' => 'External Profile',
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Console\Commands\Storage\Admin\DiscordDumpCommand;
|
||||
use App\Constants\Config\DumpConstants;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
uses(WithFaker::class);
|
||||
|
||||
test('database dump output', function (): void {
|
||||
Storage::fake('local');
|
||||
Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED));
|
||||
|
||||
Date::setTestNow(fake()->iso8601());
|
||||
|
||||
$this->artisan(DiscordDumpCommand::class)
|
||||
->assertSuccessful()
|
||||
->expectsOutputToContain('has been created');
|
||||
});
|
||||
|
||||
test('database dump file', function (): void {
|
||||
$local = Storage::fake('local');
|
||||
$fs = Storage::fake(Config::get(DumpConstants::DISK_QUALIFIED));
|
||||
|
||||
Date::setTestNow(fake()->iso8601());
|
||||
|
||||
$this->artisan(DiscordDumpCommand::class)->run();
|
||||
|
||||
$this->assertEmpty($local->allFiles());
|
||||
$this->assertCount(1, $fs->allFiles());
|
||||
});
|
||||
@@ -1,116 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\SpecialPermission;
|
||||
use App\Filament\Actions\Base\CreateAction;
|
||||
use App\Filament\Actions\Base\DeleteAction;
|
||||
use App\Filament\Actions\Base\EditAction;
|
||||
use App\Filament\Resources\Discord\DiscordThreadResource;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\Discord\DiscordThread as DiscordThreadModel;
|
||||
use App\Models\Wiki\Anime;
|
||||
use Filament\Actions\Testing\TestAction;
|
||||
use Livewire\Livewire;
|
||||
|
||||
use function Pest\Laravel\actingAs;
|
||||
use function Pest\Laravel\get;
|
||||
|
||||
test('render index page', function (): void {
|
||||
$user = User::factory()
|
||||
->withPermissions(
|
||||
SpecialPermission::VIEW_FILAMENT->value,
|
||||
CrudPermission::VIEW->format(DiscordThreadModel::class)
|
||||
)
|
||||
->createOne();
|
||||
|
||||
actingAs($user);
|
||||
|
||||
$records = DiscordThreadModel::factory()
|
||||
->for(Anime::factory())
|
||||
->count(10)
|
||||
->create();
|
||||
|
||||
get(DiscordThreadResource::getUrl('index'))
|
||||
->assertSuccessful();
|
||||
|
||||
Livewire::test(getIndexPage(DiscordThreadResource::class))
|
||||
->assertCanSeeTableRecords($records);
|
||||
});
|
||||
|
||||
test('render view page', function (): void {
|
||||
$user = User::factory()
|
||||
->withPermissions(
|
||||
SpecialPermission::VIEW_FILAMENT->value,
|
||||
CrudPermission::VIEW->format(DiscordThreadModel::class)
|
||||
)
|
||||
->createOne();
|
||||
|
||||
actingAs($user);
|
||||
|
||||
$record = DiscordThreadModel::factory()
|
||||
->for(Anime::factory())
|
||||
->createOne();
|
||||
|
||||
get(DiscordThreadResource::getUrl('view', ['record' => $record]))
|
||||
->assertSuccessful();
|
||||
});
|
||||
|
||||
test('mount create action', function (): void {
|
||||
$user = User::factory()
|
||||
->withPermissions(
|
||||
SpecialPermission::VIEW_FILAMENT->value,
|
||||
CrudPermission::CREATE->format(DiscordThreadModel::class)
|
||||
)
|
||||
->createOne();
|
||||
|
||||
actingAs($user);
|
||||
|
||||
Livewire::test(getIndexPage(DiscordThreadResource::class))
|
||||
->mountAction(CreateAction::class)
|
||||
->assertActionMounted(CreateAction::class);
|
||||
});
|
||||
|
||||
test('mount edit action', function (): void {
|
||||
$user = User::factory()
|
||||
->withPermissions(
|
||||
SpecialPermission::VIEW_FILAMENT->value,
|
||||
CrudPermission::UPDATE->format(DiscordThreadModel::class)
|
||||
)
|
||||
->createOne();
|
||||
|
||||
actingAs($user);
|
||||
|
||||
$record = DiscordThreadModel::factory()
|
||||
->for(Anime::factory())
|
||||
->createOne();
|
||||
|
||||
Livewire::test(getIndexPage(DiscordThreadResource::class))
|
||||
->mountAction(TestAction::make(EditAction::getDefaultName())->table($record))
|
||||
->callMountedAction()
|
||||
->assertHasNoErrors();
|
||||
});
|
||||
|
||||
test('user cannot create record', function (): void {
|
||||
Livewire::test(getIndexPage(DiscordThreadResource::class))
|
||||
->assertActionHidden(CreateAction::class);
|
||||
});
|
||||
|
||||
test('user cannot edit record', function (): void {
|
||||
$record = DiscordThreadModel::factory()
|
||||
->for(Anime::factory())
|
||||
->createOne();
|
||||
|
||||
Livewire::test(getIndexPage(DiscordThreadResource::class))
|
||||
->assertActionDoesNotExist(TestAction::make(EditAction::getDefaultName())->table($record));
|
||||
});
|
||||
|
||||
test('user cannot delete record', function (): void {
|
||||
$record = DiscordThreadModel::factory()
|
||||
->for(Anime::factory())
|
||||
->createOne();
|
||||
|
||||
Livewire::test(getIndexPage(DiscordThreadResource::class))
|
||||
->assertActionDoesNotExist(TestAction::make(DeleteAction::getDefaultName())->table($record));
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Constants\FeatureConstants;
|
||||
use App\Events\Discord\DiscordThread\DiscordThreadDeleted;
|
||||
use App\Events\Discord\DiscordThread\DiscordThreadUpdated;
|
||||
use App\Jobs\SendDiscordNotificationJob;
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Wiki\Anime;
|
||||
use Illuminate\Support\Facades\Bus;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Laravel\Pennant\Feature;
|
||||
|
||||
test('thread deleted sends discord notification', function (): void {
|
||||
$thread = DiscordThread::factory()
|
||||
->for(Anime::factory())
|
||||
->createOne();
|
||||
|
||||
Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS);
|
||||
Bus::fake(SendDiscordNotificationJob::class);
|
||||
Http::fake();
|
||||
Event::fakeExcept(DiscordThreadDeleted::class);
|
||||
|
||||
$thread->delete();
|
||||
|
||||
Bus::assertDispatched(SendDiscordNotificationJob::class);
|
||||
});
|
||||
|
||||
test('thread updated sends discord notification', function (): void {
|
||||
$thread = DiscordThread::factory()
|
||||
->for(Anime::factory())
|
||||
->createOne();
|
||||
|
||||
Feature::activate(FeatureConstants::ALLOW_DISCORD_NOTIFICATIONS);
|
||||
Bus::fake(SendDiscordNotificationJob::class);
|
||||
Http::fake();
|
||||
Event::fakeExcept(DiscordThreadUpdated::class);
|
||||
|
||||
$changes = DiscordThread::factory()
|
||||
->for(Anime::factory())
|
||||
->makeOne();
|
||||
|
||||
$thread->fill($changes->getAttributes());
|
||||
$thread->save();
|
||||
|
||||
Bus::assertDispatched(SendDiscordNotificationJob::class);
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\Discord\DiscordThread;
|
||||
use App\Models\Wiki\Anime;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
|
||||
uses(WithFaker::class);
|
||||
|
||||
test('nameable', function (): void {
|
||||
$thread = DiscordThread::factory()
|
||||
->for(Anime::factory())
|
||||
->createOne();
|
||||
|
||||
$this->assertIsString($thread->getName());
|
||||
});
|
||||
|
||||
test('has subtitle', function (): void {
|
||||
$thread = DiscordThread::factory()
|
||||
->for(Anime::factory())
|
||||
->createOne();
|
||||
|
||||
$this->assertIsString($thread->getSubtitle());
|
||||
});
|
||||
|
||||
test('anime', function (): void {
|
||||
$thread = DiscordThread::factory()
|
||||
->for(Anime::factory())
|
||||
->createOne();
|
||||
|
||||
$this->assertInstanceOf(BelongsTo::class, $thread->anime());
|
||||
$this->assertInstanceOf(Anime::class, $thread->anime()->first());
|
||||
});
|
||||
Reference in New Issue
Block a user