100, self::ROLE_ADMIN => 75, self::ROLE_MANAGER => 50, self::ROLE_GUEST => 25, ]; /** * Права на действия */ public const PERMISSION_VIEW = 'view'; public const PERMISSION_CREATE = 'create'; public const PERMISSION_EDIT = 'edit'; public const PERMISSION_DELETE = 'delete'; public const PERMISSION_DELETE_ANY = 'delete_any'; public const PERMISSION_MANAGE_USERS = 'manage_users'; public const PERMISSION_MANAGE_MODULES = 'manage_modules'; public const PERMISSION_VIEW_FINANCE = 'view_finance'; public const PERMISSION_DELETE_ORG = 'delete_org'; public const PERMISSION_TRANSFER_OWNER = 'transfer_owner'; /** * Матрица прав по ролям * Формат: [роль => [ресурс => [действия]]] */ private const ROLE_PERMISSIONS = [ self::ROLE_OWNER => [ '*' => ['*'], // Полный доступ ко всему ], self::ROLE_ADMIN => [ 'clients' => ['view', 'create', 'edit', 'delete'], 'deals' => ['view', 'create', 'edit', 'delete'], 'bookings' => ['view', 'create', 'edit', 'delete'], 'projects' => ['view', 'create', 'edit', 'delete'], 'tasks' => ['view', 'create', 'edit', 'delete'], 'users' => [self::PERMISSION_VIEW, self::PERMISSION_CREATE, self::PERMISSION_EDIT, self::PERMISSION_DELETE], self::PERMISSION_MANAGE_MODULES => [self::PERMISSION_VIEW, self::PERMISSION_EDIT], self::PERMISSION_VIEW_FINANCE => ['*'], ], self::ROLE_MANAGER => [ 'clients' => ['view', 'create', 'edit', 'delete'], 'deals' => ['view', 'create', 'edit', 'delete'], 'bookings' => ['view', 'create', 'edit', 'delete'], 'projects' => ['view', 'create', 'edit', 'delete'], 'tasks' => ['view', 'create', 'edit', 'delete'], 'users' => [self::PERMISSION_VIEW], // Только просмотр коллег ], self::ROLE_GUEST => [ 'clients' => [self::PERMISSION_VIEW], 'deals' => [self::PERMISSION_VIEW], 'bookings' => [self::PERMISSION_VIEW], 'projects' => [self::PERMISSION_VIEW], 'tasks' => [self::PERMISSION_VIEW], 'users' => [self::PERMISSION_VIEW], ], ]; public function __construct() { $this->orgUserModel = new OrganizationUserModel(); } /** * Получение единственного экземпляра сервиса * * @return self */ public static function getInstance(): self { return new self(); } /** * Получение текущего membership пользователя * * @return array|null */ public function getCurrentMembership(): ?array { if ($this->currentMembership !== null) { return $this->currentMembership; } $userId = session()->get('user_id'); $orgId = session()->get('active_org_id'); if (!$userId || !$orgId) { return null; } $this->currentMembership = $this->orgUserModel ->where('user_id', $userId) ->where('organization_id', $orgId) ->first(); return $this->currentMembership; } /** * Получение роли текущего пользователя * * @return string|null */ public function getCurrentRole(): ?string { $membership = $this->getCurrentMembership(); return $membership['role'] ?? null; } /** * Проверка, авторизован ли пользователь в организации * * @return bool */ public function isAuthenticated(): bool { return $this->getCurrentMembership() !== null; } /** * Проверка роли пользователя * * @param string|array $roles Роль или массив ролей для проверки * @return bool */ public function isRole($roles): bool { $currentRole = $this->getCurrentRole(); if ($currentRole === null) { return false; } $roles = (array) $roles; return in_array($currentRole, $roles, true); } /** * Проверка, является ли пользователь владельцем * * @return bool */ public function isOwner(): bool { return $this->getCurrentRole() === self::ROLE_OWNER; } /** * Проверка, является ли пользователем администратором * * @return bool */ public function isAdmin(): bool { $role = $this->getCurrentRole(); return $role === self::ROLE_ADMIN || $role === self::ROLE_OWNER; } /** * Проверка, является ли пользователем менеджером или выше * * @return bool */ public function isManagerOrHigher(): bool { $role = $this->getCurrentRole(); return in_array($role, [self::ROLE_OWNER, self::ROLE_ADMIN, self::ROLE_MANAGER], true); } /** * Проверка права на действие * * @param string $action Действие (view, create, edit, delete, delete_any, manage_users, etc.) * @param string $resource Ресурс (clients, deals, bookings, projects, tasks, users) * @return bool */ public function can(string $action, string $resource): bool { $role = $this->getCurrentRole(); if ($role === null) { return false; } $permissions = self::ROLE_PERMISSIONS[$role] ?? []; // Проверка полного доступа (*) if (isset($permissions['*']) && in_array('*', $permissions['*'], true)) { return true; } // Проверка конкретного ресурса if (!isset($permissions[$resource])) { return false; } $resourcePermissions = $permissions[$resource]; // Проверка полного доступа к ресурсу if (in_array('*', $resourcePermissions, true)) { return true; } return in_array($action, $resourcePermissions, true); } /** * Проверка права на просмотр * * @param string $resource * @return bool */ public function canView(string $resource): bool { return $this->can(self::PERMISSION_VIEW, $resource); } /** * Проверка права на создание * * @param string $resource * @return bool */ public function canCreate(string $resource): bool { return $this->can(self::PERMISSION_CREATE, $resource); } /** * Проверка права на редактирование * * @param string $resource * @return bool */ public function canEdit(string $resource): bool { return $this->can(self::PERMISSION_EDIT, $resource); } /** * Проверка права на удаление * * @param string $resource * @param bool $any Удаление любой записи (не только своей) * @return bool */ public function canDelete(string $resource, bool $any = false): bool { $action = $any ? self::PERMISSION_DELETE_ANY : self::PERMISSION_DELETE; return $this->can($action, $resource); } /** * Проверка права на управление пользователями * * Управление пользователями недоступно для личных пространств. * * @return bool */ public function canManageUsers(): bool { // Проверяем, что это бизнес-организация (не личное пространство) $orgId = session()->get('active_org_id'); if (!$orgId) { return false; } $orgModel = new \App\Models\OrganizationModel(); $organization = $orgModel->find($orgId); // Личное пространство - управление пользователями недоступно if ($organization && $organization['type'] === 'personal') { return false; } return $this->can(self::PERMISSION_MANAGE_USERS, 'users'); } /** * Проверка права на управление модулями * * @return bool */ public function canManageModules(): bool { return $this->can(self::PERMISSION_MANAGE_MODULES, self::PERMISSION_MANAGE_MODULES); } /** * Проверка права на просмотр финансов * * @return bool */ public function canViewFinance(): bool { return $this->can(self::PERMISSION_VIEW_FINANCE, self::PERMISSION_VIEW_FINANCE); } /** * Проверка права на удаление организации * * @return bool */ public function canDeleteOrganization(): bool { return $this->isOwner(); } /** * Проверка права на передачу прав владельца * * @return bool */ public function canTransferOwnership(): bool { return $this->isOwner(); } /** * Получение роли для передачи прав владельца (список допустимых ролей) * * @return array */ public function getRolesEligibleForOwnershipTransfer(): array { // Только admin может стать новым владельцем return [self::ROLE_ADMIN]; } /** * Получение уровня роли (для сравнения) * * @param string $role * @return int */ public function getRoleLevel(string $role): int { return self::ROLE_HIERARCHY[$role] ?? 0; } /** * Проверка, имеет ли роль достаточно прав для сравнения * * @param string $role * @param string $requiredRole * @return bool */ public function hasRoleLevel(string $role, string $requiredRole): bool { return $this->getRoleLevel($role) >= $this->getRoleLevel($requiredRole); } /** * Получение списка доступных ролей для назначения * * @param string $assignerRole Роль назначающего * @return array */ public function getAvailableRolesForAssignment(string $assignerRole): array { $allRoles = [self::ROLE_ADMIN, self::ROLE_MANAGER, self::ROLE_GUEST]; // Owner может назначать любые роли if ($assignerRole === self::ROLE_OWNER) { return $allRoles; } // Admin не может назначать owner if ($assignerRole === self::ROLE_ADMIN) { return [self::ROLE_ADMIN, self::ROLE_MANAGER, self::ROLE_GUEST]; } // Manager и Guest не могут назначать роли return []; } /** * Сброс кэша membership (при переключении организации) * * @return void */ public function resetCache(): void { $this->currentMembership = null; } /** * Получение текстового названия роли * * @param string $role * @return string */ public function getRoleLabel(string $role): string { $labels = [ self::ROLE_OWNER => 'Владелец', self::ROLE_ADMIN => 'Администратор', self::ROLE_MANAGER => 'Менеджер', self::ROLE_GUEST => 'Гость', ]; return $labels[$role] ?? $role; } /** * Получение всех ролей с описаниями * * @return array */ public static function getAllRoles(): array { return [ self::ROLE_OWNER => [ 'label' => 'Владелец', 'description' => 'Полный доступ к организации', 'level' => 100, ], self::ROLE_ADMIN => [ 'label' => 'Администратор', 'description' => 'Управление пользователями и модулями', 'level' => 75, ], self::ROLE_MANAGER => [ 'label' => 'Менеджер', 'description' => 'Полный доступ к функционалу модулей', 'level' => 50, ], self::ROLE_GUEST => [ 'label' => 'Гость', 'description' => 'Только просмотр данных', 'level' => 25, ], ]; } }