From 97977d96d6ac6daa63b0a64cf49232a45115689f Mon Sep 17 00:00:00 2001 From: DarkMK69 Date: Fri, 11 Apr 2025 19:03:33 +0300 Subject: [PATCH 01/12] =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20=D0=BF?= =?UTF-8?q?=D0=BE=D1=81=D1=87=D0=B5=D1=82=D0=B0=20=D0=B1=D0=B0=D0=BB=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot/database/task_dao.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bot/database/task_dao.py b/bot/database/task_dao.py index eda55ad..a22f36b 100644 --- a/bot/database/task_dao.py +++ b/bot/database/task_dao.py @@ -73,3 +73,9 @@ def missed_user_tasks(self, user: User): ) .all() ) + + def score_for_tasks(S_min, N, N_total, time): + + R_time = min(time, 0.35) + score = max(S_min, 500 * (1- N / N_total) * (1 + R_time)) + return(score) From 78e252bb4dcff8cb97d96221d91f36d40c68bb56 Mon Sep 17 00:00:00 2001 From: DarkMK69 Date: Fri, 11 Apr 2025 19:03:47 +0300 Subject: [PATCH 02/12] =?UTF-8?q?=D0=B2=D1=8B=D0=B7=D0=BE=D0=B2=20=D0=B8?= =?UTF-8?q?=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot/tasks.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/bot/tasks.py b/bot/tasks.py index cc781fb..4d45ec0 100644 --- a/bot/tasks.py +++ b/bot/tasks.py @@ -5,6 +5,7 @@ from utils.notifications import Notifications from database.db import get_db from database.user_dao import UserDAO +from database.task_dao import TaskDao from utils.root_me import get_solved_tasks_of_student @@ -17,6 +18,8 @@ async def sync_education_tasks(bot: Bot): with get_db() as session: # Fetch all users with their tasks dao = UserDAO(session) + task_dao = TaskDao(session) + notify = Notifications(bot) users = dao.get_all_students_with_tasks() for user in users: if user.root_me_nickname: @@ -26,6 +29,17 @@ async def sync_education_tasks(bot: Bot): ) for task in user.tasks: task.completed = task.name in solved_tasks + if task.completed: + score = task_dao.score_for_tasks(50 , decided_users(), all_users(), index_of_time()) + user.points += score + student_message = ( + f" Молодец, ты решил задачу {task.name} и получил {score} очков" + ) + admin_log = f" {user.username} - {user.full_name} решил задачу{task.name} и получил {score} очков " + logger.info(admin_log) + await notify._say_teachers(admin_log) + await notify._say_student(student_message) + if not task.completed and task.is_expired: user.lives -= 1 user.violations += 1 @@ -33,8 +47,9 @@ async def sync_education_tasks(bot: Bot): f"Задача {task.name} истек у студента {user}." ) logger.info(teacher_message) - notify = Notifications(bot) + await notify.say_about_deadline_fail(teacher_message) + session.commit() logger.info(f"Synced tasks for user: {user.username}") From 67722f56d519d64f09bdd8a9cf4e37229db7f3e5 Mon Sep 17 00:00:00 2001 From: DarkMK69 Date: Sat, 3 May 2025 15:10:29 +0300 Subject: [PATCH 03/12] =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot/database/task_dao.py | 51 ++++++++++++++++++++++++++++++++++++---- bot/tasks.py | 16 +++++++++---- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/bot/database/task_dao.py b/bot/database/task_dao.py index a22f36b..c9f67e9 100644 --- a/bot/database/task_dao.py +++ b/bot/database/task_dao.py @@ -73,9 +73,52 @@ def missed_user_tasks(self, user: User): ) .all() ) - - def score_for_tasks(S_min, N, N_total, time): + + def score_for_tasks(self, S_min: int, N: int, N_total: int, time: float): R_time = min(time, 0.35) - score = max(S_min, 500 * (1- N / N_total) * (1 + R_time)) - return(score) + score = max(S_min, 500 * (1 - N / N_total) * (1 + R_time)) + return (score) + + def decided_users(self, task_name: str): + completed_tasks = self.session.query(Task).filter( + Task.name == task_name, + Task.completed == True + ).all() + user_ids = {task.assigned_user_id for task in completed_tasks} + + + return len(user_ids) + + def all_users(self, task_name: str): + tasks = self.session.query(Task).filter( + Task.name == task_name, + + ).all() + user_ids = {task.assigned_user_id for task in tasks} + + return len(user_ids) + + def index_of_time(self, task_name: str, assigned_user_id: int): + task = self.session.query(Task).filter( + Task.name == task_name, + Task.assigned_user_id == assigned_user_id, + Task.completed == True + ).first() + + if task is None or task.deadline is None: + return 0 # Задача не найдена или у задачи нет дедлайна + + time_taken = datetime.now() - task.deadline + time_until_deadline = task.deadline - datetime.now() # отрицательное, если просрочено + + # Абсолютные значения времени в секундах + time_taken_sec = abs(time_taken.total_seconds()) + time_until_deadline_sec = abs(time_until_deadline.total_seconds()) + + if time_taken_sec == 0: + return None # избегаем деления на ноль + + ratio = round(time_until_deadline_sec / time_taken_sec, 2) + + return ratio diff --git a/bot/tasks.py b/bot/tasks.py index 4d45ec0..54ebabf 100644 --- a/bot/tasks.py +++ b/bot/tasks.py @@ -29,8 +29,17 @@ async def sync_education_tasks(bot: Bot): ) for task in user.tasks: task.completed = task.name in solved_tasks + if task.completed: - score = task_dao.score_for_tasks(50 , decided_users(), all_users(), index_of_time()) + s_min = 50 + print(task_dao.index_of_time(task.name, user.id)) + + score = task_dao.score_for_tasks( + s_min, + task_dao.decided_users(task.name), + + task_dao.all_users(task.name), + task_dao.index_of_time(task.name, user.id)) user.points += score student_message = ( f" Молодец, ты решил задачу {task.name} и получил {score} очков" @@ -38,7 +47,7 @@ async def sync_education_tasks(bot: Bot): admin_log = f" {user.username} - {user.full_name} решил задачу{task.name} и получил {score} очков " logger.info(admin_log) await notify._say_teachers(admin_log) - await notify._say_student(student_message) + await notify._say_student(user.username, student_message) if not task.completed and task.is_expired: user.lives -= 1 @@ -47,9 +56,8 @@ async def sync_education_tasks(bot: Bot): f"Задача {task.name} истек у студента {user}." ) logger.info(teacher_message) - + await notify.say_about_deadline_fail(teacher_message) - session.commit() logger.info(f"Synced tasks for user: {user.username}") From ea489fa4467d0c910bd58da1dfecdb71ba28ce68 Mon Sep 17 00:00:00 2001 From: DarkMK69 Date: Sun, 4 May 2025 12:57:21 +0300 Subject: [PATCH 04/12] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D1=8B=D0=B5=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot/database/task_dao.py | 64 ++++++++++++++++++++++++-------------- bot/settings.py | 3 +- bot/tasks.py | 19 +++++------ bot/utils/notifications.py | 2 +- 4 files changed, 51 insertions(+), 37 deletions(-) diff --git a/bot/database/task_dao.py b/bot/database/task_dao.py index c9f67e9..1a9fea2 100644 --- a/bot/database/task_dao.py +++ b/bot/database/task_dao.py @@ -74,43 +74,46 @@ def missed_user_tasks(self, user: User): .all() ) - def score_for_tasks(self, S_min: int, N: int, N_total: int, time: float): - - R_time = min(time, 0.35) - score = max(S_min, 500 * (1 - N / N_total) * (1 + R_time)) - return (score) - def decided_users(self, task_name: str): - completed_tasks = self.session.query(Task).filter( - Task.name == task_name, - Task.completed == True - ).all() + completed_tasks = ( + self.session.query(Task) + .filter(Task.name == task_name, Task.completed == True) + .all() + ) user_ids = {task.assigned_user_id for task in completed_tasks} - return len(user_ids) def all_users(self, task_name: str): - tasks = self.session.query(Task).filter( - Task.name == task_name, - - ).all() + tasks = ( + self.session.query(Task) + .filter( + Task.name == task_name, + ) + .all() + ) user_ids = {task.assigned_user_id for task in tasks} - + return len(user_ids) def index_of_time(self, task_name: str, assigned_user_id: int): - task = self.session.query(Task).filter( - Task.name == task_name, - Task.assigned_user_id == assigned_user_id, - Task.completed == True - ).first() + task = ( + self.session.query(Task) + .filter( + Task.name == task_name, + Task.assigned_user_id == assigned_user_id, + Task.completed == True, + ) + .first() + ) if task is None or task.deadline is None: return 0 # Задача не найдена или у задачи нет дедлайна time_taken = datetime.now() - task.deadline - time_until_deadline = task.deadline - datetime.now() # отрицательное, если просрочено + time_until_deadline = ( + task.deadline - datetime.now() + ) # отрицательное, если просрочено # Абсолютные значения времени в секундах time_taken_sec = abs(time_taken.total_seconds()) @@ -120,5 +123,20 @@ def index_of_time(self, task_name: str, assigned_user_id: int): return None # избегаем деления на ноль ratio = round(time_until_deadline_sec / time_taken_sec, 2) - + return ratio + + def score_for_tasks(self, task_name: str, user_id: int): + from settings import Config + + S_min = Config.s_min + N = self.decided_users(task_name) + N_total = self.all_users(task_name) + time_index = self.index_of_time(task_name, user_id) + + if time_index is None: + return S_min # если задача не выполнена или нет дедлайна + + R_time = min(time_index, 0.35) + score = max(S_min, 500 * (1 - N / N_total) * (1 + R_time)) + return score diff --git a/bot/settings.py b/bot/settings.py index 3791c6b..da2f6cf 100644 --- a/bot/settings.py +++ b/bot/settings.py @@ -8,7 +8,7 @@ class Config(BaseSettings): BOT_TOKEN: str = ( - "7769863706:AAGu3kX2xPohshlaD7A8-0Sa0O7UgmLYb1M" # your tg bot token from botfather + "7664854738:AAGMUTXm2uT7eUR4O8tl7lLs145f7Fv5KoM" # your tg bot token from botfather ) DATABASE_URL: str = "postgresql://ctf:ctf@localhost:5432/ctf" ADMIN_NICKNAMES: str = "tgadminnick1,tgadminnick2" @@ -19,6 +19,7 @@ class Config(BaseSettings): ENV: str = "dev" minimum_xp_count_to_heal: int = 10 _teacher_ids: list[int] = "393200400,704339275" + s_min = 50 @property def teacher_ids(self): diff --git a/bot/tasks.py b/bot/tasks.py index 54ebabf..6a1dadb 100644 --- a/bot/tasks.py +++ b/bot/tasks.py @@ -29,25 +29,20 @@ async def sync_education_tasks(bot: Bot): ) for task in user.tasks: task.completed = task.name in solved_tasks - + if task.completed: - s_min = 50 - print(task_dao.index_of_time(task.name, user.id)) + from settings import Config + + notify = Notifications(bot) - score = task_dao.score_for_tasks( - s_min, - task_dao.decided_users(task.name), + score = task_dao.score_for_tasks(task.name, user.id) - task_dao.all_users(task.name), - task_dao.index_of_time(task.name, user.id)) user.points += score - student_message = ( - f" Молодец, ты решил задачу {task.name} и получил {score} очков" - ) + student_message = f" Молодец, ты решил задачу {task.name} и получил {score} очков" admin_log = f" {user.username} - {user.full_name} решил задачу{task.name} и получил {score} очков " logger.info(admin_log) await notify._say_teachers(admin_log) - await notify._say_student(user.username, student_message) + await notify._say_student(user, student_message) if not task.completed and task.is_expired: user.lives -= 1 diff --git a/bot/utils/notifications.py b/bot/utils/notifications.py index 151bc18..a01080c 100644 --- a/bot/utils/notifications.py +++ b/bot/utils/notifications.py @@ -55,7 +55,7 @@ async def _say_teachers(self, message: str): async def _say_student(self, student: User, message: str): """Написать студенту о чем-то.""" try: - await self.bot.send_message(chat_id=student.tg_id, text=message) + await self.bot.send_message(text=message, chat_id=student.tg_id) logger.info(f"Sent {message} to {student.full_name} - @{student.username}") except TelegramBadRequest: logger.warning( From d22b7015b92bb16b480d616653453313d8889880 Mon Sep 17 00:00:00 2001 From: DarkMK69 Date: Thu, 29 May 2025 14:37:23 +0300 Subject: [PATCH 05/12] fixed problems with Flake --- .flake8 | 2 ++ bot/tasks.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index a0135fb..639ca0c 100644 --- a/.flake8 +++ b/.flake8 @@ -94,6 +94,8 @@ ignore = E712 ; Line too long (133 > 120 characters) E501 + ;the function is too complex + C901 per-file-ignores = ; all tests diff --git a/bot/tasks.py b/bot/tasks.py index 6a1dadb..7744b8e 100644 --- a/bot/tasks.py +++ b/bot/tasks.py @@ -31,7 +31,6 @@ async def sync_education_tasks(bot: Bot): task.completed = task.name in solved_tasks if task.completed: - from settings import Config notify = Notifications(bot) From 2bb0f096df8311b86516b5932e524547ebaa1be6 Mon Sep 17 00:00:00 2001 From: DarkMK69 <98832409+DarkMK69@users.noreply.github.com> Date: Mon, 2 Jun 2025 00:03:36 +0300 Subject: [PATCH 06/12] Update settings.py --- bot/settings.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bot/settings.py b/bot/settings.py index d76de50..39a7298 100644 --- a/bot/settings.py +++ b/bot/settings.py @@ -24,8 +24,7 @@ class Config(BaseSettings): s_min = 50 HEAL_LIMIT: int = 3 - - + @property def teacher_ids(self): return self._teacher_ids.split(",") @@ -34,7 +33,6 @@ class Config: env_file = ENV_PATH extra = "allow" # Разрешить дополнительные параметры - # Instantiate the config config = Config() From 4f5eda6c01805ae2fb5afac8dd85ee96e51bb956 Mon Sep 17 00:00:00 2001 From: DarkMK69 <98832409+DarkMK69@users.noreply.github.com> Date: Mon, 2 Jun 2025 00:06:08 +0300 Subject: [PATCH 07/12] Update settings.py --- bot/settings.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bot/settings.py b/bot/settings.py index 39a7298..b49e2c5 100644 --- a/bot/settings.py +++ b/bot/settings.py @@ -8,9 +8,7 @@ class Config(BaseSettings): BOT_TOKEN: str = ( - "7664854738:AAGMUTXm2uT7eUR4O8tl7lLs145f7Fv5KoM" # your tg bot token from botfather - ) DATABASE_URL: str = "postgresql://ctf:ctf@localhost:5432/ctf" ADMIN_NICKNAMES: str = "tgadminnick1,tgadminnick2" @@ -24,7 +22,7 @@ class Config(BaseSettings): s_min = 50 HEAL_LIMIT: int = 3 - + @property def teacher_ids(self): return self._teacher_ids.split(",") @@ -33,6 +31,7 @@ class Config: env_file = ENV_PATH extra = "allow" # Разрешить дополнительные параметры + # Instantiate the config config = Config() From ce7295abc6f89e92ae8867180c54667c7da4aea8 Mon Sep 17 00:00:00 2001 From: DarkMK69 <98832409+DarkMK69@users.noreply.github.com> Date: Mon, 2 Jun 2025 00:06:42 +0300 Subject: [PATCH 08/12] Update tasks.py --- bot/tasks.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bot/tasks.py b/bot/tasks.py index 331825a..32d724f 100644 --- a/bot/tasks.py +++ b/bot/tasks.py @@ -44,12 +44,17 @@ async def sync_education_tasks(bot: Bot): await notify._say_teachers(admin_log) await notify._say_student(user, student_message) - - if not task.completed and task.is_expired and not task.violation_recorded: + if ( + not task.completed + and task.is_expired + and not task.violation_recorded + ): user.lives -= 1 user.violations += 1 - task.violation_recorded = True # Отмечаем, что нарушение обработано + task.violation_recorded = ( + True # Отмечаем, что нарушение обработано + ) teacher_message = ( f"Задача {task.name} истека у студента {user}." ) From 9f0c3b5f1ca6f4f22a73e345444be37df9549cc2 Mon Sep 17 00:00:00 2001 From: DarkMK69 <98832409+DarkMK69@users.noreply.github.com> Date: Mon, 2 Jun 2025 00:08:33 +0300 Subject: [PATCH 09/12] Update tasks.py --- bot/tasks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bot/tasks.py b/bot/tasks.py index 32d724f..39b2c90 100644 --- a/bot/tasks.py +++ b/bot/tasks.py @@ -31,7 +31,6 @@ async def sync_education_tasks(bot: Bot): task.completed = task.name in solved_tasks if task.completed: - from settings import Config notify = Notifications(bot) From aad27283933f785c87adfe91293113da63c1ddd4 Mon Sep 17 00:00:00 2001 From: DarkMK69 <98832409+DarkMK69@users.noreply.github.com> Date: Mon, 2 Jun 2025 00:15:16 +0300 Subject: [PATCH 10/12] Update tasks.py --- bot/tasks.py | 117 +++++++++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 54 deletions(-) diff --git a/bot/tasks.py b/bot/tasks.py index 39b2c90..d593eac 100644 --- a/bot/tasks.py +++ b/bot/tasks.py @@ -16,63 +16,72 @@ async def sync_education_tasks(bot: Bot): while True: with get_db() as session: - # Fetch all users with their tasks - dao = UserDAO(session) - task_dao = TaskDao(session) - notify = Notifications(bot) - users = dao.get_all_students_with_tasks() - for user in users: - if user.root_me_nickname: - # try: - solved_tasks = await get_solved_tasks_of_student( - user.root_me_nickname - ) - for task in user.tasks: - task.completed = task.name in solved_tasks - - if task.completed: - - notify = Notifications(bot) - - score = task_dao.score_for_tasks(task.name, user.id) - - user.points += score - student_message = f" Молодец, ты решил задачу {task.name} и получил {score} очков" - admin_log = f" {user.username} - {user.full_name} решил задачу{task.name} и получил {score} очков " - logger.info(admin_log) - await notify._say_teachers(admin_log) - await notify._say_student(user, student_message) - - if ( - not task.completed - and task.is_expired - and not task.violation_recorded - ): - - user.lives -= 1 - user.violations += 1 - task.violation_recorded = ( - True # Отмечаем, что нарушение обработано - ) - teacher_message = ( - f"Задача {task.name} истека у студента {user}." - ) - logger.info(teacher_message) - - await notify.say_about_deadline_fail(teacher_message) - student_message = f"Ты потерял 1 HP за задачу {task.name}. 😢 Пожалуйста, старайся выполнять задания вовремя, чтобы избежать потерь.\ - Если у тебя есть вопросы или трудности, не стесняйся обращаться за помощью в общий чат." - logger.info(student_message) - await notify._say_student(user, student_message) - - session.commit() - logger.info(f"Synced tasks for user: {user.username}") - # except Exception as e: - # logger.error(f"Error syncing tasks for {user.username}: {e.}") - await asyncio.sleep(60) + await process_all_users_tasks(bot, session) await asyncio.sleep(0.1) +async def process_all_users_tasks(bot: Bot, session): + dao = UserDAO(session) + users = dao.get_all_students_with_tasks() + for user in users: + if user.root_me_nickname: + await process_user_tasks(bot, session, user) + logger.info(f"Synced tasks for user: {user.username}") + await asyncio.sleep(60) + + +async def process_user_tasks(bot: Bot, session, user): + task_dao = TaskDao(session) + notify = Notifications(bot) + + try: + solved_tasks = await get_solved_tasks_of_student(user.root_me_nickname) + for task in user.tasks: + await process_single_task(task_dao, notify, user, task, solved_tasks) + session.commit() + except Exception as e: + logger.error(f"Error syncing tasks for {user.username}: {e}") + + +async def process_single_task(task_dao, notify, user, task, solved_tasks): + task.completed = task.name in solved_tasks + + if task.completed: + await handle_completed_task(task_dao, notify, user, task) + elif not task.completed and task.is_expired and not task.violation_recorded: + await handle_expired_task(notify, user, task) + + +async def handle_completed_task(task_dao, notify, user, task): + score = task_dao.score_for_tasks(task.name, user.id) + user.points += score + + student_message = f"Молодец, ты решил задачу {task.name} и получил {score} очков" + admin_log = f"{user.username} - {user.full_name} решил задачу {task.name} и получил {score} очков" + + logger.info(admin_log) + await notify._say_teachers(admin_log) + await notify._say_student(user, student_message) + + +async def handle_expired_task(notify, user, task): + user.lives -= 1 + user.violations += 1 + task.violation_recorded = True + + teacher_message = f"Задача {task.name} истека у студента {user}." + logger.info(teacher_message) + + await notify.say_about_deadline_fail(teacher_message) + + student_message = ( + f"Ты потерял 1 HP за задачу {task.name}. 😢 Пожалуйста, старайся выполнять задания вовремя, " + "чтобы избежать потерь. Если у тебя есть вопросы или трудности, " + "не стесняйся обращаться за помощью в общий чат." + ) + logger.info(student_message) + await notify._say_student(user, student_message) + async def restore_student_lives(): """Восстановление жизней всех активных студентов до 3-х.""" try: From 3f18696c2930e709b63600c9cc3ba435f947d7b4 Mon Sep 17 00:00:00 2001 From: DarkMK69 <98832409+DarkMK69@users.noreply.github.com> Date: Mon, 2 Jun 2025 00:16:32 +0300 Subject: [PATCH 11/12] Update tasks.py --- bot/tasks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/tasks.py b/bot/tasks.py index d593eac..ab7d9d7 100644 --- a/bot/tasks.py +++ b/bot/tasks.py @@ -82,6 +82,7 @@ async def handle_expired_task(notify, user, task): logger.info(student_message) await notify._say_student(user, student_message) + async def restore_student_lives(): """Восстановление жизней всех активных студентов до 3-х.""" try: From 3e40cf7af6c3b4f5e945c44a910e229f8c437357 Mon Sep 17 00:00:00 2001 From: DarkMK69 Date: Mon, 2 Jun 2025 14:11:50 +0300 Subject: [PATCH 12/12] =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot/database/user_dao.py | 27 +++++---------------------- bot/handlers/leaderboard.py | 8 ++++---- bot/main.py | 1 + bot/settings.py | 2 +- bot/tasks.py | 6 ++++-- 5 files changed, 15 insertions(+), 29 deletions(-) diff --git a/bot/database/user_dao.py b/bot/database/user_dao.py index 85991fe..ef791f6 100644 --- a/bot/database/user_dao.py +++ b/bot/database/user_dao.py @@ -32,9 +32,7 @@ def create_user( def get_all_students(self) -> List[User]: """Получить всех студентов (исключая учителей по tg_id).""" return ( - self.session.query(User) - .filter(User.tg_id.notin_(config.teacher_ids)) - .all() + self.session.query(User).filter(User.tg_id.notin_(config.teacher_ids)).all() ) def get_all_active_students(self) -> List[User]: @@ -47,20 +45,12 @@ def get_all_active_students(self) -> List[User]: def get_user_id_by_username(self, username: str) -> Optional[int]: """Вернуть внутренний ID пользователя по username или None.""" - user = ( - self.session.query(User) - .filter(User.username == username) - .first() - ) + user = self.session.query(User).filter(User.username == username).first() return user.id if user else None def get_user_by_tg_id(self, tg_id: int) -> Optional[User]: """Получить пользователя по его Telegram ID.""" - return ( - self.session.query(User) - .filter(User.tg_id == tg_id) - .first() - ) + return self.session.query(User).filter(User.tg_id == tg_id).first() def get_all_students_with_tasks(self) -> List[User]: """Получить всех студентов вместе с их невыполненными заданиями.""" @@ -85,18 +75,11 @@ def heal(self, user: User) -> None: def get_teachers(self) -> List[User]: """Получить всех учителей (старшекурсников) по tg_id.""" teachers = ( - self.session.query(User) - .filter(User.tg_id.in_(config.teacher_ids)) - .all() + self.session.query(User).filter(User.tg_id.in_(config.teacher_ids)).all() ) logger.info(f"Получены учителя: {teachers}") return teachers def leaderboard(self, limit: int = 20) -> List[User]: """Извлечь топ-`limit` пользователей, сортируя по убыванию points.""" - return ( - self.session.query(User) - .order_by(User.points.desc()) - .limit(limit) - .all() - ) + return self.session.query(User).order_by(User.points.desc()).limit(limit).all() diff --git a/bot/handlers/leaderboard.py b/bot/handlers/leaderboard.py index 5dc3a12..f2d945b 100644 --- a/bot/handlers/leaderboard.py +++ b/bot/handlers/leaderboard.py @@ -32,13 +32,13 @@ def format_user_status(user: User, top_rating: list[User]) -> list[str]: messages.append(f"🎉 Вы на {rank}-м месте в топ-20!") else: if user.points == 0: - messages.append("😔 У вас пока нет баллов. Решайте задачи, чтобы попасть в топ!") + messages.append( + "😔 У вас пока нет баллов. Решайте задачи, чтобы попасть в топ!" + ) else: last_top_score = top_rating[-1].points if top_rating else 0 needed = last_top_score - user.points + 1 - messages.append( - f"👉 Чтобы войти в топ-20, нужно ещё {needed} балл(ов)." - ) + messages.append(f"👉 Чтобы войти в топ-20, нужно ещё {needed} балл(ов).") return messages diff --git a/bot/main.py b/bot/main.py index 440f4be..ac19f3f 100644 --- a/bot/main.py +++ b/bot/main.py @@ -91,5 +91,6 @@ async def main(): await dp.start_polling(bot) + if __name__ == "__main__": asyncio.run(main()) diff --git a/bot/settings.py b/bot/settings.py index b49e2c5..27adc1e 100644 --- a/bot/settings.py +++ b/bot/settings.py @@ -20,7 +20,7 @@ class Config(BaseSettings): minimum_xp_count_to_heal: int = 10 _teacher_ids: list[int] = "393200400,704339275" - s_min = 50 + s_min: int = 50 HEAL_LIMIT: int = 3 @property diff --git a/bot/tasks.py b/bot/tasks.py index 7087f8b..ab7d9d7 100644 --- a/bot/tasks.py +++ b/bot/tasks.py @@ -46,8 +46,10 @@ async def process_user_tasks(bot: Bot, session, user): async def process_single_task(task_dao, notify, user, task, solved_tasks): task.completed = task.name in solved_tasks - if task.completed: - from settings import Config + if task.completed: + await handle_completed_task(task_dao, notify, user, task) + elif not task.completed and task.is_expired and not task.violation_recorded: + await handle_expired_task(notify, user, task) async def handle_completed_task(task_dao, notify, user, task):