setPermissionsTeamId($tenantId); } /** 유저 로드 (존재 체크) */ protected static function loadUserOrError(int $userId): ?User { return User::find($userId); } /** 입력으로 받은 role_names[] 또는 role_ids[] → 실제 역할 이름 배열로 변환(검증 포함) */ protected static function resolveRoleNames(int $tenantId, array $params): array { $names = []; // A) role_names[] 직접 if (! empty($params['role_names']) && is_array($params['role_names'])) { foreach ($params['role_names'] as $n) { if (is_string($n) && $n !== '') { $names[] = trim($n); } } } // B) role_ids[] → 이름으로 변환 if (! empty($params['role_ids']) && is_array($params['role_ids'])) { $ids = array_values(array_unique(array_map('intval', $params['role_ids']))); if (! empty($ids)) { $rows = Role::query() ->where('tenant_id', $tenantId) ->where('guard_name', self::$guard) ->whereIn('id', $ids) ->pluck('name') ->all(); $names = array_merge($names, $rows); } } // 정제 $names = array_values(array_unique(array_filter($names))); // 존재 확인(필요시 에러 처리 확장 가능) if (! empty($names)) { $count = Role::query() ->where('tenant_id', $tenantId) ->where('guard_name', self::$guard) ->whereIn('name', $names) ->count(); // if ($count !== count($names)) { ... 필요시 상세 에러 반환 } } return $names; } /** 목록 */ public static function list(int $userId) { $tenantId = (int) app('tenant_id'); $user = self::loadUserOrError($userId); if (! $user) { return ['error' => '사용자를 찾을 수 없습니다.', 'code' => 404]; } self::setTeam($tenantId); // 현재 테넌트의 역할만 $builder = $user->roles() ->where('roles.tenant_id', $tenantId) ->where('roles.guard_name', self::$guard) ->select(['roles.id', 'roles.tenant_id', 'roles.name', 'roles.description', 'roles.guard_name', 'roles.created_at', 'roles.updated_at']) ->orderBy('roles.id', 'desc'); return $builder->get(); } /** 부여 (중복 무시) */ public static function grant(int $userId, array $params = []) { $tenantId = (int) app('tenant_id'); $user = self::loadUserOrError($userId); if (! $user) { return ['error' => '사용자를 찾을 수 없습니다.', 'code' => 404]; } $v = Validator::make($params, [ 'role_names' => 'sometimes|array', 'role_names.*' => 'string|min:1', 'role_ids' => 'sometimes|array', 'role_ids.*' => 'integer|min:1', ]); if ($v->fails()) { return ['error' => $v->errors()->first(), 'code' => 422]; } if (empty($params['role_names']) && empty($params['role_ids'])) { return ['error' => 'role_names 또는 role_ids 중 하나는 필요합니다.', 'code' => 422]; } self::setTeam($tenantId); $names = self::resolveRoleNames($tenantId, $params); if (empty($names)) { return ['error' => '유효한 역할이 없습니다.', 'code' => 422]; } $user->assignRole($names); // teams 컨텍스트 적용됨 return 'success'; } /** 회수 (없는 건 무시) */ public static function revoke(int $userId, array $params = []) { $tenantId = (int) app('tenant_id'); $user = self::loadUserOrError($userId); if (! $user) { return ['error' => '사용자를 찾을 수 없습니다.', 'code' => 404]; } $v = Validator::make($params, [ 'role_names' => 'sometimes|array', 'role_names.*' => 'string|min:1', 'role_ids' => 'sometimes|array', 'role_ids.*' => 'integer|min:1', ]); if ($v->fails()) { return ['error' => $v->errors()->first(), 'code' => 422]; } if (empty($params['role_names']) && empty($params['role_ids'])) { return ['error' => 'role_names 또는 role_ids 중 하나는 필요합니다.', 'code' => 422]; } self::setTeam($tenantId); $names = self::resolveRoleNames($tenantId, $params); if (empty($names)) { return ['error' => '유효한 역할이 없습니다.', 'code' => 422]; } $user->removeRole($names); // 배열 허용 return 'success'; } /** 동기화(완전 교체) */ public static function sync(int $userId, array $params = []) { $tenantId = (int) app('tenant_id'); $user = self::loadUserOrError($userId); if (! $user) { return ['error' => '사용자를 찾을 수 없습니다.', 'code' => 404]; } $v = Validator::make($params, [ 'role_names' => 'sometimes|array', 'role_names.*' => 'string|min:1', 'role_ids' => 'sometimes|array', 'role_ids.*' => 'integer|min:1', ]); if ($v->fails()) { return ['error' => $v->errors()->first(), 'code' => 422]; } if (empty($params['role_names']) && empty($params['role_ids'])) { return ['error' => 'role_names 또는 role_ids 중 하나는 필요합니다.', 'code' => 422]; } self::setTeam($tenantId); $names = self::resolveRoleNames($tenantId, $params); if (empty($names)) { // 정책상 빈 목록 sync 허용 시: $user->syncRoles([]) 로 전부 제거 가능 return ['error' => '유효한 역할이 없습니다.', 'code' => 422]; } $user->syncRoles($names); return 'success'; } }