refactored bot code
This commit is contained in:
@@ -1,142 +0,0 @@
|
|||||||
import os
|
|
||||||
import logging
|
|
||||||
from database.models import Students
|
|
||||||
from telebot import types
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
authenticated_users = {2032936226}
|
|
||||||
_bot = None
|
|
||||||
|
|
||||||
def get_bot():
|
|
||||||
global _bot
|
|
||||||
if _bot is None:
|
|
||||||
import telebot
|
|
||||||
BOT_TOKEN = os.environ.get("BOT_TOKEN")
|
|
||||||
_bot = telebot.TeleBot(BOT_TOKEN, threaded=False)
|
|
||||||
|
|
||||||
@_bot.message_handler(commands=["start"])
|
|
||||||
def start(message):
|
|
||||||
if message.from_user.id in authenticated_users:
|
|
||||||
_bot.reply_to(message, "authorized user! Welcome. Use /getstudents to fetch from database.")
|
|
||||||
return
|
|
||||||
_bot.reply_to(message, "Welcome! Use /getstudents to fetch from database.")
|
|
||||||
|
|
||||||
@_bot.message_handler(commands=["getstudents"])
|
|
||||||
def get_data(message):
|
|
||||||
try:
|
|
||||||
data = Students.getAllStudents()
|
|
||||||
if data:
|
|
||||||
|
|
||||||
markup = types.InlineKeyboardMarkup(row_width=2)
|
|
||||||
for row in data:
|
|
||||||
btn = types.InlineKeyboardButton(f"{row[0]}: @{row[1]}", callback_data=f"student_{row[0]}")
|
|
||||||
markup.add(btn)
|
|
||||||
|
|
||||||
_bot.send_message(message.chat.id, "Here is the data:", reply_markup=markup)
|
|
||||||
else:
|
|
||||||
_bot.reply_to(message, "No data found.")
|
|
||||||
return
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error in getdata handler: {e}")
|
|
||||||
_bot.reply_to(message, "Sorry, an error occurred.")
|
|
||||||
|
|
||||||
# Single handler for all student selections
|
|
||||||
@_bot.callback_query_handler(func=lambda call: call.data.startswith('student_'))
|
|
||||||
def show_student_details(call):
|
|
||||||
student_id = call.data.split('_')[1]
|
|
||||||
student = Students.getStudentById(student_id)
|
|
||||||
|
|
||||||
if student:
|
|
||||||
details = format_student_info(student)
|
|
||||||
markup = types.InlineKeyboardMarkup()
|
|
||||||
markup.add(types.InlineKeyboardButton("🔙 Back", callback_data="back_to_students"))
|
|
||||||
_bot.send_message(call.message.chat.id, details, reply_markup=markup, parse_mode="HTML")
|
|
||||||
else:
|
|
||||||
_bot.send_message(call.message.chat.id, "Student not found.")
|
|
||||||
|
|
||||||
def format_student_info(student):
|
|
||||||
"""
|
|
||||||
Format student data into a nice message
|
|
||||||
student is a tuple: (id, username, created_at, email, phone_number, last_seen, is_verified, birthday)
|
|
||||||
"""
|
|
||||||
print(student);
|
|
||||||
id, username, created_at, email, phone_number, last_seen, is_verfied, birthday = student
|
|
||||||
|
|
||||||
verified_status = "✅ Verified" if is_verfied else "❌ Not Verified"
|
|
||||||
|
|
||||||
# Format dates nicely
|
|
||||||
created_date = format_date(created_at)
|
|
||||||
last_seen_date = format_date(last_seen)
|
|
||||||
|
|
||||||
# Calculate age from birthday
|
|
||||||
age = calculate_age(birthday)
|
|
||||||
|
|
||||||
details = f"""
|
|
||||||
<b>👤 Student Profile</b>
|
|
||||||
|
|
||||||
<b>Username:</b> {username}
|
|
||||||
<b>Email:</b> {email}
|
|
||||||
<b>Phone:</b> {phone_number}
|
|
||||||
<b>Birthday:</b> {birthday} (Age: {age})
|
|
||||||
<b>Account Status:</b> {verified_status}
|
|
||||||
|
|
||||||
<b>📅 Account Info</b>
|
|
||||||
<b>Joined:</b> {created_date}
|
|
||||||
<b>Last Seen:</b> {last_seen_date}
|
|
||||||
<b>ID:</b> <code>{id}</code>
|
|
||||||
"""
|
|
||||||
return details.strip()
|
|
||||||
|
|
||||||
def format_date(date_string):
|
|
||||||
"""Convert database date to readable format"""
|
|
||||||
if not date_string:
|
|
||||||
return "N/A"
|
|
||||||
|
|
||||||
try:
|
|
||||||
# If date_string is already a datetime object
|
|
||||||
if isinstance(date_string, datetime):
|
|
||||||
return date_string.strftime("%d %b %Y, %H:%M")
|
|
||||||
|
|
||||||
# If it's a string, parse it first
|
|
||||||
date_obj = datetime.strptime(str(date_string), "%Y-%m-%d %H:%M:%S")
|
|
||||||
return date_obj.strftime("%d %b %Y, %H:%M")
|
|
||||||
except:
|
|
||||||
return str(date_string)
|
|
||||||
|
|
||||||
def calculate_age(birthday_string):
|
|
||||||
"""Calculate age from birthday"""
|
|
||||||
if not birthday_string:
|
|
||||||
return "N/A"
|
|
||||||
|
|
||||||
try:
|
|
||||||
birth_date = datetime.strptime(str(birthday_string), "%Y-%m-%d").date()
|
|
||||||
today = datetime.now().date()
|
|
||||||
age = today.year - birth_date.year - ((today.month, today.day) < (birth_date.month, birth_date.day))
|
|
||||||
return age
|
|
||||||
except:
|
|
||||||
return "N/A"
|
|
||||||
|
|
||||||
|
|
||||||
@_bot.message_handler(commands=["test"])
|
|
||||||
def test_handler(message):
|
|
||||||
markup = types.ReplyKeyboardMarkup(row_width=2, one_time_keyboard=True)
|
|
||||||
btn1 = types.KeyboardButton("Option 1")
|
|
||||||
btn2 = types.KeyboardButton("Option 2")
|
|
||||||
markup.add(btn1, btn2)
|
|
||||||
_bot.reply_to(message, "Test command received!", reply_markup=markup)
|
|
||||||
|
|
||||||
@_bot.message_handler(func=lambda message: message.text in ["Option 1", "Option 2"])
|
|
||||||
def handle_test_options(message):
|
|
||||||
option = message.text
|
|
||||||
_bot.send_message(message.chat.id, f"You selected: {option}")
|
|
||||||
|
|
||||||
@_bot.message_handler(func=lambda message: True)
|
|
||||||
def handle_student_selection(message):
|
|
||||||
chat_id = message.chat.id
|
|
||||||
selected_text = message.text
|
|
||||||
|
|
||||||
_bot.reply_to(message, f"You said: {message.text}")
|
|
||||||
|
|
||||||
return _bot
|
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
import os
|
||||||
|
import telebot
|
||||||
|
import logging
|
||||||
|
from bot.handlers.init import register_all_handlers
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
_bot = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_bot():
|
||||||
|
global _bot
|
||||||
|
if _bot is None:
|
||||||
|
BOT_TOKEN = os.environ.get("BOT_TOKEN")
|
||||||
|
_bot = telebot.TeleBot(BOT_TOKEN, threaded=False)
|
||||||
|
register_all_handlers(_bot)
|
||||||
|
logger.info("Telegram bot initialized.")
|
||||||
|
return _bot
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from . import students, teachers
|
||||||
|
|
||||||
|
|
||||||
|
def register_all_callbacks(bot):
|
||||||
|
"""Register all callback handlers"""
|
||||||
|
students.register(bot)
|
||||||
|
teachers.register(bot)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
from telebot import types
|
||||||
|
from database.models import Students
|
||||||
|
from bot.utils.formatters import format_student_info
|
||||||
|
|
||||||
|
|
||||||
|
def register(bot):
|
||||||
|
@bot.callback_query_handler(func=lambda call: call.data.startswith('student_'))
|
||||||
|
def show_student_details(call):
|
||||||
|
student_id = call.data.split('_')[1]
|
||||||
|
student = Students.getStudentById(student_id)
|
||||||
|
|
||||||
|
if student:
|
||||||
|
details = format_student_info(student)
|
||||||
|
markup = types.InlineKeyboardMarkup()
|
||||||
|
bot.send_message(call.message.chat.id, details,
|
||||||
|
reply_markup=markup, parse_mode="HTML")
|
||||||
|
else:
|
||||||
|
bot.send_message(call.message.chat.id, "Student not found.")
|
||||||
|
|
||||||
|
bot.answer_callback_query(call.id)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
from telebot import types
|
||||||
|
from database.models import Teachers
|
||||||
|
from bot.utils.formatters import format_teacher_info
|
||||||
|
|
||||||
|
|
||||||
|
def register(bot):
|
||||||
|
@bot.callback_query_handler(func=lambda call: call.data.startswith('teacher_'))
|
||||||
|
def show_teacher_details(call):
|
||||||
|
teacher_id = call.data.split('_')[1]
|
||||||
|
teacher = Teachers.getTeachertById(teacher_id)
|
||||||
|
|
||||||
|
if teacher:
|
||||||
|
details = format_teacher_info(teacher)
|
||||||
|
markup = types.InlineKeyboardMarkup()
|
||||||
|
bot.send_message(call.message.chat.id, details,
|
||||||
|
reply_markup=markup, parse_mode="HTML")
|
||||||
|
else:
|
||||||
|
bot.send_message(call.message.chat.id, "Teacher not found.")
|
||||||
|
|
||||||
|
bot.answer_callback_query(call.id)
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
def register(bot):
|
||||||
|
@bot.message_handler(func=lambda message: True)
|
||||||
|
def handle_unknown(message):
|
||||||
|
bot.reply_to(message, f"You said: {message.text}")
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
from . import start, students, teachers, common
|
||||||
|
from bot.callbacks.init import register_all_callbacks
|
||||||
|
|
||||||
|
|
||||||
|
def register_all_handlers(bot):
|
||||||
|
"""Register all handlers and callbacks"""
|
||||||
|
# Message handlers
|
||||||
|
start.register(bot)
|
||||||
|
students.register(bot)
|
||||||
|
teachers.register(bot)
|
||||||
|
common.register(bot) # Must be last (catch-all)
|
||||||
|
|
||||||
|
# Callback handlers
|
||||||
|
register_all_callbacks(bot)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
from telebot import types
|
||||||
|
from bot.utils.auth import is_authenticated
|
||||||
|
|
||||||
|
|
||||||
|
def register(bot):
|
||||||
|
@bot.message_handler(commands=["start"])
|
||||||
|
def start_handler(message):
|
||||||
|
if is_authenticated(message.from_user.id):
|
||||||
|
bot.send_message(
|
||||||
|
message.chat.id, "authorized user! Welcome.")
|
||||||
|
else:
|
||||||
|
bot.send_message(
|
||||||
|
message.chat.id, "Welcome! Use buttons to fetch from database.")
|
||||||
|
|
||||||
|
markup = types.ReplyKeyboardMarkup(
|
||||||
|
row_width=2, one_time_keyboard=True, resize_keyboard=True)
|
||||||
|
btn1 = types.KeyboardButton("Show Students")
|
||||||
|
btn2 = types.KeyboardButton("Show Teachers")
|
||||||
|
btn3 = types.KeyboardButton("Show Courses")
|
||||||
|
btn4 = types.KeyboardButton("Show Tag")
|
||||||
|
btn5 = types.KeyboardButton("Show Categories")
|
||||||
|
markup.add(btn1, btn2, btn3, btn4, btn5)
|
||||||
|
bot.reply_to(message, "Use buttons to fetch from database.",
|
||||||
|
reply_markup=markup)
|
||||||
|
|
||||||
|
@bot.message_handler(func=lambda message: message.text in ["Show Courses", "Show Tag", "Show Categories"])
|
||||||
|
def handle_test_options(message):
|
||||||
|
option = message.text
|
||||||
|
bot.send_message(message.chat.id, f"You selected: {option}")
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import logging
|
||||||
|
from telebot import types
|
||||||
|
from database.models import Students
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def register(bot):
|
||||||
|
@bot.message_handler(func=lambda message: message.text == "Show Students")
|
||||||
|
def get_students(message):
|
||||||
|
try:
|
||||||
|
data = Students.getAllStudents()
|
||||||
|
if data:
|
||||||
|
markup = types.InlineKeyboardMarkup(row_width=2)
|
||||||
|
|
||||||
|
for row in data:
|
||||||
|
btn = types.InlineKeyboardButton(
|
||||||
|
f"@{row[1]} | id#{row[0]}", callback_data=f"student_{row[0]}")
|
||||||
|
markup.add(btn)
|
||||||
|
bot.send_message(
|
||||||
|
message.chat.id, "Here is the data:", reply_markup=markup)
|
||||||
|
else:
|
||||||
|
bot.reply_to(message, "No data found.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error in get_students handler: {e}")
|
||||||
|
bot.reply_to(message, "Sorry, an error occurred.")
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import logging
|
||||||
|
from telebot import types
|
||||||
|
from database.models import Teachers
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def register(bot):
|
||||||
|
@bot.message_handler(func=lambda message: message.text == "Show Teachers")
|
||||||
|
def get_teachers(message):
|
||||||
|
try:
|
||||||
|
data = Teachers.getAllTeachers()
|
||||||
|
if data:
|
||||||
|
|
||||||
|
markup = types.InlineKeyboardMarkup(row_width=2)
|
||||||
|
for row in data:
|
||||||
|
btn = types.InlineKeyboardButton(
|
||||||
|
f"@{row[1]} | id#{row[0]}", callback_data=f"teacher_{row[0]}")
|
||||||
|
markup.add(btn)
|
||||||
|
bot.send_message(
|
||||||
|
message.chat.id, "Here is the data:", reply_markup=markup)
|
||||||
|
else:
|
||||||
|
bot.reply_to(message, "No data found.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error in get_teachers handler: {e}")
|
||||||
|
bot.reply_to(message, "Sorry, an error occurred.")
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
authenticated_users = {2032936226}
|
||||||
|
|
||||||
|
def is_authenticated(user_id):
|
||||||
|
return user_id in authenticated_users
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
def format_date(date_string):
|
||||||
|
"""Convert database date to readable format"""
|
||||||
|
if not date_string:
|
||||||
|
return "N/A"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# If date_string is already a datetime object
|
||||||
|
if isinstance(date_string, datetime):
|
||||||
|
return date_string.strftime("%d %b %Y, %H:%M")
|
||||||
|
|
||||||
|
# If it's a string, parse it first
|
||||||
|
date_obj = datetime.strptime(str(date_string), "%Y-%m-%d %H:%M:%S")
|
||||||
|
return date_obj.strftime("%d %b %Y, %H:%M")
|
||||||
|
except:
|
||||||
|
return str(date_string)
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_age(birthday_string):
|
||||||
|
"""Calculate age from birthday"""
|
||||||
|
if not birthday_string:
|
||||||
|
return "N/A"
|
||||||
|
|
||||||
|
try:
|
||||||
|
birth_date = datetime.strptime(str(birthday_string), "%Y-%m-%d").date()
|
||||||
|
today = datetime.now().date()
|
||||||
|
age = today.year - birth_date.year - \
|
||||||
|
((today.month, today.day) < (birth_date.month, birth_date.day))
|
||||||
|
return age
|
||||||
|
except:
|
||||||
|
return "N/A"
|
||||||
|
|
||||||
|
# Student Info Formatter
|
||||||
|
|
||||||
|
|
||||||
|
def format_student_info(student):
|
||||||
|
"""
|
||||||
|
Format student data into a nice message
|
||||||
|
student is a tuple: (id, username, name, created_at, email, phone_number, last_seen, is_verified, birthday)
|
||||||
|
"""
|
||||||
|
print(student)
|
||||||
|
id, username, name, created_at, email, phone_number, last_seen, is_verfied, birthday = student
|
||||||
|
|
||||||
|
verified_status = "✅ Verified" if is_verfied else "❌ Not Verified"
|
||||||
|
|
||||||
|
# Format dates nicely
|
||||||
|
created_date = format_date(created_at)
|
||||||
|
last_seen_date = format_date(last_seen)
|
||||||
|
|
||||||
|
# Calculate age from birthday
|
||||||
|
age = calculate_age(birthday)
|
||||||
|
|
||||||
|
details = f"""
|
||||||
|
<b>👤 Student Profile</b>
|
||||||
|
|
||||||
|
<b>Name:</b> {name}
|
||||||
|
<b>Username:</b> {username}
|
||||||
|
<b>Email:</b> {email}
|
||||||
|
<b>Phone:</b> {phone_number}
|
||||||
|
<b>Birthday:</b> {birthday} (Age: {age})
|
||||||
|
<b>Account Status:</b> {verified_status}
|
||||||
|
|
||||||
|
<b>📅 Account Info</b>
|
||||||
|
<b>Joined:</b> {created_date}
|
||||||
|
<b>Last Seen:</b> {last_seen_date}
|
||||||
|
<b>ID:</b> <code>{id}</code>
|
||||||
|
"""
|
||||||
|
return details.strip()
|
||||||
|
|
||||||
|
|
||||||
|
# Teacher Info Formatter
|
||||||
|
def format_teacher_info(teacher):
|
||||||
|
"""
|
||||||
|
Format student data into a nice message
|
||||||
|
student is a tuple: (id, username, created_at, email, phone_number, last_seen, is_verified, birthday)
|
||||||
|
"""
|
||||||
|
print(teacher)
|
||||||
|
id, username, name, created_at, email, phone_number, last_seen, is_verfied, birthday, about_me, job_title = teacher
|
||||||
|
|
||||||
|
verified_status = "✅ Verified" if is_verfied else "❌ Not Verified"
|
||||||
|
|
||||||
|
# Format dates nicely
|
||||||
|
created_date = format_date(created_at)
|
||||||
|
last_seen_date = format_date(last_seen)
|
||||||
|
|
||||||
|
# Calculate age from birthday
|
||||||
|
age = calculate_age(birthday)
|
||||||
|
|
||||||
|
details = f"""
|
||||||
|
<b>👤 Student Profile</b>
|
||||||
|
|
||||||
|
<b>Name:</b> {name}
|
||||||
|
<b>Username:</b> {username}
|
||||||
|
<b>Job Title:</b> {job_title}
|
||||||
|
<b>About Me:</b> {about_me}
|
||||||
|
|
||||||
|
<b>Email:</b> {email}
|
||||||
|
<b>Phone:</b> {phone_number}
|
||||||
|
<b>Birthday:</b> {birthday} (Age: {age})
|
||||||
|
<b>Account Status:</b> {verified_status}
|
||||||
|
|
||||||
|
<b>📅 Account Info</b>
|
||||||
|
<b>Joined:</b> {created_date}
|
||||||
|
<b>Last Seen:</b> {last_seen_date}
|
||||||
|
<b>ID:</b> <code>{id}</code>
|
||||||
|
"""
|
||||||
|
return details.strip()
|
||||||
+46
-2
@@ -13,7 +13,7 @@ class Students:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("SELECT id,name FROM students");
|
cursor.execute("SELECT id,username FROM students")
|
||||||
result = cursor.fetchall()
|
result = cursor.fetchall()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
@@ -33,7 +33,8 @@ class Students:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("SELECT id,username, created_at, email, phone_number, last_seen, is_verfied, birthday FROM students WHERE id = %s", (student_id,))
|
cursor.execute(
|
||||||
|
"SELECT id,username, name, created_at, email, phone_number, last_seen, is_verfied, birthday FROM students WHERE id = %s", (student_id,))
|
||||||
result = cursor.fetchall()
|
result = cursor.fetchall()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
@@ -44,3 +45,46 @@ class Students:
|
|||||||
finally:
|
finally:
|
||||||
if conn:
|
if conn:
|
||||||
connection.release_db_connection(conn)
|
connection.release_db_connection(conn)
|
||||||
|
|
||||||
|
|
||||||
|
class Teachers:
|
||||||
|
def getAllTeachers():
|
||||||
|
conn = None
|
||||||
|
try:
|
||||||
|
conn = connection.get_db_connection()
|
||||||
|
if not conn:
|
||||||
|
return None
|
||||||
|
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT id,username FROM teachers")
|
||||||
|
result = cursor.fetchall()
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
return result if result else None
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Database query error in getAllTeachers: {e}")
|
||||||
|
return None
|
||||||
|
finally:
|
||||||
|
if conn:
|
||||||
|
connection.release_db_connection(conn)
|
||||||
|
|
||||||
|
def getTeachertById(teacher_id):
|
||||||
|
conn = None
|
||||||
|
try:
|
||||||
|
conn = connection.get_db_connection()
|
||||||
|
if not conn:
|
||||||
|
return None
|
||||||
|
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"SELECT id,username, name, created_at, email, phone_number, last_seen, is_verfied, birthday, about_me, job_title FROM teachers WHERE id = %s", (teacher_id))
|
||||||
|
result = cursor.fetchall()
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
return result[0] if result else None
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Database query error in getTeacherById: {e}")
|
||||||
|
return None
|
||||||
|
finally:
|
||||||
|
if conn:
|
||||||
|
connection.release_db_connection(conn)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
from bot import get_bot
|
from bot.bot import get_bot
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ logger = logging.getLogger(__name__)
|
|||||||
async def telegram_webhook(request: Request):
|
async def telegram_webhook(request: Request):
|
||||||
try:
|
try:
|
||||||
import telebot
|
import telebot
|
||||||
from bot import get_bot
|
from bot.bot import get_bot
|
||||||
|
|
||||||
bot = get_bot()
|
bot = get_bot()
|
||||||
json_data = await request.json()
|
json_data = await request.json()
|
||||||
|
|||||||
Reference in New Issue
Block a user