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