Repository: whatarefuck/CtfClubBot
Pull request #21: Feature/ctfbot 2:Написать периодическую таску для обновления жизней студентов до 3х
Author: login: DarkMK69
Created: 2025-04-09T08:06:02Z | Merged: 2025-04-11T11:39:15Z



Diff:
diff --git a/bot/database/user_dao.py b/bot/database/user_dao.py
index 57dfdd9..fa90566 100644
--- a/bot/database/user_dao.py
+++ b/bot/database/user_dao.py
@@ -35,6 +35,19 @@ def get_all_students(self) -> list[User]:
             self.session.query(User).filter(User.tg_id.notin_(config.teacher_ids)).all()
         )
 
+    def get_all_active_students(self):
+        return (
+            self.session.query(User)
+            .filter(User.username.isnot(None), User.lives > 0)
+            .all()
+        )
+
+    def get_user_id_by_username(self, username: str):
+        user = self.session.query(User).filter(User.username == username).first()
+        if user:
+            return user.id
+        return None
+
     def get_user_by_tg_id(self, tg_id: int) -> User:
         """Получить пользователя по его телеграм ID.
 
diff --git a/bot/main.py b/bot/main.py
index 7a15d3c..ac19f3f 100644
--- a/bot/main.py
+++ b/bot/main.py
@@ -2,6 +2,10 @@
 import logging
 import sentry_sdk
 
+from tasks import restore_student_lives
+from apscheduler.schedulers.asyncio import AsyncIOScheduler
+from apscheduler.triggers.cron import CronTrigger
+from pytz import timezone
 
 from aiogram import Bot, Dispatcher, types
 
@@ -62,9 +66,29 @@
 
 
 async def main():
+
+    scheduler = AsyncIOScheduler()
+    # Добавляем периодическую задачу восстановления жизней
+    # Выполняется каждое 10-е число месяца в 00:00 по МСК (UTC+3)
+    scheduler.add_job(
+        restore_student_lives,
+        trigger=CronTrigger(
+            day=10,  # Каждый день
+            hour=0,  # Полночь
+            minute=0,
+            timezone=timezone("Europe/Moscow"),
+        ),
+        id="restore_lives",
+        name="Восстановление жизней студентов",
+        replace_existing=True,
+    )
+
+    # Запускаем планировщик
+    scheduler.start()
+    await bot.set_my_commands(commands)
     # Запускаем задачу синхронизации задач
     asyncio.create_task(sync_education_tasks(bot))  # Фоновая задача
-    await bot.set_my_commands(commands)
+
     await dp.start_polling(bot)
 
 
diff --git a/bot/settings.py b/bot/settings.py
index 4b4c3c2..3791c6b 100644
--- a/bot/settings.py
+++ b/bot/settings.py
@@ -8,7 +8,7 @@
 
 class Config(BaseSettings):
     BOT_TOKEN: str = (
-        "8121070643:AAHfGqB0JoE9Pe8MwTCN5jGppY71ZMrFsvQ"  # your tg bot token from botfather
+        "7769863706:AAGu3kX2xPohshlaD7A8-0Sa0O7UgmLYb1M"  # your tg bot token from botfather
     )
     DATABASE_URL: str = "postgresql://ctf:ctf@localhost:5432/ctf"
     ADMIN_NICKNAMES: str = "tgadminnick1,tgadminnick2"
diff --git a/bot/tasks.py b/bot/tasks.py
index 5b838e7..cc781fb 100644
--- a/bot/tasks.py
+++ b/bot/tasks.py
@@ -8,6 +8,7 @@
 
 from utils.root_me import get_solved_tasks_of_student
 
+
 logger = getLogger()
 
 
@@ -43,5 +44,30 @@ async def sync_education_tasks(bot: Bot):
         await asyncio.sleep(0.1)
 
 
+async def restore_student_lives():
+    """Восстановление жизней всех активных студентов до 3-х."""
+    try:
+        with get_db() as session:
+            dao = UserDAO(session)
+            # Получаем всех "живых" пользователей (HP > 0)
+            active_users = dao.get_all_active_students()
+
+            count = 0
+
+            for user in active_users:
+                if user.lives < 3:  # Восстанавливаем только если меньше максимума
+                    user.lives = 3
+                    logger.info(f"Здоровье {user.username} = 3")
+                    count += 1
+
+            if count > 0:
+                session.commit()
+                logger.info(f"Восстановлены жизни для {count} студентов.")
+            else:
+                logger.info("Нет студентов, нуждающихся в восстановлении жизней.")
+    except Exception as e:
+        logger.error(f"Ошибка при восстановлении жизней: {e}")
+
+
 if __name__ == "__main__":
     asyncio.run(sync_education_tasks())
diff --git a/bot/utils/notifications.py b/bot/utils/notifications.py
index dfb30be..151bc18 100644
--- a/bot/utils/notifications.py
+++ b/bot/utils/notifications.py
@@ -56,9 +56,7 @@ async def _say_student(self, student: User, message: str):
         """Написать студенту о чем-то."""
         try:
             await self.bot.send_message(chat_id=student.tg_id, text=message)
-            logger.info(
-                f"Sent {message} to {student.full_name} - @{student.username}"
-            )
+            logger.info(f"Sent {message} to {student.full_name} - @{student.username}")
         except TelegramBadRequest:
             logger.warning(
                 f"Чат @{student.username} - {student.full_name} с не найден."
diff --git a/requirements.txt b/requirements.txt
index 304cce0..e24f6de 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,6 +5,7 @@ aiohttp==3.10.11
 aiosignal==1.3.1
 alembic==1.14.0
 annotated-types==0.7.0
+APScheduler==3.10.4
 attrs==24.2.0
 beautifulsoup4==4.12.3
 black==25.1.0
@@ -44,3 +45,4 @@ SQLAlchemy==2.0.36
 typing_extensions==4.12.2
 urllib3==2.3.0
 yarl==1.18.0
+pytz==2024.2
\ No newline at end of file


Reviews:
user: login: whatarefuck
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-11T10:49:22Z
user: login: whatarefuck
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-11T10:59:20Z
user: login: whatarefuck
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-11T11:01:50Z
user: login: whatarefuck
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-11T11:02:29Z
user: login: whatarefuck
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-11T11:37:54Z

Review comments:
diff_hunk: @@ -2,6 +2,10 @@
 import logging
 import sentry_sdk
 
+from tasks import restore_student_lives
+from apscheduler.schedulers.asyncio import AsyncIOScheduler
+from apscheduler.triggers.cron import CronTrigger
+from pytz import timezone
path: bot/main.py
user: login: whatarefuck
body: обнови requirements.txt - добавь apscheduler и pytz пожалуйста
created_at: 2025-04-11T10:49:22Z
author_association: OWNER
diff_hunk: @@ -43,5 +44,29 @@ async def sync_education_tasks(bot: Bot):
         await asyncio.sleep(0.1)
 
 
+async def restore_student_lives():
+    """Восстановление жизней всех активных студентов до 3-х."""
+    try:
+        with get_db() as session:
+            dao = UserDAO(session)
+            # Получаем всех "живых" пользователей (HP > 0)
+            active_users = dao.get_all_active_students()
path: bot/tasks.py
user: login: whatarefuck
body: добавь сюда еще логи, плиз
created_at: 2025-04-11T10:59:20Z
author_association: OWNER
diff_hunk: @@ -43,5 +44,29 @@ async def sync_education_tasks(bot: Bot):
         await asyncio.sleep(0.1)
 
 
+async def restore_student_lives():
+    """Восстановление жизней всех активных студентов до 3-х."""
+    try:
+        with get_db() as session:
+            dao = UserDAO(session)
+            # Получаем всех "живых" пользователей (HP > 0)
+            active_users = dao.get_all_active_students()
path: bot/tasks.py
user: login: whatarefuck
body: ![Снимок экрана 2025-04-11 в 13 54 25](https://github.com/user-attachments/assets/110511e8-08db-43f2-9cf2-8f35eac4ce87)
у меня почему-то не находит пользователей... Попробуй у себя запустить и приложи логи, пожалуйста
created_at: 2025-04-11T11:01:50Z
author_association: OWNER
diff_hunk: @@ -35,6 +35,19 @@ def get_all_students(self) -> list[User]:
             self.session.query(User).filter(User.tg_id.notin_(config.teacher_ids)).all()
         )
 
+    def get_all_active_students(self):
+        return (
+            self.session.query(User)
+            .filter(User.username.notin_(ADMIN_NICKNAMES), User.lives > 0)
+            .all()
+        )
+
+    def get_user_id_by_username(self, username: str):
+        user = self.session.query(User).filter(User.username == username).first()
path: bot/database/user_dao.py
user: login: whatarefuck
body: давай для админов тоже будем восстанавливать жизни, убери фильтр, пожалуйста
created_at: 2025-04-11T11:02:28Z
author_association: OWNER
diff_hunk: @@ -35,6 +35,19 @@ def get_all_students(self) -> list[User]:
             self.session.query(User).filter(User.tg_id.notin_(config.teacher_ids)).all()
         )
 
+    def get_all_active_students(self):
+        return (
+            self.session.query(User)
+            .filter(User.username.isnot(None), User.lives > 0)
path: bot/database/user_dao.py
user: login: whatarefuck
body: аппрув
created_at: 2025-04-11T11:37:29Z
author_association: OWNER

PR comments:
user: login: linear[bot]
created_at: 2025-04-09T08:06:04Z
body: <p><a href="https://linear.app/breaking-good/issue/CTFBOT-2/napisat-periodicheskuyu-tasku-dlya-obnovleniya-zhiznej-studentov-do-3h">CTFBOT-2 Написать периодическую таску для обновления жизней студентов до 3х</a></p>
author_association: NONE
user: login: DarkMK69
created_at: 2025-04-11T11:22:32Z
body: 
![image](https://github.com/user-attachments/assets/c8f30315-cec8-4bd5-8db2-27f858ef7a7d)


author_association: COLLABORATOR