Дисклеймер
Автор статьи не утверждает, что его решение поставленной задачи - единственное и самое верное, поэтому комментарии по типу "Статья плохая, потому что можно было сделать лучше" - не приветствуются. Если у вас есть идеи, как иначе решить поставленную в статье задачу, - пишите, с радостью почитаю. Аргументированная критика также приветствуется.
Всем привет! В этой статье я покажу, как написать своего телеграм-бота с рассылкой на основе часового пояса (UTC) пользователя на языке Python. В прошлой статье я показал, как сделать рассылку по команде или в определённое время, но бывает такое, что и этого недостаточно: иногда нужно сделать рассылку по времени пользователя, например, если надо, чтобы пользователь получал уведомление в 7 утра, находясь в нескольких часовых поясах от сервера с ботом. Отчасти эта статья является продолжением прошлой, поэтому, чтобы не возникло некоторых вопросов, советую, для начала, прочитать первую статью на эту тему.
Итак, начнем писать, продолжая код из прошлой статьи, но внесем некоторые изменения: во-первых, поменяем способ хранения данных о пользователях, я выбрал SQLite, но в данной статье речи про эту ДБ не пойдёт. Во-вторых, переместим функции new_user и get_users_list в новый файл, и назовём его db.py, в нём будут функции для работы с базой данных.
Кратко про db.py
В файле db.py, как я уже сказал, будут функции для взаимодействия с базой данных. Вот перечень функций и их краткое описание:
- new_user(cid) - эта функция была в прошлой статье. Она по-прежнему добавляет id (cid) нового пользователя в базу, но теперь она также должна добавлять UTC и дату последней рассылки пользователю, относящийся к определенному id. При запуске UTC ставится по умолчанию (какой - решать вам), а потом пользователь может его поменять.
- get_users_list() - тоже уже была, возвращает список id пользователей в базе.
- set_utc(cid, utc) - изменяет UTC по id (cid). UTC будет храниться в виде числа (положительного или отрицательного).
- get_utc(cid) - возвращает UTC, относящийся к id (cid).
- set_last_mailing_date(cid, date) - изменяет дату (в формате гггг-мм-дд) последней рассылки. Далее про эту функцию будет более подробно.
- get_last_mailing_date(cid) - возвращает дату последней рассылки.
- get_id_list_by_utc(utc) - возвращает список всех id с определенным utc, который передали.
- generate_mailing_users_list() - генерирует список id, которым надо произвести рассылку на основе их UTC. Про реализацию этой функции немного позже.
Примерная структура базы данных:
Работа с UTC. Файл utc.py
Создадим файл utc.py. В нем будут функции для работы с UTC и не только.
Вот перечень этих функций:
- get_utc_by_hour(hour) - поскольку определять UTC пользователя будем по его времени (а точнее часу), данная функция принимает число.
- get_date_by_utc(utc) - определяет, какая дата в определённой часовой зоне (utc). Пригодится для того, чтобы понять, получили ли пользователи с конкретным UTC рассылку.
- next_day(date) - прибавляем к дате (date) один день и возвращаем результат.
Код
Для начала заполним utc.py:
get_date_by_utc(utc). С этой функцией всё просто - получаем датут в определённом UTC.
get_utc_by_hour(hour). С помощью этой функции подбираем UTC на основе часа (hour).
next_day(date). Здесь вычисляем следующий день на основе переданной даты в формате гггг-мм-дд (date).
Теперь про db.py. Из него распишу только про функцию generate_mailing_users_list, так как остальные функции - для взаимодействия с базой данных, а об этом - в другой раз:
Первым делом импортируем utc.py.
generate_mailing_users_list() предназначена для генерации списка пользователей, которым надо разослать рассылку. Распишу по порядку, по строкам:
5. Создаем пустой список.
6. Получаем и перебираем список пользователей.
7. Получаем UTC текущего пользователя.
8. Получаем дату последней рассылки текущему пользователю.
9. Вычисляем следующую дату (относительно последней), в которою надо совершить рассылку текущему пользователю.
10. Если следующая дата = или < текущей дате пользователя или уже прошла, то добавляем id пользователя в список.
12. Записываем последнюю дату рассылки.
13. Возвращаем получившийся список.
Надеюсь, с этой функцией понятно.
И, наконец, переходим к коду бота:
Тут почти всё так же, как и с ботом из прошлой статьи. Единственные два отличия: в этот раз, при рассылке, мы перебираем сгенерированный список id пользователей для рассылки (13 строка), а не все. Второе - расписание ставим раз в час, а не день.
Исходный код: https://gist.github.com/susanin3/c4b0d13ff37d2211e67c6f2247fbd159
Реальный пример с этим видом рассылки (мой бот): http://t.me/what_prazdnik_bot
А на этом всё. Надеюсь, я всё понятно расписал. Если эта статья помогла вам или вы считаете её полезной (а если и то и то, то вообще супер), то можете поставить лайк для продвижения статьи. Всем спасибо!