instances added god may help

This commit is contained in:
2026-02-23 12:58:19 +01:00
parent 25370a1a55
commit 99db252f60
290 changed files with 9858 additions and 4914 deletions

View File

@@ -1,103 +1,13 @@
<?php
use MintyPHP\Router;
use MintyPHP\Support\Guard;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\User\UserAvatarService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
use MintyPHP\Service\AddressBook\AddressBookServicesFactory;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::ADDRESS_BOOK_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$limit = (int) ($_GET['limit'] ?? 10);
$offset = (int) ($_GET['offset'] ?? 0);
$search = trim((string) ($_GET['search'] ?? ''));
$order = (string) ($_GET['order'] ?? 'last_name');
$dir = (string) ($_GET['dir'] ?? 'asc');
$tenant = trim((string) ($_GET['tenant'] ?? ''));
$tenants = $_GET['tenants'] ?? '';
$departments = $_GET['departments'] ?? '';
$roles = $_GET['roles'] ?? '';
$customFieldFilterSpec = UserCustomFieldValueService::extractAddressBookFilterSpec($_GET, $currentUserId);
$result = UserService::listPaged([
'limit' => $limit,
'offset' => $offset,
'search' => $search,
'order' => $order,
'dir' => $dir,
'tenant' => $tenant,
'tenants' => $tenants,
'departments' => $departments,
'roles' => $roles,
'customFieldFilterSpec' => $customFieldFilterSpec,
'tenantUserId' => $currentUserId,
'active' => 'active',
]);
$rows = [];
foreach ($result['rows'] as $row) {
$tenantLabels = $row['tenant_labels'] ?? [];
if (is_string($tenantLabels)) {
$tenantList = $tenantLabels !== ''
? array_values(array_filter(array_map('trim', explode('||', $tenantLabels))))
: [];
} elseif (is_array($tenantLabels)) {
$tenantList = array_values(array_filter(array_map('trim', $tenantLabels)));
} else {
$tenantList = [];
}
$departmentLabels = $row['department_labels'] ?? [];
if (is_string($departmentLabels)) {
$departmentList = $departmentLabels !== ''
? array_values(array_filter(array_map('trim', explode('||', $departmentLabels))))
: [];
} elseif (is_array($departmentLabels)) {
$departmentList = array_values(array_filter(array_map('trim', $departmentLabels)));
} else {
$departmentList = [];
}
$roleLabels = $row['role_labels'] ?? [];
if (is_string($roleLabels)) {
$roleList = $roleLabels !== ''
? array_values(array_filter(array_map('trim', explode('||', $roleLabels))))
: [];
} elseif (is_array($roleLabels)) {
$roleList = array_values(array_filter(array_map('trim', $roleLabels)));
} else {
$roleList = [];
}
$uuid = (string) ($row['uuid'] ?? '');
$displayName = trim((string) ($row['display_name'] ?? ''));
if ($displayName === '') {
$displayName = trim((string) ($row['first_name'] ?? '') . ' ' . (string) ($row['last_name'] ?? ''));
}
if ($displayName === '') {
$displayName = (string) ($row['email'] ?? '');
}
$rows[] = [
'uuid' => $uuid,
'display_name' => $displayName,
'first_name' => $row['first_name'] ?? '',
'last_name' => $row['last_name'] ?? '',
'email' => $row['email'] ?? '',
'phone' => $row['phone'] ?? '',
'mobile' => $row['mobile'] ?? '',
'short_dial' => $row['short_dial'] ?? '',
'tenants' => $tenantList,
'departments' => $departmentList,
'roles' => $roleList,
'has_avatar' => $uuid !== '' && UserAvatarService::hasAvatar($uuid),
];
}
Router::json([
'data' => $rows,
'total' => $result['total'] ?? 0,
]);
$addressBookService = (new AddressBookServicesFactory())->createAddressBookService();
Router::json($addressBookService->buildGridResult($currentUserId, $_GET));

View File

@@ -1,110 +1,26 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Support\Guard;
use MintyPHP\Session;
use MintyPHP\Repository\CustomField\TenantCustomFieldOptionRepository;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\AddressBook\AddressBookServicesFactory;
use MintyPHP\Session;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::ADDRESS_BOOK_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$activeTenants = array_filter(array_map('trim', explode(',', (string) ($_GET['tenants'] ?? ''))));
$activeRoles = array_filter(array_map('trim', explode(',', (string) ($_GET['roles'] ?? ''))));
$activeDepartments = array_filter(array_map('trim', explode(',', (string) ($_GET['departments'] ?? ''))));
$tenantIds = TenantScopeService::getUserTenantIds($currentUserId);
$tenants = TenantService::list();
if ($tenantIds) {
$tenants = array_values(array_filter($tenants, static function (array $tenant) use ($tenantIds): bool {
$id = (int) ($tenant['id'] ?? 0);
return $id > 0 && in_array($id, $tenantIds, true);
}));
} elseif (TenantScopeService::isStrict()) {
$tenants = [];
}
$tenantItems = array_map(
static fn (array $tenant): array => [
'id' => (string) ($tenant['uuid'] ?? ''),
'description' => $tenant['description'] ?? '',
],
$tenants
);
$departments = $tenantIds
? DepartmentService::listByTenantIds($tenantIds)
: (TenantScopeService::isStrict() ? [] : DepartmentService::list());
$roles = RoleService::listActive();
$customFieldFilterSpec = UserCustomFieldValueService::extractAddressBookFilterSpec($_GET, $currentUserId);
$customFieldFilterDefinitions = $customFieldFilterSpec['definitions'] ?? [];
$customFieldFilterQuery = $customFieldFilterSpec['query'] ?? [];
$customFieldDefinitionIds = [];
foreach ($customFieldFilterDefinitions as $definition) {
$definitionId = (int) ($definition['id'] ?? 0);
if ($definitionId > 0) {
$customFieldDefinitionIds[] = $definitionId;
}
}
$customFieldDefinitionIds = array_values(array_unique($customFieldDefinitionIds));
$customFieldOptions = TenantCustomFieldOptionRepository::listByDefinitionIds($customFieldDefinitionIds, true);
$customFieldOptionsByDefinition = [];
foreach ($customFieldOptions as $option) {
$definitionId = (int) ($option['definition_id'] ?? 0);
if ($definitionId <= 0) {
continue;
}
$customFieldOptionsByDefinition[$definitionId] ??= [];
$customFieldOptionsByDefinition[$definitionId][] = [
'id' => (string) ((int) ($option['id'] ?? 0)),
'description' => (string) ($option['label'] ?? ''),
];
}
$tenantLabelById = [];
foreach ($tenants as $tenant) {
$tenantId = (int) ($tenant['id'] ?? 0);
if ($tenantId <= 0) {
continue;
}
$tenantLabelById[$tenantId] = (string) ($tenant['description'] ?? '');
}
foreach ($customFieldFilterDefinitions as &$definition) {
$definitionId = (int) ($definition['id'] ?? 0);
$tenantId = (int) ($definition['tenant_id'] ?? 0);
$definition['options'] = $customFieldOptionsByDefinition[$definitionId] ?? [];
$definition['tenant_label'] = $tenantLabelById[$tenantId] ?? '';
}
unset($definition);
$tenantDepartmentMap = [];
if ($tenantIds) {
$departmentMapByTenantId = [];
foreach ($departments as $department) {
$departmentId = (int) ($department['id'] ?? 0);
$departmentTenantId = (int) ($department['tenant_id'] ?? 0);
if ($departmentId <= 0 || $departmentTenantId <= 0) {
continue;
}
$departmentMapByTenantId[$departmentTenantId] ??= [];
$departmentMapByTenantId[$departmentTenantId][] = $departmentId;
}
foreach ($tenants as $tenant) {
$tenantId = (int) ($tenant['id'] ?? 0);
$tenantUuid = (string) ($tenant['uuid'] ?? '');
if ($tenantId > 0 && $tenantUuid !== '') {
$tenantDepartmentMap[$tenantUuid] = array_map(
'strval',
$departmentMapByTenantId[$tenantId] ?? []
);
}
}
}
$addressBookService = (new AddressBookServicesFactory())->createAddressBookService();
$context = $addressBookService->buildIndexContext($currentUserId, $_GET);
$activeTenants = $context['activeTenants'] ?? [];
$activeRoles = $context['activeRoles'] ?? [];
$activeDepartments = $context['activeDepartments'] ?? [];
$tenantItems = $context['tenantItems'] ?? [];
$departments = $context['departments'] ?? [];
$roles = $context['roles'] ?? [];
$customFieldFilterDefinitions = $context['customFieldFilterDefinitions'] ?? [];
$customFieldFilterQuery = $context['customFieldFilterQuery'] ?? [];
$tenantDepartmentMap = $context['tenantDepartmentMap'] ?? [];
$csrfKey = Session::$csrfSessionKey;
$csrfToken = $_SESSION[$csrfKey] ?? '';

View File

