added "members" for an event that help the admins to moderate. members must be invited via email.

This commit is contained in:
Codex Agent
2025-11-09 22:24:40 +01:00
parent 082b78cd43
commit 7ec3db9c59
23 changed files with 836 additions and 101 deletions

View File

@@ -8,6 +8,7 @@ use App\Http\Controllers\Api\Tenant\EmotionController;
use App\Http\Controllers\Api\Tenant\EventController;
use App\Http\Controllers\Api\Tenant\EventJoinTokenController;
use App\Http\Controllers\Api\Tenant\EventJoinTokenLayoutController;
use App\Http\Controllers\Api\Tenant\EventMemberController;
use App\Http\Controllers\Api\Tenant\EventTypeController;
use App\Http\Controllers\Api\Tenant\NotificationLogController;
use App\Http\Controllers\Api\Tenant\OnboardingController;
@@ -80,29 +81,46 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
->name('gallery.photos.asset');
});
Route::middleware(['auth:sanctum', 'tenant.admin', 'tenant.isolation', 'throttle:tenant-api'])->prefix('tenant')->group(function () {
Route::get('profile', [ProfileController::class, 'show'])->name('tenant.profile.show');
Route::put('profile', [ProfileController::class, 'update'])->name('tenant.profile.update');
Route::get('onboarding', [OnboardingController::class, 'show'])->name('tenant.onboarding.show');
Route::post('onboarding', [OnboardingController::class, 'store'])->name('tenant.onboarding.store');
Route::get('me', [TenantAdminTokenController::class, 'legacyTenantMe'])->name('tenant.me');
Route::get('dashboard', DashboardController::class)->name('tenant.dashboard');
Route::middleware(['auth:sanctum', 'tenant.collaborator', 'tenant.isolation', 'throttle:tenant-api'])->prefix('tenant')->group(function () {
Route::get('profile', [ProfileController::class, 'show'])
->middleware('tenant.admin')
->name('tenant.profile.show');
Route::put('profile', [ProfileController::class, 'update'])
->middleware('tenant.admin')
->name('tenant.profile.update');
Route::get('onboarding', [OnboardingController::class, 'show'])
->middleware('tenant.admin')
->name('tenant.onboarding.show');
Route::post('onboarding', [OnboardingController::class, 'store'])
->middleware('tenant.admin')
->name('tenant.onboarding.store');
Route::get('me', [TenantAdminTokenController::class, 'legacyTenantMe'])
->name('tenant.me');
Route::get('dashboard', DashboardController::class)
->middleware('tenant.admin')
->name('tenant.dashboard');
Route::get('event-types', EventTypeController::class)->name('tenant.event-types.index');
Route::apiResource('events', EventController::class)
->only(['index', 'show', 'destroy'])
->parameters(['events' => 'event:slug']);
Route::get('events', [EventController::class, 'index'])
->name('tenant.events.index');
Route::get('events/{event:slug}', [EventController::class, 'show'])
->name('tenant.events.show');
Route::delete('events/{event:slug}', [EventController::class, 'destroy'])
->middleware('tenant.admin')
->name('tenant.events.destroy');
Route::middleware(['package.check', 'credit.check'])->group(function () {
Route::middleware(['package.check', 'credit.check', 'tenant.admin'])->group(function () {
Route::post('events', [EventController::class, 'store'])->name('tenant.events.store');
Route::match(['put', 'patch'], 'events/{event:slug}', [EventController::class, 'update'])->name('tenant.events.update');
});
Route::prefix('events/{event:slug}')->scopeBindings()->group(function () {
Route::get('stats', [EventController::class, 'stats'])->name('tenant.events.stats');
Route::post('toggle', [EventController::class, 'toggle'])->name('tenant.events.toggle');
Route::post('invites', [EventController::class, 'createInvite'])->name('tenant.events.invites');
Route::get('toolkit', [EventController::class, 'toolkit'])->name('tenant.events.toolkit');
Route::middleware('tenant.admin')->group(function () {
Route::get('stats', [EventController::class, 'stats'])->name('tenant.events.stats');
Route::post('toggle', [EventController::class, 'toggle'])->name('tenant.events.toggle');
Route::post('invites', [EventController::class, 'createInvite'])->name('tenant.events.invites');
Route::get('toolkit', [EventController::class, 'toolkit'])->name('tenant.events.toolkit');
});
Route::prefix('join-tokens')->group(function () {
Route::get('/', [EventJoinTokenController::class, 'index'])->name('tenant.events.join-tokens.index');
@@ -122,21 +140,37 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
->name('tenant.events.join-tokens.destroy');
});
Route::get('photos', [PhotoController::class, 'index'])->name('tenant.events.photos.index');
Route::post('photos', [PhotoController::class, 'store'])->name('tenant.events.photos.store');
Route::get('photos/{photo}', [PhotoController::class, 'show'])->name('tenant.events.photos.show');
Route::patch('photos/{photo}', [PhotoController::class, 'update'])->name('tenant.events.photos.update');
Route::delete('photos/{photo}', [PhotoController::class, 'destroy'])->name('tenant.events.photos.destroy');
Route::post('photos/{photo}/feature', [PhotoController::class, 'feature'])->name('tenant.events.photos.feature');
Route::post('photos/{photo}/unfeature', [PhotoController::class, 'unfeature'])->name('tenant.events.photos.unfeature');
Route::post('photos/bulk-approve', [PhotoController::class, 'bulkApprove'])->name('tenant.events.photos.bulk-approve');
Route::post('photos/bulk-reject', [PhotoController::class, 'bulkReject'])->name('tenant.events.photos.bulk-reject');
Route::get('photos/moderation', [PhotoController::class, 'forModeration'])->name('tenant.events.photos.for-moderation');
Route::get('photos/stats', [PhotoController::class, 'stats'])->name('tenant.events.photos.stats');
Route::prefix('photos')->group(function () {
Route::get('/', [PhotoController::class, 'index'])->name('tenant.events.photos.index');
Route::post('/', [PhotoController::class, 'store'])->name('tenant.events.photos.store');
Route::get('{photo}', [PhotoController::class, 'show'])->name('tenant.events.photos.show');
Route::patch('{photo}', [PhotoController::class, 'update'])->name('tenant.events.photos.update');
Route::delete('{photo}', [PhotoController::class, 'destroy'])->name('tenant.events.photos.destroy');
Route::post('{photo}/feature', [PhotoController::class, 'feature'])->name('tenant.events.photos.feature');
Route::post('{photo}/unfeature', [PhotoController::class, 'unfeature'])->name('tenant.events.photos.unfeature');
Route::post('bulk-approve', [PhotoController::class, 'bulkApprove'])->name('tenant.events.photos.bulk-approve');
Route::post('bulk-reject', [PhotoController::class, 'bulkReject'])->name('tenant.events.photos.bulk-reject');
Route::get('moderation', [PhotoController::class, 'forModeration'])->name('tenant.events.photos.for-moderation');
Route::get('stats', [PhotoController::class, 'stats'])->name('tenant.events.photos.stats');
});
Route::get('members', [EventMemberController::class, 'index'])
->middleware('tenant.admin')
->name('tenant.events.members.index');
Route::post('members', [EventMemberController::class, 'store'])
->middleware('tenant.admin')
->name('tenant.events.members.store');
Route::delete('members/{member}', [EventMemberController::class, 'destroy'])
->middleware('tenant.admin')
->whereNumber('member')
->name('tenant.events.members.destroy');
});
Route::post('events/bulk-status', [EventController::class, 'bulkUpdateStatus'])->name('tenant.events.bulk-status');
Route::get('events/search', [EventController::class, 'search'])->name('tenant.events.search');
Route::post('events/bulk-status', [EventController::class, 'bulkUpdateStatus'])
->middleware('tenant.admin')
->name('tenant.events.bulk-status');
Route::get('events/search', [EventController::class, 'search'])
->name('tenant.events.search');
Route::apiResource('tasks', TaskController::class);
Route::post('tasks/{task}/assign-event/{event}', [TaskController::class, 'assignToEvent'])
@@ -155,11 +189,13 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
Route::post('task-collections/{collection}/activate', [TaskCollectionController::class, 'activate'])
->name('tenant.task-collections.activate');
Route::get('emotions', [EmotionController::class, 'index'])->name('tenant.emotions.index');
Route::post('emotions', [EmotionController::class, 'store'])->name('tenant.emotions.store');
Route::patch('emotions/{emotion}', [EmotionController::class, 'update'])->name('tenant.emotions.update');
Route::middleware('tenant.admin')->group(function () {
Route::get('emotions', [EmotionController::class, 'index'])->name('tenant.emotions.index');
Route::post('emotions', [EmotionController::class, 'store'])->name('tenant.emotions.store');
Route::patch('emotions/{emotion}', [EmotionController::class, 'update'])->name('tenant.emotions.update');
});
Route::prefix('settings')->group(function () {
Route::prefix('settings')->middleware('tenant.admin')->group(function () {
Route::get('/', [SettingsController::class, 'index'])
->name('tenant.settings.index');
Route::post('/', [SettingsController::class, 'update'])
@@ -175,9 +211,10 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
});
Route::get('notifications/logs', [NotificationLogController::class, 'index'])
->middleware('tenant.admin')
->name('tenant.notifications.logs.index');
Route::prefix('credits')->group(function () {
Route::prefix('credits')->middleware('tenant.admin')->group(function () {
Route::get('balance', [CreditController::class, 'balance'])->name('tenant.credits.balance');
Route::get('ledger', [CreditController::class, 'ledger'])->name('tenant.credits.ledger');
Route::get('history', [CreditController::class, 'history'])->name('tenant.credits.history');
@@ -185,7 +222,7 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
Route::post('sync', [CreditController::class, 'sync'])->name('tenant.credits.sync');
});
Route::prefix('packages')->group(function () {
Route::prefix('packages')->middleware('tenant.admin')->group(function () {
Route::get('/', [PackageController::class, 'index'])->name('packages.index');
Route::post('/purchase', [PackageController::class, 'purchase'])->name('packages.purchase');
Route::post('/payment-intent', [PackageController::class, 'createPaymentIntent'])->name('packages.payment-intent');
@@ -194,11 +231,12 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
Route::post('/paddle-checkout', [PackageController::class, 'createPaddleCheckout'])->name('packages.paddle-checkout');
});
Route::prefix('tenant/packages')->group(function () {
Route::prefix('tenant/packages')->middleware('tenant.admin')->group(function () {
Route::get('/', [TenantPackageController::class, 'index'])->name('tenant.packages.index');
});
Route::get('tenant/billing/transactions', [TenantBillingController::class, 'transactions'])
->middleware('tenant.admin')
->name('tenant.billing.transactions');
Route::post('feedback', [TenantFeedbackController::class, 'store'])