119 lines
4.2 KiB
PHP
119 lines
4.2 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace MintyPHP\Service;
|
||
|
|
|
||
|
|
use MintyPHP\Repository\TenantDepartmentRepository;
|
||
|
|
use MintyPHP\Repository\UserTenantRepository;
|
||
|
|
use MintyPHP\Repository\TenantRepository;
|
||
|
|
use MintyPHP\Service\PermissionService;
|
||
|
|
|
||
|
|
class TenantScopeService
|
||
|
|
{
|
||
|
|
public static function isStrict(): bool
|
||
|
|
{
|
||
|
|
return defined('TENANT_SCOPE_STRICT') ? (bool) TENANT_SCOPE_STRICT : true;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function getUserTenantIds(int $userId, bool $onlyActive = true): array
|
||
|
|
{
|
||
|
|
if ($userId <= 0) {
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
if (self::canBypass($userId)) {
|
||
|
|
$ids = TenantRepository::listIds();
|
||
|
|
} else {
|
||
|
|
$ids = array_values(array_unique(array_map('intval', UserTenantRepository::listTenantIdsByUserId($userId))));
|
||
|
|
}
|
||
|
|
if ($onlyActive) {
|
||
|
|
return self::filterActiveTenantIds($ids);
|
||
|
|
}
|
||
|
|
return $ids;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function canAccess(string $resource, int $resourceId, int $userId): bool
|
||
|
|
{
|
||
|
|
if ($resourceId <= 0 || $userId <= 0) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (self::canBypass($userId)) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
$resourceTenantIdsRaw = self::getResourceTenantIds($resource, $resourceId);
|
||
|
|
$userTenantIdsRaw = self::getUserTenantIds($userId, false);
|
||
|
|
$resourceTenantIds = self::filterActiveTenantIds($resourceTenantIdsRaw);
|
||
|
|
$userTenantIds = self::filterActiveTenantIds($userTenantIdsRaw);
|
||
|
|
|
||
|
|
if ($resourceTenantIdsRaw && !$resourceTenantIds) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (!$resourceTenantIds) {
|
||
|
|
return self::isStrict() ? false : true;
|
||
|
|
}
|
||
|
|
if (!$userTenantIds) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return (bool) array_intersect($resourceTenantIds, $userTenantIds);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function filterTenantIdsForUser(array $tenantIds, int $userId): array
|
||
|
|
{
|
||
|
|
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
|
||
|
|
$userTenantIds = self::getUserTenantIds($userId);
|
||
|
|
if (!$userTenantIds) {
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
return array_values(array_intersect($tenantIds, $userTenantIds));
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function mergeTenantIdsPreservingOutOfScope(array $requestedTenantIds, array $existingTenantIds, array $allowedTenantIds): array
|
||
|
|
{
|
||
|
|
$requestedTenantIds = array_values(array_unique(array_map('intval', $requestedTenantIds)));
|
||
|
|
$existingTenantIds = array_values(array_unique(array_map('intval', $existingTenantIds)));
|
||
|
|
$allowedTenantIds = array_values(array_unique(array_map('intval', $allowedTenantIds)));
|
||
|
|
|
||
|
|
if (!$allowedTenantIds) {
|
||
|
|
return $existingTenantIds;
|
||
|
|
}
|
||
|
|
$outOfScope = array_values(array_diff($existingTenantIds, $allowedTenantIds));
|
||
|
|
return array_values(array_unique(array_merge($requestedTenantIds, $outOfScope)));
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function hasGlobalAccess(int $userId): bool
|
||
|
|
{
|
||
|
|
return self::canBypass($userId);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static function getResourceTenantIds(string $resource, int $resourceId): array
|
||
|
|
{
|
||
|
|
$resource = strtolower(trim($resource));
|
||
|
|
if ($resource === 'tenants') {
|
||
|
|
return $resourceId > 0 ? [$resourceId] : [];
|
||
|
|
}
|
||
|
|
if ($resource === 'users') {
|
||
|
|
return array_values(array_unique(array_map('intval', UserTenantRepository::listTenantIdsByUserId($resourceId))));
|
||
|
|
}
|
||
|
|
if ($resource === 'departments') {
|
||
|
|
return array_values(array_unique(array_map('intval', TenantDepartmentRepository::listTenantIdsByDepartmentId($resourceId))));
|
||
|
|
}
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
|
||
|
|
private static function filterActiveTenantIds(array $tenantIds): array
|
||
|
|
{
|
||
|
|
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
|
||
|
|
if (!$tenantIds) {
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
return TenantRepository::listActiveIdsByIds($tenantIds);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static function canBypass(int $userId): bool
|
||
|
|
{
|
||
|
|
if ($userId <= 0) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return PermissionService::userHas($userId, PermissionService::TENANTS_UPDATE)
|
||
|
|
|| PermissionService::userHas($userId, PermissionService::SETTINGS_UPDATE);
|
||
|
|
}
|
||
|
|
}
|