move into sonardesk

This commit is contained in:
Mark Gregory
2026-10-12 14:50:13 +01:00
parent 5f0d2ceb72
commit 38b4a7406f
879 changed files with 24021 additions and 1 deletions
+6
View File
@@ -0,0 +1,6 @@
<?php
return [
'name' => 'Roles',
'enabled' => true,
];
@@ -0,0 +1,119 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
$tableNames = config('permission.table_names');
$columnNames = config('permission.column_names');
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
$modelMorphKey = $columnNames['model_morph_key'] ?? 'model_id';
throw_if(
empty($tableNames),
RuntimeException::class,
'The Spatie permission configuration could not be loaded.'
);
Schema::create($tableNames['permissions'], function (Blueprint $table): void {
$table->id();
$table->string('name');
$table->string('guard_name');
$table->timestamps();
$table->unique(['name', 'guard_name']);
});
Schema::create($tableNames['roles'], function (Blueprint $table): void {
$table->id();
$table->string('name');
$table->string('guard_name');
$table->timestamps();
$table->unique(['name', 'guard_name']);
});
Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use (
$tableNames,
$pivotPermission,
$modelMorphKey
): void {
$table->unsignedBigInteger($pivotPermission);
$table->string('model_type');
$table->unsignedBigInteger($modelMorphKey);
$table->index([$modelMorphKey, 'model_type'], 'model_has_permissions_model_id_model_type_index');
$table->foreign($pivotPermission)
->references('id')
->on($tableNames['permissions'])
->cascadeOnDelete();
$table->primary(
[$pivotPermission, $modelMorphKey, 'model_type'],
'model_has_permissions_permission_model_type_primary'
);
});
Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use (
$tableNames,
$pivotRole,
$modelMorphKey
): void {
$table->unsignedBigInteger($pivotRole);
$table->string('model_type');
$table->unsignedBigInteger($modelMorphKey);
$table->index([$modelMorphKey, 'model_type'], 'model_has_roles_model_id_model_type_index');
$table->foreign($pivotRole)
->references('id')
->on($tableNames['roles'])
->cascadeOnDelete();
$table->primary(
[$pivotRole, $modelMorphKey, 'model_type'],
'model_has_roles_role_model_type_primary'
);
});
Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use (
$tableNames,
$pivotRole,
$pivotPermission
): void {
$table->unsignedBigInteger($pivotPermission);
$table->unsignedBigInteger($pivotRole);
$table->foreign($pivotPermission)
->references('id')
->on($tableNames['permissions'])
->cascadeOnDelete();
$table->foreign($pivotRole)
->references('id')
->on($tableNames['roles'])
->cascadeOnDelete();
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
});
app('cache')->store(config('permission.cache.store') === 'default'
? null
: config('permission.cache.store'))
->forget(config('permission.cache.key'));
}
public function down(): void
{
$tableNames = config('permission.table_names');
Schema::dropIfExists($tableNames['role_has_permissions']);
Schema::dropIfExists($tableNames['model_has_roles']);
Schema::dropIfExists($tableNames['model_has_permissions']);
Schema::dropIfExists($tableNames['roles']);
Schema::dropIfExists($tableNames['permissions']);
}
};
@@ -0,0 +1,96 @@
<?php
namespace Modules\Roles\Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Spatie\Permission\PermissionRegistrar;
final class RolePermissionSeeder extends Seeder
{
public function run(): void
{
$registrar = app(PermissionRegistrar::class);
$registrar->forgetCachedPermissions();
$permissions = [
'administration.access',
'users.view',
'users.create',
'users.update',
'users.delete',
'roles.manage',
'settings.manage',
'audit.view',
'media.view',
'media.upload',
'media.update',
'media.delete',
'seo.manage',
'search.manage',
'themes.manage',
'pages.manage',
'menus.manage',
'redirects.manage',
'forms.manage',
'documents.manage',
'banners.manage',
'faq.manage',
'team.manage',
'testimonials.manage',
'blog.manage',
'news.manage',
'categories.manage',
'tags.manage',
'authors.manage',
'comments.moderate',
'crm.manage',
'newsletter.manage',
'events.manage',
'careers.manage',
'locations.manage',
'workflow.view',
'workflow.manage',
'workflow.review',
'localization.manage',
'localization.translate',
'sites.view',
'sites.manage',
'sites.assign',
'developer.access',
'api.view',
'api.manage',
'enterprise.view',
'enterprise.manage',
'commerce.view',
'commerce.manage',
'commerce.orders.manage',
'commerce.products.manage',
'security.view',
'security.manage',
'security.audit',
'automation.view',
'automation.manage',
'automation.execute',
'ai.view',
'ai.manage',
'ai.execute',
'analytics.view',
'analytics.manage',
'analytics.export',
'builder.view', 'builder.manage', 'builder.publish',
'marketplace.view', 'marketplace.install', 'marketplace.update', 'marketplace.remove',
'cloud-devops.view', 'cloud-devops.manage', 'cloud-devops.deploy', 'cloud-devops.rollback',
];
foreach ($permissions as $permission) {
Permission::findOrCreate($permission, 'web');
}
$administrator = Role::findOrCreate('admin', 'web');
$administrator->syncPermissions($permissions);
$registrar->forgetCachedPermissions();
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace Modules\Roles\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
final class RoleController extends Controller
{
public function index()
{
return view('roles::index', ['roles' => Role::withCount(['users', 'permissions'])->orderBy('name')->get()]);
}
public function create()
{
return view('roles::form', ['role' => new Role(['guard_name' => 'web']), 'permissions' => Permission::orderBy('name')->get()]);
}
public function store(Request $request)
{
$data = $this->validated($request);
$role = Role::create(['name' => $data['name'], 'guard_name' => 'web']);
$role->syncPermissions($data['permissions'] ?? []);
return redirect()->route('administration.roles.index')->with('status', 'Role created.');
}
public function edit(Role $role)
{
return view('roles::form', ['role' => $role->load('permissions'), 'permissions' => Permission::orderBy('name')->get()]);
}
public function update(Request $request, Role $role)
{
$data = $this->validated($request, $role);
$role->update(['name' => $data['name']]);
$role->syncPermissions($data['permissions'] ?? []);
return redirect()->route('administration.roles.index')->with('status', 'Role updated.');
}
public function destroy(Role $role)
{
abort_if($role->name === 'admin', 422, 'The administrator role cannot be deleted.');
$role->delete();
return back()->with('status', 'Role deleted.');
}
private function validated(Request $request, ?Role $role = null): array
{
return $request->validate(['name' => ['required', 'string', 'max:100', Rule::unique('roles', 'name')->ignore($role)], 'permissions' => ['array'], 'permissions.*' => ['string', 'exists:permissions,name']]);
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace Modules\Roles\Providers;
use Illuminate\Support\ServiceProvider;
use Modules\Roles\Support\ModuleInfo;
final class RolesServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->register(RouteServiceProvider::class);
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
}
public function boot(): void
{
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
$this->loadViewsFrom(module_path(ModuleInfo::name(), 'Resources/views'), ModuleInfo::nameLower());
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace Modules\Roles\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
final class RouteServiceProvider extends ServiceProvider
{
public function boot(): void
{
parent::boot();
$this->routes(function (): void {
Route::middleware('web')->group(module_path('Roles', 'Routes/web.php'));
});
}
}
+1
View File
@@ -0,0 +1 @@
<x-layouts.app :title="$role->exists ? __('Edit role') : __('Create role')"><div class="max-w-3xl space-y-6"><div><h1 class="text-2xl font-semibold">{{ $role->exists ? 'Edit role' : 'Create role' }}</h1></div><form method="POST" action="{{ $role->exists ? route('administration.roles.update',$role) : route('administration.roles.store') }}" class="space-y-6 rounded-xl border border-zinc-200 bg-white p-6 dark:border-zinc-700 dark:bg-zinc-900">@csrf @if($role->exists)@method('PUT')@endif<flux:input name="name" label="Name" :value="old('name',$role->name)" required/><div><div class="mb-3 font-medium">Permissions</div><div class="grid gap-3 sm:grid-cols-2">@foreach($permissions as $permission)<label class="flex items-center gap-3 rounded-lg border border-zinc-200 p-3 dark:border-zinc-700"><input type="checkbox" name="permissions[]" value="{{ $permission->name }}" @checked(in_array($permission->name,old('permissions',$role->exists ? $role->permissions->pluck('name')->all() : [])))><span class="text-sm">{{ $permission->name }}</span></label>@endforeach</div></div><div class="flex justify-end gap-2"><flux:button :href="route('administration.roles.index')">Cancel</flux:button><flux:button type="submit" variant="primary">Save</flux:button></div></form></div></x-layouts.app>
+1
View File
@@ -0,0 +1 @@
<x-layouts.app :title="__('Roles')"><div class="space-y-6"><div class="flex items-start justify-between"><div><h1 class="text-2xl font-semibold">Roles & permissions</h1><p class="mt-1 text-sm text-zinc-500">Control administrative access.</p></div><flux:button variant="primary" :href="route('administration.roles.create')" wire:navigate>Create role</flux:button></div>@if(session('status'))<div class="rounded-xl bg-emerald-50 p-3 text-sm text-emerald-800">{{ session('status') }}</div>@endif<div class="rounded-xl border border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900"><div class="divide-y divide-zinc-200 dark:divide-zinc-800">@foreach($roles as $role)<div class="flex items-center justify-between p-4"><div><div class="font-medium">{{ $role->name }}</div><div class="text-xs text-zinc-500">{{ $role->users_count }} users · {{ $role->permissions_count }} permissions</div></div><div class="flex gap-2"><flux:button size="sm" :href="route('administration.roles.edit',$role)" wire:navigate>Edit</flux:button>@if($role->name!=='admin')<form method="POST" action="{{ route('administration.roles.destroy',$role) }}">@csrf @method('DELETE')<flux:button size="sm" variant="danger" type="submit">Delete</flux:button></form>@endif</div></div>@endforeach</div></div></div></x-layouts.app>
+8
View File
@@ -0,0 +1,8 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\Roles\Http\Controllers\RoleController;
Route::middleware(['auth', 'verified'])->prefix('administration/roles')->name('administration.roles.')->group(function (): void {
Route::resource('', RoleController::class)->parameters(['' => 'role'])->except(['show']);
});
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace Modules\Roles\Support;
final class ModuleInfo
{
public static function name(): string
{
return 'Roles';
}
public static function nameLower(): string
{
return 'roles';
}
}
+5
View File
@@ -0,0 +1,5 @@
<?php
it('boots the Roles module', function (): void {
expect(config('roles.name'))->toBe('Roles');
});
+10
View File
@@ -0,0 +1,10 @@
{
"name": "absdev/roles-module",
"description": "Roles foundation module for the ABSDEV Laravel application platform.",
"type": "laravel-module",
"autoload": {
"psr-4": {
"Modules\\Roles\\": ""
}
}
}
+20
View File
@@ -0,0 +1,20 @@
{
"name": "Roles",
"alias": "roles",
"version": "1.0.0",
"description": "Roles foundation module for the ABSDEV Laravel application platform.",
"keywords": [
"laravel",
"modules",
"roles"
],
"priority": 10,
"providers": [
"Modules\\Roles\\Providers\\RolesServiceProvider"
],
"aliases": {},
"files": [],
"requires": [
"Core"
]
}