1: <?php
2: /**
3: * This code is licensed under AGPLv3 license or Afterlogic Software License
4: * if commercial version of the product was purchased.
5: * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
6: */
7:
8: namespace Aurora\Modules\CalendarMeetingsPlugin;
9:
10: use Aurora\Modules\Core\Module as CoreModule;
11: use Aurora\Modules\Calendar\Module as CalendarModule;
12: use Aurora\Modules\Calendar\Classes\Helper as CalendarHelper;
13: use Aurora\System\Api;
14: use MailSo\Mime\Email;
15:
16: /**
17: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
18: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
19: * @copyright Copyright (c) 2023, Afterlogic Corp.
20: *
21: * @property Settings $oModuleSettings
22: *
23: * @package Modules
24: */
25: class Module extends \Aurora\System\Module\AbstractModule
26: {
27: /** @var Manager */
28: protected $oManager = null;
29:
30: public $oApiFileCache = null;
31: // public $oApiCalendarDecorator = null;
32: // public $oApiUsersManager = null;
33:
34: /**
35: * @return Module
36: */
37: public static function getInstance()
38: {
39: return parent::getInstance();
40: }
41:
42: /**
43: * @return Module
44: */
45: public static function Decorator()
46: {
47: return parent::Decorator();
48: }
49:
50: /**
51: * @return Settings
52: */
53: public function getModuleSettings()
54: {
55: return $this->oModuleSettings;
56: }
57:
58: public function getManager()
59: {
60: if ($this->oManager === null) {
61: $this->oManager = new Manager($this);
62: }
63:
64: return $this->oManager;
65: }
66:
67: public function getCacheManager()
68: {
69: if ($this->oApiFileCache === null) {
70: $this->oApiFileCache = new \Aurora\System\Managers\Filecache();
71: }
72:
73: return $this->oApiFileCache;
74: }
75:
76: public function init()
77: {
78: $this->AddEntries([
79: 'invite' => 'EntryInvite'
80: ]);
81:
82: $this->subscribeEvent('Calendar::CreateIcs', array($this, 'onCreateIcs'));
83: $this->subscribeEvent('Calendar::populateVCalendar', array($this, 'onPopulateVCalendar'));
84: $this->subscribeEvent('Calendar::DeleteEvent', array($this, 'onDeleteEvent'));
85: $this->subscribeEvent('Calendar::UpdateEventAttendees', array($this, 'onUpdateEventAttendees'));
86: $this->subscribeEvent('CalendarMeetingsPlugin::processICS::UpdateEvent', array($this, 'onProcessICSUpdateEvent'));
87: $this->subscribeEvent('CalendarMeetingsPlugin::processICS::Cancel', array($this, 'onProcessICSCancel'));
88: $this->subscribeEvent('Calendar::processICS::UpdateEvent', array($this, 'onProcessICSUpdateEvent'));
89: $this->subscribeEvent('Calendar::processICS::Cancel', array($this, 'onProcessICSCancel'));
90: $this->subscribeEvent('Calendar::processICS::AddAttendeesToResult', array($this, 'onAddAttendeesToResult'));
91: $this->subscribeEvent('Calendar::parseEvent', array($this, 'onParseEvent'));
92:
93: $this->aErrors = [
94: Enums\ErrorCodes::CannotSendAppointmentMessage => $this->i18N('ERROR_CANNOT_SEND_APPOINTMENT_MESSAGE'),
95: Enums\ErrorCodes::CannotSendAppointmentMessageNoOrganizer => $this->i18N('ERROR_CANNOT_SEND_APPOINTMENT_MESSAGE_NO_ORGANIZER')
96: ];
97: }
98:
99: /**
100: * @param int $UserId
101: * @param string $File
102: * @param string $FromEmail
103: * @return boolean
104: * @throws \Aurora\System\Exceptions\ApiException
105: */
106: public function UpdateAttendeeStatus($UserId, $File, $FromEmail)
107: {
108: \Aurora\System\Api::CheckAccess($UserId);
109: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
110: $mResult = false;
111:
112: if (empty($File) || empty($FromEmail)) {
113: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
114: }
115: $sData = $this->getCacheManager()->get($sUserPublicId, $File, '', CalendarModule::GetName());
116: if (!empty($sData)) {
117: $mResult = $this->getManager()->processICS($sUserPublicId, $sData, $FromEmail, true);
118: }
119:
120: return $mResult;
121: }
122:
123: /**
124: *
125: * @param int $UserId
126: * @param string $CalendarId
127: * @param string $EventId
128: * @param string $File
129: * @param string $AppointmentAction
130: * @param string $Attendee
131: * @return array|boolean
132: * @throws \Aurora\System\Exceptions\ApiException
133: */
134: public function SetAppointmentAction($UserId, $CalendarId, $EventId, $File, $AppointmentAction, $Attendee, $AllEvents = 2, $RecurrenceId = null)
135: {
136: \Aurora\System\Api::CheckAccess($UserId);
137: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
138: $mResult = false;
139:
140: if (empty($AppointmentAction) || empty($CalendarId)) {
141: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
142: }
143: $sData = '';
144: if (!empty($EventId)) {
145: $aEventData = $this->getManager()->getEvent($sUserPublicId, $CalendarId, $EventId);
146: if (isset($aEventData) && isset($aEventData['vcal']) && $aEventData['vcal'] instanceof \Sabre\VObject\Component\VCalendar) {
147: $oVCal = $aEventData['vcal'];
148: $oVCal->METHOD = 'REQUEST';
149: $sData = $oVCal->serialize();
150: }
151: } elseif (!empty($File)) {
152: $sData = $this->getCacheManager()->get($sUserPublicId, $File, '', CalendarModule::GetName());
153: }
154: if (!empty($sData)) {
155: $mProcessResult = $this->getManager()->appointmentAction($sUserPublicId, $Attendee, $AppointmentAction, $CalendarId, $sData, $AllEvents, $RecurrenceId);
156: if ($mProcessResult) {
157: $mResult = array(
158: 'Uid' => $mProcessResult
159: );
160: }
161: }
162:
163: return $mResult;
164: }
165:
166: public function EntryInvite()
167: {
168: $sResult = '';
169: $aInviteValues = \Aurora\System\Api::DecodeKeyValues($this->oHttp->GetQuery('invite'));
170:
171: if (isset($aInviteValues['organizer'])) {
172: $sOrganizerPublicId = $aInviteValues['organizer'];
173: $oOrganizerUser = CoreModule::Decorator()->GetUserByPublicId($sOrganizerPublicId);
174: if ($sOrganizerPublicId && isset($aInviteValues['attendee'], $aInviteValues['eventId'], $aInviteValues['action'])) {
175: $calendarId = $aInviteValues['calendarId'];
176: if (empty($calendarId)) {
177: $calendarId = $this->getManager()->findEventInCalendars($sOrganizerPublicId, $aInviteValues['eventId']);
178: }
179: $sAction = '';
180: $oEvent = $this->getManager()->getEvent($sOrganizerPublicId, $calendarId, $aInviteValues['eventId']);
181: $oModuleManager = \Aurora\System\Api::GetModuleManager();
182: $sTheme = $oModuleManager->getModuleConfigValue('CoreWebclient', 'Theme');
183: if ($oEvent && is_array($oEvent) && 0 < count($oEvent) && isset($oEvent[0])) {
184: $sResult = \file_get_contents($this->GetPath() . '/templates/CalendarEventInviteExternal.html');
185: if (is_string($sResult)) {
186: $dt = new \DateTime();
187: $dt->setTimestamp($oEvent[0]['startTS']);
188: if (!$oEvent[0]['allDay']) {
189: $sDefaultTimeZone = new \DateTimeZone($oOrganizerUser->DefaultTimeZone);
190: $dt->setTimezone($sDefaultTimeZone);
191: }
192:
193: $sAction = $aInviteValues['action'];
194: $sActionColor = 'green';
195: $sActionText = '';
196: switch (strtoupper($sAction)) {
197: case 'ACCEPTED':
198: $sActionColor = 'green';
199: $sActionText = 'Accepted';
200: break;
201: case 'DECLINED':
202: $sActionColor = 'red';
203: $sActionText = 'Declined';
204: break;
205: case 'TENTATIVE':
206: $sActionColor = '#A0A0A0';
207: $sActionText = 'Tentative';
208: break;
209: }
210:
211: $sDateFormat = 'm/d/Y';
212: $sTimeFormat = 'h:i A';
213: switch ($oOrganizerUser->DateFormat) {
214: case \Aurora\System\Enums\DateFormat::DDMMYYYY:
215: $sDateFormat = 'd/m/Y';
216: break;
217: case \Aurora\System\Enums\DateFormat::DD_MONTH_YYYY:
218: $sDateFormat = 'd/m/Y';
219: break;
220: default:
221: $sDateFormat = 'm/d/Y';
222: break;
223: }
224: switch ($oOrganizerUser->TimeFormat) {
225: case \Aurora\System\Enums\TimeFormat::F24:
226: $sTimeFormat = 'H:i';
227: break;
228: case \Aurora\System\Enums\DateFormat::DD_MONTH_YYYY:
229: \Aurora\System\Enums\TimeFormat::F12;
230: $sTimeFormat = 'h:i A';
231: break;
232: default:
233: $sTimeFormat = 'h:i A';
234: break;
235: }
236: $sDateTime = $dt->format($sDateFormat . ' ' . $sTimeFormat);
237:
238: $mResult = array(
239: '{{EVENT_NAME}}' => $oEvent[0]['subject'],
240: '{{EVENT_BEGIN}}' => ucfirst($this->i18N('EVENT_BEGIN')),
241: '{{EVENT_DATE}}' => $sDateTime,
242: '{{CALENDAR}}' => ucfirst($this->i18N('CALENDAR')),
243: '{{EVENT_DESCRIPTION}}' => $oEvent[0]['description'],
244: '{{EVENT_ACTION}}' => $sActionText,
245: '{{ACTION_COLOR}}' => $sActionColor,
246: '{{THEME_NAME}}' => $sTheme,
247: );
248:
249: $sResult = strtr($sResult, $mResult);
250: } else {
251: $sResult = "Error occured";
252: \Aurora\System\Api::Log('Empty page template.', \Aurora\System\Enums\LogLevel::Error);
253: }
254: } else {
255: \Aurora\System\Api::Log('Event not found.', \Aurora\System\Enums\LogLevel::Error);
256:
257: $sResult = file_get_contents($this->GetPath() . '/templates/EventNotFound.html');
258:
259: if (is_string($sResult)) {
260: $mResult = array(
261: '{{INFO}}' => ucfirst($this->i18N('ERROR_APPOINTMENT_NOT_FOUND')),
262: '{{THEME_NAME}}' => $sTheme,
263: );
264:
265: $sResult = strtr($sResult, $mResult);
266: } else {
267: $sResult = "Error occured";
268: \Aurora\System\Api::Log('Empty page template.', \Aurora\System\Enums\LogLevel::Error);
269: }
270: }
271: $sAttendee = $aInviteValues['attendee'];
272: if (!empty($sAttendee)) {
273: $oAttendee = Email::Parse($sAttendee);
274: $sAttendee = $oAttendee->GetEmail();
275:
276: if (isset($oEvent) && isset($oEvent['vcal']) && $oEvent['vcal'] instanceof \Sabre\VObject\Component\VCalendar) {
277: $oVCal = $oEvent['vcal'];
278: $oVCal->METHOD = 'REQUEST';
279: $sData = $oVCal->serialize();
280: $oAttendeeUser = CoreModule::Decorator()->GetUserByPublicId($sAttendee);
281: $bIsExternalAttendee = false;
282: if ($oAttendeeUser) {
283: $sOrganizerPublicId = $oAttendeeUser->PublicId;
284: } else {
285: $bIsExternalAttendee = true;
286: }
287: $actionResult = false;
288: try {
289: $actionResult = $this->getManager()->appointmentAction($sOrganizerPublicId, $sAttendee, $sAction, $calendarId, $sData, 2, null, true, $bIsExternalAttendee);
290: } catch (\Aurora\System\Exceptions\Exception $e) {
291: Api::LogException($e);
292: $actionResult = false;
293: }
294: if (!$actionResult) {
295: $sResult = file_get_contents($this->GetPath() . '/templates/EventNotFound.html');
296:
297: if (is_string($sResult)) {
298: $mResult = array(
299: '{{INFO}}' => ucfirst($this->i18N('ERROR_APPOINTMENT_UPDATE_STATUS')),
300: '{{THEME_NAME}}' => $sTheme,
301: );
302:
303: $sResult = strtr($sResult, $mResult);
304: }
305: }
306: }
307: }
308: }
309: }
310:
311: return $sResult;
312: }
313:
314: /**
315: *
316: * @return array
317: */
318: public function GetSettings()
319: {
320: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
321:
322: $aSettings = array(
323: 'AllowAppointments' => $this->oModuleSettings->AllowAppointments
324: );
325:
326: return $aSettings;
327: }
328:
329: public function onCreateIcs($aData, &$oIcs)
330: {
331: $oIcs->Attendee = isset($aData['Attendee']) ? $aData['Attendee'] : null;
332: $oIcs->Type = $aData['Action'];
333: }
334:
335: public function onPopulateVCalendar(&$aData, &$oVEvent)
336: {
337: /** @var \Sabre\VObject\Component\VEvent $oVEvent */
338: $oEvent = & $aData['oEvent'];
339:
340: $oUser = \Aurora\System\Api::getAuthenticatedUser();
341:
342: $aAttendees = [];
343: $aAttendeeEmails = [];
344: $aObjAttendees = [];
345: if (isset($oVEvent->ORGANIZER)) {
346: $sOwnerEmail = str_replace('mailto:', '', strtolower((string) $oVEvent->ORGANIZER));
347: $iPos = strpos($sOwnerEmail, 'principals/');
348: if ($iPos !== false) {
349: $sOwnerEmail = \trim(substr($sOwnerEmail, $iPos + 11), '/');
350: }
351: }
352:
353: if (isset($oVEvent->ATTENDEE)) {
354: $aAttendeeEmails = [];
355: foreach ($oEvent->Attendees as $aItem) {
356: $sStatus = '';
357: switch ($aItem['status']) {
358: case \Aurora\Modules\Calendar\Enums\AttendeeStatus::Accepted:
359: $sStatus = 'ACCEPTED';
360: break;
361: case \Aurora\Modules\Calendar\Enums\AttendeeStatus::Declined:
362: $sStatus = 'DECLINED';
363: break;
364: case \Aurora\Modules\Calendar\Enums\AttendeeStatus::Tentative:
365: $sStatus = 'TENTATIVE';
366: break;
367: case \Aurora\Modules\Calendar\Enums\AttendeeStatus::Unknown:
368: $sStatus = 'NEEDS-ACTION';
369: break;
370: }
371:
372: $aAttendeeEmails[strtolower($aItem['email'])] = $sStatus;
373: }
374:
375: $aObjAttendees = $oVEvent->ATTENDEE;
376: unset($oVEvent->ATTENDEE);
377: foreach ($aObjAttendees as $oAttendee) {
378: $sAttendee = str_replace('mailto:', '', strtolower((string)$oAttendee));
379: $oPartstat = $oAttendee->offsetGet('PARTSTAT');
380: if (in_array($sAttendee, array_keys($aAttendeeEmails))) {
381: if (isset($oPartstat) && (string)$oPartstat === $aAttendeeEmails[$sAttendee]) {
382: $oVEvent->add($oAttendee);
383: $aAttendees[] = $sAttendee;
384: }
385: }
386: }
387: }
388:
389: if (isset($oEvent->Attendees) && count($oEvent->Attendees) > 0) {
390: if (!isset($oVEvent->ORGANIZER)) {
391: $oVEvent->ORGANIZER = 'mailto:' . $oUser->PublicId;
392: }
393: foreach ($oEvent->Attendees as $oAttendee) {
394: if (!in_array($oAttendee['email'], $aAttendees)) {
395: $oVEvent->add(
396: 'ATTENDEE',
397: 'mailto:' . $oAttendee['email'],
398: array(
399: 'CN' => !empty($oAttendee['name']) ? $oAttendee['name'] : $oAttendee['email'],
400: 'RSVP' => 'TRUE'
401: )
402: );
403: }
404: }
405: } else {
406: unset($oVEvent->ORGANIZER);
407: }
408: }
409:
410: public function onDeleteEvent($aData, &$oVCal)
411: {
412: $sUserPublicId = $aData['sUserPublicId'];
413: /** @var \Sabre\VObject\Component\VCalendar $oVCal */
414: $iIndex = CalendarHelper::getBaseVComponentIndex($oVCal->VEVENT);
415: if ($iIndex !== false) {
416: /** @var \Sabre\VObject\Component\VEvent $oVEvent */
417: $oVEvent = $oVCal->VEVENT[$iIndex];
418:
419: $sOrganizer = (isset($oVEvent->ORGANIZER)) ?
420: str_replace('mailto:', '', strtolower((string)$oVEvent->ORGANIZER)) : null;
421: $iPos = false;
422: if (!empty($sOrganizer)) {
423: $iPos = strpos($sOrganizer, 'principals/');
424: }
425:
426: if ($iPos !== false) {
427: $sOrganizer = \trim(substr($sOrganizer, $iPos + 11), '/');
428: }
429:
430: if (isset($sOrganizer)) {
431: if ($sOrganizer === $sUserPublicId) {
432: $oDateTimeNow = new \DateTimeImmutable("now");
433: /** @var \Sabre\VObject\Property\ICalendar\DateTime $oDTSTART */
434: $oDTSTART = $oVEvent->DTSTART;
435: $oDateTimeEvent = $oDTSTART->getDateTime();
436: $oDateTimeRepeat = CalendarHelper::getNextRepeat($oDateTimeNow, $oVEvent);
437: $bRrule = isset($oVEvent->RRULE);
438: $bEventFore = $oDateTimeEvent ? $oDateTimeEvent > $oDateTimeNow : false;
439: $bNextRepeatFore = $oDateTimeRepeat ? $oDateTimeRepeat > $oDateTimeNow : false;
440:
441: if (isset($oVEvent->ATTENDEE) && ($bRrule ? $bNextRepeatFore : $bEventFore)) {
442: foreach ($oVEvent->ATTENDEE as $oAttendee) {
443: $sEmail = str_replace('mailto:', '', strtolower((string)$oAttendee));
444:
445: $oVCalResult = clone $oVCal;
446: $oVCalResult->METHOD = 'CANCEL';
447: $sSubject = (string)$oVEvent->SUMMARY . ': Canceled';
448:
449: Classes\Helper::sendAppointmentMessage($sUserPublicId, $sEmail, $sSubject, $oVCalResult, 'REQUEST');
450: unset($oVCal->METHOD);
451: }
452: }
453: }
454: }
455: }
456: }
457:
458: public function onUpdateEventAttendees($aData, &$oEvent)
459: {
460: $aEventData = $this->getManager()->getEvent($aData['UserPublicId'], $oEvent->IdCalendar, $oEvent->Id);
461: if (isset($aEventData[0]) && isset($aEventData[0]['attendees'])) {
462: $oldAttendees = $aEventData[0]['attendees'];
463: $newAttendees = @json_decode($aData['attendees'], true);
464:
465: $deleteAttendees = [];
466: foreach ($oldAttendees as $old) {
467: $found = false;
468: foreach ($newAttendees as $new) {
469: if (strtolower($new['email']) === strtolower($old['email'])) {
470: $found = true;
471: break;
472: }
473: }
474: if (!$found) {
475: $deleteAttendees[] = $old;
476: }
477: }
478:
479: $oVCalResult = clone $aEventData['vcal'];
480: $oVCalResult->METHOD = 'CANCEL';
481: if (isset($oVCalResult->VEVENT)) {
482: $sSubject = (string) $oVCalResult->VEVENT->SUMMARY . ': Canceled';
483: $oVCalResult->VEVENT->SEQUENCE = (int) $oVCalResult->VEVENT->SEQUENCE->getValue() + 1;
484:
485: foreach ($deleteAttendees as $deleteAttendee) {
486: $sEmail = $deleteAttendee['email'];
487:
488: unset($oVCalResult->VEVENT->ATTENDEE);
489:
490: $oVCalResult->VEVENT->add(
491: 'ATTENDEE',
492: 'mailto:' . $deleteAttendee['email'],
493: array(
494: 'CN' => !empty($deleteAttendee['name']) ? $deleteAttendee['name'] : $deleteAttendee['email'],
495: 'PARTSTAT' => 'DECLINED'
496: )
497: );
498:
499: Classes\Helper::sendAppointmentMessage($aData['UserPublicId'], $sEmail, $sSubject, $oVCalResult, 'REQUEST');
500: }
501: }
502: }
503: $oEvent->Attendees = @json_decode($aData['attendees'], true);
504: }
505:
506: public function onProcessICSUpdateEvent(&$aData, &$mResult)
507: {
508: $oVCalResult = $aData['oVCalResult'];
509: $oVEventResult = $aData['oVEventResult'];
510: $sUserPublicId = $aData['sUserPublicId'];
511: $sCalendarId = $aData['sCalendarId'];
512: $sEventId = $aData['sEventId'];
513: $sMethod = $aData['sMethod'];
514: $sequence = $aData['sequence'];
515: $sequenceServer = $aData['sequenceServer'];
516: /** @var \Sabre\VObject\Component\VEvent $oVEvent */
517: $oVEvent = $aData['oVEvent'];
518: $mFromEmail = $aData['mFromEmail'];
519:
520: $sType = $sMethod;
521: $oCurrentAttendee = null;
522: if (isset($oVEvent->ATTENDEE) && $sequenceServer >= $sequence) {
523: foreach ($oVEvent->ATTENDEE as $oAttendee) {
524: if ($mFromEmail && $mFromEmail === str_replace('mailto:', '', strtolower((string) $oAttendee->getValue()))) {
525: $oCurrentAttendee = $oAttendee;
526: break;
527: }
528: }
529: if (isset($oVEventResult->ATTENDEE, $oCurrentAttendee)) {
530: foreach ($oVEventResult->ATTENDEE as &$oAttendeeResult) {
531: if ($oAttendeeResult->getValue() === $oCurrentAttendee->getValue()) {
532: if (isset($oCurrentAttendee['PARTSTAT'])) {
533: $oAttendeeResult['PARTSTAT'] = $oCurrentAttendee['PARTSTAT']->getValue();
534: $sType = $sType . '-' . (string) $oAttendeeResult['PARTSTAT'];
535: /** @var \Sabre\VObject\Property\ICalendar\DateTime $oLAST_MODIFIED */
536: $oLAST_MODIFIED = $oVEvent->{'LAST-MODIFIED'};
537:
538: $oRespondedAt = $oLAST_MODIFIED->getDateTime();
539: $oRespondedAt->setTimezone(new \DateTimeZone('UTC'));
540: $oAttendeeResult['RESPONDED-AT'] = gmdate("Ymd\THis\Z", $oRespondedAt->getTimestamp());
541: }
542: break;
543: }
544: }
545: }
546: }
547: unset($oVCalResult->METHOD);
548: $oVEventResult->{'LAST-MODIFIED'} = new \DateTime('now', new \DateTimeZone('UTC'));
549: $mResult = $this->getManager()->updateEventRaw($sUserPublicId, $sCalendarId, $sEventId, $oVCalResult->serialize());
550: if ($mResult) {
551: $mResult = $sType;
552: }
553: // $oVCalResult->METHOD = $sMethod;
554: }
555:
556: public function onProcessICSCancel(&$aData, &$mResult)
557: {
558: $sCalendarId = $aData['sCalendarId'];
559: $sUserPublicId = $aData['sUserPublicId'];
560: $sEventId = $aData['sEventId'];
561:
562: if ($this->getManager()->deleteEvent($sUserPublicId, $sCalendarId, $sEventId)) {
563: $mResult = true;
564: }
565: }
566:
567: public function onAddAttendeesToResult(&$aData, &$mResult)
568: {
569: $oVEventResult = $aData['oVEventResult'];
570: $aAccountEmails = $aData['aAccountEmails'];
571: $sMethod = $aData['sMethod'];
572:
573: if (isset($oVEventResult->ATTENDEE)) {
574: foreach ($oVEventResult->ATTENDEE as $oAttendee) {
575: $sAttendee = strtolower((string)$oAttendee);
576: if (in_array($sAttendee, $aAccountEmails) && isset($oAttendee['PARTSTAT']) && $sMethod !== 'SAVE') {
577: $mResult['Attendee'] = str_replace('mailto:', '', $sAttendee);
578: $mResult['Action'] = $sMethod . '-' . $oAttendee['PARTSTAT']->getValue();
579: }
580: }
581: }
582: }
583:
584: public function onParseEvent(&$aData, &$aEvent)
585: {
586: $oVComponent = $aData['oVComponent'];
587: $sOwnerEmail = $aData['sOwnerEmail'];
588: $oUser = $aData['oUser'];
589:
590: $bIsAppointment = false;
591: $aEvent['attendees'] = array();
592: if (isset($oVComponent->ATTENDEE)) {
593: $aEvent['attendees'] = \Aurora\Modules\Calendar\Classes\Parser::parseAttendees($oVComponent);
594:
595: if (isset($oVComponent->ORGANIZER)) {
596: $sOwnerEmail = str_replace('mailto:', '', strtolower((string)$oVComponent->ORGANIZER));
597: $iPos = strpos($sOwnerEmail, 'principals/');
598: if ($iPos !== false) {
599: $sOwnerEmail = \trim(substr($sOwnerEmail, $iPos + 11), '/');
600: }
601: $aData['sOwnerEmail'] = $sOwnerEmail;
602: $aEvent['organizer'] = $sOwnerEmail;
603: $aEvent['organizerName'] = isset($oVComponent->ORGANIZER['CN']) ? (string)$oVComponent->ORGANIZER['CN'] : '';
604: }
605: $bIsAppointment = ($oUser instanceof \Aurora\Modules\Core\Models\User && $sOwnerEmail !== $oUser->PublicId);
606: }
607:
608: $aEvent['appointment'] = $bIsAppointment;
609: $aEvent['appointmentAccess'] = 0;
610: }
611: }
612: