API: KI-Deklaration als v1-Pflichtfeld, Legacy-Default fuer /service (Entscheidung 10.07.)
Befund: v1 hatte keine KI-Deklarationsfelder — Submit lief seit der KI-Kennzeichnungspflicht (09.07.) immer auf 422 und haette alle Legacy-API-Kunden blockiert (Suite uebersah es: Factory deklariert). - v1-Submit verlangt ai_text_declaration; der Call gilt dokumentiert als verbindliche Bestaetigung (Art. 50 KI-VO) und schliesst die Archiv-Kenntnisnahme (AGB par. 13) ein - Bild-Upload verlangt ai_declaration (original/ai_generated/ai_edited) - Legacy-/service-Aliasse defaulten auf none/original — das API-Kunden-Mailing (R6.4) weist auf die Erklaerungswirkung hin - OpenAPI v1.yml + lang-Hinweis aktualisiert; Tests erweitert (Submit/Image/LegacyCompatibility) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
9b2409ee54
commit
5c91e2e281
11 changed files with 213 additions and 10 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Enums\AiTextDeclaration;
|
||||
use App\Enums\PressReleaseStatus;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\StorePressReleaseRequest;
|
||||
|
|
@ -19,6 +20,7 @@ use Illuminate\Http\Request;
|
|||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class PressReleaseController extends Controller
|
||||
{
|
||||
|
|
@ -56,6 +58,15 @@ class PressReleaseController extends Controller
|
|||
// `review` erfolgt ausschließlich über die explizite submit-Route,
|
||||
// damit Blacklist-/Quota-/Log-Prüfung garantiert durchlaufen werden.
|
||||
'status' => PressReleaseStatus::Draft->value,
|
||||
// Legacy-/service-Clients kennen die KI-Kennzeichnung (Art. 50
|
||||
// KI-VO) nicht — Entscheidung 10.07.: fehlende Angabe gilt als
|
||||
// „ohne generative KI erstellt"; das API-Kunden-Mailing (R6.4)
|
||||
// weist darauf hin, dass die weitere Nutzung diese Erklärung
|
||||
// darstellt. v1-Clients deklarieren explizit beim Submit.
|
||||
...($this->isLegacyServiceRequest($request) ? [
|
||||
'ai_text_declaration' => AiTextDeclaration::None->value,
|
||||
'ai_declaration_confirmed_at' => now(),
|
||||
] : []),
|
||||
]);
|
||||
|
||||
return PressReleaseResource::make(
|
||||
|
|
@ -133,6 +144,16 @@ class PressReleaseController extends Controller
|
|||
public function submit(Request $request, int $pressRelease, PressReleaseService $service): PressReleaseResource|JsonResponse
|
||||
{
|
||||
abort_unless($request->user()->tokenCan('press-releases:write'), 403);
|
||||
|
||||
// KI-Kennzeichnungspflicht (Art. 50 KI-VO) auch via API: der
|
||||
// Submit-Call trägt den deklarierten KI-Grad des Textes und gilt
|
||||
// dokumentiert als verbindliche Bestätigung der Deklaration sowie
|
||||
// Kenntnisnahme der dauerhaften Archivierung (AGB § 13) —
|
||||
// Entscheidung 10.07.2026.
|
||||
$validated = $request->validate([
|
||||
'ai_text_declaration' => ['required', Rule::enum(AiTextDeclaration::class)],
|
||||
]);
|
||||
|
||||
$pressRelease = $this->findOwnedPressRelease($pressRelease, $request);
|
||||
abort_unless($pressRelease !== null, 403);
|
||||
|
||||
|
|
@ -142,6 +163,11 @@ class PressReleaseController extends Controller
|
|||
], 409);
|
||||
}
|
||||
|
||||
$pressRelease->update([
|
||||
'ai_text_declaration' => $validated['ai_text_declaration'],
|
||||
'ai_declaration_confirmed_at' => now(),
|
||||
]);
|
||||
|
||||
try {
|
||||
$service->submitForReview($pressRelease);
|
||||
} catch (BookingRequiredException $exception) {
|
||||
|
|
@ -211,6 +237,16 @@ class PressReleaseController extends Controller
|
|||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Kam der Call über die Legacy-Aliasse (/service/…, routes/legacy-api.php)?
|
||||
* Dort gelten Kompatibilitäts-Defaults für Felder, die die Altportale
|
||||
* nicht kannten (KI-Kennzeichnung).
|
||||
*/
|
||||
private function isLegacyServiceRequest(Request $request): bool
|
||||
{
|
||||
return str_starts_with((string) $request->route()?->getName(), 'legacy-service.');
|
||||
}
|
||||
|
||||
private function uniqueSlug(string $baseSlug, string $portal, string $language, ?int $excludeId = null): string
|
||||
{
|
||||
$slug = $baseSlug !== '' ? $baseSlug : Str::random(8);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Enums\AiImageDeclaration;
|
||||
use App\Enums\PressReleaseStatus;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\StorePressReleaseImageRequest;
|
||||
|
|
@ -63,6 +64,10 @@ class PressReleaseImageController extends Controller
|
|||
'disk' => 'public',
|
||||
'path' => $stored['path'],
|
||||
'variants' => $stored['variants'],
|
||||
// v1 verlangt die KI-Kennzeichnung je Bild (FormRequest);
|
||||
// Legacy-/service-Calls ohne Feld gelten als Originalfoto
|
||||
// (Kompatibilitäts-Default, Entscheidung 10.07.2026).
|
||||
'ai_declaration' => $validated['ai_declaration'] ?? AiImageDeclaration::Original->value,
|
||||
'title' => $validated['title'] ?? null,
|
||||
'description' => $validated['description'] ?? null,
|
||||
'copyright' => $validated['copyright'] ?? null,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
namespace App\Http\Requests\Api\V1;
|
||||
|
||||
use App\Enums\AiImageDeclaration;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StorePressReleaseImageRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -18,12 +20,23 @@ class StorePressReleaseImageRequest extends FormRequest
|
|||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* KI-Kennzeichnung je Bild (Art. 50 KI-VO) ist im v1-Vertrag Pflicht;
|
||||
* Legacy-/service-Clients kennen das Feld nicht — dort greift der
|
||||
* Kompatibilitäts-Default „original" (Entscheidung 10.07.2026).
|
||||
*
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$isLegacyServiceCall = str_starts_with((string) $this->route()?->getName(), 'legacy-service.');
|
||||
|
||||
return [
|
||||
'image' => ['required', 'image', 'mimes:jpg,jpeg,png,webp', 'max:8192'],
|
||||
'ai_declaration' => [
|
||||
Rule::requiredIf(! $isLegacyServiceCall),
|
||||
'nullable',
|
||||
Rule::enum(AiImageDeclaration::class),
|
||||
],
|
||||
'title' => ['nullable', 'string', 'max:120'],
|
||||
'description' => ['nullable', 'string', 'max:500'],
|
||||
'copyright' => ['nullable', 'string', 'max:255'],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue