S4: legacy:seed-api-testdata — API-Testkunde nach connektar-Muster
Idempotenter Command (nur local/staging): aktiver Legacy-API-User mit Grandfathering, importiertem X-ApiKey, api:immediate-publication, Firma + Pressekontakt; gibt Key + curl-Sammlung des /service-Flows aus. Live gegen die lokale App verifiziert (Firma -> Kontakt -> PM sofort published -> GET 200 im Alt-Format). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
6a45ebf607
commit
d9f25aecaf
3 changed files with 240 additions and 1 deletions
213
app/Console/Commands/SeedLegacyApiTestdata.php
Normal file
213
app/Console/Commands/SeedLegacyApiTestdata.php
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\CompanyType;
|
||||
use App\Enums\PaymentOptionType;
|
||||
use App\Enums\Portal;
|
||||
use App\Enums\RegistrationType;
|
||||
use App\Enums\UserPaymentOptionStatus;
|
||||
use App\Models\Category;
|
||||
use App\Models\Company;
|
||||
use App\Models\PaymentOption;
|
||||
use App\Models\User;
|
||||
use App\Models\UserPaymentOption;
|
||||
use App\Services\Api\LegacyApiKeyImporter;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
|
||||
/**
|
||||
* Legt einen API-Testkunden nach connektar-Muster an (S4 der Paritäts-Doku
|
||||
* dev/release/api-legacy-paritaet.md): aktiver Bestandskunde mit Grandfathering,
|
||||
* importiertem Legacy-Key, Sofort-Publish-Recht, Firma + Pressekontakt — und
|
||||
* gibt Key + fertige curl-Sammlung für den /service-Flow aus.
|
||||
*
|
||||
* Idempotent: wiederholte Läufe erneuern nur den API-Key. Nur local/staging.
|
||||
*/
|
||||
class SeedLegacyApiTestdata extends Command
|
||||
{
|
||||
protected $signature = 'legacy:seed-api-testdata
|
||||
{--portal=businessportal24 : Portal des Testkunden (businessportal24|presseecho)}
|
||||
{--email=api-test@pressekonto.test : E-Mail des Testkunden}';
|
||||
|
||||
protected $description = 'API-Testdaten nach connektar-Muster anlegen (Legacy-Key, Firma, Kontakt) + curl-Sammlung ausgeben.';
|
||||
|
||||
public function handle(LegacyApiKeyImporter $importer): int
|
||||
{
|
||||
if (app()->environment('production')) {
|
||||
$this->error('Nur fuer local/staging — nicht in Produktion ausfuehren.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$portal = (string) $this->option('portal');
|
||||
|
||||
if (! in_array($portal, [Portal::Businessportal24->value, Portal::Presseecho->value], true)) {
|
||||
$this->error('Ungueltiges Portal: '.$portal);
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$email = (string) $this->option('email');
|
||||
$legacyId = 999901;
|
||||
|
||||
// 1. Testkunde: aktiver Legacy-API-User (wie connektar).
|
||||
$user = User::query()->firstOrCreate(
|
||||
['email' => $email],
|
||||
[
|
||||
'name' => 'API Testkunde',
|
||||
'password' => Hash::make('password'),
|
||||
'email_verified_at' => now(),
|
||||
],
|
||||
);
|
||||
$user->forceFill([
|
||||
'is_active' => true,
|
||||
'portal' => $portal,
|
||||
'legacy_portal' => $portal,
|
||||
'legacy_id' => $legacyId,
|
||||
'registration_type' => RegistrationType::ApiUser,
|
||||
'agency_name' => 'API Testverteiler',
|
||||
])->save();
|
||||
|
||||
if (! $user->hasRole('customer')) {
|
||||
$user->assignRole('customer');
|
||||
}
|
||||
|
||||
// 2. Grandfathering (Bestandsschutz): macht den User API-berechtigt
|
||||
// und laesst das Buchungs-Gate passieren.
|
||||
$paymentOption = PaymentOption::query()->firstOrCreate(
|
||||
['article_number' => 'ART-API-TEST'],
|
||||
[
|
||||
'type' => PaymentOptionType::cases()[0]->value,
|
||||
'price_cents' => 0,
|
||||
'currency' => 'EUR',
|
||||
'interval' => 'monthly',
|
||||
'is_hidden' => true,
|
||||
],
|
||||
);
|
||||
|
||||
UserPaymentOption::query()->updateOrCreate(
|
||||
['user_id' => $user->id, 'payment_option_id' => $paymentOption->id],
|
||||
[
|
||||
'status' => UserPaymentOptionStatus::Grandfathered->value,
|
||||
'grandfathered_until' => null,
|
||||
'current_period_start' => now()->subMonth(),
|
||||
'current_period_end' => now()->addMonths(11),
|
||||
'stripe_subscription_id' => null,
|
||||
],
|
||||
);
|
||||
|
||||
// 3. Sofort-Publish-Privileg (Alt-Verhalten von connektar). Die
|
||||
// Permission defensiv anlegen — lokale DBs sind nicht immer auf dem
|
||||
// juengsten Seeder-Stand.
|
||||
Permission::firstOrCreate(['name' => 'api:immediate-publication']);
|
||||
|
||||
if (! $user->hasPermissionTo('api:immediate-publication')) {
|
||||
$user->givePermissionTo('api:immediate-publication');
|
||||
}
|
||||
|
||||
// 4. Firma + Pressekontakt (der API-Flow kann weitere anlegen).
|
||||
$company = Company::withoutGlobalScopes()->firstOrNew(
|
||||
['name' => 'API Test GmbH', 'portal' => $portal],
|
||||
[
|
||||
'type' => CompanyType::Company->value,
|
||||
'address' => "Teststrasse 1\n33602 Bielefeld",
|
||||
'country_code' => 'DE',
|
||||
'email' => 'firma@api-test.example',
|
||||
'website' => 'https://api-test.example',
|
||||
'is_active' => true,
|
||||
],
|
||||
);
|
||||
|
||||
if (! $company->slug) {
|
||||
$company->slug = $company->generateUniqueSlug($company->name);
|
||||
}
|
||||
$company->owner_user_id ??= $user->id;
|
||||
$company->save();
|
||||
|
||||
if (! $company->users()->whereKey($user->id)->exists()) {
|
||||
$company->users()->attach($user->id, ['role' => 'owner']);
|
||||
}
|
||||
|
||||
$contact = $company->contacts()->firstOrCreate(
|
||||
['email' => 'presse@api-test.example'],
|
||||
[
|
||||
'portal' => $portal,
|
||||
'salutation_key' => 'mr',
|
||||
'first_name' => 'Max',
|
||||
'last_name' => 'Mustermann',
|
||||
'responsibility' => 'Pressestelle',
|
||||
],
|
||||
);
|
||||
|
||||
// 5. Legacy-API-Key erneuern (wie legacy:import-api-keys).
|
||||
$apiKey = 'test-'.Str::random(40);
|
||||
$user->tokens()->delete();
|
||||
$importer->import($portal, [
|
||||
['legacy_id' => $legacyId, 'api_key' => $apiKey],
|
||||
]);
|
||||
|
||||
$category = Category::withoutGlobalScopes()->where('is_active', true)->first();
|
||||
$host = rtrim((string) config("domains.domains.{$portal}.url", config('app.url')), '/');
|
||||
|
||||
$this->info('API-Testkunde bereit.');
|
||||
$this->table(['Feld', 'Wert'], [
|
||||
['Login (Panel)', $email.' / password'],
|
||||
['Portal', $portal],
|
||||
['X-ApiKey', $apiKey],
|
||||
['Firma', "#{$company->id} {$company->name}"],
|
||||
['Pressekontakt', "#{$contact->id} {$contact->first_name} {$contact->last_name}"],
|
||||
['Kategorie (legacy_id)', $category ? "#{$category->legacy_id}" : '— (keine aktive Kategorie!)'],
|
||||
['Sofort-Publish', 'ja (api:immediate-publication)'],
|
||||
]);
|
||||
|
||||
$categoryId = $category?->legacy_id ?? 1;
|
||||
|
||||
$this->line(<<<CURL
|
||||
|
||||
# --- connektar-Flow (Alt-Vertrag, dev/release/api-legacy-paritaet.md §1) ---
|
||||
|
||||
# 1. Firma anlegen
|
||||
curl -s -i -X POST '{$host}/service/users/me/companies' \\
|
||||
-H 'X-ApiKey: {$apiKey}' \\
|
||||
-d 'company[name]=Neue Testfirma GmbH' \\
|
||||
-d 'company[address]=Musterweg 2, 33602 Bielefeld' \\
|
||||
-d 'company[country_id]=177' \\
|
||||
-d 'company[email]=info@neue-testfirma.example'
|
||||
|
||||
# 2. Pressekontakt anlegen (COMPANY_ID aus Location-Header von Schritt 1)
|
||||
curl -s -i -X POST '{$host}/service/users/me/companies/COMPANY_ID/contacts' \\
|
||||
-H 'X-ApiKey: {$apiKey}' \\
|
||||
-d 'contact[salutation_id]=1' \\
|
||||
-d 'contact[first_name]=Erika' \\
|
||||
-d 'contact[last_name]=Beispiel' \\
|
||||
-d 'contact[email]=presse@neue-testfirma.example'
|
||||
|
||||
# 3. PM anlegen (= einreichen; mit Sofort-Publish geht sie direkt live)
|
||||
curl -s -i -X POST '{$host}/service/pressreleases' \\
|
||||
-H 'X-ApiKey: {$apiKey}' \\
|
||||
-d 'press_release[company_id]={$company->id}' \\
|
||||
-d 'press_release[category_id]={$categoryId}' \\
|
||||
-d 'press_release[language]=de' \\
|
||||
-d 'press_release[title]=Testmeldung ueber die Legacy-API' \\
|
||||
-d 'press_release[text]=Dies ist eine Testmeldung aus der Legacy-API-Kompatibilitaetsschicht.' \\
|
||||
-d 'press_release[contacts_list][]={$contact->id}'
|
||||
|
||||
# 4. Bild hochladen (PM_ID aus Location-Header von Schritt 3)
|
||||
curl -s -i -X POST '{$host}/service/pressreleases/PM_ID/images' \\
|
||||
-H 'X-ApiKey: {$apiKey}' \\
|
||||
-F 'press_release_image[image]=@pressefoto.jpg' \\
|
||||
-F 'press_release_image[copyright]=API Test GmbH'
|
||||
|
||||
# 5. Veroeffentlichungs-Kontrolle (404 = noch nicht veroeffentlicht)
|
||||
curl -s '{$host}/service/pressreleases/PM_ID' -H 'X-ApiKey: {$apiKey}'
|
||||
CURL);
|
||||
|
||||
$this->newLine();
|
||||
$this->comment('Hinweis: Schalter "KI-Pruefung Legacy-API" auf /admin/press-releases steuert Sofort-Publish vs. KI-Review.');
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue