feat: Added edit profile func

This commit is contained in:
ITQ
2024-03-20 23:12:35 +03:00
parent 3ca80dea1f
commit 2d35f26b29
6 changed files with 197 additions and 7 deletions
+3
View File
@@ -5,6 +5,7 @@ from typing import Optional
from aiogram import Bot, Dispatcher
from aiogram.enums import ParseMode
from app.callbacks import profile
from app.config import Config
from app.handlers import help_command, profile_command, start_command
from app.middlewares.throttling import ThrottlingMiddleware
@@ -18,9 +19,11 @@ async def main() -> None:
bot = Bot(bot_token, parse_mode=ParseMode.HTML)
dp.message.middleware(ThrottlingMiddleware(0.5))
# type: ignore
dp.include_routers(
start_command.router,
profile_command.router,
profile.router,
help_command.router,
)
+171
View File
@@ -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()
+2
View File
@@ -26,3 +26,5 @@ PROFILE = (
"\tCity: <b>{city}</b>"
)
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>"
+4
View File
@@ -73,6 +73,10 @@ class User(Base):
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
def get_user_by_telegram_id(cls, telegram_id):
return (
+14 -6
View File
@@ -23,9 +23,13 @@ def validate_country(country: str):
if not geocode:
return False, None
is_loc_country = geocode.raw.get(
"type", None,
) == "administrative"
is_loc_country = (
geocode.raw.get(
"type",
None,
)
== "administrative"
)
if is_loc_country:
normalized_country = geocode.raw.get("name", "Invalid country")
@@ -55,9 +59,13 @@ def validate_city(city: str, country: str):
if not geocode:
return False, None
check_in_valid = geocode.raw.get(
"type", None,
) in valid_list
check_in_valid = (
geocode.raw.get(
"type",
None,
)
in valid_list
)
if geocode and check_in_valid:
normalized_country = geocode.raw.get("name", "Invalid city")
+3 -1
View File
@@ -12,4 +12,6 @@ class RegistrationForm(StatesGroup):
class UserAltering(StatesGroup):
new_value = State()
message_id = State()
column = State()
value = State()