Добавлено задание ВСР 2.5

parent 0ccae5af
/env/
/databases/
/owm_token.txt
/telegram_token.txt
\ No newline at end of file
import asyncio
import logging
import sys
import os
import random
import sqlite3
from datetime import datetime, UTC
from dataclasses import dataclass
import calendar
from typing import Any
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.interval import IntervalTrigger
from aiogram import Bot, Dispatcher, Router, F
from aiogram.client.default import DefaultBotProperties
from aiogram.filters import CommandStart, Command, CommandObject
from aiogram.types import Message, ReplyKeyboardRemove, BotCommand
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import StatesGroup, State
from pyowm.config import DEFAULT_CONFIG as OWM_DEFAULT_CONFIG
from pyowm import OWM
from pyowm.weatherapi25.weather import Weather
from pyowm.weatherapi25.location import Location
from pyowm.commons.exceptions import NotFoundError as OwmNotFoundError
with open("./telegram_token.txt", "r") as f:
TELEGRAM_TOKEN = f.read()
with open("./owm_token.txt", "r") as f:
OWM_TOKEN = f.read()
OWM_CONFIG = OWM_DEFAULT_CONFIG | {
'language': 'ru'
}
COUNTRY_CODE_TO_COUNTRY_NAME = {
'AF': 'Афганистан',
'AL': 'Албания',
'DZ': 'Алжир',
'AS': 'Американское Самоа',
'AD': 'Андорра',
'AO': 'Ангола',
'AI': 'Ангилья',
'AQ': 'Антарктика',
'AG': 'Антигуа и Барбуда',
'AR': 'Аргентина',
'AM': 'Армения',
'AW': 'Аруба',
'AU': 'Австралия',
'AT': 'Австрия',
'AZ': 'Азербайджан',
'BS': 'Багамы',
'BH': 'Бахрейн',
'BD': 'Бангладешь',
'BB': 'Барбадос',
'BY': 'Беларусь',
'BE': 'Бельгия',
'BZ': 'Белиз',
'BJ': 'Бенин',
'BM': 'Бермуды',
'BT': 'Бутан',
'BO': 'Bolivia',
'BQ': 'Бонэйр',
'BA': 'Босния и Герцеговина',
'BW': 'Ботсвана',
'BV': 'Остров Буве',
'BR': 'Бразилия',
'IO': 'Британская территория в Индийском океане',
'BN': 'Бруней',
'BG': 'Болгария',
'BF': 'Буркина-Фасо',
'BI': 'Бурунди',
'KH': 'Камбоджа',
'CM': 'Камерун',
'CA': 'Канада',
'CV': 'Кабо-Верде',
'KY': 'Острова Кайман',
'CF': 'ЦАР',
'TD': 'Чад',
'CL': 'Чили',
'CN': 'Китай',
'CX': 'Остров Рождества',
'CC': 'Кокосовые острова',
'CO': 'Колумбия',
'KM': 'Коморы',
'CG': 'Конго',
'CD': 'Демократическая республика Конго',
'CK': 'Острова Кука',
'CR': 'Коста-Рика',
'HR': 'Хорватия',
'CU': 'Куба',
'CW': 'Кюрасао',
'CY': 'Кипр',
'CZ': 'Чехия',
'CI': "Кот-д'Ивуар",
'DK': 'Дания',
'DJ': 'Джибути',
'DM': 'Доминика',
'DO': 'Доминиканская Республика',
'EC': 'Эквадор',
'EG': 'Египт',
'SV': 'Сальвадор',
'GQ': 'Equatorial Guinea',
'ER': 'Eritrea',
'EE': 'Эстония',
'ET': 'Эфиопия',
'FK': 'Фолклендские острова',
'FO': 'Фарерские острова',
'FJ': 'Фиджи',
'FI': 'Финляндия',
'FR': 'Франция',
'GF': 'Французская Гвиана',
'PF': 'Французская Полинезия',
'TF': 'Французские Южные и Антарктические Территории',
'GA': 'Габон',
'GM': 'Гамбия',
'GE': 'Грузия',
'DE': 'Германия',
'GH': 'Гана',
'GI': 'Гибралтар',
'GR': 'Греция',
'GL': 'Гренландия',
'GD': 'Гренада',
'GP': 'Гваделупа',
'GU': 'Гуам',
'GT': 'Гватемала',
'GG': 'Гернси',
'GN': 'Гвинея',
'GW': 'Гвинея-Бисау',
'GY': 'Гайана',
'HT': 'Гаити',
'HM': 'Остров Херд и остров Макдональд',
'VA': 'Папский Престол (Государство-город Ватикан)',
'HN': 'Гандурас',
'HK': 'Гонк Конг',
'HU': 'Венгрия',
'IS': 'Исландия',
'IN': 'Индия',
'ID': 'Индонезия',
'IR': 'Иран',
'IQ': 'Ирак',
'IE': 'Ирландия',
'IM': 'остров Мэн',
'IL': 'Израиль',
'IT': 'Италия',
'JM': 'Ямайка',
'JP': 'Япония',
'JE': 'Джерси',
'JO': 'Иордания',
'KZ': 'Казахстан',
'KE': 'Кения',
'KI': 'Кирибати',
'KP': "КНДР",
'KR': 'Корея',
'KW': 'Кувейт',
'KG': 'Кыргызстан',
'LA': "Лаос",
'LV': 'Латвия',
'LB': 'Ливан',
'LS': 'Лесото',
'LR': 'Либерия',
'LY': 'Ливия',
'LI': 'Лихтенштейн',
'LT': 'Литва',
'LU': 'Люксембург',
'MO': 'Макао',
'MK': 'Македония',
'MG': 'Мадагаскар',
'MW': 'Малави',
'MY': 'Малайзия',
'MV': 'Мальдивы',
'ML': 'Мали',
'MT': 'Мальта',
'MH': 'Маршалловы острова',
'MQ': 'Мартиника',
'MR': 'Мавритания',
'MU': 'Маврикий',
'YT': 'Майотта',
'MX': 'Мексика',
'FM': 'Микронезия',
'MD': 'Молдова',
'MC': 'Монако',
'MN': 'Монголия',
'ME': 'Черногория',
'MS': 'Montserrat',
'MA': 'Морокко',
'MZ': 'Мозамбик',
'MM': 'Мьянма (Бирма)',
'NA': 'Намибия',
'NR': 'Науру',
'NP': 'Непал',
'NL': 'Нидерланды',
'NC': 'Новая Каледония',
'NZ': 'Новая Зеландия',
'NI': 'Никарагуа',
'NE': 'Нигер',
'NG': 'Нигерия',
'NU': 'Ниуэ',
'NF': 'Острова Норфолк',
'MP': 'Северные Марианские острова',
'NO': 'Норвегия',
'OM': 'Оман',
'PK': 'Пакистан',
'PW': 'Палау',
'PS': 'Палестина',
'PA': 'Панама',
'PG': 'Папуа Новая Гвинея',
'PY': 'Парагвай',
'PE': 'Перу',
'PH': 'Филипины',
'PN': 'острова Питкэрн',
'PL': 'Польша',
'PT': 'Португалия',
'PR': 'Пуэрто-Рико',
'QA': 'Катар',
'RO': 'Румыния',
'RU': 'Российская Федерация',
'RW': 'Руанда',
'RE': 'Реюньон',
'BL': 'Сан-Бартелеми',
'SH': 'остров Святой Елены',
'KN': 'Сент-Китс и Невис',
'LC': 'Сент-Люсия',
'MF': 'Сен-Мертен',
'PM': 'Сен-Пьер и Микелон',
'VC': 'Сент-Винсент и Гренадины',
'WS': 'Самоа',
'SM': 'Сан-Марино',
'ST': 'Сан-Томе и Принсипи',
'SA': 'Саудовская Арабия',
'SN': 'Сенегал',
'RS': 'Сербия',
'SC': 'Сейшеллы',
'SL': 'Сьерра-Леоне',
'SG': 'Сингапур',
'SX': 'Синт-Мартен',
'SK': 'Словакия',
'SI': 'Словения',
'SB': 'Соломоновы острова',
'SO': 'Сомали',
'ZA': 'Южная Африка',
'GS': 'Южная Георгия и Южные Сандвичевы острова',
'SS': 'Южный Судан',
'ES': 'Испания',
'LK': 'Шри Ланка',
'SD': 'Судан',
'SR': 'Суринам',
'SJ': 'Шпицберген и Ян-Майен',
'SZ': 'Эсватини',
'SE': 'Швеция',
'CH': 'Швейцария',
'SY': 'Сирия',
'TW': 'Тайвань',
'TJ': 'Таджикистан',
'TZ': 'Танзания',
'TH': 'Тайланд',
'TL': 'Восточный Тимор',
'TG': 'Того',
'TK': 'Токелау',
'TO': 'Тонга',
'TT': 'Тринидад и Тобаго',
'TN': 'Тунис',
'TR': 'Турция',
'TM': 'Туркменистан',
'TC': 'Острова Теркс и Кайкос',
'TV': 'Тувалу',
'UG': 'Уганда',
'UA': 'Украина',
'AE': 'ОАЭ',
'GB': 'Великобритания',
'US': 'США',
'UM': 'Внешние малые о-ва (США)',
'UY': 'Уругвай',
'UZ': 'Узбекистан',
'VU': 'Ванауту',
'VE': 'Венесуэла',
'VN': 'Вьетнам',
'VG': 'Британские Виргинские острова',
'VI': 'Американские Виргинские острова',
'WF': 'острова Уоллис и Футуна',
'EH': 'Западная Сахара',
'YE': 'Йемен',
'ZM': 'Замбия',
'ZW': 'Зимбабве',
"AX": "Аландские острова",
}
COUNTRY_CODE_TO_FLAG = {
'AF': '🇦🇫',
'AL': '🇦🇱',
'DZ': '🇩🇿',
'AS': '🇦🇸',
'AD': '🇦🇩',
'AO': '🇦🇴',
'AI': '🇦🇮',
'AQ': '🇦🇶',
'AG': '🇦🇬',
'AR': '🇦🇷',
'AM': '🇦🇲',
'AW': '🇦🇼',
'AU': '🇦🇺',
'AT': '🇦🇹',
'AZ': '🇦🇿',
'BS': '🇧🇸',
'BH': '🇧🇭',
'BD': '🇧🇩',
'BB': '🇧🇧',
'BY': '🇧🇾',
'BE': '🇧🇪',
'BZ': '🇧🇿',
'BJ': '🇧🇯',
'BM': '🇧🇲',
'BT': '🇧🇹',
'BO': '🇧🇴',
'BQ': '🇧🇶',
'BA': '🇧🇦',
'BW': '🇧🇼',
'BV': '🇧🇻',
'BR': '🇧🇷',
'IO': '🇮🇴',
'BN': '🇧🇳',
'BG': '🇧🇬',
'BF': '🇧🇫',
'BI': '🇧🇮',
'KH': '🇰🇭',
'CM': '🇨🇲',
'CA': '🇨🇦',
'CV': '🇨🇻',
'KY': '🇰🇾',
'CF': '🇨🇫',
'TD': '🇹🇩',
'CL': '🇨🇱',
'CN': '🇨🇳',
'CX': '🇨🇽',
'CC': '🇨🇨',
'CO': '🇨🇴',
'KM': '🇰🇲',
'CG': '🇨🇬',
'CD': '🇨🇩',
'CK': '🇨🇰',
'CR': '🇨🇷',
'HR': '🇭🇷',
'CU': '🇨🇺',
'CW': '🇨🇼',
'CY': '🇨🇾',
'CZ': '🇨🇿',
'CI': '🇨🇮',
'DK': '🇩🇰',
'DJ': '🇩🇯',
'DM': '🇩🇲',
'DO': '🇩🇴',
'EC': '🇪🇨',
'EG': '🇪🇬',
'SV': '🇸🇻',
'GQ': '🇬🇶',
'ER': '🇪🇷',
'EE': '🇪🇪',
'ET': '🇪🇹',
'FK': '🇫🇰',
'FO': '🇫🇴',
'FJ': '🇫🇯',
'FI': '🇫🇮',
'FR': '🇫🇷',
'GF': '🇬🇫',
'PF': '🇵🇫',
'TF': '🇹🇫',
'GA': '🇬🇦',
'GM': '🇬🇲',
'GE': '🇬🇪',
'DE': '🇩🇪',
'GH': '🇬🇭',
'GI': '🇬🇮',
'GR': '🇬🇷',
'GL': '🇬🇱',
'GD': '🇬🇩',
'GP': '🇬🇵',
'GU': '🇬🇺',
'GT': '🇬🇹',
'GG': '🇬🇬',
'GN': '🇬🇳',
'GW': '🇬🇼',
'GY': '🇬🇾',
'HT': '🇭🇹',
'HM': '🇭🇲',
'VA': '🇻🇦',
'HN': '🇭🇳',
'HK': '🇭🇰',
'HU': '🇭🇺',
'IS': '🇮🇸',
'IN': '🇮🇳',
'ID': '🇮🇩',
'IR': '🇮🇷',
'IQ': '🇮🇶',
'IE': '🇮🇪',
'IM': '🇮🇲',
'IL': '🇮🇱',
'IT': '🇮🇹',
'JM': '🇯🇲',
'JP': '🇯🇵',
'JE': '🇯🇪',
'JO': '🇯🇴',
'KZ': '🇰🇿',
'KE': '🇰🇪',
'KI': '🇰🇮',
'KP': '🇰🇵',
'KR': '🇰🇷',
'KW': '🇰🇼',
'KG': '🇰🇬',
'LA': '🇱🇦',
'LV': '🇱🇻',
'LB': '🇱🇧',
'LS': '🇱🇸',
'LR': '🇱🇷',
'LY': '🇱🇾',
'LI': '🇱🇮',
'LT': '🇱🇹',
'LU': '🇱🇺',
'MO': '🇲🇴',
'MK': '🇲🇰',
'MG': '🇲🇬',
'MW': '🇲🇼',
'MY': '🇲🇾',
'MV': '🇲🇻',
'ML': '🇲🇱',
'MT': '🇲🇹',
'MH': '🇲🇭',
'MQ': '🇲🇶',
'MR': '🇲🇷',
'MU': '🇲🇺',
'YT': '🇾🇹',
'MX': '🇲🇽',
'FM': '🇫🇲',
'MD': '🇲🇩',
'MC': '🇲🇨',
'MN': '🇲🇳',
'ME': '🇲🇪',
'MS': '🇲🇸',
'MA': '🇲🇦',
'MZ': '🇲🇿',
'MM': '🇲🇲',
'NA': '🇳🇦',
'NR': '🇳🇷',
'NP': '🇳🇵',
'NL': '🇳🇱',
'NC': '🇳🇨',
'NZ': '🇳🇿',
'NI': '🇳🇮',
'NE': '🇳🇪',
'NG': '🇳🇬',
'NU': '🇳🇺',
'NF': '🇳🇫',
'MP': '🇲🇵',
'NO': '🇳🇴',
'OM': '🇴🇲',
'PK': '🇵🇰',
'PW': '🇵🇼',
'PS': '🇵🇸',
'PA': '🇵🇦',
'PG': '🇵🇬',
'PY': '🇵🇾',
'PE': '🇵🇪',
'PH': '🇵🇭',
'PN': '🇵🇳',
'PL': '🇵🇱',
'PT': '🇵🇹',
'PR': '🇵🇷',
'QA': '🇶🇦',
'RO': '🇷🇴',
'RU': '🇷🇺',
'RW': '🇷🇼',
'RE': '🇷🇪',
'BL': '🇧🇱',
'SH': '🇸🇭',
'KN': '🇰🇳',
'LC': '🇱🇨',
'MF': '🇲🇫',
'PM': '🇵🇲',
'VC': '🇻🇨',
'WS': '🇼🇸',
'SM': '🇸🇲',
'ST': '🇸🇹',
'SA': '🇸🇦',
'SN': '🇸🇳',
'RS': '🇷🇸',
'SC': '🇸🇨',
'SL': '🇸🇱',
'SG': '🇸🇬',
'SX': '🇸🇽',
'SK': '🇸🇰',
'SI': '🇸🇮',
'SB': '🇸🇧',
'SO': '🇸🇴',
'ZA': '🇿🇦',
'GS': '🇬🇸',
'SS': '🇸🇸',
'ES': '🇪🇸',
'LK': '🇱🇰',
'SD': '🇸🇩',
'SR': '🇸🇷',
'SJ': '🇸🇯',
'SZ': '🇸🇿',
'SE': '🇸🇪',
'CH': '🇨🇭',
'SY': '🇸🇾',
'TW': '🇹🇼',
'TJ': '🇹🇯',
'TZ': '🇹🇿',
'TH': '🇹🇭',
'TL': '🇹🇱',
'TG': '🇹🇬',
'TK': '🇹🇰',
'TO': '🇹🇴',
'TT': '🇹🇹',
'TN': '🇹🇳',
'TR': '🇹🇷',
'TM': '🇹🇲',
'TC': '🇹🇨',
'TV': '🇹🇻',
'UG': '🇺🇬',
'UA': '🇺🇦',
'AE': '🇦🇪',
'GB': '🇬🇧',
'US': '🇺🇸',
'UM': '🇺🇲',
'UY': '🇺🇾',
'UZ': '🇺🇿',
'VU': '🇻🇺',
'VE': '🇻🇪',
'VN': '🇻🇳',
'VG': '🇻🇬',
'VI': '🇻🇮',
'WF': '🇼🇫',
'EH': '🇪🇭',
'YE': '🇾🇪',
'ZM': '🇿🇲',
'ZW': '🇿🇼',
"AX": '🇦🇽',
}
@dataclass
class Reminder:
id: int
date: int
text: str
active: bool = True
REMINDERS: dict[int, list[Reminder]] = {}
WEATHER_COMMAND = BotCommand(command="weather", description="Получить прогноз погоды")
RPS_COMMAND = BotCommand(command="rps", description="Сыграть в камень, ножницы, бумага")
REMINDERS_COMMAND = BotCommand(command="reminders", description="Получить список всех напоминаний")
REMINDER_COMMAND = BotCommand(command="reminder", description="Создать напоминание")
CANCEL_COMMAND = BotCommand(command="cancel", description="Отменить текущее действие")
ALL_COMMANDS = [
WEATHER_COMMAND,
RPS_COMMAND,
REMINDERS_COMMAND,
REMINDER_COMMAND,
CANCEL_COMMAND
]
START_MESSAGE = """
Здравствуйте!
Я бот, созданный при выполнении задания ВСР 2.5 по учебной практике 1 курса в РГПУ им. Герцена.
Мои возможности:
- Показывать текущую погоду в любом городе мира с помощью команды /weather
- Играть в камень, ножницы, бумага с помощью команды /rps
- Создавать напоминания с помощью команды /reminder
"""
owm = OWM(OWM_TOKEN, config=OWM_CONFIG)
mgr = owm.weather_manager()
bot = Bot(token=TELEGRAM_TOKEN, default=DefaultBotProperties(parse_mode="html"))
dp = Dispatcher()
reminder_router = Router()
class NewReminderState(StatesGroup):
text = State()
date = State()
def create_reminders_db(chat_id: int) -> None:
database_file = f"./databases/{chat_id}.db"
if os.path.exists(database_file):
os.remove(database_file)
with sqlite3.connect(database_file) as conn:
conn.execute("CREATE TABLE Reminders (id INTEGER PRIMARY KEY AUTOINCREMENT, expires_in INTEGER, content TEXT)")
def add_reminder(chat_id: int, text: str, date: int) -> None:
database_file = f"./databases/{chat_id}.db"
with sqlite3.connect(database_file) as conn:
cur = conn.cursor()
cur.execute("INSERT INTO Reminders (expires_in, content) VALUES (?, ?)", (date, text))
if not chat_id in REMINDERS:
REMINDERS.update(chat_id, [])
REMINDERS[chat_id].append(Reminder(cur.lastrowid, date, text))
def get_reminders(chat_id: int) -> list[Reminder]:
database_file = f"./databases/{chat_id}.db"
now = datetime.now()
timestamp = calendar.timegm(now.timetuple())
result = None
with sqlite3.connect(database_file) as conn:
cur = conn.cursor()
cur.execute("SELECT * FROM Reminders")
result = cur.fetchall()
def row_to_reminder(row: list[Any]) -> Reminder:
id = int(row[0])
date = int(row[1])
text = str(row[2])
active = timestamp < date
return Reminder(id, date, text, active)
return list(map(row_to_reminder, result))
@dp.message(CommandStart())
async def command_start_handler(message: Message) -> None:
await asyncio.to_thread(create_reminders_db, message.chat.id)
await message.answer(START_MESSAGE)
@dp.message(Command(WEATHER_COMMAND))
async def command_weather_handler(message: Message, command: CommandObject) -> None:
if command.args is None or command.args.isspace():
await message.answer("Вы не указали город.\nПример использования: /weather Санкт-Петербург")
return
try:
observation = mgr.weather_at_place(command.args)
except OwmNotFoundError:
await message.answer("Город не найден :(")
return
w: Weather = observation.weather
l: Location = observation.location
detailed_status: str = w.detailed_status
country_name = COUNTRY_CODE_TO_COUNTRY_NAME[l.country]
temperature = w.temperature(unit="celsius")
temp = int(round(temperature["temp"]))
temp_max = int(round(temperature["temp_max"]))
temp_min = int(round(temperature["temp_min"]))
feels_like = int(round(temperature["feels_like"]))
humidity = w.humidity
wind = w.wind()
wind_speed = wind["speed"]
flag = COUNTRY_CODE_TO_FLAG[l.country]
await message.answer(f"Место: <b>{l.name}, {country_name} {flag}</b>\nПогода: <b>{detailed_status.capitalize()}</b>\nТемпература: <b>{temp} °C</b>\nМакс. температура: <b>{temp_max} °C</b>\nМин. температура: <b>{temp_min} °C</b>\nОщущается как: <b>{feels_like} °C</b>\nВлажность: <b>{humidity}%</b>\nВетер: <b>{wind_speed} м/c</b>")
@dp.message(Command(REMINDERS_COMMAND))
async def command_reminders_handler(message: Message) -> None:
reminders = await asyncio.to_thread(get_reminders, message.chat.id)
if len(reminders) == 0:
await message.answer("У вас нет активных напоминаний.")
return
answer = "Список напоминаний:\n\n"
for i, reminder in enumerate(reminders, start=1):
date = datetime.fromtimestamp(reminder.date, UTC).strftime("%H:%M, %d/%m/%Y")
status = '\u231B' if reminder.active else '\u2705'
answer += f"{i}. {status} [{date}] {reminder.text}\n\n"
await message.answer(answer)
@reminder_router.message(Command(CANCEL_COMMAND))
@reminder_router.message(F.text.casefold() == "cancel")
async def new_reminder_cancel(message: Message, state: FSMContext) -> None:
current_state = await state.get_state()
if current_state is None:
await message.answer("Нечего отменять.", reply_markup=ReplyKeyboardRemove())
return
await state.clear()
await message.answer("Создание напоминания отменено.", reply_markup=ReplyKeyboardRemove())
@reminder_router.message(Command(REMINDER_COMMAND))
async def command_new_reminder_handler(message: Message, state: FSMContext) -> None:
await state.set_state(NewReminderState.text)
await message.answer("Введите текст напоминания", reply_markup=ReplyKeyboardRemove())
@reminder_router.message(NewReminderState.text)
async def new_reminder_text(message: Message, state: FSMContext) -> None:
await state.update_data(text=message.text)
await state.set_state(NewReminderState.date)
await message.answer("Теперь введите время и дату напоминания в формате: ЧЧ:ММ ДД/ММ/ГГГГ\n<i>Дата не обязательна, по умолчанию - текущий день</i>")
@reminder_router.message(NewReminderState.date)
async def new_reminder_date(message: Message, state: FSMContext) -> None:
example_date = "10:20 23/12/2025"
date_time = message.text.split(" ")
if len(date_time) == 0:
await message.answer(f"Вы указали время и дату неправильно.\nПример: <b>{example_date}</b>")
return
t = date_time[0].split(":")
if len(t) != 2:
await message.answer(f"Вы указали время неправильно.\n\nПример: <b>{example_date}</b>")
return
try:
hours = int(t[0])
except ValueError:
await message.answer(f"Вы указали время неправильно.\nПример: <b>{example_date}</b>")
return
if hours >= 24:
await message.answer(f"Час должен быть меньше 24.\nПример: <b>{example_date}</b>")
return
if hours < 0:
await message.answer(f"Час должен быть больше нуля.\nПример: <b>{example_date}</b>")
return
try:
minutes = int(t[1])
except ValueError:
await message.answer(f"Вы указали время неправильно.\nПример: <b>{example_date}</b>")
return
if minutes >= 60:
await message.answer(f"Минуты должны быть меньше 60.\nПример: <b>{example_date}</b>")
return
if minutes < 0:
await message.answer(f"Минуты должны быть больше нуля.\nПример: <b>{example_date}</b>")
return
today = datetime.today()
day = today.day
month = today.month
year = today.year
if len(date_time) > 1:
d = date_time[1].split('/')
if len(d) != 3:
await message.answer(f"Вы указали дату неправильно.\nПример: <b>{example_date}</b>")
return
try:
day = int(d[0])
except ValueError:
await message.answer(f"Вы указали дату неправильно.\nПример: <b>{example_date}</b>")
return
if day < 0:
await message.answer(f"День не может быть меньше <b>нуля</b>.\nПример: <b>{example_date}</b>")
try:
month = int(d[1])
except ValueError:
await message.answer(f"Вы указали дату неправильно.\nПример: <b>{example_date}</b>")
return
if not 1 <= month <= 12:
await message.answer(f"Месяц должен быть в диапазоне от <b>1</b> до <b>12</b>.\nПример: <b>{example_date}</b>")
return
try:
year = int(d[2])
except ValueError:
await message.answer(f"Вы указали дату неправильно.\nПример: <b>{example_date}</b>")
return
_, max_days = calendar.monthrange(year, month)
if day > max_days:
await message.answer(f"Последний день месяца - <b>{max_days}</b>, а не <b>{day}</b>.\nПример: <b>{example_date}</b>")
return
date = datetime(year, month, day, hours, minutes)
timestamp = calendar.timegm(date.timetuple())
data = await state.update_data(date=timestamp)
await asyncio.to_thread(add_reminder, message.chat.id, data['text'], data['date'])
await message.answer(f"Напоминание успешно создано!")
await state.clear()
async def check_reminders_expiration() -> None:
now = datetime.now()
timestamp = calendar.timegm(now.timetuple())
for chat_id, reminders in REMINDERS.items():
for reminder in reminders:
if reminder.active and timestamp > reminder.date:
reminder.active = False
date = datetime.fromtimestamp(reminder.date, UTC).strftime("%H:%M, %d/%m/%Y")
await bot.send_message(chat_id, f"Напоминание:\n\n{reminder.text}\n\n{date}")
ROCK = "камень"
PAPER = "бумага"
SCISSORS = "ножницы"
RPS_VARIANTS = [ROCK, PAPER, SCISSORS]
RPS_MAP = {
ROCK: SCISSORS,
PAPER: ROCK,
SCISSORS: PAPER
}
@dp.message(Command(RPS_COMMAND))
async def command_rps_handler(message: Message, command: CommandObject) -> None:
if command.args is None or command.args.isspace():
await message.answer("Вы не выбрали предмет.\nПример использования: /rps камень")
return
if command.args not in RPS_VARIANTS:
await message.answer(f"Такого варианта нет.\nВозможные варианты: {ROCK}, {SCISSORS}, {PAPER}.")
return
user_variant = command.args.lower()
variant = random.choice(RPS_VARIANTS)
if RPS_MAP.get(user_variant) == variant:
await message.answer(f"Вы выиграли! Я загадал: <b>{variant}</b>")
elif RPS_MAP.get(variant) == user_variant:
await message.answer(f"Вы проиграли! Я загадал: <b>{variant}</b>")
else:
await message.answer(f"Ничья! Я загадал: <b>{variant}</b>")
def load_all_reminders() -> None:
now = datetime.now()
timestamp = calendar.timegm(now.timetuple())
for address, _, files in os.walk("./databases/"):
for name in files:
chat_id = int(name[:-3])
path = os.path.join(address, name)
result = None
with sqlite3.connect(path) as conn:
cur = conn.cursor()
cur.execute("SELECT * FROM Reminders")
result = cur.fetchall()
reminders: list[Reminder] = []
for id, date, text in result:
active = timestamp < date
reminders.append(Reminder(id, date, text, active=active))
REMINDERS[chat_id] = reminders
async def main() -> None:
await bot.set_my_commands(commands=ALL_COMMANDS)
dp.include_router(reminder_router)
scheduler = AsyncIOScheduler()
scheduler.add_job(check_reminders_expiration, IntervalTrigger(seconds=10))
scheduler.start()
await dp.start_polling(bot)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
load_all_reminders()
asyncio.run(main())
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment