HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <ul><li><a>Ход выполнения</a></li>
1 <ul><li><a>Ход выполнения</a></li>
2 <li><a>Реализация</a></li>
2 <li><a>Реализация</a></li>
3 <li><a>Результат</a></li>
3 <li><a>Результат</a></li>
4 </ul><p><em>Автор: Денис Петраков - старший программист, выпускник курса "<a>Node.js Developer</a>"</em></p>
4 </ul><p><em>Автор: Денис Петраков - старший программист, выпускник курса "<a>Node.js Developer</a>"</em></p>
5 <p><strong>Цель работы</strong>: реализовать бота для публикации в разные telegram-каналы через API. Пользователь бота может владеть несколькими каналами, но отправлять посты в них по расписанию. Идея в том, чтобы пользователь мог сначала добавлять каналы в бот, а потом создавать сообщения и назначать им дату и врем�� отправки.</p>
5 <p><strong>Цель работы</strong>: реализовать бота для публикации в разные telegram-каналы через API. Пользователь бота может владеть несколькими каналами, но отправлять посты в них по расписанию. Идея в том, чтобы пользователь мог сначала добавлять каналы в бот, а потом создавать сообщения и назначать им дату и врем�� отправки.</p>
6 <h2>Ход выполнения</h2>
6 <h2>Ход выполнения</h2>
7 <p>Выбор технологий сразу пал на Nest.JS из-за хорошей интеграции с TypeScript и готовой шаблонной архитектурой. Далее выбор библиотек:</p>
7 <p>Выбор технологий сразу пал на Nest.JS из-за хорошей интеграции с TypeScript и готовой шаблонной архитектурой. Далее выбор библиотек:</p>
8 <ul><li>стандартный набор, который идет в комплекте с Nest (для управления env, для интеграции с DB и тд);</li>
8 <ul><li>стандартный набор, который идет в комплекте с Nest (для управления env, для интеграции с DB и тд);</li>
9 <li>дополнительные: для интеграции с telegram (<a>https://grammy.dev/</a>,<a>https://www.npmjs.com/package/@grammyjs/nestjs</a>), для решения отложенных задач (<a>https://docs-nestjs.netlify.app/techniques/task-scheduling</a>);</li>
9 <li>дополнительные: для интеграции с telegram (<a>https://grammy.dev/</a>,<a>https://www.npmjs.com/package/@grammyjs/nestjs</a>), для решения отложенных задач (<a>https://docs-nestjs.netlify.app/techniques/task-scheduling</a>);</li>
10 <li>в качестве БД была выбрана postgres, т.к. в документации к nest предлагалась она, а также она достаточно популярна в данный момент.</li>
10 <li>в качестве БД была выбрана postgres, т.к. в документации к nest предлагалась она, а также она достаточно популярна в данный момент.</li>
11 </ul><p>Была настроена интеграция с базой данных, которая крутится в Docker-контейнере. Далее был зарегистрирован telegram-бот и получен tg api key (<a>https://core.telegram.org/api</a>). Все это было размещено в .env.</p>
11 </ul><p>Была настроена интеграция с базой данных, которая крутится в Docker-контейнере. Далее был зарегистрирован telegram-бот и получен tg api key (<a>https://core.telegram.org/api</a>). Все это было размещено в .env.</p>
12 <p>С настройкой покончено, пришло время реализации.</p>
12 <p>С настройкой покончено, пришло время реализации.</p>
13 <h2>Реализация</h2>
13 <h2>Реализация</h2>
14 <p>Сначала был зарегистрирован список команд бота, на которые он мог реагировать. При первом использовании бота пользователь добавлялся в БД и получал сообщение:</p>
14 <p>Сначала был зарегистрирован список команд бота, на которые он мог реагировать. При первом использовании бота пользователь добавлялся в БД и получал сообщение:</p>
15 <p>При повторном взаимодействии с ботом сообщение уже отличалось:</p>
15 <p>При повторном взаимодействии с ботом сообщение уже отличалось:</p>
16 <p>Интеграция telegram - пользователь - БД оказалась достаточно простой, поэтому я сразу накидал список команд и приступил к пошаговой реализации.</p>
16 <p>Интеграция telegram - пользователь - БД оказалась достаточно простой, поэтому я сразу накидал список команд и приступил к пошаговой реализации.</p>
17 <p>Затем было принято решение привязать к пользователю telegram-каналы. Для этого в БД появилась дополнительная сущность, также появились 2 новых обработчика команд: /add_channel, /delete_channel.</p>
17 <p>Затем было принято решение привязать к пользователю telegram-каналы. Для этого в БД появилась дополнительная сущность, также появились 2 новых обработчика команд: /add_channel, /delete_channel.</p>
18 <p>Далее начались проблемы. Дело в том, что библиотека @grammy/nest предоставляет декораторы, но обработка некоторых команд в<strong>боте</strong>и<strong>канале</strong>работают по-разному. На это стоит обратить внимание при обработке контекста.</p>
18 <p>Далее начались проблемы. Дело в том, что библиотека @grammy/nest предоставляет декораторы, но обработка некоторых команд в<strong>боте</strong>и<strong>канале</strong>работают по-разному. На это стоит обратить внимание при обработке контекста.</p>
19 <p>Также всплыл подводный камень: в канале, который нужно подключить к боту, обязательно нужно писать сообщение<strong>от своего имени</strong>, чтобы можно было сделать привязку к пользователю. Возможно, было какое-то дополнительное решение, но на его поиск не хотелось тратить время. Также в настройках канала нужно дать боту права<strong>администратора</strong>и возможность отправлять сообщения.</p>
19 <p>Также всплыл подводный камень: в канале, который нужно подключить к боту, обязательно нужно писать сообщение<strong>от своего имени</strong>, чтобы можно было сделать привязку к пользователю. Возможно, было какое-то дополнительное решение, но на его поиск не хотелось тратить время. Также в настройках канала нужно дать боту права<strong>администратора</strong>и возможность отправлять сообщения.</p>
20 <p>Теперь, после добавления бота в канал, выдачи ему прав и отправки<strong>/add_channel</strong>появлялось сообщение:</p>
20 <p>Теперь, после добавления бота в канал, выдачи ему прав и отправки<strong>/add_channel</strong>появлялось сообщение:</p>
21 <p>Также в БД появилась связка пользователь - каналы.</p>
21 <p>Также в БД появилась связка пользователь - каналы.</p>
22 <p>Итак, реализация /start, /help была самой простой, а /add_channel, /delete_channel имела нюансы.</p>
22 <p>Итак, реализация /start, /help была самой простой, а /add_channel, /delete_channel имела нюансы.</p>
23 <p>Пришло время реализовывать публикации. Сначала была заведена сущность в БД с постами. Далее добавлен обработчик команды<strong>/create_post.</strong>Поскольку идея была в том, чтобы создавать сущность поста пошагово, пришлось завести промежуточный синглтон, который бы позволил управлять текущим состоянием создания.</p>
23 <p>Пришло время реализовывать публикации. Сначала была заведена сущность в БД с постами. Далее добавлен обработчик команды<strong>/create_post.</strong>Поскольку идея была в том, чтобы создавать сущность поста пошагово, пришлось завести промежуточный синглтон, который бы позволил управлять текущим состоянием создания.</p>
24 <p>https://github.com/isitfall/tg-autoposter-otus/blob/main/src/telegram/telegram.post-creation-state.ts</p>
24 <p>https://github.com/isitfall/tg-autoposter-otus/blob/main/src/telegram/telegram.post-creation-state.ts</p>
25 <p>Сам по себе флоу создания поста не сильно изменился, добавилось лишь промежуточное состояние. Сам по себе telegram не имеет календаря, равно как и возможности выбора даты (на момент написания софта). Поэтому было решено считывать текущее значение в формате iso8601 (<a>https://www.bairesdev.com/tools/onlinedevtools/</a>)</p>
25 <p>Сам по себе флоу создания поста не сильно изменился, добавилось лишь промежуточное состояние. Сам по себе telegram не имеет календаря, равно как и возможности выбора даты (на момент написания софта). Поэтому было решено считывать текущее значение в формате iso8601 (<a>https://www.bairesdev.com/tools/onlinedevtools/</a>)</p>
26 <p>Если дата введена в корректном формате, то произойдет отложенная публикация, иначе - синхронная.</p>
26 <p>Если дата введена в корректном формате, то произойдет отложенная публикация, иначе - синхронная.</p>
27 <p>Также добавилась вспомогательная таблица, в которой хранились отложенные посты. Кроме того появился обработчик<strong>cron</strong>(<a>https://docs-nestjs.netlify.app/techniques/task-schedulin</a>). Этот инструмент позволяет совершать операции один раз в определенный промежуток времени.</p>
27 <p>Также добавилась вспомогательная таблица, в которой хранились отложенные посты. Кроме того появился обработчик<strong>cron</strong>(<a>https://docs-nestjs.netlify.app/techniques/task-schedulin</a>). Этот инструмент позволяет совершать операции один раз в определенный промежуток времени.</p>
28 <p><a>https://github.com/isitfall/tg-autoposter-otus/blob/main/src/post/post-scheduler.service.ts#L64-L92</a></p>
28 <p><a>https://github.com/isitfall/tg-autoposter-otus/blob/main/src/post/post-scheduler.service.ts#L64-L92</a></p>
29 <p>В итоге получился финальный флоу для отложенных публикаций: /create_post -&gt; выбор канала -&gt; ввод текста -&gt;<strong>ввод даты</strong>-&gt; подтверждение -&gt;<strong>запись в вспомогательную таблицу</strong>-&gt;<strong>ожидание нужного времени через Cron</strong>-&gt; публикация в нужный канал через grammyjs api -&gt; запись сущности в БД к постам. Текст появлялся в нужное время, т.к. записей было немного и нагрузка на сервер была минимальная.</p>
29 <p>В итоге получился финальный флоу для отложенных публикаций: /create_post -&gt; выбор канала -&gt; ввод текста -&gt;<strong>ввод даты</strong>-&gt; подтверждение -&gt;<strong>запись в вспомогательную таблицу</strong>-&gt;<strong>ожидание нужного времени через Cron</strong>-&gt; публикация в нужный канал через grammyjs api -&gt; запись сущности в БД к постам. Текст появлялся в нужное время, т.к. записей было немного и нагрузка на сервер была минимальная.</p>
30 <p>Флоу создания публикации:</p>
30 <p>Флоу создания публикации:</p>
31 <h2>Результат</h2>
31 <h2>Результат</h2>
32  
32