From a799e46b944d6c869eb1456607f471747b9134e3 Mon Sep 17 00:00:00 2001 From: Thibault Dockx <thibault.dockx@fusiondirectory.org> Date: Mon, 24 Mar 2025 10:46:00 +0000 Subject: [PATCH 1/6] :sparkles: Feat(gateway) - simply add gateway to get methods --- .gitignore | 7 +++++++ library/TaskController.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a474600..84558c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,9 @@ .vendor/ .composer.lock +filelist +phpstan.neon +.idea/fusiondirectory-orchestrator.iml +.idea/modules.xml +.idea/php.xml +.idea/vcs.xml +.idea/codeStyles/codeStyleConfig.xml diff --git a/library/TaskController.php b/library/TaskController.php index 849f5b6..2b4ddf3 100644 --- a/library/TaskController.php +++ b/library/TaskController.php @@ -55,7 +55,7 @@ class TaskController switch ($objectType) { case $objectType: if (class_exists($objectType)) { - $endpoint = new $objectType; + $endpoint = new $objectType($this->gateway); $result = $endpoint->processEndPointGet(); } break; -- GitLab From 164739c09897f20c213173f91acc7e614f2fc81d Mon Sep 17 00:00:00 2001 From: Thibault Dockx <thibault.dockx@fusiondirectory.org> Date: Mon, 24 Mar 2025 15:21:23 +0000 Subject: [PATCH 2/6] :sparkles: feat(archive) - implement Archive endpoint with GET, PATCH, POST, and DELETE methods --- plugins/tasks/Archive.php | 98 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 plugins/tasks/Archive.php diff --git a/plugins/tasks/Archive.php b/plugins/tasks/Archive.php new file mode 100644 index 0000000..e7838f8 --- /dev/null +++ b/plugins/tasks/Archive.php @@ -0,0 +1,98 @@ +<?php + +class Archive implements EndpointInterface +{ + private TaskGateway $gateway; + + public function __construct(TaskGateway $gateway) + { + $this->gateway = $gateway; + } + + /** + * @return array + * Part of the interface of orchestrator plugin to treat GET method + */ + public function processEndPointGet(): array + { + // Retrieve tasks of type 'archive' + return $this->gateway->getObjectTypeTask('archive'); + } + + /** + * @param array|null $data + * @return array + * @throws Exception + * Note: Part of the interface of orchestrator plugin to treat PATCH method + */ + public function processEndPointPatch(array $data = NULL): array + { + $result = []; + $archiveTasks = $this->gateway->getObjectTypeTask('archive'); + + // Initialize the webservice object + // TODO + $webservice = new FusionDirectory\Rest\WebServiceCall($_ENV['FUSION_DIRECTORY_API_URL'] . '/archive', 'POST'); + $webservice->setCurlSettings(); + + foreach ($archiveTasks as $task) { + // Verify the task status and schedule + if ($this->gateway->statusAndScheduleCheck($task)) { + // Retrieve the user's supannAccountStatus + $userStatus = $this->getUserSupannAccountStatus($task['fdtasksgranulardn'][0]); + + // Check if the user meets the "toBeArchived" condition + // TODO + if ($userStatus === 'toBeArchived') { + // Trigger the archive method via the webservice + $archiveResult = $webservice->triggerArchive($task['fdtasksgranulardn'][0]); + + // Update the task status based on the result + if ($archiveResult === TRUE) { + $result[$task['dn']]['result'] = "User successfully archived."; + $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '2'); // Mark task as completed + } else { + $result[$task['dn']]['result'] = "Error archiving user."; + $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '3'); // Mark task as failed + } + } else { + $result[$task['dn']]['result'] = "User does not meet the criteria for archiving."; + } + } + } + + return $result; + } + + /** + * @param array|null $data + * @return array + * Note: Part of the interface of orchestrator plugin to treat POST method + */ + public function processEndPointPost(array $data = NULL): array + { + return []; + } + + /** + * @param array|null $data + * @return array + * Note: Part of the interface of orchestrator plugin to treat DELETE method + */ + public function processEndPointDelete(array $data = NULL): array + { + return []; + } + + /** + * Retrieve the supannAccountStatus of a user + * @param string $userDn + * @return string|null + */ + private function getUserSupannAccountStatus(string $userDn): ?string + { + // Logic to retrieve the supannAccountStatus attribute of the user + $user = $this->gateway->getLdapEntry($userDn, ['supannAccountStatus']); + return $user['supannAccountStatus'][0] ?? NULL; + } +} \ No newline at end of file -- GitLab From a94db1b91d2391c090bd46006bcf8f48196d4c69 Mon Sep 17 00:00:00 2001 From: Thibault Dockx <thibault.dockx@fusiondirectory.org> Date: Mon, 24 Mar 2025 16:44:58 +0000 Subject: [PATCH 3/6] :sparkles: feat(archive) - enhance Archive functionality with WebServiceCall integration and improved error handling --- .idea/.gitignore | 8 ++++++++ plugins/tasks/Archive.php | 30 ++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) create mode 100755 .idea/.gitignore diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100755 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/plugins/tasks/Archive.php b/plugins/tasks/Archive.php index e7838f8..77492f8 100644 --- a/plugins/tasks/Archive.php +++ b/plugins/tasks/Archive.php @@ -1,5 +1,7 @@ <?php +use FusionDirectory\Rest\WebServiceCall; + class Archive implements EndpointInterface { private TaskGateway $gateway; @@ -30,11 +32,6 @@ class Archive implements EndpointInterface $result = []; $archiveTasks = $this->gateway->getObjectTypeTask('archive'); - // Initialize the webservice object - // TODO - $webservice = new FusionDirectory\Rest\WebServiceCall($_ENV['FUSION_DIRECTORY_API_URL'] . '/archive', 'POST'); - $webservice->setCurlSettings(); - foreach ($archiveTasks as $task) { // Verify the task status and schedule if ($this->gateway->statusAndScheduleCheck($task)) { @@ -42,19 +39,32 @@ class Archive implements EndpointInterface $userStatus = $this->getUserSupannAccountStatus($task['fdtasksgranulardn'][0]); // Check if the user meets the "toBeArchived" condition - // TODO if ($userStatus === 'toBeArchived') { - // Trigger the archive method via the webservice - $archiveResult = $webservice->triggerArchive($task['fdtasksgranulardn'][0]); + // Construct the archive URL + $archiveUrl = $_ENV['FUSION_DIRECTORY_API_URL'] . '/archive/user/' . rawurlencode($task['fdtasksgranulardn'][0]); + + // Initialize the WebServiceCall object + $webServiceCall = new WebServiceCall($archiveUrl, 'POST'); + $webServiceCall->setCurlSettings(); - // Update the task status based on the result - if ($archiveResult === TRUE) { + // Execute the request + $response = curl_exec($webServiceCall->ch); + + // Handle any cURL errors + $webServiceCall->handleCurlError($webServiceCall->ch); + + // Decode and process the response + $responseData = json_decode($response, true); + if ($responseData && isset($responseData['success']) && $responseData['success'] === true) { $result[$task['dn']]['result'] = "User successfully archived."; $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '2'); // Mark task as completed } else { $result[$task['dn']]['result'] = "Error archiving user."; $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '3'); // Mark task as failed } + + // Close the cURL resource + curl_close($webServiceCall->ch); } else { $result[$task['dn']]['result'] = "User does not meet the criteria for archiving."; } -- GitLab From bb879dfcc98cdd94a26eba0959370cc60fd81c30 Mon Sep 17 00:00:00 2001 From: Thibault Dockx <thibault.dockx@fusiondirectory.org> Date: Tue, 25 Mar 2025 00:40:12 +0000 Subject: [PATCH 4/6] :sparkles: feat(archive) - refactor archiving logic to streamline user status checks and enhance error handling (still error from API) --- plugins/tasks/Archive.php | 107 ++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 38 deletions(-) diff --git a/plugins/tasks/Archive.php b/plugins/tasks/Archive.php index 77492f8..f2bd8fb 100644 --- a/plugins/tasks/Archive.php +++ b/plugins/tasks/Archive.php @@ -32,43 +32,45 @@ class Archive implements EndpointInterface $result = []; $archiveTasks = $this->gateway->getObjectTypeTask('archive'); - foreach ($archiveTasks as $task) { - // Verify the task status and schedule - if ($this->gateway->statusAndScheduleCheck($task)) { - // Retrieve the user's supannAccountStatus - $userStatus = $this->getUserSupannAccountStatus($task['fdtasksgranulardn'][0]); - - // Check if the user meets the "toBeArchived" condition - if ($userStatus === 'toBeArchived') { - // Construct the archive URL - $archiveUrl = $_ENV['FUSION_DIRECTORY_API_URL'] . '/archive/user/' . rawurlencode($task['fdtasksgranulardn'][0]); - - // Initialize the WebServiceCall object - $webServiceCall = new WebServiceCall($archiveUrl, 'POST'); - $webServiceCall->setCurlSettings(); - - // Execute the request - $response = curl_exec($webServiceCall->ch); - - // Handle any cURL errors - $webServiceCall->handleCurlError($webServiceCall->ch); - - // Decode and process the response - $responseData = json_decode($response, true); - if ($responseData && isset($responseData['success']) && $responseData['success'] === true) { - $result[$task['dn']]['result'] = "User successfully archived."; - $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '2'); // Mark task as completed - } else { - $result[$task['dn']]['result'] = "Error archiving user."; - $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '3'); // Mark task as failed - } + // Initialize the WebServiceCall object for login + $webServiceCall = new WebServiceCall($_ENV['FUSION_DIRECTORY_API_URL'] . '/login', 'POST'); + $webServiceCall->setCurlSettings(); // Perform login and set the token - // Close the cURL resource - curl_close($webServiceCall->ch); - } else { - $result[$task['dn']]['result'] = "User does not meet the criteria for archiving."; + foreach ($archiveTasks as $task) { + try { + if (!$this->gateway->statusAndScheduleCheck($task)) { + // Skip this task if it does not meet the status and schedule criteria + continue; + } + + // Receive null or 'toBeArchived' + $supannState = $this->getUserSupannAccountStatus($task['fdtasksgranulardn'][0]); + + if ($supannState !== 'toBeArchived') { + // The task does not meet the criteria for archiving and can therefore be suppressed + $result[$task['dn']]['result'] = "User does not meet the criteria for archiving."; + $this->gateway->removeSubTask($task['dn']); + continue; + } + + // Set the archive endpoint and method using the same WebServiceCall object + $archiveUrl = $_ENV['FUSION_DIRECTORY_API_URL'] . '/archive/user/' . rawurlencode($task['fdtasksgranulardn'][0]); + $webServiceCall->setCurlSettings($archiveUrl, [], 'POST'); // Update settings for the archive request + $response = $webServiceCall->execute(); + + print_r([$response]); + exit; + + if (isset($response['success']) && $response['success'] === true) { + $result[$task['dn']]['result'] = "User successfully archived."; + $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '2'); + } else { + throw new Exception("Invalid API response format"); + } + } catch (Exception $e) { + $result[$task['dn']]['result'] = "Error archiving user: " . $e->getMessage(); + $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], $e->getMessage()); } - } } return $result; @@ -101,8 +103,37 @@ class Archive implements EndpointInterface */ private function getUserSupannAccountStatus(string $userDn): ?string { - // Logic to retrieve the supannAccountStatus attribute of the user - $user = $this->gateway->getLdapEntry($userDn, ['supannAccountStatus']); - return $user['supannAccountStatus'][0] ?? NULL; + $supannState = $this->gateway->getLdapTasks( + '(objectClass=supannPerson)', + ['supannRessourceEtatDate'], + '', + $userDn + ); + + if ($this->hasToBeArchived($supannState)) { + return 'toBeArchived'; + } + + return null; + } + + private function hasToBeArchived(array $supannState): bool + { + if (!isset($supannState[0]['supannressourceetatdate']) || !is_array($supannState[0]['supannressourceetatdate'])) { + return false; + } + + foreach ($supannState[0]['supannressourceetatdate'] as $key => $value) { + // Skip non-numeric keys (e.g., 'count') + if (!is_numeric($key)) { + continue; + } + + if (strpos($value, '{COMPTE}I:toBeArchived') !== false) { + return true; + } + } + + return false; } } \ No newline at end of file -- GitLab From cb18ec2eeab93542fc8cb009f424b8227274734b Mon Sep 17 00:00:00 2001 From: Thibault Dockx <thibault.dockx@fusiondirectory.org> Date: Tue, 25 Mar 2025 11:57:08 +0000 Subject: [PATCH 5/6] :sparkles: feat(archive) - update archive request settings and improve error handling for unexpected HTTP status codes --- plugins/tasks/Archive.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/plugins/tasks/Archive.php b/plugins/tasks/Archive.php index f2bd8fb..593c99d 100644 --- a/plugins/tasks/Archive.php +++ b/plugins/tasks/Archive.php @@ -55,17 +55,15 @@ class Archive implements EndpointInterface // Set the archive endpoint and method using the same WebServiceCall object $archiveUrl = $_ENV['FUSION_DIRECTORY_API_URL'] . '/archive/user/' . rawurlencode($task['fdtasksgranulardn'][0]); - $webServiceCall->setCurlSettings($archiveUrl, [], 'POST'); // Update settings for the archive request + $webServiceCall->setCurlSettings($archiveUrl, NULL, 'POST'); // Update settings for the archive request $response = $webServiceCall->execute(); - print_r([$response]); - exit; - - if (isset($response['success']) && $response['success'] === true) { + // Check if the HTTP status code is 204 + if ($webServiceCall->getHttpStatusCode() === 204) { $result[$task['dn']]['result'] = "User successfully archived."; $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '2'); } else { - throw new Exception("Invalid API response format"); + throw new Exception("Unexpected HTTP status code: " . $webServiceCall->getHttpStatusCode()); } } catch (Exception $e) { $result[$task['dn']]['result'] = "Error archiving user: " . $e->getMessage(); -- GitLab From 2cc0b860e15f24de5febd00fd9f3887d8c9f9f42 Mon Sep 17 00:00:00 2001 From: Thibault Dockx <thibault.dockx@fusiondirectory.org> Date: Tue, 25 Mar 2025 15:17:33 +0000 Subject: [PATCH 6/6] :art: style(archive) - apply consistent spacing in method signatures and improve code readability --- plugins/tasks/Archive.php | 112 +++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/plugins/tasks/Archive.php b/plugins/tasks/Archive.php index 593c99d..2ef3e2f 100644 --- a/plugins/tasks/Archive.php +++ b/plugins/tasks/Archive.php @@ -6,7 +6,7 @@ class Archive implements EndpointInterface { private TaskGateway $gateway; - public function __construct(TaskGateway $gateway) + public function __construct (TaskGateway $gateway) { $this->gateway = $gateway; } @@ -15,7 +15,7 @@ class Archive implements EndpointInterface * @return array * Part of the interface of orchestrator plugin to treat GET method */ - public function processEndPointGet(): array + public function processEndPointGet (): array { // Retrieve tasks of type 'archive' return $this->gateway->getObjectTypeTask('archive'); @@ -27,7 +27,7 @@ class Archive implements EndpointInterface * @throws Exception * Note: Part of the interface of orchestrator plugin to treat PATCH method */ - public function processEndPointPatch(array $data = NULL): array + public function processEndPointPatch (array $data = NULL): array { $result = []; $archiveTasks = $this->gateway->getObjectTypeTask('archive'); @@ -37,38 +37,38 @@ class Archive implements EndpointInterface $webServiceCall->setCurlSettings(); // Perform login and set the token foreach ($archiveTasks as $task) { - try { - if (!$this->gateway->statusAndScheduleCheck($task)) { - // Skip this task if it does not meet the status and schedule criteria - continue; - } - - // Receive null or 'toBeArchived' - $supannState = $this->getUserSupannAccountStatus($task['fdtasksgranulardn'][0]); - - if ($supannState !== 'toBeArchived') { - // The task does not meet the criteria for archiving and can therefore be suppressed - $result[$task['dn']]['result'] = "User does not meet the criteria for archiving."; - $this->gateway->removeSubTask($task['dn']); - continue; - } - - // Set the archive endpoint and method using the same WebServiceCall object - $archiveUrl = $_ENV['FUSION_DIRECTORY_API_URL'] . '/archive/user/' . rawurlencode($task['fdtasksgranulardn'][0]); - $webServiceCall->setCurlSettings($archiveUrl, NULL, 'POST'); // Update settings for the archive request - $response = $webServiceCall->execute(); - - // Check if the HTTP status code is 204 - if ($webServiceCall->getHttpStatusCode() === 204) { - $result[$task['dn']]['result'] = "User successfully archived."; - $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '2'); - } else { - throw new Exception("Unexpected HTTP status code: " . $webServiceCall->getHttpStatusCode()); - } - } catch (Exception $e) { - $result[$task['dn']]['result'] = "Error archiving user: " . $e->getMessage(); - $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], $e->getMessage()); + try { + if (!$this->gateway->statusAndScheduleCheck($task)) { + // Skip this task if it does not meet the status and schedule criteria + continue; } + + // Receive null or 'toBeArchived' + $supannState = $this->getUserSupannAccountStatus($task['fdtasksgranulardn'][0]); + + if ($supannState !== 'toBeArchived') { + // The task does not meet the criteria for archiving and can therefore be suppressed + $result[$task['dn']]['result'] = "User does not meet the criteria for archiving."; + $this->gateway->removeSubTask($task['dn']); + continue; + } + + // Set the archive endpoint and method using the same WebServiceCall object + $archiveUrl = $_ENV['FUSION_DIRECTORY_API_URL'] . '/archive/user/' . rawurlencode($task['fdtasksgranulardn'][0]); + $webServiceCall->setCurlSettings($archiveUrl, NULL, 'POST'); // Update settings for the archive request + $response = $webServiceCall->execute(); + + // Check if the HTTP status code is 204 + if ($webServiceCall->getHttpStatusCode() === 204) { + $result[$task['dn']]['result'] = "User successfully archived."; + $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], '2'); + } else { + throw new Exception("Unexpected HTTP status code: " . $webServiceCall->getHttpStatusCode()); + } + } catch (Exception $e) { + $result[$task['dn']]['result'] = "Error archiving user: " . $e->getMessage(); + $this->gateway->updateTaskStatus($task['dn'], $task['cn'][0], $e->getMessage()); + } } return $result; @@ -79,7 +79,7 @@ class Archive implements EndpointInterface * @return array * Note: Part of the interface of orchestrator plugin to treat POST method */ - public function processEndPointPost(array $data = NULL): array + public function processEndPointPost (array $data = NULL): array { return []; } @@ -89,7 +89,7 @@ class Archive implements EndpointInterface * @return array * Note: Part of the interface of orchestrator plugin to treat DELETE method */ - public function processEndPointDelete(array $data = NULL): array + public function processEndPointDelete (array $data = NULL): array { return []; } @@ -99,7 +99,7 @@ class Archive implements EndpointInterface * @param string $userDn * @return string|null */ - private function getUserSupannAccountStatus(string $userDn): ?string + private function getUserSupannAccountStatus (string $userDn): ?string { $supannState = $this->gateway->getLdapTasks( '(objectClass=supannPerson)', @@ -107,31 +107,31 @@ class Archive implements EndpointInterface '', $userDn ); - - if ($this->hasToBeArchived($supannState)) { - return 'toBeArchived'; - } - - return null; + + if ($this->hasToBeArchived($supannState)) { + return 'toBeArchived'; + } + + return NULL; } - private function hasToBeArchived(array $supannState): bool + private function hasToBeArchived (array $supannState): bool { - if (!isset($supannState[0]['supannressourceetatdate']) || !is_array($supannState[0]['supannressourceetatdate'])) { - return false; - } + if (!isset($supannState[0]['supannressourceetatdate']) || !is_array($supannState[0]['supannressourceetatdate'])) { + return FALSE; + } - foreach ($supannState[0]['supannressourceetatdate'] as $key => $value) { - // Skip non-numeric keys (e.g., 'count') - if (!is_numeric($key)) { - continue; - } + foreach ($supannState[0]['supannressourceetatdate'] as $key => $value) { + // Skip non-numeric keys (e.g., 'count') + if (!is_numeric($key)) { + continue; + } - if (strpos($value, '{COMPTE}I:toBeArchived') !== false) { - return true; - } + if (strpos($value, '{COMPTE}I:toBeArchived') !== FALSE) { + return TRUE; } + } - return false; + return FALSE; } } \ No newline at end of file -- GitLab