diff --git a/src/Services/InfoProviderSystem/DTOs/SearchResultDTO.php b/src/Services/InfoProviderSystem/DTOs/SearchResultDTO.php index 355041bf..c12b54f8 100644 --- a/src/Services/InfoProviderSystem/DTOs/SearchResultDTO.php +++ b/src/Services/InfoProviderSystem/DTOs/SearchResultDTO.php @@ -30,6 +30,11 @@ use App\Entity\Parts\ManufacturingStatus; */ class SearchResultDTO { + /** @var string|null An URL to a preview image */ + public readonly ?string $preview_image_url; + /** @var FileDTO|null The preview image as FileDTO object */ + public readonly ?FileDTO $preview_image_file; + public function __construct( /** @var string The provider key (e.g. "digikey") */ public readonly string $provider_key, @@ -46,7 +51,7 @@ class SearchResultDTO /** @var string|null The manufacturer part number */ public readonly ?string $mpn = null, /** @var string|null An URL to a preview image */ - public readonly ?string $preview_image_url = null, + ?string $preview_image_url = null, /** @var ManufacturingStatus|null The manufacturing status of the part */ public readonly ?ManufacturingStatus $manufacturing_status = null, /** @var string|null A link to the part on the providers page */ @@ -55,5 +60,14 @@ class SearchResultDTO public readonly ?string $footprint = null, ) { + if ($preview_image_url !== null) { + //Utilize the escaping mechanism of FileDTO to ensure that the preview image URL is correctly encoded + //See issue #521: https://github.com/Part-DB/Part-DB-server/issues/521 + $this->preview_image_file = new FileDTO($preview_image_url); + $this->preview_image_url = $this->preview_image_file->url; + } else { + $this->preview_image_file = null; + $this->preview_image_url = null; + } } } \ No newline at end of file diff --git a/tests/Services/InfoProviderSystem/DTOs/SearchResultDTOTest.php b/tests/Services/InfoProviderSystem/DTOs/SearchResultDTOTest.php new file mode 100644 index 00000000..f23439f8 --- /dev/null +++ b/tests/Services/InfoProviderSystem/DTOs/SearchResultDTOTest.php @@ -0,0 +1,62 @@ +. + */ + +namespace App\Tests\Services\InfoProviderSystem\DTOs; + +use App\Services\InfoProviderSystem\DTOs\SearchResultDTO; +use PHPUnit\Framework\TestCase; + +class SearchResultDTOTest extends TestCase +{ + public function testPreviewImageURL(): void + { + //For null preview_image_url, the url and file dto should be null + $searchResultDTO = new SearchResultDTO( + 'provider_key', + 'provider_id', + 'name', + 'description' + ); + $this->assertNull($searchResultDTO->preview_image_url); + $this->assertNull($searchResultDTO->preview_image_file); + + //If a value is passed then the url and file dto should be the same + $searchResultDTO = new SearchResultDTO( + 'provider_key', + 'provider_id', + 'name', + 'description', + preview_image_url: 'https://invalid.com/preview_image_url.jpg' + ); + $this->assertEquals('https://invalid.com/preview_image_url.jpg', $searchResultDTO->preview_image_url); + $this->assertEquals('https://invalid.com/preview_image_url.jpg', $searchResultDTO->preview_image_file->url); + + //Invalid url characters should be replaced with their URL encoded version (similar to FileDTO) + $searchResultDTO = new SearchResultDTO( + 'provider_key', + 'provider_id', + 'name', + 'description', + preview_image_url: 'https://invalid.com/preview_image^url.jpg?param1=1¶m2=2' + ); + $this->assertEquals('https://invalid.com/preview_image%5Eurl.jpg?param1=1¶m2=2', $searchResultDTO->preview_image_url); + $this->assertEquals('https://invalid.com/preview_image%5Eurl.jpg?param1=1¶m2=2', $searchResultDTO->preview_image_file->url); + } +}