浏览代码

Добавлена возможность выбрать месяц
Добавлено автоматическое оповещенеие пользователей о статусе заявок

vmshay 2 年之前
父节点
当前提交
9944e722ba
共有 11 个文件被更改,包括 115 次插入93 次删除
  1. 0 1
      bot/config.py
  2. 4 1
      bot/database.py
  3. 2 2
      bot/dispatcher.py
  4. 9 1
      bot/functions.py
  5. 6 8
      bot/keyboards.py
  6. 1 1
      bot/sql.py
  7. 13 12
      draft.py
  8. 2 2
      handlers/admin/manage_events.py
  9. 6 3
      handlers/admin/manage_users.py
  10. 65 54
      handlers/user/make_events.py
  11. 7 8
      handlers/user/registration.py

+ 0 - 1
bot/config.py

@@ -7,7 +7,6 @@ env_path = '.env'
 load_dotenv(dotenv_path=env_path)
 
 BOT_TOKEN = os.getenv('BOT_TOKEN')
-BOT_TOKEN_TEST = os.getenv('BOT_TOKEN_TEST')
 DB_HOST = os.getenv('DB_HOST')
 DB_NAME = os.getenv('DB_NAME')
 DB_USER = os.getenv('DB_USER')

+ 4 - 1
bot/database.py

@@ -60,7 +60,10 @@ class Database:
             return False
         elif len(result_set) > 0:
             for row in result_set:
-                users_data = {"ID": row['id'], "ФИО": row['name'], "Номер телефона": row['phone']}
+                users_data = {"ID": row['id'],
+                              "ФИО": row['name'],
+                              "Номер телефона": row['phone'],
+                              "tg_id": row['tg_id']}
                 users_list.append(users_data)
             return users_list
 

+ 2 - 2
bot/dispatcher.py

@@ -1,8 +1,8 @@
 from aiogram import Bot
 from aiogram.dispatcher import Dispatcher
-from bot.config import BOT_TOKEN_TEST
+from bot.config import BOT_TOKEN
 from aiogram.contrib.fsm_storage.memory import MemoryStorage
 
 
-bot = Bot(token=BOT_TOKEN_TEST, parse_mode="HTML", disable_web_page_preview=True)
+bot = Bot(token=BOT_TOKEN, parse_mode="HTML", disable_web_page_preview=True)
 dp = Dispatcher(bot, storage=MemoryStorage())

+ 9 - 1
bot/functions.py

@@ -166,7 +166,6 @@ def check_overlap(start, end, date):
     return not it.overlaps(start, end)
 
 
-
 def parse_events(data):
     events_list = []
     for elem in data:
@@ -181,3 +180,12 @@ def parse_events(data):
         events_list.append(event)
     return events_list
 
+
+def month_text(data):
+    months = ["Январь","Февраль","Март",
+              "Апрель","Май","Июнь",
+              "Июль","Август","Сентябрь",
+              "Октябрь","Ноябрь","Декабрь"]
+    return months[data]
+
+

+ 6 - 8
bot/keyboards.py

@@ -1,7 +1,5 @@
 from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardMarkup, KeyboardButton
-import calendar
-import datetime
-
+from bot.functions import month_text
 
 # Основная
 button_bind = KeyboardButton('🎯 Запланировать мероприятие')
@@ -57,7 +55,7 @@ def events_range_kb():
     today_button = InlineKeyboardButton(text="За сегодня", callback_data="today")
     week_button = InlineKeyboardButton(text="За неделю", callback_data="week")
     month_button = InlineKeyboardButton(text="За месяц", callback_data="month")
-    keyboard.add(today_button,week_button,month_button)
+    keyboard.add(today_button, week_button, month_button)
     return keyboard
 
 
@@ -72,18 +70,18 @@ def events_kb():
     keyboard = InlineKeyboardMarkup()
     booking_button = InlineKeyboardButton(text='Забронировать', callback_data="booking")
     back_button = InlineKeyboardButton(text='Отменить', callback_data="change")
-    keyboard.add(back_button,booking_button)
-    # keyboard.add(booking_button)
+    keyboard.add(back_button, booking_button)
     return keyboard
 
 
 # Генератор календаря
 def make_calendar(month, days_in_month, m_prev, m_next):
-
+    mont_text = InlineKeyboardButton(text=month_text(month-1), callback_data='NULL')
     keyboard = InlineKeyboardMarkup(row_width=7)
     prev_month = InlineKeyboardButton(text="<<", callback_data=m_prev)
     next_month = InlineKeyboardButton(text=">>", callback_data=m_next)
 
+    keyboard.row_width = 7
     for i in range(1, days_in_month+1, 1):
         if i < 10:
             day = f"0{i}"
@@ -92,6 +90,6 @@ def make_calendar(month, days_in_month, m_prev, m_next):
         date_i = InlineKeyboardButton(text=str(i), callback_data=f"date_2022-{str(month)}-{str(day)}")
         keyboard.insert(date_i)
 
-    # keyboard.add(button_today, button_tomorrow, button_after_tomorrow)
+    keyboard.add(mont_text)
     keyboard.add(prev_month, next_month)
     return keyboard

+ 1 - 1
bot/sql.py

@@ -58,7 +58,7 @@ def sql_send_event(data):
 
 
 def sql_manage_events():
-    sql = f"select events_table.id, user_table.name, user_table.phone, events_table.description, events_table.e_date, events_table.e_start, events_table.e_end from events_table inner join user_table on events_table.owner = user_table.tg_id WHERE events_table.approved = 0"
+    sql = f"select user_table.tg_id, events_table.id, user_table.name, user_table.phone, events_table.description, events_table.e_date, events_table.e_start, events_table.e_end from events_table inner join user_table on events_table.owner = user_table.tg_id WHERE events_table.approved = 0"
     return sql
 
 

+ 13 - 12
draft.py

@@ -1,12 +1,13 @@
-import calendar
-import datetime
-
-today = datetime.date.today()
-month = today.month
-days_in_month = calendar.monthrange(today.year, month)[1]
-
-
-print(f"Дата сегодня {today}")
-print(f"Месяц {month}")
-print(f"Дней в месяце {days_in_month}")
-
+# def month_text(data):
+#     months = ["Январь","Февраль","Март",
+#               "Апрель","Май","Июнь",
+#               "Июль","Август","Сентябрь",
+#               "Октябрь","Ноябрь","Декабрь"]
+#     return months[data]
+#
+#
+# print(month_text(11))
+from datetime import datetime
+
+print("2022-10-25" > "2022-9-25")
+print(datetime.now())

+ 2 - 2
handlers/admin/manage_events.py

@@ -3,7 +3,7 @@ from bot import database
 from bot.functions import parse_events, beauty_event_request
 from bot.keyboards import register_kb,manage_kb
 from bot import sql
-
+from bot.dispatcher import bot
 
 async def list_events(message: types.Message):
     db = database.Database()
@@ -55,7 +55,7 @@ async def accept_event(call: types.CallbackQuery):
     db = database.Database()
     events = db.sql_fetchall(sql.sql_manage_events())
     index = int(call.message.reply_markup.inline_keyboard[1][1].text.split("/")[0])-1
-
+    await bot.send_message(events[index]['tg_id'], "Заявка на мероприятие одобрена")
     if len(events) == 1:
         event_id = events[index]['id']
         db.sql_query_send(f"UPDATE booking.events_table SET approved='1' WHERE id={event_id}")

+ 6 - 3
handlers/admin/manage_users.py

@@ -2,6 +2,7 @@ from bot import database
 from aiogram import types, Dispatcher
 from bot.functions import beauty_reg_request
 from bot.keyboards import manage_kb, register_kb
+from bot.dispatcher import bot
 
 
 async def list_users(message: types.Message):
@@ -10,10 +11,10 @@ async def list_users(message: types.Message):
             not db.sql_fetchone(sql=f"select approved from user_table where tg_id={message.from_user.id}"):
         await message.delete()
         await message.answer("Команды станут доступны после регистрации", reply_markup=register_kb)
-    if not db.sql_parse_users("select id,name,phone from user_table where approved = '0'"):
+    if not db.sql_parse_users("select id,name,tg_id,phone from user_table where approved = '0'"):
         await message.answer('Заявки на регистрацию отсутствуют')
     else:
-        data = db.sql_parse_users("select id,name,phone from user_table where approved = '0'")
+        data = db.sql_parse_users("select id,name,tg_id,phone from user_table where approved = '0'")
         await message.answer(beauty_reg_request(data[0]),
                              reply_markup=manage_kb(f"u_accept:{data[0]['ID']}", f"u_deny:{data[0]['ID']}", f"u_next:0",
                                                     f"u_prev:0", f"1/{len(data)}"))
