mirror of
https://gitverse.ru/kpa39l/email-assistant.git
synced 2026-09-29 21:25:10 +00:00
8ea022f5c0
- scripts/contacts_caldav_sync.py: push 81 контакт → vCard (Radicale :5232), pull правок/создания/удаления с телефона → contacts.json (ETag сверка, soft-delete, конфликты 412 → приоритет телефону, лог caldav-sync.log) - fix(contacts_extractor): перестройка by_email-индексов после sort() - STATUS.md: раздел DAVx5 + Caddy (Authorization/handle_path/X-Script-Name), Задача 3 (синхронизация с телефоном) = следующая сессия - tasks.md: отмечены 1.x-3.x/V (реализовано и протестировано), добавлен раздел 5 (Caddy + DAVx5 + jtx board) для следующей сессии
8.5 KiB
8.5 KiB
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 и повторить). Сделано: MKCOL через протокол дал 201;.Radicale.props={"tag": "VADDRESSBOOK"}. - 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 генерируется как раньше. Сделано: вscripts/contacts_caldav_sync.py(модульная выноска, contacts_extractor не тронут). - 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=TrueDELETE удаляет лишние. Использовать 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поведение прежнее. Сделано: CLI вcontacts_caldav_sync.py(--sync-caldav выключен по умолчанию, --dry-run и пр.) - 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. Сделано: 81 карточка создана (81 контакт), PROPFIND 207. - 3.2 Повторный запуск — количество карточек не растёт (идемпотентность). Сделано: стабильно 162 unchanged (81 push + 81 pull), 0 PUT.
- 3.3 Изменить контакт в contacts.json (добавить телефон) → повторный синк обновляет карточку (TEL появился, ETag изменился).
- 3.4
--prune-caldav: удалить контакт из contacts.json → карточка удалена с сервера. - 3.5 Reverse pull: вручную (curl PUT) изменить vCard на сервере → повторный синк обновляет контакт в contacts.json. Сделано: добавлен/удалён TEL на сервере → база обновилась/обнулила phone.
- 3.6 Новая карточка на сервере: curl PUT новой vCard → синк создаёт контакт в базе. Сделано: pulled_created (id=phone-newcard-001, from_device=True).
- 3.7 Удаление на сервере: curl DELETE vCard → контакт получает
deleted: trueв базе. Сделано: pulled_deleted, артефакт убран из базы. - 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), порты, флаги синка. Сделано (2026-09-13): STATUS.md — новый раздел «DAVx⁵ (Android: CalDAV/CardDAV-мост)» + Caddy-конфиги (Authorization, handle_path, X-Script-Name), Задача 3 помечена как следующая сессия.
- 4.3
openspec validate contacts-caldav-server→ valid. - 4.4 Git commit и push (gitea.nixg.ru/hermes/email-assistant).
5. Синхронизация с телефоном (СЛЕДУЮЩАЯ СЕССИЯ — первая задача)
- 5.1 Настроить Caddy на vps02:
cal.nixg.ru→ Radicale bigbox :5232 (header_up Authorization, reverse_proxy 10.8.0.2:5232);tasks.nixg.ru→ Vikunja :3456. Reload Caddyfile. - 5.2 Проверить CalDAV/CardDAV снаружи: PROPFIND https://cal.nixg.ru/... → 207 (учесть кириллицу «Контакты» в URL, Auth).
- 5.3 DAVx⁵ на телефоне: аккаунт https://cal.nixg.ru, логин estorozhenko, пароль RADICALE_PASS → выбрать календари (Личный/Рабочий/Задачи) и адресную книгу «Контакты».
- 5.4 jtx board на телефоне → Vikunja https://tasks.nixg.ru (токен API), проверить задачи.
- 5.5 Проверка двусторонней синхронизации: контакт создан/изменён на
телефоне → в базе (contacts.json) после
contacts_caldav_sync.py; задача из jtx board → в Vikunja; событие из DAVx⁵ → в Radicale. - 5.6 (опц.) Вписать sync в contacts-cron.sh (4.1) и проверить V5.
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