mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 01:24:46 +02:00
feat: added admin dumps (#807)
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Storage\Admin\Dump;
|
||||
|
||||
use App\Concerns\Repositories\Admin\ReconcilesDumpRepositories;
|
||||
use App\Models\Admin\ActionLog;
|
||||
use App\Models\Admin\Announcement;
|
||||
use App\Models\Admin\Dump;
|
||||
use App\Models\Admin\Feature;
|
||||
use App\Models\Admin\FeaturedTheme;
|
||||
use App\Models\Service\View;
|
||||
use App\Models\Service\ViewAggregate;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Class DumpAdminAction.
|
||||
*/
|
||||
class DumpAdminAction extends DumpAction
|
||||
{
|
||||
use ReconcilesDumpRepositories;
|
||||
|
||||
final public const FILENAME_PREFIX = 'animethemes-db-dump-admin-';
|
||||
|
||||
/**
|
||||
* The list of tables to include in the dump.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function allowedTables(): array
|
||||
{
|
||||
return [
|
||||
'action_events', // Nova events
|
||||
ActionLog::TABLE,
|
||||
Announcement::TABLE,
|
||||
Dump::TABLE,
|
||||
Feature::TABLE,
|
||||
FeaturedTheme::TABLE,
|
||||
ViewAggregate::TABLE,
|
||||
View::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-admin-{milliseconds from epoch}.sql".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDumpFile(): string
|
||||
{
|
||||
$filesystem = Storage::disk('local');
|
||||
|
||||
return Str::of($filesystem->path(''))
|
||||
->append(DumpAdminAction::FILENAME_PREFIX)
|
||||
->append(strval(Date::now()->valueOf()))
|
||||
->append('.sql')
|
||||
->__toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Storage\Admin\Dump;
|
||||
|
||||
use App\Concerns\Repositories\Admin\ReconcilesDumpRepositories;
|
||||
use App\Models\Auth\Permission;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\List\External\ExternalToken;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Class DumpAuthAction.
|
||||
*/
|
||||
class DumpAuthAction extends DumpAction
|
||||
{
|
||||
use ReconcilesDumpRepositories;
|
||||
|
||||
final public const FILENAME_PREFIX = 'animethemes-db-dump-auth-';
|
||||
|
||||
/**
|
||||
* The list of tables to include in the dump.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function allowedTables(): array
|
||||
{
|
||||
return [
|
||||
// This table stores tokens which are sensitive data.
|
||||
ExternalToken::TABLE,
|
||||
|
||||
Permission::TABLE,
|
||||
Role::TABLE,
|
||||
User::TABLE,
|
||||
'model_has_permissions',
|
||||
'model_has_roles',
|
||||
'password_reset_tokens',
|
||||
'personal_access_tokens',
|
||||
'role_has_permissions',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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-auth-{milliseconds from epoch}.sql".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDumpFile(): string
|
||||
{
|
||||
$filesystem = Storage::disk('local');
|
||||
|
||||
return Str::of($filesystem->path(''))
|
||||
->append(DumpAuthAction::FILENAME_PREFIX)
|
||||
->append(strval(Date::now()->valueOf()))
|
||||
->append('.sql')
|
||||
->__toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?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.
|
||||
*/
|
||||
class DumpDiscordAction extends DumpAction
|
||||
{
|
||||
use ReconcilesDumpRepositories;
|
||||
|
||||
final public const FILENAME_PREFIX = 'animethemes-db-dump-discord-';
|
||||
|
||||
/**
|
||||
* The list of tables to include in the dump.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected 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".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Storage\Admin\Dump;
|
||||
|
||||
use App\Concerns\Repositories\Admin\ReconcilesDumpRepositories;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
use App\Models\List\Playlist;
|
||||
use App\Models\List\Playlist\PlaylistTrack;
|
||||
use App\Pivots\List\PlaylistImage;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Class DumpListAction.
|
||||
*/
|
||||
class DumpListAction extends DumpAction
|
||||
{
|
||||
use ReconcilesDumpRepositories;
|
||||
|
||||
final public const FILENAME_PREFIX = 'animethemes-db-dump-list-';
|
||||
|
||||
/**
|
||||
* The list of tables to include in the dump.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function allowedTables(): array
|
||||
{
|
||||
return [
|
||||
ExternalEntry::TABLE,
|
||||
ExternalProfile::TABLE,
|
||||
PlaylistTrack::TABLE,
|
||||
Playlist::TABLE,
|
||||
PlaylistImage::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-list-{milliseconds from epoch}.sql".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDumpFile(): string
|
||||
{
|
||||
$filesystem = Storage::disk('local');
|
||||
|
||||
return Str::of($filesystem->path(''))
|
||||
->append(DumpListAction::FILENAME_PREFIX)
|
||||
->append(strval(Date::now()->valueOf()))
|
||||
->append('.sql')
|
||||
->__toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Storage\Admin\Dump;
|
||||
|
||||
use App\Concerns\Repositories\Admin\ReconcilesDumpRepositories;
|
||||
use App\Models\User\Encode;
|
||||
use App\Models\User\Notification;
|
||||
use App\Models\User\Report;
|
||||
use App\Models\User\Report\ReportStep;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Class DumpUserAction.
|
||||
*/
|
||||
class DumpUserAction extends DumpAction
|
||||
{
|
||||
use ReconcilesDumpRepositories;
|
||||
|
||||
final public const FILENAME_PREFIX = 'animethemes-db-dump-user-';
|
||||
|
||||
/**
|
||||
* The list of tables to include in the dump.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function allowedTables(): array
|
||||
{
|
||||
return [
|
||||
Encode::TABLE,
|
||||
Notification::TABLE,
|
||||
Report::TABLE,
|
||||
ReportStep::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-user-{milliseconds from epoch}.sql".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDumpFile(): string
|
||||
{
|
||||
$filesystem = Storage::disk('local');
|
||||
|
||||
return Str::of($filesystem->path(''))
|
||||
->append(DumpUserAction::FILENAME_PREFIX)
|
||||
->append(strval(Date::now()->valueOf()))
|
||||
->append('.sql')
|
||||
->__toString();
|
||||
}
|
||||
}
|
||||
@@ -55,8 +55,7 @@ trait DiscordThreadActionTrait
|
||||
->label(__('filament.actions.discord.thread.name'))
|
||||
->helperText(__('filament.actions.discord.thread.help'))
|
||||
->required()
|
||||
->maxlength(100)
|
||||
->rules(['required', 'max:100']),
|
||||
->maxlength(100),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,7 @@ trait GiveRoleActionTrait
|
||||
->label(__('filament.resources.singularLabel.role'))
|
||||
->searchable()
|
||||
->required()
|
||||
->options($roles)
|
||||
->rules('required'),
|
||||
->options($roles),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,7 @@ trait RevokeRoleActionTrait
|
||||
->label(__('filament.resources.singularLabel.role'))
|
||||
->searchable()
|
||||
->required()
|
||||
->options($roles)
|
||||
->rules('required'),
|
||||
->options($roles),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,7 @@ trait GivePermissionActionTrait
|
||||
->label(__('filament.resources.singularLabel.permission'))
|
||||
->searchable()
|
||||
->required()
|
||||
->options($permissions)
|
||||
->rules('required'),
|
||||
->options($permissions),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,7 @@ trait RevokePermissionActionTrait
|
||||
->label(__('filament.resources.singularLabel.permission'))
|
||||
->searchable()
|
||||
->required()
|
||||
->options($permissions)
|
||||
->rules('required'),
|
||||
->options($permissions),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,7 @@ trait GivePermissionActionTrait
|
||||
->label(__('filament.resources.singularLabel.permission'))
|
||||
->searchable()
|
||||
->required()
|
||||
->options($permissions)
|
||||
->rules('required'),
|
||||
->options($permissions),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,7 @@ trait GiveRoleActionTrait
|
||||
->label(__('filament.resources.singularLabel.role'))
|
||||
->searchable()
|
||||
->required()
|
||||
->options($roles)
|
||||
->rules('required'),
|
||||
->options($roles),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,7 @@ trait RevokePermissionActionTrait
|
||||
->label(__('filament.resources.singularLabel.permission'))
|
||||
->searchable()
|
||||
->required()
|
||||
->options($permissions)
|
||||
->rules('required'),
|
||||
->options($permissions),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,7 @@ trait RevokeRoleActionTrait
|
||||
->label(__('filament.resources.singularLabel.role'))
|
||||
->searchable()
|
||||
->required()
|
||||
->options($roles)
|
||||
->rules('required'),
|
||||
->options($roles),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ trait AttachResourceActionTrait
|
||||
->helperText(__("filament.actions.models.wiki.attach_resource.fields.{$resourceSiteLower}.help"))
|
||||
->url()
|
||||
->maxLength(192)
|
||||
->rules(['max:192', $resourceSite->getFormatRule($model)]);
|
||||
->rule($resourceSite->getFormatRule($model));
|
||||
}
|
||||
|
||||
return $form
|
||||
|
||||
@@ -19,7 +19,6 @@ use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Trait BackfillAudioActionTrait.
|
||||
@@ -96,21 +95,24 @@ trait BackfillAudioActionTrait
|
||||
->label(__('filament.actions.video.backfill.fields.derive_source.name'))
|
||||
->helperText(__('filament.actions.video.backfill.fields.derive_source.help'))
|
||||
->options(DeriveSourceVideo::asSelectArray())
|
||||
->rules(['required', new Enum(DeriveSourceVideo::class)])
|
||||
->required()
|
||||
->enum(DeriveSourceVideo::class)
|
||||
->default(DeriveSourceVideo::YES->value),
|
||||
|
||||
Select::make(OverwriteAudio::getFieldKey())
|
||||
->label(__('filament.actions.video.backfill.fields.overwrite.name'))
|
||||
->helperText(__('filament.actions.video.backfill.fields.overwrite.help'))
|
||||
->options(OverwriteAudio::asSelectArray())
|
||||
->rules(['required', new Enum(OverwriteAudio::class)])
|
||||
->required()
|
||||
->enum(OverwriteAudio::class)
|
||||
->default(OverwriteAudio::NO->value),
|
||||
|
||||
Select::make(ReplaceRelatedAudio::getFieldKey())
|
||||
->label(__('filament.actions.video.backfill.fields.replace_related.name'))
|
||||
->helperText(__('filament.actions.video.backfill.fields.replace_related.help'))
|
||||
->options(ReplaceRelatedAudio::asSelectArray())
|
||||
->rules(['required', new Enum(ReplaceRelatedAudio::class)])
|
||||
->required()
|
||||
->enum(ReplaceRelatedAudio::class)
|
||||
->default(ReplaceRelatedAudio::NO->value),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,9 @@ trait MoveActionTrait
|
||||
->label(__('filament.actions.storage.move.fields.path.name'))
|
||||
->helperText(__('filament.actions.storage.move.fields.path.help'))
|
||||
->required()
|
||||
->rules(['required', 'string', 'doesnt_start_with:/', "ends_with:{$this->allowedFileExtension()}", new StorageFileDirectoryExistsRule($fs)])
|
||||
->doesntStartWith('/')
|
||||
->endsWith($this->allowedFileExtension())
|
||||
->rule(new StorageFileDirectoryExistsRule($fs))
|
||||
->default($defaultPath),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,9 @@ trait MoveAllActionTrait
|
||||
->label(__('filament.resources.singularLabel.video'))
|
||||
->helperText(__('filament.actions.storage.move.fields.path.help'))
|
||||
->required()
|
||||
->rules(['required', 'string', 'doesnt_start_with:/', "ends_with:.webm", new StorageFileDirectoryExistsRule($videoFs)])
|
||||
->doesntStartWith('/')
|
||||
->endsWith('.webm')
|
||||
->rule(new StorageFileDirectoryExistsRule($videoFs))
|
||||
->default($videoPath),
|
||||
|
||||
TextInput::make('audio')
|
||||
@@ -72,7 +74,9 @@ trait MoveAllActionTrait
|
||||
->helperText(__('filament.actions.storage.move.fields.path.help'))
|
||||
->hidden($audioPath === null)
|
||||
->required($audioPath !== null)
|
||||
->rules(['string', 'doesnt_start_with:/', "ends_with:.ogg", new StorageFileDirectoryExistsRule($audioFs)])
|
||||
->doesntStartWith('/')
|
||||
->endsWith('.ogg')
|
||||
->rule(new StorageFileDirectoryExistsRule($audioFs))
|
||||
->default($audioPath),
|
||||
|
||||
TextInput::make('script')
|
||||
@@ -80,7 +84,9 @@ trait MoveAllActionTrait
|
||||
->helperText(__('filament.actions.storage.move.fields.path.help'))
|
||||
->hidden($scriptPath === null)
|
||||
->required($scriptPath !== null)
|
||||
->rules(['string', 'doesnt_start_with:/', "ends_with:.txt", new StorageFileDirectoryExistsRule($scriptFs)])
|
||||
->doesntStartWith('/')
|
||||
->endsWith('.txt')
|
||||
->rule(new StorageFileDirectoryExistsRule($scriptFs))
|
||||
->default($scriptPath),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands\Storage\Admin;
|
||||
|
||||
use App\Actions\Storage\Admin\Dump\DumpAction;
|
||||
use App\Actions\Storage\Admin\Dump\DumpAdminAction;
|
||||
|
||||
/**
|
||||
* Class AdminDumpCommand.
|
||||
*/
|
||||
class AdminDumpCommand extends DumpCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'db:dump-admin
|
||||
{--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 : 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}
|
||||
';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Produces sanitized database dump, targeting admin-related tables for seeding purposes';
|
||||
|
||||
/**
|
||||
* Get the underlying action.
|
||||
*
|
||||
* @return DumpAction
|
||||
*/
|
||||
protected function action(): DumpAction
|
||||
{
|
||||
return new DumpAdminAction($this->options());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands\Storage\Admin;
|
||||
|
||||
use App\Actions\Storage\Admin\Dump\DumpAction;
|
||||
use App\Actions\Storage\Admin\Dump\DumpAuthAction;
|
||||
|
||||
/**
|
||||
* Class AuthDumpCommand.
|
||||
*/
|
||||
class AuthDumpCommand extends DumpCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'db:dump-auth
|
||||
{--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 : 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}
|
||||
';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Produces sanitized database dump, targeting auth-related tables for seeding purposes';
|
||||
|
||||
/**
|
||||
* Get the underlying action.
|
||||
*
|
||||
* @return DumpAction
|
||||
*/
|
||||
protected function action(): DumpAction
|
||||
{
|
||||
return new DumpAuthAction($this->options());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands\Storage\Admin;
|
||||
|
||||
use App\Actions\Storage\Admin\Dump\DumpAction;
|
||||
use App\Actions\Storage\Admin\Dump\DumpDiscordAction;
|
||||
|
||||
/**
|
||||
* Class DiscordDumpCommand.
|
||||
*/
|
||||
class DiscordDumpCommand extends DumpCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $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 : 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}
|
||||
';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Produces sanitized database dump, targeting discord-related tables for seeding purposes';
|
||||
|
||||
/**
|
||||
* Get the underlying action.
|
||||
*
|
||||
* @return DumpAction
|
||||
*/
|
||||
protected function action(): DumpAction
|
||||
{
|
||||
return new DumpDiscordAction($this->options());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands\Storage\Admin;
|
||||
|
||||
use App\Actions\Storage\Admin\Dump\DumpAction;
|
||||
use App\Actions\Storage\Admin\Dump\DumpListAction;
|
||||
|
||||
/**
|
||||
* Class ListDumpCommand.
|
||||
*/
|
||||
class ListDumpCommand extends DumpCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'db:dump-list
|
||||
{--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 : 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}
|
||||
';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Produces sanitized database dump, targeting list-related tables for seeding purposes';
|
||||
|
||||
/**
|
||||
* Get the underlying action.
|
||||
*
|
||||
* @return DumpAction
|
||||
*/
|
||||
protected function action(): DumpAction
|
||||
{
|
||||
return new DumpListAction($this->options());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands\Storage\Admin;
|
||||
|
||||
use App\Actions\Storage\Admin\Dump\DumpAction;
|
||||
use App\Actions\Storage\Admin\Dump\DumpUserAction;
|
||||
|
||||
/**
|
||||
* Class UserDumpCommand.
|
||||
*/
|
||||
class UserDumpCommand extends DumpCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'db:dump-user
|
||||
{--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 : 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}
|
||||
';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Produces sanitized database dump, targeting user-related tables for seeding purposes';
|
||||
|
||||
/**
|
||||
* Get the underlying action.
|
||||
*
|
||||
* @return DumpAction
|
||||
*/
|
||||
protected function action(): DumpAction
|
||||
{
|
||||
return new DumpUserAction($this->options());
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,13 @@ declare(strict_types=1);
|
||||
namespace App\Console;
|
||||
|
||||
use App\Console\Commands\Models\SyncViewAggregatesCommand;
|
||||
use App\Console\Commands\Storage\Admin\AdminDumpCommand;
|
||||
use App\Console\Commands\Storage\Admin\AuthDumpCommand;
|
||||
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;
|
||||
use App\Console\Commands\Storage\Admin\UserDumpCommand;
|
||||
use App\Console\Commands\Storage\Admin\WikiDumpCommand;
|
||||
use App\Models\BaseModel;
|
||||
use BezhanSalleh\FilamentExceptions\Models\Exception;
|
||||
@@ -44,12 +49,42 @@ class Kernel extends ConsoleKernel
|
||||
->storeOutput()
|
||||
->everyFifteenMinutes();
|
||||
|
||||
$schedule->command(AdminDumpCommand::class)
|
||||
->withoutOverlapping()
|
||||
->runInBackground()
|
||||
->storeOutput()
|
||||
->daily();
|
||||
|
||||
$schedule->command(AuthDumpCommand::class)
|
||||
->withoutOverlapping()
|
||||
->runInBackground()
|
||||
->storeOutput()
|
||||
->daily();
|
||||
|
||||
$schedule->command(DiscordDumpCommand::class)
|
||||
->withoutOverlapping()
|
||||
->runInBackground()
|
||||
->storeOutput()
|
||||
->daily();
|
||||
|
||||
$schedule->command(DocumentDumpCommand::class)
|
||||
->withoutOverlapping()
|
||||
->runInBackground()
|
||||
->storeOutput()
|
||||
->daily();
|
||||
|
||||
$schedule->command(ListDumpCommand::class)
|
||||
->withoutOverlapping()
|
||||
->runInBackground()
|
||||
->storeOutput()
|
||||
->daily();
|
||||
|
||||
$schedule->command(UserDumpCommand::class)
|
||||
->withoutOverlapping()
|
||||
->runInBackground()
|
||||
->storeOutput()
|
||||
->daily();
|
||||
|
||||
$schedule->command(WikiDumpCommand::class)
|
||||
->withoutOverlapping()
|
||||
->runInBackground()
|
||||
|
||||
@@ -74,7 +74,7 @@ class ThemeCreated extends WikiCreatedEvent implements UpdateRelatedIndicesEvent
|
||||
|
||||
/**
|
||||
* Update the sequence attribute of the first theme when creating a new sequence theme.
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function updateFirstTheme(): void
|
||||
|
||||
@@ -42,7 +42,7 @@ class MembershipCreated extends WikiCreatedEvent implements UpdateRelatedIndices
|
||||
*/
|
||||
protected function getDiscordMessageDescription(): string
|
||||
{
|
||||
return "Membership: Member '**{$this->getModel()->member->getName()}**' of Group '**{$this->getModel()->artist->getName()}**' has been created.";
|
||||
return "Membership '**{$this->getModel()->member->getName()}**' of Group '**{$this->getModel()->artist->getName()}**' has been created.";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,7 @@ class MembershipDeleted extends WikiDeletedEvent implements UpdateRelatedIndices
|
||||
*/
|
||||
protected function getDiscordMessageDescription(): string
|
||||
{
|
||||
return "Membership: Member '**{$this->getModel()->member->getName()}**' of Group '**{$this->getModel()->artist->getName()}**' has been deleted.";
|
||||
return "Membership '**{$this->getModel()->member->getName()}**' of Group '**{$this->getModel()->artist->getName()}**' has been deleted.";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -52,7 +52,7 @@ class PerformanceCreated extends WikiCreatedEvent implements UpdateRelatedIndice
|
||||
$artist = $performance->artist;
|
||||
|
||||
if ($this->getModel()->isMembership()) {
|
||||
return "Song '**{$song->getName()}**' has been attached to Artist '**{$artist->member->getName()}**' via Group '**{$artist->artist->getName()}**'.";
|
||||
return "Song '**{$song->getName()}**' has been attached to Artist '**{$artist->member->getName()}**' as member of '**{$artist->artist->getName()}**'.";
|
||||
}
|
||||
|
||||
return "Song '**{$song->getName()}**' has been attached to Artist '**{$artist->getName()}**'.";
|
||||
|
||||
@@ -14,6 +14,7 @@ use App\Models\Wiki\Song\Performance;
|
||||
use App\Pivots\Wiki\ArtistSong;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
/**
|
||||
* Class PerformanceDeleted.
|
||||
@@ -89,7 +90,14 @@ class PerformanceDeleted extends WikiDeletedEvent implements UpdateRelatedIndice
|
||||
*/
|
||||
public function updateRelatedIndices(): void
|
||||
{
|
||||
$performance = $this->getModel()->load([Performance::RELATION_ARTIST]);
|
||||
$performance = $this->getModel()->load([
|
||||
Performance::RELATION_ARTIST => function (MorphTo $morphTo) {
|
||||
$morphTo->morphWith([
|
||||
Artist::class => [],
|
||||
Membership::class => [Membership::RELATION_ARTIST, Membership::RELATION_MEMBER]
|
||||
]);
|
||||
}
|
||||
]);
|
||||
|
||||
if ($performance->isMembership()) {
|
||||
$performance->artist->artist->searchable();
|
||||
|
||||
@@ -6,7 +6,10 @@ namespace App\Events\Wiki\Song\Performance;
|
||||
|
||||
use App\Contracts\Events\UpdateRelatedIndicesEvent;
|
||||
use App\Events\BaseEvent;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\Song\Membership;
|
||||
use App\Models\Wiki\Song\Performance;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
/**
|
||||
* Class PerformanceDeleting.
|
||||
@@ -42,7 +45,14 @@ class PerformanceDeleting extends BaseEvent implements UpdateRelatedIndicesEvent
|
||||
*/
|
||||
public function updateRelatedIndices(): void
|
||||
{
|
||||
$performance = $this->getModel()->load([Performance::RELATION_ARTIST]);
|
||||
$performance = $this->getModel()->load([
|
||||
Performance::RELATION_ARTIST => function (MorphTo $morphTo) {
|
||||
$morphTo->morphWith([
|
||||
Artist::class => [],
|
||||
Membership::class => [Membership::RELATION_ARTIST, Membership::RELATION_MEMBER]
|
||||
]);
|
||||
}
|
||||
]);
|
||||
|
||||
if ($performance->isForceDeleting()) {
|
||||
if ($performance->isMembership()) {
|
||||
|
||||
@@ -12,6 +12,7 @@ use App\Models\Wiki\Song\Membership;
|
||||
use App\Models\Wiki\Song\Performance;
|
||||
use App\Pivots\Wiki\ArtistSong;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
/**
|
||||
* Class PerformanceRestored.
|
||||
@@ -57,7 +58,14 @@ class PerformanceRestored extends WikiRestoredEvent implements UpdateRelatedIndi
|
||||
*/
|
||||
public function updateRelatedIndices(): void
|
||||
{
|
||||
$performance = $this->getModel()->load([Performance::RELATION_ARTIST]);
|
||||
$performance = $this->getModel()->load([
|
||||
Performance::RELATION_ARTIST => function (MorphTo $morphTo) {
|
||||
$morphTo->morphWith([
|
||||
Artist::class => [],
|
||||
Membership::class => [Membership::RELATION_ARTIST, Membership::RELATION_MEMBER]
|
||||
]);
|
||||
}
|
||||
]);
|
||||
|
||||
if ($performance->isMembership()) {
|
||||
$performance->artist->artist->searchable();
|
||||
|
||||
@@ -12,6 +12,7 @@ use App\Models\Wiki\Song\Membership;
|
||||
use App\Models\Wiki\Song\Performance;
|
||||
use App\Pivots\Wiki\ArtistSong;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
/**
|
||||
* Class PerformanceUpdated.
|
||||
@@ -58,7 +59,14 @@ class PerformanceUpdated extends WikiUpdatedEvent implements UpdateRelatedIndice
|
||||
*/
|
||||
public function updateRelatedIndices(): void
|
||||
{
|
||||
$performance = $this->getModel()->load([Performance::RELATION_ARTIST]);
|
||||
$performance = $this->getModel()->load([
|
||||
Performance::RELATION_ARTIST => function (MorphTo $morphTo) {
|
||||
$morphTo->morphWith([
|
||||
Artist::class => [],
|
||||
Membership::class => [Membership::RELATION_ARTIST, Membership::RELATION_MEMBER]
|
||||
]);
|
||||
}
|
||||
]);
|
||||
|
||||
if ($performance->isMembership()) {
|
||||
$performance->artist->artist->searchable();
|
||||
|
||||
@@ -13,7 +13,6 @@ use App\Models\Wiki\Video;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Support\Enums\MaxWidth;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class VideoDiscordNotificationBulkAction.
|
||||
@@ -69,7 +68,7 @@ class VideoDiscordNotificationBulkAction extends BaseBulkAction
|
||||
->options(DiscordNotificationType::asSelectArray())
|
||||
->default(DiscordNotificationType::ADDED->value)
|
||||
->required()
|
||||
->rules(['required', new Enum(DiscordNotificationType::class)]),
|
||||
->enum(DiscordNotificationType::class),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use App\Models\Auth\User;
|
||||
use App\Models\BaseModel;
|
||||
use Filament\Forms\Components\Select as ComponentsSelect;
|
||||
use Filament\Forms\Form;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Laravel\Scout\Searchable;
|
||||
|
||||
/**
|
||||
@@ -49,7 +50,7 @@ class BelongsTo extends ComponentsSelect
|
||||
* Set the filament resource for the relation. Relation should be set if BelongsToThrough.
|
||||
*
|
||||
* @param class-string<BaseResource> $resource
|
||||
* @param string|null $relation
|
||||
* @param string|null $relation
|
||||
* @return static
|
||||
*/
|
||||
public function resource(string $resource, ?string $relation = ''): static
|
||||
@@ -65,9 +66,10 @@ class BelongsTo extends ComponentsSelect
|
||||
* Determine if the create option is available. The resource is required for this.
|
||||
*
|
||||
* @param bool $condition
|
||||
* @param array|null $eagerLoads
|
||||
* @return static
|
||||
*/
|
||||
public function showCreateOption(bool $condition = true): static
|
||||
public function showCreateOption(bool $condition = true, ?array $eagerLoads = []): static
|
||||
{
|
||||
$this->showCreateOption = $condition;
|
||||
$this->reload();
|
||||
@@ -87,12 +89,17 @@ class BelongsTo extends ComponentsSelect
|
||||
$this->searchable();
|
||||
$this->getOptionLabelUsing(fn ($state) => static::getSearchLabelWithBlade($model::find($state)));
|
||||
|
||||
$eagerLoads = method_exists($model, 'getEagerLoadsForSubtitle')
|
||||
? $model::getEagerLoadsForSubtitle()
|
||||
: [];
|
||||
|
||||
if (in_array(Searchable::class, class_uses_recursive($model))) {
|
||||
return $this
|
||||
->getSearchResultsUsing(function (string $search) use ($model) {
|
||||
->getSearchResultsUsing(function (string $search) use ($model, $eagerLoads) {
|
||||
$search = $this->escapeReservedChars($search);
|
||||
/** @phpstan-ignore-next-line */
|
||||
return $model::search($search)
|
||||
->query(fn (Builder $query) => $query->with($eagerLoads))
|
||||
->take(25)
|
||||
->get()
|
||||
->mapWithKeys(fn (BaseModel $model) => [$model->getKey() => static::getSearchLabelWithBlade($model)])
|
||||
@@ -101,9 +108,10 @@ class BelongsTo extends ComponentsSelect
|
||||
}
|
||||
|
||||
return $this
|
||||
->getSearchResultsUsing(function (string $search) use ($model) {
|
||||
->getSearchResultsUsing(function (string $search) use ($model, $eagerLoads) {
|
||||
return $model::query()
|
||||
->where($this->resource->getRecordTitleAttribute(), ComparisonOperator::LIKE->value, "%$search%")
|
||||
->with($eagerLoads)
|
||||
->take(25)
|
||||
->get()
|
||||
->mapWithKeys(fn (BaseModel|User $model) => [$model->getKey() => static::getSearchLabelWithBlade($model)])
|
||||
|
||||
@@ -10,6 +10,7 @@ use App\Filament\Components\Columns\BelongsToColumn;
|
||||
use App\Filament\Components\Columns\TextColumn;
|
||||
use App\Filament\Components\Filters\DateFilter;
|
||||
use App\Filament\Components\Infolist\BelongsToEntry;
|
||||
use App\Filament\Components\Infolist\KeyValueThreeEntry;
|
||||
use App\Filament\Components\Infolist\TextEntry;
|
||||
use App\Filament\Resources\Admin\ActionLog\Pages\ManageActionLogs;
|
||||
use App\Filament\Resources\Auth\User;
|
||||
@@ -18,9 +19,11 @@ use App\Models\Admin\ActionLog as ActionLogModel;
|
||||
use App\Models\Auth\User as UserModel;
|
||||
use App\Models\BaseModel;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Forms\Components\KeyValue;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Infolists\Components\KeyValueEntry;
|
||||
use Filament\Infolists\Components\RepeatableEntry;
|
||||
use Filament\Infolists\Components\TextEntry\TextEntrySize;
|
||||
use Filament\Infolists\Infolist;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
@@ -139,6 +142,13 @@ class ActionLog extends BaseResource
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
KeyValue::make(ActionLogModel::ATTRIBUTE_FIELDS)
|
||||
->label(__('filament.fields.action_log.fields.name'))
|
||||
->keyLabel(__('filament.fields.action_log.fields.keys'))
|
||||
->valueLabel(__('filament.fields.action_log.fields.values'))
|
||||
->columnSpanFull()
|
||||
->hidden(fn ($state) => is_null($state)),
|
||||
|
||||
Textarea::make(ActionLogModel::ATTRIBUTE_EXCEPTION)
|
||||
->label(__('filament.fields.action_log.exception'))
|
||||
->disabled()
|
||||
@@ -221,7 +231,9 @@ class ActionLog extends BaseResource
|
||||
->dateTime(),
|
||||
|
||||
KeyValueEntry::make(ActionLogModel::ATTRIBUTE_FIELDS)
|
||||
->label(__('filament.fields.action_log.fields'))
|
||||
->label(__('filament.fields.action_log.fields.name'))
|
||||
->keyLabel(__('filament.fields.action_log.fields.keys'))
|
||||
->valueLabel(__('filament.fields.action_log.fields.values'))
|
||||
->columnSpanFull()
|
||||
->hidden(fn ($state) => is_null($state)),
|
||||
|
||||
@@ -229,7 +241,8 @@ class ActionLog extends BaseResource
|
||||
->label(__('filament.fields.action_log.exception'))
|
||||
->columnSpanFull()
|
||||
->size(TextEntrySize::Large),
|
||||
])->columns(3);
|
||||
])
|
||||
->columns(3);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -101,7 +101,6 @@ class Announcement extends BaseResource
|
||||
MarkdownEditor::make(AnnouncementModel::ATTRIBUTE_CONTENT)
|
||||
->label(__('filament.fields.announcement.content'))
|
||||
->required()
|
||||
->rules(['required', 'max:65535'])
|
||||
->maxLength(65535),
|
||||
])
|
||||
->columns(1);
|
||||
|
||||
@@ -119,7 +119,6 @@ class Dump extends BaseResource
|
||||
->label(__('filament.fields.dump.path'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192'])
|
||||
->hiddenOn(['create', 'edit']),
|
||||
])
|
||||
->columns(1);
|
||||
|
||||
@@ -117,15 +117,13 @@ class Feature extends BaseResource
|
||||
->helperText(__('filament.fields.feature.key.help'))
|
||||
->readOnly()
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192']),
|
||||
->maxLength(192),
|
||||
|
||||
TextInput::make(FeatureModel::ATTRIBUTE_VALUE)
|
||||
->label(__('filament.fields.feature.value.name'))
|
||||
->helperText(__('filament.fields.feature.value.help'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192']),
|
||||
->maxLength(192),
|
||||
])
|
||||
->columns(1);
|
||||
}
|
||||
|
||||
@@ -129,8 +129,6 @@ class FeaturedTheme extends BaseResource
|
||||
*/
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
$allowedDateFormats = array_column(AllowedDateFormat::cases(), 'value');
|
||||
|
||||
return $form
|
||||
->schema([
|
||||
DatePicker::make(FeaturedThemeModel::ATTRIBUTE_START_AT)
|
||||
|
||||
@@ -121,7 +121,6 @@ class Permission extends BaseResource
|
||||
->label(__('filament.fields.permission.name'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192'])
|
||||
->hiddenOn(['edit']),
|
||||
])
|
||||
->columns(1);
|
||||
|
||||
@@ -128,13 +128,12 @@ class Role extends BaseResource
|
||||
TextInput::make(RoleModel::ATTRIBUTE_NAME)
|
||||
->label(__('filament.fields.role.name'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192']),
|
||||
->maxLength(192),
|
||||
|
||||
Checkbox::make(RoleModel::ATTRIBUTE_DEFAULT)
|
||||
->label(__('filament.fields.role.default.name'))
|
||||
->helperText(__('filament.fields.role.default.help'))
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
ColorPicker::make(RoleModel::ATTRIBUTE_COLOR)
|
||||
->label(__('filament.fields.role.color.name'))
|
||||
@@ -143,10 +142,8 @@ class Role extends BaseResource
|
||||
TextInput::make(RoleModel::ATTRIBUTE_PRIORITY)
|
||||
->label(__('filament.fields.role.priority.name'))
|
||||
->helperText(__('filament.fields.role.priority.help'))
|
||||
->numeric()
|
||||
->minValue(1)
|
||||
->nullable()
|
||||
->rules(['nullable', 'integer', 'min:1']),
|
||||
->integer()
|
||||
->minValue(1),
|
||||
])
|
||||
->columns(1);
|
||||
}
|
||||
|
||||
@@ -125,15 +125,13 @@ class User extends BaseResource
|
||||
TextInput::make(UserModel::ATTRIBUTE_NAME)
|
||||
->label(__('filament.fields.user.name'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192']),
|
||||
->maxLength(192),
|
||||
|
||||
TextInput::make(UserModel::ATTRIBUTE_EMAIL)
|
||||
->label(__('filament.fields.user.email'))
|
||||
->email()
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'email', 'max:192']),
|
||||
->maxLength(192),
|
||||
])
|
||||
->columns(1);
|
||||
}
|
||||
|
||||
@@ -143,15 +143,13 @@ class DiscordThread extends BaseResource
|
||||
->disabledOn(['edit'])
|
||||
->formatStateUsing(fn ($state) => strval($state))
|
||||
->required()
|
||||
->rules(['required'])
|
||||
->live()
|
||||
->afterStateUpdated(fn (Set $set, string $state) => $set(DiscordThreadModel::ATTRIBUTE_NAME, Arr::get(new DiscordThreadAction()->get($state), 'thread.name'))),
|
||||
|
||||
TextInput::make(DiscordThreadModel::ATTRIBUTE_NAME)
|
||||
->label(__('filament.fields.discord_thread.name.name'))
|
||||
->helperText(__('filament.fields.discord_thread.name.help'))
|
||||
->required()
|
||||
->rules(['required', 'string']),
|
||||
->required(),
|
||||
|
||||
BelongsTo::make(DiscordThreadModel::ATTRIBUTE_ANIME)
|
||||
->resource(AnimeResource::class)
|
||||
|
||||
@@ -121,7 +121,6 @@ class Page extends BaseResource
|
||||
->helperText(__('filament.fields.page.name.help'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192'])
|
||||
->live(true)
|
||||
->afterStateUpdated(fn (Set $set, Get $get) => static::setSlug($set, $get)),
|
||||
|
||||
@@ -135,7 +134,6 @@ class Page extends BaseResource
|
||||
->helperText(__('filament.fields.page.body.help'))
|
||||
->required()
|
||||
->maxLength(16777215)
|
||||
->rules(['required', 'max:16777215'])
|
||||
->columnSpan(2)
|
||||
->formatStateUsing(fn (?PageModel $record) => $record?->body),
|
||||
])
|
||||
|
||||
+3
-5
@@ -29,7 +29,6 @@ use Filament\Resources\RelationManagers\RelationGroup;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class ExternalEntry.
|
||||
@@ -132,13 +131,11 @@ class ExternalEntry extends BaseResource
|
||||
BelongsTo::make(ExternalEntryModel::ATTRIBUTE_PROFILE)
|
||||
->resource(ExternalProfileResource::class)
|
||||
->required()
|
||||
->rules(['required'])
|
||||
->hiddenOn([ExternalEntryExternalProfileRelationManager::class]),
|
||||
|
||||
BelongsTo::make(ExternalEntryModel::ATTRIBUTE_ANIME)
|
||||
->resource(Anime::class)
|
||||
->required()
|
||||
->rules(['required']),
|
||||
->required(),
|
||||
|
||||
TextInput::make(ExternalEntryModel::ATTRIBUTE_SCORE)
|
||||
->label(__('filament.fields.external_entry.score.name'))
|
||||
@@ -149,7 +146,8 @@ class ExternalEntry extends BaseResource
|
||||
->label(__('filament.fields.external_entry.watch_status.name'))
|
||||
->helperText(__('filament.fields.external_entry.watch_status.help'))
|
||||
->options(ExternalEntryWatchStatus::asSelectArray())
|
||||
->rules([new Enum(ExternalEntryWatchStatus::class)]),
|
||||
->required()
|
||||
->enum(ExternalEntryWatchStatus::class),
|
||||
|
||||
Checkbox::make(ExternalEntryModel::ATTRIBUTE_IS_FAVORITE)
|
||||
->label(__('filament.fields.external_entry.is_favorite.name'))
|
||||
|
||||
@@ -26,7 +26,6 @@ use Filament\Infolists\Infolist;
|
||||
use Filament\Resources\RelationManagers\RelationGroup;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class ExternalProfile.
|
||||
@@ -142,22 +141,21 @@ class ExternalProfile extends BaseResource
|
||||
->label(__('filament.fields.external_profile.name.name'))
|
||||
->helperText(__('filament.fields.external_profile.name.help'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192']),
|
||||
->maxLength(192),
|
||||
|
||||
Select::make(ExternalProfileModel::ATTRIBUTE_SITE)
|
||||
->label(__('filament.fields.external_profile.site.name'))
|
||||
->helperText(__('filament.fields.external_profile.site.help'))
|
||||
->options(ExternalProfileSite::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(ExternalProfileSite::class)]),
|
||||
->enum(ExternalProfileSite::class),
|
||||
|
||||
Select::make(ExternalProfileModel::ATTRIBUTE_VISIBILITY)
|
||||
->label(__('filament.fields.external_profile.visibility.name'))
|
||||
->helperText(__('filament.fields.external_profile.visibility.help'))
|
||||
->options(ExternalProfileVisibility::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(ExternalProfileVisibility::class)]),
|
||||
->enum(ExternalProfileVisibility::class),
|
||||
])
|
||||
->columns(2);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ use Filament\Infolists\Infolist;
|
||||
use Filament\Resources\RelationManagers\RelationGroup;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class Playlist.
|
||||
@@ -149,15 +148,14 @@ class Playlist extends BaseResource
|
||||
->label(__('filament.fields.playlist.name.name'))
|
||||
->helperText(__('filament.fields.playlist.name.help'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192']),
|
||||
->maxLength(192),
|
||||
|
||||
Select::make(PlaylistModel::ATTRIBUTE_VISIBILITY)
|
||||
->label(__('filament.fields.playlist.visibility.name'))
|
||||
->helperText(__('filament.fields.playlist.visibility.help'))
|
||||
->options(PlaylistVisibility::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(PlaylistVisibility::class)]),
|
||||
->enum(PlaylistVisibility::class),
|
||||
|
||||
TextInput::make(PlaylistModel::ATTRIBUTE_HASHID)
|
||||
->label(__('filament.fields.playlist.hashid.name'))
|
||||
@@ -175,9 +173,7 @@ class Playlist extends BaseResource
|
||||
Textarea::make(PlaylistModel::ATTRIBUTE_DESCRIPTION)
|
||||
->label(__('filament.fields.playlist.description.name'))
|
||||
->helperText(__('filament.fields.playlist.description.help'))
|
||||
->nullable()
|
||||
->maxLength(1000)
|
||||
->rules(['nullable', 'max:1000'])
|
||||
->columnSpanFull(),
|
||||
])
|
||||
->columns(2);
|
||||
|
||||
@@ -149,7 +149,6 @@ class Track extends BaseResource
|
||||
BelongsTo::make(TrackModel::ATTRIBUTE_PLAYLIST)
|
||||
->resource(PlaylistResource::class)
|
||||
->required()
|
||||
->rules(['required'])
|
||||
->hiddenOn([TrackPlaylistRelationManager::class]),
|
||||
|
||||
BelongsTo::make(TrackModel::ATTRIBUTE_ENTRY)
|
||||
|
||||
@@ -39,7 +39,6 @@ use Filament\Tables\Actions\ActionGroup;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class Anime.
|
||||
@@ -152,7 +151,6 @@ class Anime extends BaseResource
|
||||
->helperText(__('filament.fields.anime.name.help'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->rules(['required', 'max:255'])
|
||||
->live(true)
|
||||
->afterStateUpdated(fn (Set $set, ?string $state) => $set(AnimeModel::ATTRIBUTE_SLUG, Str::slug($state, '_'))),
|
||||
|
||||
@@ -163,9 +161,9 @@ class Anime extends BaseResource
|
||||
TextInput::make(AnimeModel::ATTRIBUTE_YEAR)
|
||||
->label(__('filament.fields.anime.year.name'))
|
||||
->helperText(__('filament.fields.anime.year.help'))
|
||||
->numeric()
|
||||
->required()
|
||||
->rules(['required', 'digits:4', 'integer'])
|
||||
->integer()
|
||||
->length(4)
|
||||
->minValue(1960)
|
||||
->maxValue(intval(date('Y')) + 1),
|
||||
|
||||
@@ -173,24 +171,23 @@ class Anime extends BaseResource
|
||||
->label(__('filament.fields.anime.season.name'))
|
||||
->helperText(__('filament.fields.anime.season.help'))
|
||||
->options(AnimeSeason::asSelectArrayStyled())
|
||||
->searchable()
|
||||
->allowHtml()
|
||||
->required()
|
||||
->rules(['required', new Enum(AnimeSeason::class)]),
|
||||
->enum(AnimeSeason::class)
|
||||
->searchable()
|
||||
->allowHtml(),
|
||||
|
||||
Select::make(AnimeModel::ATTRIBUTE_MEDIA_FORMAT)
|
||||
->label(__('filament.fields.anime.media_format.name'))
|
||||
->helperText(__('filament.fields.anime.media_format.help'))
|
||||
->options(AnimeMediaFormat::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(AnimeMediaFormat::class)]),
|
||||
->enum(AnimeMediaFormat::class),
|
||||
|
||||
MarkdownEditor::make(AnimeModel::ATTRIBUTE_SYNOPSIS)
|
||||
->label(__('filament.fields.anime.synopsis.name'))
|
||||
->helperText(__('filament.fields.anime.synopsis.help'))
|
||||
->columnSpan(2)
|
||||
->maxLength(65535)
|
||||
->rules('max:65535'),
|
||||
->maxLength(65535),
|
||||
])
|
||||
->columns(2);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ use Filament\Resources\RelationManagers\RelationGroup;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class Synonym.
|
||||
@@ -146,14 +145,13 @@ class Synonym extends BaseResource
|
||||
->helperText(__('filament.fields.anime_synonym.type.help'))
|
||||
->options(AnimeSynonymType::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(AnimeSynonymType::class)]),
|
||||
->enum(AnimeSynonymType::class),
|
||||
|
||||
TextInput::make(SynonymModel::ATTRIBUTE_TEXT)
|
||||
->label(__('filament.fields.anime_synonym.text.name'))
|
||||
->helperText(__('filament.fields.anime_synonym.text.help'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->rules(['required', 'max:255']),
|
||||
->maxLength(255),
|
||||
])
|
||||
->columns(1);
|
||||
}
|
||||
|
||||
@@ -29,8 +29,10 @@ use App\Filament\Resources\Wiki\Song\RelationManagers\PerformanceSongRelationMan
|
||||
use App\Filament\Resources\Wiki\Song\RelationManagers\ThemeSongRelationManager;
|
||||
use App\Models\Wiki\Anime\AnimeTheme as ThemeModel;
|
||||
use App\Models\Wiki\Anime\AnimeTheme;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\Group;
|
||||
use App\Models\Wiki\Song;
|
||||
use App\Models\Wiki\Song\Membership;
|
||||
use Filament\Forms\Components\Repeater;
|
||||
use Filament\Forms\Components\Tabs;
|
||||
use Filament\Forms\Components\Tabs\Tab;
|
||||
@@ -47,8 +49,8 @@ use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class Theme.
|
||||
@@ -120,7 +122,7 @@ class Theme extends BaseResource
|
||||
*/
|
||||
public static function getRecordTitle(?Model $record): ?string
|
||||
{
|
||||
return $record instanceof ThemeModel ? $record->anime->getName() . ' ' . $record->slug : null;
|
||||
return $record instanceof ThemeModel ? $record->getName() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,10 +157,20 @@ class Theme extends BaseResource
|
||||
$query = parent::getEloquentQuery();
|
||||
|
||||
// Necessary to prevent lazy loading when loading related resources
|
||||
/** @phpstan-ignore-next-line */
|
||||
return $query->with([
|
||||
AnimeTheme::RELATION_ANIME,
|
||||
AnimeTheme::RELATION_GROUP,
|
||||
AnimeTheme::RELATION_ENTRIES,
|
||||
AnimeTheme::RELATION_PERFORMANCES,
|
||||
AnimeTheme::RELATION_SONG,
|
||||
AnimeTheme::RELATION_GROUP
|
||||
'song.animethemes',
|
||||
AnimeTheme::RELATION_PERFORMANCES_ARTISTS => function (MorphTo $morphTo) {
|
||||
$morphTo->morphWith([
|
||||
Artist::class => [],
|
||||
Membership::class => [Membership::RELATION_ARTIST, Membership::RELATION_MEMBER]
|
||||
]);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -182,33 +194,31 @@ class Theme extends BaseResource
|
||||
BelongsTo::make(ThemeModel::ATTRIBUTE_ANIME)
|
||||
->resource(AnimeResource::class)
|
||||
->hiddenOn(ThemeRelationManager::class)
|
||||
->required()
|
||||
->rules(['required']),
|
||||
->required(),
|
||||
|
||||
Select::make(ThemeModel::ATTRIBUTE_TYPE)
|
||||
->label(__('filament.fields.anime_theme.type.name'))
|
||||
->helperText(__('filament.fields.anime_theme.type.help'))
|
||||
->options(ThemeType::asSelectArray())
|
||||
->required()
|
||||
->enum(ThemeType::class)
|
||||
->live(true)
|
||||
->afterStateUpdated(fn (Set $set, Get $get) => Theme::setThemeSlug($set, $get))
|
||||
->rules(['required', new Enum(ThemeType::class)]),
|
||||
->afterStateUpdated(fn (Set $set, Get $get) => Theme::setThemeSlug($set, $get)),
|
||||
|
||||
TextInput::make(ThemeModel::ATTRIBUTE_SEQUENCE)
|
||||
->label(__('filament.fields.anime_theme.sequence.name'))
|
||||
->helperText(__('filament.fields.anime_theme.sequence.help'))
|
||||
->numeric()
|
||||
->integer()
|
||||
->live(true)
|
||||
->afterStateUpdated(fn (Set $set, Get $get) => Theme::setThemeSlug($set, $get))
|
||||
->rules(['nullable', 'integer']),
|
||||
->afterStateUpdated(fn (Set $set, Get $get) => Theme::setThemeSlug($set, $get)),
|
||||
|
||||
TextInput::make(ThemeModel::ATTRIBUTE_SLUG)
|
||||
->label(__('filament.fields.anime_theme.slug.name'))
|
||||
->helperText(__('filament.fields.anime_theme.slug.help'))
|
||||
->required()
|
||||
->readOnly()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192', 'alpha_dash']),
|
||||
->alphaDash()
|
||||
->readOnly(),
|
||||
|
||||
BelongsTo::make(ThemeModel::ATTRIBUTE_GROUP)
|
||||
->resource(GroupResource::class)
|
||||
@@ -227,8 +237,6 @@ class Theme extends BaseResource
|
||||
->afterStateUpdated(function (Set $set, $state) {
|
||||
/** @var Song|null $song */
|
||||
$song = Song::find($state);
|
||||
|
||||
if (!$song) return;
|
||||
$set('performances', PerformanceSongRelationManager::formatArtists($song));
|
||||
}),
|
||||
|
||||
@@ -273,8 +281,7 @@ class Theme extends BaseResource
|
||||
->label(__('filament.fields.anime_theme.sequence.name')),
|
||||
|
||||
TextColumn::make(ThemeModel::ATTRIBUTE_SLUG)
|
||||
->label(__('filament.fields.anime_theme.slug.name'))
|
||||
->formatStateUsing(fn ($record) => $record->getName()),
|
||||
->label(__('filament.fields.anime_theme.slug.name')),
|
||||
|
||||
BelongsToColumn::make(ThemeModel::RELATION_GROUP, GroupResource::class),
|
||||
|
||||
@@ -310,9 +317,8 @@ class Theme extends BaseResource
|
||||
TextEntry::make(ThemeModel::ATTRIBUTE_SEQUENCE)
|
||||
->label(__('filament.fields.anime_theme.sequence.name')),
|
||||
|
||||
TextEntry::make(ThemeModel::ATTRIBUTE_ID)
|
||||
->label(__('filament.fields.anime_theme.slug.name'))
|
||||
->formatStateUsing(fn ($state) => ThemeModel::withTrashed()->find(intval($state))->getName()),
|
||||
TextEntry::make(ThemeModel::ATTRIBUTE_SLUG)
|
||||
->label(__('filament.fields.anime_theme.slug.name')),
|
||||
|
||||
BelongsToEntry::make(ThemeModel::RELATION_GROUP, GroupResource::class)
|
||||
->label(__('filament.resources.singularLabel.group')),
|
||||
|
||||
@@ -169,7 +169,6 @@ class Entry extends BaseResource
|
||||
->resource(AnimeResource::class, EntryModel::RELATION_ANIME_SHALLOW)
|
||||
->live(true)
|
||||
->required()
|
||||
->rules(['required'])
|
||||
->visibleOn([ListEntries::class, ViewEntry::class])
|
||||
->saveRelationshipsUsing(fn (EntryModel $record, $state) => $record->animetheme->anime()->associate(intval($state))->save()),
|
||||
|
||||
@@ -177,7 +176,6 @@ class Entry extends BaseResource
|
||||
->label(__('filament.resources.singularLabel.anime_theme'))
|
||||
->relationship(EntryModel::RELATION_THEME, ThemeModel::ATTRIBUTE_ID)
|
||||
->required()
|
||||
->rules(['required'])
|
||||
->visibleOn([ListEntries::class, ViewEntry::class])
|
||||
->options(function (Get $get) {
|
||||
return ThemeModel::query()
|
||||
@@ -190,30 +188,27 @@ class Entry extends BaseResource
|
||||
TextInput::make(EntryModel::ATTRIBUTE_VERSION)
|
||||
->label(__('filament.fields.anime_theme_entry.version.name'))
|
||||
->helperText(__('filament.fields.anime_theme_entry.version.help'))
|
||||
->numeric()
|
||||
->rules(['nullable', 'integer']),
|
||||
->integer(),
|
||||
|
||||
TextInput::make(EntryModel::ATTRIBUTE_EPISODES)
|
||||
->label(__('filament.fields.anime_theme_entry.episodes.name'))
|
||||
->helperText(__('filament.fields.anime_theme_entry.episodes.help'))
|
||||
->maxLength(192)
|
||||
->rules(['nullable', 'max:192']),
|
||||
->maxLength(192),
|
||||
|
||||
Checkbox::make(EntryModel::ATTRIBUTE_NSFW)
|
||||
->label(__('filament.fields.anime_theme_entry.nsfw.name'))
|
||||
->helperText(__('filament.fields.anime_theme_entry.nsfw.help'))
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
Checkbox::make(EntryModel::ATTRIBUTE_SPOILER)
|
||||
->label(__('filament.fields.anime_theme_entry.spoiler.name'))
|
||||
->helperText(__('filament.fields.anime_theme_entry.spoiler.help'))
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
TextInput::make(EntryModel::ATTRIBUTE_NOTES)
|
||||
->label(__('filament.fields.anime_theme_entry.notes.name'))
|
||||
->helperText(__('filament.fields.anime_theme_entry.notes.help'))
|
||||
->maxLength(192)
|
||||
->rules(['nullable', 'max:192']),
|
||||
->maxLength(192),
|
||||
])
|
||||
->columns(1);
|
||||
}
|
||||
|
||||
@@ -145,7 +145,6 @@ class Artist extends BaseResource
|
||||
->label(__('filament.fields.artist.name.name'))
|
||||
->helperText(__('filament.fields.artist.name.help'))
|
||||
->required()
|
||||
->rules(['required', 'max:192'])
|
||||
->maxLength(192)
|
||||
->live(true)
|
||||
->afterStateUpdated(fn (Set $set, ?string $state) => $set(ArtistModel::ATTRIBUTE_SLUG, Str::slug($state, '_'))),
|
||||
@@ -158,8 +157,7 @@ class Artist extends BaseResource
|
||||
->label(__('filament.fields.artist.information.name'))
|
||||
->helperText(__('filament.fields.artist.information.help'))
|
||||
->columnSpan(2)
|
||||
->maxLength(65535)
|
||||
->rules('max:65535'),
|
||||
->maxLength(65535),
|
||||
])
|
||||
->columns(2);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ use Filament\Infolists\Infolist;
|
||||
use Filament\Resources\RelationManagers\RelationGroup;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class ExternalResource.
|
||||
@@ -129,7 +128,7 @@ class ExternalResource extends BaseResource
|
||||
->helperText(__('filament.fields.external_resource.site.help'))
|
||||
->options(ResourceSite::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(ResourceSite::class)]),
|
||||
->enum(ResourceSite::class),
|
||||
|
||||
TextInput::make(ExternalResourceModel::ATTRIBUTE_LINK)
|
||||
->label(__('filament.fields.external_resource.link.name'))
|
||||
@@ -146,8 +145,7 @@ class ExternalResource extends BaseResource
|
||||
TextInput::make(ExternalResourceModel::ATTRIBUTE_EXTERNAL_ID)
|
||||
->label(__('filament.fields.external_resource.external_id.name'))
|
||||
->helperText(__('filament.fields.external_resource.external_id.help'))
|
||||
->numeric()
|
||||
->rules(['nullable', 'integer']),
|
||||
->integer(),
|
||||
])
|
||||
->columns(1);
|
||||
}
|
||||
|
||||
@@ -117,8 +117,7 @@ class Group extends BaseResource
|
||||
->label(__('filament.fields.group.name.name'))
|
||||
->helperText(__('filament.fields.group.name.help'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192']),
|
||||
->maxLength(192),
|
||||
|
||||
TextInput::make(GroupModel::ATTRIBUTE_SLUG)
|
||||
->label(__('filament.fields.group.slug.name'))
|
||||
|
||||
@@ -28,7 +28,6 @@ use Filament\Tables\Columns\Layout\Stack;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class Image.
|
||||
@@ -129,7 +128,7 @@ class Image extends BaseResource
|
||||
->helperText(__('filament.fields.image.facet.help'))
|
||||
->options(ImageFacet::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(ImageFacet::class)]),
|
||||
->enum(ImageFacet::class),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@ class Series extends BaseResource
|
||||
->helperText(__('filament.fields.series.name.help'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192'])
|
||||
->live(true)
|
||||
->afterStateUpdated(fn (Set $set, ?string $state) => $set(SeriesModel::ATTRIBUTE_SLUG, Str::slug($state, '_'))),
|
||||
|
||||
|
||||
@@ -136,8 +136,7 @@ class Song extends BaseResource
|
||||
->label(__('filament.fields.song.title.name'))
|
||||
->helperText(__('filament.fields.song.title.help'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192']),
|
||||
->maxLength(192),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -367,18 +367,12 @@ class Performance extends BaseResource
|
||||
->defaultItems(0)
|
||||
->columns(3)
|
||||
->columnSpanFull()
|
||||
->formatStateUsing(function ($livewire, Get $get, $state) {
|
||||
if ($livewire instanceof PerformanceSongRelationManager) {
|
||||
$song = $livewire->getOwnerRecord();
|
||||
} else {
|
||||
if ($songId = $get(PerformanceModel::ATTRIBUTE_SONG)) {
|
||||
$song = SongModel::find($songId);
|
||||
} else return $state;
|
||||
}
|
||||
->formatStateUsing(function ($livewire, Get $get) {
|
||||
/** @var SongModel|null $song */
|
||||
$song = $livewire instanceof PerformanceSongRelationManager
|
||||
? $livewire->getOwnerRecord()
|
||||
: SongModel::find($get(PerformanceModel::ATTRIBUTE_SONG));
|
||||
|
||||
if (!($song instanceof SongModel)) {
|
||||
return $state;
|
||||
}
|
||||
return PerformanceSongRelationManager::formatArtists($song);
|
||||
})
|
||||
->schema([
|
||||
@@ -386,13 +380,20 @@ class Performance extends BaseResource
|
||||
->resource(ArtistResource::class)
|
||||
->showCreateOption()
|
||||
->required()
|
||||
->rules(['required'])
|
||||
->hintAction(
|
||||
Action::make('load')
|
||||
->label(__('filament.fields.performance.load_members.name'))
|
||||
->action(function (Get $get, Set $set) {
|
||||
$artistId = $get(Artist::ATTRIBUTE_ID);
|
||||
if ($artistId === null) {
|
||||
$set('memberships', []);
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Artist $group */
|
||||
$group = Artist::query()->find($get(Artist::ATTRIBUTE_ID));
|
||||
$group = Artist::query()
|
||||
->with([Artist::RELATION_MEMBERS])
|
||||
->find($artistId);
|
||||
|
||||
$set('memberships', $group->members->map(fn (Artist $member) => [
|
||||
Membership::ATTRIBUTE_MEMBER => $member->getKey(),
|
||||
@@ -423,8 +424,7 @@ class Performance extends BaseResource
|
||||
->resource(ArtistResource::class)
|
||||
->showCreateOption()
|
||||
->label(__('filament.fields.membership.member'))
|
||||
->required()
|
||||
->rules(['required']),
|
||||
->required(),
|
||||
|
||||
TextInput::make(Membership::ATTRIBUTE_AS)
|
||||
->label(__('filament.fields.membership.as.name'))
|
||||
|
||||
+16
-6
@@ -91,7 +91,7 @@ class PerformanceSongRelationManager extends PerformanceRelationManager
|
||||
return [
|
||||
Action::make('manage performances')
|
||||
->label(__('filament.actions.performances.manage_performances'))
|
||||
->action(fn ($livewire, $data) => static::saveArtists($livewire->getOwnerRecord(), $data[Song::RELATION_PERFORMANCES]))
|
||||
->action(fn ($livewire, $data) => static::saveArtists($livewire->getOwnerRecord(), Arr::get($data, Song::RELATION_PERFORMANCES)))
|
||||
->form(PerformanceResource::performancesFields()),
|
||||
];
|
||||
}
|
||||
@@ -99,11 +99,17 @@ class PerformanceSongRelationManager extends PerformanceRelationManager
|
||||
/**
|
||||
* Format artists to the action.
|
||||
*
|
||||
* @param Song $song
|
||||
* @param Song|null $song
|
||||
* @return array
|
||||
*/
|
||||
public static function formatArtists(Song $song): array
|
||||
public static function formatArtists(?Song $song = null): array
|
||||
{
|
||||
if (!($song instanceof Song)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$song->load(Song::RELATION_PERFORMANCE_ARTISTS);
|
||||
|
||||
$performances = $song->performances;
|
||||
|
||||
$artists = [];
|
||||
@@ -145,12 +151,16 @@ class PerformanceSongRelationManager extends PerformanceRelationManager
|
||||
/**
|
||||
* Save the artists to the action.
|
||||
*
|
||||
* @param Song $song
|
||||
* @param array $data
|
||||
* @param Song|null $song
|
||||
* @param array|null $data
|
||||
* @return void
|
||||
*/
|
||||
public static function saveArtists(Song $song, array $data): void
|
||||
public static function saveArtists(?Song $song = null, ?array $data = []): void
|
||||
{
|
||||
if (!($song instanceof Song) || empty($data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$action = new ManageSongPerformances();
|
||||
|
||||
$action->forSong($song);
|
||||
|
||||
@@ -128,7 +128,6 @@ class Studio extends BaseResource
|
||||
->helperText(__('filament.fields.studio.name.help'))
|
||||
->required()
|
||||
->maxLength(192)
|
||||
->rules(['required', 'max:192'])
|
||||
->live(true)
|
||||
->afterStateUpdated(fn (Set $set, ?string $state) => $set(StudioModel::ATTRIBUTE_SLUG, Str::slug($state, '_'))),
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ use Filament\Tables\Actions\ActionGroup;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class Video.
|
||||
@@ -139,44 +138,42 @@ class Video extends BaseResource
|
||||
TextInput::make(VideoModel::ATTRIBUTE_RESOLUTION)
|
||||
->label(__('filament.fields.video.resolution.name'))
|
||||
->helperText(__('filament.fields.video.resolution.help'))
|
||||
->numeric()
|
||||
->integer()
|
||||
->minValue(360)
|
||||
->maxValue(1080)
|
||||
->nullable()
|
||||
->rules(['nullable', 'integer']),
|
||||
->maxValue(1080),
|
||||
|
||||
Checkbox::make(VideoModel::ATTRIBUTE_NC)
|
||||
->label(__('filament.fields.video.nc.name'))
|
||||
->helperText(__('filament.fields.video.nc.help'))
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
Checkbox::make(VideoModel::ATTRIBUTE_SUBBED)
|
||||
->label(__('filament.fields.video.subbed.name'))
|
||||
->helperText(__('filament.fields.video.subbed.help'))
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
Checkbox::make(VideoModel::ATTRIBUTE_LYRICS)
|
||||
->label(__('filament.fields.video.lyrics.name'))
|
||||
->helperText(__('filament.fields.video.lyrics.help'))
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
Checkbox::make(VideoModel::ATTRIBUTE_UNCEN)
|
||||
->label(__('filament.fields.video.uncen.name'))
|
||||
->helperText(__('filament.fields.video.uncen.help'))
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
Select::make(VideoModel::ATTRIBUTE_OVERLAP)
|
||||
->label(__('filament.fields.video.overlap.name'))
|
||||
->helperText(__('filament.fields.video.overlap.help'))
|
||||
->options(VideoOverlap::asSelectArray())
|
||||
->rules(['nullable', new Enum(VideoOverlap::class)]),
|
||||
->enum(VideoOverlap::class),
|
||||
|
||||
Select::make(VideoModel::ATTRIBUTE_SOURCE)
|
||||
->label(__('filament.fields.video.source.name'))
|
||||
->helperText(__('filament.fields.video.source.help'))
|
||||
->options(VideoSource::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(VideoSource::class)]),
|
||||
->enum(VideoSource::class),
|
||||
|
||||
Select::make(VideoModel::ATTRIBUTE_AUDIO)
|
||||
->label(__('filament.resources.singularLabel.audio'))
|
||||
|
||||
@@ -70,7 +70,6 @@ class DiscordEditMessageTableAction extends BaseTableAction
|
||||
->required()
|
||||
->autofocus()
|
||||
->regex('/https:\/\/discord\.com\/channels\/\d+\/\d+\/\d+/')
|
||||
->rules(['required', 'string', 'regex:/https:\/\/discord\.com\/channels\/\d+\/\d+\/\d+/'])
|
||||
->hintAction(
|
||||
Action::make('load')
|
||||
->label(__('filament.table_actions.discord_thread.message.url.action'))
|
||||
@@ -125,8 +124,7 @@ class DiscordEditMessageTableAction extends BaseTableAction
|
||||
RichEditor::make(DiscordEmbed::ATTRIBUTE_DESCRIPTION)
|
||||
->label(__('filament.table_actions.discord_thread.message.embeds.body.description.name'))
|
||||
->helperText(__('filament.table_actions.discord_thread.message.embeds.body.description.help'))
|
||||
->required()
|
||||
->rules(['required', 'string']),
|
||||
->required(),
|
||||
|
||||
ColorPicker::make(DiscordEmbed::ATTRIBUTE_COLOR)
|
||||
->label(__('filament.table_actions.discord_thread.message.embeds.body.color.name'))
|
||||
@@ -149,14 +147,12 @@ class DiscordEditMessageTableAction extends BaseTableAction
|
||||
TextInput::make(DiscordEmbed::ATTRIBUTE_FIELDS_NAME)
|
||||
->label(__('filament.table_actions.discord_thread.message.embeds.body.fields.name.name'))
|
||||
->helperText(__('filament.table_actions.discord_thread.message.embeds.body.fields.name.help'))
|
||||
->required()
|
||||
->rules(['required', 'string']),
|
||||
->required(),
|
||||
|
||||
TextInput::make(DiscordEmbed::ATTRIBUTE_FIELDS_VALUE)
|
||||
->label(__('filament.table_actions.discord_thread.message.embeds.body.fields.value.name'))
|
||||
->helperText(__('filament.table_actions.discord_thread.message.embeds.body.fields.value.help'))
|
||||
->required()
|
||||
->rules(['required', 'string']),
|
||||
->required(),
|
||||
|
||||
Checkbox::make(DiscordEmbed::ATTRIBUTE_FIELDS_INLINE)
|
||||
->label(__('filament.table_actions.discord_thread.message.embeds.body.fields.inline.name'))
|
||||
@@ -175,8 +171,7 @@ class DiscordEditMessageTableAction extends BaseTableAction
|
||||
TextInput::make(DiscordMessage::ATTRIBUTE_URL)
|
||||
->label(__('filament.table_actions.discord_thread.message.images.body.url.name'))
|
||||
->helperText(__('filament.table_actions.discord_thread.message.images.body.url.help'))
|
||||
->required()
|
||||
->rules(['required', 'string']),
|
||||
->required(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -64,8 +64,7 @@ class DiscordSendMessageTableAction extends BaseTableAction
|
||||
TextInput::make(DiscordMessage::ATTRIBUTE_CHANNEL_ID)
|
||||
->label(__('filament.table_actions.discord_thread.message.channelId.name'))
|
||||
->helperText(__('filament.table_actions.discord_thread.message.channelId.help'))
|
||||
->required()
|
||||
->rules(['required', 'string']),
|
||||
->required(),
|
||||
|
||||
RichEditor::make(DiscordMessage::ATTRIBUTE_CONTENT)
|
||||
->label(__('filament.table_actions.discord_thread.message.content.name'))
|
||||
@@ -85,8 +84,7 @@ class DiscordSendMessageTableAction extends BaseTableAction
|
||||
RichEditor::make(DiscordEmbed::ATTRIBUTE_DESCRIPTION)
|
||||
->label(__('filament.table_actions.discord_thread.message.embeds.body.description.name'))
|
||||
->helperText(__('filament.table_actions.discord_thread.message.embeds.body.description.help'))
|
||||
->required()
|
||||
->rules(['required', 'string']),
|
||||
->required(),
|
||||
|
||||
ColorPicker::make(DiscordEmbed::ATTRIBUTE_COLOR)
|
||||
->label(__('filament.table_actions.discord_thread.message.embeds.body.color.name'))
|
||||
@@ -109,14 +107,12 @@ class DiscordSendMessageTableAction extends BaseTableAction
|
||||
TextInput::make(DiscordEmbed::ATTRIBUTE_FIELDS_NAME)
|
||||
->label(__('filament.table_actions.discord_thread.message.embeds.body.fields.name.name'))
|
||||
->helperText(__('filament.table_actions.discord_thread.message.embeds.body.fields.name.help'))
|
||||
->required()
|
||||
->rules(['required', 'string']),
|
||||
->required(),
|
||||
|
||||
TextInput::make(DiscordEmbed::ATTRIBUTE_FIELDS_VALUE)
|
||||
->label(__('filament.table_actions.discord_thread.message.embeds.body.fields.value.name'))
|
||||
->helperText(__('filament.table_actions.discord_thread.message.embeds.body.fields.value.help'))
|
||||
->required()
|
||||
->rules(['required', 'string']),
|
||||
->required(),
|
||||
|
||||
Checkbox::make(DiscordEmbed::ATTRIBUTE_FIELDS_INLINE)
|
||||
->label(__('filament.table_actions.discord_thread.message.embeds.body.fields.inline.name'))
|
||||
@@ -134,8 +130,7 @@ class DiscordSendMessageTableAction extends BaseTableAction
|
||||
TextInput::make(DiscordMessage::ATTRIBUTE_URL)
|
||||
->label(__('filament.table_actions.discord_thread.message.images.body.url.name'))
|
||||
->helperText(__('filament.table_actions.discord_thread.message.images.body.url.help'))
|
||||
->required()
|
||||
->rules(['required', 'string']),
|
||||
->required(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ use App\Models\Wiki\Image;
|
||||
use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Form;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
/**
|
||||
* Class UploadImageTableAction.
|
||||
@@ -79,7 +78,7 @@ class UploadImageTableAction extends BaseTableAction
|
||||
->helperText(__('filament.fields.image.facet.help'))
|
||||
->options($options)
|
||||
->required()
|
||||
->rules(['required', new Enum(ImageFacet::class)]),
|
||||
->enum(ImageFacet::class),
|
||||
|
||||
FileUpload::make(Image::ATTRIBUTE_PATH)
|
||||
->label(__('filament.fields.image.image.name'))
|
||||
|
||||
@@ -69,7 +69,8 @@ abstract class ReconcileStorageTableAction extends ReconcileTableAction implemen
|
||||
TextInput::make('path')
|
||||
->label(__('filament.actions.repositories.storage.fields.path.name'))
|
||||
->required()
|
||||
->rules(['required', 'string', 'doesnt_start_with:/', new StorageDirectoryExistsRule($fs)])
|
||||
->doesntStartWith('/')
|
||||
->rule(new StorageDirectoryExistsRule($fs))
|
||||
->helperText(__('filament.actions.repositories.storage.fields.path.help')),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -127,8 +127,7 @@ abstract class DumpTableAction extends BaseTableAction
|
||||
TextInput::make('default-character-set')
|
||||
->label(__('filament.actions.dump.dump.fields.mysql.default_character_set.name'))
|
||||
->helperText(__('filament.actions.dump.dump.fields.mysql.default_character_set.help'))
|
||||
->nullable()
|
||||
->rules(['nullable', 'string', 'max:192']),
|
||||
->maxLength(192),
|
||||
|
||||
Select::make('set-gtid-purged')
|
||||
->label(__('filament.actions.dump.dump.fields.mysql.set_gtid_purged.name'))
|
||||
@@ -138,8 +137,7 @@ abstract class DumpTableAction extends BaseTableAction
|
||||
'ON' => __('filament.actions.dump.dump.fields.mysql.set_gtid_purged.options.on'),
|
||||
'AUTO' => __('filament.actions.dump.dump.fields.mysql.set_gtid_purged.options.auto'),
|
||||
])
|
||||
->nullable()
|
||||
->rules(['nullable', Rule::in(['OFF', 'ON', 'AUTO'])->__toString()]),
|
||||
->rule(Rule::in(['OFF', 'ON', 'AUTO'])->__toString()),
|
||||
|
||||
Checkbox::make('no-create-info')
|
||||
->label(__('filament.actions.dump.dump.fields.mysql.no_create_info.name'))
|
||||
|
||||
@@ -57,7 +57,9 @@ abstract class UploadTableAction extends StorageTableAction implements Interacts
|
||||
TextInput::make('path')
|
||||
->label(__('filament.actions.storage.upload.fields.path.name'))
|
||||
->helperText(__('filament.actions.storage.upload.fields.path.help'))
|
||||
->rules(['doesnt_start_with:/', 'doesnt_end_with:/', 'string', new StorageDirectoryExistsRule($fs)])
|
||||
->doesntStartWith('/')
|
||||
->doesntEndWith('/')
|
||||
->rule(new StorageDirectoryExistsRule($fs))
|
||||
->hidden(fn ($livewire) => $livewire instanceof VideoEntryRelationManager || $livewire instanceof ScriptVideoRelationManager),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
use Illuminate\Validation\Rules\File as FileRule;
|
||||
|
||||
/**
|
||||
@@ -106,39 +105,39 @@ class UploadVideoTableAction extends UploadTableAction
|
||||
->label(__('filament.fields.video.nc.name'))
|
||||
->helperText(__('filament.fields.video.nc.help'))
|
||||
->nullable()
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
Checkbox::make(Video::ATTRIBUTE_SUBBED)
|
||||
->label(__('filament.fields.video.subbed.name'))
|
||||
->helperText(__('filament.fields.video.subbed.help'))
|
||||
->nullable()
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
Checkbox::make(Video::ATTRIBUTE_LYRICS)
|
||||
->label(__('filament.fields.video.lyrics.name'))
|
||||
->helperText(__('filament.fields.video.lyrics.help'))
|
||||
->nullable()
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
Checkbox::make(Video::ATTRIBUTE_UNCEN)
|
||||
->label(__('filament.fields.video.uncen.name'))
|
||||
->helperText(__('filament.fields.video.uncen.help'))
|
||||
->nullable()
|
||||
->rules(['nullable', 'boolean']),
|
||||
->rules(['boolean']),
|
||||
|
||||
Select::make(Video::ATTRIBUTE_OVERLAP)
|
||||
->label(__('filament.fields.video.overlap.name'))
|
||||
->helperText(__('filament.fields.video.overlap.help'))
|
||||
->options(VideoOverlap::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(VideoOverlap::class)]),
|
||||
->enum(VideoOverlap::class),
|
||||
|
||||
Select::make(Video::ATTRIBUTE_SOURCE)
|
||||
->label(__('filament.fields.video.source.name'))
|
||||
->helperText(__('filament.fields.video.source.help'))
|
||||
->options(VideoSource::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(VideoSource::class)]),
|
||||
->enum(VideoSource::class),
|
||||
]),
|
||||
|
||||
Section::make(__('filament.resources.singularLabel.video_script'))
|
||||
@@ -146,8 +145,7 @@ class UploadVideoTableAction extends UploadTableAction
|
||||
FileUpload::make('script')
|
||||
->label(__('filament.resources.singularLabel.video_script'))
|
||||
->helperText(__('filament.actions.storage.upload.fields.file.help'))
|
||||
->nullable()
|
||||
->rules(['nullable', FileRule::types('txt')->max(2 * 1024)])
|
||||
->rule(FileRule::types('txt')->max(2 * 1024))
|
||||
->storeFiles(false),
|
||||
|
||||
BelongsTo::make('encoder')
|
||||
@@ -167,7 +165,7 @@ class UploadVideoTableAction extends UploadTableAction
|
||||
->helperText(__('filament.actions.video.backfill.fields.should.help'))
|
||||
->options(ShouldBackfillAudio::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(ShouldBackfillAudio::class)])
|
||||
->enum(ShouldBackfillAudio::class)
|
||||
->default(ShouldBackfillAudio::YES->value),
|
||||
|
||||
...BackfillAudioAction::make()->getForm($form)->getComponents(),
|
||||
@@ -181,7 +179,7 @@ class UploadVideoTableAction extends UploadTableAction
|
||||
->helperText(__('filament.bulk_actions.discord.notification.should_send.help'))
|
||||
->options(ShouldSendNotification::asSelectArray())
|
||||
->required()
|
||||
->rules(['required', new Enum(ShouldSendNotification::class)])
|
||||
->enum(ShouldSendNotification::class)
|
||||
->default(ShouldSendNotification::YES->value),
|
||||
|
||||
...VideoDiscordNotificationBulkAction::make()->getForm($form)->getComponents(),
|
||||
|
||||
@@ -14,6 +14,14 @@ use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
*/
|
||||
class DumpController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(Dump::class, 'dump');
|
||||
}
|
||||
|
||||
/**
|
||||
* Download dump.
|
||||
*
|
||||
|
||||
@@ -11,6 +11,7 @@ use App\Actions\Http\Api\RestoreAction;
|
||||
use App\Actions\Http\Api\ShowAction;
|
||||
use App\Actions\Http\Api\StoreAction;
|
||||
use App\Actions\Http\Api\UpdateAction;
|
||||
use App\Enums\Http\Api\Filter\ComparisonOperator;
|
||||
use App\Http\Api\Query\Query;
|
||||
use App\Http\Controllers\Api\BaseController;
|
||||
use App\Http\Requests\Api\IndexRequest;
|
||||
@@ -46,7 +47,13 @@ class DumpController extends BaseController
|
||||
{
|
||||
$query = new Query($request->validated());
|
||||
|
||||
$dumps = $action->index(Dump::query(), $query, $request->schema());
|
||||
$builder = Dump::query();
|
||||
|
||||
foreach (Dump::safeDumps() as $path) {
|
||||
$builder->orWhere(Dump::ATTRIBUTE_PATH, ComparisonOperator::LIKE->value, $path.'%');
|
||||
}
|
||||
|
||||
$dumps = $action->index($builder, $query, $request->schema());
|
||||
|
||||
return new DumpCollection($dumps, $query);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Models\Admin;
|
||||
|
||||
use App\Contracts\Models\HasSubtitle;
|
||||
use App\Contracts\Models\Nameable;
|
||||
use App\Discord\DiscordEmbedField;
|
||||
use App\Enums\Models\Admin\ActionLogStatus;
|
||||
@@ -40,7 +39,7 @@ use Throwable;
|
||||
* @property int $user_id
|
||||
* @property User $user
|
||||
*/
|
||||
class ActionLog extends Model implements Nameable, HasSubtitle
|
||||
class ActionLog extends Model implements Nameable
|
||||
{
|
||||
final public const TABLE = 'action_logs';
|
||||
|
||||
@@ -173,16 +172,6 @@ class ActionLog extends Model implements Nameable, HasSubtitle
|
||||
->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subtitle.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSubtitle(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actionable.
|
||||
*
|
||||
@@ -243,7 +232,7 @@ class ActionLog extends Model implements Nameable, HasSubtitle
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($model, $model->getAttributes()),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($model->getAttributes(), $model),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
@@ -267,7 +256,7 @@ class ActionLog extends Model implements Nameable, HasSubtitle
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($model, $model->getChanges()),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($model->getChanges(), $model),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
@@ -314,7 +303,7 @@ class ActionLog extends Model implements Nameable, HasSubtitle
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($model, $model->getAttributes()),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($model->getAttributes(), $model),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
@@ -332,6 +321,8 @@ class ActionLog extends Model implements Nameable, HasSubtitle
|
||||
*/
|
||||
public static function modelPivot(string $actionName, Model $related, Model $parent, Model $pivot, mixed $action = null): ActionLog
|
||||
{
|
||||
$data = $action?->getFormData();
|
||||
|
||||
return ActionLog::query()->create([
|
||||
ActionLog::ATTRIBUTE_BATCH_ID => Str::orderedUuid()->__toString(),
|
||||
ActionLog::ATTRIBUTE_USER => ActionLog::getUserId(),
|
||||
@@ -342,7 +333,7 @@ class ActionLog extends Model implements Nameable, HasSubtitle
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $parent->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $pivot->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $pivot->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => $action?->getFormData() ?? static::getFields($pivot, $pivot->getAttributes()),
|
||||
ActionLog::ATTRIBUTE_FIELDS => $data ? static::getFields($data) : static::getFields($pivot->getAttributes(), $pivot),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
@@ -368,7 +359,7 @@ class ActionLog extends Model implements Nameable, HasSubtitle
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $parent->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $related->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $related->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($related, $related->getAttributes()),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($related->getAttributes(), $related),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::FINISHED->value,
|
||||
ActionLog::ATTRIBUTE_FINISHED_AT => Date::now(),
|
||||
]);
|
||||
@@ -394,7 +385,7 @@ class ActionLog extends Model implements Nameable, HasSubtitle
|
||||
ActionLog::ATTRIBUTE_TARGET_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_MODEL_TYPE => $model->getMorphClass(),
|
||||
ActionLog::ATTRIBUTE_MODEL_ID => $model->getKey(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => $action->getFormData(),
|
||||
ActionLog::ATTRIBUTE_FIELDS => static::getFields($action->getFormData()),
|
||||
ActionLog::ATTRIBUTE_STATUS => ActionLogStatus::RUNNING->value,
|
||||
]);
|
||||
}
|
||||
@@ -495,22 +486,26 @@ class ActionLog extends Model implements Nameable, HasSubtitle
|
||||
/**
|
||||
* Format the fields to store.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param array $fields
|
||||
* @param Model|null $model
|
||||
* @return array
|
||||
*/
|
||||
protected static function getFields(Model $model, array $fields): array
|
||||
protected static function getFields(array $fields, ?Model $model = null): array
|
||||
{
|
||||
return collect($fields)
|
||||
->forget($model->getCreatedAtColumn())
|
||||
->forget($model->getUpdatedAtColumn())
|
||||
->forget(Model::CREATED_AT)
|
||||
->forget(Model::UPDATED_AT)
|
||||
->forget(BaseModel::ATTRIBUTE_DELETED_AT)
|
||||
->map(function ($value, $key) use ($model) {
|
||||
if (in_array($key, $model->getHidden())) {
|
||||
return DiscordEmbedField::DEFAULT_FIELD_VALUE;
|
||||
if ($model instanceof Model) {
|
||||
if (in_array($key, $model->getHidden())) {
|
||||
return DiscordEmbedField::DEFAULT_FIELD_VALUE;
|
||||
}
|
||||
|
||||
return DiscordEmbedField::formatEmbedFieldValue($model->getAttribute($key));
|
||||
}
|
||||
|
||||
return DiscordEmbedField::formatEmbedFieldValue($model->getAttribute($key));
|
||||
return DiscordEmbedField::formatEmbedFieldValue($value);
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Models\Admin;
|
||||
|
||||
use App\Actions\Storage\Admin\Dump\DumpDocumentAction;
|
||||
use App\Actions\Storage\Admin\Dump\DumpWikiAction;
|
||||
use App\Events\Admin\Dump\DumpCreated;
|
||||
use App\Events\Admin\Dump\DumpDeleted;
|
||||
use App\Events\Admin\Dump\DumpRestored;
|
||||
@@ -82,4 +84,17 @@ class Dump extends BaseModel
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the available safe dumps.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function safeDumps(): array
|
||||
{
|
||||
return [
|
||||
DumpDocumentAction::FILENAME_PREFIX,
|
||||
DumpWikiAction::FILENAME_PREFIX,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,18 @@ class FeaturedTheme extends BaseModel
|
||||
return $this->animethemeentry === null ? $this->getName() : $this->animethemeentry->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
FeaturedTheme::RELATION_ENTRY,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that recommended the featured theme.
|
||||
*
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Models\Auth;
|
||||
|
||||
use App\Contracts\Models\Nameable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Spatie\Permission\Models\Role as BaseRole;
|
||||
@@ -20,7 +21,7 @@ use Spatie\Permission\Models\Role as BaseRole;
|
||||
* @property int $priority
|
||||
* @property Carbon $updated_at
|
||||
*/
|
||||
class Role extends BaseRole
|
||||
class Role extends BaseRole implements Nameable
|
||||
{
|
||||
final public const TABLE = 'roles';
|
||||
|
||||
@@ -48,4 +49,14 @@ class Role extends BaseRole
|
||||
Role::ATTRIBUTE_PRIORITY => 'int',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +109,18 @@ class DiscordThread extends Model implements Nameable, HasSubtitle
|
||||
return $this->anime->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
DiscordThread::RELATION_ANIME,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the anime that the thread uses.
|
||||
*
|
||||
|
||||
+12
@@ -118,6 +118,18 @@ class ExternalEntry extends BaseModel
|
||||
return $this->anime->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
ExternalEntry::RELATION_ANIME,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the route key for the model.
|
||||
*
|
||||
|
||||
+12
@@ -103,6 +103,18 @@ class ExternalToken extends BaseModel
|
||||
return $this->externalprofile->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
ExternalToken::RELATION_PROFILE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the route key for the model.
|
||||
*
|
||||
|
||||
@@ -138,6 +138,18 @@ class ExternalProfile extends BaseModel
|
||||
return $this->user === null ? $this->getName() : $this->user->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
ExternalProfile::RELATION_USER,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the route key for the model.
|
||||
*
|
||||
|
||||
@@ -165,6 +165,18 @@ class Playlist extends BaseModel implements HasHashids, Viewable, HasImages
|
||||
return $this->user === null ? $this->getName() : $this->user->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
Playlist::RELATION_USER,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the model should be searchable.
|
||||
*
|
||||
|
||||
@@ -151,9 +151,20 @@ class PlaylistTrack extends BaseModel implements HasHashids, InteractsWithSchema
|
||||
->append(' - ');
|
||||
}
|
||||
|
||||
$subtitle = $subtitle->append($this->playlist->getName());
|
||||
return $subtitle->append($this->playlist->getName())->__toString();
|
||||
}
|
||||
|
||||
return $subtitle->__toString();
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
PlaylistTrack::RELATION_PLAYLIST,
|
||||
'playlist.user',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,8 @@ use Illuminate\Support\Facades\Request;
|
||||
*/
|
||||
class View extends BaseView
|
||||
{
|
||||
final public const TABLE = 'views';
|
||||
|
||||
/**
|
||||
* Bootstrap the model.
|
||||
*
|
||||
|
||||
@@ -17,6 +17,8 @@ class Notification extends DatabaseNotification
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
final public const TABLE = 'notifications';
|
||||
|
||||
final public const ATTRIBUTE_ID = 'id';
|
||||
final public const ATTRIBUTE_TYPE = 'type';
|
||||
final public const ATTRIBUTE_NOTIFIABLE_TYPE = 'notifiable_type';
|
||||
|
||||
@@ -116,6 +116,18 @@ class Report extends Model implements Nameable, HasSubtitle
|
||||
return strval($this->getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
Report::RELATION_USER,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
|
||||
@@ -113,6 +113,18 @@ class AnimeSynonym extends BaseModel
|
||||
return $this->anime->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
AnimeSynonym::RELATION_ANIME,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the anime that owns the synonym.
|
||||
*
|
||||
|
||||
@@ -67,6 +67,7 @@ class AnimeTheme extends BaseModel implements InteractsWithSchema
|
||||
final public const RELATION_GROUP = 'group';
|
||||
final public const RELATION_IMAGES = 'anime.images';
|
||||
final public const RELATION_PERFORMANCES = 'song.performances';
|
||||
final public const RELATION_PERFORMANCES_ARTISTS = 'song.performances.artist';
|
||||
final public const RELATION_SONG = 'song';
|
||||
final public const RELATION_SYNONYMS = 'anime.animesynonyms';
|
||||
final public const RELATION_VIDEOS = 'animethemeentries.videos';
|
||||
@@ -177,11 +178,21 @@ class AnimeTheme extends BaseModel implements InteractsWithSchema
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
$this->loadMissing(AnimeTheme::RELATION_GROUP);
|
||||
$this->loadMissing([
|
||||
AnimeTheme::RELATION_SONG,
|
||||
AnimeTheme::RELATION_GROUP,
|
||||
]);
|
||||
|
||||
return Str::of($this->type->localize())
|
||||
$name = Str::of($this->type->localize());
|
||||
|
||||
if ($this->type === ThemeType::IN && $this->song !== null) {
|
||||
$name = $name->append(" \"{$this->song->getName()}\" ");
|
||||
}
|
||||
|
||||
return $name
|
||||
->append($this->type === ThemeType::IN ? '' : strval($this->sequence ?? 1))
|
||||
->append($this->group !== null ? '-'.$this->group->slug : '')
|
||||
->trim()
|
||||
->__toString();
|
||||
}
|
||||
|
||||
@@ -195,6 +206,18 @@ class AnimeTheme extends BaseModel implements InteractsWithSchema
|
||||
return $this->anime->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
AnimeTheme::RELATION_ANIME,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the anime that owns the theme.
|
||||
*
|
||||
|
||||
@@ -202,6 +202,19 @@ class AnimeThemeEntry extends BaseModel implements InteractsWithSchema
|
||||
return "{$this->anime->getName()} {$this->animetheme->getName()}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
AnimeThemeEntry::RELATION_ANIME_SHALLOW,
|
||||
AnimeThemeEntry::RELATION_THEME,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the theme that owns the entry.
|
||||
*
|
||||
|
||||
@@ -50,6 +50,7 @@ class Song extends BaseModel implements HasResources
|
||||
final public const RELATION_ANIMETHEMES = 'animethemes';
|
||||
final public const RELATION_ARTISTS = 'artists';
|
||||
final public const RELATION_PERFORMANCES = 'performances';
|
||||
final public const RELATION_PERFORMANCE_ARTISTS = 'performances.artist';
|
||||
final public const RELATION_RESOURCES = 'resources';
|
||||
final public const RELATION_THEME_GROUPS = 'animethemes.group';
|
||||
final public const RELATION_VIDEOS = 'animethemes.animethemeentries.videos';
|
||||
@@ -118,6 +119,18 @@ class Song extends BaseModel implements HasResources
|
||||
: $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
Song::RELATION_ANIME,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the anime themes that use this song.
|
||||
*
|
||||
|
||||
@@ -107,6 +107,19 @@ class Membership extends BaseModel
|
||||
return "Member {$this->member->getName()} of Group {$this->artist->getName()}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
Membership::RELATION_ARTIST,
|
||||
Membership::RELATION_MEMBER,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the artist that owns the membership.
|
||||
*
|
||||
|
||||
@@ -111,6 +111,18 @@ class Performance extends BaseModel
|
||||
return $this->song->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
Performance::RELATION_SONG,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the performance is a membership.
|
||||
*
|
||||
|
||||
@@ -96,6 +96,18 @@ class VideoScript extends BaseModel implements InteractsWithSchema
|
||||
return $this->video->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the eager loads needed to the subtitle.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEagerLoadsForSubtitle(): array
|
||||
{
|
||||
return [
|
||||
VideoScript::RELATION_VIDEO,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the video that owns the script.
|
||||
*
|
||||
|
||||
@@ -4,11 +4,52 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Policies\Admin;
|
||||
|
||||
use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\Role;
|
||||
use App\Models\Admin\Dump;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\BaseModel;
|
||||
use App\Policies\BasePolicy;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Class DumpPolicy.
|
||||
*/
|
||||
class DumpPolicy extends BasePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(?User $user): bool
|
||||
{
|
||||
if (Filament::isServing()) {
|
||||
return $user !== null && $user->can(CrudPermission::VIEW->format(static::getModel()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param Dump $dump
|
||||
* @return bool
|
||||
*/
|
||||
public function view(?User $user, BaseModel|Model $dump): bool
|
||||
{
|
||||
if (Filament::isServing()) {
|
||||
return $user !== null && $user->can(CrudPermission::VIEW->format(static::getModel()));
|
||||
}
|
||||
|
||||
if ($user?->hasRole(Role::ADMIN->value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return str($dump->path)->contains(Dump::safeDumps());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Seeders\User;
|
||||
|
||||
use App\Models\Admin\ActionLog;
|
||||
use App\Models\User\Encode;
|
||||
use App\Models\Wiki\Video;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class EncodesSeeder.
|
||||
*/
|
||||
class EncodesSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
ActionLog::query()
|
||||
->where(ActionLog::ATTRIBUTE_NAME, 'Upload Video')
|
||||
->where(ActionLog::ATTRIBUTE_TARGET_TYPE, Video::class)
|
||||
->latest()
|
||||
->chunkById(10, fn (Collection $logs) => $logs->each(function (ActionLog $log) {
|
||||
Encode::query()
|
||||
->firstOrCreate([
|
||||
Encode::ATTRIBUTE_VIDEO => $log->target_id,
|
||||
], [
|
||||
Encode::ATTRIBUTE_USER => $log->user_id,
|
||||
]);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -477,7 +477,11 @@ return [
|
||||
'target' => 'Target',
|
||||
'status' => 'Status',
|
||||
'happened_at' => 'Happened At',
|
||||
'fields' => 'Fields',
|
||||
'fields' => [
|
||||
'name' => 'Fields',
|
||||
'keys' => 'Fields',
|
||||
'values' => 'Values',
|
||||
],
|
||||
'finished_at' => 'Finished At',
|
||||
'exception' => 'Exception',
|
||||
],
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
@endif
|
||||
<div class="flex flex-col justify-center pl-3 py-2">
|
||||
<p class="text-sm font-bold pb-1">{{ $name }}</p>
|
||||
@if ($subtitle !== null)
|
||||
<div class="flex flex-col items-start">
|
||||
<p class="text-xs leading-5">{{ $subtitle }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user