From ec2c0c7dfccb8972b47afb4aa89fb7988923c5b4 Mon Sep 17 00:00:00 2001 From: ada-dmitry Date: Sat, 3 May 2025 09:42:50 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BB=D0=BE=D0=B3=D0=B3=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 4 + .idea/.gitignore | 8 -- .idea/dataSources.xml | 19 ---- .../inspectionProfiles/profiles_settings.xml | 6 -- .idea/misc.xml | 7 -- .idea/modules.xml | 8 -- .idea/vcs.xml | 6 -- .idea/vol_bot.iml | 14 --- README.md | 94 +++++++++++++++++- __pycache__/main.cpython-313.pyc | Bin 0 -> 2708 bytes __pycache__/models.cpython-313.pyc | Bin 652 -> 763 bytes bot.log | 51 ++++++++++ handlers/__pycache__/admin.cpython-313.pyc | Bin 4577 -> 4585 bytes .../__pycache__/admin_adv.cpython-313.pyc | Bin 0 -> 4898 bytes .../__pycache__/adv_callbacks.cpython-313.pyc | Bin 0 -> 1934 bytes handlers/__pycache__/user.cpython-313.pyc | Bin 3543 -> 7942 bytes handlers/admin.py | 10 +- handlers/admin_adv.py | 6 +- handlers/user.py | 78 ++++++++++++--- main.py | 31 ++++-- requirements.txt | 1 - 21 files changed, 244 insertions(+), 99 deletions(-) create mode 100644 .env.example delete mode 100644 .idea/.gitignore delete mode 100644 .idea/dataSources.xml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/vol_bot.iml create mode 100644 __pycache__/main.cpython-313.pyc create mode 100644 bot.log create mode 100644 handlers/__pycache__/admin_adv.cpython-313.pyc create mode 100644 handlers/__pycache__/adv_callbacks.cpython-313.pyc diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..65e013c --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +BOT_TOKEN= +ADMINS= +DATABASE_URL= + diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml deleted file mode 100644 index f8ae353..0000000 --- a/.idea/dataSources.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - postgresql - true - org.postgresql.Driver - jdbc:postgresql://localhost:5432/postgres - $ProjectFileDir$ - - - postgresql - true - org.postgresql.Driver - jdbc:postgresql://localhost:5432/postgres - $ProjectFileDir$ - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 562afa4..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 3dec55b..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/vol_bot.iml b/.idea/vol_bot.iml deleted file mode 100644 index 5cd92f3..0000000 --- a/.idea/vol_bot.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index ff8ab45..4898564 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,93 @@ -## Бот для Волонтерского Центра НИЯУ МИФИ +# Volunteer Center Bot (Волонтерский Центр НИЯУ МИФИ Бот) -- \ No newline at end of file +## Описание + +Этот проект представляет собой Telegram-бота, разработанного для Волонтерского Центра НИЯУ МИФИ. Бот предоставляет функционал для регистрации пользователей, управления рассылками и взаимодействия с администраторами. + +## Основной функционал: + +1. **Регистрация пользователей:** + * Позволяет новым пользователям зарегистрироваться в системе бота. + * Данные пользователей сохраняются в базе данных. + +2. **Подписка/Отписка от рассылки:** + * Пользователи могут подписываться на рассылку сообщений от администраторов. + * Пользователи могут отписываться от рассылки в любое время. + +3. **Рассылка сообщений:** + * Администраторы могут отправлять сообщения пользователям, подписанным на рассылку. + * Поддерживаются два формата сообщений: короткий и длинный. + +4. **Статистика рассылки:** + * Предоставляет администраторам информацию об объеме рассылки (например, количество получателей). + +## Технологии: + +* **Python:** Основной язык программирования. +* **aiogram:** Библиотека для создания Telegram-ботов. +* **SQLAlchemy:** ORM для работы с базой данных. +* **PostgreSQL:** Используется в качестве базы данных. +* **dotenv:** Для управления переменными окружения. +* **FSM (Finite State Machine):** Для управления состояниями бота. +* **MemoryStorage:** Хранилище состояний в оперативной памяти. + +## Структура проекта: + +* **`main.py`:** Основной файл, запускающий бота. +* **`handlers/`:** Директория, содержащая обработчики событий (хендлеры) для различных типов пользователей (обычные пользователи, администраторы) и callback-запросов. + * `user.py`: Обработчики для обычных пользователей. + * `admin.py`: Обработчики для администраторов. + * `admin_adv.py`: Обработчики для рассылки сообщений администраторами. + * `adv_callbacks.py`: Обработчики для callback-запросов, связанных с рассылкой. +* **`database/`:** Директория, содержащая код для работы с базой данных. + * `__init__.py`: Инициализация модуля. +* **`.env`:** Файл с переменными окружения (например, токен бота). +* **`README.md`:** Этот файл. + +## Установка и запуск: + +1. **Клонируйте репозиторий:** + ```bash + git clone https://github.com/ada-dmitry/vol_bot + cd vol_bot + ``` + +2. **Создайте виртуальное окружение (рекомендуется):** + ```bash + python3 -m venv venv + source venv/bin/activate # Linux/macOS + venv\Scripts\activate # Windows + ``` + +3. **Установите зависимости:** + ```bash + pip install -r requirements.txt + ``` + (Если у вас нет файла `requirements.txt`, то установите зависимости вручную: `pip install aiogram python-dotenv sqlalchemy`) + +4. **Создайте файл `.env`:** + * Скопируйте содержимое файла `.env.example` в новый файл `.env`. + * Замените `BOT_TOKEN` на токен вашего бота, полученный от BotFather. + +5. **Запустите бота:** + ```bash + python main.py + ``` + +## Разработка: + +* Для добавления нового функционала создавайте новые обработчики в соответствующих файлах директории `handlers/`. +* Для работы с базой данных используйте SQLAlchemy. +* Для управления состояниями бота используйте FSM. + +## Планы по развитию: + +* Добавление новых команд и функций. +* Улучшение интерфейса взаимодействия с пользователем. +* Расширение возможностей администраторов. +* Добавление логирования. +* Добавление тестов. + +## Контакты +Другие проекты: [GitHub](https://github.com/ada-dmitry) +По вопросам и предложениям обращайтесь: [TG - Дмитрий](https://t.me/ada_dmitry) diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a082cdf812b2f9d6f6251df3507136d07cb16141 GIT binary patch literal 2708 zcmaJ@?Q;`F7~joZE|<$o%Zn`pXirLkU~N?z72n1NMUzOu1RQ5lCvzm%G?LtP_L9z& zaXO_q7R0fG!hj>be9#Ymt6GEs!72U&cT^{J#SzC(eyhNY%7DZGIv6X`-m^@C;oVV1mZywwDm%wCEiL}<15Gt84ZaW zQKY^!^t{PUjzi6MBa?4#_8pY+fPAadYqlFvN{qlRSn0zl?+(tMd0S1gyoQKP-0~@r)`^l=2SMU1>Pjw?)61$h7Un5mF;qg`O0HDUsMl^XN^Xn> zpvq*GV)1~IJ!rt>f~w^Uno9YoVyK7uySFMvwp=KwVMD%O?%rBd$JC;xH2TY6Ni_^u zJZv2D9MH?XMLi$psM{Vug<+kPlrj}Z6fIX&iIH8tc@`%};JYQk33nkGVkOhR2uJ<2EzjJ!E)4nK!pgPBB^K@V_eG; zKa+|jwXEcnvO=XSQI)cqfuMmnS42=CwCpo0)iP;^Wmf zf-7fA$4Y0P`DpihyQ}N_t@Zs2!AMn%m}2A)H)`#enRs*Jmj<4hI6Co{@e<566^e5B zEFS0*KHva-eE&e0n-AcDZec#iGrZCV;`t4DU<*IrAu!yHnS2XoI4newXTA>)JmjB$ zz|Zg#9+2M=!YsJ#5Izb=Q4e8uD0WFVLO2N_aCd>!f}K!HxprU;rJcly(q6~fNoXk! zEO5FJuE~I7(QH$^GoOt1<77)yaa;uep8yl(bUqpMl8j*Jc;X2^+*aQ+P3ouSHKe3JgbuI#9F8q@uHG-J4 zJ-{m<*&HzElJ&MV4Gg(#UNFze=0$nmbD4p?u^!+MSeyr&Sw}YqQyzwa=YV4{gfZ?v zCj#Xa;O3NV26UFq3wJP9c3hD`XOr|RaNuj^0&v>A1iuTg?w7q1^+xyX%k0~ec$VdQ zcUeEEY5+V&?E$EC!M4rQ&0KJ2CUBPN9SpY+4os;_H>i+T*<(T26%m#|sQ@`V56=c) z(1vx|QqZ!+N>0rXy;6o0PFR#uq1GcTrxF&egoUQfWg4)Vof*}O#e$Y+FBedsx^kli zBZMpy7D<$6xqx&7WL_K7P}Rxr3!aRgj=d8*b8unxHcPs1a_4pLs@om>d|BUaL@8tf|Lnnql*-`D?gZ+ z(jJ9n+Ja8j!-`a>J==sO73yJ^0LModjqNkP>#V8B(((a#uI>C?OV>W=7qUBbZMcx9 zd~9&n9_rgwD5}rb-e2m4%YLDDyWl%}#WNYw!B${d*uD+Q!3*#ix&?hyyD9OBlAfy+ z)u#yKEK6_3aj2F!jPcK?>nGIzD+>OIyg#9iA5riR0pZ6N&|^QNdw)T`*8?|@r;1ix zL#r006*E1@dKP^HH^i2zxbB*`?o4b!+`PnbLE)yygI!ClNLo?#hOT)-XC7VfZkiNs r3Icxk=1L!ym)0ZRfAr7-w|0^DO(&)jC-`@T@A>v64)Gzv{#5-97+=8Q literal 0 HcmV?d00001 diff --git a/__pycache__/models.cpython-313.pyc b/__pycache__/models.cpython-313.pyc index d6aff8669f52f45b033a5057d7a90b7895f2d3f8..57063a47c2a65da7c4860ac4bc96ea51cf3b7bec 100644 GIT binary patch delta 434 zcmeBS{mshvnU|M~0SLA>F=co$PUMsDwgd8}G6XXOGkP<4F%~g;F%>a+F&8m=u@tc= zfW(=+S-seb*c2Ef7?c=-nWY$lSz_2snL(y7Fch(;vud)v1Ti&PCg#d=++qtZDay=C zpV%eG7%*|AmNsiJnXP{CO%SlSAkP)U4VVs7d!?&6Ztl*;(@ zqWsc=$=QrLjQo>lFgn(Af?Nk8Sb(_L97wb=+z^p&@O{W9G9hY3$VEP*2KSo+ViU?% zuwE3LlNl7gA!r^#`PtGF;HF()}AHMg<| z6b3~gTZlX-=wLk=*1&CSeJy X%M4a`86>~3urV5Sn0#dbQef2p&DUv% delta 324 zcmey(+QZ8CnU|M~0SN4RKc_!pn8+vLZUy8`We8>nX7pz8Vk~0xVk%)MUKH;*?mNnmkcZ zl+k43RxN(!U{*_}BFHG`S~xGDb|^$EeN7 zJNXr(qa6pxWDvmu#KrPJqK)B(h;)PRLq3rSQ7b|&@)G zho2_<eqmu@H0m(<$^fLmdI3_eM?3%k diff --git a/bot.log b/bot.log new file mode 100644 index 0000000..073cda3 --- /dev/null +++ b/bot.log @@ -0,0 +1,51 @@ +2025-05-02 20:48:11,017 - INFO - __main__ - Запуск работы бота. +2025-05-02 20:48:11,070 - INFO - aiogram.dispatcher - Start polling +2025-05-02 20:48:11,331 - INFO - aiogram.dispatcher - Run polling for bot @volunteer_mephi_bot id=7827792861 - 'VC_Bot' +2025-05-02 20:48:38,874 - WARNING - aiogram.dispatcher - Received SIGINT signal +2025-05-02 20:48:38,875 - INFO - aiogram.dispatcher - Polling stopped for bot @volunteer_mephi_bot id=7827792861 - 'VC_Bot' +2025-05-02 20:48:38,875 - INFO - aiogram.dispatcher - Polling stopped +2025-05-02 20:52:05,968 - INFO - __main__ - Запуск работы бота. +2025-05-02 20:52:06,013 - INFO - aiogram.dispatcher - Start polling +2025-05-02 20:52:06,277 - INFO - aiogram.dispatcher - Run polling for bot @volunteer_mephi_bot id=7827792861 - 'VC_Bot' +2025-05-02 20:52:13,305 - WARNING - aiogram.dispatcher - Received SIGINT signal +2025-05-02 20:52:13,306 - INFO - aiogram.dispatcher - Polling stopped for bot @volunteer_mephi_bot id=7827792861 - 'VC_Bot' +2025-05-02 20:52:13,306 - INFO - aiogram.dispatcher - Polling stopped +2025-05-02 20:52:17,747 - INFO - __main__ - Запуск работы бота. +2025-05-02 20:52:17,780 - INFO - aiogram.dispatcher - Start polling +2025-05-02 20:52:18,048 - INFO - aiogram.dispatcher - Run polling for bot @volunteer_mephi_bot id=7827792861 - 'VC_Bot' +2025-05-02 20:52:32,713 - INFO - aiogram.event - Update id=328315775 is handled. Duration 226 ms by bot id=7827792861 +2025-05-02 20:52:44,275 - INFO - aiogram.event - Update id=328315776 is not handled. Duration 1 ms by bot id=7827792861 +2025-05-02 20:53:04,829 - INFO - aiogram.event - Update id=328315777 is not handled. Duration 2 ms by bot id=7827792861 +2025-05-02 20:53:17,894 - WARNING - aiogram.dispatcher - Received SIGINT signal +2025-05-02 20:53:17,895 - INFO - aiogram.dispatcher - Polling stopped for bot @volunteer_mephi_bot id=7827792861 - 'VC_Bot' +2025-05-02 20:53:17,896 - INFO - aiogram.dispatcher - Polling stopped +2025-05-02 20:55:10,923 - INFO - __main__ - Запуск работы бота. +2025-05-02 20:55:10,971 - INFO - aiogram.dispatcher - Start polling +2025-05-02 20:55:11,246 - INFO - aiogram.dispatcher - Run polling for bot @volunteer_mephi_bot id=7827792861 - 'VC_Bot' +2025-05-02 20:55:19,000 - INFO - aiogram.event - Update id=328315778 is not handled. Duration 1 ms by bot id=7827792861 +2025-05-02 20:55:20,367 - INFO - main - User 451218808 started the bot +2025-05-02 20:55:20,838 - INFO - aiogram.event - Update id=328315779 is handled. Duration 472 ms by bot id=7827792861 +2025-05-02 21:00:28,136 - INFO - aiogram.event - Update id=328315780 is not handled. Duration 1 ms by bot id=7827792861 +2025-05-02 21:00:28,840 - INFO - main - User 451218808 started the bot +2025-05-02 21:00:28,963 - INFO - aiogram.event - Update id=328315781 is handled. Duration 123 ms by bot id=7827792861 +2025-05-02 21:00:31,620 - INFO - aiogram.event - Update id=328315782 is not handled. Duration 2 ms by bot id=7827792861 +2025-05-02 21:00:33,258 - INFO - aiogram.event - Update id=328315783 is not handled. Duration 1 ms by bot id=7827792861 +2025-05-02 21:00:33,973 - INFO - aiogram.event - Update id=328315784 is not handled. Duration 1 ms by bot id=7827792861 +2025-05-02 21:00:34,039 - INFO - aiogram.event - Update id=328315785 is not handled. Duration 1 ms by bot id=7827792861 +2025-05-02 21:00:34,178 - INFO - aiogram.event - Update id=328315786 is not handled. Duration 2 ms by bot id=7827792861 +2025-05-02 21:00:34,389 - INFO - aiogram.event - Update id=328315787 is not handled. Duration 1 ms by bot id=7827792861 +2025-05-02 21:08:22,430 - WARNING - aiogram.dispatcher - Received SIGINT signal +2025-05-02 21:08:22,431 - INFO - aiogram.dispatcher - Polling stopped for bot @volunteer_mephi_bot id=7827792861 - 'VC_Bot' +2025-05-02 21:08:22,431 - INFO - aiogram.dispatcher - Polling stopped +2025-05-02 21:16:06,283 - INFO - __main__ - Запуск работы бота. +2025-05-02 21:16:06,343 - INFO - aiogram.dispatcher - Start polling +2025-05-02 21:16:06,584 - INFO - aiogram.dispatcher - Run polling for bot @volunteer_mephi_bot id=7827792861 - 'VC_Bot' +2025-05-02 21:16:23,053 - INFO - handlers.user - User 451218808 started the bot +2025-05-02 21:16:23,296 - INFO - aiogram.event - Update id=328315793 is handled. Duration 243 ms by bot id=7827792861 +2025-05-02 21:16:24,462 - INFO - aiogram.event - Update id=328315794 is handled. Duration 220 ms by bot id=7827792861 +2025-05-02 21:16:25,683 - INFO - aiogram.event - Update id=328315795 is handled. Duration 234 ms by bot id=7827792861 +2025-05-02 21:16:27,117 - INFO - aiogram.event - Update id=328315796 is handled. Duration 212 ms by bot id=7827792861 +2025-05-02 21:16:28,052 - INFO - aiogram.event - Update id=328315797 is handled. Duration 381 ms by bot id=7827792861 +2025-05-02 21:16:30,962 - INFO - aiogram.event - Update id=328315798 is handled. Duration 200 ms by bot id=7827792861 +2025-05-03 09:36:21,305 - INFO - __main__ - Запуск работы бота. +2025-05-03 09:37:58,037 - INFO - __main__ - Запуск работы бота. diff --git a/handlers/__pycache__/admin.cpython-313.pyc b/handlers/__pycache__/admin.cpython-313.pyc index 6c7decfade0934c36564f089b0623e97eab32485..745c3af62d7020c266353d8526ea58374f74abcb 100644 GIT binary patch delta 246 zcmaE;{8E|sGcPX}0}vFmi)KvT$orI8$yz@nKQ~oBF(pwypeR2pHMyi%KcKQCBR>zu zoh;6x!^peYg{6;~O$4O(&}2^*naN++4b1NF2u(5R_PNd@cacYKPRVt7!;A8UmwAk? z^H^NuvAE1*^_iJThU+^6lNeVA*LPM10r~#=4_uQ&IaH*$ft;HHRv(#wa!{H6`i}Zv zAGtP9kOd#e5F`x=Z0BHS6z5oCK delta 284 zcmaE<{7{+qGcPX}0}yac_?%v`k@qRHs-1pDer~FMVoIXEOMY@`Zfaghv3_`dQMP_S zQGQlxGLRSMJXwTAhmm`;BTFAMyC6_|@ot96Tzt}#Ke8Jbu2I_}vRdc5md!;in>``d zZT&CW`d`)xxULm;Q7i1SR>WoL$m^n!9bDg883g3}>p!qf4(CvjU=z7I@_FMw8kU}j`wyw9L?kwNJ$gW_EV*}DwlcNvs!GjKlS zoTME2PQVgJjMm= VpBX^(XJ!T_9f;5efypZb9RX6pT7Cck diff --git a/handlers/__pycache__/admin_adv.cpython-313.pyc b/handlers/__pycache__/admin_adv.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7be8a8004e140318c9c561ef3505ba95652a0863 GIT binary patch literal 4898 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 P7if*Dwan9IeY^e*vI&3` literal 0 HcmV?d00001 diff --git a/handlers/__pycache__/adv_callbacks.cpython-313.pyc b/handlers/__pycache__/adv_callbacks.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7da55773c3522887fe15c37da875bfa066b29766 GIT binary patch literal 1934 zcmb7E-A@}w5Z^tY&-Q_xLd!=~CaiZF31*%FBv{2C&3To}rJYZy9>K?4}~_Zn@CaeQkA@=Z-5eoL<$k~AJ~&0OixNnKVEo)`YCUnJ^P@LrfSdHnc11y znc1D6r{wjD2)==@xx}Ocq2JlY{+tz|^d|_{P#A^r0P4pC_j81k*q$43^z($bWXFKB zUm${nBDe*$SB?@_#1*Qs1Mc$(7pmRg*;1&^miBp=Z^z}G&BM+J-^PW7CUk+{%Tx7# z@`PO-?;&(3p8G(&>M@UB+-8aWoGFCVtga9f_xZ8u?Uhrhb8>9_qpU)vK_SZVTr{nu zRWf~%2f4#^$0{zdO6k@G*mKUoD$RrTB$D7shf&Bf9V8)W#NjWD_sZp1pbQ@2ZJ&@} zOZ&V94ey=EaKl_{#T0)Yv8cWkph zWlsV5?Yqkoy-C;Lw`?rXJM;lvrFSG?7FnYA=xs~8_AzU{mQbgna!Mh(=}Br)Ii@Fb zO7=|_D8B@Oj2Q@YU$V~JGcFmkbcL=OdC9nRFa@YU4|d}Uy>Ifm@~NI}fhhDUT{C7S z`Vic2Tfvs0lr<~Ts^ z#KnvP!)r2bI)G~oYLX{05QV$teUTp=)Hkv_O-n#tg!f4Se8D44e z*@E}QMcMGS&h-5uK9>)C8Mskj5T%*kpR0VEzWThnpwi?0^z6vIN_~-{J3`%&O}B5W z$~XU6vFhla%Lq-Rm`l3oPE&W9xrntzvB?mdiej@NHZPuBJb&|aK@1f60ObRlVr@RS z5Ts3A1+lxxcN={7ZVmE`;$1iLWbm$loWY;??#CKT3N-unkzNk3*WjKGe!aGZ$!)l& zlV5Lt3FM8VxTlNXc%hNWZMYZl8|?y)US>0m!CBg=>Sy$<4M%AOq3=Bd=)0H@B1X}|vjR{s`?I-=9APyG!!2&<{ zSgQu(Y~2Zb9UtRw2q*B6-)p+$q&i0AG+|dKY>t`UiYlN_PbeB;e}1#phFL(4r;{0m zsWQ9;Ql7^?8+y@6Hj9amof0)&Cb~A2)Dsr=tU7-{C9t9LecYXCHJ(i=U8EUw?4sJ| zKz1A$<6qFRN9g58$p5S7$XAUs!WMQFalL`-zn#3EyOJw5v>FYqx9STGXA1b$9nOp2 x!i%FN#CXYpxYx?6o#Tje|NY!zqtW0m;8Qys#zXklD<#A@J8^o~QV|I%_zTtl<5mCw literal 0 HcmV?d00001 diff --git a/handlers/__pycache__/user.cpython-313.pyc b/handlers/__pycache__/user.cpython-313.pyc index f44555b4d59b78a1dce9a6693cb2ad53430da336..a64f805f91aabbc6a56b48f71c014a05ae765b22 100644 GIT binary patch literal 7942 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 U*x;;d!GSG;yhZyOFXE&8f9qD;n*aa+ literal 3543 zcmb7GO>7&-6`t8$E`P)o^<#^&B1;q{M`B8gf@`Ic;;1n~w-wdOEh#!crJ7oiYmzp9 zUhQ#wLrr)XjSpt?If-ca2hcJ9M3QAOE@{G> zVk$K$Mz8%WFOeA!tMRgwlA<|{PiAC^0L@Ru#GK^88W#ouP(hSuGSP?(7LwTv2u{SM zTtv=K%2AS>%7H9$O`4g^iX?V}_sKaCteDd!f6?7vqc6)0?XRKkJYW!NM=sdXvGTa_ z!!R1cA(UVdn#On85tAKda2N-nf3S=}x|GV8ktpS@2wIJ?3aw}b^^~iOP%eyu_Wcst z3sxVN?cH)?JBA<`_r=VFnPBbVxyC9pY?$rZ9gao7`_U_`H!M_QH#`Q98)Fsv|F0p0 z`>|o^VC*g$jk99a;EdQ0>xY;O2fj}jniU%6#$Gadl@*Kdr^9Tp*%+zNi#Ws@afP^k z<_KT(*rQ&^AXd!2h)0?&Xk;B~0%{Oy3)Gr6u!3dQ*AqQl0?&XXT;t3D7?% z57k@h`)w}ep7I2SAA;l)by0bw-ctTlQvD-L_*i{c`3tB&8W{ZuYjz?{rDh^&kzC79 zc^sq)9B5|g9VtprFg-SeW~^p2wm#x0sRNmI$HAt_exmILMPy%wr+~m6~^ty2cYp&Zlx3r@P^D z(mOes9y%8-+UveVHZA$YnCSCoqxrOy$;rOAvgDfYrzCq7Fh%xVdeb+ZO+_ZNIbTA| z#8MKGebiR>)Ql$RND5sW>|65PfBC_&d)}hES9SM(94`)DR0l5>2ZQQhP;vJv?ogp_v}hky?4wk_d#Srn z=Pugairu~8`1u^SQGI+dGoSfz^oyRMzfZ(I?N}{ZLA=7a$dIH&0bd3XcJDOGsND?)Eq|4xTrn4zZ+;nx!uV9bO6DT^(G> zG0M>kme6~UG}1xv{OYIGoiPhOw%2ZlC%QV>T}t6JS7=; zt3RAbCydbTlsBQFsQ0X98o8sLz175am$lAJVlfvA;x2ut90)NRR{w2Q$YrNIs@5C$EkNMxS zz}-LJ?zgh5X6$GARg07It=MnkS6v+CJE}lu)rb9NZneh){MrfZZ|ByU+9>}T_MhU` z&hfynvl#T(O?nH~Kw{vaT)LqxG`S{4xZ?CX+-f|G z<-1GlPEjG7%tZA3_z3MlAC*$F32!c zc>$U&7Gu1LPHv)}O>|mCr=KF{Q{;Y%e9x_pg~prwGi-jZ<=vLsc$r_~KkQO#+y&ge z#aQumyyDzJlvlzkuJ^Vr)2x Ue<$o9O6k<|cw3i|GZ4>z0gwXqCIA2c diff --git a/handlers/admin.py b/handlers/admin.py index 4d60e51..4720299 100644 --- a/handlers/admin.py +++ b/handlers/admin.py @@ -5,24 +5,30 @@ from models import User from database import async_session import os + router = Router() admin_ids = list(map(int, os.getenv("ADMINS").split(","))) + @router.message(F.text == "/admin") async def admin_panel(message: Message): if message.from_user.id not in admin_ids: return await message.answer("Доступ запрещён.") await message.answer("Команды:\n/stat — статистика\n/broadcast <текст> — рассылка") + @router.message(F.text.startswith("/stat")) async def stat_handler(message: Message): if message.from_user.id not in admin_ids: return async with async_session() as session: total = await session.scalar(select(User).count()) - subscribed = await session.scalar(select(User).where(User.is_subscribed).count()) + subscribed = await session.scalar( + select(User).where(User.is_subscribed).count() + ) await message.answer(f"Всего пользователей: {total}\nПодписаны: {subscribed}") + @router.message(F.text.startswith("/broadcast ")) async def broadcast_handler(message: Message, bot: Bot): if message.from_user.id not in admin_ids: @@ -48,4 +54,4 @@ async def broadcast_handler(message: Message, bot: Bot): except Exception: failed += 1 - await message.answer(f"📬 Рассылка завершена:\nУспешно: {sent}\nОшибок: {failed}") \ No newline at end of file + await message.answer(f"📬 Рассылка завершена:\nУспешно: {sent}\nОшибок: {failed}") diff --git a/handlers/admin_adv.py b/handlers/admin_adv.py index d695093..23f12c1 100644 --- a/handlers/admin_adv.py +++ b/handlers/admin_adv.py @@ -11,11 +11,10 @@ import os router = Router() admin_ids = list(map(int, os.getenv("ADMINS", "").split(","))) -# Храним рассылки + adv_memory = {} # {adv_id: {"text": str, "is_active": bool}} current_adv_id = None -# Состояния для FSM class AdvForm(StatesGroup): short = State() full = State() @@ -44,18 +43,15 @@ async def get_full_text_and_send(message: Message, state: FSMContext, bot: Bot): # Генерируем уникальный ID рассылки adv_id = str(uuid4()) - # Деактивируем старые рассылки for adv in adv_memory.values(): adv["is_active"] = False - # Сохраняем новую рассылку adv_memory[adv_id] = { "text": full_text, "is_active": True } current_adv_id = adv_id - # Клавиатура kb = InlineKeyboardMarkup(inline_keyboard=[ [ InlineKeyboardButton(text="👍 Интересно", callback_data=f"adv:{adv_id}"), diff --git a/handlers/user.py b/handlers/user.py index 809840c..eac8f4e 100644 --- a/handlers/user.py +++ b/handlers/user.py @@ -3,35 +3,47 @@ from aiogram.fsm.context import FSMContext from aiogram.types import Message, CallbackQuery from aiogram.fsm.state import State, StatesGroup from sqlalchemy import select, insert, update +import logging + from models import User from database import async_session from keyboards import get_subscription_keyboard +logger = logging.getLogger(__name__) router = Router() + # Машина состояний class Register(StatesGroup): waiting_for_fullname = State() waiting_for_study_group = State() + @router.message(F.text == "/start") async def start_handler(message: Message, state: FSMContext): user_id = message.from_user.id - + logger.info(f"User {message.from_user.id} started the bot") async with async_session() as session: result = await session.execute(select(User).where(User.user_id == user_id)) user = result.scalar_one_or_none() if user: # Приветствие при повторном запуске - text = f"👋 Привет, {user.full_name or 'друг'}!\n" \ - f"Группа: {user.study_group or 'не указана'}\n" \ - "Используй кнопки ниже, чтобы управлять подпиской:" - await message.answer(text, reply_markup=get_subscription_keyboard(user.is_subscribed)) + text = ( + f"👋 Привет, {user.full_name or 'друг'}!\n" + f"Группа: {user.study_group or 'не указана'}\n" + "Используй кнопки ниже, чтобы управлять подпиской:" + ) + await message.answer( + text, reply_markup=get_subscription_keyboard(user.is_subscribed) + ) else: # Первый запуск — регистрация await state.set_state(Register.waiting_for_fullname) - await message.answer("👋 Привет! Пожалуйста, напиши свои ФИО одной строкой:") + await message.answer( + "👋 Привет! Пожалуйста, напиши свои ФИО одной строкой:" + ) + @router.message(Register.waiting_for_fullname) async def get_fullname(message: Message, state: FSMContext): @@ -39,6 +51,7 @@ async def get_fullname(message: Message, state: FSMContext): await state.set_state(Register.waiting_for_study_group) await message.answer("Теперь укажи номер своей группы (например, Б11-111):") + @router.message(Register.waiting_for_study_group) async def get_study_group(message: Message, state: FSMContext): data = await state.get_data() @@ -46,14 +59,51 @@ async def get_study_group(message: Message, state: FSMContext): study_group = message.text async with async_session() as session: - await session.execute(insert(User).values( - user_id=message.from_user.id, - full_name=full_name, - study_group=study_group, - is_subscribed=True - )) + await session.execute( + insert(User).values( + user_id=message.from_user.id, + full_name=full_name, + study_group=study_group, + is_subscribed=True, + ) + ) await session.commit() - await message.answer(f"✅ Регистрация завершена!\nФИО: {full_name}\nГруппа: {study_group}") - await message.answer("Теперь ты можешь управлять подпиской ниже 👇", reply_markup=get_subscription_keyboard(True)) + await message.answer( + f"✅ Регистрация завершена!\nФИО: {full_name}\nГруппа: {study_group}" + ) + await message.answer( + "Теперь ты можешь управлять подпиской ниже 👇", + reply_markup=get_subscription_keyboard(True), + ) await state.clear() + + +@router.callback_query(F.data == "subscribe") +async def subscribe(callback: CallbackQuery): + async with async_session() as session: + await session.execute( + update(User) + .where(User.user_id == callback.from_user.id) + .values(is_subscribed=True) + ) + await session.commit() + await callback.message.edit_reply_markup( + reply_markup=get_subscription_keyboard(True) + ) + await callback.answer("✅ Вы подписались на рассылку!") + + +@router.callback_query(F.data == "unsubscribe") +async def unsubscribe(callback: CallbackQuery): + async with async_session() as session: + await session.execute( + update(User) + .where(User.user_id == callback.from_user.id) + .values(is_subscribed=False) + ) + await session.commit() + await callback.message.edit_reply_markup( + reply_markup=get_subscription_keyboard(False) + ) + await callback.answer("❌ Вы отписались от рассылки.") diff --git a/main.py b/main.py index fb032ba..1f61f1a 100644 --- a/main.py +++ b/main.py @@ -4,30 +4,47 @@ from aiogram.fsm.storage.memory import MemoryStorage import asyncio import os from dotenv import load_dotenv +import logging + from handlers import user, admin, admin_adv, adv_callbacks from database import engine, Base + load_dotenv() +logging.basicConfig( + level=logging.INFO, # Уровень логирования (DEBUG, INFO, WARNING, ERROR, CRITICAL) + format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", + handlers=[ + logging.FileHandler("bot.log"), # Логирование в файл bot.log + # logging.StreamHandler(), # Логирование в консоль + ], +) +logger = logging.getLogger(__name__) async def on_startup(): + """ + Основная процедура для запуска работы с БД чреез SQLAlchemy. + """ async with engine.begin() as conn: # await conn.run_sync(Base.metadata.drop_all) # Сброс БД await conn.run_sync(Base.metadata.create_all) + async def main(): - bot = Bot(token=os.getenv("BOT_TOKEN")) + """ + Функция запуска бота, подключение к TG_API, создание диспетчера, подключение роутеров и запуск бота в режиме пуллинг. + """ + bot = Bot(token=os.getenv("BOT_TOKEN")) # type: ignore dp = Dispatcher(storage=MemoryStorage()) + logger.info("Запуск работы бота.") dp.include_routers( - user.router, - admin.router, - admin_adv.router, - adv_callbacks.router + user.router, admin.router, admin_adv.router, adv_callbacks.router ) await on_startup() - await dp.start_polling(bot) + await dp.start_polling(bot) # Бот в пуллинг режиме - "почтальон для API" + if __name__ == "__main__": asyncio.run(main()) - diff --git a/requirements.txt b/requirements.txt index c702118..8a97097 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ aiogram~=3.20.0 -dotenv~=0.9.9 python-dotenv~=1.1.0 sqlalchemy~=2.0.40 asyncpg~=0.30.0