- Reworked the tenant admin login page
- Updated the User model to implement Filament’s tenancy contracts - Seeded a ready-to-use demo tenant (user, tenant, active package, purchase) - Introduced a branded, translated 403 error page to replace the generic forbidden message for unauthorised admin hits - Removed the public “Register” links from the marketing header - hardened join event logic and improved error handling in the guest pwa.
This commit is contained in:
@@ -26,7 +26,7 @@ return new class extends Migration
|
||||
$table->boolean('photo_upload_enabled')->default(true);
|
||||
$table->boolean('task_checklist_enabled')->default(true);
|
||||
$table->string('default_locale', 5)->default('de');
|
||||
$table->enum('status', ['draft', 'active', 'archived'])->default('draft'); // From add_status_to_events
|
||||
$table->enum('status', ['draft', 'published', 'archived'])->default('draft'); // From add_status_to_events
|
||||
$table->timestamps();
|
||||
$table->index(['tenant_id', 'date', 'is_active']);
|
||||
$table->foreign('event_type_id')->references('id')->on('event_types')->onDelete('restrict');
|
||||
@@ -34,7 +34,7 @@ return new class extends Migration
|
||||
} else {
|
||||
if (!Schema::hasColumn('events', 'status')) {
|
||||
Schema::table('events', function (Blueprint $table) {
|
||||
$table->enum('status', ['draft', 'active', 'archived'])->default('draft')->after('is_active');
|
||||
$table->enum('status', ['draft', 'published', 'archived'])->default('draft')->after('is_active');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -165,4 +165,4 @@ return new class extends Migration
|
||||
Schema::dropIfExists('events');
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@ class DatabaseSeeder extends Seeder
|
||||
// Seed demo and admin data
|
||||
$this->call([
|
||||
SuperAdminSeeder::class,
|
||||
DemoTenantSeeder::class,
|
||||
DemoEventSeeder::class,
|
||||
OAuthClientSeeder::class,
|
||||
]);
|
||||
|
||||
@@ -20,7 +20,7 @@ class DemoEventSeeder extends Seeder
|
||||
'description' => ['de'=>'Demo-Event','en'=>'Demo event'],
|
||||
'date' => now()->addMonths(3)->toDateString(),
|
||||
'event_type_id' => $type->id,
|
||||
'status' => 'active',
|
||||
'status' => 'published',
|
||||
'is_active' => true,
|
||||
'settings' => json_encode([]),
|
||||
'default_locale' => 'de',
|
||||
|
||||
122
database/seeders/DemoTenantSeeder.php
Normal file
122
database/seeders/DemoTenantSeeder.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Package;
|
||||
use App\Models\PackagePurchase;
|
||||
use App\Models\Tenant;
|
||||
use App\Models\TenantPackage;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DemoTenantSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$email = 'tenant-demo@fotospiel.app';
|
||||
$password = config('seeding.demo_tenant_password', 'Demo1234!');
|
||||
$package = Package::query()
|
||||
->where('type', 'reseller')
|
||||
->orderBy('price')
|
||||
->first()
|
||||
?? Package::query()->orderBy('price')->first();
|
||||
|
||||
if (! $package) {
|
||||
$this->command?->warn('Skipped DemoTenantSeeder: no packages available.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$user = User::query()->firstOrCreate(
|
||||
['email' => $email],
|
||||
[
|
||||
'username' => 'tenant-demo',
|
||||
'password' => Hash::make($password),
|
||||
'first_name' => 'Demo',
|
||||
'last_name' => 'Tenant',
|
||||
'address' => 'Demo Straße 1, 12345 Musterstadt',
|
||||
'phone' => '+49 123 456789',
|
||||
'role' => 'tenant_admin',
|
||||
'pending_purchase' => false,
|
||||
'email_verified_at' => now(),
|
||||
]
|
||||
);
|
||||
|
||||
if (! $user->email_verified_at) {
|
||||
$user->forceFill(['email_verified_at' => now()])->save();
|
||||
}
|
||||
|
||||
if ($user->role !== 'tenant_admin') {
|
||||
$user->forceFill(['role' => 'tenant_admin'])->save();
|
||||
}
|
||||
|
||||
$tenant = Tenant::query()->firstOrCreate(
|
||||
['slug' => 'demo-tenant'],
|
||||
[
|
||||
'user_id' => $user->id,
|
||||
'name' => 'Demo Tenant',
|
||||
'email' => $user->email,
|
||||
'is_active' => true,
|
||||
'is_suspended' => false,
|
||||
'event_credits_balance' => 0,
|
||||
'subscription_tier' => $package->type,
|
||||
'subscription_status' => 'active',
|
||||
'settings' => [
|
||||
'contact_email' => $user->email,
|
||||
'branding' => [
|
||||
'logo_url' => null,
|
||||
'primary_color' => '#f43f5e',
|
||||
'secondary_color' => '#1f2937',
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
if ($tenant->wasRecentlyCreated && ! $tenant->slug) {
|
||||
$tenant->forceFill(['slug' => Str::slug('demo-tenant-'. $tenant->getKey())])->save();
|
||||
}
|
||||
|
||||
if ($user->tenant_id !== $tenant->id) {
|
||||
$user->forceFill(['tenant_id' => $tenant->id])->save();
|
||||
}
|
||||
|
||||
TenantPackage::query()->updateOrCreate(
|
||||
[
|
||||
'tenant_id' => $tenant->id,
|
||||
'package_id' => $package->id,
|
||||
],
|
||||
[
|
||||
'price' => $package->price,
|
||||
'active' => true,
|
||||
'purchased_at' => now()->subDays(7),
|
||||
'expires_at' => now()->addYear(),
|
||||
'used_events' => 0,
|
||||
]
|
||||
);
|
||||
|
||||
PackagePurchase::query()->updateOrCreate(
|
||||
[
|
||||
'tenant_id' => $tenant->id,
|
||||
'package_id' => $package->id,
|
||||
'provider_id' => 'demo-seed',
|
||||
],
|
||||
[
|
||||
'price' => $package->price,
|
||||
'type' => $package->type === 'reseller' ? 'reseller_subscription' : 'endcustomer_event',
|
||||
'purchased_at' => now()->subDays(7),
|
||||
'metadata' => [
|
||||
'seeded' => true,
|
||||
'note' => 'Demo tenant seed purchase',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->command?->info(sprintf(
|
||||
'Demo tenant ready. Login with %s / %s',
|
||||
$email,
|
||||
$password
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user