181 lines
5.9 KiB
PHP
181 lines
5.9 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\PermissionModule;
|
|
use App\Models\RoleTemplate;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Filesystem\Filesystem;
|
|
use Illuminate\Support\Str;
|
|
use ReflectionClass;
|
|
use Symfony\Component\Finder\Finder;
|
|
|
|
class SyncPermissions extends Command
|
|
{
|
|
protected $signature = 'permissions:sync {--dry-run : Chỉ liệt kê, không lưu}';
|
|
|
|
protected $description = 'Quét Filament Resources và đồng bộ permission modules. Action mới mặc định TẮT.';
|
|
|
|
public function handle(): int
|
|
{
|
|
$dryRun = $this->option('dry-run');
|
|
|
|
$this->info('Đang quét Filament Resources...');
|
|
|
|
$resourcesPath = app_path('Filament/Resources');
|
|
if (! is_dir($resourcesPath)) {
|
|
$this->error('Không tìm thấy thư mục Filament/Resources');
|
|
return self::FAILURE;
|
|
}
|
|
|
|
$modules = [];
|
|
$finder = new Finder();
|
|
$finder->files()->in($resourcesPath)->name('*Resource.php');
|
|
|
|
foreach ($finder as $file) {
|
|
$class = $this->getClassFromFile($file->getRealPath());
|
|
if (! $class || ! class_exists($class)) {
|
|
continue;
|
|
}
|
|
|
|
$ref = new ReflectionClass($class);
|
|
|
|
if (! $ref->hasProperty('permissionActions')) {
|
|
continue;
|
|
}
|
|
|
|
$prop = $ref->getProperty('permissionActions');
|
|
$prop->setAccessible(true);
|
|
$actions = $prop->getDefaultValue();
|
|
|
|
$label = 'Resource';
|
|
if ($ref->hasProperty('pluralModelLabel')) {
|
|
$labelProp = $ref->getProperty('pluralModelLabel');
|
|
$labelProp->setAccessible(true);
|
|
$label = $labelProp->getDefaultValue() ?? $label;
|
|
}
|
|
|
|
$moduleName = Str::snake(class_basename($class));
|
|
$moduleName = str_replace('_resource', '', $moduleName);
|
|
|
|
$modules[] = [
|
|
'module' => $moduleName,
|
|
'label' => $label,
|
|
'actions' => $actions ?? [],
|
|
];
|
|
}
|
|
|
|
if (empty($modules)) {
|
|
$this->warn('Không tìm thấy Resource nào có $permissionActions.');
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$this->info('Tìm thấy ' . count($modules) . ' module(s):');
|
|
|
|
foreach ($modules as $m) {
|
|
$this->line(" - {$m['module']}: " . implode(', ', $m['actions']));
|
|
}
|
|
|
|
if ($dryRun) {
|
|
$this->info('Dry-run: Không lưu thay đổi.');
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
foreach ($modules as $m) {
|
|
$existing = PermissionModule::where('module', $m['module'])->first();
|
|
|
|
if ($existing) {
|
|
$oldActions = $existing->actions ?? [];
|
|
$newActions = $m['actions'];
|
|
|
|
if ($oldActions === $newActions) {
|
|
continue;
|
|
}
|
|
|
|
$added = array_diff($newActions, $oldActions);
|
|
$removed = array_diff($oldActions, $newActions);
|
|
|
|
$existing->update([
|
|
'label' => $m['label'],
|
|
'actions' => $newActions,
|
|
]);
|
|
|
|
if (! empty($added)) {
|
|
$this->warn(" [{$m['module']}] Thêm actions: " . implode(', ', $added));
|
|
// Action mới mặc định TẮT cho tất cả role
|
|
$this->disableNewActionsForAllRoles($m['module'], $added);
|
|
}
|
|
if (! empty($removed)) {
|
|
$this->warn(" [{$m['module']}] Xóa actions: " . implode(', ', $removed));
|
|
$this->removeActionsFromAllRoles($m['module'], $removed);
|
|
}
|
|
} else {
|
|
PermissionModule::create([
|
|
'module' => $m['module'],
|
|
'label' => $m['label'],
|
|
'actions' => $m['actions'],
|
|
]);
|
|
$this->info(" [{$m['module']}] Tạo mới module.");
|
|
// Module mới mặc định TẮT cho tất cả role
|
|
$this->disableNewActionsForAllRoles($m['module'], $m['actions']);
|
|
}
|
|
}
|
|
|
|
$this->info('Đồng bộ hoàn tất.');
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
private function getClassFromFile(string $path): ?string
|
|
{
|
|
$contents = file_get_contents($path);
|
|
|
|
// Tìm namespace
|
|
$namespace = null;
|
|
if (preg_match('/namespace\s+([^;]+);/', $contents, $matches)) {
|
|
$namespace = $matches[1];
|
|
}
|
|
|
|
// Tìm class name
|
|
$class = null;
|
|
if (preg_match('/class\s+(\w+)/', $contents, $matches)) {
|
|
$class = $matches[1];
|
|
}
|
|
|
|
if ($namespace && $class) {
|
|
return $namespace . '\\' . $class;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function disableNewActionsForAllRoles(string $module, array $actions): void
|
|
{
|
|
$roles = RoleTemplate::all();
|
|
foreach ($roles as $role) {
|
|
$perms = $role->permissions ?? [];
|
|
foreach ($actions as $action) {
|
|
if (isset($perms[$module]) && in_array($action, $perms[$module])) {
|
|
continue; // Đã có thì giữ nguyên
|
|
}
|
|
// Không thêm vào = mặc định TẮT
|
|
}
|
|
// Không cần update vì JSONB không lưu action mới = TẮT
|
|
}
|
|
}
|
|
|
|
private function removeActionsFromAllRoles(string $module, array $actions): void
|
|
{
|
|
$roles = RoleTemplate::all();
|
|
foreach ($roles as $role) {
|
|
$perms = $role->permissions ?? [];
|
|
if (isset($perms[$module])) {
|
|
$perms[$module] = array_values(array_diff($perms[$module], $actions));
|
|
if (empty($perms[$module])) {
|
|
unset($perms[$module]);
|
|
}
|
|
$role->update(['permissions' => $perms]);
|
|
}
|
|
}
|
|
}
|
|
}
|