From b9b6ec13c546ba538329477f92d1f1fe726554c1 Mon Sep 17 00:00:00 2001 From: kr0sh512 Date: Sat, 23 Dec 2023 20:02:42 +0300 Subject: [PATCH 01/10] add random function --- .gitignore | 1 + __pycache__/admin.cpython-311.pyc | Bin 0 -> 1753 bytes __pycache__/for_json.cpython-311.pyc | Bin 0 -> 14270 bytes __pycache__/schedules.cpython-311.pyc | Bin 0 -> 29270 bytes for_json.py | 55 +++++++++++++- json/logs.json | 6 ++ schedules.py | 99 +++++++++++++++++++++----- 7 files changed, 141 insertions(+), 20 deletions(-) create mode 100644 __pycache__/admin.cpython-311.pyc create mode 100644 __pycache__/for_json.cpython-311.pyc create mode 100644 __pycache__/schedules.cpython-311.pyc create mode 100644 json/logs.json diff --git a/.gitignore b/.gitignore index 71e586a..40b2a5e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ users.json schedule.json settings.json +json/students.json diff --git a/__pycache__/admin.cpython-311.pyc b/__pycache__/admin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e9dd4ecf9f02a0e6bb5615c4b2c1c475bc27c0b7 GIT binary patch literal 1753 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 ADgXcg literal 0 HcmV?d00001 diff --git a/__pycache__/schedules.cpython-311.pyc b/__pycache__/schedules.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..afed869a8f2bddad432c3bb27450d79ef505247b GIT binary patch literal 29270 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: @{}\ + \ngroup: {}\ + \nid: {}\ + \nname: {}".format(data[infos["id"]]["username"], + data[infos["id"]]["group"], + infos["id"], + data[infos["id"]]["first_name"] + data[infos["id"]]["last_name"])) + return def change_user_param(id, key, value): @@ -52,6 +70,11 @@ def change_user_param(id, key, value): with open(path_users, 'w', encoding='utf-8') as json_file: json.dump(data, json_file, ensure_ascii=False, indent=4) create_schedule_tasks() + bot.send_admin_message("Изменения:\ + \nuser: @{}\ + \nid: {}\ + \nkey: {}\ + \nvalue: {}".format(data[id]["username"], id, key, value)) return def parse_lesson(time, lesson): @@ -149,6 +172,28 @@ def groups_in_json(): return schdl.keys() +def students_in_json(id="", key=""): + id = str(id) + + group = {} + with open(path_users, 'r', encoding='utf-8') as json_file: + group = json.load(json_file) + group = group[id]["group"] + + stud = {} + with open(path_students, 'r', encoding='utf-8') as json_file: + stud = json.load(json_file) + stud = stud.get(group) + + if stud == None: + return None + + if key == "": + return list(stud.keys()) + + return stud[key] + + def return_infos(id): id = str(id) data = {} @@ -159,9 +204,15 @@ def return_infos(id): return data def pause_bot(): - schedule.clear() global allow_update - allow_update = False + if allow_update: + schedule.clear() + allow_update = False + bot.send_admin_message('Бот больше не отправляет расписание') + else: + create_schedule_tasks(True) + allow_update = True + bot.send_admin_message('Бот возобновил рассылку!') return diff --git a/json/logs.json b/json/logs.json new file mode 100644 index 0000000..56bc9fa --- /dev/null +++ b/json/logs.json @@ -0,0 +1,6 @@ +{ + "time": { + "func": "", + "params": "" + } +} \ No newline at end of file diff --git a/schedules.py b/schedules.py index c77a709..2a19ef0 100644 --- a/schedules.py +++ b/schedules.py @@ -1,5 +1,5 @@ #!/usr/bin/python3.3 -import threading, telebot, schedule, time +import threading, telebot, schedule, time, random from datetime import datetime import os, sys from telebot import types @@ -7,15 +7,27 @@ from telegram.constants import ParseMode import for_json from admin import admin_command, is_admin, send_admin_message, send_admin_document -bot = telebot.TeleBot("TOKEN_API") +# bot = telebot.TeleBot("TOKEN_API") +bot = telebot.TeleBot("6240513112:AAFccyClvWsSNtVsZgNWAKFaNTs2-0y__pw") +# bot = telebot.TeleBot("6355753103:AAFPzya37HNjBEKnv83fqWbyXX6Bhe52DR4") +# def log(func): +# def wrapper(*args, **kwargs): +# message = args[0] + +# for_json.add_log(message) +# func(*args, **kwargs) +# return + +# return wrapper @bot.message_handler(commands=['help', 'faq']) def help(message): help_msg = 'Мои команды:\ \n/start - используй, чтобы сменить номер группы.\ \n/schedule - используй, чтобы получить расписание на сегодня.\ + \n/random - сделай очередь из людей\ \n/info - используй, чтобы узнать твои настройки бота\ \n/pause - используй, чтобы прекратить получать сообщения от бота\ \n/thread - используй в нужном чате канала, чтобы бот отправлял сообщения именно туда\ @@ -40,19 +52,19 @@ def help(message): ### --//-- -@bot.message_handler(commands=['test']) -@admin_command -def update_schedules(message): - text = 'Жирный текст\ - \nКурсивный текст\ - \nПеречёркнутый текст\ - \nСсылка\ - \nМоноширинный текст\ - \n
Форматированный с сохранением     пробелов
\ - \n
Цитата
' - send_admin_message(text) +# @bot.message_handler(commands=['test']) +# @admin_command +# def update_schedules(message): +# text = 'Жирный текст\ +# \nКурсивный текст\ +# \nПеречёркнутый текст\ +# \nСсылка\ +# \nМоноширинный текст\ +# \n
Форматированный с сохранением     пробелов
\ +# \n
Цитата
' +# send_admin_message(text) - return +# return @bot.message_handler(commands=['restart']) @admin_command @@ -75,6 +87,8 @@ def send_json(message): send_admin_document(json_file) with open(for_json.path_schedule, 'rb') as json_file: send_admin_document(json_file) + with open(for_json.path_students, 'rb') as json_file: + send_admin_document(json_file) return @@ -84,8 +98,7 @@ def send_json(message): @admin_command def pause_bot(message): for_json.pause_bot() - send_admin_message('Бот больше не отправляет расписание') - + return @bot.message_handler(commands=['stop']) @@ -145,12 +158,13 @@ def start(message): markup = types.InlineKeyboardMarkup() for i in for_json.groups_in_json(): markup.add(types.InlineKeyboardButton(text=i, callback_data=i)) + markup.add(types.InlineKeyboardButton(text="Моей группы нет в этом списке", callback_data="other")) bot.send_message(message.chat.id, 'Пожалуйста, выбери свою группу', parse_mode=ParseMode.HTML, reply_markup=markup) return -@bot.callback_query_handler(func=lambda call: not(call.data in ['left', 'right'])) +@bot.callback_query_handler(func=lambda call: call.data in for_json.groups_in_json() or call.data == "other") def callback_inline(call): infos = [ call.from_user.id, @@ -221,6 +235,55 @@ def change_schedule(call): +@bot.message_handler(commands=['random']) +def random_people(message): + list_of_num = ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6", "7", "8", "9"] + + list_of_var = for_json.students_in_json(message.chat.id) + + text = 'Для вашей группы эта команда не настроена.\n\nНапиши запрос через /request' + + if list_of_var == None: + send_message(message.chat.id, text) + send_admin_message('Запрос на random команду от {}'.format( + for_json.return_infos(message.chat.id)["group"])) + + return + + text = '• Выбери как именно мне перемешать вас:\n' + + l = [] + for i, val in enumerate(list_of_var): + text += '\n{} {}'.format(list_of_num[i], val) + l.append(types.InlineKeyboardButton(text=list_of_num[i], callback_data=val)) + + l = [l] + + markup = types.InlineKeyboardMarkup(l) + bot.send_message(message.chat.id, text, ParseMode.HTML, reply_markup=markup) + + return + +@bot.callback_query_handler(func=lambda call: not(call.data in ['left', 'right'] + or call.data in for_json.groups_in_json() or call.data == "other")) +def make_random(call): + list_of_stud = for_json.students_in_json(call.message.chat.id, call.data) + + random.shuffle(list_of_stud) + + text = '{}:\n\n'.format(call.data) + + for i, name in enumerate(list_of_stud): + text += '{}{}. {}\n'.format(' ' if i + 1 < 10 else '', i + 1, name) + + bot.edit_message_text('Хорошо, вот ваше распределение!', call.message.chat.id, + call.message.message_id, parse_mode=ParseMode.HTML) + + send_message(call.message.chat.id, text) + + return + + @bot.message_handler(commands=['info']) def send_info(message): if len(message.text.split(' ')) == 2 and is_admin(message): @@ -393,7 +456,7 @@ def send_document(id, file, text = ''): if __name__ == '__main__': - for_json.create_schedule_tasks() + for_json.create_schedule_tasks(True) send_admin_message('Я перезапустился!') print("-------------------------") From 9e6f7eebdc7481b34c4c94b5568af4143a9b84b6 Mon Sep 17 00:00:00 2001 From: kr0sh512 Date: Tue, 12 Mar 2024 00:08:58 +0300 Subject: [PATCH 02/10] some updates --- .gitignore | 1 + __pycache__/admin.cpython-311.pyc | Bin 1753 -> 0 bytes __pycache__/for_json.cpython-311.pyc | Bin 14270 -> 0 bytes __pycache__/schedules.cpython-311.pyc | Bin 29270 -> 0 bytes admin.py | 2 +- for_json.py | 36 +++++-- json/users_expl.json | 4 +- schedules.py | 142 ++++++++++++++++++++++++-- 8 files changed, 161 insertions(+), 24 deletions(-) delete mode 100644 __pycache__/admin.cpython-311.pyc delete mode 100644 __pycache__/for_json.cpython-311.pyc delete mode 100644 __pycache__/schedules.cpython-311.pyc diff --git a/.gitignore b/.gitignore index 40b2a5e..9a143ba 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ users.json schedule.json settings.json json/students.json +json/schedule_2sem.json diff --git a/__pycache__/admin.cpython-311.pyc b/__pycache__/admin.cpython-311.pyc deleted file mode 100644 index e9dd4ecf9f02a0e6bb5615c4b2c1c475bc27c0b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1753 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 ADgXcg diff --git a/__pycache__/schedules.cpython-311.pyc b/__pycache__/schedules.cpython-311.pyc deleted file mode 100644 index afed869a8f2bddad432c3bb27450d79ef505247b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29270 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: @{}\ \ngroup: {}\ \nid: {}\ - \nname: {}".format(data[infos["id"]]["username"], + \nname: {} {}".format(data[infos["id"]]["username"], data[infos["id"]]["group"], infos["id"], - data[infos["id"]]["first_name"] + data[infos["id"]]["last_name"])) + data[infos["id"]]["first_name"], + data[infos["id"]]["last_name"])) return @@ -151,17 +152,17 @@ def create_schedule_tasks(manual=False): start_task = tmp[:-1] if day == 'mon': - schedule.every().monday.at(start_task).do(bot.send_message, id, text, thread_id) + schedule.every().monday.at(start_task).do(bot.send_message, id, text, thread_id, True) elif day == 'tue': - schedule.every().tuesday.at(start_task).do(bot.send_message, id, text, thread_id) + schedule.every().tuesday.at(start_task).do(bot.send_message, id, text, thread_id, True) elif day == 'wed': - schedule.every().wednesday.at(start_task).do(bot.send_message, id, text, thread_id) + schedule.every().wednesday.at(start_task).do(bot.send_message, id, text, thread_id, True) elif day == 'thu': - schedule.every().thursday.at(start_task).do(bot.send_message, id, text, thread_id) + schedule.every().thursday.at(start_task).do(bot.send_message, id, text, thread_id, True) elif day == 'fri': - schedule.every().friday.at(start_task).do(bot.send_message, id, text, thread_id) + schedule.every().friday.at(start_task).do(bot.send_message, id, text, thread_id, True) elif day == 'sat': - schedule.every().saturday.at(start_task).do(bot.send_message, id, text, thread_id) + schedule.every().saturday.at(start_task).do(bot.send_message, id, text, thread_id, True) return @@ -172,6 +173,21 @@ def groups_in_json(): return schdl.keys() +def students_in_group(group): + group = str(group) + + data = {} + with open(path_users, 'r', encoding='utf-8') as json_file: + data = json.load(json_file) + + students = [] + + for i in data.keys(): + if data[i]["group"] == group: + students.append(i) + + return students + def students_in_json(id="", key=""): id = str(id) @@ -199,7 +215,7 @@ def return_infos(id): data = {} with open(path_users, 'r', encoding='utf-8') as json_file: data = json.load(json_file) - data = data[id] + data = data.get(id) return data diff --git a/json/users_expl.json b/json/users_expl.json index 6957ce4..16f7c68 100644 --- a/json/users_expl.json +++ b/json/users_expl.json @@ -3,8 +3,8 @@ "username": "kr0sh_512", "first_name": "Дмитрий", "last_name": "", - "group": "102", - "timeout": "12", + "group": "117", + "timeout": "10", "allow_message": "yes", "thread": "General" } diff --git a/schedules.py b/schedules.py index 2a19ef0..c532d7c 100644 --- a/schedules.py +++ b/schedules.py @@ -8,8 +8,6 @@ import for_json from admin import admin_command, is_admin, send_admin_message, send_admin_document # bot = telebot.TeleBot("TOKEN_API") -bot = telebot.TeleBot("6240513112:AAFccyClvWsSNtVsZgNWAKFaNTs2-0y__pw") -# bot = telebot.TeleBot("6355753103:AAFPzya37HNjBEKnv83fqWbyXX6Bhe52DR4") # def log(func): # def wrapper(*args, **kwargs): @@ -42,8 +40,10 @@ def help(message): admin_help_msg = 'И команды только для админа:\ \n/restart - перезапуск бота.\ \n/update - обновление schedule задач\ + \n/stats - получание статистики\ \n/json - получить файл пользователей и расписания\ \n/info id_пользователя - узнать настройки пользователя\ + \n/spam - сделать рассылку\ \n/pause_all - приостановить бота для всех (каникулы/выходные)\ \n/stop id_пользователя - приостановить отправку сообщений для пользователя' send_admin_message(admin_help_msg) @@ -57,6 +57,7 @@ def help(message): # def update_schedules(message): # text = 'Жирный текст\ # \nКурсивный текст\ +# \nПодчёркнутый\ # \nПеречёркнутый текст\ # \nСсылка\ # \nМоноширинный текст\ @@ -79,7 +80,38 @@ def update_schedules(message): send_admin_message('Произошёл update') return - + +@bot.message_handler(commands=['stats']) +@admin_command +def send_stat(message): + text = "Статистика:\ + \n(группа: всего/откл. увед./беседы)" + + sum_users = 0 + sum_dis_not = 0 + sum_chats = 0 + + groups = list(for_json.groups_in_json()) + groups.append("other") + + for i in groups: + users = for_json.students_in_group(i) + sum_users += len(users) + + dis_not = len([i for i, x in enumerate(users) if for_json.return_infos(x)["allow_message"] == "no"]) + sum_dis_not += dis_not + + chats = len([i for i, x in enumerate(users) if x[0] == "-"]) + sum_chats += chats + + text += "\n{}: {} / {} / {}".format(i, len(users), dis_not, chats) + + text += "\n\nВсего: {} / {} / {}".format(sum_users, sum_dis_not, sum_chats) + + send_admin_message(text) + + return + @bot.message_handler(commands=['json']) @admin_command def send_json(message): @@ -94,6 +126,85 @@ def send_json(message): # info user_id +@bot.message_handler(commands=['spam']) +@admin_command +def spam(message): + send_admin_message("Пришли мне id, номер группы или all для рассылки сообщения этим пользователям") + + bot.register_next_step_handler(message, spam_msg) + + return + +def spam_msg(message): + if message.text == "stop" or message.text == "стоп" or message.text[0] == '/': + send_admin_message('Отмена отпраки') + return + + send_admin_message("Пришли мне текст для рассылки сообщения этим пользователям") + + bot.register_next_step_handler(message, spam_cnf, message.text) + + return + +def spam_cnf(message, data): + if message.text == "stop" or message.text == "стоп" or message.text[0] == '/': + send_admin_message('Отмена отпраки') + return + + text = "Пожалуйста, проверь итоговое сообщение и подтверди отправку:\ + \n\nКому: " + + if data == "all": + text += "всем" + elif data in for_json.groups_in_json(): + text += "{} группе".format(data) + elif for_json.return_infos(data) != None: + text += "пользователю @{}".format(for_json.return_infos(data)["username"]) + else: + send_admin_message("Ошибка при выборе пользователей") + return + + text +="\n\nСообщение: " + message.text + + markup = types.InlineKeyboardMarkup() + + markup.add(types.InlineKeyboardButton(text="✅", callback_data="spam#{}#{}".format(data, message.text)), + types.InlineKeyboardButton(text="❌", callback_data="spam_no")) + + bot.send_message(message.from_user.id, text, parse_mode=ParseMode.HTML, reply_markup=markup) + + return + +@bot.callback_query_handler(func=lambda call: "spam" in call.data) +def spam_send(call): + if call.data == "spam_no": + send_admin_message('Отмена отпраки') + return + + tmp, data, text = call.data.split("#") + + users = [] + + if data == "all": + groups = for_json.groups_in_json() + for group in groups: + users += for_json.students_in_group(group) + users += for_json.students_in_group("other") + elif data in for_json.groups_in_json(): + users = for_json.students_in_group(data) + elif for_json.return_infos(data) != None: + users = [data] + + for i in users: + send_message(i, text) + + bot.edit_message_text(chat_id=call.message.chat.id, + message_id=call.message.message_id, + text='Успешно!', + parse_mode=ParseMode.HTML) + + return + @bot.message_handler(commands=['pause_all']) @admin_command def pause_bot(message): @@ -255,7 +366,7 @@ def random_people(message): l = [] for i, val in enumerate(list_of_var): text += '\n{} {}'.format(list_of_num[i], val) - l.append(types.InlineKeyboardButton(text=list_of_num[i], callback_data=val)) + l.append(types.InlineKeyboardButton(text=list_of_num[i], callback_data="rand#" + val)) l = [l] @@ -264,14 +375,13 @@ def random_people(message): return -@bot.callback_query_handler(func=lambda call: not(call.data in ['left', 'right'] - or call.data in for_json.groups_in_json() or call.data == "other")) +@bot.callback_query_handler(func=lambda call: "rand#" in call.data) def make_random(call): - list_of_stud = for_json.students_in_json(call.message.chat.id, call.data) + list_of_stud = for_json.students_in_json(call.message.chat.id, call.data.split("#")[1]) random.shuffle(list_of_stud) - text = '{}:\n\n'.format(call.data) + text = '{}:\n\n'.format(call.data.split("#")[1]) for i, name in enumerate(list_of_stud): text += '{}{}. {}\n'.format(' ' if i + 1 < 10 else '', i + 1, name) @@ -413,7 +523,7 @@ def send_source(message): @bot.message_handler(content_types=['text']) def text_message(message): - if message.chat.type == "supergroup": + if message.chat.type == "supergroup" or is_admin(message): return send_message(message.from_user.id, 'К сожалению, я ещё не умею обрабатывать сообщения.\ \nИспользуй команды из меню или напиши /help.') @@ -422,10 +532,20 @@ def text_message(message): -def send_message(id, text, thread_id='General'): +def send_message(id, text, thread_id='General', distribution=False): if thread_id == 'General': thread_id = None + if distribution: + count_of_weeks = (datetime.now() - datetime(2024, 2, 5)).days // 7 + is_odd = (count_of_weeks + 1) % 2 == 1 + + if is_odd and ("чёт" in text) and ("нечёт" not in text): + return + + if (not is_odd) and ("нечёт" in text): + return + try: bot.send_message(chat_id=id, text=text, parse_mode=ParseMode.HTML, message_thread_id=thread_id,disable_web_page_preview=True) except Exception as e: @@ -433,7 +553,7 @@ def send_message(id, text, thread_id='General'): try: bot.send_message(chat_id=id, text=text, parse_mode=ParseMode.HTML, message_thread_id=thread_id,disable_web_page_preview=True) except Exception as e: - text_error = 'Error from user: {}\n{}'.format(id, str(e)) + text_error = 'Error from user: @{} {}\n{}'.format(for_json.return_infos(id)["username"], id, str(e)) send_admin_message(text_error) print(id, e) From 2cedfc52e6f02540b3539f2fa9fee096f54adc5b Mon Sep 17 00:00:00 2001 From: kr0sh512 Date: Wed, 8 May 2024 15:15:56 +0300 Subject: [PATCH 03/10] . --- schedules.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/schedules.py b/schedules.py index c532d7c..ea40f57 100644 --- a/schedules.py +++ b/schedules.py @@ -8,6 +8,8 @@ import for_json from admin import admin_command, is_admin, send_admin_message, send_admin_document # bot = telebot.TeleBot("TOKEN_API") +# bot = telebot.TeleBot("6240513112:AAHRoeL1g3WpMAeSPs3G7zwShKoYaSDxfYc") # krosh +bot = telebot.TeleBot("6355753103:AAGniZ7Wf5XyPkn3z753UJvn6afbhOlImjA") # sсhedule # def log(func): # def wrapper(*args, **kwargs): @@ -316,7 +318,7 @@ def send_schedule(message): markup = types.InlineKeyboardMarkup() markup.add(types.InlineKeyboardButton(text="◀️", callback_data="left"), types.InlineKeyboardButton(text="▶️", callback_data="right")) - bot.send_message(message.chat.id, text, ParseMode.HTML, reply_markup=markup) + bot.send_message(message.chat.id, text, ParseMode.HTML, reply_markup=markup, message_thread_id=message.message_thread_id) return @@ -504,7 +506,7 @@ def send_request(message): if type(infos[i]) == type(None): infos[i] = '' - admin_text = 'Сообщение от {} {} (@{}):\n\n{}\nid: {}'.format(infos[1], infos[2], infos[3], infos[4], infos[0]) + admin_text = 'Сообщение от {} {} (@{}):\n\n{}\nid: {}'.format(infos[1], infos[2], infos[3], infos[4], infos[0]) send_admin_message(admin_text) send_message(message.from_user.id, 'Ваше сообщение успешно доставлено!') @@ -589,5 +591,4 @@ if __name__ == '__main__': time.sleep(5) except Exception as e: print(e) - time.sleep(10) - \ No newline at end of file + time.sleep(10) \ No newline at end of file From 69edd06e8c3467fd18195bc73f1aec809c09b9e7 Mon Sep 17 00:00:00 2001 From: kr0sh512 Date: Wed, 8 May 2024 16:27:03 +0300 Subject: [PATCH 04/10] / --- schedules.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/schedules.py b/schedules.py index ea40f57..c13f83b 100644 --- a/schedules.py +++ b/schedules.py @@ -8,19 +8,6 @@ import for_json from admin import admin_command, is_admin, send_admin_message, send_admin_document # bot = telebot.TeleBot("TOKEN_API") -# bot = telebot.TeleBot("6240513112:AAHRoeL1g3WpMAeSPs3G7zwShKoYaSDxfYc") # krosh -bot = telebot.TeleBot("6355753103:AAGniZ7Wf5XyPkn3z753UJvn6afbhOlImjA") # sсhedule - -# def log(func): -# def wrapper(*args, **kwargs): -# message = args[0] - -# for_json.add_log(message) - -# func(*args, **kwargs) -# return - -# return wrapper @bot.message_handler(commands=['help', 'faq']) def help(message): From f31f670bd28856a6dfd585fe2c74667fd1c91f22 Mon Sep 17 00:00:00 2001 From: kr0sh512 Date: Wed, 8 May 2024 17:40:30 +0300 Subject: [PATCH 05/10] fix bugs --- for_json.py | 20 ++++++++++---------- schedules.py | 22 ++++++++++++++-------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/for_json.py b/for_json.py index ae442db..1ffa9fc 100644 --- a/for_json.py +++ b/for_json.py @@ -47,16 +47,16 @@ def save_user(infos): with open(path_users, 'w', encoding='utf-8') as json_file: json.dump(data, json_file, ensure_ascii=False, indent=4) - create_schedule_tasks() - bot.send_admin_message("Новый пользователь:\ - \nuser: @{}\ - \ngroup: {}\ - \nid: {}\ - \nname: {} {}".format(data[infos["id"]]["username"], - data[infos["id"]]["group"], - infos["id"], - data[infos["id"]]["first_name"], - data[infos["id"]]["last_name"])) + create_schedule_tasks(manual=True) + # bot.send_admin_message("Новый пользователь:\ + # \nuser: @{}\ + # \ngroup: {}\ + # \nid: {}\ + # \nname: {} {}".format(data[infos["id"]]["username"], + # data[infos["id"]]["group"], + # infos["id"], + # data[infos["id"]]["first_name"], + # data[infos["id"]]["last_name"])) return diff --git a/schedules.py b/schedules.py index c13f83b..bccc427 100644 --- a/schedules.py +++ b/schedules.py @@ -140,6 +140,9 @@ def spam_cnf(message, data): send_admin_message('Отмена отпраки') return + global text_spam + text_spam = message.text + text = "Пожалуйста, проверь итоговое сообщение и подтверди отправку:\ \n\nКому: " @@ -153,11 +156,11 @@ def spam_cnf(message, data): send_admin_message("Ошибка при выборе пользователей") return - text +="\n\nСообщение: " + message.text + text +="\n\nСообщение: {}".format(message.text) markup = types.InlineKeyboardMarkup() - markup.add(types.InlineKeyboardButton(text="✅", callback_data="spam#{}#{}".format(data, message.text)), + markup.add(types.InlineKeyboardButton(text="✅", callback_data="spam#{}".format(data)), types.InlineKeyboardButton(text="❌", callback_data="spam_no")) bot.send_message(message.from_user.id, text, parse_mode=ParseMode.HTML, reply_markup=markup) @@ -170,7 +173,10 @@ def spam_send(call): send_admin_message('Отмена отпраки') return - tmp, data, text = call.data.split("#") + tmp, data = call.data.split("#") + + global text_spam + text = text_spam users = [] @@ -203,7 +209,7 @@ def pause_bot(message): @bot.message_handler(commands=['stop']) @admin_command -def pause_bot(message): +def stop_msg(message): if len(str(message.text).split(' ')) != 2: send_admin_message('Эта команда вида /stop id_пользователя') return @@ -418,7 +424,7 @@ def pause_schedule(message): if infos == 'yes': for_json.change_user_param(str(message.chat.id), 'allow_message', 'no') - send_message(message.chat.id, 'Рассылка сообщений преращена. \ + send_message(message.chat.id, 'Рассылка сообщений прекращена. \ \nДля возобновления воспользуйтесь командой\n/pause') else: for_json.change_user_param(str(message.chat.id), 'allow_message', 'yes') @@ -448,7 +454,7 @@ def change_thread(message): @bot.message_handler(commands=['timeout']) def set_timeout(message): send_message(message.chat.id, 'Пришли мне число от 1 до 60. \ - \nЭто будет количество минут, за которое я буду присылать тебе напоминание о уроке (По умолчанию: 10)') + \nЭто будет количество минут, за которое я буду присылать тебе напоминание о паре (По умолчанию: 10)') bot.register_next_step_handler(message, save_timeout) return @@ -529,10 +535,10 @@ def send_message(id, text, thread_id='General', distribution=False): count_of_weeks = (datetime.now() - datetime(2024, 2, 5)).days // 7 is_odd = (count_of_weeks + 1) % 2 == 1 - if is_odd and ("чёт" in text) and ("нечёт" not in text): + if is_odd and ("(чёт)" in text): return - if (not is_odd) and ("нечёт" in text): + if (not is_odd) and ("(нечёт)" in text): return try: From 681c3eee64f23d75c8edc75dae4f0a3e2fc95281 Mon Sep 17 00:00:00 2001 From: kr0sh512 Date: Sat, 31 Aug 2024 21:55:33 +0300 Subject: [PATCH 06/10] formating code --- .gitignore | 2 +- schedules.py | 740 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 443 insertions(+), 299 deletions(-) diff --git a/.gitignore b/.gitignore index 9a143ba..cdced54 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ - users.json schedule.json settings.json json/students.json json/schedule_2sem.json +nohup.out diff --git a/schedules.py b/schedules.py index bccc427..2b5b600 100644 --- a/schedules.py +++ b/schedules.py @@ -7,11 +7,12 @@ from telegram.constants import ParseMode import for_json from admin import admin_command, is_admin, send_admin_message, send_admin_document -# bot = telebot.TeleBot("TOKEN_API") +bot = telebot.TeleBot("TOKEN_API") -@bot.message_handler(commands=['help', 'faq']) + +@bot.message_handler(commands=["help", "faq"]) def help(message): - help_msg = 'Мои команды:\ + help_msg = "Мои команды:\ \n/start - используй, чтобы сменить номер группы.\ \n/schedule - используй, чтобы получить расписание на сегодня.\ \n/random - сделай очередь из людей\ @@ -21,12 +22,12 @@ def help(message): \n/timeout - настрой время, когда бот будет присылать тебе сообщение\ \n/request - используй, чтобы отправить разработчику какой-то запрос\ \n/source - Страница бота на Github\ - \n\nИли же можно всегда написать напрямую: @Kr0sH_512' - + \n\nИли же можно всегда написать напрямую: @Kr0sH_512" + send_message(message.chat.id, help_msg) - + if is_admin(message): - admin_help_msg = 'И команды только для админа:\ + admin_help_msg = "И команды только для админа:\ \n/restart - перезапуск бота.\ \n/update - обновление schedule задач\ \n/stats - получание статистики\ @@ -34,118 +35,136 @@ def help(message): \n/info id_пользователя - узнать настройки пользователя\ \n/spam - сделать рассылку\ \n/pause_all - приостановить бота для всех (каникулы/выходные)\ - \n/stop id_пользователя - приостановить отправку сообщений для пользователя' + \n/stop id_пользователя - приостановить отправку сообщений для пользователя" send_admin_message(admin_help_msg) - + return + ### --//-- -# @bot.message_handler(commands=['test']) -# @admin_command -# def update_schedules(message): -# text = 'Жирный текст\ -# \nКурсивный текст\ -# \nПодчёркнутый\ -# \nПеречёркнутый текст\ -# \nСсылка\ -# \nМоноширинный текст\ -# \n
Форматированный с сохранением     пробелов
\ -# \n
Цитата
' -# send_admin_message(text) -# return - -@bot.message_handler(commands=['restart']) +@bot.message_handler(commands=["test", "t"]) @admin_command -def restart_bot(message): - send_admin_message('bye') - os.execv(sys.executable, ['python'] + sys.argv) - -@bot.message_handler(commands=['update']) -@admin_command -def update_schedules(message): - for_json.create_schedule_tasks(manual=True) - send_admin_message('Произошёл update') +def test(message): + text = 'Жирный текст\ + \nКурсивный текст\ + \nПодчёркнутый\ + \nПеречёркнутый текст\ + \nСсылка\ + \nМоноширинный текст\ + \n
Форматированный с сохранением     пробелов
\ + \n
Цитата
' + send_admin_message(text) return -@bot.message_handler(commands=['stats']) + +@bot.message_handler(commands=["restart", 'r']) +@admin_command +def restart_bot(message): + send_admin_message("bye") + os.execv(sys.executable, ["python"] + sys.argv) + + +@bot.message_handler(commands=["update"]) +@admin_command +def update_schedules(message): + for_json.create_schedule_tasks(manual=True) + send_admin_message("Произошёл update") + + return + + +@bot.message_handler(commands=["stats"]) @admin_command def send_stat(message): text = "Статистика:\ \n(группа: всего/откл. увед./беседы)" - + sum_users = 0 sum_dis_not = 0 sum_chats = 0 - + groups = list(for_json.groups_in_json()) groups.append("other") - + for i in groups: users = for_json.students_in_group(i) sum_users += len(users) - - dis_not = len([i for i, x in enumerate(users) if for_json.return_infos(x)["allow_message"] == "no"]) + + dis_not = len( + [ + i + for i, x in enumerate(users) + if for_json.return_infos(x)["allow_message"] == "no" + ] + ) sum_dis_not += dis_not - + chats = len([i for i, x in enumerate(users) if x[0] == "-"]) sum_chats += chats - + text += "\n{}: {} / {} / {}".format(i, len(users), dis_not, chats) - + text += "\n\nВсего: {} / {} / {}".format(sum_users, sum_dis_not, sum_chats) - + send_admin_message(text) - + return -@bot.message_handler(commands=['json']) + +@bot.message_handler(commands=["json"]) @admin_command def send_json(message): - with open(for_json.path_users, 'rb') as json_file: + with open(for_json.path_users, "rb") as json_file: send_admin_document(json_file) - with open(for_json.path_schedule, 'rb') as json_file: + with open(for_json.path_schedule, "rb") as json_file: send_admin_document(json_file) - with open(for_json.path_students, 'rb') as json_file: + with open(for_json.path_students, "rb") as json_file: send_admin_document(json_file) - + return + # info user_id -@bot.message_handler(commands=['spam']) + +@bot.message_handler(commands=["spam"]) @admin_command def spam(message): - send_admin_message("Пришли мне id, номер группы или all для рассылки сообщения этим пользователям") - + send_admin_message( + "Пришли мне id, номер группы или all для рассылки сообщения этим пользователям" + ) + bot.register_next_step_handler(message, spam_msg) - + return + def spam_msg(message): - if message.text == "stop" or message.text == "стоп" or message.text[0] == '/': - send_admin_message('Отмена отпраки') + if message.text == "stop" or message.text == "стоп" or message.text[0] == "/": + send_admin_message("Отмена отпраки") return - + send_admin_message("Пришли мне текст для рассылки сообщения этим пользователям") - + bot.register_next_step_handler(message, spam_cnf, message.text) - + return + def spam_cnf(message, data): - if message.text == "stop" or message.text == "стоп" or message.text[0] == '/': - send_admin_message('Отмена отпраки') + if message.text == "stop" or message.text == "стоп" or message.text[0] == "/": + send_admin_message("Отмена отпраки") return - + global text_spam text_spam = message.text - + text = "Пожалуйста, проверь итоговое сообщение и подтверди отправку:\ \n\nКому: " - + if data == "all": text += "всем" elif data in for_json.groups_in_json(): @@ -155,31 +174,36 @@ def spam_cnf(message, data): else: send_admin_message("Ошибка при выборе пользователей") return - - text +="\n\nСообщение: {}".format(message.text) - + + text += "\n\nСообщение: {}".format(message.text) + markup = types.InlineKeyboardMarkup() - - markup.add(types.InlineKeyboardButton(text="✅", callback_data="spam#{}".format(data)), - types.InlineKeyboardButton(text="❌", callback_data="spam_no")) - - bot.send_message(message.from_user.id, text, parse_mode=ParseMode.HTML, reply_markup=markup) - + + markup.add( + types.InlineKeyboardButton(text="✅", callback_data="spam#{}".format(data)), + types.InlineKeyboardButton(text="❌", callback_data="spam_no"), + ) + + bot.send_message( + message.from_user.id, text, parse_mode=ParseMode.HTML, reply_markup=markup + ) + return + @bot.callback_query_handler(func=lambda call: "spam" in call.data) def spam_send(call): if call.data == "spam_no": - send_admin_message('Отмена отпраки') + send_admin_message("Отмена отпраки") return - + tmp, data = call.data.split("#") - + global text_spam text = text_spam - + users = [] - + if data == "all": groups = for_json.groups_in_json() for group in groups: @@ -189,372 +213,491 @@ def spam_send(call): users = for_json.students_in_group(data) elif for_json.return_infos(data) != None: users = [data] - + for i in users: send_message(i, text) - - bot.edit_message_text(chat_id=call.message.chat.id, - message_id=call.message.message_id, - text='Успешно!', - parse_mode=ParseMode.HTML) - + + bot.edit_message_text( + chat_id=call.message.chat.id, + message_id=call.message.message_id, + text="Успешно!", + parse_mode=ParseMode.HTML, + ) + return -@bot.message_handler(commands=['pause_all']) + +@bot.message_handler(commands=["pause_all"]) @admin_command def pause_bot(message): for_json.pause_bot() - + return -@bot.message_handler(commands=['stop']) + +@bot.message_handler(commands=["stop"]) @admin_command def stop_msg(message): - if len(str(message.text).split(' ')) != 2: - send_admin_message('Эта команда вида /stop id_пользователя') + if len(str(message.text).split(" ")) != 2: + send_admin_message("Эта команда вида /stop id_пользователя") return - for_json.change_user_param(str(message.text).split(' ')[1], 'allow_message', 'no') - send_admin_message('Успешно') + + for_json.change_user_param(str(message.text).split(" ")[1], "allow_message", "no") + send_admin_message("Успешно") + return -### --//-- -@bot.message_handler(commands=['start']) +### --//-- + + +@bot.message_handler(commands=["start"]) def start(message): - start_txt = 'Привет! Это бот, который будет кидать тебе сообщения перед нужной парой с номером кабинета/фамилией препода\ + start_txt = "Привет! Это бот, который будет кидать тебе сообщения перед нужной парой с номером кабинета/фамилией препода\ \n\nТы можешь настроить отправку сообщений в лс или добавить меня в группу, куда я буду присылать расписание\ -\n\nCreated by: @Kr0sH_512' - if message.chat.type == "supergroup": - if len(message.text.split(' ')) != 2: +\n\nCreated by: @Kr0sH_512" + if message.chat.type == "supergroup": + if len(message.text.split(" ")) != 2: send_message(message.chat.id, start_txt) - send_message(message.chat.id, 'Похоже, что этот бот добавлен в группу. Чтобы он присылал расписание в чат, \ + send_message( + message.chat.id, + "Похоже, что этот бот добавлен в группу. Чтобы он присылал расписание в чат, \ укажите вместе с /start@vmk_schedule_bot номер своей группы.\ - \nПример:\n/start@vmk_schedule_bot 102') + \nПример:\n/start@vmk_schedule_bot 102", + ) else: - temp = message.text.split(' ')[1] - + temp = message.text.split(" ")[1] + if temp.isdigit(): infos = [ - message.chat.id, - message.chat.title, - '', + message.chat.id, + message.chat.title, + "", message.from_user.username, - temp + temp, ] - + if temp in for_json.groups_in_json(): - send_message(message.chat.id, - 'Отлично! Теперь я буду присылать вам расписание {} группы'.format(temp)) + send_message( + message.chat.id, + "Отлично! Теперь я буду присылать вам расписание {} группы".format( + temp + ), + ) else: - send_message(message.chat.id, 'Похоже, что расписания для этой группы ещё не существует. \ - \nРазработчик уже пинается, но можете дополнительно написать ему: @Kr0sH_512') - - send_admin_message('В группе {} был запрос на {} группу.\ - \nid: {}'.format(message.chat.title, temp, message.chat.id)) - temp = 'other' + send_message( + message.chat.id, + "Похоже, что расписания для этой группы ещё не существует. \ + \nРазработчик уже пинается, но можете дополнительно написать ему: @Kr0sH_512", + ) + + send_admin_message( + "В группе {} был запрос на {} группу.\ + \nid: {}".format( + message.chat.title, temp, message.chat.id + ) + ) + temp = "other" for_json.save_user(infos) else: - send_message(message.chat.id, 'Введено не число. Попробуйте снова.\ - \nПример:\n/start@vmk_schedule_bot 102') + send_message( + message.chat.id, + "Введено не число. Попробуйте снова.\ + \nПример:\n/start@vmk_schedule_bot 102", + ) return - + send_message(message.chat.id, start_txt) - + markup = types.InlineKeyboardMarkup() for i in for_json.groups_in_json(): markup.add(types.InlineKeyboardButton(text=i, callback_data=i)) - - markup.add(types.InlineKeyboardButton(text="Моей группы нет в этом списке", callback_data="other")) - bot.send_message(message.chat.id, 'Пожалуйста, выбери свою группу', parse_mode=ParseMode.HTML, reply_markup=markup) - + + markup.add( + types.InlineKeyboardButton( + text="Моей группы нет в этом списке", callback_data="other" + ) + ) + bot.send_message( + message.chat.id, + "Пожалуйста, выбери свою группу", + parse_mode=ParseMode.HTML, + reply_markup=markup, + ) + return -@bot.callback_query_handler(func=lambda call: call.data in for_json.groups_in_json() or call.data == "other") + +@bot.callback_query_handler( + func=lambda call: call.data in for_json.groups_in_json() or call.data == "other" +) def callback_inline(call): infos = [ - call.from_user.id, - call.from_user.first_name, - call.from_user.last_name, - call.from_user.username, - call.data - ] - + call.from_user.id, + call.from_user.first_name, + call.from_user.last_name, + call.from_user.username, + call.data, + ] + for_json.save_user(infos) - - if call.data == 'other': - bot.edit_message_text(chat_id=call.message.chat.id, - message_id=call.message.message_id, - text='Используй команду /request \ + + if call.data == "other": + bot.edit_message_text( + chat_id=call.message.chat.id, + message_id=call.message.message_id, + text="Используй команду /request \ и напиши номер группы, которую хочешь добавить\ - \nПосле создания расписания для твоей группы, я пришлю тебе сообщение', - parse_mode=ParseMode.HTML) + \nПосле создания расписания для твоей группы, я пришлю тебе сообщение", + parse_mode=ParseMode.HTML, + ) else: - bot.edit_message_text(chat_id=call.message.chat.id, - message_id=call.message.message_id, - text='Отлично, теперь тебе будут приходить сообщения!', - parse_mode=ParseMode.HTML) - + bot.edit_message_text( + chat_id=call.message.chat.id, + message_id=call.message.message_id, + text="Отлично, теперь тебе будут приходить сообщения!", + parse_mode=ParseMode.HTML, + ) + return - -@bot.message_handler(commands=['schedule']) +@bot.message_handler(commands=["schedule"]) def send_schedule(message): - text = 'К сожалению, бот не может отправить тебе расписание твоей группы на сегодня :(' + text = ( + "К сожалению, бот не может отправить тебе расписание твоей группы на сегодня :(" + ) try: - day = datetime.today().strftime('%A').lower()[:3] # mon tue ... + day = datetime.today().strftime("%A").lower()[:3] # mon tue ... text = for_json.get_schedule(message.chat.id, day) except Exception as e: - send_admin_message('Schedule error from: {} \n\n {}'.format(message.chat.id, e)) - + send_admin_message("Schedule error from: {} \n\n {}".format(message.chat.id, e)) + markup = types.InlineKeyboardMarkup() - markup.add(types.InlineKeyboardButton(text="◀️", callback_data="left"), - types.InlineKeyboardButton(text="▶️", callback_data="right")) - bot.send_message(message.chat.id, text, ParseMode.HTML, reply_markup=markup, message_thread_id=message.message_thread_id) - + markup.add( + types.InlineKeyboardButton(text="◀️", callback_data="left"), + types.InlineKeyboardButton(text="▶️", callback_data="right"), + ) + bot.send_message( + message.chat.id, + text, + ParseMode.HTML, + reply_markup=markup, + message_thread_id=message.message_thread_id, + ) + return - -@bot.callback_query_handler(func=lambda call: call.data in ['left', 'right']) + + +@bot.callback_query_handler(func=lambda call: call.data in ["left", "right"]) def change_schedule(call): - days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat'] - russian_days = ['понедельник', 'вторник', 'среду', 'четверг', 'пятницу', 'субботу'] - i = 6 # выходной + days = ["mon", "tue", "wed", "thu", "fri", "sat"] + russian_days = ["понедельник", "вторник", "среду", "четверг", "пятницу", "субботу"] + i = 6 # выходной for day in russian_days: if day in call.message.text: i = russian_days.index(day) break - - delta = (1) if (call.data == 'right') else (-1) + + delta = (1) if (call.data == "right") else (-1) ind = ((i + delta) % 6) if (i + delta > 0) else (i + delta) - + text = for_json.get_schedule(call.message.chat.id, days[ind]) - + markup = types.InlineKeyboardMarkup() - markup.add(types.InlineKeyboardButton(text="◀️", callback_data="left"), - types.InlineKeyboardButton(text="▶️", callback_data="right")) - - bot.edit_message_text(text, call.message.chat.id, call.message.message_id, - parse_mode=ParseMode.HTML, reply_markup=markup) - + markup.add( + types.InlineKeyboardButton(text="◀️", callback_data="left"), + types.InlineKeyboardButton(text="▶️", callback_data="right"), + ) + + bot.edit_message_text( + text, + call.message.chat.id, + call.message.message_id, + parse_mode=ParseMode.HTML, + reply_markup=markup, + ) + return - -@bot.message_handler(commands=['random']) +@bot.message_handler(commands=["random"]) def random_people(message): list_of_num = ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6", "7", "8", "9"] - + list_of_var = for_json.students_in_json(message.chat.id) - - text = 'Для вашей группы эта команда не настроена.\n\nНапиши запрос через /request' - + + text = "Для вашей группы эта команда не настроена.\n\nНапиши запрос через /request" + if list_of_var == None: send_message(message.chat.id, text) - send_admin_message('Запрос на random команду от {}'.format( - for_json.return_infos(message.chat.id)["group"])) - + send_admin_message( + "Запрос на random команду от {}".format( + for_json.return_infos(message.chat.id)["group"] + ) + ) + return - - text = '• Выбери как именно мне перемешать вас:\n' - + + text = "• Выбери как именно мне перемешать вас:\n" + l = [] for i, val in enumerate(list_of_var): - text += '\n{} {}'.format(list_of_num[i], val) - l.append(types.InlineKeyboardButton(text=list_of_num[i], callback_data="rand#" + val)) - + text += "\n{} {}".format(list_of_num[i], val) + l.append( + types.InlineKeyboardButton(text=list_of_num[i], callback_data="rand#" + val) + ) + l = [l] - + markup = types.InlineKeyboardMarkup(l) bot.send_message(message.chat.id, text, ParseMode.HTML, reply_markup=markup) - + return + @bot.callback_query_handler(func=lambda call: "rand#" in call.data) def make_random(call): - list_of_stud = for_json.students_in_json(call.message.chat.id, call.data.split("#")[1]) - + list_of_stud = for_json.students_in_json( + call.message.chat.id, call.data.split("#")[1] + ) + random.shuffle(list_of_stud) - - text = '{}:\n\n'.format(call.data.split("#")[1]) - + + text = "{}:\n\n".format(call.data.split("#")[1]) + for i, name in enumerate(list_of_stud): - text += '{}{}. {}\n'.format(' ' if i + 1 < 10 else '', i + 1, name) - - bot.edit_message_text('Хорошо, вот ваше распределение!', call.message.chat.id, - call.message.message_id, parse_mode=ParseMode.HTML) - + text += "{}{}. {}\n".format(" " if i + 1 < 10 else "", i + 1, name) + + bot.edit_message_text( + "Хорошо, вот ваше распределение!", + call.message.chat.id, + call.message.message_id, + parse_mode=ParseMode.HTML, + ) + send_message(call.message.chat.id, text) - + return - -@bot.message_handler(commands=['info']) + +@bot.message_handler(commands=["info"]) def send_info(message): - if len(message.text.split(' ')) == 2 and is_admin(message): - send_admin_message('Окей, держи настройки {}'.format(message.text.split(' ')[1])) - infos = for_json.return_infos(message.text.split(' ')[1]) - text = 'Никнейм: @{}\ + if len(message.text.split(" ")) == 2 and is_admin(message): + send_admin_message( + "Окей, держи настройки {}".format(message.text.split(" ")[1]) + ) + infos = for_json.return_infos(message.text.split(" ")[1]) + text = "Никнейм: @{}\ \nИмя: {} {}\ \nВыбранная группа: {}\ \nВремя напоминания до урока: {}\ - \nРазрешены ли напоминания: {}'.format(infos['username'], infos['first_name'], infos['last_name'], - (infos['group'] if infos['group'] != 'other' else 'не выбрана'), - infos['timeout'], - ('да' if infos['allow_message'] == 'yes' else 'нет')) + \nРазрешены ли напоминания: {}".format( + infos["username"], + infos["first_name"], + infos["last_name"], + (infos["group"] if infos["group"] != "other" else "не выбрана"), + infos["timeout"], + ("да" if infos["allow_message"] == "yes" else "нет"), + ) send_admin_message(text) return - - send_message(message.chat.id, 'Хорошо, вот твои настройки:') + + send_message(message.chat.id, "Хорошо, вот твои настройки:") infos = for_json.return_infos(message.chat.id) - text = 'Выбранная группа: {}\ + text = "Выбранная группа: {}\ \nВремя напоминания до урока: {}\ - \nРазрешены ли напоминания: {}'.format((infos['group'] if infos['group'] != 'other' else 'не выбрана'), - infos['timeout'], - ('да' if infos['allow_message'] == 'yes' else 'нет')) + \nРазрешены ли напоминания: {}".format( + (infos["group"] if infos["group"] != "other" else "не выбрана"), + infos["timeout"], + ("да" if infos["allow_message"] == "yes" else "нет"), + ) send_message(message.chat.id, text) - + return - -@bot.message_handler(commands=['pause']) +@bot.message_handler(commands=["pause"]) def pause_schedule(message): - infos = for_json.return_infos(message.chat.id)['allow_message'] - - if infos == 'yes': - for_json.change_user_param(str(message.chat.id), 'allow_message', 'no') - send_message(message.chat.id, 'Рассылка сообщений прекращена. \ - \nДля возобновления воспользуйтесь командой\n/pause') + infos = for_json.return_infos(message.chat.id)["allow_message"] + + if infos == "yes": + for_json.change_user_param(str(message.chat.id), "allow_message", "no") + send_message( + message.chat.id, + "Рассылка сообщений прекращена. \ + \nДля возобновления воспользуйтесь командой\n/pause", + ) else: - for_json.change_user_param(str(message.chat.id), 'allow_message', 'yes') - send_message(message.chat.id, 'Рассылка сообщений возоблена!') - + for_json.change_user_param(str(message.chat.id), "allow_message", "yes") + send_message(message.chat.id, "Рассылка сообщений возоблена!") + return - - - -@bot.message_handler(commands=['thread']) + + +@bot.message_handler(commands=["thread"]) def change_thread(message): - thread_id = '' - + thread_id = "" + try: thread_id = message.reply_to_message.message_thread_id except AttributeError: thread_id = "General" - - for_json.change_user_param(str(message.chat.id), 'thread', thread_id) - - send_message(message.chat.id, 'Хорошо, теперь я буду отправлять сообщения в этот чат', thread_id) - + + for_json.change_user_param(str(message.chat.id), "thread", thread_id) + + send_message( + message.chat.id, + "Хорошо, теперь я буду отправлять сообщения в этот чат", + thread_id, + ) + return - -@bot.message_handler(commands=['timeout']) +@bot.message_handler(commands=["timeout"]) def set_timeout(message): - send_message(message.chat.id, 'Пришли мне число от 1 до 60. \ - \nЭто будет количество минут, за которое я буду присылать тебе напоминание о паре (По умолчанию: 10)') + send_message( + message.chat.id, + "Пришли мне число от 1 до 60. \ + \nЭто будет количество минут, за которое я буду присылать тебе напоминание о паре (По умолчанию: 10)", + ) bot.register_next_step_handler(message, save_timeout) - + return + def save_timeout(message): - if str(message.text).isdigit() and int(message.text) <= 60 and int(message.text) >= 1: - for_json.change_user_param(message.chat.id, 'timeout', str(message.text)) - send_message(message.chat.id, - 'Хорошо, теперь ты будешь получать напоминания за {} минут до урока'.format(str(message.text))) + if ( + str(message.text).isdigit() + and int(message.text) <= 60 + and int(message.text) >= 1 + ): + for_json.change_user_param(message.chat.id, "timeout", str(message.text)) + send_message( + message.chat.id, + "Хорошо, теперь ты будешь получать напоминания за {} минут до урока".format( + str(message.text) + ), + ) else: - send_message(message.chat.id, - 'Пожалуйста, пришли число от 1 до 60. \ - \nПо умолчанию: 10') - send_message(message.chat.id, 'Изменения не были внесены') - + send_message( + message.chat.id, + "Пожалуйста, пришли число от 1 до 60. \ + \nПо умолчанию: 10", + ) + send_message(message.chat.id, "Изменения не были внесены") + return - -@bot.message_handler(commands=['request']) +@bot.message_handler(commands=["request"]) def request(message): - send_message(message.from_user.id, 'Отправь мне сообщение и я перешлю его разработчику\ - \n(или напиши stop, чтобы отменить отправку)') + send_message( + message.from_user.id, + "Отправь мне сообщение и я перешлю его разработчику\ + \n(или напиши stop, чтобы отменить отправку)", + ) bot.register_next_step_handler(message, send_request) - + return - + + def send_request(message): - if message.text == "stop" or message.text == "стоп" or message.text[0] == '/': - send_message(message.from_user.id, 'Отмена отпраки') + if message.text == "stop" or message.text == "стоп" or message.text[0] == "/": + send_message(message.from_user.id, "Отмена отпраки") return - + infos = [ - message.from_user.id, - message.from_user.first_name, - message.from_user.last_name, + message.from_user.id, + message.from_user.first_name, + message.from_user.last_name, message.from_user.username, - message.text + message.text, ] - + for i in range(len(infos)): if type(infos[i]) == type(None): - infos[i] = '' - - admin_text = 'Сообщение от {} {} (@{}):\n\n{}\nid: {}'.format(infos[1], infos[2], infos[3], infos[4], infos[0]) + infos[i] = "" + + admin_text = "Сообщение от {} {} (@{}):\n\n{}\nid: {}".format( + infos[1], infos[2], infos[3], infos[4], infos[0] + ) send_admin_message(admin_text) - - send_message(message.from_user.id, 'Ваше сообщение успешно доставлено!') - + + send_message(message.from_user.id, "Ваше сообщение успешно доставлено!") + return - -@bot.message_handler(commands=['source']) +@bot.message_handler(commands=["source"]) def send_source(message): - bot.send_message(message.chat.id, 'https://github.com/kr0sh512/Telegram-bot-schedule', parse_mode=ParseMode.HTML) - + bot.send_message( + message.chat.id, + "https://github.com/kr0sh512/Telegram-bot-schedule", + parse_mode=ParseMode.HTML, + ) + return - -@bot.message_handler(content_types=['text']) +@bot.message_handler(content_types=["text"]) def text_message(message): if message.chat.type == "supergroup" or is_admin(message): return - send_message(message.from_user.id, 'К сожалению, я ещё не умею обрабатывать сообщения.\ - \nИспользуй команды из меню или напиши /help.') - + send_message( + message.from_user.id, + "К сожалению, я ещё не умею обрабатывать сообщения.\ + \nИспользуй команды из меню или напиши /help.", + ) + return - -def send_message(id, text, thread_id='General', distribution=False): - if thread_id == 'General': +def send_message(id, text, thread_id="General", distribution=False): + if thread_id == "General": thread_id = None - + if distribution: count_of_weeks = (datetime.now() - datetime(2024, 2, 5)).days // 7 is_odd = (count_of_weeks + 1) % 2 == 1 - + if is_odd and ("(чёт)" in text): return - + if (not is_odd) and ("(нечёт)" in text): return - + try: - bot.send_message(chat_id=id, text=text, parse_mode=ParseMode.HTML, message_thread_id=thread_id,disable_web_page_preview=True) + bot.send_message( + chat_id=id, + text=text, + parse_mode=ParseMode.HTML, + message_thread_id=thread_id, + disable_web_page_preview=True, + ) except Exception as e: time.sleep(5) try: - bot.send_message(chat_id=id, text=text, parse_mode=ParseMode.HTML, message_thread_id=thread_id,disable_web_page_preview=True) + bot.send_message( + chat_id=id, + text=text, + parse_mode=ParseMode.HTML, + message_thread_id=thread_id, + disable_web_page_preview=True, + ) except Exception as e: - text_error = 'Error from user: @{} {}\n{}'.format(for_json.return_infos(id)["username"], id, str(e)) + text_error = "Error from user: @{} {}\n{}".format( + for_json.return_infos(id)["username"], id, str(e) + ) send_admin_message(text_error) print(id, e) - + return -def send_document(id, file, text = ''): + +def send_document(id, file, text=""): try: bot.send_document(id, file, caption=text) except Exception as e: @@ -562,26 +705,27 @@ def send_document(id, file, text = ''): try: bot.send_document(id, file, caption=text) except Exception as e: - text_error = 'Error from user: {}\n{}'.format(id, str(e)) + text_error = "Error from user: {}\n{}".format(id, str(e)) send_admin_message(text_error) print(id, e) - + return - -if __name__ == '__main__': +if __name__ == "__main__": for_json.create_schedule_tasks(True) - send_admin_message('Я перезапустился!') + send_admin_message("Я перезапустился!") print("-------------------------") - - threading.Thread(target=bot.infinity_polling, name='bot_infinity_polling', daemon=True).start() - + + threading.Thread( + target=bot.infinity_polling, name="bot_infinity_polling", daemon=True + ).start() + while True: try: schedule.run_pending() time.sleep(5) except Exception as e: print(e) - time.sleep(10) \ No newline at end of file + time.sleep(10) From ee3b23ad59fe4f0b700dcdc14030bbde9a0218d7 Mon Sep 17 00:00:00 2001 From: kr0sh512 Date: Sun, 1 Sep 2024 00:52:33 +0300 Subject: [PATCH 07/10] refactor --- admin.py | 24 +++-- for_json.py | 276 +++++++++++++++++++++++++++----------------------- json/tmp.json | 42 ++++++++ schedules.py | 10 +- 4 files changed, 211 insertions(+), 141 deletions(-) create mode 100644 json/tmp.json diff --git a/admin.py b/admin.py index 6fd75a1..c47129e 100644 --- a/admin.py +++ b/admin.py @@ -1,12 +1,15 @@ import schedules as bot -admin_id = '856850518' +admin_id = "856850518" + def admin_command(func): def wrapper(*args, **kwargs): message = args[0] if str(message.from_user.id) != admin_id: - bot.send_message(message.from_user.id, 'Команда доступна только администратору') + bot.send_message( + message.from_user.id, "Команда доступна только администратору" + ) return func(*args, **kwargs) @@ -14,15 +17,20 @@ def admin_command(func): return wrapper + def is_admin(message): - if str(message.from_user.id) == admin_id and message.from_user.id == message.chat.id: + if ( + str(message.from_user.id) == admin_id + and message.from_user.id == message.chat.id + ): return True - + return False + def send_admin_message(text): - bot.send_message(admin_id, '🛑 ' + text) - + bot.send_message(admin_id, "🛑 " + text) + + def send_admin_document(file): - bot.send_document(admin_id, file, '🛑 Admin file') - \ No newline at end of file + bot.send_document(admin_id, file, "🛑 Admin file") diff --git a/for_json.py b/for_json.py index 1ffa9fc..5849588 100644 --- a/for_json.py +++ b/for_json.py @@ -3,38 +3,31 @@ import json, schedule import schedules as bot from datetime import datetime -path_users = "json/users.json" # Нужный путь до json файлов -path_schedule = "json/schedule_2sem.json" +path_users = "json/users.json" # Нужный путь до json файлов +path_schedule = "json/schedule_3sem.json" path_students = "json/students.json" -# path_logs = "json/logs.json" allow_update = True -# Возможно разбиение добавление логов на 2 функции: Распарсирование message/call -# 2) добавление самого текста в json - -# def add_logs(logs): # TODO: реализация добавления логов -# pass -# return def save_user(infos): for i in range(len(infos)): if type(infos[i]) == type(None): - infos[i] = '' + infos[i] = "" infos[i] = str(infos[i]) - + infos = { - "id" : infos[0], - "first_name" : infos[1], - "last_name" : infos[2], - "username" : infos[3], - "group" : infos[4] + "id": infos[0], + "first_name": infos[1], + "last_name": infos[2], + "username": infos[3], + "group": infos[4], } - + data = {} - with open(path_users, 'r', encoding='utf-8') as json_file: + with open(path_users, "r", encoding="utf-8") as json_file: data = json.load(json_file) - + data[infos["id"]] = { "username": infos["username"], "first_name": infos["first_name"], @@ -42,220 +35,245 @@ def save_user(infos): "group": infos["group"], "timeout": "10", "allow_message": "yes", - "thread": "General" + "thread": "General", } - with open(path_users, 'w', encoding='utf-8') as json_file: + with open(path_users, "w", encoding="utf-8") as json_file: json.dump(data, json_file, ensure_ascii=False, indent=4) - create_schedule_tasks(manual=True) - # bot.send_admin_message("Новый пользователь:\ - # \nuser: @{}\ - # \ngroup: {}\ - # \nid: {}\ - # \nname: {} {}".format(data[infos["id"]]["username"], - # data[infos["id"]]["group"], - # infos["id"], - # data[infos["id"]]["first_name"], - # data[infos["id"]]["last_name"])) - + + create_schedule_tasks() + return + def change_user_param(id, key, value): id = str(id) data = {} - with open(path_users, 'r', encoding='utf-8') as json_file: + with open(path_users, "r", encoding="utf-8") as json_file: data = json.load(json_file) - + data[id][key] = value - with open(path_users, 'w', encoding='utf-8') as json_file: + with open(path_users, "w", encoding="utf-8") as json_file: json.dump(data, json_file, ensure_ascii=False, indent=4) create_schedule_tasks() - bot.send_admin_message("Изменения:\ + bot.send_admin_message( + "Изменения:\ \nuser: @{}\ \nid: {}\ \nkey: {}\ - \nvalue: {}".format(data[id]["username"], id, key, value)) + \nvalue: {}".format( + data[id]["username"], id, key, value + ) + ) return + def parse_lesson(time, lesson): - text = '' + text = "" start, end = time.split("-") - - if len(lesson["infos"].split('|')) == 2: - teacher = lesson["infos"].split('|')[0] - room = lesson["infos"].split('|')[1] - text = '{}-{} | {}\ + + if len(lesson["infos"].split("|")) == 2: + teacher = lesson["infos"].split("|")[0] + room = lesson["infos"].split("|")[1] + text = "{}-{} | {}\ \n{}\ - \n{}'.format(start, end, room, lesson["name"], teacher) - elif len(lesson["infos"].split('|')) == 4: - infos = lesson["infos"].split('|') - text = '{}-{}\ + \n{}".format( + start, end, room, lesson["name"], teacher + ) + elif len(lesson["infos"].split("|")) == 4: + infos = lesson["infos"].split("|") + text = "{}-{}\ \n{}\ \n({}) {}\ - \n({}) {}'.format(start, end, lesson["name"], - infos[1], - infos[0], - infos[3], - infos[2]) - elif len(lesson["infos"].split('|')) == 1: - text = '{}-{}\ - \n{}'.format(start, end, lesson["name"]) + \n({}) {}".format( + start, end, lesson["name"], infos[1], infos[0], infos[3], infos[2] + ) + elif len(lesson["infos"].split("|")) == 1: + text = "{}-{}\ + \n{}".format( + start, end, lesson["name"] + ) else: print("что-то не так") print(lesson["name"]) - + return text + def create_schedule_tasks(manual=False): global allow_update + if not manual: - bot.send_admin_message('Произошёл auto-update') if not allow_update: return - + + bot.send_admin_message("Произошёл auto-update") + allow_update = True - + schedule.clear() users = {} schdl = {} - with open(path_users, 'r', encoding='utf-8') as json_file: + with open(path_users, "r", encoding="utf-8") as json_file: users = json.load(json_file) - with open(path_schedule, 'r', encoding='utf-8') as json_file: - schdl = json.load(json_file) + with open(path_schedule, "r", encoding="utf-8") as json_file: + schdl = json.load(json_file) for id, params in users.items(): - if params['allow_message'] != 'yes': + if params["allow_message"] != "yes": continue - group = params['group'] - if group == 'other': + group = params["group"] + if group == "other": continue - timeout = params['timeout'] + timeout = params["timeout"] for day in schdl[group]: for i, lesson in schdl[group][day].items(): - if lesson["name"] == "": # Неправильный формат schedule + if lesson["name"] == "": # Неправильный формат schedule continue - + start = i.split("-")[0] text = parse_lesson(i, lesson) - - if text == '': + + if text == "": continue - + thread_id = params["thread"] - - delta = '00:' + params["timeout"] - format = '%H:%M' - start_task = datetime.strptime(start, format) - datetime.strptime(delta, format) - tmp = '' - for i in str(start_task).split(':'): - tmp += (('0' + i ) if len(i) < 2 else i) + ":" + + delta = "00:" + params["timeout"] + format = "%H:%M" + start_task = datetime.strptime(start, format) - datetime.strptime( + delta, format + ) + tmp = "" + for i in str(start_task).split(":"): + tmp += (("0" + i) if len(i) < 2 else i) + ":" start_task = tmp[:-1] - - if day == 'mon': - schedule.every().monday.at(start_task).do(bot.send_message, id, text, thread_id, True) - elif day == 'tue': - schedule.every().tuesday.at(start_task).do(bot.send_message, id, text, thread_id, True) - elif day == 'wed': - schedule.every().wednesday.at(start_task).do(bot.send_message, id, text, thread_id, True) - elif day == 'thu': - schedule.every().thursday.at(start_task).do(bot.send_message, id, text, thread_id, True) - elif day == 'fri': - schedule.every().friday.at(start_task).do(bot.send_message, id, text, thread_id, True) - elif day == 'sat': - schedule.every().saturday.at(start_task).do(bot.send_message, id, text, thread_id, True) - + + if day == "mon": + schedule.every().monday.at(start_task).do( + bot.send_message, id, text, thread_id, True + ) + elif day == "tue": + schedule.every().tuesday.at(start_task).do( + bot.send_message, id, text, thread_id, True + ) + elif day == "wed": + schedule.every().wednesday.at(start_task).do( + bot.send_message, id, text, thread_id, True + ) + elif day == "thu": + schedule.every().thursday.at(start_task).do( + bot.send_message, id, text, thread_id, True + ) + elif day == "fri": + schedule.every().friday.at(start_task).do( + bot.send_message, id, text, thread_id, True + ) + elif day == "sat": + schedule.every().saturday.at(start_task).do( + bot.send_message, id, text, thread_id, True + ) + return + def groups_in_json(): schdl = {} - with open(path_schedule, 'r', encoding='utf-8') as json_file: + with open(path_schedule, "r", encoding="utf-8") as json_file: schdl = json.load(json_file) - + return schdl.keys() + def students_in_group(group): group = str(group) - + data = {} - with open(path_users, 'r', encoding='utf-8') as json_file: + with open(path_users, "r", encoding="utf-8") as json_file: data = json.load(json_file) - + students = [] - + for i in data.keys(): if data[i]["group"] == group: students.append(i) - + return students + def students_in_json(id="", key=""): id = str(id) - + group = {} - with open(path_users, 'r', encoding='utf-8') as json_file: + with open(path_users, "r", encoding="utf-8") as json_file: group = json.load(json_file) group = group[id]["group"] - + stud = {} - with open(path_students, 'r', encoding='utf-8') as json_file: + with open(path_students, "r", encoding="utf-8") as json_file: stud = json.load(json_file) stud = stud.get(group) - + if stud == None: return None - + if key == "": return list(stud.keys()) - + return stud[key] def return_infos(id): id = str(id) data = {} - with open(path_users, 'r', encoding='utf-8') as json_file: + with open(path_users, "r", encoding="utf-8") as json_file: data = json.load(json_file) data = data.get(id) - + return data + def pause_bot(): global allow_update + if allow_update: schedule.clear() allow_update = False - bot.send_admin_message('Бот больше не отправляет расписание') + bot.send_admin_message("Бот больше не отправляет расписание") else: create_schedule_tasks(True) allow_update = True - bot.send_admin_message('Бот возобновил рассылку!') - + bot.send_admin_message("Бот возобновил рассылку!") + return + def get_schedule(id, day): id = str(id) - if day == 'sun': - day = 'mon' - days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat'] - russian_days = ['понедельник', 'вторник', 'среду', 'четверг', 'пятницу', 'субботу'] - - text = 'Расписание на {}:\n\n'.format(russian_days[days.index(day)]) + if day == "sun": + day = "mon" + days = ["mon", "tue", "wed", "thu", "fri", "sat"] + russian_days = ["понедельник", "вторник", "среду", "четверг", "пятницу", "субботу"] + + text = "Расписание на {}:\n\n".format(russian_days[days.index(day)]) schdl_today = {} - with open(path_schedule, 'r', encoding='utf-8') as schedule_file: - group = '' - with open(path_users, 'r', encoding='utf-8') as user_file: - group = json.load(user_file)[id]['group'] - - if (group == 'other'): - return 'У тебя не выбрана группа для рассылки сообщений' - + with open(path_schedule, "r", encoding="utf-8") as schedule_file: + group = "" + with open(path_users, "r", encoding="utf-8") as user_file: + group = json.load(user_file)[id]["group"] + + if group == "other": + return "У тебя не выбрана группа для рассылки сообщений" + try: schdl_today = json.load(schedule_file)[group][day] except: - return 'Расписания твоей группы на {} нет'.format(russian_days[days.index(day)]) - + return "Расписания твоей группы на {} нет".format( + russian_days[days.index(day)] + ) + for i, lesson in schdl_today.items(): - text += '•' + parse_lesson(i, lesson) + '\n\n' - + text += "•" + parse_lesson(i, lesson) + "\n\n" + return text diff --git a/json/tmp.json b/json/tmp.json new file mode 100644 index 0000000..1bb6b84 --- /dev/null +++ b/json/tmp.json @@ -0,0 +1,42 @@ +{ + "studies.begin": { + "y": 2024, + "m": 9, + "d": 1 + }, + "studies.end": null, + "schedule": { + "mon": [ + { + "partity": 1, + "begin": "10:30", + "end": "12:05", + "name": "Практикум на ЭВМ", + "teacher.room": [ + { + "t": "Тюляева В.В.", + "r": "МЗ-3" + } + ], + "building": "2-й гуманитарный корпус", + "note": "Какое-то примечание", + "type": "seminar" + }, + { + "partity": null, + "begin": "10:30", + "end": "12:05", + "name": "Практикум на ЭВМ", + "teacher.room": [ + { + "t": "Тюляева В.В.", + "r": "МЗ-3" + } + ], + "building": "2-й гуманитарный корпус", + "note": "Какое-то примечание", + "type": "seminar" + } + ] + } +} \ No newline at end of file diff --git a/schedules.py b/schedules.py index 2b5b600..109ac14 100644 --- a/schedules.py +++ b/schedules.py @@ -7,7 +7,9 @@ from telegram.constants import ParseMode import for_json from admin import admin_command, is_admin, send_admin_message, send_admin_document -bot = telebot.TeleBot("TOKEN_API") +# bot = telebot.TeleBot("TOKEN_API") +bot = telebot.TeleBot("6998513979:AAGgpjgdDsCEqPE0hC8yxrzclsNSd-oRP1s") # test +# bot = telebot.TeleBot("6355753103:AAGniZ7Wf5XyPkn3z753UJvn6afbhOlImjA") # sсhedule @bot.message_handler(commands=["help", "faq"]) @@ -60,7 +62,7 @@ def test(message): return -@bot.message_handler(commands=["restart", 'r']) +@bot.message_handler(commands=["restart", "r"]) @admin_command def restart_bot(message): send_admin_message("bye") @@ -241,10 +243,10 @@ def stop_msg(message): if len(str(message.text).split(" ")) != 2: send_admin_message("Эта команда вида /stop id_пользователя") return - + for_json.change_user_param(str(message.text).split(" ")[1], "allow_message", "no") send_admin_message("Успешно") - + return From 3c0be433ae0e341605c33fd03df69baf5ff0a41f Mon Sep 17 00:00:00 2001 From: kr0sh512 Date: Sun, 1 Sep 2024 01:42:50 +0300 Subject: [PATCH 08/10] update json structure --- .gitignore | 3 +- for_json.py | 115 +++++++++++++++++++---------- json/{tmp.json => groups/202.json} | 18 +++++ json/groups/groups.json | 24 ++++++ json/logs.json | 6 -- schedules.py | 20 +++-- 6 files changed, 130 insertions(+), 56 deletions(-) rename json/{tmp.json => groups/202.json} (65%) create mode 100644 json/groups/groups.json delete mode 100644 json/logs.json diff --git a/.gitignore b/.gitignore index cdced54..34ad6fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ +__pycache__ users.json schedule.json -settings.json json/students.json json/schedule_2sem.json nohup.out +config.yaml diff --git a/for_json.py b/for_json.py index 5849588..1c23248 100644 --- a/for_json.py +++ b/for_json.py @@ -4,7 +4,8 @@ import schedules as bot from datetime import datetime path_users = "json/users.json" # Нужный путь до json файлов -path_schedule = "json/schedule_3sem.json" +# path_schedule = "json/schedule_3sem.json" +path_schedule = "json/groups/{}.json" path_students = "json/students.json" allow_update = True @@ -69,7 +70,7 @@ def change_user_param(id, key, value): return -def parse_lesson(time, lesson): +def parse_lesson_tmp(time, lesson): text = "" start, end = time.split("-") @@ -101,6 +102,37 @@ def parse_lesson(time, lesson): return text +def parse_lesson(lesson: dict[str, str]) -> str: + text = "" + start, end = lesson["begin"], lesson["end"] + + if not lesson["name"]: + return "" + + if len(lesson["teacher.room"]) == 1: + text = "{}-{} | {}\ + \n{}\ + \n{}".format( + start, + end, + lesson["teacher.room"][0]["r"], + lesson["name"], + lesson["teacher.room"][0]["t"], + ) + else: + text = "{}-{}\ + \n{}".format( + start, + end, + lesson["name"], + ) + + for tr in lesson["teacher.room"]: + text += "\n({}) {}".format(tr["r"], tr["t"]) + + return text + + def create_schedule_tasks(manual=False): global allow_update @@ -117,24 +149,25 @@ def create_schedule_tasks(manual=False): schdl = {} with open(path_users, "r", encoding="utf-8") as json_file: users = json.load(json_file) - with open(path_schedule, "r", encoding="utf-8") as json_file: - schdl = json.load(json_file) for id, params in users.items(): if params["allow_message"] != "yes": continue group = params["group"] if group == "other": continue - timeout = params["timeout"] - for day in schdl[group]: - for i, lesson in schdl[group][day].items(): - if lesson["name"] == "": # Неправильный формат schedule + + with open(path_schedule.format(group), "r", encoding="utf-8") as json_file: + schdl = json.load(json_file)["schedule"] + + for day in schdl: + for lesson in schdl[day]: + if not lesson["name"]: # Неправильный формат schedule continue - start = i.split("-")[0] - text = parse_lesson(i, lesson) + start = lesson["begin"] + text = parse_lesson(lesson) - if text == "": + if not text: continue thread_id = params["thread"] @@ -151,41 +184,41 @@ def create_schedule_tasks(manual=False): if day == "mon": schedule.every().monday.at(start_task).do( - bot.send_message, id, text, thread_id, True + bot.send_message, id, text, thread_id, lesson["partity"] ) elif day == "tue": schedule.every().tuesday.at(start_task).do( - bot.send_message, id, text, thread_id, True + bot.send_message, id, text, thread_id, lesson["partity"] ) elif day == "wed": schedule.every().wednesday.at(start_task).do( - bot.send_message, id, text, thread_id, True + bot.send_message, id, text, thread_id, lesson["partity"] ) elif day == "thu": schedule.every().thursday.at(start_task).do( - bot.send_message, id, text, thread_id, True + bot.send_message, id, text, thread_id, lesson["partity"] ) elif day == "fri": schedule.every().friday.at(start_task).do( - bot.send_message, id, text, thread_id, True + bot.send_message, id, text, thread_id, lesson["partity"] ) elif day == "sat": schedule.every().saturday.at(start_task).do( - bot.send_message, id, text, thread_id, True + bot.send_message, id, text, thread_id, lesson["partity"] ) return -def groups_in_json(): +def groups_in_json() -> list[str]: schdl = {} - with open(path_schedule, "r", encoding="utf-8") as json_file: + with open(path_schedule.format("groups"), "r", encoding="utf-8") as json_file: schdl = json.load(json_file) - return schdl.keys() + return schdl -def students_in_group(group): +def students_in_group(group) -> list[str]: group = str(group) data = {} @@ -201,7 +234,7 @@ def students_in_group(group): return students -def students_in_json(id="", key=""): +def students_in_json(id: str, key: str = "") -> list[str] | None: id = str(id) group = {} @@ -223,7 +256,7 @@ def students_in_json(id="", key=""): return stud[key] -def return_infos(id): +def return_infos(id) -> dict[str, str] | None: id = str(id) data = {} with open(path_users, "r", encoding="utf-8") as json_file: @@ -248,32 +281,38 @@ def pause_bot(): return -def get_schedule(id, day): +def get_schedule(id: str, day: str) -> str: id = str(id) + if day == "sun": day = "mon" + days = ["mon", "tue", "wed", "thu", "fri", "sat"] russian_days = ["понедельник", "вторник", "среду", "четверг", "пятницу", "субботу"] text = "Расписание на {}:\n\n".format(russian_days[days.index(day)]) schdl_today = {} - with open(path_schedule, "r", encoding="utf-8") as schedule_file: - group = "" - with open(path_users, "r", encoding="utf-8") as user_file: - group = json.load(user_file)[id]["group"] - if group == "other": - return "У тебя не выбрана группа для рассылки сообщений" + group = "" + with open(path_users, "r", encoding="utf-8") as user_file: + group = json.load(user_file)[id]["group"] - try: - schdl_today = json.load(schedule_file)[group][day] - except: - return "Расписания твоей группы на {} нет".format( - russian_days[days.index(day)] - ) + if group == "other": + return "У тебя не выбрана группа для рассылки сообщений" - for i, lesson in schdl_today.items(): - text += "•" + parse_lesson(i, lesson) + "\n\n" + try: + with open(path_schedule.format(group), "r", encoding="utf-8") as schedule_file: + try: + schdl_today = json.load(schedule_file)["schedule"][day] + except: + return "Расписания твоей группы на {} нет".format( + russian_days[days.index(day)] + ) + + for lesson in schdl_today: + text += "•" + parse_lesson(lesson) + "\n\n" + except: + return "Расписания твоей группы нет" return text diff --git a/json/tmp.json b/json/groups/202.json similarity index 65% rename from json/tmp.json rename to json/groups/202.json index 1bb6b84..7433f87 100644 --- a/json/tmp.json +++ b/json/groups/202.json @@ -28,6 +28,14 @@ "end": "12:05", "name": "Практикум на ЭВМ", "teacher.room": [ + { + "t": "Тюляева В.В.", + "r": "МЗ-3" + }, + { + "t": "Тюляева В.В.", + "r": "МЗ-3" + }, { "t": "Тюляева В.В.", "r": "МЗ-3" @@ -36,6 +44,16 @@ "building": "2-й гуманитарный корпус", "note": "Какое-то примечание", "type": "seminar" + }, + { + "partity": null, + "begin": "10:30", + "end": "12:05", + "name": "Практикум на ЭВМ", + "teacher.room": [], + "building": "2-й гуманитарный корпус", + "note": "Какое-то примечание", + "type": "seminar" } ] } diff --git a/json/groups/groups.json b/json/groups/groups.json new file mode 100644 index 0000000..12ad73b --- /dev/null +++ b/json/groups/groups.json @@ -0,0 +1,24 @@ +[ + "201", + "202", + "203", + "204", + "205", + "206", + "219", + "207", + "208", + "209", + "210", + "211", + "212", + "213", + "214", + "215", + "216", + "217", + "218", + "220", + "241", + "242" +] \ No newline at end of file diff --git a/json/logs.json b/json/logs.json deleted file mode 100644 index 56bc9fa..0000000 --- a/json/logs.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "time": { - "func": "", - "params": "" - } -} \ No newline at end of file diff --git a/schedules.py b/schedules.py index 109ac14..092aa83 100644 --- a/schedules.py +++ b/schedules.py @@ -1,5 +1,5 @@ #!/usr/bin/python3.3 -import threading, telebot, schedule, time, random +import threading, telebot, schedule, time, random, yaml from datetime import datetime import os, sys from telebot import types @@ -7,9 +7,10 @@ from telegram.constants import ParseMode import for_json from admin import admin_command, is_admin, send_admin_message, send_admin_document -# bot = telebot.TeleBot("TOKEN_API") -bot = telebot.TeleBot("6998513979:AAGgpjgdDsCEqPE0hC8yxrzclsNSd-oRP1s") # test -# bot = telebot.TeleBot("6355753103:AAGniZ7Wf5XyPkn3z753UJvn6afbhOlImjA") # sсhedule +config = yaml.safe_load(open("config.yaml")) +bot = telebot.TeleBot(config["test_token"]) + +PARTITY_FIRST = 1 @bot.message_handler(commands=["help", "faq"]) @@ -657,18 +658,15 @@ def text_message(message): return -def send_message(id, text, thread_id="General", distribution=False): +def send_message(id, text, thread_id="General", partity=None): if thread_id == "General": thread_id = None - if distribution: + if partity: count_of_weeks = (datetime.now() - datetime(2024, 2, 5)).days // 7 - is_odd = (count_of_weeks + 1) % 2 == 1 + is_odd = (count_of_weeks + 1) % 2 == PARTITY_FIRST - if is_odd and ("(чёт)" in text): - return - - if (not is_odd) and ("(нечёт)" in text): + if is_odd != bool(partity): return try: From 28b264032754acb7fd2bec278b61eb9f2a4c9c19 Mon Sep 17 00:00:00 2001 From: kr0sh512 Date: Tue, 3 Sep 2024 00:40:08 +0300 Subject: [PATCH 09/10] add first course --- .gitignore | 3 ++ for_json.py | 78 +++++++++++++++-------------------------- json/groups/groups.json | 22 ++++++++++++ schedules.py | 69 ++++++++++++++++++++++++------------ 4 files changed, 100 insertions(+), 72 deletions(-) diff --git a/.gitignore b/.gitignore index 34ad6fc..73243d0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,8 @@ users.json schedule.json json/students.json json/schedule_2sem.json +test_json +json_remake +script.py nohup.out config.yaml diff --git a/for_json.py b/for_json.py index 1c23248..e8fea00 100644 --- a/for_json.py +++ b/for_json.py @@ -58,50 +58,20 @@ def change_user_param(id, key, value): with open(path_users, "w", encoding="utf-8") as json_file: json.dump(data, json_file, ensure_ascii=False, indent=4) create_schedule_tasks() - bot.send_admin_message( - "Изменения:\ - \nuser: @{}\ - \nid: {}\ - \nkey: {}\ - \nvalue: {}".format( - data[id]["username"], id, key, value - ) - ) + + # bot.send_admin_message( + # "Изменения:\ + # \nuser: @{}\ + # \nid: {}\ + # \nkey: {}\ + # \nvalue: {}".format( + # data[id]["username"], id, key, value + # ) + # ) + return -def parse_lesson_tmp(time, lesson): - text = "" - start, end = time.split("-") - - if len(lesson["infos"].split("|")) == 2: - teacher = lesson["infos"].split("|")[0] - room = lesson["infos"].split("|")[1] - text = "{}-{} | {}\ - \n{}\ - \n{}".format( - start, end, room, lesson["name"], teacher - ) - elif len(lesson["infos"].split("|")) == 4: - infos = lesson["infos"].split("|") - text = "{}-{}\ - \n{}\ - \n({}) {}\ - \n({}) {}".format( - start, end, lesson["name"], infos[1], infos[0], infos[3], infos[2] - ) - elif len(lesson["infos"].split("|")) == 1: - text = "{}-{}\ - \n{}".format( - start, end, lesson["name"] - ) - else: - print("что-то не так") - print(lesson["name"]) - - return text - - def parse_lesson(lesson: dict[str, str]) -> str: text = "" start, end = lesson["begin"], lesson["end"] @@ -128,6 +98,8 @@ def parse_lesson(lesson: dict[str, str]) -> str: ) for tr in lesson["teacher.room"]: + if not tr["t"] and not tr["r"]: + continue text += "\n({}) {}".format(tr["r"], tr["t"]) return text @@ -140,7 +112,7 @@ def create_schedule_tasks(manual=False): if not allow_update: return - bot.send_admin_message("Произошёл auto-update") + # bot.send_admin_message("Произошёл auto-update") allow_update = True @@ -184,27 +156,27 @@ def create_schedule_tasks(manual=False): if day == "mon": schedule.every().monday.at(start_task).do( - bot.send_message, id, text, thread_id, lesson["partity"] + bot.send_message, id, text, thread_id, lesson["parity"] ) elif day == "tue": schedule.every().tuesday.at(start_task).do( - bot.send_message, id, text, thread_id, lesson["partity"] + bot.send_message, id, text, thread_id, lesson["parity"] ) elif day == "wed": schedule.every().wednesday.at(start_task).do( - bot.send_message, id, text, thread_id, lesson["partity"] + bot.send_message, id, text, thread_id, lesson["parity"] ) elif day == "thu": schedule.every().thursday.at(start_task).do( - bot.send_message, id, text, thread_id, lesson["partity"] + bot.send_message, id, text, thread_id, lesson["parity"] ) elif day == "fri": schedule.every().friday.at(start_task).do( - bot.send_message, id, text, thread_id, lesson["partity"] + bot.send_message, id, text, thread_id, lesson["parity"] ) elif day == "sat": schedule.every().saturday.at(start_task).do( - bot.send_message, id, text, thread_id, lesson["partity"] + bot.send_message, id, text, thread_id, lesson["parity"] ) return @@ -311,8 +283,16 @@ def get_schedule(id: str, day: str) -> str: ) for lesson in schdl_today: - text += "•" + parse_lesson(lesson) + "\n\n" + str_lesson = parse_lesson(lesson) + if str_lesson: + text += "•" + str_lesson + "\n\n" except: return "Расписания твоей группы нет" return text + + +if __name__ == "__main__": + print(groups_in_json()) + + pass diff --git a/json/groups/groups.json b/json/groups/groups.json index 12ad73b..f77e36a 100644 --- a/json/groups/groups.json +++ b/json/groups/groups.json @@ -1,4 +1,26 @@ [ + "101", + "102", + "103", + "104", + "105", + "106", + "107", + "108", + "109", + "110", + "111", + "112", + "113", + "114", + "115", + "116", + "117", + "118", + "119", + "120", + "141", + "142", "201", "202", "203", diff --git a/schedules.py b/schedules.py index 092aa83..a00a8c2 100644 --- a/schedules.py +++ b/schedules.py @@ -10,7 +10,7 @@ from admin import admin_command, is_admin, send_admin_message, send_admin_docume config = yaml.safe_load(open("config.yaml")) bot = telebot.TeleBot(config["test_token"]) -PARTITY_FIRST = 1 +parity_FIRST = 1 @bot.message_handler(commands=["help", "faq"]) @@ -67,7 +67,7 @@ def test(message): @admin_command def restart_bot(message): send_admin_message("bye") - os.execv(sys.executable, ["python"] + sys.argv) + os.execv(sys.executable, ["python3", "-u"] + sys.argv) @bot.message_handler(commands=["update"]) @@ -147,7 +147,7 @@ def spam(message): def spam_msg(message): if message.text == "stop" or message.text == "стоп" or message.text[0] == "/": - send_admin_message("Отмена отпраки") + send_admin_message("Отмена отправки") return send_admin_message("Пришли мне текст для рассылки сообщения этим пользователям") @@ -159,7 +159,7 @@ def spam_msg(message): def spam_cnf(message, data): if message.text == "stop" or message.text == "стоп" or message.text[0] == "/": - send_admin_message("Отмена отпраки") + send_admin_message("Отмена отправки") return global text_spam @@ -197,7 +197,7 @@ def spam_cnf(message, data): @bot.callback_query_handler(func=lambda call: "spam" in call.data) def spam_send(call): if call.data == "spam_no": - send_admin_message("Отмена отпраки") + send_admin_message("Отмена отправки") return tmp, data = call.data.split("#") @@ -314,17 +314,14 @@ def start(message): send_message(message.chat.id, start_txt) markup = types.InlineKeyboardMarkup() - for i in for_json.groups_in_json(): - markup.add(types.InlineKeyboardButton(text=i, callback_data=i)) + # for i in for_json.groups_in_json(): + # markup.add(types.InlineKeyboardButton(text=i, callback_data=i)) + markup.add(types.InlineKeyboardButton(text="1 курс", callback_data="1course")) + markup.add(types.InlineKeyboardButton(text="2 курс", callback_data="2course")) - markup.add( - types.InlineKeyboardButton( - text="Моей группы нет в этом списке", callback_data="other" - ) - ) bot.send_message( message.chat.id, - "Пожалуйста, выбери свою группу", + "Пожалуйста, выбери свой курс", parse_mode=ParseMode.HTML, reply_markup=markup, ) @@ -333,9 +330,36 @@ def start(message): @bot.callback_query_handler( - func=lambda call: call.data in for_json.groups_in_json() or call.data == "other" + func=lambda call: call.data in for_json.groups_in_json() + or call.data in ["other", "1course", "2course"] ) def callback_inline(call): + if "course" in call.data: + course = call.data[0] + + markup = types.InlineKeyboardMarkup() + for i in [i for i in for_json.groups_in_json() if i[0] == course]: + markup.add(types.InlineKeyboardButton(text=i, callback_data=i)) + + markup.add( + types.InlineKeyboardButton( + text="Моей группы нет в этом списке", callback_data="other" + ) + ) + + bot.edit_message_text( + text="Пожалуйста, выбери свою группу", + chat_id=call.message.chat.id, + message_id=call.message.message_id, + reply_markup=markup, + ) + + # bot.edit_message_reply_markup( + # call.message.chat.id, call.message.message_id, reply_markup=markup + # ) + + return + infos = [ call.from_user.id, call.from_user.first_name, @@ -350,8 +374,7 @@ def callback_inline(call): bot.edit_message_text( chat_id=call.message.chat.id, message_id=call.message.message_id, - text="Используй команду /request \ - и напиши номер группы, которую хочешь добавить\ + text="Используй команду /request и напиши номер группы, которую хочешь добавить\ \nПосле создания расписания для твоей группы, я пришлю тебе сообщение", parse_mode=ParseMode.HTML, ) @@ -609,7 +632,7 @@ def request(message): def send_request(message): if message.text == "stop" or message.text == "стоп" or message.text[0] == "/": - send_message(message.from_user.id, "Отмена отпраки") + send_message(message.from_user.id, "Отмена отправки") return infos = [ @@ -658,15 +681,15 @@ def text_message(message): return -def send_message(id, text, thread_id="General", partity=None): +def send_message(id, text, thread_id="General", parity=None): if thread_id == "General": thread_id = None - if partity: + if parity: count_of_weeks = (datetime.now() - datetime(2024, 2, 5)).days // 7 - is_odd = (count_of_weeks + 1) % 2 == PARTITY_FIRST + is_odd = (count_of_weeks + 1) % 2 == parity_FIRST - if is_odd != bool(partity): + if is_odd != bool(parity): return try: @@ -691,8 +714,8 @@ def send_message(id, text, thread_id="General", partity=None): text_error = "Error from user: @{} {}\n{}".format( for_json.return_infos(id)["username"], id, str(e) ) - send_admin_message(text_error) - print(id, e) + # send_admin_message(text_error) + print(f"--- {text_error} ---") return From 653364b8a6e7c444e6a3b6f9cfabd12580cb72b2 Mon Sep 17 00:00:00 2001 From: kr0sh512 Date: Sat, 14 Sep 2024 14:05:08 +0300 Subject: [PATCH 10/10] Update requirements.txt, readme.md and .gitignore now groups schedule in yaml format --- .gitignore | 3 + README.md | 83 +++++++++- convert_into_yaml.py | 40 +++++ for_json.py | 20 +-- json/{groups => }/groups.json | 0 json/groups/202.json | 60 -------- json/schedule_expl.json | 282 ---------------------------------- requirements.txt | 4 + schedules.py | 16 +- yaml_groups/202.yaml | 201 ++++++++++++++++++++++++ 10 files changed, 352 insertions(+), 357 deletions(-) create mode 100644 convert_into_yaml.py rename json/{groups => }/groups.json (100%) delete mode 100644 json/groups/202.json delete mode 100644 json/schedule_expl.json create mode 100644 requirements.txt create mode 100644 yaml_groups/202.yaml diff --git a/.gitignore b/.gitignore index 73243d0..a14b345 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ json_remake script.py nohup.out config.yaml +old_files/ +yaml_groups/* +!yaml_groups/202.yaml \ No newline at end of file diff --git a/README.md b/README.md index 5c6a447..eb259f0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,81 @@ -# Telegram-bot-schedule - Прямо сейчас бот работает здесь: https://t.me/vmk_schedule_bot +# Telegram Bot Schedule +This project is a Telegram bot designed to manage and display schedules. The bot can help users keep track of their daily activities, appointments, and events. + +## Features + +- View preloaded schedules +- Group schedules for better organization +- Receive reminders for upcoming events +- User-friendly commands and interface + +## Installation + +1. Clone the repository: + ```sh + git clone https://github.com/yourusername/Telegram-bot-schedule.git + ``` +2. Navigate to the project directory: + ```sh + cd Telegram-bot-schedule + ``` +3. Install the required dependencies: + ```sh + pip install -r requirements.txt + ``` + +## Usage + +1. Create a new bot on Telegram and get the API token. +2. Set the API token in the environment variables or in a configuration file. +3. You need to create schedules files for groups. +4. Run the bot: + ```sh + python bot.py + ``` + +## Commands + +- `/start` - используй, чтобы сменить номер группы. +- `/schedule` - используй, чтобы получить расписание на сегодня. +- `/random` - сделай очередь из людей +- `/info` - используй, чтобы узнать твои настройки бота +- `/pause` - используй, чтобы прекратить получать сообщения от бота +- `/thread` - используй в нужном чате канала, чтобы бот отправлял сообщения именно туда +- `/timeout` - настрой время, когда бот будет присылать тебе сообщение +- `/request` - используй, чтобы отправить разработчику какой-то запрос +- `/source` - Страница бота на Github +- `/restart` - перезапуск бота (admin only). +- `/update` - обновление schedule задач (admin only) +- `/stats` - получание статистики (admin only) +- `/json` - получить файл пользователей и расписания (admin only) +- `/info` id_пользователя - узнать настройки пользователя (admin only) +- `/spam` - сделать рассылку (admin only) +- `/pause_all` - приостановить бота для всех (каникулы/выходные) (admin only) +- `/stop` id_пользователя - приостановить отправку сообщений для пользователя (admin only) + +## Contributing + +Contributions are welcome! Please fork the repository and create a pull request with your changes. + +## Contact + +For any questions or suggestions, please open an issue or contact the project maintainer at [gudovdo@my.msu.ru]. + +## Target Audience + +This bot is particularly useful for students to track their lessons and manage their academic schedules effectively. + +## Limitations + +- Cannot create or edit schedule entities directly +- Only works with preloaded schedules and groups + + + + + + + + + + diff --git a/convert_into_yaml.py b/convert_into_yaml.py new file mode 100644 index 0000000..c664738 --- /dev/null +++ b/convert_into_yaml.py @@ -0,0 +1,40 @@ +import os +import json +import yaml + + +def convert_json_to_yaml(json_dir, yaml_dir): + # Iterate over all files in the directory + for filename in os.listdir(json_dir): + if filename.endswith(".json"): + json_path = os.path.join(json_dir, filename) + + # Read JSON file + with open(json_path, "r", encoding="utf-8") as json_file: + data = json.load(json_file) + + # Convert to YAML + yaml_data = yaml.dump( + data, + default_flow_style=None, + encoding="utf-8", + allow_unicode=True, + width=float("inf"), + sort_keys=False, + ) + + # Write YAML file + yaml_path = os.path.join(yaml_dir, filename.replace(".json", ".yaml")) + with open(yaml_path, "wb") as yaml_file: + yaml_file.write(yaml_data) + + print("Conversion completed.") + + +if __name__ == "__main__": + json_dir = "json_remake" + yaml_dir = "yaml_groups" + + convert_json_to_yaml(json_dir, yaml_dir) + + pass diff --git a/for_json.py b/for_json.py index e8fea00..0edc58f 100644 --- a/for_json.py +++ b/for_json.py @@ -1,12 +1,12 @@ #!/usr/bin/python3.3 -import json, schedule +import json, yaml, schedule import schedules as bot from datetime import datetime path_users = "json/users.json" # Нужный путь до json файлов -# path_schedule = "json/schedule_3sem.json" -path_schedule = "json/groups/{}.json" +path_schedule = "yaml_groups/{}.yaml" path_students = "json/students.json" +path_groups = "json/groups.json" allow_update = True @@ -129,7 +129,8 @@ def create_schedule_tasks(manual=False): continue with open(path_schedule.format(group), "r", encoding="utf-8") as json_file: - schdl = json.load(json_file)["schedule"] + # schdl = json.load(json_file)["schedule"] + schdl = yaml.safe_load(json_file)["schedule"] for day in schdl: for lesson in schdl[day]: @@ -183,11 +184,11 @@ def create_schedule_tasks(manual=False): def groups_in_json() -> list[str]: - schdl = {} - with open(path_schedule.format("groups"), "r", encoding="utf-8") as json_file: - schdl = json.load(json_file) + groups = {} + with open(path_groups, "r", encoding="utf-8") as json_file: + groups = json.load(json_file) - return schdl + return groups def students_in_group(group) -> list[str]: @@ -276,7 +277,8 @@ def get_schedule(id: str, day: str) -> str: try: with open(path_schedule.format(group), "r", encoding="utf-8") as schedule_file: try: - schdl_today = json.load(schedule_file)["schedule"][day] + # schdl_today = json.load(schedule_file)["schedule"][day] + schdl_today = yaml.safe_load(schedule_file)["schedule"][day] except: return "Расписания твоей группы на {} нет".format( russian_days[days.index(day)] diff --git a/json/groups/groups.json b/json/groups.json similarity index 100% rename from json/groups/groups.json rename to json/groups.json diff --git a/json/groups/202.json b/json/groups/202.json deleted file mode 100644 index 7433f87..0000000 --- a/json/groups/202.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "studies.begin": { - "y": 2024, - "m": 9, - "d": 1 - }, - "studies.end": null, - "schedule": { - "mon": [ - { - "partity": 1, - "begin": "10:30", - "end": "12:05", - "name": "Практикум на ЭВМ", - "teacher.room": [ - { - "t": "Тюляева В.В.", - "r": "МЗ-3" - } - ], - "building": "2-й гуманитарный корпус", - "note": "Какое-то примечание", - "type": "seminar" - }, - { - "partity": null, - "begin": "10:30", - "end": "12:05", - "name": "Практикум на ЭВМ", - "teacher.room": [ - { - "t": "Тюляева В.В.", - "r": "МЗ-3" - }, - { - "t": "Тюляева В.В.", - "r": "МЗ-3" - }, - { - "t": "Тюляева В.В.", - "r": "МЗ-3" - } - ], - "building": "2-й гуманитарный корпус", - "note": "Какое-то примечание", - "type": "seminar" - }, - { - "partity": null, - "begin": "10:30", - "end": "12:05", - "name": "Практикум на ЭВМ", - "teacher.room": [], - "building": "2-й гуманитарный корпус", - "note": "Какое-то примечание", - "type": "seminar" - } - ] - } -} \ No newline at end of file diff --git a/json/schedule_expl.json b/json/schedule_expl.json deleted file mode 100644 index 1ae3328..0000000 --- a/json/schedule_expl.json +++ /dev/null @@ -1,282 +0,0 @@ -{ - "102": { - "mon": { - "8:45-10:20": { - "name": "Алгоритмы и алгоритмические языки", - "infos": "Белеванцев Андрей Андреевич|П-6" - }, - "10:30-12:05": { - "name": "Английский язык", - "infos": "Шубина Юлия Витальевна|73|Бим Мария Моисеевна|735" - }, - "12:50-14:25": { - "name": "Математический анализ", - "infos": "Лапонин Владислав Сергеевич|606" - }, - "15:00-16:30": { - "name": "Физическая культура", - "infos": "" - }, - "16:45-18:15": { - "name": "Консультация. Алгебра и геометрия", - "infos": "Руднев Сергей Геннадьевич|???" - } - }, - "tue": { - "10:30-12:05": { - "name": "Алгебра и геометрия", - "infos": "Тыртышников Евгений Евгеньевич|П-6" - }, - "12:50-14:25": { - "name": "Математический анализ", - "infos": "Садовничая Инна Викторовна|П-6" - }, - "14:35-16:10": { - "name": "Алгебра и геометрия", - "infos": "Руднев Сергей Геннадьевич|682" - }, - "16:20-17:55": { - "name": "Практикум на ЭВМ", - "infos": "Цыбров Евгений Германович|371|Кулагин Алексей Владимирович|МЗ-0" - } - }, - "wed": { - "8:45-10:20": { - "name": "Алгоритмы и алгоритмические языки", - "infos": "Белеванцев Андрей Андреевич|П-6" - }, - "10:30-12:05": { - "name": "Математический анализ", - "infos": "Лапонин Владислав Сергеевич|606" - }, - "12:50-14:25": { - "name": "Английский язык", - "infos": "Шубина Юлия Витальевна|735|Бим Мария Моисеевна|71" - } - }, - "thu": { - "8:45-10:20": { - "name": "Алгебра и геометрия", - "infos": "Тыртышников Евгений Евгеньевич|П-6" - }, - "10:30-12:05": { - "name": "Математический анализ", - "infos": "Садовничая Инна Викторовна|П-6" - }, - "12:50-14:25": { - "name": "История России", - "infos": "Чубыкин Игорь Валерьевич|523" - }, - "14:35-16:10": { - "name": "Алгебра и геометрия", - "infos": "Руднев Сергей Геннадьевич|606" - }, - "16:20-17:55": { - "name": "История России", - "infos": "Чубыкин Игорь Валерьевич|П-6" - } - }, - "fri": { - "9:00-10:30": { - "name": "Физическая культура", - "infos": "" - }, - "10:40-12:15": { - "name": "Безопасность жизнедеятельности", - "infos": "Сладкова Наталья Валерьевна|609" - }, - "12:50-14:25": { - "name": "Практикум на ЭВМ", - "infos": "Цыбров Евгений Германович|371|Кулагин Алексей Владимирович|МЗ-0" - } - } - }, - "103": { - "mon": { - "8:45-10:20": { - "name": "Алгоритмы и алгоритмические языки", - "infos": "Белеванцев Андрей Андреевич|П-6" - }, - "10:30-12:05": { - "name": "Математический анализ", - "infos": "Зайцева Наталья Владимировна|71" - }, - "12:50-14:25": { - "name": "Практикум на ЭВМ", - "infos": "Кузьменкова Евгения Анатольевна|731|Малышев Никита Евгеньевич|778" - }, - "15:00-16:30": { - "name": "Физическая культура", - "infos": "" - } - }, - "tue": { - "8:45-10:20": { - "name": "Консультация. Алгебра и геометрия", - "infos": "Будак Александр Борисович|612" - }, - "10:30-12:05": { - "name": "Алгебра и геометрия", - "infos": "Тыртышников Евгений Евгеньевич|П-6" - }, - "12:50-14:25": { - "name": "Математический анализ", - "infos": "Садовничая Инна Викторовна|П-6" - }, - "14:35-16:10": { - "name": "Английский язык", - "infos": "Плиева Сима Ивановна|783|Дзампова Татьяна Борисовна|736" - }, - "16:20-17:55": { - "name": "Английский язык", - "infos": "Дзампова Татьяна Борисовна|736" - } - }, - "wed": { - "8:45-10:20": { - "name": "Алгоритмы и алгоритмические языки", - "infos": "Белеванцев Андрей Андреевич|П-6" - }, - "10:30-12:05": { - "name": "Математический анализ", - "infos": "Зайцева Наталья Владимировна|72" - }, - "12:50-14:25": { - "name": "Алгебра и геометрия", - "infos": "Будак Александр Борисович|605" - } - }, - "thu": { - "8:45-10:20": { - "name": "Алгебра и геометрия", - "infos": "Тыртышников Евгений Евгеньевич|П-6" - }, - "10:30-12:05": { - "name": "Математический анализ", - "infos": "Садовничая Инна Викторовна|П-6" - }, - "12:50-14:25": { - "name": "Алгебра и геометрия", - "infos": "Будак Александр Борисович|605" - }, - "14:35-16:10": { - "name": "Английский язык", - "infos": "Плиева Сима Ивановна|783" - }, - "16:20-17:55": { - "name": "История России", - "infos": "Чубыкин Игорь Валерьевич|П-6" - } - }, - "fri": { - "9:00-10:30": { - "name": "Физическая культура", - "infos": "" - }, - "10:40-12:15": { - "name": "Безопасность жизнедеятельности", - "infos": "Гимишли Николай Федосеевич|614" - }, - "12:50-14:25": { - "name": "Практикум на ЭВМ", - "infos": "Кузьменкова Евгения Анатольевна|248|Малышев Никита Евгеньевич|780" - }, - "14:35-16:10": { - "name": "История России", - "infos": "Чубыкин Игорь Валерьевич|523" - } - } - }, - "105": { - "mon": { - "8:45-10:20": { - "name": "Алгоритмы и алгоритмические языки", - "infos": "Белеванцев Андрей Андреевич|П-6" - }, - "10:30-12:05": { - "name": "Математический анализ", - "infos": "Никитин Алексей Антонович|72" - }, - "12:15-13:40": { - "name": "Алгебра и геометрия", - "infos": "Лебедева Ольга Сергеевна|508|Замарашкин Николай Леонидович|508" - }, - "15:00-16:30": { - "name": "Физическая культура", - "infos": "" - } - }, - "tue": { - "10:30-12:05": { - "name": "Алгебра и геометрия", - "infos": "Тыртышников Евгений Евгеньевич|П-6" - }, - "12:50-14:25": { - "name": "Математический анализ", - "infos": "Садовничая Инна Викторовна|П-6" - }, - "14:35-16:10": { - "name": "Английский язык", - "infos": "Лаптинова Анастасия Ильинична|73|Кашелкина Ольга Александровна|790" - }, - "16:20-17:55": { - "name": "Практикум на ЭВМ", - "infos": "Русол Андрей Владимирович|МЗ-4|Гуляев Анатолий Викторович|574" - } - }, - "wed": { - "8:45-10:20": { - "name": "Алгоритмы и алгоритмические языки", - "infos": "Белеванцев Андрей Андреевич|П-6" - }, - "10:30-12:05": { - "name": "Математический анализ", - "infos": "Никитин Алексей Антонович|778" - }, - "12:50-14:25": { - "name": "Алгебра и геометрия", - "infos": "Лебедева Ольга Сергеевна|506|Замарашкин Николай Леонидович|506" - } - }, - "thu": { - "8:45-10:20": { - "name": "Алгебра и геометрия", - "infos": "Тыртышников Евгений Евгеньевич|П-6" - }, - "10:30-12:05": { - "name": "Математический анализ", - "infos": "Садовничая Инна Викторовна|П-6" - }, - "12:50-14:25": { - "name": "История России", - "infos": "Чубыкин Игорь Валерьевич|523" - }, - "14:35-16:10": { - "name": "Английский язык", - "infos": "Лаптинова Анастасия Ильинична|71|Кашелкина Ольга Александровна|736" - }, - "16:20-17:55": { - "name": "История России", - "infos": "Чубыкин Игорь Валерьевич|П-6" - } - }, - "fri": { - "9:00-10:30": { - "name": "Физическая культура", - "infos": "" - }, - "10:40-12:15": { - "name": "Консультация. Математический анализ", - "infos": "Никитин Алексей Антонович|72" - }, - "12:50-14:25": { - "name": "Практикум на ЭВМ", - "infos": "Русол Андрей Владимирович|МЗ-4|Гуляев Анатолий Викторович|574" - }, - "14:35-16:10": { - "name": "Безопасность жизнедеятельности", - "infos": "Гимишли Николай Федосеевич|614" - } - } - } -} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..47f0fd0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +python-telegram-bot==13.7 +requests==2.26.0 +python-dotenv==0.19.0 +schedule==1.1.0 \ No newline at end of file diff --git a/schedules.py b/schedules.py index a00a8c2..a093dd3 100644 --- a/schedules.py +++ b/schedules.py @@ -398,7 +398,15 @@ def send_schedule(message): day = datetime.today().strftime("%A").lower()[:3] # mon tue ... text = for_json.get_schedule(message.chat.id, day) except Exception as e: - send_admin_message("Schedule error from: {} \n\n {}".format(message.chat.id, e)) + # send_admin_message( + # "Schedule error from: {} \n\n {}".format(message.chat.id, str(e)) + # ) + bot.send_message( + message.chat.id, + "Пожалуйста, проверь, что ты зарегестрировался с помощью команды /start", + ParseMode.HTML, + message_thread_id=message.message_thread_id, + ) markup = types.InlineKeyboardMarkup() markup.add( @@ -586,7 +594,7 @@ def change_thread(message): def set_timeout(message): send_message( message.chat.id, - "Пришли мне число от 1 до 60. \ + "Пришли мне число от 1 до 59. \ \nЭто будет количество минут, за которое я буду присылать тебе напоминание о паре (По умолчанию: 10)", ) bot.register_next_step_handler(message, save_timeout) @@ -597,7 +605,7 @@ def set_timeout(message): def save_timeout(message): if ( str(message.text).isdigit() - and int(message.text) <= 60 + and int(message.text) <= 59 and int(message.text) >= 1 ): for_json.change_user_param(message.chat.id, "timeout", str(message.text)) @@ -610,7 +618,7 @@ def save_timeout(message): else: send_message( message.chat.id, - "Пожалуйста, пришли число от 1 до 60. \ + "Пожалуйста, пришли число от 1 до 59. \ \nПо умолчанию: 10", ) send_message(message.chat.id, "Изменения не были внесены") diff --git a/yaml_groups/202.yaml b/yaml_groups/202.yaml new file mode 100644 index 0000000..7dde3c7 --- /dev/null +++ b/yaml_groups/202.yaml @@ -0,0 +1,201 @@ +studies.begin: {y: 2024, m: 9, d: 1} +studies.end: null +schedule: + mon: + - begin: '8:45' + end: '10:20' + name: Английский язык + teacher.room: + - {t: Бим М.М., r: '735'} + - {t: ' Шубина Ю.В.', r: '73'} + type: seminar + parity: null + - begin: '10:30' + end: '12:05' + name: Практикум на ЭВМ + teacher.room: + - {t: Тюляева В.В., r: МЗ-4} + - {t: '', r: null} + type: seminar + parity: null + - begin: '12:15' + end: '13:50' + name: Классическая механика + teacher.room: + - {t: Брандт Н.Н., r: '659'} + type: seminar + parity: null + - begin: '15:00' + end: '16:30' + name: Физическая культура + teacher.room: [] + type: null + parity: null + tue: + - begin: '8:45' + end: '10:20' + name: Теория вероятностей и математическая статистика + teacher.room: + - {t: профессор Королёв Виктор Юрьевич, r: П-13} + type: lecture + parity: null + - begin: '10:30' + end: '12:05' + name: Математический анализ + teacher.room: + - {t: доцент Крицков Леонид Владимирович, r: П-11} + type: lecture + parity: null + - begin: '12:15' + end: '13:50' + name: Математический анализ + teacher.room: + - {t: Сычугов Д.Ю., r: '606'} + type: seminar + parity: null + - begin: '14:35' + end: '16:10' + name: Обыкновенные дифференциальные ур-я + teacher.room: + - {t: Дмитриева И.В., r: '607'} + type: seminar + parity: null + - begin: '16:20' + end: '17:55' + name: null + teacher.room: [] + type: seminar + parity: null + wed: + - begin: '8:45' + end: '10:20' + name: Практикум на ЭВМ + teacher.room: + - {t: Тюляева В.В., r: '507'} + type: seminar + parity: null + - begin: '10:30' + end: '12:05' + name: Математический анализ + teacher.room: + - {t: доцент Крицков Леонид Владимирович, r: П-6} + type: lecture + parity: null + - begin: '12:15' + end: '13:50' + name: Обыкновенные дифференциальные уравнения + teacher.room: + - {t: профессор Денисов Александр Михайлович, r: П-6} + type: lecture + parity: null + - begin: '15:10' + end: '18:50' + name: Межфакультетские курсы + teacher.room: [] + type: seminar + parity: null + thu: + - begin: '8:45' + end: '10:20' + name: Операционные системы + teacher.room: + - {t: профессор Машечкин Игорь Валерьевич, r: П-13} + type: lecture + parity: null + - begin: '10:30' + end: '12:05' + name: Операционные системы + teacher.room: + - {t: профессор Машечкин Игорь Валерьевич, r: П-13} + type: lecture + parity: null + - begin: '12:15' + end: '13:50' + name: Английский язык + teacher.room: + - {t: Бим М.М., r: '71'} + - {t: '', r: null} + type: seminar + parity: null + - begin: '14:35' + end: '16:10' + name: Введение в численные методы + teacher.room: + - {t: доцент Нефёдов Владимир Вадимович, r: П-5} + type: lecture + parity: null + - begin: '16:20' + end: '17:55' + name: null + teacher.room: [] + type: seminar + parity: null + fri: + - begin: '8:45' + end: '10:20' + name: Английский язык + teacher.room: + - {t: Шубина Ю.В., r: '506'} + type: seminar + parity: null + - begin: '10:50' + end: '12:20' + name: Физическая культура + teacher.room: [] + type: null + parity: null + - begin: '12:50' + end: '14:25' + name: Теория вероятностей и математич. статистика + teacher.room: + - {t: Шевцова И.Г., r: '504'} + type: seminar + parity: null + - begin: '14:35' + end: '16:10' + name: Математический анализ + teacher.room: + - {t: Сычугов Д.Ю., r: '615'} + type: seminar + parity: null + - begin: '16:20' + end: '17:55' + name: null + teacher.room: [] + type: seminar + parity: null + sat: + - begin: '8:45' + end: '10:20' + name: Философия + teacher.room: + - {t: профессор Девятова Светлана Владимировна, r: П-14} + type: lecture + parity: null + - begin: '10:30' + end: '12:05' + name: Философия Девятова С.В. + teacher.room: + - {t: null, r: '508'} + type: seminar + parity: null + - begin: '12:15' + end: '13:50' + name: null + teacher.room: [] + type: seminar + parity: null + - begin: '14:35' + end: '16:10' + name: Операционные системы + teacher.room: + - {t: профессор Машечкин Игорь Валерьевич, r: П-13} + type: lecture + parity: null + - begin: '16:20' + end: '17:55' + name: Операционные системы + teacher.room: + - {t: профессор Машечкин Игорь Валерьевич, r: П-13} + type: lecture + parity: null