Update Submissions and add fields

This commit is contained in:
2026-06-10 11:04:26 +02:00
parent 1d8ea70b72
commit 4f9f6c63b3
64 changed files with 2278 additions and 174 deletions

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Filament\Resources\Categories;
use App\Filament\Resources\Categories\Pages\CreateCategory;
use App\Filament\Resources\Categories\Pages\EditCategory;
use App\Filament\Resources\Categories\Pages\ListCategories;
use App\Filament\Resources\Categories\Schemas\CategoryForm;
use App\Filament\Resources\Categories\Tables\CategoriesTable;
use App\Models\Category;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class CategoryResource extends Resource
{
protected static ?string $model = Category::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return CategoryForm::configure($schema);
}
public static function table(Table $table): Table
{
return CategoriesTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListCategories::route('/'),
'create' => CreateCategory::route('/create'),
'edit' => EditCategory::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Resources\Pages\CreateRecord;
class CreateCategory extends CreateRecord
{
protected static string $resource = CategoryResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditCategory extends EditRecord
{
protected static string $resource = CategoryResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListCategories extends ListRecords
{
protected static string $resource = CategoryResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Filament\Resources\Categories\Schemas;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Schemas\Schema;
class CategoryForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->required(),
TextInput::make('slug')
->required(),
Textarea::make('restricted_to')
->default(null)
->columnSpanFull(),
]);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Filament\Resources\Categories\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class CategoriesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->searchable(),
TextColumn::make('slug')
->searchable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Filament\Resources\Levels;
use App\Filament\Resources\Levels\Pages\CreateLevel;
use App\Filament\Resources\Levels\Pages\EditLevel;
use App\Filament\Resources\Levels\Pages\ListLevels;
use App\Filament\Resources\Levels\Schemas\LevelForm;
use App\Filament\Resources\Levels\Tables\LevelsTable;
use App\Models\Level;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class LevelResource extends Resource
{
protected static ?string $model = Level::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return LevelForm::configure($schema);
}
public static function table(Table $table): Table
{
return LevelsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListLevels::route('/'),
'create' => CreateLevel::route('/create'),
'edit' => EditLevel::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Levels\Pages;
use App\Filament\Resources\Levels\LevelResource;
use Filament\Resources\Pages\CreateRecord;
class CreateLevel extends CreateRecord
{
protected static string $resource = LevelResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Levels\Pages;
use App\Filament\Resources\Levels\LevelResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditLevel extends EditRecord
{
protected static string $resource = LevelResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Levels\Pages;
use App\Filament\Resources\Levels\LevelResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListLevels extends ListRecords
{
protected static string $resource = LevelResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Filament\Resources\Levels\Schemas;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
class LevelForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->required(),
TextInput::make('slug')
->required(),
]);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Filament\Resources\Levels\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class LevelsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->searchable(),
TextColumn::make('slug')
->searchable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Systems\Pages;
use App\Filament\Resources\Systems\SystemResource;
use Filament\Resources\Pages\CreateRecord;
class CreateSystem extends CreateRecord
{
protected static string $resource = SystemResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Systems\Pages;
use App\Filament\Resources\Systems\SystemResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditSystem extends EditRecord
{
protected static string $resource = SystemResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Systems\Pages;
use App\Filament\Resources\Systems\SystemResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListSystems extends ListRecords
{
protected static string $resource = SystemResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Filament\Resources\Systems\Schemas;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
class SystemForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->required(),
TextInput::make('slug')
->required(),
]);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Filament\Resources\Systems;
use App\Filament\Resources\Systems\Pages\CreateSystem;
use App\Filament\Resources\Systems\Pages\EditSystem;
use App\Filament\Resources\Systems\Pages\ListSystems;
use App\Filament\Resources\Systems\Schemas\SystemForm;
use App\Filament\Resources\Systems\Tables\SystemsTable;
use App\Models\System;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class SystemResource extends Resource
{
protected static ?string $model = System::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return SystemForm::configure($schema);
}
public static function table(Table $table): Table
{
return SystemsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListSystems::route('/'),
'create' => CreateSystem::route('/create'),
'edit' => EditSystem::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Filament\Resources\Systems\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class SystemsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->searchable(),
TextColumn::make('slug')
->searchable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -44,7 +44,64 @@ class FormHelpers {
'homebrew' => [ 'homebrew' => [
'page_title' => "Submit an homebrew", 'page_title' => "Submit an homebrew",
'about_the' => "About the homebrew", 'about_the' => "About the homebrew",
'version' => "Patch version", 'version' => "Version",
'status' => "Status",
'release_date' => "Release date",
'release_date_helper' => "If only initial release exist, the release date.",
'description' => "Description",
'about_game' => "Game Information",
'attachments' => "Attachments",
'authors' => "Team members",
'related_links' => "Related links",
'release_site' => "Release site",
'release_site_helper' => "Project entry on site/blog/forum/Github.",
'youtube_video' => "YouTube video",
],
'utilities' => [
'page_title' => "Submit a utility",
'entry_title' => "Title",
'about_the' => "About the utility",
'version' => "Version",
'status' => "Status",
'system' => "OS",
'categories' => "Categories",
'level' => "Experience Level",
'release_date' => "Release date",
'release_date_helper' => "If only initial release exist, the release date.",
'description' => "Description",
'about_game' => "Game Information",
'attachments' => "Attachments",
'authors' => "Team members",
'related_links' => "Related links",
'release_site' => "Release site",
'release_site_helper' => "Project entry on site/blog/forum/Github.",
'youtube_video' => "YouTube video",
],
'documents' => [
'page_title' => "Submit a document",
'entry_title' => "Title",
'about_the' => "About the document",
'version' => "Version",
'status' => "Status",
'categories' => "Categories",
'level' => "Experience Level",
'release_date' => "Release date",
'release_date_helper' => "If only initial release exist, the release date.",
'description' => "Description",
'about_game' => "Game Information",
'attachments' => "Attachments",
'authors' => "Team members",
'related_links' => "Related links",
'release_site' => "Release site",
'release_site_helper' => "Project entry on site/blog/forum/Github.",
'youtube_video' => "YouTube video",
],
'lua-scripts' => [
'page_title' => "Submit a LUA Script",
'about_the' => "About the script",
'entry_title' => "Title",
'type_of_hack' => "Modifications",
'version' => "Version",
'status' => "Status", 'status' => "Status",
'release_date' => "Release date", 'release_date' => "Release date",
'release_date_helper' => "If only initial release exist, the release date.", 'release_date_helper' => "If only initial release exist, the release date.",

View File

@@ -10,14 +10,16 @@ use App\Jobs\DeleteXenForoCommentsThread;
use App\Models\Author; use App\Models\Author;
use App\Models\Entry; use App\Models\Entry;
use App\Models\EntryFile; use App\Models\EntryFile;
use App\Models\EntryGallery; use App\Models\Gallery;
use App\Models\EntryHash; use App\Models\EntryHash;
use App\Models\Game; use App\Models\Game;
use App\Models\Genre; use App\Models\Genre;
use App\Models\Language; use App\Models\Language;
use App\Models\Level;
use App\Models\Modification; use App\Models\Modification;
use App\Models\Platform; use App\Models\Platform;
use App\Models\Status; use App\Models\Status;
use App\Models\System;
use App\Services\SubmissionsService; use App\Services\SubmissionsService;
use App\Services\XenforoApiService; use App\Services\XenforoApiService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -39,19 +41,27 @@ class SubmissionController extends Controller
'words' => FormHelpers::getEntryFormWords($section), 'words' => FormHelpers::getEntryFormWords($section),
'isEdit' => false, 'isEdit' => false,
'oldModifications' => old( 'modifications', [] ), 'oldModifications' => old( 'modifications', [] ),
'oldSystems' => old( 'systems', [] ),
'oldLanguages' => old( 'languages', [] ), 'oldLanguages' => old( 'languages', [] ),
'oldCategories' => old( 'categories', [] ),
'oldFilesArray' => $this->services->prepareOldFiles( null ) 'oldFilesArray' => $this->services->prepareOldFiles( null )
]; ];
if( $data['words'] === [] ) if( $data['words'] === [] )
abort(500); abort(500);
if( section_must_be( 'romhacks', $section ) ){ if( section_must_be( ['romhacks', 'lua-scripts'], $section ) ){
$data['modifications'] = Modification::orderBy('name')->get(); $data['modifications'] = Modification::orderBy('name')->get();
} }
if( section_must_be( [ 'romhacks', 'translations', 'homebrew' ], $section ) ){ if( section_must_be( [ 'romhacks', 'translations', 'homebrew', 'lua-scripts' ], $section ) ){
$data['statuses'] = Status::orderBy('id')->get(); $data['statuses'] = Status::orderBy('id')->get();
} }
if( section_must_be( 'utilities' , $section ) ){
$data['systems'] = System::orderBy('name')->get();
}
if( section_must_be( [ 'utilities', 'documents' ], $section ) ) {
$data['levels'] = Level::orderBy('id')->get();
}
return view('submissions.create', $data); return view('submissions.create', $data);
} }
@@ -68,19 +78,27 @@ class SubmissionController extends Controller
'words' => FormHelpers::getEntryFormWords($section), 'words' => FormHelpers::getEntryFormWords($section),
'isEdit' => true, 'isEdit' => true,
'oldModifications' => old('modifications', $entry->modifications->pluck('id')->toArray() ?? [] ), 'oldModifications' => old('modifications', $entry->modifications->pluck('id')->toArray() ?? [] ),
'oldSystems' => old( 'systems', $entry->systems->pluck('id')->toArray() ?? [] ),
'oldLanguages' => old('languages', $entry->languages->pluck('id')->toArray() ?? [] ), 'oldLanguages' => old('languages', $entry->languages->pluck('id')->toArray() ?? [] ),
'oldCategories' => old('categories', $entry->categories->pluck('id')->toArray() ?? [] ),
'oldFilesArray' => $this->services->prepareOldFiles( $entry ) 'oldFilesArray' => $this->services->prepareOldFiles( $entry )
]; ];
if( $data['words'] === [] ) if( $data['words'] === [] )
abort(500); abort(500);
if( section_must_be( 'romhacks', $section ) ){ if( section_must_be( [ 'romhacks', 'lua-scripts' ], $section ) ){
$data['modifications'] = Modification::orderBy('name')->get(); $data['modifications'] = Modification::orderBy('name')->get();
} }
if( section_must_be( [ 'romhacks', 'translations' ], $section ) ){ if( section_must_be( [ 'romhacks', 'translations', 'homebrew', 'lua-scripts' ], $section ) ){
$data['statuses'] = Status::orderBy('id')->get(); $data['statuses'] = Status::orderBy('id')->get();
} }
if( section_must_be( 'utilities' , $section ) ){
$data['systems'] = System::orderBy('name')->get();
}
if( section_must_be( [ 'utilities', 'documents' ], $section ) ) {
$data['levels'] = Level::orderBy('id')->get();
}
return view('submissions.edit', $data); return view('submissions.edit', $data);
} }

View File

@@ -70,28 +70,49 @@ class StoreEntryRequest extends FormRequest
$rules['entry_title'] = "nullable|string|max:255"; $rules['entry_title'] = "nullable|string|max:255";
} }
if( section_must_be( 'romhacks', $section ) ){ if( section_must_be( ['romhacks', 'lua-scripts'], $section ) ){
$rules['modifications'] = 'array|required|min:1'; $rules['modifications'] = 'array|required|min:1';
$rules['modifications.*'] = 'integer|exists:modifications,id'; $rules['modifications.*'] = 'integer|exists:modifications,id';
} else if( section_must_be( 'utilities', $section ) ){
$rules['categories'] = 'array|required|min:1';
$rules['categories.*'] = 'integer|exists:categories,id';
}
if( section_must_be( 'utilities', $section ) ){
$rules['systems'] = 'array|required|min:1';
$rules['systems.*'] = 'integer|exists:systems,id';
} }
$rules['version'] = 'required|string|max:50'; $rules['version'] = 'required|string|max:50';
$rules['release-date'] = 'required|date'; $rules['release-date'] = 'required|date';
$rules['status'] = 'required|integer|exists:statuses,id'; if( section_must_not_be( 'utilities', $section ) ){
$rules['status'] = 'required|integer|exists:statuses,id';
} else {
$rules['level'] = 'required|integer|exists:levels,id';
}
$rules['description'] = 'required|string'; $rules['description'] = 'required|string';
if( section_must_be( ['romhacks', 'translations' ], $section ) ){ $rules['game_selection_mode'] = 'required|string|in:game,platform,none';
$gameSelectionMode = $this->input('game_selection_mode') !== '' ? $this->input('game_selection_mode') : 'game';
if( $gameSelectionMode === 'none' ){
// ...
} else if( $gameSelectionMode === 'platform' ){
$rules['platform_only_id'] = 'required|integer|exists:platforms,id';
} else {
$rules['game_id'] = 'required_without:new-game-title|nullable|integer|exists:games,id'; $rules['game_id'] = 'required_without:new-game-title|nullable|integer|exists:games,id';
$rules['new-game-title'] = 'required_without:game_id|nullable|string|max:255'; $rules['new-game-title'] = 'required_without:game_id|nullable|string|max:255';
$rules['new-game-platform'] = 'required_with:new-game-title|nullable|integer|exists:platforms,id'; $rules['new-game-platform'] = 'required_with:new-game-title|nullable|integer|exists:platforms,id';
$rules['new-game-genre'] = 'required_with:new-game-title|integer|nullable|exists:genres,id'; $rules['new-game-genre'] = 'required_with:new-game-title|integer|nullable|exists:genres,id';
} }
$rules['hashes'] = 'array|required|min:1'; if( section_must_be( ['translations', 'romhacks'], $section ) ){
$rules['hashes.*.filename'] = 'required|string|max:512'; $rules['hashes'] = 'array|required|min:1';
$rules['hashes.*.hash_crc32'] = 'required|string|max:512'; $rules['hashes.*.filename'] = 'required|string|max:512';
$rules['hashes.*.hash_sha1'] = 'required|string|max:512'; $rules['hashes.*.hash_crc32'] = 'required|string|max:512';
$rules['hashes.*.verified'] = 'required|string|max:512'; $rules['hashes.*.hash_sha1'] = 'required|string|max:512';
$rules['hashes.*.verified'] = 'required|string|max:512';
}
$rules['languages'] = 'array|required|min:1'; $rules['languages'] = 'array|required|min:1';
$rules['languages.*'] = 'integer|exists:languages,id'; $rules['languages.*'] = 'integer|exists:languages,id';

