o365-2.0.3/modules/o365_outlook_calendar/src/OutlookCalendarSaveEventService.php
modules/o365_outlook_calendar/src/OutlookCalendarSaveEventService.php
<?php
namespace Drupal\o365_outlook_calendar;
use Drupal\Component\Utility\EmailValidatorInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Link;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\o365\GraphService;
/**
* Service that handles to saving of events in Outlook.
*/
class OutlookCalendarSaveEventService {
/**
* The o365 Graph service.
*
* @var \Drupal\o365\GraphService
*/
protected GraphService $graphService;
/**
* The module config.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected ImmutableConfig $config;
/**
* The email validator.
*
* @var \Drupal\Component\Utility\EmailValidatorInterface
*/
protected EmailValidatorInterface $emailValidator;
/**
* The Drupal messenger.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected MessengerInterface $messenger;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected EntityFieldManagerInterface $entityFieldManager;
/**
* Constructor for the OutlookCalendarSaveEventService service.
*
* @param \Drupal\o365\GraphService $graphService
* The graph service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* The config factory.
* @param \Drupal\Component\Utility\EmailValidatorInterface $emailValidator
* The email validator.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The Drupal messenger service.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entityFieldManager
* The entity field manager.
*/
public function __construct(GraphService $graphService, ConfigFactoryInterface $configFactory, EmailValidatorInterface $emailValidator, MessengerInterface $messenger, EntityFieldManagerInterface $entityFieldManager) {
$this->graphService = $graphService;
$this->config = $configFactory->get('o365_outlook_calendar.settings');
$this->emailValidator = $emailValidator;
$this->messenger = $messenger;
$this->entityFieldManager = $entityFieldManager;
}
/**
* Generate the calendar form fields.
*
* @return array
* The list of fields.
*/
public function getCalendarFormFields(): array {
return [
'subject' => [
'#title' => new TranslatableMarkup('Subject'),
'#description' => new TranslatableMarkup('This is the name of the event in Outlook. You need to select a string field.'),
'#required' => TRUE,
],
'body' => [
'#title' => new TranslatableMarkup('Body'),
'#description' => new TranslatableMarkup('This will be used as the body of the event. You need to select a string or text field.'),
],
'start' => [
'#title' => new TranslatableMarkup('Start date'),
'#description' => new TranslatableMarkup('The start date of the event. You need to select a date(time) field.'),
'#required' => TRUE,
],
'end' => [
'#title' => new TranslatableMarkup('End date'),
'#description' => new TranslatableMarkup('The end date of the event. You need to select a date(time) field.'),
'#required' => TRUE,
],
'location' => [
'#title' => new TranslatableMarkup('Location'),
'#description' => new TranslatableMarkup('The location of the event. You can select a string or text field.'),
],
];
}
/**
* Get all fields in a certain content type.
*
* @param string $contentType
* The content type.
*
* @return array
* The list of fields.
*/
public function getEntityTypeFields(string $contentType): array {
$empty = new TranslatableMarkup('- Make your choice -');
$fields = [
'' => $empty,
];
if (str_starts_with($contentType, 'node_')) {
$contentType = str_replace('node_', '', $contentType);
$entityFields = $this->entityFieldManager->getFieldDefinitions('node', $contentType);
}
else {
$contentType = str_replace('content_entity_', '', $contentType);
$entityFields = $this->entityFieldManager->getFieldDefinitions($contentType, $contentType);
}
if (!empty($entityFields)) {
foreach ($entityFields as $fieldDefinition) {
$fields[$fieldDefinition->getName()] = $fieldDefinition->getLabel() . ' (' . $fieldDefinition->getType() . ')';
}
}
return $fields;
}
/**
* Add the event to Outlook.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity that contains the event values.
* @param string $attendees
* The comma seperated string of attendees.
* @param bool $returnLink
* If we want to return the weblink. If true, no messages are logged.
*
* @return bool|string
* The web link or TRUE/FALSE.
*
* @throws \Drupal\Core\TempStore\TempStoreException
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException
*/
public function addEvent(EntityInterface $entity, string $attendees = '', bool $returnLink = FALSE): bool|string {
// Get the field names from config.
$subjectField = $this->config->get('subject');
$bodyField = $this->config->get('body');
$startField = $this->config->get('start');
$endField = $this->config->get('end');
$locationField = $this->config->get('location');
// Load values from the node.
// @phpstan-ignore-next-line
$subject = $entity->get($subjectField)->value;
// @phpstan-ignore-next-line
$start = $entity->get($startField)->value;
// @phpstan-ignore-next-line
$end = $entity->get($endField)->value;
if ($startField === $endField) {
// @phpstan-ignore-next-line
$end = $entity->get($endField)->end_value;
}
// Body and location are not required, so we need to check.
$body = $location = FALSE;
// @phpstan-ignore-next-line
if ($entity->hasField($bodyField)) {
// @phpstan-ignore-next-line
$body = $entity->get($bodyField)->value;
}
// @phpstan-ignore-next-line
if ($entity->hasField($locationField)) {
// @phpstan-ignore-next-line
$location = $entity->get($locationField)->value;
}
// Create the data array we want to send.
$data = [
'subject' => $subject,
'start' => [
'dateTime' => $start,
'timeZone' => 'UTC',
],
'end' => [
'dateTime' => $end,
'timeZone' => 'UTC',
],
'allowNewTimeProposals' => TRUE,
'isOnlineMeeting' => TRUE,
];
// Check if this is an all day event (start & end date are the same)
if ($start === $end) {
// Set all day data.
$data['isAllDay'] = TRUE;
$timestamp = strtotime($start);
$startDate = date('Y-m-d', $timestamp) . 'T00:00:00';
$startTs = strtotime($startDate);
$endTs = strtotime('+ 1 day', $startTs);
// Change the start & end dates according to the API documentation.
$data['start']['dateTime'] = $startDate;
$data['end']['dateTime'] = date('Y-m-d', $endTs) . 'T00:00:00';
}
// Append the link to the entity to the body and add the body.
$url = $entity->toUrl('canonical', ['absolute' => TRUE]);
$linkText = new TranslatableMarkup('View this event here');
$link = Link::fromTextAndUrl($linkText, $url);
$body .= $link->toString();
$data['body'] = [
'contentType' => 'HTML',
'content' => $body,
];
// Add the location, if any.
if (!empty($location)) {
$data['location'] = [
'displayName' => $location,
];
}
// Set up attendees if there are any.
if (!empty($attendees)) {
$attendeesArray = explode(',', $attendees);
if (!empty($attendeesArray)) {
$invalidEmails = [];
$data['attendees'] = [];
foreach ($attendeesArray as $attendee) {
$attendee = trim($attendee);
if ($this->emailValidator->isValid($attendee)) {
$data['attendees'][] = [
'emailAddress' => [
'address' => $attendee,
],
'type' => 'optional',
];
}
else {
$invalidEmails[] = $attendee;
}
}
// Show a warning if there are any invalid email addresses.
if (!empty($invalidEmails)) {
$warning = new TranslatableMarkup('The following mail addresses where not valid and not automatically added as attendee: @addresses', ['@addresses' => implode(', ', $invalidEmails)]);
$this->messenger->addWarning($warning);
}
}
}
// Do a call to the webservice and a according message.
$return = $this->graphService->sendGraphData('/me/events', $data);
if ($return) {
if ($returnLink) {
return $return['webLink'];
}
$url = Url::fromUri($return['webLink'], ['attributes' => ['target' => '_blank']]);
$link = Link::fromTextAndUrl('Outlook Calendar', $url);
$message = new TranslatableMarkup('This event has been created in your @link', ['@link' => $link->toString()]);
$this->messenger->addMessage($message);
return TRUE;
}
if (!$returnLink) {
$warning = new TranslatableMarkup('Something went wrong creating this event in Outlook. Please add it manually.');
$this->messenger->addError($warning);
}
return FALSE;
}
}
