feat: update to new dashboard permissions format

Replace flat nav[] with nav_folder/pages/permissions structure.
Update routes to use app.access + permission: middleware groups.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joel Wedemire
2026-04-09 21:22:27 -07:00
parent bce98c0d4b
commit a66f61c638
2 changed files with 59 additions and 48 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "dashboard/ticketing", "name": "dashboard/ticketing",
"description": "Ticketing snap-in for dashboard-shell", "description": "Help desk ticketing snap-in for the Dashboard platform",
"version": "1.0.0", "version": "1.0.0",
"type": "library", "type": "library",
"require": { "require": {
@@ -19,21 +19,21 @@
"providers": ["Dashboard\\Ticketing\\TicketingServiceProvider"] "providers": ["Dashboard\\Ticketing\\TicketingServiceProvider"]
}, },
"dashboard": { "dashboard": {
"nav": [ "nav_folder": {
{
"label": "Help Desk", "label": "Help Desk",
"route_name": "ticketing.index",
"icon": "ticket", "icon": "ticket",
"sort_order": 40, "sort_order": 40
"roles": ["admin", "staff", "student"]
}, },
{ "pages": [
"label": "My Tickets", { "label": "All Tickets", "route_name": "ticketing.index", "icon": "ticket", "permission": "ticketing.manage", "sort_order": 1 },
"route_name": "ticketing.my-tickets", { "label": "My Tickets", "route_name": "ticketing.my-tickets", "icon": "inbox-stack", "permission": "ticketing.view", "sort_order": 2 },
"icon": "inbox-stack", { "label": "Settings", "route_name": "ticketing.settings", "icon": "cog-6-tooth", "permission": "ticketing.settings","sort_order": 99 }
"sort_order": 41, ],
"roles": ["admin", "staff", "student"] "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" }
] ]
} }
} }

View File

@@ -6,11 +6,38 @@ use Dashboard\Ticketing\Http\Controllers\TicketMessageController;
use Dashboard\Ticketing\Http\Controllers\TicketingSettingsController; use Dashboard\Ticketing\Http\Controllers\TicketingSettingsController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
Route::middleware(['web', 'auth', 'app.access:ticketing'])->prefix('app/ticketing')->name('ticketing.')->group(function () { Route::middleware(['web', 'auth', 'app.access:ticketing'])
// Submitter portal (must come before /{ticket} to avoid conflict) ->prefix('app/ticketing')
Route::get('/my-tickets', [TicketController::class, 'myTickets'])->name('my-tickets'); ->name('ticketing.')
->group(function () {
// Settings // ── 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');
// ── 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');
});
// ── 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');
});
// ── 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');
});
// ── Requires settings permission ───────────────────────────────────────
Route::middleware('permission:ticketing.settings')->group(function () {
Route::get('/settings', [TicketingSettingsController::class, 'index']) ->name('settings'); Route::get('/settings', [TicketingSettingsController::class, 'index']) ->name('settings');
Route::post('/settings/groups', [TicketingSettingsController::class, 'storeGroup']) ->name('settings.groups.store'); Route::post('/settings/groups', [TicketingSettingsController::class, 'storeGroup']) ->name('settings.groups.store');
Route::put('/settings/groups/{group}', [TicketingSettingsController::class, 'updateGroup']) ->name('settings.groups.update'); Route::put('/settings/groups/{group}', [TicketingSettingsController::class, 'updateGroup']) ->name('settings.groups.update');
@@ -25,21 +52,5 @@ Route::middleware(['web', 'auth', 'app.access:ticketing'])->prefix('app/ticketin
Route::post('/settings/email', [TicketingSettingsController::class, 'storeEmailConnection'])->name('settings.email.store'); Route::post('/settings/email', [TicketingSettingsController::class, 'storeEmailConnection'])->name('settings.email.store');
Route::put('/settings/email/{connection}', [TicketingSettingsController::class, 'updateEmailConnection'])->name('settings.email.update'); Route::put('/settings/email/{connection}', [TicketingSettingsController::class, 'updateEmailConnection'])->name('settings.email.update');
Route::delete('/settings/email/{connection}', [TicketingSettingsController::class, 'destroyEmailConnection'])->name('settings.email.destroy'); Route::delete('/settings/email/{connection}', [TicketingSettingsController::class, 'destroyEmailConnection'])->name('settings.email.destroy');
});
// Ticket routes
Route::get('/', [TicketController::class, 'index'])->name('index');
Route::get('/create', [TicketController::class, 'create'])->name('create');
Route::post('/', [TicketController::class, 'store'])->name('store');
// Attachment show (before /{ticket} wildcard)
Route::get('/attachments/{attachment}', [TicketAttachmentController::class, 'show'])->name('attachments.show');
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 & attachments
Route::post('/{ticket}/messages', [TicketMessageController::class, 'store'])->name('messages.store');
Route::post('/{ticket}/attachments', [TicketAttachmentController::class, 'store'])->name('attachments.store');
}); });