This commit is contained in:
2025-02-20 12:32:57 +03:00
parent c22085eeb3
commit cb4300c801
6 changed files with 138 additions and 134 deletions
+5
View File
@@ -1,5 +1,8 @@
FROM python:3.9-slim FROM python:3.9-slim
RUN apt-get update && apt-get install -y cron
# RUN apt-get install -y cron
WORKDIR /app WORKDIR /app
COPY requirements.txt requirements.txt COPY requirements.txt requirements.txt
@@ -7,4 +10,6 @@ RUN pip install -r requirements.txt
COPY ./app . COPY ./app .
RUN chmod +x install.sh
CMD ["./install.sh"] CMD ["./install.sh"]
+25 -7
View File
@@ -1,11 +1,12 @@
#!/usr/bin/python3.3 #!/usr/bin/python3.3
import json, yaml, schedule import schedule
import schedules as bot import schedules as bot
from datetime import datetime from datetime import datetime
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
from sshtunnel import SSHTunnelForwarder from sshtunnel import SSHTunnelForwarder
from psycopg2 import pool from psycopg2 import pool
from typing import Optional, Dict
allow_update = True allow_update = True
@@ -107,11 +108,12 @@ def parse_lesson(lesson: dict[str, str]) -> str:
if lesson["lector"]: if lesson["lector"]:
if "/" not in lesson["lector"]: if "/" not in lesson["lector"]:
text = "{}-{} | {}\ text = "{}-{} | {}\
\n<b>{}</b>\ \n{}<b>{}</b>\
\n<i>{}</i>".format( \n<i>{}</i>".format(
start, start,
end, end,
lesson["room"], lesson["room"],
"🎓 " if lesson["is_lecture"] else "",
lesson["course"], lesson["course"],
lesson["lector"], lesson["lector"],
) )
@@ -119,7 +121,8 @@ def parse_lesson(lesson: dict[str, str]) -> str:
lectors = lesson["lector"].split("/") lectors = lesson["lector"].split("/")
text = "{}-{} | {}\ text = "{}-{} | {}\
\n<b>{}</b>\ \n<b>{}</b>\
\n<i>{}</i> / <i>{}</i>".format( \n<i>{}</i>\
\n<i>{}</i>".format(
start, start,
end, end,
lesson["room"].replace("/", ", "), lesson["room"].replace("/", ", "),
@@ -129,12 +132,15 @@ def parse_lesson(lesson: dict[str, str]) -> str:
) )
else: else:
text = "{}-{}\ text = "{}-{}\
\n<b>{}</b>".format( \n{}<b>{}</b>".format(
start, start,
end, end,
"🎓 " if lesson["is_lecture"] else "",
lesson["course"], lesson["course"],
) )
# text += f"\n{lesson['info']}"
return text return text
@@ -148,6 +154,12 @@ def create_schedule_tasks(manual=False):
allow_update = True allow_update = True
schedule.clear() schedule.clear()
def run_script():
os.system("python3 -u upload_sql.py")
schedule.every(6).minutes.do(run_script)
conn = db.getconn() conn = db.getconn()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute("SELECT * FROM users") cursor.execute("SELECT * FROM users")
@@ -155,7 +167,7 @@ def create_schedule_tasks(manual=False):
users = into_list(data, cursor.description) users = into_list(data, cursor.description)
for user in users: for user in users:
if user["allow_message"] != "yes": if not user["allow_message"]:
continue continue
group = user["group"] group = user["group"]
if group == "other": if group == "other":
@@ -179,7 +191,7 @@ def create_schedule_tasks(manual=False):
thread_id = user["thread"] thread_id = user["thread"]
delta = "00:" + user["timeout"] delta = "00:" + str(user["timeout"])
format = "%H:%M" format = "%H:%M"
start_task = datetime.strptime(start, format) - datetime.strptime( start_task = datetime.strptime(start, format) - datetime.strptime(
delta, format delta, format
@@ -243,7 +255,7 @@ def students_in_group(group) -> list[str]:
return students return students
def return_infos(id) -> dict[str, str] | None: def return_infos(id) -> Optional[Dict[str, str]]:
conn = db.getconn() conn = db.getconn()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE id = %s", (id,)) cursor.execute("SELECT * FROM users WHERE id = %s", (id,))
@@ -259,6 +271,12 @@ def pause_bot():
if allow_update: if allow_update:
schedule.clear() schedule.clear()
def run_script():
os.system("python3 -u upload_sql.py")
schedule.every(6).minutes.do(run_script)
allow_update = False allow_update = False
bot.send_admin_message("Бот больше не отправляет расписание") bot.send_admin_message("Бот больше не отправляет расписание")
else: else:
+14 -11
View File
@@ -1,19 +1,22 @@
#!/bin/bash #!/bin/bash
# List of environment variables to check # 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 # for var in "${env_vars[@]}"; do
if [ -z "${!var}" ]; then # if [ -z "${!var}" ]; then
echo "Environment variable $var is not set or is empty." # echo "Environment variable $var is not set or is empty."
exit 1 # exit 1
# else # # else
# echo "Environment variable $var is set to '${!var}'." # # echo "Environment variable $var is set to '${!var}'."
fi # fi
done # done
# Add cron jobs to crontab # 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 # Start the schedules.py script
python3 -u /app/schedules.py & python3 -u /app/schedules.py
+17 -5
View File
@@ -10,7 +10,14 @@ from dotenv import load_dotenv
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 PARITY_FIRST = 0
@@ -476,15 +483,15 @@ def send_info(message):
def pause_schedule(message): def pause_schedule(message):
infos = db.return_infos(message.chat.id)["allow_message"] infos = db.return_infos(message.chat.id)["allow_message"]
if infos == "yes": if infos == True:
db.change_user_param(str(message.chat.id), "allow_message", "no") db.change_user_param(str(message.chat.id), "allow_message", False)
send_message( send_message(
message.chat.id, message.chat.id,
"Рассылка сообщений прекращена. \ "Рассылка сообщений прекращена. \
\nДля возобновления воспользуйтесь командой\n/pause", \nДля возобновления воспользуйтесь командой\n/pause",
) )
else: 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, "Рассылка сообщений возоблена!") send_message(message.chat.id, "Рассылка сообщений возоблена!")
return return
@@ -614,7 +621,7 @@ def send_message(id, text, thread_id="General", parity=None):
thread_id = None thread_id = None
if parity and parity != "-": 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 count_of_weeks = (datetime.now() - datetime(2024, 2, 5)).days // 7
is_odd = (count_of_weeks + 1) % 2 == PARITY_FIRST 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 target=bot.infinity_polling, name="bot_infinity_polling", daemon=True
).start() ).start()
def run_script():
os.system("python3 -u upload_sql.py")
schedule.every(6).minutes.do(run_script)
while True: while True:
try: try:
schedule.run_pending() schedule.run_pending()
+69 -109
View File
@@ -5,69 +5,13 @@ from dotenv import load_dotenv
from google.oauth2 import service_account from google.oauth2 import service_account
from sshtunnel import SSHTunnelForwarder from sshtunnel import SSHTunnelForwarder
from psycopg2 import pool from psycopg2 import pool
from datetime import datetime
load_dotenv() load_dotenv()
bot = telebot.TeleBot(os.environ.get("TG_TEST_TOKEN"))
""" SERVICE_ACCOUNT_FILE = "credentials.json"
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"
credentials = service_account.Credentials.from_service_account_file( credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, SERVICE_ACCOUNT_FILE,
@@ -81,10 +25,6 @@ gc = gspread.authorize(credentials)
table = gc.open_by_key(os.environ.get("TABLE_ID")) 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": if os.environ.get("ENV") == "dev":
print("DEV: Connecting to local database") print("DEV: Connecting to local database")
server = SSHTunnelForwarder( server = SSHTunnelForwarder(
@@ -113,52 +53,72 @@ db = pool.SimpleConnectionPool(
) )
for i in ws: def f():
print(i.title) ws = table.worksheets()
if not (i.title == "Пример" or i.title == "main") and i.title.isdigit(): for i in ws:
df = pd.DataFrame(i.get_all_records()) # print(i.title)
if not df.empty:
with db.getconn() as conn: if not (i.title == "Пример" or i.title == "main") and i.title.isdigit():
with conn.cursor() as cursor: df = pd.DataFrame(i.get_all_records())
cursor.execute( if not df.empty:
'DELETE FROM schedule WHERE "group" = %s', (str(i.title),) with db.getconn() as conn:
) with conn.cursor() as cursor:
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( cursor.execute(
""" 'DELETE FROM schedule WHERE "group" = %s', (str(i.title),)
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() 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)
+8 -2
View File
@@ -6,15 +6,21 @@ services:
container_name: schedule_bot container_name: schedule_bot
environment: environment:
- ENV=production - ENV=production
- TZ=Europe/Moscow
restart: unless-stopped restart: unless-stopped
networks: networks:
- postgres_postgres - postgres_postgres
volumes:
- "/etc/timezone:/etc/timezone:ro"
- "/etc/localtime:/etc/localtime:ro"
deploy: deploy:
resources: resources:
limits: limits:
cpus: '0.3' cpus: '0.3'
memory: 200M memory: 300M # Set a hard memory limit
reservations:
memory: 200M # Reserve a soft memory limit
networks: networks:
postgres_postgres: postgres_postgres:
external: true external: true