diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index bd2438753f82077a525061986aad7b9f31543b60..7dd118dd326c07da1e41374db045feed5270387f 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -35,8 +35,8 @@ use function method_exists; use OCA\Calendar\Middleware\InvitationMiddleware; use OCP\IRequest; use OCP\IConfig; -use \OCP\IDBConnection; -use \OC\Core\Application as CoreApplication; +use OCP\IDBConnection; +use OC\Core\Application as CoreApplication; use OCP\Http\Client\IResponse; use OCP\Calendar\IManager; use OCP\Mail\IMailer; @@ -45,88 +45,92 @@ use OCP\L10N\IFactory as L10NFactory; use OCP\Defaults; use OCP\ILogger; use OCP\IUserManager; +use OCP\BackgroundJob\IJobList; - -class Application extends App implements IBootstrap { - +class Application extends App implements IBootstrap +{ /** @var string */ - public const APP_ID = 'calendar'; + public const APP_ID = "calendar"; /** * @param array $params */ - public function __construct(array $params = []) { + public function __construct(array $params = []) + { parent::__construct(self::APP_ID, $params); - //$app = new \OCP\AppFramework\App('ecloud-theme-helper'); - //$containerinvite = $app->getContainer() ; + } + + /** + * @inheritDoc + */ + public function register(IRegistrationContext $context): void + { + $context->registerDashboardWidget(CalendarWidget::class); + + // TODO: drop conditional code when the app is 23+ + if (method_exists($context, "registerProfileLinkAction")) { + $context->registerProfileLinkAction(AppointmentsAction::class); + } + + $context->registerEventListener( + UserDeletedEvent::class, + UserDeletedListener::class + ); + } + + /** + * @inheritDoc + */ + public function boot(IBootContext $context): void + { $container = $this->getContainer(); /** - * Middleware - */ - $container->registerService('InvitationMiddleware', function($c){ - return new InvitationMiddleware( - $c->get(IRequest::class), - $c->get(IConfig::class), - $c->get(IDBConnection::class), - $c->get(IManager::class), + * Middleware + */ + $container->registerService("InvitationMiddleware", function ($c) { + return new InvitationMiddleware( + $c->get(IRequest::class), + $c->get(IConfig::class), + $c->get(IDBConnection::class), + $c->get(IManager::class), $c->get(IMailer::class), $c->get(IL10N::class), $c->get(Defaults::class), $c->get(ILogger::class), $c->get(IUserManager::class), $c->get(L10NFactory::class), - ); - }); + $c->get(IJobList::class) + ); + }); - // executed in the order that it is registered - $container->registerMiddleware('InvitationMiddleware'); + // executed in the order that it is registered + $container->registerMiddleware("InvitationMiddleware"); - $app = new \OCP\AppFramework\App('dav'); - $containerinvite = $app->getContainer() ; + $davAppContainer = new \OCP\AppFramework\App("dav"); + $containerinvite = $davAppContainer->getContainer(); /** - * Middleware - */ - $containerinvite->registerService('InvitationMiddleware', function($c){ - return new InvitationMiddleware( - $c->get(IRequest::class), - $c->get(IConfig::class), - $c->get(IDBConnection::class), - $c->get(IManager::class), + * Middleware + */ + $containerinvite->registerService("InvitationMiddleware", function ( + $c + ) { + return new InvitationMiddleware( + $c->get(IRequest::class), + $c->get(IConfig::class), + $c->get(IDBConnection::class), + $c->get(IManager::class), $c->get(IMailer::class), $c->get(IL10N::class), $c->get(Defaults::class), $c->get(ILogger::class), $c->get(IUserManager::class), $c->get(L10NFactory::class), - ); - }); - - // executed in the order that it is registered - $containerinvite->registerMiddleware('InvitationMiddleware'); - } - - /** - * @inheritDoc - */ - public function register(IRegistrationContext $context): void { - $context->registerDashboardWidget(CalendarWidget::class); - - // TODO: drop conditional code when the app is 23+ - if (method_exists($context, 'registerProfileLinkAction')) { - $context->registerProfileLinkAction(AppointmentsAction::class); - } - - $context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class); - - - } - - /** - * @inheritDoc - */ - public function boot(IBootContext $context): void { - + $c->get(IJobList::class) + ); + }); + // executed in the order that it is registered + $containerinvite->registerMiddleware("InvitationMiddleware"); } -} \ No newline at end of file +} diff --git a/lib/BackgroundJob/SendInviteResponseMailJob.php b/lib/BackgroundJob/SendInviteResponseMailJob.php new file mode 100644 index 0000000000000000000000000000000000000000..133ca8bca34d2ec8dc3b10e8ee43a5ce7fdd77cd --- /dev/null +++ b/lib/BackgroundJob/SendInviteResponseMailJob.php @@ -0,0 +1,257 @@ + + * + * @author Anna Larch + * + * 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\Calendar\BackgroundJob; + + +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\QueuedJob ; +use Psr\Log\LoggerInterface; +use OCP\IDBConnection; +use OCP\Defaults; +use OCP\Mail\IMailer; +use OCP\IL10N; +use OCP\IUserManager; +use OCP\Calendar\IManager; +use Sabre\VObject\Reader; +use OCP\Util; + +class SendInviteResponseMailJob extends QueuedJob { + + private const translations = [ + "tentative" => [ + "meeting_title" => "Invitation Tentatively Accepted: %s", + "meeting_body" => + "%s has tentatively accepted your invitation to %s on %s", + "meeting_head" => "Tentatively Accepted", + ], + "accept" => [ + "meeting_title" => "Invitation Accepted: %s", + "meeting_body" => "%s has accepted your invitation to %s on %s", + "meeting_head" => "Accepted", + ], + "decline" => [ + "meeting_title" => "Invitation Declined: %s", + "meeting_body" => "%s has declined your invitation to %s on %s", + "meeting_head" => "Declined", + ], + ]; + + + public function __construct(ITimeFactory $time, + IDBConnection $db, + IManager $calendarManager, + IMailer $mailer, + IL10N $l10n, + Defaults $defaults, + IUserManager $iusermanager, + + LoggerInterface $logger) { + parent::__construct($time); + $this->db = $db; + $this->logger = $logger; + $this->calendarManager = $calendarManager; + $this->mailer = $mailer; + $this->l10n = $l10n; + $this->defaults = $defaults; + $this->iusermanager = $iusermanager; + + + } + + private function getMailAttributes( + string $methodName, + array $translationData + ) { + $meetingTitle = $this->l10n->t( + self::translations[$methodName]["meeting_title"], + $translationData["summary"] + ); + $meetingBody = $this->l10n->t( + self::translations[$methodName]["meeting_body"], + [ + $translationData["attendee_name"], + $translationData["summary"], + $translationData["event_date"], + ] + ); + $meetingHead = $this->l10n->t( + self::translations[$methodName]["meeting_head"] + ); + return [ + "meeting_title" => $meetingTitle, + "meeting_body" => $meetingBody, + "meeting_head" => $meetingHead, + ]; + } + private function extract_emails_from($string) + { + $string= (string) $string; + $matches = []; + $found = preg_match("/mailto:(.*)/i", $string, $matches); + if ($found === 1) { + return $matches[1]; + } + return ""; + } + protected function run($arguments) { + $token = $arguments['token']; + $methodName = $arguments['methodName']; + $defaultVal = '--'; + //$outdated = $this->service->sendInviteResponseMail($argument); + $queryCalendarInvitations = $this->db->getQueryBuilder(); + $queryCalendarInvitations + ->select("id", "uid", "attendee", "organizer") + ->from("calendar_invitations") + ->where( + $queryCalendarInvitations + ->expr() + ->eq( + "token", + $queryCalendarInvitations->createNamedParameter( + $token + ) + ) + ); + $stmt = $queryCalendarInvitations->execute(); + $row = $stmt->fetch(\PDO::FETCH_ASSOC); + $uid = $row["uid"]; + $sender = $this->extract_emails_from($row["attendee"]); + $recipient = $this->extract_emails_from($row["organizer"]); + $userdata = $this->iusermanager->getByEmail($recipient); + if (count($userdata) > 0) { + $username = $userdata[0]->getUID(); + $principaluri = "principals/users/" . $username; + $queryCalendarObjects = $this->db->getQueryBuilder(); + $queryCalendarObjects + ->select("co.id", "co.calendardata") + ->from("calendarobjects", "co") + ->innerJoin( + "co", + "calendars", + "c", + $queryCalendarObjects + ->expr() + ->eq("co.calendarid", "c.id") + ) + ->where( + $queryCalendarObjects + ->expr() + ->eq( + "c.principaluri", + $queryCalendarObjects->createNamedParameter( + $principaluri + ) + ) + ) + ->andWhere( + $queryCalendarObjects + ->expr() + ->eq( + "co.uid", + $queryCalendarObjects->createNamedParameter( + $uid + ) + ) + ); + $stmt2 = $queryCalendarObjects->execute(); + + if ($row2 = $stmt2->fetch(\PDO::FETCH_ASSOC)) { + $vObject = Reader::read($row2["calendardata"]); + $attendeeName = $sender; + foreach ($vObject->VEVENT->ATTENDEE as $attendee1) { + $attendee = $this->extract_emails_from($attendee1); + if ($attendee == $sender) { + if(!empty($attendee1["CN"])){ + $attendeeName = $attendee1["CN"]; + break; + } + + } + } + $organizerName = empty($vObject->VEVENT->ORGANIZER["CN"]) + ? $recipient + : $vObject->VEVENT->ORGANIZER["CN"]; + + $SUMMARY = $vObject->VEVENT->SUMMARY; + $datestart = (string) $vObject->VEVENT->DTSTART; + if (str_contains($datestart, "T")) { + $eventdate = date("F d, Y h:i", strtotime($datestart)); + } else { + $eventdate = date("F d, Y", strtotime($datestart)); + } + $translationData = [ + "summary" => $SUMMARY, + "attendee_name" => $attendeeName, + "event_date" => $eventdate, + ]; + $translations = $this->getMailAttributes( + $methodName, + $translationData + ); + + $data = [ + "attendee_name" => (string) $sender ?: $defaultVal, + "invitee_name" => (string) $recipient ?: $defaultVal, + "meeting_title" => + (string) $translations["meeting_title"] ?: + $defaultVal, + ]; + $method = "reply"; + $emailTemplate = $this->mailer->createEMailTemplate( + "dav.calendarInvite." . $method, + $data + ); + $emailTemplate->setSubject( + $this->l10n->t($translations["meeting_title"], [ + $SUMMARY, + ]) + ); + $emailTemplate->addHeader(); + $emailTemplate->addHeading($translations["meeting_head"]); + $emailTemplate->addBodyText( + htmlspecialchars($translations["meeting_body"]), + $translations["meeting_body"] + ); + $emailTemplate->addFooter(); + try { + $fromEMail = Util::getDefaultEmailAddress('invitations-noreply'); + $fromName = $this->l10n->t('%1$s via %2$s', [$attendeeName, $this->defaults->getName()]); + $message = $this->mailer->createMessage(); + $message->setTo([$recipient => $organizerName]); + $message->setFrom([$fromEMail => $fromName]); + $message->setReplyTo([$sender => $attendeeName]); + $message->useTemplate($emailTemplate); + $this->mailer->send($message); + } catch (\Exception $e) { + // Log the exception and continue + $this->logger->logException($e); + } + } + $this->logger->info('Found and deleted ' . $outdated . ' outdated booking confirmations.'); + } + } +} \ No newline at end of file diff --git a/lib/Middleware/InvitationMiddleware.php b/lib/Middleware/InvitationMiddleware.php index 2f6c6d510658f9c017f15081088b23f1abc7f34d..249ba418b9bd8121867c89b258674386a060b064 100644 --- a/lib/Middleware/InvitationMiddleware.php +++ b/lib/Middleware/InvitationMiddleware.php @@ -5,6 +5,8 @@ namespace OCA\Calendar\Middleware; use OCP\AppFramework\Middleware; use OCA\Calendar\Controller\InvitationMaybeController; use OCA\Dav\Controller\InvitationResponseController; +use OCA\Calendar\BackgroundJob\SendInviteResponseMailJob; +use OCP\BackgroundJob\IJobList; use OCP\IDBConnection; use OCP\IConfig; use OCP\IRequest; @@ -20,9 +22,11 @@ use OCP\IUser; use OCP\L10N\IFactory; use OCP\Util; + class InvitationMiddleware extends Middleware { private $request; + private $jobList; /** @var IManager */ private $calendarManager; private const translations = [ @@ -54,7 +58,8 @@ class InvitationMiddleware extends Middleware Defaults $defaults, ILogger $logger, IUserManager $iusermanager, - IFactory $languageFactory + IFactory $languageFactory, + IJobList $jobList ) { $this->request = $request; $this->config = $config; @@ -66,41 +71,9 @@ class InvitationMiddleware extends Middleware $this->logger = $logger; $this->iusermanager = $iusermanager; $this->languageFactory = $languageFactory; + $this->jobList = $jobList; } - private function getMailAttributes( - string $methodName, - array $translationData - ) { - $meetingTitle = $this->l10n->t( - self::translations[$methodName]["meeting_title"], - $translationData["summary"] - ); - $meetingBody = $this->l10n->t( - self::translations[$methodName]["meeting_body"], - [ - $translationData["attendee_name"], - $translationData["summary"], - $translationData["event_date"], - ] - ); - $meetingHead = $this->l10n->t( - self::translations[$methodName]["meeting_head"] - ); - return [ - "meeting_title" => $meetingTitle, - "meeting_body" => $meetingBody, - "meeting_head" => $meetingHead, - ]; - } - private function extract_emails_from($string) - { - $matches = []; - $found = preg_match("/mailto:(.*)/i", $string, $matches); - if ($found === 1) { - return $matches[1]; - } - return ""; - } + public function afterController( $controller, $methodName, @@ -115,138 +88,12 @@ class InvitationMiddleware extends Middleware $response->getTemplateName() == "schedule-response-success") ) { $token = $this->request->getParam("token"); - $queryCalendarInvitations = $this->db->getQueryBuilder(); - $queryCalendarInvitations - ->select("id", "uid", "attendee", "organizer") - ->from("calendar_invitations") - ->where( - $queryCalendarInvitations - ->expr() - ->eq( - "token", - $queryCalendarInvitations->createNamedParameter( - $token - ) - ) - ); - $stmt = $queryCalendarInvitations->execute(); - $row = $stmt->fetch(\PDO::FETCH_ASSOC); - $uid = $row["uid"]; - $sender = $this->extract_emails_from($row["attendee"]); - $recipient = $this->extract_emails_from($row["organizer"]); - $userdata = $this->iusermanager->getByEmail($recipient); - if (count($userdata) > 0) { - $username = $userdata[0]->getUID(); - $principaluri = "principals/users/" . $username; - $queryCalendarObjects = $this->db->getQueryBuilder(); - $queryCalendarObjects - ->select("co.id", "co.calendardata") - ->from("calendarobjects", "co") - ->innerJoin( - "co", - "calendars", - "c", - $queryCalendarObjects - ->expr() - ->eq("co.calendarid", "c.id") - ) - ->where( - $queryCalendarObjects - ->expr() - ->eq( - "c.principaluri", - $queryCalendarObjects->createNamedParameter( - $principaluri - ) - ) - ) - ->andWhere( - $queryCalendarObjects - ->expr() - ->eq( - "co.uid", - $queryCalendarObjects->createNamedParameter( - $uid - ) - ) - ); - $stmt2 = $queryCalendarObjects->execute(); - - if ($row2 = $stmt2->fetch(\PDO::FETCH_ASSOC)) { - $vObject = Reader::read($row2["calendardata"]); - - foreach ($vObject->VEVENT->ATTENDEE as $attendee1) { - $attendee = $this->extract_emails_from($attendee1); - if ($attendee == $sender) { - $attendeeName = empty($attendee1["CN"]) - ? $sender - : $attendee1["CN"]; - break; - } - } - $organizerName = empty($vObject->VEVENT->ORGANIZER["CN"]) - ? $recipient - : $vObject->VEVENT->ORGANIZER["CN"]; + $this->jobList->add(SendInviteResponseMailJob::class, ['token' => $token,'methodName' => $methodName]); - $SUMMARY = $vObject->VEVENT->SUMMARY; - $datestart = (string) $vObject->VEVENT->DTSTART; - if (str_contains($datestart, "T")) { - $eventdate = date("F d, Y h:i", strtotime($datestart)); - } else { - $eventdate = date("F d, Y", strtotime($datestart)); - } - $translationData = [ - "summary" => $SUMMARY, - "attendee_name" => $attendeeName, - "event_date" => $eventdate, - ]; - $translations = $this->getMailAttributes( - $methodName, - $translationData - ); - - $data = [ - "attendee_name" => (string) $sender ?: $defaultVal, - "invitee_name" => (string) $recipient ?: $defaultVal, - "meeting_title" => - (string) $translations["meeting_title"] ?: - $defaultVal, - ]; - $method = "reply"; - $emailTemplate = $this->mailer->createEMailTemplate( - "dav.calendarInvite." . $method, - $data - ); - $emailTemplate->setSubject( - $this->l10n->t($translations["meeting_title"], [ - $SUMMARY, - ]) - ); - $emailTemplate->addHeader(); - $emailTemplate->addHeading($translations["meeting_head"]); - $emailTemplate->addBodyText( - htmlspecialchars($translations["meeting_body"]), - $translations["meeting_body"] - ); - $emailTemplate->addFooter(); - try { - $fromEMail = Util::getDefaultEmailAddress('invitations-noreply'); - $fromName = $this->l10n->t('%1$s via %2$s', [$attendeeName, $this->defaults->getName()]); - $message = $this->mailer->createMessage(); - $message->setTo([$recipient => $organizerName]); - $message->setFrom([$fromEMail => $fromName]); - $message->setReplyTo([$sender => $attendeeName]); - $message->useTemplate($emailTemplate); - $this->mailer->send($message); - } catch (\Exception $e) { - // Log the exception and continue - $this->logger->logException($e); - } - } - } } + return $response; } }