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",
"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" }
]
}
}

View File

@@ -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');
});
});