9 changed files with 339 additions and 3 deletions
@ -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 @@ |
|||||||
|
<?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 @@ |
|||||||
|
<?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 @@ |
|||||||
|
<?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 @@ |
|||||||
|
<?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