@@ -52,7 +53,7 @@ async def prev_user_page(call: types.CallbackQuery):
 
 async def accept_user(call: types.CallbackQuery):
     db = database.Database()
-    data = db.sql_parse_users("select id,name,phone from user_table where approved = '0'")
+    data = db.sql_parse_users("select id,name,phone,tg_id from user_table where approved = '0'")
     index = int(call.message.reply_markup.inline_keyboard[1][1].text.split("/")[0])-1
 
     if len(data) == 1:
@@ -60,12 +61,14 @@ async def accept_user(call: types.CallbackQuery):
         db.sql_query_send(f"UPDATE booking.user_table SET approved='1' WHERE id={user_id}")
         await call.message.delete()
         await call.message.answer('Заявки на регистрацию отсутствуют')
+        await bot.send_message(data[index]["tg_id"], "Заявка на регистрацию одобрена")
     elif index == 0:
         user_id = data[index]['ID']
         db.sql_query_send(f"UPDATE booking.user_table SET approved='1' WHERE id={user_id}")
         await call.message.edit_text(beauty_reg_request(data[index+1]),
                                      reply_markup=manage_kb(f"u_accept:{user_id}", f"u_deny:{user_id}", f"u_next:{index + 1}",
                                                             f"u_prev:{index + 1}", f"{index + 1}/{len(data) - 1}"))
+
     elif index == len(data)-1:
         user_id = data[index]['ID']
         db.sql_query_send(f"UPDATE booking.user_table SET approved='1' WHERE id={user_id}")

+ 65 - 54
handlers/user/make_events.py

@@ -7,12 +7,12 @@ from handlers.user.states import BookingState
 from aiogram.dispatcher.storage import FSMContext
 from bot import messages
 from handlers.admin.notifications import new_event
-import datetime
+from datetime import date, datetime
 import calendar
 
 
 async def make_event(message: types.message):
-    today = datetime.date.today()
+    today = date.today()
     month = today.month
     days_in_month = calendar.monthrange(today.year, month)[1]
     db = database.Database()
@@ -23,56 +23,74 @@ async def make_event(message: types.message):
     else:
         if message.text == "🎯 Запланировать мероприятие":
             await message.delete()
-            # TODO: Добавить переход на следующий месяц
-
             await message.answer(messages.events_welcome(make_date()), reply_markup=make_calendar(month,
                                                                                                   days_in_month,
-                                                                                                  'month_prev:0',
-                                                                                                  'month_next:0'))
-            # await message.answer(messages.events_welcome(make_date()), reply_markup=make_calendar())
-            # await asyncio.sleep(60)
-            # await msg.delete()
+                                                                                                  f"month_prev:{month}",
+                                                                                                  f"month_next:{month}"))
 
 
 async def select_date(call: types.CallbackQuery, state: FSMContext):
     db = database.Database()
     date = call.data.split("_")[1]
     booked = db.sql_fetchall(sql.sql_booked_time(date))
-    today = datetime.datetime.now()
-    if date >= datetime.datetime.strftime(today, '%Y-%m-%d'):
+    today = datetime.strftime(datetime.today(), '%Y-%m-%d')
+    t_day = today.split("-")[2]
+    t_month = today.split("-")[1]
+
+    if int(date.split("-")[1]) == int(t_month):
+        if int(date.split("-")[2]) >= int(t_day):
+            if len(booked) == 0:
+                await BookingState.start.set()
+                await state.update_data(date=to_quotes(date))
+                await state.update_data(owner=call.from_user.id)
+                await call.message.edit_text(f"Вы выбрали дату: {date}\n"
+                                             f"На этот день мероприятий не запланированно", reply_markup=events_kb())
+            else:
+                await BookingState.start.set()
+                await state.update_data(date=to_quotes(date))
+                await state.update_data(owner=call.from_user.id)
+                await call.message.edit_text(f"Вы выбрали дату: {date}\n\n"
+                                             f"Занятое время\n\n"
+                                             f"{beauty_booked_time(sorted(booked, key=lambda t: t['e_start'], reverse=False))}",
+                                             reply_markup=events_kb())
+        else:
+            msg = await call.message.answer("Нельзя выбрать дату позже сегодняшней")
+            await asyncio.sleep(5)
+            await msg.delete()
+    elif int(date.split("-")[1]) > int(t_month):
         if len(booked) == 0:
             await BookingState.start.set()
             await state.update_data(date=to_quotes(date))
             await state.update_data(owner=call.from_user.id)
             await call.message.edit_text(f"Вы выбрали дату: {date}\n"
-                                               f"На этот день мероприятий не запланированно", reply_markup=events_kb())
-            # await asyncio.sleep(30)
-            # await msg.delete()
+                                         f"На этот день мероприятий не запланированно", reply_markup=events_kb())
         else:
             await BookingState.start.set()
             await state.update_data(date=to_quotes(date))
             await state.update_data(owner=call.from_user.id)
             await call.message.edit_text(f"Вы выбрали дату: {date}\n\n"
-                                               f"Занятое время\n\n"
-                                               f"{beauty_booked_time(sorted(booked, key=lambda t: t['e_start'], reverse=False))}",
-                                               reply_markup=events_kb())
-            # await asyncio.sleep(60)
-            # await msg.delete()
+                                         f"Занятое время\n\n"
+                                         f"{beauty_booked_time(sorted(booked, key=lambda t: t['e_start'], reverse=False))}",
+                                         reply_markup=events_kb())
     else:
-        await call.message.answer("Нельзя выбрать дату позже сегодняшней")
-        # await asyncio.sleep(5)
-        # await msg.delete()
+        msg = await call.message.answer("Нельзя выбрать дату позже сегодняшней")
+        await asyncio.sleep(5)
+        await msg.delete()
 
 
 async def edit_date(call: types.CallbackQuery, state: FSMContext):
+    today = date.today()
+    month = today.month
+    days_in_month = calendar.monthrange(today.year, month)[1]
     await call.message.edit_text(f"выберите дату чтобы увидеть список мероприятий\n\n"
-                                       f"Так же календарь мероприятий можно посмотреть в "
-                                       f"<a href=moodle.tomtit-tomsk.ru>Moodle</a>\n\n"
-                                       f"Сегодняшняя дата <b>{make_date()}</b>", reply_markup=make_calendar(month, days_in_month))
-    await call.message.delete()
+                                 f"Так же календарь мероприятий можно посмотреть в "
+                                 f"<a href=moodle.tomtit-tomsk.ru>Moodle</a>\n\n"
+                                 f"Сегодняшняя дата <b>{make_date()}</b>", reply_markup=make_calendar(month,
+                                                                                                      days_in_month,
+                                                                                                      f"month_prev:{month}",
+                                                                                                      f"month_next:{month}"))
+
     await state.finish()
-    # await asyncio.sleep(30)
-    # await msg.delete()
 
 
 async def booking_date(call: types.CallbackQuery):
@@ -83,49 +101,36 @@ async def booking_date(call: types.CallbackQuery):
                               "10:30 14:00\n"
                               "11.50-12.30\n", reply_markup=cancel_booking())
     await BookingState.time.set()
-    # await asyncio.sleep(20)
-    # await msg.delete()
 
 
 async def get_time(message: types.Message, state: FSMContext):
     # Парсим то что ввел пользователь
     time = normalize_time(message.text)
     await message.delete()
-    # Забираем текущую дату
     date = await state.get_data()
     # Проверяем валидность времени
     if time_validator(message.text):
         # Проверяем что старт не позже конца
         if time[0] > time[1]:
             await message.answer("Начало не может быть раньше конца")
-            # await asyncio.sleep(5)
-            # await msg.delete()
         elif not check_overlap(time[0], time[1], date['date']):
-            print(time[0],time[1])
             await message.answer("Указанное время пеерсекается")
-            # await asyncio.sleep(5)
-            # await msg.delete()
+
         else:
             await state.update_data(t_start=time[0])
             await state.update_data(t_end=time[1])
-            print(time)
             await BookingState.description.set()
             await message.answer("Введите краткое описание мероприятия", reply_markup=cancel_booking())
-            # await asyncio.sleep(10)
-            # await msg.delete()
+
     else:
         await message.answer("Неверный формат времени")
-        # await asyncio.sleep(5)
-        # await msg.delete()
 
 
 async def send_event(message: types.Message, state: FSMContext):
     db = database.Database()
     if len(message.text) > 100:
         await message.answer("Описание слишком длинное")
-        # await asyncio.sleep(5)
-        # await msg.delete()
-        # await message.delete()
+
     else:
         await state.update_data(description=message.text)
         await state.update_data(approved=0)