@@ -1,11 +1,11 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserSavedFilterService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::ADDRESS_BOOK_VIEW);
@@ -91,6 +91,7 @@ if ($userId <= 0) {
Router::redirect('login');
return;
}
$userSavedFilterService = (new UserServicesFactory())->createUserSavedFilterService();
$uuid = trim((string) ($_POST['uuid'] ?? ''));
if ($uuid === '') {
@@ -98,9 +99,9 @@ if ($uuid === '') {
return;
}
$deleted = UserSavedFilterService::deleteAddressBookFilter($userId, $uuid);
$deleted = $userSavedFilterService->deleteAddressBookFilter($userId, $uuid);
if ($deleted) {
$_SESSION['address_book_saved_filters'] = UserSavedFilterService::listForAddressBook($userId);
$_SESSION['address_book_saved_filters'] = $userSavedFilterService->listForAddressBook($userId);
Flash::success(t('Filter deleted'), 'address-book', 'address_book_saved_filter_deleted');
}

View File

@@ -1,11 +1,11 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserSavedFilterService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::ADDRESS_BOOK_VIEW);
@@ -91,9 +91,10 @@ if ($userId <= 0) {
Router::redirect('login');
return;
}
$userSavedFilterService = (new UserServicesFactory())->createUserSavedFilterService();
$name = trim((string) ($_POST['name'] ?? ''));
$result = UserSavedFilterService::saveAddressBookFilter($userId, $name, $_POST);
$result = $userSavedFilterService->saveAddressBookFilter($userId, $name, $_POST);
if (!($result['ok'] ?? false)) {
$error = (string) ($result['error'] ?? '');
@@ -108,6 +109,6 @@ if (!($result['ok'] ?? false)) {
return;
}
$_SESSION['address_book_saved_filters'] = UserSavedFilterService::listForAddressBook($userId);
$_SESSION['address_book_saved_filters'] = $userSavedFilterService->listForAddressBook($userId);
Flash::success(t('Filter saved'), 'address-book', 'address_book_saved_filter_saved');
Router::redirect($redirect);

View File

@@ -1,13 +1,11 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\DB;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\AddressBook\AddressBookServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\User\UserService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::ADDRESS_BOOK_VIEW);
@@ -18,117 +16,21 @@ if ($uuid === '') {
Router::redirect('address-book');
}
$user = UserService::findByUuid($uuid);
if (!$user || !isset($user['id'])) {
$addressBookService = (new AddressBookServicesFactory())->createAddressBookService();
$viewContext = $addressBookService->buildViewContext($currentUserId, $uuid);
$status = (string) ($viewContext['status'] ?? '');
if ($status === 'not_found') {
Flash::error('User not found', 'address-book', 'user_not_found');
Router::redirect('address-book');
}
$userId = (int) ($user['id'] ?? 0);
if ($currentUserId !== $userId && !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if ($status === 'forbidden') {
Router::redirect('error/forbidden');
}
$getRowValue = static function (array $row, string $key): ?string {
foreach ($row as $value) {
if (is_array($value) && array_key_exists($key, $value)) {
return (string) $value[$key];
}
}
if (array_key_exists($key, $row) && !is_array($row[$key])) {
return (string) $row[$key];
}
return null;
};
$extractLabels = static function (array $rows): array {
$labels = [];
foreach ($rows as $row) {
$label = '';
foreach ($row as $value) {
if (is_array($value) && isset($value['description'])) {
$label = (string) $value['description'];
break;
}
}
if ($label === '' && isset($row['description'])) {
$label = (string) $row['description'];
}
if ($label !== '') {
$labels[] = $label;
}
}
return array_values(array_unique($labels));
};
$viewerTenantIds = array_values(array_unique(array_map(
'intval',
TenantScopeService::getUserTenantIds($currentUserId)
)));
$viewerTenantIds = array_values(array_filter($viewerTenantIds, static fn ($id) => $id > 0));
$tenantRows = [];
$departmentRows = [];
if ($viewerTenantIds) {
$tenantPlaceholders = implode(',', array_fill(0, count($viewerTenantIds), '?'));
$tenantRows = call_user_func_array(['MintyPHP\\DB', 'select'], array_merge(
[
'select t.id as id, t.description as description ' .
'from user_tenants ut ' .
"join tenants t on t.id = ut.tenant_id and t.status = 'active' " .
'where ut.user_id = ? and ut.tenant_id in (' . $tenantPlaceholders . ') ' .
'order by t.description asc',
],
array_merge([(string) $userId], array_map('strval', $viewerTenantIds))
));
$departmentRows = call_user_func_array(['MintyPHP\\DB', 'select'], array_merge(
[
'select d.tenant_id as tenant_id, d.description as description ' .
'from user_departments ud ' .
"join departments d on d.id = ud.department_id and d.active = 1 " .
'where ud.user_id = ? and d.tenant_id in (' . $tenantPlaceholders . ') ' .
'order by d.description asc',
],
array_merge([(string) $userId], array_map('strval', $viewerTenantIds))
));
$user = $viewContext['user'] ?? null;
if (!is_array($user)) {
Router::redirect('address-book');
}
$roleRows = DB::select(
'select r.description as description from user_roles ur join roles r on r.id = ur.role_id and r.active = 1 where ur.user_id = ? order by r.description asc',
(string) $userId
);
$departmentMap = [];
foreach (is_array($departmentRows) ? $departmentRows : [] as $row) {
$tenantId = (int) ($getRowValue($row, 'tenant_id') ?? 0);
$label = (string) ($getRowValue($row, 'description') ?? '');
if ($tenantId > 0 && $label !== '') {
$departmentMap[$tenantId][] = $label;
}
}
foreach ($departmentMap as $tenantId => $labels) {
$departmentMap[$tenantId] = array_values(array_unique($labels));
}
$primaryTenantId = (int) ($user['primary_tenant_id'] ?? 0);
$tenantGroups = [];
foreach (is_array($tenantRows) ? $tenantRows : [] as $row) {
$tenantId = (int) ($getRowValue($row, 'id') ?? 0);
$tenantLabel = (string) ($getRowValue($row, 'description') ?? '');
if ($tenantId <= 0 || $tenantLabel === '') {
continue;
}
$tenantGroups[] = [
'label' => $tenantLabel,
'is_primary' => $primaryTenantId > 0 && $tenantId === $primaryTenantId,
'departments' => $departmentMap[$tenantId] ?? [],
];
}
$roleLabels = $extractLabels(is_array($roleRows) ? $roleRows : []);
$user['tenant_groups'] = $tenantGroups;
$user['role_labels'] = $roleLabels;
Buffer::set('style_groups', json_encode(['address-book']));
$name = trim(($user['first_name'] ?? '') . ' ' . ($user['last_name'] ?? ''));

View File

@@ -1,6 +1,5 @@
<?php
use MintyPHP\Service\User\UserAvatarService;
use MintyPHP\I18n;
$values = $user ?? [];
@@ -28,7 +27,7 @@ if ($hireDate !== '') {
}
}
$avatarUuid = (string) ($values['uuid'] ?? '');
$hasAvatar = $avatarUuid !== '' && UserAvatarService::hasAvatar($avatarUuid);
$hasAvatar = !empty($values['has_avatar']) && $avatarUuid !== '';
$initials = '';
if ($displayName !== '') {

View File

@@ -2,8 +2,8 @@
use MintyPHP\Router;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Audit\ApiAuditService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Audit\AuditServicesFactory;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::API_AUDIT_VIEW);
@@ -13,7 +13,8 @@ if (strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')) !== 'GET') {
Router::json(['error' => 'method_not_allowed']);
}
$result = ApiAuditService::listPaged([
$factory = new AuditServicesFactory();
$result = $factory->createApiAuditService()->listPaged([
'limit' => (int) ($_GET['limit'] ?? 20),
'offset' => (int) ($_GET['offset'] ?? 0),
'search' => trim((string) ($_GET['search'] ?? '')),
@@ -69,4 +70,3 @@ Router::json([
'data' => $rows,
'total' => (int) ($result['total'] ?? 0),
]);

View File

@@ -4,8 +4,8 @@ use MintyPHP\Router;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Audit\ApiAuditService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Audit\AuditServicesFactory;
Guard::requireLogin();
Guard::requirePermission(PermissionService::SETTINGS_UPDATE);
@@ -18,6 +18,7 @@ if (!Session::checkCsrfToken()) {
Router::redirect('admin/api-audit');
}
$deleted = ApiAuditService::purgeExpired();
$factory = new AuditServicesFactory();
$deleted = $factory->createApiAuditService()->purgeExpired();
Flash::success(sprintf(t('%d API audit entries purged'), $deleted), 'admin/api-audit', 'api_audit_purged');
Router::redirect('admin/api-audit');

View File

@@ -4,18 +4,18 @@ use MintyPHP\Buffer;
use MintyPHP\Router;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Audit\ApiAuditService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Audit\AuditServicesFactory;
Guard::requireLogin();
Guard::requirePermission(PermissionService::API_AUDIT_VIEW);
$auditId = (int) ($id ?? 0);
$auditLog = $auditId > 0 ? ApiAuditService::find($auditId) : null;
$factory = new AuditServicesFactory();
$auditLog = $auditId > 0 ? $factory->createApiAuditService()->find($auditId) : null;
if (!$auditLog) {
Flash::error('API audit entry not found', 'admin/api-audit', 'api_audit_not_found');
Router::redirect('admin/api-audit');
}
Buffer::set('title', t('View API audit entry'));

View File

@@ -1,20 +1,17 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\Tenant\TenantScopeService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::DEPARTMENTS_CREATE);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$allowedTenantIds = TenantScopeService::getUserTenantIds($currentUserId);
if (TenantScopeService::isStrict() && !$allowedTenantIds) {
$allowedTenantIds = directoryServicesFactory()->createDirectoryScopeGateway()->getUserTenantIds($currentUserId);
if (directoryServicesFactory()->createDirectoryScopeGateway()->isStrict() && !$allowedTenantIds) {
Router::redirect('error/forbidden');
return;
}
@@ -28,24 +25,24 @@ $form = [
'cost_center' => '',
'active' => '1',
];
$tenants = TenantService::list();
$tenants = directoryServicesFactory()->createTenantService()->list();
if ($allowedTenantIds) {
$tenants = array_values(array_filter($tenants, static function (array $tenant) use ($allowedTenantIds): bool {
$tenantId = (int) ($tenant['id'] ?? 0);
return $tenantId > 0 && in_array($tenantId, $allowedTenantIds, true);
}));
} elseif (TenantScopeService::isStrict()) {
} elseif (directoryServicesFactory()->createDirectoryScopeGateway()->isStrict()) {
$tenants = [];
}
if (isset($_POST['description'])) {
$selectedTenantId = (int) ($_POST['tenant_id'] ?? 0);
$selectedTenantIds = TenantScopeService::filterTenantIdsForUser([$selectedTenantId], $currentUserId);
$selectedTenantIds = directoryServicesFactory()->createDirectoryScopeGateway()->filterTenantIdsForUser([$selectedTenantId], $currentUserId);
$selectedTenantId = (int) ($selectedTenantIds[0] ?? 0);
$input = $_POST;
$input['tenant_id'] = $selectedTenantId;
$result = DepartmentService::createFromAdmin($input, $currentUserId);
$result = directoryServicesFactory()->createDepartmentService()->createFromAdmin($input, $currentUserId);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];
$warnings = $result['warnings'] ?? [];

View File

@@ -1,18 +1,16 @@
<?php
use MintyPHP\Router;
use MintyPHP\Support\Guard;
use MintyPHP\Repository\Org\UserDepartmentRepository;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Settings\SettingService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\Settings\SettingServicesFactory;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::DEPARTMENTS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$tenantIds = TenantScopeService::getUserTenantIds($currentUserId);
$tenantIds = directoryServicesFactory()->createDirectoryScopeGateway()->getUserTenantIds($currentUserId);
$limit = (int) ($_GET['limit'] ?? 10);
$offset = (int) ($_GET['offset'] ?? 0);
@@ -22,7 +20,7 @@ $dir = (string) ($_GET['dir'] ?? 'asc');
$tenant = trim((string) ($_GET['tenant'] ?? ''));
$active = trim((string) ($_GET['active'] ?? ''));
$result = DepartmentService::listPaged([
$result = directoryServicesFactory()->createDepartmentService()->listPaged([
'limit' => $limit,
'offset' => $offset,
'search' => $search,
@@ -34,7 +32,9 @@ $result = DepartmentService::listPaged([
'tenantUserId' => $currentUserId,
]);
$defaultDepartmentId = SettingService::getDefaultDepartmentId();
$settingsFactory = new SettingServicesFactory();
$settingGateway = $settingsFactory->createSettingGateway();
$defaultDepartmentId = $settingGateway->getDefaultDepartmentId();
$departmentIds = [];
foreach ($result['rows'] as $departmentRow) {
$departmentId = (int) ($departmentRow['id'] ?? 0);
@@ -43,8 +43,9 @@ foreach ($result['rows'] as $departmentRow) {
}
}
$departmentIds = array_values(array_unique($departmentIds));
$departmentUserCounts = UserDepartmentRepository::countUsersByDepartmentIds($departmentIds);
$departmentActiveUserCounts = UserDepartmentRepository::countActiveUsersByDepartmentIds($departmentIds);
$userDepartmentRepository = (new UserServicesFactory())->createUserDepartmentRepository();
$departmentUserCounts = $userDepartmentRepository->countUsersByDepartmentIds($departmentIds);
$departmentActiveUserCounts = $userDepartmentRepository->countActiveUsersByDepartmentIds($departmentIds);
$rows = [];
foreach ($result['rows'] as $row) {

View File

@@ -1,12 +1,10 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Auth\AuthService;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantScopeService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::DEPARTMENTS_DELETE);
@@ -17,20 +15,20 @@ if ($uuid === '') {
}
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$department = $uuid !== '' ? DepartmentService::findByUuid($uuid) : null;
if ($department && !TenantScopeService::canAccess('departments', (int) ($department['id'] ?? 0), $currentUserId)) {
$department = $uuid !== '' ? directoryServicesFactory()->createDepartmentService()->findByUuid($uuid) : null;
if ($department && !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('departments', (int) ($department['id'] ?? 0), $currentUserId)) {
Router::redirect('error/forbidden');
return;
}
$result = DepartmentService::deleteByUuid($uuid);
$result = directoryServicesFactory()->createDepartmentService()->deleteByUuid($uuid);
if (!($result['ok'] ?? false)) {
Flash::error('Department not found', 'admin/departments', 'department_not_found');
Router::redirect('admin/departments');
}
if ($currentUserId > 0) {
AuthService::loadTenantDataIntoSession($currentUserId);
(new AuthServicesFactory())->createAuthService()->loadTenantDataIntoSession($currentUserId);
}
Flash::success('Department deleted', 'admin/departments', 'department_deleted');

View File

@@ -1,39 +1,37 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantScopeService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::DEPARTMENTS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
$allowedTenantIds = TenantScopeService::getUserTenantIds($currentUserId);
$userAccountService = (new UserServicesFactory())->createUserAccountService();
$allowedTenantIds = directoryServicesFactory()->createDirectoryScopeGateway()->getUserTenantIds($currentUserId);
$uuid = trim((string) ($id ?? ''));
$department = $uuid !== '' ? DepartmentService::findByUuid($uuid) : null;
$department = $uuid !== '' ? directoryServicesFactory()->createDepartmentService()->findByUuid($uuid) : null;
if (!$department) {
Flash::error('Department not found', 'admin/departments', 'department_not_found');
Router::redirect('admin/departments');
}
$departmentId = (int) ($department['id'] ?? 0);
if (!TenantScopeService::canAccess('departments', $departmentId, $currentUserId)) {
if (!directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('departments', $departmentId, $currentUserId)) {
Router::redirect('error/forbidden');
return;
}
$creatorId = (int) ($department['created_by'] ?? 0);
if ($creatorId > 0) {
$creator = UserService::findById($creatorId);
$creator = $userAccountService->findById($creatorId);
if ($creator) {
$creatorName = trim(($creator['first_name'] ?? '') . ' ' . ($creator['last_name'] ?? ''));
$department['created_by_label'] = $creatorName !== '' ? $creatorName : ($creator['email'] ?? '');
@@ -42,7 +40,7 @@ if ($creatorId > 0) {
}
$modifierId = (int) ($department['modified_by'] ?? 0);
if ($modifierId > 0) {
$modifier = UserService::findById($modifierId);
$modifier = $userAccountService->findById($modifierId);
if ($modifier) {
$modifierName = trim(($modifier['first_name'] ?? '') . ' ' . ($modifier['last_name'] ?? ''));
$department['modified_by_label'] = $modifierName !== '' ? $modifierName : ($modifier['email'] ?? '');
@@ -53,7 +51,7 @@ if ($modifierId > 0) {
$errors = [];
$warnings = [];
$form = $department;
$tenants = TenantService::list();
$tenants = directoryServicesFactory()->createTenantService()->list();
if ($allowedTenantIds) {
$tenants = array_values(array_filter($tenants, static function (array $tenant) use ($allowedTenantIds): bool {
$tenantId = (int) ($tenant['id'] ?? 0);
@@ -62,30 +60,30 @@ if ($allowedTenantIds) {
if (!in_array((int) ($form['tenant_id'] ?? 0), $allowedTenantIds, true)) {
$form['tenant_id'] = 0;
}
} elseif (TenantScopeService::isStrict()) {
} elseif (directoryServicesFactory()->createDirectoryScopeGateway()->isStrict()) {
$tenants = [];
$form['tenant_id'] = 0;
}
if (isset($_POST['description'])) {
if (!PermissionService::userHas($currentUserId, PermissionService::DEPARTMENTS_UPDATE)) {
if (!permissionGateway()->userHas($currentUserId, PermissionService::DEPARTMENTS_UPDATE)) {
Router::redirect('error/forbidden');
return;
}
$selectedTenantId = (int) ($_POST['tenant_id'] ?? 0);
$selectedTenantIds = TenantScopeService::filterTenantIdsForUser([$selectedTenantId], $currentUserId);
$selectedTenantIds = directoryServicesFactory()->createDirectoryScopeGateway()->filterTenantIdsForUser([$selectedTenantId], $currentUserId);
$selectedTenantId = (int) ($selectedTenantIds[0] ?? 0);
$input = $_POST;
$input['tenant_id'] = $selectedTenantId;
$result = DepartmentService::updateFromAdmin($departmentId, $input, $currentUserId);
$result = directoryServicesFactory()->createDepartmentService()->updateFromAdmin($departmentId, $input, $currentUserId);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];
$warnings = $result['warnings'] ?? [];
$form['tenant_id'] = $selectedTenantId;
if (($result['ok'] ?? false) && !$errors) {
$cleaned = DepartmentService::cleanupUserAssignments($departmentId);
$cleaned = directoryServicesFactory()->createDepartmentService()->cleanupUserAssignments($departmentId);
$action = (string) ($_POST['action'] ?? 'save');
if ($cleaned > 0) {
Flash::info(t('Department assignments cleaned: %d', $cleaned), "admin/departments/edit/{$uuid}", 'department_assignments_cleaned');

View File

@@ -1,28 +1,26 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Support\Guard;
use MintyPHP\Session;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Session;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::DEPARTMENTS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
$tenants = TenantService::list();
$allowedTenantIds = TenantScopeService::getUserTenantIds($currentUserId);
$tenants = directoryServicesFactory()->createTenantService()->list();
$allowedTenantIds = directoryServicesFactory()->createDirectoryScopeGateway()->getUserTenantIds($currentUserId);
if ($allowedTenantIds) {
$tenants = array_values(array_filter($tenants, static function (array $tenant) use ($allowedTenantIds): bool {
$tenantId = (int) ($tenant['id'] ?? 0);
return $tenantId > 0 && in_array($tenantId, $allowedTenantIds, true);
}));
} elseif (TenantScopeService::isStrict()) {
} elseif (directoryServicesFactory()->createDirectoryScopeGateway()->isStrict()) {
$tenants = [];
}
usort($tenants, static function ($a, $b) {

View File

@@ -12,22 +12,31 @@
<div class="app-docs-container">
<aside class="app-docs-nav" aria-label="<?php e(t('Documentation navigation')); ?>">
<nav>
<nav data-details-storage="admin-docs-nav-groups-v1">
<?php $groupIndex = 0; ?>
<?php foreach ($docGroups as $groupLabel => $items): ?>
<?php
$groupKey = 'docs-nav-group-' . ((string) (array_key_first($items) ?? $groupIndex));
$groupOpen = array_key_exists($currentSlug, $items);
$groupIndex++;
?>
<div class="app-docs-nav-group">
<small class="muted"><?php e($groupLabel); ?></small>
<ul>
<?php foreach ($items as $docSlug => $label): ?>
<?php $isActive = $docSlug === $currentSlug; ?>
<li>
<a href="<?php e(lurl('admin/docs/' . $docSlug)); ?>"
class="<?php e($isActive ? 'active' : ''); ?>"
<?php if ($isActive): ?>aria-current="page" <?php endif; ?>>
<?php e($label); ?>
</a>
</li>
<?php endforeach; ?>
</ul>
<details data-details-key="<?php e($groupKey); ?>" <?php if ($groupOpen): ?>open<?php endif; ?>>
<summary><small class="muted"><?php e($groupLabel); ?></small></summary>
<ul>
<?php foreach ($items as $docSlug => $label): ?>
<?php $isActive = $docSlug === $currentSlug; ?>
<li>
<a href="<?php e(lurl('admin/docs/' . $docSlug)); ?>"
class="<?php e($isActive ? 'active' : ''); ?>"
<?php if ($isActive): ?>aria-current="page" <?php endif; ?>>
<?php e($label); ?>
</a>
</li>
<?php endforeach; ?>
</ul>
</details>
<hr>
</div>
<?php endforeach; ?>
</nav>

View File

@@ -1,9 +1,9 @@
<?php
use MintyPHP\Router;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Audit\ImportAuditService;
use MintyPHP\Service\Import\ImportServicesFactory;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::IMPORTS_AUDIT_VIEW);
@@ -13,7 +13,10 @@ if (strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')) !== 'GET') {
Router::json(['error' => 'method_not_allowed']);
}
$result = ImportAuditService::listPaged([
$factory = new ImportServicesFactory();
$importAuditService = $factory->createImportAuditService();
$result = $importAuditService->listPaged([
'limit' => (int) ($_GET['limit'] ?? 20),
'offset' => (int) ($_GET['offset'] ?? 0),
'search' => trim((string) ($_GET['search'] ?? '')),

View File

@@ -1,11 +1,11 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Import\ImportServicesFactory;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Audit\ImportAuditService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::SETTINGS_UPDATE);
@@ -18,6 +18,7 @@ if (!Session::checkCsrfToken()) {
Router::redirect('admin/import-audit');
}
$deleted = ImportAuditService::purgeExpired();
$factory = new ImportServicesFactory();
$deleted = $factory->createImportAuditService()->purgeExpired();
Flash::success(sprintf(t('%d import audit entries purged'), $deleted), 'admin/import-audit', 'import_audit_purged');
Router::redirect('admin/import-audit');

View File

@@ -2,16 +2,17 @@
use MintyPHP\Buffer;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Import\ImportServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Audit\ImportAuditService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::IMPORTS_AUDIT_VIEW);
$runId = (int) ($id ?? 0);
$auditRun = $runId > 0 ? ImportAuditService::find($runId) : null;
$factory = new ImportServicesFactory();
$auditRun = $runId > 0 ? $factory->createImportAuditService()->find($runId) : null;
if (!$auditRun) {
Flash::error(t('Import audit entry not found'), 'admin/import-audit', 'import_audit_not_found');
Router::redirect('admin/import-audit');

View File

@@ -1,21 +1,23 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Import\ImportServicesFactory;
use MintyPHP\Session;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Import\ImportService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::IMPORTS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$factory = new ImportServicesFactory();
$importService = $factory->createImportService();
$profileOptions = [];
foreach (ImportService::listProfileOptions() as $option) {
foreach ($importService->listProfileOptions() as $option) {
$key = (string) $option['key'];
$permission = ImportService::requiredPermissionForType($key);
$allowed = $permission !== '' && PermissionService::userHas($currentUserId, $permission);
$permission = $importService->requiredPermissionForType($key);
$allowed = $permission !== '' && permissionGateway()->userHas($currentUserId, $permission);
$profileOptions[] = [
'key' => $key,
'label' => (string) $option['label'],
@@ -31,7 +33,7 @@ if ($allowedProfileOptions) {
}
$selectedType = trim((string) ($_POST['type'] ?? ($_GET['type'] ?? $firstAllowedType)));
if ($selectedType === '' || !ImportService::profile($selectedType)) {
if ($selectedType === '' || !$importService->profile($selectedType)) {
$selectedType = $firstAllowedType;
}
@@ -46,9 +48,9 @@ $result = null;
$csrfKey = Session::$csrfSessionKey;
$csrfToken = $_SESSION[$csrfKey] ?? '';
$hasImportPermission = static function (string $type) use ($currentUserId): bool {
$permission = ImportService::requiredPermissionForType($type);
return $permission !== '' && PermissionService::userHas($currentUserId, $permission);
$hasImportPermission = static function (string $type) use ($currentUserId, $importService): bool {
$permission = $importService->requiredPermissionForType($type);
return $permission !== '' && permissionGateway()->userHas($currentUserId, $permission);
};
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
@@ -59,30 +61,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($selectedType === '' || !$hasImportPermission($selectedType)) {
$errors[] = t('Permission denied');
} else {
$analysis = ImportService::analyzeUpload($_FILES['csv_file'] ?? [], $selectedType, $currentUserId);
$analysis = $importService->analyzeUpload($_FILES['csv_file'] ?? [], $selectedType, $currentUserId);
if (!($analysis['ok'] ?? false)) {
$errors[] = ImportService::messageForCode((string) ($analysis['code'] ?? 'unexpected_error'));
$errors[] = $importService->messageForCode((string) ($analysis['code'] ?? 'unexpected_error'));
} else {
$token = (string) ($analysis['token'] ?? '');
$state = ImportService::state($token);
$state = $importService->state($token);
$mapping = is_array($analysis['auto_mapping'] ?? null) ? $analysis['auto_mapping'] : [];
$step = 'mapping';
}
}
} elseif ($stage === 'preview') {
$token = trim((string) ($_POST['token'] ?? ''));
$state = ImportService::state($token);
$state = $importService->state($token);
$mapping = is_array($_POST['mapping'] ?? null) ? $_POST['mapping'] : [];
if (!$state) {
$errors[] = ImportService::messageForCode('invalid_file_type');
$errors[] = $importService->messageForCode('invalid_file_type');
} else {
$selectedType = (string) ($state['type'] ?? $selectedType);
if ($selectedType === '' || !$hasImportPermission($selectedType)) {
$errors[] = t('Permission denied');
} else {
$preview = ImportService::preview($token, ['mapping' => $mapping], $currentUserId);
$preview = $importService->preview($token, ['mapping' => $mapping], $currentUserId);
if (!($preview['ok'] ?? false)) {
$errors[] = ImportService::messageForCode((string) ($preview['code'] ?? 'unexpected_error'));
$errors[] = $importService->messageForCode((string) ($preview['code'] ?? 'unexpected_error'));
$step = 'mapping';
} else {
$step = 'preview';
@@ -92,17 +94,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} elseif ($stage === 'commit') {
$token = trim((string) ($_POST['token'] ?? ''));
$mapping = is_array($_POST['mapping'] ?? null) ? $_POST['mapping'] : [];
$state = ImportService::state($token);
$state = $importService->state($token);
if (!$state) {
$errors[] = ImportService::messageForCode('invalid_file_type');
$errors[] = $importService->messageForCode('invalid_file_type');
} else {
$selectedType = (string) ($state['type'] ?? $selectedType);
if ($selectedType === '' || !$hasImportPermission($selectedType)) {
$errors[] = t('Permission denied');
} else {
$result = ImportService::commit($token, ['mapping' => $mapping], $currentUserId);
$result = $importService->commit($token, ['mapping' => $mapping], $currentUserId);
if (!($result['ok'] ?? false)) {
$errors[] = ImportService::messageForCode((string) ($result['code'] ?? 'unexpected_error'));
$errors[] = $importService->messageForCode((string) ($result['code'] ?? 'unexpected_error'));
$step = 'mapping';
} else {
$step = 'result';
@@ -113,10 +115,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
}
if ($step === 'mapping' && !$state && $token !== '') {
$state = ImportService::state($token);
$state = $importService->state($token);
}
$activeProfile = $selectedType !== '' ? ImportService::profile($selectedType) : null;
$activeProfile = $selectedType !== '' ? $importService->profile($selectedType) : null;
$allowedTargets = $activeProfile ? $activeProfile->allowedTargets() : [];
$requiredTargets = $activeProfile ? $activeProfile->requiredTargets() : [];
$requiredTargetsHint = implode(', ', $requiredTargets);

View File

@@ -1,8 +1,8 @@
<?php
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Import\ImportService;
use MintyPHP\Service\Import\ImportServicesFactory;
use MintyPHP\Support\Guard;
define('MINTY_ALLOW_OUTPUT', true);
@@ -10,16 +10,18 @@ Guard::requireLogin();
Guard::requirePermission(PermissionService::IMPORTS_VIEW);
$type = trim((string) ($type ?? ''));
$profile = ImportService::profile($type);
$factory = new ImportServicesFactory();
$importService = $factory->createImportService();
$profile = $importService->profile($type);
if (!$profile) {
http_response_code(404);
return;
}
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$requiredPermission = ImportService::requiredPermissionForType($type);
$requiredPermission = $importService->requiredPermissionForType($type);
if ($requiredPermission === '' || !PermissionService::userHas($currentUserId, $requiredPermission)) {
if ($requiredPermission === '' || !permissionGateway()->userHas($currentUserId, $requiredPermission)) {
http_response_code(403);
return;
}

View File

@@ -2,8 +2,8 @@
use MintyPHP\Router;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Mail\MailLogService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Mail\MailServicesFactory;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::MAIL_LOG_VIEW);
@@ -17,7 +17,8 @@ $status = trim((string) ($_GET['status'] ?? ''));
$createdFrom = trim((string) ($_GET['created_from'] ?? ''));
$createdTo = trim((string) ($_GET['created_to'] ?? ''));
$result = MailLogService::listPaged([
$mailLogService = (new MailServicesFactory())->createMailLogService();
$result = $mailLogService->listPaged([
'limit' => $limit,
'offset' => $offset,
'search' => $search,

View File

@@ -10,7 +10,7 @@ Guard::requirePermission(PermissionService::MAIL_LOG_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
Buffer::set('title', t('Mail logs'));

View File

@@ -4,19 +4,20 @@ use MintyPHP\Buffer;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Mail\MailLogService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Mail\MailServicesFactory;
Guard::requireLogin();
Guard::requirePermission(PermissionService::MAIL_LOG_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
$mailLogId = (int) ($id ?? 0);
$mailLog = $mailLogId > 0 ? MailLogService::find($mailLogId) : null;
$mailLogService = (new MailServicesFactory())->createMailLogService();
$mailLog = $mailLogId > 0 ? $mailLogService->find($mailLogId) : null;
if (!$mailLog) {
Flash::error('Mail log not found', 'admin/mail-log', 'mail_log_not_found');
Router::redirect('admin/mail-log');

View File

@@ -18,7 +18,7 @@ $form = [
];
if (isset($_POST['key'])) {
$result = PermissionService::createFromAdmin($_POST);
$result = permissionGateway()->createFromAdmin($_POST);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];

View File

@@ -18,7 +18,7 @@ $order = (string) ($_GET['order'] ?? 'key');
$dir = (string) ($_GET['dir'] ?? 'asc');
$active = (string) ($_GET['active'] ?? '');
$result = PermissionService::listPaged([
$result = permissionGateway()->listPaged([
'limit' => $limit,
'offset' => $offset,
'search' => $search,

View File

@@ -13,7 +13,7 @@ if ($id <= 0) {
Router::redirect('admin/permissions');
}
$result = PermissionService::deleteById($id);
$result = permissionGateway()->deleteById($id);
if (!($result['ok'] ?? false)) {
$error = (string) ($result['error'] ?? '');
if ($error === 'system_permission_protected') {

View File

@@ -1,23 +1,23 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Repository\Access\RoleRepository;
use MintyPHP\Router;
use MintyPHP\Service\Access\AccessServicesFactory;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Repository\Access\RolePermissionRepository;
use MintyPHP\Repository\Access\RoleRepository;
use MintyPHP\Service\Access\PermissionService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::PERMISSIONS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
$id = (int) ($id ?? 0);
$permission = $id > 0 ? PermissionService::find($id) : null;
$permission = $id > 0 ? permissionGateway()->find($id) : null;
if (!$permission) {
Flash::error('Permission not found', 'admin/permissions', 'permission_not_found');
Router::redirect('admin/permissions');
@@ -25,16 +25,17 @@ if (!$permission) {
$errors = [];
$form = $permission;
$roles = RoleRepository::listActive();
$selectedRoleIds = RolePermissionRepository::listRoleIdsByPermissionId($id);
$roles = (new RoleRepository())->listActive();
$rolePermissionRepository = (new AccessServicesFactory())->createRolePermissionRepository();
$selectedRoleIds = $rolePermissionRepository->listRoleIdsByPermissionId($id);
if (isset($_POST['key'])) {
if (!PermissionService::userHas($currentUserId, PermissionService::PERMISSIONS_UPDATE)) {
if (!permissionGateway()->userHas($currentUserId, PermissionService::PERMISSIONS_UPDATE)) {
Flash::error('Permission denied', "admin/permissions/edit/{$id}", 'permission_denied');
Router::redirect("admin/permissions/edit/{$id}");
return;
}
$result = PermissionService::updateFromAdmin($id, $_POST);
$result = permissionGateway()->updateFromAdmin($id, $_POST);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];
$selectedRoleIds = $_POST['role_ids'] ?? $selectedRoleIds;
@@ -49,7 +50,7 @@ if (isset($_POST['key'])) {
$roleIds = [$roleIds];
}
$roleIds = array_values(array_unique(array_map('intval', $roleIds)));
RolePermissionRepository::replaceForPermission($id, $roleIds);
$rolePermissionRepository->replaceForPermission($id, $roleIds);
$action = (string) ($_POST['action'] ?? 'save');
if ($action === 'save_close') {
Flash::success('Permission updated', 'admin/permissions', 'permission_updated');

View File

@@ -10,7 +10,7 @@ Guard::requirePermission(PermissionService::PERMISSIONS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
Buffer::set('title', t('Permissions'));

View File

@@ -1,13 +1,11 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Router;
use MintyPHP\Service\Access\AccessServicesFactory;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Repository\Access\PermissionRepository;
use MintyPHP\Repository\Access\RolePermissionRepository;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\Access\PermissionService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::ROLES_CREATE);
@@ -18,12 +16,15 @@ $form = [
'code' => '',
'active' => 1,
];
$permissions = PermissionRepository::listActive();
$accessServicesFactory = new AccessServicesFactory();
$permissionRepository = $accessServicesFactory->createPermissionRepository();
$rolePermissionRepository = $accessServicesFactory->createRolePermissionRepository();
$permissions = $permissionRepository->listActive();
$selectedPermissionIds = [];
if (isset($_POST['description'])) {
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$result = RoleService::createFromAdmin($_POST, $currentUserId);
$result = directoryServicesFactory()->createRoleService()->createFromAdmin($_POST, $currentUserId);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];
$selectedPermissionIds = $_POST['permission_ids'] ?? $selectedPermissionIds;
@@ -40,7 +41,7 @@ if (isset($_POST['description'])) {
$permissionIds = array_values(array_unique(array_map('intval', $permissionIds)));
$createdId = (int) ($result['id'] ?? 0);
if ($createdId > 0) {
RolePermissionRepository::replaceForRole($createdId, $permissionIds);
$rolePermissionRepository->replaceForRole($createdId, $permissionIds);
}
$action = (string) ($_POST['action'] ?? 'create');
if ($action === 'create_close') {

View File

@@ -1,12 +1,11 @@
<?php
use MintyPHP\Router;
use MintyPHP\Support\Guard;
use MintyPHP\Repository\Access\UserRoleRepository;
use MintyPHP\Repository\Access\RolePermissionRepository;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\Settings\SettingService;
use MintyPHP\Service\Access\AccessServicesFactory;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Settings\SettingServicesFactory;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermission(PermissionService::ROLES_VIEW);
@@ -18,7 +17,7 @@ $order = (string) ($_GET['order'] ?? 'description');
$dir = (string) ($_GET['dir'] ?? 'asc');
$active = (string) ($_GET['active'] ?? '');
$result = RoleService::listPaged([
$result = directoryServicesFactory()->createRoleService()->listPaged([
'limit' => $limit,
'offset' => $offset,
'search' => $search,
@@ -27,7 +26,10 @@ $result = RoleService::listPaged([
'active' => $active,
]);
$defaultRoleId = SettingService::getDefaultRoleId();
$settingsFactory = new SettingServicesFactory();
$settingGateway = $settingsFactory->createSettingGateway();
$defaultRoleId = $settingGateway->getDefaultRoleId();
$rolePermissionRepository = (new AccessServicesFactory())->createRolePermissionRepository();
$roleIds = [];
foreach ($result['rows'] as $roleRow) {
$roleId = (int) ($roleRow['id'] ?? 0);
@@ -36,9 +38,10 @@ foreach ($result['rows'] as $roleRow) {
}
}
$roleIds = array_values(array_unique($roleIds));
$roleUserCounts = UserRoleRepository::countUsersByRoleIds($roleIds);
$roleActiveUserCounts = UserRoleRepository::countActiveUsersByRoleIds($roleIds);
$rolePermissionCounts = RolePermissionRepository::countPermissionsByRoleIds($roleIds);
$userRoleRepository = (new UserServicesFactory())->createUserRoleRepository();
$roleUserCounts = $userRoleRepository->countUsersByRoleIds($roleIds);
$roleActiveUserCounts = $userRoleRepository->countActiveUsersByRoleIds($roleIds);
$rolePermissionCounts = $rolePermissionRepository->countPermissionsByRoleIds($roleIds);
$rows = [];
foreach ($result['rows'] as $row) {

View File

@@ -1,10 +1,9 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\Access\PermissionService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::ROLES_DELETE);
@@ -14,7 +13,7 @@ if ($uuid === '') {
Router::redirect('admin/roles');
}
$result = RoleService::deleteByUuid($uuid);
$result = directoryServicesFactory()->createRoleService()->deleteByUuid($uuid);
if (!($result['ok'] ?? false)) {
$error = $result['error'] ?? 'unknown';
if ($error === 'admin_role_protected') {

View File

@@ -1,26 +1,27 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Router;
use MintyPHP\Service\Access\AccessServicesFactory;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Repository\Access\PermissionRepository;
use MintyPHP\Repository\Access\RolePermissionRepository;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Settings\SettingService;
use MintyPHP\Service\Access\PermissionService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::ROLES_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
$accessServicesFactory = new AccessServicesFactory();
$permissionRepository = $accessServicesFactory->createPermissionRepository();
$rolePermissionRepository = $accessServicesFactory->createRolePermissionRepository();
$userAccountService = (new UserServicesFactory())->createUserAccountService();
$uuid = trim((string) ($id ?? ''));
$role = $uuid !== '' ? RoleService::findByUuid($uuid) : null;
$role = $uuid !== '' ? directoryServicesFactory()->createRoleService()->findByUuid($uuid) : null;
if (!$role) {
Flash::error('Role not found', 'admin/roles', 'role_not_found');
Router::redirect('admin/roles');
@@ -29,7 +30,7 @@ if (!$role) {
$roleId = (int) ($role['id'] ?? 0);
$creatorId = (int) ($role['created_by'] ?? 0);
if ($creatorId > 0) {
$creator = UserService::findById($creatorId);
$creator = $userAccountService->findById($creatorId);
if ($creator) {
$creatorName = trim(($creator['first_name'] ?? '') . ' ' . ($creator['last_name'] ?? ''));
$role['created_by_label'] = $creatorName !== '' ? $creatorName : ($creator['email'] ?? '');
@@ -38,7 +39,7 @@ if ($creatorId > 0) {
}
$modifierId = (int) ($role['modified_by'] ?? 0);
if ($modifierId > 0) {
$modifier = UserService::findById($modifierId);
$modifier = $userAccountService->findById($modifierId);
if ($modifier) {
$modifierName = trim(($modifier['first_name'] ?? '') . ' ' . ($modifier['last_name'] ?? ''));
$role['modified_by_label'] = $modifierName !== '' ? $modifierName : ($modifier['email'] ?? '');
@@ -48,16 +49,16 @@ if ($modifierId > 0) {
$errors = [];
$form = $role;
$permissions = PermissionRepository::listActive();
$selectedPermissionIds = RolePermissionRepository::listPermissionIdsByRoleId($roleId);
$permissions = $permissionRepository->listActive();
$selectedPermissionIds = $rolePermissionRepository->listPermissionIdsByRoleId($roleId);
if (isset($_POST['description'])) {
if (!PermissionService::userHas($currentUserId, PermissionService::ROLES_UPDATE)) {
if (!permissionGateway()->userHas($currentUserId, PermissionService::ROLES_UPDATE)) {
Flash::error('Permission denied', "admin/roles/edit/{$uuid}", 'permission_denied');
Router::redirect("admin/roles/edit/{$uuid}");
return;
}
$result = RoleService::updateFromAdmin($roleId, $_POST, $currentUserId);
$result = directoryServicesFactory()->createRoleService()->updateFromAdmin($roleId, $_POST, $currentUserId);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];
$selectedPermissionIds = $_POST['permission_ids'] ?? $selectedPermissionIds;
@@ -72,7 +73,7 @@ if (isset($_POST['description'])) {
$permissionIds = [$permissionIds];
}
$permissionIds = array_values(array_unique(array_map('intval', $permissionIds)));
RolePermissionRepository::replaceForRole($roleId, $permissionIds);
$rolePermissionRepository->replaceForRole($roleId, $permissionIds);
$action = (string) ($_POST['action'] ?? 'save');
if ($action === 'save_close') {
Flash::success('Role updated', 'admin/roles', 'role_updated');

View File

@@ -10,7 +10,7 @@ Guard::requirePermission(PermissionService::ROLES_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
Buffer::set('title', t('Roles'));

View File

@@ -2,7 +2,7 @@
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Scheduler\ScheduledJobService;
use MintyPHP\Service\Scheduler\SchedulerServicesFactory;
use MintyPHP\Support\Guard;
Guard::requireLogin();
@@ -13,7 +13,10 @@ if (strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')) !== 'GET') {
Router::json(['error' => 'method_not_allowed']);
}
$result = ScheduledJobService::listPaged([
$factory = new SchedulerServicesFactory();
$scheduledJobService = $factory->createScheduledJobService();
$result = $scheduledJobService->listPaged([
'limit' => (int) ($_GET['limit'] ?? 20),
'offset' => (int) ($_GET['offset'] ?? 0),
'search' => trim((string) ($_GET['search'] ?? '')),
@@ -48,7 +51,7 @@ foreach ((array) ($result['rows'] ?? []) as $row) {
'job_key' => $jobKey,
'label' => $jobLabel,
'enabled' => (int) ($row['enabled'] ?? 0),
'schedule_summary' => ScheduledJobService::scheduleSummary($row),
'schedule_summary' => $scheduledJobService->scheduleSummary($row),
'next_run_at' => dt((string) ($row['next_run_at'] ?? '')),
'last_run_finished_at' => dt((string) ($row['last_run_finished_at'] ?? '')),
'last_run_status' => $status,

View File

@@ -2,17 +2,20 @@
use MintyPHP\Buffer;
use MintyPHP\Router;
use MintyPHP\Session;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Scheduler\ScheduledJobService;
use MintyPHP\Service\Scheduler\SchedulerServicesFactory;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermission(PermissionService::JOBS_VIEW);
$factory = new SchedulerServicesFactory();
$scheduledJobService = $factory->createScheduledJobService();
$jobId = (int) ($id ?? 0);
$job = $jobId > 0 ? ScheduledJobService::find($jobId) : null;
$job = $jobId > 0 ? $scheduledJobService->find($jobId) : null;
if (!$job) {
Flash::error(t('Scheduled job not found'), 'admin/scheduled-jobs', 'scheduled_job_not_found');
Router::redirect('admin/scheduled-jobs');
@@ -26,7 +29,7 @@ $form = [
'schedule_type' => (string) ($job['schedule_type'] ?? 'daily'),
'schedule_interval' => (int) ($job['schedule_interval'] ?? 1),
'schedule_time' => (string) ($job['schedule_time'] ?? ''),
'schedule_weekdays' => ScheduledJobService::weekdaysFromCsv((string) ($job['schedule_weekdays_csv'] ?? '')),
'schedule_weekdays' => $scheduledJobService->weekdaysFromCsv((string) ($job['schedule_weekdays_csv'] ?? '')),
'catchup_once' => (int) ($job['catchup_once'] ?? 1),
];
@@ -41,7 +44,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
Router::redirect("admin/scheduled-jobs/edit/$jobId");
}
$saved = ScheduledJobService::updateFromAdmin($jobId, $_POST);
$saved = $scheduledJobService->updateFromAdmin($jobId, $_POST);
if (!($saved['ok'] ?? false)) {
foreach ((array) ($saved['errors'] ?? [t('Scheduled job could not be saved')]) as $error) {
Flash::error((string) $error, "admin/scheduled-jobs/edit/$jobId", 'scheduled_job_save_failed');
@@ -56,11 +59,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'schedule_type' => (string) ($job['schedule_type'] ?? 'daily'),
'schedule_interval' => (int) ($job['schedule_interval'] ?? 1),
'schedule_time' => (string) ($job['schedule_time'] ?? ''),
'schedule_weekdays' => ScheduledJobService::weekdaysFromCsv((string) ($job['schedule_weekdays_csv'] ?? '')),
'schedule_weekdays' => $scheduledJobService->weekdaysFromCsv((string) ($job['schedule_weekdays_csv'] ?? '')),
'catchup_once' => (int) ($job['catchup_once'] ?? 1),
];
}
}
$scheduleSummary = $scheduledJobService->scheduleSummary($job ?? []);
Buffer::set('title', t('Edit scheduled job'));
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));

View File

@@ -1,7 +1,6 @@
<?php
use MintyPHP\Session;
use MintyPHP\Service\Scheduler\ScheduledJobService;
$job = is_array($job ?? null) ? $job : [];
$form = is_array($form ?? null) ? $form : [];
@@ -21,7 +20,7 @@ $weekdayOptions = [
7 => t('Sun'),
];
$status = strtolower(trim((string) ($job['last_run_status'] ?? '')));
$scheduleSummary = ScheduledJobService::scheduleSummary($job);
$scheduleSummary = (string) ($scheduleSummary ?? '-');
$statusVariant = 'neutral';
if ($status === 'success') {
$statusVariant = 'success';
@@ -368,4 +367,4 @@ if ($canRunNow) {
],
urlSync: false
});
</script>
</script>

View File

@@ -1,9 +1,9 @@
<?php
use MintyPHP\Router;
use MintyPHP\Session;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Scheduler\ScheduledJobService;
use MintyPHP\Service\Scheduler\SchedulerServicesFactory;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
@@ -18,6 +18,7 @@ if (!Session::checkCsrfToken()) {
Router::redirect('admin/scheduled-jobs');
}
$deleted = ScheduledJobService::purgeRunsExpired();
$factory = new SchedulerServicesFactory();
$deleted = $factory->createScheduledJobService()->purgeRunsExpired();
Flash::success(sprintf(t('%d scheduler run logs purged'), $deleted), 'admin/scheduled-jobs', 'scheduled_job_runs_purged');
Router::redirect('admin/scheduled-jobs');

View File

@@ -1,9 +1,9 @@
<?php
use MintyPHP\Router;
use MintyPHP\Session;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Scheduler\SchedulerRunService;
use MintyPHP\Service\Scheduler\SchedulerServicesFactory;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
@@ -19,7 +19,8 @@ if (!Session::checkCsrfToken()) {
Router::redirect("admin/scheduled-jobs/edit/$jobId");
}
$result = SchedulerRunService::runJobNow($jobId, (int) ($_SESSION['user']['id'] ?? 0));
$factory = new SchedulerServicesFactory();
$result = $factory->createSchedulerRunService()->runJobNow($jobId, (int) ($_SESSION['user']['id'] ?? 0));
if (!($result['ok'] ?? false)) {
$error = (string) ($result['error'] ?? '');
if ($error === 'lock_not_acquired') {

View File

@@ -2,7 +2,7 @@
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Scheduler\ScheduledJobService;
use MintyPHP\Service\Scheduler\SchedulerServicesFactory;
use MintyPHP\Support\Guard;
Guard::requireLogin();
@@ -18,7 +18,8 @@ if ($jobId <= 0) {
Router::json(['data' => [], 'total' => 0]);
}
$result = ScheduledJobService::listRunsByJobId($jobId, [
$factory = new SchedulerServicesFactory();
$result = $factory->createScheduledJobService()->listRunsByJobId($jobId, [
'limit' => (int) ($_GET['limit'] ?? 10),
'offset' => (int) ($_GET['offset'] ?? 0),
'search' => trim((string) ($_GET['search'] ?? '')),

View File

@@ -1,18 +1,18 @@
<?php
use MintyPHP\Router;
use MintyPHP\Support\Guard;
use MintyPHP\Support\SearchConfig;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\DB;
use MintyPHP\I18n;
use MintyPHP\Repository\Tenant\UserTenantRepository;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Guard;
use MintyPHP\Support\SearchConfig;
Guard::requireLogin();
$userId = (int) ($_SESSION['user']['id'] ?? 0);
if ($userId > 0) {
PermissionService::getUserPermissions($userId);
permissionGateway()->getUserPermissions($userId);
}
$query = trim((string) ($_GET['q'] ?? ''));
@@ -22,7 +22,8 @@ if ($query === '') {
$previewLimit = 5;
$locale = I18n::$locale ?? (I18n::$defaultLocale ?? 'de');
$tenantIds = $userId > 0 ? UserTenantRepository::listTenantIdsByUserId($userId) : [];
$userTenantRepository = (new UserServicesFactory())->createUserTenantRepository();
$tenantIds = $userId > 0 ? $userTenantRepository->listTenantIdsByUserId($userId) : [];
$tenantScoped = !empty($tenantIds);
$tenantScopeFilters = SearchConfig::tenantScopeFilters();
@@ -42,7 +43,7 @@ foreach ($resources as $resource) {
}
$perm = (string) ($resource['permission'] ?? '');
if ($perm !== '' && !PermissionService::userHas($userId, $perm)) {
if ($perm !== '' && !permissionGateway()->userHas($userId, $perm)) {
continue;
}
@@ -94,7 +95,7 @@ if ($hotkeyResource !== null) {
$results[] = $hotkeyResource;
}
if (PermissionService::userHas($userId, PermissionService::DOCS_VIEW)) {
if (permissionGateway()->userHas($userId, PermissionService::DOCS_VIEW)) {
$docsResource = SearchConfig::docsPreviewResource($query);
if ($docsResource !== null) {
$results[] = $docsResource;

View File

@@ -1,10 +1,10 @@
<?php
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\RememberMeService;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermission(PermissionService::SETTINGS_UPDATE);
@@ -13,6 +13,7 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
Router::redirect('admin/settings');
}
$count = RememberMeService::expireAllTokensByAdmin();
$rememberMeService = (new AuthServicesFactory())->createRememberMeService();
$count = $rememberMeService->expireAllTokensByAdmin();
Flash::success(sprintf(t('%d login tokens expired'), $count), 'admin/settings', 'login_tokens_expired');
Router::redirect('admin/settings');

View File

@@ -1,7 +1,7 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Branding\BrandingFaviconService;
use MintyPHP\Service\Branding\BrandingServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
@@ -14,7 +14,8 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
return;
}
$result = BrandingFaviconService::saveUpload($_FILES['favicon'] ?? []);
$faviconService = (new BrandingServicesFactory())->createBrandingFaviconService();
$result = $faviconService->saveUpload($_FILES['favicon'] ?? []);
if (!($result['ok'] ?? false)) {
$error = $result['error'] ?? t('Upload failed');
Flash::error($error, 'admin/settings', 'favicon_upload_failed');

View File

@@ -1,7 +1,7 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Branding\BrandingFaviconService;
use MintyPHP\Service\Branding\BrandingServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
@@ -14,6 +14,7 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
return;
}
BrandingFaviconService::delete();
$faviconService = (new BrandingServicesFactory())->createBrandingFaviconService();
$faviconService->delete();
Flash::success('Favicon removed', 'admin/settings', 'favicon_removed');
Router::redirect('admin/settings');

View File

@@ -1,24 +1,27 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Repository\Auth\ApiTokenRepository;
use MintyPHP\Repository\Auth\RememberTokenRepository;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Settings\SettingService;
use MintyPHP\Service\Settings\SettingServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Settings\SettingService;
use MintyPHP\Service\Settings\SettingCacheService;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Repository\Auth\RememberTokenRepository;
use MintyPHP\Repository\Auth\ApiTokenRepository;
Guard::requireLogin();
Guard::requirePermission(PermissionService::SETTINGS_VIEW);
$tenants = TenantService::list();
$roles = RoleService::listActive();
$departments = DepartmentService::list();
$rememberTokenRepository = new RememberTokenRepository();
$apiTokenRepository = new ApiTokenRepository();
$settingsFactory = new SettingServicesFactory();
$settingGateway = $settingsFactory->createSettingGateway();
$settingCacheService = $settingsFactory->createSettingCacheService();
$tenants = directoryServicesFactory()->createTenantService()->list();
$roles = directoryServicesFactory()->createRoleService()->listActive();
$departments = directoryServicesFactory()->createDepartmentService()->list();
$sortByDescription = static function ($a, $b) {
return strcmp((string) ($a['description'] ?? ''), (string) ($b['description'] ?? ''));
@@ -28,57 +31,57 @@ usort($roles, $sortByDescription);
usort($departments, $sortByDescription);
$values = [
'default_tenant_id' => SettingService::getDefaultTenantId(),
'default_role_id' => SettingService::getDefaultRoleId(),
'default_department_id' => SettingService::getDefaultDepartmentId(),
'default_tenant_id' => $settingGateway->getDefaultTenantId(),
'default_role_id' => $settingGateway->getDefaultRoleId(),
'default_department_id' => $settingGateway->getDefaultDepartmentId(),
// Read raw values for form display so existing DB values are always visible.
'app_title' => SettingService::getValue(SettingService::APP_TITLE_KEY),
'app_locale' => SettingService::getValue(SettingService::APP_LOCALE_KEY),
'app_theme' => SettingService::getValue(SettingService::APP_THEME_KEY),
'app_theme_user' => SettingService::isUserThemeAllowed(),
'app_registration' => SettingService::isRegistrationEnabled(),
'app_primary_color' => SettingService::getValue(SettingService::APP_PRIMARY_COLOR_KEY),
'api_token_default_ttl_days' => SettingService::getApiTokenDefaultTtlDays(),
'api_token_max_ttl_days' => SettingService::getApiTokenMaxTtlDays(),
'user_inactivity_deactivate_days' => SettingService::getUserInactivityDeactivateDays(),
'user_inactivity_delete_days' => SettingService::getUserInactivityDeleteDays(),
'api_cors_allowed_origins' => SettingService::getApiCorsAllowedOriginsText(),
'microsoft_shared_client_id' => SettingService::getValue(SettingService::MICROSOFT_SHARED_CLIENT_ID_KEY),
'microsoft_authority' => SettingService::getMicrosoftAuthority(),
'smtp_host' => SettingService::getValue(SettingService::SMTP_HOST_KEY),
'smtp_port' => SettingService::getValue(SettingService::SMTP_PORT_KEY),
'smtp_user' => SettingService::getValue(SettingService::SMTP_USER_KEY),
'smtp_secure' => SettingService::getSmtpSecure(),
'smtp_from' => SettingService::getValue(SettingService::SMTP_FROM_KEY),
'smtp_from_name' => SettingService::getValue(SettingService::SMTP_FROM_NAME_KEY),
'app_title' => $settingGateway->getValue(SettingService::APP_TITLE_KEY),
'app_locale' => $settingGateway->getValue(SettingService::APP_LOCALE_KEY),
'app_theme' => $settingGateway->getValue(SettingService::APP_THEME_KEY),
'app_theme_user' => $settingGateway->isUserThemeAllowed(),
'app_registration' => $settingGateway->isRegistrationEnabled(),
'app_primary_color' => $settingGateway->getValue(SettingService::APP_PRIMARY_COLOR_KEY),
'api_token_default_ttl_days' => $settingGateway->getApiTokenDefaultTtlDays(),
'api_token_max_ttl_days' => $settingGateway->getApiTokenMaxTtlDays(),
'user_inactivity_deactivate_days' => $settingGateway->getUserInactivityDeactivateDays(),
'user_inactivity_delete_days' => $settingGateway->getUserInactivityDeleteDays(),
'api_cors_allowed_origins' => $settingGateway->getApiCorsAllowedOriginsText(),
'microsoft_shared_client_id' => $settingGateway->getValue(SettingService::MICROSOFT_SHARED_CLIENT_ID_KEY),
'microsoft_authority' => $settingGateway->getMicrosoftAuthority(),
'smtp_host' => $settingGateway->getValue(SettingService::SMTP_HOST_KEY),
'smtp_port' => $settingGateway->getValue(SettingService::SMTP_PORT_KEY),
'smtp_user' => $settingGateway->getValue(SettingService::SMTP_USER_KEY),
'smtp_secure' => $settingGateway->getSmtpSecure(),
'smtp_from' => $settingGateway->getValue(SettingService::SMTP_FROM_KEY),
'smtp_from_name' => $settingGateway->getValue(SettingService::SMTP_FROM_NAME_KEY),
];
$activeLoginTokens = RememberTokenRepository::countActive();
$activeApiTokens = ApiTokenRepository::countActive();
$activeLoginTokens = $rememberTokenRepository->countActive();
$activeApiTokens = $apiTokenRepository->countActive();
$settings = [
'default_tenant' => SettingService::get(SettingService::DEFAULT_TENANT_KEY),
'default_role' => SettingService::get(SettingService::DEFAULT_ROLE_KEY),
'default_department' => SettingService::get(SettingService::DEFAULT_DEPARTMENT_KEY),
'app_title' => SettingService::get(SettingService::APP_TITLE_KEY),
'app_locale' => SettingService::get(SettingService::APP_LOCALE_KEY),
'app_theme' => SettingService::get(SettingService::APP_THEME_KEY),
'app_theme_user' => SettingService::get(SettingService::APP_THEME_USER_KEY),
'app_registration' => SettingService::get(SettingService::APP_REGISTRATION_KEY),
'app_primary_color' => SettingService::get(SettingService::APP_PRIMARY_COLOR_KEY),
'api_token_default_ttl_days' => SettingService::get(SettingService::API_TOKEN_DEFAULT_TTL_DAYS_KEY),
'api_token_max_ttl_days' => SettingService::get(SettingService::API_TOKEN_MAX_TTL_DAYS_KEY),
'user_inactivity_deactivate_days' => SettingService::get(SettingService::USER_INACTIVITY_DEACTIVATE_DAYS_KEY),
'user_inactivity_delete_days' => SettingService::get(SettingService::USER_INACTIVITY_DELETE_DAYS_KEY),
'api_cors_allowed_origins' => SettingService::get(SettingService::API_CORS_ALLOWED_ORIGINS_KEY),
'microsoft_shared_client_id' => SettingService::get(SettingService::MICROSOFT_SHARED_CLIENT_ID_KEY),
'microsoft_shared_client_secret_enc' => SettingService::get(SettingService::MICROSOFT_SHARED_CLIENT_SECRET_ENC_KEY),
'microsoft_authority' => SettingService::get(SettingService::MICROSOFT_AUTHORITY_KEY),
'smtp_host' => SettingService::get(SettingService::SMTP_HOST_KEY),
'smtp_port' => SettingService::get(SettingService::SMTP_PORT_KEY),
'smtp_user' => SettingService::get(SettingService::SMTP_USER_KEY),
'smtp_password' => SettingService::get(SettingService::SMTP_PASSWORD_KEY),
'smtp_secure' => SettingService::get(SettingService::SMTP_SECURE_KEY),
'smtp_from' => SettingService::get(SettingService::SMTP_FROM_KEY),
'smtp_from_name' => SettingService::get(SettingService::SMTP_FROM_NAME_KEY),
'default_tenant' => $settingGateway->get(SettingService::DEFAULT_TENANT_KEY),
'default_role' => $settingGateway->get(SettingService::DEFAULT_ROLE_KEY),
'default_department' => $settingGateway->get(SettingService::DEFAULT_DEPARTMENT_KEY),
'app_title' => $settingGateway->get(SettingService::APP_TITLE_KEY),
'app_locale' => $settingGateway->get(SettingService::APP_LOCALE_KEY),
'app_theme' => $settingGateway->get(SettingService::APP_THEME_KEY),
'app_theme_user' => $settingGateway->get(SettingService::APP_THEME_USER_KEY),
'app_registration' => $settingGateway->get(SettingService::APP_REGISTRATION_KEY),
'app_primary_color' => $settingGateway->get(SettingService::APP_PRIMARY_COLOR_KEY),
'api_token_default_ttl_days' => $settingGateway->get(SettingService::API_TOKEN_DEFAULT_TTL_DAYS_KEY),
'api_token_max_ttl_days' => $settingGateway->get(SettingService::API_TOKEN_MAX_TTL_DAYS_KEY),
'user_inactivity_deactivate_days' => $settingGateway->get(SettingService::USER_INACTIVITY_DEACTIVATE_DAYS_KEY),
'user_inactivity_delete_days' => $settingGateway->get(SettingService::USER_INACTIVITY_DELETE_DAYS_KEY),
'api_cors_allowed_origins' => $settingGateway->get(SettingService::API_CORS_ALLOWED_ORIGINS_KEY),
'microsoft_shared_client_id' => $settingGateway->get(SettingService::MICROSOFT_SHARED_CLIENT_ID_KEY),
'microsoft_shared_client_secret_enc' => $settingGateway->get(SettingService::MICROSOFT_SHARED_CLIENT_SECRET_ENC_KEY),
'microsoft_authority' => $settingGateway->get(SettingService::MICROSOFT_AUTHORITY_KEY),
'smtp_host' => $settingGateway->get(SettingService::SMTP_HOST_KEY),
'smtp_port' => $settingGateway->get(SettingService::SMTP_PORT_KEY),
'smtp_user' => $settingGateway->get(SettingService::SMTP_USER_KEY),
'smtp_password' => $settingGateway->get(SettingService::SMTP_PASSWORD_KEY),
'smtp_secure' => $settingGateway->get(SettingService::SMTP_SECURE_KEY),
'smtp_from' => $settingGateway->get(SettingService::SMTP_FROM_KEY),
'smtp_from_name' => $settingGateway->get(SettingService::SMTP_FROM_NAME_KEY),
];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
@@ -122,23 +125,23 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$microsoftSharedClientSecret = (string) ($_POST['microsoft_shared_client_secret'] ?? '');
$microsoftAuthority = trim((string) ($_POST['microsoft_authority'] ?? ''));
SettingService::setDefaultTenantId($defaultTenantId > 0 ? $defaultTenantId : null);
SettingService::setDefaultRoleId($defaultRoleId > 0 ? $defaultRoleId : null);
SettingService::setDefaultDepartmentId($defaultDepartmentId > 0 ? $defaultDepartmentId : null);
SettingService::setAppTitle($appTitle);
SettingService::setAppLocale($appLocale);
SettingService::setAppTheme($appTheme);
SettingService::setUserThemeAllowed($appThemeUser);
SettingService::setRegistrationEnabled($appRegistration);
$apiTokenMaxTtlOk = SettingService::setApiTokenMaxTtlDays($apiTokenMaxTtlDays > 0 ? $apiTokenMaxTtlDays : null);
$settingGateway->setDefaultTenantId($defaultTenantId > 0 ? $defaultTenantId : null);
$settingGateway->setDefaultRoleId($defaultRoleId > 0 ? $defaultRoleId : null);
$settingGateway->setDefaultDepartmentId($defaultDepartmentId > 0 ? $defaultDepartmentId : null);
$settingGateway->setAppTitle($appTitle);
$settingGateway->setAppLocale($appLocale);
$settingGateway->setAppTheme($appTheme);
$settingGateway->setUserThemeAllowed($appThemeUser);
$settingGateway->setRegistrationEnabled($appRegistration);
$apiTokenMaxTtlOk = $settingGateway->setApiTokenMaxTtlDays($apiTokenMaxTtlDays > 0 ? $apiTokenMaxTtlDays : null);
if (!$apiTokenMaxTtlOk) {
Flash::error('API token max lifetime is invalid', 'admin/settings', 'api_token_max_ttl_invalid');
}
$apiTokenTtlOk = SettingService::setApiTokenDefaultTtlDays($apiTokenDefaultTtlDays > 0 ? $apiTokenDefaultTtlDays : null);
$apiTokenTtlOk = $settingGateway->setApiTokenDefaultTtlDays($apiTokenDefaultTtlDays > 0 ? $apiTokenDefaultTtlDays : null);
if (!$apiTokenTtlOk) {
Flash::error('API token default lifetime is invalid', 'admin/settings', 'api_token_default_ttl_invalid');
}
$userDeactivateOk = SettingService::setUserInactivityDeactivateDays($userInactivityDeactivateDays);
$userDeactivateOk = $settingGateway->setUserInactivityDeactivateDays($userInactivityDeactivateDays);
if (!$userDeactivateOk) {
Flash::error(
'User inactivity deactivation period is invalid',
@@ -147,7 +150,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
);
}
if ($userInactivityDeactivateDays > 0) {
$userDeleteOk = SettingService::setUserInactivityDeleteDays($userInactivityDeleteDays);
$userDeleteOk = $settingGateway->setUserInactivityDeleteDays($userInactivityDeleteDays);
if (!$userDeleteOk) {
Flash::error(
'User inactivity deletion period is invalid',
@@ -163,52 +166,52 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'user_inactivity_delete_requires_deactivate'
);
}
SettingService::setUserInactivityDeleteDays(0);
$settingGateway->setUserInactivityDeleteDays(0);
}
$apiCorsOriginsOk = SettingService::setApiCorsAllowedOrigins($apiCorsAllowedOrigins);
$apiCorsOriginsOk = $settingGateway->setApiCorsAllowedOrigins($apiCorsAllowedOrigins);
if (!$apiCorsOriginsOk) {
Flash::error('CORS allowed origins are invalid', 'admin/settings', 'api_cors_allowed_origins_invalid');
}
$primaryOk = SettingService::setAppPrimaryColor($appPrimaryColor);
$primaryOk = $settingGateway->setAppPrimaryColor($appPrimaryColor);
if (!$primaryOk) {
$appPrimaryColor = '';
Flash::error('Primary color is invalid', 'admin/settings', 'app_primary_invalid');
}
SettingService::setSmtpHost($smtpHost);
SettingService::setSmtpPort($smtpPort > 0 ? $smtpPort : null);
SettingService::setSmtpUser($smtpUser);
$settingGateway->setSmtpHost($smtpHost);
$settingGateway->setSmtpPort($smtpPort > 0 ? $smtpPort : null);
$settingGateway->setSmtpUser($smtpUser);
if (trim($smtpPassword) !== '') {
SettingService::setSmtpPassword($smtpPassword);
$settingGateway->setSmtpPassword($smtpPassword);
}
SettingService::setSmtpSecure($smtpSecure);
SettingService::setSmtpFrom($smtpFrom);
SettingService::setSmtpFromName($smtpFromName);
$msClientIdOk = SettingService::setMicrosoftSharedClientId($microsoftSharedClientId);
$settingGateway->setSmtpSecure($smtpSecure);
$settingGateway->setSmtpFrom($smtpFrom);
$settingGateway->setSmtpFromName($smtpFromName);
$msClientIdOk = $settingGateway->setMicrosoftSharedClientId($microsoftSharedClientId);
if (!$msClientIdOk) {
Flash::error('Microsoft client ID is invalid', 'admin/settings', 'microsoft_client_id_invalid');
}
$msAuthorityOk = SettingService::setMicrosoftAuthority($microsoftAuthority);
$msAuthorityOk = $settingGateway->setMicrosoftAuthority($microsoftAuthority);
if (!$msAuthorityOk) {
Flash::error('Microsoft authority is invalid', 'admin/settings', 'microsoft_authority_invalid');
}
if (trim($microsoftSharedClientSecret) !== '') {
try {
SettingService::setMicrosoftSharedClientSecret($microsoftSharedClientSecret);
$settingGateway->setMicrosoftSharedClientSecret($microsoftSharedClientSecret);
} catch (\Throwable $exception) {
Flash::error('Microsoft client secret could not be encrypted', 'admin/settings', 'microsoft_client_secret_invalid');
}
}
SettingCacheService::update([
$settingCacheService->update([
'app_title' => $appTitle !== '' ? $appTitle : null,
'app_locale' => $appLocale !== '' ? $appLocale : null,
'app_theme' => $appTheme !== '' ? $appTheme : null,
'app_theme_user' => $appThemeUser ? '1' : '0',
'app_registration' => $appRegistration ? '1' : '0',
'app_primary_color' => $appPrimaryColor !== '' ? $appPrimaryColor : null,
'api_token_default_ttl_days' => (string) SettingService::getApiTokenDefaultTtlDays(),
'api_token_max_ttl_days' => (string) SettingService::getApiTokenMaxTtlDays(),
'api_cors_allowed_origins' => SettingService::getValue(SettingService::API_CORS_ALLOWED_ORIGINS_KEY),
'api_token_default_ttl_days' => (string) $settingGateway->getApiTokenDefaultTtlDays(),
'api_token_max_ttl_days' => (string) $settingGateway->getApiTokenMaxTtlDays(),
'api_cors_allowed_origins' => $settingGateway->getValue(SettingService::API_CORS_ALLOWED_ORIGINS_KEY),
]);
Flash::success('Settings updated', 'admin/settings', 'settings_updated');

View File

@@ -9,8 +9,7 @@
*/
use MintyPHP\Session;
use MintyPHP\Service\Branding\BrandingLogoService;
use MintyPHP\Service\Branding\BrandingFaviconService;
use MintyPHP\Service\Branding\BrandingServicesFactory;
$values = $values ?? [];
$settings = $settings ?? [];
@@ -64,8 +63,9 @@ $smtpSecureDesc = $settings['smtp_secure']['description'] ?? 'setting.smtp_secur
$smtpFromDesc = $settings['smtp_from']['description'] ?? 'setting.smtp_from';
$smtpFromNameDesc = $settings['smtp_from_name']['description'] ?? 'setting.smtp_from_name';
$locales = defined('APP_LOCALES') ? APP_LOCALES : [];
$hasLogo = BrandingLogoService::hasLogo();
$hasFavicon = BrandingFaviconService::hasFavicon();
$brandingServicesFactory = new BrandingServicesFactory();
$hasLogo = $brandingServicesFactory->createBrandingLogoService()->hasLogo();
$hasFavicon = $brandingServicesFactory->createBrandingFaviconService()->hasFavicon();
$canUpdateSettings = can('settings.update');
$isReadOnly = !$canUpdateSettings;
$readonlyAttr = $isReadOnly ? 'readonly' : '';

View File

@@ -1,7 +1,7 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Branding\BrandingLogoService;
use MintyPHP\Service\Branding\BrandingServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
@@ -14,7 +14,8 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
return;
}
$result = BrandingLogoService::saveUpload($_FILES['logo'] ?? []);
$logoService = (new BrandingServicesFactory())->createBrandingLogoService();
$result = $logoService->saveUpload($_FILES['logo'] ?? []);
if (!($result['ok'] ?? false)) {
$error = $result['error'] ?? t('Upload failed');
Flash::error($error, 'admin/settings', 'logo_upload_failed');

View File

@@ -1,7 +1,7 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Branding\BrandingLogoService;
use MintyPHP\Service\Branding\BrandingServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
@@ -14,6 +14,7 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
return;
}
BrandingLogoService::delete();
$logoService = (new BrandingServicesFactory())->createBrandingLogoService();
$logoService->delete();
Flash::success('Logo removed', 'admin/settings', 'logo_removed');
Router::redirect('admin/settings');

View File

@@ -1,10 +1,10 @@
<?php
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\ApiTokenService;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermission(PermissionService::SETTINGS_UPDATE);
@@ -13,6 +13,7 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
Router::redirect('admin/settings');
}
$count = ApiTokenService::revokeAllByAdmin();
$apiTokenService = (new AuthServicesFactory())->createApiTokenService();
$count = $apiTokenService->revokeAllByAdmin();
Flash::success(sprintf(t('%d API tokens revoked'), $count), 'admin/settings', 'api_tokens_revoked');
Router::redirect('admin/settings');

View File

@@ -1,10 +1,10 @@
<?php
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserLifecycleService;
use MintyPHP\Service\Scheduler\SchedulerServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermission(PermissionService::SETTINGS_UPDATE);
@@ -13,7 +13,8 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
Router::redirect('admin/settings');
}
$result = UserLifecycleService::run((int) ($_SESSION['user']['id'] ?? 0));
$factory = new SchedulerServicesFactory();
$result = $factory->createUserLifecycleService()->run((int) ($_SESSION['user']['id'] ?? 0));
if (!($result['ok'] ?? false)) {
$error = (string) ($result['error'] ?? 'unexpected_error');
if ($error === 'lock_not_acquired') {
@@ -34,4 +35,3 @@ Flash::success(
'user_lifecycle_completed'
);
Router::redirect('admin/settings');

View File

@@ -16,9 +16,10 @@
* @var array $ssoUiState
*/
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Session;
use MintyPHP\Service\Auth\TenantSsoService;
$tenantSsoService = (new AuthServicesFactory())->createTenantSsoService();
$values = $values ?? [];
$formId = $formId ?? 'tenant-form';
$detailsOpenAll = $detailsOpenAll ?? false;
@@ -60,13 +61,13 @@ $useSharedApp = !in_array(strtolower(trim((string) $useSharedAppRaw)), ['0', 'fa
$clientIdOverride = trim((string) ($values['client_id_override'] ?? ''));
$syncProfileOnLoginRaw = $values['sync_profile_on_login'] ?? false;
$syncProfileOnLogin = in_array(strtolower(trim((string) $syncProfileOnLoginRaw)), ['1', 'true', 'yes', 'on'], true);
$syncFieldOptions = TenantSsoService::profileSyncFieldOptions();
$syncFieldOptions = $tenantSsoService->profileSyncFieldOptions();
$syncProfileFieldsRaw = $values['sync_profile_fields_list'] ?? ($values['sync_profile_fields'] ?? []);
$syncProfileFields = TenantSsoService::normalizeProfileSyncFields($syncProfileFieldsRaw);
$syncProfileFields = $tenantSsoService->normalizeProfileSyncFields($syncProfileFieldsRaw);
$tenantId = (int) ($values['id'] ?? 0);
$ssoUiState = is_array($ssoUiState ?? null)
? $ssoUiState
: TenantSsoService::buildMicrosoftUiState($tenantId, $values);
: $tenantSsoService->buildMicrosoftUiState($tenantId, $values);
$ssoConfigComplete = !empty($ssoUiState['config_complete']);
$ssoConfigErrorLabel = trim((string) ($ssoUiState['config_error_label'] ?? ''));
$ssoPasswordMode = (string) ($ssoUiState['password_mode'] ?? ($microsoftEnforce ? 'microsoft_only' : 'local_and_microsoft'));

View File

@@ -1,13 +1,14 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Tenant\TenantAvatarService;
use MintyPHP\Service\Tenant\TenantServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::TENANTS_UPDATE);
$tenantAvatarService = (new TenantServicesFactory())->createTenantAvatarService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin/tenants');
@@ -15,13 +16,13 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
}
$uuid = trim((string) ($id ?? ''));
if (!TenantAvatarService::isValidUuid($uuid)) {
if (!$tenantAvatarService->isValidUuid($uuid)) {
Flash::error('Tenant not found', 'admin/tenants', 'tenant_not_found');
Router::redirect('admin/tenants');
return;
}
$result = TenantAvatarService::saveUpload($uuid, $_FILES['avatar'] ?? []);
$result = $tenantAvatarService->saveUpload($uuid, $_FILES['avatar'] ?? []);
if (!($result['ok'] ?? false)) {
$error = $result['error'] ?? t('Upload failed');
Flash::error($error, "admin/tenants/edit/{$uuid}", 'tenant_avatar_upload_failed');

View File

@@ -1,13 +1,14 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Tenant\TenantAvatarService;
use MintyPHP\Service\Tenant\TenantServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::TENANTS_UPDATE);
$tenantAvatarService = (new TenantServicesFactory())->createTenantAvatarService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin/tenants');
@@ -15,12 +16,12 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
}
$uuid = trim((string) ($id ?? ''));
if (!TenantAvatarService::isValidUuid($uuid)) {
if (!$tenantAvatarService->isValidUuid($uuid)) {
Flash::error('Tenant not found', 'admin/tenants', 'tenant_not_found');
Router::redirect('admin/tenants');
return;
}
TenantAvatarService::delete($uuid);
$tenantAvatarService->delete($uuid);
Flash::success('Avatar removed', "admin/tenants/edit/{$uuid}", 'tenant_avatar_removed');
Router::redirect("admin/tenants/edit/{$uuid}");

View File

@@ -1,40 +1,39 @@
<?php
use MintyPHP\Service\Tenant\TenantAvatarService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\Tenant\TenantServicesFactory;
use MintyPHP\Support\Guard;
define('MINTY_ALLOW_OUTPUT', true);
Guard::requireLogin();
$tenantAvatarService = (new TenantServicesFactory())->createTenantAvatarService();
$uuid = trim((string) ($_GET['uuid'] ?? ''));
$size = isset($_GET['size']) ? (int) $_GET['size'] : null;
if (!TenantAvatarService::isValidUuid($uuid)) {
if (!$tenantAvatarService->isValidUuid($uuid)) {
http_response_code(404);
return;
}
$tenant = TenantService::findByUuid($uuid);
$tenant = directoryServicesFactory()->createTenantService()->findByUuid($uuid);
$tenantId = (int) ($tenant['id'] ?? 0);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($tenantId <= 0) {
http_response_code(404);
return;
}
if (!TenantScopeService::canAccess('tenants', $tenantId, $currentUserId)) {
if (!directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('tenants', $tenantId, $currentUserId)) {
http_response_code(403);
return;
}
$path = TenantAvatarService::findAvatarPath($uuid, $size);
$path = $tenantAvatarService->findAvatarPath($uuid, $size);
if (!$path || !is_file($path)) {
http_response_code(404);
return;
}
$mime = TenantAvatarService::detectMime($path);
$mime = $tenantAvatarService->detectMime($path);
header('Content-Type: ' . $mime);
header('X-Content-Type-Options: nosniff');
header('Content-Security-Policy: sandbox');

View File

@@ -1,18 +1,18 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\TenantSsoService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::TENANTS_CREATE);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$canManageSso = PermissionService::userHas($currentUserId, PermissionService::TENANTS_SSO_MANAGE);
$canManageSso = permissionGateway()->userHas($currentUserId, PermissionService::TENANTS_SSO_MANAGE);
$tenantSsoService = (new AuthServicesFactory())->createTenantSsoService();
$errors = [];
$form = [
@@ -39,7 +39,7 @@ $form = [
'allow_user_theme_mode' => '',
'status' => 'active',
];
$ssoUiState = $canManageSso ? TenantSsoService::buildMicrosoftUiState(0, $form) : [];
$ssoUiState = $canManageSso ? $tenantSsoService->buildMicrosoftUiState(0, $form) : [];
if (isset($_POST['description'])) {
$ssoFields = [
@@ -60,7 +60,7 @@ if (isset($_POST['description'])) {
return;
}
}
$result = TenantService::createFromAdmin($_POST, $currentUserId);
$result = directoryServicesFactory()->createTenantService()->createFromAdmin($_POST, $currentUserId);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];
if ($canManageSso) {
@@ -68,20 +68,20 @@ if (isset($_POST['description'])) {
'microsoft_enabled' => !empty($_POST['microsoft_enabled']) ? '1' : '0',
'enforce_microsoft_login' => !empty($_POST['enforce_microsoft_login']) ? '1' : '0',
'sync_profile_on_login' => !empty($_POST['sync_profile_on_login']) ? '1' : '0',
'sync_profile_fields_list' => TenantSsoService::normalizeProfileSyncFields($_POST['sync_profile_fields'] ?? []),
'sync_profile_fields_list' => $tenantSsoService->normalizeProfileSyncFields($_POST['sync_profile_fields'] ?? []),
'entra_tenant_id' => trim((string) ($_POST['entra_tenant_id'] ?? '')),
'allowed_domains' => trim((string) ($_POST['allowed_domains'] ?? '')),
'use_shared_app' => !empty($_POST['use_shared_app']) ? '1' : '0',
'client_id_override' => trim((string) ($_POST['client_id_override'] ?? '')),
]);
$ssoUiState = TenantSsoService::buildMicrosoftUiState(0, $_POST);
$ssoUiState = $tenantSsoService->buildMicrosoftUiState(0, $_POST);
}
if ($result['ok'] ?? false) {
if ($canManageSso) {
$createdTenantId = (int) ($result['id'] ?? 0);
if ($createdTenantId > 0) {
$ssoSaveResult = TenantSsoService::saveTenantMicrosoftAuth($createdTenantId, $_POST);
$ssoSaveResult = $tenantSsoService->saveTenantMicrosoftAuth($createdTenantId, $_POST);
if (!($ssoSaveResult['ok'] ?? false)) {
Flash::error(
(string) (($ssoSaveResult['errors'][0] ?? t('Tenant SSO settings could not be saved'))),

View File

@@ -1,19 +1,17 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\Tenant\TenantService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::CUSTOM_FIELDS_MANAGE);
$tenantUuid = trim((string) ($id ?? ''));
$tenant = $tenantUuid !== '' ? TenantService::findByUuid($tenantUuid) : null;
$tenant = $tenantUuid !== '' ? directoryServicesFactory()->createTenantService()->findByUuid($tenantUuid) : null;
if (!$tenant) {
Flash::error(t('Tenant not found'), 'admin/tenants', 'tenant_not_found');
Router::redirect('admin/tenants');
@@ -22,7 +20,7 @@ if (!$tenant) {
$tenantId = (int) ($tenant['id'] ?? 0);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if (!TenantScopeService::canAccess('tenants', $tenantId, $currentUserId)) {
if (!directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('tenants', $tenantId, $currentUserId)) {
Router::redirect('error/forbidden');
return;
}

View File

@@ -1,13 +1,11 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\Tenant\TenantService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::CUSTOM_FIELDS_MANAGE);
@@ -21,12 +19,12 @@ if ($tenantId <= 0) {
}
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if (!TenantScopeService::canAccess('tenants', $tenantId, $currentUserId)) {
if (!directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('tenants', $tenantId, $currentUserId)) {
Router::redirect('error/forbidden');
return;
}
$tenant = TenantService::findById($tenantId);
$tenant = directoryServicesFactory()->createTenantService()->findById($tenantId);
$tenantUuid = trim((string) ($tenant['uuid'] ?? ''));
if ($tenantUuid === '') {
Flash::error(t('Tenant not found'), 'admin/tenants', 'tenant_not_found');

View File

@@ -1,13 +1,11 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\Tenant\TenantService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::CUSTOM_FIELDS_MANAGE);
@@ -21,12 +19,12 @@ if ($tenantId <= 0) {
}
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if (!TenantScopeService::canAccess('tenants', $tenantId, $currentUserId)) {
if (!directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('tenants', $tenantId, $currentUserId)) {
Router::redirect('error/forbidden');
return;
}
$tenant = TenantService::findById($tenantId);
$tenant = directoryServicesFactory()->createTenantService()->findById($tenantId);
$tenantUuid = trim((string) ($tenant['uuid'] ?? ''));
if ($tenantUuid === '') {
Flash::error(t('Tenant not found'), 'admin/tenants', 'tenant_not_found');

View File

@@ -1,12 +1,11 @@
<?php
use MintyPHP\Router;
use MintyPHP\Support\Guard;
use MintyPHP\Repository\Tenant\UserTenantRepository;
use MintyPHP\Repository\Tenant\TenantMicrosoftAuthRepository;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\Settings\SettingService;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Settings\SettingServicesFactory;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::TENANTS_VIEW);
@@ -18,8 +17,15 @@ $order = (string) ($_GET['order'] ?? 'description');
$dir = (string) ($_GET['dir'] ?? 'asc');
$dir = strtolower($dir) === 'desc' ? 'desc' : 'asc';
$computedOrderKeys = ['theme', 'sso', 'active_users', 'inactive_users'];
$userTenantRepository = (new UserServicesFactory())->createUserTenantRepository();
$tenantMicrosoftAuthRepository = new TenantMicrosoftAuthRepository();
$settingGateway = (new SettingServicesFactory())->createSettingGateway();
$fetchRows = static function (array $tenantRows, array $themes, string $globalDefaultTheme): array {
$fetchRows = static function (
array $tenantRows,
array $themes,
string $globalDefaultTheme
) use ($userTenantRepository, $tenantMicrosoftAuthRepository, $settingGateway): array {
$tenantIds = [];
foreach ($tenantRows as $tenantRow) {
$tenantId = (int) ($tenantRow['id'] ?? 0);
@@ -29,11 +35,11 @@ $fetchRows = static function (array $tenantRows, array $themes, string $globalDe
}
$tenantIds = array_values(array_unique($tenantIds));
$tenantSsoMap = TenantMicrosoftAuthRepository::listByTenantIds($tenantIds);
$tenantUserCounts = UserTenantRepository::countUsersByTenantIds($tenantIds);
$tenantActiveUserCounts = UserTenantRepository::countActiveUsersByTenantIds($tenantIds);
$tenantSsoMap = $tenantMicrosoftAuthRepository->listByTenantIds($tenantIds);
$tenantUserCounts = $userTenantRepository->countUsersByTenantIds($tenantIds);
$tenantActiveUserCounts = $userTenantRepository->countActiveUsersByTenantIds($tenantIds);
$defaultTenantId = SettingService::getDefaultTenantId();
$defaultTenantId = $settingGateway->getDefaultTenantId();
$rows = [];
foreach ($tenantRows as $row) {
@@ -88,13 +94,13 @@ $fetchRows = static function (array $tenantRows, array $themes, string $globalDe
};
$themes = appThemes();
$globalDefaultTheme = SettingService::getAppTheme();
$globalDefaultTheme = $settingGateway->getAppTheme();
if ($globalDefaultTheme === null || !isset($themes[$globalDefaultTheme])) {
$envTheme = strtolower(trim((string) (getenv('APP_THEME') ?: 'light')));
$globalDefaultTheme = isset($themes[$envTheme]) ? $envTheme : 'light';
}
$result = TenantService::listPaged([
$result = directoryServicesFactory()->createTenantService()->listPaged([
'limit' => $limit,
'offset' => $offset,
'search' => $search,
@@ -105,7 +111,7 @@ $result = TenantService::listPaged([
$rows = [];
$total = (int) ($result['total'] ?? 0);
if (in_array($order, $computedOrderKeys, true)) {
$fullResult = TenantService::listPaged([
$fullResult = directoryServicesFactory()->createTenantService()->listPaged([
'limit' => max(1, $total),
'offset' => 0,
'search' => $search,
@@ -121,18 +127,18 @@ if (in_array($order, $computedOrderKeys, true)) {
$valueA = strtolower((string) ($a['theme']['label'] ?? ''));
$valueB = strtolower((string) ($b['theme']['label'] ?? ''));
} elseif ($order === 'sso') {
$valueA = ((int) ($a['sso']['enabled'] ?? 0) * 10) + (int) ($a['sso']['microsoft_only'] ?? 0);
$valueB = ((int) ($b['sso']['enabled'] ?? 0) * 10) + (int) ($b['sso']['microsoft_only'] ?? 0);
$valueA = ((int) $a['sso']['enabled'] * 10) + (int) $a['sso']['microsoft_only'];
$valueB = ((int) $b['sso']['enabled'] * 10) + (int) $b['sso']['microsoft_only'];
} elseif ($order === 'inactive_users') {
$valueA = (int) ($a['inactive_users'] ?? 0);
$valueB = (int) ($b['inactive_users'] ?? 0);
$valueA = (int) $a['inactive_users'];
$valueB = (int) $b['inactive_users'];
} else {
$valueA = (int) ($a['active_users'] ?? 0);
$valueB = (int) ($b['active_users'] ?? 0);
$valueA = (int) $a['active_users'];
$valueB = (int) $b['active_users'];
}
$cmp = $valueA <=> $valueB;
if ($cmp === 0) {
$cmp = strcasecmp((string) ($a['description'] ?? ''), (string) ($b['description'] ?? ''));
$cmp = strcasecmp((string) $a['description'], (string) $b['description']);
}
return $dir === 'desc' ? -$cmp : $cmp;
});

View File

@@ -1,11 +1,10 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\AuthService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::TENANTS_DELETE);
@@ -15,7 +14,7 @@ if ($uuid === '') {
Router::redirect('admin/tenants');
}
$result = TenantService::deleteByUuid($uuid);
$result = directoryServicesFactory()->createTenantService()->deleteByUuid($uuid);
if (!($result['ok'] ?? false)) {
if (($result['error'] ?? '') === 'tenant_has_departments') {
Flash::error('Tenant can not be deleted while departments are assigned', 'admin/tenants', 'tenant_has_departments');
@@ -28,7 +27,7 @@ if (!($result['ok'] ?? false)) {
// Refresh session tenant data (removes deleted tenant, switches if it was current)
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
AuthService::loadTenantDataIntoSession($currentUserId);
(new AuthServicesFactory())->createAuthService()->loadTenantDataIntoSession($currentUserId);
}
Flash::success('Tenant deleted', 'admin/tenants', 'tenant_deleted');

View File

@@ -1,41 +1,42 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Settings\SettingService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Service\Auth\TenantSsoService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::TENANTS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
$userAccountService = (new UserServicesFactory())->createUserAccountService();
$uuid = trim((string) ($id ?? ''));
$tenant = $uuid !== '' ? TenantService::findByUuid($uuid) : null;
$tenant = $uuid !== '' ? directoryServicesFactory()->createTenantService()->findByUuid($uuid) : null;
if (!$tenant) {
Flash::error('Tenant not found', 'admin/tenants', 'tenant_not_found');
Router::redirect('admin/tenants');
}
$tenantId = (int) ($tenant['id'] ?? 0);
$canManageCustomFields = PermissionService::userHas($currentUserId, PermissionService::CUSTOM_FIELDS_MANAGE);
$canManageSso = PermissionService::userHas($currentUserId, PermissionService::TENANTS_SSO_MANAGE);
$authServicesFactory = new AuthServicesFactory();
$tenantSsoService = $authServicesFactory->createTenantSsoService();
$canManageCustomFields = permissionGateway()->userHas($currentUserId, PermissionService::CUSTOM_FIELDS_MANAGE);
$canManageSso = permissionGateway()->userHas($currentUserId, PermissionService::TENANTS_SSO_MANAGE);
$customFieldDefinitions = $canManageCustomFields
? TenantCustomFieldService::listForTenant($tenantId)
: [];
$ssoConfig = $canManageSso ? TenantSsoService::getTenantMicrosoftAuth($tenantId) : [];
$ssoUiState = $canManageSso ? TenantSsoService::buildMicrosoftUiState($tenantId, $ssoConfig) : [];
$ssoConfig = $canManageSso ? $tenantSsoService->getTenantMicrosoftAuth($tenantId) : [];
$ssoUiState = $canManageSso ? $tenantSsoService->buildMicrosoftUiState($tenantId, $ssoConfig) : [];
$creatorId = (int) ($tenant['created_by'] ?? 0);
if ($creatorId > 0) {
$creator = UserService::findById($creatorId);
$creator = $userAccountService->findById($creatorId);
if ($creator) {
$creatorName = trim(($creator['first_name'] ?? '') . ' ' . ($creator['last_name'] ?? ''));
$tenant['created_by_label'] = $creatorName !== '' ? $creatorName : ($creator['email'] ?? '');
@@ -44,7 +45,7 @@ if ($creatorId > 0) {
}
$modifierId = (int) ($tenant['modified_by'] ?? 0);
if ($modifierId > 0) {
$modifier = UserService::findById($modifierId);
$modifier = $userAccountService->findById($modifierId);
if ($modifier) {
$modifierName = trim(($modifier['first_name'] ?? '') . ' ' . ($modifier['last_name'] ?? ''));
$tenant['modified_by_label'] = $modifierName !== '' ? $modifierName : ($modifier['email'] ?? '');
@@ -53,7 +54,7 @@ if ($modifierId > 0) {
}
$statusChangedById = (int) ($tenant['status_changed_by'] ?? 0);
if ($statusChangedById > 0) {
$statusChanger = UserService::findById($statusChangedById);
$statusChanger = $userAccountService->findById($statusChangedById);
if ($statusChanger) {
$statusChangerName = trim(($statusChanger['first_name'] ?? '') . ' ' . ($statusChanger['last_name'] ?? ''));
$tenant['status_changed_by_label'] = $statusChangerName !== '' ? $statusChangerName : ($statusChanger['email'] ?? '');
@@ -65,7 +66,7 @@ $errors = [];
$form = array_merge($tenant, $ssoConfig);
if (isset($_POST['description'])) {
if (!PermissionService::userHas($currentUserId, PermissionService::TENANTS_UPDATE)) {
if (!permissionGateway()->userHas($currentUserId, PermissionService::TENANTS_UPDATE)) {
Router::redirect('error/forbidden');
return;
}
@@ -87,13 +88,13 @@ if (isset($_POST['description'])) {
return;
}
}
$result = TenantService::updateFromAdmin($tenantId, $_POST, $currentUserId);
$result = directoryServicesFactory()->createTenantService()->updateFromAdmin($tenantId, $_POST, $currentUserId);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];
if ($result['ok'] ?? false) {
if ($canManageSso) {
$ssoSaveResult = TenantSsoService::saveTenantMicrosoftAuth($tenantId, $_POST);
$ssoSaveResult = $tenantSsoService->saveTenantMicrosoftAuth($tenantId, $_POST);
if (!($ssoSaveResult['ok'] ?? false)) {
$errors = array_merge($errors, $ssoSaveResult['errors'] ?? [t('Tenant SSO settings could not be saved')]);
}
@@ -102,7 +103,7 @@ if (isset($_POST['description'])) {
if (($result['ok'] ?? false) && !$errors) {
if ($currentUserId > 0) {
\MintyPHP\Service\Auth\AuthService::loadTenantDataIntoSession($currentUserId);
$authServicesFactory->createAuthService()->loadTenantDataIntoSession($currentUserId);
}
$action = (string) ($_POST['action'] ?? 'save');
if ($action === 'save_close') {
@@ -119,18 +120,18 @@ if (isset($_POST['description'])) {
'microsoft_enabled' => !empty($_POST['microsoft_enabled']) ? '1' : '0',
'enforce_microsoft_login' => !empty($_POST['enforce_microsoft_login']) ? '1' : '0',
'sync_profile_on_login' => !empty($_POST['sync_profile_on_login']) ? '1' : '0',
'sync_profile_fields_list' => TenantSsoService::normalizeProfileSyncFields($_POST['sync_profile_fields'] ?? []),
'sync_profile_fields_list' => $tenantSsoService->normalizeProfileSyncFields($_POST['sync_profile_fields'] ?? []),
'entra_tenant_id' => trim((string) ($_POST['entra_tenant_id'] ?? '')),
'allowed_domains' => trim((string) ($_POST['allowed_domains'] ?? '')),
'use_shared_app' => !empty($_POST['use_shared_app']) ? '1' : '0',
'client_id_override' => trim((string) ($_POST['client_id_override'] ?? '')),
]);
$ssoUiState = TenantSsoService::buildMicrosoftUiState($tenantId, $_POST);
$ssoUiState = $tenantSsoService->buildMicrosoftUiState($tenantId, $_POST);
}
}
if ($canManageSso && empty($ssoUiState)) {
$ssoUiState = TenantSsoService::buildMicrosoftUiState($tenantId, $form);
$ssoUiState = $tenantSsoService->buildMicrosoftUiState($tenantId, $form);
}
Buffer::set('title', t('Edit tenant'));

View File

@@ -7,14 +7,16 @@
*/
use MintyPHP\Session;
use MintyPHP\Service\Tenant\TenantAvatarService;
use MintyPHP\Service\Tenant\TenantFaviconService;
use MintyPHP\Service\Tenant\TenantServicesFactory;
$values = $form ?? $tenant ?? [];
$isReadOnly = !can('tenants.update');
$avatarUuid = (string) ($values['uuid'] ?? '');
$hasAvatar = $avatarUuid !== '' && TenantAvatarService::hasAvatar($avatarUuid);
$hasFavicon = $avatarUuid !== '' && TenantFaviconService::hasFavicon($avatarUuid);
$tenantServicesFactory = new TenantServicesFactory();
$tenantAvatarService = $tenantServicesFactory->createTenantAvatarService();
$tenantFaviconService = $tenantServicesFactory->createTenantFaviconService();
$hasAvatar = $avatarUuid !== '' && $tenantAvatarService->hasAvatar($avatarUuid);
$hasFavicon = $avatarUuid !== '' && $tenantFaviconService->hasFavicon($avatarUuid);
$canDeleteTenant = can('tenants.delete');
?>

View File

@@ -1,13 +1,14 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Tenant\TenantFaviconService;
use MintyPHP\Service\Tenant\TenantServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::TENANTS_UPDATE);
$tenantFaviconService = (new TenantServicesFactory())->createTenantFaviconService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin/tenants');
@@ -15,13 +16,13 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
}
$uuid = trim((string) ($id ?? ''));
if (!TenantFaviconService::isValidUuid($uuid)) {
if (!$tenantFaviconService->isValidUuid($uuid)) {
Flash::error('Tenant not found', 'admin/tenants', 'tenant_not_found');
Router::redirect('admin/tenants');
return;
}
$result = TenantFaviconService::saveUpload($uuid, $_FILES['favicon'] ?? []);
$result = $tenantFaviconService->saveUpload($uuid, $_FILES['favicon'] ?? []);
if (!($result['ok'] ?? false)) {
$error = $result['error'] ?? t('Upload failed');
Flash::error($error, "admin/tenants/edit/{$uuid}", 'tenant_favicon_upload_failed');

View File

@@ -1,13 +1,14 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Tenant\TenantFaviconService;
use MintyPHP\Service\Tenant\TenantServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::TENANTS_UPDATE);
$tenantFaviconService = (new TenantServicesFactory())->createTenantFaviconService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin/tenants');
@@ -15,12 +16,12 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
}
$uuid = trim((string) ($id ?? ''));
if (!TenantFaviconService::isValidUuid($uuid)) {
if (!$tenantFaviconService->isValidUuid($uuid)) {
Flash::error('Tenant not found', 'admin/tenants', 'tenant_not_found');
Router::redirect('admin/tenants');
return;
}
TenantFaviconService::delete($uuid);
$tenantFaviconService->delete($uuid);
Flash::success('Favicon removed', "admin/tenants/edit/{$uuid}", 'tenant_favicon_removed');
Router::redirect("admin/tenants/edit/{$uuid}");

View File

@@ -10,7 +10,7 @@ Guard::requirePermissionOrForbidden(PermissionService::TENANTS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
Buffer::set('title', t('Tenants'));

View File

@@ -3,7 +3,7 @@
use MintyPHP\Router;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Audit\UserLifecycleAuditService;
use MintyPHP\Service\Audit\AuditServicesFactory;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::USER_LIFECYCLE_AUDIT_VIEW);
@@ -13,7 +13,8 @@ if (strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')) !== 'GET') {
Router::json(['error' => 'method_not_allowed']);
}
$result = UserLifecycleAuditService::listPaged([
$factory = new AuditServicesFactory();
$result = $factory->createUserLifecycleAuditService()->listPaged([
'limit' => (int) ($_GET['limit'] ?? 20),
'offset' => (int) ($_GET['offset'] ?? 0),
'search' => trim((string) ($_GET['search'] ?? '')),
@@ -56,4 +57,3 @@ Router::json([
'data' => $rows,
'total' => (int) ($result['total'] ?? 0),
]);

View File

@@ -5,7 +5,7 @@ use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Audit\UserLifecycleAuditService;
use MintyPHP\Service\Audit\AuditServicesFactory;
Guard::requireLogin();
Guard::requirePermission(PermissionService::SETTINGS_UPDATE);
@@ -18,11 +18,11 @@ if (!Session::checkCsrfToken()) {
Router::redirect('admin/user-lifecycle-audit');
}
$deleted = UserLifecycleAuditService::purgeExpired();
$factory = new AuditServicesFactory();
$deleted = $factory->createUserLifecycleAuditService()->purgeExpired();
Flash::success(
sprintf(t('%d user lifecycle audit entries purged'), $deleted),
'admin/user-lifecycle-audit',
'user_lifecycle_audit_purged'
);
Router::redirect('admin/user-lifecycle-audit');

View File

@@ -1,11 +1,11 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserLifecycleRestoreService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::USERS_LIFECYCLE_RESTORE);
@@ -20,7 +20,7 @@ if (!Session::checkCsrfToken()) {
Router::redirect('admin/user-lifecycle-audit');
}
$result = UserLifecycleRestoreService::restoreFromLifecycleAudit(
$result = (new UserServicesFactory())->createUserLifecycleRestoreService()->restoreFromLifecycleAudit(
$auditId,
(int) ($_SESSION['user']['id'] ?? 0)
);
@@ -43,4 +43,3 @@ if (!($result['ok'] ?? false)) {
Flash::success(t('User restored'), "admin/user-lifecycle-audit/view/$auditId", 'user_restored');
Router::redirect("admin/user-lifecycle-audit/view/$auditId");

View File

@@ -5,13 +5,15 @@ use MintyPHP\Router;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Audit\UserLifecycleAuditService;
use MintyPHP\Service\Audit\AuditServicesFactory;
Guard::requireLogin();
Guard::requirePermission(PermissionService::USER_LIFECYCLE_AUDIT_VIEW);
$auditId = (int) ($id ?? 0);
$auditLog = $auditId > 0 ? UserLifecycleAuditService::find($auditId) : null;
$factory = new AuditServicesFactory();
$auditService = $factory->createUserLifecycleAuditService();
$auditLog = $auditId > 0 ? $auditService->find($auditId) : null;
if (!$auditLog) {
Flash::error(t('Lifecycle audit entry not found'), 'admin/user-lifecycle-audit', 'user_lifecycle_audit_not_found');
Router::redirect('admin/user-lifecycle-audit');
@@ -19,8 +21,7 @@ if (!$auditLog) {
$snapshot = null;
if ((string) ($auditLog['action'] ?? '') === 'delete') {
$snapshot = UserLifecycleAuditService::decryptSnapshot($auditLog);
$snapshot = $auditService->decryptSnapshot($auditLog);
}
Buffer::set('title', t('View user lifecycle audit entry'));

View File

@@ -39,9 +39,8 @@
* @var string|null $tokenDangerActionLabel
*/
use MintyPHP\Session;
use MintyPHP\Service\User\UserService;
use MintyPHP\I18n;
use MintyPHP\Session;
$values = $values ?? [];
$isOwnAccount = (int) ($_SESSION['user']['id'] ?? 0) === (int) ($values['id'] ?? 0);
@@ -93,7 +92,8 @@ $showTokenDangerAction = (bool) ($showTokenDangerAction ?? false);
$tokenDangerFormId = (string) ($tokenDangerFormId ?? '');
$tokenDangerWarning = (string) ($tokenDangerWarning ?? t('This action cannot be undone.'));
$tokenDangerActionLabel = (string) ($tokenDangerActionLabel ?? t('Clear login tokens'));
$minLength = UserService::passwordMinLength();
$minLength = (int) ($passwordMinLength ?? 0);
$passwordHints = is_array($passwordHints ?? null) ? $passwordHints : [];
$requiredAttr = $passwordRequired ? 'required' : '';
$readonlyAttr = $isReadOnly ? 'readonly' : '';
$disabledAttr = $isReadOnly ? 'disabled' : '';
@@ -299,7 +299,7 @@ foreach ($tenants as $tenant) {
data-email-input="#email" data-min-length="<?php e($minLength); ?>">
<strong><?php e(t('Password requirements')); ?></strong>
<ul class="form-hint-list">
<?php foreach (UserService::passwordHints() as $hint): ?>
<?php foreach ($passwordHints as $hint): ?>
<li data-rule="<?php e($hint['rule']); ?>"><?php e($hint['text']); ?></li>
<?php endforeach; ?>
<li data-rule="match"><?php e(t('Passwords must match')); ?></li>

View File

@@ -1,24 +1,24 @@
<?php
use MintyPHP\Support\Guard;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\User\UserAccessPdfService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserAccessPdfService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Guard;
define('MINTY_ALLOW_OUTPUT', true);
// Hard gate: user must be logged in and explicitly allowed to generate access PDFs.
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::USERS_ACCESS_PDF);
$userAccountService = (new UserServicesFactory())->createUserAccountService();
// Support both route param and POSTed uuid (POST avoids exposing uuid in URL/history).
$uuid = trim((string) ($id ?? ''));
if ($uuid === '' && strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')) === 'POST') {
$uuid = trim((string) ($_POST['uuid'] ?? ''));
}
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
if (!$user) {
http_response_code(404);
return;
@@ -27,7 +27,7 @@ if (!$user) {
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$userId = (int) ($user['id'] ?? 0);
// Enforce tenant scope on the target user before rendering any sensitive document.
if ($userId <= 0 || !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if ($userId <= 0 || !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
Router::redirect('error/forbidden');
return;
}

View File

@@ -2,9 +2,8 @@
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\User\UserAccessPdfService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
@@ -13,6 +12,7 @@ define('MINTY_ALLOW_OUTPUT', true);
// Hard gate: user must be logged in and explicitly allowed to generate access PDFs.
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::USERS_ACCESS_PDF);
$userAccountService = (new UserServicesFactory())->createUserAccountService();
if (strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')) !== 'POST') {
Router::redirect('admin/users');
@@ -43,7 +43,7 @@ if (count($uuids) > 100) {
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$users = [];
foreach ($uuids as $uuid) {
$user = UserService::findByUuid($uuid);
$user = $userAccountService->findByUuid($uuid);
if (!$user) {
continue;
}
@@ -52,7 +52,7 @@ foreach ($uuids as $uuid) {
continue;
}
// Scope check per user prevents cross-tenant exports in mixed selections.
if (!TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if (!directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
continue;
}
$users[] = $user;

View File

@@ -1,12 +1,12 @@
<?php
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\User\UserService;
use MintyPHP\Http\Request;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Router;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Guard;
Guard::requireLogin();
$userAccountService = (new UserServicesFactory())->createUserAccountService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin/users');
@@ -15,9 +15,9 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
$uuid = trim((string) ($id ?? ''));
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
$userId = (int) ($user['id'] ?? 0);
if ($userId > 0 && $currentUserId !== $userId && !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if ($userId > 0 && $currentUserId !== $userId && !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
if (Request::wantsJson()) {
http_response_code(403);
Router::json(['error' => 'permission_denied']);
@@ -26,7 +26,7 @@ if ($userId > 0 && $currentUserId !== $userId && !TenantScopeService::canAccess(
Router::redirect('error/forbidden');
return;
}
$result = UserService::setActiveByUuid($uuid, true, $currentUserId);
$result = $userAccountService->setActiveByUuid($uuid, true, $currentUserId);
if ($result['ok'] ?? false) {
if (Request::wantsJson()) {
http_response_code(204);

View File

@@ -1,17 +1,19 @@
<?php
use MintyPHP\Support\Guard;
use MintyPHP\Support\Flash;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\ApiTokenService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::API_TOKENS_MANAGE);
$userAccountService = (new UserServicesFactory())->createUserAccountService();
$apiTokenService = (new AuthServicesFactory())->createApiTokenService();
$uuid = trim((string) ($id ?? ''));
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
if (!$user) {
Router::redirect('admin/users');
}
@@ -25,7 +27,7 @@ if ($name === '') {
Router::redirect("admin/users/edit/{$uuid}");
}
$result = ApiTokenService::create($userId, $name, null, null, $currentUserId);
$result = $apiTokenService->create($userId, $name, null, null, $currentUserId);
if ($result['ok'] ?? false) {
$_SESSION['api_token_created'] = ['token' => $result['token'], 'uuid' => $uuid];

View File

@@ -1,17 +1,19 @@
<?php
use MintyPHP\Support\Guard;
use MintyPHP\Support\Flash;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\ApiTokenService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::API_TOKENS_MANAGE);
$userAccountService = (new UserServicesFactory())->createUserAccountService();
$apiTokenService = (new AuthServicesFactory())->createApiTokenService();
$uuid = trim((string) ($id ?? ''));
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
if (!$user) {
Router::redirect('admin/users');
}
@@ -19,7 +21,7 @@ if (!$user) {
$tokenId = (int) ($_POST['token_id'] ?? 0);
if ($tokenId > 0) {
ApiTokenService::revoke($tokenId);
$apiTokenService->revoke($tokenId);
Flash::success(t('API token revoked'), "admin/users/edit/{$uuid}", 'api_token_revoked');
}

View File

@@ -1,13 +1,14 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\User\UserAvatarService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Tenant\TenantScopeService;
Guard::requireLogin();
$userServicesFactory = new UserServicesFactory();
$userAccountService = $userServicesFactory->createUserAccountService();
$userAvatarService = $userServicesFactory->createUserAvatarService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin');
@@ -15,21 +16,21 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
}
$uuid = trim((string) ($id ?? ''));
if (!UserAvatarService::isValidUuid($uuid)) {
if (!$userAvatarService->isValidUuid($uuid)) {
Flash::error('User not found', 'admin', 'user_not_found');
Router::redirect('admin');
return;
}
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
$userId = (int) ($user['id'] ?? 0);
if ($userId > 0 && $currentUserId !== $userId && !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if ($userId > 0 && $currentUserId !== $userId && !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
Router::redirect('error/forbidden');
return;
}
$result = UserAvatarService::saveUpload($uuid, $_FILES['avatar'] ?? []);
$result = $userAvatarService->saveUpload($uuid, $_FILES['avatar'] ?? []);
if (!($result['ok'] ?? false)) {
$error = $result['error'] ?? t('Upload failed');
Flash::error($error, "admin/users/edit/{$uuid}", 'avatar_upload_failed');

View File

@@ -1,13 +1,14 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\User\UserAvatarService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Tenant\TenantScopeService;
Guard::requireLogin();
$userServicesFactory = new UserServicesFactory();
$userAccountService = $userServicesFactory->createUserAccountService();
$userAvatarService = $userServicesFactory->createUserAvatarService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin');
@@ -15,20 +16,20 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
}
$uuid = trim((string) ($id ?? ''));
if (!UserAvatarService::isValidUuid($uuid)) {
if (!$userAvatarService->isValidUuid($uuid)) {
Flash::error('User not found', 'admin', 'user_not_found');
Router::redirect('admin');
return;
}
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
$userId = (int) ($user['id'] ?? 0);
if ($userId > 0 && $currentUserId !== $userId && !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if ($userId > 0 && $currentUserId !== $userId && !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
Router::redirect('error/forbidden');
return;
}
UserAvatarService::delete($uuid);
$userAvatarService->delete($uuid);
Flash::success('Avatar removed', "admin/users/edit/{$uuid}", 'avatar_removed');
Router::redirect("admin/users/edit/{$uuid}");

View File

@@ -1,36 +1,37 @@
<?php
use MintyPHP\Service\User\UserAvatarService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Guard;
define('MINTY_ALLOW_OUTPUT', true);
Guard::requireLogin();
$userServicesFactory = new UserServicesFactory();
$userAccountService = $userServicesFactory->createUserAccountService();
$userAvatarService = $userServicesFactory->createUserAvatarService();
$uuid = trim((string) ($_GET['uuid'] ?? ''));
$size = isset($_GET['size']) ? (int) $_GET['size'] : null;
if (!UserAvatarService::isValidUuid($uuid)) {
if (!$userAvatarService->isValidUuid($uuid)) {
http_response_code(404);
return;
}
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
$userId = (int) ($user['id'] ?? 0);
if ($userId > 0 && $currentUserId !== $userId && !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if ($userId > 0 && $currentUserId !== $userId && !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
http_response_code(403);
return;
}
$path = UserAvatarService::findAvatarPath($uuid, $size);
$path = $userAvatarService->findAvatarPath($uuid, $size);
if (!$path || !is_file($path)) {
http_response_code(404);
return;
}
$mime = UserAvatarService::detectMime($path);
$mime = $userAvatarService->detectMime($path);
header('Content-Type: ' . $mime);
header('X-Content-Type-Options: nosniff');
header('Content-Security-Policy: sandbox');

View File

@@ -1,22 +1,17 @@
<?php
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Mail\MailServicesFactory;
use MintyPHP\Service\User\UserAccessTemplateService;
use MintyPHP\Service\Mail\MailService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Guard;
Guard::requireLogin();
$action = strtolower(trim((string) ($action ?? '')));
$handlers = [
'activate' => 'handleActivate',
'deactivate' => 'handleDeactivate',
'delete' => 'handleDelete',
'send-access' => 'handleSendAccess',
];
if (!isset($handlers[$action])) {
$allowedActions = ['activate', 'deactivate', 'delete', 'send-access'];
if (!in_array($action, $allowedActions, true)) {
Router::json(['ok' => false, 'error' => 'invalid_action']);
}
if ($action === 'delete') {
@@ -39,21 +34,20 @@ if (!$uuids) {
}
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
call_user_func($handlers[$action], $uuids, $currentUserId);
$userAccountService = (new UserServicesFactory())->createUserAccountService();
$mailService = (new MailServicesFactory())->createMailService();
function handleActivate(array $uuids, int $currentUserId): void
{
$result = UserService::setActiveByUuids($uuids, true, $currentUserId);
if ($action === 'activate') {
$result = $userAccountService->setActiveByUuids($uuids, true, $currentUserId);
if (!($result['ok'] ?? false)) {
Router::json(['ok' => false, 'error' => 'update_failed']);
}
Router::json(['ok' => true, 'count' => (int) ($result['count'] ?? 0)]);
}
function handleDeactivate(array $uuids, int $currentUserId): void
{
if ($action === 'deactivate') {
if ($currentUserId > 0) {
$currentUser = UserService::findById($currentUserId);
$currentUser = $userAccountService->findById($currentUserId);
$currentUuid = $currentUser['uuid'] ?? '';
if ($currentUuid !== '') {
$uuids = array_values(array_filter($uuids, static fn ($uuid) => $uuid !== $currentUuid));
@@ -63,50 +57,46 @@ function handleDeactivate(array $uuids, int $currentUserId): void
}
}
$result = UserService::setActiveByUuids($uuids, false, $currentUserId);
$result = $userAccountService->setActiveByUuids($uuids, false, $currentUserId);
if (!($result['ok'] ?? false)) {
Router::json(['ok' => false, 'error' => 'update_failed']);
}
Router::json(['ok' => true, 'count' => (int) ($result['count'] ?? 0)]);
}
function handleDelete(array $uuids, int $currentUserId): void
{
$result = UserService::deleteByUuids($uuids, $currentUserId);
if ($action === 'delete') {
$result = $userAccountService->deleteByUuids($uuids, $currentUserId);
if (!($result['ok'] ?? false)) {
Router::json(['ok' => false, 'error' => $result['error'] ?? 'delete_failed']);
}
Router::json(['ok' => true, 'count' => (int) ($result['count'] ?? 0)]);
}
function handleSendAccess(array $uuids, int $currentUserId): void
{
$successCount = 0;
$failedCount = 0;
$successCount = 0;
$failedCount = 0;
foreach ($uuids as $uuid) {
$user = UserService::findByUuid($uuid);
if (!$user || empty($user['email'])) {
$failedCount++;
continue;
}
$context = UserAccessTemplateService::buildContext($user);
$locale = (string) ($context['locale'] ?? '');
$subject = (string) ($context['subject'] ?? t('Your access details'));
$vars = is_array($context['vars'] ?? null) ? $context['vars'] : [];
$result = MailService::sendTemplate('access_info', $vars, (string) $user['email'], $subject, $locale);
if ($result['ok'] ?? false) {
$successCount++;
} else {
$failedCount++;
}
foreach ($uuids as $uuid) {
$user = $userAccountService->findByUuid($uuid);
if (!$user || empty($user['email'])) {
$failedCount++;
continue;
}
Router::json([
'ok' => $successCount > 0,
'count' => $successCount,
'failed' => $failedCount,
]);
$context = UserAccessTemplateService::buildContext($user);
$locale = (string) ($context['locale'] ?? '');
$subject = (string) ($context['subject'] ?? t('Your access details'));
$vars = is_array($context['vars'] ?? null) ? $context['vars'] : [];
$result = $mailService->sendTemplate('access_info', $vars, (string) $user['email'], $subject, $locale);
if ($result['ok'] ?? false) {
$successCount++;
} else {
$failedCount++;
}
}
Router::json([
'ok' => $successCount > 0,
'count' => $successCount,
'failed' => $failedCount,
]);

View File

@@ -1,40 +1,43 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\I18n;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
use MintyPHP\Service\Settings\SettingService;
use MintyPHP\Service\Settings\SettingServicesFactory;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requirePermissionOrForbidden(PermissionService::USERS_CREATE);
$userServicesFactory = new UserServicesFactory();
$userAccountService = $userServicesFactory->createUserAccountService();
$userAssignmentService = $userServicesFactory->createUserAssignmentService();
$userPasswordPolicyService = $userServicesFactory->createUserPasswordPolicyService();
$passwordMinLength = $userPasswordPolicyService->minLength();
$passwordHints = $userPasswordPolicyService->hints();
$settingGateway = (new SettingServicesFactory())->createSettingGateway();
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$allowedTenantIds = TenantScopeService::getUserTenantIds($currentUserId);
$allowedTenantIds = directoryServicesFactory()->createDirectoryScopeGateway()->getUserTenantIds($currentUserId);
$tenants = TenantService::list();
$tenants = directoryServicesFactory()->createTenantService()->list();
if ($allowedTenantIds) {
$tenants = array_values(array_filter($tenants, static function (array $tenant) use ($allowedTenantIds): bool {
$tenantId = (int) ($tenant['id'] ?? 0);
return $tenantId > 0 && in_array($tenantId, $allowedTenantIds, true);
}));
} elseif (TenantScopeService::isStrict()) {
} elseif (directoryServicesFactory()->createDirectoryScopeGateway()->isStrict()) {
$tenants = [];
}
$roles = RoleService::listActive();
$roles = directoryServicesFactory()->createRoleService()->listActive();
$selectedTenantIds = [];
$selectedRoleIds = [];
$selectedDepartmentIds = [];
$departmentOptionsByTenant = [];
$canEditCustomFieldValues = PermissionService::userHas($currentUserId, PermissionService::CUSTOM_FIELDS_EDIT_VALUES)
&& PermissionService::userHas($currentUserId, PermissionService::USERS_UPDATE_ASSIGNMENTS);
$canEditCustomFieldValues = permissionGateway()->userHas($currentUserId, PermissionService::CUSTOM_FIELDS_EDIT_VALUES)
&& permissionGateway()->userHas($currentUserId, PermissionService::USERS_UPDATE_ASSIGNMENTS);
$customFieldDefinitionsByTenant = [];
$customFieldValueMap = [];
$customFieldPostedValues = [
@@ -65,20 +68,20 @@ $form = [
if (isset($_POST['email'])) {
$input = $_POST;
$tenantIds = UserService::normalizeIdInput($input['tenant_ids'] ?? []);
$tenantIds = $userAssignmentService->normalizeIdInput($input['tenant_ids'] ?? []);
if ($allowedTenantIds) {
$tenantIds = array_values(array_intersect($tenantIds, $allowedTenantIds));
} elseif (TenantScopeService::isStrict()) {
} elseif (directoryServicesFactory()->createDirectoryScopeGateway()->isStrict()) {
$tenantIds = [];
}
$defaultTenantId = SettingService::getDefaultTenantId();
if (TenantScopeService::isStrict() && !$tenantIds && !$defaultTenantId) {
$defaultTenantId = $settingGateway->getDefaultTenantId();
if (directoryServicesFactory()->createDirectoryScopeGateway()->isStrict() && !$tenantIds && !$defaultTenantId) {
$errors[] = t('Please select at least one tenant');
}
$selectedTenantIds = $tenantIds;
$selectedRoleIds = UserService::normalizeIdInput($input['role_ids'] ?? []);
$selectedDepartmentIds = UserService::normalizeIdInput($input['department_ids'] ?? []);
$departmentOptionsByTenant = DepartmentService::groupActiveByTenantIds($selectedTenantIds);
$selectedRoleIds = $userAssignmentService->normalizeIdInput($input['role_ids'] ?? []);
$selectedDepartmentIds = $userAssignmentService->normalizeIdInput($input['department_ids'] ?? []);
$departmentOptionsByTenant = directoryServicesFactory()->createDepartmentService()->groupActiveByTenantIds($selectedTenantIds);
$customFieldDefinitionsByTenant = UserCustomFieldValueService::buildDefinitionsByTenant($selectedTenantIds);
$customFieldPostedValues = [
'custom_field_values' => is_array($_POST['custom_field_values'] ?? null) ? $_POST['custom_field_values'] : [],
@@ -109,7 +112,7 @@ if (isset($_POST['email'])) {
$input['department_ids'] = $selectedDepartmentIds;
$result = ['ok' => false];
if (!$errors) {
$result = UserService::createFromAdmin($input, $currentUserId);
$result = $userAccountService->createFromAdmin($input, $currentUserId);
$form = $result['form'] ?? $form;
$errors = array_merge($errors, $result['errors'] ?? []);
}
@@ -117,7 +120,7 @@ if (isset($_POST['email'])) {
if (($result['ok'] ?? false) && !$errors) {
$createdUuid = (string) ($result['uuid'] ?? '');
if ($canEditCustomFieldValues && $createdUuid !== '') {
$createdUser = UserService::findByUuid($createdUuid);
$createdUser = $userAccountService->findByUuid($createdUuid);
$createdUserId = (int) ($createdUser['id'] ?? 0);
if ($createdUserId > 0) {
$customFieldSyncResult = UserCustomFieldValueService::syncForUser(
@@ -157,7 +160,7 @@ if (isset($_POST['email'])) {
}
if (!$departmentOptionsByTenant && $selectedTenantIds) {
$departmentOptionsByTenant = DepartmentService::groupActiveByTenantIds($selectedTenantIds);
$departmentOptionsByTenant = directoryServicesFactory()->createDepartmentService()->groupActiveByTenantIds($selectedTenantIds);
}
if (!$customFieldDefinitionsByTenant && $selectedTenantIds) {
$customFieldDefinitionsByTenant = UserCustomFieldValueService::buildDefinitionsByTenant($selectedTenantIds);

View File

@@ -71,6 +71,8 @@
$customFieldDefinitionsByTenant = $customFieldDefinitionsByTenant ?? [];
$customFieldValueMap = $customFieldValueMap ?? [];
$customFieldPostedValues = $customFieldPostedValues ?? [];
$passwordMinLength = $passwordMinLength ?? 12;
$passwordHints = $passwordHints ?? [];
require __DIR__ . '/_form.phtml';
?>
</section>

View File

@@ -1,9 +1,10 @@
<?php
use MintyPHP\Router;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\User\UserAvatarService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\User\UserServicesFactory;
$userServicesFactory = new UserServicesFactory();
$userAccountService = $userServicesFactory->createUserAccountService();
$userAvatarService = $userServicesFactory->createUserAvatarService();
if (!isset($_SESSION['user'])) {
http_response_code(401);
@@ -26,7 +27,7 @@ $departments = $_GET['departments'] ?? '';
$emailVerified = $_GET['email_verified'] ?? 'all';
$loginStatus = $_GET['login_status'] ?? 'all';
$result = UserService::listPaged([
$result = $userAccountService->listPaged([
'limit' => $limit,
'offset' => $offset,
'search' => $search,
@@ -99,7 +100,7 @@ foreach ($result['rows'] as $row) {
'modified' => dt($row['modified'] ?? ''),
'last_login' => dt($row['last_login_at'] ?? ''),
'active' => (int) ($row['active'] ?? 0),
'has_avatar' => $uuid !== '' && UserAvatarService::hasAvatar($uuid),
'has_avatar' => $uuid !== '' && $userAvatarService->hasAvatar($uuid),
];
}

View File

@@ -1,13 +1,13 @@
<?php
use MintyPHP\Http\Request;
use MintyPHP\Router;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\User\UserService;
use MintyPHP\Http\Request;
use MintyPHP\Service\Tenant\TenantScopeService;
Guard::requireLogin();
$userAccountService = (new UserServicesFactory())->createUserAccountService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin/users');
@@ -16,9 +16,9 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
$uuid = trim((string) ($id ?? ''));
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
$userId = (int) ($user['id'] ?? 0);
if ($userId > 0 && $currentUserId !== $userId && !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if ($userId > 0 && $currentUserId !== $userId && !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
if (Request::wantsJson()) {
http_response_code(403);
Router::json(['error' => 'permission_denied']);
@@ -27,7 +27,7 @@ if ($userId > 0 && $currentUserId !== $userId && !TenantScopeService::canAccess(
Router::redirect('error/forbidden');
return;
}
$result = UserService::setActiveByUuid($uuid, false, $currentUserId);
$result = $userAccountService->setActiveByUuid($uuid, false, $currentUserId);
if (!($result['ok'] ?? false)) {
if (($result['error'] ?? '') === 'self_deactivate') {
Flash::error('You cannot deactivate your own account', 'admin/users', 'user_self_deactivate');

View File

@@ -1,15 +1,15 @@
<?php
use MintyPHP\Http\Request;
use MintyPHP\Router;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Http\Request;
use MintyPHP\Service\Tenant\TenantScopeService;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::USERS_DELETE);
$userAccountService = (new UserServicesFactory())->createUserAccountService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin/users');
@@ -18,9 +18,9 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
$uuid = trim((string) ($id ?? ''));
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
$userId = (int) ($user['id'] ?? 0);
if ($userId > 0 && $currentUserId !== $userId && !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if ($userId > 0 && $currentUserId !== $userId && !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
if (Request::wantsJson()) {
http_response_code(403);
Router::json(['error' => 'permission_denied']);
@@ -29,7 +29,7 @@ if ($userId > 0 && $currentUserId !== $userId && !TenantScopeService::canAccess(
Router::redirect('error/forbidden');
return;
}
$result = UserService::deleteByUuid($uuid, $currentUserId);
$result = $userAccountService->deleteByUuid($uuid, $currentUserId);
if (!($result['ok'] ?? false)) {
if (($result['error'] ?? '') === 'self_delete') {

View File

@@ -1,49 +1,58 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\I18n;
use MintyPHP\Router;
use MintyPHP\DB;
use MintyPHP\Repository\Access\UserRoleRepository;
use MintyPHP\Repository\Tenant\UserTenantRepository;
use MintyPHP\Repository\Org\UserDepartmentRepository;
use MintyPHP\Repository\Access\RolePermissionRepository;
use MintyPHP\I18n;
use MintyPHP\Repository\Auth\PasswordResetRepository;
use MintyPHP\Repository\Auth\RememberTokenRepository;
use MintyPHP\Service\Auth\AuthService;
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Router;
use MintyPHP\Service\Access\AccessServicesFactory;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requireLogin();
$userServicesFactory = new UserServicesFactory();
$userAccountService = $userServicesFactory->createUserAccountService();
$userAssignmentService = $userServicesFactory->createUserAssignmentService();
$userTenantRepository = $userServicesFactory->createUserTenantRepository();
$userRoleRepository = $userServicesFactory->createUserRoleRepository();
$userDepartmentRepository = $userServicesFactory->createUserDepartmentRepository();
$userPasswordPolicyService = $userServicesFactory->createUserPasswordPolicyService();
$authServiceFactory = new AuthServicesFactory();
$accessServicesFactory = new AccessServicesFactory();
$rolePermissionRepository = $accessServicesFactory->createRolePermissionRepository();
$authService = $authServiceFactory->createAuthService();
$apiTokenService = $authServiceFactory->createApiTokenService();
$passwordResetRepository = new PasswordResetRepository();
$rememberTokenRepository = new RememberTokenRepository();
$passwordMinLength = $userPasswordPolicyService->minLength();
$passwordHints = $userPasswordPolicyService->hints();
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId, true);
permissionGateway()->getUserPermissions($currentUserId, true);
}
$uuid = trim((string) ($id ?? ''));
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
if (!$user) {
Flash::error('User not found', 'admin/users', 'user_not_found');
Router::redirect('admin/users');
}
$userId = (int) ($user['id'] ?? 0);
$canViewUsers = PermissionService::userHas($currentUserId, PermissionService::USERS_VIEW);
$canUpdateUser = PermissionService::userHas($currentUserId, PermissionService::USERS_UPDATE);
$canUpdateSelf = PermissionService::userHas($currentUserId, PermissionService::USERS_SELF_UPDATE);
$canUpdateAssignments = PermissionService::userHas($currentUserId, PermissionService::USERS_UPDATE_ASSIGNMENTS);
$canViewUsers = permissionGateway()->userHas($currentUserId, PermissionService::USERS_VIEW);
$canUpdateUser = permissionGateway()->userHas($currentUserId, PermissionService::USERS_UPDATE);
$canUpdateSelf = permissionGateway()->userHas($currentUserId, PermissionService::USERS_SELF_UPDATE);
$canUpdateAssignments = permissionGateway()->userHas($currentUserId, PermissionService::USERS_UPDATE_ASSIGNMENTS);
$isOwnAccount = $currentUserId === $userId;
$canEditUser = $isOwnAccount ? ($canUpdateUser || $canUpdateSelf) : $canUpdateUser;
$canEditAssignments = $canEditUser && $canUpdateAssignments;
if (!$isOwnAccount && !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if (!$isOwnAccount && !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
Router::redirect('error/forbidden');
return;
}
@@ -53,7 +62,7 @@ if (!$canViewUsers && !$canEditUser) {
}
$creatorId = (int) ($user['created_by'] ?? 0);
if ($creatorId > 0) {
$creator = UserService::findById($creatorId);
$creator = $userAccountService->findById($creatorId);
if ($creator) {
$creatorName = trim(($creator['first_name'] ?? '') . ' ' . ($creator['last_name'] ?? ''));
$user['created_by_label'] = $creatorName !== '' ? $creatorName : ($creator['email'] ?? '');
@@ -62,7 +71,7 @@ if ($creatorId > 0) {
}
$modifierId = (int) ($user['modified_by'] ?? 0);
if ($modifierId > 0) {
$modifier = UserService::findById($modifierId);
$modifier = $userAccountService->findById($modifierId);
if ($modifier) {
$modifierName = trim(($modifier['first_name'] ?? '') . ' ' . ($modifier['last_name'] ?? ''));
$user['modified_by_label'] = $modifierName !== '' ? $modifierName : ($modifier['email'] ?? '');
@@ -71,7 +80,7 @@ if ($modifierId > 0) {
}
$activeChangedById = (int) ($user['active_changed_by'] ?? 0);
if ($activeChangedById > 0) {
$activeChanger = UserService::findById($activeChangedById);
$activeChanger = $userAccountService->findById($activeChangedById);
if ($activeChanger) {
$activeChangerName = trim(($activeChanger['first_name'] ?? '') . ' ' . ($activeChanger['last_name'] ?? ''));
$user['active_changed_by_label'] = $activeChangerName !== '' ? $activeChangerName : ($activeChanger['email'] ?? '');
@@ -81,19 +90,19 @@ if ($activeChangedById > 0) {
$errors = [];
$form = $user;
// Users with tenants.update permission can see ALL tenants (to assign new tenants to users)
$canManageTenants = PermissionService::userHas($currentUserId, PermissionService::TENANTS_UPDATE);
$allowedTenantIds = $canManageTenants ? null : TenantScopeService::getUserTenantIds($currentUserId);
$canManageTenants = permissionGateway()->userHas($currentUserId, PermissionService::TENANTS_UPDATE);
$allowedTenantIds = $canManageTenants ? null : directoryServicesFactory()->createDirectoryScopeGateway()->getUserTenantIds($currentUserId);
$tenants = TenantService::list();
$tenants = directoryServicesFactory()->createTenantService()->list();
if ($allowedTenantIds) {
$tenants = array_values(array_filter($tenants, static function (array $tenant) use ($allowedTenantIds): bool {
$tenantId = (int) ($tenant['id'] ?? 0);
return $tenantId > 0 && in_array($tenantId, $allowedTenantIds, true);
}));
} elseif (!$canManageTenants && TenantScopeService::isStrict()) {
} elseif (!$canManageTenants && directoryServicesFactory()->createDirectoryScopeGateway()->isStrict()) {
$tenants = [];
}
$selectedTenantIds = UserTenantRepository::listTenantIdsByUserId($userId);
$selectedTenantIds = $userTenantRepository->listTenantIdsByUserId($userId);
if ($allowedTenantIds) {
$selectedTenantIds = array_values(array_intersect($selectedTenantIds, $allowedTenantIds));
}
@@ -102,13 +111,13 @@ if (!$primaryTenantId && count($selectedTenantIds) === 1) {
$primaryTenantId = (int) $selectedTenantIds[0];
$user['primary_tenant_id'] = $primaryTenantId;
}
$roles = RoleService::listActive();
$selectedRoleIds = UserRoleRepository::listRoleIdsByUserId($userId);
$permissionRows = RolePermissionRepository::listPermissionsWithRolesByRoleIds($selectedRoleIds);
$selectedDepartmentIds = UserDepartmentRepository::listDepartmentIdsByUserId($userId);
$departmentOptionsByTenant = DepartmentService::groupActiveByTenantIds($selectedTenantIds);
$roles = directoryServicesFactory()->createRoleService()->listActive();
$selectedRoleIds = $userRoleRepository->listRoleIdsByUserId($userId);
$permissionRows = $rolePermissionRepository->listPermissionsWithRolesByRoleIds($selectedRoleIds);
$selectedDepartmentIds = $userDepartmentRepository->listDepartmentIdsByUserId($userId);
$departmentOptionsByTenant = directoryServicesFactory()->createDepartmentService()->groupActiveByTenantIds($selectedTenantIds);
$canEditCustomFieldValues = $canEditUser
&& (PermissionService::userHas($currentUserId, PermissionService::CUSTOM_FIELDS_EDIT_VALUES)
&& (permissionGateway()->userHas($currentUserId, PermissionService::CUSTOM_FIELDS_EDIT_VALUES)
|| ($isOwnAccount && $canUpdateSelf));
$customFieldDefinitionsByTenant = UserCustomFieldValueService::buildDefinitionsByTenant($selectedTenantIds);
$customFieldDefinitionIds = [];
@@ -127,17 +136,17 @@ $customFieldPostedValues = [
];
$passwordResets = [];
if ($canViewUsers || $canEditUser) {
$passwordResets = PasswordResetRepository::listByUserId($userId, 25);
$passwordResets = $passwordResetRepository->listByUserId($userId, 25);
}
$rememberTokens = [];
if ($canViewUsers || $canEditUser) {
$rememberTokens = RememberTokenRepository::listByUserId($userId, 25);
$rememberTokens = $rememberTokenRepository->listByUserId($userId, 25);
}
$apiTokens = [];
$canManageApiTokens = $canEditUser
&& PermissionService::userHas($currentUserId, PermissionService::API_TOKENS_MANAGE);
&& permissionGateway()->userHas($currentUserId, PermissionService::API_TOKENS_MANAGE);
if ($canViewUsers || $canEditUser) {
$apiTokens = \MintyPHP\Service\Auth\ApiTokenService::listForUser($userId);
$apiTokens = $apiTokenService->listForUser($userId);
}
$showApiTokens = !empty($apiTokens) || $canManageApiTokens;
// Keep initial $isOwnAccount/$canEditUser values for view permissions.
@@ -147,25 +156,25 @@ if (isset($_POST['email'])) {
Router::redirect('error/forbidden');
return;
}
$result = UserService::updateFromAdmin($userId, $_POST, $currentUserId);
$result = $userAccountService->updateFromAdmin($userId, $_POST, $currentUserId);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];
$tenantIds = UserService::normalizeIdInput($_POST['tenant_ids'] ?? []);
$existingTenantIds = UserTenantRepository::listTenantIdsByUserId($userId);
$tenantIds = $userAssignmentService->normalizeIdInput($_POST['tenant_ids'] ?? []);
$existingTenantIds = $userTenantRepository->listTenantIdsByUserId($userId);
$tenantIdsForSync = $tenantIds;
if ($canEditAssignments && $allowedTenantIds) {
$tenantIds = array_values(array_intersect($tenantIds, $allowedTenantIds));
$tenantIdsForSync = TenantScopeService::mergeTenantIdsPreservingOutOfScope(
$tenantIdsForSync = directoryServicesFactory()->createDirectoryScopeGateway()->mergeTenantIdsPreservingOutOfScope(
$tenantIds,
$existingTenantIds,
$allowedTenantIds
);
} elseif ($canEditAssignments && !$canManageTenants && TenantScopeService::isStrict()) {
} elseif ($canEditAssignments && !$canManageTenants && directoryServicesFactory()->createDirectoryScopeGateway()->isStrict()) {
$tenantIds = [];
$tenantIdsForSync = $existingTenantIds;
}
if (!$canEditAssignments) {
$tenantIds = UserTenantRepository::listTenantIdsByUserId($userId);
$tenantIds = $userTenantRepository->listTenantIdsByUserId($userId);
if ($allowedTenantIds) {
$tenantIds = array_values(array_intersect($tenantIds, $allowedTenantIds));
}
@@ -173,9 +182,9 @@ if (isset($_POST['email'])) {
}
$selectedTenantIds = $tenantIds;
$primaryTenantId = (int) ($_POST['primary_tenant_id'] ?? 0);
$selectedRoleIds = UserService::normalizeIdInput($_POST['role_ids'] ?? []);
$selectedDepartmentIds = UserService::normalizeIdInput($_POST['department_ids'] ?? []);
$departmentOptionsByTenant = DepartmentService::groupActiveByTenantIds($selectedTenantIds);
$selectedRoleIds = $userAssignmentService->normalizeIdInput($_POST['role_ids'] ?? []);
$selectedDepartmentIds = $userAssignmentService->normalizeIdInput($_POST['department_ids'] ?? []);
$departmentOptionsByTenant = directoryServicesFactory()->createDepartmentService()->groupActiveByTenantIds($selectedTenantIds);
$customFieldDefinitionsByTenant = UserCustomFieldValueService::buildDefinitionsByTenant($selectedTenantIds);
$customFieldDefinitionIds = [];
foreach ($customFieldDefinitionsByTenant as $tenantDefinitions) {
@@ -197,10 +206,10 @@ if (isset($_POST['email'])) {
$db = DB::handle();
$db->begin_transaction();
try {
UserService::syncTenants($userId, $tenantIdsForSync, false);
UserService::syncRoles($userId, $selectedRoleIds, false);
UserService::syncDepartments($userId, $selectedDepartmentIds, false);
UserService::bumpAuthzVersion($userId);
$userAssignmentService->syncTenants($userId, $tenantIdsForSync, false);
$userAssignmentService->syncRoles($userId, $selectedRoleIds, false);
$userAssignmentService->syncDepartments($userId, $selectedDepartmentIds, false);
$userAssignmentService->bumpAuthzVersion($userId);
$db->commit();
} catch (\Throwable $exception) {
$db->rollback();
@@ -209,7 +218,7 @@ if (isset($_POST['email'])) {
// Update session if editing own account (tenant assignments changed)
if ($currentUserId === $userId && !$errors) {
AuthService::loadTenantDataIntoSession($userId);
$authService->loadTenantDataIntoSession($userId);
}
}
$customFieldSyncResult = UserCustomFieldValueService::syncForUser(

View File

@@ -6,13 +6,13 @@
* @var array $user
*/
use MintyPHP\Router;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Session;
use MintyPHP\Service\User\UserAvatarService;
$values = $form ?? $user ?? [];
$avatarUuid = (string) ($values['uuid'] ?? '');
$hasAvatar = $avatarUuid !== '' && UserAvatarService::hasAvatar($avatarUuid);
$userAvatarService = (new UserServicesFactory())->createUserAvatarService();
$hasAvatar = $avatarUuid !== '' && $userAvatarService->hasAvatar($avatarUuid);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$isOwnAccount = $currentUserId > 0 && $currentUserId === (int) ($values['id'] ?? 0);
$titleText = $isOwnAccount ? t('My account') : t('Edit user');
@@ -160,6 +160,8 @@ if ($lastLoginAt !== '') {
$customFieldDefinitionsByTenant = $customFieldDefinitionsByTenant ?? [];
$customFieldValueMap = $customFieldValueMap ?? [];
$customFieldPostedValues = $customFieldPostedValues ?? [];
$passwordMinLength = $passwordMinLength ?? 12;
$passwordHints = $passwordHints ?? [];
require __DIR__ . '/_form.phtml';
?>
<?php if ($canManageApiTokens ?? false): ?>

View File

@@ -1,9 +1,10 @@
<?php
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Guard;
Guard::requireLogin();
$userAccountService = (new UserServicesFactory())->createUserAccountService();
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
@@ -30,7 +31,7 @@ if ($limit > 5000) {
$limit = 5000;
}
$result = UserService::listPaged([
$result = $userAccountService->listPaged([
'limit' => $limit,
'offset' => 0,
'search' => $search,

View File

@@ -1,21 +1,22 @@
<?php
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Auth\RememberMeService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requireLogin();
$userAccountService = (new UserServicesFactory())->createUserAccountService();
$rememberMeService = (new AuthServicesFactory())->createRememberMeService();
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$canUpdateUser = PermissionService::userHas($currentUserId, PermissionService::USERS_UPDATE);
$canUpdateSelf = PermissionService::userHas($currentUserId, PermissionService::USERS_SELF_UPDATE);
$canUpdateUser = permissionGateway()->userHas($currentUserId, PermissionService::USERS_UPDATE);
$canUpdateSelf = permissionGateway()->userHas($currentUserId, PermissionService::USERS_SELF_UPDATE);
$uuid = trim((string) ($id ?? ''));
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
if (!$user) {
Flash::error(t('User not found'), 'admin/users', 'user_not_found');
Router::redirect('admin/users');
@@ -29,11 +30,11 @@ if (!$canEditUser) {
Router::redirect('error/forbidden');
return;
}
if (!$isOwnAccount && !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if (!$isOwnAccount && !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
Router::redirect('error/forbidden');
return;
}
RememberMeService::forgetAllForUser($userId);
$rememberMeService->forgetAllForUser($userId);
Flash::success(t('Login tokens cleared'), "admin/users/edit/{$uuid}", 'tokens_cleared');
Router::redirect("admin/users/edit/{$uuid}");

View File

@@ -1,22 +1,18 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Support\Guard;
use MintyPHP\Session;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\Tenant\TenantService;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Session;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requirePermissionOrForbidden(PermissionService::USERS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
permissionGateway()->getUserPermissions($currentUserId);
}
$allowedTenantIds = TenantScopeService::getUserTenantIds($currentUserId);
$allowedTenantIds = directoryServicesFactory()->createDirectoryScopeGateway()->getUserTenantIds($currentUserId);
Buffer::set('title', t('Users'));
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
@@ -27,22 +23,22 @@ Buffer::set(
json_encode(['key' => $csrfKey, 'token' => $csrfToken], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
);
$tenants = TenantService::list();
$tenants = directoryServicesFactory()->createTenantService()->list();
if ($allowedTenantIds) {
$tenants = array_values(array_filter($tenants, static function (array $tenant) use ($allowedTenantIds): bool {
$tenantId = (int) ($tenant['id'] ?? 0);
return $tenantId > 0 && in_array($tenantId, $allowedTenantIds, true);
}));
} elseif (TenantScopeService::isStrict()) {
} elseif (directoryServicesFactory()->createDirectoryScopeGateway()->isStrict()) {
$tenants = [];
}
sortByDescription($tenants);
$roles = RoleService::listActive();
$roles = directoryServicesFactory()->createRoleService()->listActive();
sortByDescription($roles);
$departments = $allowedTenantIds ? DepartmentService::listByTenantIds($allowedTenantIds) : [];
if (!$allowedTenantIds && !TenantScopeService::isStrict()) {
$departments = DepartmentService::list();
$departments = $allowedTenantIds ? directoryServicesFactory()->createDepartmentService()->listByTenantIds($allowedTenantIds) : [];
if (!$allowedTenantIds && !directoryServicesFactory()->createDirectoryScopeGateway()->isStrict()) {
$departments = directoryServicesFactory()->createDepartmentService()->list();
}
sortByDescription($departments);

View File

@@ -1,22 +1,23 @@
<?php
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\Tenant\TenantScopeService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\Mail\MailServicesFactory;
use MintyPHP\Service\User\UserAccessTemplateService;
use MintyPHP\Service\Mail\MailService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requireLogin();
$userAccountService = (new UserServicesFactory())->createUserAccountService();
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
$canUpdateUser = PermissionService::userHas($currentUserId, PermissionService::USERS_UPDATE);
$canUpdateSelf = PermissionService::userHas($currentUserId, PermissionService::USERS_SELF_UPDATE);
$canUpdateUser = permissionGateway()->userHas($currentUserId, PermissionService::USERS_UPDATE);
$canUpdateSelf = permissionGateway()->userHas($currentUserId, PermissionService::USERS_SELF_UPDATE);
$mailService = (new MailServicesFactory())->createMailService();
$uuid = trim((string) ($id ?? ''));
$user = $uuid !== '' ? UserService::findByUuid($uuid) : null;
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
if (!$user) {
Flash::error(t('User not found'), 'admin/users', 'user_not_found');
Router::redirect('admin/users');
@@ -30,7 +31,7 @@ if (!$canEditUser) {
Router::redirect('error/forbidden');
return;
}
if (!$isOwnAccount && !TenantScopeService::canAccess('users', $userId, $currentUserId)) {
if (!$isOwnAccount && !directoryServicesFactory()->createDirectoryScopeGateway()->canAccess('users', $userId, $currentUserId)) {
Router::redirect('error/forbidden');
return;
}
@@ -40,7 +41,7 @@ $locale = (string) ($context['locale'] ?? '');
$subject = (string) ($context['subject'] ?? t('Your access details'));
$vars = is_array($context['vars'] ?? null) ? $context['vars'] : [];
$result = MailService::sendTemplate('access_info', $vars, (string) $user['email'], $subject, $locale);
$result = $mailService->sendTemplate('access_info', $vars, (string) $user['email'], $subject, $locale);
if (!($result['ok'] ?? false)) {
Flash::error(t('Access email failed'), "admin/users/edit/{$uuid}", 'access_email_failed');
Router::redirect("admin/users/edit/{$uuid}");

View File

@@ -2,11 +2,12 @@
use MintyPHP\Http\Request;
use MintyPHP\Router;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Session;
use MintyPHP\Service\User\UserService;
use MintyPHP\Support\Guard;
Guard::requireLogin();
$userTenantContextService = (new UserServicesFactory())->createUserTenantContextService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin');
@@ -47,7 +48,7 @@ if ($tenantId <= 0) {
return;
}
$result = UserService::setCurrentTenant($userId, $tenantId);
$result = $userTenantContextService->setCurrentTenant($userId, $tenantId);
if (!($result['ok'] ?? false)) {
$error = $result['error'] ?? 'update_failed';
http_response_code(400);
@@ -68,8 +69,8 @@ if (isset($_SESSION['user'])) {
$_SESSION['current_tenant'] = $result['tenant'] ?? null;
// Reload available tenants and departments
$_SESSION['available_tenants'] = UserService::getAvailableTenants($userId);
$_SESSION['available_departments_by_tenant'] = UserService::getAvailableDepartmentsByTenant($userId);
$_SESSION['available_tenants'] = $userTenantContextService->getAvailableTenants($userId);
$_SESSION['available_departments_by_tenant'] = $userTenantContextService->getAvailableDepartmentsByTenant($userId);
if (Request::wantsJson()) {
Router::json([

View File

@@ -2,12 +2,13 @@
use MintyPHP\Http\Request;
use MintyPHP\Router;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Session;
use MintyPHP\Service\User\UserService;
use MintyPHP\Support\Guard;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
Guard::requireLogin();
$userAccountService = (new UserServicesFactory())->createUserAccountService();
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
Router::redirect('admin');
@@ -58,7 +59,7 @@ if ($theme === '' || !isset($themes[$theme])) {
return;
}
$updated = UserService::setTheme($userId, $theme);
$updated = $userAccountService->setTheme($userId, $theme);
if (!$updated) {
http_response_code(500);
if (Request::wantsJson()) {

View File

@@ -0,0 +1,129 @@
<?php
use MintyPHP\Http\ApiBootstrap;
use MintyPHP\Http\ApiResponse;
use MintyPHP\Repository\Tenant\TenantRepository;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Service\Security\SecurityServicesFactory;
use MintyPHP\Service\User\UserServicesFactory;
ApiBootstrap::init();
ApiResponse::requireMethod('POST');
$input = ApiResponse::readJsonBody();
// ---- Login-specific rate limits (stricter than the general API rate limit in ApiBootstrap) ----
$rateLimiter = (new SecurityServicesFactory())->createRateLimiterService();
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$ipResult = $rateLimiter->isBlocked('api.auth.login.ip', $ip);
if (!($ipResult['allowed'] ?? true)) {
ApiResponse::tooManyRequests((int) ($ipResult['retry_after'] ?? 60));
}
// ---- Input ----
$email = strtolower(trim((string) ($input['email'] ?? '')));
$password = (string) ($input['password'] ?? '');
$tokenName = trim((string) ($input['token_name'] ?? '')) ?: 'Login';
$tenantUuid = trim((string) ($input['tenant_uuid'] ?? ''));
$validationErrors = [];
if ($email === '') {
$validationErrors['email'] = ['required'];
}
if ($password === '') {
$validationErrors['password'] = ['required'];
}
if ($validationErrors) {
ApiResponse::validationError($validationErrors);
}
// ---- Email+IP rate limit ----
$emailKey = $email . '|' . $ip;
$emailResult = $rateLimiter->isBlocked('api.auth.login.email_ip', $emailKey);
if (!($emailResult['allowed'] ?? true)) {
ApiResponse::tooManyRequests((int) ($emailResult['retry_after'] ?? 60));
}
// ---- User lookup ----
$userReadRepository = (new UserServicesFactory())->createUserReadRepository();
$user = $userReadRepository->findByEmail($email);
if (!$user) {
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
ApiResponse::error('invalid_credentials', 401);
}
// ---- Account checks ----
if (!(int) ($user['active'] ?? 0)) {
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
ApiResponse::error('account_inactive', 401);
}
if (empty($user['email_verified_at'])) {
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
ApiResponse::error('invalid_credentials', 401);
}
// ---- Password verification ----
if (!password_verify($password, (string) ($user['password'] ?? ''))) {
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
ApiResponse::error('invalid_credentials', 401);
}
// ---- 2FA stub ----
// When TOTP is implemented, intercept here if totp_secret is non-empty:
// return a short-lived challenge token instead of issuing a full API token.
// Example: ApiResponse::success(['requires_2fa' => true, 'challenge_token' => '...'], 200);
// $totpSecret = trim((string) ($user['totp_secret'] ?? ''));
// if ($totpSecret !== '') { /* TODO: 2FA challenge flow */ }
// ---- Successful login: reset email+IP rate limit ----
$rateLimiter->reset('api.auth.login.email_ip', $emailKey);
// ---- Optional tenant scope ----
$tenantId = null;
if ($tenantUuid !== '') {
$tenant = (new TenantRepository())->findByUuid($tenantUuid);
if (!$tenant) {
ApiResponse::error('invalid_tenant_uuid', 422);
}
$tenantId = (int) ($tenant['id'] ?? 0);
if ($tenantId <= 0) {
ApiResponse::error('invalid_tenant_uuid', 422);
}
$userId = (int) ($user['id'] ?? 0);
$userTenantIds = (new AuthServicesFactory())->createAuthScopeGateway()->getUserTenantIds($userId);
if (!in_array($tenantId, $userTenantIds, true)) {
ApiResponse::error('tenant_not_assigned', 403);
}
}
// ---- Create token ----
$userId = (int) ($user['id'] ?? 0);
$result = (new AuthServicesFactory())->createApiTokenService()->create(
$userId,
$tokenName,
$tenantId,
null, // expiresAt null → uses getApiTokenDefaultTtlDays() from settings
$userId // createdBy = self-issued
);
if (!($result['ok'] ?? false)) {
$error = (string) ($result['error'] ?? 'create_failed');
if ($error === 'max_tokens_reached') {
ApiResponse::error($error, 409);
}
ApiResponse::error($error, 422);
}
ApiResponse::success([
'data' => [
'token' => (string) ($result['token'] ?? ''),
'token_uuid' => (string) ($result['uuid'] ?? ''),
'expires_at' => $result['expires_at'] ?? null,
],
], 201);

View File

@@ -1,9 +1,8 @@
<?php
use MintyPHP\Http\ApiAuth;
use MintyPHP\Http\ApiBootstrap;
use MintyPHP\Http\ApiResponse;
use MintyPHP\Http\ApiAuth;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Access\PermissionService;
ApiBootstrap::init();
@@ -25,7 +24,7 @@ if ($method === 'GET') {
if ($scopedTenantId) {
$options['tenantIds'] = [$scopedTenantId];
}
$result = DepartmentService::listPaged($options);
$result = directoryServicesFactory()->createDepartmentService()->listPaged($options);
$rows = [];
foreach ($result['rows'] as $row) {
@@ -59,7 +58,7 @@ if ($method === 'POST') {
}
$input['tenant_id'] = $scopedTenantId;
}
$result = DepartmentService::createFromAdmin($input, ApiAuth::userId());
$result = directoryServicesFactory()->createDepartmentService()->createFromAdmin($input, ApiAuth::userId());
ApiResponse::fromServiceResult($result, 201);
}

View File

@@ -1,9 +1,8 @@
<?php
use MintyPHP\Http\ApiAuth;
use MintyPHP\Http\ApiBootstrap;
use MintyPHP\Http\ApiResponse;
use MintyPHP\Http\ApiAuth;
use MintyPHP\Service\Org\DepartmentService;
use MintyPHP\Service\Access\PermissionService;
ApiBootstrap::init();
@@ -18,7 +17,7 @@ $method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
if ($method === 'GET') {
ApiResponse::requirePermission(PermissionService::DEPARTMENTS_VIEW);
$department = DepartmentService::findByUuid($uuid);
$department = directoryServicesFactory()->createDepartmentService()->findByUuid($uuid);
if (!$department) {
ApiResponse::notFound();
}
@@ -42,7 +41,7 @@ if ($method === 'GET') {
if ($method === 'PUT' || $method === 'PATCH') {
ApiResponse::requirePermission(PermissionService::DEPARTMENTS_UPDATE);
$department = DepartmentService::findByUuid($uuid);
$department = directoryServicesFactory()->createDepartmentService()->findByUuid($uuid);
if (!$department) {
ApiResponse::notFound();
}
@@ -51,14 +50,14 @@ if ($method === 'PUT' || $method === 'PATCH') {
ApiAuth::requireResourceAccess('departments', $departmentId);
$input = ApiResponse::readJsonBody();
$result = DepartmentService::updateFromAdmin($departmentId, $input, ApiAuth::userId());
$result = directoryServicesFactory()->createDepartmentService()->updateFromAdmin($departmentId, $input, ApiAuth::userId());
ApiResponse::fromServiceResult($result);
}
if ($method === 'DELETE') {
ApiResponse::requirePermission(PermissionService::DEPARTMENTS_DELETE);
$department = DepartmentService::findByUuid($uuid);
$department = directoryServicesFactory()->createDepartmentService()->findByUuid($uuid);
if (!$department) {
ApiResponse::notFound();
}
@@ -66,7 +65,7 @@ if ($method === 'DELETE') {
$departmentId = (int) ($department['id'] ?? 0);
ApiAuth::requireResourceAccess('departments', $departmentId);
$result = DepartmentService::deleteByUuid($uuid);
$result = directoryServicesFactory()->createDepartmentService()->deleteByUuid($uuid);
ApiResponse::fromServiceResult($result);
}

View File

@@ -1,26 +1,27 @@
<?php
use MintyPHP\Http\ApiAuth;
use MintyPHP\Http\ApiBootstrap;
use MintyPHP\Http\ApiResponse;
use MintyPHP\Http\ApiAuth;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
use MintyPHP\Service\User\UserService;
use MintyPHP\Service\User\UserServicesFactory;
ApiBootstrap::init();
ApiResponse::requireMethod('GET');
$userAssignmentService = (new UserServicesFactory())->createUserAssignmentService();
$user = ApiAuth::user();
$userId = ApiAuth::userId();
$assignments = UserService::buildAssignmentsForUser($userId);
$assignments = $userAssignmentService->buildAssignmentsForUser($userId);
$currentTenantId = (int) (ApiAuth::tenantId() ?? 0);
$currentTenant = UserService::findTenantSummaryInAssignments($assignments, $currentTenantId);
$currentTenant = $userAssignmentService->findTenantSummaryInAssignments($assignments, $currentTenantId);
$primaryTenantId = (int) ($user['primary_tenant_id'] ?? 0);
$primaryTenant = UserService::findTenantSummaryInAssignments($assignments, $primaryTenantId);
$primaryTenant = $userAssignmentService->findTenantSummaryInAssignments($assignments, $primaryTenantId);
$publicAssignments = UserService::mapAssignmentsToPublic($assignments);
$publicAssignments = $userAssignmentService->mapAssignmentsToPublic($assignments);
$canViewPermissions = ApiAuth::hasPermission(PermissionService::PERMISSIONS_VIEW);
$publicPermissions = $canViewPermissions ? ApiAuth::permissions() : [];
$publicCustomFields = UserCustomFieldValueService::buildPublicValuesByTenant(

View File

@@ -5,9 +5,11 @@ use MintyPHP\Http\ApiBootstrap;
use MintyPHP\Http\ApiResponse;
use MintyPHP\Repository\Auth\ApiTokenRepository;
use MintyPHP\Repository\Tenant\TenantRepository;
use MintyPHP\Service\Auth\ApiTokenService;
use MintyPHP\Service\Auth\AuthServicesFactory;
ApiBootstrap::init();
$apiTokenService = (new AuthServicesFactory())->createApiTokenService();
$apiTokenRepository = new ApiTokenRepository();
$userId = ApiAuth::userId();
if ($userId <= 0) {
@@ -27,7 +29,7 @@ if ($method === 'GET') {
}
$scopedTenantId = ApiAuth::scopedTenantId();
$tokens = ApiTokenRepository::listByUserId($userId, $limit);
$tokens = $apiTokenRepository->listByUserId($userId, $limit);
$tenantIds = [];
foreach ($tokens as $token) {
$tokenTenantId = isset($token['tenant_id']) ? (int) $token['tenant_id'] : 0;
@@ -38,7 +40,7 @@ if ($method === 'GET') {
$tenantIds = array_values(array_unique($tenantIds));
$tenantUuidById = [];
if ($tenantIds) {
foreach (TenantRepository::listByIds($tenantIds) as $tenant) {
foreach ((new TenantRepository())->listByIds($tenantIds) as $tenant) {
$tenantId = (int) ($tenant['id'] ?? 0);
$tenantUuid = trim((string) ($tenant['uuid'] ?? ''));
if ($tenantId > 0 && $tenantUuid !== '') {
@@ -92,7 +94,7 @@ if ($method === 'POST') {
$tenantUuid = null;
$tenantUuidInput = trim((string) ($input['tenant_uuid'] ?? ''));
if ($tenantUuidInput !== '') {
$tenant = TenantRepository::findByUuid($tenantUuidInput);
$tenant = (new TenantRepository())->findByUuid($tenantUuidInput);
if (!$tenant) {
ApiResponse::validationError(['tenant_uuid' => ['invalid_tenant_uuid']]);
}
@@ -105,7 +107,7 @@ if ($method === 'POST') {
$scopedTenantId = ApiAuth::scopedTenantId();
if ($scopedTenantId !== null && $scopedTenantId > 0) {
$scopedTenant = TenantRepository::find($scopedTenantId);
$scopedTenant = (new TenantRepository())->find($scopedTenantId);
$scopedTenantUuid = trim((string) ($scopedTenant['uuid'] ?? ''));
if ($scopedTenantUuid === '') {
ApiResponse::forbidden('tenant_scoped_token_forbidden');
@@ -149,7 +151,7 @@ if ($method === 'POST') {
}
}
$result = ApiTokenService::create($userId, $name, $tenantId, $expiresAt, $userId);
$result = $apiTokenService->create($userId, $name, $tenantId, $expiresAt, $userId);
if (!($result['ok'] ?? false)) {
$error = (string) ($result['error'] ?? 'create_failed');
if ($error === 'tenant_not_assigned') {

View File

@@ -4,10 +4,11 @@ use MintyPHP\Http\ApiAuth;
use MintyPHP\Http\ApiBootstrap;
use MintyPHP\Http\ApiResponse;
use MintyPHP\Repository\Tenant\TenantRepository;
use MintyPHP\Service\Auth\ApiTokenService;
use MintyPHP\Service\Auth\AuthServicesFactory;
ApiBootstrap::init();
ApiResponse::requireMethod('POST');
$apiTokenService = (new AuthServicesFactory())->createApiTokenService();
$userId = ApiAuth::userId();
if ($userId <= 0) {
@@ -19,13 +20,13 @@ ApiAuth::requireSelfManageTokens();
$scopedTenantId = ApiAuth::scopedTenantId();
$scopedTenantUuid = null;
if ($scopedTenantId !== null && $scopedTenantId > 0) {
$tenant = TenantRepository::find($scopedTenantId);
$tenant = (new TenantRepository())->find($scopedTenantId);
$scopedTenantUuid = trim((string) ($tenant['uuid'] ?? ''));
if ($scopedTenantUuid === '') {
$scopedTenantUuid = null;
}
}
$result = ApiTokenService::revokeAllForUser($userId, $scopedTenantId);
$result = $apiTokenService->revokeAllForUser($userId, $scopedTenantId);
ApiResponse::success([
'data' => [

View File

@@ -4,10 +4,11 @@ use MintyPHP\Http\ApiAuth;
use MintyPHP\Http\ApiBootstrap;
use MintyPHP\Http\ApiResponse;
use MintyPHP\Repository\Tenant\TenantRepository;
use MintyPHP\Service\Auth\ApiTokenService;
use MintyPHP\Service\Auth\AuthServicesFactory;
ApiBootstrap::init();
ApiResponse::requireMethod('POST');
$apiTokenService = (new AuthServicesFactory())->createApiTokenService();
$userId = ApiAuth::userId();
if ($userId <= 0) {
@@ -25,7 +26,7 @@ $input = ApiResponse::readJsonBody();
$expiresInput = trim((string) ($input['expires_at'] ?? ''));
$expiresAt = $expiresInput !== '' ? $expiresInput : null;
$result = ApiTokenService::rotateCurrentToken($userId, $currentTokenId, $expiresAt);
$result = $apiTokenService->rotateCurrentToken($userId, $currentTokenId, $expiresAt);
if (!($result['ok'] ?? false)) {
$error = (string) ($result['error'] ?? 'rotate_failed');
if ($error === 'current_token_not_found') {
@@ -43,7 +44,7 @@ if (!($result['ok'] ?? false)) {
$tenantUuid = null;
$tenantId = isset($result['tenant_id']) ? (int) ($result['tenant_id']) : 0;
if ($tenantId > 0) {
$tenant = TenantRepository::find($tenantId);
$tenant = (new TenantRepository())->find($tenantId);
$tenantUuid = trim((string) ($tenant['uuid'] ?? ''));
if ($tenantUuid === '') {
$tenantUuid = null;

View File

@@ -7,6 +7,7 @@ use MintyPHP\Repository\Auth\ApiTokenRepository;
use MintyPHP\Repository\Tenant\TenantRepository;
ApiBootstrap::init();
$apiTokenRepository = new ApiTokenRepository();
$userId = ApiAuth::userId();
if ($userId <= 0) {
@@ -16,11 +17,11 @@ if ($userId <= 0) {
ApiAuth::requireSelfManageTokens();
$tokenUuid = trim((string) ($id ?? ''));
if (!ApiTokenRepository::isUuid($tokenUuid)) {
if (!$apiTokenRepository->isUuid($tokenUuid)) {
ApiResponse::notFound();
}
$token = ApiTokenRepository::findByUuidForUser($tokenUuid, $userId);
$token = $apiTokenRepository->findByUuidForUser($tokenUuid, $userId);
if (!$token) {
ApiResponse::notFound();
}
@@ -35,7 +36,7 @@ if ($scopedTenantId !== null && $scopedTenantId > 0 && $tokenTenantId !== $scope
}
$tenantUuid = null;
if ($tokenTenantId !== null) {
$tenant = TenantRepository::find($tokenTenantId);
$tenant = (new TenantRepository())->find($tokenTenantId);
$tenantUuid = trim((string) ($tenant['uuid'] ?? ''));
if ($tenantUuid === '') {
$tenantUuid = null;
@@ -62,7 +63,7 @@ if ($method === 'GET') {
}
if ($method === 'DELETE') {
$revoked = ApiTokenRepository::revokeByUuidForUser($tokenUuid, $userId);
$revoked = $apiTokenRepository->revokeByUuidForUser($tokenUuid, $userId);
if (!$revoked) {
ApiResponse::error('revoke_failed', 422);
}

View File

@@ -1,9 +1,8 @@
<?php
use MintyPHP\Http\ApiAuth;
use MintyPHP\Http\ApiBootstrap;
use MintyPHP\Http\ApiResponse;
use MintyPHP\Http\ApiAuth;
use MintyPHP\Service\Access\RoleService;
use MintyPHP\Service\Access\PermissionService;
ApiBootstrap::init();
@@ -13,7 +12,7 @@ $method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
if ($method === 'GET') {
ApiResponse::requirePermission(PermissionService::ROLES_VIEW);
$result = RoleService::listPaged([
$result = directoryServicesFactory()->createRoleService()->listPaged([
'limit' => (int) ($_GET['limit'] ?? 25),
'offset' => (int) ($_GET['offset'] ?? 0),
'search' => trim((string) ($_GET['search'] ?? '')),
@@ -44,7 +43,7 @@ if ($method === 'POST') {
ApiResponse::requirePermission(PermissionService::ROLES_CREATE);
$input = ApiResponse::readJsonBody();
$result = RoleService::createFromAdmin($input, ApiAuth::userId());
$result = directoryServicesFactory()->createRoleService()->createFromAdmin($input, ApiAuth::userId());
ApiResponse::fromServiceResult($result, 201);
}

Some files were not shown because too many files have changed in this diff Show More