major update
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Repository\Tenant\TenantRepository;
|
||||
use MintyPHP\Service\Auth\ApiTokenEndpointService;
|
||||
use MintyPHP\Service\Auth\AuthServicesFactory;
|
||||
use MintyPHP\Service\Security\SecurityServicesFactory;
|
||||
use MintyPHP\Service\User\UserServicesFactory;
|
||||
@@ -10,10 +10,12 @@ use MintyPHP\Service\User\UserServicesFactory;
|
||||
ApiBootstrap::init(false);
|
||||
ApiResponse::requireMethod('POST');
|
||||
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$request = requestInput();
|
||||
$input = $request->bodyAll();
|
||||
$apiTokenEndpointService = app(ApiTokenEndpointService::class);
|
||||
|
||||
// ---- Login-specific rate limits (stricter than the general API rate limit in ApiBootstrap) ----
|
||||
$rateLimiter = (new SecurityServicesFactory())->createRateLimiterService();
|
||||
$rateLimiter = (app(SecurityServicesFactory::class))->createRateLimiterService();
|
||||
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
|
||||
|
||||
$ipResult = $rateLimiter->isBlocked('api.auth.login.ip', $ip);
|
||||
@@ -27,15 +29,15 @@ $password = (string) ($input['password'] ?? '');
|
||||
$tokenName = trim((string) ($input['token_name'] ?? '')) ?: 'Login';
|
||||
$tenantUuid = trim((string) ($input['tenant_uuid'] ?? ''));
|
||||
|
||||
$validationErrors = [];
|
||||
$validationErrors = formErrors();
|
||||
if ($email === '') {
|
||||
$validationErrors['email'] = ['required'];
|
||||
$validationErrors->add('email', 'required');
|
||||
}
|
||||
if ($password === '') {
|
||||
$validationErrors['password'] = ['required'];
|
||||
$validationErrors->add('password', 'required');
|
||||
}
|
||||
if ($validationErrors) {
|
||||
ApiResponse::validationError($validationErrors);
|
||||
if ($validationErrors->hasAny()) {
|
||||
ApiResponse::validationFromFormErrors($validationErrors);
|
||||
}
|
||||
|
||||
// ---- Email+IP rate limit ----
|
||||
@@ -46,7 +48,7 @@ if (!($emailResult['allowed'] ?? true)) {
|
||||
}
|
||||
|
||||
// ---- User lookup ----
|
||||
$userReadRepository = (new UserServicesFactory())->createUserReadRepository();
|
||||
$userReadRepository = (app(UserServicesFactory::class))->createUserReadRepository();
|
||||
$user = $userReadRepository->findByEmail($email);
|
||||
if (!$user) {
|
||||
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
|
||||
@@ -87,24 +89,19 @@ $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);
|
||||
$tenantResolution = $apiTokenEndpointService->resolveLoginTenant((int) ($user['id'] ?? 0), $tenantUuid);
|
||||
if (!($tenantResolution['ok'] ?? false)) {
|
||||
ApiResponse::error(
|
||||
(string) ($tenantResolution['error'] ?? 'invalid_tenant_uuid'),
|
||||
(int) ($tenantResolution['status'] ?? 422)
|
||||
);
|
||||
}
|
||||
$tenantId = array_key_exists('tenant_id', $tenantResolution) ? (int) ($tenantResolution['tenant_id'] ?? 0) : null;
|
||||
}
|
||||
|
||||
// ---- Create token ----
|
||||
$userId = (int) ($user['id'] ?? 0);
|
||||
$result = (new AuthServicesFactory())->createApiTokenService()->create(
|
||||
$result = (app(AuthServicesFactory::class))->createApiTokenService()->create(
|
||||
$userId,
|
||||
$tokenName,
|
||||
$tenantId,
|
||||
|
||||
@@ -3,28 +3,30 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
|
||||
ApiBootstrap::init();
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$request = requestInput();
|
||||
$method = $request->method();
|
||||
|
||||
if ($method === 'GET') {
|
||||
ApiResponse::requirePermission(PermissionService::DEPARTMENTS_VIEW);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_DEPARTMENTS_VIEW);
|
||||
|
||||
$limit = $request->queryInt('limit', 25);
|
||||
$offset = $request->queryInt('offset', 0);
|
||||
$options = [
|
||||
'limit' => (int) ($_GET['limit'] ?? 25),
|
||||
'offset' => (int) ($_GET['offset'] ?? 0),
|
||||
'search' => trim((string) ($_GET['search'] ?? '')),
|
||||
'order' => (string) ($_GET['order'] ?? 'description'),
|
||||
'dir' => (string) ($_GET['dir'] ?? 'asc'),
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'search' => $request->queryString('search'),
|
||||
'order' => $request->queryString('order', 'description'),
|
||||
'dir' => $request->queryString('dir', 'asc'),
|
||||
'tenantUserId' => ApiAuth::userId(),
|
||||
];
|
||||
$scopedTenantId = ApiAuth::scopedTenantId();
|
||||
if ($scopedTenantId) {
|
||||
$options['tenantIds'] = [$scopedTenantId];
|
||||
}
|
||||
$result = directoryServicesFactory()->createDepartmentService()->listPaged($options);
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createDepartmentService()->listPaged($options);
|
||||
|
||||
$rows = [];
|
||||
foreach ($result['rows'] as $row) {
|
||||
@@ -41,24 +43,24 @@ if ($method === 'GET') {
|
||||
ApiResponse::success([
|
||||
'data' => $rows,
|
||||
'total' => $result['total'] ?? 0,
|
||||
'limit' => (int) ($_GET['limit'] ?? 25),
|
||||
'offset' => (int) ($_GET['offset'] ?? 0),
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($method === 'POST') {
|
||||
ApiResponse::requirePermission(PermissionService::DEPARTMENTS_CREATE);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_DEPARTMENTS_CREATE);
|
||||
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$input = $request->bodyAll();
|
||||
if (array_key_exists('tenant_id', $input)) {
|
||||
ApiResponse::validationError(['tenant_id' => ['use_tenant_uuid']]);
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom(['tenant_id' => ['use_tenant_uuid']]));
|
||||
}
|
||||
if (array_key_exists('tenant_uuid', $input)) {
|
||||
$tenantUuid = trim((string) ($input['tenant_uuid'] ?? ''));
|
||||
if ($tenantUuid !== '') {
|
||||
$tenant = directoryServicesFactory()->createTenantService()->findByUuid($tenantUuid);
|
||||
$tenant = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->findByUuid($tenantUuid);
|
||||
if (!$tenant) {
|
||||
ApiResponse::validationError(['tenant_uuid' => ['not_found']]);
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom(['tenant_uuid' => ['not_found']]));
|
||||
}
|
||||
$input['tenant_id'] = (int) ($tenant['id'] ?? 0);
|
||||
}
|
||||
@@ -72,7 +74,7 @@ if ($method === 'POST') {
|
||||
}
|
||||
$input['tenant_id'] = $scopedTenantId;
|
||||
}
|
||||
$result = directoryServicesFactory()->createDepartmentService()->createFromAdmin($input, ApiAuth::userId());
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createDepartmentService()->createFromAdmin($input, ApiAuth::userId());
|
||||
ApiResponse::fromServiceResult($result, 201);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
|
||||
ApiBootstrap::init();
|
||||
$request = requestInput();
|
||||
|
||||
$uuid = trim((string) ($id ?? ''));
|
||||
if ($uuid === '') {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$method = $request->method();
|
||||
|
||||
if ($method === 'GET') {
|
||||
ApiResponse::requirePermission(PermissionService::DEPARTMENTS_VIEW);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_DEPARTMENTS_VIEW);
|
||||
|
||||
$department = directoryServicesFactory()->createDepartmentService()->findByUuid($uuid);
|
||||
$department = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createDepartmentService()->findByUuid($uuid);
|
||||
if (!$department) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
@@ -27,7 +27,7 @@ if ($method === 'GET') {
|
||||
$tenantUuid = '';
|
||||
$tenantId = (int) ($department['tenant_id'] ?? 0);
|
||||
if ($tenantId > 0) {
|
||||
$tenant = directoryServicesFactory()->createTenantService()->findById($tenantId);
|
||||
$tenant = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->findById($tenantId);
|
||||
$tenantUuid = (string) ($tenant['uuid'] ?? '');
|
||||
}
|
||||
|
||||
@@ -46,9 +46,9 @@ if ($method === 'GET') {
|
||||
}
|
||||
|
||||
if ($method === 'PUT' || $method === 'PATCH') {
|
||||
ApiResponse::requirePermission(PermissionService::DEPARTMENTS_UPDATE);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_DEPARTMENTS_UPDATE);
|
||||
|
||||
$department = directoryServicesFactory()->createDepartmentService()->findByUuid($uuid);
|
||||
$department = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createDepartmentService()->findByUuid($uuid);
|
||||
if (!$department) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
@@ -56,16 +56,16 @@ if ($method === 'PUT' || $method === 'PATCH') {
|
||||
$departmentId = (int) ($department['id'] ?? 0);
|
||||
ApiAuth::requireResourceAccess('departments', $departmentId);
|
||||
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$input = $request->bodyAll();
|
||||
if (array_key_exists('tenant_id', $input)) {
|
||||
ApiResponse::validationError(['tenant_id' => ['use_tenant_uuid']]);
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom(['tenant_id' => ['use_tenant_uuid']]));
|
||||
}
|
||||
if (array_key_exists('tenant_uuid', $input)) {
|
||||
$tenantUuid = trim((string) ($input['tenant_uuid'] ?? ''));
|
||||
if ($tenantUuid !== '') {
|
||||
$tenant = directoryServicesFactory()->createTenantService()->findByUuid($tenantUuid);
|
||||
$tenant = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->findByUuid($tenantUuid);
|
||||
if (!$tenant) {
|
||||
ApiResponse::validationError(['tenant_uuid' => ['not_found']]);
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom(['tenant_uuid' => ['not_found']]));
|
||||
}
|
||||
$input['tenant_id'] = (int) ($tenant['id'] ?? 0);
|
||||
} else {
|
||||
@@ -81,14 +81,14 @@ if ($method === 'PUT' || $method === 'PATCH') {
|
||||
}
|
||||
$input['tenant_id'] = $scopedTenantId;
|
||||
}
|
||||
$result = directoryServicesFactory()->createDepartmentService()->updateFromAdmin($departmentId, $input, ApiAuth::userId());
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createDepartmentService()->updateFromAdmin($departmentId, $input, ApiAuth::userId());
|
||||
ApiResponse::fromServiceResult($result);
|
||||
}
|
||||
|
||||
if ($method === 'DELETE') {
|
||||
ApiResponse::requirePermission(PermissionService::DEPARTMENTS_DELETE);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_DEPARTMENTS_DELETE);
|
||||
|
||||
$department = directoryServicesFactory()->createDepartmentService()->findByUuid($uuid);
|
||||
$department = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createDepartmentService()->findByUuid($uuid);
|
||||
if (!$department) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
@@ -96,7 +96,7 @@ if ($method === 'DELETE') {
|
||||
$departmentId = (int) ($department['id'] ?? 0);
|
||||
ApiAuth::requireResourceAccess('departments', $departmentId);
|
||||
|
||||
$result = directoryServicesFactory()->createDepartmentService()->deleteByUuid($uuid);
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createDepartmentService()->deleteByUuid($uuid);
|
||||
ApiResponse::fromServiceResult($result);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
use MintyPHP\Service\User\UserServicesFactory;
|
||||
|
||||
define('MINTY_ALLOW_OUTPUT', true);
|
||||
|
||||
ApiBootstrap::init();
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$userServicesFactory = new UserServicesFactory();
|
||||
$request = requestInput();
|
||||
$method = $request->method();
|
||||
$userServicesFactory = app(UserServicesFactory::class);
|
||||
$userAvatarService = $userServicesFactory->createUserAvatarService();
|
||||
$user = ApiAuth::user();
|
||||
$uuid = (string) ($user['uuid'] ?? '');
|
||||
|
||||
if ($method === 'GET') {
|
||||
$size = isset($_GET['size']) ? (int) $_GET['size'] : null;
|
||||
$size = $request->hasQuery('size') ? $request->queryInt('size') : null;
|
||||
|
||||
$path = $userAvatarService->findAvatarPath($uuid, $size);
|
||||
if (!$path || !is_file($path)) {
|
||||
@@ -38,11 +38,9 @@ if ($method === 'GET') {
|
||||
}
|
||||
|
||||
if ($method === 'POST') {
|
||||
if (!ApiAuth::hasPermission(PermissionService::USERS_SELF_UPDATE)) {
|
||||
ApiResponse::forbidden();
|
||||
}
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_ME_SELF_UPDATE);
|
||||
|
||||
$result = $userAvatarService->saveUpload($uuid, $_FILES['avatar'] ?? []);
|
||||
$result = $userAvatarService->saveUpload($uuid, $request->file('avatar', []));
|
||||
if (!($result['ok'] ?? false)) {
|
||||
$error = $result['error'] ?? 'upload_failed';
|
||||
ApiResponse::error($error, 422);
|
||||
@@ -52,9 +50,7 @@ if ($method === 'POST') {
|
||||
}
|
||||
|
||||
if ($method === 'DELETE') {
|
||||
if (!ApiAuth::hasPermission(PermissionService::USERS_SELF_UPDATE)) {
|
||||
ApiResponse::forbidden();
|
||||
}
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_ME_SELF_UPDATE);
|
||||
|
||||
$userAvatarService->delete($uuid);
|
||||
ApiResponse::noContent();
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
|
||||
use MintyPHP\Service\User\UserServicesFactory;
|
||||
|
||||
ApiBootstrap::init();
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$userServicesFactory = new UserServicesFactory();
|
||||
$request = requestInput();
|
||||
$method = $request->method();
|
||||
$userServicesFactory = app(UserServicesFactory::class);
|
||||
$userAssignmentService = $userServicesFactory->createUserAssignmentService();
|
||||
|
||||
if ($method === 'GET') {
|
||||
@@ -23,19 +23,17 @@ if ($method === 'GET') {
|
||||
}
|
||||
|
||||
if ($method === 'PUT' || $method === 'PATCH') {
|
||||
if (!ApiAuth::hasPermission(PermissionService::USERS_SELF_UPDATE)) {
|
||||
ApiResponse::forbidden();
|
||||
}
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_ME_SELF_UPDATE);
|
||||
|
||||
$userId = ApiAuth::userId();
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$input = $request->bodyAll();
|
||||
|
||||
$userAccountService = $userServicesFactory->createUserAccountService();
|
||||
$result = $userAccountService->updateSelfProfile($userId, $input);
|
||||
if (!($result['ok'] ?? false)) {
|
||||
$errors = $result['errors'] ?? [];
|
||||
if (is_array($errors) && $errors !== []) {
|
||||
ApiResponse::validationError(['profile' => array_values($errors)]);
|
||||
ApiResponse::validationFromFormErrors(formErrors()->addMany('profile', array_values($errors)));
|
||||
}
|
||||
ApiResponse::fromServiceResult($result);
|
||||
}
|
||||
@@ -70,9 +68,9 @@ function buildMeResponse(array $user, int $userId, $userAssignmentService): arra
|
||||
$primaryTenant = $userAssignmentService->findTenantSummaryInAssignments($assignments, $primaryTenantId);
|
||||
|
||||
$publicAssignments = $userAssignmentService->mapAssignmentsToPublic($assignments);
|
||||
$canViewPermissions = ApiAuth::hasPermission(PermissionService::PERMISSIONS_VIEW);
|
||||
$canViewPermissions = ApiAuth::can(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_PERMISSIONS_VIEW);
|
||||
$publicPermissions = $canViewPermissions ? ApiAuth::permissions() : [];
|
||||
$publicCustomFields = UserCustomFieldValueService::buildPublicValuesByTenant(
|
||||
$publicCustomFields = app(UserCustomFieldValueService::class)->buildPublicValuesByTenant(
|
||||
$userId,
|
||||
$assignments['tenants'] ?? [],
|
||||
ApiAuth::scopedTenantId()
|
||||
|
||||
@@ -3,36 +3,35 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
use MintyPHP\Service\User\UserServicesFactory;
|
||||
|
||||
ApiBootstrap::init();
|
||||
ApiResponse::requireMethod('POST');
|
||||
|
||||
if (!ApiAuth::hasPermission(PermissionService::USERS_SELF_UPDATE)) {
|
||||
ApiResponse::forbidden();
|
||||
}
|
||||
$request = requestInput();
|
||||
|
||||
$input = ApiResponse::readJsonBody();
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_ME_SELF_UPDATE);
|
||||
|
||||
$input = $request->bodyAll();
|
||||
$currentPassword = (string) ($input['current_password'] ?? '');
|
||||
$password = (string) ($input['password'] ?? '');
|
||||
$password2 = (string) ($input['password2'] ?? '');
|
||||
|
||||
$validationErrors = [];
|
||||
$validationErrors = formErrors();
|
||||
if ($currentPassword === '') {
|
||||
$validationErrors['current_password'] = ['required'];
|
||||
$validationErrors->add('current_password', 'required');
|
||||
}
|
||||
if ($password === '') {
|
||||
$validationErrors['password'] = ['required'];
|
||||
$validationErrors->add('password', 'required');
|
||||
}
|
||||
if ($password2 === '') {
|
||||
$validationErrors['password2'] = ['required'];
|
||||
$validationErrors->add('password2', 'required');
|
||||
}
|
||||
if ($validationErrors) {
|
||||
ApiResponse::validationError($validationErrors);
|
||||
if ($validationErrors->hasAny()) {
|
||||
ApiResponse::validationFromFormErrors($validationErrors);
|
||||
}
|
||||
|
||||
$userServicesFactory = new UserServicesFactory();
|
||||
$userServicesFactory = app(UserServicesFactory::class);
|
||||
$userAccountService = $userServicesFactory->createUserAccountService();
|
||||
$userPasswordService = $userServicesFactory->createUserPasswordService();
|
||||
|
||||
@@ -43,14 +42,14 @@ if (!$user) {
|
||||
}
|
||||
|
||||
if (!password_verify($currentPassword, (string) ($user['password'] ?? ''))) {
|
||||
ApiResponse::validationError(['current_password' => ['invalid']]);
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom(['current_password' => ['invalid']]));
|
||||
}
|
||||
|
||||
$result = $userPasswordService->resetPassword($userId, $password, $password2);
|
||||
if (!($result['ok'] ?? false)) {
|
||||
$errors = $result['errors'] ?? [];
|
||||
if ($errors) {
|
||||
ApiResponse::validationError(['password' => $errors]);
|
||||
ApiResponse::validationFromFormErrors(formErrors()->addMany('password', $errors));
|
||||
}
|
||||
ApiResponse::error('password_change_failed', 422);
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Repository\Auth\ApiTokenRepository;
|
||||
use MintyPHP\Repository\Tenant\TenantRepository;
|
||||
use MintyPHP\Service\Auth\ApiTokenEndpointService;
|
||||
use MintyPHP\Service\Auth\AuthServicesFactory;
|
||||
|
||||
ApiBootstrap::init();
|
||||
$apiTokenService = (new AuthServicesFactory())->createApiTokenService();
|
||||
$apiTokenRepository = new ApiTokenRepository();
|
||||
$apiTokenService = (app(AuthServicesFactory::class))->createApiTokenService();
|
||||
$apiTokenEndpointService = app(ApiTokenEndpointService::class);
|
||||
$request = requestInput();
|
||||
|
||||
$userId = ApiAuth::userId();
|
||||
if ($userId <= 0) {
|
||||
@@ -18,60 +18,12 @@ if ($userId <= 0) {
|
||||
|
||||
ApiAuth::requireSelfManageTokens();
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$method = $request->method();
|
||||
|
||||
if ($method === 'GET') {
|
||||
$limit = (int) ($_GET['limit'] ?? 50);
|
||||
if ($limit < 1) {
|
||||
$limit = 1;
|
||||
} elseif ($limit > 100) {
|
||||
$limit = 100;
|
||||
}
|
||||
|
||||
$limit = $apiTokenEndpointService->normalizeLimit($request->queryInt('limit', 50));
|
||||
$scopedTenantId = ApiAuth::scopedTenantId();
|
||||
$tokens = $apiTokenRepository->listByUserId($userId, $limit);
|
||||
$tenantIds = [];
|
||||
foreach ($tokens as $token) {
|
||||
$tokenTenantId = isset($token['tenant_id']) ? (int) $token['tenant_id'] : 0;
|
||||
if ($tokenTenantId > 0) {
|
||||
$tenantIds[] = $tokenTenantId;
|
||||
}
|
||||
}
|
||||
$tenantIds = array_values(array_unique($tenantIds));
|
||||
$tenantUuidById = [];
|
||||
if ($tenantIds) {
|
||||
foreach ((new TenantRepository())->listByIds($tenantIds) as $tenant) {
|
||||
$tenantId = (int) ($tenant['id'] ?? 0);
|
||||
$tenantUuid = trim((string) ($tenant['uuid'] ?? ''));
|
||||
if ($tenantId > 0 && $tenantUuid !== '') {
|
||||
$tenantUuidById[$tenantId] = $tenantUuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$rows = [];
|
||||
foreach ($tokens as $token) {
|
||||
$tokenTenantId = isset($token['tenant_id']) ? (int) $token['tenant_id'] : null;
|
||||
if ($tokenTenantId !== null && $tokenTenantId <= 0) {
|
||||
$tokenTenantId = null;
|
||||
}
|
||||
if ($scopedTenantId !== null && $scopedTenantId > 0 && $tokenTenantId !== $scopedTenantId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rows[] = [
|
||||
'uuid' => (string) ($token['uuid'] ?? ''),
|
||||
'name' => (string) ($token['name'] ?? ''),
|
||||
'selector_prefix' => substr((string) ($token['selector'] ?? ''), 0, 8),
|
||||
'tenant_uuid' => $tokenTenantId !== null ? ($tenantUuidById[$tokenTenantId] ?? null) : null,
|
||||
'last_used_at' => $token['last_used_at'] ?? null,
|
||||
'last_ip' => (string) ($token['last_ip'] ?? ''),
|
||||
'expires_at' => $token['expires_at'] ?? null,
|
||||
'revoked_at' => $token['revoked_at'] ?? null,
|
||||
'created' => $token['created'] ?? null,
|
||||
'is_current_token' => (int) ($token['id'] ?? 0) === (int) (ApiAuth::tokenId() ?? 0),
|
||||
];
|
||||
}
|
||||
$rows = $apiTokenEndpointService->listSelfTokens($userId, $limit, $scopedTenantId, ApiAuth::tokenId());
|
||||
|
||||
ApiResponse::success([
|
||||
'data' => $rows,
|
||||
@@ -80,76 +32,47 @@ if ($method === 'GET') {
|
||||
}
|
||||
|
||||
if ($method === 'POST') {
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$input = $request->bodyAll();
|
||||
|
||||
$name = trim((string) ($input['name'] ?? ''));
|
||||
if ($name === '') {
|
||||
ApiResponse::validationError(['name' => [t('Token name is required')]]);
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom(['name' => [t('Token name is required')]]));
|
||||
}
|
||||
if (array_key_exists('tenant_id', $input)) {
|
||||
ApiResponse::validationError(['tenant_id' => ['use_tenant_uuid']]);
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom(['tenant_id' => ['use_tenant_uuid']]));
|
||||
}
|
||||
|
||||
$tenantId = null;
|
||||
$tenantUuid = null;
|
||||
$tenantUuidInput = trim((string) ($input['tenant_uuid'] ?? ''));
|
||||
if ($tenantUuidInput !== '') {
|
||||
$tenant = (new TenantRepository())->findByUuid($tenantUuidInput);
|
||||
if (!$tenant) {
|
||||
ApiResponse::validationError(['tenant_uuid' => ['invalid_tenant_uuid']]);
|
||||
$tenantResolution = $apiTokenEndpointService->resolveSelfCreateTenant(
|
||||
$userId,
|
||||
ApiAuth::scopedTenantId(),
|
||||
trim((string) ($input['tenant_uuid'] ?? ''))
|
||||
);
|
||||
if (!($tenantResolution['ok'] ?? false)) {
|
||||
$status = (int) ($tenantResolution['status'] ?? 422);
|
||||
$error = (string) ($tenantResolution['error'] ?? 'invalid_tenant_uuid');
|
||||
$field = trim((string) ($tenantResolution['field'] ?? ''));
|
||||
if ($status === 403) {
|
||||
ApiResponse::forbidden($error);
|
||||
}
|
||||
$tenantId = (int) ($tenant['id'] ?? 0);
|
||||
if ($tenantId <= 0) {
|
||||
ApiResponse::validationError(['tenant_uuid' => ['invalid_tenant_uuid']]);
|
||||
if ($field !== '') {
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom([$field => [$error]]));
|
||||
}
|
||||
$tenantUuid = (string) ($tenant['uuid'] ?? '');
|
||||
ApiResponse::error($error, $status);
|
||||
}
|
||||
$tenantId = array_key_exists('tenant_id', $tenantResolution) ? (int) ($tenantResolution['tenant_id'] ?? 0) : null;
|
||||
if ($tenantId !== null && $tenantId <= 0) {
|
||||
$tenantId = null;
|
||||
}
|
||||
$tenantUuid = (string) ($tenantResolution['tenant_uuid'] ?? '') ?: null;
|
||||
|
||||
$scopedTenantId = ApiAuth::scopedTenantId();
|
||||
if ($scopedTenantId !== null && $scopedTenantId > 0) {
|
||||
$scopedTenant = (new TenantRepository())->find($scopedTenantId);
|
||||
$scopedTenantUuid = trim((string) ($scopedTenant['uuid'] ?? ''));
|
||||
if ($scopedTenantUuid === '') {
|
||||
ApiResponse::forbidden('tenant_scoped_token_forbidden');
|
||||
}
|
||||
if ($tenantId !== null && $tenantId !== $scopedTenantId) {
|
||||
ApiResponse::forbidden('tenant_scoped_token_forbidden');
|
||||
}
|
||||
$tenantId = $scopedTenantId;
|
||||
$tenantUuid = $scopedTenantUuid;
|
||||
}
|
||||
|
||||
$expiresAt = null;
|
||||
$expiresInput = trim((string) ($input['expires_at'] ?? ''));
|
||||
if ($expiresInput !== '') {
|
||||
try {
|
||||
$expiresDate = new \DateTimeImmutable($expiresInput);
|
||||
$expiresDateUtc = $expiresDate->setTimezone(new \DateTimeZone('UTC'));
|
||||
$nowUtc = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
|
||||
if ($expiresDateUtc <= $nowUtc) {
|
||||
ApiResponse::validationError(['expires_at' => ['must_be_in_future']]);
|
||||
}
|
||||
$expiresAt = $expiresDateUtc->format('Y-m-d H:i:s');
|
||||
} catch (\Exception $e) {
|
||||
ApiResponse::validationError(['expires_at' => ['invalid_datetime']]);
|
||||
}
|
||||
$expiresParse = $apiTokenEndpointService->parseExpiresAt((string) ($input['expires_at'] ?? ''));
|
||||
if (!($expiresParse['ok'] ?? false)) {
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom(['expires_at' => [(string) ($expiresParse['error'] ?? 'invalid_datetime')]]));
|
||||
}
|
||||
$expiresAt = $expiresParse['expires_at'] ?? null;
|
||||
|
||||
$currentTokenRecord = ApiAuth::tokenRecord();
|
||||
$parentExpiresAt = trim((string) ($currentTokenRecord['expires_at'] ?? ''));
|
||||
if ($parentExpiresAt !== '') {
|
||||
try {
|
||||
$parentExpiry = new \DateTimeImmutable($parentExpiresAt, new \DateTimeZone('UTC'));
|
||||
$requestedExpiry = $expiresAt !== null
|
||||
? new \DateTimeImmutable($expiresAt, new \DateTimeZone('UTC'))
|
||||
: null;
|
||||
if ($requestedExpiry === null || $requestedExpiry > $parentExpiry) {
|
||||
$expiresAt = $parentExpiresAt;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Parent token has no parseable expiry — keep requested value.
|
||||
}
|
||||
}
|
||||
$expiresAt = $apiTokenEndpointService->capExpiryToParent($expiresAt, (string) ($currentTokenRecord['expires_at'] ?? ''));
|
||||
|
||||
$result = $apiTokenService->create($userId, $name, $tenantId, $expiresAt, $userId);
|
||||
if (!($result['ok'] ?? false)) {
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Repository\Tenant\TenantRepository;
|
||||
use MintyPHP\Service\Auth\AuthServicesFactory;
|
||||
|
||||
ApiBootstrap::init();
|
||||
ApiResponse::requireMethod('POST');
|
||||
$apiTokenService = (new AuthServicesFactory())->createApiTokenService();
|
||||
$apiTokenService = app(\MintyPHP\Service\Auth\ApiTokenService::class);
|
||||
$apiTokenEndpointService = app(\MintyPHP\Service\Auth\ApiTokenEndpointService::class);
|
||||
|
||||
$userId = ApiAuth::userId();
|
||||
if ($userId <= 0) {
|
||||
@@ -18,14 +17,7 @@ if ($userId <= 0) {
|
||||
ApiAuth::requireSelfManageTokens();
|
||||
|
||||
$scopedTenantId = ApiAuth::scopedTenantId();
|
||||
$scopedTenantUuid = null;
|
||||
if ($scopedTenantId !== null && $scopedTenantId > 0) {
|
||||
$tenant = (new TenantRepository())->find($scopedTenantId);
|
||||
$scopedTenantUuid = trim((string) ($tenant['uuid'] ?? ''));
|
||||
if ($scopedTenantUuid === '') {
|
||||
$scopedTenantUuid = null;
|
||||
}
|
||||
}
|
||||
$scopedTenantUuid = $apiTokenEndpointService->resolveTenantUuidById($scopedTenantId);
|
||||
$result = $apiTokenService->revokeAllForUser($userId, $scopedTenantId);
|
||||
|
||||
ApiResponse::success([
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Repository\Tenant\TenantRepository;
|
||||
use MintyPHP\Service\Auth\ApiTokenEndpointService;
|
||||
use MintyPHP\Service\Auth\AuthServicesFactory;
|
||||
|
||||
ApiBootstrap::init();
|
||||
ApiResponse::requireMethod('POST');
|
||||
$apiTokenService = (new AuthServicesFactory())->createApiTokenService();
|
||||
$apiTokenService = (app(AuthServicesFactory::class))->createApiTokenService();
|
||||
$apiTokenEndpointService = app(ApiTokenEndpointService::class);
|
||||
$request = requestInput();
|
||||
|
||||
$userId = ApiAuth::userId();
|
||||
if ($userId <= 0) {
|
||||
@@ -22,7 +24,7 @@ if ($currentTokenId <= 0) {
|
||||
ApiResponse::error('current_token_not_found', 404);
|
||||
}
|
||||
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$input = $request->bodyAll();
|
||||
$expiresInput = trim((string) ($input['expires_at'] ?? ''));
|
||||
$expiresAt = $expiresInput !== '' ? $expiresInput : null;
|
||||
|
||||
@@ -44,11 +46,7 @@ if (!($result['ok'] ?? false)) {
|
||||
$tenantUuid = null;
|
||||
$tenantId = isset($result['tenant_id']) ? (int) ($result['tenant_id']) : 0;
|
||||
if ($tenantId > 0) {
|
||||
$tenant = (new TenantRepository())->find($tenantId);
|
||||
$tenantUuid = trim((string) ($tenant['uuid'] ?? ''));
|
||||
if ($tenantUuid === '') {
|
||||
$tenantUuid = null;
|
||||
}
|
||||
$tenantUuid = $apiTokenEndpointService->resolveTenantUuidById($tenantId);
|
||||
}
|
||||
|
||||
ApiResponse::success([
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Repository\Auth\ApiTokenRepository;
|
||||
use MintyPHP\Repository\Tenant\TenantRepository;
|
||||
use MintyPHP\Service\Auth\ApiTokenEndpointService;
|
||||
|
||||
ApiBootstrap::init();
|
||||
$apiTokenRepository = new ApiTokenRepository();
|
||||
$apiTokenEndpointService = app(ApiTokenEndpointService::class);
|
||||
$request = requestInput();
|
||||
|
||||
$userId = ApiAuth::userId();
|
||||
if ($userId <= 0) {
|
||||
@@ -17,33 +17,12 @@ if ($userId <= 0) {
|
||||
ApiAuth::requireSelfManageTokens();
|
||||
|
||||
$tokenUuid = trim((string) ($id ?? ''));
|
||||
if (!$apiTokenRepository->isUuid($tokenUuid)) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
|
||||
$token = $apiTokenRepository->findByUuidForUser($tokenUuid, $userId);
|
||||
$token = $apiTokenEndpointService->findSelfToken($tokenUuid, $userId, ApiAuth::scopedTenantId(), ApiAuth::tokenId());
|
||||
if (!$token) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
|
||||
$scopedTenantId = ApiAuth::scopedTenantId();
|
||||
$tokenTenantId = isset($token['tenant_id']) ? (int) $token['tenant_id'] : null;
|
||||
if ($tokenTenantId !== null && $tokenTenantId <= 0) {
|
||||
$tokenTenantId = null;
|
||||
}
|
||||
if ($scopedTenantId !== null && $scopedTenantId > 0 && $tokenTenantId !== $scopedTenantId) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
$tenantUuid = null;
|
||||
if ($tokenTenantId !== null) {
|
||||
$tenant = (new TenantRepository())->find($tokenTenantId);
|
||||
$tenantUuid = trim((string) ($tenant['uuid'] ?? ''));
|
||||
if ($tenantUuid === '') {
|
||||
$tenantUuid = null;
|
||||
}
|
||||
}
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$method = $request->method();
|
||||
|
||||
if ($method === 'GET') {
|
||||
ApiResponse::success([
|
||||
@@ -51,7 +30,7 @@ if ($method === 'GET') {
|
||||
'uuid' => (string) ($token['uuid'] ?? ''),
|
||||
'name' => (string) ($token['name'] ?? ''),
|
||||
'selector_prefix' => substr((string) ($token['selector'] ?? ''), 0, 8),
|
||||
'tenant_uuid' => $tenantUuid,
|
||||
'tenant_uuid' => $token['tenant_uuid'] ?? null,
|
||||
'last_used_at' => $token['last_used_at'] ?? null,
|
||||
'last_ip' => (string) ($token['last_ip'] ?? ''),
|
||||
'expires_at' => $token['expires_at'] ?? null,
|
||||
@@ -63,7 +42,7 @@ if ($method === 'GET') {
|
||||
}
|
||||
|
||||
if ($method === 'DELETE') {
|
||||
$revoked = $apiTokenRepository->revokeByUuidForUser($tokenUuid, $userId);
|
||||
$revoked = $apiTokenEndpointService->revokeSelfToken($tokenUuid, $userId);
|
||||
if (!$revoked) {
|
||||
ApiResponse::error('revoke_failed', 422);
|
||||
}
|
||||
|
||||
@@ -3,25 +3,27 @@
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\AccessServicesFactory;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
|
||||
ApiBootstrap::init();
|
||||
ApiResponse::requireMethod('GET');
|
||||
ApiResponse::requirePermission(PermissionService::PERMISSIONS_VIEW);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_PERMISSIONS_VIEW);
|
||||
$request = requestInput();
|
||||
|
||||
$permissionService = (new AccessServicesFactory())->createPermissionService();
|
||||
$permissionService = (app(AccessServicesFactory::class))->createPermissionService();
|
||||
|
||||
$allowedOrders = ['key', 'description', 'active', 'created'];
|
||||
$order = in_array($_GET['order'] ?? '', $allowedOrders, true) ? $_GET['order'] : 'key';
|
||||
$dir = in_array(strtolower($_GET['dir'] ?? ''), ['asc', 'desc'], true) ? strtolower($_GET['dir']) : 'asc';
|
||||
$limit = max(1, min(100, (int) ($_GET['limit'] ?? 25)));
|
||||
$offset = max(0, (int) ($_GET['offset'] ?? 0));
|
||||
$orderParam = $request->queryString('order');
|
||||
$dirParam = strtolower($request->queryString('dir'));
|
||||
$order = in_array($orderParam, $allowedOrders, true) ? $orderParam : 'key';
|
||||
$dir = in_array($dirParam, ['asc', 'desc'], true) ? $dirParam : 'asc';
|
||||
$limit = max(1, min(100, $request->queryInt('limit', 25)));
|
||||
$offset = max(0, $request->queryInt('offset', 0));
|
||||
|
||||
$options = [
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'search' => trim((string) ($_GET['search'] ?? '')),
|
||||
'active' => $_GET['active'] ?? null,
|
||||
'search' => $request->queryString('search'),
|
||||
'active' => $request->query('active'),
|
||||
'order' => $order,
|
||||
'dir' => $dir,
|
||||
];
|
||||
@@ -29,7 +31,7 @@ $options = [
|
||||
$result = $permissionService->listPaged($options);
|
||||
|
||||
$rows = [];
|
||||
foreach (($result['data'] ?? []) as $row) {
|
||||
foreach (($result['rows'] ?? []) as $row) {
|
||||
$rows[] = [
|
||||
'key' => $row['key'] ?? '',
|
||||
'description' => $row['description'] ?? '',
|
||||
|
||||
@@ -3,21 +3,23 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
|
||||
ApiBootstrap::init();
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$request = requestInput();
|
||||
$method = $request->method();
|
||||
|
||||
if ($method === 'GET') {
|
||||
ApiResponse::requirePermission(PermissionService::ROLES_VIEW);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_ROLES_VIEW);
|
||||
|
||||
$result = directoryServicesFactory()->createRoleService()->listPaged([
|
||||
'limit' => (int) ($_GET['limit'] ?? 25),
|
||||
'offset' => (int) ($_GET['offset'] ?? 0),
|
||||
'search' => trim((string) ($_GET['search'] ?? '')),
|
||||
'order' => (string) ($_GET['order'] ?? 'description'),
|
||||
'dir' => (string) ($_GET['dir'] ?? 'asc'),
|
||||
$limit = $request->queryInt('limit', 25);
|
||||
$offset = $request->queryInt('offset', 0);
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createRoleService()->listPaged([
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'search' => $request->queryString('search'),
|
||||
'order' => $request->queryString('order', 'description'),
|
||||
'dir' => $request->queryString('dir', 'asc'),
|
||||
]);
|
||||
|
||||
$rows = [];
|
||||
@@ -34,16 +36,16 @@ if ($method === 'GET') {
|
||||
ApiResponse::success([
|
||||
'data' => $rows,
|
||||
'total' => $result['total'] ?? 0,
|
||||
'limit' => (int) ($_GET['limit'] ?? 25),
|
||||
'offset' => (int) ($_GET['offset'] ?? 0),
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($method === 'POST') {
|
||||
ApiResponse::requirePermission(PermissionService::ROLES_CREATE);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_ROLES_CREATE);
|
||||
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$result = directoryServicesFactory()->createRoleService()->createFromAdmin($input, ApiAuth::userId());
|
||||
$input = $request->bodyAll();
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createRoleService()->createFromAdmin($input, ApiAuth::userId());
|
||||
ApiResponse::fromServiceResult($result, 201);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,31 +3,29 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\AccessServicesFactory;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
use MintyPHP\Repository\Access\RolePermissionRepository;
|
||||
|
||||
ApiBootstrap::init();
|
||||
$request = requestInput();
|
||||
|
||||
$uuid = trim((string) ($id ?? ''));
|
||||
if ($uuid === '') {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$method = $request->method();
|
||||
|
||||
if ($method === 'GET') {
|
||||
ApiResponse::requirePermission(PermissionService::ROLES_VIEW);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_ROLES_VIEW);
|
||||
|
||||
$role = directoryServicesFactory()->createRoleService()->findByUuid($uuid);
|
||||
$role = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createRoleService()->findByUuid($uuid);
|
||||
if (!$role) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
$roleId = (int) ($role['id'] ?? 0);
|
||||
$permissionKeys = [];
|
||||
if ($roleId > 0) {
|
||||
$permissionKeys = (new AccessServicesFactory())
|
||||
->createRolePermissionRepository()
|
||||
->listPermissionKeysByRoleIds([$roleId]);
|
||||
$permissionKeys = app(RolePermissionRepository::class)->listPermissionKeysByRoleIds([$roleId]);
|
||||
sort($permissionKeys);
|
||||
}
|
||||
|
||||
@@ -45,23 +43,23 @@ if ($method === 'GET') {
|
||||
}
|
||||
|
||||
if ($method === 'PUT' || $method === 'PATCH') {
|
||||
ApiResponse::requirePermission(PermissionService::ROLES_UPDATE);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_ROLES_UPDATE);
|
||||
|
||||
$role = directoryServicesFactory()->createRoleService()->findByUuid($uuid);
|
||||
$role = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createRoleService()->findByUuid($uuid);
|
||||
if (!$role) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
|
||||
$roleId = (int) ($role['id'] ?? 0);
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$result = directoryServicesFactory()->createRoleService()->updateFromAdmin($roleId, $input, ApiAuth::userId());
|
||||
$input = $request->bodyAll();
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createRoleService()->updateFromAdmin($roleId, $input, ApiAuth::userId());
|
||||
ApiResponse::fromServiceResult($result);
|
||||
}
|
||||
|
||||
if ($method === 'DELETE') {
|
||||
ApiResponse::requirePermission(PermissionService::ROLES_DELETE);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_ROLES_DELETE);
|
||||
|
||||
$result = directoryServicesFactory()->createRoleService()->deleteByUuid($uuid);
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createRoleService()->deleteByUuid($uuid);
|
||||
ApiResponse::fromServiceResult($result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
use MintyPHP\Service\Audit\SystemAuditService;
|
||||
use MintyPHP\Service\Settings\SettingServicesFactory;
|
||||
|
||||
ApiBootstrap::init();
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$settingService = (new SettingServicesFactory())->createSettingService();
|
||||
$request = requestInput();
|
||||
$method = $request->method();
|
||||
$settingService = (app(SettingServicesFactory::class))->createSettingService();
|
||||
|
||||
if ($method === 'GET') {
|
||||
ApiResponse::requirePermission(PermissionService::SETTINGS_VIEW);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_SETTINGS_VIEW);
|
||||
|
||||
ApiResponse::success([
|
||||
'data' => buildSettingsResponse($settingService),
|
||||
@@ -19,10 +21,11 @@ if ($method === 'GET') {
|
||||
}
|
||||
|
||||
if ($method === 'PUT' || $method === 'PATCH') {
|
||||
ApiResponse::requirePermission(PermissionService::SETTINGS_UPDATE);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_SETTINGS_UPDATE);
|
||||
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$errors = [];
|
||||
$input = $request->bodyAll();
|
||||
$errors = formErrors();
|
||||
$beforeSettings = buildSettingsResponse($settingService);
|
||||
|
||||
$setters = [
|
||||
'app_title' => static fn(?string $v) => $settingService->setAppTitle($v),
|
||||
@@ -39,6 +42,8 @@ if ($method === 'PUT' || $method === 'PATCH') {
|
||||
'default_department_id' => static fn($v) => $settingService->setDefaultDepartmentId($v !== null ? (int) $v : null),
|
||||
'user_inactivity_deactivate_days' => static fn($v) => $settingService->setUserInactivityDeactivateDays($v !== null ? (int) $v : null),
|
||||
'user_inactivity_delete_days' => static fn($v) => $settingService->setUserInactivityDeleteDays($v !== null ? (int) $v : null),
|
||||
'system_audit_enabled' => static fn($v) => $settingService->setSystemAuditEnabled((bool) $v),
|
||||
'system_audit_retention_days' => static fn($v) => $settingService->setSystemAuditRetentionDays($v !== null ? (int) $v : null),
|
||||
'microsoft_shared_client_id' => static fn(?string $v) => $settingService->setMicrosoftSharedClientId($v),
|
||||
'microsoft_authority' => static fn(?string $v) => $settingService->setMicrosoftAuthority($v),
|
||||
'smtp_host' => static fn(?string $v) => $settingService->setSmtpHost($v),
|
||||
@@ -56,16 +61,28 @@ if ($method === 'PUT' || $method === 'PATCH') {
|
||||
}
|
||||
$ok = $setters[$key]($value);
|
||||
if (!$ok) {
|
||||
$errors[$key] = ['invalid_value'];
|
||||
$errors->add($key, 'invalid_value');
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
ApiResponse::validationError($errors);
|
||||
if ($errors->hasAny()) {
|
||||
app(SystemAuditService::class)->record('admin.settings.update', 'failed', [
|
||||
'actor_user_id' => ApiAuth::userId(),
|
||||
'error_code' => 'validation_error',
|
||||
'metadata' => ['errors' => array_keys($errors->toArray())],
|
||||
]);
|
||||
ApiResponse::validationFromFormErrors($errors);
|
||||
}
|
||||
|
||||
$afterSettings = buildSettingsResponse($settingService);
|
||||
app(SystemAuditService::class)->record('admin.settings.update', 'success', [
|
||||
'actor_user_id' => ApiAuth::userId(),
|
||||
'before' => $beforeSettings,
|
||||
'after' => $afterSettings,
|
||||
]);
|
||||
|
||||
ApiResponse::success([
|
||||
'data' => buildSettingsResponse($settingService),
|
||||
'data' => $afterSettings,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -92,6 +109,8 @@ function buildSettingsResponse(\MintyPHP\Service\Settings\SettingService $s): ar
|
||||
'default_department_id' => $s->getDefaultDepartmentId(),
|
||||
'user_inactivity_deactivate_days' => $s->getUserInactivityDeactivateDays(),
|
||||
'user_inactivity_delete_days' => $s->getUserInactivityDeleteDays(),
|
||||
'system_audit_enabled' => $s->isSystemAuditEnabled(),
|
||||
'system_audit_retention_days' => $s->getSystemAuditRetentionDays(),
|
||||
'microsoft_shared_client_id' => $s->getMicrosoftSharedClientId(),
|
||||
'microsoft_authority' => $s->getMicrosoftAuthority(),
|
||||
'smtp_host' => $s->getSmtpHost(),
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Settings\SettingServicesFactory;
|
||||
|
||||
ApiBootstrap::init(requireAuth: false);
|
||||
ApiResponse::requireMethod('GET');
|
||||
|
||||
$settingService = (new SettingServicesFactory())->createSettingService();
|
||||
$settingService = app(\MintyPHP\Service\Settings\SettingService::class);
|
||||
|
||||
header('Cache-Control: public, max-age=60');
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
use MintyPHP\Service\Tenant\TenantServicesFactory;
|
||||
|
||||
define('MINTY_ALLOW_OUTPUT', true);
|
||||
|
||||
ApiBootstrap::init();
|
||||
ApiResponse::requireMethod('GET');
|
||||
ApiResponse::requirePermission(PermissionService::TENANTS_VIEW);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_TENANTS_VIEW);
|
||||
$request = requestInput();
|
||||
|
||||
$uuid = trim((string) ($id ?? ''));
|
||||
if ($uuid === '') {
|
||||
@@ -20,7 +20,7 @@ if ($uuid === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$tenantAvatarService = (new TenantServicesFactory())->createTenantAvatarService();
|
||||
$tenantAvatarService = (app(TenantServicesFactory::class))->createTenantAvatarService();
|
||||
|
||||
if (!$tenantAvatarService->isValidUuid($uuid)) {
|
||||
http_response_code(404);
|
||||
@@ -29,7 +29,7 @@ if (!$tenantAvatarService->isValidUuid($uuid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tenant = directoryServicesFactory()->createTenantService()->findByUuid($uuid);
|
||||
$tenant = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->findByUuid($uuid);
|
||||
$tenantId = (int) ($tenant['id'] ?? 0);
|
||||
if ($tenantId <= 0) {
|
||||
http_response_code(404);
|
||||
@@ -40,7 +40,7 @@ if ($tenantId <= 0) {
|
||||
|
||||
ApiAuth::requireResourceAccess('tenants', $tenantId);
|
||||
|
||||
$size = isset($_GET['size']) ? (int) $_GET['size'] : null;
|
||||
$size = $request->hasQuery('size') ? $request->queryInt('size') : null;
|
||||
$path = $tenantAvatarService->findAvatarPath($uuid, $size);
|
||||
if (!$path || !is_file($path)) {
|
||||
http_response_code(404);
|
||||
|
||||
@@ -3,28 +3,30 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
|
||||
ApiBootstrap::init();
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$request = requestInput();
|
||||
$method = $request->method();
|
||||
|
||||
if ($method === 'GET') {
|
||||
ApiResponse::requirePermission(PermissionService::TENANTS_VIEW);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_TENANTS_VIEW);
|
||||
|
||||
$limit = $request->queryInt('limit', 25);
|
||||
$offset = $request->queryInt('offset', 0);
|
||||
$options = [
|
||||
'limit' => (int) ($_GET['limit'] ?? 25),
|
||||
'offset' => (int) ($_GET['offset'] ?? 0),
|
||||
'search' => trim((string) ($_GET['search'] ?? '')),
|
||||
'order' => (string) ($_GET['order'] ?? 'description'),
|
||||
'dir' => (string) ($_GET['dir'] ?? 'asc'),
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'search' => $request->queryString('search'),
|
||||
'order' => $request->queryString('order', 'description'),
|
||||
'dir' => $request->queryString('dir', 'asc'),
|
||||
'tenantUserId' => ApiAuth::userId(),
|
||||
];
|
||||
$scopedTenantId = ApiAuth::scopedTenantId();
|
||||
if ($scopedTenantId) {
|
||||
$options['tenantIds'] = [$scopedTenantId];
|
||||
}
|
||||
$result = directoryServicesFactory()->createTenantService()->listPaged($options);
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->listPaged($options);
|
||||
|
||||
$rows = [];
|
||||
foreach ($result['rows'] as $row) {
|
||||
@@ -41,19 +43,19 @@ if ($method === 'GET') {
|
||||
ApiResponse::success([
|
||||
'data' => $rows,
|
||||
'total' => $result['total'] ?? 0,
|
||||
'limit' => (int) ($_GET['limit'] ?? 25),
|
||||
'offset' => (int) ($_GET['offset'] ?? 0),
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($method === 'POST') {
|
||||
ApiResponse::requirePermission(PermissionService::TENANTS_CREATE);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_TENANTS_CREATE);
|
||||
if (ApiAuth::isTenantScopedToken()) {
|
||||
ApiResponse::forbidden('tenant_scoped_token_forbidden');
|
||||
}
|
||||
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$result = directoryServicesFactory()->createTenantService()->createFromAdmin($input, ApiAuth::userId());
|
||||
$input = $request->bodyAll();
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->createFromAdmin($input, ApiAuth::userId());
|
||||
ApiResponse::fromServiceResult($result, 201);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
|
||||
ApiBootstrap::init();
|
||||
$request = requestInput();
|
||||
|
||||
$uuid = trim((string) ($id ?? ''));
|
||||
if ($uuid === '') {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$method = $request->method();
|
||||
|
||||
if ($method === 'GET') {
|
||||
ApiResponse::requirePermission(PermissionService::TENANTS_VIEW);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_TENANTS_VIEW);
|
||||
|
||||
$tenant = directoryServicesFactory()->createTenantService()->findByUuid($uuid);
|
||||
$tenant = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->findByUuid($uuid);
|
||||
if (!$tenant) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
@@ -63,9 +63,9 @@ if ($method === 'GET') {
|
||||
}
|
||||
|
||||
if ($method === 'PUT' || $method === 'PATCH') {
|
||||
ApiResponse::requirePermission(PermissionService::TENANTS_UPDATE);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_TENANTS_UPDATE);
|
||||
|
||||
$tenant = directoryServicesFactory()->createTenantService()->findByUuid($uuid);
|
||||
$tenant = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->findByUuid($uuid);
|
||||
if (!$tenant) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
@@ -73,15 +73,15 @@ if ($method === 'PUT' || $method === 'PATCH') {
|
||||
$tenantId = (int) ($tenant['id'] ?? 0);
|
||||
ApiAuth::requireResourceAccess('tenants', $tenantId);
|
||||
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$result = directoryServicesFactory()->createTenantService()->updateFromAdmin($tenantId, $input, ApiAuth::userId());
|
||||
$input = $request->bodyAll();
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->updateFromAdmin($tenantId, $input, ApiAuth::userId());
|
||||
ApiResponse::fromServiceResult($result);
|
||||
}
|
||||
|
||||
if ($method === 'DELETE') {
|
||||
ApiResponse::requirePermission(PermissionService::TENANTS_DELETE);
|
||||
ApiResponse::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_TENANTS_DELETE);
|
||||
|
||||
$tenant = directoryServicesFactory()->createTenantService()->findByUuid($uuid);
|
||||
$tenant = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->findByUuid($uuid);
|
||||
if (!$tenant) {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
@@ -89,7 +89,7 @@ if ($method === 'DELETE') {
|
||||
$tenantId = (int) ($tenant['id'] ?? 0);
|
||||
ApiAuth::requireResourceAccess('tenants', $tenantId);
|
||||
|
||||
$result = directoryServicesFactory()->createTenantService()->deleteByUuid($uuid);
|
||||
$result = app(\MintyPHP\Service\Directory\DirectoryServicesFactory::class)->createTenantService()->deleteByUuid($uuid);
|
||||
ApiResponse::fromServiceResult($result);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\AccessServicesFactory;
|
||||
use MintyPHP\Service\Access\AuthorizationDecision;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Service\User\UserServicesFactory;
|
||||
use MintyPHP\Service\User\UserAccountService;
|
||||
use MintyPHP\Service\User\UserAvatarService;
|
||||
|
||||
define('MINTY_ALLOW_OUTPUT', true);
|
||||
|
||||
ApiBootstrap::init();
|
||||
ApiResponse::requireMethod('GET');
|
||||
$request = requestInput();
|
||||
|
||||
$uuid = trim((string) ($id ?? ''));
|
||||
if ($uuid === '') {
|
||||
@@ -21,14 +22,13 @@ if ($uuid === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$userServicesFactory = new UserServicesFactory();
|
||||
$userAccountService = $userServicesFactory->createUserAccountService();
|
||||
$userAvatarService = $userServicesFactory->createUserAvatarService();
|
||||
$userAccountService = app(UserAccountService::class);
|
||||
$userAvatarService = app(UserAvatarService::class);
|
||||
|
||||
$user = $userAccountService->findByUuid($uuid);
|
||||
$userId = (int) ($user['id'] ?? 0);
|
||||
|
||||
$authorizationService = (new AccessServicesFactory())->createAuthorizationService();
|
||||
$authorizationService = app(\MintyPHP\Service\Access\AuthorizationService::class);
|
||||
$decision = $authorizationService->authorize(UserAuthorizationPolicy::ABILITY_API_USERS_SHOW_GET, [
|
||||
'actor_user_id' => ApiAuth::userId(),
|
||||
'target_user_id' => $userId,
|
||||
@@ -50,7 +50,7 @@ if (!$user) {
|
||||
return;
|
||||
}
|
||||
|
||||
$size = isset($_GET['size']) ? (int) $_GET['size'] : null;
|
||||
$size = $request->hasQuery('size') ? $request->queryInt('size') : null;
|
||||
$path = $userAvatarService->findAvatarPath($uuid, $size);
|
||||
if (!$path || !is_file($path)) {
|
||||
http_response_code(404);
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\AccessServicesFactory;
|
||||
use MintyPHP\Service\Access\AuthorizationDecision;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Service\User\UserServicesFactory;
|
||||
use MintyPHP\Service\Tenant\TenantService;
|
||||
use MintyPHP\Service\User\UserAccountService;
|
||||
use MintyPHP\Service\User\UserApiWriteInputMapper;
|
||||
|
||||
ApiBootstrap::init();
|
||||
$authorizationService = (new AccessServicesFactory())->createAuthorizationService();
|
||||
$userServicesFactory = new UserServicesFactory();
|
||||
$userAccountService = $userServicesFactory->createUserAccountService();
|
||||
$request = requestInput();
|
||||
$authorizationService = app(\MintyPHP\Service\Access\AuthorizationService::class);
|
||||
$userAccountService = app(UserAccountService::class);
|
||||
$apiDeny = static function (AuthorizationDecision $decision): void {
|
||||
if ($decision->isAllowed()) {
|
||||
return;
|
||||
@@ -32,8 +33,7 @@ $apiDeny = static function (AuthorizationDecision $decision): void {
|
||||
|
||||
ApiResponse::error($error, $status > 0 ? $status : 403);
|
||||
};
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$method = $request->method();
|
||||
|
||||
if ($method === 'GET') {
|
||||
$decision = $authorizationService->authorize(UserAuthorizationPolicy::ABILITY_API_USERS_INDEX_GET, [
|
||||
@@ -41,19 +41,21 @@ if ($method === 'GET') {
|
||||
]);
|
||||
$apiDeny($decision);
|
||||
|
||||
$limit = max(1, min(100, (int) ($_GET['limit'] ?? 25)));
|
||||
$offset = max(0, (int) ($_GET['offset'] ?? 0));
|
||||
$limit = max(1, min(100, $request->queryInt('limit', 25)));
|
||||
$offset = max(0, $request->queryInt('offset', 0));
|
||||
$allowedOrders = ['id', 'uuid', 'first_name', 'last_name', 'display_name', 'email', 'created', 'modified', 'active', 'last_login_at'];
|
||||
$order = in_array($_GET['order'] ?? '', $allowedOrders, true) ? $_GET['order'] : 'last_name';
|
||||
$dir = in_array(strtolower($_GET['dir'] ?? ''), ['asc', 'desc'], true) ? strtolower($_GET['dir']) : 'asc';
|
||||
$activeParam = $_GET['active'] ?? null;
|
||||
$orderParam = $request->queryString('order');
|
||||
$order = in_array($orderParam, $allowedOrders, true) ? $orderParam : 'last_name';
|
||||
$dirParam = strtolower($request->queryString('dir'));
|
||||
$dir = in_array($dirParam, ['asc', 'desc'], true) ? $dirParam : 'asc';
|
||||
$activeParam = $request->query('active');
|
||||
if ($activeParam !== null) {
|
||||
$activeParam = in_array($activeParam, ['0', '1', 'true', 'false'], true) ? $activeParam : null;
|
||||
}
|
||||
$options = [
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'search' => trim((string) ($_GET['search'] ?? '')),
|
||||
'search' => $request->queryString('search'),
|
||||
'order' => $order,
|
||||
'dir' => $dir,
|
||||
'active' => $activeParam,
|
||||
@@ -61,7 +63,7 @@ if ($method === 'GET') {
|
||||
];
|
||||
$scopedTenantId = ApiAuth::scopedTenantId();
|
||||
if ($scopedTenantId) {
|
||||
$tenant = directoryServicesFactory()->createTenantService()->findById($scopedTenantId);
|
||||
$tenant = app(TenantService::class)->findById($scopedTenantId);
|
||||
$tenantUuid = trim((string) ($tenant['uuid'] ?? ''));
|
||||
if ($tenantUuid === '') {
|
||||
ApiResponse::notFound();
|
||||
@@ -98,11 +100,11 @@ if ($method === 'GET') {
|
||||
}
|
||||
|
||||
if ($method === 'POST') {
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$normalizeResult = normalizeUserWriteInputToInternalIds($input);
|
||||
$input = $request->bodyAll();
|
||||
$normalizeResult = app(UserApiWriteInputMapper::class)->normalize($input);
|
||||
if ($normalizeResult['ok'] !== true) {
|
||||
$errors = $normalizeResult['errors'] ?? [];
|
||||
ApiResponse::validationError($errors ?: ['input' => ['invalid_value']]);
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom($errors ?: ['input' => ['invalid_value']]));
|
||||
}
|
||||
$input = $normalizeResult['input'] ?? $input;
|
||||
|
||||
@@ -122,118 +124,3 @@ if ($method === 'POST') {
|
||||
}
|
||||
|
||||
ApiResponse::methodNotAllowed();
|
||||
|
||||
/**
|
||||
* Normalize public UUID-based assignment payload to internal IDs used by services.
|
||||
*
|
||||
* @param array<string, mixed> $input
|
||||
* @return array{ok: bool, input?: array<string, mixed>, errors?: array<string, array<int, string>>}
|
||||
*/
|
||||
function normalizeUserWriteInputToInternalIds(array $input): array
|
||||
{
|
||||
$errors = [];
|
||||
foreach ([
|
||||
'tenant_ids' => 'use_tenant_uuids',
|
||||
'primary_tenant_id' => 'use_primary_tenant_uuid',
|
||||
'role_ids' => 'use_role_uuids',
|
||||
'department_ids' => 'use_department_uuids',
|
||||
] as $legacyKey => $errorCode) {
|
||||
if (array_key_exists($legacyKey, $input)) {
|
||||
$errors[$legacyKey] = [$errorCode];
|
||||
}
|
||||
}
|
||||
if ($errors) {
|
||||
return ['ok' => false, 'errors' => $errors];
|
||||
}
|
||||
|
||||
$tenantService = directoryServicesFactory()->createTenantService();
|
||||
$roleService = directoryServicesFactory()->createRoleService();
|
||||
$departmentService = directoryServicesFactory()->createDepartmentService();
|
||||
|
||||
$normalizeUuidList = static function (mixed $raw): array {
|
||||
$values = is_array($raw) ? $raw : [$raw];
|
||||
$uuids = [];
|
||||
foreach ($values as $value) {
|
||||
$uuid = trim((string) $value);
|
||||
if ($uuid !== '') {
|
||||
$uuids[] = $uuid;
|
||||
}
|
||||
}
|
||||
return array_values(array_unique($uuids));
|
||||
};
|
||||
|
||||
if (array_key_exists('tenant_uuids', $input)) {
|
||||
$tenantUuids = $normalizeUuidList($input['tenant_uuids']);
|
||||
$tenantIds = [];
|
||||
foreach ($tenantUuids as $tenantUuid) {
|
||||
$tenant = $tenantService->findByUuid($tenantUuid);
|
||||
if (!$tenant) {
|
||||
$errors['tenant_uuids'][] = 'not_found';
|
||||
continue;
|
||||
}
|
||||
$tenantId = (int) ($tenant['id'] ?? 0);
|
||||
if ($tenantId > 0) {
|
||||
$tenantIds[] = $tenantId;
|
||||
}
|
||||
}
|
||||
$input['tenant_ids'] = array_values(array_unique($tenantIds));
|
||||
unset($input['tenant_uuids']);
|
||||
}
|
||||
|
||||
if (array_key_exists('primary_tenant_uuid', $input)) {
|
||||
$primaryTenantUuid = trim((string) ($input['primary_tenant_uuid'] ?? ''));
|
||||
if ($primaryTenantUuid === '') {
|
||||
$input['primary_tenant_id'] = 0;
|
||||
} else {
|
||||
$primaryTenant = $tenantService->findByUuid($primaryTenantUuid);
|
||||
if (!$primaryTenant) {
|
||||
$errors['primary_tenant_uuid'][] = 'not_found';
|
||||
} else {
|
||||
$input['primary_tenant_id'] = (int) ($primaryTenant['id'] ?? 0);
|
||||
}
|
||||
}
|
||||
unset($input['primary_tenant_uuid']);
|
||||
}
|
||||
|
||||
if (array_key_exists('role_uuids', $input)) {
|
||||
$roleUuids = $normalizeUuidList($input['role_uuids']);
|
||||
$roleIds = [];
|
||||
foreach ($roleUuids as $roleUuid) {
|
||||
$role = $roleService->findByUuid($roleUuid);
|
||||
if (!$role) {
|
||||
$errors['role_uuids'][] = 'not_found';
|
||||
continue;
|
||||
}
|
||||
$roleId = (int) ($role['id'] ?? 0);
|
||||
if ($roleId > 0) {
|
||||
$roleIds[] = $roleId;
|
||||
}
|
||||
}
|
||||
$input['role_ids'] = array_values(array_unique($roleIds));
|
||||
unset($input['role_uuids']);
|
||||
}
|
||||
|
||||
if (array_key_exists('department_uuids', $input)) {
|
||||
$departmentUuids = $normalizeUuidList($input['department_uuids']);
|
||||
$departmentIds = [];
|
||||
foreach ($departmentUuids as $departmentUuid) {
|
||||
$department = $departmentService->findByUuid($departmentUuid);
|
||||
if (!$department) {
|
||||
$errors['department_uuids'][] = 'not_found';
|
||||
continue;
|
||||
}
|
||||
$departmentId = (int) ($department['id'] ?? 0);
|
||||
if ($departmentId > 0) {
|
||||
$departmentIds[] = $departmentId;
|
||||
}
|
||||
}
|
||||
$input['department_ids'] = array_values(array_unique($departmentIds));
|
||||
unset($input['department_uuids']);
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
return ['ok' => false, 'errors' => $errors];
|
||||
}
|
||||
|
||||
return ['ok' => true, 'input' => $input];
|
||||
}
|
||||
|
||||
@@ -3,21 +3,20 @@
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\ApiBootstrap;
|
||||
use MintyPHP\Http\ApiResponse;
|
||||
use MintyPHP\Service\Access\AccessServicesFactory;
|
||||
use MintyPHP\Service\Access\AuthorizationDecision;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
|
||||
use MintyPHP\Service\User\UserServicesFactory;
|
||||
use MintyPHP\Service\User\UserAccountService;
|
||||
use MintyPHP\Service\User\UserApiWriteInputMapper;
|
||||
use MintyPHP\Service\User\UserAssignmentService;
|
||||
|
||||
ApiBootstrap::init();
|
||||
$accessServicesFactory = new AccessServicesFactory();
|
||||
$authorizationService = $accessServicesFactory->createAuthorizationService();
|
||||
$userServicesFactory = new UserServicesFactory();
|
||||
$userAccountService = $userServicesFactory->createUserAccountService();
|
||||
$userAssignmentService = $userServicesFactory->createUserAssignmentService();
|
||||
$userRoleRepository = $userServicesFactory->createUserRoleRepository();
|
||||
$rolePermissionRepository = $accessServicesFactory->createRolePermissionRepository();
|
||||
$request = requestInput();
|
||||
$authorizationService = app(\MintyPHP\Service\Access\AuthorizationService::class);
|
||||
$userAccountService = app(UserAccountService::class);
|
||||
$userAssignmentService = app(UserAssignmentService::class);
|
||||
$userRoleRepository = app(\MintyPHP\Repository\Access\UserRoleRepository::class);
|
||||
$rolePermissionRepository = app(\MintyPHP\Repository\Access\RolePermissionRepository::class);
|
||||
$apiDeny = static function (AuthorizationDecision $decision): void {
|
||||
if ($decision->isAllowed()) {
|
||||
return;
|
||||
@@ -44,7 +43,7 @@ if ($uuid === '') {
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||
$method = $request->method();
|
||||
|
||||
if ($method === 'GET') {
|
||||
$user = $userAccountService->findByUuid($uuid);
|
||||
@@ -65,13 +64,13 @@ if ($method === 'GET') {
|
||||
$primaryTenantId = (int) ($user['primary_tenant_id'] ?? 0);
|
||||
$primaryTenant = $userAssignmentService->findTenantSummaryInAssignments($assignments, $primaryTenantId);
|
||||
$publicAssignments = $userAssignmentService->mapAssignmentsToPublic($assignments);
|
||||
$publicCustomFields = UserCustomFieldValueService::buildPublicValuesByTenant(
|
||||
$publicCustomFields = app(UserCustomFieldValueService::class)->buildPublicValuesByTenant(
|
||||
$userId,
|
||||
$assignments['tenants'] ?? [],
|
||||
ApiAuth::scopedTenantId()
|
||||
);
|
||||
$publicPermissions = [];
|
||||
if (ApiAuth::hasPermission(PermissionService::PERMISSIONS_VIEW)) {
|
||||
if (ApiAuth::can(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_API_PERMISSIONS_VIEW)) {
|
||||
$roleIds = $userRoleRepository->listRoleIdsByUserId($userId);
|
||||
$publicPermissions = $rolePermissionRepository->listPermissionKeysByRoleIds($roleIds);
|
||||
}
|
||||
@@ -115,11 +114,11 @@ if ($method === 'PUT' || $method === 'PATCH') {
|
||||
$user = $userAccountService->findByUuid($uuid);
|
||||
$userId = (int) ($user['id'] ?? 0);
|
||||
|
||||
$input = ApiResponse::readJsonBody();
|
||||
$normalizeResult = normalizeUserWriteInputToInternalIds($input);
|
||||
$input = $request->bodyAll();
|
||||
$normalizeResult = app(UserApiWriteInputMapper::class)->normalize($input);
|
||||
if ($normalizeResult['ok'] !== true) {
|
||||
$errors = $normalizeResult['errors'] ?? [];
|
||||
ApiResponse::validationError($errors ?: ['input' => ['invalid_value']]);
|
||||
ApiResponse::validationFromFormErrors(formErrorsFrom($errors ?: ['input' => ['invalid_value']]));
|
||||
}
|
||||
$input = $normalizeResult['input'] ?? $input;
|
||||
|
||||
@@ -160,118 +159,3 @@ if ($method === 'DELETE') {
|
||||
}
|
||||
|
||||
ApiResponse::methodNotAllowed();
|
||||
|
||||
/**
|
||||
* Normalize public UUID-based assignment payload to internal IDs used by services.
|
||||
*
|
||||
* @param array<string, mixed> $input
|
||||
* @return array{ok: bool, input?: array<string, mixed>, errors?: array<string, array<int, string>>}
|
||||
*/
|
||||
function normalizeUserWriteInputToInternalIds(array $input): array
|
||||
{
|
||||
$errors = [];
|
||||
foreach ([
|
||||
'tenant_ids' => 'use_tenant_uuids',
|
||||
'primary_tenant_id' => 'use_primary_tenant_uuid',
|
||||
'role_ids' => 'use_role_uuids',
|
||||
'department_ids' => 'use_department_uuids',
|
||||
] as $legacyKey => $errorCode) {
|
||||
if (array_key_exists($legacyKey, $input)) {
|
||||
$errors[$legacyKey] = [$errorCode];
|
||||
}
|
||||
}
|
||||
if ($errors) {
|
||||
return ['ok' => false, 'errors' => $errors];
|
||||
}
|
||||
|
||||
$tenantService = directoryServicesFactory()->createTenantService();
|
||||
$roleService = directoryServicesFactory()->createRoleService();
|
||||
$departmentService = directoryServicesFactory()->createDepartmentService();
|
||||
|
||||
$normalizeUuidList = static function (mixed $raw): array {
|
||||
$values = is_array($raw) ? $raw : [$raw];
|
||||
$uuids = [];
|
||||
foreach ($values as $value) {
|
||||
$uuid = trim((string) $value);
|
||||
if ($uuid !== '') {
|
||||
$uuids[] = $uuid;
|
||||
}
|
||||
}
|
||||
return array_values(array_unique($uuids));
|
||||
};
|
||||
|
||||
if (array_key_exists('tenant_uuids', $input)) {
|
||||
$tenantUuids = $normalizeUuidList($input['tenant_uuids']);
|
||||
$tenantIds = [];
|
||||
foreach ($tenantUuids as $tenantUuid) {
|
||||
$tenant = $tenantService->findByUuid($tenantUuid);
|
||||
if (!$tenant) {
|
||||
$errors['tenant_uuids'][] = 'not_found';
|
||||
continue;
|
||||
}
|
||||
$tenantId = (int) ($tenant['id'] ?? 0);
|
||||
if ($tenantId > 0) {
|
||||
$tenantIds[] = $tenantId;
|
||||
}
|
||||
}
|
||||
$input['tenant_ids'] = array_values(array_unique($tenantIds));
|
||||
unset($input['tenant_uuids']);
|
||||
}
|
||||
|
||||
if (array_key_exists('primary_tenant_uuid', $input)) {
|
||||
$primaryTenantUuid = trim((string) ($input['primary_tenant_uuid'] ?? ''));
|
||||
if ($primaryTenantUuid === '') {
|
||||
$input['primary_tenant_id'] = 0;
|
||||
} else {
|
||||
$primaryTenant = $tenantService->findByUuid($primaryTenantUuid);
|
||||
if (!$primaryTenant) {
|
||||
$errors['primary_tenant_uuid'][] = 'not_found';
|
||||
} else {
|
||||
$input['primary_tenant_id'] = (int) ($primaryTenant['id'] ?? 0);
|
||||
}
|
||||
}
|
||||
unset($input['primary_tenant_uuid']);
|
||||
}
|
||||
|
||||
if (array_key_exists('role_uuids', $input)) {
|
||||
$roleUuids = $normalizeUuidList($input['role_uuids']);
|
||||
$roleIds = [];
|
||||
foreach ($roleUuids as $roleUuid) {
|
||||
$role = $roleService->findByUuid($roleUuid);
|
||||
if (!$role) {
|
||||
$errors['role_uuids'][] = 'not_found';
|
||||
continue;
|
||||
}
|
||||
$roleId = (int) ($role['id'] ?? 0);
|
||||
if ($roleId > 0) {
|
||||
$roleIds[] = $roleId;
|
||||
}
|
||||
}
|
||||
$input['role_ids'] = array_values(array_unique($roleIds));
|
||||
unset($input['role_uuids']);
|
||||
}
|
||||
|
||||
if (array_key_exists('department_uuids', $input)) {
|
||||
$departmentUuids = $normalizeUuidList($input['department_uuids']);
|
||||
$departmentIds = [];
|
||||
foreach ($departmentUuids as $departmentUuid) {
|
||||
$department = $departmentService->findByUuid($departmentUuid);
|
||||
if (!$department) {
|
||||
$errors['department_uuids'][] = 'not_found';
|
||||
continue;
|
||||
}
|
||||
$departmentId = (int) ($department['id'] ?? 0);
|
||||
if ($departmentId > 0) {
|
||||
$departmentIds[] = $departmentId;
|
||||
}
|
||||
}
|
||||
$input['department_ids'] = array_values(array_unique($departmentIds));
|
||||
unset($input['department_uuids']);
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
return ['ok' => false, 'errors' => $errors];
|
||||
}
|
||||
|
||||
return ['ok' => true, 'input' => $input];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user