Upload beautify
This commit is contained in:
140
app/Uploads/Services/PublishService.php
Normal file
140
app/Uploads/Services/PublishService.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Uploads\Services;
|
||||
|
||||
use App\Models\Upload;
|
||||
use App\Models\User;
|
||||
use App\Uploads\Exceptions\UploadNotFoundException;
|
||||
use App\Uploads\Exceptions\UploadOwnershipException;
|
||||
use App\Uploads\Exceptions\UploadPublishValidationException;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use RuntimeException;
|
||||
|
||||
final class PublishService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly FileMoveService $fileMoveService,
|
||||
private readonly SlugService $slugService,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public function publish(string $uploadId, User $user): Upload
|
||||
{
|
||||
$upload = Upload::query()->find($uploadId);
|
||||
if (! $upload) {
|
||||
throw new UploadNotFoundException('Upload not found.');
|
||||
}
|
||||
|
||||
$this->validateBeforePublish($upload, $user);
|
||||
|
||||
$mainFile = DB::table('upload_files')
|
||||
->where('upload_id', $uploadId)
|
||||
->where('type', 'main')
|
||||
->orderBy('id')
|
||||
->first(['path', 'hash']);
|
||||
|
||||
if (! $mainFile || empty($mainFile->hash)) {
|
||||
throw new UploadPublishValidationException('Main file hash is missing.');
|
||||
}
|
||||
|
||||
$hash = strtolower((string) preg_replace('/[^a-z0-9]/', '', (string) $mainFile->hash));
|
||||
if ($hash === '' || strlen($hash) < 4) {
|
||||
throw new UploadPublishValidationException('Invalid main file hash.');
|
||||
}
|
||||
|
||||
$aa = substr($hash, 0, 2);
|
||||
$bb = substr($hash, 2, 2);
|
||||
$targetDir = "files/artworks/{$aa}/{$bb}/{$hash}";
|
||||
|
||||
$tempPrefix = 'tmp/drafts/' . $uploadId . '/';
|
||||
$promoted = false;
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
$this->fileMoveService->promoteDraft($uploadId, $targetDir);
|
||||
$promoted = true;
|
||||
|
||||
$files = DB::table('upload_files')->where('upload_id', $uploadId)->get(['id', 'path']);
|
||||
foreach ($files as $file) {
|
||||
$oldPath = (string) $file->path;
|
||||
if (str_starts_with($oldPath, $tempPrefix)) {
|
||||
$newPath = $targetDir . '/' . ltrim(substr($oldPath, strlen($tempPrefix)), '/');
|
||||
DB::table('upload_files')->where('id', $file->id)->update(['path' => $newPath]);
|
||||
}
|
||||
}
|
||||
|
||||
$upload->status = 'published';
|
||||
$upload->processing_state = 'published';
|
||||
if (empty($upload->slug)) {
|
||||
$upload->slug = $this->slugService->makeSlug((string) ($upload->title ?? ''));
|
||||
}
|
||||
$upload->published_at = now();
|
||||
$upload->final_path = $targetDir;
|
||||
$upload->save();
|
||||
|
||||
DB::commit();
|
||||
} catch (\Throwable $e) {
|
||||
DB::rollBack();
|
||||
|
||||
if ($promoted) {
|
||||
Storage::disk('local')->deleteDirectory($targetDir);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
Storage::disk('local')->deleteDirectory('tmp/drafts/' . $uploadId);
|
||||
|
||||
return Upload::query()->findOrFail($uploadId);
|
||||
}
|
||||
|
||||
private function validateBeforePublish(Upload $upload, User $user): void
|
||||
{
|
||||
if ((int) $upload->user_id !== (int) $user->id) {
|
||||
throw new UploadOwnershipException('You do not own this upload.');
|
||||
}
|
||||
|
||||
$role = strtolower((string) ($user->role ?? ''));
|
||||
$isAdmin = $role === 'admin';
|
||||
|
||||
if (! $isAdmin && (string) ($upload->moderation_status ?? 'pending') !== 'approved') {
|
||||
throw new UploadPublishValidationException('Upload requires moderation approval before publish.');
|
||||
}
|
||||
|
||||
if ((string) $upload->status !== 'draft') {
|
||||
throw new UploadPublishValidationException('Only draft uploads can be published.');
|
||||
}
|
||||
|
||||
if (! (bool) $upload->is_scanned) {
|
||||
throw new UploadPublishValidationException('Upload must be scanned before publish.');
|
||||
}
|
||||
|
||||
if (empty($upload->preview_path)) {
|
||||
throw new UploadPublishValidationException('Preview is required before publish.');
|
||||
}
|
||||
|
||||
if (! (bool) $upload->has_tags) {
|
||||
throw new UploadPublishValidationException('Tag analysis must complete before publish.');
|
||||
}
|
||||
|
||||
if (empty($upload->title) || empty($upload->category_id)) {
|
||||
throw new UploadPublishValidationException('Title and category are required before publish.');
|
||||
}
|
||||
|
||||
if ((string) $upload->type === 'archive') {
|
||||
$hasScreenshot = DB::table('upload_files')
|
||||
->where('upload_id', (string) $upload->id)
|
||||
->where('type', 'screenshot')
|
||||
->exists();
|
||||
|
||||
if (! $hasScreenshot) {
|
||||
throw new UploadPublishValidationException('Archive uploads require at least one screenshot.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user