2021-11-19 08:49:22 +00:00
< ? php
declare ( strict_types = 1 );
/**
* Calendar App
*
* @ copyright 2021 Anna Larch < anna . larch @ gmx . net >
*
* @ author Anna Larch < anna . larch @ gmx . net >
*
* 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 < http :// www . gnu . org / licenses />.
*
*/
namespace OCA\Calendar\Service\Appointments ;
use Exception ;
use OCA\Calendar\Db\AppointmentConfig ;
use OCA\Calendar\Db\Booking ;
use OCA\Calendar\Exception\ServiceException ;
use OCP\Defaults ;
use OCP\IDateTimeFormatter ;
use OCP\IL10N ;
2023-06-28 13:19:59 +00:00
use OCP\IURLGenerator ;
2023-02-16 12:19:45 +00:00
use OCP\IUser ;
2021-11-19 08:49:22 +00:00
use OCP\IUserManager ;
use OCP\L10N\IFactory ;
use OCP\Mail\IEMailTemplate ;
use OCP\Mail\IMailer ;
2023-02-16 12:19:45 +00:00
use OCP\Notification\IManager ;
2021-11-19 08:49:22 +00:00
use Psr\Log\LoggerInterface ;
2021-11-24 15:40:37 +00:00
use function implode ;
2021-11-19 08:49:22 +00:00
class MailService {
/** @var IUserManager */
private $userManager ;
/** @var IMailer */
private $mailer ;
/** @var IL10N */
private $l10n ;
/** @var Defaults */
private $defaults ;
/** @var LoggerInterface */
private $logger ;
2023-06-28 13:19:59 +00:00
/** @var IURLGenerator */
2021-11-19 08:49:22 +00:00
private $urlGenerator ;
/** @var IDateTimeFormatter */
private $dateFormatter ;
/** @var IFactory */
private $lFactory ;
2023-02-16 12:19:45 +00:00
private IManager $notificationManager ;
public function __construct ( IMailer $mailer ,
2023-04-19 08:18:28 +00:00
IUserManager $userManager ,
IL10N $l10n ,
Defaults $defaults ,
LoggerInterface $logger ,
2023-06-28 13:19:59 +00:00
IURLGenerator $urlGenerator ,
2023-04-19 08:18:28 +00:00
IDateTimeFormatter $dateFormatter ,
IFactory $lFactory ,
IManager $notificationManager ) {
2021-11-19 08:49:22 +00:00
$this -> userManager = $userManager ;
$this -> mailer = $mailer ;
$this -> l10n = $l10n ;
$this -> defaults = $defaults ;
$this -> logger = $logger ;
$this -> urlGenerator = $urlGenerator ;
$this -> dateFormatter = $dateFormatter ;
$this -> lFactory = $lFactory ;
2023-02-16 12:19:45 +00:00
$this -> notificationManager = $notificationManager ;
2021-11-19 08:49:22 +00:00
}
/**
* @ param Booking $booking
* @ param AppointmentConfig $config
* @ throws ServiceException
*/
public function sendConfirmationEmail ( Booking $booking , AppointmentConfig $config ) : void {
$user = $this -> userManager -> get ( $config -> getUserId ());
2021-11-24 13:20:09 +00:00
if ( $user === null ) {
2021-11-19 08:49:22 +00:00
throw new ServiceException ( 'Could not find organizer' );
}
$fromEmail = $user -> getEMailAddress ();
2023-06-28 13:19:59 +00:00
if ( $fromEmail === null ) {
throw new ServiceException ( 'Organizer has no email set' );
}
2021-11-19 08:49:22 +00:00
$fromName = $user -> getDisplayName ();
$sys = $this -> getSysEmail ();
$message = $this -> mailer -> createMessage ()
-> setFrom ([ $sys => $fromName ])
-> setTo ([ $booking -> getEmail () => $booking -> getDisplayName ()])
-> setReplyTo ([ $fromEmail => $fromName ]);
$template = $this -> mailer -> createEMailTemplate ( 'calendar.confirmAppointment' );
$template -> addHeader ();
//Subject
2022-10-03 16:04:03 +00:00
$subject = $this -> l10n -> t ( 'Your appointment "%s" with %s needs confirmation' , [ $config -> getName (), $user -> getDisplayName ()]);
2021-11-19 08:49:22 +00:00
$template -> setSubject ( $subject );
// Heading
$summary = $this -> l10n -> t ( " Dear %s, please confirm your booking " , [ $booking -> getDisplayName ()]);
$template -> addHeading ( $summary );
2023-06-28 13:19:59 +00:00
2023-05-15 12:28:35 +00:00
$bookingUrl = $this -> urlGenerator -> linkToRouteAbsolute ( 'calendar.booking.confirmBooking' , [ 'token' => $booking -> getToken ()]);
$template -> addBodyButton ( $this -> l10n -> t ( 'Confirm' ), $bookingUrl );
2023-06-28 13:19:59 +00:00
2022-10-03 16:04:03 +00:00
$template -> addBodyListItem ( $user -> getDisplayName (), 'Appointment with:' );
if ( ! empty ( $config -> getDescription ())) {
$template -> addBodyListItem ( $config -> getDescription (), 'Description:' );
}
2021-11-19 08:49:22 +00:00
// Create Booking overview
2023-06-12 06:23:35 +00:00
$this -> addBulletList ( $template , $this -> l10n , $booking , $config -> getLocation ());
2021-11-19 08:49:22 +00:00
2021-11-24 13:20:09 +00:00
$bodyText = $this -> l10n -> t ( 'This confirmation link expires in %s hours.' , [( BookingService :: EXPIRY / 3600 )]);
2021-11-19 08:49:22 +00:00
$template -> addBodyText ( $bodyText );
2022-10-03 16:04:03 +00:00
$bodyText = $this -> l10n -> t ( 'If you wish to cancel the appointment after all, please contact your organizer by replying to this email or by visiting their profile page.' );
2021-11-19 08:49:22 +00:00
$template -> addBodyText ( $bodyText );
$template -> addFooter ();
$message -> useTemplate ( $template );
try {
$failed = $this -> mailer -> send ( $message );
if ( count ( $failed ) > 0 ) {
$this -> logger -> warning ( 'Mail delivery failed for some recipients.' );
2021-11-24 13:20:09 +00:00
foreach ( $failed as $fail ) {
2021-11-19 08:49:22 +00:00
$this -> logger -> debug ( 'Failed to deliver email to ' . $fail );
}
2021-11-24 15:40:37 +00:00
throw new ServiceException ( 'Could not send mail for recipient(s) ' . implode ( ', ' , $failed ));
2021-11-19 08:49:22 +00:00
}
} catch ( Exception $ex ) {
$this -> logger -> error ( $ex -> getMessage (), [ 'exception' => $ex ]);
2021-11-24 15:40:37 +00:00
throw new ServiceException ( 'Could not send mail: ' . $ex -> getMessage (), $ex -> getCode (), $ex );
2021-11-19 08:49:22 +00:00
}
}
2022-10-03 16:04:03 +00:00
/**
* @ param Booking $booking
* @ param AppointmentConfig $config
* @ throws ServiceException
*/
public function sendBookingInformationEmail ( Booking $booking , AppointmentConfig $config , string $calendar ) : void {
$user = $this -> userManager -> get ( $config -> getUserId ());
if ( $user === null ) {
throw new ServiceException ( 'Could not find organizer' );
}
$fromEmail = $user -> getEMailAddress ();
2023-06-28 13:19:59 +00:00
if ( $fromEmail === null ) {
throw new ServiceException ( 'Organizer has no email set' );
}
2022-10-03 16:04:03 +00:00
$fromName = $user -> getDisplayName ();
$sys = $this -> getSysEmail ();
$message = $this -> mailer -> createMessage ()
-> setFrom ([ $sys => $fromName ])
-> setTo ([ $booking -> getEmail () => $booking -> getDisplayName ()])
-> setReplyTo ([ $fromEmail => $fromName ]);
$template = $this -> mailer -> createEMailTemplate ( 'calendar.confirmAppointment' );
$template -> addHeader ();
2023-02-16 12:19:45 +00:00
// Subject
2022-10-03 16:04:03 +00:00
$subject = $this -> l10n -> t ( 'Your appointment "%s" with %s has been accepted' , [ $config -> getName (), $user -> getDisplayName ()]);
$template -> setSubject ( $subject );
// Heading
$summary = $this -> l10n -> t ( 'Dear %s, your booking has been accepted.' , [ $booking -> getDisplayName ()]);
$template -> addHeading ( $summary );
$template -> addBodyListItem ( $user -> getDisplayName (), 'Appointment with:' );
if ( ! empty ( $config -> getDescription ())) {
$template -> addBodyListItem ( $config -> getDescription (), 'Description:' );
}
// Create Booking overview
2023-06-12 06:23:35 +00:00
$this -> addBulletList ( $template , $this -> l10n , $booking , $config -> getLocation ());
2022-10-03 16:04:03 +00:00
$bodyText = $this -> l10n -> t ( 'If you wish to cancel the appointment after all, please contact your organizer by replying to this email or by visiting their profile page.' );
$template -> addBodyText ( $bodyText );
$template -> addFooter ();
$attachment = $this -> mailer -> createAttachment ( $calendar , " appointment.ics " , " text/calendar " );
$message -> attach ( $attachment );
$message -> useTemplate ( $template );
try {
$failed = $this -> mailer -> send ( $message );
if ( count ( $failed ) > 0 ) {
$this -> logger -> warning ( 'Mail delivery failed for some recipients.' );
foreach ( $failed as $fail ) {
$this -> logger -> debug ( 'Failed to deliver email to ' . $fail );
}
throw new ServiceException ( 'Could not send mail for recipient(s) ' . implode ( ', ' , $failed ));
}
} catch ( Exception $ex ) {
$this -> logger -> error ( $ex -> getMessage (), [ 'exception' => $ex ]);
throw new ServiceException ( 'Could not send mail: ' . $ex -> getMessage (), $ex -> getCode (), $ex );
}
}
2021-11-19 08:49:22 +00:00
private function addBulletList ( IEMailTemplate $template ,
2023-04-19 08:18:28 +00:00
IL10N $l10n ,
Booking $booking ,
2023-06-12 06:23:35 +00:00
? string $location = null ) : void {
2022-10-03 16:04:03 +00:00
$template -> addBodyListItem ( $booking -> getDisplayName (), $l10n -> t ( 'Appointment for:' ));
2021-11-19 08:49:22 +00:00
$l = $this -> lFactory -> findGenericLanguage ();
$relativeDateTime = $this -> dateFormatter -> formatDateTimeRelativeDay (
$booking -> getStart (),
'long' ,
'short' ,
new \DateTimeZone ( $booking -> getTimezone ()),
2022-08-05 06:59:41 +00:00
$this -> lFactory -> get ( 'calendar' , $l )
2021-11-19 08:49:22 +00:00
);
$template -> addBodyListItem ( $relativeDateTime , $l10n -> t ( 'Date:' ));
2023-06-12 06:23:35 +00:00
if ( ! empty ( $location )) {
$template -> addBodyListItem ( $location , $l10n -> t ( 'Where:' ));
2022-10-03 16:04:03 +00:00
}
2021-11-19 08:49:22 +00:00
if ( ! empty ( $booking -> getDescription ())) {
2023-02-16 12:19:45 +00:00
$template -> addBodyListItem ( $booking -> getDescription (), $l10n -> t ( 'Comment:' ));
2021-11-19 08:49:22 +00:00
}
}
/**
* @ return string
*/
private function getSysEmail () : string {
$instanceName = $this -> defaults -> getName ();
return \OCP\Util :: getDefaultEmailAddress ( 'appointments-noreply' );
}
2023-02-16 12:19:45 +00:00
public function sendOrganizerBookingInformationEmail ( Booking $booking , AppointmentConfig $config , string $calendar ) {
/** @var IUser $user */
$user = $this -> userManager -> get ( $config -> getUserId ());
if ( $user === null ) {
throw new ServiceException ( 'Could not find organizer' );
}
2023-06-28 13:19:59 +00:00
$toEmail = $user -> getEMailAddress ();
if ( $toEmail === null ) {
throw new ServiceException ( 'Organizer has no email set' );
}
2023-02-16 12:19:45 +00:00
$fromName = $user -> getDisplayName ();
$sys = $this -> getSysEmail ();
$message = $this -> mailer -> createMessage ()
-> setFrom ([ $sys => $fromName ])
2023-06-28 13:19:59 +00:00
-> setTo ([ $toEmail => $booking -> getDisplayName ()]);
2023-02-16 12:19:45 +00:00
$template = $this -> mailer -> createEMailTemplate ( 'calendar.confirmOrganizer' );
$template -> addHeader ();
// Subject
$subject = $this -> l10n -> t ( 'You have a new appointment booking "%s" from %s' , [ $config -> getName (), $booking -> getDisplayName ()]);
$template -> setSubject ( $subject );
// Heading
$summary = $this -> l10n -> t ( 'Dear %s, %s (%s) booked an appointment with you.' , [ $user -> getDisplayName (), $booking -> getDisplayName (), $booking -> getEmail ()]);
$template -> addHeading ( $summary );
$template -> addBodyListItem ( $booking -> getDisplayName () . ' (' . $booking -> getEmail () . ')' , 'Appointment with:' );
if ( ! empty ( $config -> getDescription ())) {
$template -> addBodyListItem ( $config -> getDescription (), 'Description:' );
}
// Create Booking overview
2023-06-12 06:23:35 +00:00
$this -> addBulletList ( $template , $this -> l10n , $booking , $config -> getLocation ());
2023-02-16 12:19:45 +00:00
$template -> addFooter ();
$attachment = $this -> mailer -> createAttachment ( $calendar , 'appointment.ics' , 'text/calendar' );
$message -> attach ( $attachment );
$message -> useTemplate ( $template );
try {
$failed = $this -> mailer -> send ( $message );
if ( count ( $failed ) > 0 ) {
$this -> logger -> warning ( 'Mail delivery failed for some recipients.' );
foreach ( $failed as $fail ) {
$this -> logger -> debug ( 'Failed to deliver email to ' . $fail );
}
throw new ServiceException ( 'Could not send mail for recipient(s) ' . implode ( ', ' , $failed ));
}
} catch ( Exception $ex ) {
$this -> logger -> error ( 'Could not send appointment organizer email: ' . $ex -> getMessage (), [ 'exception' => $ex ]);
throw new ServiceException ( 'Could not send mail: ' . $ex -> getMessage (), $ex -> getCode (), $ex );
}
}
public function sendOrganizerBookingInformationNotification ( Booking $booking , AppointmentConfig $config ) {
$relativeDateTime = $this -> dateFormatter -> formatDateTimeRelativeDay (
$booking -> getStart (),
'long' ,
'short' ,
new \DateTimeZone ( $booking -> getTimezone ()),
$this -> lFactory -> get ( 'calendar' )
);
$notification = $this -> notificationManager -> createNotification ();
$notification
-> setApp ( 'calendar' )
-> setUser ( $config -> getUserId ())
-> setObject ( 'booking' , ( string ) $booking -> getId ())
-> setSubject ( 'booking_accepted' ,
[
'type' => 'highlight' ,
'id' => $booking -> getId (),
'name' => $config -> getName (),
'link' => $config -> getPrincipalUri ()
])
-> setDateTime ( new \DateTime ())
-> setMessage ( 'booking_accepted_message' ,
[
'type' => 'highlight' ,
'id' => $booking -> getId (),
'display_name' => $booking -> getDisplayName (),
'config_display_name' => $config -> getName (),
'link' => $config -> getPrincipalUri (),
'email' => $booking -> getEmail (),
'date_time' => $relativeDateTime
]
);
$this -> notificationManager -> notify ( $notification );
}
2021-11-19 08:49:22 +00:00
}