fix: corriger l'erreur HTTP 400 sur les endpoints content-sources POST/PUT
- ContentSourceForm.vue : convertir testChapterNumber en float/null avant envoi (évite d'envoyer "" pour ?float, rejeté par Symfony 8 strict) - UpsertContentSourceResource : ajouter collectDenormalizationErrors: true pour que les erreurs de type retournent 422 au lieu de 400 via le chemin input: de API Platform 4 - ContentSource entity : corriger setImageSelector(string) → setImageSelector(?string) cohérent avec la colonne nullable - Ajouter les tests manquants (testChapterNumber float/null/chaîne vide) qui auraient détecté ces bugs plus tôt
This commit is contained in:
parent
21d8111734
commit
69c6757cf8
@@ -242,8 +242,17 @@ watch(() => props.source, (newSource) => {
|
|||||||
}
|
}
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
|
const buildPayload = (formData) => {
|
||||||
|
const data = { ...formData };
|
||||||
|
const raw = data.testChapterNumber;
|
||||||
|
data.testChapterNumber = (raw === '' || raw === null || raw === undefined)
|
||||||
|
? null
|
||||||
|
: parseFloat(raw);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
emit('submit', { ...form.value });
|
emit('submit', buildPayload(form.value));
|
||||||
};
|
};
|
||||||
|
|
||||||
defineExpose({ submitForm: handleSubmit });
|
defineExpose({ submitForm: handleSubmit });
|
||||||
@@ -252,7 +261,7 @@ const testConfiguration = async () => {
|
|||||||
testing.value = true;
|
testing.value = true;
|
||||||
try {
|
try {
|
||||||
await emit('test', {
|
await emit('test', {
|
||||||
configuration: { ...form.value },
|
configuration: buildPayload(form.value),
|
||||||
testData: {
|
testData: {
|
||||||
mangaSlug: form.value.testSlug,
|
mangaSlug: form.value.testSlug,
|
||||||
chapterNumber: form.value.testChapterNumber,
|
chapterNumber: form.value.testChapterNumber,
|
||||||
|
|||||||
@@ -1834,8 +1834,8 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* }
|
* }
|
||||||
* @psalm-type MercureConfig = array{
|
* @psalm-type MercureConfig = array{
|
||||||
* hubs?: array<string, array{ // Default: []
|
* hubs?: array<string, array{ // Default: []
|
||||||
* url?: scalar|Param|null, // URL of the hub's publish endpoint
|
* url?: scalar|Param|null, // URL of the hub's publish endpoint // Default: null
|
||||||
* public_url?: scalar|Param|null, // URL of the hub's public endpoint // Default: null
|
* public_url?: scalar|Param|null, // URL of the hub's public endpoint
|
||||||
* jwt?: string|array{ // JSON Web Token configuration.
|
* jwt?: string|array{ // JSON Web Token configuration.
|
||||||
* value?: scalar|Param|null, // JSON Web Token to use to publish to this hub.
|
* value?: scalar|Param|null, // JSON Web Token to use to publish to this hub.
|
||||||
* provider?: scalar|Param|null, // The ID of a service to call to provide the JSON Web Token.
|
* provider?: scalar|Param|null, // The ID of a service to call to provide the JSON Web Token.
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||||||
uriTemplate: '/content-sources',
|
uriTemplate: '/content-sources',
|
||||||
processor: UpsertContentSourceStateProcessor::class,
|
processor: UpsertContentSourceStateProcessor::class,
|
||||||
input: UpsertContentSourceResource::class,
|
input: UpsertContentSourceResource::class,
|
||||||
|
collectDenormalizationErrors: true,
|
||||||
status: 201,
|
status: 201,
|
||||||
description: 'Crée une nouvelle source de contenu'
|
description: 'Crée une nouvelle source de contenu'
|
||||||
),
|
),
|
||||||
@@ -24,6 +25,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||||||
provider: GetContentSourceStateProvider::class,
|
provider: GetContentSourceStateProvider::class,
|
||||||
processor: UpsertContentSourceStateProcessor::class,
|
processor: UpsertContentSourceStateProcessor::class,
|
||||||
input: UpsertContentSourceResource::class,
|
input: UpsertContentSourceResource::class,
|
||||||
|
collectDenormalizationErrors: true,
|
||||||
description: 'Met à jour une source de contenu existante'
|
description: 'Met à jour une source de contenu existante'
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class ContentSource
|
|||||||
return $this->imageSelector;
|
return $this->imageSelector;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setImageSelector(string $imageSelector): static
|
public function setImageSelector(?string $imageSelector): static
|
||||||
{
|
{
|
||||||
$this->imageSelector = $imageSelector;
|
$this->imageSelector = $imageSelector;
|
||||||
|
|
||||||
|
|||||||
@@ -181,4 +181,35 @@ final class CreateContentSourceTest extends AbstractApiTestCase
|
|||||||
|
|
||||||
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
|
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItAcceptsTestChapterNumberAsFloat(): void
|
||||||
|
{
|
||||||
|
$response = static::createClient()->request('POST', '/api/content-sources', [
|
||||||
|
'json' => [
|
||||||
|
'baseUrl' => 'https://mangadex.org',
|
||||||
|
'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}',
|
||||||
|
'scrapingType' => 'html',
|
||||||
|
'testSlug' => 'one-piece',
|
||||||
|
'testChapterNumber' => 1.5,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertResponseStatusCodeSame(Response::HTTP_CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItRejectsTestChapterNumberAsEmptyStringWith422(): void
|
||||||
|
{
|
||||||
|
// Cas réel du formulaire Vue : le champ vide envoie "" au lieu de null.
|
||||||
|
// Doit retourner 422 (erreur de validation) et non 400 (données malformées).
|
||||||
|
$response = static::createClient()->request('POST', '/api/content-sources', [
|
||||||
|
'json' => [
|
||||||
|
'baseUrl' => 'https://mangadex.org',
|
||||||
|
'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}',
|
||||||
|
'scrapingType' => 'html',
|
||||||
|
'testChapterNumber' => '',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,4 +188,49 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
|
|||||||
|
|
||||||
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
|
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItAcceptsTestChapterNumberAsFloat(): void
|
||||||
|
{
|
||||||
|
$response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [
|
||||||
|
'json' => [
|
||||||
|
'baseUrl' => 'https://mangadex.org',
|
||||||
|
'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}',
|
||||||
|
'scrapingType' => 'html',
|
||||||
|
'testSlug' => 'one-piece',
|
||||||
|
'testChapterNumber' => 1.5,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertResponseIsSuccessful();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItAcceptsTestChapterNumberAsNull(): void
|
||||||
|
{
|
||||||
|
$response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [
|
||||||
|
'json' => [
|
||||||
|
'baseUrl' => 'https://mangadex.org',
|
||||||
|
'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}',
|
||||||
|
'scrapingType' => 'html',
|
||||||
|
'testChapterNumber' => null,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertResponseIsSuccessful();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItRejectsTestChapterNumberAsEmptyStringWith422(): void
|
||||||
|
{
|
||||||
|
// Cas réel du formulaire Vue : le champ vide envoie "" au lieu de null.
|
||||||
|
// Doit retourner 422 (erreur de validation) et non 400 (données malformées).
|
||||||
|
$response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [
|
||||||
|
'json' => [
|
||||||
|
'baseUrl' => 'https://mangadex.org',
|
||||||
|
'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}',
|
||||||
|
'scrapingType' => 'html',
|
||||||
|
'testChapterNumber' => '',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user