fediverse: публикация в GoToSocial (@vesti@dedinit.ru) из publisher-service

- gotosocial.py: клиент GtS (httpx): post_status (markdown), upload_media v2, verify_credentials, delete_status
- config.py: gt_social_url/token/visibility/format/channels
- channels.py: fediverse-каналы (VESTI_GTS_CHANNELS, префикс gt:), gt: уходит только в fediverse
- main.py: _publish_gotosocial + healthz-блок gotosocial + dry_run; status_id (ULID) в ответе
- .env.example: GT_SOCIAL_* и VESTI_GTS_CHANNELS
- STATUS.md/WALKTHROUGH.md: fediverse-раздел, хронология
- openspec: change gotosocial-publisher (proposal/design/tasks/specs), validate чисто
This commit is contained in:
kpa39l
2026-09-13 20:19:52 +00:00
parent 71fd48aa06
commit bf176cc02b
12 changed files with 677 additions and 16 deletions
+26 -4
View File
@@ -1,15 +1,21 @@
# VESTI — Статус
Обновлено: 2026-09-13 (publisher снова на Docker; systemd1 ожил)
Обновлено: 2026-09-13 (fediverse-публикация в GoToSocial @vesti)
<!--
История обновлений:
2026-09-13 — publisher: Docker-контейнер (основной способ); user-юнит disabled (костыль убран)
2026-09-13 — fediverse: publisher умеет постить в GoToSocial (@vesti@dedinit.ru)
2026-09-13 — publisher снова на Docker; systemd1 ожил
2026-09-12 — publisher → systemd user-юнит (костыль, пока сломан systemd1)
2026-09-11 — веб-интерфейс: 4 openspec change (CDN/htmx, markdown, даты, фильтр без CDN)
-->
## Текущее состояние
- Базовый конвейер (прототип) работает: краулер (8 источников, инкрементальный, метрики), классификатор (Ollama qwen3:8b-nothink + словари), банк статей (bundles + origin:own), веб :8400 (кандидаты/approve/reject/опубликованные/метрики).
- **FEDIVERSE-ПУБЛИКАЦИЯ РАБОТАЕТ** (2026-09-13): publisher-service умеет публиковать карточки в GoToSocial (social.dedinit.ru) от имени бот-аккаунта **@vesti@dedinit.ru** (Mastodon-совместимый API). Change `gotosocial-publisher`.
- Аккаунт **vesti** создан на GtS (2026-09-13, confirmed+approved, admin=0), OAuth-приложение `vesti-publisher` (client_id=01B09QNDM9YQ2VQVSRXHCVAV6K), токен в .env (`GT_SOCIAL_ACCESS_TOKEN`, scope `read write`), канал `VESTI_GTS_CHANNELS=@vesti@dedinit.ru`.
- healthz publisher: блок `gotosocial` — url, account=vesti, token_set=true, account_ok=true.
- Реальные тесты: текст → пост, медиа → пост с картинкой (media_attachments=1), delete → 200. Посты-тесты удалены, канал чист.
- Канал в запросе: `channels: ["gt:@vesti@dedinit.ru"]` (префикс `gt:`) — fediverse; `@dedinit_vesti` — Telegram. dry_run эмулирует оба.
- Базовый конвейер (прототип) работает (далее по-прежнему): краулер, классификатор, банк статей, веб :8400.
- **Бэкфилл @dedinit ЗАВЕРШЁН** (2026-09-10): crawler/backfill_dedinit.py, fetched=1040, max_post_id=1092; в БД 846 постов is_own=1, медиа в media/media/ (исторический баг пути: БД media/<file>, файл media/media/<file>; с 2026-09-12 краулер качает в media/<file>, для старых — fallback в make_card). Скрипт оставлен для повторного дозаполнения.
- **РЕАЛЬНАЯ ПУБЛИКАЦИЯ РАБОТАЕТ**: бот-контроллер @dedinit_controller_bot (id 7765665742) → @dedinit_vesti. Токен в .env. Проверено: тестовые посты (message_id 2–4).
- **publisher-service**: **Docker-контейнер** `vesti-publisher` (docker compose -f services/publisher/docker-compose.yml, 127.0.0.1:8410, restart=unless-stopped, healthy). Compose: env из /.env, TG_PROXY=socks5://host.docker.internal:1080, маунт ../../media/media:/srv/publisher/media:ro. Старый user-юнит `vesti-publisher.service` (~/.config/systemd/user/) — **disabled, не используется** (костыль на время сломанного systemd1, порт 8410 конфликтовал бы).
@@ -60,6 +66,17 @@ vesti-web (:8400) ──HTTP POST──▶ publisher-service (:8410) ──Bot A
- [x] **Проверено на реальном канале**: publish ушёл в @dedinit_vesti (message_id 6), текст с <b>&amp; доставлен как есть, без превью; тестовые сообщения удалены (delete_message ok). Канал чист
- [x] **publisher временно работает как локальный uvicorn** (127.0.0.1:8410, PID 807769) — Docker недоступен из-за зависшего systemd1 на хосте (внешняя проблема, не vesti)
## Сделано (сессия gotosocial-publisher 2026-09-13)
- [x] **OpenSpec change `gotosocial-publisher`** — proposal/design/tasks/specs/gotosocial-publisher, `openspec validate` чисто
- [x] services/publisher/app/gotosocial.py — клиент GtS (httpx): post_status (format=markdown), upload_media (v2), verify_credentials, delete_status, GoToSocialError
- [x] config.py: gt_social_url/token/visibility/format/channels (+ содержимое .env, .env.example)
- [x] channels.py: resolve_channels (TG) + resolve_gotosocial_channels (fediverse из VESTI_GTS_CHANNELS или `gt:`-каналы из запроса)
- [x] main.py: `_publish_gotosocial` (upload_media → post_status; status_id в ответе), healthz-блок gotosocial, dry_run для fediverse
- [x] **Аккаунт vesti создан** на GtS (admin account create, confirmed+approved), НЕ от имени kpa39l — по запросу пользователя отдельный бот-аккаунт
- [x] **OAuth-приложение vesti-publisher** (POST /api/v1/apps, scopes write write:media); токен для vesti: вставлен в БД tokens (user_id из users, scope read write) + записан в .env
- [x] **Тесты e2e**: dry_run (fediverse), реальный текст → пост, медиа → пост с картинкой, delete → 200; посты-тесты удалены
- [x] **Фикс**: message_id=0 для GtS (id — ULID-строка) → добавлен `status_id: str`
## Сделано ранее (own-content-hub)
- [x] Миграция БД (migrate_own.py): is_own, is_own_canonical, sources.own, published.distributed_dirs
- [x] sources.yaml: +dedinit (own: true), синк
@@ -74,7 +91,7 @@ vesti-web (:8400) ──HTTP POST──▶ publisher-service (:8410) ──Bot A
- [ ] Проверить результат классификации (в БД: direction заполнены) и выборочно качество на своих постах
- [ ] **rich-repost-card в проде**: после оживления systemd1 на хосте пересобрать Docker-контейнер publisher (docker compose -f services/publisher/docker-compose.yml up -d --build), перезапустить веб (подхватит шаблон + comment), проверить approve поста с медиа (send_photo/send_video)
- [ ] **Закрыть OpenSpec change rich-repost-card** (статус APPLIED после подтверждения), архивировать
- [ ] git-репозитории (gitverse истина, gitea зеркало) — /opt/vesti ещё НЕ git-репо
- [x] ~~git-репозитории (gitverse истина, gitea зеркало)~~ — /opt/vesti **git-репо** (2026-09-13): gitverse kpa39l/vesti (main) + gitea-зеркало bigbox
- [ ] openspec archive web-изменений (deexternalize-web-assets, web-render-markdown, web-format-datetime, web-list-filter-no-js) и publisher-service / tg-crawler-publisher-prototype (после подтверждения)
## Как запустить / проверить
@@ -87,6 +104,11 @@ docker logs -f vesti-publisher # лог
curl -s -X POST http://127.0.0.1:8410/api/v1/publish \
-H 'Content-Type: application/json' \
-d '{"card":{"text":"<b>Тест</b>","direction":"linux","lang":"ru"}}'
# fediverse (GoToSocial @vesti@dedinit.ru):
curl -s -X POST http://127.0.0.1:8410/api/v1/publish \
-H 'Content-Type: application/json' \
-d '{"card":{"text":"Тест fediverse","direction":"linux"},"channels":["gt:@vesti@dedinit.ru"]}'
# dry_run (эмуляция без внешних вызовов): добавить "dry_run":true
# (старый user-юнит vesti-publisher.service disabled — не использовать, порт занят)
# веб (пароль из .env: VESTI_WEB_PASSWORD or ADMIN_PASSWORD):
# systemd-юнит: /etc/systemd/system/vesti-web.service (после daemon-reload)