Implement multi-tenancy support with OAuth2 authentication for tenant admins, Stripe integration for event purchases and credits ledger, new Filament resources for event purchases, updated API routes and middleware for tenant isolation and token guarding, added factories/seeders/migrations for new models (Tenant, EventPurchase, OAuth entities, etc.), enhanced tests, and documentation updates. Removed outdated DemoAchievementsSeeder.
This commit is contained in:
21
app/Http/Resources/Tenant/CreditLedgerResource.php
Normal file
21
app/Http/Resources/Tenant/CreditLedgerResource.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Tenant;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class CreditLedgerResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'delta' => $this->delta,
|
||||
'reason' => $this->reason,
|
||||
'note' => $this->note,
|
||||
'related_purchase_id' => $this->related_purchase_id,
|
||||
'created_at' => $this->created_at->toISOString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
24
app/Http/Resources/Tenant/EventPurchaseResource.php
Normal file
24
app/Http/Resources/Tenant/EventPurchaseResource.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Tenant;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class EventPurchaseResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'events_purchased' => $this->events_purchased,
|
||||
'amount' => $this->amount,
|
||||
'currency' => $this->currency,
|
||||
'provider' => $this->provider,
|
||||
'status' => $this->status,
|
||||
'external_receipt_id' => $this->external_receipt_id,
|
||||
'purchased_at' => $this->purchased_at ? $this->purchased_at->toISOString() : null,
|
||||
'created_at' => $this->created_at->toISOString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
56
app/Http/Resources/Tenant/EventResource.php
Normal file
56
app/Http/Resources/Tenant/EventResource.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Tenant;
|
||||
|
||||
use App\Http\Resources\Tenant\EventTypeResource;
|
||||
use App\Http\Resources\Tenant\PhotoResource;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class EventResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
|
||||
// Hide sensitive data for other tenants
|
||||
$showSensitive = $this->tenant_id === $tenantId;
|
||||
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'slug' => $this->slug,
|
||||
'description' => $this->description,
|
||||
'event_date' => $this->event_date ? $this->event_date->toISOString() : null,
|
||||
'location' => $this->location,
|
||||
'max_participants' => $this->max_participants,
|
||||
'current_participants' => $showSensitive ? $this->photos_count : null,
|
||||
'public_url' => $this->public_url,
|
||||
'custom_domain' => $showSensitive ? $this->custom_domain : null,
|
||||
'theme_color' => $this->theme_color,
|
||||
'status' => $showSensitive ? $this->status : 'published',
|
||||
'password_protected' => $this->password_protected,
|
||||
'features' => $this->features,
|
||||
'event_type' => new EventTypeResource($this->whenLoaded('eventType')),
|
||||
'photos' => PhotoResource::collection($this->whenLoaded('photos')),
|
||||
'tasks' => $showSensitive ? $this->whenLoaded('tasks') : [],
|
||||
'tenant' => $showSensitive ? [
|
||||
'id' => $this->tenant->id,
|
||||
'name' => $this->tenant->name,
|
||||
'event_credits_balance' => $this->tenant->event_credits_balance,
|
||||
] : null,
|
||||
'created_at' => $this->created_at->toISOString(),
|
||||
'updated_at' => $this->updated_at->toISOString(),
|
||||
'photo_count' => $this->photos_count,
|
||||
'like_count' => $this->photos->sum('likes_count'),
|
||||
'is_public' => $this->status === 'published' && !$this->password_protected,
|
||||
'public_share_url' => $showSensitive ? route('api.v1.events.show', ['slug' => $this->slug]) : null,
|
||||
'qr_code_url' => $showSensitive ? route('api.v1.events.qr', ['event' => $this->id]) : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
28
app/Http/Resources/Tenant/EventTypeResource.php
Normal file
28
app/Http/Resources/Tenant/EventTypeResource.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Tenant;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class EventTypeResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'icon' => $this->icon,
|
||||
'color' => $this->color,
|
||||
'is_active' => $this->is_active,
|
||||
'created_at' => $this->created_at->toISOString(),
|
||||
'updated_at' => $this->updated_at->toISOString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
58
app/Http/Resources/Tenant/PhotoResource.php
Normal file
58
app/Http/Resources/Tenant/PhotoResource.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Tenant;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class PhotoResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
$showSensitive = $this->event->tenant_id === $tenantId;
|
||||
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'filename' => $this->filename,
|
||||
'original_name' => $this->original_name,
|
||||
'mime_type' => $this->mime_type,
|
||||
'size' => $this->size,
|
||||
'url' => $showSensitive ? $this->getFullUrl() : $this->getThumbnailUrl(),
|
||||
'thumbnail_url' => $this->getThumbnailUrl(),
|
||||
'width' => $this->width,
|
||||
'height' => $this->height,
|
||||
'status' => $showSensitive ? $this->status : 'approved',
|
||||
'moderation_notes' => $showSensitive ? $this->moderation_notes : null,
|
||||
'likes_count' => $this->likes_count,
|
||||
'is_liked' => $showSensitive ? $this->isLikedByTenant($tenantId) : false,
|
||||
'uploaded_at' => $this->created_at->toISOString(),
|
||||
'event' => [
|
||||
'id' => $this->event->id,
|
||||
'name' => $this->event->name,
|
||||
'slug' => $this->event->slug,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full image URL
|
||||
*/
|
||||
private function getFullUrl(): string
|
||||
{
|
||||
return url("storage/events/{$this->event->slug}/photos/{$this->filename}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get thumbnail URL
|
||||
*/
|
||||
private function getThumbnailUrl(): string
|
||||
{
|
||||
return url("storage/events/{$this->event->slug}/thumbnails/{$this->filename}");
|
||||
}
|
||||
}
|
||||
42
app/Http/Resources/Tenant/TaskResource.php
Normal file
42
app/Http/Resources/Tenant/TaskResource.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Tenant;
|
||||
|
||||
use App\Http\Resources\Tenant\EventResource;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class TaskResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'title' => $this->title,
|
||||
'description' => $this->description,
|
||||
'priority' => $this->priority,
|
||||
'due_date' => $this->due_date?->toISOString(),
|
||||
'is_completed' => $this->is_completed,
|
||||
'collection_id' => $this->collection_id,
|
||||
'assigned_events_count' => $this->assignedEvents()->count(),
|
||||
// TaskCollectionResource wird später implementiert
|
||||
// 'collection' => $this->whenLoaded('taskCollection', function () {
|
||||
// return new TaskCollectionResource($this->taskCollection);
|
||||
// }),
|
||||
'assigned_events' => $this->whenLoaded('assignedEvents', function () {
|
||||
return EventResource::collection($this->assignedEvents);
|
||||
}),
|
||||
// UserResource wird später implementiert
|
||||
// 'assigned_to' => $this->whenLoaded('assignedTo', function () {
|
||||
// return new UserResource($this->assignedTo);
|
||||
// }),
|
||||
'created_at' => $this->created_at->toISOString(),
|
||||
'updated_at' => $this->updated_at->toISOString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user