diff --git a/app/Data/Ui/Dashboard/ServiceAppDto.php b/app/Data/Ui/Dashboard/ServiceAppDto.php new file mode 100644 index 0000000..495e1c3 --- /dev/null +++ b/app/Data/Ui/Dashboard/ServiceAppDto.php @@ -0,0 +1,19 @@ +contains(DefaultUserRole::Admin->value)) { return 'dashboard.admin'; } - if ($roles->contains(DefaultUserRole::User->value)) { - return 'dashboard.user'; - } - return 'home'; + return 'dashboard.user'; } } diff --git a/app/Services/UserAppAccessService.php b/app/Services/UserAppAccessService.php new file mode 100644 index 0000000..268f3e3 --- /dev/null +++ b/app/Services/UserAppAccessService.php @@ -0,0 +1,137 @@ + + */ + public function getActiveServices(User $user): Collection + { + $user->loadMissing(['roles.apps', 'roles.permissions']); + + $restrictedPermissions = $this->getRestrictedPermissions($user); + + /** @var Collection $appsMap */ + $appsMap = collect(); + + /** @var Collection $roles */ + $roles = $user->roles; + + foreach ($roles as $role) { + /** @var Collection $apps */ + $apps = $role->apps; + + foreach ($apps as $app) { + if ($this->isAppRestrictedForRole($role, $app, $restrictedPermissions)) { + continue; + } + + /** @var mixed $pivot */ + $pivot = $app->pivot; + $durationStr = (string) $pivot->duration; + + $daysRemaining = $this->getDaysRemainingIfActive($durationStr); + + // If null is returned, the app has expired. + if (null === $daysRemaining) { + continue; + } + + $this->addOrUpdateAppInMap($appsMap, $app, $durationStr, $daysRemaining); + } + } + + return $appsMap->values(); + } + + /** + * Retrieves a map of restricted permissions for the user, grouped by role ID. + * + * * @return array> + */ + private function getRestrictedPermissions(User $user): array + { + return RestrictedUserPermission::query() + ->where('user_id', $user->id) + ->get() + ->groupBy('role_id') + ->map(fn ($item) => $item->pluck('permission_id')->all()) + ->all(); + } + + /** + * Checks if the app is restricted for the given role. + * + * * @param array> $restrictedPermissions + */ + private function isAppRestrictedForRole(Role $role, ConnectedApp $app, array $restrictedPermissions): bool + { + $permissionName = AppPermission::name(ConnectedAppPermissonEnum::Use, ConnectedAppData::from($app)); + $permission = $role->permissions->firstWhere('name', $permissionName); + + if (! $permission) { + return false; + } + + return isset($restrictedPermissions[$role->id]) + && in_array($permission->id, $restrictedPermissions[$role->id], true); + } + + /** + * Calculates the days remaining. Returns null if the duration has expired. + */ + private function getDaysRemainingIfActive(string $durationStr): ?int + { + $duration = Carbon::parse($durationStr); + $now = now(); + + if ($duration->isPast()) { + return null; + } + + $daysRemaining = (int) $now->diffInDays($duration, false); + + if (0 === $daysRemaining && $now->lt($duration)) { + return 1; + } + + return $daysRemaining; + } + + /** + * Adds the app to the map or updates it if the new duration is greater than the existing one. + * + * * @param Collection $appsMap + */ + private function addOrUpdateAppInMap(Collection $appsMap, ConnectedApp $app, string $durationStr, int $daysRemaining): void + { + /** @var ServiceAppDto|null $existing */ + $existing = $appsMap->get($app->id); + $duration = Carbon::parse($durationStr); + + if (! $existing || Carbon::parse($existing->duration)->lt($duration)) { + $appsMap->put($app->id, new ServiceAppDto( + id: $app->id, + name: $app->name, + slug: $app->slug, + duration: $durationStr, + days_remaining: $daysRemaining, + is_warning: $daysRemaining <= 3, + )); + } + } +} diff --git a/resources/views/pages/dashboards/⚡user.blade.php b/resources/views/pages/dashboards/⚡user.blade.php index f5c4ef9..3488706 100644 --- a/resources/views/pages/dashboards/⚡user.blade.php +++ b/resources/views/pages/dashboards/⚡user.blade.php @@ -1,13 +1,140 @@ service = $service; + } + + public function mount(): void + { + $user = auth()->user(); + + // Using spatie/laravel-activitylog v5 to log dashboard access + if ($user) { + activity() + ->causedBy($user) + ->event('dashboard_access') + ->log('User accessed their assigned services dashboard.'); + } + } + + #[Computed] + public function services(): Collection + { + $user = auth()->user(); + + if (!$user) { + return collect(); + } + + return $this->service->getActiveServices($user); + } }; ?> -
- {{-- People find pleasure in different ways. I find it in keeping my mind clear. - Marcus Aurelius --}} -
\ No newline at end of file +
+ + + +

+ Manage and access your authenticated single sign-on services. +

+
+
+ +
+ + Active Account + + + + {{ now()->format('F j, Y') }} + +
+
+ + @if($this->services->isEmpty()) + +
+ +
+

No Active Services Assigned

+

+ Your account does not currently have any active or visible services assigned by your role, or your + access duration has expired. +

+ + To request access to specific applications, please contact your system administrator or IT helpdesk with + your account details + +
+ @else +
+ @foreach($this->services as $service) + + + @if($service->is_warning) + + + Expiring Soon + + @else + + Active + + @endif + + +
+
+

+ {{ $service->slug }} +

+
+ +
+
+ + + {{ $service->days_remaining }} {{ Str::plural('day', $service->days_remaining) }} left + +
+ + +
+
+
+ @endforeach +
+ @endif +