• Модуль: dav
  • Путь к файлу: ~/bitrix/modules/dav/classes/general/exchangecalendar2.php
  • Класс: CDavExchangeCalendar
  • Вызов: CDavExchangeCalendar::DoDataSync
static function DoDataSync($paramUserId, &$lastError): ?bool
	{
		if (DAV_EXCH_DEBUG)
		{
			CDav::WriteToLog("Starting EXCHANGE sync...", "SYNCE");
		}

		$exchangeScheme = COption::GetOptionString("dav", "exchange_scheme", "http");
		$exchangeServer = COption::GetOptionString("dav", "exchange_server", "");
		$exchangePort = COption::GetOptionString("dav", "exchange_port", "80");
		$exchangeUsername = COption::GetOptionString("dav", "exchange_username", "");
		$exchangePassword = COption::GetOptionString("dav", "exchange_password", "");

		if (empty($exchangeServer)/* || (COption::GetOptionString("dav", "agent_calendar", "N") != "Y")*/)
		{
			CAgent::RemoveAgent("CDavExchangeCalendar::DataSync();", "dav");
			COption::SetOptionString("dav", "agent_calendar", "N");
			return null;
		}

		static $arWeekDayMap = ["sunday" => 6, "monday" => 0, "tuesday" => 1, "wednesday" => 2, "thursday" => 3, "friday" => 4, "saturday" => 5];
		$exchange = new CDavExchangeCalendar(
			$exchangeScheme,
			$exchangeServer,
			$exchangePort,
			$exchangeUsername,
			$exchangePassword
		);
		if (GW_DEBUG)
		{
			$exchange->Debug();
		}

		$exchangeMailbox = COption::GetOptionString("dav", "exchange_mailbox", "");
		$exchangeUseLogin = COption::GetOptionString("dav", "exchange_use_login", "Y");

		self::InitUserEntity();

		$maxNumber = 15;
		$index = 0;
		$bShouldClearCache = null;

		$paramUserId = (int)$paramUserId;
		$arUserFilter = ["ACTIVE" => "Y", "!UF_DEPARTMENT" => false];
		if ($paramUserId > 0)
		{
			$arUserFilter["ID_EQUAL_EXACT"] = $paramUserId;
		}
		if ($exchangeUseLogin === "N")
		{
			$arUserFilter["!UF_BXDAVEX_MAILBOX"] = false;
		}

		$dbUserList = CUser::GetList("UF_BXDAVEX_CALSYNC",
			"asc",
			$arUserFilter,
			[
				"SELECT" => ["UF_BXDAVEX_MAILBOX", "UF_BXDAVEX_CALSYNC"],
				"FIELDS" => ['ID', 'LOGIN'],
				"NAV_PARAMS" => ["nTopCount" => $maxNumber]
			]
		);

		$usersToSync = [];
		$handledUsers = [];

		while ($arUser = $dbUserList->Fetch())
		{
			$index++;
			if ($index > $maxNumber)
			{
				break;
			}

			if (DAV_EXCH_DEBUG)
			{
				CDav::WriteToLog("Processing user [" . $arUser["ID"] . "] " . $arUser["LOGIN"], "SYNCE");
			}

			$GLOBALS["USER_FIELD_MANAGER"]->Update("USER", $arUser["ID"], array("UF_BXDAVEX_CALSYNC" => ConvertTimeStamp(time(), "FULL")));

			$mailbox = (($exchangeUseLogin === "Y") ? $arUser["LOGIN"].$exchangeMailbox : trim($arUser["UF_BXDAVEX_MAILBOX"]));
			if (empty($mailbox))
			{
				$lastError = GetMessage("DAV_EC_EMPTY_MAILBOX");
				continue;
			}

			$arCalendarsList = $exchange->GetCalendarsList(["mailbox" => $mailbox]);
			$arErrorsTmp = $exchange->GetErrors();
			if (!empty($arErrorsTmp))
			{
				$txt = '';
				foreach ($arErrorsTmp as $v)
				{
					if (!empty($txt))
					{
						$txt .= ", ";
					}
					$txt .= "[".$v[0]."] ".$v[1];
				}
				if (DAV_EXCH_DEBUG)
				{
					CDav::WriteToLog("ERROR: " . $txt, "SYNCE");
				}
				$lastError = $txt;
				continue;
			}

			if (!is_array($arCalendarsList))
			{
				$lastError = "Incorrect Data from Exchange Server";
				continue;
			}

			$bShouldClearCache = false;
			$arUserCalendars = [
				[
					"XML_ID" => "calendar_".$arUser["ID"],
					"NAME" => GetMessage("DAV_EC_CALENDAR"),
					"MODIFICATION_LABEL" => "",
				]
			];
			foreach ($arCalendarsList as $value)
			{
				$arUserCalendars[] = [
					"XML_ID" => $value["XML_ID"],
					"NAME" => $value["NAME"],
					"MODIFICATION_LABEL" => $value["MODIFICATION_LABEL"],
				];
			}

			$tmpNumCals = count($arUserCalendars);
			$arUserCalendars = CCalendarSync::SyncCalendarSections("exchange", $arUserCalendars, "user", $arUser["ID"]);
			$tmpNumItems = 0;

			foreach ($arUserCalendars as $userCalendar)
			{
				$userCalendarXmlId = $userCalendar["XML_ID"];
				$userCalendarXmlId = (($userCalendarXmlId === "calendar_".$arUser["ID"]) ? "calendar" : $userCalendarXmlId);

				$arCalendarItemsList = $exchange->GetList(
					["mailbox" => $mailbox, "CalendarId" => $userCalendarXmlId],
					["ItemShape" => "IdOnly"]
				);

				if(!empty($arCalendarItemsList))
				{
					$arUserCalendarItems = [];
					foreach ($arCalendarItemsList as $value)
					{
						$arUserCalendarItems[$value["XML_ID"]] = $value["MODIFICATION_LABEL"];
					}

					$arModifiedUserCalendarItems = CCalendar::SyncCalendarItems(
						"exchange",
						$userCalendar["CALENDAR_ID"],
						$arUserCalendarItems
					);

					$tmpNumItems += count($arModifiedUserCalendarItems);
					if (is_array($arModifiedUserCalendarItems))
					{
						$eventIds = [];
						$eventsFromExchange = [];
						foreach ($arModifiedUserCalendarItems as $value)
						{
							$eventIds[] = ['id' => $value['XML_ID']];
						}

						$modifiedItems = $exchange->GetById($eventIds);

						if (is_array($modifiedItems) && !empty($modifiedItems))
						{
							foreach ($modifiedItems as $item)
							{
								$eventsFromExchange[$item['XML_ID']] = $item;
							}
						}

						foreach ($arModifiedUserCalendarItems as $value)
						{
							if (
								array_key_exists($value["XML_ID"], $eventsFromExchange)
								&& $eventsFromExchange[$value["XML_ID"]]
								&& is_array($eventsFromExchange[$value["XML_ID"]])
							)
							{
								$modifiedItem = $eventsFromExchange[$value["XML_ID"]];
								$modifyEventFields = [
									"ID" => $value["ID"],
									"NAME" => $modifiedItem["NAME"],
									"DESCRIPTION" => $modifiedItem["DESCRIPTION"] ?? null,
									"XML_ID" => $modifiedItem["XML_ID"],
									"PROPERTY_LOCATION" => $modifiedItem["PROPERTY_LOCATION"] ?? null,
									"DATE_FROM" => $modifiedItem["ACTIVE_FROM"],
									"DATE_TO" => $modifiedItem["ACTIVE_TO"],
									"SKIP_TIME" => $modifiedItem["SKIP_TIME"] ?? null,
									"PROPERTY_IMPORTANCE" => $modifiedItem["PROPERTY_IMPORTANCE"] ?? null,
									"PROPERTY_REMIND_SETTINGS" => $modifiedItem["PROPERTY_REMIND_SETTINGS"] ?? null,
									"PROPERTY_PERIOD_TYPE" => "NONE",
									"PROPERTY_BXDAVEX_LABEL" => $modifiedItem["MODIFICATION_LABEL"] ?? null,
									"PRIVATE_EVENT" => mb_strtolower($modifiedItem["PROPERTY_SENSITIVITY"]) === 'private',
									'TZ_FROM' => $modifiedItem['TIMEZONE'] ?? null,
									'TZ_TO' => $modifiedItem['TIMEZONE'] ?? null,
								];

								if ($modifiedItem["PROPERTY_FREEBUSY"])
								{
									$modifiedItem["PROPERTY_FREEBUSY"] = mb_strtolower($modifiedItem["PROPERTY_FREEBUSY"]);
									if ($modifiedItem["PROPERTY_FREEBUSY"] === "oof")
									{
										$modifyEventFields["PROPERTY_ACCESSIBILITY"] = "absent";
									}
									else if ($modifiedItem["PROPERTY_FREEBUSY"] === "free")
									{
										$modifyEventFields["PROPERTY_ACCESSIBILITY"] = "free";
									}
									else if ($modifiedItem["PROPERTY_FREEBUSY"] === "tentative")
									{
										$modifyEventFields["PROPERTY_ACCESSIBILITY"] = "quest";
									}
									else
									{
										$modifyEventFields["PROPERTY_ACCESSIBILITY"] = "busy";
									}
								}


								if ($modifiedItem["IS_RECURRING"])
								{
									if ($modifiedItem["RECURRING_TYPE"] === "MONTHLY_ABSOLUTE"
										|| $modifiedItem["RECURRING_TYPE"] === "MONTHLY_RELATIVE"
										|| $modifiedItem["RECURRING_TYPE"] === "MONTHLY"
									)
									{
										$modifyEventFields["PROPERTY_PERIOD_TYPE"] = "MONTHLY";
									}
									elseif ($modifiedItem["RECURRING_TYPE"] === "YEARLY_ABSOLUTE"
										|| $modifiedItem["RECURRING_TYPE"] === "YEARLY_RELATIVE"
										|| $modifiedItem["RECURRING_TYPE"] === "YEARLY"
									)
									{
										$modifyEventFields["PROPERTY_PERIOD_TYPE"] = "YEARLY";
									}
									elseif ($modifiedItem["RECURRING_TYPE"] === "WEEKLY")
									{
										$modifyEventFields["PROPERTY_PERIOD_TYPE"] = "WEEKLY";
									}
									elseif ($modifiedItem["RECURRING_TYPE"] === "DAILY")
									{
										$modifyEventFields["PROPERTY_PERIOD_TYPE"] = "DAILY";
									}

									if (isset($modifiedItem["RECURRING_INTERVAL"]))
									{
										$modifyEventFields["PROPERTY_PERIOD_COUNT"] = $modifiedItem["RECURRING_INTERVAL"];
									}

									if (
										($modifyEventFields["PROPERTY_PERIOD_TYPE"] === "WEEKLY")
										&& isset($modifiedItem["RECURRING_DAYSOFWEEK"])
									)
									{
										$ar = preg_split("/[;,s]/i", $modifiedItem["RECURRING_DAYSOFWEEK"]);
										$ar1 = [];
										foreach ($ar as $v)
										{
											$ar1[] = $arWeekDayMap[mb_strtolower($v)];
										}
										$modifyEventFields["PROPERTY_PERIOD_ADDITIONAL"] = implode(",", $ar1);
									}

									$modifyEventFields["PROPERTY_EVENT_LENGTH"] = MakeTimeStamp($modifyEventFields["DATE_TO"]) - MakeTimeStamp($modifyEventFields["DATE_FROM"]);
									if ($modifyEventFields["PROPERTY_EVENT_LENGTH"] <= 0)
									{
										$modifyEventFields["PROPERTY_EVENT_LENGTH"] = 86400;
									}

									if (isset($modifiedItem["RECURRING_NUMBEROFOCCURRENCES"]) && $modifiedItem["RECURRING_NUMBEROFOCCURRENCES"] > 0)
									{
										$modifyEventFields["PROPERTY_RRULE_COUNT"] = (int)$modifiedItem["RECURRING_NUMBEROFOCCURRENCES"];
									}
									elseif (isset($modifiedItem["RECURRING_ENDDATE"]))
									{
										$modifyEventFields["PROPERTY_PERIOD_UNTIL"] = $modifiedItem["RECURRING_ENDDATE"];
									}
									else
									{
										$modifyEventFields["PROPERTY_PERIOD_UNTIL"] = ConvertTimeStamp(mktime(0, 0, 0, 12, 31, 2025), "FULL");
									}
								}

								if (
									isset($modifiedItem["ATTENDEES_EMAIL_LIST"])
									&& !empty($modifiedItem["ATTENDEES_EMAIL_LIST"])
									&& class_exists('CCalendarSync')
									&& method_exists('CCalendarSync', 'isExchangeMeetingEnabled')
									&& CCalendarSync::isExchangeMeetingEnabled()
								)
								{
									$organizer = self::GetUsersByEmailList(array($modifiedItem["ORGANIZER_EMAIL"]));
									$entityId = $arUser["ID"];

									// Following code executes only for events from organizer
									if (!empty($organizer) && $organizer[0])
									{
										if ($organizer[0] === $entityId)
										{
											$attendeesMap = self::GetUsersEmailMap($modifiedItem["ATTENDEES_EMAIL_LIST"]);
											$modifyEventFields['IS_MEETING'] = true;
											$modifyEventFields['MEETING_HOST'] = $entityId;
											$modifyEventFields['MEETING'] = ['HOST_NAME' => CCalendar::GetUserName($entityId)];

											$modifyEventFields['ATTENDEES_CODES'] = [];
											$modifyEventFields['ATTENDEES_RESPONSE'] = [];

											foreach($modifiedItem["ATTENDEES_EMAIL_LIST"] as $email)
											{
												$email = mb_strtolower($email);
												if ($entityId == $attendeesMap[$email])
												{
													continue;
												}

												if(isset($attendeesMap[$email]) && $attendeesMap[$email])
												{
													$modifyEventFields['ATTENDEES_CODES'][] = 'U'.$attendeesMap[$email];
													if (!empty($modifiedItem['ATTENDEES_RESPONSE'][$email]))
													{
														$modifyEventFields['ATTENDEES_RESPONSE'][$attendeesMap[$email]] = self::ConvertExchangeResponse($modifiedItem['ATTENDEES_RESPONSE'][$email]);
													}
												}
												else
												{
													$modifyEventFields['ATTENDEES_CODES'][] = $email;
												}
											}
											$modifyEventFields['ATTENDEES_CODES'] = array_unique($modifyEventFields['ATTENDEES_CODES']);
											CCalendarSync::ModifyEvent($userCalendar["CALENDAR_ID"], $modifyEventFields);
										}
										else
										{
											$usersToSync[] = (int)$organizer[0];
										}
									}
								}
								// For not meetings
								else
								{
									CCalendarSync::ModifyEvent($userCalendar["CALENDAR_ID"], $modifyEventFields);
								}
								$bShouldClearCache = true;
							}
						}
					}

				}
			}

			if (DAV_EXCH_DEBUG)
			{
				CDav::WriteToLog(
					"Sync " . (int)$tmpNumCals . " calendars, " . (int)$tmpNumItems . " items",
					"SYNCE"
				);
			}

			$notify = new BitrixMainEvent(
				'dav', 'OnExchandeCalendarDataSync',
				[
					'userId' => $arUser["ID"],
					'shouldClearCache' => $bShouldClearCache,
					'lastError' => $lastError
				]
			);
			$notify->send();

			$handledUsers[] = (int)$arUser["ID"];
		}

		if (!empty($usersToSync))
		{
			$usersToSync = array_unique($usersToSync);
			$usersToSync = array_diff($usersToSync, $handledUsers);

			// Here we set UF_BXDAVEX_CALSYNC to value one day before now to triger
			// sync for these users as soon as possible
			foreach($usersToSync as $userId)
			{
				$GLOBALS["USER_FIELD_MANAGER"]->Update("USER", $userId, ["UF_BXDAVEX_CALSYNC" => ConvertTimeStamp(time() - 86400, "FULL")]
				);
			}
		}

		if (DAV_EXCH_DEBUG)
		{
			CDav::WriteToLog("EXCHANGE sync finished", "SYNCE");
		}

		return $bShouldClearCache;
	}