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>
83 lines
4.1 KiB
PHP
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/');
|
|
});
|