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