%PDF- %PDF-
Direktori : /home/bitrix/www/bitrix/modules/calendar/classes/general/ |
Current File : //home/bitrix/www/bitrix/modules/calendar/classes/general/calendar_sync.php |
<? use \Bitrix\Calendar\Sync\GoogleApiSync; use \Bitrix\Calendar\Sync\GoogleApiPush; use \Bitrix\Calendar\PushTable; class CCalendarSync { public static $handleExchangeMeeting; public static $doNotSendToGoogle = false; public static function doSync() { if (CCalendar::isGoogleApiEnabled()) { self::$doNotSendToGoogle = true; self::dataSync(); self::$doNotSendToGoogle = false; } return "CCalendarSync::doSync();"; } public static function dataSync($connectionData = array()) { if (!CModule::includeModule('dav') || !CModule::includeModule('socialservices')) { return; } $bShouldClearCache = false; $pushEnabled = CCalendar::IsBitrix24() || COption::GetOptionString('calendar', 'sync_by_push', false); if (!empty($connectionData)) { if ($pushEnabled) { GoogleApiPush::createWatchChannels($connectionData['ID'] - 1); } $forceSync = false; if (isset($connectionData['forceSync'])) { $forceSync = $connectionData['forceSync']; } $bShouldClearCache = (self::syncConnection($connectionData, $forceSync)) ? true : $bShouldClearCache; } else { $davConnections = \CDavConnection::GetList( array("SYNCHRONIZED" => "ASC"), array('ACCOUNT_TYPE' => 'google_api_oauth'), false, array('nTopCount' => GoogleApiSync::MAXIMUM_CONNECTIONS_TO_SYNC) ); while($connection = $davConnections->fetch()) { if ($pushEnabled) { $pushResult = PushTable::getByPrimary(array( 'ENTITY_TYPE' => 'CONNECTION', 'ENTITY_ID' => $connection['ID']) ); if ($row = $pushResult->fetch()) { CDavConnection::SetLastResult($connection["ID"], '[204] SYNCED BY PUSH'); continue; } } $bShouldClearCache = (self::syncConnection($connection)) ? true : $bShouldClearCache; } } if ($bShouldClearCache) { CCalendar::ClearCache(); } } public static function syncConnection($connectionData, $forceSync = false) { $bShouldClearCache = false; CDavConnection::Update($connectionData["ID"], array("LAST_RESULT" => "[0]"), false); $googleApiConnection = new GoogleApiSync($connectionData['ENTITY_ID']); if ($error = $googleApiConnection->getTransportConnectionError()) { CDavConnection::Update($connectionData["ID"], array("LAST_RESULT" => $error), false); return false; } $googleCalendars = $googleApiConnection->getCalendarItems(); $localCalendars = CCalendarSect::GetList(array( 'arFilter' => array( 'OWNER_ID' => $connectionData['ENTITY_ID'], 'CAL_TYPE' => 'user', 'CAL_DAV_CON' => $connectionData['ID'] ), 'arOrder' => array('ID' => 'DESC'), 'checkPermissions' => false, 'getPermissions' => false )); $localSections = array(); $localSectionIndex = array(); foreach ($localCalendars as $section) { if ($section['GAPI_CALENDAR_ID']) { if (!isset($localSectionIndex[$section['GAPI_CALENDAR_ID']])) { $localSections[] = $section; $localSectionIndex[$section['GAPI_CALENDAR_ID']] = count($localSections) - 1; } else { CCalendarSect::Delete($section["ID"], false); PushTable::delete(array('ENTITY_TYPE' => 'SECTION', 'ENTITY_ID' => $section["ID"])); } } } if ($googleCalendars) { foreach ($googleCalendars as $externalCalendar) { $localCalendarIndex = isset($localSectionIndex[$externalCalendar['id']]) ? $localSectionIndex[$externalCalendar['id']] : false; if ($localCalendarIndex === false) { $arFields = array( 'COLOR' => $externalCalendar['backgroundColor'], 'TEXT_COLOR' => $externalCalendar['textColor'], 'GAPI_CALENDAR_ID' => $externalCalendar['id'], 'NAME' => $externalCalendar['summary'], 'DESCRIPTION' => (!empty($externalCalendar['description'])) ? $externalCalendar['description'] : '', 'OWNER_ID' => $connectionData["ENTITY_ID"], 'CAL_TYPE' => 'user', 'CAL_DAV_CON' => $connectionData["ID"], ); $localSections[] = array_merge($arFields, array('ID' => CCalendarSect::Edit(array('arFields' => $arFields)))); } elseif (empty($externalCalendar['deleted']) || !$externalCalendar['deleted']) { $arFields = array( 'COLOR' => $externalCalendar['backgroundColor'], 'TEXT_COLOR' => $externalCalendar['textColor'], 'GAPI_CALENDAR_ID' => $externalCalendar['id'], 'NAME' => $externalCalendar['summary'], 'DESCRIPTION' => (!empty($externalCalendar['description'])) ? $externalCalendar['description'] : '', 'OWNER_ID' => $connectionData["ENTITY_ID"], 'CAL_TYPE' => 'user', 'CAL_DAV_CON' => $connectionData["ID"], 'ID' => $localSections[$localCalendarIndex]['ID'] ); CCalendarSect::Edit(array('arFields' => $arFields)); } elseif (!empty($externalCalendar['deleted']) && $externalCalendar['deleted']) { CCalendarSect::Edit(array('arFields' => array('ID' => $localSections[$localCalendarIndex]['ID'], 'ACTIVE' => 'N'))); } } CDavConnection::SetLastResult($connectionData["ID"], "[200] OK"); } $pushOptionEnabled = COption::GetOptionString('calendar', 'sync_by_push', false) || CCalendar::IsBitrix24(); if ($pushOptionEnabled) { $pushResult = PushTable::getByPrimary(array('ENTITY_TYPE' => 'CONNECTION', 'ENTITY_ID' => $connectionData['ID'])); if ($row = $pushResult->fetch()) { GoogleApiPush::checkSectionsPush($localSections, $connectionData['ENTITY_ID']); $bShouldClearCache = true; } } foreach ($localSections as $localCalendar) { $eventsSyncToken = self::syncCalendarEvents($localCalendar); CCalendarSect::Edit(array('arFields' => array('ID' => $localCalendar['ID'], 'SYNC_TOKEN' => $eventsSyncToken))); } return $bShouldClearCache; } public static function syncCalendarEvents($localCalendar) { $googleApiConnection = new GoogleApiSync($localCalendar['OWNER_ID']); if ($error = $googleApiConnection->getTransportConnectionError()) { CDavConnection::Update($localCalendar['CAL_DAV_CON'], array("LAST_RESULT" => $error), false); return false; } self::$doNotSendToGoogle = true; $localEventsList = CCalendarEvent::getList(array( 'userId' => $localCalendar['OWNER_ID'], 'arFilter' => array('SECTION' => $localCalendar['ID']) )); $localEvents = array(); foreach ($localEventsList as $localEvent) { if (!empty($localEvent['DAV_XML_ID'])) $localEvents[$localEvent['DAV_XML_ID']] = $localEvent; } unset($localEvent); $externalEvents = $googleApiConnection->getEvents($localCalendar); $eventsSyncToken = $googleApiConnection->getEventsSyncToken(); foreach ($externalEvents as $externalEvent) { $eventExists = !empty($localEvents[$externalEvent['DAV_XML_ID']]); if ($externalEvent['status'] == 'cancelled') { if ($eventExists) { if (!empty($externalEvent[$externalEvent['recurringEventId']]) && $externalEvent[$externalEvent['recurringEventId']]['status'] == 'cancelled' && !empty($localEvents[$externalEvent['recurringEventId']])) { CCalendarEvent::Delete(array( 'id' => $localEvents[$externalEvent['recurringEventId']]['ID'], 'bMarkDeleted' => true, 'Event' => $localEvents[$externalEvent['recurringEventId']], 'userId' => $localCalendar['OWNER_ID'], 'sendNotification' => false )); } if (!empty($localEvents[$externalEvent['DAV_XML_ID']]['IS_MEETING']) && $localEvents[$externalEvent['DAV_XML_ID']]['IS_MEETING']) self::$doNotSendToGoogle = false; CCalendarEvent::Delete(array( 'id' => $localEvents[$externalEvent['DAV_XML_ID']]['ID'], 'bMarkDeleted' => true, 'Event' => $localEvents[$externalEvent['DAV_XML_ID']], 'userId' => $localCalendar['OWNER_ID'], 'sendNotification' => false )); if (!empty($localEvents[$externalEvent['DAV_XML_ID']]['IS_MEETING']) && $localEvents[$externalEvent['DAV_XML_ID']]['IS_MEETING']) self::$doNotSendToGoogle = true; foreach ($localEvents as $localEvent) { if (!empty($localEvent['RECURRENCE_ID']) && $localEvent['RECURRENCE_ID'] == $localEvents[$externalEvent['DAV_XML_ID']]['ID']) { CCalendarEvent::Delete(array( 'id' => $localEvent['ID'], 'bMarkDeleted' => true, 'Event' => $localEvent, 'userId' => $localCalendar['OWNER_ID'], 'sendNotification' => false )); } } } elseif (!empty($externalEvent['recurringEventId']) && !empty($localEvents[$externalEvent['recurringEventId']]) && $externalEvent['isRecurring'] == 'Y') { $excludeDates = CCalendarEvent::GetExDate($localEvents[$externalEvent['recurringEventId']]['EXDATE']); $excludeDates[] = $externalEvent['EXDATE']; $localEvents[$externalEvent['recurringEventId']]['EXDATE'] = implode(';', $excludeDates); $newParentData = array('arFields' => $localEvents[$externalEvent['recurringEventId']], 'userId' => $localCalendar['OWNER_ID'], 'fromWebservice' => true); $newParentData['arFields']['EXDATE'] = CCalendarEvent::SetExDate($excludeDates); $newParentData['arFields']['RRULE'] = CCalendarEvent::ParseRRULE($newParentData['arFields']['RRULE']); CCalendar::SaveEvent($newParentData); } continue; } if ($externalEvent['isRecurring'] == "N") { if (!$eventExists) { $newEventData = array_merge( $externalEvent, array( 'SECTIONS' => array($localCalendar['ID']), 'OWNER_ID' => $localCalendar['OWNER_ID'], 'userId' => $localCalendar['OWNER_ID'] ) ); $newEvent = array_merge(array('ID' => CCalendarEvent::Edit(array('arFields' => $newEventData))), $newEventData); $localEvents[$externalEvent['DAV_XML_ID']] = $newEvent; $bShouldClearCache = true; } else { $newParentData = array( 'arFields' => array_merge(array( 'ID' => $localEvents[$externalEvent['DAV_XML_ID']]['ID'], ), $externalEvent), 'userId' => $localCalendar['OWNER_ID'], 'fromWebservice' => true ); if (!empty($localEvents[$externalEvent['DAV_XML_ID']]['IS_MEETING']) && $localEvents[$externalEvent['DAV_XML_ID']]['IS_MEETING']) self::$doNotSendToGoogle = false; CCalendar::SaveEvent($newParentData); if (!empty($localEvents[$externalEvent['DAV_XML_ID']]['IS_MEETING']) && $localEvents[$externalEvent['DAV_XML_ID']]['IS_MEETING']) self::$doNotSendToGoogle = true; } } elseif ($externalEvent['isRecurring'] == "Y") { if ($externalEvent['status'] == 'confirmed' && $externalEvent['hasMoved'] == "Y") { $recurrentParentEventExists = !empty($localEvents[$externalEvent['recurringEventId']]); if ($recurrentParentEventExists) { $eventId = !empty($localEvents[$externalEvent['DAV_XML_ID']]) ? $localEvents[$externalEvent['DAV_XML_ID']]['ID'] : NULL; if (!$eventId && preg_match('/_/', $externalEvent['DAV_XML_ID'])) { unset($externalEvent['DAV_XML_ID']); } $recurrenceId = NULL; if ($localEvents[$externalEvent['recurringEventId']]) { $recurrenceId = $localEvents[$externalEvent['recurringEventId']]['ID']; $excludeDates = CCalendarEvent::GetExDate($localEvents[$externalEvent['recurringEventId']]['EXDATE']); $excludeDates[] = $externalEvent['EXDATE']; $localEvents[$externalEvent['recurringEventId']]['EXDATE'] = implode(';', $excludeDates); $newParentData = array('arFields' => $localEvents[$externalEvent['recurringEventId']], 'userId' => $localCalendar['OWNER_ID'], 'fromWebservice' => true); $newParentData['arFields']['EXDATE'] = CCalendarEvent::SetExDate($excludeDates); $newParentData['arFields']['RRULE'] = CCalendarEvent::ParseRRULE($newParentData['arFields']['RRULE']); CCalendar::SaveEvent($newParentData); } CCalendar::SaveEvent(array( 'arFields' => array_merge($externalEvent, array( 'RECURRENCE_ID' => $recurrenceId, 'DATE_FROM' => $externalEvent['DATE_FROM'], 'SECTIONS' => array($localCalendar['ID']), 'DATE_TO' => $externalEvent['DATE_TO'], )), 'userId' => $localCalendar['OWNER_ID'], 'fromWebservice' => true )); } } } } self::$doNotSendToGoogle = false; return $eventsSyncToken; } public static function ModifyEvent($calendarId, $arFields, $params = array()) { list($sectionId, $entityType, $entityId) = $calendarId; $userId = $entityType == 'user' ? $entityId : 0; $eventId = false; $bExchange = CCalendar::IsExchangeEnabled($userId) && $entityType == 'user'; $saveEvent = true; CCalendar::SetSilentErrorMode(); if ($sectionId && CCalendarSect::GetById($sectionId, false)) { CCalendar::SetOffset(false, CCalendar::GetOffset($userId)); $entityType = strtolower($entityType); $eventId = ((isset($arFields["ID"]) && (intval($arFields["ID"]) > 0)) ? intval($arFields["ID"]) : 0); $arNewFields = array( "DAV_XML_ID" => $arFields['XML_ID'], "CAL_DAV_LABEL" => (isset($arFields['PROPERTY_BXDAVCD_LABEL']) && strlen($arFields['PROPERTY_BXDAVCD_LABEL']) > 0) ? $arFields['PROPERTY_BXDAVCD_LABEL'] : '', "DAV_EXCH_LABEL" => (isset($arFields['PROPERTY_BXDAVEX_LABEL']) && strlen($arFields['PROPERTY_BXDAVEX_LABEL']) > 0) ? $arFields['PROPERTY_BXDAVEX_LABEL'] : '', "ID" => $eventId, 'NAME' => $arFields["NAME"] ? $arFields["NAME"] : GetMessage('EC_NONAME_EVENT'), 'CAL_TYPE' => $entityType, 'OWNER_ID' => $entityId, 'DESCRIPTION' => isset($arFields['DESCRIPTION']) ? $arFields['DESCRIPTION'] : '', 'SECTIONS' => $sectionId, 'ACCESSIBILITY' => isset($arFields['ACCESSIBILITY']) ? $arFields['ACCESSIBILITY'] : 'busy', 'IMPORTANCE' => isset($arFields['IMPORTANCE']) ? $arFields['IMPORTANCE'] : 'normal', "REMIND" => is_array($arFields['REMIND']) ? $arFields['REMIND'] : array(), "RRULE" => is_array($arFields['RRULE']) ? is_array($arFields['RRULE']) : array(), "VERSION" => isset($arFields['VERSION']) ? intVal($arFields['VERSION']) : 1, "PRIVATE_EVENT" => !!$arFields['PRIVATE_EVENT'] ); $arNewFields["DATE_FROM"] = $arFields['DATE_FROM']; $arNewFields["DATE_TO"] = $arFields['DATE_TO']; $arNewFields["TZ_FROM"] = $arFields['TZ_FROM']; $arNewFields["TZ_TO"] = $arFields['TZ_TO']; $arNewFields["SKIP_TIME"] = $arFields['SKIP_TIME']; if (isset($arFields['RECURRENCE_ID'])) $arNewFields['RECURRENCE_ID'] = $arFields['RECURRENCE_ID']; if ($arNewFields["SKIP_TIME"]) { $arNewFields["DATE_FROM"] = CCalendar::Date(CCalendar::Timestamp($arNewFields['DATE_FROM']), false); $arNewFields["DATE_TO"] = CCalendar::Date(CCalendar::Timestamp($arNewFields['DATE_TO']) - CCalendar::GetDayLen(), false); } if (!empty($arFields['PROPERTY_REMIND_SETTINGS'])) { if (is_array($arFields['PROPERTY_REMIND_SETTINGS'])) { foreach ($arFields['PROPERTY_REMIND_SETTINGS'] as $remindSetting) { $ar = explode("_", $remindSetting); if(count($ar) == 2) $arNewFields["REMIND"][] = array('type' => $ar[1],'count' => floatVal($ar[0])); } } else { $ar = explode("_", $arFields["PROPERTY_REMIND_SETTINGS"]); if(count($ar) == 2) $arNewFields["REMIND"][] = array('type' => $ar[1],'count' => floatVal($ar[0])); } } if (!empty($arFields['PROPERTY_ACCESSIBILITY'])) $arNewFields["ACCESSIBILITY"] = $arFields['PROPERTY_ACCESSIBILITY']; if (!empty($arFields['PROPERTY_IMPORTANCE'])) $arNewFields["IMPORTANCE"] = $arFields['PROPERTY_IMPORTANCE']; if (!empty($arFields['PROPERTY_LOCATION'])) $arNewFields["LOCATION"] = CCalendar::UnParseTextLocation($arFields['PROPERTY_LOCATION']); if (!empty($arFields['DETAIL_TEXT'])) $arNewFields["DESCRIPTION"] = $arFields['DETAIL_TEXT']; $arNewFields["DESCRIPTION"] = CCalendar::ClearExchangeHtml($arNewFields["DESCRIPTION"]); if (isset($arFields["PROPERTY_PERIOD_TYPE"]) && in_array($arFields["PROPERTY_PERIOD_TYPE"], array("DAILY", "WEEKLY", "MONTHLY", "YEARLY"))) { $arNewFields['RRULE']['FREQ'] = $arFields["PROPERTY_PERIOD_TYPE"]; $arNewFields['RRULE']['INTERVAL'] = $arFields["PROPERTY_PERIOD_COUNT"]; if (!isset($arNewFields['DT_LENGTH']) && !empty($arFields['PROPERTY_EVENT_LENGTH'])) { $arNewFields['DT_LENGTH'] = intval($arFields['PROPERTY_EVENT_LENGTH']); } else { $arNewFields['DT_LENGTH'] = $arFields['DT_TO_TS'] - $arFields['DT_FROM_TS']; } if ($arNewFields['RRULE']['FREQ'] == "WEEKLY" && !empty($arFields['PROPERTY_PERIOD_ADDITIONAL'])) { $arNewFields['RRULE']['BYDAY'] = array(); $bydays = explode(',',$arFields['PROPERTY_PERIOD_ADDITIONAL']); foreach($bydays as $day) { $day = CCalendar::WeekDayByInd($day, false); if ($day !== false) $arNewFields['RRULE']['BYDAY'][] = $day; } $arNewFields['RRULE']['BYDAY'] = implode(',',$arNewFields['RRULE']['BYDAY']); } if (isset($arFields['PROPERTY_RRULE_COUNT'])) $arNewFields['RRULE']['COUNT'] = $arFields['PROPERTY_RRULE_COUNT']; elseif (isset($arFields['PROPERTY_PERIOD_UNTIL'])) $arNewFields['RRULE']['UNTIL'] = $arFields['PROPERTY_PERIOD_UNTIL']; else $arNewFields['RRULE']['UNTIL'] = $arFields['DT_TO_TS']; if (isset($arFields['EXDATE'])) $arNewFields['EXDATE'] = $arFields["EXDATE"]; } if ($arFields['IS_MEETING'] && $bExchange && self::isExchangeMeetingEnabled()) { $arNewFields['IS_MEETING'] = $arFields['IS_MEETING']; $arNewFields['MEETING_HOST'] = $arFields['MEETING_HOST']; $arNewFields['MEETING'] = $arFields['MEETING']; $arNewFields['ATTENDEES_CODES'] = $arFields['ATTENDEES_CODES']; } if ($saveEvent) { $eventId = CCalendar::SaveEvent( array( 'arFields' => $arNewFields, 'userId' => $userId, 'bAffectToDav' => false, // Used to prevent syncro with calDav again 'bSilentAccessMeeting' => true, 'autoDetectSection' => false ) ); } if ($eventId && $arFields['IS_MEETING'] && $arFields['ATTENDEES_RESPONSE'] && $bExchange && self::isExchangeMeetingEnabled()) { foreach($arFields['ATTENDEES_RESPONSE'] as $attendeeId => $status) { CCalendarEvent::SetMeetingStatus(array( 'userId' => $attendeeId, 'eventId' => $eventId, 'status' => $status, 'personalNotification' => false, 'hostNotification' => false, 'affectRecRelatedEvents' => false )); } } } CCalendar::SetSilentErrorMode(false); return $eventId; } public static function ModifyReccurentInstances($params = array()) { CCalendar::SetSilentErrorMode(); $parentEvent = CCalendarEvent::GetById($params['parentId']); if ($parentEvent && CCalendarEvent::CheckRecurcion($parentEvent)) { $excludeDates = CCalendarEvent::GetExDate($parentEvent['EXDATE']); foreach ($params['events'] as $arFields) { $arFields['RECURRENCE_ID'] = $parentEvent['ID']; self::ModifyEvent($params['calendarId'], $arFields); if ($arFields['RECURRENCE_ID_DATE']) { $excludeDates[] = CCalendar::Date(CCalendar::Timestamp($arFields['RECURRENCE_ID_DATE']), false); } } $res = CCalendar::SaveEventEx(array( 'arFields' => array( 'ID' => $parentEvent['ID'], 'EXDATE' => CCalendarEvent::SetExDate($excludeDates) ), 'bSilentAccessMeeting' => true, 'recursionEditMode' => 'skip', 'silentErrorMode' => true, 'sendInvitations' => false, 'bAffectToDav' => false, 'sendEditNotification' => false )); } CCalendar::SetSilentErrorMode(false); } public static function DoSaveToDav($params = array(), &$arFields, $event = false) { if (self::$doNotSendToGoogle) { return true; } $sectionId = $params['sectionId']; $bExchange = $params['bExchange']; $bCalDav = $params['bCalDav']; if (isset($event['DAV_XML_ID'])) $arFields['DAV_XML_ID'] = $event['DAV_XML_ID']; if (isset($event['DAV_EXCH_LABEL'])) $arFields['DAV_EXCH_LABEL'] = $event['DAV_EXCH_LABEL']; if (isset($event['CAL_DAV_LABEL'])) $arFields['CAL_DAV_LABEL'] = $event['CAL_DAV_LABEL']; if (!isset($arFields['DATE_CREATE']) && isset($event['DATE_CREATE'])) $arFields['DATE_CREATE'] = $event['DATE_CREATE']; $section = CCalendarSect::GetById($sectionId, false); if ($event) { if ($event['SECT_ID'] != $sectionId) { $bCalDavCur = CCalendar::IsCalDAVEnabled() && $event['CAL_TYPE'] == 'user' && strlen($event['CAL_DAV_LABEL']) > 0; $bExchangeEnabledCur = CCalendar::IsExchangeEnabled() && $event['CAL_TYPE'] == 'user'; if ($bExchangeEnabledCur || $bCalDavCur) { $res = CCalendarSync::DoDeleteToDav(array( 'bCalDav' => $bCalDavCur, 'bExchangeEnabled' => $bExchangeEnabledCur, 'sectionId' => $event['SECT_ID'] ), $event); if ($event['DAV_EXCH_LABEL']) $event['DAV_EXCH_LABEL'] = ''; if ($res !== true) return CCalendar::ThrowError($res); } } } $arDavFields = $arFields; CCalendarEvent::CheckFields($arDavFields); if ($arDavFields['RRULE'] != '') $arDavFields['RRULE'] = $arFields['RRULE']; if ($arDavFields['LOCATION']['NEW'] !== '') $arDavFields['LOCATION']['NEW'] = CCalendar::GetTextLocation($arDavFields['LOCATION']['NEW']); $arDavFields['PROPERTY_IMPORTANCE'] = $arDavFields['IMPORTANCE']; $arDavFields['PROPERTY_LOCATION'] = $arDavFields['LOCATION']['NEW']; $arDavFields['REMIND_SETTINGS'] = ''; if ($arFields['REMIND'] && is_array($arFields['REMIND']) && is_array($arFields['REMIND'][0])) $arDavFields['REMIND_SETTINGS'] = floatVal($arFields['REMIND'][0]['count']).'_'.$arFields['REMIND'][0]['type']; if (isset($arDavFields['RRULE'], $arDavFields['RRULE']['BYDAY']) && is_array($arDavFields['RRULE']['BYDAY'])) $arDavFields['RRULE']['BYDAY'] = implode(',',$arDavFields['RRULE']['BYDAY']); // **** Synchronize with GoogleApi **** $bGoogleApi = CCalendar::isGoogleApiEnabled() && !is_null($section['GAPI_CALENDAR_ID']); if ($bGoogleApi) { $googleApiCalendar = new GoogleApiSync($arFields['OWNER_ID']); $arFields['DAV_XML_ID'] = $googleApiCalendar->saveEvent($arDavFields, $section['GAPI_CALENDAR_ID']); // TODO: handle google errors // $googleApiCalendar->getTransportErrors() return true; } // **** Synchronize with CalDav **** if ($bCalDav && $section['CAL_DAV_CON'] > 0) { // New event or move existent event to DAV calendar if($arFields['ID'] <= 0 || ($event && !$event['CAL_DAV_LABEL'])) { $DAVRes = CDavGroupdavClientCalendar::DoAddItem($section['CAL_DAV_CON'], $section['CAL_DAV_CAL'], $arDavFields); } else // Edit existent event { $DAVRes = CDavGroupdavClientCalendar::DoUpdateItem($section['CAL_DAV_CON'], $section['CAL_DAV_CAL'], $event['DAV_XML_ID'], $event['CAL_DAV_LABEL'], $arDavFields); } if (!is_array($DAVRes) || !array_key_exists("XML_ID", $DAVRes)) return CCalendar::CollectCalDAVErros($DAVRes); // // It's ok, we successfuly save event to caldav calendar - and save it to DB $arFields['DAV_XML_ID'] = $DAVRes['XML_ID']; $arFields['CAL_DAV_LABEL'] = $DAVRes['MODIFICATION_LABEL']; } // **** Synchronize with Exchange **** elseif ($bExchange && $section['IS_EXCHANGE'] && strlen($section['DAV_EXCH_CAL']) > 0 && $section['DAV_EXCH_CAL'] !== 0) { $ownerId = $arFields['OWNER_ID']; // Here we check if parent event was created in exchange calendar and if it is meeting // If yes, we expect that it was already created in MS Exchange server // and we don't need to dublicate this entry. if (self::isExchangeMeetingEnabled() && $arFields['IS_MEETING'] && $arFields['MEETING_HOST'] != $ownerId && CCalendar::IsExchangeEnabled($arFields['MEETING_HOST'])) { $parentEvent = CCalendarEvent::GetById($arFields['PARENT_ID']); if ($parentEvent['DAV_EXCH_LABEL']) { $parentSection = CCalendarSect::GetById($parentEvent['SECT_ID'], false); if ($parentSection['IS_EXCHANGE'] && strlen($parentSection['DAV_EXCH_CAL']) > 0 && $parentSection['DAV_EXCH_CAL'] !== 0) { return; } } } if (self::isExchangeMeetingEnabled() && $arFields['IS_MEETING'] && $arFields['MEETING_HOST'] == $ownerId && count($arFields['ATTENDEES']) > 0) { $arDavFields['REQUIRED_ATTENDEES'] = self::GetExchangeEmailForUser($arFields['ATTENDEES']); if (empty($arDavFields['REQUIRED_ATTENDEES'])) { unset($arDavFields['REQUIRED_ATTENDEES']); } } $fromTo = CCalendarEvent::GetEventFromToForUser($arDavFields, $ownerId); $arDavFields["DATE_FROM"] = $fromTo['DATE_FROM']; $arDavFields["DATE_TO"] = $fromTo['DATE_TO']; // Convert BBcode to HTML for exchange $arDavFields["DESCRIPTION"] = CCalendarEvent::ParseText($arDavFields['DESCRIPTION']); // New event or move existent event to Exchange calendar if ($arFields['ID'] <= 0 || ($event && !$event['DAV_EXCH_LABEL'])) { $exchRes = CDavExchangeCalendar::DoAddItem($ownerId, $section['DAV_EXCH_CAL'], $arDavFields); } else { $exchRes = CDavExchangeCalendar::DoUpdateItem($ownerId, $event['DAV_XML_ID'], $event['DAV_EXCH_LABEL'], $arDavFields); } if (!is_array($exchRes) || !array_key_exists("XML_ID", $exchRes)) { return CCalendar::CollectExchangeErrors($exchRes); } // It's ok, we successfuly save event to exchange calendar - and save it to DB $arFields['DAV_XML_ID'] = $exchRes['XML_ID']; $arFields['DAV_EXCH_LABEL'] = $exchRes['MODIFICATION_LABEL']; } return true; } public static function DoDeleteToDav($params, $event) { $sectionId = $params['sectionId']; $section = CCalendarSect::GetById($sectionId, false); $bGoogleApi = CCalendar::isGoogleApiEnabled() && $event['CAL_TYPE'] == 'user' && !is_null($section['GAPI_CALENDAR_ID']); if (!empty($section) && $section['CAL_DAV_CON'] && \Bitrix\Main\Loader::includeModule('dav')) { $calendarConnection = CDavConnection::getById($section['CAL_DAV_CON']); if ($calendarConnection['ACCOUNT_TYPE'] == 'caldav_google_oauth' || empty($section['GAPI_CALENDAR_ID'])) { $bGoogleApi = false; } } if ($bGoogleApi) { if (!self::$doNotSendToGoogle) { $googleApiCalendar = new GoogleApiSync($event['OWNER_ID']); $googleApiCalendar->deleteEvent($event['DAV_XML_ID'], $section['GAPI_CALENDAR_ID']); } return true; } $bExchangeEnabled = $params['bExchangeEnabled']; $bCalDav = $params['bCalDav']; // Google and other caldav if ($bCalDav && $section['CAL_DAV_CON'] > 0) { $DAVRes = CDavGroupdavClientCalendar::DoDeleteItem($section['CAL_DAV_CON'], $section['CAL_DAV_CAL'], $event['DAV_XML_ID']); if ($DAVRes !== true) return CCalendar::CollectCalDAVErros($DAVRes); } // Exchange if ($bExchangeEnabled && $section['IS_EXCHANGE']) { $exchRes = CDavExchangeCalendar::DoDeleteItem($event['OWNER_ID'], $event['DAV_XML_ID']); if ($exchRes !== true) return CCalendar::CollectExchangeErrors($exchRes); } return true; } public static function SyncCalendarSections($connectionType, $arCalendars, $entityType, $entityId, $connectionId = null) { CCalendar::SetSilentErrorMode(); //Array( // [0] => Array( // [XML_ID] => calendar // [NAME] => calendar // ) // [1] => Array( // [XML_ID] => AQATAGFud... // [NAME] => geewgvwe 1 // [DESCRIPTION] => gewgvewgvw // [COLOR] => #FF0000 // [MODIFICATION_LABEL] => af720e7c7b6a // ) //) $entityType = strtolower($entityType); $entityId = intVal($entityId); $tempUser = CCalendar::TempUser(false, true); $calendarNames = array(); foreach ($arCalendars as $value) $calendarNames[$value["XML_ID"]] = $value; if ($connectionType == 'exchange') { $xmlIdField = "DAV_EXCH_CAL"; $xmlIdModLabel = "DAV_EXCH_MOD"; } elseif ($connectionType == 'caldav') { $xmlIdField = "CAL_DAV_CAL"; $xmlIdModLabel = "CAL_DAV_MOD"; } else return array(); $arFilter = array( 'CAL_TYPE' => $entityType, 'OWNER_ID' => $entityId, '!'.$xmlIdField => false ); if ($connectionType == 'caldav') $arFilter["CAL_DAV_CON"] = $connectionId; if ($connectionType == 'exchange') $arFilter["IS_EXCHANGE"] = 1; $arResult = array(); $res = CCalendarSect::GetList(array( 'arFilter' => $arFilter, 'checkPermissions' => false, 'getPermissions' => false )); foreach($res as $section) { $xmlId = $section[$xmlIdField]; $modificationLabel = $section[$xmlIdModLabel]; if ($connectionType == 'caldav' && $section['DAV_EXCH_CAL']) continue; if (empty($xmlId)) continue; if (!array_key_exists($xmlId, $calendarNames)) { CCalendarSect::Delete($section["ID"]); } else { if ($modificationLabel != $calendarNames[$xmlId]["MODIFICATION_LABEL"]) { CCalendarSect::Edit(array( 'arFields' => array( "ID" => $section["ID"], "NAME" => $calendarNames[$xmlId]["NAME"], "OWNER_ID" => $entityType == 'user' ? $entityId : 0, "CREATED_BY" => $entityType == 'user' ? $entityId : 0, "DESCRIPTION" => $calendarNames[$xmlId]["DESCRIPTION"], "COLOR" => $calendarNames[$xmlId]["COLOR"], $xmlIdModLabel => $calendarNames[$xmlId]["MODIFICATION_LABEL"], ) )); } if (empty($modificationLabel) || ($modificationLabel != $calendarNames[$xmlId]["MODIFICATION_LABEL"])) { $arResult[] = array( "XML_ID" => $xmlId, "CALENDAR_ID" => array($section["ID"], $entityType, $entityId) ); } unset($calendarNames[$xmlId]); } } foreach($calendarNames as $key => $value) { $arFields = Array( 'CAL_TYPE' => $entityType, 'OWNER_ID' => $entityId, 'NAME' => $value["NAME"], 'DESCRIPTION' => $value["DESCRIPTION"], 'COLOR' => $value["COLOR"], 'EXPORT' => array('ALLOW' => false), "CREATED_BY" => $entityType == 'user' ? $entityId : 0, 'ACCESS' => array(), $xmlIdField => $key, $xmlIdModLabel => $value["MODIFICATION_LABEL"] ); if ($connectionType == 'caldav') $arFields["CAL_DAV_CON"] = $connectionId; if ($entityType == 'user') $arFields["CREATED_BY"] = $entityId; if ($connectionType == 'exchange') $arFields["IS_EXCHANGE"] = 1; $id = intVal(CCalendar::SaveSection(array('arFields' => $arFields, 'bAffectToDav' => false))); if ($id) $arResult[] = array("XML_ID" => $key, "CALENDAR_ID" => array($id, $entityType, $entityId)); } CCalendar::TempUser($tempUser, false); CCalendar::SetSilentErrorMode(false); return $arResult; } public static function GetGoogleCalendarConnection() { $userId = CCalendar::GetCurUserId(); $result = array(); if (\Bitrix\Main\Loader::includeModule('socialservices')) { $client = new CSocServGoogleOAuth($userId); $client->getEntityOAuth()->addScope(array('https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/calendar.readonly')); $id = false; if($client->getEntityOAuth()->GetAccessToken()) { $url = "https://www.googleapis.com/calendar/v3/users/me/calendarList"; $h = new \Bitrix\Main\Web\HttpClient(); $h->setHeader('Authorization', 'Bearer '.$client->getEntityOAuth()->getToken()); $response = \Bitrix\Main\Web\Json::decode($h->get($url)); $id = self::GetGoogleOauthPrimaryId($response); $result['googleCalendarPrimaryId'] = $id; } if(!$id) { $curPath = CCalendar::GetPath(); if($curPath) $curPath = CHTTP::urlDeleteParams($curPath, array("action", "sessid", "bx_event_calendar_request", "EVENT_ID")); $result['authLink'] = $client->getUrl('opener', null, array('BACKURL' => $curPath)); } } return $result; } private static function GetGoogleOauthPrimaryId($data = array()) { $id = false; if (is_array($data['items']) && count($data['items']) > 0) { foreach($data['items'] as $item) { if (is_array($item) && $item['primary'] && $item['accessRole'] == 'owner') { $id = $item['id']; break; } } } return $id; } public static function GetExchangeEmailForUser($idList = array()) { global $DB; $users = array(); if (CCalendar::IsSocNet()) { if(is_array($idList)) { $idList = array_unique($idList); } else { $idList = array($idList); } $strIdList = ""; foreach($idList as $id) { if(intVal($id) > 0) { $strIdList .= ','.intVal($id); } } $strIdList = trim($strIdList, ', '); if($strIdList != '') { $exchangeMailbox = COption::GetOptionString("dav", "exchange_mailbox", ""); $exchangeUseLogin = COption::GetOptionString("dav", "exchange_use_login", "Y"); $strSql = "SELECT U.ID, U.LOGIN, U.EMAIL, BUF.UF_BXDAVEX_MAILBOX FROM b_user U LEFT JOIN b_uts_user BUF ON (BUF.VALUE_ID = U.ID) WHERE U.ACTIVE = 'Y' AND U.ID in (".$strIdList.")"; $res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__); while($entry = $res->Fetch()) { $users[$entry['ID']] = (($exchangeUseLogin == "Y") ? $entry["LOGIN"].$exchangeMailbox : $entry["UF_BXDAVEX_MAILBOX"]); if (empty($users[$entry['ID']])) $users[$entry['ID']] = $entry['EMAIL']; } } } return $users; } public static function GetUsersByEmailList($emailList = array()) { global $DB; $users = array(); if (CCalendar::IsSocNet()) { $exchangeMailbox = COption::GetOptionString("dav", "exchange_mailbox", ""); $exchangeUseLogin = COption::GetOptionString("dav", "exchange_use_login", "Y"); $exchangeMailboxStrlen = strlen($exchangeMailbox); $strValue = ""; foreach($emailList as $email) { $strValue .= ",'".CDatabase::ForSql($email)."'"; } $strValue = trim($strValue, ', '); if($strValue != '') { $strSql = "SELECT U.ID, BUF.UF_BXDAVEX_MAILBOX FROM b_user U LEFT JOIN b_uts_user BUF ON (BUF.VALUE_ID = U.ID) WHERE U.ACTIVE = 'Y' AND BUF.UF_BXDAVEX_MAILBOX in (".$strValue.")"; $res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__); $checkedEmails = array(); while($entry = $res->Fetch()) { $checkedEmails[] = strtolower($entry["UF_BXDAVEX_MAILBOX"]); $users[] = $entry['ID']; } if ($exchangeUseLogin == "Y") { $strLogins = ''; foreach($emailList as $email) { if(!in_array(strtolower($email), $checkedEmails) && strtolower(substr($email, strlen($email) - $exchangeMailboxStrlen)) == strtolower($exchangeMailbox)) { $value = substr($email, 0, strlen($email) - $exchangeMailboxStrlen); $strLogins .= ",'".CDatabase::ForSql($value)."'"; } } $strLogins = trim($strLogins, ', '); if ($strLogins !== '') { $res = $DB->Query("SELECT U.ID, U.LOGIN FROM b_user U WHERE U.ACTIVE = 'Y' AND U.LOGIN in (".$strLogins.")", false, "File: ".__FILE__."<br>Line: ".__LINE__); while($entry = $res->Fetch()) { $users[] = $entry['ID']; } } } } } return $users; } public static function isExchangeMeetingEnabled() { if (!isset(self::$handleExchangeMeeting)) { self::$handleExchangeMeeting = COption::GetOptionString('calendar', 'sync_exchange_meeting', false); } return self::$handleExchangeMeeting; } } ?>