* * @author Anna Larch * @author Richard Steinmetz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE * License as published by the Free Software Foundation; either * version 3 of the License, or any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU AFFERO GENERAL PUBLIC LICENSE for more details. * * You should have received a copy of the GNU Affero General Public * License along with this library. If not, see . * */ namespace OCA\Gestion\Service; use OCP\IConfig; use OCP\DB\Exception; use OCP\IUserSession; use OCP\Mail\IMailer; use Ramsey\Uuid\Uuid; use OCA\Gestion\Db\Bdd; use OC\Files\Filesystem; use OCP\Files\IRootFolder; use OCA\Gestion\Db\OrderBdd; use Psr\Log\LoggerInterface; use OCA\Mail\Contracts\IMailManager; use OCA\Mail\IMAP\IMAPClientFactory; use OCA\Mail\Service\AccountService; use OCA\Gestion\Constants\BddConstant; use OCA\Gestion\Helpers\FolderHelpers; use GuzzleHttp\Exception\GuzzleException; use OCA\Gestion\Helpers\VCalendarHelpers; use OCA\Gestion\Constants\OrderStatusConstant; use OCA\Gestion\Constants\ThanatoTypeConstant; use OCA\Gestion\Service\Order\OrderPdfService; use OCP\AppFramework\Db\DoesNotExistException; use OCA\Gestion\Constants\DevisMentionConstant; use OCA\Gestion\Service\Devis\Pdf\DevisPdfService; use OCA\Gestion\Constants\VCalendarPropertyConstant; class GestionService { /** @var Bdd */ private $gestionBdd; /** @var LoggerInterface */ private $logger; /** @var \OCA\Gestion\Db\OrderBdd */ private $orderBdd; private TalkService $talkService; private $orderPdfService; private $devisPdfService; private string $userConnectedUuid; private $userConnectedStorage; private $mailer; protected $config; private IMailManager $mailManager; private $accountService; private IMAPClientFactory $clientFactory; private ?string $currentUserId; public function __construct( ?string $UserId, Bdd $gestionBdd, OrderBdd $orderBdd, LoggerInterface $logger, OrderPdfService $orderPdfService, DevisPdfService $devisPdfService, TalkService $talkService, IUserSession $userSession, IRootFolder $rootFolder, IMailer $mailer, IConfig $config, IMailManager $mailManager, AccountService $accountService, IMAPClientFactory $clientFactory, ) { $this->currentUserId = $UserId; $this->orderBdd = $orderBdd; $this->logger = $logger; $this->gestionBdd = $gestionBdd; $this->orderPdfService = $orderPdfService; $this->devisPdfService = $devisPdfService; $this->talkService = $talkService; $this->userConnectedUuid = $userSession->getUser()?->getUID() ?? BddConstant::DEFAULT_ADMIN_APP_ID_NEXTCLOUD; $this->userConnectedStorage = $rootFolder->getUserFolder($this->userConnectedUuid); $this->mailer = $mailer; $this->config = $config; $this->mailManager = $mailManager; $this->accountService = $accountService; $this->clientFactory = $clientFactory; } private function GetCalendarSummaryFromVCalendarString(string $vCalendarString): string { $summaryValue = "Nom du défunt"; $value = VCalendarHelpers::GetValueFromKeyInVCalendarString("SUMMARY", $vCalendarString); if($value !== ""){ $summaryValue = trim($value); } return $summaryValue; } private function GetThanatoFromVCalendarString(string $vCalendarString){ $thanato = null; $thanatoNames = $this->GetAttendeesNameFromVCalendarString($vCalendarString); if(count($thanatoNames) > 0){ $thanatoName = $thanatoNames[0]; $thanatoFromDb = $this->gestionBdd->getThanatoByUserUuid($thanatoName); if($thanatoFromDb != null){ $thanato = $thanatoFromDb; } } else{ //get from calendar object $organizerName = $this->getPrincipalUsernameFromVCalendarString($vCalendarString); if($organizerName != null){ $thanatoFromDb = $this->gestionBdd->getThanatoByUserUuid($organizerName); if($thanatoFromDb != null){ $thanato = $thanatoFromDb; } } } return $thanato; } private function GetThanatoIdFromVCalendarString(string $vCalendarString) { $thanatoId = 0; $thanatoNames = $this->GetAttendeesNameFromVCalendarString($vCalendarString); if(count($thanatoNames) > 0){ $thanatoName = $thanatoNames[0]; $thanatoIdFromDb = $this->gestionBdd->getThanatoIdByUserUuid($thanatoName); if($thanatoIdFromDb != null){ $thanatoId = $thanatoIdFromDb; } } else{ //get from calendar object $organizerName = $this->getPrincipalUsernameFromVCalendarString($vCalendarString); if($organizerName != null){ $thanatoIdFromDb = $this->gestionBdd->getThanatoIdByUserUuid($organizerName); if($thanatoIdFromDb != null){ $thanatoId = $thanatoIdFromDb; } } } return $thanatoId; } private function getPrincipalUsernameFromVCalendarString(string $vCalendarString){ $calendarUuid = VCalendarHelpers::GetValueFromKeyInVCalendarString("UID", $vCalendarString); $principalUsername = $this->gestionBdd->getCalendarOrganizerNameByCalendarObjectUuid($calendarUuid); return $principalUsername; } private function GetAttendeesNameFromVCalendarString(string $vCalendarString): array { $names = []; preg_match_all('/CN=([^;]+)/', $vCalendarString, $matches); if (isset($matches[1])) { $names = $matches[1]; } return $names; } private function IsDevisAlreadyCreated($clientId,$locationId,$thanatoId,$defuntName,$calendarUuid="not-related"){ $defuntId = $this->gestionBdd->getLastDefuntIdByName($defuntName); $devisId = $this->gestionBdd->getLastDevisIdFromVCalendarProperty($thanatoId,$clientId,$locationId,$defuntId,$calendarUuid); return $devisId != null; } private function GetCalendarUuidFromVCalendarString(string $vCalendarString): string { $calendarUuid = VCalendarHelpers::GetValueFromKeyInVCalendarString("UID", $vCalendarString); if($calendarUuid == ""){ $calendarUuid = $this->gestionBdd::DEFAULT_CALENDAR_UUID_FOR_DEVIS; } return $calendarUuid; } private function GetCalendarDateFromVCalendarString(string $vCalendarString){ $calendarStartDate = VCalendarHelpers::GetDateStartOrDateEndFromVCalendarString('DTSTART',$vCalendarString); return $calendarStartDate; } private function GetIsPivateFromVCalendarString(string $vCalendarString): bool{ $isPrivateValue = VCalendarHelpers::GetValueFromKeyInVCalendarString(VCalendarPropertyConstant::PROPERTY_IS_PRIVATE, $vCalendarString); return $isPrivateValue === "1" ? true : false; } private function GetIsReturnToSiegeFromVCalendarString(string $vCalendarString): bool{ $isPrivateValue = VCalendarHelpers::GetValueFromKeyInVCalendarString(VCalendarPropertyConstant::RETURN_TO_SIEGE, $vCalendarString); return $isPrivateValue === "1" ? true : false; } private function GetDevisCommentFromVCalendarString(string $vCalendarString){ $commentValue = VCalendarHelpers::GetValueFromKeyInVCalendarString("COMMENT", $vCalendarString); if($commentValue == ""){ $commentValue = "Commentaire"; } return $commentValue; } public function HandleCreatedCalendarObject(string $vCalendarString ,$cookie){ try{ $isPrivate = $this->GetIsPivateFromVCalendarString($vCalendarString); $absenceType = VCalendarHelpers::GetValueFromKeyInVCalendarString('ABSENCETYPE',$vCalendarString); if($isPrivate || $absenceType){ //Nothing to do manage fo a private calendar return; } $orderContent = []; $attachmentsCalendar = []; $thanato = $this->GetThanatoFromVCalendarString($vCalendarString); if($thanato != null){ $thanatoId = $thanato["id"]; } else{ $thanatoId = 0; } $calendarSummary = $this->GetCalendarSummaryFromVCalendarString($vCalendarString); $clientId = $this->GetClientIdFromVCalendarString($vCalendarString); $locationId = $this->GetLocationIdFromVCalendarString($vCalendarString); $calendarUuid = $this->GetCalendarUuidFromVCalendarString($vCalendarString); $userName = $this->GetThanatoNameFromVCalendarString($vCalendarString); $devisAlreadyCreated = $this->IsDevisAlreadyCreated($clientId,$locationId,$thanatoId,$calendarSummary,$calendarUuid); if($devisAlreadyCreated){ return; } $defuntId = $this->gestionBdd->insertDefuntByNameAndReturnId($calendarSummary); $calendarStartDate = $this->GetCalendarDateFromVCalendarString($vCalendarString); $devisComment = $this->GetDevisCommentFromVCalendarString($vCalendarString); $devisDate = $calendarStartDate->format(format: 'Y-m-d'); $returnToSiege = $this->GetIsReturnToSiegeFromVCalendarString($vCalendarString); $devisId = $this->gestionBdd->insertDevisFromVCalendarAndReturnId($thanatoId,$clientId,$locationId,$defuntId,$devisComment,$calendarUuid,$devisDate,$userName ,$returnToSiege); $articlesValue = $this->GetArticlesNameFromVCalendarString($vCalendarString); if(!empty($articlesValue)){ $articleIds = $this->gestionBdd->getArticleIdsByArticleReferences($articlesValue); $this->gestionBdd->insertDevisArticleFromDevisIdAndArticlesIdArray($devisId, $articleIds); } $thanatoIsSubcontractor = $thanato["fk_thanato_type_key"] === ThanatoTypeConstant::THANATO_TYPE_SUBCONTRACTOR; if($thanatoIsSubcontractor){ $orderCreated = $this->orderBdd->createOrderFromDevisIdAndDate($devisId,$calendarStartDate,$userName); if($orderCreated){ $order = $this->orderBdd->getOrderByDevisId($devisId); $this->logger->debug(json_encode($order)); if($order != null){ $orderPdf = $this->orderPdfService->generateOrderPdfByOrderId($order['id'],$this->userConnectedUuid); if (!empty($orderPdf['content'])) { $orderContent[] = $orderPdf['content']; } } } } $devisTalkMessage = $this->gestionBdd->getDevisTalkRoomMessage($devisId,$userName); $this->talkService->sendDevisTalkNotifications($devisTalkMessage,$userName,$this->userConnectedUuid); $this->devisPdfService->generateDevisPdfByDevisId($devisId,$this->userConnectedUuid); $devis = $this->gestionBdd->getDevisByDevisId($devisId); //Move calendar attachment file to defunt folder $devisExist = $devis != null && $devis["client_entreprise"] != null; if (VCalendarHelpers::hasAttachment($vCalendarString)) { if($devisExist){ $destinationFolderAttachment = FolderHelpers::GetDefuntFolder($devis["client_entreprise"],$devis["defunt_nom"]); $attachmentsCalendar = VCalendarHelpers::extractAttachments($vCalendarString); $this->moveCalendarAttachmentFile($attachmentsCalendar,$destinationFolderAttachment); if (!$thanatoIsSubcontractor) { $roomToken = $this->talkService->getRoomTokenBeetwenTwoUser($this->userConnectedUuid, $userName); if($roomToken != null){ foreach ( $attachmentsCalendar as $attachment) { $this->userConnectedStorage->getFullPath("/"); $path = Filesystem::getPath($attachment['file_id']); $destination = 'Talk/'; Filesystem::copy($path, $destination . $attachment['name']); $this->sendFileAttachmentToTalk($roomToken,$cookie , $attachment['name']); } } } } } if ($thanatoIsSubcontractor && $devisExist) { $thanatoHasEmail = $thanato["thanato_email"] != null && $thanato["thanato_email"] != "" && $thanato["thanato_email"] != "-"; if($thanatoHasEmail){ $emailBody = $this->extractBodyOfEmailAttachment(VCalendarHelpers::getEmailIdInVCalendar($vCalendarString)); $this->sendEmailAndAttachment($thanato["thanato_email"] , $devis["defunt_nom"],$emailBody ,$attachmentsCalendar ,$orderContent); } } $this->gestionBdd->createDevisTrajetFromVCalendar($devisId,$userName); } catch(Exception $e){ $this->logger->debug("error creating devis"); } } public function moveCalendarAttachmentFile(array $attachments ,string $destinationFolder ){ $this->userConnectedStorage->getFullPath("/"); foreach ($attachments as $attachment) { $path = Filesystem::getPath($attachment['file_id']); Filesystem::copy($path, $destinationFolder . $attachment['name']); } } private function GetThanatoNameFromVCalendarString($vCalendarString){ $thanatoName = null; $thanatoNames = $this->GetAttendeesNameFromVCalendarString($vCalendarString); if(count($thanatoNames) > 0){ $thanatoName = $thanatoNames[0]; } else{ //get from calendar object $thanatoName = $this->getPrincipalUsernameFromVCalendarString($vCalendarString); } return $thanatoName; } private function GetClientIdFromVCalendarString(string $vCalendarString){ $this->logger->debug($vCalendarString); $clientValue = VCalendarHelpers::GetValueFromKeyInVCalendarString("CLIENT", $vCalendarString); if($clientValue == null || $clientValue == ""){ $clientValue = 0; } return (int)$clientValue; } private function GetLocationIdFromVCalendarString(string $vCalendarString){ $locationValue = VCalendarHelpers::GetValueFromKeyInVCalendarString("LOCATION", $vCalendarString); if($locationValue == null || $locationValue == ""){ $locationValue = 0; } return (int)$locationValue; } private function GetArticlesNameFromVCalendarString(string $vCalendarString): array { $devisArticleValue = VCalendarHelpers::GetValueFromKeyInVCalendarString("DESCRIPTION", $vCalendarString); $articles = explode('\;', $devisArticleValue); $mapped = array_map('trim', $articles); return $mapped; } public function HandleCalendarObjectMovedToTrash(string $vCalendarString){ $thanato = $this->GetThanatoFromVCalendarString($vCalendarString); if($thanato == null){ return; } $calendarUuid = $this->GetCalendarUuidFromVCalendarString($vCalendarString); $thanatoIsSubcontractor = $thanato["fk_thanato_type_key"] === ThanatoTypeConstant::THANATO_TYPE_SUBCONTRACTOR; if($thanatoIsSubcontractor){ $order = $this->orderBdd->getOrderByCalendarUuid($calendarUuid); if($order != null){ $this->orderBdd->updateOrderStatus($order['id'],OrderStatusConstant::CANCELED_KEY); } } else{ $devis = $this->gestionBdd->getDevisByCalendarUuid($calendarUuid); if($devis != null){ $this->gestionBdd->updateDevisMentionToCanceled($devis['id']); } } return true; } private function CheckIfDevisIsAlreadyUpdated($devis,$vCalendarString){ $requestedDefuntName = $this->GetCalendarSummaryFromVCalendarString($vCalendarString); $requestedClientId = $this->GetClientIdFromVCalendarString($vCalendarString); $requestLocationId = $this->GetLocationIdFromVCalendarString($vCalendarString); $requestedArticleReferences = $this->GetArticlesNameFromVCalendarString($vCalendarString); $requestedDevisComment = $this->GetDevisCommentFromVCalendarString($vCalendarString); $requestedArticleIds = $this->gestionBdd->getArticleIdsByArticleReferences($requestedArticleReferences); $requestedDevisDate = $this->GetCalendarDateFromVCalendarString($vCalendarString); $requestedDevisDate = $requestedDevisDate->format('Y-m-d'); $articleDevis = $this->gestionBdd->getProduitDevisByDevisId($devis['id']); $articleDevisIds = []; foreach($articleDevis as $currentArticleDevis){ $articleDevisIds[] = $currentArticleDevis['produit_id']; } sort($requestedArticleIds); sort($articleDevisIds); return $devis['defunt_nom'] == $requestedDefuntName && $devis['client_id'] == $requestedClientId && $devis['lieu_id'] == $requestLocationId && $devis['comment'] == $requestedDevisComment && $devis['date'] == $requestedDevisDate && $requestedArticleIds == $articleDevisIds; } private function UpdateDevisDataByVCalendarString($devis,$vCalendarString){ $requestedDefuntName = $this->GetCalendarSummaryFromVCalendarString($vCalendarString); $defuntId = $this->gestionBdd->createOrUpdateDefuntByNameAndReturnDefuntId($devis['defunt_id'],$devis['defunt_nom'],$requestedDefuntName); $this->gestionBdd->updateDevisDefunt($devis['id'],$defuntId,$devis['defunt_id']); $requestedClientId = $this->GetClientIdFromVCalendarString($vCalendarString); $this->gestionBdd->updateDevisClient($devis['id'],$requestedClientId,$devis['client_id']); $requestLocationId = $this->GetLocationIdFromVCalendarString($vCalendarString); $this->gestionBdd->updateDevisLieu($devis['id'],$requestLocationId,$devis['lieu_id']); $requestedDevisComment = $this->GetDevisCommentFromVCalendarString($vCalendarString); $this->gestionBdd->updateDevisComment($devis['id'],$requestedDevisComment,$devis['comment']); $requestedDevisDate = $this->GetCalendarDateFromVCalendarString($vCalendarString); $requestedDevisDate = $requestedDevisDate->format('Y-m-d'); $this->gestionBdd->updateDevisDate($devis['id'],$requestedDevisDate); $articlesValue = $this->GetArticlesNameFromVCalendarString($vCalendarString); if(!empty($articlesValue)){ $articleIds = $this->gestionBdd->getArticleIdsByArticleReferences($articlesValue); $this->gestionBdd->updateDevisArticles($devis['id'],$articleIds); } } public function HandleUpdatedCalendarObject(string $vCalendarString , $cookie){ try{ $isPrivate = $this->GetIsPivateFromVCalendarString($vCalendarString); $absenceType = VCalendarHelpers::GetValueFromKeyInVCalendarString('ABSENCETYPE',$vCalendarString); if($isPrivate || $absenceType){ //Nothing to do manage fo a private calendar return; } $calendarUuid = $this->GetCalendarUuidFromVCalendarString($vCalendarString); $devis = $this->gestionBdd->getDevisByCalendarUuid($calendarUuid); if($devis != null){ $isDevisAlreadyUpdated = $this->CheckIfDevisIsAlreadyUpdated($devis,$vCalendarString); if($isDevisAlreadyUpdated){ return true; } $devisIsAlreadyFactured = $devis['mentions'] == DevisMentionConstant::FACTURED || $devis['mentions'] == DevisMentionConstant::FACTURED_FORMATTED; $this->UpdateDevisDataByVCalendarString($devis,$vCalendarString); $userName = $this->GetThanatoNameFromVCalendarString($vCalendarString); if($devisIsAlreadyFactured == false){ $devisTalkMessage = $this->gestionBdd->getDevisTalkRoomMessage($devis['id'],$userName); $this->talkService->sendDevisTalkNotifications($devisTalkMessage,$userName,$this->userConnectedUuid); $this->devisPdfService->generateDevisPdfByDevisId($devis['id'],$this->userConnectedUuid); } if (VCalendarHelpers::hasAttachment($vCalendarString) || VCalendarHelpers::hasEmailIdInVCalendar($vCalendarString)) { $thanato = $this->gestionBdd->getThanatoByThanatoId($devis['id_thanato']); $thanatoIsSubcontractor = $thanato["fk_thanato_type_key"] === ThanatoTypeConstant::THANATO_TYPE_SUBCONTRACTOR; $devis = $this->gestionBdd->getDevisByDevisId($devis['id']); if($devis != null && $devis["client_entreprise"] != null){ $destinationFolderAttachment = FolderHelpers::GetDefuntFolder($devis["client_entreprise"],$devis["defunt_nom"]); $attachments = VCalendarHelpers::extractAttachments($vCalendarString); $this->moveCalendarAttachmentFile($attachments , $destinationFolderAttachment); if ($thanatoIsSubcontractor ) { $thanatoHasEmail = $thanato["thanato_email"] != null; if($thanatoHasEmail){ $emailBody = $this->extractBodyOfEmailAttachment(VCalendarHelpers::getEmailIdInVCalendar($vCalendarString)); $this->sendEmailAndAttachment($thanato["thanato_email"] , $devis["defunt_nom"],$emailBody,$attachments); } }else{ $roomToken = $this->talkService->getRoomTokenBeetwenTwoUser($this->userConnectedUuid, $userName); if($roomToken != null){ foreach ( $attachments as $attachment) { $this->userConnectedStorage->getFullPath("/"); $path = Filesystem::getPath($attachment['file_id']); $destination = 'Talk/'; Filesystem::copy($path, $destination . $attachment['name']); //sendFileAttachmentToTalk $this->sendFileAttachmentToTalk($roomToken,$cookie , $attachment['name']); } } } } } } else{ $this->HandleCreatedCalendarObject($vCalendarString,$cookie); } return true; } catch(Exception $e){ $this->logger->debug("error creating devis"); } } private function extractBodyOfEmailAttachment($emailId){ if ( $emailId == null || $emailId == '') { return []; } $messageId = (int) $emailId; try { $message = $this->mailManager->getMessage($this->currentUserId, $messageId); $mailbox = $this->mailManager->getMailbox($this->currentUserId, $message->getMailboxId()); $account = $this->accountService->find($this->currentUserId, $mailbox->getAccountId()); } catch (DoesNotExistException $e) { return []; } if ($account == null) { return []; } $client = $this->clientFactory->getClient($account); try { $imapMessage = $this->mailManager->getImapMessage( $client, $account, $mailbox, $message->getUid(), true ); $fullMessage = $imapMessage->getFullMessage($messageId); } finally { $client->logout(); } return [ "body" => $fullMessage["body"] ?? '', "subject" => $fullMessage["subject"] ?? '', 'from' => $fullMessage["from"] ? $fullMessage["from"]['label'] : '', ]; } public function sendEmailAndAttachment($to , $defunt_nom ,$emailBody = [] ,$attachmentsCalendar = [] ,$attachmentOrderContent = []){ $this->userConnectedStorage->getFullPath("/"); $subject = "Piece jointe"; $body = "

Bonjour.

Vous trouverez ci-dessous l'email et le(s) pièce(s) jointe(s) de « $defunt_nom ».

Vous en souhaitant bonne réception

" . ($emailBody['from'] ?? '') . "
" . ($emailBody['subject'] ?? '') . "
" . ($emailBody['body'] ?? '') . "
"; $message = $this->mailer->createMessage(); $message->setSubject($subject); $message->setTo(recipients: [$to]); foreach ($attachmentsCalendar as $attachment) { $path = Filesystem::getPath($attachment['file_id']) ; $content = $this->mailer->createAttachment( Filesystem::file_get_contents($path), ($attachment['name'] ?? null),($attachment['mime_type']) ?? null); $message->attach($content); } foreach ($attachmentOrderContent as $orderContent) { $content = $this->mailer->createAttachment( $orderContent ,"bdc.pdf", "application/pdf"); $message->attach($content); } $senderEmailAddress = $this->config->getSystemValue('mail_from_address') ?? null; $senderEmailDomain = $this->config->getSystemValue('mail_domain') ?? null; if($senderEmailAddress && $senderEmailDomain){ $senderEmail = $senderEmailAddress.'@'.$senderEmailDomain; $message->setCc([$senderEmail]); } $message->setHtmlBody($body); $this->mailer->send($message); } public function sendFileAttachmentToTalk($roomToken, $cookie , $fileName ) { try{ $host = 'http://127.0.0.1'; $client = \OC::$server->getHTTPClientService()->newClient(); $token = file_get_contents("$host/ocs/v2.php/core/getcsrftoken", false, stream_context_create([ 'http' => [ 'header' => "OCS-APIRequest: true\r\n" ] ])); $client->post("$host/ocs/v2.php/apps/files_sharing/api/v1/shares", [ 'body' => [ "path" => "//Talk/$fileName", "referenceId" => Uuid::uuid4()->toString(), "shareWith" => $roomToken, "shareType" => 10, 'talkMetaData' => "{\"messageType\":\"\"}" ], 'headers' => [ 'Cookie' =>$cookie, 'OCS-APIRequest' => 'true', 'requesttoken' => $token ] ]); } catch(GuzzleException $e){ $this->logger->debug("error sending file to talk"); } catch(Exception $e){ $this->logger->debug("error sending file to talk"); } } }