9 changed files with 339 additions and 3 deletions
@ -0,0 +1,79 @@
@@ -0,0 +1,79 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Api\V1; |
||||
|
||||
use App\Http\Controllers\Api\Concerns\RespondsWithJson; |
||||
use App\Http\Controllers\Controller; |
||||
use App\Models\GroupPermission; |
||||
use App\Services\PermissionService; |
||||
use App\Support\ApiActor; |
||||
use Illuminate\Http\JsonResponse; |
||||
use Illuminate\Http\Request; |
||||
|
||||
class GroupPermissionController extends Controller |
||||
{ |
||||
use RespondsWithJson; |
||||
|
||||
public function __construct( |
||||
private readonly PermissionService $permissions, |
||||
) { |
||||
} |
||||
|
||||
public function index(): JsonResponse |
||||
{ |
||||
$rows = GroupPermission::orderBy('group_key')->orderBy('permission')->get(); |
||||
|
||||
$grouped = $rows->groupBy('group_key')->map(fn ($items) => $items->pluck('permission')->values()); |
||||
|
||||
return $this->ok([ |
||||
'group_permissions' => $grouped, |
||||
'available_permissions' => $this->permissions->allPermissions(), |
||||
]); |
||||
} |
||||
|
||||
public function store(Request $request): JsonResponse |
||||
{ |
||||
$data = $request->validate([ |
||||
'group_key' => ['required', 'string', 'max:100'], |
||||
'permission' => ['required', 'string', 'max:100', 'in:' . implode(',', $this->permissions->allPermissions())], |
||||
]); |
||||
|
||||
$row = GroupPermission::firstOrCreate([ |
||||
'group_key' => $data['group_key'], |
||||
'permission' => $data['permission'], |
||||
]); |
||||
|
||||
$this->permissions->flushCacheForGroups([$data['group_key']]); |
||||
|
||||
return $this->ok($row->toArray(), [], $row->wasRecentlyCreated ? 201 : 200); |
||||
} |
||||
|
||||
public function destroy(Request $request, string $group, string $permission): JsonResponse |
||||
{ |
||||
$deleted = GroupPermission::where('group_key', $group) |
||||
->where('permission', $permission) |
||||
->delete(); |
||||
|
||||
$this->permissions->flushCacheForGroups([$group]); |
||||
|
||||
return $this->ok(['deleted' => (bool) $deleted]); |
||||
} |
||||
|
||||
public function syncGroup(Request $request, string $group): JsonResponse |
||||
{ |
||||
$data = $request->validate([ |
||||
'permissions' => ['required', 'array'], |
||||
'permissions.*' => ['string', 'in:' . implode(',', $this->permissions->allPermissions())], |
||||
]); |
||||
|
||||
GroupPermission::where('group_key', $group)->delete(); |
||||
|
||||
foreach ($data['permissions'] as $permission) { |
||||
GroupPermission::create(['group_key' => $group, 'permission' => $permission]); |
||||
} |
||||
|
||||
$this->permissions->flushCacheForGroups([$group]); |
||||
|
||||
return $this->ok(['group_key' => $group, 'permissions' => $data['permissions']]); |
||||
} |
||||
} |
||||
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class GroupPermission extends Model |
||||
{ |
||||
protected $fillable = ['group_key', 'permission']; |
||||
|
||||
public static function permissionsForGroups(array $groups): array |
||||
{ |
||||
if (empty($groups)) { |
||||
return []; |
||||
} |
||||
|
||||
return self::whereIn('group_key', $groups) |
||||
->pluck('permission') |
||||
->unique() |
||||
->values() |
||||
->all(); |
||||
} |
||||
} |
||||
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
<?php |
||||
|
||||
namespace App\Services; |
||||
|
||||
use App\Models\GroupPermission; |
||||
use Illuminate\Support\Facades\Cache; |
||||
|
||||
class PermissionService |
||||
{ |
||||
private const CACHE_TTL = 300; |
||||
|
||||
public function permissionsForGroups(array $groups): array |
||||
{ |
||||
if (empty($groups)) { |
||||
return []; |
||||
} |
||||
|
||||
$cacheKey = 'group_perms:' . md5(implode(',', $groups)); |
||||
|
||||
return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($groups) { |
||||
return GroupPermission::permissionsForGroups($groups); |
||||
}); |
||||
} |
||||
|
||||
public function hasPermission(array $groups, string $permission): bool |
||||
{ |
||||
return in_array($permission, $this->permissionsForGroups($groups), true); |
||||
} |
||||
|
||||
public function allPermissions(): array |
||||
{ |
||||
return [ |
||||
'profile.view', |
||||
'profile.edit', |
||||
'dashboard.view', |
||||
'cmdb.view', |
||||
'cmdb.manage', |
||||
'cmdb.assign_owner', |
||||
'monitoring.view', |
||||
'ticketing.view', |
||||
'ticketing.create', |
||||
'ticketing.manage', |
||||
'mail.view', |
||||
'asset_mgmt.view', |
||||
'asset_mgmt.manage', |
||||
'geonet_agent.view', |
||||
'admin.users', |
||||
'admin.groups', |
||||
'admin.permissions', |
||||
]; |
||||
} |
||||
|
||||
public function flushCacheForGroups(array $groups): void |
||||
{ |
||||
$cacheKey = 'group_perms:' . md5(implode(',', $groups)); |
||||
Cache::forget($cacheKey); |
||||
} |
||||
} |
||||
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
<?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 |
||||
{ |
||||
Schema::create('group_permissions', function (Blueprint $table) { |
||||
$table->id(); |
||||
$table->string('group_key', 100)->index(); |
||||
$table->string('permission', 100)->index(); |
||||
$table->timestamps(); |
||||
|
||||
$table->unique(['group_key', 'permission']); |
||||
}); |
||||
} |
||||
|
||||
public function down(): void |
||||
{ |
||||
Schema::dropIfExists('group_permissions'); |
||||
} |
||||
}; |
||||
@ -0,0 +1,96 @@
@@ -0,0 +1,96 @@
|
||||
<?php |
||||
|
||||
namespace Database\Seeders; |
||||
|
||||
use App\Models\GroupPermission; |
||||
use Illuminate\Database\Seeder; |
||||
|
||||
class GroupPermissionSeeder extends Seeder |
||||
{ |
||||
/** |
||||
* Default permission mapping per LDAP group. |
||||
* |
||||
* Permissions catalogue: |
||||
* profile.view – lihat profil sendiri |
||||
* profile.edit – edit profil sendiri |
||||
* cmdb.view – lihat semua asset di CMDB |
||||
* cmdb.manage – edit meta asset, set status/tag |
||||
* cmdb.assign_owner – assign asset ke user LDAP |
||||
* monitoring.view – akses halaman monitoring |
||||
* ticketing.view – lihat tiket |
||||
* ticketing.create – buat tiket |
||||
* ticketing.manage – manage semua tiket (admin) |
||||
* mail.view – akses fitur mail |
||||
* dashboard.view – akses dashboard |
||||
* asset_mgmt.view – menu Asset Management |
||||
* asset_mgmt.manage – kelola inventaris (create/edit/delete) |
||||
* geonet_agent.view – lihat GeoNetAgent data |
||||
* admin.users – manage LDAP users |
||||
* admin.groups – manage LDAP groups |
||||
* admin.permissions – manage group-permission mapping |
||||
*/ |
||||
private array $defaults = [ |
||||
'Domain Admins' => [ |
||||
'profile.view', 'profile.edit', |
||||
'dashboard.view', |
||||
'cmdb.view', 'cmdb.manage', 'cmdb.assign_owner', |
||||
'monitoring.view', |
||||
'ticketing.view', 'ticketing.create', 'ticketing.manage', |
||||
'mail.view', |
||||
'asset_mgmt.view', 'asset_mgmt.manage', |
||||
'geonet_agent.view', |
||||
'admin.users', 'admin.groups', 'admin.permissions', |
||||
], |
||||
'IT-Admin' => [ |
||||
'profile.view', 'profile.edit', |
||||
'dashboard.view', |
||||
'cmdb.view', 'cmdb.manage', 'cmdb.assign_owner', |
||||
'monitoring.view', |
||||
'ticketing.view', 'ticketing.create', 'ticketing.manage', |
||||
'asset_mgmt.view', 'asset_mgmt.manage', |
||||
'geonet_agent.view', |
||||
], |
||||
'IT-Staff' => [ |
||||
'profile.view', 'profile.edit', |
||||
'dashboard.view', |
||||
'cmdb.view', 'cmdb.manage', 'cmdb.assign_owner', |
||||
'monitoring.view', |
||||
'ticketing.view', 'ticketing.create', |
||||
'asset_mgmt.view', |
||||
'geonet_agent.view', |
||||
], |
||||
'Management' => [ |
||||
'profile.view', 'profile.edit', |
||||
'dashboard.view', |
||||
'cmdb.view', |
||||
'monitoring.view', |
||||
'ticketing.view', 'ticketing.create', |
||||
'mail.view', |
||||
'asset_mgmt.view', |
||||
], |
||||
'Staff' => [ |
||||
'profile.view', 'profile.edit', |
||||
'dashboard.view', |
||||
'ticketing.view', 'ticketing.create', |
||||
'mail.view', |
||||
], |
||||
'HR' => [ |
||||
'profile.view', 'profile.edit', |
||||
'dashboard.view', |
||||
'ticketing.view', 'ticketing.create', |
||||
'mail.view', |
||||
], |
||||
]; |
||||
|
||||
public function run(): void |
||||
{ |
||||
foreach ($this->defaults as $group => $permissions) { |
||||
foreach ($permissions as $permission) { |
||||
GroupPermission::firstOrCreate([ |
||||
'group_key' => $group, |
||||
'permission' => $permission, |
||||
]); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue