1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
calendar_sect.php
См. документацию.
1<?
2
31
33{
34 public const EXTERNAL_TYPE_LOCAL = 'local';
35 public const OPERATION_VIEW_TIME = 'calendar_view_time';
36 public const OPERATION_VIEW_TITLE = 'calendar_view_title';
37 public const OPERATION_VIEW_FULL = 'calendar_view_full';
38 public const OPERATION_ADD = 'calendar_add';
39 public const OPERATION_EDIT = 'calendar_edit';
40 public const OPERATION_EDIT_SECTION = 'calendar_edit_section';
41 public const OPERATION_EDIT_ACCESS = 'calendar_edit_access';
42
43 public static $sendPush = true;
44 public static $sectionConnectionCache = [];
45 public static $sectionAccessCache = [];
46
47 private static
48 $sections,
49 $Permissions = [],
50 $userSectionPermissions = [],
51 $arOp = [],
52 $bClearOperationCache = false,
53 $authHashiCal = null, // for login by hash
54 $Fields = []
55 ;
56
57 private static function GetFields()
58 {
59 global $DB;
60 if (empty(self::$Fields))
61 {
62 self::$Fields = [
63 "ID" => ["FIELD_NAME" => "CS.ID", "FIELD_TYPE" => "int"],
64 "NAME" => ["FIELD_NAME" => "CS.NAME", "FIELD_TYPE" => "string"],
65 "XML_ID" => ["FIELD_NAME" => "CS.XML_ID", "FIELD_TYPE" => "string"],
66 "EXTERNAL_ID" => ["FIELD_NAME" => "CS.EXTERNAL_ID", "FIELD_TYPE" => "string"],
67 "ACTIVE" => ["FIELD_NAME" => "CS.ACTIVE", "FIELD_TYPE" => "string"],
68 "COLOR" => ["FIELD_NAME" => "CS.COLOR", "FIELD_TYPE" => "string"],
69 "SORT" => ["FIELD_NAME" => "CS.SORT", "FIELD_TYPE" => "int"],
70 "CAL_TYPE" => ["FIELD_NAME" => "CS.CAL_TYPE", "FIELD_TYPE" => "string", "PROCENT" => "N"],
71 "OWNER_ID" => ["FIELD_NAME" => "CS.OWNER_ID", "FIELD_TYPE" => "int"],
72 "CREATED_BY" => ["FIELD_NAME" => "CS.CREATED_BY", "FIELD_TYPE" => "int"],
73 "PARENT_ID" => ["FIELD_NAME" => "CS.PARENT_ID", "FIELD_TYPE" => "int"],
74 "TIMESTAMP_X" => [
75 "~FIELD_NAME" => "CS.TIMESTAMP_X",
76 "FIELD_NAME" => $DB->DateToCharFunction("CS.TIMESTAMP_X") . ' as TIMESTAMP_X',
77 "FIELD_TYPE" => "date"
78 ],
79 "DATE_CREATE" => [
80 "~FIELD_NAME" => "CS.DATE_CREATE",
81 "FIELD_NAME" => $DB->DateToCharFunction("CS.DATE_CREATE") . ' as DATE_CREATE',
82 "FIELD_TYPE" => "date"
83 ],
84 "DAV_EXCH_CAL" => ["FIELD_NAME" => "CS.DAV_EXCH_CAL", "FIELD_TYPE" => "string"],
85 // Exchange calendar
86 "DAV_EXCH_MOD" => ["FIELD_NAME" => "CS.DAV_EXCH_MOD", "FIELD_TYPE" => "string"],
87 // Exchange calendar modification label
88 "CAL_DAV_CON" => ["FIELD_NAME" => "CS.CAL_DAV_CON", "FIELD_TYPE" => "string"],
89 // CalDAV connection
90 "CAL_DAV_CAL" => ["FIELD_NAME" => "CS.CAL_DAV_CAL", "FIELD_TYPE" => "string"],
91 // CalDAV calendar
92 "CAL_DAV_MOD" => ["FIELD_NAME" => "CS.CAL_DAV_MOD", "FIELD_TYPE" => "string"],
93 // CalDAV calendar modification label
94 "IS_EXCHANGE" => ["FIELD_NAME" => "CS.IS_EXCHANGE", "FIELD_TYPE" => "string"],
95 "SYNC_TOKEN" => ["FIELD_NAME" => "CS.SYNC_TOKEN", "FIELD_TYPE" => "string"],
96 "PAGE_TOKEN" => ["FIELD_NAME" => "CS.PAGE_TOKEN", "FIELD_TYPE" => "string"],
97 ];
98 }
99 return self::$Fields;
100 }
101
102 private static function getSectionFields(): array
103 {
104 return [
105 'ID',
106 'NAME',
107 'XML_ID',
108 'EXTERNAL_ID',
109 'ACTIVE',
110 'COLOR',
111 'SORT',
112 'CAL_TYPE',
113 'OWNER_ID',
114 'CREATED_BY',
115 'PARENT_ID',
116 'TIMESTAMP_X',
117 'DATE_CREATE',
118 'DAV_EXCH_CAL',
119 'DAV_EXCH_MOD',
120 'CAL_DAV_CON',
121 'CAL_DAV_CAL',
122 'CAL_DAV_MOD',
123 'IS_EXCHANGE',
124 'SYNC_TOKEN',
125 'PAGE_TOKEN',
126 'GAPI_CALENDAR_ID',
127 ];
128 }
129
130 public static function GetList($params = [])
131 {
132 $result = false;
133 $checkPermissions = ($params['checkPermissions'] ?? null) !== false;
134 $params['joinTypeInfo'] = (bool)($params['joinTypeInfo'] ?? null);
135 $params['checkPermissions'] = $checkPermissions;
136 $params['getPermissions'] = ($params['getPermissions'] ?? null) !== false;
137 $userId = ($params['userId'] ?? false) ? (int)$params['userId'] : CCalendar::GetCurUserId();
138 $params['userId'] = $userId;
139 $cacheEnabled = CCalendar::CacheTime() > 0;
140
141 if ($cacheEnabled)
142 {
143 $cache = new CPHPCache;
144 $cacheId = 'section_list_'.serialize($params).(CCalendar::IsSocnetAdmin() ? 'socnet_admin' : '');
145 $cachePath = CCalendar::CachePath().'section_list';
146
147 if ($cache->InitCache(CCalendar::CacheTime(), $cacheId, $cachePath))
148 {
149 $res = $cache->GetVars();
150 $result = $res["arResult"];
151 $sectionIdList = $res["arSectionIds"];
152 $permissions = $res["permissions"];
153 if (is_array($permissions))
154 {
155 foreach($res["permissions"] as $sectionId => $perms)
156 {
157 self::$Permissions[$sectionId] = $perms;
158 }
159 }
160 }
161 }
162
163 if (!$cacheEnabled || !isset($sectionIdList))
164 {
165 $sectionList = self::getListOrm($params);
166
167 $result = [];
168 $sectionIdList = [];
169 $checkedConnections = [];
170 $isExchangeEnabled = CCalendar::IsExchangeEnabled();
171 $isCalDAVEnabled = CCalendar::IsCalDAVEnabled();
172 $isIntranetEnabled = CCalendar::IsIntranetEnabled();
173 $groupCalType = Dictionary::CALENDAR_TYPE['group'];
174 $groupSectionIds = array_filter(
175 array_map(
176 static fn (array $section) => (
177 $section['CAL_TYPE'] === $groupCalType ? (int)$section['OWNER_ID'] : null
178 ),
179 $sectionList
180 )
181 );
182 $collabIds = $groupSectionIds ? Collab\Collabs::getInstance()->getCollabIdsByGroupIds($groupSectionIds) : [];
183
184 foreach ($sectionList as $section)
185 {
186 $sectId = (int)$section['ID'];
187
188 if (in_array($sectId, $sectionIdList, true))
189 {
190 continue;
191 }
192
193 if ($checkPermissions)
194 {
195 self::HandlePermission($section);
196 }
197
198 $sectionType = $section['CAL_TYPE'];
199
200 // Outlook js
201 if (
202 $isIntranetEnabled
203 && !in_array($sectionType, [
204 Dictionary::CALENDAR_TYPE['location'],
205 Dictionary::CALENDAR_TYPE['open_event']
206 ], true)
207 )
208 {
209 $section['OUTLOOK_JS'] = 'needAction';
210 }
211
212 unset($section['ACCESS_CODE'], $section['TASK_ID']);
213
214 $sectionIdList[] = $sectId;
215
216 $section['EXPORT'] = [
217 'ALLOW' => true,
218 'LINK' => self::GetExportLink($section['ID'], $sectionType, $section['OWNER_ID'] ?? null)
219 ];
220
221 if ($sectionType === 'user')
222 {
223 $section['IS_EXCHANGE'] = $section['DAV_EXCH_CAL'] && $isExchangeEnabled;
224 if ($section['CAL_DAV_CON'] && $isCalDAVEnabled)
225 {
226 $connectionId = (int)$section["CAL_DAV_CON"];
227
228 if (isset($checkedConnections[$connectionId]))
229 {
230 $section['CAL_DAV_CON'] = $checkedConnections[$connectionId] ? $connectionId : false;
231 }
232 else
233 {
234 $connection = CDavConnection::GetList(
235 ["ID" => "ASC"],
236 ["ID" => $connectionId]
237 );
238
239 if ($connection)
240 {
241 $section['CAL_DAV_CON'] = (int)$connection["ID"];
242 }
243 else
244 {
245 $section['CAL_DAV_CON'] = false;
246 }
247
248 $checkedConnections[$connectionId] = (bool)$connection;
249 }
250 }
251 }
252 else
253 {
254 $section['IS_EXCHANGE'] = false;
255 $section['CAL_DAV_CON'] = false;
256 }
257
258 $isCollab = false;
259 if (
260 $sectionType === Dictionary::CALENDAR_TYPE['group']
261 && in_array((int)$section['OWNER_ID'], $collabIds, true)
262 )
263 {
264 $isCollab = true;
265 }
266 $section['IS_COLLAB'] = $isCollab;
267
268 $result[] = $section;
269 }
270
271 if ($cacheEnabled)
272 {
273 $cache->StartDataCache(CCalendar::CacheTime(), $cacheId, $cachePath);
274 $cache->EndDataCache([
275 "arResult" => $result,
276 "arSectionIds" => $sectionIdList,
277 "permissions" => self::$Permissions,
278 ]);
279 }
280 }
281
282 if (($checkPermissions || $params['getPermissions']) && $userId >= 0 && !empty($sectionIdList))
283 {
284 $result = self::GetSectionPermission($result, $params['getPermissions']);
285 }
286
287 return $result;
288 }
289
297 private static function getListOrm($params)
298 {
299 $sectionFields = self::getSectionFields();
300 $filterFields = $params['arFilter'] ?? [];
301 $orderFields = $params['arOrder'] ?? [];
302 $selectFields = $params['arSelect'] ?? ['*'];
303
304 $query = SectionTable::query();
305 $queryFilter = null;
306
307 if (!empty($filterFields) && is_array($filterFields))
308 {
310 foreach ($filterFields as $key => $value)
311 {
312 if (is_string($value) && !$value)
313 {
314 continue;
315 }
316
317 switch ($key)
318 {
319 case 'ID':
320 case 'XML_ID':
321 case 'OWNER_ID':
322 case 'EXTERNAL_TYPE':
323 if (is_array($value))
324 {
325 $queryFilter->whereIn($key, $value);
326 }
327 else
328 {
329 $queryFilter->where($key, $value);
330 }
331 break;
332 case '>ID':
333 if ((int)$value)
334 {
335 $queryFilter->where('ID', '>', (int)$value);
336 }
337 break;
338 case 'ACTIVE':
339 if ($value === 'Y')
340 {
341 $queryFilter->where('ACTIVE', $value);
342 }
343 break;
344 case 'CAL_TYPE':
345 if (is_array($value))
346 {
347 $params['joinTypeInfo'] = true;
348
349 $queryFilter
350 ->where('TYPE.ACTIVE', 'Y')
351 ->whereIn('CAL_TYPE', $value)
352 ;
353 }
354 else
355 {
356 $queryFilter->where('CAL_TYPE', $value);
357 }
358 break;
359 default:
360 if (in_array($key, $sectionFields, true))
361 {
362 if (is_array($value))
363 {
364 $queryFilter->whereIn($key, $value);
365 }
366 else
367 {
368 $queryFilter->where($key, $value);
369 }
370 }
371 break;
372 }
373
374 }
375 }
376
377 if (!empty($filterFields['ADDITIONAL_IDS']) && is_array($filterFields['ADDITIONAL_IDS']))
378 {
379 if ($queryFilter)
380 {
381 $query->where(
382 \Bitrix\Main\ORM\Query\Query::filter()
383 ->logic('or')
384 ->whereIn('ID', $filterFields['ADDITIONAL_IDS'])
385 ->where($queryFilter)
386 );
387 }
388 else
389 {
390 $query->whereIn('ID', $filterFields['ADDITIONAL_IDS']);
391 }
392 }
393 else if ($queryFilter)
394 {
395 $query->where($queryFilter);
396 }
397
398 if ($params['joinTypeInfo'])
399 {
400 $query->registerRuntimeField(
401 'TYPE',
402 new \Bitrix\Main\Entity\ReferenceField(
403 'TYPE',
404 \Bitrix\Calendar\Internals\TypeTable::getEntity(),
405 \Bitrix\Main\ORM\Query\Join::on('ref.XML_ID', 'this.CAL_TYPE'),
406 ['join_type' => \Bitrix\Main\ORM\Query\Join::TYPE_INNER]
407
408 )
409 );
410
411 $selectFields['TYPE_NAME'] = 'TYPE.NAME';
412 $selectFields['TYPE_DESC'] = 'TYPE.DESCRIPTION';
413 }
414
415 $query->setSelect($selectFields);
416
417 $orderList = [];
418 foreach ($orderFields as $key => $order)
419 {
420 if (in_array($key, $sectionFields, true))
421 {
422 $orderList[$key] = (mb_strtoupper($order) === 'DESC') ? 'DESC' : 'ASC';
423 }
424 }
425
426 if (!empty($orderList))
427 {
428 $query->setOrder($orderList);
429 }
430
431 if (isset($params['limit']) && (int)$params['limit'] > 0)
432 {
433 $query->setLimit((int)$params['limit']);
434 }
435
436 $sectionQuery = $query->exec();
437
438 [$sectionIdList, $result] = self::prepareSectionQueryData($sectionQuery);
439
440 if ($params['getPermissions'])
441 {
442 $result = self::getSectionAccess($sectionIdList, $result);
443 }
444
445 return $result;
446 }
447
448 private static function prepareSectionQueryData($query)
449 {
450 $sectionIdList = [];
451 $result = [];
452
453 while ($section = $query->fetch())
454 {
455 $section['COLOR'] = CCalendar::Color($section['COLOR'] ?? '');
456 $section['NAME'] = Emoji::decode($section['NAME'] ?? '');
457
458 if (!empty($section['DATE_CREATE']))
459 {
460 $section['DATE_CREATE'] = (string)$section['DATE_CREATE'];
461 }
462
463 if (!empty($section['TIMESTAMP_X']))
464 {
465 $section['TIMESTAMP_X'] = (string)$section['TIMESTAMP_X'];
466 }
467
468 $sectionId = (int)$section['ID'];
469 $sectionIdList[] = $sectionId;
470 $result[$sectionId] = $section;
471 }
472
473 return [$sectionIdList, $result];
474 }
475
476 private static function getSectionAccess($sectionIdList, $sections)
477 {
478 if (empty($sectionIdList))
479 {
480 return [];
481 }
482
483 $noCacheForSectionIds = array_diff($sectionIdList, array_keys(self::$sectionAccessCache));
484 if (!$noCacheForSectionIds)
485 {
486 $result = [];
487 foreach ($sectionIdList as $sectionId)
488 {
489 $result[$sectionId] = self::$sectionAccessCache[$sectionId];
490 }
491
492 return $result;
493 }
494
495 $accessQuery = \Bitrix\Calendar\Internals\AccessTable::query()
496 ->setSelect([
497 'ACCESS_CODE',
498 'TASK_ID',
499 'SECT_ID'
500 ])
501 ->whereIn('SECT_ID', $sectionIdList)
502 ->exec()
503 ;
504
505 while ($access = $accessQuery->fetch())
506 {
507 if (!isset($sections[$access['SECT_ID']]['ACCESS']))
508 {
509 $sections[$access['SECT_ID']]['ACCESS'] = [];
510 }
511
512 $sections[$access['SECT_ID']]['ACCESS'][$access['ACCESS_CODE']] = (int)$access['TASK_ID'];
513 }
514
515 foreach ($sectionIdList as $sectionId)
516 {
517 unset(self::$sectionAccessCache[$sectionId]);
518 self::$sectionAccessCache[$sectionId] = $sections[$sectionId];
519 }
520
521 return $sections;
522 }
523
524 private static function getListOld($params)
525 {
526 global $DB;
527
528 $filter = $params['arFilter'];
529 $sort = $params['arOrder'] ?? ['SORT' => 'asc'];
530
531 $arFields = self::GetFields();
532 $arSqlSearch = [];
533 if(is_array($filter))
534 {
535 $filterKeys = array_keys($filter);
536 foreach ($filterKeys as $filterKey)
537 {
538 $n = mb_strtoupper($filterKey);
539 $val = $filter[$filterKey] ?? '';
540 if (($val === '') || $val === "NOT_REF")
541 {
542 continue;
543 }
544
545 if ($n === 'CAL_TYPE' && ($val === 'company_calendar' || $val === 'calendar_company'))
546 {
547 $arSqlSearch[] = 'CS.CAL_TYPE = \'' . $val . '\' AND CS.CAL_TYPE IS NOT NULL';
548 }
549 else if (
550 $n === 'ID'
551 || $n === 'XML_ID'
552 || $n === 'OWNER_ID'
553 || $n === 'EXTERNAL_TYPE'
554 // || $n === 'CAL_DAV_CON'
555 )
556 {
557 if (is_array($val))
558 {
559 $val = array_map(array($DB, "ForSQL"), $val);
560 $arSqlSearch[] = 'CS.'.$n.' IN (\''.implode('\',\'', $val).'\')';
561 }
562 else
563 {
564 $arSqlSearch[] = GetFilterQuery("CS.".$n, $val, 'N');
565 }
566 }
567 else if($n === '>ID' && (int)$val > 0)
568 {
569 $arSqlSearch[] = "CS.ID > ". (int)$val;
570 }
571 elseif($n === 'ACTIVE' && $val === "Y")
572 {
573 $arSqlSearch[] = "CS.ACTIVE = 'Y'";
574 }
575 elseif ($n === 'CAL_TYPE' && is_array($val))
576 {
577 $params['joinTypeInfo'] = true;
578 $strType = "";
579 foreach($val as $type)
580 {
581 $strType .= ",'" . $DB->ForSql($type) . "'";
582 }
583 $arSqlSearch[] = "CS.CAL_TYPE in (".trim($strType, ", ").")";
584 $arSqlSearch[] = "CT.ACTIVE='Y'";
585 }
586 elseif(isset($arFields[$n]))
587 {
588 $arSqlSearch[] = GetFilterQuery(
589 $arFields[$n]["FIELD_NAME"],
590 $val,
591 (isset($arFields[$n]["PROCENT"]) && $arFields[$n]["PROCENT"] === "N") ? "N" : "Y"
592 );
593 }
594 }
595 }
596
597 $strOrderBy = '';
598 foreach($sort as $by => $order)
599 {
600 if(isset($arFields[mb_strtoupper($by)]))
601 {
602 $byName = $arFields[mb_strtoupper($by)]["~FIELD_NAME"]
603 ?? $arFields[mb_strtoupper($by)]["FIELD_NAME"]
604 ;
605 $strOrderBy .= $byName.' '.(mb_strtolower($order) === 'desc'?'desc':'asc').',';
606 }
607 }
608
609 if($strOrderBy)
610 {
611 $strOrderBy = "ORDER BY ".rtrim($strOrderBy, ",");
612 }
613
614 $strSqlSearch = GetFilterSqlSearch($arSqlSearch);
615
616 if (!empty($filter['ADDITIONAL_IDS'] && is_array($filter['ADDITIONAL_IDS'])))
617 {
618 $strTypes = "";
619 foreach($filter['ADDITIONAL_IDS'] as $adid)
620 {
621 $strTypes .= ",". (int)$adid;
622 }
623 $strSqlSearch = '('.$strSqlSearch.') OR ID in('.trim($strTypes, ', ').')';
624 }
625
626 $strLimit = '';
627 if (isset($params['limit']) && (int)$params['limit'] > 0)
628 {
629 $strLimit = 'LIMIT '. (int)$params['limit'];
630 }
631
632 $select = 'CS.*';
633 $from = 'b_calendar_section CS';
634
635 // Fetch types info into selection
636 if ($params['joinTypeInfo'])
637 {
638 $select .= ", CT.NAME AS TYPE_NAME, CT.DESCRIPTION AS TYPE_DESC";
639 $from .= "\n INNER JOIN b_calendar_type CT ON (CS.CAL_TYPE=CT.XML_ID)";
640 }
641
642 if ($params['getPermissions'])
643 {
644 $select .= ", CAP.ACCESS_CODE, CAP.TASK_ID";
645 $from .= "\n LEFT JOIN b_calendar_access CAP ON (CS.ID=".$DB->ToNumber('CAP.SECT_ID').")";
646 }
647
648 $strSql = "
649 SELECT
650 $select
651 FROM
652 $from
653 WHERE
654 $strSqlSearch
655 $strOrderBy
656 $strLimit";
657
658 $result = [];
659 $res = $DB->Query($strSql);
660
661 while ($sect = $res->Fetch())
662 {
663 $result[] = $sect;
664 }
665
666 return $result;
667 }
668
669 public static function GetSectionPermission(array $array, $getPermissions = null)
670 {
671 $res = [];
672 $accessCodes = [];
673
674 foreach ($array as $section)
675 {
676 $sectId = $section['ID'];
677 $userId = CCalendar::GetUserId();
678
679 $accessController = new SectionAccessController($userId);
680 $sectionModel = SectionModel::createFromArray($section);
681
682 $request = [
683 ActionDictionary::ACTION_SECTION_EVENT_VIEW_TIME => [],
684 ActionDictionary::ACTION_SECTION_EVENT_VIEW_TITLE => [],
685 ActionDictionary::ACTION_SECTION_EVENT_VIEW_FULL => [],
686 ActionDictionary::ACTION_SECTION_ADD => [],
687 ActionDictionary::ACTION_SECTION_EDIT => [],
688 ActionDictionary::ACTION_SECTION_ACCESS => [],
689 ];
690
691 $result = $accessController->batchCheck($request, $sectionModel);
692
693 if ($result[ActionDictionary::ACTION_SECTION_EVENT_VIEW_TIME])
694 {
695 $section['PERM'] = [
696 'view_time' => $result[ActionDictionary::ACTION_SECTION_EVENT_VIEW_TIME],
697 'view_title' => $result[ActionDictionary::ACTION_SECTION_EVENT_VIEW_TITLE],
698 'view_full' => $result[ActionDictionary::ACTION_SECTION_EVENT_VIEW_FULL],
699 'add' => $result[ActionDictionary::ACTION_SECTION_ADD],
700 'edit' => $result[ActionDictionary::ACTION_SECTION_EDIT],
701 'edit_section' => $result[ActionDictionary::ACTION_SECTION_EDIT],
702 'access' => $result[ActionDictionary::ACTION_SECTION_ACCESS],
703 ];
704
705 if ($getPermissions || $section['PERM']['access'] || $section['CAL_TYPE'] === 'location')
706 {
707 $section['ACCESS'] = [];
708 if (
709 isset(self::$Permissions[$sectId])
710 && is_array(self::$Permissions[$sectId])
711 && !empty(self::$Permissions[$sectId])
712 )
713 {
714 // Add codes to get they full names for interface
715 $currentAccessCodes = array_keys(self::$Permissions[$sectId]);
716 foreach ($currentAccessCodes as $code)
717 {
718 if (!in_array($code, $accessCodes, true))
719 {
720 $accessCodes[] = $code;
721 }
722 }
723
724 $section['ACCESS'] = self::$Permissions[$sectId];
725 }
726 }
727
728 CCalendar::PushAccessNames($accessCodes);
729
730 $res[] = $section;
731 }
732 }
733
734 return $res;
735 }
736
737 public static function GetById(int $id = 0, bool $checkPermissions = true, bool $bRerequest = false)
738 {
739 if ($id > 0)
740 {
741 if (!isset(self::$sections[$id]) || $bRerequest)
742 {
743 $section = self::GetList([
744 'arFilter' => ['ID' => $id],
745 'checkPermissions' => $checkPermissions,
746 ]);
747
748 if($section && is_array($section) && is_array($section[0]))
749 {
750 self::$sections[$id] = $section[0];
751 return $section[0];
752 }
753 }
754 else
755 {
756 return self::$sections[$id];
757 }
758 }
759
760 return false;
761 }
762
763 //
764 public static function GetSuperposedList($params = [])
765 {
766 global $DB;
767 $checkPermissions = ($params['checkPermissions'] ?? null) !== false;
768 $userId = isset($params['userId']) ? (int)$params['userId'] : CCalendar::GetCurUserId();
769
770 $arResult = [];
771 $arSectionIds = [];
772 $sqlSearch = "";
773
774 $select = '';
775 $from = '';
776
777 $helper = Application::getConnection()->getSqlHelper();
778
779 if ($checkPermissions)
780 {
781 $select .= ", CAP.ACCESS_CODE, CAP.TASK_ID";
782 $from .= "\n LEFT JOIN b_calendar_access CAP ON ({$helper->castToChar('CS.ID')}=CAP.SECT_ID)";
783 }
784
785 // Common types
786 $strTypes = "";
787 if (isset($params['TYPES']) && is_array($params['TYPES']))
788 {
789 foreach($params['TYPES'] as $type)
790 {
791 $strTypes .= ",'" . $DB->ForSql($type) . "'";
792 }
793
794 $strTypes = trim($strTypes, ", ");
795 if ($strTypes != "")
796 {
797 $sqlSearch .= "(CS.CAL_TYPE in (" . $strTypes . "))";
798 }
799 }
800
801 // Group's calendars
802 $strGroups = "0";
803 if (!empty($params['GROUPS']) && is_array($params['GROUPS']))
804 {
805 foreach($params['GROUPS'] as $ownerId)
806 {
807 if ((int)$ownerId > 0)
808 {
809 $strGroups .= "," . (int)$ownerId;
810 }
811 }
812
813 if ($strGroups != "0")
814 {
815 if ($sqlSearch != "")
816 {
817 $sqlSearch .= " OR ";
818 }
819 $sqlSearch .= "(CS.OWNER_ID in (".$strGroups.") AND CS.CAL_TYPE='group')";
820 }
821 }
822
823 if ($sqlSearch != "")
824 {
825 $strSql = "
826 SELECT
827 CS.*,
828 CT.NAME AS TYPE_NAME, CT.DESCRIPTION AS TYPE_DESC".$select."
829 FROM
830 b_calendar_section CS
831 LEFT JOIN b_calendar_type CT ON (CS.CAL_TYPE=CT.XML_ID)".$from."
832 WHERE
833 (
834 CT.ACTIVE='Y'
835 AND
836 CS.ACTIVE='Y'
837 AND
838 (
839 $sqlSearch
840 ))";
841
842 $res = $DB->Query($strSql);
843
844 while($arRes = $res->Fetch())
845 {
846 if ($checkPermissions)
847 {
848 self::HandlePermission($arRes);
849 unset($arRes['ACCESS_CODE'], $arRes['TASK_ID']);
850 }
851
852 if (!in_array($arRes['ID'], $arSectionIds))
853 {
854 $arSectionIds[] = $arRes['ID'];
855 $arResult[] = $arRes;
856 }
857 }
858 }
859
860 // User's calendars
861 $strUsers = "0";
862
863 if (isset($params['USERS']) && is_array($params['USERS']) && count($params['USERS']) > 0)
864 {
865 foreach($params['USERS'] as $ownerId)
866 {
867 if ((int)$ownerId > 0)
868 {
869 $strUsers .= ",". (int)$ownerId;
870 }
871 }
872
873 if ($strUsers != "0")
874 {
875 $strSql = "
876 SELECT
877 CS.*,
878 U.LOGIN AS USER_LOGIN, U.NAME AS USER_NAME, U.LAST_NAME AS USER_LAST_NAME, U.SECOND_NAME AS USER_SECOND_NAME".$select."
879 FROM
880 b_calendar_section CS
881 LEFT JOIN b_user U ON (CS.OWNER_ID=U.ID)".$from."
882 WHERE
883 (
884 CS.ACTIVE='Y'
885 AND
886 CS.OWNER_ID in (".$strUsers.")
887 AND
888 CS.CAL_TYPE='user'
889 )";
890
891 $res = $DB->Query($strSql);
892 }
893
894 while($arRes = $res->Fetch())
895 {
896 if ($checkPermissions)
897 {
898 self::HandlePermission($arRes);
899 unset($arRes['ACCESS_CODE'], $arRes['TASK_ID']);
900 }
901
902 if (!in_array($arRes['ID'], $arSectionIds))
903 {
904 $arSectionIds[] = $arRes['ID'];
905 $arResult[] = $arRes;
906 }
907 }
908 }
909
910 if ($checkPermissions && !empty($arSectionIds))
911 {
912 $res = [];
913 $sectIds = [];
914 foreach($arResult as $sect)
915 {
916 $sectId = $sect['ID'];
917 $ownerId = $sect['OWNER_ID'];
918
919 $accessController = new SectionAccessController($userId);
920 $sectionModel =
921 SectionModel::createFromId((int)$sectId)
922 ->setType($sect['CAL_TYPE'])
923 ->setOwnerId((int)$ownerId)
924 ;
925 $request = [
926 ActionDictionary::ACTION_SECTION_EVENT_VIEW_TIME => [],
927 ActionDictionary::ACTION_SECTION_EVENT_VIEW_TITLE => [],
928 ActionDictionary::ACTION_SECTION_EVENT_VIEW_FULL => [],
929 ActionDictionary::ACTION_SECTION_ADD => [],
930 ActionDictionary::ACTION_SECTION_EDIT => [],
931 ActionDictionary::ACTION_SECTION_ACCESS => [],
932 ];
933
934 $result = $accessController->batchCheck($request, $sectionModel);
935
936 if ($result[ActionDictionary::ACTION_SECTION_EVENT_VIEW_TIME] && !in_array($sectId, $sectIds))
937 {
938 $sect['PERM'] = [
939 'view_time' => $result[ActionDictionary::ACTION_SECTION_EVENT_VIEW_TIME],
940 'view_title' => $result[ActionDictionary::ACTION_SECTION_EVENT_VIEW_TITLE],
941 'view_full' => $result[ActionDictionary::ACTION_SECTION_EVENT_VIEW_FULL],
942 'add' => $result[ActionDictionary::ACTION_SECTION_ADD],
943 'edit' => $result[ActionDictionary::ACTION_SECTION_EDIT],
944 'edit_section' => $result[ActionDictionary::ACTION_SECTION_EDIT],
945 'access' => $result[ActionDictionary::ACTION_SECTION_ACCESS],
946 ];
947
948 if ($sect['CAL_TYPE'] === 'user')
949 {
950 if (isset($sect['USER_NAME'], $sect['USER_LAST_NAME']))
951 {
952 $sect['OWNER_NAME'] = CCalendar::GetUserName(array(
953 "NAME" => $sect['USER_NAME'],
954 "LAST_NAME" => $sect['USER_LAST_NAME'],
955 "LOGIN" => $sect['USER_LOGIN'],
956 "ID" => $ownerId,
957 "SECOND_NAME" => $sect['USER_SECOND_NAME'])
958 );
959 unset(
960 $sect['USER_LOGIN'],
961 $sect['USER_LAST_NAME'],
962 $sect['USER_SECOND_NAME'],
963 $sect['USER_NAME']
964 );
965 }
966 else
967 {
968 $sect['OWNER_NAME'] = CCalendar::GetUserName($ownerId);
969 }
970 }
971 elseif ($sect['CAL_TYPE'] === 'group' && isset($params['arGroups']))
972 {
973 $sect['OWNER_NAME'] = $params['arGroups'][$ownerId]['NAME'];
974 }
975
976 $res[] = $sect;
977 $sectIds[] = $sectId;
978 }
979 }
980 $arResult = $res;
981 }
982
983 foreach ($arResult as &$section)
984 {
985 if (!empty($section['NAME']))
986 {
987 $section['NAME'] = Emoji::decode($section['NAME']);
988 }
989 }
990
991 return $arResult;
992 }
993
994 public static function Edit($params)
995 {
996 global $DB;
997 $sectionFields = $params['arFields'];
998 $userId = (isset($params['userId']) ? (int)$params['userId'] : CCalendar::GetCurUserId());
999
1000 $isNewSection = !isset($sectionFields['ID']) || $sectionFields['ID'] <= 0;
1001 if (isset($sectionFields['COLOR']) || $isNewSection)
1002 {
1003 $sectionFields['COLOR'] = CCalendar::Color($sectionFields['COLOR'] ?? null);
1004 }
1005
1006 $sectionFields['TIMESTAMP_X'] = CCalendar::Date(time());
1007
1008 if (isset($sectionFields['EXPORT']) && is_array($sectionFields['EXPORT']))
1009 {
1010 $sectionFields['EXPORT'] = [
1011 'ALLOW' => (bool)$sectionFields['EXPORT']['ALLOW'],
1012 'SET' => (in_array($sectionFields['EXPORT']['set'] ?? null, array('all', '3_9', '6_12')))
1013 ? $sectionFields['EXPORT']['set']
1014 : 'all',
1015 ];
1016
1017 $sectionFields['EXPORT'] = serialize($sectionFields['EXPORT']);
1018 }
1019
1020 if (!empty($sectionFields['NAME']))
1021 {
1022 $sectionFields['NAME'] = Emoji::encode($sectionFields['NAME']);
1023 }
1024
1025 if ($isNewSection) // Add
1026 {
1027 if (!isset($sectionFields['DATE_CREATE']))
1028 {
1029 $sectionFields['DATE_CREATE'] = CCalendar::Date(time());
1030 }
1031
1032 if ((!isset($sectionFields['CREATED_BY']) || !$sectionFields['CREATED_BY']))
1033 {
1034 $sectionFields['CREATED_BY'] = CCalendar::GetCurUserId();
1035 }
1036
1037 if (!isset($sectionFields['EXTERNAL_TYPE']))
1038 {
1039 $sectionFields['EXTERNAL_TYPE'] = 'local';
1040 }
1041
1042 unset($sectionFields['ID']);
1043 $id = $DB->Add("b_calendar_section", $sectionFields, ['DESCRIPTION']);
1044 }
1045 else // Update
1046 {
1047 $id = (int)$sectionFields['ID'];
1048
1049 $originalSection = SectionTable::getById($id);
1050 if (
1051 $originalSection !== false
1052 && is_array($originalSection)
1053 && $originalSection['EXTERNAL_TYPE'] !== self::EXTERNAL_TYPE_LOCAL
1054 )
1055 {
1056 $sectionFields['EXTERNAL_TYPE'] = $originalSection['EXTERNAL_TYPE'];
1057 }
1058
1059 unset($sectionFields['ID']);
1060 $strUpdate = $DB->PrepareUpdate("b_calendar_section", $sectionFields);
1061 $strSql = "UPDATE b_calendar_section SET ". $strUpdate . " WHERE ID = " . $id;
1062
1063 $DB->QueryBind($strSql, array('DESCRIPTION' => $sectionFields['DESCRIPTION'] ?? null));
1064 }
1065
1066 //SaveAccess
1067 if ($id > 0 && isset($sectionFields['ACCESS']) && is_array($sectionFields['ACCESS']))
1068 {
1069 $sectionModel =
1070 SectionModel::createFromId($id)
1071 ->setType($sectionFields['CAL_TYPE'])
1072 ->setOwnerId((int)($sectionFields['OWNER_ID'] ?? null))
1073 ;
1074 if ((new SectionAccessController($userId))->check(ActionDictionary::ACTION_SECTION_ACCESS, $sectionModel))
1075 {
1076 if (empty($sectionFields['ACCESS']))
1077 {
1078 self::SavePermissions(
1079 $id,
1080 self::GetDefaultAccess($sectionFields['CAL_TYPE'], $sectionFields['OWNER_ID'] ?? null)
1081 );
1082 }
1083 else
1084 {
1085 self::SavePermissions($id, $sectionFields['ACCESS']);
1086 }
1087 }
1088 elseif($isNewSection)
1089 {
1090 self::SavePermissions(
1091 $id,
1092 self::GetDefaultAccess($sectionFields['CAL_TYPE'], $sectionFields['OWNER_ID'])
1093 );
1094 }
1095 }
1096
1097 if ($isNewSection && $id > 0 && !isset($sectionFields['ACCESS']))
1098 {
1099 self::SavePermissions(
1100 $id,
1101 self::GetDefaultAccess($sectionFields['CAL_TYPE'], $sectionFields['OWNER_ID'])
1102 );
1103 }
1104
1105 if ($isNewSection && $id && !isset($sectionFields['XML_ID']))
1106 {
1107 $xmlId = md5($sectionFields['CAL_TYPE'] . '_' . $id . '_' . Random::getString(8));
1108
1109 SectionTable::update($id, [
1110 'XML_ID' => $xmlId
1111 ]);
1112 }
1113
1114 CCalendar::ClearCache(['section_list', 'event_list']);
1115
1116 if ($id > 0 && isset(self::$Permissions[$id]))
1117 {
1118 unset(self::$Permissions[$id]);
1119 self::$arOp = [];
1120 }
1121
1122 if ($isNewSection)
1123 {
1124 self::onCreateSync($id, [
1125 'params' => $params,
1126 'sectionFields' => $sectionFields,
1127 'userId' => $userId,
1128 ]);
1129 }
1130 else
1131 {
1132 self::onUpdateSync($id, [
1133 'params' => $params,
1134 'sectionFields' => $sectionFields,
1135 'userId' => $userId,
1136 ]);
1137 }
1138
1139 if ($isNewSection)
1140 {
1141 foreach(EventManager::getInstance()->findEventHandlers("calendar", "OnAfterCalendarSectionAdd") as $event)
1142 {
1144 }
1145 }
1146 else
1147 {
1148 foreach(EventManager::getInstance()->findEventHandlers("calendar", "OnAfterCalendarSectionUpdate") as $event)
1149 {
1151 }
1152
1153 }
1154
1155 $pullUserId = (int)($sectionFields['CREATED_BY'] ?? $userId);
1156 if (
1157 $pullUserId
1158 && self::$sendPush
1159 )
1160 {
1162 PushCommand::EditSection,
1163 $pullUserId,
1164 [
1165 'fields' => [...$sectionFields, 'ID' => $id],
1166 'newSection' => $isNewSection,
1167 ]
1168 );
1169 }
1170
1171 return $id;
1172 }
1173
1174 public static function Delete($id, $checkPermissions = true, $params = [])
1175 {
1176 global $DB;
1177 $id = (int)$id;
1178
1179 $sectionFields = self::GetById($id);
1180 $canEdit = $sectionFields['PERM']['edit'] ?? false;
1181 if ($checkPermissions !== false && !$canEdit)
1182 {
1183 return CCalendar::ThrowError('EC_ACCESS_DENIED');
1184 }
1185
1186 $meetingIds = [];
1188 {
1189 $strSql = "select CE.ID, CE.PARENT_ID, CE.CREATED_BY
1190 from b_calendar_event CE
1191 where CE.SECTION_ID=".$id."
1192 and (CE.IS_MEETING='1' and CE.IS_MEETING is not null)
1193 and (CE.DELETED='N' and CE.DELETED is not null)";
1194 }
1195 else
1196 {
1197 // Here we don't use GetList to speed up delete process
1198 // mantis: 82918
1199 $strSql = "SELECT CE.ID, CE.PARENT_ID, CE.DELETED, CE.CREATED_BY, CES.SECT_ID, CES.EVENT_ID
1200 FROM b_calendar_event CE
1201 LEFT JOIN b_calendar_event_sect CES ON (CE.ID=CES.EVENT_ID)
1202 WHERE CES.SECT_ID=".$id."
1203 AND (CE.IS_MEETING='1' and CE.IS_MEETING is not null)
1204 AND (CE.DELETED='N' and CE.DELETED is not null)";
1205 }
1206
1207 $res = $DB->Query($strSql );
1208 while($ev = $res->Fetch())
1209 {
1210 if ((int)$ev['ID'] === (int)$ev['PARENT_ID'])
1211 {
1212 $meetingIds[] = (int)$ev['PARENT_ID'];
1214 }
1215
1216 $pullUserId = (int)$ev['CREATED_BY'] > 0 ? (int)$ev['CREATED_BY'] : CCalendar::GetCurUserId();
1217 if (
1218 $pullUserId
1219 && self::$sendPush
1220 )
1221 {
1223 PushCommand::DeleteEvent,
1224 $pullUserId,
1225 [
1226 'fields' => $ev,
1227 ]
1228 );
1229 }
1230 }
1231
1232 if (!empty($meetingIds))
1233 {
1234 $DB->Query("DELETE from b_calendar_event WHERE PARENT_ID in (".implode(',', $meetingIds).")");
1235 }
1236
1237 //delete section in services
1238 self::onDeleteSync($id, [
1239 'originalFrom' => $params['originalFrom'] ?? '',
1240 ]);
1241
1242 // Del link from table
1244 {
1245 $DB->Query("DELETE FROM b_calendar_event_sect WHERE SECT_ID=".$id);
1246 }
1247
1248 // Del from
1249 $DB->Query("DELETE FROM b_calendar_section WHERE ID=".$id);
1250
1251 CCalendarEvent::DeleteEmpty($id);
1252 self::CleanAccessTable($id);
1253 CCalendar::ClearCache(array('section_list', 'event_list'));
1254
1255 foreach(EventManager::getInstance()->findEventHandlers("calendar", "OnAfterCalendarSectionDelete") as $event)
1256 {
1258 }
1259
1260 $pullUserId = (int)$sectionFields['CREATED_BY'] > 0 ? (int)$sectionFields['CREATED_BY'] : CCalendar::GetCurUserId();
1261 if (
1262 $pullUserId
1263 && self::$sendPush
1264 )
1265 {
1267 PushCommand::DeleteSection,
1268 $pullUserId,
1269 [
1270 'fields' => $sectionFields,
1271 ]
1272 );
1273 }
1274
1275
1276 return true;
1277 }
1278
1279 public static function CreateDefault($params = [])
1280 {
1281 if (
1282 $params['type'] === Dictionary::CALENDAR_TYPE['user']
1283 || $params['type'] === Dictionary::CALENDAR_TYPE['group']
1284 )
1285 {
1286 $name = CCalendar::GetOwnerName($params['type'], $params['ownerId']);
1287 }
1288 else
1289 {
1290 $name = $params['type'] === 'location' ? Loc::getMessage('EC_DEF_SECT_LOCATION_CAL') : Loc::getMessage('EC_DEF_SECT_GROUP_CAL');
1291 }
1292
1293 $userId = $params['type'] === 'user' ? $params['ownerId'] : CCalendar::GetCurUserId();
1294
1295 $isCollabSection = $params['type'] === Dictionary::CALENDAR_TYPE['group']
1296 && Collab\Collabs::getInstance()->getCollabIfExists((int)$params['ownerId'])
1297 ;
1298
1299 $color = '#9DCF00';
1300 if ($isCollabSection)
1301 {
1302 $color = '#19CC45';
1303 }
1304
1305 if ($userId > 0)
1306 {
1307 $arFields = [
1308 'CAL_TYPE' => $params['type'],
1309 'NAME' => $name,
1310 'DESCRIPTION' => Loc::getMessage('EC_DEF_SECT_DESC'),
1311 'COLOR' => $color,
1312 'OWNER_ID' => $params['ownerId'],
1313 'IS_EXCHANGE' => 0,
1314 'ACCESS' => self::GetDefaultAccess($params['type'], $params['ownerId']),
1315 'PERM' => [
1316 'view_time' => true,
1317 'view_title' => true,
1318 'view_full' => true,
1319 'add' => true,
1320 'edit' => true,
1321 'edit_section' => true,
1322 'access' => true,
1323 ],
1324 'EXTERNAL_TYPE' => self::EXTERNAL_TYPE_LOCAL,
1325 'IS_COLLAB' => $isCollabSection,
1326 ];
1327
1328 if($params['type'] === 'location')
1329 {
1330 $arFields['NECESSITY'] = 'N';
1331 $arFields['CAPACITY'] = 0;
1332
1333 $builder = new \Bitrix\Calendar\Core\Builders\Rooms\RoomBuilderFromArray($arFields);
1334 $room = $builder->build();
1335
1337 ->createRoom()
1338 ->saveAccess()
1339 ->clearCache()
1340 ->eventHandler('OnAfterCalendarRoomCreate')
1341 ->addPullEvent(PushCommand::CreateRoom)
1342 ;
1343
1344 $arFields['ID'] = $room->getId();
1345 }
1346 else
1347 {
1348 $arFields['ID'] = self::Edit([
1349 'arFields' => $arFields,
1350 'userId' => $userId,
1351 ]);
1352 }
1353
1354 if ($arFields['ID'] > 0)
1355 {
1356 return $arFields;
1357 }
1358 }
1359 return false;
1360 }
1361
1362 public static function SavePermissions($sectId, $taskPerm)
1363 {
1364 global $DB;
1365 $DB->Query("DELETE FROM b_calendar_access WHERE SECT_ID='".(int)$sectId."'");
1366
1367 if (is_array($taskPerm))
1368 {
1369 foreach($taskPerm as $accessCode => $taskId)
1370 {
1371 if (strpos($accessCode, "SG") === 0)
1372 {
1373 $accessCode = self::prepareGroupCode($accessCode);
1374 }
1375
1376 $insert = $DB->PrepareInsert(
1377 "b_calendar_access",
1378 [
1379 "ACCESS_CODE" => $accessCode,
1380 "TASK_ID" => (int)$taskId,
1381 "SECT_ID" => (int)$sectId,
1382 ]
1383 );
1384 $strSql = "INSERT INTO b_calendar_access(".$insert[0].") VALUES(".$insert[1].")";
1385 $DB->Query($strSql );
1386 }
1387 }
1388 }
1389
1390 private static function prepareGroupCode($code)
1391 {
1392 $parsedCode = explode('_', $code);
1393
1394 if (count($parsedCode) === 1)
1395 {
1396 $code .= '_K';
1397 }
1398
1399 return $code;
1400 }
1401
1402 public static function GetArrayPermissions($arSections = [])
1403 {
1404 global $DB;
1405 $s = "'0'";
1406 foreach($arSections as $id)
1407 {
1408 if ($id > 0)
1409 {
1410 $s .= ",'". (int)$id ."'";
1411 }
1412 }
1413
1414 $helper = Application::getConnection()->getSqlHelper();
1415 $strSql = 'SELECT SC.ID, CAP.ACCESS_CODE, CAP.TASK_ID, SC.CAL_TYPE, SC.OWNER_ID, SC.CREATED_BY
1416 FROM b_calendar_section SC
1417 LEFT JOIN b_calendar_access CAP ON CAP.SECT_ID = '.$helper->castToChar('SC.ID').'
1418 WHERE SC.ID in ('.$s.')'
1419 ;
1420
1421 $res = $DB->Query($strSql );
1422 while($arRes = $res->Fetch())
1423 {
1424 if ($arRes['ID'] > 0)
1425 {
1426 self::HandlePermission($arRes);
1427 }
1428 }
1429
1430 return self::$Permissions;
1431 }
1432
1433 public static function SetClearOperationCache($val = true)
1434 {
1435 self::$bClearOperationCache = $val;
1436 }
1437
1438 public static function CanDo($operation, $sectId = 0, $userId = null)
1439 {
1440 $res = null;
1441 global $USER;
1442 if ((!$USER || !is_object($USER)) || $USER->CanDoOperation('edit_php'))
1443 {
1444 return true;
1445 }
1446
1447 if (!is_numeric($userId))
1448 {
1449 $userId = CCalendar::GetCurUserId();
1450 }
1451
1452 if (
1453 CCalendar::IsBitrix24()
1454 && Loader::includeModule('bitrix24')
1455 && CBitrix24::isPortalAdmin($userId)
1456 )
1457 {
1458 return true;
1459 }
1460
1461 if (
1462 CCalendar::IsSocNet()
1463 && CCalendar::IsSocnetAdmin()
1464 &&(
1465 CCalendar::GetType() === 'group'
1466 || CCalendar::GetType() === 'user'
1467 || CCalendar::IsBitrix24()
1468 )
1469 )
1470 {
1471 return true;
1472 }
1473
1474 if ((int)$sectId && (int)$userId && !self::$bClearOperationCache)
1475 {
1476 $sectionPermKey = $userId . '|' . $sectId;
1477 if (isset(self::$userSectionPermissions[$sectionPermKey]))
1478 {
1479 $res = in_array($operation, self::$userSectionPermissions[$sectionPermKey], true);
1480 }
1481 }
1482
1483 if ($res === null)
1484 {
1485 $res = in_array($operation, self::GetOperations($sectId, $userId), true);
1486 }
1487
1488 self::$bClearOperationCache = false;
1489 return $res;
1490 }
1491
1492 public static function GetOperations($sectId, $userId = null)
1493 {
1494 if (!$userId)
1495 {
1496 $userId = CCalendar::GetCurUserId();
1497 }
1498
1499 if ((int)$sectId && (int)$userId && !self::$bClearOperationCache)
1500 {
1501 $sectionPermKey = $userId . '|' . $sectId;
1502 if (isset(self::$userSectionPermissions[$sectionPermKey]))
1503 {
1504 return self::$userSectionPermissions[$sectionPermKey];
1505 }
1506 }
1507
1509
1510 $key = $sectId.'|'.implode(',', $codes);
1511 if (self::$bClearOperationCache || !is_array(self::$arOp[$key] ?? null))
1512 {
1513 if (!isset(self::$Permissions[$sectId]))
1514 {
1515 self::GetArrayPermissions([$sectId]);
1516 }
1517 $perms = self::$Permissions[$sectId];
1518
1519 self::$arOp[$key] = [];
1520 if (is_array($perms))
1521 {
1522 foreach ($perms as $code => $taskId)
1523 {
1524 if (in_array($code, $codes, true))
1525 {
1526 self::$arOp[$key] = array_merge(self::$arOp[$key], CTask::GetOperations($taskId, true));
1527 }
1528 }
1529 }
1530 }
1531
1532 if ((int)$sectId && (int)$userId)
1533 {
1534 $sectionPermKey = $userId . '|' . $sectId;
1535 self::$userSectionPermissions[$sectionPermKey] = self::$arOp[$key];
1536 }
1537
1538 self::$bClearOperationCache = false;
1539
1540 return self::$arOp[$key];
1541 }
1542
1543 public static function GetCalDAVConnectionId($section = 0)
1544 {
1545 global $DB;
1546
1547 $arIds = is_array($section) ? $section : array($section);
1548 $arIds = array_unique($arIds);
1549 $strIds = [];
1550 $result = [];
1551 foreach($arIds as $id)
1552 {
1553 if ((int)$id > 0)
1554 {
1555 $strIds[] = (int)$id;
1556 $result[(int)$id] = 0;
1557 }
1558 }
1559 $strIds = implode(',', $strIds);
1560
1561 $strSql = "SELECT ID, CAL_DAV_CON FROM b_calendar_section WHERE ID in (".$strIds.")";
1562 $res = $DB->Query($strSql);
1563
1564 while ($arRes = $res->Fetch())
1565 {
1566 $result[$arRes['ID']] = ($arRes['CAL_DAV_CON'] > 0) ? (int)$arRes['CAL_DAV_CON'] : 0;
1567 }
1568
1569 if (!is_array($section))
1570 {
1571 return $result[$section];
1572 }
1573
1574 return $result;
1575 }
1576
1577 public static function GetExportLink($sectionId, $type = '', $ownerId = null)
1578 {
1579 $userId = CCalendar::getCurUserId();
1580 $ownerId = (int)$ownerId;
1581 $path = Util::getPathToCalendar($ownerId, $type);
1582
1583 return '&type='.mb_strtolower($type)
1584 .'&owner='.$ownerId
1585 .'&ncc=1&user='.$userId
1586 .'&'.'sec_id='.(int)$sectionId
1587 .'&sign='.self::getSign($userId, $sectionId)
1588 .'&bx_hit_hash='.self::getAuthHash($userId, $path);
1589 }
1590
1595 public static function CleanFieldsValueById(int $sectionId, array $fields): void
1596 {
1597 if (!$fields)
1598 {
1599 return;
1600 }
1601
1602 global $DB;
1603 $dbFields = [];
1604
1605 foreach ($fields as $field)
1606 {
1607 $dbFields[$field] = false;
1608 }
1609
1610 $DB->Query("UPDATE b_calendar_section SET "
1611 . $DB->PrepareUpdate('b_calendar_section', $dbFields)
1612 . " WHERE ID = " . $sectionId);
1613 }
1614
1625 private static function onCreateSync(int $id, array $params): ?Result
1626 {
1627 if (!Loader::includeModule('dav'))
1628 {
1629 return null;
1630 }
1631
1632 $originalFrom = $params['params']['originalFrom'] ?? null;
1633 if ($originalFrom === ($params['sectionFields']['EXTERNAL_TYPE'] ?? null))
1634 {
1635 return null;
1636 }
1637
1638 if (
1639 !empty($params['sectionFields']['EXTERNAL_TYPE'])
1640 && (
1641 $params['sectionFields']['EXTERNAL_TYPE'] === Bitrix\Calendar\Sync\Caldav\Helper::CALDAV_TYPE
1642 || $params['sectionFields']['EXTERNAL_TYPE'] === Bitrix\Calendar\Sync\Caldav\Helper::EXCHANGE_TYPE
1643 )
1644 )
1645 {
1646 return null;
1647 }
1648
1649 if ($params['params']['arFields']['CAL_TYPE'] !== 'user')
1650 {
1651 return null;
1652 }
1653
1655 $section = (new Bitrix\Calendar\Core\Mappers\Section())->getById($id);
1656 if (!$section)
1657 {
1658 return null;
1659 }
1660
1661 $factories = FactoriesCollection::createByUserId($params['userId']);
1662 if ($factories->count() === 0)
1663 {
1664 return null;
1665 }
1666
1667 $syncManager = new Synchronization($factories);
1668 $context = new Context([]);
1669 if (!empty($originalFrom))
1670 {
1671 $context->add('sync', 'originalFrom', $originalFrom);
1672 }
1673
1674 $result = $syncManager->createSection($section, $context);
1675
1676 // TODO: temporary. Need to move into separated method
1677 if ($result->isSuccess())
1678 {
1680 foreach ($factories as $factory)
1681 {
1682 if ($factory->canSubscribeSection())
1683 {
1684 $outgoingManager = new \Bitrix\Calendar\Sync\Managers\OutgoingManager($factory->getConnection());
1686 if (
1687 ($vendorResult = $result->getData()[$factory->getCode()])
1688 && $sectionConnection = $vendorResult->getData()['sectionConnection']
1689 )
1690 {
1691 $outgoingManager->subscribeSection($sectionConnection);
1692 }
1693 }
1694 }
1695 }
1696
1697
1698 return $result;
1699 }
1700
1701 private static function onUpdateSync(int $id, array $params)
1702 {
1703 if (!Loader::includeModule('dav'))
1704 {
1705 return null;
1706 }
1707
1708 if (($params['params']['arFields']['CAL_TYPE'] ?? null) !== 'user')
1709 {
1710 return null;
1711 }
1712
1713 if (empty($params['params']['arFields']['NAME']))
1714 {
1715 return new Result();
1716 }
1717
1719 $section = (new Bitrix\Calendar\Core\Mappers\Section())->getById($id);
1720 if (!$section)
1721 {
1722 return null;
1723 }
1724
1725 $factories = FactoriesCollection::createBySection($section);
1726 if ($factories->count() === 0)
1727 {
1728 return null;
1729 }
1730 $syncManager = new Synchronization($factories);
1731 $context = new Context([]);
1732 if (!empty($params['params']['originalFrom']))
1733 {
1734 $context->add('sync', 'originalFrom', $params['params']['originalFrom']);
1735 }
1736
1737 return $syncManager->updateSection($section, $context);
1738 }
1739
1740 private static function onDeleteSync(int $id, array $params)
1741 {
1742 if (!Loader::includeModule('dav'))
1743 {
1744 return null;
1745 }
1746
1747 $section = new Bitrix\Calendar\Core\Section\Section();
1748 $section->setId($id);
1749
1750 $factories = FactoriesCollection::createBySection($section);
1751
1752 if ($factories->count() === 0)
1753 {
1754 self::cleanLinkTables($id);
1755
1756 return null;
1757 }
1758 $syncManager = new Synchronization($factories);
1759 $context = new Context([]);
1760 if (!empty($params['originalFrom']))
1761 {
1762 $context->add('sync', 'originalFrom', $params['originalFrom']);
1763 }
1764
1765 return $syncManager->deleteSection($section, $context);
1766 }
1767
1768 public static function cleanLinkTables($sectId)
1769 {
1770 global $DB;
1771
1772 $DB->Query("DELETE FROM b_calendar_event_connection
1773 WHERE EVENT_ID IN (SELECT EV.ID FROM b_calendar_event EV
1774 WHERE EV.SECTION_ID = " . (int)$sectId . ");"
1775 );
1776
1777 $DB->Query("DELETE FROM b_calendar_section_connection
1778 WHERE SECTION_ID = " . (int)$sectId . ";"
1779 );
1780 }
1781
1783 {
1784 $userId = CCalendar::GetCurUserId();
1785 return '&user_id='.$userId.'&sign='.self::GetSign($userId, 'superposed_calendars');
1786 }
1787
1788 public static function GetOutlookLink($Params)
1789 {
1790 if (Bitrix\Main\Loader::includeModule('intranet'))
1791 {
1792 return CIntranetUtils::GetStsSyncURL($Params);
1793 }
1794
1795 return null;
1796 }
1797
1798 private static function GetUniqCalendarId()
1799 {
1800 $uniq = COption::GetOptionString("calendar", "~export_uniq_id", "");
1801 if($uniq == '')
1802 {
1803 $uniq = md5(uniqid(rand(), true));
1804 COption::SetOptionString("calendar", "~export_uniq_id", $uniq);
1805 }
1806 return $uniq;
1807 }
1808
1809 public static function GetSign($userId, $sectId)
1810 {
1811 return md5($userId."||".$sectId."||".self::GetUniqCalendarId());
1812 }
1813
1814 public static function CheckSign($sign, $userId, $sectId)
1815 {
1816 return (md5($userId."||".$sectId."||".self::GetUniqCalendarId()) == $sign);
1817 }
1818
1819 // * * * * EXPORT TO ICAL * * * *
1820 public static function ReturnICal($Params)
1821 {
1822 $sectId = $Params['sectId'];
1823 $userId = (int)$Params['userId'];
1824 $sign = $Params['sign'];
1825 $type = mb_strtolower($Params['type']);
1826 $ownerId = (int)$Params['ownerId'];
1827 $bCache = false;
1828
1829 $GLOBALS['APPLICATION']->RestartBuffer();
1830
1831 if (!self::CheckSign($sign, $userId, $sectId))
1832 {
1833 return CCalendar::ThrowError(Loc::getMessage('EC_ACCESS_DENIED'));
1834 }
1835
1836 $arSections = self::GetList(
1837 array(
1838 'arFilter' => array('ID' => $sectId),
1839 'checkPermissions' => false,
1840 ));
1841
1842 if ($arSections && $arSections[0] && $arSections[0]['EXPORT'] && $arSections[0]['EXPORT']['ALLOW'])
1843 {
1844 $arSection = $arSections[0];
1845 $arEvents = CCalendarEvent::GetList(
1846 array(
1847 'arFilter' => array(
1848 'SECTION' => $arSection['ID'],
1849 ),
1850 'getUserfields' => false,
1851 'parseRecursion' => false,
1852 'fetchAttendees' => false,
1853 'fetchMeetings' => true,
1854 'userId' => $userId,
1855 )
1856 );
1857 $iCalEvents = self::FormatICal($arSection, $arEvents);
1858 }
1859 else
1860 {
1861 return CCalendar::ThrowError(Loc::getMessage('EC_ACCESS_DENIED'));
1862 }
1863
1864 self::ShowICalHeaders();
1865 echo $iCalEvents;
1866 exit();
1867 }
1868
1869 private static function ShowICalHeaders()
1870 {
1871 header("Content-Type: text/calendar; charset=UTF-8");
1872 header("Accept-Ranges: bytes");
1873 header("Connection: Keep-Alive");
1874 header("Keep-Alive: timeout=15, max=100");
1875 }
1876
1877 private static function FormatICal($section, $events)
1878 {
1879 global $APPLICATION;
1880
1881 $res = 'BEGIN:VCALENDAR'."\n".
1882 'PRODID:-//Bitrix//Bitrix Calendar//EN'."\n".
1883 'VERSION:2.0'."\n".
1884 'CALSCALE:GREGORIAN'."\n".
1885 'METHOD:PUBLISH'."\n".
1886 'X-WR-CALNAME:'.self::_ICalPaste($section['NAME'])."\n".
1887 'X-WR-CALDESC:'.self::_ICalPaste($section['DESCRIPTION'])."\n";
1888
1889 $localTime = new DateTime();
1890 $localOffset = $localTime->getOffset();
1891
1892 foreach ($events as $event)
1893 {
1894 $fromTs = CCalendar::Timestamp($event['DATE_FROM']);
1895 $toTs = CCalendar::Timestamp($event['DATE_TO']);
1896 if ($event['DT_SKIP_TIME'] === "Y")
1897 {
1898 $dtStart = date("Ymd", $fromTs);
1899 $dtEnd = date("Ymd", $toTs + CCalendar::GetDayLen());
1900 }
1901 else
1902 {
1903 $fromTsUTC = $fromTs - $event['TZ_OFFSET_FROM'];
1904 $toTsUTC = $toTs - $event['TZ_OFFSET_TO'];
1905 $dtStart = date("Ymd\THis\Z", $fromTsUTC);
1906 $dtEnd = date("Ymd\THis\Z", $toTsUTC);
1907 }
1908
1909 $dtStamp = str_replace('T000000Z', '', date("Ymd\THisZ", CCalendar::Timestamp($event['TIMESTAMP_X']) - $localOffset));
1910 $uid = md5(uniqid(rand(), true).$event['ID']).'@bitrix';
1911 $period = '';
1912
1913 $rrule = CCalendarEvent::ParseRRULE($event['RRULE']);
1914
1915 if($rrule && isset($rrule['FREQ']) && $rrule['FREQ'] !== 'NONE')
1916 {
1917 $period = 'RRULE:FREQ='.$rrule['FREQ'].';';
1918 $period .= 'INTERVAL='.$rrule['INTERVAL'].';';
1919 if ($rrule['FREQ'] === 'WEEKLY')
1920 {
1921 $period .= 'BYDAY='.implode(',', $rrule['BYDAY']).';';
1922 }
1923
1924 if (isset($rrule['COUNT']) && (int)$rrule['COUNT'] > 0)
1925 {
1926 $period .= 'COUNT='. (int)$rrule['COUNT'] .';';
1927 }
1928 else
1929 {
1930 $until = date("Ymd", $event['DATE_TO_TS_UTC']);
1931 if($until != '20380101')
1932 $period .= 'UNTIL='.$until.';';
1933 }
1934 $period .= 'WKST=MO';
1935 $period .= "\n";
1936 }
1937
1938 $res .= 'BEGIN:VEVENT'."\n";
1939
1940 if ($event['DT_SKIP_TIME'] === "Y")
1941 {
1942 $res .= 'DTSTART;VALUE=DATE:'.$dtStart."\n".
1943 'DTEND;VALUE=DATE:'.$dtEnd."\n";
1944 }
1945 else
1946 {
1947 $res .= 'DTSTART;VALUE=DATE-TIME:'.$dtStart."\n".
1948 'DTEND;VALUE=DATE-TIME:'.$dtEnd."\n";
1949 }
1950
1951 $res .= 'DTSTAMP:'.$dtStamp."\n".
1952 'UID:'.$uid."\n".
1953 'SUMMARY:'.self::_ICalPaste($event['NAME'])."\n".
1954 'DESCRIPTION:'.self::_ICalPaste($event['DESCRIPTION'])."\n".$period."\n".
1955 'LOCATION:'.self::_ICalPaste(CCalendar::GetTextLocation($event['LOCATION']))."\n".
1956 'SEQUENCE:0'."\n".
1957 'STATUS:CONFIRMED'."\n".
1958 'TRANSP:TRANSPARENT'."\n".
1959 'END:VEVENT'."\n";
1960 }
1961
1962 $res .= 'END:VCALENDAR';
1963
1964 return $res;
1965 }
1966
1967 private static function _ICalPaste($str)
1968 {
1969 $str = preg_replace ("/\r/i", '', $str);
1970 $str = preg_replace ("/\n/i", '\\n', $str);
1971 return $str;
1972 }
1973
1974 public static function GetModificationLabel($calendarId) // GetCalendarModificationLabel
1975 {
1976 global $DB;
1977 // We didn't have cashing for task list,
1978 // so just change modification label every 3 minutes
1979 if ($calendarId[0] === CCalendar::TASK_SECTION_ID)
1980 {
1981 return CCalendar::Date(round(time() / 180) * 180);
1982 }
1983
1984 $sectionId = (int)$calendarId[0];
1985 if ($sectionId > 0)
1986 {
1987 $strSql = "
1988 SELECT ".$DB->DateToCharFunction("CS.TIMESTAMP_X")." as TIMESTAMP_X
1989 FROM b_calendar_section CS
1990 WHERE ID=".$sectionId;
1991 $res = $DB->Query($strSql);
1992
1993 if($sect = $res->Fetch())
1994 return $sect['TIMESTAMP_X'];
1995 }
1996 return "";
1997 }
1998
1999 public static function UpdateModificationLabel($arId = [])
2000 {
2001 global $DB;
2002 if (!is_array($arId) && $arId)
2003 {
2004 $arId = [$arId];
2005 }
2006
2007 $arId = array_unique($arId);
2008 $strIds = [];
2009 foreach($arId as $id)
2010 {
2011 if ((int)$id > 0)
2012 {
2013 $strIds[] = (int)$id;
2014 }
2015 }
2016 $strIds = implode(',', $strIds);
2017
2018 if ($strIds)
2019 {
2020 $strSql =
2021 "UPDATE b_calendar_section SET ".
2022 $DB->PrepareUpdate("b_calendar_section", array('TIMESTAMP_X' => FormatDate(CCalendar::DFormat(true), time()))).
2023 " WHERE ID in (".$strIds.")";
2024 $DB->Query($strSql);
2025 }
2026 }
2027
2028 public static function GetDefaultAccess($type, $ownerId)
2029 {
2030 if (CCalendar::IsIntranetEnabled())
2031 {
2032 $access = array('G2' => CCalendar::GetAccessTasksByName('calendar_section', 'calendar_view_time'));
2033 }
2034 else
2035 {
2036 $access = array('G2' => CCalendar::GetAccessTasksByName('calendar_section', 'calendar_view'));
2037 }
2038
2039 if ($type === 'group' && $ownerId > 0)
2040 {
2041 $access['SG'.$ownerId.'_A'] = CCalendar::GetAccessTasksByName('calendar_section', 'calendar_access');
2042 $access['SG'.$ownerId.'_E'] = CCalendar::GetAccessTasksByName('calendar_section', 'calendar_edit');
2043 $access['SG'.$ownerId.'_K'] = CCalendar::GetAccessTasksByName('calendar_section', 'calendar_edit');
2044 }
2045 else if ($type !== 'user')
2046 {
2047 $access['G2'] = CCalendar::GetAccessTasksByName('calendar_section', 'calendar_edit');
2048 }
2049
2050 // Creator of the section
2051 if ($type !== 'user')
2052 {
2053 $access['U'.CCalendar::GetUserId()] = CCalendar::GetAccessTasksByName('calendar_section', 'calendar_access');
2054 }
2055
2056 $accessCodes = [];
2057 foreach($access as $code => $o)
2058 {
2059 $accessCodes[] = $code;
2060 }
2061
2062 CCalendar::PushAccessNames($accessCodes);
2063 return $access;
2064 }
2065
2066 public static function getAuthHash(int $userId, string $path)
2067 {
2068 global $USER;
2069 if ((!isset(self::$authHashiCal) || empty(self::$authHashiCal)) && $USER && is_object($USER))
2070 {
2071 self::$authHashiCal = $USER::GetHitAuthHash($path, $userId);
2072 if (empty(self::$authHashiCal))
2073 {
2074 self::$authHashiCal = $USER::AddHitAuthHash($path, $userId);
2075 }
2076 }
2077 return self::$authHashiCal;
2078 }
2079
2080 public static function CheckAuthHash()
2081 {
2082 global $USER;
2083 if ($_REQUEST['bx_hit_hash'] ?? null)
2084 {
2085 return $USER->LoginHitByHash($_REQUEST['bx_hit_hash']);
2086 }
2087
2088 return false;
2089 }
2090
2091 public static function GetLastUsedSection($type, $ownerId, $userId)
2092 {
2093 $userSettings = UserSettings::get($userId);
2094 return $userSettings['lastUsedSection'];
2095 }
2096
2097 public static function GetSectionForOwner($type, $ownerId, $autoCreate = true)
2098 {
2099 $sectionId = false;
2100 $autoCreated = false;
2101
2102 if (empty($type))
2103 {
2104 $type = 'user';
2105 }
2106
2107 $res = self::GetList([
2108 'arFilter' => [
2109 'CAL_TYPE' => $type,
2110 'OWNER_ID' => $ownerId,
2111 'DELETED' => 'N',
2112 'ACTIVE' => 'Y',
2113 'GAPI_CALENDAR_ID' => null,
2114 ],
2115 'checkPermissions' => false,
2116 'getPermissions' => false,
2117 'limit' => 1,
2118 ]);
2119
2120 $section = $res[0] ?? false;
2121
2122 if ($section)
2123 {
2124 $ownerId = $section['OWNER_ID'];
2125 $sectionId = $section['ID'];
2126 }
2127
2128 if (!$section && $autoCreate)
2129 {
2130 $section = self::CreateDefault([
2131 'type' => $type,
2132 'ownerId' => $ownerId,
2133 ]);
2134
2135 $autoCreated = true;
2136 $sectionId = $section['ID'];
2137 }
2138
2139 return [
2140 'sectionId' => $sectionId,
2141 'autoCreated' => $autoCreated,
2142 'section' => $section
2143 ];
2144 }
2145
2146 public static function HandlePermission($section = [])
2147 {
2148 if ($section && $section['ID'])
2149 {
2150 $sectionId = $section['ID'];
2151 if (!isset(self::$Permissions[$sectionId]) || !is_array(self::$Permissions[$sectionId]))
2152 {
2153 self::$Permissions[$sectionId] = [];
2154 }
2155
2156 if (isset($section['ACCESS_CODE']) && $section['ACCESS_CODE'] && $section['ACCESS_CODE'] !== '0' && (int)$section['TASK_ID'] > 0)
2157 {
2158 self::$Permissions[$sectionId][$section['ACCESS_CODE']] = (int)$section['TASK_ID'];
2159 }
2160
2161 if (isset($section['ACCESS']) && $section['ACCESS'])
2162 {
2163 self::$Permissions[$sectionId] = $section['ACCESS'];
2164 }
2165
2166 if ($section['CAL_TYPE'] !== 'group' && (int)$section['OWNER_ID'] > 0) // Owner for user or other calendar types
2167 {
2168 self::$Permissions[$sectionId]['U'.$section['OWNER_ID']] = CCalendar::GetAccessTasksByName('calendar_section', 'calendar_access');
2169 }
2170
2171 if ($section['CAL_TYPE'] === 'group' && (int)$section['OWNER_ID'] > 0) // Owner for group
2172 {
2173 self::$Permissions[$sectionId]['SG'.$section['OWNER_ID'].'_A'] = CCalendar::GetAccessTasksByName('calendar_section', 'calendar_access');
2174 }
2175 }
2176 }
2177
2178
2179 public static function CleanAccessTable(string $sectionId)
2180 {
2181 if (empty($sectionId))
2182 {
2183 return;
2184 }
2185
2186 global $DB;
2187
2188 $DB->Query("DELETE FROM b_calendar_access WHERE SECT_ID = '" . $sectionId . "'");
2189 }
2190
2196 public static function CheckGoogleVirtualSection($davXmlId = '', $externalType = ''): bool
2197 {
2198 return $davXmlId !== '' && (preg_match('/@virtual\/events\//i', (string)$davXmlId)
2199 || preg_match('/@group\.v\.calendar\.google/i', (string)$davXmlId)
2200 || $externalType === Google\Dictionary::ACCESS_ROLE_TO_EXTERNAL_TYPE['reader']
2201 || $externalType === Google\Dictionary::ACCESS_ROLE_TO_EXTERNAL_TYPE['freeBusyOrder']
2202 );
2203 }
2204
2205 public static function GetCount()
2206 {
2207 global $DB;
2208 $count = 0;
2209 $res = $DB->Query('select count(*) as c from b_calendar_section');
2210
2211 if($res = $res->Fetch())
2212 {
2213 $count = $res['c'];
2214 }
2215
2216 return $count;
2217 }
2218
2219 public static function GetSectionByEventId($id)
2220 {
2221 $resDb = EventTable::getList([
2222 'select' => ['SECTION_ID', 'OWNER_ID', 'CAL_TYPE'],
2223 'filter' => ['ID' => $id],
2224 ]);
2225
2226 return $resDb->fetch();
2227 }
2228
2229 public static function containsLocalSection($sections, $type): bool
2230 {
2231 if ($type !== 'user')
2232 {
2233 return true;
2234 }
2235
2236 if ($sections && is_array($sections))
2237 {
2238 foreach ($sections as $section)
2239 {
2240 if (
2241 $section['EXTERNAL_TYPE'] === self::EXTERNAL_TYPE_LOCAL
2242 && $section['CAL_TYPE'] === 'user'
2243 && (int)$section['OWNER_ID'] === CCalendar::GetOwnerId()
2244 )
2245 {
2246 return true;
2247 }
2248 }
2249 }
2250
2251 return false;
2252 }
2253
2265 public static function getAllSectionsForVendor(int $connectionId, array $type)
2266 {
2267 if (!Loader::includeModule('dav'))
2268 {
2269 return [
2270 'status' => 'error',
2271 'message' => Loc::getMessage('EC_SYNCAJAX_DAV_REQUIRED'),
2272 ];
2273 }
2275 $mapperFactory = \Bitrix\Main\DI\ServiceLocator::getInstance()->get('calendar.service.mappers.factory');
2276 if ($connection = $mapperFactory->getConnection()->getById($connectionId))
2277 {
2278 $userId = \CCalendar::GetUserId();
2279
2280 if ($connection->getOwner()->getId() !== $userId)
2281 {
2282 return [];
2283 }
2284
2285 return SectionTable::query()
2286 ->setSelect(['*', 'CONNECTION_ID' => 'LINK.CONNECTION_ID'])
2287 ->where('CAL_TYPE', 'user')
2288 ->where('OWNER_ID', $userId)
2289 ->whereIn('EXTERNAL_TYPE', $type)
2290 ->where('CONNECTION_ID', $connectionId)
2291 ->registerRuntimeField(
2292 new \Bitrix\Main\Entity\ReferenceField(
2293 'LINK',
2294 SectionConnectionTable::class,
2295 ['=this.ID' => 'ref.SECTION_ID'],
2296 ['join_type' => 'INNER']
2297 ),
2298 )->exec()->fetchAll()
2299 ;
2300 }
2301
2302 return [];
2303 }
2304
2305 public static function prepareSectionListResponse(string $type, string $ownerId): array
2306 {
2307 $userId = CCalendar::GetCurUserId();
2308 $followedSectionList = UserSettings::getFollowedSectionIdList($userId);
2309
2310 $isNotInternalUser =
2311 Loader::includeModule('extranet')
2312 && !\CExtranet::IsIntranetUser(SITE_ID, $userId)
2313 ;
2314 if ($isNotInternalUser)
2315 {
2316 // Check permissions for group
2317 if ($type === 'group')
2318 {
2319 $perm = CCalendar::GetPermissions([
2320 'type' => $type,
2321 'ownerId' => $ownerId,
2322 'userId' => $userId,
2323 'setProperties' => false
2324 ]);
2325 // For all members of the group it will be true so we want to skip everybody else
2326 if (!$perm['edit'])
2327 {
2328 return [];
2329 }
2330 }
2331 else // user's and company calendars are not available for external users
2332 {
2333 return [];
2334 }
2335 }
2336
2337 if (
2338 in_array($type, ['user', Dictionary::CALENDAR_TYPE['open_event']], true)
2339 && OpenEvents\Feature::getInstance()->isAvailable()
2340 )
2341 {
2342 $type = ['user', Dictionary::CALENDAR_TYPE['open_event']];
2343 $ownerId = [$ownerId, 0];
2344 }
2345
2346 $sectionList = CCalendar::getSectionList([
2347 'CAL_TYPE' => $type,
2348 'OWNER_ID' => $ownerId,
2349 'ACTIVE' => 'Y',
2350 'ADDITIONAL_IDS' => $followedSectionList,
2351 'checkPermissions' => true,
2352 'getPermissions' => true,
2353 'getImages' => true
2354 ]);
2355
2356 $sectionList = array_merge($sectionList, CCalendar::getSectionListAvailableForUser($userId));
2357 $sections = [];
2358 $sectionIdList = [];
2359
2360 foreach ($sectionList as $section)
2361 {
2362 if (!in_array((int)$section['ID'], $sectionIdList))
2363 {
2364 if (in_array($section['ID'], $followedSectionList))
2365 {
2366 $section['SUPERPOSED'] = true;
2367 }
2368
2369 if (!empty($section['NAME']))
2370 {
2371 $section['NAME'] = Emoji::decode($section['NAME']);
2372 }
2373 $sections[] = $section;
2374 $sectionIdList[] = (int) $section['ID'];
2375 }
2376 }
2377
2378 return $sections;
2379 }
2380
2388 public static function getSectionConnectionList(array $sectionIdList): array
2389 {
2390 $noCacheForSectionIds = array_diff($sectionIdList, array_keys(self::$sectionConnectionCache));
2391
2392 if (!$noCacheForSectionIds)
2393 {
2394 $result = [];
2395 foreach ($sectionIdList as $sectionId)
2396 {
2397 $result = [...$result, ...self::$sectionConnectionCache[$sectionId]];
2398 }
2399
2400 return $result;
2401 }
2402
2403 $sectionConnections = SectionConnectionTable::query()
2404 ->setSelect([
2405 'SECTION_ID',
2406 'CONNECTION_ID',
2407 'ACTIVE',
2408 'IS_PRIMARY',
2409 ])
2410 ->whereIn('SECTION_ID', $sectionIdList)
2411 ->fetchCollection()
2412 ;
2413
2414 foreach ($sectionIdList as $sectionId)
2415 {
2416 self::$sectionConnectionCache[$sectionId] = [];
2417 }
2418
2419 foreach ($sectionConnections as $sectionConnection)
2420 {
2421 self::$sectionConnectionCache[$sectionConnection->getSectionId()][] = $sectionConnection;
2422 }
2423
2424 return $sectionConnections->getAll();
2425 }
2426}
2427?>
$path
Определения access_edit.php:21
$connection
Определения actionsdefinitions.php:38
$count
Определения admin_tab.php:4
$type
Определения options.php:106
global $APPLICATION
Определения include.php:80
if($strVal !='') $sectionFields
Определения options.php:1848
$accessController
Определения options.php:23
$arResult
Определения generate_coupon.php:16
if(!Loader::includeModule('catalog')) if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_PRICE_EDIT)) if(!check_bitrix_sessid()) $request
Определения catalog_reindex.php:36
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
static getInstance()
Определения Feature.php:16
static createInstanceWithRoom(Room $room)
Определения manager.php:41
const ACCESS_ROLE_TO_EXTERNAL_TYPE
Определения dictionary.php:8
static getFollowedSectionIdList($userId=false)
Определения usersettings.php:330
static get($userId=null)
Определения usersettings.php:86
Определения util.php:21
static isSectionStructureConverted()
Определения util.php:49
static addPullEvent(PushCommand $command, int $userId, array $params=[])
Определения util.php:385
static getPathToCalendar(?int $ownerId, ?string $type)
Определения util.php:591
static getUserAccessCodes(int $userId)
Определения util.php:546
static getConnection($name="")
Определения application.php:638
static getInstance()
Определения eventmanager.php:31
Определения loader.php:13
static includeModule($moduleName)
Определения loader.php:67
static filter()
Определения query.php:906
static getString($length, $caseSensitive=false)
Определения random.php:76
Определения emoji.php:10
static encode($text)
Определения emoji.php:17
static decode($text)
Определения emoji.php:24
static GetOperations($ID, $return_names=false)
Определения task.php:230
static ParseRRULE($rule=null)
Определения calendar_event.php:2732
static Color($color='', $defaultColor=true)
Определения calendar.php:3645
static Timestamp($date, $bRound=true, $bTime=true)
Определения calendar.php:5219
static GetUserName($user)
Определения calendar.php:5674
static OnDeleteCalendarEventEntry($eventId)
Определения calendar_livefeed.php:1052
Определения calendar_sect.php:33
static getAuthHash(int $userId, string $path)
Определения calendar_sect.php:2066
const OPERATION_EDIT_SECTION
Определения calendar_sect.php:40
static CleanFieldsValueById(int $sectionId, array $fields)
Определения calendar_sect.php:1595
static GetModificationLabel($calendarId)
Определения calendar_sect.php:1974
static prepareSectionListResponse(string $type, string $ownerId)
Определения calendar_sect.php:2305
static Edit($params)
Определения calendar_sect.php:994
static GetCount()
Определения calendar_sect.php:2205
static CreateDefault($params=[])
Определения calendar_sect.php:1279
static getSectionConnectionList(array $sectionIdList)
Определения calendar_sect.php:2388
static GetLastUsedSection($type, $ownerId, $userId)
Определения calendar_sect.php:2091
static UpdateModificationLabel($arId=[])
Определения calendar_sect.php:1999
static $sectionAccessCache
Определения calendar_sect.php:45
static SetClearOperationCache($val=true)
Определения calendar_sect.php:1433
static cleanLinkTables($sectId)
Определения calendar_sect.php:1768
static CleanAccessTable(string $sectionId)
Определения calendar_sect.php:2179
static HandlePermission($section=[])
Определения calendar_sect.php:2146
const OPERATION_EDIT
Определения calendar_sect.php:39
static CheckGoogleVirtualSection($davXmlId='', $externalType='')
Определения calendar_sect.php:2196
GetSPExportLink()
Определения calendar_sect.php:1782
static CheckSign($sign, $userId, $sectId)
Определения calendar_sect.php:1814
static $sectionConnectionCache
Определения calendar_sect.php:44
static GetDefaultAccess($type, $ownerId)
Определения calendar_sect.php:2028
static GetOutlookLink($Params)
Определения calendar_sect.php:1788
static GetList($params=[])
Определения calendar_sect.php:130
const OPERATION_VIEW_TIME
Определения calendar_sect.php:35
const OPERATION_VIEW_FULL
Определения calendar_sect.php:37
static GetSectionForOwner($type, $ownerId, $autoCreate=true)
Определения calendar_sect.php:2097
static GetArrayPermissions($arSections=[])
Определения calendar_sect.php:1402
const OPERATION_ADD
Определения calendar_sect.php:38
static GetSectionByEventId($id)
Определения calendar_sect.php:2219
static Delete($id, $checkPermissions=true, $params=[])
Определения calendar_sect.php:1174
static ReturnICal($Params)
Определения calendar_sect.php:1820
static CheckAuthHash()
Определения calendar_sect.php:2080
static GetSign($userId, $sectId)
Определения calendar_sect.php:1809
static $sendPush
Определения calendar_sect.php:43
static containsLocalSection($sections, $type)
Определения calendar_sect.php:2229
static SavePermissions($sectId, $taskPerm)
Определения calendar_sect.php:1362
static CanDo($operation, $sectId=0, $userId=null)
Определения calendar_sect.php:1438
static GetExportLink($sectionId, $type='', $ownerId=null)
Определения calendar_sect.php:1577
static GetCalDAVConnectionId($section=0)
Определения calendar_sect.php:1543
const EXTERNAL_TYPE_LOCAL
Определения calendar_sect.php:34
static GetOperations($sectId, $userId=null)
Определения calendar_sect.php:1492
const OPERATION_EDIT_ACCESS
Определения calendar_sect.php:41
const OPERATION_VIEW_TITLE
Определения calendar_sect.php:36
$str
Определения commerceml2.php:63
$arFields
Определения dblapprove.php:5
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
$perm
Определения options.php:169
$_REQUEST["admin_mnu_menu_id"]
Определения get_menu.php:8
$result
Определения get_property_values.php:14
$query
Определения get_search.php:11
$uid
Определения hot_keys_act.php:8
$filter
Определения iblock_catalog_list.php:54
$filterFields
Определения iblock_catalog_list.php:55
$selectFields
Определения iblock_catalog_list.php:160
global $DB
Определения cron_frame.php:29
global $USER
Определения csv_new_run.php:40
$context
Определения csv_new_setup.php:223
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
Определения options.php:195
if(!is_array($deviceNotifyCodes)) $access
Определения options.php:174
ExecuteModuleEventEx($arEvent, $arParams=[])
Определения tools.php:5214
FormatDate($format="", $timestamp=false, $now=false, ?string $languageId=null)
Определения tools.php:871
$name
Определения menu_edit.php:35
Определения culture.php:9
string $sectionId
Определения columnfields.php:71
$GLOBALS['____1690880296']
Определения license.php:1
$order
Определения payment.php:8
$sign
Определения payment.php:69
$event
Определения prolog_after.php:141
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$val
Определения options.php:1793
$arRes
Определения options.php:104
const SITE_ID
Определения sonet_set_content_view.php:12
$n
Определения update_log.php:107
$arSections
Определения yandex_run.php:805
$fields
Определения yandex_run.php:501