From 2b5f4f55a2d432c9fcac53aa6fccd16b24ff0593 Mon Sep 17 00:00:00 2001 From: Alex Cabal Date: Thu, 18 Jan 2024 10:50:14 -0600 Subject: [PATCH] Style tweaks to artworks DB --- lib/Artist.php | 15 ----- lib/Artwork.php | 64 ++++++++++--------- .../InvalidImageUploadException.php | 8 ++- lib/Library.php | 4 +- www/artworks/post.php | 26 ++++---- 5 files changed, 54 insertions(+), 63 deletions(-) diff --git a/lib/Artist.php b/lib/Artist.php index 7ced9854..4c18a478 100644 --- a/lib/Artist.php +++ b/lib/Artist.php @@ -147,19 +147,4 @@ class Artist extends PropertiesBase{ where ArtistId = ? ', [$this->ArtistId]); } - - public static function DeleteUnreferencedArtists(): void{ - Db::Query(' - DELETE - from Artists - where ArtistId NOT IN - (SELECT DISTINCT ArtistId FROM Artworks) - '); - Db::Query(' - DELETE - from ArtistAlternateNames - where ArtistId NOT IN - (SELECT DISTINCT ArtistId FROM Artworks) - '); - } } diff --git a/lib/Artwork.php b/lib/Artwork.php index 5d784435..1e931e7a 100644 --- a/lib/Artwork.php +++ b/lib/Artwork.php @@ -336,10 +336,9 @@ class Artwork extends PropertiesBase{ } /** - * @param array $uploadedFile * @throws \Exceptions\ValidationException */ - protected function Validate(array &$uploadedFile = []): void{ + protected function Validate(?string $imagePath = null, bool $isImageRequired = true): void{ $now = new DateTime('now', new DateTimeZone('UTC')); $thisYear = intval($now->format('Y')); $error = new Exceptions\ValidationException(); @@ -503,23 +502,17 @@ class Artwork extends PropertiesBase{ // No duplicates found, continue } - if(!is_writable(WEB_ROOT . COVER_ART_UPLOAD_PATH)){ - $error->Add(new Exceptions\InvalidImageUploadException('Upload path not writable.')); + if($isImageRequired && $imagePath === null){ + $error->Add(new Exceptions\InvalidImageUploadException('An image is required.')); } - if(!empty($uploadedFile) && $this->MimeType !== null){ - $uploadError = $uploadedFile['error']; - if($uploadError > UPLOAD_ERR_OK){ - // see https://www.php.net/manual/en/features.file-upload.errors.php - $message = match($uploadError){ - UPLOAD_ERR_INI_SIZE => 'Image upload too large (maximum ' . ini_get('upload_max_filesize') . ').', - default => 'Image failed to upload (error code ' . $uploadError . ').', - }; - $error->Add(new Exceptions\InvalidImageUploadException($message)); + if($imagePath !== null && $this->MimeType !== null){ + if(!is_writable(WEB_ROOT . COVER_ART_UPLOAD_PATH)){ + $error->Add(new Exceptions\InvalidImageUploadException('Upload path not writable.')); } // Check for minimum dimensions - list($imageWidth, $imageHeight) = getimagesize($uploadedFile['tmp_name']); + list($imageWidth, $imageHeight) = getimagesize($imagePath); if(!$imageWidth || !$imageHeight || $imageWidth < ARTWORK_IMAGE_MINIMUM_WIDTH || $imageHeight < ARTWORK_IMAGE_MINIMUM_HEIGHT){ $error->Add(new Exceptions\ArtworkImageDimensionsTooSmallException()); } @@ -639,13 +632,13 @@ class Artwork extends PropertiesBase{ return $outputUrl; } - private function WriteImageAndThumbnails(string $imageUploadPath): void{ - exec('exiftool -quiet -overwrite_original -all= ' . escapeshellarg($imageUploadPath)); - copy($imageUploadPath, $this->ImageFsPath); + private function WriteImageAndThumbnails(string $imagePath): void{ + exec('exiftool -quiet -overwrite_original -all= ' . escapeshellarg($imagePath)); + copy($imagePath, $this->ImageFsPath); // Generate the thumbnails try{ - $image = new Image($imageUploadPath); + $image = new Image($imagePath); $image->Resize($this->ThumbFsPath, ARTWORK_THUMBNAIL_WIDTH, ARTWORK_THUMBNAIL_HEIGHT); $image->Resize($this->Thumb2xFsPath, ARTWORK_THUMBNAIL_WIDTH * 2, ARTWORK_THUMBNAIL_HEIGHT * 2); } @@ -655,14 +648,13 @@ class Artwork extends PropertiesBase{ } /** - * @param array $uploadedFile * @throws \Exceptions\ValidationException * @throws \Exceptions\InvalidImageUploadException */ - public function Create(array $uploadedFile): void{ - $this->MimeType = ImageMimeType::FromFile($uploadedFile['tmp_name'] ?? null); + public function Create(?string $imagePath = null): void{ + $this->MimeType = ImageMimeType::FromFile($imagePath); - $this->Validate($uploadedFile); + $this->Validate($imagePath, true); $this->Created = new DateTime(); @@ -713,18 +705,19 @@ class Artwork extends PropertiesBase{ ', [$this->ArtworkId, $tag->TagId]); } - $this->WriteImageAndThumbnails($uploadedFile['tmp_name']); + if($imagePath !== null){ + $this->WriteImageAndThumbnails($imagePath); + } } /** - * @param array $uploadedFile * @throws \Exceptions\ValidationException */ - public function Save(array $uploadedFile = []): void{ + public function Save(?string $imagePath = null): void{ $this->_UrlName = null; - if(!empty($uploadedFile) && $uploadedFile['error'] == UPLOAD_ERR_OK){ - $this->MimeType = ImageMimeType::FromFile($uploadedFile['tmp_name'] ?? null); + if($imagePath !== null){ + $this->MimeType = ImageMimeType::FromFile($imagePath); // Manually set the updated timestamp, because if we only update the image and nothing else, the row's // updated timestamp won't change automatically. @@ -734,7 +727,7 @@ class Artwork extends PropertiesBase{ $this->_Thumb2xUrl = null; } - $this->Validate($uploadedFile); + $this->Validate($imagePath, false); $tags = []; foreach($this->Tags as $artworkTag){ @@ -781,8 +774,17 @@ class Artwork extends PropertiesBase{ $this->ArtworkId] ); - Artist::DeleteUnreferencedArtists(); + // Delete artists who are no longer to attached to an artwork + // Don't delete from the ArtistAlternateNames table to prevent accidentally + // deleting those manually-added entries. + Db::Query(' + DELETE + from Artists + where ArtistId not in + (select distinct ArtistId from Artworks) + '); + // Update tags for this artworke Db::Query(' DELETE from ArtworkTags where @@ -799,8 +801,8 @@ class Artwork extends PropertiesBase{ } // Handle the uploaded file if the user provided one during the save. - if(!empty($uploadedFile) && $uploadedFile['error'] == UPLOAD_ERR_OK){ - $this->WriteImageAndThumbnails($uploadedFile['tmp_name']); + if($imagePath !== null){ + $this->WriteImageAndThumbnails($imagePath); } } diff --git a/lib/Exceptions/InvalidImageUploadException.php b/lib/Exceptions/InvalidImageUploadException.php index f3b5535b..19b9fe60 100644 --- a/lib/Exceptions/InvalidImageUploadException.php +++ b/lib/Exceptions/InvalidImageUploadException.php @@ -3,5 +3,11 @@ namespace Exceptions; class InvalidImageUploadException extends AppException{ - protected $message = 'Uploaded image is invalid.'; + public function __construct(?string $message = null){ + if($message === null){ + $message = 'Uploaded image is invalid.'; + } + + parent::__construct($message); + } } diff --git a/lib/Library.php b/lib/Library.php index 681e7beb..b58e81c4 100644 --- a/lib/Library.php +++ b/lib/Library.php @@ -187,8 +187,8 @@ class Library{ $artworks = Db::Query(' SELECT * from Artworks - where Status = ? and EbookWwwFilesystemPath is not null - ', [ArtworkStatus::Approved->value], 'Artwork'); + where EbookWwwFilesystemPath is not null + ', [], 'Artwork'); } elseif($status == 'all-submitter' && $submitterUserId !== null){ $artworks = Db::Query(' diff --git a/www/artworks/post.php b/www/artworks/post.php index 2d830166..a3644981 100644 --- a/www/artworks/post.php +++ b/www/artworks/post.php @@ -36,12 +36,12 @@ try{ $artwork->ReviewerUserId = $GLOBALS['User']->UserId; } - // Confirm that the files came from POST - if(!is_uploaded_file($_FILES['artwork-image']['tmp_name'])){ + // Confirm that we have an image and that it came from POST + if(isset($_FILES['artwork-image']) && (!is_uploaded_file($_FILES['artwork-image']['tmp_name']) || $_FILES['artwork-image']['error'] > UPLOAD_ERR_OK)){ throw new Exceptions\InvalidImageUploadException(); } - $artwork->Create($_FILES['artwork-image'] ?? []); + $artwork->Create($_FILES['artwork-image']['tmp_name'] ?? null); $_SESSION['artwork'] = $artwork; $_SESSION['artwork-created'] = true; @@ -75,18 +75,18 @@ try{ $artwork->Status = $newStatus; } - $uploadedFile = []; - $uploadError = $_FILES['artwork-image']['error']; - - if($uploadError == UPLOAD_ERR_OK){ - $uploadedFile = $_FILES['artwork-image']; + // Confirm that we have an image and that it came from POST + if(isset($_FILES['artwork-image'])){ + if(!is_uploaded_file($_FILES['artwork-image']['tmp_name']) || $_FILES['artwork-image']['error'] > UPLOAD_ERR_OK){ + throw new Exceptions\InvalidImageUploadException(); + } } - // No uploaded file as part of this edit, so retain the MimeType of the original submission. else{ + // No uploaded file as part of this edit, so retain the MimeType of the original submission. $artwork->MimeType = $originalArtwork->MimeType; } - $artwork->Save($uploadedFile); + $artwork->Save($_FILES['artwork-image']['tmp_name'] ?? null); $_SESSION['artwork'] = $artwork; $_SESSION['artwork-saved'] = true; @@ -110,7 +110,6 @@ try{ } $artwork->ReviewerUserId = $GLOBALS['User']->UserId; - $artwork->Status = $newStatus; } $newEbookWwwFilesystemPath = HttpInput::Str(POST, 'artwork-ebook-www-filesystem-path', false) ?? null; @@ -118,9 +117,8 @@ try{ throw new Exceptions\InvalidPermissionsException(); } - $artwork->ReviewerUserId = $GLOBALS['User']->UserId; - $artwork->Status = $newStatus; - $artwork->EbookWwwFilesystemPath = $newEbookWwwFilesystemPath; + $artwork->Status = $newStatus ?? $artwork->Status; + $artwork->EbookWwwFilesystemPath = $newEbookWwwFilesystemPath ?? $artwork->EbookWwwFilesystemPath; $artwork->Save();