diff --git a/composer.json b/composer.json index 4de79dd..c0e2a9a 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "dashboard/ticketing", - "description": "Ticketing snap-in for dashboard-shell", + "description": "Help desk ticketing snap-in for the Dashboard platform", "version": "1.0.0", "type": "library", "require": { @@ -19,21 +19,21 @@ "providers": ["Dashboard\\Ticketing\\TicketingServiceProvider"] }, "dashboard": { - "nav": [ - { - "label": "Help Desk", - "route_name": "ticketing.index", - "icon": "ticket", - "sort_order": 40, - "roles": ["admin", "staff", "student"] - }, - { - "label": "My Tickets", - "route_name": "ticketing.my-tickets", - "icon": "inbox-stack", - "sort_order": 41, - "roles": ["admin", "staff", "student"] - } + "nav_folder": { + "label": "Help Desk", + "icon": "ticket", + "sort_order": 40 + }, + "pages": [ + { "label": "All Tickets", "route_name": "ticketing.index", "icon": "ticket", "permission": "ticketing.manage", "sort_order": 1 }, + { "label": "My Tickets", "route_name": "ticketing.my-tickets", "icon": "inbox-stack", "permission": "ticketing.view", "sort_order": 2 }, + { "label": "Settings", "route_name": "ticketing.settings", "icon": "cog-6-tooth", "permission": "ticketing.settings","sort_order": 99 } + ], + "permissions": [ + { "key": "ticketing.view", "label": "View My Tickets", "description": "Submit tickets and view own ticket history" }, + { "key": "ticketing.create", "label": "Create Tickets", "description": "Create tickets on behalf of other users" }, + { "key": "ticketing.manage", "label": "Manage Tickets", "description": "View, assign, and resolve all tickets" }, + { "key": "ticketing.settings", "label": "Manage Settings", "description": "Configure groups, priorities, and integrations" } ] } } diff --git a/src/routes/ticketing.php b/src/routes/ticketing.php index 0668899..45e0246 100644 --- a/src/routes/ticketing.php +++ b/src/routes/ticketing.php @@ -6,40 +6,51 @@ use Dashboard\Ticketing\Http\Controllers\TicketMessageController; use Dashboard\Ticketing\Http\Controllers\TicketingSettingsController; use Illuminate\Support\Facades\Route; -Route::middleware(['web', 'auth', 'app.access:ticketing'])->prefix('app/ticketing')->name('ticketing.')->group(function () { - // Submitter portal (must come before /{ticket} to avoid conflict) - Route::get('/my-tickets', [TicketController::class, 'myTickets'])->name('my-tickets'); +Route::middleware(['web', 'auth', 'app.access:ticketing']) + ->prefix('app/ticketing') + ->name('ticketing.') + ->group(function () { - // Settings - Route::get('/settings', [TicketingSettingsController::class, 'index'])->name('settings'); - Route::post('/settings/groups', [TicketingSettingsController::class, 'storeGroup'])->name('settings.groups.store'); - Route::put('/settings/groups/{group}', [TicketingSettingsController::class, 'updateGroup'])->name('settings.groups.update'); - Route::post('/settings/agents', [TicketingSettingsController::class, 'storeAgent'])->name('settings.agents.store'); - Route::delete('/settings/agents/{access}', [TicketingSettingsController::class, 'destroyAgent'])->name('settings.agents.destroy'); - Route::post('/settings/priorities', [TicketingSettingsController::class, 'storePriority'])->name('settings.priorities.store'); - Route::put('/settings/priorities/{priority}', [TicketingSettingsController::class, 'updatePriority'])->name('settings.priorities.update'); - Route::delete('/settings/priorities/{priority}', [TicketingSettingsController::class, 'destroyPriority'])->name('settings.priorities.destroy'); - Route::post('/settings/projects', [TicketingSettingsController::class, 'storeProject'])->name('settings.projects.store'); - Route::put('/settings/projects/{project}', [TicketingSettingsController::class, 'updateProject'])->name('settings.projects.update'); - Route::delete('/settings/projects/{project}', [TicketingSettingsController::class, 'destroyProject'])->name('settings.projects.destroy'); - Route::post('/settings/email', [TicketingSettingsController::class, 'storeEmailConnection'])->name('settings.email.store'); - Route::put('/settings/email/{connection}', [TicketingSettingsController::class, 'updateEmailConnection'])->name('settings.email.update'); - Route::delete('/settings/email/{connection}', [TicketingSettingsController::class, 'destroyEmailConnection'])->name('settings.email.destroy'); + // ── Visible to anyone with module access (ticketing.view minimum) ────── + Route::get('/my-tickets', [TicketController::class, 'myTickets'])->name('my-tickets'); + Route::get('/attachments/{attachment}', [TicketAttachmentController::class, 'show'])->name('attachments.show'); - // Ticket routes - Route::get('/', [TicketController::class, 'index'])->name('index'); - Route::get('/create', [TicketController::class, 'create'])->name('create'); - Route::post('/', [TicketController::class, 'store'])->name('store'); + // ── Create/view tickets ──────────────────────────────────────────────── + Route::middleware('permission:ticketing.view,ticketing.manage')->group(function () { + Route::get('/create', [TicketController::class, 'create'])->name('create'); + Route::post('/', [TicketController::class, 'store']) ->name('store'); + Route::get('/{ticket}', [TicketController::class, 'show']) ->name('show'); + }); - // Attachment show (before /{ticket} wildcard) - Route::get('/attachments/{attachment}', [TicketAttachmentController::class, 'show'])->name('attachments.show'); + // ── Requires manage permission (agents / staff) ──────────────────────── + Route::middleware('permission:ticketing.manage')->group(function () { + Route::get('/', [TicketController::class, 'index']) ->name('index'); + Route::get('/{ticket}/edit', [TicketController::class, 'edit']) ->name('edit'); + Route::put('/{ticket}', [TicketController::class, 'update'])->name('update'); + Route::delete('/{ticket}', [TicketController::class, 'destroy'])->name('destroy'); + }); - Route::get('/{ticket}', [TicketController::class, 'show'])->name('show'); - Route::get('/{ticket}/edit', [TicketController::class, 'edit'])->name('edit'); - Route::put('/{ticket}', [TicketController::class, 'update'])->name('update'); - Route::delete('/{ticket}', [TicketController::class, 'destroy'])->name('destroy'); + // ── Messages and attachments (view or manage) ────────────────────────── + Route::middleware('permission:ticketing.view,ticketing.manage')->group(function () { + Route::post('/{ticket}/messages', [TicketMessageController::class, 'store']) ->name('messages.store'); + Route::post('/{ticket}/attachments', [TicketAttachmentController::class, 'store'])->name('attachments.store'); + }); - // Messages & attachments - Route::post('/{ticket}/messages', [TicketMessageController::class, 'store'])->name('messages.store'); - Route::post('/{ticket}/attachments', [TicketAttachmentController::class, 'store'])->name('attachments.store'); -}); + // ── Requires settings permission ─────────────────────────────────────── + Route::middleware('permission:ticketing.settings')->group(function () { + Route::get('/settings', [TicketingSettingsController::class, 'index']) ->name('settings'); + Route::post('/settings/groups', [TicketingSettingsController::class, 'storeGroup']) ->name('settings.groups.store'); + Route::put('/settings/groups/{group}', [TicketingSettingsController::class, 'updateGroup']) ->name('settings.groups.update'); + Route::post('/settings/agents', [TicketingSettingsController::class, 'storeAgent']) ->name('settings.agents.store'); + Route::delete('/settings/agents/{access}', [TicketingSettingsController::class, 'destroyAgent']) ->name('settings.agents.destroy'); + Route::post('/settings/priorities', [TicketingSettingsController::class, 'storePriority']) ->name('settings.priorities.store'); + Route::put('/settings/priorities/{priority}', [TicketingSettingsController::class, 'updatePriority']) ->name('settings.priorities.update'); + Route::delete('/settings/priorities/{priority}', [TicketingSettingsController::class, 'destroyPriority']) ->name('settings.priorities.destroy'); + Route::post('/settings/projects', [TicketingSettingsController::class, 'storeProject']) ->name('settings.projects.store'); + Route::put('/settings/projects/{project}', [TicketingSettingsController::class, 'updateProject']) ->name('settings.projects.update'); + Route::delete('/settings/projects/{project}', [TicketingSettingsController::class, 'destroyProject']) ->name('settings.projects.destroy'); + Route::post('/settings/email', [TicketingSettingsController::class, 'storeEmailConnection'])->name('settings.email.store'); + Route::put('/settings/email/{connection}', [TicketingSettingsController::class, 'updateEmailConnection'])->name('settings.email.update'); + Route::delete('/settings/email/{connection}', [TicketingSettingsController::class, 'destroyEmailConnection'])->name('settings.email.destroy'); + }); + });