Added hasRole twig extension and Auditer role & permission set

This commit is contained in:
2023-05-31 14:00:52 +01:00
parent a67214d024
commit fc707b1abf
7 changed files with 465 additions and 2 deletions

View File

@@ -11,3 +11,5 @@ Fixes/tweaks a few "issues" with the default UserFrosting installation, includin
- Fixes showing user activity depending on the current user's permission to view it
- Allow site-admins to view roles & permissions
- Allow site-admins to edit basic role details (name, slug & description)
- Added 'hasRole' twig function to check if a user has a role (if a role doesn't exist, always returns false)
- Added 'Auditer' role and split the activities permission away from site-admins (exclusive only) and everyone else

View File

@@ -0,0 +1,140 @@
<?php
/*
* AVSDev UF Tweaks (https://avsdev.uk)
*
* @link https://git.avsdev.uk/avsdev/sprinkle-uf-tweaks
* @license https://git.avsdev.uk/avsdev/sprinkle-uf-tweaks/blob/master/LICENSE.md (LGPL-3.0 License)
*/
namespace UserFrosting\Sprinkle\UFTweaks\Database\Seeds;
use UserFrosting\Sprinkle\Account\Database\Models\Permission;
use UserFrosting\Sprinkle\Account\Database\Models\Role;
use UserFrosting\Sprinkle\Core\Database\Seeder\BaseSeed;
use UserFrosting\Sprinkle\Core\Facades\Seeder;
/**
* Seeder for removing the permissions related to activities log.
*
* @author Craig Williams (https://avsdev.uk)
*/
class DisableAuditer extends BaseSeed
{
/**
* {@inheritdoc}
*/
public function run()
{
// Modify the base permissions to exclude activities
$this->modifyBasePermissions();
// Get permissions
$permissions = $this->getPermissions();
$this->deletePermissions($permissions);
// Get and save roles
$roles = $this->getRoles();
$this->deleteRoles($roles);
}
/**
* @return array Roles to seed
*/
protected function getRoles()
{
return [
Role::where([
'slug' => 'auditer'
])->first(),
];
}
/**
* @return array Permissions to seed
*/
protected function getPermissions()
{
$siteAdminRole = Role::where('slug', 'site-admin')->first();
$groupAdminRole = Role::where('slug', 'group-admin')->first();
return [
Permission::where([
'slug' => 'view_user_field',
'conditions' => "in(property,['activities'])"
])->first(),
Permission::where([
'slug' => 'view_user_field',
'conditions' => "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$siteAdminRole->id}) && (!has_role(user.id,{$groupAdminRole->id}) || equals_num(self.id,user.id)) && in(property,['activities'])"
])->first(),
];
}
/**
* Save roles.
*
* @param array $roles
*/
protected function deleteRoles(array $roles)
{
for ($idx = count($roles) - 1; $idx >= 0; $idx--) {
if ($roles[$idx]) {
$roles[$idx]->users()->detach();
$roles[$idx]->delete();
}
}
}
/**
* Save permissions.
*
* @param array $permissions
*/
protected function deletePermissions(array $permissions)
{
for ($idx = count($permissions) - 1; $idx >= 0; $idx--) {
if ($permissions[$idx]) {
$permissions[$idx]->roles()->detach();
$permissions[$idx]->delete();
}
}
}
/**
* Modify base permissions.
*
* @param array $permissions
*/
protected function modifyBasePermissions()
{
$siteAdminRole = Role::where('slug', 'site-admin')->first();
$groupAdminRole = Role::where('slug', 'group-admin')->first();
$viewPermissionsAny = Permission::query()
->where('slug', 'view_user_field')
->where('conditions', "in(property,['user_name','name','email','locale','theme','roles','group'])")
->first();
if ($viewPermissionsAny) {
$viewPermissionsAny->conditions = "in(property,['user_name','name','email','locale','theme','roles','group','activities'])";
$viewPermissionsAny->save();
}
$viewPermissionsGroup = Permission::query()
->where('slug', 'view_user_field')
->where('conditions', "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$siteAdminRole->id}) && (!has_role(user.id,{$groupAdminRole->id}) || equals_num(self.id,user.id)) && in(property,['user_name','name','email','locale','roles','group'])")
->first();
if ($viewPermissionsGroup) {
$viewPermissionsGroup->conditions = "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$siteAdminRole->id}) && (!has_role(user.id,{$groupAdminRole->id}) || equals_num(self.id,user.id)) && in(property,['user_name','name','email','locale','roles','group','activities'])";
$viewPermissionsGroup->save();
}
// Make sure site admin still has activities page permissions
$siteAdmin = Role::where('slug', 'site-admin')->first();
if ($siteAdmin) {
$siteAdmin->permissions()->syncWithoutDetaching([
Permission::where('slug', 'uri_activities')->first()->id,
]);
}
}
}

View File

@@ -0,0 +1,193 @@
<?php
/*
* AVSDev UF Tweaks (https://avsdev.uk)
*
* @link https://git.avsdev.uk/avsdev/sprinkle-uf-tweaks
* @license https://git.avsdev.uk/avsdev/sprinkle-uf-tweaks/blob/master/LICENSE.md (LGPL-3.0 License)
*/
namespace UserFrosting\Sprinkle\UFTweaks\Database\Seeds;
use UserFrosting\Sprinkle\Account\Database\Models\Permission;
use UserFrosting\Sprinkle\Account\Database\Models\Role;
use UserFrosting\Sprinkle\Core\Database\Seeder\BaseSeed;
use UserFrosting\Sprinkle\Core\Facades\Seeder;
/**
* Seeder for the permissions related to activities log.
*
* @author Craig Williams (https://avsdev.uk)
*/
class EnableAuditer extends BaseSeed
{
/**
* {@inheritdoc}
*/
public function run()
{
// We require the default roles
Seeder::execute('DefaultRoles');
// We require the default permissions
Seeder::execute('DefaultPermissions');
// Get and save roles
$roles = $this->getRoles();
$this->saveRoles($roles);
// Get and save permissions
$permissions = $this->getPermissions();
$this->savePermissions($permissions);
// Modify the base permissions to exclude activities
$this->modifyBasePermissions();
// Add default mappings to permissions
$this->syncPermissionsRole($permissions);
}
/**
* @return array Roles to seed
*/
protected function getRoles()
{
return [
new Role([
'slug' => 'auditer',
'name' => 'Audit Viewer',
'description' => 'This role is meant for "auditers", who are allowed to view the activity log.',
]),
];
}
/**
* @return array Permissions to seed
*/
protected function getPermissions()
{
$siteAdminRole = Role::where('slug', 'site-admin')->first();
$groupAdminRole = Role::where('slug', 'group-admin')->first();
return [
'view_user_field_activities_any' => new Permission([
'slug' => 'view_user_field',
'name' => 'View user activities',
'conditions' => "in(property,['activities'])",
'description' => 'View any user\'s activities log',
]),
'view_user_field_activities_group' => new Permission([
'slug' => 'view_user_field',
'name' => 'View user activities',
'conditions' => "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$siteAdminRole->id}) && (!has_role(user.id,{$groupAdminRole->id}) || equals_num(self.id,user.id)) && in(property,['activities'])",
'description' => 'View activities log of any user in your own group, except the master user and Site and Group Administrators (except yourself).',
]),
];
}
/**
* Save roles.
*
* @param array $roles
*/
protected function saveRoles(array &$roles)
{
foreach ($roles as $role) {
// Trying to find if the role already exist
$existingRole = Role::where(['slug' => $role->slug])->first();
// Don't save if already exist, use existing role reference
// otherwise to re-sync permissions and roles
if ($existingRole == null) {
$role->save();
} else {
$roles[$slug] = $existingRole;
}
}
}
/**
* Save permissions.
*
* @param array $permissions
*/
protected function savePermissions(array &$permissions)
{
foreach ($permissions as $slug => $permission) {
// Trying to find if the permission already exist
$existingPermission = Permission::where(['slug' => $permission->slug, 'conditions' => $permission->conditions])->first();
// Don't save if already exist, use existing permission reference
// otherwise to re-sync permissions and roles
if ($existingPermission == null) {
$permission->save();
} else {
$permissions[$slug] = $existingPermission;
}
}
}
/**
* Modify base permissions.
*
* @param array $permissions
*/
protected function modifyBasePermissions()
{
$siteAdminRole = Role::where('slug', 'site-admin')->first();
$groupAdminRole = Role::where('slug', 'group-admin')->first();
$viewPermissionsAny = Permission::query()
->where('slug', 'view_user_field')
->where('conditions', "in(property,['user_name','name','email','locale','theme','roles','group','activities'])")
->first();
if ($viewPermissionsAny) {
$viewPermissionsAny->conditions = "in(property,['user_name','name','email','locale','theme','roles','group'])";
$viewPermissionsAny->save();
}
$viewPermissionsGroup = Permission::query()
->where('slug', 'view_user_field')
->where('conditions', "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$siteAdminRole->id}) && (!has_role(user.id,{$groupAdminRole->id}) || equals_num(self.id,user.id)) && in(property,['user_name','name','email','locale','roles','group','activities'])")
->first();
if ($viewPermissionsGroup) {
$viewPermissionsGroup->conditions = "equals_num(self.group_id,user.group_id) && !is_master(user.id) && !has_role(user.id,{$siteAdminRole->id}) && (!has_role(user.id,{$groupAdminRole->id}) || equals_num(self.id,user.id)) && in(property,['user_name','name','email','locale','roles','group'])";
$viewPermissionsGroup->save();
}
}
/**
* Sync permissions with default roles.
*
* @param array $permissions
*/
protected function syncPermissionsRole(array $permissions)
{
$siteAdmin = Role::where('slug', 'site-admin')->first();
if ($siteAdmin) {
$siteAdmin->permissions()->syncWithoutDetaching([
$permissions['view_user_field_activities_any']->id,
$permissions['view_user_field_activities_group']->id,
]);
}
$groupAdmin = Role::where('slug', 'group-admin')->first();
if ($groupAdmin) {
$groupAdmin->permissions()->syncWithoutDetaching([
$permissions['view_user_field_activities_group']->id,
]);
}
$roleAuditer = Role::where('slug', 'auditer')->first();
if ($roleAuditer) {
$roleAuditer->permissions()->sync([
Permission::where('slug', 'uri_dashboard')->first()->id,
Permission::where('slug', 'uri_activities')->first()->id,
$permissions['view_user_field_activities_any']->id,
$permissions['view_user_field_activities_group']->id,
]);
}
}
}

View File

@@ -0,0 +1,49 @@
<?php
/*
* AVSDev UF Tweaks (https://avsdev.uk)
*
* @link https://git.avsdev.uk/avsdev/sprinkle-uf-tweaks
* @license https://git.avsdev.uk/avsdev/sprinkle-uf-tweaks/blob/master/LICENSE.md (LGPL-3.0 License)
*/
namespace UserFrosting\Sprinkle\UFTweaks\Database\Seeds;
use UserFrosting\Sprinkle\Account\Database\Models\Permission;
use UserFrosting\Sprinkle\Account\Database\Models\Role;
use UserFrosting\Sprinkle\Core\Database\Seeder\BaseSeed;
use UserFrosting\Sprinkle\Core\Facades\Seeder;
use UserFrosting\Sprinkle\UFTweaks\Database\Seeds\EnableAuditer;
/**
* Seeder for the permissions related to activities log.
*
* @author Craig Williams (https://avsdev.uk)
*/
class EnableExclusiveAuditer extends EnableAuditer
{
/**
* Sync permissions with default roles.
*
* @param array $permissions
*/
protected function syncPermissionsRole(array $permissions)
{
$siteAdmin = Role::where('slug', 'site-admin')->first();
if ($siteAdmin) {
$siteAdmin->permissions()->detach([
Permission::where('slug', 'uri_activities')->first()->id,
]);
}
$roleAuditer = Role::where('slug', 'auditer')->first();
if ($roleAuditer) {
$roleAuditer->permissions()->sync([
Permission::where('slug', 'uri_dashboard')->first()->id,
Permission::where('slug', 'uri_activities')->first()->id,
$permissions['view_user_field_activities_any']->id,
$permissions['view_user_field_activities_group']->id,
]);
}
}
}

View File

@@ -12,6 +12,7 @@ namespace UserFrosting\Sprinkle\UFTweaks\ServicesProvider;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use UserFrosting\Sprinkle\UFTweaks\Twig\HasRoleExtension;
/**
@@ -103,5 +104,18 @@ class ServicesProvider
return $authorizer;
});
/*
* Extends the 'view' service with the HasRole extension for Twig.
*
* @return \Slim\Views\Twig
*/
$container->extend('view', function ($view, $c) {
$twig = $view->getEnvironment();
$twig->addExtension(new HasRoleExtension($c));
return $view;
});
}
}

