77 lines
6.1 KiB
Markdown
77 lines
6.1 KiB
Markdown
# Tasks: CardDAV-сервер для синхронизации контактов
|
||
|
||
## 1. Адресная книга в Radicale
|
||
|
||
- [ ] 1.1 Создать адресную книгу «Контакты» на ФС:
|
||
`mkdir -p /opt/hermes/email-assistant/radicale/data/collections/collection-root/estorozhenko/Контакты`
|
||
и проверить, что Radicale видит её как addressbook:
|
||
`curl -u estorozhenko:$RADICALE_PASS -X PROPFIND -H 'Depth: 0' http://127.0.0.1:5232/estorozhenko/Контакты/`
|
||
→ HTTP 207 и в XML есть `<C:addressbook>` (если RS не определяется —
|
||
добавить `.Radicale.props` с addressbook и повторить).
|
||
- [ ] 1.2 Положить тестовую vCard (test.vcf) в коллекцию и проверить, что
|
||
она отдаётся: `curl ... /estorozhenko/Контакты/test.vcf` → 200 + vCard;
|
||
затем удалить тестовую карточку.
|
||
|
||
## 2. Синк в contacts_extractor.py
|
||
|
||
- [ ] 2.1 Рефакторинг: вынести генерацию vCard 4.0 из существующей
|
||
generate_vcard() в отдельную функцию `contact_to_vcard(contact) -> str`,
|
||
чтобы переиспользовать для CardDAV-карточек. Проверка: скрипт
|
||
запускается без ошибок, contacts.vcf генерируется как раньше.
|
||
- [ ] 2.2 Добавить функцию `sync_contacts_to_caldav(contacts_dir, base_url,
|
||
user, password, prune=False)`: читает contacts.json, строит карту
|
||
uid→(ETag, href) через PROPFIND Depth:1, PUT создаёт/обновляет vCard,
|
||
при `prune=True` DELETE удаляет лишние. Использовать urllib + Basic
|
||
Auth. Проверка: юнит-запуск с тестовым Radicale (см. 3.x).
|
||
- [ ] 2.3 CLI-флаги: `--sync-caldav`, `--prune-caldav`, `--caldav-url`,
|
||
`--caldav-user`, `--caldav-pass` (или env CALDAV_PASS). По умолчанию
|
||
синк выключен. Проверка: `python3 scripts/contacts_extractor.py --help`
|
||
показывает все флаги; без `--sync-caldav` поведение прежнее.
|
||
- [ ] 2.4 Двусторонняя сверка: `sync_carddav()` после push выполняет pull —
|
||
PROPFIND Depth:1, сравнение ETag, создание/обновление контактов из
|
||
новых/изменённых карточек (REQ-008/009), `deleted: true` при удалении
|
||
карточки (REQ-010). Проверка: см. 3.5-3.8 (reverse-pull тесты).
|
||
- [ ] 2.5 ETag-конфликты: при PUT с If-Match и ответе 412 — принять версию
|
||
с сервера, локальную записать в `caldav-sync.log` (`conflict_local`),
|
||
продолжить (REQ-011). Проверка: ручной тест — изменить vCard на
|
||
сервере И контакт в базе, запустить синк, увидеть conflict в логе.
|
||
|
||
## 3. Сквозной тест sync
|
||
|
||
- [ ] 3.1 Запустить синк с реальной базой:
|
||
`python3 scripts/contacts_extractor.py --sync-caldav`
|
||
(или отдельный скрипт) → в Radicale появились карточки (счётчик
|
||
PROPFIND/cards): `curl ... PROPFIND Depth:1 /estorozhenko/Контакты/`
|
||
показывает N карточек ≈ количеству контактов в contacts.json с email.
|
||
- [ ] 3.2 Повторный запуск — количество карточек не растёт (идемпотентность).
|
||
- [ ] 3.3 Изменить контакт в contacts.json (добавить телефон) → повторный
|
||
синк обновляет карточку (TEL появился, ETag изменился).
|
||
- [ ] 3.4 `--prune-caldav`: удалить контакт из contacts.json → карточка
|
||
удалена с сервера.
|
||
- [ ] 3.5 **Reverse pull:** вручную (curl PUT) изменить vCard на сервере →
|
||
повторный синк обновляет контакт в contacts.json.
|
||
- [ ] 3.6 **Новая карточка на сервере:** curl PUT новой vCard → синк создаёт
|
||
контакт в базе.
|
||
- [ ] 3.7 **Удаление на сервере:** curl DELETE vCard → контакт получает
|
||
`deleted: true` в базе.
|
||
- [ ] 3.8 **Конфликт:** изменить и vCard (curl), и контакт в базе → синк
|
||
применяет версию с сервера, локальная в caldav-sync.log.
|
||
|
||
## 4. Интеграция в cron и документация
|
||
|
||
- [ ] 4.1 Обновить `config/contacts-cron.sh`: добавить `--sync-caldav` и
|
||
подтянуть пароль из radicale/.env (env CALDAV_PASS). Проверка:
|
||
запуск cron-скрипта вручную синкает контакты без ошибок.
|
||
- [ ] 4.2 Обновить README/STATUS: раздел «CardDAV (контакты)» — как
|
||
подключить на Android (DAVx5, URL http://cal.nixg.ru:5232
|
||
или cal.nixg.ru, логин estorozhenko), порты, флаги синка.
|
||
- [ ] 4.3 `openspec validate contacts-caldav-server` → valid.
|
||
- [ ] 4.4 Git commit и push (gitea.nixg.ru/hermes/email-assistant).
|
||
|
||
## Verification
|
||
|
||
- [ ] V1: `curl -X PROPFIND -u estorozhenko:PASS http://127.0.0.1:5232/estorozhenko/Контакты/` → 207 + addressbook
|
||
- [ ] V2: после синка количество vCard в адресной книге == числу контактов с email в contacts.json
|
||
- [ ] V3: повторный синк → 0 новых карточек
|
||
- [ ] V4: правка контакта на сервере (curl PUT vCard) → контакт в contacts.json обновлён после синка
|
||
- [ ] V5: `python3 scripts/contacts_extractor.py --sync-caldav` из cron-обёртки завершается кодом 0 и пишет caldav-sync.log |