@@ -136,19 +141,24 @@ async def send_event(message: types.Message, state: FSMContext):
                              "они получат оповощение автоматически", reply_markup=main_kb)
         await state.finish()
         db.sql_query_send(sql.sql_send_event(data))
-        # await asyncio.sleep(5)
-        # await msg.delete()
-        await new_event()
 
 
 async def next_month(call: types.CallbackQuery):
-    m_id = int(call.data.split(":")[1]) + 1
-    month = datetime.date.today().month
-    month = month-m_id
-    days_in_month = calendar.monthrange(2022, month-1)[1]
-    print(month)
-    await call.message.edit_reply_markup(reply_markup=make_calendar(month, days_in_month,
-                                                                    f"month_prev:{m_id}", f"month_next:{m_id}"))
+    m_id = int(call.data.split(":")[1])+1
+    days = calendar.monthrange(2022, m_id)[1]
+    await call.message.edit_reply_markup(reply_markup=make_calendar(m_id,
+                                                                    days,
+                                                                    f"month_prev:{m_id}",
+                                                                    f"month_next:{m_id}"))
+
+
+async def prev_month(call: types.CallbackQuery):
+    m_id = int(call.data.split(":")[1])-1
+    days = calendar.monthrange(2022, m_id)[1]
+    await call.message.edit_reply_markup(reply_markup=make_calendar(m_id,
+                                                                    days,
+                                                                    f"month_prev:{m_id}",
+                                                                    f"month_next:{m_id}"))
 
 
 def events_register(dp: Dispatcher):
@@ -161,3 +171,4 @@ def events_register(dp: Dispatcher):
     dp.register_message_handler(get_time, state=BookingState.time)
     dp.register_message_handler(send_event, state=BookingState.description)
     dp.register_callback_query_handler(next_month, text_startswith='month_next')
+    dp.register_callback_query_handler(prev_month, text_startswith='month_prev')

+ 7 - 8
handlers/user/registration.py

@@ -6,18 +6,17 @@ from bot.keyboards import reset_register_kb, register_kb, main_kb, check_registe
 from bot import database, sql
 from handlers.admin.notifications import new_user
 
+
 async def registration(message: types.Message):
     db = database.Database()
     await message.delete()
     if db.sql_fetchone(f'select tg_id from user_table where tg_id = {message.from_user.id} and approved = 0'):
         await message.answer("Ваша заявка находится на рассмотрернии", reply_markup=check_register_kb)
     elif db.sql_fetchone(f'select tg_id from user_table where tg_id = {message.from_user.id} and approved = 1'):
-        msg = await message.answer("Вы зарегистрированны", reply_markup=main_kb)
+        msg = await message.answer("Вы зарегистрированы", reply_markup=main_kb)
         await msg.delete()
     else:
-        await message.answer(f"Дkя регистрации необходимо будет указать\n"
-                             f"Номер телефона и "
-                             f"Фамилию Имя Отчество")
+        await message.answer(f"Для регистрации необходимо указать номер телефона")
 
         await message.answer(f"Введите номер телефона\n"
                              f"Возможные форматы:\n\n"
@@ -35,15 +34,15 @@ async def check_reg_status(message: types.Message):
     if db.sql_fetchone(f'select tg_id from user_table where tg_id = {message.from_user.id} and approved = 0'):
         await message.answer("Ваша заявка находится на рассмотрернии", reply_markup=check_register_kb)
     elif db.sql_fetchone(f'select tg_id from user_table where tg_id = {message.from_user.id} and approved = 1'):
-        await message.answer("Вы зарегистрированны", reply_markup=main_kb)
+        await message.answer("Вы зарегистрированы", reply_markup=main_kb)
     else:
-        await message.answer("Вы не зарегистрированны", reply_markup=register_kb)
+        await message.answer("Вы не зарегистрированы", reply_markup=register_kb)
 
 
 async def get_number(message: types.Message, state: FSMContext):
     if validate_phone(message.text):
         await state.update_data(number=message.text)
-        await message.answer(f"Теперь укажите ФИО\n"
+        await message.answer(f"Укажите ФИО\n"
                              f"Например: Иванов Иван Иванович", reply_markup=reset_register_kb)
         await RegisterStates.FIO.set()
     else:
@@ -70,7 +69,7 @@ async def get_fio(message: types.Message, state: FSMContext):
 
         db.sql_query_send(sql.sql_send(reg_data))
         await state.finish()
-        await new_user()
+        # await new_user()
 
 
 async def reset_register(message: types.Message, state: FSMContext):