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
+38
View File
@@ -439,3 +439,41 @@ sudo systemctl restart vesti-web # active; login → 200, candidates/published
3. Переписывание новостей от себя (LLM-пересказ) + пайплайн «выбранные → дообогащение → публикация».
4. Извлечение источников из постов + сервис поиска в интернете (только одобренные).
5. Страница управления источниками (CRUD + фильтр по типу).
## 2026-09-13 — gotosocial-publisher: публикация VESTI в GoToSocial (@vesti@dedinit.ru)
### Контекст
- Пользователь: «хочу публиковать в свой gotosocial из проекта vesti». Проект /opt/federation не существует — реальная цель: /opt/gotosocial (нода social.dedinit.ru, Docker-контейнер gotosocial, :8082→:8080, версия 0.22.1).
- Решение: НЕ от имени kpa39l (личный аккаунт), а **отдельный бот-аккаунт `vesti`** — «пользователя-бота, который новости и постит».
### Реализация
1. **OpenSpec change `gotosocial-publisher`** (proposal/design/tasks/specs/gotosocial-publisher/spec.md), `openspec validate` чисто. Валиден.
2. **Аккаунт vesti**: `docker exec gotosocial /gotosocial/gotosocial admin account create --username vesti --email vesti@dedinit.ru --password <rand>` → confirmed+approved, admin=0.
- Питфол: пароль передал в CLI как переменную (не в хронологию); подтверждение прошло автоматически (confirmed_at заполнен).
3. **OAuth-приложение** `vesti-publisher` через `POST /api/v1/apps` (Mastodon API): scopes `write write:media`, redirect `urn:ietf:wg:oauth:2.0:oob` → client_id=01B09QNDM9YQ2VQVSRXHCVAV6K.
- Питфол: app-токен (client_credentials) НЕ подходит — verify_credentials требует привязки к user; для сервер-сервер нужен user-токен.
4. **User-токен vesti**: вставлен в БД `tokens` (SQLite /opt/gotosocial/data/sqlite.db):
- Питфол: **user_id должен быть id из таблицы `users` (не `accounts`!)** — иначе verify_credentials → null; scope `read write`; access 48 симв.
- Проверка: `GET /api/v1/accounts/verify_credentials` с Bearer → username=vesti. Токен записан в /opt/vesti/.env как GT_SOCIAL_ACCESS_TOKEN.
5. **Код publisher** (services/publisher/app/): gotosocial.py (httpx-клиент: post_status c format=markdown, upload_media v2, verify_credentials, delete_status), config.py (gt_social_*), channels.py (resolve_gotosocial_channels; `gt:`-каналы из запроса), main.py (_publish_gotosocial, healthz-блок gotosocial, dry_run).
- Питфол: `gt:@vesti@dedinit.ru` трактовался и как TG — resolve_channels теперь отбрасывает `gt:`-префикс.
- Питфол: message_id=0 для GtS (id — ULID-строка, не int) → добавлен `status_id: str` в ответ.
6. **Тесты e2e** (все реальные, потом удалены delete): текст → пост (status 01M2E6AC...), медиа → пост с картинкой (media_attachments=1), delete → HTTP 200. Канал @vesti@dedinit.ru чист.
7. **Доки**: STATUS.md (раздел fediverse + «Сделано»), .env.example (GT_SOCIAL_*), tasks.md (все [x]).
### Команды
```bash
docker exec gotosocial /gotosocial/gotosocial admin account create --username vesti --email vesti@dedinit.ru --password '<rand>'
curl -s -X POST https://social.dedinit.ru/api/v1/apps -H 'Content-Type: application/json' \
-d '{"client_name":"vesti-publisher","redirect_uris":"urn:ietf:wg:oauth:2.0:oob","scopes":"write write:media"}'
# токен — вставка в sqlite (python3, см. выше), затем в .env
curl -s http://127.0.0.1:8410/healthz # gotosocial: account=vesti, token_set=true, account_ok=true
curl -s -X POST http://127.0.0.1:8410/api/v1/publish -H 'Content-Type: application/json' \
-d '{"card":{"text":"Тест","direction":"linux"},"channels":["gt:@vesti@dedinit.ru"]}'
```
### Следующая сессия
1. Проработать **candidates-mail-ui** (2 панели) — открытые вопросы см. предыдущая сессия.
2. Закрыть rich-repost-card (архив) + архивировать gotosocial-publisher после подтверждения.
3. Пометить аккаунт vesti как **bot** (в GtS 0.22.1 bot-флаг: PATCH /api/v1/accounts/update_credentials → bot:true, либо actor_type Service) — не критично, желательно.
4. Фан-аут направлений → каналы (в т.ч. fediverse-каналы по направлениям).