diff --git a/library/TaskController.php b/library/TaskController.php index 64a932557c632683a79e292f046339111b04d957..849f5b65c2971b92097a9098e764bcca0987b2cb 100644 --- a/library/TaskController.php +++ b/library/TaskController.php @@ -61,7 +61,6 @@ class TaskController break; default: - // TODO: Default result in a non getProcess method found - could enhance below error report. $this->respondMethodAllowed("GET, PATCH, DELETE"); } $this->parseJsonResult($result); diff --git a/library/TaskGateway.php b/library/TaskGateway.php index ac801be786a0c63115a45b2db512223c3d79c0eb..823872e3dcb9a45aa3e9d995a0a9b8f3ccd4bce5 100644 --- a/library/TaskGateway.php +++ b/library/TaskGateway.php @@ -38,6 +38,11 @@ class TaskGateway $this->unsetCountKeys($list_tasks); break; + case "reminder": + $list_tasks = $this->getLdapTasks("(&(objectClass=fdTasksGranular)(fdtasksgranulartype=Reminder))"); + $this->unsetCountKeys($list_tasks); + break; + case "removeSubTasks": case "activateCyclicTasks": // No need to get any parent tasks here, but to note break logic - we will return an array. diff --git a/plugins/tasks/Mail.php b/plugins/tasks/Mail.php index fe760e453b8cc91e1f27ec4a71c30178487690d1..55ef06e9ebe11cc0c6cfff9dc5d6874989d4d9b3 100644 --- a/plugins/tasks/Mail.php +++ b/plugins/tasks/Mail.php @@ -56,7 +56,6 @@ class Mail implements EndpointInterface public function processMailTasks (array $tasks): array { $result = []; - // DEBUGGING $fdTasksConf = $this->getMailObjectConfiguration(); $maxMailsConfig = $this->returnMaximumMailToBeSend($fdTasksConf); diff --git a/plugins/tasks/Reminder.php b/plugins/tasks/Reminder.php new file mode 100644 index 0000000000000000000000000000000000000000..55fadf1fb4777b29d68e38c495c8f9d90d2f733d --- /dev/null +++ b/plugins/tasks/Reminder.php @@ -0,0 +1,764 @@ +<?php + +class Reminder 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 + { + return []; + } + + /** + * @param array|null $data + * @return array + */ + public function processEndPointPost (array $data = NULL): array + { + return []; + } + + /** + * @param array|NULL $data + * @return array + * @throws Exception + */ + public function processEndPointPatch (array $data = NULL): array + { + return $this->processReminder($this->gateway->getObjectTypeTask('reminder')); + } + + /** + * @param array|NULL $data + * @return array + */ + public function processEndPointDelete (array $data = NULL): array + { + return []; + } + + /** + * @param array $reminderSubTasks + * @return array + * @throws Exception + */ + public function processReminder (array $reminderSubTasks): array + { + $result = []; + // It will contain all required reminders to be potentially sent per main task. + $reminders = []; + + foreach ($reminderSubTasks as $task) { + // If the tasks must be treated - status and scheduled - process the sub-tasks + if ($this->gateway->statusAndScheduleCheck($task)) { + + // Retrieve data from the main task + $remindersMainTaskName = $task['fdtasksgranularmaster'][0]; //dn + $remindersMainTask = $this->getRemindersMainTask($remindersMainTaskName); + // remove the count keys + $this->gateway->unsetCountKeys($remindersMainTask); + + // Retrieve email attribute for the monitored members requiring reminding. + $mailOfTheReminded = $this->getEmailFromReminded($task['fdtasksgranulardn'][0]); + + // Generate the mail form with all mail controller requirements + $mailTemplateForm = $this->generateMainTaskMailTemplate($remindersMainTask, $mailOfTheReminded); + + // Get monitored resources + $monitoredResources = $this->getMonitoredResources($remindersMainTask[0]); + + // Case where no supann are monitored nor prolongation desired. (Useless subTask). + if ($monitoredResources['resource'][0] === 'NONE' && $monitoredResources['prolongation'] === 'FALSE') { + // Removal subtask + $result[$task['dn']]['Removed'] = $this->gateway->removeSubTask($task['dn']); + $result[$task['dn']]['Status'] = 'No reminder triggers were found, therefore removing the sub-task!'; + } + + // Case where supann is set monitored but no prolongation desired. + if ($monitoredResources['resource'][0] !== 'NONE' && $monitoredResources['prolongation'] === 'FALSE') { + if ($this->supannAboutToExpire($task['fdtasksgranulardn'][0], $monitoredResources, $task['fdtasksgranularhelper'][0])) { + + // Require to be set for updating the status of the task later on and sent the email. + $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['dn'] = $task['dn']; + $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['uid'] = $task['fdtasksgranulardn'][0]; + // Recipient email form + $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['mail'] = $mailTemplateForm; + + } else { + // Not about to expire, delete subTask + $result[$task['dn']]['Removed'] = $this->gateway->removeSubTask($task['dn']); + $result[$task['dn']]['Status'] = 'No reminder triggers were found, therefore removing the sub-task!'; + } + } + + // Case where supann is set and prolongation is desired. + if ($monitoredResources['resource'][0] !== 'NONE' && $monitoredResources['prolongation'] === 'TRUE') { + if ($this->supannAboutToExpire($task['fdtasksgranulardn'][0], $monitoredResources, $task['fdtasksgranularhelper'][0])) { + // Require to be set for updating the status of the task later on and sent the email. + $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['dn'] = $task['dn']; + $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['uid'] = $task['fdtasksgranulardn'][0]; + + // Create timeStamp expiration for token + $tokenExpire = $this->getTokenExpiration($task['fdtasksgranularhelper'][0], + $remindersMainTask[0]['fdtasksreminderfirstcall'][0], + $remindersMainTask[0]['fdtasksremindersecondcall'][0]); + // Create token for SubTask + $token = $this->generateToken($task['fdtasksgranulardn'][0], $tokenExpire); + // Edit the mailForm with the url link containing the token + $tokenMailTemplateForm = $this->generateTokenUrl($token, $mailTemplateForm, $remindersMainTaskName); + // Recipient email form + $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['mail'] = $tokenMailTemplateForm; + + + } else { + // Not about to expire, delete subTask + $result[$task['dn']]['Removed'] = $this->gateway->removeSubTask($task['dn']); + $result[$task['dn']]['Status'] = 'No reminder triggers were found, therefore removing the sub-task!'; + } + } + + // Case where prolongation is set without supann. + if ($monitoredResources['resource'][0] === 'NONE' && $monitoredResources['prolongation'] === 'TRUE') { + if ($this->posixAboutToExpire($task['fdtasksgranulardn'][0], $task['fdtasksgranularhelper'][0])) { + + // Require to be set for updating the status of the task later on and sent the email. + $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['dn'] = $task['dn']; + $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['uid'] = $task['fdtasksgranulardn'][0]; + + // Create timeStamp expiration for token + $tokenExpire = $this->getTokenExpiration($task['fdtasksgranularhelper'][0], + $remindersMainTask[0]['fdtasksreminderfirstcall'][0], + $remindersMainTask[0]['fdtasksremindersecondcall'][0]); + // Create token for SubTask + $token = $this->generateToken($task['fdtasksgranulardn'][0], $tokenExpire); + // Edit the mailForm with the url link containing the token + $tokenMailTemplateForm = $this->generateTokenUrl($token, $mailTemplateForm, $remindersMainTaskName); + // Recipient email form + $reminders[$remindersMainTaskName]['subTask'][$task['cn'][0]]['mail'] = $tokenMailTemplateForm; + + + } else { + // Not about to expire, delete subTask + $result[$task['dn']]['Removed'] = $this->gateway->removeSubTask($task['dn']); + $result[$task['dn']]['Status'] = 'No reminder triggers were found, therefore removing the sub-task!'; + } + } + } + } + + if (!empty($reminders)) { + $result[] = $this->sendRemindersMail($reminders); + } + + return $result; + } + + /** + * @param $dn + * @param $days + * @return bool + * Note : Compare the date of today and the shadowExpire epoch to see if expiration is soon to happen. + */ + private function posixAboutToExpire ($dn, $days) : bool + { + $result = FALSE; + + $userShadowExpire = $this->retrieveUserPosix($dn); + // Verification if shadowExpire was retrieved + if (!empty($userShadowExpire)) { + // Create the date of today + $today = new DateTime(); + // Create a proper timestamp for verification + $epoch = new DateTime("1970-01-01"); + // Add the shadowExpire days to the epoch + $epoch->add(new DateInterval("P{$userShadowExpire}D")); + + // Get the interval between today and the expiration of shadow expire. + $interval = $today->diff($epoch); + + // Interval can be negative if date is in the past - we make sure it is not in the past by using invert. + if ($interval->days <= $days && $interval->invert == 0) { + $result = TRUE; + } + } + + return $result; + } + + /** + * @param $dn + * @return string + * Note : Simply retrieve shadowExpire attribute for the DN specified. + */ + private function retrieveUserPosix ($dn) : string + { + $result = ''; + $userPosix = $this->gateway->getLdapTasks('(objectClass=shadowAccount)', ['shadowExpire'], + '', $dn); + + // Simply remove key "count" + $this->gateway->unsetCountKeys($userPosix); + + // Removing un-required keys + if (!empty($userPosix[0]['shadowexpire'][0])) { + $result = $userPosix[0]['shadowexpire'][0]; + } + + return $result; + } + + /** + * @param string $token + * @param array $mailTemplateForm + * @param string $taskDN + * @return array + */ + private function generateTokenUrl (string $token, array $mailTemplateForm, string $taskDN): array + { + //Only take the cn of the main task name : + preg_match('/cn=([^,]+),ou=/', $taskDN, $matches); + $taskName = $matches[1]; + + // Remove the API URI + $cleanedUrl = preg_replace('#/rest\.php/v1$#', '', $_ENV['FUSION_DIRECTORY_API_URL']); + $url = $cleanedUrl . '/accountProlongation.php?token=' . $token . '&task=' . $taskName; + + $mailTemplateForm['body'] .= $url; + + return $mailTemplateForm; + } + + /** + * @param int $subTaskCall + * @param int $firstCall + * @param int $secondCall + * @return int + * Note : Simply return the difference between first and second call. (First call can be null). + */ + private function getTokenExpiration (int $subTaskCall, int $firstCall, int $secondCall): int + { + // if firstCall is empty, secondCall is the timestamp expiry for the token. + $result = $secondCall; + + if (!empty($firstCall)) { + // Verification if the subTask is the second reminder or the first reminder. + if ($subTaskCall === $firstCall) { + $result = $firstCall - $secondCall; + } + } + + return $result; + } + + /** + * @param string $userDN + * @param int $timeStamp + * @return string + * @throws Exception + */ + private function generateToken (string $userDN, int $timeStamp): string + { + $token = NULL; + // Salt has been generated with APG. + $salt = '8onOlEsItKond'; + $payload = json_encode($userDN . $salt); + // This allows the token to be different every time. + $time = time(); + + // Create hmac with sha256 alg and the key provided for JWT token signature in ENV. + $token_hmac = hash_hmac("sha256", $time . $payload, $_ENV["SECRET_KEY"], TRUE); + + // We need to have a token allowed to be used within an URL. + $token = $this->base64urlEncode($token_hmac); + + // Save token within LDAP + $this->saveTokenInLdap($userDN, $token, $timeStamp); + + return $token; + } + + /** + * @param string $userDN + * @param string $token + * NOTE : UID is the full DN of the user. (uid=...). + * @param int $days + * @return bool + * @throws Exception + */ + private function saveTokenInLdap (string $userDN, string $token, int $days): bool + { + $result = FALSE; + + $currentTimestamp = time(); + // Calculate the future timestamp by adding days to the current timestamp (We actually adds number of seconds). + $futureTimestamp = $currentTimestamp + ($days * 24 * 60 * 60); + + preg_match('/uid=([^,]+),ou=/', $userDN, $matches); + $uid = $matches[1]; + $dn = 'cn=' . $uid . ',' . 'ou=tokens' . ',' . $_ENV["LDAP_BASE"]; + + $ldap_entry["objectClass"] = ['top', 'fdTokenEntry']; + $ldap_entry["fdTokenUserDN"] = $userDN; + $ldap_entry["fdTokenType"] = 'reminder'; + $ldap_entry["fdToken"] = $token; + $ldap_entry["fdTokenTimestamp"] = $futureTimestamp; + $ldap_entry["cn"] = $uid; + + // set the dn for the token, only take what's between "uid=" and ",ou=" + + + // Verify if token ou branch exists + if (!$this->tokenBranchExist('ou=tokens' . ',' . $_ENV["LDAP_BASE"])) { + // Create the branch + $this->createBranchToken(); + } + + // The user token DN creation + $userTokenDN = 'cn=' . $uid . ',ou=tokens' . ',' . $_ENV["LDAP_BASE"]; + // Verify if a token already exists for specified user and remove it to create new one correctly. + if ($this->tokenBranchExist($userTokenDN)) { + // Remove the user token + $this->removeUserToken($userTokenDN); + } + + // Add token to LDAP for specific UID + try { + $result = ldap_add($this->gateway->ds, $dn, $ldap_entry); // bool returned + } catch (Exception $e) { + echo json_encode(["Ldap Error - Token could not be saved!" => "$e"]); // string returned + exit; + } + + return $result; + } + + /** + * @param $userTokenDN + * @return void + * Note : Simply remove the token for specific user DN + */ + private function removeUserToken ($userTokenDN): void + { + // Add token to LDAP for specific UID + try { + $result = ldap_delete($this->gateway->ds, $userTokenDN); // bool returned + } catch (Exception $e) { + echo json_encode(["Ldap Error - User token could not be removed!" => "$e"]); // string returned + exit; + } + } + + /** + * Create ou=pluginManager LDAP branch + * @throws Exception + */ + protected function createBranchToken (): void + { + try { + ldap_add( + $this->gateway->ds, 'ou=tokens' . ',' . $_ENV["LDAP_BASE"], + [ + 'ou' => 'tokens', + 'objectClass' => 'organizationalUnit', + ] + ); + } catch (Exception $e) { + + echo json_encode(["Ldap Error - Impossible to create the token branch" => "$e"]); // string returned + exit; + } + } + + + /** + * @param string $dn + * @return bool + * Note : Simply inspect if the branch for token is existing. + */ + private function tokenBranchExist (string $dn): bool + { + $result = FALSE; + + try { + $search = ldap_search($this->gateway->ds, $dn, "(objectClass=*)"); + // Check if the search was successful + if ($search) { + // Get the number of entries found + $entries = ldap_get_entries($this->gateway->ds, $search); + + // If entries are found, set result to true + if ($entries["count"] > 0) { + $result = TRUE; + } + } + } catch (Exception $e) { + $result = FALSE; + } + + return $result; + } + + /** + * @param string $text + * @return string + * Note : This come from jwtToken, as it is completely private - it is cloned here for now. + */ + private function base64urlEncode (string $text): string + { + return str_replace(["+", "/", "="], ["A", "B", ""], base64_encode($text)); + } + + /** + * @param string $dn + * @return string + * Note : return the mail attribute from gosaMail objectclass. + */ + private function getEmailFromReminded (string $dn): string + { + // in case the DN do not have an email set. - Return string FALSE. + $result = "FALSE"; + $email = $this->gateway->getLdapTasks('(objectClass=gosaMailAccount)', ['mail'], + '', $dn); + // Simply remove key "count" + $this->gateway->unsetCountKeys($email); + + // Removing un-required keys (ldap return array with count and 0). + if (!empty($email[0]['mail'][0])) { + $result = $email[0]['mail'][0]; + } + + return $result; + } + + /** + * @param $task + * @return bool + * Note : Verify the account status of the DN with the requirements of main tasks. + */ + private function supannAboutToExpire (string $dn, array $monitoredResources, int $days): bool + { + $result = FALSE; + + // Search the DN for supannRessourceEtatDate (With DATE) + $supannResources = $this->retrieveSupannResources($dn); + // Get the matching resource (without date) + $matchedResource = $this->verifySupannState($monitoredResources, $supannResources); + + if ($matchedResource) { + // verify + $DnSupannDateObject = $this->retrieveDateFromSupannResourceState($supannResources['supannressourceetatdate'], $matchedResource); + //Verification if the time is lower or equal than the reminder time. + if ($DnSupannDateObject !== FALSE) { + $today = new DateTime(); + $interval = $today->diff($DnSupannDateObject); + + // Interval can be negative if date is in the past - we make sure it is not in the past by using invert. + if ($interval->days <= $days && $interval->invert == 0) { + $result = TRUE; + } + } + } + + return $result; + } + + /** + * @param $dn + * @return array + * Note : Simply return supann resource array from the specific passed DN. + */ + private function retrieveSupannResources ($dn): array + { + $supannResources = []; + $supannResources = $this->gateway->getLdapTasks('(objectClass=supannPerson)', ['supannRessourceEtatDate', 'supannRessourceEtat'], + '', $dn); + // Simply remove key "count" + $this->gateway->unsetCountKeys($supannResources); + + // Removing un-required keys + if (!empty($supannResources)) { + $supannResources = $supannResources[0]; + } + + return $supannResources; + + } + + + /** + * Get the monitored resources for reminder to be activated. + * @param array $remindersMainTask + * @return array + */ + private function getMonitoredResources (array $remindersMainTask): array + { + $monitoredResourcesArray = [ + 'resource' => $remindersMainTask['fdtasksreminderresource'], + 'state' => $remindersMainTask['fdtasksreminderstate'], + 'subState' => $remindersMainTask['fdtasksremindersubstate'] ?? NULL + ]; + + // Boolean returned by ldap is a string. + if (isset($remindersMainTask['fdtasksreminderaccountprolongation'][0]) && $remindersMainTask['fdtasksreminderaccountprolongation'][0] === 'TRUE') { + // Add the potential next resources states to the array + if (isset($remindersMainTask['fdtasksremindernextresource'])) { + + $monitoredResourcesArray['nextResource'] = $remindersMainTask['fdtasksremindernextresource']; + $monitoredResourcesArray['nextState'] = $remindersMainTask['fdtasksremindernextstate']; + $monitoredResourcesArray['nextSubState'] = $remindersMainTask['fdtasksremindernextsubstate'] ?? NULL; + } + // Posix attributes + $monitoredResourcesArray['fdTasksReminderPosix'] = $remindersMainTask['fdtasksreminderposix'] ?? FALSE; + + } + + // For development logic, add the prolongation attribute. It will be checked later in the logic process. + $monitoredResourcesArray['prolongation'] = $remindersMainTask['fdtasksreminderaccountprolongation'][0] ?? FALSE; + + return $monitoredResourcesArray; + } + + + /** + * @param array $reminderSupann + * @param array $dnSupann + * @return string + * Note : Create the supann format and check for a match. + */ + private function verifySupannState (array $reminderSupann, array $dnSupann): string + { + // Result will contain the supann resource matching. + $result = ''; + + //Construct the reminder Supann Resource State as string + if (!empty($reminderSupann['subState'][0])) { + $monitoredSupannState = '{' . $reminderSupann['resource'][0] . '}' . $reminderSupann['state'][0] . ':' . $reminderSupann['subState'][0]; + } else { + $monitoredSupannState = '{' . $reminderSupann['resource'][0] . '}' . $reminderSupann['state'][0]; + } + + if (!empty($dnSupann['supannressourceetat'])) { + // Simply iterate within the resource available till a match is found. + foreach ($dnSupann['supannressourceetat'] as $resource) { + if ($monitoredSupannState === $resource) { + $result = $resource; + break; + } + } + } + + return $result; + } + + /** + * @param array $supannEtatDate + * @param string $resource + * @return DateTime|false + * Note : Simply transform string date of supann to a dateTime object. + * Can return bool (false) or dateTime object. + */ + private function retrieveDateFromSupannResourceState (array $supannEtatDate, string $resource) + { + $dateString = NULL; + $matchFound = NULL; // Variable to store the match if found + + // Create a regex pattern to match the exact resource at the beginning, followed by ":" or ":::". + $pattern = '/^' . preg_quote($resource, '/') . '(:|:::)?.*/'; + + foreach ($supannEtatDate as $resourceWithDate) { + if (preg_match($pattern, $resourceWithDate)) { + $matchFound = $resourceWithDate; + break; // Stop once a match is found + } + } + + // Simply take the last 8 digit + preg_match('/(\d{8})$/', $matchFound, $matches); + + if (!empty($matches)) { + $dateString = $matches[0]; + } + + return DateTime::createFromFormat('Ymd', $dateString); + } + + /** + * @param $array + * @return array + * Note : simply return all values of a multi-dimensional array. + */ + public function getArrayValuesRecursive ($array) + { + $values = []; + foreach ($array as $value) { + if (is_array($value)) { + // If value is an array, merge its values recursively + $values = array_merge($values, $this->getArrayValuesRecursive($value)); + } else { + // If value is not an array, add it to the result + $values[] = $value; + } + } + return $values; + } + + /** + * @param string $mainTaskDn + * @return array + */ + public function getRemindersMainTask (string $mainTaskDn): array + { + // Retrieve data from the main Reminder task + return $this->gateway->getLdapTasks( '(objectClass=fdTasksReminder)', ['fdTasksReminderListOfRecipientsMails', + 'fdTasksReminderResource', 'fdTasksReminderState', 'fdTasksReminderPosix', 'fdTasksReminderMailTemplate', + 'fdTasksReminderSupannNewEndDate', 'fdTasksReminderRecipientsMembers', 'fdTasksReminderEmailSender', + 'fdTasksReminderManager', 'fdTasksReminderAccountProlongation', 'fdTasksReminderMembers', 'fdTasksReminderNextResource', + 'fdTasksReminderNextState', 'fdTasksReminderNextSubState', 'fdTasksReminderSubState', 'fdTasksReminderFirstCall', 'fdTasksReminderSecondCall'], '', $mainTaskDn); + } + + /** + * @param array $mainTask + * @param string $remindedEmail + * @return array + * Note : Simply generate the email to be sent as reminder. + * Note 2 : The boolean is created to generate the token and is only sent to reminded. Not recipients. + */ + private function generateMainTaskMailTemplate (array $mainTask, string $remindedEmail): array + { + // Generate email configuration for each result of subtasks having the same main task. + $sender = $mainTask[0]['fdtasksreminderemailsender'][0]; + $mailTemplateName = $mainTask[0]['fdtasksremindermailtemplate'][0]; + + $mailInfos = $this->gateway->getLdapTasks("(|(objectClass=fdMailTemplate)(objectClass=fdMailAttachments))", [], $mailTemplateName); + $mailContent = $mailInfos[0]; + + // If no forward-to mail recipients is set, simply send the reminder to the monitored members. + if (!empty($mainTask[0]["fdtasksreminderlistofrecipientsmails"])) { + $recipients = array_merge($mainTask[0]["fdtasksreminderlistofrecipientsmails"], [$remindedEmail]); + $this->gateway->unsetCountKeys($recipients); + + // There is no reason to send an email twice to the same person. Render the array unique. + $recipients = array_unique($recipients); + } else { + $recipients = $remindedEmail; + } + + // Render the array unique. + + // Set the reminder array with all required variable for all sub-tasks of same main task origin. + $mailForm['setFrom'] = $sender; + $mailForm['recipients'] = $recipients; + $mailForm['body'] = $mailContent["fdmailtemplatebody"][0]; + $mailForm['signature'] = $mailContent["fdmailtemplatesignature"][0] ?? NULL; + $mailForm['subject'] = $mailContent["fdmailtemplatesubject"][0]; + $mailForm['receipt'] = $mailContent["fdmailtemplatereadreceipt"][0]; + + return $mailForm; + } + + /** + * @param array $reminders + * @return array + * Note : Collect information and send reminder email. + */ + protected function sendRemindersMail (array $reminders): array + { + $result = []; + // Re-use of the same mail processing template logic + $fdTasksConf = $this->gateway->getLdapTasks( + "(objectClass=fdTasksConf)", + ["fdTasksConfLastExecTime", "fdTasksConfIntervalEmails", "fdTasksConfMaxEmails"] + ); + $maxMailsConfig = $fdTasksConf[0]["fdtasksconfmaxemails"][0] ?? 50; + + /* + Increment var starts a zero and added values will be the number of recipients per main tasks, as one mail is + sent per main task. + */ + $maxMailsIncrement = 0; + + // Each reminders + foreach ($reminders as $reminder) { + // Each main task reminder + foreach ($reminder as $reminderItem) { + // Each subTask reminder + foreach ($reminderItem as $mailDetails) { + $numberOfRecipients = count($mailDetails['mail']['recipients']); + + $mail_controller = new \FusionDirectory\Mail\MailLib( + $mailDetails['mail']['setFrom'], + NULL, + $mailDetails['mail']['recipients'], + $mailDetails['mail']['body'], + $mailDetails['mail']['signature'], + $mailDetails['mail']['subject'], + $mailDetails['mail']['receipt'], + NULL + ); + + $mailSentResult = $mail_controller->sendMail(); + // Here we incremented as well the counter of spam to the backend. + $result[] = $this->processMailResponseAndUpdateTasks($mailSentResult, $reminder, $fdTasksConf); + + // Verification anti-spam max mails to be sent and quit loop if matched. + $maxMailsIncrement += $numberOfRecipients; + if ($maxMailsIncrement == $maxMailsConfig) { + break; + } + } + } + } + + return $result; + } + + /** + * @param array $serverResults + * @param array $subTask + * @param array $mailTaskBackend + * @return array + * Note : + */ + protected function processMailResponseAndUpdateTasks (array $serverResults, array $subTask, array $mailTaskBackend): array + { + $result = []; + if ($serverResults[0] == "SUCCESS") { + foreach ($subTask['subTask'] as $subTask => $details) { + + // CN of the main task + $cn = $subTask; + // DN of the main task + $dn = $details['dn']; + + // Update task status for the current $dn + $result[$dn]['statusUpdate'] = $this->gateway->updateTaskStatus($dn, $cn, "2"); + $result[$dn]['mailStatus'] = 'reminder was successfully sent'; + $result[$dn]['updateLastMailExec'] = $this->gateway->updateLastMailExecTime($mailTaskBackend[0]["dn"]); + } + } else { + foreach ($subTask['subTask'] as $subTask => $details) { + + // CN of the main task + $cn = $subTask; + // DN of the main task + $dn = $details['dn']; + + $result[$dn]['statusUpdate'] = $this->gateway->updateTaskStatus($dn, $cn, $serverResults[0]); + $result[$dn]['mailStatus'] = $serverResults; + } + } + + return $result; + } + +} \ No newline at end of file