Initialize repo and add session changes (2025-09-08)
This commit is contained in:
97
app/Console/Commands/AddDummyTenantUser.php
Normal file
97
app/Console/Commands/AddDummyTenantUser.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Console\Attributes\AsCommand;
|
||||
|
||||
#[AsCommand(name: 'tenant:add-dummy')]
|
||||
class AddDummyTenantUser extends Command
|
||||
{
|
||||
protected $signature = 'tenant:add-dummy
|
||||
{--email=demo@example.com}
|
||||
{--password=secret123!}
|
||||
{--tenant="Demo Tenant"}
|
||||
{--name="Demo Admin"}
|
||||
{--update-password : Overwrite password if user already exists}
|
||||
';
|
||||
protected $description = 'Create a demo tenant and a tenant user with given credentials.';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$email = (string) $this->option('email');
|
||||
$password = (string) $this->option('password');
|
||||
$tenantName = (string) $this->option('tenant');
|
||||
$userName = (string) $this->option('name');
|
||||
|
||||
// Pre-flight checks for common failures
|
||||
if (! Schema::hasTable('users')) {
|
||||
$this->error("Table 'users' does not exist. Run: php artisan migrate");
|
||||
return self::FAILURE;
|
||||
}
|
||||
if (! Schema::hasTable('tenants')) {
|
||||
$this->error("Table 'tenants' does not exist. Run: php artisan migrate");
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// Create or fetch tenant
|
||||
$slug = Str::slug($tenantName ?: 'demo-tenant');
|
||||
/** @var Tenant $tenant */
|
||||
$tenant = Tenant::query()->where('slug', $slug)->first();
|
||||
if (! $tenant) {
|
||||
$tenant = new Tenant();
|
||||
$tenant->name = $tenantName;
|
||||
$tenant->slug = $slug;
|
||||
$tenant->domain = null;
|
||||
$tenant->contact_name = $userName;
|
||||
$tenant->contact_email = $email;
|
||||
$tenant->contact_phone = null;
|
||||
$tenant->event_credits_balance = 1;
|
||||
$tenant->max_photos_per_event = 500;
|
||||
$tenant->max_storage_mb = 1024;
|
||||
$tenant->features = ['custom_branding' => false];
|
||||
$tenant->save();
|
||||
}
|
||||
|
||||
// Create or fetch user
|
||||
/** @var User $user */
|
||||
$user = User::query()->where('email', $email)->first();
|
||||
$updatePassword = (bool) $this->option('update-password');
|
||||
if (! $user) {
|
||||
$user = new User();
|
||||
if (Schema::hasColumn($user->getTable(), 'name')) $user->name = $userName;
|
||||
$user->email = $email;
|
||||
$user->password = Hash::make($password);
|
||||
} else if ($updatePassword) {
|
||||
$user->password = Hash::make($password);
|
||||
}
|
||||
if (Schema::hasColumn($user->getTable(), 'tenant_id')) {
|
||||
$user->tenant_id = $tenant->id;
|
||||
}
|
||||
if (Schema::hasColumn($user->getTable(), 'role')) {
|
||||
$user->role = 'tenant_admin';
|
||||
}
|
||||
$user->save();
|
||||
|
||||
DB::commit();
|
||||
} catch (\Throwable $e) {
|
||||
DB::rollBack();
|
||||
$this->error('Failed: '.$e->getMessage());
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->info('Dummy tenant user created/updated.');
|
||||
$this->line('Tenant: '.$tenant->name.' (#'.$tenant->id.')');
|
||||
$this->line('Email: '.$email);
|
||||
$this->line('Password: '.$password);
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
85
app/Console/Commands/AttachDemoEvent.php
Normal file
85
app/Console/Commands/AttachDemoEvent.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Attributes\AsCommand;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
#[AsCommand(name: 'tenant:attach-demo-event')]
|
||||
class AttachDemoEvent extends Command
|
||||
{
|
||||
protected $signature = 'tenant:attach-demo-event
|
||||
{--tenant-email=demo@example.com : Email of tenant admin user to locate tenant}
|
||||
{--tenant-slug= : Tenant slug (overrides tenant-email lookup)}
|
||||
{--event-id= : Event ID}
|
||||
{--event-slug= : Event slug}
|
||||
';
|
||||
|
||||
protected $description = 'Attach an existing demo event to a tenant (by email or slug). Safe and idempotent.';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
if (! \Illuminate\Support\Facades\Schema::hasTable('events')) {
|
||||
$this->error("Table 'events' does not exist. Run: php artisan migrate");
|
||||
return self::FAILURE;
|
||||
}
|
||||
if (! \Illuminate\Support\Facades\Schema::hasColumn('events', 'tenant_id')) {
|
||||
$this->error("Column 'events.tenant_id' does not exist. Add it and rerun. Suggested: create a migration to add a nullable foreignId to tenants.");
|
||||
return self::FAILURE;
|
||||
}
|
||||
$tenant = null;
|
||||
if ($slug = $this->option('tenant-slug')) {
|
||||
$tenant = Tenant::where('slug', $slug)->first();
|
||||
}
|
||||
if (! $tenant) {
|
||||
$email = (string) $this->option('tenant-email');
|
||||
/** @var User|null $user */
|
||||
$user = User::where('email', $email)->first();
|
||||
if ($user && $user->tenant_id) {
|
||||
$tenant = Tenant::find($user->tenant_id);
|
||||
}
|
||||
}
|
||||
if (! $tenant) {
|
||||
$this->error('Tenant not found. Provide --tenant-slug or a user with tenant_id via --tenant-email.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$event = null;
|
||||
if ($id = $this->option('event-id')) {
|
||||
$event = Event::find($id);
|
||||
} elseif ($slug = $this->option('event-slug')) {
|
||||
$event = Event::where('slug', $slug)->first();
|
||||
} else {
|
||||
// Heuristics: first event without tenant, or a demo wedding by slug/name
|
||||
$event = Event::whereNull('tenant_id')->first();
|
||||
if (! $event) {
|
||||
$event = Event::where('slug', 'like', '%demo%')->where('slug', 'like', '%wedding%')->first();
|
||||
}
|
||||
if (! $event) {
|
||||
// Try JSON name contains "Demo" or "Wedding"
|
||||
$event = Event::where('name', 'like', '%Demo%')->orWhere('name', 'like', '%Wedding%')->first();
|
||||
}
|
||||
}
|
||||
|
||||
if (! $event) {
|
||||
$this->error('Event not found. Provide --event-id or --event-slug.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// Idempotent update
|
||||
if ((int) $event->tenant_id === (int) $tenant->id) {
|
||||
$this->info("Event #{$event->id} already attached to tenant #{$tenant->id} ({$tenant->slug}).");
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$event->tenant_id = $tenant->id;
|
||||
$event->save();
|
||||
|
||||
$this->info("Attached event #{$event->id} ({$event->slug}) to tenant #{$tenant->id} ({$tenant->slug}).");
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
53
app/Console/Commands/BackfillThumbnails.php
Normal file
53
app/Console/Commands/BackfillThumbnails.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Support\ImageHelper;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class BackfillThumbnails extends Command
|
||||
{
|
||||
protected $signature = 'media:backfill-thumbnails {--limit=500}';
|
||||
protected $description = 'Generate thumbnails for photos missing thumbnail_path or where thumbnail equals original.';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$limit = (int) $this->option('limit');
|
||||
$rows = DB::table('photos')
|
||||
->select(['id','event_id','file_path','thumbnail_path'])
|
||||
->orderBy('id')
|
||||
->limit($limit)
|
||||
->get();
|
||||
$count = 0;
|
||||
foreach ($rows as $r) {
|
||||
$orig = $this->relativeFromUrl((string)$r->file_path);
|
||||
$thumb = (string)($r->thumbnail_path ?? '');
|
||||
if ($thumb && $thumb !== $r->file_path) continue; // already set to different thumb
|
||||
if (! $orig) continue;
|
||||
$baseName = pathinfo($orig, PATHINFO_FILENAME);
|
||||
$destRel = "events/{$r->event_id}/photos/thumbs/{$baseName}_thumb.jpg";
|
||||
$made = ImageHelper::makeThumbnailOnDisk('public', $orig, $destRel, 640, 82);
|
||||
if ($made) {
|
||||
$url = Storage::url($made);
|
||||
DB::table('photos')->where('id', $r->id)->update(['thumbnail_path' => $url, 'updated_at' => now()]);
|
||||
$count++;
|
||||
$this->line("Photo {$r->id}: thumb created");
|
||||
}
|
||||
}
|
||||
$this->info("Done. Thumbnails generated: {$count}");
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function relativeFromUrl(string $url): ?string
|
||||
{
|
||||
// Assume Storage::url maps to /storage/*
|
||||
$p = parse_url($url, PHP_URL_PATH) ?? '';
|
||||
if (str_starts_with($p, '/storage/')) {
|
||||
return substr($p, strlen('/storage/'));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user