From cb4300c801be22d55f53cde3fd8d153edb6e93c6 Mon Sep 17 00:00:00 2001 From: krosh Date: Thu, 20 Feb 2025 12:32:57 +0300 Subject: [PATCH] some upd --- Dockerfile | 5 ++ app/db.py | 32 ++++++-- app/install.sh | 25 ++++--- app/schedules.py | 22 ++++-- app/upload_sql.py | 178 +++++++++++++++++--------------------------- docker-compose.yaml | 10 ++- 6 files changed, 138 insertions(+), 134 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1aaecdf..944b942 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,8 @@ FROM python:3.9-slim +RUN apt-get update && apt-get install -y cron +# RUN apt-get install -y cron + WORKDIR /app COPY requirements.txt requirements.txt @@ -7,4 +10,6 @@ RUN pip install -r requirements.txt COPY ./app . +RUN chmod +x install.sh + CMD ["./install.sh"] \ No newline at end of file diff --git a/app/db.py b/app/db.py index 6bf992f..89d4ca2 100644 --- a/app/db.py +++ b/app/db.py @@ -1,11 +1,12 @@ #!/usr/bin/python3.3 -import json, yaml, schedule +import schedule import schedules as bot from datetime import datetime import os from dotenv import load_dotenv from sshtunnel import SSHTunnelForwarder from psycopg2 import pool +from typing import Optional, Dict allow_update = True @@ -107,11 +108,12 @@ def parse_lesson(lesson: dict[str, str]) -> str: if lesson["lector"]: if "/" not in lesson["lector"]: text = "{}-{} | {}\ - \n{}\ + \n{}{}\ \n{}".format( start, end, lesson["room"], + "🎓 " if lesson["is_lecture"] else "", lesson["course"], lesson["lector"], ) @@ -119,7 +121,8 @@ def parse_lesson(lesson: dict[str, str]) -> str: lectors = lesson["lector"].split("/") text = "{}-{} | {}\ \n{}\ - \n{} / {}".format( + \n{}\ + \n{}".format( start, end, lesson["room"].replace("/", ", "), @@ -129,12 +132,15 @@ def parse_lesson(lesson: dict[str, str]) -> str: ) else: text = "{}-{}\ - \n{}".format( + \n{}{}".format( start, end, + "🎓 " if lesson["is_lecture"] else "", lesson["course"], ) + # text += f"\n{lesson['info']}" + return text @@ -148,6 +154,12 @@ def create_schedule_tasks(manual=False): allow_update = True schedule.clear() + + def run_script(): + os.system("python3 -u upload_sql.py") + + schedule.every(6).minutes.do(run_script) + conn = db.getconn() cursor = conn.cursor() cursor.execute("SELECT * FROM users") @@ -155,7 +167,7 @@ def create_schedule_tasks(manual=False): users = into_list(data, cursor.description) for user in users: - if user["allow_message"] != "yes": + if not user["allow_message"]: continue group = user["group"] if group == "other": @@ -179,7 +191,7 @@ def create_schedule_tasks(manual=False): thread_id = user["thread"] - delta = "00:" + user["timeout"] + delta = "00:" + str(user["timeout"]) format = "%H:%M" start_task = datetime.strptime(start, format) - datetime.strptime( delta, format @@ -243,7 +255,7 @@ def students_in_group(group) -> list[str]: return students -def return_infos(id) -> dict[str, str] | None: +def return_infos(id) -> Optional[Dict[str, str]]: conn = db.getconn() cursor = conn.cursor() cursor.execute("SELECT * FROM users WHERE id = %s", (id,)) @@ -259,6 +271,12 @@ def pause_bot(): if allow_update: schedule.clear() + + def run_script(): + os.system("python3 -u upload_sql.py") + + schedule.every(6).minutes.do(run_script) + allow_update = False bot.send_admin_message("Бот больше не отправляет расписание") else: diff --git a/app/install.sh b/app/install.sh index 19e9eed..2c8a694 100644 --- a/app/install.sh +++ b/app/install.sh @@ -1,19 +1,22 @@ #!/bin/bash # List of environment variables to check -env_vars=("TG_ADMIN_ID" "TG_API_TOKEN" "DB_HOST" "DB_PORT" "DB_USER" "DB_PASSWORD" "DB_NAME" "TABLE_ID") +# env_vars=("TG_ADMIN_ID" "TG_API_TOKEN" "DB_HOST" "DB_PORT" "DB_USER" "DB_PASSWORD" "DB_NAME" "TABLE_ID") -for var in "${env_vars[@]}"; do - if [ -z "${!var}" ]; then - echo "Environment variable $var is not set or is empty." - exit 1 - # else - # echo "Environment variable $var is set to '${!var}'." - fi -done +# for var in "${env_vars[@]}"; do +# if [ -z "${!var}" ]; then +# echo "Environment variable $var is not set or is empty." +# exit 1 +# # else +# # echo "Environment variable $var is set to '${!var}'." +# fi +# done # Add cron jobs to crontab -(crontab -l 2>/dev/null; echo "0 * * * * python3 /app/upload_sql.py") | crontab - +# (crontab -l 2>/dev/null; echo "0 * * * * python3 /app/upload_sql.py") | crontab - +# (crontab -l 2>/dev/null; echo "*/14 * * * * python3 /app/upload_sql.py") | crontab - + + # Start the schedules.py script -python3 -u /app/schedules.py & +python3 -u /app/schedules.py diff --git a/app/schedules.py b/app/schedules.py index ffec3e0..299eb06 100644 --- a/app/schedules.py +++ b/app/schedules.py @@ -10,7 +10,14 @@ from dotenv import load_dotenv load_dotenv() -bot = telebot.TeleBot(os.environ.get("TG_TEST_TOKEN"), parse_mode=ParseMode.HTML) +bot = telebot.TeleBot( + ( + os.environ.get("TG_TEST_TOKEN") + if os.environ.get("ENV") == "dev" + else os.environ.get("TG_API_TOKEN") + ), + parse_mode=ParseMode.HTML, +) PARITY_FIRST = 0 @@ -476,15 +483,15 @@ def send_info(message): def pause_schedule(message): infos = db.return_infos(message.chat.id)["allow_message"] - if infos == "yes": - db.change_user_param(str(message.chat.id), "allow_message", "no") + if infos == True: + db.change_user_param(str(message.chat.id), "allow_message", False) send_message( message.chat.id, "Рассылка сообщений прекращена. \ \nДля возобновления воспользуйтесь командой\n/pause", ) else: - db.change_user_param(str(message.chat.id), "allow_message", "yes") + db.change_user_param(str(message.chat.id), "allow_message", True) send_message(message.chat.id, "Рассылка сообщений возоблена!") return @@ -614,7 +621,7 @@ def send_message(id, text, thread_id="General", parity=None): thread_id = None if parity and parity != "-": - parity = int(parity) + parity = 0 if parity == "чёт" else 1 if parity == "нечёт" else None count_of_weeks = (datetime.now() - datetime(2024, 2, 5)).days // 7 is_odd = (count_of_weeks + 1) % 2 == PARITY_FIRST @@ -674,6 +681,11 @@ if __name__ == "__main__": target=bot.infinity_polling, name="bot_infinity_polling", daemon=True ).start() + def run_script(): + os.system("python3 -u upload_sql.py") + + schedule.every(6).minutes.do(run_script) + while True: try: schedule.run_pending() diff --git a/app/upload_sql.py b/app/upload_sql.py index 8da1562..0983603 100644 --- a/app/upload_sql.py +++ b/app/upload_sql.py @@ -5,69 +5,13 @@ from dotenv import load_dotenv from google.oauth2 import service_account from sshtunnel import SSHTunnelForwarder from psycopg2 import pool +from datetime import datetime load_dotenv() +bot = telebot.TeleBot(os.environ.get("TG_TEST_TOKEN")) -""" -CREATE TABLE IF NOT EXISTS schedule( - id BIGSERIAL PRIMARY KEY, - day_of_week VARCHAR(255), - begin_time VARCHAR(20), - end_time VARCHAR(20), - course VARCHAR(255), - lector VARCHAR(255), - is_lecture BOOLEAN DEFAULT FALSE, - room VARCHAR(20), - group VARCHAR(10), - parity VARCHAR(10), -); -""" - -""" -День недели Время начала Название Чётность пары Лекция? Преподаватель Кабинет 2-ой преподаватель Прочие кабинеты Остальная информация -Понедельник 8:45 Английский язык - FALSE Бим Мария Моисеевна 735 Шубина Юлия Витальевна 790 -Понедельник 10:30 Практикум на ЭВМ - FALSE Тюляева Вера Викторовна МЗ-4 -Понедельник 12:15 Действительный и комплексный анализ - TRUE Крицков Леонид Владимирович П-12 -Понедельник 15:00 Физическая культура - FALSE -Понедельник 16:20 FALSE -Вторник 8:45 Теория вероятностей и математическая статистика - TRUE Королёв Виктор Юрьевич П-13 -Вторник 10:30 Обыкновенные дифференциальные уравнения - FALSE Дмитриева Ирина Владимировна 607 -Вторник 12:15 Действительный и комплексный анализ - FALSE Сычугов Дмитрий Юрьевич 613 -Вторник 14:35 Электродинамика - FALSE Аксенов Владимир Николаевич 659 -Вторник 16:20 - FALSE -Среда 8:45 Практикум на ЭВМ - FALSE Тюляева Вера Викторовна 505 -Среда 10:30 Теория вероятностей и математическая статистика - FALSE Ирина Геннадьевна Шевцова 645 -Среда 12:15 Обыкновенные дифференциальные уравнения - TRUE Денисов Александр Михайлович П-13 -Среда 15:00 FALSE -Среда 16:20 FALSE -Четверг 9:00 FALSE -Четверг 10:30 FALSE -Четверг 12:15 FALSE -Четверг 15:00 FALSE -Четверг 16:20 FALSE -Пятница 9:00 FALSE -Пятница 10:30 FALSE -Пятница 12:15 FALSE -Пятница 15:00 FALSE -Пятница 16:20 FALSE -Суббота 9:00 FALSE -Суббота 10:30 FALSE -Суббота 12:15 FALSE -Суббота 15:00 FALSE -Суббота 16:20 FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE - FALSE -""" - -SERVICE_ACCOUNT_FILE = "app/credentials.json" +SERVICE_ACCOUNT_FILE = "credentials.json" credentials = service_account.Credentials.from_service_account_file( SERVICE_ACCOUNT_FILE, @@ -81,10 +25,6 @@ gc = gspread.authorize(credentials) table = gc.open_by_key(os.environ.get("TABLE_ID")) -ws = table.worksheets() - -bot = telebot.TeleBot(os.environ.get("TG_TEST_TOKEN")) - if os.environ.get("ENV") == "dev": print("DEV: Connecting to local database") server = SSHTunnelForwarder( @@ -113,52 +53,72 @@ db = pool.SimpleConnectionPool( ) -for i in ws: - print(i.title) +def f(): + ws = table.worksheets() - if not (i.title == "Пример" or i.title == "main") and i.title.isdigit(): - df = pd.DataFrame(i.get_all_records()) - if not df.empty: - with db.getconn() as conn: - with conn.cursor() as cursor: - cursor.execute( - 'DELETE FROM schedule WHERE "group" = %s', (str(i.title),) - ) - conn.commit() - for index, row in df.iterrows(): - day_of_week_map = { - "Понедельник": "mon", - "Вторник": "tue", - "Среда": "wed", - "Четверг": "thu", - "Пятница": "fri", - "Суббота": "sat", - "Воскресенье": "sun", - } - row["День недели"] = day_of_week_map.get( - row["День недели"], row["День недели"] - ) - if row["Название"] == "": - continue - end_time = ( - pd.to_datetime(row["Время начала"], format="%H:%M") - + pd.Timedelta(hours=1, minutes=35) - ).strftime("%H:%M") + for i in ws: + # print(i.title) + + if not (i.title == "Пример" or i.title == "main") and i.title.isdigit(): + df = pd.DataFrame(i.get_all_records()) + if not df.empty: + with db.getconn() as conn: + with conn.cursor() as cursor: cursor.execute( - """ - INSERT INTO schedule (day_of_week, begin_time, end_time, course, lector, is_lecture, room, "group", parity) - VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) - """, - ( - row["День недели"], - row["Время начала"], - end_time, - row["Название"], - f'{row["Преподаватель"]}{"/" + str(row["2-ой преподаватель"]) if row["2-ой преподаватель"] else ""}', - row["Лекция?"], - f'{row["Кабинет"]}{"/" + str(row["Прочие кабинеты"]) if row["Прочие кабинеты"] else ""}', - i.title, - row["Чётность пары"], - ), + 'DELETE FROM schedule WHERE "group" = %s', (str(i.title),) ) - conn.commit() + conn.commit() + for index, row in df.iterrows(): + day_of_week_map = { + "Понедельник": "mon", + "Вторник": "tue", + "Среда": "wed", + "Четверг": "thu", + "Пятница": "fri", + "Суббота": "sat", + "Воскресенье": "sun", + } + row["День недели"] = day_of_week_map.get( + row["День недели"], row["День недели"] + ) + if row["Название"] == "": + continue + end_time = ( + pd.to_datetime(row["Время начала"], format="%H:%M") + + pd.Timedelta(hours=1, minutes=35) + ).strftime("%H:%M") + cursor.execute( + """ + INSERT INTO schedule (day_of_week, begin_time, end_time, course, lector, is_lecture, room, "group", parity) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) + """, + ( + row["День недели"], + row["Время начала"], + end_time, + row["Название"], + f'{row["Преподаватель"]}{"/" + str(row["2-ой преподаватель"]) if row["2-ой преподаватель"] else ""}', + row["Лекция?"], + f'{row["Кабинет"]}{"/" + str(row["Прочие кабинеты"]) if row["Прочие кабинеты"] else ""}', + i.title, + row["Чётность пары"], + ), + ) + conn.commit() + + text = f"Last tg-bot update was at: {datetime.now().astimezone().strftime('%Y-%m-%d %H:%M %Z')}" + table.get_worksheet(0).update_acell("A25", text) + + return + + +if __name__ == "__main__": + try: + f() + except Exception as e: + print(e) + + bot.send_message(int(os.environ.get("ADMIN_ID")), "Check logs! upload error.") + bot.send_message(int(os.environ.get("ADMIN_ID")), e) + + exit(0) diff --git a/docker-compose.yaml b/docker-compose.yaml index 9b006b5..ba1e769 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -6,15 +6,21 @@ services: container_name: schedule_bot environment: - ENV=production + - TZ=Europe/Moscow restart: unless-stopped networks: - postgres_postgres + volumes: + - "/etc/timezone:/etc/timezone:ro" + - "/etc/localtime:/etc/localtime:ro" deploy: resources: limits: cpus: '0.3' - memory: 200M + memory: 300M # Set a hard memory limit + reservations: + memory: 200M # Reserve a soft memory limit networks: postgres_postgres: - external: true \ No newline at end of file + external: true