*/ use HasFactory, Notifiable; /** * Check if user is an admin. */ public function isAdmin(): bool { return $this->role === 'admin' || $this->hasRole('admin'); } /** * Check if the user has a specific role by name. */ public function hasRole(string $roleName): bool { if ($this->roles->isEmpty()) { $defaultRoleName = \App\Models\Setting::get('default_role', 'Developer'); return strtolower($roleName) === strtolower($defaultRoleName); } return $this->roles->contains(function ($r) use ($roleName) { return strtolower($r->name) === strtolower($roleName); }); } /** * Get the roles assigned to this user. */ public function roles() { return $this->belongsToMany(Role::class, 'role_user'); } /** * Get the app overrides (allow/deny) for this user. */ public function overrides() { return $this->hasMany(UserAppOverride::class); } /** * Get the personal custom apps for this user. */ public function personalApps() { return $this->hasMany(PersonalApp::class); } /** * Get the authorized apps for this user, computed from roles and overrides. */ public function authorizedApps() { if ($this->isAdmin()) { return App::orderBy('name', 'asc')->get(); } $roleIds = $this->roles()->pluck('roles.id')->toArray(); // If no roles are assigned, fallback to configured default role first if (empty($roleIds)) { $defaultRoleName = \App\Models\Setting::get('default_role', 'Developer'); $defaultRole = \App\Models\Role::where('name', $defaultRoleName)->first(); if ($defaultRole) { $roleIds = [$defaultRole->id]; } } // Get apps associated with user's roles $roleAppIds = \DB::table('app_role') ->whereIn('role_id', $roleIds) ->pluck('app_id') ->toArray(); // If still no roles/apps resolved, user gets default access to Outlook email and Drive apps if registered if (empty($roleAppIds)) { $defaultAppIds = App::where(function ($query) { $query->whereRaw('LOWER(name) LIKE ?', ['%outlook%']) ->orWhereRaw('LOWER(name) LIKE ?', ['%mail%']) ->orWhereRaw('LOWER(name) LIKE ?', ['%email%']) ->orWhereRaw('LOWER(name) LIKE ?', ['%drive%']) ->orWhereRaw('LOWER(name) LIKE ?', ['%onedrive%']) ->orWhereRaw('LOWER(tag) LIKE ?', ['%outlook%']) ->orWhereRaw('LOWER(tag) LIKE ?', ['%mail%']) ->orWhereRaw('LOWER(tag) LIKE ?', ['%email%']) ->orWhereRaw('LOWER(tag) LIKE ?', ['%drive%']) ->orWhereRaw('LOWER(tag) LIKE ?', ['%onedrive%']); })->pluck('id')->toArray(); $roleAppIds = array_unique(array_merge($roleAppIds, $defaultAppIds)); } // Get user overrides $overrides = $this->overrides()->get(); $allowedAppIds = $overrides->where('type', 'allow')->pluck('app_id')->toArray(); $deniedAppIds = $overrides->where('type', 'deny')->pluck('app_id')->toArray(); // Compute final allowed app IDs: (Role Apps + Allowed Overrides) - Denied Overrides $finalAppIds = array_diff( array_unique(array_merge($roleAppIds, $allowedAppIds)), $deniedAppIds ); return App::whereIn('id', $finalAppIds)->orderBy('name', 'asc')->get(); } /** * Check if user is authorized to manage Onboarding & Offboarding. */ public function canManageOnboarding(): bool { // 1. Module must be enabled in system settings if (\App\Models\Setting::get('onboarding_enabled', '1') !== '1') { return false; } // 2. Admins always have access if ($this->isAdmin()) { return true; } // 3. User with 'hr' role or any role having can_manage_onboarding = true if (strtolower($this->role) === 'hr') { return true; } return $this->roles()->where(function ($q) { $q->whereRaw('LOWER(name) LIKE ?', ['%hr%']) ->orWhere('can_manage_onboarding', true); })->exists(); } /** * Check if user can view temporary "Interview Zone" tab based on assigned active timelines. */ public function hasActiveInterviewZone(): bool { if ($this->isAdmin() || strtolower($this->role) === 'hr') { return Interview::all()->contains(function ($interview) { return $interview->isActiveTimeline(); }); } return Interview::all()->contains(function ($interview) { return $interview->isActiveTimeline() && $interview->isAssignedInterviewer($this->id); }); } /** * Get interviews accessible to this user based on assignment. */ public function getAccessibleInterviews() { if ($this->isAdmin() || strtolower($this->role) === 'hr') { return Interview::with(['creator', 'warnings.sender']) ->orderBy('created_at', 'desc') ->get(); } return Interview::with(['creator', 'warnings.sender']) ->orderBy('created_at', 'desc') ->get() ->filter(function ($interview) { return $interview->isAssignedInterviewer($this->id); }); } /** * Check if user is authorized to access and manage Client Calls. * PM, TL, Director, Admin, and assigned personnel. */ public function canAccessClientCalls(): bool { if ($this->isAdmin()) { return true; } $allowedRolePatterns = ['pm', 'project manager', 'tl', 'team lead', 'lead', 'director', 'management', 'head']; // Check direct role column foreach ($allowedRolePatterns as $pattern) { if (str_contains(strtolower($this->role ?? ''), $pattern)) { return true; } } // Check assigned roles return $this->roles()->where(function ($q) use ($allowedRolePatterns) { foreach ($allowedRolePatterns as $pattern) { $q->orWhereRaw('LOWER(name) LIKE ?', ['%' . $pattern . '%']); } })->exists(); } /** * Get accessible clients for this user. */ public function getAccessibleClients() { if ($this->isAdmin() || $this->hasRole('director') || str_contains(strtolower($this->role ?? ''), 'director')) { return \App\Models\Client::with(['responsibleUser', 'creator', 'meetings', 'callNotes']) ->orderBy('created_at', 'desc') ->get(); } return \App\Models\Client::with(['responsibleUser', 'creator', 'meetings', 'callNotes']) ->orderBy('created_at', 'desc') ->get() ->filter(function ($client) { return $client->responsible_user_id === $this->id || $client->created_by === $this->id || (is_array($client->assigned_team_members) && in_array($this->id, $client->assigned_team_members)); }); } /** * Get the attributes that should be cast. * * @return array */ protected function casts(): array { return [ 'email_verified_at' => 'datetime', 'password' => 'hashed', ]; } }