diff --git a/docs/content/1_docs/10_user-management/2_advanced-permissions.md b/docs/content/1_docs/10_user-management/2_advanced-permissions.md
index 5e3f92c99..58b3cd1ac 100644
--- a/docs/content/1_docs/10_user-management/2_advanced-permissions.md
+++ b/docs/content/1_docs/10_user-management/2_advanced-permissions.md
@@ -29,6 +29,9 @@ In addition to this we have to configure the permissions' system. There are 3 le
Set the `twill.permissions.level` to the desired type. And also set the modules to manage in
the `twill.permissions.modules` key.
+Beside setting global `twill.permissions.level` it is also possible to set per-module level by adding
+it to `twill.permissions.modules` as keyed item as shown for model `pages` in example below.
+
```php {7-10}
[
- 'level' => \A17\Twill\Enums\PermissionLevel::LEVEL_ROLE,
- 'modules' => ['blogs'],
+ 'level' => \A17\Twill\Enums\PermissionLevel::LEVEL_ROLE_GROUP,
+ 'modules' => [
+ 'blogs',
+ 'pages' => \A17\Twill\Enums\PermissionLevel::LEVEL_ROLE_GROUP_ITEM
+ ],
],
]
```
diff --git a/src/Http/Controllers/Admin/GroupController.php b/src/Http/Controllers/Admin/GroupController.php
index 5451cd1b9..ef8f89fbf 100644
--- a/src/Http/Controllers/Admin/GroupController.php
+++ b/src/Http/Controllers/Admin/GroupController.php
@@ -2,6 +2,7 @@
namespace A17\Twill\Http\Controllers\Admin;
+use A17\Twill\Enums\PermissionLevel;
use A17\Twill\Facades\TwillPermissions;
use A17\Twill\Models\Contracts\TwillModelContract;
use A17\Twill\Services\Listings\Columns\Text;
@@ -67,8 +68,10 @@ protected function getIndexOption($option, $item = null): mixed
protected function formData($request): array
{
+ // Divide permissions based on level to minimize instance fetching
return [
- 'permissionModules' => Permission::permissionableParentModuleItems(),
+ 'permissionModulesLevelGroup' => Permission::permissionableModulesForLevel([PermissionLevel::LEVEL_ROLE_GROUP, PermissionLevel::LEVEL_ROLE_GROUP_ITEM]),
+ 'permissionModulesLevelItem' => Permission::permissionableParentModuleItemsForLevel(PermissionLevel::LEVEL_ROLE_GROUP_ITEM),
];
}
diff --git a/src/Http/Controllers/Admin/UserController.php b/src/Http/Controllers/Admin/UserController.php
index 7cf38c4a9..36f535169 100755
--- a/src/Http/Controllers/Admin/UserController.php
+++ b/src/Http/Controllers/Admin/UserController.php
@@ -201,12 +201,7 @@ protected function formData($request)
$titleThumbnail = $user->cmsImage($role, $crop, $params);
}
- if (TwillPermissions::levelIs(PermissionLevel::LEVEL_ROLE_GROUP_ITEM)) {
- $permissionsData = [
- 'permissionModules' => $this->getPermissionModules(),
- ];
- }
-
+ // Fetch modules with LEVEL_ROLE_GROUP_ITEM permission level
return [
'roleList' => $this->getRoleList(),
'titleThumbnail' => $titleThumbnail ?? null,
@@ -214,7 +209,8 @@ protected function formData($request)
'qrCode' => $qrCode ?? null,
'groupPermissionMapping' => $this->getGroupPermissionMapping(),
'groupOptions' => $this->getGroups(),
- ] + ($permissionsData ?? []);
+ 'permissionModules' => Permission::permissionableParentModuleItemsForLevel(PermissionLevel::LEVEL_ROLE_GROUP_ITEM)
+ ];
}
/**
@@ -354,15 +350,6 @@ private function getRoleList()
})->values()->toArray();
}
- private function getPermissionModules()
- {
- if (config('twill.enabled.permissions-management')) {
- return Permission::permissionableParentModuleItems();
- }
-
- return [];
- }
-
public function getSubmitOptions(Model $item): ?array
{
// Use options from form template
diff --git a/src/Models/Permission.php b/src/Models/Permission.php
index 743a39142..ddd46f76e 100644
--- a/src/Models/Permission.php
+++ b/src/Models/Permission.php
@@ -5,12 +5,15 @@
use A17\Twill\Enums\PermissionLevel;
use A17\Twill\Exceptions\ModuleNotFoundException;
use A17\Twill\Facades\TwillPermissions;
+use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Illuminate\Foundation\Auth\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Model as BaseModel;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\NotFoundExceptionInterface;
class Permission extends BaseModel
{
@@ -87,6 +90,35 @@ public static function available($scope)
}
}
+ /**
+ * Retrieve the list of modules with specific permission levels that can be applied.
+ *
+ * @return Collection
+ */
+ public static function permissionableModulesWithLevel()
+ {
+ return collect(config('twill.permissions.modules', []))
+ ->mapWithKeys(function ($item, $key) {
+ if (is_integer($key)) {
+ return [$item => config('twill.permissions.level', PermissionLevel::LEVEL_ROLE)];
+ }
+ return [$key => $item];
+ });
+ }
+
+ /**
+ * Retrieve the list of modules that permissions can be applied to for specific permission level.
+ *
+ * @return Collection
+ */
+ public static function permissionableModulesForLevel(string|array $level)
+ {
+ if (is_string($level)) {
+ return self::permissionableModulesWithLevel()->filter(fn($item, $key) => $item === $level)->keys();
+ }
+ return self::permissionableModulesWithLevel()->filter(fn($item, $key) => in_array($item, $level))->keys();
+ }
+
/**
* Retrieve the list of modules that permissions can be applied to.
*
@@ -94,7 +126,7 @@ public static function available($scope)
*/
public static function permissionableModules()
{
- return collect(config('twill.permissions.modules', []));
+ return self::permissionableModulesWithLevel()->keys();
}
/**
@@ -115,6 +147,31 @@ public static function permissionableParentModuleItems()
});
}
+ /**
+ * Retrieve a collection of items that belongs to models with specific permission level.
+ *
+ * @param string $level
+ * @return Collection
+ * @throws ContainerExceptionInterface
+ * @throws NotFoundExceptionInterface
+ */
+ public static function permissionableParentModuleItemsForLevel(string $level)
+ {
+ return self::permissionableModulesWithLevel()
+ ->filter(fn($item, $key) => $item === $level)
+ ->keys()
+ ->filter(function ($module) {
+ return !strpos($module, '.');
+ })
+ ->mapWithKeys(function ($module) {
+ try {
+ return [$module => getRepositoryByModuleName($module)->get([], [], [], -1)];
+ } catch (ModuleNotFoundException $e) {
+ return [];
+ }
+ });
+ }
+
/**
* Get the parent permissionable model (one of the permissionale module).
*
diff --git a/src/Repositories/Behaviors/HandleGroupPermissions.php b/src/Repositories/Behaviors/HandleGroupPermissions.php
index 7ea303cb8..9e16d9890 100644
--- a/src/Repositories/Behaviors/HandleGroupPermissions.php
+++ b/src/Repositories/Behaviors/HandleGroupPermissions.php
@@ -27,7 +27,7 @@ public function getFormFieldsHandleGroupPermissions($object, $fields)
}
// Add active module permissions
- foreach (Permission::permissionableModules() as $moduleName) {
+ foreach (Permission::permissionableModulesForLevel([PermissionLevel::LEVEL_ROLE_GROUP, PermissionLevel::LEVEL_ROLE_GROUP_ITEM]) as $moduleName) {
$modulePermission = $object->permissions()->module()->ofModuleName($moduleName)->first();
if ($modulePermission) {
$fields['module_' . $moduleName . '_permissions'] = $modulePermission->name;
@@ -35,6 +35,13 @@ public function getFormFieldsHandleGroupPermissions($object, $fields)
$fields['module_' . $moduleName . '_permissions'] = 'none';
}
}
+
+ // Add LEVEL_ROLE_GROUP_ITEM permission level modules with items
+ foreach ($object->permissions()->moduleItem()->get() as $permission) {
+ $model = $permission->permissionable()->first();
+ $moduleName = getModuleNameByModel($model);
+ $fields[$moduleName . '_' . $model->id . '_permission'] = $permission->name;
+ }
} elseif (TwillPermissions::levelIs(PermissionLevel::LEVEL_ROLE_GROUP_ITEM)) {
// Add active item permissions
foreach ($object->permissions()->moduleItem()->get() as $permission) {
diff --git a/src/Repositories/Behaviors/HandlePermissions.php b/src/Repositories/Behaviors/HandlePermissions.php
index a0d398c26..55a87493b 100644
--- a/src/Repositories/Behaviors/HandlePermissions.php
+++ b/src/Repositories/Behaviors/HandlePermissions.php
@@ -134,7 +134,7 @@ public function afterSaveHandlePermissions($object, $fields)
private function shouldProcessPermissions($moduleName): bool
{
- return TwillPermissions::levelIs(PermissionLevel::LEVEL_ROLE_GROUP_ITEM)
+ return TwillPermissions::levelForModuleIs($moduleName, PermissionLevel::LEVEL_ROLE_GROUP_ITEM)
&& TwillPermissions::getPermissionModule($moduleName);
}
diff --git a/src/Repositories/Behaviors/HandleUserPermissions.php b/src/Repositories/Behaviors/HandleUserPermissions.php
index a40cde8db..5104fe5bd 100644
--- a/src/Repositories/Behaviors/HandleUserPermissions.php
+++ b/src/Repositories/Behaviors/HandleUserPermissions.php
@@ -3,7 +3,6 @@
namespace A17\Twill\Repositories\Behaviors;
use A17\Twill\Enums\PermissionLevel;
-use A17\Twill\Facades\TwillPermissions;
use A17\Twill\Models\Model;
use A17\Twill\Models\Permission;
use A17\Twill\Models\User;
@@ -23,7 +22,7 @@ public function getFormFieldsHandleUserPermissions($object, $fields)
{
if (
!config('twill.enabled.permissions-management') ||
- !TwillPermissions::levelIs(PermissionLevel::LEVEL_ROLE_GROUP_ITEM)
+ Permission::permissionableModulesForLevel(PermissionLevel::LEVEL_ROLE_GROUP_ITEM)->isEmpty()
) {
return $fields;
}
@@ -58,7 +57,7 @@ public function afterSaveHandleUserPermissions($object, $fields)
$this->addOrRemoveUserToEveryoneGroup($object);
- if (TwillPermissions::levelIs(PermissionLevel::LEVEL_ROLE_GROUP_ITEM)) {
+ if (Permission::permissionableModulesForLevel(PermissionLevel::LEVEL_ROLE_GROUP_ITEM)->isNotEmpty()) {
$this->updateUserItemPermissions($object, $fields);
}
}
diff --git a/src/TwillPermissions.php b/src/TwillPermissions.php
index 3ff0fafae..a76f8a0cd 100644
--- a/src/TwillPermissions.php
+++ b/src/TwillPermissions.php
@@ -64,6 +64,23 @@ public function levelIs(string $level): bool
return $this->enabled() && config('twill.permissions.level') === $level;
}
+ /**
+ * Check specific permission level for module
+ *
+ * @param string $module
+ * @param string $level
+ * @return bool
+ * @throws \Exception
+ */
+ public function levelForModuleIs(string $module, string $level): bool
+ {
+ if (!PermissionLevel::isValid($level)) {
+ throw new \Exception('Invalid permission level. Check TwillPermissions for available levels');
+ }
+
+ return $this->enabled() && Permission::permissionableModulesWithLevel()->get($module) === $level;
+ }
+
public function levelIsOneOf(array $levels): bool
{
foreach ($levels as $level) {
diff --git a/views/groups/form.blade.php b/views/groups/form.blade.php
index 962916289..6bfdb4a1e 100644
--- a/views/groups/form.blade.php
+++ b/views/groups/form.blade.php
@@ -17,8 +17,22 @@
:max="999"
/>
- @if(\A17\Twill\Facades\TwillPermissions::levelIs(\A17\Twill\Enums\PermissionLevel::LEVEL_ROLE_GROUP))
-
+ @if(config('twill.support_subdomain_admin_routing'))
+
+ @foreach(config('twill.app_names') as $subdomain => $subdomainTitle)
+
+ @endforeach
+
+ @endif
+@stop
+
+
+@section('fieldsets')
+ @if($permissionModulesLevelGroup->isNotEmpty())
+
- @foreach($permissionModules as $moduleName => $moduleItems)
+ @foreach($permissionModulesLevelGroup as $moduleName)
@endforeach
-
+
@endif
- @if(config('twill.support_subdomain_admin_routing'))
-
- @foreach(config('twill.app_names') as $subdomain => $subdomainTitle)
-
- @endforeach
-
- @endif
-@stop
-
-@if(\A17\Twill\Facades\TwillPermissions::levelIs(\A17\Twill\Enums\PermissionLevel::LEVEL_ROLE_GROUP_ITEM))
- @can('edit-user-groups')
- @section('fieldsets')
- @foreach($permissionModules as $moduleName => $moduleItems)
+ @if($permissionModulesLevelItem->isNotEmpty())
+ @can('edit-user-groups')
+ @foreach($permissionModulesLevelItem as $moduleName => $moduleItems)
@endforeach
- @stop
- @endcan
-@endif
+ @endcan
+ @endif
+@stop
diff --git a/views/layouts/form.blade.php b/views/layouts/form.blade.php
index 23dc2d38f..9c8317ba7 100644
--- a/views/layouts/form.blade.php
+++ b/views/layouts/form.blade.php
@@ -126,7 +126,7 @@
@yield('fieldsets')
@endif
- @if(\A17\Twill\Facades\TwillPermissions::levelIs(\A17\Twill\Enums\PermissionLevel::LEVEL_ROLE_GROUP_ITEM))
+ @if(\A17\Twill\Facades\TwillPermissions::levelForModuleIs(getModuleNameByModel($item), \A17\Twill\Enums\PermissionLevel::LEVEL_ROLE_GROUP_ITEM))
@if($showPermissionFieldset ?? null)
@can('manage-item', isset($item) ? $item : null)
'Edit ' . $module_name
]
],
- (\A17\Twill\Facades\TwillPermissions::levelIs(\A17\Twill\Enums\PermissionLevel::LEVEL_ROLE_GROUP_ITEM) ? [['value' => 'manage-module', 'label' => 'Manage ' . $module_name ]] : []))"
+ (\A17\Twill\Facades\TwillPermissions::levelForModuleIs($module_name, \A17\Twill\Enums\PermissionLevel::LEVEL_ROLE_GROUP_ITEM) ? [['value' => 'manage-module', 'label' => 'Manage ' . $module_name ]] : []))"
/>
@endforeach
diff --git a/views/users/form.blade.php b/views/users/form.blade.php
index fc5845844..f3c9374c9 100644
--- a/views/users/form.blade.php
+++ b/views/users/form.blade.php
@@ -156,7 +156,7 @@ function($locale) {
@section('fieldsets')
- @if(\A17\Twill\Facades\TwillPermissions::levelIs(\A17\Twill\Enums\PermissionLevel::LEVEL_ROLE_GROUP_ITEM))
+ @if($permissionModules->isNotEmpty())
@can('edit-users')
@unless($item->isSuperAdmin() || $item->id === $currentUser->id)