feat: Added travel detail, added proccessing message when changing/setting user location, improvements in messages text

This commit is contained in:
ITQ
2024-03-23 16:19:15 +03:00
parent 7b28635f09
commit 40ea9689ab
12 changed files with 202 additions and 26 deletions
+11 -2
View File
@@ -93,8 +93,17 @@ async def travels_callback(
await callback.message.answer(
messages.TRAVELS,
reply_markup=travels_keyboard(travels, page, pages),
reply_markup=travels_keyboard(
travels,
page,
pages,
user.telegram_id,
),
)
await callback.message.delete()
try:
await callback.message.delete()
except TelegramBadRequest:
pass
await callback.answer()
+41 -5
View File
@@ -152,11 +152,20 @@ async def profile_change_entered(message: Message, state: FSMContext) -> None:
elif column == "location":
location = value.split(", ")
proccessing_message = await message.answer(messages.PROCCESSING)
if len(location) != 2:
await handle_validation_error(
message,
await delete_message_from_state(
state,
messages.VALIDATION_ERROR,
message.chat.id,
message.bot,
)
await proccessing_message.edit_text(messages.VALIDATION_ERROR)
await message.delete()
error_message = proccessing_message
await state.update_data(
error_message_id=error_message.message_id,
)
return
@@ -169,7 +178,18 @@ async def profile_change_entered(message: Message, state: FSMContext) -> None:
value=country,
)
except AssertionError as e:
await handle_validation_error(message, state, e)
await delete_message_from_state(
state,
message.chat.id,
message.bot,
)
await proccessing_message.edit_text("" + str(e))
await message.delete()
error_message = proccessing_message
await state.update_data(
error_message_id=error_message.message_id,
)
return
@@ -179,7 +199,18 @@ async def profile_change_entered(message: Message, state: FSMContext) -> None:
country=validated_country,
)
except AssertionError as e:
await handle_validation_error(message, state, e)
await delete_message_from_state(
state,
message.chat.id,
message.bot,
)
await proccessing_message.edit_text("" + str(e))
await message.delete()
error_message = proccessing_message
await state.update_data(
error_message_id=error_message.message_id,
)
return
@@ -204,6 +235,11 @@ async def profile_change_entered(message: Message, state: FSMContext) -> None:
"city": state_data["value"][1],
},
)
try:
await proccessing_message.delete()
except TelegramBadRequest:
pass
else:
data = {state_data["column"]: state_data["value"]}
user.update(data)
+30 -1
View File
@@ -9,6 +9,8 @@ from app import messages
from app.config import Config
from app.filters.user import RegisteredCallback
from app.keyboards.builders import travels_keyboard
from app.keyboards.travel import get
from app.models.travel import Travel
from app.models.user import User
@@ -40,5 +42,32 @@ async def travels_callback(callback: CallbackQuery) -> None:
await callback.message.edit_text(
messages.TRAVELS,
reply_markup=travels_keyboard(travels, page, pages),
reply_markup=travels_keyboard(
travels,
page,
pages,
user.telegram_id,
),
)
@router.callback_query(
F.data.startswith("travel_detail"),
RegisteredCallback(),
StateFilter(None),
)
async def travel_detail_callback(callback: CallbackQuery) -> None:
if callback.data is None or not isinstance(callback.message, Message):
return
travel_id = int(callback.data.replace("travel_detail_", ""))
travel = Travel().get_travel_by_id(travel_id)
if not travel:
return
await callback.message.edit_text(
travel.get_travel_text(),
reply_markup=get(travel_id),
)
+42 -5
View File
@@ -1,6 +1,7 @@
__all__ = ("router",)
from aiogram import F, Router
from aiogram.exceptions import TelegramBadRequest
from aiogram.filters import CommandStart, StateFilter
from aiogram.fsm.context import FSMContext
from aiogram.types import Message, ReplyKeyboardRemove
@@ -166,13 +167,22 @@ async def location_handler(message: Message, state: FSMContext) -> None:
if message.text is None or message.from_user is None:
return
proccessing_message = await message.answer(messages.PROCCESSING)
location = message.text.strip().split(", ")
if len(location) != 2:
await handle_validation_error(
message,
await delete_message_from_state(
state,
messages.VALIDATION_ERROR,
message.chat.id,
message.bot,
)
await proccessing_message.edit_text(messages.VALIDATION_ERROR)
await message.delete()
error_message = proccessing_message
await state.update_data(
error_message_id=error_message.message_id,
)
return
@@ -185,7 +195,18 @@ async def location_handler(message: Message, state: FSMContext) -> None:
value=country,
)
except AssertionError as e:
await handle_validation_error(message, state, e)
await delete_message_from_state(
state,
message.chat.id,
message.bot,
)
await proccessing_message.edit_text("" + str(e))
await message.delete()
error_message = proccessing_message
await state.update_data(
error_message_id=error_message.message_id,
)
return
@@ -195,10 +216,26 @@ async def location_handler(message: Message, state: FSMContext) -> None:
country=validated_country,
)
except AssertionError as e:
await handle_validation_error(message, state, e)
await delete_message_from_state(
state,
message.chat.id,
message.bot,
)
await proccessing_message.edit_text("" + str(e))
await message.delete()
error_message = proccessing_message
await state.update_data(
error_message_id=error_message.message_id,
)
return
try:
await proccessing_message.delete()
except TelegramBadRequest:
pass
await delete_message_from_state(state, message.chat.id, message.bot)
await state.update_data(location=[validated_country, validated_city])
+6 -1
View File
@@ -32,5 +32,10 @@ async def command_help_handler(message: Message) -> None:
await message.answer(
messages.TRAVELS,
reply_markup=travels_keyboard(travels, page, pages),
reply_markup=travels_keyboard(
travels,
page,
pages,
user.telegram_id,
),
)
+7 -2
View File
@@ -16,7 +16,7 @@ def sex_keyboard(choices: str | list):
return builder.as_markup(resize_keyboard=True)
def travels_keyboard(travels: list, page: int, pages: int):
def travels_keyboard(travels: list, page: int, pages: int, user_id: int):
builder = InlineKeyboardBuilder()
rows = []
@@ -24,9 +24,14 @@ def travels_keyboard(travels: list, page: int, pages: int):
end_index = min((page + 1) * Config.PAGE_SIZE, len(travels))
for travel in travels[start_index:end_index]:
button_text = travel.title
if travel.author_id == user_id:
button_text += " 👑"
rows.append(
InlineKeyboardButton(
text=travel.title,
text=button_text,
callback_data=f"travel_detail_{travel.id}",
),
)
+37
View File
@@ -0,0 +1,37 @@
__all__ = ("get",)
from aiogram import types
from aiogram.utils.keyboard import InlineKeyboardBuilder
def get(travel_id: int):
builder = InlineKeyboardBuilder()
builder.row(
types.InlineKeyboardButton(
text="📝 Change title",
callback_data=f"travel_change_{travel_id}_title",
),
types.InlineKeyboardButton(
text="️ Change description",
callback_data=f"travel_change_{travel_id}_description",
),
)
builder.row(
types.InlineKeyboardButton(
text=" Add location",
callback_data=f"travel_add_{travel_id}_location",
),
types.InlineKeyboardButton(
text=" Add user",
callback_data=f"travel_add_{travel_id}_user",
),
)
builder.row(
types.InlineKeyboardButton(
text="⬅️",
callback_data="menu_travels",
),
)
return builder.as_markup()
+13 -6
View File
@@ -2,7 +2,7 @@
MENU = "<b>Menu:</b>"
TRAVELS = "📃 <b>Travels:</b>"
TRAVELS = "📃 <b>Travels:</b>\n<i>👑 - owner</i>"
NO_TRAVELS = "No travels yet. You can create one with /create_travel command."
CREATE_TRAVEL = (
"🧳 Let's create new travel!\n<i>Enter /cancel to cancel creating.</i>"
@@ -14,9 +14,14 @@ INPUT_TRAVEL_CALLBACK = (
"All right, travel <b>{key}</b> is set to: <b>{value}</b>"
)
INPUT_TRAVEL_DESCRIPTION = "Enter travel description (enter /skip if you want to skip this step):\n<i>Maximum length: 100 characters</i>"
INPUT_TRAVEL_DESCRIPTION_SKIPPED = "Sure. You can always fill it later."
INPUT_TRAVEL_DESCRIPTION_SKIPPED = "Sure. You can always fill it later."
TRAVEL_CREATED = "Travel <b>{title}</b> successfully created! You can now view and edit it in the travels list (/travels command)."
ACTION_CANCELED = "❌ Action canceled"
TRAVEL_DETAIL = (
"📝 <b>Travel detail</b>\n\n"
"\tTitle: <b>{title}</b>\n"
"\tDescription: <b>{description}</b>\n"
)
WELCOME_MESSAGE = "Hello, <b>{name}</b>! Welcome to the ✈️ Travel Agent bot! Let's start our journey by filling out some information about you."
WELCOME_AGAIN_MESSAGE = "Hello, <b>{name}</b>! Welcome back to the ✈️ Travel Agent bot! If you get lost, you can always call the /help command for assistance."
@@ -39,14 +44,14 @@ INPUT_USERNAME = "Enter your username (this will be used to interact with other
INPUT_AGE = "Enter your age:\n<i>Range: 13-120</i>"
INPUT_SEX = "Enter your sex:\n<i>Options: Male or Female</i>"
INPUT_BIO = "Enter your bio (enter /skip if you want to skip this step):\n<i>Maximum length: 100 characters</i>"
INPUT_BIO_SKIPPED = "Sure. You can always fill it later."
INPUT_BIO_SKIPPED = "Sure. You can always fill it later."
INPUT_LOCATION = "Enter your location in this format:\n<i>Format: country, city</i>\n<i>Example: Russia, Moscow</i>"
INPUT_CALLBACK = "All right, your <b>{key}</b> is set to: <b>{value}</b>"
VALIDATION_ERROR = "Invalid input. Please try again."
INPUT_CALLBACK = "All right, your <b>{key}</b> is set to: <b>{value}</b>"
VALIDATION_ERROR = "Invalid input. Please try again."
CANCEL_CHANGE = "<i>Enter /cancel to cancel change.</i>"
PROFILE = (
"<b>Your profile:</b>\n\n"
"<b>👤 Your profile:</b>\n\n"
"\tUsername: <b>{username}</b>\n"
"\tAge: <b>{age}</b>\n"
"\tSex: <b>{sex}</b>\n"
@@ -60,3 +65,5 @@ EDIT_USERNAME = "Enter your username:\n<i>Allowed characters: a-z, A-Z, 0-9, _</
EDIT_BIO = "Enter your bio (enter /skip if you want to set it to None):\n<i>Maximum length: 100 characters</i>"
PROFILE_UPDATED = "✅ Profile updated"
CHANGE_CANCELED = "❌ Change canceled"
PROCCESSING = "⌛️ Processing..."
+12 -1
View File
@@ -3,7 +3,7 @@ __all__ = ("Travel", "Location")
import sqlalchemy as sa
from sqlalchemy.orm import relationship, validates
from app import session
from app import messages, session
from app.models import Base
from app.models.user import User
@@ -55,6 +55,7 @@ class Travel(Base):
@validates("title")
def validate_title(self, key, value):
assert len(value) <= 30, "Title must be 30 characters or fewer."
assert "👑" not in value, "👑 is not allowed symbol."
if session.query(Travel).filter(Travel.title == value).first():
raise AssertionError("This title is already taken.")
@@ -70,6 +71,16 @@ class Travel(Base):
return value
def get_travel_text(self):
return messages.TRAVEL_DETAIL.format(
title=self.title,
description=self.description,
)
@classmethod
def get_travel_by_id(cls, travel_id):
return session.query(Travel).filter(Travel.id == travel_id).first()
class Location(Base):
__tablename__ = "locations"
+1 -1
View File
@@ -56,7 +56,7 @@ async def handle_validation_error(
message.bot,
)
error_message = await message.answer(str(e))
error_message = await message.answer("" + str(e))
await state.update_data(
error_message_id=error_message.message_id,
)