presseportale/tests/Feature/Api/V1/PressReleaseApiTest.php
Kevin Adametz 6e84266f90 press-releases: Publish-Rechte, Quota-Races & Slug vereinheitlichen
- Publish/Reject/Archive und changeStatus erzwingen konsistent
  press-releases:publish; changeStatus schloss die Lücke, über die das
  Status-Modal die Prüfung umging (Fix#1/H2).
- publish()/changeStatusFromAdmin sperren PM- und User-Zeile
  transaktional; QuotaExceededException wird in Admin-Publish und im
  Auto-Publish-Job abgefangen (Warnung statt 500 / bleibt in Review, Fix#3/M2).
- Slug-Erzeugung nur noch über HasUniqueSlug (generateUniqueSlug +
  saveWithUniqueSlugRetry), redundanter Controller-Helper entfernt (M3).
- API-/Legacy-Text wird vor der Persistenz sanitisiert (M6);
  Scheduler/Legacy-Tracking ignorieren soft-gelöschte PMs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:47:51 +00:00

111 lines
3.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
use App\Models\Category;
use App\Models\Company;
use App\Models\PressRelease;
use App\Models\User;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;
test('api user can create list update and delete own press releases', function () {
/** @var TestCase $this */
$user = User::factory()->create();
$company = Company::factory()->presseecho()->create();
$category = Category::factory()->withTranslations()->create();
$user->companies()->attach($company->id, ['role' => 'owner']);
Sanctum::actingAs($user, ['press-releases:read', 'press-releases:write']);
$createResponse = $this->postJson('/api/v1/press-releases', [
'company_id' => $company->id,
'category_id' => $category->id,
'language' => 'de',
'title' => 'Neue API Pressemitteilung',
'text' => 'Inhalt der Pressemitteilung',
'status' => 'draft',
]);
$createResponse
->assertCreated()
->assertJsonPath('data.title', 'Neue API Pressemitteilung')
->assertJsonPath('data.portal', 'presseecho');
$pressReleaseId = PressRelease::withoutGlobalScopes()
->where('title', 'Neue API Pressemitteilung')
->value('id');
$this->getJson('/api/v1/press-releases')
->assertOk()
->assertJsonPath('data.0.id', $pressReleaseId);
$this->patchJson("/api/v1/press-releases/{$pressReleaseId}", [
'title' => 'Aktualisierte API Pressemitteilung',
])
->assertOk()
->assertJsonPath('data.title', 'Aktualisierte API Pressemitteilung');
$this->deleteJson("/api/v1/press-releases/{$pressReleaseId}")
->assertNoContent();
expect(PressRelease::withoutGlobalScopes()->withTrashed()->find($pressReleaseId)?->trashed())->toBeTrue();
});
test('api submitted html text is sanitized before persistence', function () {
/**
* Regression zu Befund M6 (Audit 14.07.2026): Über die API eingereichtes
* HTML muss – wie im Web-Formular – vor der Speicherung durch den Sanitizer.
*/
/** @var TestCase $this */
$user = User::factory()->create();
$company = Company::factory()->presseecho()->create();
$category = Category::factory()->withTranslations()->create();
$user->companies()->attach($company->id, ['role' => 'owner']);
Sanctum::actingAs($user, ['press-releases:read', 'press-releases:write']);
$this->postJson('/api/v1/press-releases', [
'company_id' => $company->id,
'category_id' => $category->id,
'language' => 'de',
'title' => 'XSS Versuch',
'text' => '<p>Sauber</p><script>alert(document.cookie)</script><a href="javascript:alert(1)">x</a>',
'status' => 'draft',
])->assertCreated();
$stored = PressRelease::withoutGlobalScopes()->where('title', 'XSS Versuch')->firstOrFail();
expect($stored->text)
->not->toContain('<script')
->not->toContain('javascript:')
->toContain('<p>Sauber</p>');
});
test('api write ability is required to create press releases', function () {
/** @var TestCase $this */
$user = User::factory()->create();
$company = Company::factory()->presseecho()->create();
$category = Category::factory()->withTranslations()->create();
$user->companies()->attach($company->id, ['role' => 'owner']);
Sanctum::actingAs($user, ['press-releases:read']);
$this->postJson('/api/v1/press-releases', [
'company_id' => $company->id,
'category_id' => $category->id,
'language' => 'de',
'title' => 'Nicht erlaubt',
'text' => 'Inhalt',
])->assertForbidden();
});
test('api user cannot access another users press release', function () {
/** @var TestCase $this */
$owner = User::factory()->create();
$otherUser = User::factory()->create();
$pressRelease = PressRelease::factory()->create(['user_id' => $owner->id]);
Sanctum::actingAs($otherUser, ['press-releases:read']);
$this->getJson("/api/v1/press-releases/{$pressRelease->id}")
->assertForbidden();
});