feat(media monitoring): implement crud
- create enums for channel - create model and migration - create many to many relation to theme - feat resource
This commit is contained in:
parent
6161126d9f
commit
a6ea4cfdc5
26
app/Enums/Channel.php
Normal file
26
app/Enums/Channel.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
use App\Traits\Enum\WithComment;
|
||||||
|
use App\Traits\Enum\WithValue;
|
||||||
|
|
||||||
|
enum Channel: string
|
||||||
|
{
|
||||||
|
use WithComment, WithValue;
|
||||||
|
|
||||||
|
case WEBSITE = 'Website';
|
||||||
|
case TIKTOK = 'Tiktok';
|
||||||
|
case YOUTUBE = 'Youtube';
|
||||||
|
case FACEBOOK = 'Facebook';
|
||||||
|
case INSTAGRAM = 'Instagram';
|
||||||
|
case OTHER = 'Other';
|
||||||
|
|
||||||
|
public static function options(): array
|
||||||
|
{
|
||||||
|
return array_combine(
|
||||||
|
array_map(fn ($status) => $status->value, self::cases()),
|
||||||
|
array_map(fn ($status) => $status->value, self::cases())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Monitoring\MediaMonitorings;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Monitoring\MediaMonitorings\Pages\CreateMediaMonitoring;
|
||||||
|
use App\Filament\Resources\Monitoring\MediaMonitorings\Pages\EditMediaMonitoring;
|
||||||
|
use App\Filament\Resources\Monitoring\MediaMonitorings\Pages\ListMediaMonitorings;
|
||||||
|
use App\Filament\Resources\Monitoring\MediaMonitorings\Schemas\MediaMonitoringForm;
|
||||||
|
use App\Filament\Resources\Monitoring\MediaMonitorings\Tables\MediaMonitoringsTable;
|
||||||
|
use App\Models\MediaMonitoring;
|
||||||
|
use BackedEnum;
|
||||||
|
use Filament\Resources\Resource;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
use Filament\Support\Icons\Heroicon;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||||
|
use UnitEnum;
|
||||||
|
|
||||||
|
class MediaMonitoringResource extends Resource
|
||||||
|
{
|
||||||
|
protected static ?string $model = MediaMonitoring::class;
|
||||||
|
|
||||||
|
protected static string|BackedEnum|null $navigationIcon = Heroicon::ClipboardDocumentCheck;
|
||||||
|
|
||||||
|
protected static ?string $navigationLabel = 'Monitoring Media';
|
||||||
|
|
||||||
|
protected static string|UnitEnum|null $navigationGroup = 'Monitoring';
|
||||||
|
|
||||||
|
protected static ?string $slug = 'monitoring/media-monitorings';
|
||||||
|
|
||||||
|
protected static ?string $recordTitleAttribute = 'media_name';
|
||||||
|
|
||||||
|
protected static ?int $navigationSort = 12;
|
||||||
|
|
||||||
|
public static function form(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return MediaMonitoringForm::configure($schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return MediaMonitoringsTable::configure($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRelations(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'index' => ListMediaMonitorings::route('/'),
|
||||||
|
'create' => CreateMediaMonitoring::route('/create'),
|
||||||
|
'edit' => EditMediaMonitoring::route('/{record}/edit'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||||
|
{
|
||||||
|
return parent::getRecordRouteBindingEloquentQuery()
|
||||||
|
->withoutGlobalScopes([
|
||||||
|
SoftDeletingScope::class,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Monitoring\MediaMonitorings\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Monitoring\MediaMonitorings\MediaMonitoringResource;
|
||||||
|
use App\Models\MediaMonitoring;
|
||||||
|
use Filament\Actions\Action;
|
||||||
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
|
|
||||||
|
class CreateMediaMonitoring extends CreateRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = MediaMonitoringResource::class;
|
||||||
|
|
||||||
|
protected static ?string $title = 'Tambah Monitoring Media';
|
||||||
|
|
||||||
|
protected function getRedirectUrl(): string
|
||||||
|
{
|
||||||
|
return $this->getResource()::getUrl('index');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Action::make('back')
|
||||||
|
->label('Kembali')
|
||||||
|
->url(fn (): string => route('filament.dashboard.resources.monitoring.media-monitorings.index'))
|
||||||
|
->outlined()
|
||||||
|
->color('secondary'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function mutateFormDataBeforeCreate(array $data): array
|
||||||
|
{
|
||||||
|
$latestCode = MediaMonitoring::max('code');
|
||||||
|
|
||||||
|
$lastNumber = $latestCode
|
||||||
|
? intval(substr($latestCode, 3))
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
$newNumber = str_pad($lastNumber + 1, 6, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
|
$data['code'] = 'ADN'.$newNumber;
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Monitoring\MediaMonitorings\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Monitoring\MediaMonitorings\MediaMonitoringResource;
|
||||||
|
use Filament\Actions\Action;
|
||||||
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
|
||||||
|
class EditMediaMonitoring extends EditRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = MediaMonitoringResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Action::make('back')
|
||||||
|
->label('Kembali')
|
||||||
|
->url(fn (): string => route('filament.dashboard.resources.monitoring.media-monitorings.index'))
|
||||||
|
->outlined()
|
||||||
|
->color('secondary'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRedirectUrl(): string
|
||||||
|
{
|
||||||
|
return $this->getResource()::getUrl('index');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Monitoring\MediaMonitorings\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Monitoring\MediaMonitorings\MediaMonitoringResource;
|
||||||
|
use Filament\Actions\CreateAction;
|
||||||
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
|
||||||
|
class ListMediaMonitorings extends ListRecords
|
||||||
|
{
|
||||||
|
protected static string $resource = MediaMonitoringResource::class;
|
||||||
|
|
||||||
|
protected static ?string $title = 'Monitoring Media';
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
CreateAction::make()
|
||||||
|
->label('Tambah'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Monitoring\MediaMonitorings\Schemas;
|
||||||
|
|
||||||
|
use App\Enums\Channel;
|
||||||
|
use Filament\Forms\Components\DatePicker;
|
||||||
|
use Filament\Forms\Components\RichEditor;
|
||||||
|
use Filament\Forms\Components\Select;
|
||||||
|
use Filament\Forms\Components\SpatieMediaLibraryFileUpload;
|
||||||
|
use Filament\Forms\Components\TextInput;
|
||||||
|
use Filament\Schemas\Components\Grid;
|
||||||
|
use Filament\Schemas\Components\Section;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
|
||||||
|
class MediaMonitoringForm
|
||||||
|
{
|
||||||
|
public static function configure(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return $schema
|
||||||
|
->components([
|
||||||
|
Section::make([
|
||||||
|
TextInput::make('media_name')
|
||||||
|
->label('Nama Media')
|
||||||
|
->placeholder('PWK News')
|
||||||
|
->autocomplete(false)
|
||||||
|
->autofocus()
|
||||||
|
->required()
|
||||||
|
->maxLength(50),
|
||||||
|
|
||||||
|
TextInput::make('title')
|
||||||
|
->label('Judul')
|
||||||
|
->placeholder('Berita Purwakarta Hari Ini')
|
||||||
|
->autocomplete(false)
|
||||||
|
->required()
|
||||||
|
->maxLength(255),
|
||||||
|
|
||||||
|
Grid::make(2)
|
||||||
|
->schema([
|
||||||
|
TextInput::make('writter')
|
||||||
|
->label('Penulis')
|
||||||
|
->placeholder('John Doe')
|
||||||
|
->autocomplete(false)
|
||||||
|
->required()
|
||||||
|
->maxLength(50),
|
||||||
|
|
||||||
|
TextInput::make('news_page')
|
||||||
|
->label('Halaman Berita')
|
||||||
|
->placeholder('Halaman 1 s/d 10')
|
||||||
|
->autocomplete(false)
|
||||||
|
->nullable()
|
||||||
|
->maxLength(20),
|
||||||
|
]),
|
||||||
|
|
||||||
|
TextInput::make('link')
|
||||||
|
->label('Tautan')
|
||||||
|
->placeholder('https://www.pwknews.com')
|
||||||
|
->autocomplete(false)
|
||||||
|
->nullable()
|
||||||
|
->maxLength(50)
|
||||||
|
->url(),
|
||||||
|
|
||||||
|
RichEditor::make('quote')
|
||||||
|
->label('Kutipan')
|
||||||
|
->placeholder('....')
|
||||||
|
->nullable(),
|
||||||
|
|
||||||
|
RichEditor::make('content')
|
||||||
|
->label('Konten')
|
||||||
|
->placeholder('....')
|
||||||
|
->required(),
|
||||||
|
])->columnSpan(2),
|
||||||
|
|
||||||
|
Section::make([
|
||||||
|
Select::make('channel')
|
||||||
|
->label('Kanal')
|
||||||
|
->options(Channel::options())
|
||||||
|
->native(false)
|
||||||
|
->required()
|
||||||
|
->in(implode(',', array_column(Channel::cases(), 'value'))),
|
||||||
|
|
||||||
|
Select::make('themes')
|
||||||
|
->label('Tema')
|
||||||
|
->relationship('themes', 'name')
|
||||||
|
->native(false)
|
||||||
|
->multiple()
|
||||||
|
->preload()
|
||||||
|
->required(),
|
||||||
|
|
||||||
|
DatePicker::make('release_date')
|
||||||
|
->label('Tanggal Rilis')
|
||||||
|
->placeholder(fn () => now()->format('Y-m-d'))
|
||||||
|
->native(false)
|
||||||
|
->displayFormat('l, d F Y')
|
||||||
|
->required(),
|
||||||
|
|
||||||
|
TextInput::make('influencer')
|
||||||
|
->label('Influencer')
|
||||||
|
->placeholder('Sekretariat Daerah')
|
||||||
|
->autocomplete(false)
|
||||||
|
->nullable()
|
||||||
|
->maxLength(50),
|
||||||
|
|
||||||
|
TextInput::make('keyword')
|
||||||
|
->label('Kata Kunci')
|
||||||
|
->placeholder('Purwakarta, Berita Terbaru, Hari Ini')
|
||||||
|
->autocomplete(false)
|
||||||
|
->required()
|
||||||
|
->maxLength(100),
|
||||||
|
|
||||||
|
SpatieMediaLibraryFileUpload::make('image')
|
||||||
|
->label('Gambar')
|
||||||
|
->disk(config('filesystems.default'))
|
||||||
|
->acceptedFileTypes(['images/*'])
|
||||||
|
->maxSize(1024 * 3)
|
||||||
|
->collection('media-monitorings')
|
||||||
|
->image()
|
||||||
|
->required(),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
->columns(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Monitoring\MediaMonitorings\Tables;
|
||||||
|
|
||||||
|
use App\Filament\Actions\DefaultBulkActions;
|
||||||
|
use App\Filament\Columns\TimestampColumns;
|
||||||
|
use Filament\Actions\BulkActionGroup;
|
||||||
|
use Filament\Actions\DeleteAction;
|
||||||
|
use Filament\Actions\EditAction;
|
||||||
|
use Filament\Actions\ForceDeleteAction;
|
||||||
|
use Filament\Actions\RestoreAction;
|
||||||
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Filters\TrashedFilter;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
|
||||||
|
class MediaMonitoringsTable
|
||||||
|
{
|
||||||
|
public static function configure(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->columns([
|
||||||
|
TextColumn::make('code')
|
||||||
|
->label('Kode')
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
TextColumn::make('media_name')
|
||||||
|
->label('Nama media')
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
TextColumn::make('title')
|
||||||
|
->label('Judul')
|
||||||
|
->searchable()
|
||||||
|
->sortable()
|
||||||
|
->wrap(),
|
||||||
|
|
||||||
|
TextColumn::make('channel')
|
||||||
|
->label('Kanal')
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
TextColumn::make('writter')
|
||||||
|
->label('Penulis')
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
TextColumn::make('link')
|
||||||
|
->label('Tautan')
|
||||||
|
->searchable()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
|
||||||
|
TextColumn::make('news_page')
|
||||||
|
->label('Halaman Berita')
|
||||||
|
->searchable()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
|
||||||
|
TextColumn::make('influencer')
|
||||||
|
->searchable()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
|
||||||
|
TextColumn::make('keyword')
|
||||||
|
->searchable()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
|
||||||
|
TextColumn::make('themes.name')
|
||||||
|
->label('Tema')
|
||||||
|
->searchable()
|
||||||
|
->sortable()
|
||||||
|
->wrap()
|
||||||
|
->badge(),
|
||||||
|
|
||||||
|
TextColumn::make('release_date')
|
||||||
|
->label('Tgl Rilis')
|
||||||
|
->searchable()
|
||||||
|
->sortable()
|
||||||
|
->date('l, d F Y'),
|
||||||
|
|
||||||
|
...TimestampColumns::make(),
|
||||||
|
])
|
||||||
|
->filters([
|
||||||
|
TrashedFilter::make()->native(false),
|
||||||
|
])
|
||||||
|
->recordActions([
|
||||||
|
EditAction::make(),
|
||||||
|
DeleteAction::make(),
|
||||||
|
ForceDeleteAction::make(),
|
||||||
|
RestoreAction::make(),
|
||||||
|
])
|
||||||
|
->toolbarActions([
|
||||||
|
BulkActionGroup::make([
|
||||||
|
...DefaultBulkActions::make('Monitoring Media'),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
->emptyStateIcon('heroicon-o-bookmark')
|
||||||
|
->emptyStateDescription('Setelah Anda membubat data pertama, maka akan muncul disini.')
|
||||||
|
->defaultSort('created_at', 'desc')
|
||||||
|
->deferFilters(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
app/Models/MediaMonitoring.php
Normal file
21
app/Models/MediaMonitoring.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
|
||||||
|
class MediaMonitoring extends Model implements HasMedia
|
||||||
|
{
|
||||||
|
use InteractsWithMedia, SoftDeletes;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
|
||||||
|
public function themes(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Theme::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
app/Models/MediaMonitoringTheme.php
Normal file
12
app/Models/MediaMonitoringTheme.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class MediaMonitoringTheme extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'media_monitoring_theme';
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use App\Enums\IsActive;
|
use App\Enums\IsActive;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
class Theme extends Model
|
class Theme extends Model
|
||||||
@ -19,4 +20,9 @@ protected function casts(): array
|
|||||||
'sort_order' => 'integer',
|
'sort_order' => 'integer',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function mediaMonitorings(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(MediaMonitoring::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('media_monitorings', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('code', 10);
|
||||||
|
$table->string('media_name', 50);
|
||||||
|
$table->text('title', 255);
|
||||||
|
$table->string('channel', 20);
|
||||||
|
$table->string('writter', 50);
|
||||||
|
$table->text('link', 50)->nullable();
|
||||||
|
$table->string('news_page', 20)->nullable();
|
||||||
|
$table->text('quote')->nullable();
|
||||||
|
$table->text('content');
|
||||||
|
$table->string('influencer', 50)->nullable();
|
||||||
|
$table->string('keyword', 100);
|
||||||
|
$table->date('release_date');
|
||||||
|
$table->timestamp('created_at')->useCurrent();
|
||||||
|
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
|
||||||
|
$table->softDeletes();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('media_monitorings');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\MediaMonitoring;
|
||||||
|
use App\Models\Theme;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('media_monitoring_theme', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignIdFor(MediaMonitoring::class);
|
||||||
|
$table->foreignIdFor(Theme::class);
|
||||||
|
$table->timestamp('created_at')->useCurrent();
|
||||||
|
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('media_monitoring_theme');
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user