%PDF- %PDF-
Direktori : /home/bitrix/www/bitrix/modules/calendar/classes/general/ |
Current File : /home/bitrix/www/bitrix/modules/calendar/classes/general/calendar.php |
<? /** var CMain $APPLICATION */ use Bitrix\Main; use Bitrix\Main\Localization\Loc; use Bitrix\Calendar\PushTable; use Bitrix\Calendar\Sync\GoogleApiSync; IncludeModuleLangFile(__FILE__); class CCalendar { const INTEGRATION_GOOGLE_API = "googleapi", CALENDAR_MAX_TIMESTAMP = 2145938400, DAY_LENGTH = 86400; // 60 * 60 * 24 private static $id = false, $instance, $CALENDAR_MAX_DATE, $CALENDAR_MIN_DATE, $type, $arTypes, $ownerId = 0, $settings, $siteId, $userSettings = array(), $pathToUser, $bOwner, $userId, $curUserId, $userMeetingSection, $meetingSections = array(), $crmSections = array(), $offset, $arTimezoneOffsets = array(), $perm = array(), $isArchivedGroup = false, $userNameTemplate = "#NAME# #LAST_NAME#", $bSuperpose, $bCanAddToSuperpose, $bExtranet, $bIntranet, $bWebservice, $arSPTypes = array(), $showTasks, $viewTaskPath = '', $editTaskPath = '', $actionUrl, $path = '', $outerUrl, $accessNames = array(), $bSocNet, $bAnonym, $allowReserveMeeting = true, $SectionsControlsDOMId = 'sidebar', $arAccessTask = array(), $ownerNames = array(), $meetingRoomList, $cachePath = "calendar/", $cacheTime = 2592000, // 30 days by default $bCache = true, $readOnly, $showLogin = true, $pathesForSite = false, $pathes = array(), // links for several sites $userManagers = array(), $arUserDepartment = array(), $bAMPM = false, $bWideDate = false, $arExchEnabledCache = array(), $silentErrorMode = false, $weekStart, $bCurUserSocNetAdmin, $serverPath, $pathesList = array('path_to_user','path_to_user_calendar','path_to_group','path_to_group_calendar','path_to_vr','path_to_rm'), $pathesListEx = null, $isGoogleApiEnabled = null, $timezones = array(); function Init($params) { global $USER, $APPLICATION; $access = new CAccess(); $access->UpdateCodes(); if (!$USER || !is_object($USER)) $USER = new CUser; // Owner params self::$siteId = isset($params['siteId']) ? $params['siteId'] : SITE_ID; self::$type = $params['type']; self::$arTypes = CCalendarType::GetList(); self::$bIntranet = CCalendar::IsIntranetEnabled(); self::$bSocNet = self::IsSocNet(); self::$userId = (isset($params['userId']) && $params['userId'] > 0) ? intVal($params['userId']) : CCalendar::GetCurUserId(true); self::$bOwner = self::$type == 'user' || self::$type == 'group'; self::$settings = self::GetSettings(); self::$userSettings = CCalendarUserSettings::Get(); self::$pathesForSite = self::GetPathes(self::$siteId); self::$pathToUser = self::$pathesForSite['path_to_user']; self::$bSuperpose = $params['allowSuperpose'] != false && self::$bSocNet; self::$bAnonym = !$USER || !$USER->IsAuthorized(); self::$userNameTemplate = self::$settings['user_name_template']; self::$bAMPM = IsAmPmMode(); self::$bWideDate = strpos(FORMAT_DATETIME, 'MMMM') !== false; self::$id = $this->GetId(); if (isset($params['SectionControlsDOMId'])) self::$SectionsControlsDOMId = $params['SectionControlsDOMId']; if (self::$bOwner && isset($params['ownerId']) && $params['ownerId'] > 0) self::$ownerId = intVal($params['ownerId']); self::$showTasks = (self::$type == 'user' || self::$type == 'group') && $params['showTasks'] !== false && \Bitrix\Main\Loader::includeModule('tasks') && self::$userSettings['showTasks'] != 'N'; if (self::$showTasks) { self::$viewTaskPath = $params['viewTaskPath']; self::$editTaskPath = $params['editTaskPath']; if (!self::$viewTaskPath) { self::$showTasks = false; } } self::GetPermissions(array( 'type' => self::$type, 'bOwner' => self::$bOwner, 'userId' => self::$userId, 'ownerId' => self::$ownerId )); // Cache params if (isset($params['cachePath'])) self::$cachePath = $params['cachePath']; if (isset($params['cacheTime'])) self::$cacheTime = $params['cacheTime']; self::$bCache = self::$cacheTime > 0; // Urls $page = preg_replace( array( "/EVENT_ID=.*?\&/i", "/EVENT_DATE=.*?\&/i", "/CHOOSE_MR=.*?\&/i", "/action=.*?\&/i", "/bx_event_calendar_request=.*?\&/i", "/clear_cache=.*?\&/i", "/bitrix_include_areas=.*?\&/i", "/bitrix_show_mode=.*?\&/i", "/back_url_admin=.*?\&/i" ), "", $params['pageUrl'].'&' ); $page = preg_replace(array("/^(.*?)\&$/i","/^(.*?)\?$/i"), "\$1", $page); self::$actionUrl = $page; if (self::$bOwner && !empty(self::$ownerId)) self::$path = self::GetPath(self::$type, self::$ownerId, true); else self::$path = CCalendar::GetServerPath().$page; self::$outerUrl = $APPLICATION->GetCurPageParam('', array("action", "bx_event_calendar_request", "clear_cache", "bitrix_include_areas", "bitrix_show_mode", "back_url_admin", "SEF_APPLICATION_CUR_PAGE_URL", "EVENT_ID", "EVENT_DATE", "CHOOSE_MR"), false); // *** Meeting room params *** $RMiblockId = self::$settings['rm_iblock_id']; self::$allowReserveMeeting = $params["allowResMeeting"] && $RMiblockId > 0; if(self::$allowReserveMeeting && !$USER->IsAdmin() && (CIBlock::GetPermission($RMiblockId) < "R")) self::$allowReserveMeeting = false; } public function Show($params = array()) { global $APPLICATION; $arType = false; foreach(self::$arTypes as $type) { if(self::$type == $type['XML_ID']) $arType = $type; } if (!$arType) { $APPLICATION->ThrowException('[EC_WRONG_TYPE] '.Loc::getMessage('EC_WRONG_TYPE')); return false; } if (!CCalendarType::CanDo('calendar_type_view', self::$type)) { $APPLICATION->ThrowException(Loc::getMessage("EC_ACCESS_DENIED")); return false; } $startupEvent = false; $showNewEventDialog = false; //Show new event dialog if (isset($_GET['EVENT_ID'])) { if ($_GET['EVENT_ID'] == 'NEW') { $showNewEventDialog = true; } elseif(substr($_GET['EVENT_ID'], 0, 4) == 'EDIT') { $startupEvent = self::GetStartUpEvent(intval(substr($_GET['EVENT_ID'], 4))); if ($startupEvent) $startupEvent['EDIT'] = true; if ($startupEvent['DT_FROM']) { $ts = self::Timestamp($startupEvent['DT_FROM']); $init_month = date('m', $ts); $init_year = date('Y', $ts); } } // Show popup event at start elseif ($startupEvent = self::GetStartUpEvent($_GET['EVENT_ID'])) { $eventFromTs = self::Timestamp($startupEvent['DATE_FROM']); $currentDateTs = self::Timestamp($_GET['EVENT_DATE']); if ($currentDateTs > $eventFromTs) { $startupEvent['~CURRENT_DATE'] = self::Date($currentDateTs, false); $init_month = date('m', $currentDateTs); $init_year = date('Y', $currentDateTs); } else { $init_month = date('m', $eventFromTs); $init_year = date('Y', $eventFromTs); } } } if (!$init_month && !$init_year && strlen($params["initDate"]) > 0 && strpos($params["initDate"], '.') !== false) { $ts = self::Timestamp($params["initDate"]); $init_month = date('m', $ts); $init_year = date('Y', $ts); } if (!isset($init_month)) $init_month = date("m"); if (!isset($init_year)) $init_year = date("Y"); $id = $this->GetId(); $weekHolidays = array(); if (isset(self::$settings['week_holidays'])) { $days = array('MO' => 0, 'TU' => 1, 'WE' => 2,'TH' => 3,'FR' => 4,'SA' => 5,'SU' => 6); foreach(self::$settings['week_holidays'] as $day) $weekHolidays[] = $days[$day]; } else $weekHolidays = array(5, 6); $yearHolidays = array(); if (isset(self::$settings['year_holidays'])) { foreach(explode(',', self::$settings['year_holidays']) as $date) { $date = trim($date); $ardate = explode('.', $date); if (count($ardate) == 2 && $ardate[0] && $ardate[1]) $yearHolidays[] = intVal($ardate[0]).'.'.(intVal($ardate[1]) - 1); } } $yearWorkdays = array(); if (isset(self::$settings['year_workdays'])) { foreach(explode(',', self::$settings['year_workdays']) as $date) { $date = trim($date); $ardate = explode('.', $date); if (count($ardate) == 2 && $ardate[0] && $ardate[1]) $yearWorkdays[] = intVal($ardate[0]).'.'.(intVal($ardate[1]) - 1); } } $bSyncPannel = self::IsPersonal(); $bExchange = CCalendar::IsExchangeEnabled() && self::$type == 'user'; $bExchangeConnected = $bExchange && CDavExchangeCalendar::IsExchangeEnabledForUser(self::$ownerId); $bCalDAV = CCalendar::IsCalDAVEnabled() && self::$type == "user"; $bGoogleApi = CCalendar::isGoogleApiEnabled() && self::$type == "user"; $bWebservice = CCalendar::IsWebserviceEnabled(); $bExtranet = CCalendar::IsExtranetEnabled(); $userTimezoneOffsetUTC = self::GetCurrentOffsetUTC(self::$userId); $userTimezoneName = self::GetUserTimezoneName(self::$userId, false); $userTimezoneDefault = ''; // We don't have default timezone for this offset for this user // We will ask him but we should suggest some suitable for his offset if (!$userTimezoneName) { $userTimezoneDefault = self::GetGoodTimezoneForOffset($userTimezoneOffsetUTC); } $JSConfig = Array( 'id' => $id, 'type' => self::$type, 'userId' => self::$userId, 'userName' => self::GetUserName(self::$userId), // deprecated 'ownerId' => self::$ownerId, 'user' => array( 'id' => self::$userId, 'name' => self::GetUserName(self::$userId), 'url' => self::GetUserUrl(self::$userId), 'avatar' => self::GetUserAvatarSrc(self::$userId), 'smallAvatar' => self::GetUserAvatarSrc(self::$userId, array('AVATAR_SIZE' => 18)) ), 'perm' => $arType['PERM'], // Permissions from type 'permEx' => self::$perm, 'showTasks' => self::$showTasks, 'sectionControlsDOMId' => self::$SectionsControlsDOMId, 'week_holidays' => $weekHolidays, 'year_holidays' => $yearHolidays, 'year_workdays' => $yearWorkdays, 'init_month' => $init_month, 'init_year' => $init_year, 'pathToUser' => self::$pathToUser, 'path' => self::$path, 'actionUrl' => self::$actionUrl, 'settings' => self::$settings, 'userSettings' => self::$userSettings, 'bAnonym' => self::$bAnonym, 'bIntranet' => self::$bIntranet, 'bWebservice' => $bWebservice, 'bExtranet' => $bExtranet, 'bSocNet' => self::$bSocNet, 'bExchange' => $bExchangeConnected, 'startupEvent' => $startupEvent, 'workTime' => array(self::$settings['work_time_start'], self::$settings['work_time_end']), // Decrecated !! 'userWorkTime' => array(self::$settings['work_time_start'], self::$settings['work_time_end']), 'meetingRooms' => self::GetMeetingRoomList(array( 'RMiblockId' => self::$settings['rm_iblock_id'], 'pathToMR' => self::$pathesForSite['path_to_rm'] )), 'allowResMeeting' => self::$allowReserveMeeting, 'bAMPM' => self::$bAMPM, 'WDControllerCID' => 'UFWD'.$id, 'userTimezoneOffsetUTC' => $userTimezoneOffsetUTC, 'userTimezoneName' => $userTimezoneName, 'userTimezoneDefault' => $userTimezoneDefault, 'sectionCustomization' => CCalendarUserSettings::getSectionCustomization(self::$userId), 'locationFeatureEnabled' => !self::IsBitrix24() || \Bitrix\Bitrix24\Feature::isFeatureEnabled("calendar_location") ); $JSConfig['lastSection'] = CCalendarSect::GetLastUsedSection(self::$type, self::$ownerId, self::$userId); if(self::$type == 'user' && self::$userId != self::$ownerId) { $JSConfig['ownerUser'] = array( 'id' => self::$ownerId, 'name' => self::GetUserName(self::$ownerId), 'url' => self::GetUserUrl(self::$ownerId), 'avatar' => self::GetUserAvatarSrc(self::$ownerId), 'smallAvatar' => self::GetUserAvatarSrc(self::$ownerId, array('AVATAR_SIZE' => 18)) ); } $placementParams = false; if (\Bitrix\Main\Loader::includeModule('rest')) { $placementParams = [ 'gridPlacementCode' => \CCalendarRestService::PLACEMENT_GRID_VIEW, 'gridPlacementList' => \Bitrix\Rest\PlacementTable::getHandlersList(\CCalendarRestService::PLACEMENT_GRID_VIEW), 'serviceUrl' => '/bitrix/components/bitrix/app.layout/lazyload.ajax.php?&site='.SITE_ID.'&'.bitrix_sessid_get() ]; // if(is_array($gridPlacementHandlerList)) // { // foreach($gridPlacementHandlerList as $placementHandler) // { //$tabId = 'placement_'.$placementHandler['ID']; // $arResult["Title"][$tabId] = ( // !empty($placementHandler['TITLE']) > 0 // ? $placementHandler['TITLE'] // : $placementHandler['APP_NAME'] // ); // $arResult["Urls"][$tabId] = $arResult["Urls"]["view"]."app/".$placementHandler['ID']."/"; // } // } } $JSConfig['placementParams'] = $placementParams; if(self::$type == 'user' && self::$userId == self::$ownerId) { $JSConfig['counters'] = array( 'invitation' => CUserCounter::GetValue(self::$userId, 'calendar') ); $JSConfig['filterId'] = \Bitrix\Calendar\Ui\CalendarFilter::getFilterId(self::$type, self::$ownerId, self::$userId); } // Access permissons for type if (CCalendarType::CanDo('calendar_type_edit_access', self::$type)) $JSConfig['TYPE_ACCESS'] = $arType['ACCESS']; if ($bCalDAV || $bGoogleApi) { self::InitExternalCalendarsSyncParams($JSConfig); } if ($bSyncPannel) { $macSyncInfo = self::GetSyncInfo(self::$userId, 'mac'); $iphoneSyncInfo = self::GetSyncInfo(self::$userId, 'iphone'); $androidSyncInfo = self::GetSyncInfo(self::$userId, 'android'); $outlookSyncInfo = self::GetSyncInfo(self::$userId, 'outlook'); $exchangeSyncInfo = self::GetSyncInfo(self::$userId, 'exchange'); $JSConfig['syncInfo'] = array( 'google' => array( 'active' => ($bCalDAV || $bGoogleApi) && ($JSConfig['googleCalDavStatus']['connection_id'] > 0 || $JSConfig['googleCalDavStatus']['authLink']), 'connected' => $JSConfig['googleCalDavStatus']['connection_id'] > 0, 'syncDate' => $JSConfig['googleCalDavStatus']['sync_date'] ), 'macosx' => array( 'active' => true, 'connected' => $macSyncInfo['connected'], 'syncDate' => $macSyncInfo['date'], ), 'iphone' => array( 'active' => true, 'connected' => $iphoneSyncInfo['connected'], 'syncDate' => $iphoneSyncInfo['date'], ), 'android' => array( 'active' => true, 'connected' => $androidSyncInfo['connected'], 'syncDate' => $androidSyncInfo['date'], ), 'outlook' => array( 'active' => true, 'connected' => $outlookSyncInfo['connected'], 'syncDate' => $outlookSyncInfo['date'], ), 'office365' => array( 'active' => false, 'connected' => false, 'syncDate' => false ), 'exchange' => array( 'active' => $bExchange, 'connected' => $bExchangeConnected, 'syncDate' => $exchangeSyncInfo['date'] ) ); } else { $JSConfig['syncInfo'] = false; } // If enabled superposed sections - fetch it $arAddSections = self::GetDisplayedSuperposed(self::$userId); if (!is_array($arAddSections)) $arAddSections = array(); $arSectionIds = array(); $hiddenSections = CCalendarUserSettings::getHiddenSections(self::$userId); $arDisplayedSPSections = array(); $arDisplayedNowSPSections = array(); foreach($arAddSections as $sect) { $arDisplayedSPSections[] = $sect; if (!in_array($sect, $hiddenSections)) $arDisplayedNowSPSections[] = $sect; } self::$userMeetingSection = CCalendar::GetCurUserMeetingSection(); // **** GET SECTIONS **** $sections = self::GetSectionList(array( 'ADDITIONAL_IDS' => $arDisplayedSPSections )); $readOnly = !self::$perm['edit'] && !self::$perm['section_edit']; if (self::$type == 'user' && self::$ownerId != self::$userId) $readOnly = true; if (self::$bAnonym) $readOnly = true; $bCreateDefault = !self::$bAnonym; if (self::$type == 'user') $bCreateDefault = self::$ownerId == self::$userId; $additonalMeetingsId = array(); $groupOrUser = self::$type == 'user' || self::$type == 'group'; if ($groupOrUser) { $noEditAccessedCalendars = true; } $trackingUsers = array(); $trackingGroups = array(); foreach ($sections as $i => $section) { $sections[$i]['~IS_MEETING_FOR_OWNER'] = $section['CAL_TYPE'] == 'user' && $section['OWNER_ID'] != self::$userId && CCalendar::GetMeetingSection($section['OWNER_ID']) == $section['ID']; if (!in_array($section['ID'], $hiddenSections) && $section['ACTIVE'] !== 'N') { $arSectionIds[] = $section['ID']; // It's superposed calendar of the other user and it's need to show user's meetings if ($sections[$i]['~IS_MEETING_FOR_OWNER']) $additonalMeetingsId[] = array('ID' => $section['OWNER_ID'], 'SECTION_ID' => $section['ID']); } // We check access only for main sections because we can't edit superposed section if ($groupOrUser && $sections[$i]['CAL_TYPE'] == self::$type && $sections[$i]['OWNER_ID'] == self::$ownerId) { if ($noEditAccessedCalendars && $section['PERM']['edit']) $noEditAccessedCalendars = false; if ($readOnly && ($section['PERM']['edit'] || $section['PERM']['edit_section']) && !self::$isArchivedGroup) $readOnly = false; } if (self::$bSuperpose && in_array($section['ID'], $arAddSections)) $sections[$i]['SUPERPOSED'] = true; if ($bCreateDefault && $section['CAL_TYPE'] == self::$type && $section['OWNER_ID'] == self::$ownerId) $bCreateDefault = false; if ($sections[$i]['SUPERPOSED']) { $type = $sections[$i]['CAL_TYPE']; if ($type == 'user') { $path = self::$pathesForSite['path_to_user_calendar']; $path = CComponentEngine::MakePathFromTemplate($path, array("user_id" => $sections[$i]['OWNER_ID'])); $trackingUsers[] = $sections[$i]['OWNER_ID']; } elseif($type == 'group') { $path = self::$pathesForSite['path_to_group_calendar']; $path = CComponentEngine::MakePathFromTemplate($path, array("group_id" => $sections[$i]['OWNER_ID'])); $trackingGroups[] = $sections[$i]['OWNER_ID']; } else { $path = self::$pathesForSite['path_to_type_'.$type]; } $sections[$i]['LINK'] = $path; } } if ($groupOrUser && $noEditAccessedCalendars && !$bCreateDefault) $readOnly = true; self::$readOnly = $readOnly; if (!$readOnly && $showNewEventDialog) { $JSConfig['showNewEventDialog'] = true; $JSConfig['bChooseMR'] = isset($_GET['CHOOSE_MR']) && $_GET['CHOOSE_MR'] == "Y"; } if (!in_array($JSConfig['lastSection'], $arSectionIds)) { $JSConfig['lastSection'] = $arSectionIds[0]; } $JSConfig = array_merge($JSConfig, Array( 'trackingUsersList' => CCalendarUserSettings::getTrackingUsers(false, array('userList' => $trackingUsers)), 'trackingGroupList' => CCalendarUserSettings::getTrackingGroups(false, array('groupList' => $trackingGroups)) )); // **** GET TASKS **** if (self::$showTasks) { $JSConfig['viewTaskPath'] = self::$viewTaskPath; $JSConfig['editTaskPath'] = self::$editTaskPath; } // We don't have any section if ($bCreateDefault) { $fullSectionsList = $groupOrUser ? self::GetSectionList(array('checkPermissions' => false, 'getPermissions' => false)) : array(); // Section exists but it closed to this user (Ref. mantis:#64037) if (count($fullSectionsList) > 0) { $readOnly = true; } else { $defCalendar = CCalendarSect::CreateDefault(array( 'type' => CCalendar::GetType(), 'ownerId' => CCalendar::GetOwnerId() )); $arSectionIds[] = $defCalendar['ID']; $sections[] = $defCalendar; self::$userMeetingSection = $defCalendar['ID']; } } if (CCalendarType::CanDo('calendar_type_edit', self::$type)) $JSConfig['new_section_access'] = CCalendarSect::GetDefaultAccess(self::$type, self::$ownerId); $colors = array( '#9dcf00','#2FC6F6','#56D1E0','#FFA900','#47E4C2','#F87396','#9985DD','#A8ADB4','#AF7E00' ); $JSConfig['hiddenSections'] = $hiddenSections; $JSConfig['readOnly'] = $readOnly; // access $JSConfig['accessNames'] = self::GetAccessNames(); $JSConfig['sectionAccessTasks'] = self::GetAccessTasks('calendar_section'); $JSConfig['typeAccessTasks'] = self::GetAccessTasks('calendar_type'); $JSConfig['bSuperpose'] = self::$bSuperpose; $JSConfig['additonalMeetingsId'] = $additonalMeetingsId; $selectedUserCodes = array('U'.self::$userId); if (self::$type == 'user') { $selectedUserCodes[] = 'U'.self::$ownerId; } $additionalParams = array( 'socnetDestination' => CCalendar::GetSocNetDestination(false, $selectedUserCodes), 'locationList' => CCalendarLocation::GetList(), 'timezoneList' => CCalendar::GetTimezoneList(), 'defaultColorsList' => $colors, 'formSettings' => array( 'slider_main' => CCalendarUserSettings::getFormSettings('slider_main') ) ); // Append Javascript files and CSS files, and some base configs CCalendarSceleton::InitJS( $JSConfig, array( 'sections' => $sections ), $additionalParams ); } public static function GetUserGroups($userId = 0) { if (!$userId || !class_exists('CSocNetUserToGroup') || !class_exists('CSocNetFeatures')) return; $dbGroups = CSocNetUserToGroup::GetList( array("GROUP_NAME" => "ASC"), array( "USER_ID" => $userId, "<=ROLE" => SONET_ROLES_USER, "GROUP_SITE_ID" => SITE_ID, "GROUP_ACTIVE" => "Y" ), false, false, array("GROUP_ID", "GROUP_NAME") ); $arRes = array(); if ($dbGroups) { $arGroupIds = array(); $arGroups = array(); while ($g = $dbGroups->GetNext()) { $arGroups[] = $g; $arGroupIds[] = $g['GROUP_ID']; } if (count($arGroupIds) > 0) { $arFeaturesActive = CSocNetFeatures::IsActiveFeature(SONET_ENTITY_GROUP, $arGroupIds, "calendar"); $arView = CSocNetFeaturesPerms::CanPerformOperation($userId, SONET_ENTITY_GROUP, $arGroupIds, "calendar", 'view'); $arWrite = CSocNetFeaturesPerms::CanPerformOperation($userId, SONET_ENTITY_GROUP, $arGroupIds, "calendar", 'write'); foreach($arGroups as $group) { $groupId = intVal($group['~GROUP_ID']); // Calendar is disabled as feature or user can't even view it if (!$arFeaturesActive[$groupId] || !$arView[$groupId]) continue; $arRes[$groupId] = array( 'ID' => $groupId, 'NAME' => $group['~GROUP_NAME'], 'READONLY' => !$arWrite[$groupId] // Can't write to group's calendars ); } } } return $arRes; } public static function SetDisplayedSuperposed($userId = false, $arIds = array()) { if (!class_exists('CUserOptions') || !$userId) return false; $res = array(); if (is_array($arIds)) { foreach($arIds as $id) { if (intVal($id) > 0) { $res[] = intVal($id); } } } CUserOptions::SetOption("calendar", "superpose_displayed", serialize($res)); return true; } public static function DeleteSection($id) { if (CCalendar::IsExchangeEnabled(self::GetCurUserId()) && self::$type == 'user') { $oSect = CCalendarSect::GetById($id); // For exchange we change only calendar name if ($oSect && $oSect['IS_EXCHANGE'] && $oSect['DAV_EXCH_CAL']) { $exchRes = CDavExchangeCalendar::DoDeleteCalendar($oSect['OWNER_ID'], $oSect['DAV_EXCH_CAL']); if ($exchRes !== true) return CCalendar::CollectExchangeErrors($exchRes); } } $pushChannels = PushTable::getById(array('ENTITY_TYPE' => 'SECTION', 'ENTITY_ID' => $id)); if ($row = $pushChannels->fetch()) { \Bitrix\Calendar\Sync\GoogleApiPush::stopChannel($row); } return CCalendarSect::Delete($id); } public static function CollectExchangeErrors($arErrors = array()) { if (count($arErrors) == 0 || !is_array($arErrors)) return '[EC_NO_EXCH] '.Loc::getMessage('EC_NO_EXCHANGE_SERVER'); $str = ""; $errorCount = count($arErrors); for($i = 0; $i < $errorCount; $i++) $str .= "[".$arErrors[$i][0]."] ".$arErrors[$i][1]."\n"; return $str; } public static function DeleteEvent($id, $doExternalSync = true, $params = array()) { global $CACHE_MANAGER; $id = intVal($id); if (!$id) { return false; } $checkPermissions = isset($params['checkPermissions']) ? $params['checkPermissions'] : true; if (!isset(self::$userId)) { self::$userId = CCalendar::GetCurUserId(); } CCalendar::SetOffset(false, 0); $res = CCalendarEvent::GetList( array( 'arFilter' => array("ID" => $id), 'parseRecursion' => false, 'setDefaultLimit' => false, 'fetchAttendees' => true, 'checkPermissions' => $checkPermissions ) ); if ($event = $res[0]) { if (!isset(self::$type)) { self::$type = $event['CAL_TYPE']; } if (!isset(self::$ownerId)) { self::$ownerId = $event['OWNER_ID']; } if ($checkPermissions && !self::IsPersonal($event['CAL_TYPE'], $event['OWNER_ID'], self::$userId) && !CCalendarSect::CanDo('calendar_edit', $event['SECT_ID'], self::$userId)) { return Loc::getMessage('EC_ACCESS_DENIED'); } if ($doExternalSync !== false && $event['SECT_ID']) { $bGoogleApi = CCalendar::isGoogleApiEnabled() && $event['CAL_TYPE'] == 'user'; $bCalDav = CCalendar::IsCalDAVEnabled() && $event['CAL_TYPE'] == 'user'; $bExchangeEnabled = CCalendar::IsExchangeEnabled() && $event['CAL_TYPE'] == 'user'; if ($bExchangeEnabled || $bCalDav || $bGoogleApi) { $res = CCalendarSync::DoDeleteToDav(array( 'bCalDav' => $bCalDav, 'bExchangeEnabled' => $bExchangeEnabled, 'sectionId' => $event['SECT_ID'] ), $event); if ($res !== true) return $res; } } $sendNotification = isset($params['sendNotification']) ? $params['sendNotification'] : ($params['recursionMode'] !== 'all'); $res = CCalendarEvent::Delete(array( 'id' => $id, 'Event' => $event, 'bMarkDeleted' => true, 'userId' => self::$userId, 'sendNotification' => $sendNotification )); if ($params['recursionMode'] != 'this' && $event['RECURRENCE_ID']) { self::DeleteEvent($event['RECURRENCE_ID'], $doExternalSync, array('sendNotification' => $sendNotification)); } if (CCalendarEvent::CheckRecurcion($event)) { $events = CCalendarEvent::GetEventsByRecId($id); foreach($events as $ev) { self::DeleteEvent($ev['ID'], $doExternalSync, array('sendNotification' => $sendNotification)); } } if($params['recursionMode'] == 'all') { foreach($event['~ATTENDEES'] as $attendee) { if ($attendee['STATUS'] != 'N') { $CACHE_MANAGER->ClearByTag('calendar_user_'.$attendee["USER_ID"]); CCalendarNotify::Send(array( "mode" => 'cancel_all', "name" => $event['NAME'], "from" => $event['DATE_FROM'], "guestId" => $attendee["USER_ID"], "eventId" => $event['PARENT_ID'], "userId" => $event['MEETING_HOST'], "fields" => $event )); } } } return $res; } return false; } public static function SetOffset($userId = false, $value = 0) { if ($userId === false) self::$offset = $value; else self::$arTimezoneOffsets[$userId] = $value; } public static function CollectCalDAVErros($arErrors = array()) { if (count($arErrors) == 0 || !is_array($arErrors)) return '[EC_NO_EXCH] '.Loc::getMessage('EC_NO_CAL_DAV'); $str = ""; $errorCount = count($arErrors); for($i = 0; $i < $errorCount; $i++) { $str .= "[".$arErrors[$i][0]."] ".$arErrors[$i][1]."\n"; } return $str; } public static function GetPathForCalendarEx($userId = 0) { $bExtranet = \Bitrix\Main\Loader::includeModule('extranet'); // It's extranet user if ($bExtranet && self::IsExtranetUser($userId)) { $siteId = CExtranet::GetExtranetSiteID(); } else { if ($bExtranet && !self::IsExtranetUser($userId)) $siteId = CSite::GetDefSite(); else $siteId = self::GetSiteId(); if (self::$siteId == $siteId && isset(self::$pathesForSite) && is_array(self::$pathesForSite)) self::$pathes[$siteId] = self::$pathesForSite; } if (!isset(self::$pathes[$siteId]) || !is_array(self::$pathes[$siteId])) self::$pathes[$siteId] = self::GetPathes($siteId); $calendarUrl = self::$pathes[$siteId]['path_to_user_calendar']; $calendarUrl = str_replace(array('#user_id#', '#USER_ID#'), $userId, $calendarUrl); $calendarUrl = CCalendar::GetServerPath().$calendarUrl; return $calendarUrl; } public static function IsExtranetUser($userId = 0) { return !count(self::GetUserDepartment($userId)); } public static function GetUserDepartment($userId = 0) { if (!isset(self::$arUserDepartment[$userId])) { $rsUser = CUser::GetByID($userId); if($arUser = $rsUser->Fetch()) self::SetUserDepartment($userId, $arUser["UF_DEPARTMENT"]); } return self::$arUserDepartment[$userId]; } public static function SetUserDepartment($userId = 0, $dep = array()) { if (!is_array($dep)) $dep = array(); self::$arUserDepartment[$userId] = $dep; } public static function HandleImCallback($module, $tag, $value, $arNotify) { $userId = CCalendar::GetCurUserId(); if ($module == "calendar" && $userId) { $arTag = explode("|", $tag); $eventId = intVal($arTag[2]); if ($arTag[0] == "CALENDAR" && $arTag[1] == "INVITE" && $eventId > 0 && $userId) { CCalendarEvent::SetMeetingStatus(array( 'userId' => $userId, 'eventId' => $eventId, 'status' => $value == 'Y' ? 'Y' : 'N', 'personalNotification' => true )); return $value == 'Y' ? Loc::getMessage('EC_PROP_CONFIRMED_TEXT_Y') : Loc::getMessage('EC_PROP_CONFIRMED_TEXT_N'); } } } public static function ClearSettings() { self::SetSettings(array(), true); } public static function SetSettings($settings = array(), $bClear = false) { $arPathes = self::GetPathesList(); $arOpt = array('work_time_start', 'work_time_end', 'year_holidays', 'year_workdays', 'week_holidays', 'week_start', 'user_name_template', 'sync_by_push', 'user_show_login', 'rm_iblock_type', 'rm_iblock_id', 'denied_superpose_types', 'pathes_for_sites', 'pathes', 'dep_manager_sub', 'forum_id', 'rm_for_sites'); $arOpt = array_merge($arOpt, $arPathes); if ($settings['rm_iblock_ids'] && !$settings['rm_for_sites']) { foreach($settings['rm_iblock_ids'] as $site => $value) { COption::SetOptionString("calendar", 'rm_iblock_id', $value, false, $site); } } foreach($arOpt as $opt) { if ($bClear) { COption::RemoveOption("calendar", $opt); } elseif (isset($settings[$opt])) { if ($opt == 'rm_iblock_id' && !$settings['rm_for_sites']) { continue; } elseif ($opt == 'sync_by_push' && self::isGoogleApiEnabled()) { if ($settings[$opt]) { // start push agents \CAgent::RemoveAgent("\\Bitrix\\Calendar\\Sync\\GoogleApiPush::clearPushChannels();", "calendar"); \CAgent::AddAgent("\\Bitrix\\Calendar\\Sync\\GoogleApiPush::createWatchChannels(0);", "calendar", "N", 60); \CAgent::AddAgent("\\Bitrix\\Calendar\\Sync\\GoogleApiPush::processPush();", "calendar", "N", 180); \CAgent::AddAgent("\\Bitrix\\Calendar\\Sync\\GoogleApiPush::renewWatchChannels();", "calendar", "N", 14400); } else { // start clear push channels agent \CAgent::AddAgent("\\Bitrix\\Calendar\\Sync\\GoogleApiPush::clearPushChannels();", "calendar", "N", 60); \CAgent::RemoveAgent("\\Bitrix\\Calendar\\Sync\\GoogleApiPush::processPush();", "calendar"); \CAgent::RemoveAgent("\\Bitrix\\Calendar\\Sync\\GoogleApiPush::renewWatchChannels();", "calendar"); } } elseif ($opt == 'pathes' && is_array($settings[$opt])) { $sitesPathes = $settings[$opt]; $ar = array(); $arAffectedSites = array(); foreach($sitesPathes as $s => $pathes) { $affect = false; foreach($arPathes as $path) { if ($pathes[$path] != $settings[$path]) { $ar[$path] = $pathes[$path]; $affect = true; } } if ($affect && !in_array($s, $arAffectedSites)) { $arAffectedSites[] = $s; COption::SetOptionString("calendar", 'pathes_'.$s, serialize($ar)); } else { COption::RemoveOption("calendar", 'pathes_'.$s); } } COption::SetOptionString("calendar", 'pathes_sites', serialize($arAffectedSites)); continue; } elseif ($opt == 'denied_superpose_types' && is_array($settings[$opt])) { $settings[$opt] = serialize($settings[$opt]); } COption::SetOptionString("calendar", $opt, $settings[$opt]); } } } public static function IsBitrix24() { return \Bitrix\Main\ModuleManager::isModuleInstalled('bitrix24'); } public static function SearchAttendees($name = '', $Params = array()) { if (!isset($Params['arFoundUsers'])) $Params['arFoundUsers'] = CSocNetUser::SearchUser($name); $arUsers = array(); if (!is_array($Params['arFoundUsers']) || count($Params['arFoundUsers']) <= 0) { if ($Params['addExternal'] !== false) { if (check_email($name, true)) { $arUsers[] = array( 'type' => 'ext', 'email' => htmlspecialcharsex($name) ); } else { $arUsers[] = array( 'type' => 'ext', 'name' => htmlspecialcharsex($name) ); } } } else { foreach ($Params['arFoundUsers'] as $userId => $userName) { $userId = intVal($userId); $by = "id"; $order = "asc"; $r = CUser::GetList($by, $order, array("ID_EQUAL_EXACT" => $userId, "ACTIVE" => "Y")); if (!$User = $r->Fetch()) continue; $name = trim($User['NAME'].' '.$User['LAST_NAME']); if ($name == '') $name = trim($User['LOGIN']); $arUsers[] = array( 'type' => 'int', 'id' => $userId, 'name' => $name, 'status' => 'Q', 'busy' => 'free' ); } } return $arUsers; } public static function GetGroupMembers($groupId) { $dbMembers = CSocNetUserToGroup::GetList( array("RAND" => "ASC"), array( "GROUP_ID" => $groupId, "<=ROLE" => SONET_ROLES_USER, "USER_ACTIVE" => "Y" ), false, false, array("USER_ID", "USER_NAME", "USER_LAST_NAME", "USER_SECOND_NAME", "USER_LOGIN") ); $arMembers = array(); if ($dbMembers) { while ($Member = $dbMembers->GetNext()) { $name = trim($Member['USER_NAME'].' '.$Member['USER_LAST_NAME']); if ($name == '') $name = trim($Member['USER_LOGIN']); $arMembers[] = array('id' => $Member["USER_ID"],'name' => $name); } } return $arMembers; } public static function ReminderAgent($eventId = 0, $userId = 0, $viewPath = '', $calendarType = '', $ownerId = 0) { CCalendarReminder::ReminderAgent($eventId, $userId, $viewPath, $calendarType, $ownerId); } public static function GetMaxTimestamp() { return self::CALENDAR_MAX_TIMESTAMP; } public static function GetOwnerName($type = '', $ownerId = '') { $type = strtolower($type); $key = $type.'_'.$ownerId; if (isset(self::$ownerNames[$key])) return self::$ownerNames[$key]; $ownerName = ''; if($type == 'user') { $ownerName = CCalendar::GetUserName($ownerId); } elseif($type == 'group') { // Get group name if (!\Bitrix\Main\Loader::includeModule("socialnetwork")) return $ownerName; if ($arGroup = CSocNetGroup::GetByID($ownerId)) $ownerName = $arGroup["~NAME"]; } else { // Get type name $arTypes = CCalendarType::GetList(array("arFilter" => array("XML_ID" => $type))); $ownerName = $arTypes[0]['NAME']; } self::$ownerNames[$key] = $ownerName; $ownerName = trim($ownerName); return $ownerName; } public static function GetTimezoneOffset($timezoneId, $dateTimestamp = false) { $offset = 0; if ($timezoneId) { try { $oTz = new DateTimeZone($timezoneId); if ($oTz) { $offset = $oTz->getOffset(new DateTime($dateTimestamp ? "@$dateTimestamp" : "now", $oTz)); } } catch(Exception $e){} } return $offset; } public static function GetAbsentEvents($params) { if (!isset($params['arUserIds'])) return false; return CCalendarEvent::GetAbsent($params['arUserIds'], $params); } public static function GetAccessibilityForUsers($params) { if (!isset($params['checkPermissions'])) $params['checkPermissions'] = true; $res = CCalendarEvent::GetAccessibilityForUsers(array( 'users' => $params['users'], 'from' => $params['from'], 'to' => $params['to'], 'curEventId' => $params['curEventId'], 'checkPermissions' => $params['checkPermissions'] )); // Fetch absence from intranet if ($params['getFromHR'] && CCalendar::IsIntranetEnabled()) { $resHR = CIntranetUtils::GetAbsenceData( array( 'DATE_START' => $params['from'], 'DATE_FINISH' => $params['to'], 'USERS' => $params['users'], 'PER_USER' => true, 'SELECT' => array('ID', 'DATE_ACTIVE_FROM', 'DATE_ACTIVE_TO') ), BX_INTRANET_ABSENCE_HR ); foreach($resHR as $userId => $forUser) { if (!isset($res[$userId]) || !is_array($res[$userId])) $res[$userId] = array(); foreach($forUser as $event) { $res[$userId][] = array( 'FROM_HR' => true, 'ID' => $event['ID'], 'DT_FROM' => $event['DATE_ACTIVE_FROM'], 'DT_TO' => $event['DATE_ACTIVE_TO'], 'ACCESSIBILITY' => 'absent', 'IMPORTANCE' => 'normal', "FROM" => CCalendar::Timestamp($event['DATE_ACTIVE_FROM']), "TO" => CCalendar::Timestamp($event['DATE_ACTIVE_TO']) ); } } } return $res; } public static function GetNearestEventsList($params = array()) { $type = $params['bCurUserList'] ? 'user' : $params['type']; // Get current user id if (!isset($params['userId']) || $params['userId'] <= 0) $curUserId = CCalendar::GetCurUserId(); else $curUserId = intval($params['userId']); if (!CCalendarType::CanDo('calendar_type_view', $type, $curUserId)) return 'access_denied'; if ($params['bCurUserList'] && ($curUserId <= 0 || (class_exists('CSocNetFeatures') && !CSocNetFeatures::IsActiveFeature(SONET_ENTITY_USER, $curUserId, "calendar")))) return 'inactive_feature'; $arFilter = array( 'CAL_TYPE' => $type, 'FROM_LIMIT' => $params['fromLimit'], 'TO_LIMIT' => $params['toLimit'], 'DELETED' => 'N', 'ACTIVE_SECTION' => 'Y' ); if ($params['bCurUserList']) $arFilter['OWNER_ID'] = $curUserId; if (isset($params['sectionId']) && $params['sectionId']) $arFilter["SECTION"] = $params['sectionId']; if ($type == 'user') unset($arFilter['CAL_TYPE']); $arEvents = CCalendarEvent::GetList( array( 'arFilter' => $arFilter, 'parseRecursion' => true, 'fetchAttendees' => true, 'userId' => $curUserId, 'fetchMeetings' => $type == 'user', 'preciseLimits' => true, 'skipDeclined' => true ) ); if (CCalendar::Date(time(), false) == $params['fromLimit']) $limitTime = time(); else $limitTime = CCalendar::Timestamp($params['fromLimit']); $arResult = array(); $serverOffset = intVal(date("Z")); foreach($arEvents as $event) { if ($event['IS_MEETING'] && $event["MEETING_STATUS"] == 'N') continue; if ($type == 'user' && !$event['IS_MEETING'] && $event['CAL_TYPE'] != 'user') continue; // $serverToTs = timestamp in utc + server offset; $serverToTs = (CCalendar::Timestamp($event['DATE_TO']) - $event['TZ_OFFSET_TO']) + $serverOffset; if ($event['DT_SKIP_TIME'] == 'Y') { $serverToTs += self::DAY_LENGTH; } if ($serverToTs >= $limitTime) { $fromTs = CCalendar::Timestamp($event['DATE_FROM']); $toTs = CCalendar::Timestamp($event['DATE_TO']); if ($event['DT_SKIP_TIME'] !== "Y") { $fromTs -= $event['~USER_OFFSET_FROM']; $toTs -= $event['~USER_OFFSET_TO']; } $event['DATE_FROM'] = CCalendar::Date($fromTs, $event['DT_SKIP_TIME'] != 'Y'); $event['DATE_TO'] = CCalendar::Date($toTs, $event['DT_SKIP_TIME'] != 'Y'); unset($event['TZ_FROM'], $event['TZ_TO'], $event['TZ_OFFSET_FROM'], $event['TZ_OFFSET_TO']); $event['DT_FROM_TS'] = $fromTs; $event['DT_TO_TS'] = $toTs; $arResult[] = $event; } } // Sort by DATE_FROM_TS usort($arResult, array('CCalendar', '_NearestSort')); return $arResult; } public static function _NearestSort($a, $b) { if ($a['DT_FROM_TS'] == $b['DT_FROM_TS']) return 0; if ($a['DT_FROM_TS'] < $b['DT_FROM_TS']) return -1; return 1; } public static function GetAccessibilityForMeetingRoom($params) { $allowReserveMeeting = isset($params['allowReserveMeeting']) ? $params['allowReserveMeeting'] : self::$allowReserveMeeting; $RMiblockId = isset($params['RMiblockId']) ? $params['RMiblockId'] : self::$settings['rm_iblock_id']; $curEventId = $params['curEventId'] > 0 ? $params['curEventId'] : false; $arResult = array(); $offset = CCalendar::GetOffset(); if ($allowReserveMeeting) { $arSelect = array("ID", "NAME", "IBLOCK_SECTION_ID", "IBLOCK_ID", "ACTIVE_FROM", "ACTIVE_TO"); $arFilter = array( "IBLOCK_ID" => $RMiblockId, "SECTION_ID" => $params['id'], "INCLUDE_SUBSECTIONS" => "Y", "ACTIVE" => "Y", "CHECK_PERMISSIONS" => 'N', ">=DATE_ACTIVE_TO" => $params['from'], "<=DATE_ACTIVE_FROM" => $params['to'] ); if(IntVal($curEventId) > 0) { $arFilter["!ID"] = IntVal($curEventId); } $rsElement = CIBlockElement::GetList(Array('ACTIVE_FROM' => 'ASC'), $arFilter, false, false, $arSelect); while($obElement = $rsElement->GetNextElement()) { $arItem = $obElement->GetFields(); $arItem["DISPLAY_ACTIVE_FROM"] = CIBlockFormatProperties::DateFormat(self::DFormat(true), MakeTimeStamp($arItem["ACTIVE_FROM"])); $arItem["DISPLAY_ACTIVE_TO"] = CIBlockFormatProperties::DateFormat(self::DFormat(true), MakeTimeStamp($arItem["ACTIVE_TO"])); $arResult[] = array( "ID" => intVal($arItem['ID']), "NAME" => $arItem['~NAME'], "DT_FROM" => CCalendar::CutZeroTime($arItem['DISPLAY_ACTIVE_FROM']), "DT_TO" => CCalendar::CutZeroTime($arItem['DISPLAY_ACTIVE_TO']), "DT_FROM_TS" => (CCalendar::Timestamp($arItem['DISPLAY_ACTIVE_FROM']) - $offset) * 1000, "DT_TO_TS" => (CCalendar::Timestamp($arItem['DISPLAY_ACTIVE_TO']) - $offset) * 1000 ); } } return $arResult; } public static function GetMeetingRoomById($Params) { if (IntVal($Params['RMiblockId']) > 0 && CIBlock::GetPermission($Params['RMiblockId']) >= "R") { $arFilter = array("IBLOCK_ID" => $Params['RMiblockId'], "ACTIVE" => "Y", "ID" => $Params['id']); $arSelectFields = array("NAME"); $res = CIBlockSection::GetList(array(), $arFilter, false, array("NAME")); if ($arMeeting = $res->GetNext()) return $arMeeting; } if(IntVal($Params['VMiblockId']) > 0 && CIBlock::GetPermission($Params['VMiblockId']) >= "R") { $arFilter = array("IBLOCK_ID" => $Params['VMiblockId'], "ACTIVE" => "Y"); $arSelectFields = array("ID", "NAME", "DESCRIPTION", "IBLOCK_ID"); $res = CIBlockSection::GetList(Array(), $arFilter, false, $arSelectFields); if($arMeeting = $res->GetNext()) { return array( 'ID' => $Params['VMiblockId'], 'NAME' => $arMeeting["NAME"], 'DESCRIPTION' => $arMeeting['DESCRIPTION'], ); } } return false; } public static function ReleaseLocation($loc) { $set = CCalendar::GetSettings(array('request' => false)); if($set['rm_iblock_id']) { CCalendar::ReleaseMeetingRoom(array( 'mrevid' => $loc['mrevid'], 'mrid' => $loc['mrid'], 'RMiblockId' => $set['rm_iblock_id'] )); } if ($loc['room_id'] && $loc['room_event_id'] !== false) { CCalendarLocation::releaseRoom(array( 'room_id' => $loc['room_id'], 'room_event_id' => $loc['room_event_id'] )); } } public static function ReleaseMeetingRoom($Params) { $Params['RMiblockId'] = isset($Params['RMiblockId']) ? $Params['RMiblockId'] : self::$settings['rm_iblock_id']; $arFilter = array( "ID" => $Params['mrevid'], "IBLOCK_ID" => $Params['RMiblockId'], "IBLOCK_SECTION_ID" => $Params['mrid'], "SECTION_ID" => array($Params['mrid']) ); $res = CIBlockElement::GetList(array(), $arFilter, false, false, array("ID")); if($arElement = $res->Fetch()) { $obElement = new CIBlockElement; $obElement->Delete($Params['mrevid']); } // Hack: reserve meeting calendar based on old calendar's cache $cache = new CPHPCache; $cache->CleanDir('event_calendar/'); $cache->CleanDir('event_calendar/events/'); $cache->CleanDir('event_calendar/events/'.$Params['RMiblockId']); } public static function GetCalendarList($calendarId, $params = array()) { self::SetSilentErrorMode(); list($sectionId, $entityType, $entityId) = $calendarId; $arFilter = array( 'CAL_TYPE' => $entityType, 'OWNER_ID' => $entityId ); if (!is_array($params)) $params = array(); if ($sectionId > 0) $arFilter['ID'] = $sectionId; if (isset($params['active'])) { $arFilter['ACTIVE'] = $params['active'] ? 'Y' : 'N'; } $res = CCalendarSect::GetList(array('arFilter' => $arFilter)); $arCalendars = array(); foreach($res as $calendar) { if ($params['skipExchange'] == true && strlen($calendar['DAV_EXCH_CAL']) > 0) { continue; } $arCalendars[] = array( 'ID' => $calendar['ID'], '~NAME' => $calendar['NAME'], 'NAME' => htmlspecialcharsbx($calendar['NAME']), 'DESCRIPTION' => htmlspecialcharsbx($calendar['DESCRIPTION']), 'COLOR' => htmlspecialcharsbx($calendar['COLOR']) //"DATE_CREATE" => date("d.m.Y H:i", self::Timestamp($arSection['DATE_CREATE'])) ); } self::SetSilentErrorMode(false); return $arCalendars; } /* * $params['from'], $params['from'] - datetime in UTC * */ public static function GetDavCalendarEventsList($calendarId, $arFilter = array()) { list($sectionId, $entityType, $entityId) = $calendarId; CCalendar::SetOffset(false, 0); $arFilter1 = array( 'OWNER_ID' => $entityId, 'DELETED' => 'N' ); if (isset($arFilter['DAV_XML_ID'])) { unset($arFilter['DATE_START'], $arFilter['FROM_LIMIT'], $arFilter['DATE_END'], $arFilter['TO_LIMIT']); } else { if (isset($arFilter['DATE_START'])) { $arFilter['FROM_LIMIT'] = $arFilter['DATE_START']; unset($arFilter['DATE_START']); } if (isset($arFilter['DATE_END'])) { $arFilter['TO_LIMIT'] = $arFilter['DATE_END']; unset($arFilter['DATE_END']); } } $fetchMeetings = true; if ($sectionId > 0) { $arFilter['SECTION'] = $sectionId; $fetchMeetings = false; if ($entityType == 'user') $fetchMeetings = self::GetMeetingSection($entityId) == $sectionId; } $arFilter = array_merge($arFilter1, $arFilter); $arEvents = CCalendarEvent::GetList( array( 'arFilter' => $arFilter, 'getUserfields' => false, 'parseRecursion' => false, 'fetchAttendees' => false, 'fetchMeetings' => $fetchMeetings, 'userId' => CCalendar::GetCurUserId() ) ); $result = array(); foreach ($arEvents as $event) { if ($event['IS_MEETING'] && $event["MEETING_STATUS"] == 'N') continue; // Skip events from where owner is host of the meeting and it's meeting from other section if ($entityType == 'user' && $event['IS_MEETING'] && $event['MEETING_HOST'] == $entityId && $event['SECT_ID'] != $sectionId) continue; $event['XML_ID'] = $event['DAV_XML_ID']; if ($event['LOCATION'] !== '') $event['LOCATION'] = CCalendar::GetTextLocation($event['LOCATION']); $event['RRULE'] = CCalendarEvent::ParseRRULE($event['RRULE']); $result[] = $event; } return $result; } public static function GetTextLocation($loc = '') { $location = self::ParseLocation($loc); $result = $loc; if ($location['mrid'] === false && $location['room_id'] === false) { $result = $location['str']; } elseif($location['room_id'] > 0) { $room = CCalendarLocation::getById($location['room_id']); $result = $room ? $room['NAME'] : ''; } else { $MRList = CCalendar::GetMeetingRoomList(); foreach($MRList as $MR) { if ($MR['ID'] == $location['mrid']) { $result = $MR['NAME']; break; } } } return $result; } public static function ParseLocation($location = '') { $res = array( 'mrid' => false, 'mrevid' => false, 'room_id' => false, 'room_event_id' => false, 'str' => $location ); if (strlen($location) > 5 && substr($location, 0, 5) == 'ECMR_') { $location = explode('_', $location); if (count($location) >= 2) { if (intVal($location[1]) > 0) $res['mrid'] = intVal($location[1]); if (intVal($location[2]) > 0) $res['mrevid'] = intVal($location[2]); } } elseif (strlen($location) > 9 && substr($location, 0, 9) == 'calendar_') { $location = explode('_', $location); if (count($location) >= 2) { if (intVal($location[1]) > 0) $res['room_id'] = intVal($location[1]); if (intVal($location[2]) > 0) $res['room_event_id'] = intVal($location[2]); } } return $res; } /* * * * RESERVE MEETING ROOMS * * * */ public static function GetUserPermissionsForCalendar($calendarId, $userId) { list($sectionId, $entityType, $entityId) = $calendarId; $entityType = strtolower($entityType); if ($sectionId == 0) { $res = array( 'bAccess' => CCalendarType::CanDo('calendar_type_view', $entityType, $userId), 'bReadOnly' => !CCalendarType::CanDo('calendar_type_edit', $entityType, $userId) ); } $bOwner = $entityType == 'user' && $entityId == $userId; $res = array( 'bAccess' => $bOwner || CCalendarSect::CanDo('calendar_view_time', $sectionId, $userId), 'bReadOnly' => !$bOwner && !CCalendarSect::CanDo('calendar_edit', $sectionId, $userId) ); if ($res['bReadOnly'] && !$bOwner) { if (CCalendarSect::CanDo('calendar_view_time', $sectionId, $userId)) $res['privateStatus'] = 'time'; if (CCalendarSect::CanDo('calendar_view_title', $sectionId, $userId)) $res['privateStatus'] = 'title'; } return $res; } public static function GetDayLen() { return self::DAY_LENGTH; } public static function UnParseTextLocation($loc = '') { $result = array('NEW' => $loc); if ($loc != "") { $location = self::ParseLocation($loc); if ($location['mrid'] === false) { $MRList = CCalendar::GetMeetingRoomList(); $loc_ = trim(strtolower($loc)); foreach($MRList as $MR) { if (trim(strtolower($MR['NAME'])) == $loc_) { $result['NEW'] = 'ECMR_'.$MR['ID']; break; } } } } return $result; } public static function ClearExchangeHtml($html = "") { // Echange in chrome puts chr(13) instead of \n $html = str_replace(chr(13), "\n", trim($html, chr(13))); $html = preg_replace("/(\s|\S)*<a\s*name=\"bm_begin\"><\/a>/is".BX_UTF_PCRE_MODIFIER,"", $html); $html = preg_replace("/<br>(\n|\r)+/is".BX_UTF_PCRE_MODIFIER,"<br>", $html); return self::ParseHTMLToBB($html); } public static function ParseHTMLToBB($html = "") { $id = AddEventHandler("main", "TextParserBeforeTags", Array("CCalendar", "_ParseHack")); $TextParser = new CTextParser(); $TextParser->allow = array("HTML" => "N", "ANCHOR" => "Y", "BIU" => "Y", "IMG" => "Y", "QUOTE" => "Y", "CODE" => "Y", "FONT" => "N", "LIST" => "Y", "SMILES" => "Y", "NL2BR" => "Y", "VIDEO" => "Y", "TABLE" => "Y", "CUT_ANCHOR" => "Y", "ALIGN" => "Y"); $html = $TextParser->convertText($html); $html = htmlspecialcharsback($html); // Replace BR $html = preg_replace("/\<br\s*\/*\>/is".BX_UTF_PCRE_MODIFIER,"\n", $html); // Kill $html = preg_replace("/ /is".BX_UTF_PCRE_MODIFIER,"", $html); // Kill tags $html = preg_replace("/\<([^>]*?)>/is".BX_UTF_PCRE_MODIFIER,"", $html); $html = htmlspecialcharsbx($html); RemoveEventHandler("main", "TextParserBeforeTags", $id); return $html; } public static function WeekDayByInd($i, $binv = true) { if ($binv) $arDays = array('SU','MO','TU','WE','TH','FR','SA'); else $arDays = array('MO','TU','WE','TH','FR','SA','SU'); return isset($arDays[$i]) ? $arDays[$i] : false; } public static function SaveEvent($params = array()) { $res = self::SaveEventEx($params); if (is_array($res) && isset($res['id'])) { return $res['id']; } else { return $res; } } public static function SaveEventEx($params = array()) { $arFields = $params['arFields']; if (self::$type && !isset($arFields['CAL_TYPE'])) $arFields['CAL_TYPE'] = self::$type; if (self::$bOwner && !isset($arFields['OWNER_ID'])) $arFields['OWNER_ID'] = self::$ownerId; if (!isset($arFields['SKIP_TIME']) && isset($arFields['DT_SKIP_TIME'])) $arFields['SKIP_TIME'] = $arFields['DT_SKIP_TIME'] == 'Y'; $result = array(); $userId = isset($params['userId']) ? $params['userId'] : self::GetCurUserId(); $sectionId = (is_array($arFields['SECTIONS']) && count($arFields['SECTIONS']) > 0) ? $arFields['SECTIONS'][0] : intval($arFields['SECTIONS']); $bPersonal = self::IsPersonal($arFields['CAL_TYPE'], $arFields['OWNER_ID'], $userId); $checkPermission = !isset($params['checkPermission']) || $params['checkPermission'] !== false; $silentErrorMode = isset($params['silentErrorMode']) ? $params['silentErrorMode'] : true; $silentErrorModePrev = self::$silentErrorMode; self::SetSilentErrorMode(); if (!isset($arFields['DATE_FROM']) && !isset($arFields['DATE_TO']) && isset($arFields['DT_FROM']) && isset($arFields['DT_TO'])) { $arFields['DATE_FROM'] = $arFields['DT_FROM']; $arFields['DATE_TO'] = $arFields['DT_TO']; unset($arFields['DT_FROM']); unset($arFields['DT_TO']); } // Fetch current event $curEvent = false; $bNew = !isset($arFields['ID']) || !$arFields['ID']; if (!$bNew) { $curEvent = CCalendarEvent::GetList( array( 'arFilter' => array( "ID" => intVal($arFields['ID']), "DELETED" => "N" ), 'parseRecursion' => false, 'fetchAttendees' => true, 'fetchMeetings' => false, 'userId' => $userId ) ); if ($curEvent) $curEvent = $curEvent[0]; $bPersonal = $bPersonal && self::IsPersonal($curEvent['CAL_TYPE'], $curEvent['OWNER_ID'], $userId); $arFields['CAL_TYPE'] = $curEvent['CAL_TYPE']; $arFields['OWNER_ID'] = $curEvent['OWNER_ID']; $arFields['CREATED_BY'] = $curEvent['CREATED_BY']; $arFields['ACTIVE'] = $curEvent['ACTIVE']; $bChangeMeeting = !$checkPermission || CCalendarSect::CanDo('calendar_edit', $curEvent['SECT_ID'], $userId); if (!isset($arFields['NAME'])) $arFields['NAME'] = $curEvent['NAME']; if (!isset($arFields['DESCRIPTION'])) $arFields['DESCRIPTION'] = $curEvent['DESCRIPTION']; if (!isset($arFields['COLOR']) && $curEvent['COLOR']) $arFields['COLOR'] = $curEvent['COLOR']; if (!isset($arFields['TEXT_COLOR']) && $curEvent['TEXT_COLOR']) $arFields['TEXT_COLOR'] = $curEvent['TEXT_COLOR']; if (!isset($arFields['SECTIONS'])) { $arFields['SECTIONS'] = array($curEvent['SECT_ID']); $sectionId = (is_array($arFields['SECTIONS']) && count($arFields['SECTIONS']) > 0) ? $arFields['SECTIONS'][0] : 0; } if (!isset($arFields['IS_MEETING'])) $arFields['IS_MEETING'] = $curEvent['IS_MEETING']; if (!isset($arFields['ACTIVE'])) $arFields['ACTIVE'] = $curEvent['ACTIVE']; if (!isset($arFields['PRIVATE_EVENT'])) $arFields['PRIVATE_EVENT'] = $curEvent['PRIVATE_EVENT']; if (!isset($arFields['ACCESSIBILITY'])) $arFields['ACCESSIBILITY'] = $curEvent['ACCESSIBILITY']; if (!isset($arFields['IMPORTANCE'])) $arFields['IMPORTANCE'] = $curEvent['IMPORTANCE']; if (!isset($arFields['SKIP_TIME'])) $arFields['SKIP_TIME'] = $curEvent['DT_SKIP_TIME'] == 'Y'; if (!isset($arFields['DATE_FROM']) && isset($curEvent['DATE_FROM'])) $arFields['DATE_FROM'] = $curEvent['DATE_FROM']; if (!isset($arFields['DATE_TO']) && isset($curEvent['DATE_TO'])) $arFields['DATE_TO'] = $curEvent['DATE_TO']; if (!isset($arFields['TZ_FROM'])) $arFields['TZ_FROM'] = $curEvent['TZ_FROM']; if (!isset($arFields['TZ_TO'])) $arFields['TZ_TO'] = $curEvent['TZ_TO']; if (!isset($arFields['MEETING']) && $arFields['IS_MEETING']) $arFields['MEETING'] = $curEvent['MEETING']; if (!isset($arFields['MEETING']) && $arFields['IS_MEETING']) $arFields['MEETING'] = $curEvent['MEETING']; if (!isset($arFields['ATTENDEES']) && !isset($arFields['ATTENDEES_CODES']) && $arFields['IS_MEETING'] && isset($curEvent['~ATTENDEES'])) { $arFields['ATTENDEES'] = array(); foreach($curEvent['~ATTENDEES'] as $att) { $arFields['ATTENDEES'][] = $att['USER_ID']; } } if (!isset($arFields['ATTENDEES_CODES']) && $arFields['IS_MEETING']) { $arFields['ATTENDEES_CODES'] = $curEvent['ATTENDEES_CODES']; } if (!isset($arFields['LOCATION']) && $curEvent['LOCATION'] != "") { $arFields['LOCATION'] = Array( "OLD" => $curEvent['LOCATION'], "NEW" => $curEvent['LOCATION'] ); } if (!$bChangeMeeting) { $arFields['IS_MEETING'] = $curEvent['IS_MEETING']; } if ($arFields['IS_MEETING'] && !$bPersonal && $arFields['CAL_TYPE'] == 'user') { $arFields['SECTIONS'] = array($curEvent['SECT_ID']); } if ($curEvent['IS_MEETING']) { $arFields['MEETING_HOST'] = $curEvent['MEETING_HOST']; } // If it's attendee and but modifying called from CalDav methods if (($params['bSilentAccessMeeting'] || $params['fromWebservice'] === true) && $curEvent['IS_MEETING'] && $curEvent['PARENT_ID'] != $curEvent['ID']) { $params['recursionEditMode'] = 'skip'; $params['sendInvitations'] = false; $params['sendEditNotification'] = false; $params['significantChanges'] = false; $params['arFields'] = array( "ID" => $arFields["ID"], "PARENT_ID" => $arFields["PARENT_ID"], "OWNER_ID" => $arFields["OWNER_ID"], "DAV_XML_ID" => $arFields['DAV_XML_ID'], "CAL_DAV_LABEL" => $arFields['CAL_DAV_LABEL'], "DAV_EXCH_LABEL" => $arFields['DAV_EXCH_LABEL'] ); $params['userId'] = $userId; CCalendarEvent::Edit($params); return true; // CalDav will return 204 } if (!isset($arFields["RRULE"]) && $curEvent["RRULE"] != '' && $params['fromWebservice'] !== true) { $arFields["RRULE"] = CCalendarEvent::ParseRRULE($curEvent["RRULE"]); } if ($params['fromWebservice'] === true) { if ($arFields["RRULE"] == -1 && CCalendarEvent::CheckRecurcion($curEvent)) { $arFields["RRULE"] = CCalendarEvent::ParseRRULE($curEvent['RRULE']); } } if (!isset($arFields['EXDATE']) && $arFields["RRULE"]) $arFields['EXDATE'] = $curEvent['EXDATE']; if ($curEvent) $params['currentEvent'] = $curEvent; if ($checkPermission && !$bPersonal && !CCalendarSect::CanDo('calendar_edit', $curEvent['SECT_ID'], $userId)) { return Loc::getMessage('EC_ACCESS_DENIED'); } } elseif ($sectionId > 0 && $checkPermission && !$bPersonal && !CCalendarSect::CanDo('calendar_add', $sectionId, $userId)) { return CCalendar::ThrowError(Loc::getMessage('EC_ACCESS_DENIED')); } if ($params['autoDetectSection'] && $sectionId <= 0) { $sectionId = false; if ($arFields['CAL_TYPE'] == 'user') { $sectionId = CCalendarSect::GetLastUsedSection('user', $arFields['OWNER_ID'], $userId); if ($sectionId) { $res = CCalendarSect::GetList(array('arFilter' => array('CAL_TYPE' => $arFields['CAL_TYPE'],'OWNER_ID' => $arFields['OWNER_ID'], 'ID'=> $sectionId))); if (!$res || !$res[0]) $sectionId = false; } else { $sectionId = false; } if ($sectionId) $arFields['SECTIONS'] = array($sectionId); } if (!$sectionId) { $sectRes = self::GetSectionForOwner($arFields['CAL_TYPE'], $arFields['OWNER_ID'], $params['autoCreateSection']); if ($sectRes['sectionId'] > 0) { $arFields['SECTIONS'] = array($sectRes['sectionId']); if ($sectRes['autoCreated']) $params['bAffectToDav'] = false; } else { return false; } } } if (isset($arFields["RRULE"])) { $arFields["RRULE"] = CCalendarEvent::CheckRRULE($arFields["RRULE"]); } // Set version if (!isset($arFields['VERSION']) || $arFields['VERSION'] <= $curEvent['VERSION']) $arFields['VERSION'] = $curEvent['VERSION'] ? $curEvent['VERSION'] + 1 : 1; if ($params['autoDetectSection'] && $sectionId <= 0 && $arFields['OWNER_ID'] > 0) { $res = CCalendarSect::GetList(array('arFilter' => array('CAL_TYPE' => $arFields['CAL_TYPE'],'OWNER_ID' => $arFields['OWNER_ID']), 'checkPermissions' => false)); if ($res && is_array($res) && isset($res[0])) { $sectionId = $res[0]['ID']; } elseif ($params['autoCreateSection']) { $defCalendar = CCalendarSect::CreateDefault(array( 'type' => $arFields['CAL_TYPE'], 'ownerId' => $arFields['OWNER_ID'] )); $sectionId = $defCalendar['ID']; $params['bAffectToDav'] = false; } if ($sectionId > 0) $arFields['SECTIONS'] = array($sectionId); else return false; } $bExchange = CCalendar::IsExchangeEnabled() && $arFields['CAL_TYPE'] == 'user'; $bCalDav = CCalendar::IsCalDAVEnabled() && $arFields['CAL_TYPE'] == 'user'; $bGoogleApi = CCalendar::isGoogleApiEnabled(); if ($params['bAffectToDav'] !== false && ($bExchange || $bCalDav || $bGoogleApi) && $sectionId > 0) { $res = CCalendarSync::DoSaveToDav(array( 'bCalDav' => $bCalDav, 'bExchange' => $bExchange, 'sectionId' => $sectionId ), $arFields, $curEvent); if ($res !== true) { return CCalendar::ThrowError($res); } } $params['arFields'] = $arFields; $params['userId'] = $userId; if (self::$ownerId != $arFields['OWNER_ID'] && self::$type != $arFields['CAL_TYPE']) $params['path'] = self::GetPath($arFields['CAL_TYPE'], $arFields['OWNER_ID'], 1); else $params['path'] = self::$path; if ($curEvent && in_array($params['recursionEditMode'], array('this', 'next')) && CCalendarEvent::CheckRecurcion($curEvent)) { // Edit only current instance of the set of reccurent events if ($params['recursionEditMode'] == 'this') { // 1. Edit current reccurent event: exclude current date $excludeDates = CCalendarEvent::GetExDate($curEvent['EXDATE']); $excludeDate = self::Date(self::Timestamp($params['currentEventDateFrom']), false); $excludeDates[] = $excludeDate; // Save current event $id = CCalendar::SaveEvent(array( 'arFields' => array( "ID" => $curEvent["ID"], 'EXDATE' => CCalendarEvent::SetExDate($excludeDates) ), 'recursionEditMode' => 'skip', 'silentErrorMode' => $params['silentErrorMode'], 'sendInvitations' => false, 'sendEditNotification' => false, 'userId' => $userId )); // 2. Copy event with new changes, but without reccursion $newParams = $params; $newParams['sendEditNotification'] = false; if (!$newParams['arFields']['MEETING']['REINVITE']) { $newParams['saveAttendeesStatus'] = true; } $newParams['arFields']['RECURRENCE_ID'] = $curEvent['RECURRENCE_ID'] ? $curEvent['RECURRENCE_ID'] : $newParams['arFields']['ID']; unset($newParams['arFields']['ID']); unset($newParams['arFields']['DAV_XML_ID']); unset($newParams['arFields']['RRULE']); unset($newParams['recursionEditMode']); $newParams['arFields']['REMIND'] = $params['currentEvent']['REMIND']; $fromTs = self::Timestamp($newParams['currentEventDateFrom']); $currentFromTs = self::Timestamp($newParams['arFields']['DATE_FROM']); $length = self::Timestamp($newParams['arFields']['DATE_TO']) - self::Timestamp($newParams['arFields']['DATE_FROM']); if (!isset($newParams['arFields']['DATE_FROM']) || !isset($newParams['arFields']['DATE_TO'])) { $length = $curEvent['DT_LENGTH']; $currentFromTs = self::Timestamp($curEvent['DATE_FROM']); } $instanceDate = !isset($newParams['arFields']['DATE_FROM']) ||self::Date(self::Timestamp($curEvent['DATE_FROM']), false) == self::Date($currentFromTs, false); if ($newParams['arFields']['SKIP_TIME']) { if ($instanceDate) { $newParams['arFields']['DATE_FROM'] = self::Date($fromTs, false); $newParams['arFields']['DATE_TO'] = self::Date($fromTs + $length - CCalendar::GetDayLen(), false); } else { $newParams['arFields']['DATE_FROM'] = self::Date($currentFromTs, false); $newParams['arFields']['DATE_TO'] = self::Date($currentFromTs + $length - CCalendar::GetDayLen(), false); } } else { if ($instanceDate) { $newFromTs = self::DateWithNewTime($currentFromTs, $fromTs); $newParams['arFields']['DATE_FROM'] = self::Date($newFromTs); $newParams['arFields']['DATE_TO'] = self::Date($newFromTs + $length); } } $eventMod = $curEvent; $eventMod['DATE_FROM'] = $newParams['currentEventDateFrom']; $commentXmlId = CCalendarEvent::GetEventCommentXmlId($eventMod); $newParams['arFields']['RELATIONS'] = array('COMMENT_XML_ID' => $commentXmlId); $result['recEventId'] = CCalendar::SaveEvent($newParams); } // Edit all next instances of the set of reccurent events elseif($params['recursionEditMode'] == 'next') { $currentDateTimestamp = self::Timestamp($params['currentEventDateFrom']); // Copy event with new changes $newParams = $params; $recId = $newParams['arFields']['RECURRENCE_ID'] = $curEvent['RECURRENCE_ID'] ? $curEvent['RECURRENCE_ID'] : $newParams['arFields']['ID']; // Check if it's first instance of the series, so we shoudn't create another event if (CCalendar::Date(self::Timestamp($curEvent['DATE_FROM']), false) == CCalendar::Date($currentDateTimestamp, false)) { $newParams['recursionEditMode'] = 'skip'; } else { // 1. Edit current reccurent event - finish it $arFieldsCurrent = array( "ID" => $curEvent["ID"], "RRULE" => CCalendarEvent::ParseRRULE($curEvent['RRULE']) ); $arFieldsCurrent['RRULE']['UNTIL'] = self::Date($currentDateTimestamp - self::GetDayLen(), false); unset($arFieldsCurrent['RRULE']['~UNTIL']); unset($arFieldsCurrent['RRULE']['COUNT']); // Save current event $id = CCalendar::SaveEvent(array( 'arFields' => $arFieldsCurrent, 'silentErrorMode' => $params['silentErrorMode'], 'recursionEditMode' => 'skip', 'sendInvitations' => false, 'sendEditNotification' => false, 'userId' => $userId )); unset($newParams['arFields']['ID']); unset($newParams['arFields']['DAV_XML_ID']); unset($newParams['recursionEditMode']); } if (!$newParams['arFields']['MEETING']['REINVITE']) { $newParams['saveAttendeesStatus'] = true; } $currentFromTs = self::Timestamp($newParams['arFields']['DATE_FROM']); $length = self::Timestamp($newParams['arFields']['DATE_TO']) - self::Timestamp($newParams['arFields']['DATE_FROM']); if (!isset($newParams['arFields']['DATE_FROM']) || !isset($newParams['arFields']['DATE_TO'])) { $length = $curEvent['DT_LENGTH']; $currentFromTs = self::Timestamp($curEvent['DATE_FROM']); } $instanceDate = !isset($newParams['arFields']['DATE_FROM']) ||self::Date(self::Timestamp($curEvent['DATE_FROM']), false) == self::Date($currentFromTs, false); if ($newParams['arFields']['SKIP_TIME']) { if ($instanceDate) { $newParams['arFields']['DATE_FROM'] = self::Date($currentDateTimestamp, false); $newParams['arFields']['DATE_TO'] = self::Date($currentDateTimestamp + $length, false); } else { $newParams['arFields']['DATE_FROM'] = self::Date($currentFromTs, false); $newParams['arFields']['DATE_TO'] = self::Date($currentFromTs + $length, false); } } else { if ($instanceDate) { $newFromTs = self::DateWithNewTime($currentFromTs, $currentDateTimestamp); $newParams['arFields']['DATE_FROM'] = self::Date($newFromTs); $newParams['arFields']['DATE_TO'] = self::Date($newFromTs + $length); } } if (isset($curEvent['EXDATE']) && $curEvent['EXDATE'] != '') $newParams['arFields']['EXDATE'] = $curEvent['EXDATE']; $result['recEventId'] = CCalendar::SaveEvent($newParams); if ($recId) { $recRelatedEvents = CCalendarEvent::GetEventsByRecId($recId, false); foreach($recRelatedEvents as $ev) { $evFromTs = CCalendar::Timestamp($ev['DATE_FROM']); if($evFromTs > $currentDateTimestamp) { $newParams['arFields']['ID'] = $ev['ID']; $newParams['arFields']['RRULE'] = CCalendarEvent::ParseRRULE($ev['RRULE']); if ($newParams['arFields']['SKIP_TIME']) { $newParams['arFields']['DATE_FROM'] = self::Date($evFromTs, false); $newParams['arFields']['DATE_TO'] = self::Date(CCalendar::Timestamp($ev['DATE_TO']), false); } else { $newFromTs = self::DateWithNewTime($currentFromTs, $evFromTs); $newParams['arFields']['DATE_FROM'] = self::Date($newFromTs); $newParams['arFields']['DATE_TO'] = self::Date($newFromTs + $length); } CCalendar::SaveEvent($newParams); } } } } } else { if ($params['recursionEditMode'] !== 'all') $params['recursionEditMode'] = 'skip'; else $params['recursionEditMode'] = ''; $id = CCalendarEvent::Edit($params); if($id) { $UFs = $params['UF']; if(isset($UFs) && count($UFs) > 0) { CCalendarEvent::UpdateUserFields($id, $UFs); if($arFields['IS_MEETING']) { if(!empty($UFs['UF_WEBDAV_CAL_EVENT'])) { $UF = $GLOBALS['USER_FIELD_MANAGER']->GetUserFields("CALENDAR_EVENT", $id, LANGUAGE_ID); CCalendar::UpdateUFRights($UFs['UF_WEBDAV_CAL_EVENT'], $arFields['ATTENDEES_CODES'], $UF['UF_WEBDAV_CAL_EVENT']); } } } } // Here we should select all events connected with edited via RECURRENCE_ID: // It could be original source event (without RECURRENCE_ID) or sibling events if ($curEvent && CCalendarEvent::CheckRecurcion($curEvent) && !$params['recursionEditMode'] && !$params['arFields']['RECURRENCE_ID'] ) { $events = array(); $recId = $curEvent['RECURRENCE_ID'] ? $curEvent['RECURRENCE_ID'] : $curEvent['ID']; if ($curEvent['RECURRENCE_ID'] && $curEvent['RECURRENCE_ID'] !== $curEvent['ID']) { $topEvent = CCalendarEvent::GetById($curEvent['RECURRENCE_ID']); if ($topEvent) { $events[] = $topEvent; } } if ($recId) { $events_1 = CCalendarEvent::GetList(array('arFilter' => array('RECURRENCE_ID' => $recId), 'parseRecursion' => false, 'setDefaultLimit' => false)); if ($events_1) $events = array_merge($events, $events_1); } foreach($events as $ev) { if ($ev['ID'] !== $curEvent['ID']) { $newParams = $params; $newParams['arFields']['ID'] = $ev['ID']; $newParams['arFields']['RECURRENCE_ID'] = $ev['RECURRENCE_ID']; $newParams['arFields']['DAV_XML_ID'] = $ev['DAV_XML_ID']; $newParams['arFields']['CAL_DAV_LABEL'] = $ev['CAL_DAV_LABEL']; $newParams['arFields']['RRULE'] = CCalendarEvent::ParseRRULE($ev['RRULE']); $newParams['recursionEditMode'] = 'skip'; $newParams['currentEvent'] = $ev; $eventFromTs = self::Timestamp($ev['DATE_FROM']); $currentFromTs = self::Timestamp($newParams['arFields']['DATE_FROM']); $length = self::Timestamp($newParams['arFields']['DATE_TO']) - self::Timestamp($newParams['arFields']['DATE_FROM']); if ($newParams['arFields']['SKIP_TIME']) { $newParams['arFields']['DATE_FROM'] = $ev['DATE_FROM']; $newParams['arFields']['DATE_TO'] = self::Date($eventFromTs + $length, false); } else { $newFromTs = self::DateWithNewTime($currentFromTs, $eventFromTs); $newParams['arFields']['DATE_FROM'] = self::Date($newFromTs); $newParams['arFields']['DATE_TO'] = self::Date($newFromTs + $length); } if (isset($ev['EXDATE']) && $ev['EXDATE'] != '') $newParams['arFields']['EXDATE'] = $ev['EXDATE']; CCalendar::SaveEvent($newParams); } } } $arFields['ID'] = $id; foreach(GetModuleEvents("calendar", "OnAfterCalendarEventEdit", true) as $arEvent) ExecuteModuleEventEx($arEvent, array('arFields' => $arFields, 'bNew' => $bNew, 'userId' => $userId)); } self::SetSilentErrorMode($silentErrorModePrev); $result['id'] = $id; return $result; } public static function ThrowError($str) { if (self::$silentErrorMode) return false; global $APPLICATION; echo '<!-- BX_EVENT_CALENDAR_ACTION_ERROR:'.$str.'-->'; return $APPLICATION->ThrowException($str); } public static function GetSectionForOwner($calType, $ownerId, $autoCreate = true) { return CCalendarSect::GetSectionForOwner($calType, $ownerId, $autoCreate); } public static function UpdateUFRights($files, $rights, $ufEntity = array()) { global $USER; static $arTasks = null; if (!is_array($rights) || sizeof($rights) <= 0) return false; if ($files===null || $files===false) return false; if (!is_array($files)) $files = array($files); if (sizeof($files) <= 0) return false; if (!\Bitrix\Main\Loader::includeModule('iblock') || !\Bitrix\Main\Loader::includeModule('webdav')) return false; $arFiles = array(); foreach($files as $id) { $id = intval($id); if (intval($id) > 0) $arFiles[] = $id; } if (sizeof($arFiles) <= 0) return false; if ($arTasks == null) $arTasks = CWebDavIblock::GetTasks(); $arCodes = array(); foreach($rights as $value) { if (substr($value, 0, 2) === 'SG') $arCodes[] = $value.'_K'; $arCodes[] = $value; } $arCodes = array_unique($arCodes); $i=0; $arViewRights = $arEditRights = array(); $curUserID = 'U'.$USER->GetID(); foreach($arCodes as $right) { if ($curUserID == $right) // do not override owner's rights continue; $key = 'n' . $i++; $arViewRights[$key] = array( 'GROUP_CODE' => $right, 'TASK_ID' => $arTasks['R'], ); } $ibe = new CIBlockElement(); $dbWDFile = $ibe->GetList(array(), array('ID' => $arFiles, 'SHOW_NEW' => 'Y'), false, false, array('ID', 'NAME', 'SECTION_ID', 'IBLOCK_ID', 'WF_NEW')); $iblockIds = array(); if ($dbWDFile) { while ($arWDFile = $dbWDFile->Fetch()) { $id = $arWDFile['ID']; if ($arWDFile['WF_NEW'] == 'Y') $ibe->Update($id, array('BP_PUBLISHED' => 'Y')); if (CIBlock::GetArrayByID($arWDFile['IBLOCK_ID'], "RIGHTS_MODE") === "E") { $ibRights = CWebDavIblock::_get_ib_rights_object('ELEMENT', $id, $arWDFile['IBLOCK_ID']); $ibRights->SetRights(CWebDavTools::appendRights($ibRights, $arViewRights, $arTasks)); if(empty($iblockIds[$arWDFile['IBLOCK_ID']])) $iblockIds[$arWDFile['IBLOCK_ID']] = $arWDFile['IBLOCK_ID']; } } global $CACHE_MANAGER; foreach ($iblockIds as $iblockId) $CACHE_MANAGER->ClearByTag('iblock_id_' . $iblockId); unset($iblockId); } } public static function TempUser($TmpUser = false, $create = true, $ID = false) { global $USER; if ($create && $TmpUser === false && (!$USER || !is_object($USER))) { $USER = new CUser; if ($ID && intVal($ID) > 0) $USER->Authorize(intVal($ID)); return $USER; } elseif (!$create && $USER && is_object($USER)) { unset($USER); return false; } return false; } public static function SaveSection($Params) { $type = isset($Params['arFields']['CAL_TYPE']) ? $Params['arFields']['CAL_TYPE'] : self::$type; // Exchange if ($Params['bAffectToDav'] !== false && CCalendar::IsExchangeEnabled(self::$ownerId) && $type == 'user') { $exchRes = true; $ownerId = isset($Params['arFields']['OWNER_ID']) ? $Params['arFields']['OWNER_ID'] : self::$ownerId; if(isset($Params['arFields']['ID']) && $Params['arFields']['ID'] > 0) { // Fetch section //$oSect = CCalendarSect::GetById($Params['arFields']['ID']); // For exchange we change only calendar name //if ($oSect && $oSect['IS_EXCHANGE'] && $oSect['DAV_EXCH_CAL'] && $oSect["NAME"] != $Params['arFields']['NAME']) // $exchRes = CDavExchangeCalendar::DoUpdateCalendar($ownerId, $oSect['DAV_EXCH_CAL'], $oSect['DAV_EXCH_MOD'], $Params['arFields']); } elseif($Params['arFields']['IS_EXCHANGE']) { $exchRes = CDavExchangeCalendar::DoAddCalendar($ownerId, $Params['arFields']); } if ($exchRes !== true) { if (!is_array($exchRes) || !array_key_exists("XML_ID", $exchRes)) return CCalendar::ThrowError(CCalendar::CollectExchangeErrors($exchRes)); // // It's ok, we successfuly save event to exchange calendar - and save it to DB $Params['arFields']['DAV_EXCH_CAL'] = $exchRes['XML_ID']; $Params['arFields']['DAV_EXCH_MOD'] = $exchRes['MODIFICATION_LABEL']; } } // Save here $ID = CCalendarSect::Edit($Params); CCalendar::ClearCache(array('section_list', 'event_list')); return $ID; } public static function ClearCache($arPath = false) { global $CACHE_MANAGER; $CACHE_MANAGER->ClearByTag("CALENDAR_EVENT_LIST"); if ($arPath === false) $arPath = array( 'access_tasks', 'type_list', 'section_list', 'attendees_list', 'event_list' ); elseif (!is_array($arPath)) $arPath = array($arPath); if (is_array($arPath) && count($arPath) > 0) { $cache = new CPHPCache; foreach($arPath as $path) if ($path != '') $cache->CleanDir(CCalendar::CachePath().$path); } } public static function CachePath() { return self::$cachePath; } // * * * * * * * * * * * * CalDAV + Exchange * * * * * * * * * * * * * * * * public static function SyncCalendarItems($connectionType, $calendarId, $arCalendarItems) { self::$silentErrorMode = true; // $arCalendarItems: //Array( // [0] => Array( // [XML_ID] => AAATAGFudGlfYn... // [MODIFICATION_LABEL] => DwAAABYAAA... // ) // [1] => Array( // [XML_ID] => AAATAGFudGlfYnVn... // [MODIFICATION_LABEL] => DwAAABYAAAAQ... // ) //) list($sectionId, $entityType, $entityId) = $calendarId; $entityType = strtolower($entityType); if ($connectionType == 'exchange') $xmlIdField = "DAV_EXCH_LABEL"; elseif ($connectionType == 'caldav') $xmlIdField = "CAL_DAV_LABEL"; else return array(); $arCalendarItemsMap = array(); foreach ($arCalendarItems as $value) $arCalendarItemsMap[$value["XML_ID"]] = $value["MODIFICATION_LABEL"]; $arModified = array(); $eventsList = CCalendarEvent::GetList( array( 'arFilter' => array( 'CAL_TYPE' => $entityType, 'OWNER_ID' => $entityId, 'SECTION' => $sectionId ), 'getUserfields' => false, 'parseRecursion' => false, 'fetchAttendees' => false, 'fetchMeetings' => false, 'userId' => $entityType == 'user' ? $entityId : '0' ) ); foreach ($eventsList as $event) { if (isset($arCalendarItemsMap[$event["DAV_XML_ID"]])) { if ($event[$xmlIdField] != $arCalendarItemsMap[$event["DAV_XML_ID"]]) $arModified[$event["DAV_XML_ID"]] = $event["ID"]; unset($arCalendarItemsMap[$event["DAV_XML_ID"]]); } else { if ($connectionType == 'exchange') { if ($event['ID'] == $event['PARENT_ID']) { self::DeleteCalendarEvent($calendarId, $event["ID"], self::$userId, $event); } } else { self::DeleteCalendarEvent($calendarId, $event["ID"], self::$userId, $event); } } } $arResult = array(); foreach ($arCalendarItems as $value) { if (array_key_exists($value["XML_ID"], $arModified)) { $arResult[] = array( "XML_ID" => $value["XML_ID"], "ID" => $arModified[$value["XML_ID"]] ); } } foreach ($arCalendarItemsMap as $key => $value) { $arResult[] = array( "XML_ID" => $key, "ID" => 0 ); } self::$silentErrorMode = false; return $arResult; } public static function DeleteCalendarEvent($calendarId, $eventId, $userId, $oEvent = false) { self::$silentErrorMode = true; list($sectionId, $entityType, $entityId) = $calendarId; $res = CCalendarEvent::Delete(array( 'id' => $eventId, 'userId' => $userId, 'bMarkDeleted' => true, 'Event' => $oEvent )); self::$silentErrorMode = false; return $res; } // Called from CalDav sync functions and from CCalendar::SyncCalendarItems public static function SyncClearCache() { } public static function Color($color = '', $defaultColor = true) { if ($color != '') { $color = ltrim(trim(preg_replace('/[^\d|\w]/', '', $color)), "#"); if (strlen($color) > 6) $color = substr($color, 0, 6); elseif(strlen($color) < 6) $color = ''; } $color = '#'.$color; // Default color $DEFAULT_COLOR = '#9dcf00'; if ($color == '#') { if ($defaultColor === true) $color = $DEFAULT_COLOR; elseif($defaultColor) $color = $defaultColor; else $color = ''; } return $color; } public static function ConvertDayInd($i) { return $i == 0 ? 6 : $i - 1; } // return array('bAccess' => true/false, 'bReadOnly' => true/false, 'privateStatus' => 'time'/'title'); public static function _fixTimestamp($timestamp) { if (date("Z") !== date("Z", $timestamp)) { $timestamp += (date("Z") - date("Z", $timestamp)); } return $timestamp; } // Called from CalDav, Exchange methods public static function FormatTime($h = 0, $m = 0) { $m = intVal($m); if ($m > 59) $m = 59; elseif ($m < 0) $m = 0; if ($m < 10) $m = '0'.$m; $h = intVal($h); if ($h > 24) $h = 24; if ($h < 0) $h = 0; if (IsAmPmMode()) { $ampm = 'am'; if ($h == 0) { $h = 12; } else if ($h == 12) { $ampm = 'pm'; } else if ($h > 12) { $ampm = 'pm'; $h -= 12; } $res = $h.':'.$m.' '.$ampm; } else { $res = (($h < 10) ? '0' : '').$h.':'.$m; } return $res; } // Called from SaveEvent: try to save event in Exchange or to Dav Server and if it's Ok, return true public static function GetUserId() { if (!self::$userId) self::$userId = self::GetCurUserId(); return self::$userId; } public static function GetReadonlyMode() { return self::$readOnly; } // Called from CalDav sync methods public static function GetUserAvatarSrc($user = array(), $params = array()) { if (!is_array($user) && intVal($user) > 0) $user = self::GetUser($user); $avatar_src = self::GetUserAvatar($user, $params); if ($avatar_src === false) $avatar_src = '/bitrix/images/1.gif'; return $avatar_src; } public static function GetUserAvatar($user = array(), $params = array()) { if (!is_array($user) && intVal($user) > 0) $user = self::GetUser($user); if (!empty($user["PERSONAL_PHOTO"])) { if (empty($params['AVATAR_SIZE'])) { $params['AVATAR_SIZE'] = 42; } $arFileTmp = CFile::ResizeImageGet( $user["PERSONAL_PHOTO"], array('width' => $params['AVATAR_SIZE'], 'height' => $params['AVATAR_SIZE']), BX_RESIZE_IMAGE_EXACT, false ); $avatar_src = $arFileTmp['src']; } else { $avatar_src = false; } return $avatar_src; } public static function GetUserUrl($userId = 0, $pathToUser = "") { if ($pathToUser == '') { if (self::$pathToUser == '') { if (empty(self::$pathesForSite)) self::$pathesForSite = self::GetPathes(SITE_ID); self::$pathToUser = self::$pathesForSite['path_to_user']; } $pathToUser = self::$pathToUser; } return CUtil::JSEscape(CComponentEngine::MakePathFromTemplate($pathToUser, array("user_id" => $userId, "USER_ID" => $userId))); } public static function GetAccessTasksByName($binging = 'calendar_section', $name = 'calendar_denied') { $arTasks = CCalendar::GetAccessTasks($binging); foreach($arTasks as $id => $task) if ($task['name'] == $name) return $id; return false; } public static function GetAccessTasks($binging = 'calendar_section') { \Bitrix\Main\Localization\Loc::loadLanguageFile($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/calendar/admin/task_description.php"); if (is_array(self::$arAccessTask[$binging])) return self::$arAccessTask[$binging]; $bIntranet = self::IsIntranetEnabled(); $arTasks = Array(); $res = CTask::GetList(Array('ID' => 'asc'), Array('MODULE_ID' => 'calendar', 'BINDING' => $binging)); while($arRes = $res->Fetch()) { if (!$bIntranet && (strtolower($arRes['NAME']) == 'calendar_view_time' || strtolower($arRes['NAME']) == 'calendar_view_title')) continue; $name = ''; if ($arRes['SYS']) $name = Loc::getMessage('TASK_NAME_'.strtoupper($arRes['NAME'])); if (strlen($name) == 0) $name = $arRes['NAME']; $arTasks[$arRes['ID']] = array( 'name' => $arRes['NAME'], 'title' => $name ); } self::$arAccessTask[$binging] = $arTasks; return $arTasks; } public static function PushAccessNames($arCodes = array()) { foreach($arCodes as $code) { if (!array_key_exists($code, self::$accessNames)) { self::$accessNames[$code] = null; } } } public static function SetLocation($old = '', $new = '', $params = array()) { $tzEnabled = CTimeZone::Enabled(); if ($tzEnabled) { CTimeZone::Disable(); } // *** ADD MEETING ROOM *** $locOld = CCalendar::ParseLocation($old); $locNew = CCalendar::ParseLocation($new); CCalendar::GetSettings(array('request' => false)); $res = $locNew['mrid'] ? $locNew['str'] : $new; $RMiblockId = isset($params['RMiblockId']) ? $params['RMiblockId'] : self::$settings['rm_iblock_id']; // If not allowed if ($RMiblockId && $locOld['mrid'] !== false && $locOld['mrevid'] !== false) // Release MR { CCalendar::ReleaseMeetingRoom(array( 'mrevid' => $locOld['mrevid'], 'mrid' => $locOld['mrid'], 'RMiblockId' => $RMiblockId )); } if ($locOld['room_id'] !== false && $locOld['room_event_id'] !== false) // Release MR { CCalendar::ReleaseLocation($locOld); } if ($locNew['mrid'] !== false) // Reserve MR { $mrevid = false; if ($params['bRecreateReserveMeetings']) { $mrevid = CCalendar::ReserveMeetingRoom(array( 'RMiblockId' => $RMiblockId, 'mrid' => $locNew['mrid'], 'dateFrom' => $params['dateFrom'], 'dateTo' => $params['dateTo'], 'name' => $params['name'], 'description' => Loc::getMessage('EC_RESERVE_FOR_EVENT').': '.$params['name'], 'persons' => $params['persons'], 'members' => $params['attendees'] )); } elseif(is_array($locNew) && $locNew['mrevid'] !== false) { $mrevid = $locNew['mrevid']; } $locNew = ($mrevid && $mrevid != 'reserved' && $mrevid != 'expire' && $mrevid > 0) ? 'ECMR_'.$locNew['mrid'].'_'.$mrevid : ''; } elseif($locNew['room_id']) { $roomEventId = CCalendarLocation::reserveRoom(array( 'room_id' => $locNew['room_id'], 'room_event_id' => false, 'parentParams' => $params['parentParams'] )); $locNew = $roomEventId ? 'calendar_'.$locNew['room_id'].'_'.$roomEventId : ''; } else { $locNew = $locNew['str']; } if ($locNew) { $res = $locNew; } if ($tzEnabled) { CTimeZone::Enable(); } return $res; } public static function ReserveMeetingRoom($params) { $tst = MakeTimeStamp($params['dateTo']); if (date("H:i", $tst) == '00:00') $params['dateTo'] = CIBlockFormatProperties::DateFormat(self::DFormat(true), $tst + (23 * 60 + 59) * 60); CCalendar::GetSettings(array('request' => false)); $params['RMiblockId'] = (isset($params['RMiblockId']) && $params['RMiblockId']) ? $params['RMiblockId'] : self::$settings['rm_iblock_id']; $check = CCalendar::CheckMeetingRoom($params); if ($check !== true) return $check; $arFields = array( "IBLOCK_ID" => $params['RMiblockId'], "IBLOCK_SECTION_ID" => $params['mrid'], "NAME" => $params['name'], "DATE_ACTIVE_FROM" => $params['dateFrom'], "DATE_ACTIVE_TO" => $params['dateTo'], "CREATED_BY" => CCalendar::GetCurUserId(), "DETAIL_TEXT" => $params['description'], "PROPERTY_VALUES" => array( "UF_PERSONS" => $params['persons'], "PERIOD_TYPE" => 'NONE' ), "ACTIVE" => "Y" ); $bs = new CIBlockElement; $id = $bs->Add($arFields); // Hack: reserve meeting calendar based on old calendar's cache $cache = new CPHPCache; $cache->CleanDir('event_calendar/'); $cache->CleanDir('event_calendar/events/'); $cache->CleanDir('event_calendar/events/'.$params['RMiblockId']); return $id; } public static function CheckMeetingRoom($Params) { $fromDateTime = MakeTimeStamp($Params['dateFrom']); $toDateTime = MakeTimeStamp($Params['dateTo']); $arFilter = array( "ACTIVE" => "Y", "IBLOCK_ID" => $Params['RMiblockId'], "SECTION_ID" => $Params['mrid'], "<DATE_ACTIVE_FROM" => $Params['dateTo'], ">DATE_ACTIVE_TO" => $Params['dateFrom'], "PROPERTY_PERIOD_TYPE" => "NONE", ); if ($Params['mrevid_old'] > 0) $arFilter["!=ID"] = $Params['mrevid_old']; $dbElements = CIBlockElement::GetList(array("DATE_ACTIVE_FROM" => "ASC"), $arFilter, false, false, array('ID')); if ($arElements = $dbElements->GetNext()) return 'reserved'; include_once($_SERVER['DOCUMENT_ROOT']."/bitrix/components/bitrix/intranet.reserve_meeting/init.php"); $arPeriodicElements = __IRM_SearchPeriodic($fromDateTime, $toDateTime, $Params['RMiblockId'], $Params['mrid']); for ($i = 0, $l = count($arPeriodicElements); $i < $l; $i++) if (!$Params['mrevid_old'] || $arPeriodicElements[$i]['ID'] != $Params['mrevid_old']) return 'reserved'; return true; } public static function GetOuterUrl() { return self::$outerUrl; } public static function ManageConnections($arConnections = array()) { global $APPLICATION; $bSync = false; $l = count($arConnections); for ($i = 0; $i < $l; $i++) { $con = $arConnections[$i]; $conId = intVal($con['id']); if ($conId <= 0) // It's new connection { if ($con['del'] != 'Y') { if(!CCalendar::CheckCalDavUrl($con['link'], $con['user_name'], $con['pass'])) return Loc::getMessage("EC_CALDAV_URL_ERROR"); CDavConnection::Add(array( "ENTITY_TYPE" => 'user', "ENTITY_ID" => self::$ownerId, "ACCOUNT_TYPE" => 'caldav', "NAME" => $con['name'], "SERVER" => $con['link'], "SERVER_USERNAME" => $con['user_name'], "SERVER_PASSWORD" => $con['pass']) ); $bSync = true; } } elseif ($con['del'] != 'Y') // Edit connection { $arFields = array( "NAME" => $con['name'], "SERVER" => $con['link'], "SERVER_USERNAME" => $con['user_name'] ); if ($con['pass'] !== 'bxec_not_modify_pass') $arFields["SERVER_PASSWORD"] = $con['pass']; $resCon = CDavConnection::GetList(array("ID" => "ASC"), array("ID" => $conId)); if ($arCon = $resCon->Fetch()) { if($arCon['ACCOUNT_TYPE'] !== 'caldav_google_oauth' && $arCon['ACCOUNT_TYPE'] !== 'google_api_oauth') { CDavConnection::Update($conId, $arFields); } } if (is_array($con['sections'])) { foreach ($con['sections'] as $sectId => $active) { $sectId = intVal($sectId); if(CCalendar::IsPersonal() || CCalendarSect::CanDo('calendar_edit_section', $sectId, self::$userId)) { CCalendarSect::Edit(array('arFields' => array("ID" => $sectId, "ACTIVE" => $active == "Y" ? "Y" : "N"))); } } } $bSync = true; } else { CCalendar::RemoveConnection(array('id' => $conId, 'del_calendars' => $con['del_calendars'])); } } if($err = $APPLICATION->GetException()) { return $err->GetString(); } if ($bSync) CDavGroupdavClientCalendar::DataSync("user", self::$ownerId); $res = CDavConnection::GetList( array("ID" => "DESC"), array( "ENTITY_TYPE" => "user", "ENTITY_ID" => self::$ownerId ), false, false ); while($arCon = $res->Fetch()) { if ($arCon['ACCOUNT_TYPE'] == 'caldav_google_oauth' || $arCon['ACCOUNT_TYPE'] == 'caldav') { if(strpos($arCon['LAST_RESULT'], "[200]") === false) return Loc::getMessage('EC_CALDAV_CONNECTION_ERROR', array('#CONNECTION_NAME#' => $arCon['NAME'], '#ERROR_STR#' => $arCon['LAST_RESULT'])); } } return true; } public static function CheckCalDavUrl($url, $username, $password) { $arServer = parse_url($url); // Mantis #71074 if (strpos(strtolower($_SERVER['SERVER_NAME']), strtolower($arServer['host'])) !== false || strpos(strtolower($_SERVER['HTTP_HOST']), strtolower($arServer['host'])) !== false) return false; return CDavGroupdavClientCalendar::DoCheckCalDAVServer($arServer["scheme"], $arServer["host"], $arServer["port"], $username, $password, $arServer["path"]); } public static function RemoveConnection($connection = array()) { // Clean sections $res = CCalendarSect::GetList(array('arFilter' => array('CAL_TYPE' => 'user', 'OWNER_ID' => self::$ownerId, 'CAL_DAV_CON' => $connection['id']))); $pushChannelResult = PushTable::getList(array( 'select' => array('*'), 'filter' => array('ENTITY_TYPE' => 'CONNECTION', 'ENTITY_ID' => $connection['id']) )); if ($row = $pushChannelResult->fetch()) { \Bitrix\Calendar\Sync\GoogleApiPush::stopChannel($row, $connection['ENTITY_ID']); } foreach ($res as $sect) { if ($connection['del_calendars'] == 'Y') // Delete all callendars from this connection { $pushChannelResult = PushTable::getList(array( 'select' => array('*'), 'filter' => array('ENTITY_TYPE' => 'SECTION', 'ENTITY_ID' => $sect['ID']) )); if ($row = $pushChannelResult->fetch()) { \Bitrix\Calendar\Sync\GoogleApiPush::stopChannel($row, $sect['OWNER_ID']); } CCalendarSect::Delete($sect['ID'], false); } else CCalendarSect::Edit(array('arFields' => array("ID" => $sect['ID'], "CAL_DAV_CON" => '', 'CAL_DAV_CAL' => '', 'CAL_DAV_MOD' => ''))); } // Delete Google oauth token if it's google oauth caldav connection $resCon = CDavConnection::GetList(array("ID" => "ASC"), array("ID" => $connection['id'])); if ($arCon = $resCon->Fetch()) { $googleCalDavStatus = CCalendarSync::GetGoogleCalendarConnection(); if($googleCalDavStatus['googleCalendarPrimaryId'] && $arCon['ACCOUNT_TYPE'] == 'caldav_google_oauth') { $serverPath = 'https://apidata.googleusercontent.com/caldav/v2/' . $googleCalDavStatus['googleCalendarPrimaryId'] . '/user'; } elseif ($googleCalDavStatus['googleCalendarPrimaryId'] && $arCon['ACCOUNT_TYPE'] == 'google_api_oauth') { $serverPath = 'https://www.googleapis.com/calendar/v3'; } if ($arCon['SERVER'] == $serverPath) { if (\Bitrix\Main\Loader::includeModule('socialservices')) { $client = new CSocServGoogleOAuth(CCalendar::GetCurUserId()); $client->getEntityOAuth()->addScope(array('https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/calendar.readonly')); // Delete stored tokens $client->getEntityOAuth()->deleteStorageTokens(); } } } // Delete dav connections CDavConnection::Delete($connection['id']); } public static function GetTypeByExternalId($externalId = false) { if ($externalId) { $res = CCalendarType::GetList(array('arFilter' => array('EXTERNAL_ID' => $externalId))); if ($res && $res[0]) return $res[0]['XML_ID']; } return false; } public static function SetCurUserMeetingSection($userMeetingSection) { self::$userMeetingSection = $userMeetingSection; } public static function CacheTime($time = false) { if ($time !== false) self::$cacheTime = $time; return self::$cacheTime; } public static function _ParseHack(&$text, &$TextParser) { $text = preg_replace(array("/\</is".BX_UTF_PCRE_MODIFIER, "/\>/is".BX_UTF_PCRE_MODIFIER),array('<', '>'),$text); $text = preg_replace("/\<br\s*\/*\>/is".BX_UTF_PCRE_MODIFIER,"", $text); $text = preg_replace("/\<(\w+)[^>]*\>(.+?)\<\/\\1[^>]*\>/is".BX_UTF_PCRE_MODIFIER,"\\2",$text); $text = preg_replace("/\<*\/li\>/is".BX_UTF_PCRE_MODIFIER,"", $text); $text = str_replace(array("<", ">"),array("<", ">"),$text); $TextParser->allow = array(); return true; } public static function IsSocnetAdmin() { if (!isset(self::$bCurUserSocNetAdmin)) self::$bCurUserSocNetAdmin = self::IsSocNet() && CSocNetUser::IsCurrentUserModuleAdmin(); return self::$bCurUserSocNetAdmin; } public static function GetMaxDate() { if (!self::$CALENDAR_MAX_DATE) { $date = new DateTime(); $date->setDate(2038, 1, 1); self::$CALENDAR_MAX_DATE = self::Date($date->getTimestamp(), false); } return self::$CALENDAR_MAX_DATE; } public static function GetMinDate() { if (!self::$CALENDAR_MIN_DATE) { $date = new DateTime(); $date->setDate(1970, 1, 1); self::$CALENDAR_MIN_DATE = self::Date($date->getTimestamp(), false); } return self::$CALENDAR_MIN_DATE; } public static function GetDestinationUsers($codes, $fetchUsers = false) { if (!Main\Loader::includeModule('socialnetwork')) { return array(); } $users = \CSocNetLogDestination::getDestinationUsers($codes, $fetchUsers); if ($fetchUsers) { for ($i = 0, $l = count($users); $i < $l; $i++) { $users[$i]['FORMATTED_NAME'] = CCalendar::GetUserName($users[$i]); } } return $users; } public static function GetAttendeesMessage($cnt = 0) { if ( ($cnt % 100) > 10 && ($cnt % 100) < 20 ) $suffix = 5; else $suffix = $cnt % 10; return Loc::getMessage("EC_ATTENDEE_".$suffix, Array("#NUM#" => $cnt)); } public static function GetMoreAttendeesMessage($cnt = 0) { if ( ($cnt % 100) > 10 && ($cnt % 100) < 20 ) $suffix = 5; else $suffix = $cnt % 10; return Loc::getMessage("EC_ATTENDEE_MORE_".$suffix, Array("#NUM#" => $cnt)); } public static function GetFormatedDestination($codes = array()) { $ac = CSocNetLogTools::FormatDestinationFromRights($codes, array( "CHECK_PERMISSIONS_DEST" => "Y", "DESTINATION_LIMIT" => 100000, "NAME_TEMPLATE" => "#NAME# #LAST_NAME#", "PATH_TO_USER" => "/company/personal/user/#user_id#/", )); return $ac; } public static function GetFromToHtml($fromTs = false, $toTs = false, $skipTime = false, $dtLength = 0, $forRrule = false) { if (intVal($fromTs) != $fromTs) { $fromTs = self::Timestamp($fromTs); } if (intVal($toTs) != $toTs) { $toTs = self::Timestamp($toTs); } if ($toTs < $fromTs) { $toTs = $fromTs; } // Formats $formatShort = CCalendar::DFormat(false); $formatFull = CCalendar::DFormat(true); $formatTime = str_replace($formatShort, '', $formatFull); $formatTime = $formatTime == $formatFull ? "H:i" : str_replace(':s', '', $formatTime); $html = ''; $formatFull = str_replace(':s', '', $formatFull); if ($skipTime) { if ($dtLength == self::DAY_LENGTH || !$dtLength) // One full day event { if (!$forRrule) { $html = FormatDate(array( "tommorow" => "tommorow", "today" => "today", "yesterday" => "yesterday", "-" => $formatShort, "" => $formatShort, ), $fromTs, time() + CTimeZone::GetOffset()); $html .= ', '; } $html .= Loc::getMessage('EC_VIEW_FULL_DAY'); } else // Event for several days { $from = FormatDate(array( "tommorow" => "tommorow", "today" => "today", "yesterday" => "yesterday", "-" => $formatShort, "" => $formatShort, ), $fromTs, time() + CTimeZone::GetOffset()); $to = FormatDate(array( "tommorow" => "tommorow", "today" => "today", "yesterday" => "yesterday", "-" => $formatShort, "" => $formatShort, ), $toTs - self::DAY_LENGTH, time() + CTimeZone::GetOffset()); $html = Loc::getMessage('EC_VIEW_DATE_FROM_TO', array('#DATE_FROM#' => $from, '#DATE_TO#' => $to)); } } else { // Event during one day if(date('dmY', $fromTs) == date('dmY', $toTs)) { if (!$forRrule) { $html = FormatDate(array( "tommorow" => "tommorow", "today" => "today", "yesterday" => "yesterday", "-" => $formatShort, "" => $formatShort, ), $fromTs, time() + CTimeZone::GetOffset()); $html .= ', '; } $html .= Loc::getMessage('EC_VIEW_TIME_FROM_TO_TIME', array('#TIME_FROM#' => FormatDate($formatTime, $fromTs), '#TIME_TO#' => FormatDate($formatTime, $toTs))); } else { $html = Loc::getMessage('EC_VIEW_DATE_FROM_TO', array('#DATE_FROM#' => FormatDate($formatFull, $fromTs, time() + CTimeZone::GetOffset()), '#DATE_TO#' => FormatDate($formatFull, $toTs, time() + CTimeZone::GetOffset()))); } } return $html; } public static function GetSocNetDestination($user_id = false, $selected = array(), $userList = array()) { if (!\Bitrix\Main\Loader::includeModule("socialnetwork")) { return false; } global $CACHE_MANAGER; if (!is_array($selected)) { $selected = array(); } if (method_exists('CSocNetLogDestination','GetDestinationSort')) { $DESTINATION = array( 'LAST' => array(), 'DEST_SORT' => CSocNetLogDestination::GetDestinationSort(array("DEST_CONTEXT" => "CALENDAR")) ); CSocNetLogDestination::fillLastDestination($DESTINATION['DEST_SORT'], $DESTINATION['LAST']); } else { $DESTINATION = array( 'LAST' => array( 'SONETGROUPS' => CSocNetLogDestination::GetLastSocnetGroup(), 'DEPARTMENT' => CSocNetLogDestination::GetLastDepartment(), 'USERS' => CSocNetLogDestination::GetLastUser() ) ); } if (!$user_id) $user_id = CCalendar::GetCurUserId(); $cacheTtl = defined("BX_COMP_MANAGED_CACHE") ? 3153600 : 3600*4; $cacheId = 'calendar_dest_'.$user_id; $cacheDir = '/calendar/socnet_destination/'.SITE_ID.'/'.$user_id; $obCache = new CPHPCache; if($obCache->InitCache($cacheTtl, $cacheId, $cacheDir)) { $DESTINATION['SONETGROUPS'] = $obCache->GetVars(); } else { $obCache->StartDataCache(); $DESTINATION['SONETGROUPS'] = CSocNetLogDestination::GetSocnetGroup(Array('features' => array("calendar", array("view")))); if(defined("BX_COMP_MANAGED_CACHE")) { $CACHE_MANAGER->StartTagCache($cacheDir); foreach($DESTINATION['SONETGROUPS'] as $val) { $CACHE_MANAGER->RegisterTag("sonet_features_G_".$val["entityId"]); $CACHE_MANAGER->RegisterTag("sonet_group_".$val["entityId"]); } $CACHE_MANAGER->RegisterTag("sonet_user2group_U".$user_id); $CACHE_MANAGER->EndTagCache(); } $obCache->EndDataCache($DESTINATION['SONETGROUPS']); } $destinationUserList = Array(); $DESTINATION['SELECTED'] = Array(); if (!empty($userList)) { foreach ($userList as $userId) { $DESTINATION['SELECTED']['U'.$userId] = "users"; $DESTINATION['LAST']['USERS']['U'.$userId] = 'U'.$userId; } } foreach ($selected as $ind => $code) { if (substr($code, 0 , 2) == 'DR') { $DESTINATION['SELECTED'][$code] = "department"; } elseif (substr($code, 0 , 2) == 'UA') { $DESTINATION['SELECTED'][$code] = "groups"; } elseif (substr($code, 0 , 2) == 'SG') { $DESTINATION['SELECTED'][$code] = "sonetgroups"; } elseif (substr($code, 0 , 1) == 'U') { $DESTINATION['SELECTED'][$code] = "users"; $destinationUserList[] = intVal(str_replace('U', '', $code)); } } // intranet structure $arStructure = CSocNetLogDestination::GetStucture(); $DESTINATION['DEPARTMENT'] = $arStructure['department']; $DESTINATION['DEPARTMENT_RELATION'] = $arStructure['department_relation']; $DESTINATION['DEPARTMENT_RELATION_HEAD'] = $arStructure['department_relation_head']; if (\Bitrix\Main\Loader::includeModule('extranet') && !CExtranet::IsIntranetUser()) { $DESTINATION['EXTRANET_USER'] = 'Y'; $DESTINATION['USERS'] = CSocNetLogDestination::GetExtranetUser(); } else { if (is_array($DESTINATION['LAST']['USERS'])) { foreach ($DESTINATION['LAST']['USERS'] as $value) { $destinationUserList[] = intVal(str_replace('U', '', $value)); } } if (!empty($userList)) { $destinationUserList = array_unique(array_merge($destinationUserList, $userList)); } $DESTINATION['EXTRANET_USER'] = 'N'; $DESTINATION['USERS'] = CSocNetLogDestination::GetUsers(Array('id' => $destinationUserList)); } $users = array(); foreach ($DESTINATION['USERS'] as $key => $entry) { if ($entry['isExtranet'] == 'N') $users[$key] = $entry; } $DESTINATION['USERS'] = $users; return $DESTINATION; } public static function SaveUserTimezoneName($user, $tzName = '') { if (!is_array($user) && intVal($user) > 0) $user = self::GetUser($user, true); CUserOptions::SetOption("calendar", "timezone".self::GetCurrentOffsetUTC($user['ID']), $tzName, false, $user['ID']); } public static function CheckOffsetForTimezone($timezone, $offset, $date = false) { return true; } public static function GetOffsetUTC($userId = false, $dateTimestamp) { if (!$userId && self::$userId) $userId = self::$userId; $tzName = self::GetUserTimezoneName($userId); if ($tzName) { $offset = self::GetTimezoneOffset($tzName, $dateTimestamp); } else { $offset = date("Z", $dateTimestamp) + CCalendar::GetOffset($userId); } return intVal($offset); } public static function OnSocNetGroupDelete($groupId) { $groupId = intVal($groupId); if ($groupId > 0) { $res = CCalendarSect::GetList( array( 'arFilter' => array( 'CAL_TYPE' => 'group', 'OWNER_ID' => $groupId ), 'checkPermissions' => false ) ); foreach($res as $sect) { CCalendarSect::Delete($sect['ID'], false); } } return true; } /** * Handles last caldav activity from mobile devices * * @param \Bitrix\Main\Event $event Event. * @return null */ public static function OnDavCalendarSync(\Bitrix\Main\Event $event) { $calendarId = $event->getParameter('id'); $userAgent = strtolower($event->getParameter('agent')); $agent = false; list($sectionId, $entityType, $entityId) = $calendarId; static $arAgentsMap = array( 'android' => 'android', // Android/iOS CardDavBitrix24 'iphone' => 'iphone', // Apple iPhone iCal 'davkit' => 'mac', // Apple iCal 'mac os' => 'mac', // Apple iCal (Mac Os X > 10.8) 'mac_os_x' => 'mac', // Apple iCal (Mac Os X > 10.8) 'mac+os+x' => 'mac', // Apple iCal (Mac Os X > 10.10) 'dataaccess' => 'iphone', // Apple addressbook iPhone //'sunbird' => 'sunbird', // Mozilla Sunbird 'ios' => 'iphone' ); foreach ($arAgentsMap as $pattern => $name) { if (strpos($userAgent, $pattern) !== false) { $agent = $name; break; } } if ($entityType == 'user' && $agent) { self::SaveSyncDate($entityId, $agent); } } /** * Saves date of last successful sync * * @param int $userId User Id * @param string $syncType Type of synchronization. * @param string $date Date of synchronization. * @return null */ public static function SaveSyncDate($userId, $syncType, $date = false) { if ($date === false) $date = self::Date(time()); $syncTypes = array('iphone', 'android', 'mac', 'exchange', 'outlook', 'office365'); if (in_array($syncType, $syncTypes)) { CUserOptions::SetOption("calendar", "last_sync_".$syncType, $date, false, $userId); } } public static function OnExchangeCalendarSync(\Bitrix\Main\Event $event) { self::SaveSyncDate($event->getParameter('userId'), 'exchange'); } public static function ClearSyncInfo($userId, $syncType) { $syncTypes = array('iphone', 'android', 'mac', 'exchange', 'outlook', 'office365'); if (in_array($syncType, $syncTypes)) { CUserOptions::DeleteOption("calendar", "last_sync_".$syncType, false, $userId); } } /** * Updates counter in left menu in b24, sets amount of requests for meeting for current user or * set of users * * @param int|array $users array of user's ids or user id as an int * @return null */ public static function UpdateCounter($users = false) { if ($users == false) $users = array(self::GetCurUserId()); elseif(!is_array($users)) $users = array($users); $ids = array(); foreach($users as $user) { if (intVal($user) > 0) $ids[] = intVal($user); } $users = $ids; if (count($users) > 0) { $events = CCalendarEvent::GetList(array( 'arFilter' => array( 'CAL_TYPE' => 'user', 'OWNER_ID' => $users, 'FROM_LIMIT' => self::Date(time(), false), 'TO_LIMIT' => self::Date(time() + self::DAY_LENGTH * 90, false), 'IS_MEETING' => 1, 'MEETING_STATUS' => 'Q', 'DELETED' => 'N' ), 'parseRecursion' => false, 'checkPermissions' => false) ); $counters = array(); foreach($events as $event) { if(!isset($counters[$event['OWNER_ID']])) $counters[$event['OWNER_ID']] = 0; $counters[$event['OWNER_ID']]++; } foreach($users as $user) { if($user > 0) { if(isset($counters[$user]) && $counters[$user] > 0) CUserCounter::Set($user, 'calendar', $counters[$user], '**', '', false); else CUserCounter::Set($user, 'calendar', 0, '**', '', false); } } } } // TODO: cache it!!!!!! private static function __tzsort($a, $b) { if($a['offset'] == $b['offset']) return strcmp($a['timezone_id'], $b['timezone_id']); return ($a['offset'] < $b['offset']? -1 : 1); } private static function GetInstance() { if (!isset(self::$instance)) { $c = __CLASS__; self::$instance = new $c; } return self::$instance; } public static function IsIntranetEnabled() { if (!isset(self::$bIntranet)) { self::$bIntranet = IsModuleInstalled('intranet'); } return self::$bIntranet; } public static function IsSocNet() { if (!isset(self::$bSocNet)) { \Bitrix\Main\Loader::includeModule("socialnetwork"); self::$bSocNet = class_exists('CSocNetUserToGroup') && CBXFeatures::IsFeatureEnabled("Calendar") && self::IsIntranetEnabled(); } return self::$bSocNet; } public static function GetCurUserId($refresh = false) { global $USER; if (!isset(self::$curUserId) || $refresh || !self::$curUserId) { if (is_object($USER) && $USER->IsAuthorized()) self::$curUserId = $USER->GetId(); else self::$curUserId = 0; } return self::$curUserId; } public static function GetSettings($params = array()) { if (!is_array($params)) $params = array(); if (isset(self::$settings) && count(self::$settings) > 0 && $params['request'] === false) return self::$settings; $pathes_for_sites = COption::GetOptionString('calendar', 'pathes_for_sites', true); if ($params['forseGetSitePathes'] || !$pathes_for_sites) $pathes = self::GetPathes(isset($params['site']) ? $params['site'] : false); else $pathes = array(); if (!isset($params['getDefaultForEmpty']) || $params['getDefaultForEmpty'] !== false) $params['getDefaultForEmpty'] = true; $siteId = isset($params['site']) ? $params['site'] : SITE_ID; $resMeetingCommonForSites = COption::GetOptionString('calendar', 'rm_for_sites', true); $siteIdForResMeet = !$resMeetingCommonForSites && $siteId ? $siteId : false; self::$settings = array( 'work_time_start' => COption::GetOptionString('calendar', 'work_time_start', 9), 'work_time_end' => COption::GetOptionString('calendar', 'work_time_end', 19), 'year_holidays' => COption::GetOptionString('calendar', 'year_holidays', Loc::getMessage('EC_YEAR_HOLIDAYS_DEFAULT')), 'year_workdays' => COption::GetOptionString('calendar', 'year_workdays', Loc::getMessage('EC_YEAR_WORKDAYS_DEFAULT')), 'week_holidays' => explode('|', COption::GetOptionString('calendar', 'week_holidays', 'SA|SU')), 'week_start' => COption::GetOptionString('calendar', 'week_start', 'MO'), 'user_name_template' => self::GetUserNameTemplate($params['getDefaultForEmpty']), 'sync_by_push' => COption::GetOptionString('calendar', 'sync_by_push', false), 'user_show_login' => COption::GetOptionString('calendar', 'user_show_login', true), 'path_to_user' => COption::GetOptionString('calendar', 'path_to_user', "/company/personal/user/#user_id#/"), 'path_to_user_calendar' => COption::GetOptionString('calendar', 'path_to_user_calendar', "/company/personal/user/#user_id#/calendar/"), 'path_to_group' => COption::GetOptionString('calendar', 'path_to_group', "/workgroups/group/#group_id#/"), 'path_to_group_calendar' => COption::GetOptionString('calendar', 'path_to_group_calendar', "/workgroups/group/#group_id#/calendar/"), 'path_to_vr' => COption::GetOptionString('calendar', 'path_to_vr', ""), 'path_to_rm' => COption::GetOptionString('calendar', 'path_to_rm', ""), 'rm_iblock_type' => COption::GetOptionString('calendar', 'rm_iblock_type', ""), 'rm_iblock_id' => COption::GetOptionString('calendar', 'rm_iblock_id', "", $siteIdForResMeet, !!$siteIdForResMeet), 'dep_manager_sub' => COption::GetOptionString('calendar', 'dep_manager_sub', true), 'denied_superpose_types' => unserialize(COption::GetOptionString('calendar', 'denied_superpose_types', serialize(array()))), 'pathes_for_sites' => $pathes_for_sites, 'pathes' => $pathes, 'forum_id' => COption::GetOptionString('calendar', 'forum_id', ""), 'rm_for_sites' => COption::GetOptionString('calendar', 'rm_for_sites', true) ); $arPathes = self::GetPathesList(); foreach($arPathes as $pathName) { if (!isset(self::$settings[$pathName])) self::$settings[$pathName] = COption::GetOptionString('calendar', $pathName, ""); } if(self::$settings['work_time_start'] > 23) self::$settings['work_time_start'] = 23; if (self::$settings['work_time_end'] <= self::$settings['work_time_start']) self::$settings['work_time_end'] = self::$settings['work_time_start'] + 1; if (self::$settings['work_time_end'] > 23.30) self::$settings['work_time_end'] = 23.30; if (self::$settings['forum_id'] == "") { self::$settings['forum_id'] = COption::GetOptionString("tasks", "task_forum_id", ""); if (self::$settings['forum_id'] == "" && \Bitrix\Main\Loader::includeModule("forum")) { $db = CForumNew::GetListEx(); if ($ar = $db->GetNext()) self::$settings['forum_id'] = $ar["ID"]; } COption::SetOptionString("calendar", "forum_id", self::$settings['forum_id']); } return self::$settings; } public static function GetPathes($forSite = false) { $pathes = array(); $pathes_for_sites = COption::GetOptionString('calendar', 'pathes_for_sites', true); if ($forSite === false) { $arAffectedSites = COption::GetOptionString('calendar', 'pathes_sites', false); if ($arAffectedSites != false && CheckSerializedData($arAffectedSites)) $arAffectedSites = unserialize($arAffectedSites); } else { if (is_array($forSite)) $arAffectedSites = $forSite; else $arAffectedSites = array($forSite); } if(is_array($arAffectedSites) && count($arAffectedSites) > 0) { foreach($arAffectedSites as $s) { $ar = COption::GetOptionString("calendar", 'pathes_'.$s, false); if ($ar != false && CheckSerializedData($ar)) { $ar = unserialize($ar); if(is_array($ar)) $pathes[$s] = $ar; } } } if ($forSite !== false) { $result = array(); if (isset($pathes[$forSite]) && is_array($pathes[$forSite])) $result = $pathes[$forSite]; $arPathes = self::GetPathesList(); foreach($arPathes as $pathName) { $val = $result[$pathName]; if (!isset($val) || empty($val) || $pathes_for_sites) { if (!isset($SET)) $SET = self::GetSettings(); $val = $SET[$pathName]; $result[$pathName] = $val; } } return $result; } return $pathes; } public static function GetPathesList() { if (!self::$pathesListEx) { self::$pathesListEx = self::$pathesList; $arTypes = CCalendarType::GetList(array('checkPermissions' => false)); for ($i = 0, $l = count($arTypes); $i < $l; $i++) { if ($arTypes[$i]['XML_ID'] !== 'user' && $arTypes[$i]['XML_ID'] !== 'group') { self::$pathesList[] = 'path_to_type_'.$arTypes[$i]['XML_ID']; } } } return self::$pathesList; } public static function GetUserNameTemplate($fromSite = true) { $user_name_template = COption::GetOptionString('calendar', 'user_name_template', ''); if ($fromSite && empty($user_name_template)) $user_name_template = CSite::GetNameFormat(false); return $user_name_template; } public static function SetUserSettings($settings = array(), $userId = false) { CCalendarUserSettings::Set($settings, $userId); } public static function GetUserSettings($userId = false) { return CCalendarUserSettings::Get($userId); } public static function GetPermissions($Params = array()) { global $USER; $type = isset($Params['type']) ? $Params['type'] : self::$type; $ownerId = isset($Params['ownerId']) ? $Params['ownerId'] : self::$ownerId; $userId = isset($Params['userId']) ? $Params['userId'] : self::$userId; $bView = true; $bEdit = true; $bEditSection = true; if ($type == 'user' && $ownerId != $userId) { $bEdit = false; $bEditSection = false; } if ($type == 'group') { if (!$USER->CanDoOperation('edit_php')) { $keyOwner = 'SG'.$ownerId.'_A'; $keyMod = 'SG'.$ownerId.'_E'; $keyMember = 'SG'.$ownerId.'_K'; $arCodes = array(); $rCodes = CAccess::GetUserCodes($userId); while($code = $rCodes->Fetch()) $arCodes[] = $code['ACCESS_CODE']; if (\Bitrix\Main\Loader::includeModule("socialnetwork")) { $group = CSocNetGroup::getByID($ownerId); if(!empty($group['CLOSED']) && $group['CLOSED'] === 'Y' && \Bitrix\Main\Config\Option::get('socialnetwork', 'work_with_closed_groups', 'N') === 'N') { self::$isArchivedGroup = true; } } if (in_array($keyOwner, $arCodes))// Is owner { $bEdit = true; $bEditSection = true; } elseif(in_array($keyMod, $arCodes) && !self::$isArchivedGroup)// Is moderator { $bEdit = true; $bEditSection = true; } elseif(in_array($keyMember, $arCodes) && !self::$isArchivedGroup)// Is member { $bEdit = true; $bEditSection = false; } else { $bEdit = false; $bEditSection = false; } } } if ($type != 'user' && $type != 'group') { $bView = CCalendarType::CanDo('calendar_type_view', $type); $bEdit = CCalendarType::CanDo('calendar_type_edit', $type); $bEditSection = CCalendarType::CanDo('calendar_type_edit_section', $type); } if ($Params['setProperties'] !== false) { self::$perm['view'] = $bView; self::$perm['edit'] = $bEdit; self::$perm['section_edit'] = $bEditSection; } return array( 'view' => $bView, 'edit' => $bEdit, 'section_edit' => $bEditSection ); } public static function GetPath($type = '', $ownerId = '', $hard = false) { if (self::$path == '' || $hard) { $path = ''; if (empty($type)) $type = self::$type; if (!empty($type)) { if ($type == 'user') { $path = COption::GetOptionString( 'calendar', 'path_to_user_calendar', COption::getOptionString('socialnetwork', 'user_page', "/company/personal/")."user/#user_id#/calendar/" ); } elseif($type == 'group') { $path = COption::GetOptionString( 'calendar', 'path_to_group_calendar', COption::getOptionString('socialnetwork', 'workgroups_page', "/workgroups/")."group/#group_id#/calendar/" ); } if (!COption::GetOptionString('calendar', 'pathes_for_sites', true)) { $siteId = self::GetSiteId(); $pathes = self::GetPathes(); if (isset($pathes[$siteId])) { if ($type == 'user' && isset($pathes[$siteId]['path_to_user_calendar'])) $path = $pathes[$siteId]['path_to_user_calendar']; elseif($type == 'group' && isset($pathes[$siteId]['path_to_group_calendar'])) $path = $pathes[$siteId]['path_to_group_calendar']; } } if (empty($ownerId)) $ownerId = self::$ownerId; if (!empty($path) && !empty($ownerId)) { if ($type == 'user') $path = str_replace(array('#user_id#', '#USER_ID#'), $ownerId, $path); elseif($type == 'group') $path = str_replace(array('#group_id#', '#GROUP_ID#'), $ownerId, $path); } $path = CCalendar::GetServerPath().$path; } } else { $path = self::$path; } return $path; } public static function GetSiteId() { if (!self::$siteId) self::$siteId = SITE_ID; return self::$siteId; } public static function GetServerPath() { if (!isset(self::$serverPath)) { self::$serverPath = (CMain::IsHTTPS() ? "https://" : "http://").self::GetServerName(); } return self::$serverPath; } public static function GetServerName() { if (defined("SITE_SERVER_NAME") && strlen(SITE_SERVER_NAME) > 0) $server_name = SITE_SERVER_NAME; if (!$server_name) $server_name = COption::GetOptionString("main", "server_name", ""); if (!$server_name) $server_name = $_SERVER['HTTP_HOST']; $server_name = rtrim($server_name, '/'); if (!preg_match('/^[a-z0-9\.\-]+$/i', $server_name)) // cyrillic domain hack { $converter = new CBXPunycode(defined('BX_UTF') && BX_UTF === true ? 'UTF-8' : 'windows-1251'); $host = $converter->Encode($server_name); if (!preg_match('#--p1ai$#', $host)) // trying to guess $host = $converter->Encode(CharsetConverter::ConvertCharset($server_name, 'utf-8', 'windows-1251')); $server_name = $host; } return $server_name; } public static function GetStartUpEvent($eventId = false) { if (!$eventId) return false; $res = CCalendarEvent::GetList( array( 'arFilter' => array( "PARENT_ID" => $eventId, "OWNER_ID" => self::$userId, "IS_MEETING" => 1, "DELETED" => "N" ), 'parseRecursion' => false, 'fetchAttendees' => true, 'fetchMeetings' => true, 'checkPermissions' => true, 'setDefaultLimit' => false ) ); if (!$res || !is_array($res[0])) { $res = CCalendarEvent::GetList( array( 'arFilter' => array( "ID" => $eventId, "DELETED" => "N" ), 'parseRecursion' => false, 'userId' => self::$userId, 'fetchAttendees' => false, 'fetchMeetings' => true ) ); } if ($res && isset($res[0]) && ($event = $res[0])) { if ($event['MEETING_STATUS'] == 'Y' || $event['MEETING_STATUS'] == 'N' || $event['MEETING_STATUS'] == 'Q') { if ($event['IS_MEETING'] && self::$userId == self::$ownerId && self::$type == 'user' && ($_GET['CONFIRM'] == 'Y' || $_GET['CONFIRM'] == 'N')) { CCalendarEvent::SetMeetingStatus(array( 'userId' => self::$userId, 'eventId' => $event['ID'], 'status' => $_GET['CONFIRM'] == 'Y' ? 'Y' : 'N', 'personalNotification' => true )); } } if ($event['RRULE']) $event['RRULE'] = CCalendarEvent::ParseRRULE($event['RRULE']); return $event; } else { CCalendarNotify::ClearNotifications($eventId); } return false; } public static function Timestamp($date, $bRound = true, $bTime = true) { $timestamp = MakeTimeStamp($date, self::TSFormat($bTime ? "FULL" : "SHORT")); if ($bRound) $timestamp = self::RoundTimestamp($timestamp); return $timestamp; } public static function TSFormat($format = "FULL") { return CSite::GetDateFormat($format); } public static function RoundTimestamp($ts) { return round($ts / 60) * 60; // We don't need for seconds here } public static function IsPersonal($type = false, $ownerId = false, $userId = false) { if (!$type) $type = self::$type; if(!$ownerId) $ownerId = self::$ownerId; if(!$userId) $userId = self::$userId; return $type == 'user' && $ownerId == $userId; } public static function IsExchangeEnabled($userId = false) { if (isset(self::$arExchEnabledCache[$userId])) return self::$arExchEnabledCache[$userId]; if (!IsModuleInstalled('dav') || COption::GetOptionString("dav", "agent_calendar") != "Y") $res = false; elseif (!\Bitrix\Main\Loader::includeModule('dav')) $res = false; elseif ($userId === false) $res = CDavExchangeCalendar::IsExchangeEnabled(); else $res = CDavExchangeCalendar::IsExchangeEnabled() && CDavExchangeCalendar::IsExchangeEnabledForUser($userId); self::$arExchEnabledCache[$userId] = $res; return $res; } public static function isGoogleApiEnabled() { if (!isset(self::$isGoogleApiEnabled)) { self::$isGoogleApiEnabled = \Bitrix\Main\ModuleManager::isModuleInstalled('socialservices') && (is_null(\Bitrix\Main\Config\Configuration::getValue("calendar_integration")) || \Bitrix\Main\Config\Configuration::getValue("calendar_integration") === self::INTEGRATION_GOOGLE_API); if (self::$isGoogleApiEnabled && !self::IsBitrix24() && \Bitrix\Main\Loader::includeModule('socialservices')) { self::$isGoogleApiEnabled = CSocServGoogleOAuth::GetOption('google_appid') !== '' && CSocServGoogleOAuth::GetOption('google_appsecret') !== ''; } } return self::$isGoogleApiEnabled; } public static function IsCalDAVEnabled() { if (!IsModuleInstalled('dav') || COption::GetOptionString("dav", "agent_calendar_caldav") != "Y") return false; return \Bitrix\Main\Loader::includeModule('dav') && CDavGroupdavClientCalendar::IsCalDAVEnabled(); } public static function IsWebserviceEnabled() { if (!isset(self::$bWebservice)) self::$bWebservice = IsModuleInstalled('webservice'); return self::$bWebservice; } public static function IsExtranetEnabled() { if (!isset(self::$bExtranet)) self::$bExtranet = \Bitrix\Main\Loader::includeModule('extranet') && CExtranet::IsExtranetSite(); return self::$bExtranet; } public static function IsAbsenceEnabled() { return !self::IsBitrix24() || COption::GetOptionString("bitrix24", "absence_limits_enabled", "") != "Y" || \Bitrix\Bitrix24\Feature::isFeatureEnabled("absence"); } public static function GetMeetingRoomList($Params = array()) { if (isset(self::$meetingRoomList)) return self::$meetingRoomList; if (!isset($Params['RMiblockId']) && !isset($Params['VMiblockId'])) { if (!isset(self::$settings)) self::$settings = self::GetSettings(); if (!self::$pathesForSite) self::$pathesForSite = self::GetSettings(array('forseGetSitePathes' => true,'site' =>self::GetSiteId())); $RMiblockId = self::$settings['rm_iblock_id']; $pathToMR = self::$pathesForSite['path_to_rm']; } else { $RMiblockId = $Params['RMiblockId']; $pathToMR = $Params['pathToMR']; } $MRList = Array(); if (IntVal($RMiblockId) > 0 && CIBlock::GetPermission($RMiblockId) >= "R" && self::$allowReserveMeeting) { $arOrderBy = array("NAME" => "ASC", "ID" => "DESC"); $arFilter = array("IBLOCK_ID" => $RMiblockId, "ACTIVE" => "Y"); $arSelectFields = array("IBLOCK_ID","ID","NAME","DESCRIPTION","UF_FLOOR","UF_PLACE","UF_PHONE"); $res = CIBlockSection::GetList($arOrderBy, $arFilter, false, $arSelectFields ); while ($arMeeting = $res->GetNext()) { $MRList[] = array( 'ID' => $arMeeting['ID'], 'NAME' => $arMeeting['~NAME'], 'DESCRIPTION' => $arMeeting['~DESCRIPTION'], 'UF_PLACE' => $arMeeting['UF_PLACE'], 'UF_PHONE' => $arMeeting['UF_PHONE'], 'URL' => str_replace(array("#id#", "#ID#"), $arMeeting['ID'], $pathToMR) ); } } self::$meetingRoomList = $MRList; return $MRList; } public static function GetCurrentOffsetUTC($userId = false) { if (!$userId && self::$userId) $userId = self::$userId; return intVal(date("Z") + self::GetOffset($userId)); } public static function GetOffset($userId = false) { if ($userId > 0) { if (!isset(self::$arTimezoneOffsets[$userId])) { $offset = CTimeZone::GetOffset($userId, true); self::$arTimezoneOffsets[$userId] = $offset; } else { $offset = self::$arTimezoneOffsets[$userId]; } } else { if (!isset(self::$offset)) { $offset = CTimeZone::GetOffset(null, true); self::$offset = $offset; } else { $offset = self::$offset; } } return $offset; } public static function GetUserTimezoneName($user, $getDefault = true) { if (!is_array($user) && intVal($user) > 0) { $user = self::GetUser($user, true); } $offset = self::GetCurrentOffsetUTC($user['ID']); $tzName = CUserOptions::GetOption("calendar", "timezone".$offset, false, $user['ID']); if ($tzName === 'undefined' || $tzName === 'false') $tzName = false; if (!$tzName && $user['AUTO_TIME_ZONE'] !== 'Y' && $user['TIME_ZONE']) { $tzName = $user['TIME_ZONE']; } if (!$tzName && $getDefault) { $tzName = self::GetGoodTimezoneForOffset($offset); } return $tzName; } public static function GetUser($userId, $bPhoto = false) { global $USER; if (is_object($USER) && intVal($userId) == $USER->GetId() && !$bPhoto) { $user = array( 'ID' => $USER->GetId(), 'NAME' => $USER->GetFirstName(), 'LAST_NAME' => $USER->GetLastName(), 'SECOND_NAME' => $USER->GetParam('SECOND_NAME'), 'LOGIN' => $USER->GetLogin(), 'PERSONAL_PHOTO' => $USER->GetParam('PERSONAL_PHOTO'), ); } else { $rsUser = CUser::GetByID(intVal($userId)); $user = $rsUser->Fetch(); } return $user; } public static function GetGoodTimezoneForOffset($offset) { $timezones = self::GetTimezoneList(); $goodTz = array(); $result = false; foreach($timezones as $tz) { if ($tz['offset'] == $offset) { $goodTz[] = $tz; if (LANGUAGE_ID == 'ru') { if (preg_match('/(kaliningrad|moscow|samara|yekaterinburg|novosibirsk|krasnoyarsk|irkutsk|yakutsk|vladivostok)/i', $tz['timezone_id'])) { $result = $tz['timezone_id']; break; } } elseif (strpos($tz['timezone_id'], 'Europe') !== false) { $result = $tz['timezone_id']; break; } } } if (!$result && count($goodTz) > 0) { $result = $goodTz[0]['timezone_id']; } return $result; } public static function GetTimezoneList() { if (empty(self::$timezones)) { self::$timezones = array(); static $aExcept = array("Etc/", "GMT", "UTC", "UCT", "HST", "PST", "MST", "CST", "EST", "CET", "MET", "WET", "EET", "PRC", "ROC", "ROK", "W-SU"); foreach(DateTimeZone::listIdentifiers() as $tz) { foreach($aExcept as $ex) if(strpos($tz, $ex) === 0) continue 2; try { $oTz = new DateTimeZone($tz); self::$timezones[$tz] = array('timezone_id' => $tz, 'offset' => $oTz->getOffset(new DateTime("now", $oTz))); } catch(Exception $e){} } uasort(self::$timezones, array('CCalendar', '__tzsort')); foreach(self::$timezones as $k => $z) { self::$timezones[$k]['title'] = '(UTC'.($z['offset'] <> 0? ' '.($z['offset'] < 0? '-':'+').sprintf("%02d", ($h = floor(abs($z['offset'])/3600))).':'.sprintf("%02d", abs($z['offset'])/60 - $h*60) : '').') '.$z['timezone_id']; } } return self::$timezones; } public static function GetUserName($user) { if (!is_array($user) && intVal($user) > 0) $user = self::GetUser($user); if(!$user || !is_array($user)) return ''; return CUser::FormatName(self::$userNameTemplate, $user, self::$showLogin, false); } public static function GetWeekStart() { if (!isset(self::$weekStart)) { $days = array('1' => 'MO', '2' => 'TU', '3' => 'WE', '4' => 'TH', '5' => 'FR', '6' => 'SA', '0' => 'SU'); self::$weekStart = $days[CSite::GetWeekStart()]; if (!in_array(self::$weekStart, $days)) self::$weekStart = 'MO'; } return self::$weekStart; } public static function InitExternalCalendarsSyncParams(&$JSConfig) { $isGoogleApiEnabled = CCalendar::isGoogleApiEnabled() && self::$type == "user"; $googleCalDavStatus = array(); $googleApiStatus = array(); $JSConfig['bCalDAV'] = true; $JSConfig['caldav_link_all'] = CCalendar::GetServerPath(); if (self::$type == 'user' && self::IsPersonal() && \Bitrix\Main\Loader::includeModule('dav')) { $tzEnabled = CTimeZone::Enabled(); if ($tzEnabled) CTimeZone::Disable(); $connectionList = array(); $res = CDavConnection::GetList( array("ID" => "DESC"), array( "ENTITY_TYPE" => "user", "ENTITY_ID" => self::$ownerId, 'ACCOUNT_TYPE' => array('caldav_google_oauth', 'google_api_oauth', 'caldav') ), false, false); if ($isGoogleApiEnabled) { $googleApiConnection = new GoogleApiSync(self::getCurUserId()); $transportErrors = $googleApiConnection->getTransportErrors(); if (!$transportErrors) { $googleApiStatus['googleCalendarPrimaryId'] = $googleApiConnection->getPrimaryId(); } if (empty($googleApiStatus['googleCalendarPrimaryId'])) { $curPath = CCalendar::GetPath(); if($curPath) $curPath = CHTTP::urlDeleteParams($curPath, array("action", "sessid", "bx_event_calendar_request", "EVENT_ID")); $client = new CSocServGoogleOAuth(self::$ownerId); $client->getEntityOAuth()->addScope(array( 'https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/calendar.readonly' )); $googleApiStatus['authLink'] = $client->getUrl('opener', null, array('BACKURL' => $curPath)); } } else { $googleCalDavStatus = CCalendarSync::GetGoogleCalendarConnection(); } $googleApiConnections = array(); while($connection = $res->Fetch()) { $connectionListItem = array( 'id' => $connection['ID'], 'server_host' => $connection['SERVER_HOST'], 'account_type' => $connection['ACCOUNT_TYPE'], 'name' => $connection['NAME'], 'link' => $connection['SERVER'], 'user_name' => $connection['SERVER_USERNAME'], 'last_result' => $connection['LAST_RESULT'], 'sync_date' => $connection['SYNCHRONIZED'] ); $connectionList[] = $connectionListItem; if ($connection['ACCOUNT_TYPE'] == 'caldav_google_oauth' || $connection['ACCOUNT_TYPE'] == 'google_api_oauth') { $googleApiConnections[] = $connectionListItem; } } $addConnection = true; if ($isGoogleApiEnabled) { if (empty($googleApiConnections)) { $googleApiConnection = new GoogleApiSync(self::getCurUserId()); $transportErrors = $googleApiConnection->getTransportErrors(); if (!$transportErrors) { $googleApiStatus['googleCalendarPrimaryId'] = $googleApiConnection->getPrimaryId(); } if (empty($googleApiStatus['googleCalendarPrimaryId'])) { $curPath = CCalendar::GetPath(); if($curPath) $curPath = CHTTP::urlDeleteParams($curPath, array("action", "sessid", "bx_event_calendar_request", "EVENT_ID")); $client = new CSocServGoogleOAuth(self::$ownerId); $client->getEntityOAuth()->addScope(array( 'https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/calendar.readonly' )); $googleApiStatus['authLink'] = $client->getUrl('opener', null, array('BACKURL' => $curPath)); } } if ($googleApiStatus['googleCalendarPrimaryId'] || !empty($googleApiConnections)) { $serverPath = 'https://www.googleapis.com/calendar/v3'; foreach ($googleApiConnections as $connection) { if (($connection['link'] == $serverPath || $connection['account_type'] == 'caldav_google_oauth') || $connection['account_type'] == 'google_api_oauth') { $googleApiStatus['last_result'] = $connection['last_result']; $googleApiStatus['sync_date'] = CCalendar::Date(self::Timestamp($connection['sync_date']) + CCalendar::GetOffset(self::$ownerId), true, true, true); $googleApiStatus['connection_id'] = $connection['id']; $addConnection = false; break; } } if ($addConnection) { $sAccountType = 'google_api_oauth'; $sServer = 'https://www.googleapis.com/calendar/v3'; $connectionData = array( "ENTITY_TYPE" => 'user', "ENTITY_ID" => self::$ownerId, "ACCOUNT_TYPE" => $sAccountType, "NAME" => 'Google Calendar ('.$googleApiStatus['googleCalendarPrimaryId'].')', "SERVER" => $sServer, "SYNC_TOKEN" => NULL, ); $conId = CDavConnection::Add($connectionData); if ($conId) { CCalendarSync::dataSync(array_merge($connectionData, array('ID' => $conId))); $pushOptionEnabled = COption::GetOptionString('calendar', 'sync_by_push', false); if ($pushOptionEnabled || CCalendar::IsBitrix24()) { $googleApiConnection = new GoogleApiSync($connectionData['ENTITY_ID']); $channelInfo = $googleApiConnection->startWatchCalendarList($connectionData['NAME']); if ($channelInfo) { PushTable::delete(array("ENTITY_TYPE" => 'CONNECTION', 'ENTITY_ID' => $conId)); PushTable::add(array( 'ENTITY_TYPE' => 'CONNECTION', 'ENTITY_ID' => $conId, 'CHANNEL_ID' => $channelInfo['id'], 'RESOURCE_ID' => $channelInfo['resourceId'], 'EXPIRES' => $channelInfo['expiration'], 'NOT_PROCESSED' => 'N' )); } } $res = CDavConnection::GetList(array("ID" => "DESC"), array("ID" => $conId), false, false); if ($connection = $res->Fetch()) { $connectionList[] = array( 'id' => $connection['ID'], 'server_host' => $connection['SERVER_HOST'], 'account_type' => $connection['ACCOUNT_TYPE'], 'name' => $connection['NAME'], 'link' => $connection['SERVER'], 'user_name' => $connection['SERVER_USERNAME'], 'last_result' => $connection['LAST_RESULT'], 'sync_date' => $connection['SYNCHRONIZED'] ); $googleApiStatus['connection_id'] = $connection['ID']; $googleApiStatus['last_result'] = $googleApiConnections['LAST_RESULT']; $googleApiStatus['sync_date'] = CCalendar::Date(self::Timestamp($connection['SYNCHRONIZED']) + CCalendar::GetOffset(self::$ownerId), true, true, true); } } } } $JSConfig['googleCalDavStatus'] = $googleApiStatus; } else if ($googleCalDavStatus && $googleCalDavStatus['googleCalendarPrimaryId']) { $serverPath = 'https://apidata.googleusercontent.com/caldav/v2/'.$googleCalDavStatus['googleCalendarPrimaryId'].'/user'; foreach($connectionList as $connection) { if ($connection['link'] == $serverPath) { $googleCalDavStatus['last_result'] = $connection['last_result']; $googleCalDavStatus['sync_date'] = CCalendar::Date(self::Timestamp($connection['sync_date']) + CCalendar::GetOffset(self::$ownerId), true, true, true); $googleCalDavStatus['connection_id'] = $connection['id']; $addConnection = false; break; } } if ($addConnection) { $conId = CDavConnection::Add(array( "ENTITY_TYPE" => 'user', "ENTITY_ID" => self::$ownerId, "ACCOUNT_TYPE" => 'caldav_google_oauth', "NAME" => 'Google Calendar ('.$googleCalDavStatus['googleCalendarPrimaryId'].')', "SERVER" => 'https://apidata.googleusercontent.com/caldav/v2/'.$googleCalDavStatus['googleCalendarPrimaryId'].'/user' )); if ($conId) { CDavGroupdavClientCalendar::DataSync("user", self::$ownerId); $res = CDavConnection::GetList(array("ID" => "DESC"), array("ID" => $conId), false, false); if($connection = $res->Fetch()) { $connectionList[] = array( 'id' => $connection['ID'], 'server_host' => $connection['SERVER_HOST'], 'account_type' => $connection['ACCOUNT_TYPE'], 'name' => $connection['NAME'], 'link' => $connection['SERVER'], 'user_name' => $connection['SERVER_USERNAME'], 'last_result' => $connection['LAST_RESULT'], 'sync_date' => $connection['SYNCHRONIZED'] ); $googleCalDavStatus['connection_id'] = $connection['ID']; $googleCalDavStatus['last_result'] = $connection['LAST_RESULT']; $googleCalDavStatus['sync_date'] = CCalendar::Date(self::Timestamp($googleApiConnections['SYNCHRONIZED']) + CCalendar::GetOffset(self::$ownerId), true, true, true); } } } $JSConfig['googleCalDavStatus'] = $googleCalDavStatus; } $JSConfig['connections'] = $connectionList; if ($tzEnabled) CTimeZone::Enable(); } } // public static function InitGoogleApiParams(&$JSConfig) // { // if (!\Bitrix\Main\Loader::includeModule('socialservices') || !\Bitrix\Main\Loader::includeModule('dav')) // { // return; // } // $googleApiStatus = array(); // // if (self::$type != 'user') // { // return; // } // // $connectionList = array(); // $res = CDavConnection::GetList( // array("ID" => "DESC"), // array( // "ENTITY_TYPE" => "user", // "ENTITY_ID" => self::$ownerId, // 'ACCOUNT_TYPE' => array('caldav_google_oauth', 'google_api_oauth') // ), false, false); // // while ($arCon = $res->Fetch()) // { // $connectionList[] = array( // 'id' => $arCon['ID'], // 'server_host' => $arCon['SERVER_HOST'], // 'account_type' => $arCon['ACCOUNT_TYPE'], // 'name' => $arCon['NAME'], // 'link' => $arCon['SERVER'], // 'user_name' => $arCon['SERVER_USERNAME'], // 'last_result' => $arCon['LAST_RESULT'], // 'sync_date' => $arCon['SYNCHRONIZED'] // ); // } // // if (self::IsPersonal()) // { // if (!$connectionList) // { // $googleApiConnection = new GoogleApiSync(self::getCurUserId()); // $transportErrors = $googleApiConnection->getTransportErrors(); // if (!$transportErrors) // { // $googleApiStatus['googleCalendarPrimaryId'] = $googleApiConnection->getPrimaryId(); // } // // if (empty($googleApiStatus['googleCalendarPrimaryId'])) // { // $curPath = CCalendar::GetPath(); // if($curPath) // $curPath = CHTTP::urlDeleteParams($curPath, array("action", "sessid", "bx_event_calendar_request", "EVENT_ID")); // $client = new CSocServGoogleOAuth(self::$ownerId); // $client->getEntityOAuth()->addScope(array( // 'https://www.googleapis.com/auth/calendar', // 'https://www.googleapis.com/auth/calendar.readonly' // )); // $googleApiStatus['authLink'] = $client->getUrl('opener', null, array('BACKURL' => $curPath)); // } // } // // if ($googleApiStatus['googleCalendarPrimaryId'] || $connectionList) // { // $serverPath = 'https://www.googleapis.com/calendar/v3'; // $addConnection = true; // // foreach ($connectionList as $arCon) // { // if (($arCon['link'] == $serverPath || $arCon['account_type'] == 'caldav_google_oauth') || $arCon['account_type'] == 'google_api_oauth') // { // $googleApiStatus['last_result'] = $arCon['last_result']; // $googleApiStatus['sync_date'] = CCalendar::Date(self::Timestamp($arCon['sync_date']) + CCalendar::GetOffset(self::$ownerId), true, true, true); // $googleApiStatus['connection_id'] = $arCon['id']; // // $addConnection = false; // break; // } // // } // // if ($addConnection && !$connectionList) // { // $sAccountType = 'google_api_oauth'; // $sServer = 'https://www.googleapis.com/calendar/v3'; // $connectionData = array( // "ENTITY_TYPE" => 'user', // "ENTITY_ID" => self::$ownerId, // "ACCOUNT_TYPE" => $sAccountType, // "NAME" => 'Google Calendar ('.$googleApiStatus['googleCalendarPrimaryId'].')', // "SERVER" => $sServer, // "SYNC_TOKEN" => NULL, // ); // $conId = CDavConnection::Add($connectionData); // // if ($conId) // { // CCalendarSync::dataSync(array_merge($connectionData, array('ID' => $conId))); // // $pushOptionEnabled = COption::GetOptionString('calendar', 'sync_by_push', false); // if ($pushOptionEnabled || CCalendar::IsBitrix24()) // { // $googleApiConnection = new GoogleApiSync($connectionData['ENTITY_ID']); // $channelInfo = $googleApiConnection->startWatchCalendarList($connectionData['NAME']); // if ($channelInfo) // { // PushTable::delete(array("ENTITY_TYPE" => 'CONNECTION', 'ENTITY_ID' => $conId)); // PushTable::add(array( // 'ENTITY_TYPE' => 'CONNECTION', // 'ENTITY_ID' => $conId, // 'CHANNEL_ID' => $channelInfo['id'], // 'RESOURCE_ID' => $channelInfo['resourceId'], // 'EXPIRES' => $channelInfo['expiration'], // 'NOT_PROCESSED' => 'N' // )); // } // } // $res = CDavConnection::GetList(array("ID" => "DESC"), array("ID" => $conId), false, false); // if ($arCon = $res->Fetch()) // { // $connectionList[] = array( // 'id' => $arCon['ID'], // 'server_host' => $arCon['SERVER_HOST'], // 'account_type' => $arCon['ACCOUNT_TYPE'], // 'name' => $arCon['NAME'], // 'link' => $arCon['SERVER'], // 'user_name' => $arCon['SERVER_USERNAME'], // 'last_result' => $arCon['LAST_RESULT'], // 'sync_date' => $arCon['SYNCHRONIZED'] // ); // $googleApiStatus['connection_id'] = $arCon['ID']; // $googleApiStatus['last_result'] = $arCon['LAST_RESULT']; // $googleApiStatus['sync_date'] = CCalendar::Date(self::Timestamp($arCon['SYNCHRONIZED']) + CCalendar::GetOffset(self::$ownerId), true, true, true); // } // } // } // } // } // // $JSConfig['googleCalDavStatus'] = $googleApiStatus; // $JSConfig['connections'] = $connectionList; // } public static function Date($timestamp, $bTime = true, $bRound = true, $bCutSeconds = false) { if ($bRound) $timestamp = self::RoundTimestamp($timestamp); $format = self::DFormat($bTime); if ($bTime && $bCutSeconds) $format = str_replace(':s', '', $format); return FormatDate($format, $timestamp); } public static function DFormat($bTime = true) { return CDatabase::DateFormatToPHP(CSite::GetDateFormat($bTime ? "FULL" : "SHORT", SITE_ID)); } public static function DateWithNewTime($timestampTime, $timestampDate) { return mktime(date("H", $timestampTime), date("i", $timestampTime), 0, date("m", $timestampDate), date("d", $timestampDate), date("Y", $timestampDate)); } public static function GetSyncInfo($userId, $syncType) { $activeSyncPeriod = 604800; // 3600 * 24 * 7 - one week $syncTypes = array('iphone', 'android', 'mac', 'exchange', 'outlook', 'office365'); $result = array('connected' => false); if (in_array($syncType, $syncTypes)) { $result['date'] = CUserOptions::GetOption("calendar", "last_sync_".$syncType, false, $userId); } if ($result['date']) { $period = time() - self::Timestamp($result['date']); if ($period >= 0 && $period <= $activeSyncPeriod) { $result['date'] = CCalendar::Date(self::Timestamp($result['date']) + CCalendar::GetOffset($userId), true, true, true); $result['connected'] = true; } } return $result; } public static function GetDisplayedSuperposed($userId = false) { if (!class_exists('CUserOptions') || !$userId) return false; $res = array(); $def = CUserOptions::GetOption("calendar", "superpose_displayed_default", false, $userId); $saveOption = false; if (intval($def) > 0) { $saveOption = true; $res[] = intVal($def); } $str = CUserOptions::GetOption("calendar", "superpose_displayed", false, $userId); if (CheckSerializedData($str)) { $arIds = unserialize($str); if (is_array($arIds) && count($arIds) > 0) { foreach($arIds as $id) { if (intVal($id) > 0) { $res[] = intVal($id); } } } } if ($saveOption) { CUserOptions::SetOption("calendar", "superpose_displayed", serialize($res)); CUserOptions::SetOption("calendar", "superpose_displayed_default", false); } return $res; } public static function GetCurUserMeetingSection($bCreate = false) { if (!isset(self::$userMeetingSection) || !self::$userMeetingSection) self::$userMeetingSection = CCalendar::GetMeetingSection(self::$userId, $bCreate); return self::$userMeetingSection; } public static function GetMeetingSection($userId, $autoCreate = false) { if (isset(self::$meetingSections[$userId])) return self::$meetingSections[$userId]; $result = false; if ($userId > 0) { $set = CCalendarUserSettings::Get($userId); $result = $set['meetSection']; $section = false; if ($result) { $section = CCalendarSect::GetList( array('arFilter' => array('ID' => $result), 'checkPermissions' => false, 'getPermissions' => false )); if($section && is_array($section) && is_array($section[0])) { $section = $section[0]; } } if($result && !$section) $result = false; if (!$result) { $res = CCalendarSect::GetList(array( 'arFilter' => array( 'CAL_TYPE' => 'user', 'OWNER_ID' => $userId ), 'checkPermissions' => false, 'getPermissions' => false )); if ($res && count($res) > 0 && $res[0]['ID']) $result = $res[0]['ID']; if (!$result && $autoCreate) { $defCalendar = CCalendarSect::CreateDefault(array( 'type' => 'user', 'ownerId' => $userId )); if ($defCalendar && $defCalendar['ID'] > 0) $result = $defCalendar['ID']; } if($result) { $set['meetSection'] = $result; CCalendarUserSettings::Set($set, $userId); } } } $actualResult = $result; foreach(\Bitrix\Main\EventManager::getInstance()->findEventHandlers("calendar", "OnGetMeetingSectionForUser") as $event) { ExecuteModuleEventEx($event, array($userId, &$result)); } if ($actualResult != $result) { $set['meetSection'] = $result; CCalendarUserSettings::Set($set, $userId); } self::$meetingSections[$userId] = $result; return $result; } public static function GetCrmSection($userId, $autoCreate = false) { if (isset(self::$crmSections[$userId])) return self::$crmSections[$userId]; $result = false; if ($userId > 0) { $set = CCalendarUserSettings::Get($userId); $result = $set['crmSection']; $section = false; if ($result) { $section = CCalendarSect::GetList( array('arFilter' => array('ID' => $result), 'checkPermissions' => false, 'getPermissions' => false )); if($section && is_array($section) && is_array($section[0])) { $section = $section[0]; } } if($result && !$section) $result = false; if (!$result) { $res = CCalendarSect::GetList(array( 'arFilter' => array( 'CAL_TYPE' => 'user', 'OWNER_ID' => $userId ), 'checkPermissions' => false, 'getPermissions' => false )); if ($res && count($res) > 0 && $res[0]['ID']) $result = $res[0]['ID']; if (!$result && $autoCreate) { $defCalendar = CCalendarSect::CreateDefault(array( 'type' => 'user', 'ownerId' => $userId )); if ($defCalendar && $defCalendar['ID'] > 0) $result = $defCalendar['ID']; } if($result) { $set['crmSection'] = $result; CCalendarUserSettings::Set($set, $userId); } } } self::$crmSections[$userId] = $result; return $result; } public static function GetSectionList($params = array()) { $type = isset($params['CAL_TYPE']) ? $params['CAL_TYPE'] : self::$type; $arFilter = array( 'CAL_TYPE' => $type, ); if (isset($params['OWNER_ID'])) $arFilter['OWNER_ID'] = $params['OWNER_ID']; elseif ($type == 'user' || $type == 'group') $arFilter['OWNER_ID'] = self::GetOwnerId(); if (isset($params['ACTIVE'])) $arFilter['ACTIVE'] = $params['ACTIVE']; if (isset($params['ADDITIONAL_IDS']) && count($params['ADDITIONAL_IDS']) > 0) $arFilter['ADDITIONAL_IDS'] = $params['ADDITIONAL_IDS']; $res = CCalendarSect::GetList( array( 'arFilter' => $arFilter, 'checkPermissions' => $params['checkPermissions'], 'getPermissions' => $params['getPermissions'] ) ); return $res; } public static function GetOwnerId() { return self::$ownerId; } public static function GetEventList($params = array(), &$arAttendees) { $type = isset($params['type']) ? $params['type'] : self::$type; $ownerId = isset($params['ownerId']) ? $params['ownerId'] : self::$ownerId; $userId = isset($params['userId']) ? $params['userId'] : self::$userId; if ($type != 'user' && !isset($params['section']) || count($params['section']) <= 0) return array(); $arFilter = array(); CCalendarEvent::SetLastAttendees(false); if (isset($params['fromLimit'])) $arFilter["FROM_LIMIT"] = $params['fromLimit']; if (isset($params['toLimit'])) $arFilter["TO_LIMIT"] = $params['toLimit']; $arFilter["OWNER_ID"] = $ownerId; if ($type == 'user') { $fetchMeetings = in_array(self::GetMeetingSection($ownerId), $params['section']); } else { $fetchMeetings = in_array(self::GetCurUserMeetingSection(), $params['section']); if ($type) { $arFilter['CAL_TYPE'] = $type; } } $res = CCalendarEvent::GetList( array( 'arFilter' => $arFilter, 'parseRecursion' => true, 'fetchAttendees' => true, 'userId' => $userId, 'fetchMeetings' => $fetchMeetings, 'setDefaultLimit' => false, 'limit' => $params['limit'] ) ); if (count($params['section']) > 0) { $NewRes = array(); foreach($res as $event) { if (in_array($event['SECT_ID'], $params['section'])) { unset($event['DESCRIPTION'], $event['~DESCRIPTION']); $NewRes[] = $event; } } $res = $NewRes; } $arAttendees = CCalendarEvent::GetLastAttendees(); return $res; } public static function getTaskList($params = array()) { $res = array(); $arFilter = array( '!STATUS' => array( CTasks::STATE_DEFERRED, ), 'CHECK_PERMISSIONS' => 'Y' ); if (self::$userSettings['showCompletedTasks'] == 'N') { $arFilter['!STATUS'][] = CTasks::STATE_COMPLETED; } if ($params['type'] == 'user') { $arFilter['DOER'] = $params['ownerId']; } elseif ($params['type'] == 'group') { $arFilter['GROUP_ID'] = $params['ownerId']; } $tzEnabled = CTimeZone::Enabled(); if($tzEnabled) CTimeZone::Disable(); $mgrResult = \Bitrix\Tasks\Manager\Task::getList( \Bitrix\Tasks\Util\User::getId(), array( 'order' => array("START_DATE_PLAN" => "ASC"), 'select' => array("ID", "TITLE", "DESCRIPTION", "CREATED_DATE", "DEADLINE", "START_DATE_PLAN", "END_DATE_PLAN", "CLOSED_DATE", "STATUS_CHANGED_DATE", "STATUS", "REAL_STATUS"), 'legacyFilter' => $arFilter, ), array() ); $offset = CCalendar::GetOffset(); foreach ($mgrResult['DATA'] as $task) { $dtFrom = NULL; $dtTo = NULL; $skipFromOffset = false; $skipToOffset = false; if(isset($task["START_DATE_PLAN"]) && $task["START_DATE_PLAN"]) $dtFrom = CCalendar::CutZeroTime($task["START_DATE_PLAN"]); if(isset($task["END_DATE_PLAN"]) && $task["END_DATE_PLAN"]) $dtTo = CCalendar::CutZeroTime($task["END_DATE_PLAN"]); if(!isset($dtTo) && isset($task["CLOSED_DATE"])) $dtTo = CCalendar::CutZeroTime($task["CLOSED_DATE"]); //Task statuses: 1 - New, 2 - Pending, 3 - In Progress, 4 - Supposedly completed, 5 - Completed, 6 - Deferred, 7 - Declined if(!isset($dtTo) && isset($task["STATUS_CHANGED_DATE"]) && in_array($task["REAL_STATUS"], array('4', '5', '6', '7'))) $dtTo = CCalendar::CutZeroTime($task["STATUS_CHANGED_DATE"]); if(isset($dtTo)) { $ts = CCalendar::Timestamp($dtTo); // Correction display logic for harmony with Tasks interfaces if(date("H:i", $ts) == '00:00') $dtTo = CCalendar::Date($ts - 24 * 60 * 60); } elseif(isset($task["DEADLINE"])) { $dtTo = CCalendar::CutZeroTime($task["DEADLINE"]); $ts = CCalendar::Timestamp($dtTo); // Correction display logic for harmony with Tasks interfaces if(date("H:i", $ts) == '00:00') $dtTo = CCalendar::Date($ts - 24 * 60 * 60); if(!isset($dtFrom)) { $skipFromOffset = true; $dtFrom = CCalendar::Date(time(), false); } } if(!isset($dtTo)) $dtTo = CCalendar::Date(time(), false); if(!isset($dtFrom)) $dtFrom = $dtTo; $dtFromTS = CCalendar::Timestamp($dtFrom); $dtToTS = CCalendar::Timestamp($dtTo); if($dtToTS < $dtFromTS) { $dtToTS = $dtFromTS; $dtTo = CCalendar::Date($dtToTS, true); } $skipTime = date("H:i", $dtFromTS) == '00:00' && date("H:i", $dtToTS) == '00:00'; if(!$skipTime && $offset != 0) { if(!$skipFromOffset) { $dtFromTS += $offset; $dtFrom = CCalendar::Date($dtFromTS, true); } if(!$skipToOffset) { $dtToTS += $offset; $dtTo = CCalendar::Date($dtToTS, true); } } $res[] = array( "ID" => $task["ID"], "~TYPE" => "tasks", "NAME" => $task["TITLE"], "DATE_FROM" => $dtFrom, "DATE_TO" => $dtTo, "DT_SKIP_TIME" => $skipTime ? 'Y' : 'N', "CAN_EDIT" => CTasks::CanCurrentUserEdit($task) ); } if($tzEnabled) CTimeZone::Enable(); return $res; } public static function CutZeroTime($date) { if (preg_match('/.*\s\d\d:\d\d:\d\d/i', $date)) { $date = trim($date); if (substr($date, -9) == ' 00:00:00') return substr($date, 0, -9); if (substr($date, -3) == ':00') return substr($date, 0, -3); } return $date; } public static function GetType() { return self::$type; } public static function GetAccessNames() { $arCodes = array(); foreach (self::$accessNames as $code => $name) { if ($name === null) $arCodes[] = $code; } if ($arCodes) { $access = new CAccess(); $arNames = $access->GetNames($arCodes); foreach($arNames as $code => $name) { self::$accessNames[$code] = trim(htmlspecialcharsbx($name['provider'].' '.$name['name'])); } } return self::$accessNames; } function TrimTime($strTime) { $strTime = trim($strTime); $strTime = preg_replace("/:00$/", "", $strTime); $strTime = preg_replace("/:00$/", "", $strTime); $strTime = preg_replace("/\\s00$/", "", $strTime); return rtrim($strTime); } public static function SetSilentErrorMode($silentErrorMode = true) { self::$silentErrorMode = $silentErrorMode; } public function GetId() { return self::$id ? self::$id : 'EC'.rand(); } } ?>