1009 lines
36 KiB
PHP
1009 lines
36 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Exceptions\SubmissionException;
|
|
use App\Helpers\EntryHelpers;
|
|
use App\Helpers\PlayOnlineHelpers;
|
|
use App\Helpers\XenForoHelpers;
|
|
use App\Http\Requests\StoreEntryRequest;
|
|
use App\Jobs\CreateXenForoCommentsThread;
|
|
use App\Jobs\DeleteFile;
|
|
use App\Models\Author;
|
|
use App\Models\Category;
|
|
use App\Models\Entry;
|
|
use App\Models\EntryFile;
|
|
use App\Models\Gallery;
|
|
use App\Models\EntryHash;
|
|
use App\Models\Game;
|
|
use App\Models\Genre;
|
|
use App\Models\Language;
|
|
use App\Models\Modification;
|
|
use App\Models\Platform;
|
|
use App\Models\System;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
/**
|
|
* @phpstan-import-type FSFileData from \App\Types\FSTypes
|
|
*/
|
|
class SubmissionsService {
|
|
|
|
/**
|
|
* Request for store/edit.
|
|
* @var Request|null
|
|
*/
|
|
private ?Request $request = null;
|
|
|
|
/**
|
|
* Section for store/edit.
|
|
* @var string|null
|
|
*/
|
|
private ?string $section = null;
|
|
|
|
/**
|
|
* Entry for edit.
|
|
* @var Entry|null
|
|
*/
|
|
private ?Entry $entry = null;
|
|
|
|
/**
|
|
* @return list<FSFileData>
|
|
*/
|
|
public function prepareOldFiles( ?Entry $entry = null ): array
|
|
{
|
|
if( $entry === null ){
|
|
$files = old( 'files_uuid', [] );
|
|
} else {
|
|
$files = old( 'files_uuid', $entry->files->pluck('file_uuid')->toArray() );
|
|
}
|
|
|
|
if( $files === [] )
|
|
return [];
|
|
|
|
$service = app(FileServersService::class);
|
|
|
|
return array_map(
|
|
function( string $uuid ) use ($service) {
|
|
$file = EntryFile::where('file_uuid', $uuid)->first();
|
|
|
|
if( $file )
|
|
return [
|
|
'name' => $file->filename,
|
|
'totalChunks' => 0, // Already uploaded.
|
|
'rawFile' => null,
|
|
'progressValue' => 0,
|
|
'currentChunk' => 0,
|
|
'done' => true,
|
|
'error' => null,
|
|
'uuid' => $uuid,
|
|
'state' => $file->state,
|
|
'file_explorer' => $service->getArchiveExplorerUrl($file),
|
|
'file_explorer_files' => null,
|
|
'download_url' => $service->getDownloadFileUrl($file, false),
|
|
'can_be_online_patched' => EntryHelpers::enableOnlinePatcherBasedOnExtension($file['filename']),
|
|
'meta_online_patcher' => $file->online_patcher,
|
|
'meta_secondary_online_patcher' => $file->secondary_online_patcher,
|
|
'meta_play_online' => $file->playOnlineSetting()->exists() ? true : false,
|
|
'meta_play_online_core' => $file->playOnlineSetting()->exists() ? $file->playOnlineSetting->core : '',
|
|
'meta_play_online_threads' => $file->playOnlineSetting()->exists() ? $file->playOnlineSetting->threads : false,
|
|
];
|
|
|
|
$file = Cache::get("uploaded_file_{$uuid}");
|
|
if( $file )
|
|
return [
|
|
'name' => $file['filename'],
|
|
'totalChunks' => 0, // Already uploaded.
|
|
'rawFile' => null,
|
|
'progressValue' => 0,
|
|
'currentChunk' => 0,
|
|
'done' => true,
|
|
'error' => null,
|
|
'uuid' => $uuid,
|
|
'state' => $file['state'],
|
|
'file_explorer' => null,
|
|
'file_explorer_files' => null,
|
|
'download_url' => null,
|
|
'can_be_online_patched' => EntryHelpers::enableOnlinePatcherBasedOnExtension($file['filename']),
|
|
'meta_online_patcher' => false,
|
|
'meta_secondary_online_patcher' => false,
|
|
'meta_play_online' => false,
|
|
'meta_play_online_core' => null,
|
|
'meta_play_online_threads' => false
|
|
];
|
|
|
|
return null;
|
|
},
|
|
$files );
|
|
}
|
|
|
|
/**
|
|
* @param StoreEntryRequest $request
|
|
* @param string $section
|
|
*
|
|
* @return Entry
|
|
* @throws SubmissionException
|
|
* @throws \Throwable
|
|
*/
|
|
public function storeEntry( Request $request, string $section ){
|
|
|
|
// STEP 1 : Prepare basic fields.
|
|
|
|
$this->request = $request;
|
|
$this->section = $section;
|
|
$user_id = \Auth::user()->user_id;
|
|
|
|
$entry = DB::transaction(function () use ( $user_id ) {
|
|
|
|
// STEP 2 : Create game.
|
|
$gameId = $this->Step2_CreateAndReturnGameId();
|
|
|
|
// STEP 3 : Create Complete title.
|
|
$completeTitle = $this->Step3_BuildCompleteTitle( $gameId );
|
|
|
|
// STEP 4 : Generate slug and entry title.
|
|
$entrySlug = EntryHelpers::uniqueSlug( $completeTitle, Entry::class );
|
|
|
|
if( section_must_be( 'translations', $this->section ) &&
|
|
!$this->request->input('entry_title') ){
|
|
$entryTitle = Game::find($gameId)->name ?? "";
|
|
} else {
|
|
$entryTitle = $this->request->input('entry_title');
|
|
}
|
|
|
|
// STEP 5 : Removed / Delayed.
|
|
// $mainImage = $this->Step5_MoveMainImage();
|
|
|
|
// STEP 6 : Prepare entry fields and save entry.
|
|
$fields = [
|
|
'type' => $this->section,
|
|
'title' => $entryTitle,
|
|
'slug' => $entrySlug,
|
|
'description' => $this->request->input('description'),
|
|
'main_image' => $this->request->input('main-image'),
|
|
'state' => $this->request->input('submit-state'),
|
|
'game_id' => $gameId,
|
|
'platform_id' => $this->request->input('platform_only_id'),
|
|
'status_id' => $this->request->input('status'),
|
|
'version' => $this->request->input('version'),
|
|
'release_date' => $this->request->input('release-date'),
|
|
'staff_credits' => $this->request->input('staff_credits'),
|
|
'relevant_link' => $this->request->input('release_site'),
|
|
'youtube_link' => $this->request->input('youtube_video'),
|
|
'user_id' => $user_id,
|
|
'complete_title' => $completeTitle,
|
|
'level_id' => $this->request->input('level')
|
|
];
|
|
|
|
$entry = Entry::create( $fields );
|
|
|
|
// STEP 7 : Save entry fields.
|
|
$this->Step7_SaveEntryFiles( $entry );
|
|
|
|
// STEP 8 : Save hashes.
|
|
if( section_must_be( ['translations', 'romhacks' ], $this->section ) )
|
|
$this->Step8_SaveHashes( $entry->id );
|
|
|
|
// STEP 9 : Save Authors.
|
|
$this->Step9_SaveAuthors( $entry );
|
|
|
|
// STEP 10 : Save Modifications.
|
|
if( section_must_be( ['romhacks','lua-scripts'], $this->section ) ){
|
|
$this->Step10_SaveRomhacksModifications( $entry );
|
|
}
|
|
if( section_must_be( 'utilities', $this->section ) ){
|
|
$this->Step10_SaveUtilitiesSystems( $entry );
|
|
}
|
|
|
|
// STEP 11 : Save Languages
|
|
$this->Step11_SaveLanguages( $entry );
|
|
|
|
// STEP 11.5 : Save Categories
|
|
if( section_must_be( ['utilities', 'documents'], $this->section ) ) {
|
|
$this->Step11_5_SaveCategories($entry);
|
|
}
|
|
|
|
// STEP 12 : Prepare Gallery images.
|
|
$this->Step12a_PrepareGalleryImages( $entry );
|
|
|
|
return $entry;
|
|
|
|
});
|
|
|
|
// Step 12, Move main image and gallery.
|
|
$this->Step12b_MoveMainImage( $entry );
|
|
$this->Step12c_SaveGalleryImages( $entry );
|
|
|
|
// Step 13: Try to create the comments section.
|
|
$this->Step13_CreateCommentsThread( $entry );
|
|
|
|
// Step 14: Refresh XF count.
|
|
if( $entry->state !== 'draft')
|
|
XenForoHelpers::updateEntriesCount( $entry->user_id );
|
|
|
|
return $entry;
|
|
|
|
}
|
|
|
|
/**
|
|
* @return null|int
|
|
*
|
|
* @throws SubmissionException
|
|
*/
|
|
private function Step2_CreateAndReturnGameId(): ?int {
|
|
|
|
$mode = $this->request->input('game_selection_mode', 'game');
|
|
if( $mode !== 'game' )
|
|
return null;
|
|
|
|
// Already existing game.
|
|
if( $this->request->input('game_id') )
|
|
return $this->request->input('game_id');
|
|
|
|
// No fields like a draft.
|
|
if( !$this->request->input('new-game-title') &&
|
|
!$this->request->input('new-game-platform') &&
|
|
!$this->request->input('new-game-genre') )
|
|
return null;
|
|
|
|
// Need to create a game.
|
|
$game = $this->createGameFromFormFields();
|
|
|
|
return $game->id;
|
|
}
|
|
|
|
private function createGameFromFormFields(): Game
|
|
{
|
|
if( !$this->request->input('new-game-title') || !$this->request->input('new-game-platform') || !$this->request->input('new-game-genre') )
|
|
throw new SubmissionException( "New game informations is missing" );
|
|
|
|
$platform = Platform::find( $this->request->input('new-game-platform') );
|
|
$genre = Genre::find( $this->request->input('new-game-genre') );
|
|
|
|
if( !$platform || !$genre )
|
|
throw new SubmissionException( "Incorrect game platform id" );
|
|
|
|
$gameSlug = EntryHelpers::uniqueSlug( $this->request->input('new-game-title'), Game::class );
|
|
|
|
return Game::create([
|
|
'name' => trim( $this->request->input('new-game-title') ),
|
|
'slug' => $gameSlug,
|
|
'platform_id' => $platform->id,
|
|
'genre_id' => $genre->id,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Prepare and build complete title.
|
|
*
|
|
* @param int|null $gameId
|
|
*
|
|
* @return string
|
|
*/
|
|
private function Step3_BuildCompleteTitle( ?int $gameId = null ): string {
|
|
$fields = [];
|
|
|
|
$fields['entry_title'] = $this->request->input('entry_title') ?? null;
|
|
if( section_must_be( [ 'homebrew', 'translations' ], $this->section ) && $gameId ){
|
|
$fields['game_name'] = $gameId ? Game::find( $gameId )->name : null;
|
|
}
|
|
if( section_must_be( 'translations', $this->section ) ) {
|
|
$fields['languages_string'] = Language::whereIn('id', $this->request->input('languages', []))->pluck('name')->implode(', ');
|
|
}
|
|
if( section_must_be(['romhacks', 'translations', 'homebrew', 'lua-scripts'], $this->section ) ) {
|
|
// TODO: Add single platform ID compatibility.
|
|
$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 );
|
|
}
|
|
|
|
/**
|
|
* @param int $entryId
|
|
*
|
|
* @return void
|
|
* @throws SubmissionException
|
|
*/
|
|
private function Step7_SaveEntryFiles( Entry $entry, ?array $uuidData = null ): void
|
|
{
|
|
if( !$uuidData )
|
|
$uuidData = $this->request->input('files_uuid', [] );
|
|
|
|
$metadataArray = $this->request->input('files_metadata', []);
|
|
|
|
foreach ( $uuidData ?? [] as $uuid ) {
|
|
$fileData = Cache::pull("uploaded_file_{$uuid}");
|
|
if( !$fileData )
|
|
throw new SubmissionException( "File {$uuid} has expired. Please delete all your files and retry. If it's an edition, delete all the new files and retry." );
|
|
|
|
if( section_must_be( [ 'romhacks', 'translations' ], $entry->type ) ) {
|
|
$onlinePatcher = (bool)($metadataArray[$uuid]['online_patcher'] ?? false);
|
|
if (!$onlinePatcher)
|
|
$onlinePatcher = EntryHelpers::enableOnlinePatcherBasedOnExtension($fileData['filename']);
|
|
|
|
$secondaryOnlinePatcher = (bool)($metadataArray[$uuid]['secondary_online_patcher'] ?? false);
|
|
} else {
|
|
$onlinePatcher = false;
|
|
$secondaryOnlinePatcher = false;
|
|
}
|
|
|
|
$file = EntryFile::create([
|
|
'entry_id' => $entry->id,
|
|
'file_uuid' => $uuid,
|
|
'filename' => $fileData['filename'],
|
|
'filepath' => $fileData['filepath'],
|
|
'favorite_server' => $fileData['favorite_server'],
|
|
'favorite_at' => \DateTimeImmutable::createFromTimestamp( $fileData['favorite_at'] ),
|
|
'filesize' => $fileData['filesize'],
|
|
'state' => 'public',
|
|
'online_patcher' => $onlinePatcher,
|
|
'secondary_online_patcher' => $secondaryOnlinePatcher,
|
|
]);
|
|
|
|
if( section_must_be( ['romhacks', 'translations', 'homebrew'], $entry->type ) ) {
|
|
$playOnline = (bool)($metadataArray[$uuid]['play_online'] ?? false);
|
|
$playOnlineCore = $metadataArray[$uuid]['play_online_core'] ?? null;
|
|
$playOnlineThreads = (bool)($metadataArray[$uuid]['play_online_threads'] ?? false);
|
|
|
|
if (!$playOnline && $entry->getRealPlatform()?->play_online_core !== null) {
|
|
$playOnline = true;
|
|
$playOnlineCore = $entry->getRealPlatform()?->play_online_core;
|
|
}
|
|
|
|
if ($playOnline) {
|
|
$file->playOnlineSetting()->updateOrCreate(
|
|
['file_id' => $file->id],
|
|
[
|
|
'core' => $playOnlineCore,
|
|
'threads' => $playOnlineThreads,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param int $entryId
|
|
*
|
|
* @return void
|
|
*/
|
|
private function Step8_SaveHashes( int $entryId ): void
|
|
{
|
|
foreach ( $this->request->input('hashes', [] ) ?? [] as $hash ) {
|
|
if( !isset($hash['filename'], $hash['hash_crc32'], $hash['hash_sha1'], $hash['verified']) ) {
|
|
continue;
|
|
}
|
|
|
|
EntryHash::create([
|
|
'entry_id' => $entryId,
|
|
'filename' => $hash['filename'],
|
|
'hash_crc32' => $hash['hash_crc32'],
|
|
'hash_sha1' => $hash['hash_sha1'],
|
|
'verified' => $hash['verified'],
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param Entry $entry
|
|
*
|
|
* @return void
|
|
* @throws SubmissionException
|
|
*/
|
|
private function Step9_SaveAuthors( Entry $entry ): void
|
|
{
|
|
// TODO: Code fragment to be replaced by edit version.
|
|
|
|
// Existing authors.
|
|
foreach ( $this->request->input('authors', [] ) ?? [] as $authorId ) {
|
|
$author = Author::find( $authorId );
|
|
if( !$author )
|
|
throw new SubmissionException( "Author {$authorId} does not exist." );
|
|
$entry->authors()->attach( $author->id );
|
|
}
|
|
|
|
// New Authors
|
|
foreach ( $this->request->input('new-authors', [] ) ?? [] as $authorName ) {
|
|
$authorName = trim( $authorName );
|
|
if( $authorName === '' )
|
|
continue;
|
|
|
|
$author = Author::firstOrCreate(
|
|
['slug' => EntryHelpers::uniqueSlug( $authorName, Author::class )],
|
|
['name' => $authorName]
|
|
);
|
|
$entry->authors()->attach( $author->id );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param Entry $entry
|
|
*
|
|
* @return void
|
|
* @throws SubmissionException
|
|
*/
|
|
private function Step10_SaveRomhacksModifications( Entry $entry ): void
|
|
{
|
|
// TODO: Replace by edit version
|
|
|
|
foreach ( $this->request->input('modifications', [] ) ?? [] as $modificationId ) {
|
|
$modification = Modification::find( $modificationId );
|
|
if( !$modification )
|
|
throw new SubmissionException( "Modification {$modificationId} does not exist." );
|
|
$entry->modifications()->attach( $modification->id );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*
|
|
* @return void
|
|
* @throws SubmissionException
|
|
*/
|
|
private function Step11_SaveLanguages( Entry $entry ): void
|
|
{
|
|
// TODO: Replace by edit version.
|
|
|
|
foreach ( $this->request->input('languages', [] ) ?? [] as $languageId ) {
|
|
$language = Language::find( $languageId );
|
|
if( !$language )
|
|
throw new SubmissionException( "Language {$languageId} does not exist." );
|
|
$entry->languages()->attach( $language->id );
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
{
|
|
foreach ( $this->request->input('gallery', [] ) ?? [] as $i => $imagePath ) {
|
|
$entry->gallery()->create([
|
|
'image' => $imagePath,
|
|
'order' => $i
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param Entry $entry
|
|
*
|
|
* @return void
|
|
*/
|
|
private function Step12b_MoveMainImage( Entry $entry ): void {
|
|
$mainImage = $entry->main_image;
|
|
|
|
if( !$mainImage )
|
|
return;
|
|
|
|
$newPath = 'entries/main-images/' . basename($mainImage);
|
|
|
|
if( !Storage::disk('public')->move($mainImage, $newPath) )
|
|
return;
|
|
|
|
$entry->update(['main_image' => $newPath]);
|
|
}
|
|
|
|
private function Step12c_SaveGalleryImages( Entry $entry ): void
|
|
{
|
|
foreach ( $entry->gallery ?? [] as $galleryItem ) {
|
|
$newPath = 'entries/gallery-images/' . $entry->id . '/' . basename($galleryItem->image);
|
|
|
|
if( !Storage::disk('public')->move($galleryItem->image, $newPath) )
|
|
continue;
|
|
|
|
$galleryItem->update(['image' => $newPath]);
|
|
}
|
|
}
|
|
|
|
public function editEntry(Request $request, string $section, Entry $entry ): Entry
|
|
{
|
|
|
|
// STEP 1: Prepare basic fields and keep in save some others fields.
|
|
$this->request = $request;
|
|
$this->section = $section;
|
|
$this->entry = $entry;
|
|
|
|
if( \Auth::user()->can('moderate', $entry) ){
|
|
$user_id = $this->request->input('owner_user_id');
|
|
$oldUserId = $this->entry->user_id;
|
|
} else {
|
|
$user_id = \Auth::user()->user_id;
|
|
$oldUserId = null;
|
|
}
|
|
|
|
$oldMainImage = $entry->main_image;
|
|
$galleryPaths = [];
|
|
|
|
$entry = DB::transaction( function() use ( $user_id, &$galleryPaths ){
|
|
|
|
// STEP 2: Create game if different.
|
|
$gameId = null;
|
|
$gameId = $this->eStep2_VerifyCreateAndEditGameId();
|
|
|
|
// STEP 3: Recreate complete title and refresh slug if needed.
|
|
$completeTitle = $this->Step3_BuildCompleteTitle( $gameId );
|
|
if( $completeTitle !== $this->entry->complete_title ) {
|
|
$this->entry->complete_title = $completeTitle;
|
|
$this->entry->slug = EntryHelpers::uniqueSlug( $completeTitle, Entry::class, $this->entry->id );
|
|
}
|
|
|
|
// STEP 4: Regenerate entry title.
|
|
|
|
if( section_must_be( 'translations', $this->section ) &&
|
|
!$this->request->input('entry_title') ){
|
|
$this->entry->title = Game::find($gameId)->name;
|
|
} else {
|
|
$this->entry->title = $this->request->input('entry_title');
|
|
}
|
|
|
|
// STEP 5: Update entry fields.
|
|
|
|
$fields = [
|
|
'type' => $this->section,
|
|
'title' => $this->entry->title, // Useless, I know.
|
|
'slug' => $this->entry->slug,
|
|
'description' => $this->request->input('description'),
|
|
'main_image' => $this->request->input('main-image'),
|
|
'state' => $this->request->input('submit-state'),
|
|
'game_id' => $gameId,
|
|
'platform_id' => $this->request->input('platform_only_id'),
|
|
'status_id' => $this->request->input('status'),
|
|
'version' => $this->request->input('version'),
|
|
'release_date' => $this->request->input('release-date'),
|
|
'staff_credits' => $this->request->input('staff_credits'),
|
|
'relevant_link' => $this->request->input('release_site'),
|
|
'youtube_link' => $this->request->input('youtube_video'),
|
|
'user_id' => $user_id,
|
|
'complete_title' => $completeTitle,
|
|
'level_id' => $this->request->input('level'),
|
|
];
|
|
|
|
if( \Auth::user()->can('moderate', $this->entry) ){
|
|
$fields['staff_comment'] = $this->request->input('staff_comment');
|
|
$fields['featured'] = $this->request->input('featured') ?? false;
|
|
if( $fields['featured'] == true && $this->entry->featured_at === null )
|
|
$fields['featured_at'] = now();
|
|
if( $fields['featured'] == false )
|
|
$fields['featured_at'] = null;
|
|
$fields['comments_thread_id'] = $this->request->input('comments_thread_id');
|
|
$refresh_created_at = $this->request->input('refresh_created_at') ?? false;
|
|
if( $refresh_created_at )
|
|
$fields['created_at'] = now();
|
|
}
|
|
|
|
$this->entry->update( $fields );
|
|
|
|
// STEP 6: Update entry files.
|
|
$this->eStep6_UpdateEntryFiles( $this->entry->id );
|
|
|
|
// STEP 7: Update hashes.
|
|
if( section_must_be( ['translations', 'romhacks' ], $this->section ) )
|
|
$this->eStep7_UpdateHashes( $this->entry->id );
|
|
|
|
// STEP 8: Update Authors.
|
|
$this->eStep8_UpdateAuthors();
|
|
|
|
// STEP 9: Update romhacks modifications.
|
|
if( section_must_be( ['romhacks', 'lua-scripts'], $this->section ) ) {
|
|
$this->eStep9_UpdateRomhacksModifications();
|
|
}
|
|
if( section_must_be( 'utilities', $this->section ) ) {
|
|
$this->eStep9_UpdateUtilitiesSystems();
|
|
}
|
|
|
|
// STEP 10: Update Languages.
|
|
$this->eStep10_UpdateLanguages();
|
|
|
|
// STEP 10.5 : Update categories
|
|
if( section_must_be( ['utilities', 'documents'], $this->section ) )
|
|
$this->eStep10_5_UpdateCategories();
|
|
|
|
// STEP 11: Prepare new gallery images and prepare deletion of others ones.
|
|
$galleryPaths = $this->eStep11a_UpdateGalleryImages();
|
|
|
|
return $this->entry;
|
|
|
|
});
|
|
|
|
// STEP 11 : Update main image if needed.
|
|
$this->eStep11b_UpdateMainImage( $oldMainImage );
|
|
|
|
// STEP 11 : Update gallery storage.
|
|
$this->eStep11c_UpdateGalleryImages( $galleryPaths );
|
|
|
|
// STEP 12: Refresh XF count.
|
|
if( $entry->state !== 'draft' ) {
|
|
if ($oldUserId)
|
|
XenForoHelpers::updateEntriesCount($oldUserId);
|
|
XenForoHelpers::updateEntriesCount($entry->user_id);
|
|
}
|
|
|
|
// STEP 13: Try to create comments area if it doesn't exist.
|
|
$this->Step13_CreateCommentsThread( $this->entry );
|
|
|
|
return $entry;
|
|
}
|
|
|
|
/**
|
|
* @throws SubmissionException
|
|
*/
|
|
private function eStep2_VerifyCreateAndEditGameId(): ?int
|
|
{
|
|
|
|
$mode = $this->request->input('game_selection_mode', 'game');
|
|
if ($mode !== 'game') {
|
|
return null;
|
|
}
|
|
|
|
// Already existing game.
|
|
if( $this->request->input('game_id') ){
|
|
|
|
if( $this->entry->game_id == $this->request->input('game_id') ){
|
|
|
|
return $this->entry->game_id; // No changes.
|
|
|
|
} else { // Change in game but already exist.
|
|
|
|
$game = Game::find( $this->request->input('game_id') );
|
|
if( !$game )
|
|
throw new SubmissionException( "Game {$this->request->input('game_id')} does not exist." );
|
|
$this->entry->game_id = $game->id;
|
|
return $this->entry->game_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// In draft.
|
|
if( !$this->request->input('new-game-title') &&
|
|
!$this->request->input('new-game-platform') &&
|
|
!$this->request->input('new-game-genre') )
|
|
return $this->entry->game_id;
|
|
|
|
// Need to create a game.
|
|
$game = $this->createGameFromFormFields();
|
|
|
|
$this->entry->game_id = $game->id;
|
|
return $this->entry->game_id;
|
|
}
|
|
|
|
/**
|
|
* @throws SubmissionException
|
|
*/
|
|
private function eStep6_UpdateEntryFiles(int $entryId ): void
|
|
{
|
|
$requestUuids = $this->request->input('files_uuid', []) ?? [];
|
|
$requestStates = $this->request->input('files_state', []) ?? [];
|
|
$existingUuids = EntryFile::where( 'entry_id', $entryId )->pluck('file_uuid')->toArray();
|
|
|
|
$needDeletion = array_diff( $existingUuids, $requestUuids );
|
|
if( !empty( $needDeletion ) ){
|
|
$userId = \Auth::user()->user_id;
|
|
EntryFile::where('entry_id', $entryId)->whereIn('file_uuid', $needDeletion)->whereNot('state', 'archived')->get()->each( function ( $f ) use ( $userId ) {
|
|
DeleteFile::dispatch( $f->filepath, $f->filename, $userId);
|
|
});
|
|
EntryFile::where('entry_id', $entryId)->whereIn('file_uuid', $needDeletion)->whereNot('state', 'archived')->delete();
|
|
}
|
|
|
|
$needAddition = array_diff( $requestUuids, $existingUuids );
|
|
|
|
if( !empty( $needAddition ) ){
|
|
$this->Step7_SaveEntryFiles( $this->entry, $needAddition ); // Same code.
|
|
}
|
|
|
|
$metadataArray = $this->request->input('files_metadata', []);
|
|
$stateMap = array_combine( $requestUuids, $requestStates );
|
|
|
|
foreach( $stateMap as $uuid => $state ){
|
|
|
|
if( section_must_be( ['romhacks', 'translations'], $this->entry->type ) ) {
|
|
$onlinePatcher = (bool)($metadataArray[$uuid]['online_patcher'] ?? false);
|
|
$secondaryOnlinePatcher = (bool)($metadataArray[$uuid]['secondary_online_patcher'] ?? false);
|
|
} else {
|
|
$onlinePatcher = false;
|
|
$secondaryOnlinePatcher = false;
|
|
}
|
|
|
|
$entryFile = EntryFile::where('file_uuid', $uuid)->where('entry_id', $entryId)->where('state', '!=', 'archived')->first();
|
|
if( !$entryFile )
|
|
continue;
|
|
|
|
$entryFile->update([
|
|
'state' => $state,
|
|
'online_patcher' => $onlinePatcher,
|
|
'secondary_online_patcher' => $secondaryOnlinePatcher,
|
|
]);
|
|
|
|
if( section_must_be( ['romhacks', 'translations', 'homebrew'], $this->entry->type ) ) {
|
|
|
|
$playOnline = (bool)($metadataArray[$uuid]['play_online'] ?? false);
|
|
$playOnlineCore = $metadataArray[$uuid]['play_online_core'] ?? null;
|
|
$playOnlineThreads = (bool)($metadataArray[$uuid]['play_online_threads'] ?? false);
|
|
|
|
if ($playOnline) {
|
|
if ($playOnlineCore === null || !in_array($playOnlineCore, PlayOnlineHelpers::getCoreLists()))
|
|
$playOnlineCore = $this->entry->getRealPlatform()->play_online_core ? $this->entry->getRealPlatform()->play_online_core : 'nes';
|
|
|
|
$entryFile->playOnlineSetting()->updateOrCreate(
|
|
['file_id' => $entryFile->id],
|
|
[
|
|
'core' => $playOnlineCore,
|
|
'threads' => $playOnlineThreads,
|
|
]
|
|
);
|
|
} else {
|
|
$entryFile->playOnlineSetting()->delete();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private function eStep7_UpdateHashes(int $entryId): void
|
|
{
|
|
$requestHashes = collect( $this->request->input('hashes', [] ) )
|
|
->filter( fn($h) => isset( $h['filename'], $h['hash_crc32'], $h['hash_sha1'], $h['verified'] ) )
|
|
->keyBy( 'hash_sha1' )
|
|
->toArray();
|
|
;
|
|
|
|
$existingHashes = EntryHash::where( 'entry_id', $entryId )->get()->keyBy( 'hash_sha1' );
|
|
|
|
$hashsToDelete = array_diff( $existingHashes->keys()->toArray(), array_keys( $requestHashes ) );
|
|
|
|
if( !empty( $hashsToDelete ) ){
|
|
EntryHash::where( 'entry_id', $entryId )->whereIn('hash_sha1', $hashsToDelete)->delete();
|
|
}
|
|
|
|
foreach( $requestHashes as $sha1 => $hash ){
|
|
if( $existingHashes->has( $sha1 ) ){
|
|
$existingHashes->get( $sha1 )->update([
|
|
'filename' => $hash['filename'],
|
|
'hash_crc32' => $hash['hash_crc32'],
|
|
'hash_sha1' => $hash['hash_sha1'],
|
|
'verified' => $hash['verified'],
|
|
]);
|
|
} else {
|
|
EntryHash::create([
|
|
'entry_id' => $entryId,
|
|
'filename' => $hash['filename'],
|
|
'hash_crc32' => $hash['hash_crc32'],
|
|
'hash_sha1' => $hash['hash_sha1'],
|
|
'verified' => $hash['verified'],
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
* @throws SubmissionException
|
|
*/
|
|
private function eStep8_UpdateAuthors(): void
|
|
{
|
|
$syncAuthorsId = [];
|
|
$requestAuthorsId = $this->request->input('authors', [] ) ?? [];
|
|
|
|
if( !empty( $requestAuthorsId ) ){
|
|
$valid = Author::whereIn( 'id', $requestAuthorsId )->pluck('id')->toArray();
|
|
|
|
if( count( $valid ) !== count( $requestAuthorsId ) ){
|
|
throw new SubmissionException( "One of the authors doesn't exist." );
|
|
}
|
|
|
|
$syncAuthorsId = array_merge( $syncAuthorsId, $requestAuthorsId );
|
|
}
|
|
|
|
foreach ( $this->request->input('new-authors', [] ) ?? [] as $authorName ) {
|
|
$authorName = trim($authorName);
|
|
if ($authorName === '')
|
|
continue;
|
|
|
|
$author = Author::firstOrCreate(
|
|
['slug' => EntryHelpers::uniqueSlug($authorName, Author::class)],
|
|
['name' => $authorName]
|
|
);
|
|
|
|
$syncAuthorsId[] = $author->id;
|
|
}
|
|
|
|
$this->entry->authors()->sync( $syncAuthorsId );
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
* @throws SubmissionException
|
|
*/
|
|
private function eStep9_UpdateRomhacksModifications(): void
|
|
{
|
|
$requestModifications = $this->request->input('modifications', [] ) ?? [];
|
|
if( !empty( $requestModifications ) ){
|
|
$valid = Modification::whereIn( 'id', $requestModifications )->pluck('id')->toArray();
|
|
|
|
if( count( $valid ) !== count( $requestModifications ) ){
|
|
throw new SubmissionException( "One of the modifications doesn't exist." );
|
|
}
|
|
|
|
|
|
}
|
|
|
|
$this->entry->modifications()->sync( $requestModifications );
|
|
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
* @throws SubmissionException
|
|
*/
|
|
private function eStep10_UpdateLanguages(): void
|
|
{
|
|
$requestLanguages = $this->request->input('languages', [] ) ?? [];
|
|
if( !empty( $requestLanguages ) ){
|
|
$valid = Language::whereIn( 'id', $requestLanguages )->pluck('id')->toArray();
|
|
if( count( $valid ) !== count( $requestLanguages ) ){
|
|
throw new SubmissionException( "One of the languages doesn't exist." );
|
|
}
|
|
|
|
}
|
|
|
|
$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
|
|
{
|
|
$requestGallery = $this->request->input('gallery', [] ) ?? [];
|
|
$existingGalleryPaths = $this->entry->gallery->pluck('image')->toArray();
|
|
|
|
$needDeletion = array_diff( $existingGalleryPaths, $requestGallery );
|
|
|
|
if( !empty( $needDeletion ) ){
|
|
$this->entry->gallery()->whereIn('image', $needDeletion )->delete();
|
|
}
|
|
|
|
$needAddition = array_diff( $requestGallery, $existingGalleryPaths );
|
|
$images = [];
|
|
foreach( $needAddition as $imagePath ){
|
|
$images[] = $this->entry->gallery()->create([
|
|
'image' => $imagePath,
|
|
]);
|
|
}
|
|
|
|
foreach ( $requestGallery as $i => $imagePath ){
|
|
$this->entry->gallery()->where('image', $imagePath )->update(['order' => $i]);
|
|
}
|
|
|
|
return [ 'addition' => $images, 'deletion' => $needDeletion ];
|
|
}
|
|
|
|
private function eStep11b_UpdateMainImage( ?string $oldMainImagePath ): void
|
|
{
|
|
$currentMainImagePath = $this->entry->main_image;
|
|
|
|
if( $currentMainImagePath === $oldMainImagePath )
|
|
return;
|
|
|
|
if( !$currentMainImagePath ) {
|
|
if( $oldMainImagePath && Storage::disk('public')->exists($oldMainImagePath) )
|
|
Storage::disk('public')->delete($oldMainImagePath);
|
|
return;
|
|
}
|
|
|
|
$newPath = 'entries/main-images/' . basename( $currentMainImagePath );
|
|
|
|
if( !Storage::disk('public')->move( $currentMainImagePath, $newPath ) ){
|
|
$this->entry->update(['main_image' => $oldMainImagePath]);
|
|
return;
|
|
}
|
|
|
|
$this->entry->update(['main_image' => $newPath]);
|
|
if( $oldMainImagePath && Storage::disk('public')->exists($oldMainImagePath) )
|
|
Storage::disk('public')->delete($oldMainImagePath);
|
|
}
|
|
|
|
private function eStep11c_UpdateGalleryImages( array $pathsChanges ): void
|
|
{
|
|
foreach ( $pathsChanges['deletion'] as $deletePath ){
|
|
if( Storage::disk('public')->exists($deletePath) )
|
|
Storage::disk('public')->delete($deletePath);
|
|
}
|
|
|
|
foreach ( $pathsChanges['addition'] as $galleryItem ){
|
|
$newPath = 'entries/gallery-images/' . $this->entry->id . '/' . basename( $galleryItem->image );
|
|
|
|
if( !Storage::disk('public')->move( $galleryItem->image, $newPath ) ){
|
|
continue;
|
|
}
|
|
|
|
$galleryItem->update(['image' => $newPath]);
|
|
}
|
|
}
|
|
|
|
private function Step13_CreateCommentsThread( Entry $entry ): void
|
|
{
|
|
if( $entry->state !== 'published' )
|
|
return;
|
|
|
|
if( !$entry->comments_thread_id )
|
|
CreateXenForoCommentsThread::dispatch( $entry );
|
|
// app(XenforoApiService::class)->createCommentsThread( $entry );
|
|
}
|
|
|
|
}
|