TRF Certest first commit

This commit is contained in:
2025-02-26 08:57:46 +01:00
commit 3ce064a108
2524 changed files with 475404 additions and 0 deletions
@@ -0,0 +1,161 @@
<?php
namespace Vanguard\Support\Authorization;
use Cache;
use Config;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Vanguard\Permission;
trait AuthorizationRoleTrait
{
/**
* Get cached permissions for this role.
*
* @return Collection<Permission>
*/
public function cachedPermissions(): Collection
{
return Cache::remember($this->getCacheKey(), Config::get('cache.ttl'), function () {
return $this->permissions()->get();
});
}
/**
* Override "save" role method to clear role cache.
*/
public function save(array $options = []): void
{
$this->flushCache();
parent::save($options);
}
/**
* Override "delete" role method to clear role cache.
*
* @throws \Exception
*/
public function delete(array $options = []): void
{
$this->flushCache();
parent::delete($options);
}
public function restore(): void
{
$this->flushCache();
parent::restore();
}
public function permissions(): BelongsToMany
{
return $this->belongsToMany(Permission::class, 'permission_role', 'role_id');
}
/**
* Checks if the role has a permission by its name.
*/
public function hasPermission($name): bool
{
$perms = $this->cachedPermissions()->pluck('name')->toArray();
return in_array($name, $perms, true);
}
/**
* Save the inputted permissions.
*/
public function savePermissions(array $inputPermissions): void
{
if (! empty($inputPermissions)) {
$this->permissions()->sync($inputPermissions);
} else {
$this->permissions()->detach();
}
$this->flushCache();
}
/**
* Attach permission to current role.
*/
public function attachPermission(object|array $permission): void
{
if (is_object($permission)) {
$permission = $permission->getKey();
}
if (is_array($permission)) {
$permission = $permission['id'];
}
$this->permissions()->attach($permission);
$this->flushCache();
}
/**
* Detach permission from current role.
*/
public function detachPermission(object|array $permission): void
{
if (is_object($permission)) {
$permission = $permission->getKey();
}
if (is_array($permission)) {
$permission = $permission['id'];
}
$this->permissions()->detach($permission);
$this->flushCache();
}
/**
* Attach multiple permissions to current role.
*/
public function attachPermissions(array $permissions): void
{
foreach ($permissions as $permission) {
$this->attachPermission($permission);
}
}
/**
* Detach multiple permissions from current role
*/
public function detachPermissions(array $permissions): void
{
foreach ($permissions as $permission) {
$this->detachPermission($permission);
}
}
/**
* Sync role permissions.
*/
public function syncPermissions(array $permissions): void
{
$this->permissions()->sync($permissions);
$this->flushCache();
}
/**
* Get permissions cache key.
*/
private function getCacheKey(): string
{
return 'permissions_for_role_'.$this->{$this->primaryKey};
}
/**
* Flush cached permissions for this role.
*/
private function flushCache(): void
{
Cache::forget($this->getCacheKey());
}
}
@@ -0,0 +1,79 @@
<?php
namespace Vanguard\Support\Authorization;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Vanguard\Role;
trait AuthorizationUserTrait
{
/**
* @return mixed
*/
public function role(): BelongsTo
{
return $this->belongsTo(Role::class, 'role_id');
}
/**
* Check if user has specified role.
*/
public function hasRole(string $roleName): bool
{
return $this->role->name === $roleName;
}
/**
* Check if user has a provided permission.
*/
public function hasPermission(string|array $permission, $allRequired = true): bool
{
$permission = (array) $permission;
return $allRequired
? $this->hasAllPermissions($permission)
: $this->hasAtLeastOnePermission($permission);
}
/**
* Check if user has all provided permissions (translates to AND logic between permissions).
*/
private function hasAllPermissions(array $permissions): bool
{
$availablePermissions = $this->role->cachedPermissions()->pluck('name')->toArray();
foreach ($permissions as $perm) {
if (! in_array($perm, $availablePermissions, true)) {
return false;
}
}
return true;
}
/**
* Check if user has at least one of provided permissions (translates to OR logic between permissions).
*/
private function hasAtLeastOnePermission(array $permissions): bool
{
$availablePermissions = $this->role->cachedPermissions()->pluck('name')->toArray();
foreach ($permissions as $perm) {
if (in_array($perm, $availablePermissions, true)) {
return true;
}
}
return false;
}
/**
* Set user's role.
*/
public function setRole(Role|int $role): bool
{
return $this->forceFill([
'role_id' => $role instanceof Role ? $role->id : $role,
])->save();
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace Vanguard\Support;
trait CanImpersonateUsers
{
/**
* Check if a user can impersonate other users.
*/
public function canImpersonate(): bool
{
return $this->hasPermission('users.manage');
}
/**
* Check if a target user can be impersonated.
* By default, all users can be impersonated if a currently logged
* user is not already impersonating another user.
*/
public function canBeImpersonated(): bool
{
return ! app('impersonate')->isImpersonating();
}
}
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace Vanguard\Support\Enum;
enum UserStatus: string
{
case UNCONFIRMED = 'Unconfirmed';
case ACTIVE = 'Active';
case BANNED = 'Banned';
public static function lists(): array
{
return [
self::ACTIVE->value => trans('app.status.'.self::ACTIVE->value),
self::BANNED->value => trans('app.status.'.self::BANNED->value),
self::UNCONFIRMED->value => trans('app.status.'.self::UNCONFIRMED->value),
];
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace Vanguard\Support;
class Locale
{
public const AVAILABLE_LOCALES = ['en', 'de', 'sr'];
public static function flagUrl(string $locale): ?string
{
return match ($locale) {
'en' => url('/flags/GB.png'),
'de' => url('/flags/DE.png'),
'sr' => url('/flags/RS.png'),
default => null,
};
}
public static function validateLocale(string $locale): bool
{
return in_array($locale, self::AVAILABLE_LOCALES);
}
}
@@ -0,0 +1,17 @@
<?php
namespace Vanguard\Support\Plugins\Dashboard;
use Vanguard\Plugins\Plugin;
use Vanguard\Support\Sidebar\Item;
class Dashboard extends Plugin
{
public function sidebar(): Item
{
return Item::create(__('Dashboard'))
->route('dashboard')
->icon('fas fa-home')
->active('/');
}
}
@@ -0,0 +1,35 @@
<?php
namespace Vanguard\Support\Plugins\Dashboard\Widgets;
use Illuminate\Contracts\View\View;
use Vanguard\Plugins\Widget;
use Vanguard\Repositories\User\UserRepository;
use Vanguard\Support\Enum\UserStatus;
class BannedUsers extends Widget
{
/**
* {@inheritdoc}
*/
public ?string $width = '3';
/**
* {@inheritdoc}
*/
protected string|\Closure|array $permissions = 'users.manage';
public function __construct(protected readonly UserRepository $users)
{
}
/**
* {@inheritDoc}
*/
public function render(): View
{
return view('plugins.dashboard.widgets.banned-users', [
'count' => $this->users->countByStatus(UserStatus::BANNED),
]);
}
}
@@ -0,0 +1,34 @@
<?php
namespace Vanguard\Support\Plugins\Dashboard\Widgets;
use Illuminate\Contracts\View\View;
use Vanguard\Plugins\Widget;
use Vanguard\Repositories\User\UserRepository;
class LatestRegistrations extends Widget
{
/**
* {@inheritdoc}
*/
public ?string $width = '4';
/**
* {@inheritdoc}
*/
protected string|\Closure|array $permissions = 'users.manage';
public function __construct(protected readonly UserRepository $users)
{
}
/**
* {@inheritdoc}
*/
public function render(): View
{
return view('plugins.dashboard.widgets.latest-registrations', [
'latestRegistrations' => $this->users->latest(6),
]);
}
}
@@ -0,0 +1,34 @@
<?php
namespace Vanguard\Support\Plugins\Dashboard\Widgets;
use Illuminate\Contracts\View\View;
use Vanguard\Plugins\Widget;
use Vanguard\Repositories\User\UserRepository;
class NewUsers extends Widget
{
/**
* {@inheritdoc}
*/
public ?string $width = '3';
/**
* {@inheritdoc}
*/
protected string|\Closure|array $permissions = 'users.manage';
public function __construct(protected readonly UserRepository $users)
{
}
/**
* {@inheritdoc}
*/
public function render(): View
{
return view('plugins.dashboard.widgets.new-users', [
'count' => $this->users->newUsersCount(),
]);
}
}
@@ -0,0 +1,59 @@
<?php
namespace Vanguard\Support\Plugins\Dashboard\Widgets;
use Carbon\Carbon;
use Illuminate\Contracts\View\View;
use Vanguard\Plugins\Widget;
use Vanguard\Repositories\User\UserRepository;
class RegistrationHistory extends Widget
{
/**
* {@inheritdoc}
*/
public ?string $width = '8';
protected string|\Closure|array $permissions = 'users.manage';
/**
* @var array Count of new users per month.
*/
protected array $usersPerMonth;
public function __construct(protected UserRepository $users)
{
}
/**
* {@inheritdoc}
*/
public function render(): View
{
return view('plugins.dashboard.widgets.registration-history', [
'usersPerMonth' => $this->getUsersPerMonth(),
]);
}
/**
* {@inheritDoc}
*/
public function scripts(): View
{
return view('plugins.dashboard.widgets.registration-history-scripts', [
'usersPerMonth' => $this->getUsersPerMonth(),
]);
}
private function getUsersPerMonth(): array
{
if (isset($this->usersPerMonth)) {
return $this->usersPerMonth;
}
return $this->usersPerMonth = $this->users->countOfNewUsersPerMonthPerRole(
Carbon::now()->subYear()->startOfMonth(),
Carbon::now()->endOfMonth()
);
}
}
@@ -0,0 +1,34 @@
<?php
namespace Vanguard\Support\Plugins\Dashboard\Widgets;
use Illuminate\Contracts\View\View;
use Vanguard\Plugins\Widget;
use Vanguard\Repositories\User\UserRepository;
class TotalUsers extends Widget
{
/**
* {@inheritdoc}
*/
public ?string $width = '3';
/**
* {@inheritdoc}
*/
protected string|\Closure|array $permissions = 'users.manage';
public function __construct(protected readonly UserRepository $users)
{
}
/**
* {@inheritdoc}
*/
public function render(): View
{
return view('plugins.dashboard.widgets.total-users', [
'count' => $this->users->count(),
]);
}
}
@@ -0,0 +1,35 @@
<?php
namespace Vanguard\Support\Plugins\Dashboard\Widgets;
use Illuminate\Contracts\View\View;
use Vanguard\Plugins\Widget;
use Vanguard\Repositories\User\UserRepository;
use Vanguard\Support\Enum\UserStatus;
class UnconfirmedUsers extends Widget
{
/**
* {@inheritdoc}
*/
public ?string $width = '3';
/**
* {@inheritdoc}
*/
protected string|\Closure|array $permissions = 'users.manage';
public function __construct(protected readonly UserRepository $users)
{
}
/**
* {@inheritdoc}
*/
public function render(): View
{
return view('plugins.dashboard.widgets.unconfirmed-users', [
'count' => $this->users->countByStatus(UserStatus::UNCONFIRMED),
]);
}
}
@@ -0,0 +1,25 @@
<?php
namespace Vanguard\Support\Plugins\Dashboard\Widgets;
use Illuminate\Contracts\View\View;
use Vanguard\Plugins\Widget;
use Vanguard\User;
class UserActions extends Widget
{
public function __construct()
{
$this->permissions(function (User $user) {
return $user->hasRole('User');
});
}
/**
* {@inheritdoc}
*/
public function render(): View
{
return view('plugins.dashboard.widgets.user-actions');
}
}
@@ -0,0 +1,31 @@
<?php
namespace Vanguard\Support\Plugins;
use Vanguard\Plugins\Plugin;
use Vanguard\Support\Sidebar\Item;
class RolesAndPermissions extends Plugin
{
public function sidebar(): Item
{
$roles = Item::create(__('Roles'))
->route('roles.index')
->active('roles*')
->permissions('roles.manage');
$permissions = Item::create(__('Permissions'))
->route('permissions.index')
->active('permissions*')
->permissions('permissions.manage');
return Item::create(__('Roles & Permissions'))
->href('#roles-dropdown')
->icon('fas fa-users-cog')
->permissions(['roles.manage', 'permissions.manage'])
->addChildren([
$roles,
$permissions,
]);
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace Vanguard\Support\Plugins;
use Vanguard\Plugins\Plugin;
use Vanguard\Support\Sidebar\Item;
use Vanguard\User;
class Settings extends Plugin
{
public function sidebar(): Item
{
$general = Item::create(__('General'))
->route('settings.general')
->active('settings')
->permissions('settings.general');
$authAndRegistration = Item::create(__('Auth & Registration'))
->route('settings.auth')
->active('settings/auth')
->permissions('settings.auth');
$notifications = Item::create(__('Notifications'))
->route('settings.notifications')
->active('settings/notifications')
->permissions(function (User $user) {
return $user->hasPermission('settings.notifications');
});
return Item::create(__('Settings'))
->href('#settings-dropdown')
->icon('fas fa-cogs')
->permissions(function (User $user) {
return $user->hasPermission(
['settings.general', 'settings.auth', 'settings.notifications'],
allRequired: false
);
})
->addChildren([
$general,
$authAndRegistration,
$notifications,
]);
}
}
+18
View File
@@ -0,0 +1,18 @@
<?php
namespace Vanguard\Support\Plugins;
use Vanguard\Plugins\Plugin;
use Vanguard\Support\Sidebar\Item;
class Users extends Plugin
{
public function sidebar(): Item
{
return Item::create(__('Users'))
->route('users.index')
->icon('fas fa-users')
->active('users*')
->permissions('users.manage');
}
}
+187
View File
@@ -0,0 +1,187 @@
<?php
namespace Vanguard\Support\Sidebar;
use Closure;
use Illuminate\Support\Collection;
use Vanguard\User;
class Item
{
protected ?string $route = null;
protected ?string $href = null;
protected ?string $icon = null;
protected ?string $activePath = null;
protected string|array|closure|null $permissions = null;
protected ?Collection $children = null;
public function __construct(protected string $title)
{
}
/**
* Factory method to easily create a new Item instance with a given title.
*/
public static function create($title): Item
{
return new self($title);
}
/**
* The route to which the rendered item should point to.
*/
public function route($route): self
{
$this->route = $route;
return $this;
}
/**
* A URL to be used if there is no named route defined for the navigation item or if it is an external URL.
* If this attribute is set, it will have higher priority than the $route attribute.
*/
public function href(string $href): self
{
$this->href = $href;
return $this;
}
/**
* Sidebar navigation icon.
*/
public function icon(string $icon): self
{
$this->icon = $icon;
return $this;
}
/**
* The path which indicates when this navigation item should be marked as active.
* It can contain wildcard characters.
*
* Example:
*
* 'users*' (the item will be active whenever a current URL start with "user")
*/
public function active(string $path): self
{
$this->activePath = $path;
return $this;
}
public function getActivePath(): ?string
{
return $this->activePath;
}
/**
* If item has secondary navigation links, this method will return all the URL patterns when
* this navigation item should be expanded.
*/
public function getExpandedPath(): ?array
{
if (! $this->children->count()) {
return null;
}
return $this->children->toBase()->map(function (Item $item) {
return $item->getActivePath();
})->toArray();
}
/**
* Returns the "href" attribute (the URL) for the navigation item.
*/
public function getHref(): ?string
{
if ($this->href) {
return $this->href;
}
return $this->route ? route($this->route) : null;
}
public function getIcon(): ?string
{
return $this->icon;
}
public function getTitle(): string
{
return $this->title;
}
/**
* Set the permissions required for rendering the navigation item.
*/
public function permissions(string|array|closure $permissions): self
{
$this->permissions = $permissions;
return $this;
}
public function getPermissions(): string|array|closure|null
{
return $this->permissions;
}
/**
* Checks if item has nested "children" items.
*/
public function isDropdown(): bool
{
return $this->children && $this->children->count();
}
/**
* Get the collection of nested items.
*/
public function children(): ?Collection
{
return $this->children;
}
/**
* Attach an array of children to the item.
*/
public function addChildren(array $children): self
{
if (is_null($this->children)) {
$this->children = new Collection;
}
foreach ($children as $child) {
$this->children->push($child);
}
return $this;
}
/**
* Check if the specified user can view the item.
*/
public function authorize(User $user): bool
{
if ($this->permissions instanceof Closure) {
return call_user_func($this->permissions, $user);
}
foreach ((array) $this->permissions as $permission) {
if (! $user->hasPermission($permission)) {
return false;
}
}
return true;
}
}