View File

@@ -3,13 +3,16 @@
namespace App\Livewire; namespace App\Livewire;
use App\Models\Author; use App\Models\Author;
use App\Models\Category;
use App\Models\Entry; use App\Models\Entry;
use App\Models\Game; use App\Models\Game;
use App\Models\Genre; use App\Models\Genre;
use App\Models\Language; use App\Models\Language;
use App\Models\Level;
use App\Models\Modification; use App\Models\Modification;
use App\Models\Platform; use App\Models\Platform;
use App\Models\Status; use App\Models\Status;
use App\Models\System;
use Livewire\Attributes\Url; use Livewire\Attributes\Url;
use Livewire\Component; use Livewire\Component;
use Livewire\WithPagination; use Livewire\WithPagination;
@@ -114,6 +117,41 @@ class Database extends Component
#[Url(except:'or')] #[Url(except:'or')]
public string $modificationsMode = 'or'; public string $modificationsMode = 'or';
/**
* Categories IDs filter.
* @var array
*/
#[Url(except:[])]
public array $categories = [];
/**
* Categories mode and/or
* @var string
*/
#[Url(except:['or'])]
public string $categoriesMode = 'or';
/**
* Systems IDs filter.
* @var array
*/
#[Url(except:[])]
public array $systems = [];
/**
* Systems mode and/or
* @var string
*/
#[Url(except:['or'])]
public string $systemsMode = 'or';
/**
* Levels IDs filter.
* @var array
*/
#[Url(except:[])]
public array $levels = [];
/** /**
* Sort by field. * Sort by field.
* @var string * @var string
@@ -164,11 +202,16 @@ class Database extends Component
public function updatedLanguagesMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); } public function updatedLanguagesMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedModifications(): void { $this->resetPage(); $this->dispatch('filters-updated'); } public function updatedModifications(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedModificationsMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); } public function updatedModificationsMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedCategories(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedCategoriesMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedSystems(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedSystemsMode(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function updatedLevels(): void { $this->resetPage(); $this->dispatch('filters-updated'); }
public function clearFilters(): void public function clearFilters(): void
{ {
$this->reset([ $this->reset([
'search', 'types', 'platforms', 'genres', 'statuses', 'authors', 'authorsMode', 'languages', 'languagesMode', 'modifications', 'modificationsMode' 'search', 'types', 'platforms', 'genres', 'statuses', 'authors', 'authorsMode', 'languages', 'languagesMode', 'modifications', 'modificationsMode', 'categories', 'categoriesMode', 'systems', 'systemsMode', 'levels'
]); ]);
$this->resetPage(); $this->resetPage();
} }
@@ -188,7 +231,7 @@ class Database extends Component
private function buildQuery() private function buildQuery()
{ {
$query = Entry::query()->published()->with([ $query = Entry::query()->published()->with([
'game.platform', 'game.genre', 'status', 'authors', 'languages' 'game.platform', 'game.genre', 'status', 'authors', 'languages', 'level', 'systems', 'categories', 'modifications'
]); ]);
if( $this->search ) { if( $this->search ) {
@@ -253,6 +296,30 @@ class Database extends Component
} }
} }
if( $this->levels ) {
$query->whereIn('level_id', $this->levels);
}
if( $this->categories ) {
if( $this->categoriesMode === 'and' ) {
foreach ( $this->categories as $categoryId ) {
$query->whereHas('categories', fn($q) => $q->where('categories.id', $categoryId));
}
} else {
$query->whereHas('categories', fn($q) => $q->whereIn('categories.id', $this->categories));
}
}
if( $this->systems ) {
if( $this->systemsMode === 'and' ) {
foreach ( $this->systems as $systemId ) {
$query->whereHas('systems', fn($q) => $q->where('systems.id', $systemId));
}
} else {
$query->whereHas('systems', fn($q) => $q->whereIn('systems.id', $this->systems));
}
}
return $query->orderBy($this->sortBy, $this->sortDir); return $query->orderBy($this->sortBy, $this->sortDir);
} }
@@ -267,6 +334,9 @@ class Database extends Component
'allAuthors' => Author::orderBy('name')->get(), 'allAuthors' => Author::orderBy('name')->get(),
'allLanguages' => Language::orderBy('name')->get(), 'allLanguages' => Language::orderBy('name')->get(),
'allModifications' => Modification::orderBy('name')->get(), 'allModifications' => Modification::orderBy('name')->get(),
'allCategories' => Category::orderBy('name')->get(),
'allLevels' => Level::orderBy('name')->get(),
'allSystems' => System::orderBy('name')->get(),
]); ]);
} }
} }

View File

@@ -16,6 +16,17 @@ class GameSelector extends Component
public const int REQUIRED_CHARS = 3; public const int REQUIRED_CHARS = 3;
/**
* Which section we can change selection mode.
*/
public const array CHANGE_SECTION_MODE = [ 'utilities', 'documents' ];
/**
* Selection mode between game|platform|none.
* @var string
*/
public string $selectionMode = 'game';
/** /**
* If we are in new game mode. * If we are in new game mode.
* @var bool * @var bool
@@ -70,9 +81,25 @@ class GameSelector extends Component
*/ */
public bool $dropdown = false; public bool $dropdown = false;
public function mount( ?int $gameId = null, ?string $newGameTitle = null, ?int $newGamePlatform = null, ?int $newGameGenre = null ): void /**
* In platform mode.
* @var int|null
*/
public ?int $platformModeId = null;
/**
* In platform mode.
* @var string|null
*/
public ?string $platformModeName = null;
public ?string $section = null;
public function mount( ?int $gameId = null, ?string $newGameTitle = null, ?int $newGamePlatform = null, ?int $newGameGenre = null, ?string $section, ?int $platformOnlyId ): void
{ {
$this->section = $section;
// If we selected an existent game. // If we selected an existent game.
if( $gameId ){ if( $gameId ){
$game = Game::with(['platform','genre'])->find($gameId); $game = Game::with(['platform','genre'])->find($gameId);
@@ -93,6 +120,36 @@ class GameSelector extends Component
$this->gamePlatformId = is_numeric($newGamePlatform) ? (int) $newGamePlatform : null; $this->gamePlatformId = is_numeric($newGamePlatform) ? (int) $newGamePlatform : null;
$this->gameGenreId = is_numeric($newGameGenre) ? (int) $newGameGenre : null; $this->gameGenreId = is_numeric($newGameGenre) ? (int) $newGameGenre : null;
} }
if( in_array( $section, self::CHANGE_SECTION_MODE ) ) {
if ($platformOnlyId) {
$this->selectionMode = 'platform';
$this->platformModeId = $platformOnlyId;
$platform = Platform::find($platformOnlyId);
if ($platform) {
$this->platformModeName = $platform->name;
} else {
$this->platformModeId = null;
}
}
}
}
public function setSelectionMode(string $mode): void
{
if( !in_array( $this->section, self::CHANGE_SECTION_MODE ) )
return;
$this->selectionMode = $mode;
if( $mode !== 'game' ){
$this->clearGame();
$this->newGame = false;
}
if( $mode !== 'platform' ){
$this->platformModeId = null;
$this->platformModeName = null;
}
} }
/** /**
@@ -134,6 +191,15 @@ class GameSelector extends Component
} }
public function selectPlatformOnly( int $id ): void
{
$platform = Platform::find($id);
if( $platform ){
$this->platformModeId = $platform->id;
$this->platformModeName = $platform->name;
}
}
/** /**
* Clear existent game selection. * Clear existent game selection.
* @return void * @return void
@@ -179,6 +245,10 @@ class GameSelector extends Component
} }
$data['hasOldNewGame'] = old('new-game-title') || old('new-game-platform') || old('new-game-genre'); $data['hasOldNewGame'] = old('new-game-title') || old('new-game-platform') || old('new-game-genre');
$data['canChangeSelection'] = in_array( $this->section, self::CHANGE_SECTION_MODE );
if( in_array( $this->section, self::CHANGE_SECTION_MODE ) )
$data['platforms'] = Platform::orderBy('name')->get();
return view('livewire.game-selector', $data ); return view('livewire.game-selector', $data );
} }
} }

View File

@@ -8,6 +8,28 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property string|null $website
* @property int|null $user_id
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Entry> $entries
* @property-read int|null $entries_count
* @method static \Illuminate\Database\Eloquent\Builder<static>|Author newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Author newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Author query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Author whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Author whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Author whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Author whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Author whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Author whereUserId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Author whereWebsite($value)
* @mixin \Eloquent
*/
class Author extends Model class Author extends Model
{ {
protected $fillable = [ protected $fillable = [

33
app/Models/Category.php Normal file
View File

@@ -0,0 +1,33 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property array<array-key, mixed>|null $restricted_to
* @method static \Illuminate\Database\Eloquent\Builder<static>|Category newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Category newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Category query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Category whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Category whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Category whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Category whereRestrictedTo($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Category whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Category whereUpdatedAt($value)
* @mixin \Eloquent
*/
class Category extends Model
{
protected $fillable = ['name', 'slug', 'restricted_to'];
protected $casts = [
'restricted_to' => 'array',
];
}

View File

@@ -2,17 +2,100 @@
namespace App\Models; namespace App\Models;
use App\Traits\HasGallery;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Monolog\Level;
/**
* @property int $id
* @property string $type
* @property string|null $title
* @property string|null $slug
* @property string|null $description
* @property string|null $main_image
* @property string $state
* @property string|null $staff_comment
* @property \Illuminate\Support\Carbon|null $rejected_at
* @property bool $featured
* @property int|null $game_id
* @property int|null $platform_id
* @property int|null $status_id
* @property string|null $version
* @property \Illuminate\Support\Carbon|null $release_date
* @property string|null $staff_credits
* @property string|null $relevant_link
* @property string|null $youtube_link
* @property int $user_id
* @property int|null $comments_thread_id
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property string|null $complete_title
* @property \Illuminate\Support\Carbon|null $deleted_at
* @property int|null $level_id
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Author> $authors
* @property-read int|null $authors_count
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Category> $categories
* @property-read int|null $categories_count
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\EntryFile> $files
* @property-read int|null $files_count
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Gallery> $gallery
* @property-read int|null $gallery_count
* @property-read \App\Models\Game|null $game
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\EntryHash> $hashes
* @property-read int|null $hashes_count
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Language> $languages
* @property-read int|null $languages_count
* @property-read \App\Models\Level|null $level
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Modification> $modifications
* @property-read int|null $modifications_count
* @property-read \App\Models\Platform|null $platform
* @property-read \App\Models\Status|null $status
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\System> $systems
* @property-read int|null $systems_count
* @method static Builder<static>|Entry inQueue(int $daysRejected = 7)
* @method static Builder<static>|Entry newModelQuery()
* @method static Builder<static>|Entry newQuery()
* @method static Builder<static>|Entry onlyTrashed()
* @method static Builder<static>|Entry published()
* @method static Builder<static>|Entry query()
* @method static Builder<static>|Entry whereCommentsThreadId($value)
* @method static Builder<static>|Entry whereCompleteTitle($value)
* @method static Builder<static>|Entry whereCreatedAt($value)
* @method static Builder<static>|Entry whereDeletedAt($value)
* @method static Builder<static>|Entry whereDescription($value)
* @method static Builder<static>|Entry whereFeatured($value)
* @method static Builder<static>|Entry whereGameId($value)
* @method static Builder<static>|Entry whereId($value)
* @method static Builder<static>|Entry whereLevelId($value)
* @method static Builder<static>|Entry whereMainImage($value)
* @method static Builder<static>|Entry wherePlatformId($value)
* @method static Builder<static>|Entry whereRejectedAt($value)
* @method static Builder<static>|Entry whereReleaseDate($value)
* @method static Builder<static>|Entry whereRelevantLink($value)
* @method static Builder<static>|Entry whereSlug($value)
* @method static Builder<static>|Entry whereStaffComment($value)
* @method static Builder<static>|Entry whereStaffCredits($value)
* @method static Builder<static>|Entry whereState($value)
* @method static Builder<static>|Entry whereStatusId($value)
* @method static Builder<static>|Entry whereTitle($value)
* @method static Builder<static>|Entry whereType($value)
* @method static Builder<static>|Entry whereUpdatedAt($value)
* @method static Builder<static>|Entry whereUserId($value)
* @method static Builder<static>|Entry whereVersion($value)
* @method static Builder<static>|Entry whereYoutubeLink($value)
* @method static Builder<static>|Entry withTrashed(bool $withTrashed = true)
* @method static Builder<static>|Entry withoutTrashed()
* @mixin \Eloquent
*/
class Entry extends Model class Entry extends Model
{ {
use SoftDeletes; use SoftDeletes, HasGallery;
/** /**
* @var string[] * @var string[]
@@ -38,6 +121,7 @@ class Entry extends Model
'comments_thread_id', 'comments_thread_id',
'staff_comment', 'staff_comment',
'rejected_at', 'rejected_at',
'level_id'
]; ];
/** /**
@@ -81,6 +165,10 @@ class Entry extends Model
return $this->belongsTo(Status::class ); return $this->belongsTo(Status::class );
} }
public function level(): BelongsTo {
return $this->belongsTo(\App\Models\Level::class);
}
public function authors(): BelongsToMany { public function authors(): BelongsToMany {
return $this->belongsToMany(Author::class, 'entry_authors'); return $this->belongsToMany(Author::class, 'entry_authors');
} }
@@ -93,12 +181,16 @@ class Entry extends Model
return $this->belongsToMany( Modification::class, 'entry_modifications'); return $this->belongsToMany( Modification::class, 'entry_modifications');
} }
public function files(): HasMany { public function categories(): BelongsToMany {
return $this->hasMany(EntryFile::class)->orderBy('filename'); return $this->belongsToMany(Category::class, 'entry_categories');
} }
public function gallery(): HasMany { public function systems(): BelongsToMany {
return $this->hasMany(EntryGallery::class)->orderBy('id'); return $this->belongsToMany(System::class, 'entry_systems');
}
public function files(): HasMany {
return $this->hasMany(EntryFile::class)->orderBy('filename');
} }
public function hashes(): HasMany { public function hashes(): HasMany {

View File

@@ -5,6 +5,39 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property int $id
* @property int $entry_id
* @property string $filename
* @property string $filepath
* @property string $favorite_server
* @property int $favorite_at
* @property int|null $filesize
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property string $file_uuid
* @property string $state
* @property int $online_patcher
* @property int $secondary_online_patcher
* @property-read \App\Models\Entry|null $entry
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereEntryId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereFavoriteAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereFavoriteServer($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereFileUuid($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereFilename($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereFilepath($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereFilesize($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereOnlinePatcher($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereSecondaryOnlinePatcher($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereState($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryFile whereUpdatedAt($value)
* @mixin \Eloquent
*/
class EntryFile extends Model class EntryFile extends Model
{ {
protected $fillable = [ protected $fillable = [

View File

@@ -2,10 +2,7 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model; /**
* @deprecated Use Gallery instead.
class EntryGallery extends Model */
{ class EntryGallery extends Gallery {}
protected $fillable = ['entry_id','image'];
}

View File

@@ -5,6 +5,29 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property int $id
* @property int $entry_id
* @property string $filename
* @property string $hash_crc32
* @property string $hash_sha1
* @property string $verified
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \App\Models\Entry|null $entry
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash whereEntryId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash whereFilename($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash whereHashCrc32($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash whereHashSha1($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|EntryHash whereVerified($value)
* @mixin \Eloquent
*/
class EntryHash extends Model class EntryHash extends Model
{ {
protected $fillable = [ protected $fillable = [

34
app/Models/Gallery.php Normal file
View File

@@ -0,0 +1,34 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
/**
* @property int $id
* @property int $entry_id
* @property string $image
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder<static>|Gallery newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Gallery newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Gallery query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Gallery whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Gallery whereEntryId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Gallery whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Gallery whereImage($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Gallery whereUpdatedAt($value)
* @mixin \Eloquent
*/
class Gallery extends Model
{
protected $table = 'galleries';
protected $fillable = ['image', 'galleryable_id', 'galleryable_type'];
public function galleryable(): MorphTo
{
return $this->morphTo();
}
}

View File

@@ -5,6 +5,30 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property int $platform_id
* @property int $genre_id
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Entry> $entries
* @property-read int|null $entries_count
* @property-read \App\Models\Genre $genre
* @property-read \App\Models\Platform $platform
* @method static \Illuminate\Database\Eloquent\Builder<static>|Game newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Game newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Game query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Game whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Game whereGenreId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Game whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Game whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Game wherePlatformId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Game whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Game whereUpdatedAt($value)
* @mixin \Eloquent
*/
class Game extends Model class Game extends Model
{ {
/** /**

View File

@@ -6,6 +6,24 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Game> $games
* @property-read int|null $games_count
* @method static \Illuminate\Database\Eloquent\Builder<static>|Genre newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Genre newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Genre query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Genre whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Genre whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Genre whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Genre whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Genre whereUpdatedAt($value)
* @mixin \Eloquent
*/
class Genre extends Model class Genre extends Model
{ {
protected $fillable = [ 'name', 'slug' ]; protected $fillable = [ 'name', 'slug' ];

View File

@@ -6,6 +6,24 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Entry> $entries
* @property-read int|null $entries_count
* @method static \Illuminate\Database\Eloquent\Builder<static>|Language newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Language newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Language query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Language whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Language whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Language whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Language whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Language whereUpdatedAt($value)
* @mixin \Eloquent
*/
class Language extends Model class Language extends Model
{ {
protected $fillable = [ 'name', 'slug' ]; protected $fillable = [ 'name', 'slug' ];

26
app/Models/Level.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder<static>|Level newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Level newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Level query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Level whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Level whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Level whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Level whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Level whereUpdatedAt($value)
* @mixin \Eloquent
*/
class Level extends Model
{
protected $fillable = ['name', 'slug'];
}

View File

@@ -4,6 +4,22 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder<static>|Modification newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Modification newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Modification query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Modification whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Modification whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Modification whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Modification whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Modification whereUpdatedAt($value)
* @mixin \Eloquent
*/
class Modification extends Model class Modification extends Model
{ {
protected $fillable = [ 'name', 'slug' ]; protected $fillable = [ 'name', 'slug' ];

View File

@@ -5,6 +5,28 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property string|null $short_name
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Entry> $entries
* @property-read int|null $entries_count
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Game> $games
* @property-read int|null $games_count
* @method static \Illuminate\Database\Eloquent\Builder<static>|Platform newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Platform newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Platform query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Platform whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Platform whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Platform whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Platform whereShortName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Platform whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Platform whereUpdatedAt($value)
* @mixin \Eloquent
*/
class Platform extends Model class Platform extends Model
{ {

View File

@@ -4,6 +4,22 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder<static>|Status newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Status newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Status query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|Status whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Status whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Status whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Status whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|Status whereUpdatedAt($value)
* @mixin \Eloquent
*/
class Status extends Model class Status extends Model
{ {
protected $fillable = ['name', 'slug']; protected $fillable = ['name', 'slug'];

26
app/Models/System.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder<static>|System newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|System newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|System query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|System whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|System whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|System whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|System whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|System whereUpdatedAt($value)
* @mixin \Eloquent
*/
class System extends Model
{
protected $fillable = ['name', 'slug'];
}

View File

@@ -10,6 +10,31 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
/**
* @property int $id
* @property string $name
* @property string $email
* @property \Illuminate\Support\Carbon|null $email_verified_at
* @property string $password
* @property string|null $remember_token
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read int|null $notifications_count
* @method static \Database\Factories\UserFactory factory($count = null, $state = [])
* @method static \Illuminate\Database\Eloquent\Builder<static>|User newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|User newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|User query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereEmail($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereEmailVerifiedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|User wherePassword($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereRememberToken($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereUpdatedAt($value)
* @mixin \Eloquent
*/
#[Fillable(['name', 'email', 'password'])] #[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])] #[Hidden(['password', 'remember_token'])]
class User extends Authenticatable class User extends Authenticatable

View File

@@ -8,15 +8,17 @@ use App\Helpers\XenForoHelpers;
use App\Http\Requests\StoreEntryRequest; use App\Http\Requests\StoreEntryRequest;
use App\Jobs\CreateXenForoCommentsThread; use App\Jobs\CreateXenForoCommentsThread;
use App\Models\Author; use App\Models\Author;
use App\Models\Category;
use App\Models\Entry; use App\Models\Entry;
use App\Models\EntryFile; use App\Models\EntryFile;
use App\Models\EntryGallery; use App\Models\Gallery;
use App\Models\EntryHash; use App\Models\EntryHash;
use App\Models\Game; use App\Models\Game;
use App\Models\Genre; use App\Models\Genre;
use App\Models\Language; use App\Models\Language;
use App\Models\Modification; use App\Models\Modification;
use App\Models\Platform; use App\Models\Platform;
use App\Models\System;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@@ -118,11 +120,7 @@ class SubmissionsService {
$entry = DB::transaction(function () use ( $user_id ) { $entry = DB::transaction(function () use ( $user_id ) {
// STEP 2 : Create game. // STEP 2 : Create game.
$gameId = $this->Step2_CreateAndReturnGameId();
$gameId = null;
if( section_must_be( ['romhacks', 'translations'], $this->section ) ){
$gameId = $this->Step2_CreateAndReturnGameId();
}
// STEP 3 : Create Complete title. // STEP 3 : Create Complete title.
$completeTitle = $this->Step3_BuildCompleteTitle( $gameId ); $completeTitle = $this->Step3_BuildCompleteTitle( $gameId );
@@ -132,7 +130,7 @@ class SubmissionsService {
if( section_must_be( 'translations', $this->section ) && if( section_must_be( 'translations', $this->section ) &&
!$this->request->input('entry_title') ){ !$this->request->input('entry_title') ){
$entryTitle = Game::find($gameId)->name; $entryTitle = Game::find($gameId)->name ?? "";
} else { } else {
$entryTitle = $this->request->input('entry_title'); $entryTitle = $this->request->input('entry_title');
} }
@@ -149,6 +147,7 @@ class SubmissionsService {
'main_image' => $this->request->input('main-image'), 'main_image' => $this->request->input('main-image'),
'state' => $this->request->input('submit-state'), 'state' => $this->request->input('submit-state'),
'game_id' => $gameId, 'game_id' => $gameId,
'platform_id' => $this->request->input('platform_only_id'),
'status_id' => $this->request->input('status'), 'status_id' => $this->request->input('status'),
'version' => $this->request->input('version'), 'version' => $this->request->input('version'),
'release_date' => $this->request->input('release-date'), 'release_date' => $this->request->input('release-date'),
@@ -157,6 +156,7 @@ class SubmissionsService {
'youtube_link' => $this->request->input('youtube_video'), 'youtube_link' => $this->request->input('youtube_video'),
'user_id' => $user_id, 'user_id' => $user_id,
'complete_title' => $completeTitle, 'complete_title' => $completeTitle,
'level_id' => $this->request->input('level')
]; ];
$entry = Entry::create( $fields ); $entry = Entry::create( $fields );
@@ -165,19 +165,28 @@ class SubmissionsService {
$this->Step7_SaveEntryFiles( $entry ); $this->Step7_SaveEntryFiles( $entry );
// STEP 8 : Save hashes. // STEP 8 : Save hashes.
$this->Step8_SaveHashes( $entry->id ); if( section_must_be( ['translations', 'romhacks' ], $this->section ) )
$this->Step8_SaveHashes( $entry->id );
// STEP 9 : Save Authors. // STEP 9 : Save Authors.
$this->Step9_SaveAuthors( $entry ); $this->Step9_SaveAuthors( $entry );
// STEP 10 : Save Modifications. // STEP 10 : Save Modifications.
if( section_must_be( 'romhacks', $this->section ) ){ if( section_must_be( ['romhacks','lua-scripts'], $this->section ) ){
$this->Step10_SaveRomhacksModifications( $entry ); $this->Step10_SaveRomhacksModifications( $entry );
} }
if( section_must_be( 'utilities', $this->section ) ){
$this->Step10_SaveUtilitiesSystems( $entry );
}
// STEP 11 : Save Languages // STEP 11 : Save Languages
$this->Step11_SaveLanguages( $entry ); $this->Step11_SaveLanguages( $entry );
// STEP 11.5 : Save Categories
if( section_must_be( 'utilities', $this->section ) ) {
$this->Step11_5_SaveCategories($entry);
}
// STEP 12 : Prepare Gallery images. // STEP 12 : Prepare Gallery images.
$this->Step12a_PrepareGalleryImages( $entry ); $this->Step12a_PrepareGalleryImages( $entry );
@@ -207,6 +216,10 @@ class SubmissionsService {
*/ */
private function Step2_CreateAndReturnGameId(): ?int { private function Step2_CreateAndReturnGameId(): ?int {
$mode = $this->request->input('game_selection_mode', 'game');
if( $mode !== 'game' )
return null;
// Already existing game. // Already existing game.
if( $this->request->input('game_id') ) if( $this->request->input('game_id') )
return $this->request->input('game_id'); return $this->request->input('game_id');
@@ -261,9 +274,9 @@ class SubmissionsService {
if( section_must_be( 'translations', $this->section ) ) { if( section_must_be( 'translations', $this->section ) ) {
$fields['languages_string'] = Language::whereIn('id', $this->request->input('languages', []))->pluck('name')->implode(', '); $fields['languages_string'] = Language::whereIn('id', $this->request->input('languages', []))->pluck('name')->implode(', ');
} }
if( section_must_be(['romhacks', 'translations', 'homebrew', 'lua-scripts', 'tutorials'], $this->section ) ) { if( section_must_be(['romhacks', 'translations', 'homebrew', 'lua-scripts'], $this->section ) ) {
// TODO: Add single platform ID compatibility. // TODO: Add single platform ID compatibility.
$fields['platform_name'] = $gameId ? Game::find( $gameId )->platform->name : null; $fields['platform_name'] = $gameId ? Game::find( $gameId )->platform->name : Platform::find( $this->request->input('platform_only_id') )?->name ?? null;
} }
return EntryHelpers::buildCompleteTitle( $this->section, $fields ); return EntryHelpers::buildCompleteTitle( $this->section, $fields );
@@ -381,6 +394,24 @@ class SubmissionsService {
} }
} }
/**
* @param Entry $entry
*
* @return void
* @throws SubmissionException
*/
private function Step10_SaveUtilitiesSystems( Entry $entry ): void
{
// TODO: Replace by edit version
foreach ( $this->request->input('systems', [] ) ?? [] as $systemId ) {
$system = System::find( $systemId );
if( !$system )
throw new SubmissionException( "System {$systemId} does not exist." );
$entry->systems()->attach( $system->id );
}
}
/** /**
* @param Entry $entry * @param Entry $entry
* *
@@ -400,11 +431,29 @@ class SubmissionsService {
} }
/**
* @param Entry $entry
*
* @return void
* @throws SubmissionException
*/
private function Step11_5_SaveCategories( Entry $entry ): void
{
// TODO: Replace by edit version.
foreach ( $this->request->input('categories', [] ) ?? [] as $categoryId ) {
$category = Category::find( $categoryId );
if( !$category )
throw new SubmissionException( "Category {$categoryId} does not exist." );
$entry->categories()->attach( $category->id );
}
}
private function Step12a_PrepareGalleryImages( Entry $entry ): void private function Step12a_PrepareGalleryImages( Entry $entry ): void
{ {
foreach ( $this->request->input('gallery', [] ) ?? [] as $imagePath ) { foreach ( $this->request->input('gallery', [] ) ?? [] as $imagePath ) {
EntryGallery::create([ $entry->gallery()->create([
'entry_id' => $entry->id,
'image' => $imagePath, 'image' => $imagePath,
]); ]);
} }
@@ -464,9 +513,7 @@ class SubmissionsService {
// STEP 2: Create game if different. // STEP 2: Create game if different.
$gameId = null; $gameId = null;
if( section_must_be( ['romhacks', 'translations' ], $this->section ) ){ $gameId = $this->eStep2_VerifyCreateAndEditGameId();
$gameId = $this->eStep2_VerifyCreateAndEditGameId();
}
// STEP 3: Recreate complete title and refresh slug if needed. // STEP 3: Recreate complete title and refresh slug if needed.
$completeTitle = $this->Step3_BuildCompleteTitle( $gameId ); $completeTitle = $this->Step3_BuildCompleteTitle( $gameId );
@@ -494,6 +541,7 @@ class SubmissionsService {
'main_image' => $this->request->input('main-image'), 'main_image' => $this->request->input('main-image'),
'state' => $this->request->input('submit-state'), 'state' => $this->request->input('submit-state'),
'game_id' => $gameId, 'game_id' => $gameId,
'platform_id' => $this->request->input('platform_only_id'),
'status_id' => $this->request->input('status'), 'status_id' => $this->request->input('status'),
'version' => $this->request->input('version'), 'version' => $this->request->input('version'),
'release_date' => $this->request->input('release-date'), 'release_date' => $this->request->input('release-date'),
@@ -502,12 +550,13 @@ class SubmissionsService {
'youtube_link' => $this->request->input('youtube_video'), 'youtube_link' => $this->request->input('youtube_video'),
'user_id' => $user_id, 'user_id' => $user_id,
'complete_title' => $completeTitle, 'complete_title' => $completeTitle,
'comments_thread_id' => $this->request->input('comments_thread_id'), 'level_id' => $this->request->input('level'),
'featured' => $this->request->input('featured') ?? false,
]; ];
if( \Auth::user()->can('moderate', $this->entry) ){ if( \Auth::user()->can('moderate', $this->entry) ){
$fields['staff_comment'] = $this->request->input('staff_comment'); $fields['staff_comment'] = $this->request->input('staff_comment');
$fields['featured'] = $this->request->input('featured') ?? false;
$fields['comments_thread_id'] = $this->request->input('comments_thread_id');
} }
$this->entry->update( $fields ); $this->entry->update( $fields );
@@ -516,19 +565,27 @@ class SubmissionsService {
$this->eStep6_UpdateEntryFiles( $this->entry->id ); $this->eStep6_UpdateEntryFiles( $this->entry->id );
// STEP 7: Update hashes. // STEP 7: Update hashes.
$this->eStep7_UpdateHashes( $this->entry->id ); if( section_must_be( ['translations', 'romhacks' ], $this->section ) )
$this->eStep7_UpdateHashes( $this->entry->id );
// STEP 8: Update Authors. // STEP 8: Update Authors.
$this->eStep8_UpdateAuthors(); $this->eStep8_UpdateAuthors();
// STEP 9: Update romhacks modifications. // STEP 9: Update romhacks modifications.
if( section_must_be( 'romhacks', $this->section ) ) { if( section_must_be( ['romhacks', 'lua-scripts'], $this->section ) ) {
$this->eStep9_UpdateRomhacksModifications(); $this->eStep9_UpdateRomhacksModifications();
} }
if( section_must_be( 'utilities', $this->section ) ) {
$this->eStep9_UpdateUtilitiesSystems();
}
// STEP 10: Update Languages. // STEP 10: Update Languages.
$this->eStep10_UpdateLanguages(); $this->eStep10_UpdateLanguages();
// STEP 10.5 : Update categories
if( section_must_be( 'utilities', $this->section ) )
$this->eStep10_5_UpdateCategories();
// STEP 11: Prepare new gallery images and prepare deletion of others ones. // STEP 11: Prepare new gallery images and prepare deletion of others ones.
$galleryPaths = $this->eStep11a_UpdateGalleryImages(); $galleryPaths = $this->eStep11a_UpdateGalleryImages();
@@ -558,8 +615,14 @@ class SubmissionsService {
/** /**
* @throws SubmissionException * @throws SubmissionException
*/ */
private function eStep2_VerifyCreateAndEditGameId(): int private function eStep2_VerifyCreateAndEditGameId(): ?int
{ {
$mode = $this->request->input('game_selection_mode', 'game');
if ($mode !== 'game') {
return null;
}
// Already existing game. // Already existing game.
if( $this->request->input('game_id') ){ if( $this->request->input('game_id') ){
@@ -721,6 +784,27 @@ class SubmissionsService {
} }
/**
* @return void
* @throws SubmissionException
*/
private function eStep9_UpdateUtilitiesSystems(): void
{
$requestSystems = $this->request->input('systems', [] ) ?? [];
if( !empty( $requestSystems ) ){
$valid = System::whereIn( 'id', $requestSystems )->pluck('id')->toArray();
if( count( $valid ) !== count( $requestSystems ) ){
throw new SubmissionException( "One of the systems doesn't exist." );
}
}
$this->entry->systems()->sync( $requestSystems );
}
/** /**
* @return void * @return void
* @throws SubmissionException * @throws SubmissionException
@@ -739,6 +823,24 @@ class SubmissionsService {
$this->entry->languages()->sync( $requestLanguages ); $this->entry->languages()->sync( $requestLanguages );
} }
/**
* @return void
* @throws SubmissionException
*/
private function eStep10_5_UpdateCategories(): void
{
$requestCategories = $this->request->input('categories', [] ) ?? [];
if( !empty( $requestCategories ) ){
$valid = Category::whereIn( 'id', $requestCategories )->pluck('id')->toArray();
if( count( $valid ) !== count( $requestCategories ) ){
throw new SubmissionException( "One of the categories doesn't exist." );
}
}
$this->entry->categories()->sync( $requestCategories );
}
private function eStep11a_UpdateGalleryImages(): array private function eStep11a_UpdateGalleryImages(): array
{ {
$requestGallery = $this->request->input('gallery', [] ) ?? []; $requestGallery = $this->request->input('gallery', [] ) ?? [];
@@ -747,14 +849,13 @@ class SubmissionsService {
$needDeletion = array_diff( $existingGalleryPaths, $requestGallery ); $needDeletion = array_diff( $existingGalleryPaths, $requestGallery );
if( !empty( $needDeletion ) ){ if( !empty( $needDeletion ) ){
EntryGallery::where('entry_id', $this->entry->id)->whereIn('image', $needDeletion )->delete(); $this->entry->gallery()->whereIn('image', $needDeletion )->delete();
} }
$needAddition = array_diff( $requestGallery, $existingGalleryPaths ); $needAddition = array_diff( $requestGallery, $existingGalleryPaths );
$images = []; $images = [];
foreach( $needAddition as $imagePath ){ foreach( $needAddition as $imagePath ){
$images[] = EntryGallery::create([ $images[] = $this->entry->gallery()->create([
'entry_id' => $this->entry->id,
'image' => $imagePath, 'image' => $imagePath,
]); ]);
} }

14
app/Traits/HasGallery.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
namespace App\Traits;
use App\Models\Gallery;
use Illuminate\Database\Eloquent\Relations\MorphMany;
trait HasGallery
{
public function gallery(): MorphMany
{
return $this->morphMany(Gallery::class, 'galleryable')->orderBy('id');
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\View\Components;
use App\Models\Category;
use App\Models\Language;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class CategorySelector extends Component
{
public $categories;
/**f
* Create a new component instance.
*/
public function __construct(
public string $section,
public array $selected = [],
public bool $required = true
)
{
$this->categories = Category::query()
->where(function ($query) {
$query->whereJsonContains('restricted_to', $this->section)
->orWhereNull('restricted_to');
})
->orderBy('name')
->get();
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.category-selector');
}
}

View File

@@ -18,6 +18,7 @@
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^4.2", "barryvdh/laravel-debugbar": "^4.2",
"barryvdh/laravel-ide-helper": "^3.7",
"fakerphp/faker": "^1.23", "fakerphp/faker": "^1.23",
"larastan/larastan": "^3.9", "larastan/larastan": "^3.9",
"laravel/pail": "^1.2.5", "laravel/pail": "^1.2.5",

301
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "a1c836758aaea45cc09c0c7786ea366f", "content-hash": "79ce85f4c121f30d964f9322cb7120a4",
"packages": [ "packages": [
{ {
"name": "blade-ui-kit/blade-heroicons", "name": "blade-ui-kit/blade-heroicons",
@@ -8316,6 +8316,301 @@
], ],
"time": "2026-04-20T13:31:29+00:00" "time": "2026-04-20T13:31:29+00:00"
}, },
{
"name": "barryvdh/laravel-ide-helper",
"version": "v3.7.0",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-ide-helper.git",
"reference": "ad7e37676f1ff985d55ef1b6b96a0c0a40f2609a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/ad7e37676f1ff985d55ef1b6b96a0c0a40f2609a",
"reference": "ad7e37676f1ff985d55ef1b6b96a0c0a40f2609a",
"shasum": ""
},
"require": {
"barryvdh/reflection-docblock": "^2.4",
"composer/class-map-generator": "^1.0",
"ext-json": "*",
"illuminate/console": "^11.15 || ^12 || ^13.0",
"illuminate/database": "^11.15 || ^12 || ^13.0",
"illuminate/filesystem": "^11.15 || ^12 || ^13.0",
"illuminate/support": "^11.15 || ^12 || ^13.0",
"php": "^8.2"
},
"require-dev": {
"ext-pdo_sqlite": "*",
"friendsofphp/php-cs-fixer": "^3",
"illuminate/config": "^11.15 || ^12 || ^13.0",
"illuminate/view": "^11.15 || ^12 || ^13.0",
"larastan/larastan": "^3.1",
"mockery/mockery": "^1.4",
"orchestra/testbench": "^9.2 || ^10 || ^11.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^10.5 || ^11.5.3 || ^12.5.12",
"spatie/phpunit-snapshot-assertions": "^4 || ^5",
"vlucas/phpdotenv": "^5"
},
"suggest": {
"illuminate/events": "Required for automatic helper generation (^6|^7|^8|^9|^10|^11)."
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider"
]
},
"branch-alias": {
"dev-master": "3.6-dev"
}
},
"autoload": {
"psr-4": {
"Barryvdh\\LaravelIdeHelper\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.",
"keywords": [
"autocomplete",
"codeintel",
"dev",
"helper",
"ide",
"laravel",
"netbeans",
"phpdoc",
"phpstorm",
"sublime"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-ide-helper/issues",
"source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.7.0"
},
"funding": [
{
"url": "https://fruitcake.nl",
"type": "custom"
},
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2026-03-17T14:12:51+00:00"
},
{
"name": "barryvdh/reflection-docblock",
"version": "v2.4.1",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/ReflectionDocBlock.git",
"reference": "4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b",
"reference": "4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"require-dev": {
"phpunit/phpunit": "^8.5.14|^9"
},
"suggest": {
"dflydev/markdown": "~1.0",
"erusev/parsedown": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3.x-dev"
}
},
"autoload": {
"psr-0": {
"Barryvdh": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "mike.vanriel@naenius.com"
}
],
"support": {
"source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.4.1"
},
"time": "2026-03-05T20:09:01+00:00"
},
{
"name": "composer/class-map-generator",
"version": "1.7.3",
"source": {
"type": "git",
"url": "https://github.com/composer/class-map-generator.git",
"reference": "86d8208fc3c649a3a999daf1a63c25201be2990f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/class-map-generator/zipball/86d8208fc3c649a3a999daf1a63c25201be2990f",
"reference": "86d8208fc3c649a3a999daf1a63c25201be2990f",
"shasum": ""
},
"require": {
"composer/pcre": "^2.1 || ^3.1",
"php": "^7.2 || ^8.0",
"symfony/finder": "^4.4 || ^5.3 || ^6 || ^7 || ^8"
},
"require-dev": {
"phpstan/phpstan": "^1.12 || ^2",
"phpstan/phpstan-deprecation-rules": "^1 || ^2",
"phpstan/phpstan-phpunit": "^1 || ^2",
"phpstan/phpstan-strict-rules": "^1.1 || ^2",
"phpunit/phpunit": "^8",
"symfony/filesystem": "^5.4 || ^6 || ^7 || ^8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\ClassMapGenerator\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "https://seld.be"
}
],
"description": "Utilities to scan PHP code and generate class maps.",
"keywords": [
"classmap"
],
"support": {
"issues": "https://github.com/composer/class-map-generator/issues",
"source": "https://github.com/composer/class-map-generator/tree/1.7.3"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
}
],
"time": "2026-05-05T09:17:07+00:00"
},
{
"name": "composer/pcre",
"version": "3.3.2",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0"
},
"conflict": {
"phpstan/phpstan": "<1.11.10"
},
"require-dev": {
"phpstan/phpstan": "^1.12 || ^2",
"phpstan/phpstan-strict-rules": "^1 || ^2",
"phpunit/phpunit": "^8 || ^9"
},
"type": "library",
"extra": {
"phpstan": {
"includes": [
"extension.neon"
]
},
"branch-alias": {
"dev-main": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Pcre\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
"keywords": [
"PCRE",
"preg",
"regex",
"regular expression"
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/3.3.2"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2024-11-12T16:29:46+00:00"
},
{ {
"name": "fakerphp/faker", "name": "fakerphp/faker",
"version": "v1.24.1", "version": "v1.24.1",
@@ -10945,7 +11240,9 @@
"prefer-stable": true, "prefer-stable": true,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": "^8.4" "php": "^8.4",
"ext-xmlreader": "*",
"ext-simplexml": "*"
}, },
"platform-dev": {}, "platform-dev": {},
"plugin-api-version": "2.9.0" "plugin-api-version": "2.9.0"

View File

@@ -0,0 +1,29 @@
<?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('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('slug')->unique();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('categories');
}
};

View File

@@ -0,0 +1,29 @@
<?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('systems', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('slug')->unique();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('systems');
}
};

View File

@@ -0,0 +1,29 @@
<?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('levels', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('slug')->unique();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('levels');
}
};

View File

@@ -0,0 +1,28 @@
<?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::table('entries', function (Blueprint $table) {
$table->foreignId('level_id')->nullable()->constrained('levels')->nullOnDelete();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('entries', function (Blueprint $table) {
$table->dropColumn('level_id');
});
}
};

View File

@@ -0,0 +1,28 @@
<?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('entry_systems', function (Blueprint $table) {
$table->foreignId('entry_id')->constrained('entries')->cascadeOnDelete();
$table->foreignId('system_id')->constrained('systems')->cascadeOnDelete();
$table->primary(['entry_id', 'system_id']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('entry_systems');
}
};

View File

@@ -0,0 +1,28 @@
<?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('entry_categories', function (Blueprint $table) {
$table->foreignId('entry_id')->constrained('entries')->cascadeOnDelete();
$table->foreignId('category_id')->constrained('categories')->cascadeOnDelete();
$table->primary(['entry_id', 'category_id']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('entry_categories');
}
};

View File

@@ -0,0 +1,28 @@
<?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::table('categories', function (Blueprint $table) {
$table->json('restricted_to')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('categories', function (Blueprint $table) {
$table->dropColumn('restricted_to');
});
}
};

View File

@@ -0,0 +1,40 @@
<?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::rename('entry_galleries', 'galleries');
Schema::table('galleries', function (Blueprint $table) {
$table->string('galleryable_type')->default('App\\Models\\Entry')
->after('id');
$table->renameColumn('entry_id', 'galleryable_id');
$table->index(['galleryable_type', 'galleryable_id']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('galleries', function (Blueprint $table) {
$table->dropColumn('galleryable_type');
$table->renameColumn('galleryable_id', 'entry_id');
$table->dropIndex(['galleryable_type', 'galleryable_id']);
});
Schema::rename('galleries', 'entry_galleries');
}
};

View File

@@ -0,0 +1,27 @@
<?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('news', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('news');
}
};

View File

@@ -63,7 +63,7 @@ ul {
--error: #e57373; --error: #e57373;
--info: #1976d2; --info: #1976d2;
--success: #81c784; --success: #81c784;
--success2: #388e3c; --success2: #fdeb0f;
/* Typo */ /* Typo */
--typography: 'Segoe UI', 'San Francisco', 'Helvetica Neue', sans-serif; --typography: 'Segoe UI', 'San Francisco', 'Helvetica Neue', sans-serif;

View File

@@ -104,6 +104,11 @@
color: var(--text); color: var(--text);
border-color: var(--success2); border-color: var(--success2);
} }
.badge.yellow, .badge.utilities {
background-color: #fdeb0f;
color: #000;
border-color: #fdeb0f;
}
.topbar-badge { .topbar-badge {
position: absolute; position: absolute;

View File

@@ -528,3 +528,44 @@
} }
.author-search-item:hover { background-color: var(--bg3); } .author-search-item:hover { background-color: var(--bg3); }
.game-selector-mode {
display: flex;
gap: 0;
margin-bottom: 15px;
border: 1px solid var(--border);
}
.game-selector-mode-btn {
display: flex;
align-items: center;
gap: 7px;
padding: 8px 14px;
background: none;
border: none;
border-right: 1px solid var(--border);
color: var(--text2);
font-size: 0.85rem;
cursor: pointer;
font-family: var(--font-family);
transition: background-color 0.1s, color 0.1s;
}
.game-selector-mode-btn:last-child {
border-right: none;
}
.game-selector-mode-btn:hover {
background-color: var(--bg3);
color: var(--text);
}
.game-selector-mode-btn.active {
background-color: var(--bg3);
color: var(--rhpz-orange);
border-bottom: 2px solid var(--rhpz-orange);
}
.game-selector-platform-only {
grid-column: span 1;
}

View File

@@ -22,6 +22,7 @@ const ERROR_TABLE = {
uploadError: "One or more files failed to upload.", uploadError: "One or more files failed to upload.",
notAllFilesDone: "Not all the files have finished uploading yet.", notAllFilesDone: "Not all the files have finished uploading yet.",
noModifications: "Please select at least a type of hack.", noModifications: "Please select at least a type of hack.",
noSystems: "Please select at least a system.",
noDescription: "Please provide a description.", noDescription: "Please provide a description.",
noGame: "Please provide a game or create a new one and fill all the required fields.", noGame: "Please provide a game or create a new one and fill all the required fields.",
noLanguages: "Please select at least a language.", noLanguages: "Please select at least a language.",
@@ -117,6 +118,10 @@ window.SubmissionVerifications = {
return verifyCheckboxes( document.querySelector( '#modifications-group' ) ); return verifyCheckboxes( document.querySelector( '#modifications-group' ) );
}, },
step5_UtilitiesSystemsCheckboxes: function(){
return verifyCheckboxes( document.querySelector( '#systems-group' ) );
},
/** /**
* Verify if the description field has at least one character. * Verify if the description field has at least one character.
* @returns {boolean} * @returns {boolean}
@@ -132,6 +137,10 @@ window.SubmissionVerifications = {
*/ */
step7_VerifyGame: function( element ){ step7_VerifyGame: function( element ){
const GAME_SELECTOR_MODE = document.querySelector('input[name="game_selection_mode"]')?.value ?? "game";
if( GAME_SELECTOR_MODE === 'platform' || GAME_SELECTOR_MODE === 'none' )
return true;
// Check if we have an already existent selected game. // Check if we have an already existent selected game.
const GAME_ID_INPUT = document.querySelector('input[name="game_id"]'); const GAME_ID_INPUT = document.querySelector('input[name="game_id"]');
if( GAME_ID_INPUT ){ if( GAME_ID_INPUT ){
@@ -283,12 +292,18 @@ window.Submission = function(){
return false; return false;
} }
if( SECTION() === "romhacks" ){ if( SECTION() === "romhacks" || SECTION() === "lua-scripts" ){
console.log( "Step 5" ); console.log( "Step 5" );
if( !SubmissionVerifications.step5_RomhacksModificationsCheckboxes()){ if( !SubmissionVerifications.step5_RomhacksModificationsCheckboxes()){
this.errorKey = "noModifications"; this.errorKey = "noModifications";
return false; return false;
} }
} else if( SECTION() === "utilities" ){
console.log( "Step 5" );
if( !SubmissionVerifications.step5_UtilitiesSystemsCheckboxes()){
this.errorKey = "noSystems";
return false;
}
} }
console.log( "Step 6" ); console.log( "Step 6" );
@@ -341,6 +356,7 @@ window.Submission = function(){
notAllFilesDone: 'uploadTarget', notAllFilesDone: 'uploadTarget',
uploadError: 'uploadTarget', uploadError: 'uploadTarget',
noModifications: 'modificationsGroup', noModifications: 'modificationsGroup',
noSystems: 'systemsGroup',
noDescription: 'descriptionField', noDescription: 'descriptionField',
noGame: 'gameSelector', noGame: 'gameSelector',
noLanguages: 'languagesGroup', noLanguages: 'languagesGroup',

View File

@@ -0,0 +1,29 @@
<?php /** @var \App\Models\Category $category */ ?>
<div class="languages-selector form-group level" x-data="{
search: '',
selected: @js((array) $selected),
toggle(value){
const i = this.selected.indexOf(value);
i === -1 ? this.selected.push(value) : this.selected.splice(i,1);
},
valueSelect(value){
return this.selected.includes(value);
},
get count(){ return this.selected.length; }
}">
<div class="language-search">
<i data-lucide="search"></i>
<input type="text" x-model="search" placeholder="Search a category" autocomplete="off">
<button class="btn" type="button" x-show="search !== ''" @click="search = ''" x-cloak>
<i data-lucide="x"></i>
</button>
</div>
<div class="language-list" id="languages-group">
@foreach( $categories as $category )
<label class="language-item" x-show="'{{ strtolower($category->name) }}'.includes(search.toLowerCase())">
<input type="checkbox" name="categories[]" value="{{ $category->id }}" x-model="selected" :value="{{ $category->id }}" {{ in_array($category->id, $selected) ? 'checked' : '' }}> {{ $category->name }}
</label>
@endforeach
</div>
</div>

View File

@@ -24,13 +24,26 @@
@foreach( $entry->modifications as $modif ) @foreach( $entry->modifications as $modif )
<span class="badge orange">{{ $modif->name }}</span> <span class="badge orange">{{ $modif->name }}</span>
@endforeach @endforeach
@elseif( section_must_be( 'translations', $entry->type ) )
@foreach( $entry->languages as $lang )
<span class="badge orange">{{ $lang->name }}</span>
@endforeach
@elseif( section_must_be( 'utilities', $entry->type ) )
@foreach( $entry->categories as $category )
<span class="badge orange">{{ $category->name }}</span>
@endforeach
@endif @endif
@if( $entry->status_id ) @if( $entry->status_id )
<span class="badge">{{ $entry->status->name }}</span> <span class="badge">{{ $entry->status->name }}</span>
@endif @endif
@foreach( $entry->languages as $lang ) @if( $entry->level_id )
<span class="badge">{{ $lang->name }}</span> <span class="badge">{{ $entry->level->name }}</span>
@endforeach @endif
@if( section_must_not_be( 'translations', $entry->type ) )
@foreach( $entry->languages as $lang )
<span class="badge">{{ $lang->name }}</span>
@endforeach
@endif
</div> </div>
<div class="entry-card-meta"> <div class="entry-card-meta">
<span><i data-lucide="download" size="12"></i> x</span> <span><i data-lucide="download" size="12"></i> x</span>

View File

@@ -1,4 +1,4 @@
<?php /** @var \App\Models\EntryGallery $galleryItem */ ?> <?php /** @var \App\Models\Gallery $galleryItem */ ?>
@extends('layouts.app') @extends('layouts.app')
@section('page-title', $entry->title . " - " . config('app.name') ) @section('page-title', $entry->title . " - " . config('app.name') )
@@ -54,9 +54,13 @@
</h1> </h1>
<div class="entry-authors"> <div class="entry-authors">
@forelse( $entry->authors as $author) @forelse( $entry->authors as $author)
@if($loop->first)By @endif @if($loop->first)
By
@endif
{{ $author->name }} {{ $author->name }}
@if( !$loop->last ), @endif @if( !$loop->last )
,
@endif
@empty @empty
No authors No authors
@endforelse @endforelse
@@ -65,7 +69,7 @@
@if($entry->user_id) @if($entry->user_id)
<span> <span>
<i data-lucide="user" size="14"></i> <i data-lucide="user" size="14"></i>
Posted by <x-xf-username-link :user-id="$entry->user_id" /> Posted by <x-xf-username-link :user-id="$entry->user_id"/>
</span> </span>
@endif @endif
@@ -83,43 +87,68 @@
</div> </div>
<div class="entry-meta-grid"> <div class="entry-meta-grid">
@if( $entry->game ) @if( $entry->game )
<x-entry-meta-item label="Game Name" value="{{ $entry->game->name }}" route="{!! databaseRoute( [ 'games' => [ $entry->game->id ], 'platforms' => [ $entry->getRealPlatform()?->id ] ] ) !!}" /> <x-entry-meta-item label="Game Name" value="{{ $entry->game->name }}"
route="{!! databaseRoute( [ 'games' => [ $entry->game->id ], 'platforms' => [ $entry->getRealPlatform()?->id ] ] ) !!}"/>
@endif @endif
@if( $entry->getRealPlatform() ) @if( $entry->getRealPlatform() )
<x-entry-meta-item label="Platform" value="{{ ($entry->getRealPlatform())->name }}" route="{!! databaseRoute( ['platforms' => [ $entry->getRealPlatform()->id ] ] ) !!}" /> <x-entry-meta-item label="Platform" value="{{ ($entry->getRealPlatform())->name }}"
route="{!! databaseRoute( ['platforms' => [ $entry->getRealPlatform()->id ] ] ) !!}"/>
@endif @endif
@if( $entry->game && $entry->game->genre ) @if( $entry->game && $entry->game->genre )
<x-entry-meta-item label="Genre" value="{{ $entry->game->genre->name }}" route="{!! databaseRoute( ['genres' => [ $entry->game->genre->id ] ]) !!}" /> <x-entry-meta-item label="Genre" value="{{ $entry->game->genre->name }}"
route="{!! databaseRoute( ['genres' => [ $entry->game->genre->id ] ]) !!}"/>
@endif @endif
@if( $entry->languages->isNotEmpty() ) @if( $entry->languages->isNotEmpty() )
<x-entry-meta-item label="Language" value="{{ $entry->languages->pluck('name')->implode(', ') }}" route="{!! databaseRoute( [ 'languages' => $entry->languages->pluck('id')->toArray() ]) !!}" /> <x-entry-meta-item label="Language"
value="{{ $entry->languages->pluck('name')->implode(', ') }}"
route="{!! databaseRoute( [ 'languages' => $entry->languages->pluck('id')->toArray() ]) !!}"/>
@endif @endif
@if( $entry->status_id ) @if( $entry->status_id )
<x-entry-meta-item label="Status" value="{{ $entry->status->name }}" route="{!! databaseRoute( ['statuses' => [ $entry->status->id ] ]) !!}" /> <x-entry-meta-item label="Status" value="{{ $entry->status->name }}"
route="{!! databaseRoute( ['statuses' => [ $entry->status->id ] ]) !!}"/>
@endif
@if( $entry->level_id )
<x-entry-meta-item label="Experience Level" value="{{ $entry->level->name }}"
route="{!! databaseRoute( ['levels' => [ $entry->level->id ] ]) !!}"/>
@endif @endif
@if( $entry->modifications->isNotEmpty() ) @if( $entry->modifications->isNotEmpty() )
<x-entry-meta-item label="Type of hack" value="{{ $entry->modifications->pluck('name')->implode(', ') }}" route="{!! databaseRoute( [ 'modifications' => $entry->modifications->pluck('id')->toArray() ] ) !!}" /> <x-entry-meta-item label="Type of hack"
value="{{ $entry->modifications->pluck('name')->implode(', ') }}"
route="{!! databaseRoute( [ 'modifications' => $entry->modifications->pluck('id')->toArray() ] ) !!}"/>
@endif
@if( $entry->categories->isNotEmpty() )
<x-entry-meta-item label="Categories"
value="{{ $entry->categories->pluck('name')->implode(', ') }}"
route="{!! databaseRoute( [ 'categories' => $entry->categories->pluck('id')->toArray() ] ) !!}"/>
@endif
@if( $entry->systems->isNotEmpty() )
<x-entry-meta-item label="OS" value="{{ $entry->systems->pluck('name')->implode(', ') }}"
route="{!! databaseRoute( [ 'systems' => $entry->systems->pluck('id')->toArray() ] ) !!}"/>
@endif @endif
@if( $entry->version ) @if( $entry->version )
<x-entry-meta-item label="Version" value="{{ $entry->version }}" route="none" /> <x-entry-meta-item label="Version" value="{{ $entry->version }}" route="none"/>
@endif @endif
@if( $entry->release_date ) @if( $entry->release_date )
<x-entry-meta-item label="Release Date" value="{{ $entry->release_date->format('Y-m-d') }}" route="none" /> <x-entry-meta-item label="Release Date" value="{{ $entry->release_date->format('Y-m-d') }}"
route="none"/>
@endif @endif
</div> </div>
<div class="hack-actions" style="display:flex;gap:10px;"> <div class="hack-actions" style="display:flex;gap:10px;">
@if($entry->state === 'pending') @if($entry->state === 'pending')
@can('approve', $entry) @can('approve', $entry)
<div x-data="{ rejectOpen: false }"> <div x-data="{ rejectOpen: false }">
<form action="{{ route('queue.approve', $entry) }}" method="POST" style="display:inline"> <form action="{{ route('queue.approve', $entry) }}" method="POST"
style="display:inline">
@csrf @csrf
@method('PATCH') @method('PATCH')
<button type="submit" class="btn success" onclick="return confirm('Approve this entry?')"> <button type="submit" class="btn success"
onclick="return confirm('Approve this entry?')">
<i data-lucide="check-circle" size="14"></i> <i data-lucide="check-circle" size="14"></i>
Approve Approve
</button> </button>
</form> </form>
<button type="button" class="btn danger" style="margin-right:15px;" @click="rejectOpen = !rejectOpen"> <button type="button" class="btn danger" style="margin-right:15px;"
@click="rejectOpen = !rejectOpen">
<i data-lucide="x-circle" size="14"></i> <i data-lucide="x-circle" size="14"></i>
Reject Reject
</button> </button>
@@ -145,7 +174,7 @@
@csrf @csrf
@method('PATCH') @method('PATCH')
<div class="form-group"> <div class="form-group">
<x-form-field-title name="Rejection reason" required="true" /> <x-form-field-title name="Rejection reason" required="true"/>
<textarea <textarea
class="form-input" class="form-input"
name="reason" name="reason"
@@ -171,11 +200,13 @@
</div> </div>
@endcan @endcan
@endif @endif
<button class="btn primary" onclick="Livewire.dispatch('entryOpenFilesModal', { entryId: {{ $entry->id }} })"> <button class="btn primary"
onclick="Livewire.dispatch('entryOpenFilesModal', { entryId: {{ $entry->id }} })">
<i data-lucide="download"></i> Download <i data-lucide="download"></i> Download
</button> </button>
@can('update',$entry) @can('update',$entry)
<a href="{{ route('submit.edit', ['section' => $entry->type, 'entry' => $entry ] ) }}" class="btn"> <a href="{{ route('submit.edit', ['section' => $entry->type, 'entry' => $entry ] ) }}"
class="btn">
<i data-lucide="edit"></i> Edit <i data-lucide="edit"></i> Edit
</a> </a>
@endcan @endcan
@@ -190,13 +221,13 @@
<div class="entry-content"> <div class="entry-content">
@if( $entry->description ) @if( $entry->description )
<x-entry-section-title label="Description" icon="file-text" /> <x-entry-section-title label="Description" icon="file-text"/>
<div class="entry-description"> <div class="entry-description">
{{ $entry->description }} {{ $entry->description }}
</div> </div>
@endif @endif
@if( $entry->hashes->isNotEmpty() ) @if( $entry->hashes->isNotEmpty() )
<x-entry-section-title label="Hashes" icon="table-properties" /> <x-entry-section-title label="Hashes" icon="table-properties"/>
<div class="entry-description"> <div class="entry-description">
@foreach( $entry->hashes->all() as $hash ) @foreach( $entry->hashes->all() as $hash )
Filename: {{ $hash->filename }}<br> Filename: {{ $hash->filename }}<br>
@@ -207,7 +238,7 @@
</div> </div>
@endif @endif
@if( $entry->parseStaffCredits() ) @if( $entry->parseStaffCredits() )
<x-entry-section-title label="Staff Credits" icon="users-round" /> <x-entry-section-title label="Staff Credits" icon="users-round"/>
<div class="entry-description"> <div class="entry-description">
<ul> <ul>
@foreach( $entry->parseStaffCredits() as $item ) @foreach( $entry->parseStaffCredits() as $item )
@@ -218,13 +249,16 @@
@endif @endif
@if( $entry->gallery->isNotEmpty() ) @if( $entry->gallery->isNotEmpty() )
<div x-data="{ open: false, currentImage: ''}" x-cloak> <div x-data="{ open: false, currentImage: ''}" x-cloak>
<x-entry-section-title label="Gallery" icon="images" /> <x-entry-section-title label="Gallery" icon="images"/>
<div class="entry-gallery"> <div class="entry-gallery">
@foreach( $entry->gallery as $galleryItem ) @foreach( $entry->gallery as $galleryItem )
<div class="entry-gallery-item" @click="currentImage = '{{ Storage::url($galleryItem->image) }}'; open = true; "><img src="{{ Storage::url($galleryItem->image) }}"></div> <div class="entry-gallery-item"
@click="currentImage = '{{ Storage::url($galleryItem->image) }}'; open = true; "><img
src="{{ Storage::url($galleryItem->image) }}"></div>
@endforeach @endforeach
</div> </div>
<div class="gallery-modal" x-show="open" x-transition.opacity.duration.300ms @click="open = false" @keydown.escape.window="open = false"> <div class="gallery-modal" x-show="open" x-transition.opacity.duration.300ms @click="open = false"
@keydown.escape.window="open = false">
<span class="gallery-modal-close" @click="open = false;"><i data-lucide="x"></i></span> <span class="gallery-modal-close" @click="open = false;"><i data-lucide="x"></i></span>
<div class="gallery-modal-content" @click.stop> <div class="gallery-modal-content" @click.stop>
<img :src="currentImage"> <img :src="currentImage">
@@ -233,7 +267,7 @@
</div> </div>
@endif @endif
@if( $entry->relevant_link ) @if( $entry->relevant_link )
<x-entry-section-title label="Relevant Link" icon="link" /> <x-entry-section-title label="Relevant Link" icon="link"/>
<div class="entry-description"> <div class="entry-description">
<a href="{{ $entry->relevant_link }}" target="_blank">{{ $entry->relevant_link }}</a> <a href="{{ $entry->relevant_link }}" target="_blank">{{ $entry->relevant_link }}</a>
</div> </div>
@@ -241,19 +275,24 @@
@if( $entry->getYoutubeVideoId() ) @if( $entry->getYoutubeVideoId() )
<div x-data="{open: false, src: ''}" x-cloak class="youtube-section"> <div x-data="{open: false, src: ''}" x-cloak class="youtube-section">
<x-entry-section-title label="Youtube Video" icon="play" /> <x-entry-section-title label="Youtube Video" icon="play"/>
<div class="video-thumbnail-wrapper" @click="src = 'https://www.youtube.com/embed/{{ $entry->getYoutubeVideoId() }}?autoplay=1'; open = true"> <div class="video-thumbnail-wrapper"
@click="src = 'https://www.youtube.com/embed/{{ $entry->getYoutubeVideoId() }}?autoplay=1'; open = true">
<img src="https://img.youtube.com/vi/{{ $entry->youtube_id }}/maxresdefault.jpg"> <img src="https://img.youtube.com/vi/{{ $entry->youtube_id }}/maxresdefault.jpg">
<div class="play-trigger"> <div class="play-trigger">
<i data-lucide="play"></i> <i data-lucide="play"></i>
</div> </div>
</div> </div>
<div class="gallery-modal" x-show="open" x-transition.opacity.duration.300ms @click="open = false; src = ''" @keydown.escape.window="open = false; src = ''"> <div class="gallery-modal" x-show="open" x-transition.opacity.duration.300ms
<span class="gallery-modal-close" @click="open = false; src = '';"><i data-lucide="x"></i></span> @click="open = false; src = ''" @keydown.escape.window="open = false; src = ''">
<span class="gallery-modal-close" @click="open = false; src = '';"><i
data-lucide="x"></i></span>
<div class="gallery-modal-video" @click.stop> <div class="gallery-modal-video" @click.stop>
<iframe :src="src" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> <iframe :src="src"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -52,6 +52,15 @@
{{-- Modifications --}} {{-- Modifications --}}
<x-database-filter-with-mode title="Modifications" :items="$allModifications" model="modifications" mode-model="modificationsMode" :selected-mode="$modificationsMode" /> <x-database-filter-with-mode title="Modifications" :items="$allModifications" model="modifications" mode-model="modificationsMode" :selected-mode="$modificationsMode" />
{{-- Categories --}}
<x-database-filter-with-mode title="Categories" :items="$allCategories" model="categories" mode-model="categoriesMode" :selected-mode="$categoriesMode" />
{{-- Levels --}}
<x-database-filter-without-mode title="Level" :items="$allLevels" model="levels"/>
{{-- Systems --}}
<x-database-filter-with-mode title="Systems" :items="$allSystems" model="systems" mode-model="systemsMode" :selected-mode="$systemsMode" />
</aside> </aside>
<div class="database-results"> <div class="database-results">

View File

@@ -3,59 +3,113 @@
platformId: @json(old('new-game-platform') ? (string) old('new-game-platform') : null), platformId: @json(old('new-game-platform') ? (string) old('new-game-platform') : null),
genreId: @json(old('new-game-genre') ? (string) old('new-game-genre') : null) genreId: @json(old('new-game-genre') ? (string) old('new-game-genre') : null)
})"> })">
<input type="hidden" name="game_selection_mode" value="{{ $selectionMode ?? 'game' }}">
{{-- {{--
Prefill if server-side error. Prefill if server-side error.
--}} --}}
@if( $canChangeSelection )
<div class="game-selector-mode">
<button
type="button"
class="game-selector-mode-btn {{ $selectionMode === 'game' ? 'active' : '' }}"
wire:click="setSelectionMode('game')"
>
Link to a game
</button>
<button
type="button"
class="game-selector-mode-btn {{ $selectionMode === 'platform' ? 'active' : '' }}"
wire:click="setSelectionMode('platform')"
>
Platform only
</button>
<button
type="button"
class="game-selector-mode-btn {{ $selectionMode === 'none' ? 'active' : '' }}"
wire:click="setSelectionMode('none')"
>
Nothing
</button>
</div>
@endif
<div class="form-group grid-c3"> <div class="form-group grid-c3">
@if( !$newGame && !$hasOldNewGame ) @if($selectionMode === 'none')
{{-- Search game mode --}} <div style="color: var(--text2); font-size: 0.88rem; padding: 10px 0;">
<div class="game-selector"> <i data-lucide="info" size="13"></i>
<div class="game-selector-level2"> This entry will not be linked to any game or platform.
</div>
@elseif( $selectionMode === 'platform' )
<input type="hidden" name="platform_only_id" value="{{ $platformModeId ?? '' }}">
<x-form-field-title name="Game" required="true" /> <div class="game-selector-platform-only">
<input class="form-input" type="text" wire:model.live.debounce="search" placeholder="Search a game..." autocomplete="off" <x-form-field-title name="Platform" required="true" />
@focus="$wire.dropdown = $wire.search.length >= {{ $required_chars }}" @click.outside="$wire.dropdown = false" > <select
class="form-select"
wire:change="selectPlatformOnly($event.target.value)"
>
<option value="" disabled {{ !$platformModeId ? 'selected' : '' }}>
Select a platform...
</option>
@foreach($platforms as $platform)
<option
value="{{ $platform->id }}"
{{ $platformModeId == $platform->id ? 'selected' : '' }}
>
{{ $platform->name }}
</option>
@endforeach
</select>
</div>
@else
@if( !$newGame && !$hasOldNewGame )
{{-- Search game mode --}}
<div class="game-selector">
<div class="game-selector-level2">
<input type="hidden" name="game_id" value="{{ $gameId ?? '' }}" /> <x-form-field-title name="Game" required="true" />
<input class="form-input" type="text" wire:model.live.debounce="search" placeholder="Search a game..." autocomplete="off"
@focus="$wire.dropdown = $wire.search.length >= {{ $required_chars }}" @click.outside="$wire.dropdown = false" >
<input type="hidden" name="game_id" value="{{ $gameId ?? '' }}" />
</div>
@if( $dropdown )
{{-- List games --}}
<ul class="game-selector-dropdown">
@forelse($games as $game)
<li>
<button type="button" wire:click="selectGame({{ $game->id }}, '{{ addslashes($game->name) }}')"
class="dropdown-item" {{ $gameId === $game->id ? 'selected' : '' }} >
<span class="dropdown-item-name">{{ $game->name }}</span>
@if($game->platform)
<span class="badge">{{ $game->platform->short_name }}</span>
@endif
@if($game->genre)
<span class="badge">{{ $game->genre->name }}</span>
@endif
</button>
</li>
@empty
<li class="dropdown-empty">No games found</li>
@endforelse
</ul>
@endif
</div> </div>
@if( $dropdown ) <div class="platform-prefilled">
{{-- List games --}} <x-form-field-title name="Platform" helper="Prefilled" />
<ul class="game-selector-dropdown"> <input class="form-input" disabled="disabled" type="text" autocomplete="off" value="{{ $platformName }}">
@forelse($games as $game) </div>
<li>
<button type="button" wire:click="selectGame({{ $game->id }}, '{{ addslashes($game->name) }}')"
class="dropdown-item" {{ $gameId === $game->id ? 'selected' : '' }} >
<span class="dropdown-item-name">{{ $game->name }}</span>
@if($game->platform)
<span class="badge">{{ $game->platform->short_name }}</span>
@endif
@if($game->genre)
<span class="badge">{{ $game->genre->name }}</span>
@endif
</button>
</li>
@empty
<li class="dropdown-empty">No games found</li>
@endforelse
</ul>
@endif
</div> <div class="genre-prefilled">
<x-form-field-title name="Genre" helper="Prefilled" />
<input class="form-input" disabled="disabled" type="text" autocomplete="off" value="{{ $genreName }}" >
</div>
<div class="platform-prefilled"> @else {{-- New game --}}
<x-form-field-title name="Platform" helper="Prefilled" />
<input class="form-input" disabled="disabled" type="text" autocomplete="off" value="{{ $platformName }}">
</div>
<div class="genre-prefilled">
<x-form-field-title name="Genre" helper="Prefilled" />
<input class="form-input" disabled="disabled" type="text" autocomplete="off" value="{{ $genreName }}" >
</div>
@else {{-- New game --}}
<div class="new-game-title"> <div class="new-game-title">
<x-form-field-title name="Game" required="true" /> <x-form-field-title name="Game" required="true" />
@@ -65,12 +119,12 @@
<div class="new-game-platform"> <div class="new-game-platform">
<x-form-field-title name="Platform" required="true" /> <x-form-field-title name="Platform" required="true" />
<select class="form-select" name="new-game-platform" x-model="platformId" required> <select class="form-select" name="new-game-platform" x-model="platformId" required>
<option value="" disabled>---</option> <option value="" disabled>---</option>
@foreach( $platforms as $platform ) @foreach( $platforms as $platform )
<option value="{{ (string) $platform->id }}">{{ $platform->name }}</option> <option value="{{ (string) $platform->id }}">{{ $platform->name }}</option>
@endforeach @endforeach
</select> </select>
</div> </div>
<div class="new-game-genre"> <div class="new-game-genre">
<x-form-field-title name="Genre" required="true" /> <x-form-field-title name="Genre" required="true" />
@@ -82,17 +136,19 @@
</select> </select>
</div> </div>
@endif
@endif @endif
</div> </div>
@if( $selectionMode === 'game')
<div style="display:flex;align-items: flex-end;justify-content: right;gap:15px;"> <div style="display:flex;align-items: flex-end;justify-content: right;gap:15px;">
@if($gameId) @if($gameId)
<button type="button" class="btn" wire:click="clearGame"> <button type="button" class="btn" wire:click="clearGame">
Remove Remove
</button> </button>
@endif @endif
<button type="button" class="btn primary" wire:click="switchNewGame">{{ $newGame ? "Cancel" : "Add a game" }}</button> <button type="button" class="btn primary" wire:click="switchNewGame">{{ $newGame ? "Cancel" : "Add a game" }}</button>
</div> </div>
@endif
</div> </div>

View File

@@ -47,7 +47,7 @@
</div> </div>
@endif @endif
@if( section_must_be( 'romhacks', $section ) ) @if( section_must_be( ['romhacks', 'lua-scripts'], $section ) )
<div class="form-group"> <div class="form-group">
<x-form-field-title name="{{ $words['type_of_hack'] }}" required="true" /> <x-form-field-title name="{{ $words['type_of_hack'] }}" required="true" />
<div class="form-type-of-checkboxes form-group level" id="modifications-group" x-ref="modificationsGroup"> <div class="form-type-of-checkboxes form-group level" id="modifications-group" x-ref="modificationsGroup">
@@ -57,9 +57,26 @@
</div> </div>
<div class="form-error-text" x-show="errorKey === 'noModifications'" x-text="errorMessage"></div> <div class="form-error-text" x-show="errorKey === 'noModifications'" x-text="errorMessage"></div>
</div> </div>
@elseif( section_must_be( [ 'utilities', 'documents' ], $section ) )
<div class="form-group">
<x-form-field-title name="Categories" required="true" />
<x-category-selector :section="$section" :selected="$oldCategories" />
</div>
@endif @endif
@if( section_must_be( ['romhacks', 'translations', 'homebrew'], $section ) ) @if( section_must_be( 'utilities', $section ) )
<div class="form-group">
<x-form-field-title name="{{ $words['system'] }}" required="true" />
<div class="form-type-of-checkboxes form-group level" id="systems-group" x-ref="systemsGroup">
@foreach( $systems as $system )
<label><input class="form-checkbox" type="checkbox" name="systems[]" value="{{ $system->id }}" {{ in_array($system->id, $oldSystems) ? 'checked' : '' }}>{{ $system->name }}</label>
@endforeach
</div>
<div class="form-error-text" x-show="errorKey === 'noSystems'" x-text="errorMessage"></div>
</div>
@endif
@if( section_must_be( ['romhacks', 'translations', 'homebrew', 'utilities', 'documents', 'lua-scripts'], $section ) )
<div class="form-group grid-c3"> <div class="form-group grid-c3">
<div> <div>
<x-form-field-title name="{{ $words['version'] }}" required="true" /> <x-form-field-title name="{{ $words['version'] }}" required="true" />
@@ -71,17 +88,26 @@
<input type="date" class="form-input" name="release-date" value="{{ old('release-date') ?? $entry->release_date?->format('Y-m-d') ?? '' }}" required> <input type="date" class="form-input" name="release-date" value="{{ old('release-date') ?? $entry->release_date?->format('Y-m-d') ?? '' }}" required>
</div> </div>
<div> <div>
<x-form-field-title name="{{ $words['status'] }}" required="true" /> @if( section_must_be( ['utilities', 'documents'], $section ) )
<x-form-field-title name="{{ $words['level'] }}" required="true" />
<div class="form-status-radio form-group level"> <div class="form-status-radio form-group level">
@foreach( $statuses as $status ) @foreach( $levels as $level )
<label><input class="form-radio" type="radio" name="status" value="{{ $status->id }}" {{ old('status', $entry->status_id ) == $status->id ? 'checked' : '' }} required>{{ $status->name }}</label> <label><input class="form-radio" type="radio" name="level" value="{{ $level->id }}" {{ old('level', $entry->level_id ) == $level->id ? 'checked' : '' }} required>{{ $level->name }}</label>
@endforeach @endforeach
</div> </div>
@else
<x-form-field-title name="{{ $words['status'] }}" required="true" />
<div class="form-status-radio form-group level">
@foreach( $statuses as $status )
<label><input class="form-radio" type="radio" name="status" value="{{ $status->id }}" {{ old('status', $entry->status_id ) == $status->id ? 'checked' : '' }} required>{{ $status->name }}</label>
@endforeach
</div>
@endif
</div> </div>
</div> </div>
@endif @endif
@if( section_must_be( 'translations', $section ) ) @if( section_must_be( [ 'translations', 'utilities', 'documents'] , $section ) )
<x-form-field-title name="Languages" required="true" /> <x-form-field-title name="Languages" required="true" />
<x-languages-selector :selected="$oldLanguages" /> <x-languages-selector :selected="$oldLanguages" />
@error('languages') @error('languages')
@@ -104,10 +130,12 @@
<x-form-group-title label="{{ $words['about_game'] }}" icon="gamepad-2" /> <x-form-group-title label="{{ $words['about_game'] }}" icon="gamepad-2" />
<div x-ref="gameSelector"> <div x-ref="gameSelector">
<livewire:game-selector <livewire:game-selector
:game-id="old('game_id', $entry->game_id ?? null )" :game-id="old('game_id', $entry->game_id ?? null)"
:new-game-title="old('new-game-title')" :new-game-title="old('new-game-title')"
:new-game-platform="old('new-game-platform')" :new-game-platform="old('new-game-platform')"
:new-game-genre="old('new-game-genre')" :new-game-genre="old('new-game-genre')"
:platform-only-id="old('platform_only_id', $entry->platform_id ?? null)"
:section="$section"
/> />
</div> </div>
<div class="form-error-text" x-show="errorKey === 'noGame'" x-text="errorMessage"></div> <div class="form-error-text" x-show="errorKey === 'noGame'" x-text="errorMessage"></div>
@@ -123,9 +151,11 @@
@error('new-game-genre') @error('new-game-genre')
<x-form-error-text message="{{ $message }}" /> <x-form-error-text message="{{ $message }}" />
@enderror @enderror
<livewire:hashes-upload :old-hashes="old('hashes', $entry->hashes->toArray(), [])" /> @if( section_must_be( [ 'romhacks', 'translations' ], $section ))
<livewire:hashes-upload :old-hashes="old('hashes', $entry->hashes->toArray(), [])" />
@endif
@if( section_must_not_be( 'translations', $section ) ) @if( section_must_not_be( [ 'translations', 'utilities', 'documents' ], $section ) )
<x-form-field-title name="Languages" required="true" /> <x-form-field-title name="Languages" required="true" />
<x-languages-selector :selected="$oldLanguages" /> <x-languages-selector :selected="$oldLanguages" />
@error('languages') @error('languages')
@@ -156,17 +186,21 @@
@enderror @enderror
<x-staff-credits-field :old-staff-credits="old('staff_credits', $entry->staff_credits ?? null)" /> <x-staff-credits-field :old-staff-credits="old('staff_credits', $entry->staff_credits ?? null)" />
<x-form-group-title label="{{ $words['related_links'] }}" icon="link" /> @if( section_must_not_be( 'documents', $section ) )
<div class="form-group grid-c2"> <x-form-group-title label="{{ $words['related_links'] }}" icon="link" />
<div> <div class="form-group grid-c2">
<x-form-field-title name="{{ $words['release_site'] }}" helper="{{ $words['release_site_helper'] }}" required="" /> <div>
<input class="form-input" type="url" name="release_site" value="{{ old( 'release_site', $entry->relevant_link ?? '' ) }}"> <x-form-field-title name="{{ $words['release_site'] }}" helper="{{ $words['release_site_helper'] }}" required="" />
<input class="form-input" type="url" name="release_site" value="{{ old( 'release_site', $entry->relevant_link ?? '' ) }}">
</div>
<div>
<x-form-field-title name="{{ $words['youtube_video'] }}" required="" />
<input class="form-input" type="url" name="youtube_video" value="{{ old( 'youtube_video', $entry->youtube_link ?? '' ) }}">
</div>
</div> </div>
<div> @else
<x-form-field-title name="{{ $words['youtube_video'] }}" required="" /> <div class="form-group"></div>
<input class="form-input" type="url" name="youtube_video" value="{{ old( 'youtube_video', $entry->youtube_link ?? '' ) }}"> @endif
</div>
</div>
@if($isEdit) @if($isEdit)
<x-form-group-title label="Entry Management" icon="wrench" /> <x-form-group-title label="Entry Management" icon="wrench" />

View File

@@ -14,11 +14,11 @@ Route::name('entries.')->controller(EntryController::class)->group(function () {
Route::get('/database', 'index' )->name('index'); Route::get('/database', 'index' )->name('index');
Route::get('/{section}', 'section_redirect' )->name('section_redirect') Route::get('/{section}', 'section_redirect' )->name('section_redirect')
->where(['section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts|tutorials']); ->where(['section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts']);
Route::get('/{section}/{entry:slug}', 'show' )->name('show')->where( Route::get('/{section}/{entry:slug}', 'show' )->name('show')->where(
[ [
'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts|tutorials', 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts',
'entry' => '[a-zA-Z0-9\-_]+' 'entry' => '[a-zA-Z0-9\-_]+'
] ]
); );
@@ -30,18 +30,18 @@ Route::name('entries.')->controller(EntryController::class)->group(function () {
// SubmissionController. // SubmissionController.
Route::name('submit.')->prefix('/submit')->controller(\App\Http\Controllers\SubmissionController::class)->middleware(['xf.auth', 'can:create,\App\Models\Entry'])->group(function () { Route::name('submit.')->prefix('/submit')->controller(\App\Http\Controllers\SubmissionController::class)->middleware(['xf.auth', 'can:create,\App\Models\Entry'])->group(function () {
Route::get('/{section}', 'create' )->name('create') Route::get('/{section}', 'create' )->name('create')
->where([ 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts|tutorials' ]); ->where([ 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts' ]);
Route::post('/{section}', 'store' )->name('store') Route::post('/{section}', 'store' )->name('store')
->where([ 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts|tutorials' ]); ->where([ 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts' ]);
}); });
Route::name('submit.')->prefix('/edit')->controller(\App\Http\Controllers\SubmissionController::class)->middleware(['xf.auth', 'can:update,entry'])->group(function () { Route::name('submit.')->prefix('/edit')->controller(\App\Http\Controllers\SubmissionController::class)->middleware(['xf.auth', 'can:update,entry'])->group(function () {
Route::get('/{section}/{entry:id}', 'edit' )->name('edit') Route::get('/{section}/{entry:id}', 'edit' )->name('edit')
->where([ 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts|tutorials', 'entry' => '[0-9\-]+' ]); ->where([ 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts', 'entry' => '[0-9\-]+' ]);
Route::post('/{section}/{entry:id}', 'update' )->name('update') Route::post('/{section}/{entry:id}', 'update' )->name('update')
->where([ 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts|tutorials', 'entry' => '[0-9\-]+' ]); ->where([ 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts', 'entry' => '[0-9\-]+' ]);
Route::delete('/{section}/{entry:id}', 'destroy' )->name('destroy') Route::delete('/{section}/{entry:id}', 'destroy' )->name('destroy')
->where([ 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts|tutorials', 'entry' => '[0-9\-]+' ]); ->where([ 'section' => 'translations|romhacks|homebrew|utilities|documents|lua-scripts', 'entry' => '[0-9\-]+' ]);
}); });
// QueueController // QueueController