Initial import: vesti.nixg.ru — новостной апрув-проект (web, crawler, classifier, publisher, openspec)

This commit is contained in:
kpa39l
2026-09-13 15:58:32 +00:00
commit c3f59f7b7a
113 changed files with 7065 additions and 0 deletions
@@ -0,0 +1,120 @@
# TG Publisher — формат «богатого репоста»
## ADDED Requirements
### Requirement: Карточка репоста — полный текст
При публикации внешнего поста карточка MUST содержать полный текст
исходного поста (а не сниппет из первых 120 символов), обрезанный до лимита Telegram
(4096 символов).
#### Scenario: публикация поста с длинным текстом
- Given пост с текстом длиной 3000 символов и ссылкой на оригинал
- When модератор подтверждает пост в вебе
- Then в канале отправляется текст с полным содержимым поста (обрезанный до 4096)
- And заголовок-сниппет из 120 символов НЕ используется
### Requirement: Карточка репоста — комментарий модератора
При подтверждении поста модератор МОЖЕТ указать комментарий; комментарий
MUST публиковаться первым блоком в тексте поста.
#### Scenario: approve с комментарием
- Given пост, подтверждаемый через веб
- When модератор вводит комментарий «Отличный материал по Linux» и нажимает «Опубликовать»
- Then текст карточки начинается с комментария «Отличный материал по Linux»
- And полный текст исходного поста следует после комментария
#### Scenario: approve без комментария
- Given пост, подтверждаемый через веб
- When модератор оставляет поле комментария пустым
- Then текст карточки начинается с полного текста исходного поста
- And лишних пустых блоков нет
### Requirement: Карточка репоста — ссылка на оригинал без предпросмотра
Ссылка на оригинальный пост MUST присутствовать в тексте карточки, и
Telegram-предпросмотр этой ссылки MUST быть отключён (link_preview_options is_disabled).
#### Scenario: публикация внешнего поста
- Given внешний пост с url на оригинал
- When карточка отправляется в канал
- Then в тексте есть строка со ссылкой на оригинал
- And Telegram НЕ добавляет предпросмотр ссылки внизу поста
### Requirement: Карточка репоста — медиа из оригинала
Если у исходного поста есть медиа (photo/video), публикация MUST
отправлять медиа первым сообщением, а текст — следующим; видео (.mp4) MUST
поддерживаться.
#### Scenario: пост с фото
- Given пост с media_path=media/xyz.jpg
- When модератор подтверждает пост
- Then в канал отправляется фото (sendPhoto) первым сообщением
- And текст карточки отправляется следующим сообщением
#### Scenario: пост с видео
- Given пост с content_type=video и media_path=media/xyz.mp4
- When модератор подтверждает пост
- Then в канал отправляется видео (sendVideo) первым сообщением
- And текст карточки отправляется следующим сообщением
### Requirement: Карточка репоста — без служебной информации
Служебная информация (направление/язык, источник, просмотры/реакции)
MAY НЕ выводиться в теле поста; основное содержимое — текст, комментарий, ссылка на
оригинал.
#### Scenario: пост без служебки
- Given внешний пост с направлением и просмотрами
- When карточка формируется
- Then в тексте карточки НЕТ строк «📁 linux / ru», «📰 источник», «👁 123 💬 4»
- And текст содержит полный текст поста и ссылку на оригинал
## MODIFIED Requirements
### Requirement: Формат карточки (publisher/card.py)
Функция make_card MUST принимать необязательный параметр `comment` и
строить текст из: комментария (если задан), полного текста поста, ссылки на оригинал
(атрибуция для своих).
#### Scenario: make_card с comment
- Given post с текстом «Важная новость» и comment «Мой комментарий»
- When вызывается make_card(post, comment)
- Then результат содержит «Мой комментарий» перед «Важная новость»
- And ссылка на оригинал присутствует
#### Scenario: make_card без comment
- Given post с текстом «Важная новость» и comment=None
- When вызывается make_card(post)
- Then результат НЕ содержит пустого первого блока
- And результат содержит полный текст «Важная новость» и ссылку на оригинал
### Requirement: Отправка медиа в publisher-service
Сервис публикации MUST отправлять медиа первым и текст вторым; для
sendMessage параметр link_preview_options MUST отключать предпросмотр ссылки.
#### Scenario: sendMessage без предпросмотра
- Given канал @dedinit_vesti и текст со ссылкой на оригинал
- When вызывается sendMessage
- Then параметр link_preview_options={"is_disabled": True} передаётся в Bot API
#### Scenario: sendVideo для mp4
- Given файл media/xyz.mp4 существует в медиа-маунте
- When публикуется пост с этим видео
- Then вызывается sendVideo (а не sendPhoto)
- And текст отправляется следом