presseportale/tests/Feature/CompanyNameNormalizerTest.php
Kevin Adametz e77d9e7d09 feat: API-Zugang endet mit der Buchung, optionales Ablaufdatum für API-Tokens
Bisher blieb ein einmal erstellter Token gültig, auch wenn Abo bzw. Buchung
längst beendet waren. EnsureApiAccessIsBooked prüft jetzt bei jeder Anfrage
(v1 und /service/…-Altpfade), ob das Konto API-Zugang hat
(ApiAccessEligibilityService::hasApiAccess), sonst 403. Die Tokens bleiben
erhalten und funktionieren nach erneuter Buchung wieder.

Kunden können beim Erstellen optional ein Ablaufdatum setzen (bis 5 Jahre);
die Token-Liste zeigt „Gültig bis“ und einen Hinweis, wenn der Zugang
pausiert ist. sanctum:prune-expired räumt abgelaufene Tokens nach 30 Tagen
täglich ab. API-Doku (public/api/v1.yml) ergänzt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:41:24 +00:00

83 lines
4.1 KiB
PHP

<?php
use App\Enums\Portal;
use App\Models\ActivityEvent;
use App\Models\Company;
use App\Models\PressRelease;
use App\Models\User;
use App\Services\Company\CompanyNameNormalizer;
use Database\Seeders\RolesAndPermissionsSeeder;
use Tests\TestCase;
/**
* Links gehören nicht in Firmennamen (17.09.2026): Normalisierung am
* API-Eingang und einmalig im Bestand — nicht ablehnen, sondern die URL ins
* Website-Feld ziehen.
*/
test('urls are pulled out of the name and moved to the website field', function (string $name, string $expectedName, ?string $expectedWebsite) {
$result = CompanyNameNormalizer::normalize($name);
expect($result['name'])->toBe($expectedName)
->and($result['website'])->toBe($expectedWebsite);
})->with([
['Steinreinigung - https://www.bgn.at/steinreinigung', 'Steinreinigung', 'https://www.bgn.at/steinreinigung'],
['Nasenkorrektur Wien - https://www.nasen-chirurgie.at/ - Nasen-OP Wien', 'Nasenkorrektur Wien - Nasen-OP Wien', 'https://www.nasen-chirurgie.at/'],
['Teledeal Media / www.standortanzeige.de', 'Teledeal Media', 'www.standortanzeige.de'],
['ECCO (www.eccowalkathon.de)', 'ECCO', 'www.eccowalkathon.de'],
['https://www.ak-autos.de/', 'ak-autos.de', 'https://www.ak-autos.de/'],
['www.wunderbare-seifenblasen.de', 'wunderbare-seifenblasen.de', 'www.wunderbare-seifenblasen.de'],
['Muster GmbH & Co. KG', 'Muster GmbH & Co. KG', null],
['meinshop.de GmbH', 'meinshop.de GmbH', null],
]);
test('an existing website is kept, the removed url only fills an empty field', function () {
$result = CompanyNameNormalizer::normalize('Muster - https://spam.example', 'https://muster.example');
expect($result['name'])->toBe('Muster')
->and($result['website'])->toBe('https://muster.example')
->and($result['removed'])->toBe(['https://spam.example']);
});
test('the legacy api stores a clean name and records the correction', function () {
/** @var TestCase $this */
$this->seed(RolesAndPermissionsSeeder::class);
config()->set('billing.enforce_booking', false);
$user = User::factory()->create(['is_active' => true, 'portal' => Portal::Businessportal24]);
$user->forceFill(['registration_type' => 'apiuser'])->save();
apiActingAs($user, ['press-releases:write']);
$response = $this->postJson('/service/users/me/companies', [
'company' => ['name' => 'Steinreinigung - https://www.bgn.at/steinreinigung', 'email' => 'info@bgn.at'],
])->assertCreated();
$company = Company::withoutGlobalScopes()->findOrFail((int) basename((string) $response->headers->get('Location')));
expect($company->name)->toBe('Steinreinigung')
->and($company->website)->toBe('https://www.bgn.at/steinreinigung')
->and($company->slug)->toBe('steinreinigung');
expect(ActivityEvent::query()->where('subject_id', $company->id)->where('description', 'like', '%Link aus dem Namen entfernt%')->exists())->toBeTrue();
});
test('the cleanup command shows a dry run and then rewrites only public companies', function () {
/** @var TestCase $this */
$public = Company::factory()->businessportal24()->create(['name' => 'Medienprofi - www.medienprofi.org', 'slug' => 'medienprofi-www-medienprofi-org', 'website' => null]);
PressRelease::factory()->published()->forPortal(Portal::Businessportal24)->create(['company_id' => $public->id]);
$silent = Company::factory()->businessportal24()->create(['name' => 'https://spam.example/', 'website' => null]);
$this->artisan('companies:strip-links-from-names', ['--dry-run' => true])
->expectsOutputToContain('[Dry-Run] 1 Firmennamen würden bereinigt.')
->assertSuccessful();
expect($public->fresh()->name)->toBe('Medienprofi - www.medienprofi.org');
$this->artisan('companies:strip-links-from-names')
->expectsOutputToContain('1 Firmennamen bereinigt.')
->assertSuccessful();
$public->refresh();
expect($public->name)->toBe('Medienprofi')
->and($public->website)->toBe('www.medienprofi.org')
->and($public->slug)->toBe('medienprofi-www-medienprofi-org')
->and($silent->fresh()->name)->toBe('https://spam.example/');
});