PageRenderTime 116ms CodeModel.GetById 51ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/calendar/lib/util.php

https://gitlab.com/alexprowars/bitrix
PHP | 672 lines | 504 code | 68 blank | 100 comment | 72 complexity | ec9a27adc9ebf9e6b27b1e1ad9928aa5 MD5 | raw file
  1<?php
  2namespace Bitrix\Calendar;
  3
  4use Bitrix\Calendar\Sync\Util\MsTimezoneConverter;
  5use Bitrix\Main;
  6use Bitrix\Main\Loader;
  7use Bitrix\Main\Localization\LanguageTable;
  8use Bitrix\Main\Type\Date;
  9use Bitrix\Main\Type\DateTime;
 10
 11class Util
 12{
 13	public const USER_SELECTOR_CONTEXT = "CALENDAR";
 14	public const LIMIT_NUMBER_BANNER_IMPRESSIONS = 3;
 15	public const DATETIME_PHP_FORMAT = 'Y-m-d H:i:sP';
 16
 17	private static $requestUid = '';
 18	private static $userAccessCodes = [];
 19	private static $pathCache = [];
 20
 21	/**
 22	 * @param $managerId
 23	 * @param $userId
 24	 * @return bool
 25	 */
 26	public static function isManagerForUser($managerId, $userId): bool
 27	{
 28		return in_array('IU'.$userId, self::getUserAccessCodes($managerId));
 29	}
 30
 31	/**
 32	 * @return bool
 33	 * @throws Main\ArgumentNullException
 34	 * @throws Main\ArgumentOutOfRangeException
 35	 */
 36	public static function isSectionStructureConverted(): bool
 37	{
 38		return \Bitrix\Main\Config\Option::get('calendar', 'sectionStructureConverted', 'N') === 'Y';
 39	}
 40
 41	/**
 42	 * @param $date
 43	 * @param bool $round
 44	 * @param bool $getTime
 45	 * @return false|float|int
 46	 */
 47	public static function getTimestamp($date, $round = true, $getTime = true)
 48	{
 49		$timestamp = MakeTimeStamp($date, \CSite::getDateFormat($getTime ? "FULL" : "SHORT"));
 50
 51		return $round ? (round($timestamp / 60) * 60) : $timestamp;
 52	}
 53
 54	/**
 55	 * @param string|null $timeZone
 56	 * @return bool
 57	 */
 58	public static function isTimezoneValid(?string $timeZone): bool
 59	{
 60		return (!is_null($timeZone) && $timeZone !== 'false' && in_array($timeZone, timezone_identifiers_list(), true));
 61	}
 62
 63	/**
 64	 * @param string|null $tz
 65	 * @return \DateTimeZone
 66	 */
 67	public static function prepareTimezone(?string $tz = null): \DateTimeZone
 68	{
 69		if (!$tz)
 70		{
 71			return new \DateTimeZone("UTC");
 72		}
 73
 74		if (self::isTimezoneValid($tz))
 75		{
 76			return new \DateTimeZone($tz);
 77		}
 78
 79		if ($timezones = MsTimezoneConverter::getValidateTimezones($tz))
 80		{
 81			return new \DateTimeZone($timezones[0]);
 82		}
 83
 84		return new \DateTimeZone(self::getServerTimezoneName());
 85	}
 86
 87	/**
 88	 * @param string|null $date
 89	 * @param bool $fullDay
 90	 * @param string $tz
 91	 * @return Date
 92	 * @throws Main\ObjectException
 93	 */
 94	public static function getDateObject(string $date = null, $fullDay = true, $tz = 'UTC'): Date
 95	{
 96		$preparedDate = $date;
 97		if ($date)
 98		{
 99			$timestamp = \CCalendar::Timestamp($date, false, !$fullDay);
100			$preparedDate = \CCalendar::Date($timestamp, !$fullDay);
101		}
102
103		return $fullDay
104			? new Date($preparedDate, Date::convertFormatToPhp(FORMAT_DATE))
105			: new DateTime($preparedDate, Date::convertFormatToPhp(FORMAT_DATETIME), Util::prepareTimezone($tz));
106	}
107
108	/**
109	 * @return string
110	 */
111	public static function getUserSelectorContext(): string
112	{
113		return self::USER_SELECTOR_CONTEXT;
114	}
115
116	public static function checkRuZone(): bool
117	{
118		if (\Bitrix\Main\ModuleManager::isModuleInstalled('bitrix24'))
119		{
120			$isRussian = (\CBitrix24::getPortalZone() === 'ru');
121		}
122		else
123		{
124			$iterator = LanguageTable::getList([
125				'select' => ['ID'],
126				'filter' => ['=ID' => 'ru', '=ACTIVE' => 'Y']
127			]);
128
129			$row = $iterator->fetch();
130			if (empty($row))
131			{
132				$isRussian = false;
133			}
134			else
135			{
136				$iterator = LanguageTable::getList([
137					'select' => ['ID'],
138					'filter' => ['@ID' => ['ua', 'by', 'kz'], '=ACTIVE' => 'Y'],
139					'limit' => 1
140				]);
141				$row = $iterator->fetch();
142				$isRussian = empty($row);
143			}
144		}
145
146		return $isRussian;
147	}
148
149	public static function convertEntitiesToCodes($entityList = [])
150	{
151		$codeList = [];
152		if (is_array($entityList))
153		{
154			foreach($entityList as $entity)
155			{
156				if ($entity['entityId'] === 'meta-user' && $entity['id'] === 'all-users')
157				{
158					$codeList[] = 'UA';
159				}
160				elseif ($entity['entityId'] === 'user')
161				{
162					$codeList[] = 'U'.$entity['id'];
163				}
164				elseif ($entity['entityId'] === 'project' || $entity['entityId'] === 'project-roles')
165				{
166					$codeList[] = 'SG'.$entity['id'];
167				}
168				elseif ($entity['entityId'] === 'department')
169				{
170					$codeList[] = 'DR'.$entity['id'];
171				}
172			}
173		}
174		return $codeList;
175	}
176
177	public static function convertCodesToEntities($codeList = [])
178	{
179		$entityList = [];
180		if (is_array($codeList))
181		{
182			foreach($codeList as $code)
183			{
184				if ($code === 'UA')
185				{
186					$entityList[] = [
187						'entityId' => 'meta-user',
188						'id' => 'all-users'
189					];
190				}
191				elseif (mb_substr($code, 0, 1) == 'U')
192				{
193					$entityList[] = [
194						'entityId' => 'user',
195						'id' => intval(mb_substr($code, 1))
196					];
197				}
198				if (mb_substr($code, 0, 2) == 'DR')
199				{
200					$entityList[] = [
201						'entityId' => 'department',
202						'id' => intval(mb_substr($code, 2))
203					];
204				}
205				elseif (preg_match('/^SG([0-9]+)_?([AEKMO])?$/', $code, $match) && isset($match[2]))
206				{
207					// todo May need to be removed/rewrite after creating new roles in projects.
208					$entityList[] = [
209						'entityId' => 'project-roles',
210						'id' => mb_substr($code, 2)
211					];
212				}
213				elseif (mb_substr($code, 0, 2) == 'SG')
214				{
215					$entityList[] = [
216						'entityId' => 'project',
217						'id' => intval(mb_substr($code, 2))
218					];
219				}
220			}
221		}
222
223		return $entityList;
224	}
225
226	public static function getUsersByEntityList($entityList, $fetchUsers = false)
227	{
228		if (!Main\Loader::includeModule('socialnetwork'))
229		{
230			return [];
231		}
232		$users = \CSocNetLogDestination::getDestinationUsers(self::convertEntitiesToCodes($entityList), $fetchUsers);
233		if ($fetchUsers)
234		{
235			for ($i = 0, $l = count($users); $i < $l; $i++)
236			{
237				$users[$i]['FORMATTED_NAME'] = \CCalendar::getUserName($users[$i]);
238			}
239		}
240		return $users;
241	}
242
243
244	public static function getDefaultEntityList($userId, $type, $ownerId)
245	{
246		$entityList = [['entityId' => 'user', 'id' => $userId]];
247		if ($type === 'user' && $ownerId !== $userId)
248		{
249			$entityList[] = ['entityId' => 'user', 'id' => $ownerId];
250		}
251		else if($type === 'group')
252		{
253			$entityList[] = ['entityId' => 'project', 'id' => $ownerId];
254		}
255		return $entityList;
256	}
257
258	/**
259	 * @param array|null $codeAttendees
260	 * @param string $stringWrapper
261	 * @return array
262	 * @throws Main\ArgumentException
263	 * @throws Main\ObjectPropertyException
264	 * @throws Main\SystemException
265	 */
266	public static function getAttendees(array $codeAttendees = null, string $stringWrapper = ''): array
267	{
268		if (empty($codeAttendees))
269		{
270			return [];
271		}
272
273		$userIdList = [];
274		$userList = [];
275
276		foreach ($codeAttendees as $codeAttend)
277		{
278			if (mb_strpos($codeAttend, 'U') === 0)
279			{
280				$userId = (int)(mb_substr($codeAttend, 1));
281				$userIdList[] = $userId;
282			}
283		}
284
285		if (!empty($userIdList))
286		{
287			$res = \Bitrix\Main\UserTable::getList(array(
288				'filter' => [
289					'=ID' => $userIdList,
290				],
291				'select' => ['NAME', 'LAST_NAME'],
292			));
293
294			while ($user = $res->fetch())
295			{
296				$userList[] = addcslashes($stringWrapper . $user['NAME'].' '.$user['LAST_NAME'] . $stringWrapper, "()");
297			}
298		}
299
300		return $userList;
301	}
302
303	/**
304	 * @return bool
305	 */
306	public static function isShowDailyBanner(): bool
307	{
308		$isInstallMobileApp = (bool)\CUserOptions::GetOption('mobile', 'iOsLastActivityDate', false)
309			|| (bool)\CUserOptions::GetOption('mobile', 'AndroidLastActivityDate', false)
310		;
311		$isSyncCalendar = (bool)\CUserOptions::GetOption('calendar', 'last_sync_iphone', false)
312			|| (bool)\CUserOptions::GetOption('calendar', 'last_sync_android', false)
313		;
314		if ($isInstallMobileApp && $isSyncCalendar)
315		{
316			return false;
317		}
318
319		$dailySyncBanner = \CUserOptions::GetOption('calendar', 'daily_sync_banner', []);
320		if (!isset($dailySyncBanner['last_sync_day']) && !isset($dailySyncBanner['count']))
321		{
322			$dailySyncBanner['last_sync_day'] = '';
323			$dailySyncBanner['count'] = 0;
324		}
325		$today = (new Main\Type\Date())->format('Y-m-d');
326		$isShowToday = ($today === $dailySyncBanner['last_sync_day']);
327		$isLimitExceeded = ($dailySyncBanner['count'] >= self::LIMIT_NUMBER_BANNER_IMPRESSIONS);
328
329		if ($isLimitExceeded || $isShowToday)
330		{
331			return false;
332		}
333		else
334		{
335			++$dailySyncBanner['count'];
336			$dailySyncBanner['last_sync_day'] = (new Main\Type\Date())->format('Y-m-d');
337			\CUserOptions::SetOption('calendar', 'daily_sync_banner', $dailySyncBanner);
338			return true;
339		}
340
341	}
342
343	/**
344	 * @param int $userId
345	 * @return bool
346	 * @throws Main\ArgumentException
347	 * @throws Main\LoaderException
348	 * @throws Main\ObjectPropertyException
349	 * @throws Main\SystemException
350	 */
351	public static function isExtranetUser(int $userId): bool
352	{
353		if (Loader::includeModule('intranet'))
354		{
355			$userDb = \Bitrix\Intranet\UserTable::getList([
356				'filter' => [
357					'ID' => $userId,
358				],
359				'select' => [
360					'USER_TYPE',
361				]
362			]);
363
364			$user = $userDb->fetch();
365			return $user['USER_TYPE'] === 'extranet';
366		}
367
368		return false;
369	}
370
371	/**
372	 * @param int $eventId
373	 * @return array|null
374	 * @throws Main\ArgumentException
375	 * @throws Main\ObjectPropertyException
376	 * @throws Main\SystemException
377	 */
378	public static function getEventById(int $eventId): ?array
379	{
380		$eventDb = Internals\EventTable::getList([
381			'filter' => [
382				'=ID' => $eventId,
383			],
384		]);
385
386		if ($event = $eventDb->fetch())
387		{
388			return $event;
389		}
390
391		return null;
392	}
393
394	/**
395	 * @param string $command
396	 * @param int $userId
397	 * @param array $params
398	 * @return bool
399	 */
400	public static function addPullEvent(string $command, int $userId, array $params = []): bool
401	{
402		if (!Loader::includeModule("pull"))
403		{
404			return false;
405		}
406
407		if (
408			in_array($command, [
409				'edit_event',
410				'delete_event',
411				'set_meeting_status',
412			])
413		)
414		{
415			\CPullWatch::AddToStack(
416				'calendar-planner-'.$userId,
417				[
418					'module_id' => 'calendar',
419					'command' => $command,
420					'params' => $params
421				]
422			);
423		}
424
425		if (
426			in_array($command, [
427				'edit_event',
428				'delete_event',
429				'set_meeting_status',
430			])
431			&& isset($params['fields'])
432			&& isset($params['fields']['SECTION_OWNER_ID'])
433			&& (int)$params['fields']['SECTION_OWNER_ID'] !== $userId
434		)
435		{
436			\Bitrix\Pull\Event::add(
437				(int)$params['fields']['SECTION_OWNER_ID'],
438				[
439					'module_id' => 'calendar',
440					'command' => $command,
441					'params' => $params
442				]
443			);
444		}
445
446		return \Bitrix\Pull\Event::add(
447			$userId,
448			[
449				'module_id' => 'calendar',
450				'command' => $command,
451				'params' => $params
452			]
453		);
454	}
455
456	/**
457	 * @param int $currentUserId
458	 * @param array $userIdList
459	 *
460	 * @return void
461	 */
462	public static function initPlannerPullWatches(int $currentUserId, array $userIdList = []): void
463	{
464		if (Loader::includeModule("pull"))
465		{
466			foreach($userIdList as $userId)
467			{
468				if ((int)$userId !== $currentUserId)
469				{
470					\CPullWatch::Add($currentUserId, 'calendar-planner-'.$userId);
471				}
472			}
473		}
474	}
475
476	public static function getUserFieldsByEventId(int $eventId): array
477	{
478		global $DB;
479		$result = [];
480		$strSql = "SELECT * from b_uts_calendar_event WHERE VALUE_ID=" . $eventId;
481		$ufDb = $DB->query($strSql);
482
483		while ($uf = $ufDb->fetch())
484		{
485			$result[] = [
486				'crm' => unserialize($uf['UF_CRM_CAL_EVENT'], ['allowed_classes' => false]),
487				'webdav' => unserialize($uf['UF_WEBDAV_CAL_EVENT'], ['allowed_classes' => false]),
488			];
489		}
490
491		return $result;
492	}
493
494	/**
495	 * @return string
496	 */
497	public static function getServerTimezoneName(): string
498	{
499		return (new \DateTime())->getTimezone()->getName();
500	}
501
502	/**
503	 * @return int
504	 */
505	public static function getServerOffsetUTC(): int
506	{
507		return (new \DateTime())->getOffset();
508	}
509
510	/**
511	 * @param string|null $tz
512	 * @param null $date
513	 * @return int
514	 * @throws \Exception
515	 */
516	public static function getTimezoneOffsetFromServer(?string $tz = 'UTC', $date = null): int
517	{
518		if ($date instanceof Date)
519		{
520			$timestamp = $date->format(self::DATETIME_PHP_FORMAT);
521		}
522		elseif ($date === null)
523		{
524			$timestamp = 'now';
525		}
526		else
527		{
528			$timestamp = "@".(int)$date;
529		}
530
531		$date = new \DateTime($timestamp, self::prepareTimezone($tz));
532
533		return $date->getOffset() - self::getServerOffsetUTC();
534	}
535
536	/**
537	 * @param string $requestUid
538	 */
539	public static function setRequestUid(string $requestUid = ''): void
540	{
541		self::$requestUid = $requestUid;
542	}
543
544	/**
545	 * @return string
546	 */
547	public static function getRequestUid(): string
548	{
549		return self::$requestUid;
550	}
551
552	/**
553	 * @param int $userId
554	 * @return array
555	 */
556	public static function getUserAccessCodes(int $userId): array
557	{
558		global $USER;
559		$userId = (int)$userId;
560		if (!$userId)
561		{
562			$userId = \CCalendar::GetCurUserId();
563		}
564
565		if (!isset(self::$userAccessCodes[$userId]))
566		{
567			$codes = [];
568			$r = \CAccess::GetUserCodes($userId);
569			while($code = $r->Fetch())
570			{
571				$codes[] = $code['ACCESS_CODE'];
572			}
573
574			if (!in_array('G2', $codes))
575			{
576				$codes[] = 'G2';
577			}
578
579			if (!in_array('AU', $codes) && $USER && (int)$USER->GetId() === $userId)
580			{
581				$codes[] = 'AU';
582			}
583
584			if(!in_array('UA', $codes) && $USER && (int)$USER->GetId() == $userId)
585			{
586				$codes[] = 'UA';
587			}
588
589			self::$userAccessCodes[$userId] = $codes;
590		}
591
592		return self::$userAccessCodes[$userId];
593	}
594
595
596	/**
597	 * @param int $ownerId
598	 * @param string $type
599	 * @return string
600	 */
601	public static function getPathToCalendar(?int $ownerId, ?string $type): string
602	{
603		$key = $type . $ownerId;
604		if (!isset(self::$pathCache[$key]) || !is_string(self::$pathCache[$key]))
605		{
606			if ($type === 'user')
607			{
608				$path = \COption::GetOptionString(
609					'calendar',
610					'path_to_user_calendar',
611					\COption::getOptionString('socialnetwork', 'user_page', "/company/personal/")
612					. "user/#user_id#/calendar/"
613				);
614			}
615			elseif ($type === 'group')
616			{
617				$path = \COption::GetOptionString(
618					'calendar',
619					'path_to_group_calendar',
620					\COption::getOptionString('socialnetwork', 'workgroups_page', "/workgroups/")
621					. "group/#group_id#/calendar/"
622				);
623			}
624			else
625			{
626				$settings = \CCalendar::GetSettings();
627				$path = $settings['path_to_type_' . $type];
628			}
629
630			if (!\COption::GetOptionString('calendar', 'pathes_for_sites', true))
631			{
632				$siteId = \CCalendar::GetSiteId();
633				$pathList = \CCalendar::GetPathes();
634				if (isset($pathList[$siteId]))
635				{
636					if ($type === 'user' && isset($pathList[$siteId]['path_to_user_calendar']))
637					{
638						$path = $pathList[$siteId]['path_to_user_calendar'];
639					}
640					elseif ($type === 'group' && isset($pathList[$siteId]['path_to_group_calendar']))
641					{
642						$path = $pathList[$siteId]['path_to_group_calendar'];
643					}
644					else
645					{
646						$path = $pathList[$siteId]['path_to_type_' . $type];
647					}
648				}
649			}
650
651			if (!is_string($path))
652			{
653				$path =  '';
654			}
655
656			if (!empty($path) && $ownerId > 0)
657			{
658				if ($type === 'user')
659				{
660					$path = str_replace(['#user_id#', '#USER_ID#'], $ownerId, $path);
661				}
662				elseif ($type === 'group')
663				{
664					$path = str_replace(['#group_id#', '#GROUP_ID#'], $ownerId, $path);
665				}
666			}
667			self::$pathCache[$key] = $path;
668		}
669
670		return self::$pathCache[$key];
671	}
672}