View File

@@ -0,0 +1,65 @@
<?php
/*
* AVSDev UF Tweaks (https://avsdev.uk)
*
* @link https://git.avsdev.uk/avsdev/sprinkle-uf-tweaks
* @license https://git.avsdev.uk/avsdev/sprinkle-uf-tweaks/blob/master/LICENSE.md (LGPL-3.0 License)
*/
namespace UserFrosting\Sprinkle\UFTweaks\Twig;
use Illuminate\Database\Capsule\Manager as Capsule;
use Psr\Container\ContainerInterface;
use Twig\Extension\AbstractExtension;
use Twig\Extension\GlobalsInterface;
use Twig\TwigFunction;
use UserFrosting\Support\Repository\Repository as Config;
/**
* Extends Twig functionality to add hasRole.
*
* @author Craig Williams (https://avsdev.uk)
*/
class HasRoleExtension extends AbstractExtension implements GlobalsInterface
{
/**
* @var ContainerInterface
*/
protected $services;
/**
* @var Config
*/
protected $config;
/**
* @param ContainerInterface $services
*/
public function __construct(ContainerInterface $services)
{
$this->services = $services;
$this->config = $services->config;
}
public function getName()
{
return 'avsdev/uf-tweaks-hasRole';
}
public function getFunctions()
{
return [
// Add Twig function for checking permissions during dynamic menu rendering
new TwigFunction('hasRole', function ($roleSlug) {
$currentUser = $this->services->currentUser;
return $currentUser->roles()->where('slug', $roleSlug)->count() > 0;
}),
];
}
public function getGlobals()
{
return [];
}
}

View File

@@ -155,7 +155,7 @@
{% if checkAccess('uri_activities') %}
{% set dashboard_is_empty = false %}
<div class="col-md-6 col-sm-12 col-xs-12">
<div class="col-md-{% if (hasRole('auditer')) %}12{% else %}6{% endif %} col-sm-12 col-xs-12">
<div id="widget-activities" class="box box-primary">
<div class="box-header">
<h3 class="box-title"><i class="fas fa-tasks fa-fw"></i> {{translate('ACTIVITY', 2)}}</h3>