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