Провайдер CalDAV¶
Документ описывает провайдер CalDAV: поддерживаемые серверы (стандартный CalDAV, Яндекс, Kerio, CommuniGate), подключение через почтовый ящик и Basic Auth, операции с событиями по протоколу CalDAV, формат ICS и маппинг полей. Для администраторов и инженеров, настраивающих интеграцию внешних календарей с 1Формой.
1. Архитектура¶
Провайдер CalDAV состоит из двух уровней:
- высокоуровневый провайдер — адаптер между календарём 1Формы и протоколом CalDAV (преобразует события 1Ф в формат CalDAV и обратно);
- низкоуровневый HTTP-клиент — реализация протокола CalDAV под конкретный тип сервера (стандартный, Яндекс, Kerio, CommuniGate).
Над ними — сервисный слой, который по почтовому ящику пользователя выбирает нужный тип клиента.
2. Поддерживаемые серверы¶
В таблице — особенности подключения для каждого типа CalDAV-сервера:
| Сервер | Особенности |
|---|---|
| Стандартный CalDAV | Стандартная реализация протокола без особенностей |
| Яндекс | Обнаружение календарей идёт через HTTP GET (не PROPFIND), ответ разбирается как HTML. Не принимает участников при создании — событие записывается в два приёма |
| Kerio | Отбрасывает @домен из логина. Чтение через запрос REPORT. Идентификатор (UID) берётся из адреса события — UID в теле может отличаться |
| CommuniGate | К адресу добавляется /CalDav/. Чтение — REPORT с откатом на PROPFIND. Удаление из серии помечает событие как отменённое (CANCELLED), не удаляя его |
Google Calendar не поддерживается: только Basic Auth, OAuth2 не реализован.
3. Аутентификация и подключение¶
Подключение выполняется через почтовый ящик (mailbox) пользователя с авторизацией Basic Auth (логин и пароль). Пароль хранится в зашифрованном виде. Адрес CalDAV берётся из персональной настройки ящика или из настроек почтового сервера.
Учитываются только почтовые ящики, у которых:
- задан CalDAV-логин;
- на почтовом сервере включён признак CalDAV;
- ящик не отключён.
Связанные таблицы БД:
| Таблица | Назначение |
|---|---|
CalDavProviders |
Справочник типов CalDAV-серверов (Id, Name) |
EmailMailServers |
Почтовые серверы; признак IsCalDav и адрес CalDavAddress, ссылка на тип через CalDavProviderId |
EmailMailBoxes (ящик пользователя) |
CalDavLogin, CalDavPassword (зашифрован), CalDavAddress (персональный адрес) |
4. Операции с событиями¶
Все операции выполняются по протоколу CalDAV (HTTP-запросы PUT / PROPFIND / REPORT / DELETE).
Создание:
- Выбирается календарь (по наличию «calendar» в адресе, иначе — первый доступный).
- Событие сериализуется в формат ICS.
- Выполняется HTTP
PUTсобытия по адресу{адрес-календаря}/{идентификатор}.ics. - Для Яндекса — обходной путь: событие создаётся без участников, затем перечитывается и обновляется с участниками.
Чтение:
- одно событие — запрос
PROPFIND, разбор и десериализация ICS; - список — запрос
REPORTсcalendar-query.
Изменение:
Текущее событие читается, изменяется и записывается обратно. Для отдельного экземпляра повторяющейся серии создаётся изменённый экземпляр с RecurrenceId, при необходимости правится список исключений (EXDATE). Записывается полный ICS (все экземпляры в одном VCALENDAR).
Удаление:
- одиночное событие — HTTP
DELETE; - из серии — добавление даты в список исключений (EXDATE) или удаление изменённого экземпляра с последующей записью.
Ответ на приглашение:
| Действие | Организатор | Участник |
|---|---|---|
| Принять | — | Статус ответа → ACCEPTED |
| Отклонить | = удаление | Статус ответа → DECLINED |
| Принять под вопросом | — | Статус ответа → TENTATIVE |
| Отменить | = удаление | — |
5. Формат ICS¶
Порядок полей события (VEVENT):
BEGIN:VEVENT
UID, ATTENDEE[], CATEGORIES, RRULE[], CLASS, CREATED,
DESCRIPTION, DTEND, DTSTAMP, DTSTART,
LAST-MODIFIED, LOCATION, ORGANIZER, PRIORITY, SEQUENCE,
RECURRENCE-ID, EXDATE[], STATUS, SUMMARY, TRANSP, URL,
[пользовательские свойства], VALARM[]
END:VEVENT
Формат дат: yyyyMMddTHHmmssZ (UTC). Строки длиннее 75 символов переносятся по правилам ICS (line folding).
Признак «весь день» определяется как Начало == Конец или Начало + 1 день == Конец (второе условие — для Яндекса).
6. Маппинг полей¶
Соответствие полей события 1Ф и полей VEVENT в ICS:
| Поле 1Forma | Поле VEVENT | Примечание |
|---|---|---|
| Start | DTSTART | В UTC |
| End | DTEND | В UTC |
| Subject | SUMMARY | |
| TextBody | DESCRIPTION | Без конвертации HTML → текст (см. FAQ: HTML-теги в описании) |
| IsAllDayEvent | IsAllDay | |
| Location | LOCATION | |
| IsPrivate | CLASS | PRIVATE / PUBLIC |
| Organizer | ORGANIZER | По справочнику пользователей |
| RequiredAttendees[] | ATTENDEE[] | Email + имя, статус ответа = NeedsAction |
| Recurrence | RRULE | По типу повторяемости |
7. Механизм синхронизации¶
Модель: чтение по запросу. Автоматической синхронизации нет:
- при каждом открытии календаря выполняется полный запрос к CalDAV-серверу;
- метки изменений (
Ctag/SyncToken) считываются, но для инкрементальной синхронизации не используются; - push-подписок на CalDAV-сервер нет;
- повторяющиеся события разворачиваются на стороне 1Формы, а не на сервере.
Статус занятости (absence) подтягивается тоже по запросу: для каждого пользователя запрашиваются события на сегодня, обработка идёт пачками по 20 человек.
Уведомления интерфейса отправляются разово после каждой операции создания / изменения / удаления (не потоково).
8. Ограничения и известные проблемы¶
Критичные¶
Ограничения, заметные пользователю или влияющие на работоспособность интеграции:
| # | Проблема | Детали |
|---|---|---|
| 1 | HTML в DESCRIPTION | Описание пишется в поле DESCRIPTION как есть, а по стандарту RFC 5545 это обычный текст. Сторонние календари показывают HTML-теги. См. FAQ: HTML-теги в описании |
| 2 | Нет инкрементальной синхронизации | Каждый запрос — полный REPORT/PROPFIND. На больших календарях дорого |
| 3 | Google Calendar не поддерживается | Только Basic Auth, нет OAuth2 |
Архитектурные¶
Особенности реализации, которые стоит учитывать при настройке:
| # | Проблема | Детали |
|---|---|---|
| 4 | Развёртывание повторяемости нестандартное | Не полностью соответствует RFC; нет относительного ежемесячного правила (например, «третий понедельник месяца») |
| 5 | Нет VTIMEZONE | Все даты переводятся в UTC, информация о часовом поясе в ICS не передаётся |
| 6 | Потеря вложений | Вложения (ATTACH) читаются, но при записи не сохраняются |
| 7 | Шифрование паролей | Единый ключ шифрования на всю систему, не отдельный на пользователя |
Серверо-специфичные¶
Особенности отдельных типов CalDAV-серверов:
| # | Проблема | Детали |
|---|---|---|
| 8 | Яндекс: участники при создании | Не принимаются — запись в два приёма (создание + обновление) |
| 9 | Kerio: расхождение UID | UID в адресе и в теле события могут отличаться — берётся из адреса |
| 10 | CommuniGate: смешанные запросы | REPORT с откатом на PROPFIND |
| 11 | Выбор календаря | Эвристика — поиск «calendar» в адресе; отдельного выбора в интерфейсе нет |
| 12 | Ложный признак «весь день» | Правило Начало + 1 день == Конец срабатывает на событиях ровно с полуночи |
9. Диагностика¶
Частые симптомы при работе CalDAV-интеграции и где искать причину:
| Симптом | Где смотреть |
|---|---|
| Пустой список событий | Логи CalDAV-запросов (HTTP-ответы). Проверить ящик: CalDavLogin, CalDavAddress, признак CalDAV на сервере |
| Встреча не создаётся при включённом CalDAV | Проверить выбор календаря (поиск «calendar» в адресе) и участников для Яндекса |
| HTML-теги в описании | Известное ограничение, см. FAQ |
| Ошибки аутентификации | Логин и пароль (Basic Auth) в настройках почтового ящика |
Диагностический SQL¶
Запросы для проверки настроек CalDAV у пользователя:
-- Почтовые ящики пользователя с CalDAV
select m.ID, m.EmailLogin, m.CalDavLogin, m.CalDavAddress,
s.Name as ServerName, s.CalDavAddress as ServerCalDavAddress,
s.IsCalDav, p.Name as ProviderName
from EmailMailBoxes m
join EmailMailServers s on m.MailServerID = s.ID
left join CalDavProviders p on s.CalDavProviderId = p.Id
where m.UserID = @userId
and m.CalDavLogin is not null
and s.IsCalDav = 1
and m.Disabled = 0;
-- Справочник типов CalDAV-серверов
select * from CalDavProviders;
Связанные документы: