You've already forked Travel-Agent
feat: Added edit profile func
This commit is contained in:
@@ -5,6 +5,7 @@ from typing import Optional
|
|||||||
from aiogram import Bot, Dispatcher
|
from aiogram import Bot, Dispatcher
|
||||||
from aiogram.enums import ParseMode
|
from aiogram.enums import ParseMode
|
||||||
|
|
||||||
|
from app.callbacks import profile
|
||||||
from app.config import Config
|
from app.config import Config
|
||||||
from app.handlers import help_command, profile_command, start_command
|
from app.handlers import help_command, profile_command, start_command
|
||||||
from app.middlewares.throttling import ThrottlingMiddleware
|
from app.middlewares.throttling import ThrottlingMiddleware
|
||||||
@@ -18,9 +19,11 @@ async def main() -> None:
|
|||||||
bot = Bot(bot_token, parse_mode=ParseMode.HTML)
|
bot = Bot(bot_token, parse_mode=ParseMode.HTML)
|
||||||
|
|
||||||
dp.message.middleware(ThrottlingMiddleware(0.5))
|
dp.message.middleware(ThrottlingMiddleware(0.5))
|
||||||
|
# type: ignore
|
||||||
dp.include_routers(
|
dp.include_routers(
|
||||||
start_command.router,
|
start_command.router,
|
||||||
profile_command.router,
|
profile_command.router,
|
||||||
|
profile.router,
|
||||||
help_command.router,
|
help_command.router,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
# type: ignore
|
||||||
|
__all__ = ()
|
||||||
|
|
||||||
|
from aiogram import F, Router
|
||||||
|
from aiogram.exceptions import TelegramBadRequest
|
||||||
|
from aiogram.filters import StateFilter
|
||||||
|
from aiogram.fsm.context import FSMContext
|
||||||
|
from aiogram.types import CallbackQuery, Message, ReplyKeyboardRemove
|
||||||
|
|
||||||
|
from app import messages, session
|
||||||
|
from app.filters.user_filter import Registered, RegisteredCallback
|
||||||
|
from app.keyboards.builders import profile
|
||||||
|
from app.keyboards.profile import get
|
||||||
|
from app.models.user import User
|
||||||
|
from app.utils.states import UserAltering
|
||||||
|
|
||||||
|
|
||||||
|
router = Router(name="profile_callback")
|
||||||
|
|
||||||
|
|
||||||
|
@router.callback_query(
|
||||||
|
F.data.startswith("profile_change_"),
|
||||||
|
StateFilter(None),
|
||||||
|
RegisteredCallback(),
|
||||||
|
)
|
||||||
|
async def profile_change_callback(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
state: FSMContext,
|
||||||
|
) -> None:
|
||||||
|
if callback.data is None or callback.message is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
column = callback.data.replace("profile_change_", "")
|
||||||
|
|
||||||
|
if column == "username":
|
||||||
|
await callback.message.answer(messages.EDIT_USERNAME)
|
||||||
|
elif column == "age":
|
||||||
|
await callback.message.answer(messages.INPUT_AGE)
|
||||||
|
elif column == "bio":
|
||||||
|
await callback.message.answer(messages.EDIT_BIO)
|
||||||
|
elif column == "sex":
|
||||||
|
await callback.message.answer(
|
||||||
|
messages.INPUT_SEX,
|
||||||
|
reply_markup=profile(["Male", "Female"]),
|
||||||
|
)
|
||||||
|
elif column == "location":
|
||||||
|
await callback.message.answer(messages.INPUT_LOCATION)
|
||||||
|
|
||||||
|
await state.update_data(
|
||||||
|
column=column,
|
||||||
|
message_id=callback.message.message_id,
|
||||||
|
)
|
||||||
|
await state.set_state(UserAltering.value)
|
||||||
|
|
||||||
|
await callback.answer()
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(UserAltering.value, F.text, Registered())
|
||||||
|
async def profile_change_entered(message: Message, state: FSMContext) -> None:
|
||||||
|
column = (await state.get_data()).get("column")
|
||||||
|
value = message.text.strip()
|
||||||
|
|
||||||
|
if column == "username":
|
||||||
|
try:
|
||||||
|
validated_value = User().validate_username(
|
||||||
|
key="username",
|
||||||
|
value=value,
|
||||||
|
)
|
||||||
|
except AssertionError as e:
|
||||||
|
await message.answer(str(e))
|
||||||
|
return
|
||||||
|
|
||||||
|
await state.update_data(value=validated_value)
|
||||||
|
elif column == "age":
|
||||||
|
try:
|
||||||
|
validated_age = User().validate_age(key="age", value=value)
|
||||||
|
except AssertionError as e:
|
||||||
|
await message.answer(str(e))
|
||||||
|
return
|
||||||
|
|
||||||
|
await state.update_data(value=validated_age)
|
||||||
|
elif column == "bio":
|
||||||
|
if value == "/skip":
|
||||||
|
await state.update_data(value=None)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
validated_bio = User().validate_bio(key="bio", value=value)
|
||||||
|
except AssertionError as e:
|
||||||
|
await message.answer(str(e))
|
||||||
|
return
|
||||||
|
|
||||||
|
await state.update_data(value=validated_bio)
|
||||||
|
elif column == "sex":
|
||||||
|
value = value.lower()
|
||||||
|
|
||||||
|
if value not in ["male", "female"]:
|
||||||
|
await message.answer(messages.VALIDATION_ERROR_MESSAGE)
|
||||||
|
return
|
||||||
|
|
||||||
|
await state.update_data(value=value)
|
||||||
|
elif column == "location":
|
||||||
|
location = value.split(", ")
|
||||||
|
if len(location) != 2:
|
||||||
|
await message.answer(messages.VALIDATION_ERROR_MESSAGE)
|
||||||
|
return
|
||||||
|
|
||||||
|
country, city = location
|
||||||
|
|
||||||
|
try:
|
||||||
|
validated_country = User().validate_country(
|
||||||
|
key="country",
|
||||||
|
value=country,
|
||||||
|
)
|
||||||
|
except AssertionError as e:
|
||||||
|
await message.answer(str(e))
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
validated_city = User().validate_city(
|
||||||
|
city=city,
|
||||||
|
country=validated_country,
|
||||||
|
)
|
||||||
|
except AssertionError as e:
|
||||||
|
await message.answer(str(e))
|
||||||
|
return
|
||||||
|
|
||||||
|
await state.update_data(value=[validated_country, validated_city])
|
||||||
|
|
||||||
|
state_data = await state.get_data()
|
||||||
|
|
||||||
|
user = User.get_user_queryset_by_telegram_id(message.from_user.id)
|
||||||
|
|
||||||
|
if isinstance(state_data["value"], list):
|
||||||
|
user.update(
|
||||||
|
{
|
||||||
|
"country": state_data["value"][0],
|
||||||
|
"city": state_data["value"][1],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
data = {state_data["column"]: state_data["value"]}
|
||||||
|
user.update(data)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
user = user.first()
|
||||||
|
session.refresh(user)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await message.bot.edit_message_text(
|
||||||
|
messages.PROFILE.format(
|
||||||
|
username=user.username,
|
||||||
|
age=user.age,
|
||||||
|
bio=user.bio if user.bio else messages.NOT_SET,
|
||||||
|
sex=user.sex.capitalize(),
|
||||||
|
country=user.country,
|
||||||
|
city=user.city,
|
||||||
|
),
|
||||||
|
message.chat.id,
|
||||||
|
state_data["message_id"],
|
||||||
|
reply_markup=get(),
|
||||||
|
)
|
||||||
|
except TelegramBadRequest:
|
||||||
|
pass
|
||||||
|
|
||||||
|
await message.answer(
|
||||||
|
"✅ Profile updated",
|
||||||
|
reply_markup=ReplyKeyboardRemove(),
|
||||||
|
)
|
||||||
|
|
||||||
|
await state.clear()
|
||||||
@@ -26,3 +26,5 @@ PROFILE = (
|
|||||||
"\tCity: <b>{city}</b>"
|
"\tCity: <b>{city}</b>"
|
||||||
)
|
)
|
||||||
NOT_SET = "<i>Not set</i>"
|
NOT_SET = "<i>Not set</i>"
|
||||||
|
EDIT_USERNAME = "Enter your username:\n<i>Allowed characters: a-z, A-Z, 0-9, _</i>\n<i>Length: 5-20 characters</i>"
|
||||||
|
EDIT_BIO = "Enter your bio (enter /skip if you want to set it to None):\n<i>Maximum length: 100 characters</i>"
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ class User(Base):
|
|||||||
|
|
||||||
return normalized_value
|
return normalized_value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_user_queryset_by_telegram_id(cls, telegram_id):
|
||||||
|
return session.query(cls).filter(cls.telegram_id == telegram_id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_user_by_telegram_id(cls, telegram_id):
|
def get_user_by_telegram_id(cls, telegram_id):
|
||||||
return (
|
return (
|
||||||
|
|||||||
+14
-6
@@ -23,9 +23,13 @@ def validate_country(country: str):
|
|||||||
if not geocode:
|
if not geocode:
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
is_loc_country = geocode.raw.get(
|
is_loc_country = (
|
||||||
"type", None,
|
geocode.raw.get(
|
||||||
) == "administrative"
|
"type",
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
== "administrative"
|
||||||
|
)
|
||||||
|
|
||||||
if is_loc_country:
|
if is_loc_country:
|
||||||
normalized_country = geocode.raw.get("name", "Invalid country")
|
normalized_country = geocode.raw.get("name", "Invalid country")
|
||||||
@@ -55,9 +59,13 @@ def validate_city(city: str, country: str):
|
|||||||
if not geocode:
|
if not geocode:
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
check_in_valid = geocode.raw.get(
|
check_in_valid = (
|
||||||
"type", None,
|
geocode.raw.get(
|
||||||
) in valid_list
|
"type",
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
in valid_list
|
||||||
|
)
|
||||||
|
|
||||||
if geocode and check_in_valid:
|
if geocode and check_in_valid:
|
||||||
normalized_country = geocode.raw.get("name", "Invalid city")
|
normalized_country = geocode.raw.get("name", "Invalid city")
|
||||||
|
|||||||
+3
-1
@@ -12,4 +12,6 @@ class RegistrationForm(StatesGroup):
|
|||||||
|
|
||||||
|
|
||||||
class UserAltering(StatesGroup):
|
class UserAltering(StatesGroup):
|
||||||
new_value = State()
|
message_id = State()
|
||||||
|
column = State()
|
||||||
|
value = State()
|
||||||
|
|||||||
Reference in New Issue
Block a user