Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
incominginvitationrequesthandler.php
1<?php
2
3
5
6
21use CCalendar;
22
23IncludeModuleLangFile($_SERVER["DOCUMENT_ROOT"].BX_ROOT."/modules/calendar/classes/general/calendar.php");
24IncludeModuleLangFile($_SERVER["DOCUMENT_ROOT"].BX_ROOT."/modules/calendar/lib/ical/incomingeventmanager.php");
25
31{
32 public const MEETING_STATUS_ACCEPTED_CODE = 'accepted';
33 public const MEETING_STATUS_QUESTION_CODE = 'question';
34 public const MEETING_STATUS_DECLINED_CODE = 'declined';
35 public const SAFE_DELETED_YES = 'Y';
36
37 protected string $decision;
39 protected int $userId;
40 protected ?string $emailTo;
41 protected ?string $emailFrom;
42 protected ?array $organizer;
43
48 {
49 return new self();
50 }
51
58 public static function createWithDecision(int $userId, Calendar $icalCalendar, string $decision): IncomingInvitationRequestHandler
59 {
60 $handler = new self();
61 $handler->decision = $decision;
62 $handler->userId = $userId;
63 $handler->icalComponent = $icalCalendar;
64
65 return $handler;
66 }
67
75 public function handle(): bool
76 {
77 $icalEvent = $this->icalComponent->getEvent();
78 $localEvent = Helper::getEventByUId($icalEvent->getUid());
79 if ($localEvent === null)
80 {
81 $preparedEvent = $this->prepareEventToSave($icalEvent);
82 $parentId = $this->saveEvent($preparedEvent);
83 $childEvent = EventTable::query()
84 ->setSelect(['ID','PARENT_ID','OWNER_ID'])
85 ->where('PARENT_ID', $parentId)
86 ->where('OWNER_ID', $this->userId)
87 ->exec()->fetch()
88 ;
89
90 if ((int)$childEvent['ID'] > 0)
91 {
92 $this->eventId = (int)$childEvent['ID'];
93 return true;
94 }
95 }
96 else
97 {
98 $preparedEvent = $this->prepareToUpdateEvent($icalEvent, $localEvent);
99 if ($this->updateEvent($preparedEvent, $localEvent))
100 {
101 $this->eventId = $localEvent['ID'];
102 return true;
103 }
104 }
105
106 return false;
107 }
108
114 {
115 $this->decision = $decision;
116
117 return $this;
118 }
119
125 {
126 $this->icalComponent = $component;
127
128 return $this;
129 }
130
136 {
137 $this->emailTo = $emailTo;
138
139 return $this;
140 }
141
143 {
144 $this->emailFrom = $emailFrom;
145
146 return $this;
147 }
148
154 {
155 $this->userId = $userId;
156
157 return $this;
158 }
159
168 protected function prepareEventToSave(Event $icalEvent): array
169 {
170 $event = [];
171
172 if ($icalEvent->getStart() !== null)
173 {
174 if ($icalEvent->getStart()->getParameterValueByName('tzid') !== null)
175 {
176 $event['DATE_FROM'] = Helper::getIcalDateTime(
177 $icalEvent->getStart()->getValue(),
178 $icalEvent->getStart()->getParameterValueByName('tzid')
179 )->format(Date::convertFormatToPhp(FORMAT_DATETIME));
180 $event['TZ_FROM'] = $icalEvent->getStart()->getParameterValueByName('tzid');
181 }
182 else
183 {
184 $event['DATE_FROM'] = Helper::getIcalDate($icalEvent->getStart()->getValue())
185 ->format(Date::convertFormatToPhp(FORMAT_DATE))
186 ;
187 $event['TZ_FROM'] = null;
188 $event['SKIP_TIME'] = 'Y';
189 }
190 }
191
192 if ($icalEvent->getEnd() !== null)
193 {
194 if ($icalEvent->getEnd()->getParameterValueByName('tzid') !== null)
195 {
196 $event['DATE_TO'] = Helper::getIcalDateTime(
197 $icalEvent->getEnd()->getValue(),
198 $icalEvent->getEnd()->getParameterValueByName('tzid')
199 )->format(Date::convertFormatToPhp(FORMAT_DATETIME));
200 $event['TZ_TO'] = $icalEvent->getEnd()->getParameterValueByName('tzid');
201 }
202 else
203 {
204 $event['DATE_TO'] = Helper::getIcalDate($icalEvent->getEnd()->getValue())
205 ->add('-1 days')
206 ->format(Date::convertFormatToPhp(FORMAT_DATE));
207 $event['TZ_TO'] = null;
208 }
209 }
210
211 if ($icalEvent->getName() !== null)
212 {
213 $event['NAME'] = !empty($icalEvent->getName()->getValue())
214 ? $icalEvent->getName()->getValue()
215 : Loc::getMessage('EC_DEFAULT_EVENT_NAME_V2')
216 ;
217 }
218
219 if ($icalEvent->getUid() !== null)
220 {
221 $event['DAV_XML_ID'] = $icalEvent->getUid();
222 }
223
224 if ($icalEvent->getModified() !== null)
225 {
226 $event['TIMESTAMP_X'] = Helper::getIcalDateTime($icalEvent->getModified()->getValue())
227 ->format(Date::convertFormatToPhp(FORMAT_DATETIME));
228 }
229
230 if ($icalEvent->getCreated() !== null)
231 {
232 $event['DATE_CREATE'] = Helper::getIcalDateTime($icalEvent->getCreated()->getValue())
233 ->format(Date::convertFormatToPhp(FORMAT_DATETIME));
234 }
235
236 if ($icalEvent->getDtStamp() !== null)
237 {
238 $event['DT_STAMP'] = Helper::getIcalDateTime($icalEvent->getDtStamp()->getValue())
239 ->format(Date::convertFormatToPhp(FORMAT_DATETIME));
240 }
241
242 if ($icalEvent->getSequence() !== null)
243 {
244 $event['VERSION'] = $icalEvent->getSequence()->getValue();
245 }
246
247 if ($icalEvent->getRRule() !== null)
248 {
249 $rrule = $this->parseRRule($icalEvent->getRRule());
250 if (isset($rrule['FREQ']) && in_array($rrule['FREQ'], Dictionary::RRULE_FREQUENCY, true))
251 {
252 $event['RRULE']['FREQ'] = $rrule['FREQ'];
253
254 if (isset($rrule['COUNT']) && (int)$rrule['COUNT'] > 0)
255 {
256 $event['RRULE']['COUNT'] = $rrule['COUNT'];
257 }
258 elseif (isset($rrule['UNTIL']))
259 {
260 $now = Util::getDateObject(null, false)->getTimestamp();
261 try
262 {
263 $until = Helper::getIcalDateTime($rrule['UNTIL']);
264 }
265 catch (ObjectException $exception)
266 {
267 // 0181908
268 try
269 {
270 $until = new DateTime($rrule['UNTIL']);
271 }
272 catch (ObjectException $exception)
273 {
274 $until = new DateTime(CCalendar::GetMaxDate());
275 }
276 }
277
278 if ($now < $until->getTimestamp())
279 {
280 $event['RRULE']['UNTIL'] = $until->format(Date::convertFormatToPhp(FORMAT_DATE));
281 }
282 }
283
284 if ($rrule['FREQ'] === Dictionary::RRULE_FREQUENCY['weekly'] && isset($rrule['BYDAY']))
285 {
286 $event['RRULE']['BYDAY'] = $rrule['BYDAY'];
287 }
288
289 if (isset($rrule['INTERVAL']))
290 {
291 $event['RRULE']['INTERVAL'] = $rrule['INTERVAL'];
292 }
293 else
294 {
295 $event['RRULE']['INTERVAL'] = 1;
296 }
297 }
298 }
299
300 $event['DESCRIPTION'] = $icalEvent->getDescription() !== null
301 ? $icalEvent->getDescription()->getValue()
302 : ''
303 ;
304
305
306 $this->organizer = $this->parseOrganizer($icalEvent->getOrganizer());
307 $event['MEETING_HOST'] = Helper::getUserIdByEmail($this->organizer);
308
309 $event['OWNER_ID'] = $this->userId;
310 $event['IS_MEETING'] = 1;
311 $event['SECTION_CAL_TYPE'] = 'user';
312 $event['ATTENDEES_CODES'] = ['U'.$event['OWNER_ID'], 'U'.$event['MEETING_HOST']];
313
314 $event['MEETING_STATUS'] = Tools\Dictionary::MEETING_STATUS['Host'];
315
316 $event['ACCESSIBILITY'] = 'free';
317 $event['IMPORTANCE'] = 'normal';
318 $event['REMIND'][] = [
319 'type' => 'min',
320 'count' => '15',
321 ];
322 $event['MEETING'] = [
323 'HOST_NAME' => $icalEvent->getOrganizer() !== null
324 ? $icalEvent->getOrganizer()->getParameterValueByName('cn')
325 : $this->organizer['EMAIL'],
326 'NOTIFY' => 1,
327 'REINVITE' => 0,
328 'ALLOW_INVITE' => 0,
329 'MEETING_CREATOR' => $event['MEETING_HOST'],
330 'EXTERNAL_TYPE' => 'mail',
331 ];
332
333 if ($this->decision === 'declined')
334 {
335 $event['DELETED'] = self::SAFE_DELETED_YES;
336 }
337
338 if ($icalEvent->getLocation() !== null)
339 {
340 $event['LOCATION'] = CCalendar::GetTextLocation($icalEvent->getLocation()->getValue() ?? null);
341 }
342
343 return $event;
344 }
345
350 protected function saveEvent(array $preparedEvent): int
351 {
352 $preparedEvent['OWNER_ID'] = $preparedEvent['MEETING_HOST'];
353 $preparedEvent['MEETING']['MAILTO'] = $this->organizer['EMAIL'] ?? $this->emailTo;
354 $preparedEvent['MEETING']['MAIL_FROM'] = $this->emailFrom;
355
356 if ($this->icalComponent->getEvent()->getAttendees())
357 {
358 $preparedEvent['DESCRIPTION'] .= "\r\n"
359 . Loc::getMessage('EC_EDEV_GUESTS') . ": "
360 . $this->parseAttendeesForDescription($this->icalComponent->getEvent()->getAttendees());
361 }
362
363 if ($this->icalComponent->getEvent()->getAttachments())
364 {
365 $preparedEvent['DESCRIPTION'] .= "\r\n"
366 . Loc::getMessage('EC_FILES_TITLE') . ': '
367 . $this->parseAttachmentsForDescription($this->icalComponent->getEvent()->getAttachments());
368 }
369
370 $id = (int)CCalendar::SaveEvent([
371 'arFields' => $preparedEvent,
372 'autoDetectSection' => true,
373 ]);
374
375 \CCalendarNotify::Send([
376 "mode" => 'invite',
377 "name" => $preparedEvent['NAME'] ?? null,
378 "from" => $preparedEvent['DATE_FROM'] ?? null,
379 "to" => $preparedEvent['DATE_TO'] ?? null,
380 "location" => CCalendar::GetTextLocation($preparedEvent["LOCATION"] ?? null),
381 "guestId" => $this->userId ?? null,
382 "eventId" => $id,
383 "userId" => $preparedEvent['MEETING_HOST'],
384 "fields" => $preparedEvent,
385 ]);
386 \CCalendar::UpdateCounter([$this->userId]);
387
388 return $id;
389 }
390
395 protected function parseAttendeesForDescription(?array $attendeesCollection): string
396 {
397 if (!$attendeesCollection)
398 {
399 return '';
400 }
401
402 $attendees = [];
403 foreach ($attendeesCollection as $attendee)
404 {
408 $email = $this->getMailTo($attendee->getValue());
409 if (
410 !$attendee->getParameterValueByName('cn')
411 || $attendee->getParameterValueByName('cn') === $email
412 )
413 {
414 $attendees[] = $email;
415 }
416 else
417 {
418 $attendees[] = $attendee->getParameterValueByName('cn') . " (" . $email . ")";
419 }
420 }
421
422 return implode(", ", $attendees);
423 }
424
429 protected function parseOrganizer(?ParserPropertyType $organizer): array
430 {
431 if (!$organizer)
432 {
433 return [];
434 }
435
436 $result = [];
437 $result['EMAIL'] = $this->getMailTo($organizer->getValue());
438 $parts = explode(" ", $organizer->getParameterValueByName('cn'), 2);
439 if (isset($parts[0]))
440 {
441 $result['NAME'] = $parts[0];
442 }
443 if (isset($parts[1]))
444 {
445 $result['LAST_NAME'] = $parts[1];
446 }
447 return $result;
448 }
449
459 protected function prepareToUpdateEvent(Event $icalEvent, array $localEvent): array
460 {
461 $event = [];
462
463 if ($icalEvent->getStart() !== null)
464 {
465 if ($icalEvent->getStart()->getParameterValueByName('tzid') !== null)
466 {
467 $event['DATE_FROM'] = Helper::getIcalDateTime(
468 $icalEvent->getStart()->getValue(),
469 $icalEvent->getStart()->getParameterValueByName('tzid')
470 )->format(Date::convertFormatToPhp(FORMAT_DATETIME));
471 $event['TZ_FROM'] = $icalEvent->getStart()->getParameterValueByName('tzid');
472 $event['DT_SKIP_TIME'] = 'N';
473 $event['SKIP_TIME'] = false;
474 }
475 else
476 {
477 $event['DATE_FROM'] = Helper::getIcalDate($icalEvent->getStart()->getValue())
478 ->format(Date::convertFormatToPhp(FORMAT_DATE));
479 $event['TZ_FROM'] = null;
480 $event['DT_SKIP_TIME'] = 'Y';
481 $event['SKIP_TIME'] = true;
482 }
483 }
484 else
485 {
486 $event['DATE_FROM'] = $localEvent['DATE_FROM'];
487 $event['TZ_FROM'] = $localEvent['TZ_FROM'];
488 }
489
490 if ($icalEvent->getEnd() !== null)
491 {
492 if ($icalEvent->getEnd()->getParameterValueByName('tzid') !== null)
493 {
494 $event['DATE_TO'] = Helper::getIcalDateTime(
495 $icalEvent->getEnd()->getValue(),
496 $icalEvent->getEnd()->getParameterValueByName('tzid')
497 )->format(Date::convertFormatToPhp(FORMAT_DATETIME));
498 $event['TZ_TO'] = $icalEvent->getEnd()->getParameterValueByName('tzid');
499 }
500 else
501 {
502 $event['DATE_TO'] = Helper::getIcalDate($icalEvent->getEnd()->getValue())
503 ->add('-1 days')
504 ->format(Date::convertFormatToPhp(FORMAT_DATE));
505 $event['TZ_TO'] = null;
506 }
507 }
508 else
509 {
510 $event['DATE_TO'] = $localEvent['DATE_TO'];
511 $event['TZ_TO'] = $localEvent['TZ_TO'];
512 }
513
514 if ($icalEvent->getName() !== null)
515 {
516 $event['NAME'] = $icalEvent->getName()->getValue();
517 }
518
519 if ($icalEvent->getModified() !== null)
520 {
521 $event['TIMESTAMP_X'] = Helper::getIcalDateTime($icalEvent->getModified()->getValue())
522 ->format(Date::convertFormatToPhp(FORMAT_DATETIME));
523 }
524
525
526 if ($icalEvent->getCreated() !== null)
527 {
528 $invitationDateCreate = Helper::getIcalDateTime($icalEvent->getCreated()->getValue())->getTimestamp();
529 $localDateCreate = Util::getDateObject($localEvent['DATE_CREATE'])->getTimestamp();
530 if ($invitationDateCreate === $localDateCreate)
531 {
532 $event['DATE_CREATE'] = Helper::getIcalDateTime($icalEvent->getCreated()->getValue())
533 ->format(Date::convertFormatToPhp(FORMAT_DATETIME))
534 ;
535 }
536 }
537
538 if ($icalEvent->getDtStamp() !== null)
539 {
540 $event['DT_STAMP'] = Helper::getIcalDateTime($icalEvent->getDtStamp()->getValue())
541 ->format(Date::convertFormatToPhp(FORMAT_DATETIME));
542 }
543
544 if ($icalEvent->getSequence() !== null && $icalEvent->getSequence()->getValue() > $localEvent['VERSION'])
545 {
546 $event['VERSION'] = $icalEvent->getSequence()->getValue();
547 }
548
549 if ($icalEvent->getDescription() !== null)
550 {
551 $event['DESCRIPTION'] = $icalEvent->getDescription()->getValue();
552 }
553 else
554 {
555 $event['DESCRIPTION'] = null;
556 }
557
558 if ($icalEvent->getRRule() !== null)
559 {
560 $rrule = $this->parseRRule($icalEvent->getRRule());
561 if (isset($rrule['FREQ']) && in_array($rrule['FREQ'], Dictionary::RRULE_FREQUENCY, true))
562 {
563 $event['RRULE']['FREQ'] = $rrule['FREQ'];
564
565 if (isset($rrule['COUNT']) && (int)$rrule['COUNT'] > 0)
566 {
567 $event['RRULE']['COUNT'] = $rrule['COUNT'];
568 }
569 elseif (isset($rrule['UNTIL']))
570 {
571 $now = Util::getDateObject(null, false)->getTimestamp();
572 try
573 {
574 $until = Helper::getIcalDateTime($rrule['UNTIL']);
575 }
576 catch (ObjectException $exception)
577 {
578 // 0181908
579 try
580 {
581 $until = new DateTime($rrule['UNTIL']);
582 }
583 catch (ObjectException $exception)
584 {
585 $until = new DateTime(CCalendar::GetMaxDate());
586 }
587 }
588
589 if ($now < $until->getTimestamp())
590 {
591 $event['RRULE']['UNTIL'] = $until->format(Date::convertFormatToPhp(FORMAT_DATE));
592 }
593 }
594
595 if ($rrule['FREQ'] === Dictionary::RRULE_FREQUENCY['weekly'] && isset($rrule['BYDAY']))
596 {
597 $event['RRULE']['BYDAY'] = $rrule['BYDAY'];
598 }
599
600 if (isset($rrule['INTERVAL']))
601 {
602 $event['RRULE']['INTERVAL'] = $rrule['INTERVAL'];
603 }
604 else
605 {
606 $event['RRULE']['INTERVAL'] = 1;
607 }
608 }
609 }
610
611 $organizer = [];
612 if ($icalEvent->getOrganizer() !== null)
613 {
614 $organizer = $this->parseOrganizer($icalEvent->getOrganizer());
615 }
616
617 $event['OWNER_ID'] = $this->userId;
618 $event['MEETING_HOST'] = count($organizer)
620 : $localEvent['MEETING_HOST']
621 ;
622 $event['IS_MEETING'] = 1;
623 $event['SECTION_CAL_TYPE'] = 'user';
624 $event['ATTENDEES_CODES'] = ['U'.$event['OWNER_ID'], 'U'.$event['MEETING_HOST']];
625 $event['MEETING_STATUS'] = match ($this->decision) {
626 self::MEETING_STATUS_ACCEPTED_CODE => Tools\Dictionary::MEETING_STATUS['Yes'],
627 self::MEETING_STATUS_DECLINED_CODE => Tools\Dictionary::MEETING_STATUS['No'],
628 default => Tools\Dictionary::MEETING_STATUS['Question'],
629 };
630 $event['ACCESSIBILITY'] = 'free';
631 $event['IMPORTANCE'] = 'normal';
632 $event['REMIND'] = [
633 'type' => 'min',
634 'count' => '15',
635 ];
636 $organizerCn = $icalEvent->getOrganizer()?->getParameterValueByName('cn');
637 $meeting = unserialize($localEvent['MEETING'], ['allowed_classes' => false]);
638 $event['MEETING'] = [
639 'HOST_NAME' => $organizerCn ?? $organizer['EMAIL'] ?? $meeting['HOST_NAME'] ?? null,
640 'NOTIFY' => $meeting['NOTIFY'] ?? 1,
641 'REINVITE' => $meeting['REINVITE'] ?? 0,
642 'ALLOW_INVITE' => $meeting['ALLOW_INVITE'] ?? 0,
643 'MEETING_CREATOR' => $meeting['MEETING_CREATOR'] ?? $event['MEETING_HOST'],
644 'EXTERNAL_TYPE' => 'mail',
645 ];
646 $event['PARENT_ID'] = $localEvent['PARENT_ID'] ?? null;
647 $event['ID'] = $localEvent['ID'] ?? null;
648 $event['CAL_TYPE'] = $localEvent['CAL_TYPE'] ?? null;
649
650 if ($this->decision === 'declined')
651 {
652 $event['DELETED'] = self::SAFE_DELETED_YES;
653 }
654
655 if ($icalEvent->getLocation() !== null)
656 {
657 $event['LOCATION'] = CCalendar::GetTextLocation($icalEvent->getLocation()->getValue() ?? null);
658 }
659
660 return $event;
661 }
662
668 protected function updateEvent(array $updatedEvent, array $localEvent): bool
669 {
670 $updatedEvent['ID'] = $updatedEvent['PARENT_ID'];
671 $updatedEvent['OWNER_ID'] = $updatedEvent['MEETING_HOST'];
672 $updatedEvent['MEETING']['MAILTO'] = $this->organizer['EMAIL'] ?? $this->emailTo;
673 $updatedEvent['MEETING']['MAIL_FROM'] = $this->emailFrom;
674
675 if ($this->icalComponent->getEvent()->getAttendees())
676 {
677 $updatedEvent['DESCRIPTION'] .= "\r\n"
678 . Loc::getMessage('EC_EDEV_GUESTS') . ": "
679 . $this->parseAttendeesForDescription($this->icalComponent->getEvent()->getAttendees());
680 }
681
682 if ($this->icalComponent->getEvent()->getAttachments())
683 {
684 $updatedEvent['DESCRIPTION'] .= "\r\n"
685 . Loc::getMessage('EC_FILES_TITLE') . ': '
686 . $this->parseAttachmentsForDescription($this->icalComponent->getEvent()->getAttachments());
687 }
688
689 \CCalendar::SaveEvent([
690 'arFields' => $updatedEvent,
691 ]);
692
693 $entryChanges = \CCalendarEvent::CheckEntryChanges($updatedEvent, $localEvent);
694
695 \CCalendarNotify::Send([
696 'mode' => 'change_notify',
697 'name' => $updatedEvent['NAME'] ?? null,
698 "from" => $updatedEvent['DATE_FROM'] ?? null,
699 "to" => $updatedEvent['DATE_TO'] ?? null,
700 "location" => CCalendar::GetTextLocation($updatedEvent["LOCATION"] ?? null),
701 "guestId" => $this->userId ?? null,
702 "eventId" => $updatedEvent['PARENT_ID'] ?? null,
703 "userId" => $updatedEvent['MEETING_HOST'],
704 "fields" => $updatedEvent,
705 "entryChanges" => $entryChanges,
706 ]);
707 \CCalendar::UpdateCounter([$this->userId]);
708
709 return true;
710 }
711
712 protected function parseAttachmentsForDescription(array $icalAttachments): string
713 {
714 $res = [];
716 foreach ($icalAttachments as $attachment)
717 {
718 $link = $attachment->getValue();
719 if ($name = $attachment->getParameterValueByName('filename'))
720 {
721 $res[] = $name . ' (' . $link . ')';
722 }
723 else
724 {
725 $res[] = $link;
726 }
727 }
728
729 return implode(', ', $res);
730 }
731
732 private function parseRRule(ParserPropertyType $icalRRule): array
733 {
734 $result = [];
735 $parts = explode(";", $icalRRule->getValue());
736 foreach ($parts as $part)
737 {
738 [$name, $value] = explode("=", $part);
739 if ($name === 'BYDAY')
740 {
741 $value = explode(',', $value);
742 }
743 $result[$name] = $value;
744 }
745
746 return $result;
747 }
748}
static getIcalDate(string $date=null)
Definition helper.php:533
static getIcalDateTime(string $dateTime=null, string $tz=null)
Definition helper.php:521
static getUserIdByEmail(array $userInfo)
Definition helper.php:545
static createWithDecision(int $userId, Calendar $icalCalendar, string $decision)
static getDateObject(string $date=null, ?bool $fullDay=true, ?string $tz='UTC')
Definition util.php:102
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29