1: | <?php |
2: | |
3: | |
4: | |
5: | |
6: | |
7: | |
8: | namespace Aurora\Modules\CalendarMeetingsPlugin; |
9: | |
10: | use Aurora\Modules\Core\Models\User; |
11: | use Aurora\Modules\Mail\Models\MailAccount; |
12: | use Aurora\System\Api; |
13: | use Aurora\Modules\Core\Module as CoreModule; |
14: | use Aurora\System\Enums\LogLevel; |
15: | |
16: | |
17: | |
18: | |
19: | |
20: | |
21: | class Manager extends \Aurora\Modules\Calendar\Manager |
22: | { |
23: | |
24: | |
25: | |
26: | |
27: | |
28: | |
29: | |
30: | |
31: | |
32: | |
33: | |
34: | |
35: | |
36: | |
37: | public function updateAppointment($sUserPublicId, $sCalendarId, $sEventId, $sAttendee, $sAction) |
38: | { |
39: | $oResult = null; |
40: | |
41: | $aData = $this->oStorage->getEvent($sUserPublicId, $sCalendarId, $sEventId); |
42: | if ($aData !== false) { |
43: | $oVCal = $aData['vcal']; |
44: | $oVCal->METHOD = 'REQUEST'; |
45: | return $this->appointmentAction($sUserPublicId, $sAttendee, $sAction, $sCalendarId, $oVCal->serialize()); |
46: | } |
47: | |
48: | return $oResult; |
49: | } |
50: | |
51: | |
52: | |
53: | |
54: | |
55: | protected function getMessageSubjectFromPartstat($sPartstat, $sSummary) |
56: | { |
57: | $sSubject = $sSummary; |
58: | switch ($sPartstat) { |
59: | case 'ACCEPTED': |
60: | $sSubject = $this->GetModule()->i18N('SUBJECT_PREFFIX_ACCEPTED') . ': ' . $sSummary; |
61: | break; |
62: | case 'DECLINED': |
63: | $sSubject = $this->GetModule()->i18N('SUBJECT_PREFFIX_DECLINED') . ': ' . $sSummary; |
64: | break; |
65: | case 'TENTATIVE': |
66: | $sSubject = $this->GetModule()->i18N('SUBJECT_PREFFIX_TENTATIVE') . ': ' . $sSummary; |
67: | break; |
68: | } |
69: | |
70: | return $sSubject; |
71: | } |
72: | |
73: | |
74: | |
75: | |
76: | |
77: | protected function getFromAccount($oUser, $sAttendee) |
78: | { |
79: | $oFromAccount = null; |
80: | |
81: | if ($oUser && $oUser->PublicId !== $sAttendee) { |
82: | $oMailModule = Api::GetModule('Mail'); |
83: | |
84: | if ($oMailModule) { |
85: | $aAccounts = $oMailModule->getAccountsManager()->getUserAccounts($oUser->Id); |
86: | foreach ($aAccounts as $oAccount) { |
87: | if ($oAccount instanceof MailAccount && $oAccount->Email === $sAttendee) { |
88: | $oFromAccount = $oAccount; |
89: | break; |
90: | } |
91: | } |
92: | } |
93: | } |
94: | |
95: | return $oFromAccount; |
96: | } |
97: | |
98: | |
99: | |
100: | |
101: | |
102: | |
103: | |
104: | |
105: | |
106: | |
107: | |
108: | |
109: | |
110: | |
111: | |
112: | |
113: | |
114: | public function appointmentAction($sUserPublicId, $sAttendee, $sAction, $sCalendarId, $sData, $AllEvents = 2, $RecurrenceId = null, $bIsLinkAction = false, $bIsExternalAttendee = false) |
115: | { |
116: | $oUser = null; |
117: | $bResult = false; |
118: | $sEventId = null; |
119: | $sTo = $sSubject = ''; |
120: | |
121: | $oUser = CoreModule::Decorator()->GetUserByPublicId($sUserPublicId); |
122: | |
123: | if (!($oUser instanceof User)) { |
124: | throw new Exceptions\Exception( |
125: | Enums\ErrorCodes::CannotSendAppointmentMessage, |
126: | null, |
127: | 'User not found' |
128: | ); |
129: | } |
130: | |
131: | if ($bIsLinkAction && !$bIsExternalAttendee) { |
132: | |
133: | $oCalendar = $this->getDefaultCalendar($oUser->PublicId); |
134: | if ($oCalendar) { |
135: | $sCalendarId = $oCalendar->Id; |
136: | } |
137: | } |
138: | |
139: | |
140: | $oVCal = \Sabre\VObject\Reader::read($sData); |
141: | |
142: | if ($oVCal) { |
143: | $sMethod = strtoupper((string) $oVCal->METHOD); |
144: | $sPartstat = strtoupper($sAction); |
145: | $sCN = ''; |
146: | if ($sAttendee === $oUser->PublicId) { |
147: | $sCN = !empty($oUser->Name) ? $oUser->Name : $sAttendee; |
148: | } |
149: | $bNeedsToUpdateEvent = false; |
150: | |
151: | |
152: | |
153: | $masterEvent = $oVCal->getBaseComponent('VEVENT'); |
154: | |
155: | if (!$masterEvent) { |
156: | |
157: | return false; |
158: | } |
159: | |
160: | $sEventId = (string) $masterEvent->UID; |
161: | if ($AllEvents === 2) { |
162: | if ($sPartstat === 'DECLINED' || $sMethod === 'CANCEL') { |
163: | if ($sCalendarId !== false) { |
164: | $this->deleteEvent($sAttendee, $sCalendarId, $sEventId); |
165: | } |
166: | } else { |
167: | $bNeedsToUpdateEvent = true; |
168: | } |
169: | |
170: | $attendeeFound = false; |
171: | if (isset($masterEvent->ATTENDEE)) { |
172: | foreach ($masterEvent->ATTENDEE as $attendee) { |
173: | $sEmail = str_replace('mailto:', '', strtolower($attendee->getValue())); |
174: | if (strtolower($sEmail) === strtolower($sAttendee)) { |
175: | $attendeeFound = true; |
176: | $attendee['PARTSTAT'] = $sPartstat; |
177: | $attendee['RESPONDED-AT'] = gmdate("Ymd\THis\Z"); |
178: | |
179: | |
180: | unset($attendee['RSVP']); |
181: | break; |
182: | } |
183: | } |
184: | } |
185: | |
186: | if (!$attendeeFound) { |
187: | |
188: | |
189: | $attendee = $masterEvent->add('ATTENDEE', $sAttendee, [ |
190: | 'PARTSTAT' => $sPartstat, |
191: | 'CN' => $sCN, |
192: | 'RESPONDED-AT' => gmdate("Ymd\THis\Z") |
193: | ]); |
194: | } |
195: | } |
196: | |
197: | $masterEvent->{'LAST-MODIFIED'} = new \DateTime('now', new \DateTimeZone('UTC')); |
198: | |
199: | if ($AllEvents === 1 && $RecurrenceId !== null) { |
200: | if ($sPartstat === 'DECLINED' || $sMethod === 'CANCEL') { |
201: | if ($sCalendarId !== false) { |
202: | $oEvent = new \Aurora\Modules\Calendar\Classes\Event(); |
203: | $oEvent->IdCalendar = $sCalendarId; |
204: | $oEvent->Id = $sEventId; |
205: | $this->updateExclusion($sAttendee, $oEvent, $RecurrenceId, true); |
206: | } |
207: | } else { |
208: | $bNeedsToUpdateEvent = true; |
209: | } |
210: | |
211: | $vevent = null; |
212: | $index = \Aurora\Modules\Calendar\Classes\Helper::isRecurrenceExists($oVCal->VEVENT, $RecurrenceId); |
213: | if ($index === false) { |
214: | |
215: | |
216: | $recurrenceIterator = new \Sabre\VObject\Recur\EventIterator($oVCal, $masterEvent->UID); |
217: | $found = false; |
218: | $iterations = 1000; |
219: | do { |
220: | $newObject = $recurrenceIterator->getEventObject(); |
221: | $recurrenceIterator->next(); |
222: | |
223: | if (isset($newObject->{'RECURRENCE-ID'})) { |
224: | $iRecurrenceId = \Aurora\Modules\Calendar\Classes\Helper::getTimestamp($newObject->{'RECURRENCE-ID'}, $oUser->DefaultTimeZone); |
225: | if ((int) $iRecurrenceId === (int) $RecurrenceId) { |
226: | $found = true; |
227: | } |
228: | } |
229: | --$iterations; |
230: | } while ($recurrenceIterator->valid() && !$found && $iterations); |
231: | |
232: | if ($found) { |
233: | unset( |
234: | $newObject->RRULE, |
235: | $newObject->EXDATE, |
236: | $newObject->RDATE |
237: | ); |
238: | $vevent = $oVCal->add($newObject); |
239: | } |
240: | } else { |
241: | $vevent = $oVCal->VEVENT[$index]; |
242: | } |
243: | |
244: | $attendeeFound = false; |
245: | if (isset($vevent->ATTENDEE)) { |
246: | foreach ($vevent->ATTENDEE as $attendee) { |
247: | $sEmail = str_replace('mailto:', '', strtolower($attendee->getValue())); |
248: | if (strtolower($sEmail) === strtolower($sAttendee)) { |
249: | $attendeeFound = true; |
250: | $attendee['PARTSTAT'] = $sPartstat; |
251: | $attendee['RESPONDED-AT'] = gmdate("Ymd\THis\Z"); |
252: | break; |
253: | } |
254: | } |
255: | } |
256: | if ($vevent && !$attendeeFound) { |
257: | |
258: | $attendee = $vevent->add('ATTENDEE', $sAttendee, [ |
259: | 'PARTSTAT' => $sPartstat, |
260: | 'CN' => $sCN, |
261: | 'RESPONDED-AT' => gmdate("Ymd\THis\Z") |
262: | ]); |
263: | } |
264: | } |
265: | |
266: | if ($sMethod === 'REQUEST') { |
267: | $sMethod = 'REPLY'; |
268: | } |
269: | |
270: | $oVCalForSend = clone $oVCal; |
271: | $oVCalForSend->METHOD = $sMethod; |
272: | |
273: | $sTo = isset($masterEvent->ORGANIZER) ? str_replace(['mailto:', 'principals/'], '', strtolower((string) $masterEvent->ORGANIZER)) : ''; |
274: | $sSummary = isset($masterEvent->SUMMARY) ? (string) $masterEvent->SUMMARY : ''; |
275: | $sSubject = $this->getMessageSubjectFromPartstat($sPartstat, $sSummary); |
276: | |
277: | if ($bNeedsToUpdateEvent) { |
278: | unset($oVCal->METHOD); |
279: | $this->oStorage->updateEventRaw( |
280: | $oUser->PublicId, |
281: | $sCalendarId, |
282: | $sEventId, |
283: | $oVCal->serialize() |
284: | ); |
285: | } |
286: | |
287: | if ($oVCalForSend) { |
288: | if (empty($sTo)) { |
289: | throw new Exceptions\Exception( |
290: | Enums\ErrorCodes::CannotSendAppointmentMessageNoOrganizer |
291: | ); |
292: | } |
293: | $oFromAccount = $this->getFromAccount($oUser, $sAttendee); |
294: | $bResult = Classes\Helper::sendAppointmentMessage( |
295: | $oUser->PublicId, |
296: | $sTo, |
297: | $sSubject, |
298: | $oVCalForSend, |
299: | $sMethod, |
300: | '', |
301: | $oFromAccount, |
302: | $sAttendee |
303: | ); |
304: | } |
305: | } |
306: | |
307: | if (!$bResult) { |
308: | Api::Log('Ics Appointment Action FALSE result!', LogLevel::Error); |
309: | if ($sUserPublicId) { |
310: | Api::Log('Email: ' . $oUser->PublicId . ', Action: ' . $sAction . ', Data:', LogLevel::Error); |
311: | } |
312: | Api::Log($sData, LogLevel::Error); |
313: | } else { |
314: | $bResult = $sEventId; |
315: | } |
316: | |
317: | return $bResult; |
318: | } |
319: | } |
320: | |