1: <?php
2: /**
3: * This code is licensed under Afterlogic Software License.
4: * For full statements of the license see LICENSE file.
5: */
6:
7: namespace Aurora\Modules\Calendar;
8:
9: use Aurora\System\Exceptions\ApiException;
10:
11: /**
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\AbstractLicensedModule
18: {
19: public $oManager = null;
20: public $oFilecacheManager = null;
21: protected $oUserForDelete = null;
22:
23: /**
24: *
25: * @return Module
26: */
27: public static function getInstance()
28: {
29: return \Aurora\System\Api::GetModule(self::GetName());
30: }
31:
32: public function getManager()
33: {
34: if ($this->oManager === null) {
35: $this->oManager = new Manager($this);
36: }
37:
38: return $this->oManager;
39: }
40:
41: public function getFilecacheManager()
42: {
43: if ($this->oFilecacheManager === null) {
44: $this->oFilecacheManager = new \Aurora\System\Managers\Filecache();
45: }
46:
47: return $this->oFilecacheManager;
48: }
49:
50: public function init()
51: {
52: $this->aErrors = [
53: Enums\ErrorCodes::CannotFindCalendar => $this->i18N('ERROR_NO_CALENDAR'),
54: Enums\ErrorCodes::InvalidSubscribedIcs => $this->i18N('ERROR_INVALID_SUBSCRIBED_ICS')
55: ];
56:
57: $this->AddEntries(
58: array(
59: 'calendar-pub' => 'EntryCalendarPub',
60: 'calendar-download' => 'EntryCalendarDownload'
61: )
62: );
63:
64: $this->subscribeEvent('Mail::GetBodyStructureParts', array($this, 'onGetBodyStructureParts'));
65: $this->subscribeEvent('MobileSync::GetInfo', array($this, 'onGetMobileSyncInfo'));
66: $this->subscribeEvent('Mail::ExtendMessageData', array($this, 'onExtendMessageData'));
67: $this->subscribeEvent('Core::DeleteUser::before', array($this, 'onBeforeDeleteUser'));
68: $this->subscribeEvent('Core::DeleteUser::after', array($this, 'onAftereDeleteUser'));
69: }
70:
71: /**
72: * Obtains list of module settings for authenticated user.
73: *
74: * @return array
75: */
76: public function GetSettings()
77: {
78: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
79:
80: $aSettings = array(
81: 'AddDescriptionToTitle' => $this->getConfig('AddDescriptionToTitle', false),
82: 'AllowTasks' => $this->getConfig('AllowTasks', true),
83: 'DefaultTab' => $this->getConfig('DefaultTab', 3),
84: 'HighlightWorkingDays' => $this->getConfig('HighlightWorkingDays', true),
85: 'HighlightWorkingHours' => $this->getConfig('HighlightWorkingHours', true),
86: 'PublicCalendarId' => $this->oHttp->GetQuery('calendar-pub', ''),
87: 'WeekStartsOn' => $this->getConfig('WeekStartsOn', 0),
88: 'WorkdayEnds' => $this->getConfig('WorkdayEnds', 18),
89: 'WorkdayStarts' => $this->getConfig('WorkdayStarts', 9),
90: 'AllowSubscribedCalendars' => $this->getConfig('AllowSubscribedCalendars', false),
91: 'AllowPrivateEvents' => $this->getConfig('AllowPrivateEvents', true),
92: 'AllowDefaultReminders' => $this->getConfig('AllowDefaultReminders', true),
93: 'DefaultReminders' => $this->getConfig('DefaultReminders', []),
94: );
95:
96: $oUser = \Aurora\System\Api::getAuthenticatedUser();
97: if ($oUser && $oUser->isNormalOrTenant()) {
98: if (isset($oUser->{self::GetName().'::HighlightWorkingDays'})) {
99: $aSettings['HighlightWorkingDays'] = $oUser->{self::GetName().'::HighlightWorkingDays'};
100: }
101: if (isset($oUser->{self::GetName().'::HighlightWorkingHours'})) {
102: $aSettings['HighlightWorkingHours'] = $oUser->{self::GetName().'::HighlightWorkingHours'};
103: }
104: if (isset($oUser->{self::GetName().'::WorkdayStarts'})) {
105: $aSettings['WorkdayStarts'] = $oUser->{self::GetName().'::WorkdayStarts'};
106: }
107: if (isset($oUser->{self::GetName().'::WorkdayEnds'})) {
108: $aSettings['WorkdayEnds'] = $oUser->{self::GetName().'::WorkdayEnds'};
109: }
110: if (isset($oUser->{self::GetName().'::WeekStartsOn'})) {
111: $aSettings['WeekStartsOn'] = $oUser->{self::GetName().'::WeekStartsOn'};
112: }
113: if (isset($oUser->{self::GetName().'::DefaultTab'})) {
114: $aSettings['DefaultTab'] = $oUser->{self::GetName().'::DefaultTab'};
115: }
116: if (isset($oUser->{self::GetName().'::DefaultReminders'})) {
117: $aSettings['DefaultReminders'] = $oUser->{self::GetName().'::DefaultReminders'};
118: }
119:
120: $oUser->save();
121: }
122:
123: return $aSettings;
124: }
125:
126: public function UpdateSettings($HighlightWorkingDays, $HighlightWorkingHours, $WorkdayStarts, $WorkdayEnds, $WeekStartsOn, $DefaultTab, $DefaultReminders)
127: {
128: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
129:
130: $oUser = \Aurora\System\Api::getAuthenticatedUser();
131: if ($oUser) {
132: if ($oUser->isNormalOrTenant()) {
133: $oCoreDecorator = \Aurora\Modules\Core\Module::Decorator();
134: $oUser->setExtendedProps([
135: self::GetName().'::HighlightWorkingDays' => $HighlightWorkingDays,
136: self::GetName().'::HighlightWorkingHours' => $HighlightWorkingHours,
137: self::GetName().'::WorkdayStarts' => $WorkdayStarts,
138: self::GetName().'::WorkdayEnds' => $WorkdayEnds,
139: self::GetName().'::WeekStartsOn' => $WeekStartsOn,
140: self::GetName().'::DefaultTab' => $DefaultTab,
141: self::GetName().'::DefaultReminders' => $DefaultReminders,
142: ]);
143: return $oCoreDecorator->UpdateUserObject($oUser);
144: }
145: if ($oUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
146: $this->setConfig('HighlightWorkingDays', $HighlightWorkingDays);
147: $this->setConfig('HighlightWorkingHours', $HighlightWorkingHours);
148: $this->setConfig('WorkdayStarts', $WorkdayStarts);
149: $this->setConfig('WorkdayEnds', $WorkdayEnds);
150: $this->setConfig('WeekStartsOn', $WeekStartsOn);
151: $this->setConfig('DefaultTab', $DefaultTab);
152: return $this->saveModuleConfig();
153: }
154: }
155:
156: return false;
157: }
158:
159: /**
160: * Loads calendar.
161: *
162: * @param int $UserId
163: * @param string sCalendarId Calendar ID
164: *
165: * @return \Aurora\Modules\Calendar\Classes\Calendar|false $oCalendar
166: */
167: public function GetCalendar($UserId, $CalendarId)
168: {
169: \Aurora\System\Api::CheckAccess($UserId);
170: $oUser = \Aurora\System\Api::getUserById($UserId);
171:
172: $oCalendar = $this->getManager()->getCalendar($oUser->PublicId, $CalendarId);
173: if ($oCalendar) {
174: // $oCalendar = $this->getManager()->populateCalendarShares($UserId, $oCalendar);
175: }
176: return $oCalendar;
177: }
178:
179: /**
180: *
181: * @param string $CalendarId
182: *
183: * @return \Aurora\Modules\Calendar\Classes\Calendar|false
184: */
185: public function GetPublicCalendar($CalendarId)
186: {
187: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
188: return $this->getManager()->getPublicCalendar($CalendarId);
189: }
190:
191: /**
192: *
193: * @param int $UserId
194: * @param boolean $IsPublic
195: * @param string $PublicCalendarId
196: * @return array|boolean
197: */
198: public function GetCalendars($UserId, $IsPublic = false, $PublicCalendarId = '')
199: {
200: $mResult = false;
201: $mCalendars = false;
202:
203: if ($IsPublic) {
204: $oCalendar = self::Decorator()->GetPublicCalendar($PublicCalendarId);
205: $mCalendars = array($oCalendar);
206: } else {
207: \Aurora\System\Api::CheckAccess($UserId);
208: $oUser = \Aurora\System\Api::getUserById($UserId);
209: if ($oUser) {
210: $mCalendars = $this->getManager()->getCalendars($oUser->PublicId);
211: }
212: }
213:
214: // When $mCalendars is an empty array with condition "if ($mCalendars)" $mResult will be false
215: if (is_array($mCalendars)) {
216: $mResult = array(
217: 'Calendars' => $mCalendars
218: );
219: }
220:
221: return $mResult;
222: }
223:
224: /**
225: *
226: * @return void
227: */
228: public function EntryCalendarDownload()
229: {
230: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
231:
232: $RawKey = \Aurora\System\Router::getItemByIndex(1, '');
233: $aValues = \Aurora\System\Api::DecodeKeyValues($RawKey);
234:
235: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById(\Aurora\System\Api::getAuthenticatedUserId());
236:
237: if (isset($aValues['CalendarId'])) {
238: $sCalendarId = $aValues['CalendarId'];
239: $sOutput = $this->getManager()->exportCalendarToIcs($sUserPublicId, $sCalendarId);
240: if (false !== $sOutput) {
241: header('Pragma: public');
242: header('Content-Type: text/calendar');
243: header('Content-Disposition: attachment; filename="' . $sCalendarId . '.ics";');
244: header('Content-Transfer-Encoding: binary');
245: echo $sOutput;
246: }
247: }
248: }
249:
250: /**
251: *
252: * @param int $UserId
253: * @param string $Name
254: * @param string $Description
255: * @param string $Color
256: * @return array|boolean
257: */
258: public function CreateCalendar($UserId, $Name, $Description, $Color, $UUID = null)
259: {
260: \Aurora\System\Api::CheckAccess($UserId);
261: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
262: $mResult = false;
263:
264: $mCalendarId = $this->getManager()->createCalendar($sUserPublicId, $Name, $Description, 1, $Color, $UUID);
265: if ($mCalendarId) {
266: $oCalendar = $this->getManager()->getCalendar($sUserPublicId, $mCalendarId);
267: if ($oCalendar instanceof \Aurora\Modules\Calendar\Classes\Calendar) {
268: $mResult = $oCalendar->toResponseArray($sUserPublicId);
269: }
270: }
271:
272: return $mResult;
273: }
274:
275: public function CreateSubscribedCalendar($UserId, $Name, $Source, $Color, $UUID = null)
276: {
277: \Aurora\System\Api::CheckAccess($UserId);
278: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
279: $mResult = false;
280:
281: if (!$this->getManager()->validateSubscribedCalebdarSource($Source)) {
282: throw new ApiException(Enums\ErrorCodes::InvalidSubscribedIcs);
283: }
284:
285: $mCalendarId = $this->getManager()->createSubscribedCalendar($sUserPublicId, $Name, $Source, 1, $Color, $UUID);
286: if ($mCalendarId) {
287: $oCalendar = $this->getManager()->getCalendar($sUserPublicId, $mCalendarId);
288: if ($oCalendar instanceof \Aurora\Modules\Calendar\Classes\Calendar) {
289: $mResult = $oCalendar->toResponseArray($sUserPublicId);
290: }
291: }
292:
293: return $mResult;
294: }
295:
296: /**
297: *
298: * @param int $UserId
299: * @param string $Id
300: * @param string $Name
301: * @param string $Description
302: * @param string $Color
303: * @return array|boolean
304: */
305: public function UpdateCalendar($UserId, $Id, $Name, $Description, $Color)
306: {
307: \Aurora\System\Api::CheckAccess($UserId);
308: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
309: return $this->getManager()->updateCalendar($sUserPublicId, $Id, $Name, $Description, 0, $Color);
310: }
311:
312: /**
313: *
314: * @param int $UserId
315: * @param string $Id
316: * @param string $Name
317: * @param string $Description
318: * @param string $Color
319: * @return array|boolean
320: */
321: public function UpdateSubscribedCalendar($UserId, $Id, $Name, $Source, $Color)
322: {
323: \Aurora\System\Api::CheckAccess($UserId);
324: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
325:
326: if (!$this->getManager()->validateSubscribedCalebdarSource($Source)) {
327: throw new ApiException(Enums\ErrorCodes::InvalidSubscribedIcs);
328: }
329:
330: return $this->getManager()->updateSubscribedCalendar($sUserPublicId, $Id, $Name, $Source, 0, $Color);
331: }
332:
333: /**
334: *
335: * @param int $UserId
336: * @param string $Id
337: * @param string $Color
338: * @return array|boolean
339: */
340: public function UpdateCalendarColor($UserId, $Id, $Color)
341: {
342: \Aurora\System\Api::CheckAccess($UserId);
343: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
344: return $this->getManager()->updateCalendarColor($sUserPublicId, $Id, $Color);
345: }
346:
347: /**
348: *
349: * @param int $UserId
350: * @param string $Id
351: * @param boolean $IsPublic
352: * @param string $Shares
353: * @param boolean $ShareToAll
354: * @param int $ShareToAllAccess
355: * @return array|boolean
356: */
357: public function UpdateCalendarShare($UserId, $Id, $IsPublic, $Shares, $ShareToAll = false, $ShareToAllAccess = \Aurora\Modules\Calendar\Enums\Permission::Read)
358: {
359: \Aurora\System\Api::CheckAccess($UserId);
360: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
361: $aShares = json_decode($Shares, true) ;
362: $oUser = null;
363: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
364: if ($oAuthenticatedUser->Id !== $UserId && $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
365: $oUser = \Aurora\System\Api::getUserById($UserId);
366: } else {
367: $oUser = $oAuthenticatedUser;
368: }
369: $oCalendar = $this->getManager()->getCalendar($oUser->PublicId, $Id);
370: if (!$oCalendar) {
371: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
372: }
373: //Calendar can be shared by owner or user with write access except SharedWithAll calendars
374: if ($oCalendar->Owner !== $sUserPublicId
375: && $oCalendar->Access !== \Aurora\Modules\Calendar\Enums\Permission::Write) {
376: return false;
377: }
378: // Share calendar to all users
379: if ($ShareToAll) {
380: $aShares[] = array(
381: 'email' => $this->getManager()->getTenantUser($oUser),
382: 'access' => $ShareToAllAccess
383: );
384: } else {
385: $aShares[] = array(
386: 'email' => $this->getManager()->getTenantUser($oUser),
387: 'access' => \Aurora\Modules\Calendar\Enums\Permission::RemovePermission
388: );
389: }
390:
391: return $this->getManager()->updateCalendarShares($sUserPublicId, $Id, $aShares);
392: }
393:
394: /**
395: *
396: * @param string $Id User publicId
397: * @param boolean $IsPublic
398: * @param int $UserId
399: * @return array|boolean
400: */
401: public function UpdateCalendarPublic($Id, $IsPublic, $UserId = null)
402: {
403: \Aurora\System\Api::CheckAccess($UserId);
404: $oUser = null;
405: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
406: if ($oAuthenticatedUser->PublicId !== $Id && $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
407: $oUser = \Aurora\System\Api::getUserById($UserId);
408: }
409: return $this->getManager()->publicCalendar($Id, $IsPublic, $oUser);
410: }
411:
412: /**
413: *
414: * @param int $UserId
415: * @param string $Id
416: * @return array|boolean
417: */
418: public function DeleteCalendar($UserId, $Id)
419: {
420: \Aurora\System\Api::CheckAccess($UserId);
421: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
422: return $this->getManager()->deleteCalendar($sUserPublicId, $Id);
423: }
424:
425: /**
426: *
427: * @param int $UserId
428: * @param string $calendarId
429: * @param string $uid
430: * @return array|boolean
431: */
432: public function GetBaseEvent($UserId, $calendarId, $uid)
433: {
434: \Aurora\System\Api::CheckAccess($UserId);
435: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
436: return $this->getManager()->getBaseEvent($sUserPublicId, $calendarId, $uid);
437: }
438:
439: /**
440: *
441: * @param int $UserId
442: * @param array $CalendarIds
443: * @param int $Start
444: * @param int $End
445: * @param boolean $IsPublic
446: * @param boolean $Expand
447: * @return array|boolean
448: */
449: public function GetEvents($UserId, $CalendarIds, $Start, $End, $IsPublic, $Expand = true, $DefaultTimeZone = null)
450: {
451: $mResult = false;
452: if ($IsPublic) {
453: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
454: $mResult = $this->getManager()->getPublicEvents($CalendarIds, $Start, $End, $Expand, $DefaultTimeZone);
455: } else {
456: \Aurora\System\Api::CheckAccess($UserId);
457: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
458: $mResult = $this->getManager()->getEvents($sUserPublicId, $CalendarIds, $Start, $End);
459: }
460:
461: $aResult = [];
462: if (is_array($mResult)) {
463: foreach ($mResult as $event) {
464: $sDescription = $event['description'];
465: $bHtmlDescription = $sDescription != strip_tags($sDescription);
466: if ($bHtmlDescription) {
467: $event['description'] = $this->clearHtml($sDescription);
468: } else {
469: $event['description'] = \MailSo\Base\HtmlUtils::ConvertPlainToHtml($sDescription);
470: }
471:
472: $sLocation = $event['location'];
473: $bHtmlLocation = $sLocation != strip_tags($sLocation);
474: if ($bHtmlLocation) {
475: $event['location'] = $this->clearHtml($sLocation);
476: }
477: $aResult[] = $event;
478: }
479: }
480:
481: return $aResult;
482: }
483:
484: /**
485: *
486: * @param int $UserId
487: * @param array $CalendarIds
488: * @param int $Start
489: * @param int $End
490: * @param boolean $IsPublic
491: * @param boolean $Expand
492: * @return array|boolean
493: */
494: public function GetTasks($UserId, $CalendarIds, $Completed = true, $Search = '', $Start = null, $End = null, $Expand = true)
495: {
496: $mResult = [];
497: if ($this->getConfig('AllowTasks', true)) {
498: \Aurora\System\Api::CheckAccess($UserId);
499: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
500:
501: $mResult = $this->getManager()->getTasks($sUserPublicId, $CalendarIds, $Completed, $Search, $Start, $End, $Expand);
502: }
503:
504: return $mResult;
505: }
506:
507: private function _checkUserCalendar($sUserPublicId, $sCalendarId)
508: {
509: $oCalendar = $this->getManager()->getCalendar($sUserPublicId, $sCalendarId);
510: if (!$oCalendar) {
511: throw new \Aurora\Modules\Calendar\Exceptions\Exception(Enums\ErrorCodes::CannotFindCalendar);
512: } elseif ($oCalendar->Access === \Aurora\Modules\Calendar\Enums\Permission::Read) {
513: throw new \Aurora\Modules\Calendar\Exceptions\Exception(Enums\ErrorCodes::NoWriteAccessForCalendar);
514: }
515: }
516:
517: private function clearHtml($sText)
518: {
519: $oDom = \MailSo\Base\HtmlUtils::GetDomFromText($sText);
520: $aNodes = $oDom->getElementsByTagName('*');
521:
522: $bHasExternals = false;
523: $aFoundCIDs = [];
524: $aContentLocationUrls = [];
525: $aFoundedContentLocationUrls = [];
526:
527: foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement) {
528: $sTagNameLower = \strtolower($oElement->tagName);
529: if ('img' === $sTagNameLower) {
530: $oElement->parentNode->removeChild($oElement);
531: }
532:
533: $sBackground = $oElement->hasAttribute('background') ? \trim($oElement->getAttribute('background')) : '';
534: $sBackgroundColor = $oElement->hasAttribute('bgcolor') ? \trim($oElement->getAttribute('bgcolor')) : '';
535:
536: if (!empty($sBackground) || !empty($sBackgroundColor)) {
537: if (!empty($sBackground)) {
538: $oElement->removeAttribute('background');
539: }
540:
541: if (!empty($sBackgroundColor)) {
542: $oElement->removeAttribute('bgcolor');
543: }
544: }
545:
546: if ($oElement->hasAttribute('style')) {
547: $oElement->setAttribute(
548: 'style',
549: \MailSo\Base\HtmlUtils::ClearStyle(
550: $oElement->getAttribute('style'),
551: $oElement,
552: $bHasExternals,
553: $aFoundCIDs,
554: $aContentLocationUrls,
555: $aFoundedContentLocationUrls
556: )
557: );
558: }
559: }
560: $sText = $oDom->saveHTML();
561: unset($oDom);
562:
563: $sText = \MailSo\Base\HtmlUtils::ClearTags($sText);
564: $sText = \MailSo\Base\HtmlUtils::ClearBodyAndHtmlTag($sText);
565: $sText = \MailSo\Base\HtmlUtils::ClearOn($sText);
566:
567: return $sText;
568: }
569:
570: /**
571: *
572: * @param int $UserId
573: * @param string $newCalendarId
574: * @param string $subject
575: * @param string $description
576: * @param string $location
577: * @param int $startTS
578: * @param int $endTS
579: * @param boolean $allDay
580: * @param string $alarms
581: * @param string $attendees
582: * @param string $rrule
583: * @param int $selectStart
584: * @param int $selectEnd
585: * @return array|boolean
586: */
587: public function CreateEvent(
588: $UserId,
589: $newCalendarId,
590: $subject,
591: $description,
592: $location,
593: $startTS,
594: $endTS,
595: $allDay,
596: $alarms,
597: $attendees,
598: $rrule,
599: $selectStart,
600: $selectEnd,
601: $type = 'VEVENT',
602: $status = false,
603: $withDate = true,
604: $owner = '',
605: $isPrivate = false
606: ) {
607: \Aurora\System\Api::CheckAccess($UserId);
608: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
609:
610: $this->_checkUserCalendar($sUserPublicId, $newCalendarId);
611:
612: $oEvent = new \Aurora\Modules\Calendar\Classes\Event();
613: $oEvent->IdCalendar = $newCalendarId;
614: $oEvent->Name = $subject;
615: $oEvent->Description = $this->clearHtml($description);
616: $oEvent->Location = $this->clearHtml($location);
617: $oEvent->IsPrivate = $isPrivate;
618: if ($withDate) {
619: $oEvent->Start = $startTS;
620: $oEvent->End = $endTS;
621: $oEvent->AllDay = $allDay;
622: $oEvent->Alarms = @json_decode($alarms, true);
623: $aRRule = isset($rrule) ? @json_decode($rrule, true) : false;
624: if ($aRRule) {
625: $oUser = \Aurora\System\Api::getAuthenticatedUser();
626: $oRRule = new \Aurora\Modules\Calendar\Classes\RRule($oUser->DefaultTimeZone);
627: $oRRule->Populate($aRRule);
628: $oEvent->RRule = $oRRule;
629: }
630: }
631: $oEvent->Attendees = [];
632: $oEvent->Type = $type;
633: $oEvent->Status = $status && $type === 'VTODO';
634: if ($type === 'VTODO') {
635: $attendees = json_encode([]);
636: }
637: $aArgs = [
638: 'attendees' => $attendees,
639: 'owner' => $owner,
640: 'UserPublicId' => $sUserPublicId
641: ];
642: $this->broadcastEvent(
643: 'UpdateEventAttendees',
644: $aArgs,
645: $oEvent
646: );
647:
648: $mResult = $this->getManager()->createEvent($sUserPublicId, $oEvent);
649:
650: if ($mResult) {
651: $aArgs = ['Event' => $oEvent];
652: $this->broadcastEvent(
653: 'CreateEvent',
654: $aArgs
655: );
656: $mResult = $this->getManager()->getExpandedEvent($sUserPublicId, $oEvent->IdCalendar, $mResult, $selectStart, $selectEnd);
657: }
658:
659: return $mResult;
660: }
661:
662: /**
663: *
664: * @param type $UserId
665: * @param type $CalendarId
666: * @param type $EventId
667: * @param type $Data
668: * @return type
669: */
670: public function CreateEventFromData($UserId, $CalendarId, $EventId, $Data)
671: {
672: \Aurora\System\Api::CheckAccess($UserId);
673: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
674:
675: $this->_checkUserCalendar($sUserPublicId, $CalendarId);
676:
677: return $this->getManager()->createEventFromRaw($sUserPublicId, $CalendarId, $EventId, $Data);
678: }
679:
680: /**
681: *
682: * @param int $UserId
683: * @param string $CalendarId
684: * @param string $Subject
685: * @return array|boolean
686: */
687: public function CreateTask($UserId, $CalendarId, $Subject)
688: {
689: $mResult = false;
690: if ($this->getConfig('AllowTasks', true)) {
691: \Aurora\System\Api::CheckAccess($UserId);
692: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
693:
694: $this->_checkUserCalendar($sUserPublicId, $CalendarId);
695:
696: $oEvent = new \Aurora\Modules\Calendar\Classes\Event();
697: $oEvent->IdCalendar = $CalendarId;
698: $oEvent->Name = $Subject;
699: $oEvent->Start = \time();
700: $oEvent->End = \time();
701: $oEvent->Type = 'VTODO';
702:
703: $mResult = $this->getManager()->createEvent($sUserPublicId, $oEvent);
704: }
705:
706: return $mResult;
707: }
708:
709: /**
710: *
711: * @param int $UserId
712: * @param string $CalendarId
713: * @param string $Subject
714: * @param string $Sescription
715: * @return array|boolean
716: */
717: public function UpdateTask($UserId, $CalendarId, $TaskId, $Subject, $Status, $WithDate = false)
718: {
719: $bResult = false;
720: if ($this->getConfig('AllowTasks', true)) {
721: \Aurora\System\Api::CheckAccess($UserId);
722: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
723:
724: $this->_checkUserCalendar($sUserPublicId, $CalendarId);
725:
726: $oEvent = new \Aurora\Modules\Calendar\Classes\Event();
727: $oEvent->IdCalendar = $CalendarId;
728: $oEvent->Id = $TaskId;
729: $oEvent->Name = $Subject;
730: $oEvent->Type = 'VTODO';
731: $oEvent->Status = $Status ? 'COMPLETED' : '';
732:
733: if ($WithDate) {
734: $aEvent = $this->GetBaseEvent($UserId, $CalendarId, $TaskId);
735: if ($aEvent) {
736: $oEvent->Start = $aEvent['startTS'];
737: $oEvent->End = $aEvent['endTS'];
738: }
739: }
740:
741: if ($this->getManager()->updateEvent($sUserPublicId, $oEvent)) {
742: return $this->GetBaseEvent($UserId, $CalendarId, $TaskId);
743: }
744: }
745:
746: return $bResult;
747: }
748:
749:
750: /**
751: *
752: * @param int $UserId
753: * @param string $newCalendarId
754: * @param string $calendarId
755: * @param string $uid
756: * @param string $subject
757: * @param string $description
758: * @param string $location
759: * @param int $startTS
760: * @param int $endTS
761: * @param boolean $allDay
762: * @param string $alarms
763: * @param string $attendees
764: * @param string $rrule
765: * @param int $allEvents
766: * @param string $recurrenceId
767: * @param int $selectStart
768: * @param int $selectEnd
769: * @return array|boolean
770: */
771: public function UpdateEvent(
772: $UserId,
773: $newCalendarId,
774: $calendarId,
775: $uid,
776: $subject,
777: $description,
778: $location,
779: $startTS,
780: $endTS,
781: $allDay,
782: $alarms,
783: $attendees,
784: $rrule,
785: $allEvents,
786: $recurrenceId,
787: $selectStart,
788: $selectEnd,
789: $type = 'VEVENT',
790: $status = false,
791: $withDate = true,
792: $isPrivate = false,
793: $owner = ''
794: ) {
795: \Aurora\System\Api::CheckAccess($UserId);
796: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
797: $mResult = false;
798:
799: $this->_checkUserCalendar($sUserPublicId, $calendarId);
800: if ($calendarId !== $newCalendarId) {
801: $this->_checkUserCalendar($sUserPublicId, $newCalendarId);
802: }
803:
804: $oEvent = new \Aurora\Modules\Calendar\Classes\Event();
805: $oEvent->IdCalendar = $calendarId;
806: $oEvent->Id = $uid;
807: $oEvent->Name = $subject;
808: $oEvent->Description = $this->clearHtml($description);
809: $oEvent->Location = $this->clearHtml($location);
810: $oEvent->IsPrivate = $isPrivate;
811: if ($withDate) {
812: $oEvent->Start = $startTS;
813: $oEvent->End = $endTS;
814: $oEvent->AllDay = $allDay;
815: $oEvent->Alarms = @json_decode($alarms, true);
816: $aRRule = @json_decode($rrule, true);
817: if ($aRRule) {
818: $oUser = \Aurora\System\Api::getAuthenticatedUser();
819: $oRRule = new \Aurora\Modules\Calendar\Classes\RRule($oUser->DefaultTimeZone);
820: $oRRule->Populate($aRRule);
821: $oEvent->RRule = $oRRule;
822: }
823: }
824: $oEvent->Attendees = [];
825: $oEvent->Type = $type;
826: if ($type === 'VTODO') {
827: $attendees = json_encode([]);
828: }
829: $aArgs = [
830: 'attendees' => $attendees,
831: 'owner' => $owner,
832: 'UserPublicId' => $sUserPublicId
833: ];
834: $this->broadcastEvent(
835: 'UpdateEventAttendees',
836: $aArgs,
837: $oEvent
838: );
839: if (!empty($status)) {
840: $oEvent->Status = $status && $type === 'VTODO';
841: }
842:
843: if ($allEvents === 1) {
844: $mResult = $this->getManager()->updateExclusion($sUserPublicId, $oEvent, $recurrenceId);
845: } else {
846: $mResult = $this->getManager()->updateEvent($sUserPublicId, $oEvent);
847: if ($mResult && $newCalendarId !== $oEvent->IdCalendar) {
848: $mResult = $this->getManager()->moveEvent($sUserPublicId, $oEvent->IdCalendar, $newCalendarId, $oEvent->Id);
849: $oEvent->IdCalendar = $newCalendarId;
850: }
851: }
852: if ($mResult) {
853: $aArgs = ['Event' => $oEvent];
854: $this->broadcastEvent(
855: 'CreateEvent',
856: $aArgs
857: );
858: $mResult = $this->getManager()->getExpandedEvent($sUserPublicId, $oEvent->IdCalendar, $oEvent->Id, $selectStart, $selectEnd);
859: }
860:
861: return $mResult;
862: }
863:
864: /**
865: *
866: * @param int $UserId
867: * @param string $calendarId
868: * @param string $uid
869: * @param boolean $allEvents
870: * @param string $recurrenceId
871: * @return array|boolean
872: */
873: public function DeleteEvent($UserId, $calendarId, $uid, $allEvents, $recurrenceId)
874: {
875: \Aurora\System\Api::CheckAccess($UserId);
876: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
877:
878: $this->_checkUserCalendar($sUserPublicId, $calendarId);
879:
880: $mResult = false;
881: if ($sUserPublicId) {
882: if ($allEvents === 1) {
883: $oEvent = new \Aurora\Modules\Calendar\Classes\Event();
884: $oEvent->IdCalendar = $calendarId;
885: $oEvent->Id = $uid;
886: $mResult = $this->getManager()->updateExclusion($sUserPublicId, $oEvent, $recurrenceId, true);
887: } else {
888: $mResult = $this->getManager()->deleteEvent($sUserPublicId, $calendarId, $uid);
889: }
890: }
891:
892: return $mResult;
893: }
894:
895: /**
896: *
897: * @param int $UserId
898: * @param string $CalendarId
899: * @param string $File
900: * @return array|boolean
901: * @throws \Aurora\System\Exceptions\ApiException
902: */
903: public function AddEventsFromFile($UserId, $CalendarId, $File)
904: {
905: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
906: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
907: $mResult = false;
908:
909: $this->_checkUserCalendar($sUserPublicId, $CalendarId);
910:
911: if (empty($CalendarId) || empty($File)) {
912: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
913: }
914:
915: $sData = $this->getFilecacheManager()->get($sUserPublicId, $File, '', self::GetName());
916: if (!empty($sData)) {
917: $mResult = $this->getManager()->createEventFromRaw($sUserPublicId, $CalendarId, null, $sData);
918: }
919:
920: return $mResult;
921: }
922:
923: public function EntryCalendarPub()
924: {
925: $sResult = '';
926:
927: $oApiIntegrator = \Aurora\System\Managers\Integrator::getInstance();
928:
929: if ($oApiIntegrator) {
930: \Aurora\Modules\CoreWebclient\Module::Decorator()->SetHtmlOutputHeaders();
931:
932: if (!strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'firefox')) {
933: @\header('Last-Modified: '.\gmdate('D, d M Y H:i:s').' GMT');
934: }
935:
936: $oSettings =& \Aurora\System\Api::GetSettings();
937: if (($oSettings->GetValue('CacheCtrl', true) && isset($_COOKIE['aft-cache-ctrl']))) {
938: @\setcookie(
939: 'aft-cache-ctrl',
940: '',
941: \strtotime('-1 hour'),
942: \Aurora\System\Api::getCookiePath(),
943: null,
944: \Aurora\System\Api::getCookieSecure()
945: );
946: \MailSo\Base\Http::NewInstance()->StatusHeader(304);
947: exit();
948: }
949: $oCoreClientModule = \Aurora\System\Api::GetModule('CoreWebclient');
950: if ($oCoreClientModule instanceof \Aurora\System\Module\AbstractModule) {
951: $sResult = file_get_contents($oCoreClientModule->GetPath().'/templates/Index.html');
952: if (is_string($sResult)) {
953: $sFrameOptions = $oSettings->GetValue('XFrameOptions', '');
954: if (0 < \strlen($sFrameOptions)) {
955: @\header('X-Frame-Options: '.$sFrameOptions);
956: }
957:
958: $sAuthToken = isset($_COOKIE[\Aurora\System\Application::AUTH_TOKEN_KEY]) ? $_COOKIE[\Aurora\System\Application::AUTH_TOKEN_KEY] : '';
959: $sResult = strtr($sResult, array(
960: '{{AppVersion}}' => AU_APP_VERSION,
961: '{{IntegratorDir}}' => $oApiIntegrator->isRtl() ? 'rtl' : 'ltr',
962: '{{IntegratorLinks}}' => $oApiIntegrator->buildHeadersLink(),
963: '{{IntegratorBody}}' => $oApiIntegrator->buildBody(
964: array(
965: 'public_app' => true,
966: 'modules_list' => $oApiIntegrator->GetModulesForEntry('CalendarWebclient')
967: )
968: )
969: ));
970: }
971: }
972: }
973: return $sResult;
974: }
975:
976: /**
977: *
978: * @param int $UserId
979: * @param string $Data
980: * @param string $FromEmail
981: * @return boolean
982: */
983: public function ProcessICS($UserId, $Data, $FromEmail)
984: {
985: \Aurora\System\Api::CheckAccess($UserId);
986:
987: return $this->getManager()->processICS($UserId, $Data, $FromEmail);
988: }
989:
990: /**
991: *
992: * @param int $UserId
993: * @param array $UploadData
994: * @param string $AdditionalData
995: * @return array
996: * @throws \Aurora\System\Exceptions\ApiException
997: */
998: public function UploadCalendar($UserId, $UploadData, $CalendarID)
999: {
1000: \Aurora\System\Api::CheckAccess($UserId);
1001: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
1002:
1003: $sCalendarId = isset($CalendarID) ? $CalendarID : '';
1004:
1005: $sError = '';
1006: $aResponse = array(
1007: 'ImportedCount' => 0
1008: );
1009:
1010: if (is_array($UploadData)) {
1011: $bIsIcsExtension = strtolower(pathinfo($UploadData['name'], PATHINFO_EXTENSION)) === 'ics';
1012:
1013: if ($bIsIcsExtension) {
1014: $sSavedName = 'import-post-' . md5($UploadData['name'] . $UploadData['tmp_name']);
1015: if ($this->getFilecacheManager()->moveUploadedFile($sUserPublicId, $sSavedName, $UploadData['tmp_name'], '', self::GetName())) {
1016: $iImportedCount = $this->getManager()->importToCalendarFromIcs(
1017: $sUserPublicId,
1018: $sCalendarId,
1019: $this->getFilecacheManager()->generateFullFilePath($sUserPublicId, $sSavedName, '', self::GetName())
1020: );
1021:
1022: if (false !== $iImportedCount && -1 !== $iImportedCount) {
1023: $aResponse['ImportedCount'] = $iImportedCount;
1024: } else {
1025: $sError = 'unknown';
1026: }
1027:
1028: $this->getFilecacheManager()->clear($sUserPublicId, $sSavedName, '', self::GetName());
1029: } else {
1030: $sError = 'unknown';
1031: }
1032: } else {
1033: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::IncorrectFileExtension);
1034: }
1035: } else {
1036: $sError = 'unknown';
1037: }
1038:
1039: if (0 < strlen($sError)) {
1040: $aResponse['Error'] = $sError;
1041: }
1042:
1043: return $aResponse;
1044: }
1045:
1046: public function onGetBodyStructureParts($aParts, &$aResult)
1047: {
1048: foreach ($aParts as $oPart) {
1049: if ($oPart instanceof \MailSo\Imap\BodyStructure &&
1050: $oPart->ContentType() === 'text/calendar') {
1051: $aResult[] = $oPart;
1052: break;
1053: }
1054: }
1055: }
1056:
1057: public function onExtendMessageData($aData, &$oMessage)
1058: {
1059: $oUser = \Aurora\System\Api::getAuthenticatedUser();
1060: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($oUser->Id);
1061: $sFromEmail = '';
1062: $oFromCollection = $oMessage->getFrom();
1063: if ($oFromCollection && 0 < $oFromCollection->Count()) {
1064: $oFrom =& $oFromCollection->GetByIndex(0);
1065: if ($oFrom) {
1066: $sFromEmail = trim($oFrom->GetEmail());
1067: }
1068: }
1069: foreach ($aData as $aDataItem) {
1070: if ($aDataItem['Part'] instanceof \MailSo\Imap\BodyStructure && $aDataItem['Part']->ContentType() === 'text/calendar') {
1071: $sData = $aDataItem['Data'];
1072: if (!empty($sData)) {
1073: try {
1074: $mResult = $this->getManager()->processICS($sUserPublicId, $sData, $sFromEmail);
1075: } catch (\Exception $oEx) {
1076: $mResult = false;
1077: }
1078: if (is_array($mResult) && !empty($mResult['Action']) && !empty($mResult['Body'])) {
1079: $sTemptFile = md5($sFromEmail . $sData).'.ics';
1080: if ($this->getFilecacheManager()->put($sUserPublicId, $sTemptFile, $sData, '', self::GetName())) {
1081: $oIcs = \Aurora\Modules\Calendar\Classes\Ics::createInstance();
1082:
1083: $oIcs->Uid = $mResult['UID'];
1084: $oIcs->Sequence = $mResult['Sequence'];
1085: $oIcs->File = $sTemptFile;
1086: $oIcs->Type = 'SAVE';
1087: $oIcs->Attendee = null;
1088: $oIcs->Location = !empty($mResult['Location']) ? $mResult['Location'] : '';
1089: $oIcs->Description = !empty($mResult['Description']) ? $mResult['Description'] : '';
1090: $oIcs->Summary = !empty($mResult['Summary']) ? $mResult['Summary'] : '';
1091: $oIcs->When = !empty($mResult['When']) ? $mResult['When'] : '';
1092: $oIcs->CalendarId = !empty($mResult['CalendarId']) ? $mResult['CalendarId'] : '';
1093: $oIcs->AttendeeList = $mResult['AttendeeList'];
1094: $oIcs->Organizer = $mResult['Organizer'];
1095:
1096: $this->broadcastEvent(
1097: 'CreateIcs',
1098: $mResult,
1099: $oIcs
1100: );
1101:
1102: $oMessage->addExtend('ICAL', $oIcs);
1103: } else {
1104: \Aurora\System\Api::Log('Can\'t save temp file "'.$sTemptFile.'"', \Aurora\System\Enums\LogLevel::Error);
1105: }
1106: }
1107: }
1108: }
1109: }
1110: }
1111:
1112: public function onGetMobileSyncInfo($aArgs, &$mResult)
1113: {
1114: $oDavModule = \Aurora\Modules\Dav\Module::Decorator();
1115: $iUserId = \Aurora\System\Api::getAuthenticatedUserId();
1116: $aCalendars = self::Decorator()->GetCalendars($iUserId);
1117:
1118: if (isset($aCalendars['Calendars']) && is_array($aCalendars['Calendars']) && 0 < count($aCalendars['Calendars'])) {
1119: foreach ($aCalendars['Calendars'] as $oCalendar) {
1120: if ($oCalendar instanceof \Aurora\Modules\Calendar\Classes\Calendar) {
1121: $mResult['Dav']['Calendars'][] = array(
1122: 'Name' => $oCalendar->DisplayName,
1123: 'Url' => rtrim($oDavModule->GetServerUrl().$oCalendar->Url, "/")."/"
1124: );
1125: }
1126: }
1127: }
1128: }
1129:
1130: public function onBeforeDeleteUser($aArgs, &$mResult)
1131: {
1132: if (isset($aArgs['UserId'])) {
1133: $this->oUserForDelete = \Aurora\System\Api::getUserById($aArgs['UserId']);
1134: }
1135: }
1136:
1137: public function onAfterDeleteUser($aArgs, &$mResult)
1138: {
1139: $sUserPublicId = $this->oUserForDelete instanceof \Aurora\Modules\Core\Models\User ? $this->oUserForDelete->PublicId : null;
1140: if ($sUserPublicId) {
1141: $this->getManager()->deletePrincipalCalendars($sUserPublicId);
1142: }
1143: }
1144: }
1145: