You've already forked Travel-Agent
feat: Added ability to change travel
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
__all__ = ("router",)
|
__all__ = ("router",)
|
||||||
|
|
||||||
from aiogram import F, Router
|
from aiogram import F, Router
|
||||||
from aiogram.exceptions import TelegramBadRequest
|
|
||||||
from aiogram.filters import StateFilter
|
from aiogram.filters import StateFilter
|
||||||
from aiogram.fsm.context import FSMContext
|
from aiogram.fsm.context import FSMContext
|
||||||
from aiogram.types import CallbackQuery, Message
|
from aiogram.types import CallbackQuery, Message
|
||||||
@@ -35,11 +34,6 @@ async def profile_callback(callback: CallbackQuery) -> None:
|
|||||||
)
|
)
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
|
|
||||||
try:
|
|
||||||
await callback.message.delete()
|
|
||||||
except TelegramBadRequest:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(
|
@router.callback_query(
|
||||||
F.data == "menu_create_travel",
|
F.data == "menu_create_travel",
|
||||||
@@ -63,11 +57,6 @@ async def create_travel_callback(
|
|||||||
|
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
|
|
||||||
try:
|
|
||||||
await callback.message.delete()
|
|
||||||
except TelegramBadRequest:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(
|
@router.callback_query(
|
||||||
F.data == "menu_travels",
|
F.data == "menu_travels",
|
||||||
@@ -101,9 +90,4 @@ async def travels_callback(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
|
||||||
await callback.message.delete()
|
|
||||||
except TelegramBadRequest:
|
|
||||||
pass
|
|
||||||
|
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ async def profile_change_entered(message: Message, state: FSMContext) -> None:
|
|||||||
|
|
||||||
if column == "username":
|
if column == "username":
|
||||||
try:
|
try:
|
||||||
validated_value = User().validate_username(
|
validated_title = User().validate_username(
|
||||||
key="username",
|
key="username",
|
||||||
value=value,
|
value=value,
|
||||||
)
|
)
|
||||||
@@ -111,7 +111,7 @@ async def profile_change_entered(message: Message, state: FSMContext) -> None:
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
await state.update_data(value=validated_value, successfully=True)
|
await state.update_data(value=validated_title, successfully=True)
|
||||||
elif column == "age":
|
elif column == "age":
|
||||||
try:
|
try:
|
||||||
validated_age = User().validate_age(key="age", value=value)
|
validated_age = User().validate_age(key="age", value=value)
|
||||||
|
|||||||
+171
-2
@@ -3,20 +3,54 @@ __all__ = ("router",)
|
|||||||
from aiogram import F, Router
|
from aiogram import F, Router
|
||||||
from aiogram.exceptions import TelegramBadRequest
|
from aiogram.exceptions import TelegramBadRequest
|
||||||
from aiogram.filters import StateFilter
|
from aiogram.filters import StateFilter
|
||||||
|
from aiogram.fsm.context import FSMContext
|
||||||
from aiogram.types import CallbackQuery, Message
|
from aiogram.types import CallbackQuery, Message
|
||||||
|
|
||||||
from app import messages
|
from app import messages, session
|
||||||
from app.config import Config
|
from app.config import Config
|
||||||
from app.filters.user import RegisteredCallback
|
from app.filters.user import Registered, RegisteredCallback
|
||||||
from app.keyboards.builders import travels_keyboard
|
from app.keyboards.builders import travels_keyboard
|
||||||
from app.keyboards.travel import get
|
from app.keyboards.travel import get
|
||||||
from app.models.travel import Travel
|
from app.models.travel import Travel
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
|
from app.states.travel import TravelAlteringState
|
||||||
|
from app.utils.states import delete_message_from_state, handle_validation_error
|
||||||
|
|
||||||
|
|
||||||
router = Router(name="menu_callback")
|
router = Router(name="menu_callback")
|
||||||
|
|
||||||
|
|
||||||
|
@router.callback_query(
|
||||||
|
F.data == "travels",
|
||||||
|
RegisteredCallback(),
|
||||||
|
StateFilter(None),
|
||||||
|
)
|
||||||
|
async def travels_index_callback(callback: CallbackQuery) -> None:
|
||||||
|
page = 0
|
||||||
|
|
||||||
|
if callback.from_user is None or not isinstance(callback.message, Message):
|
||||||
|
return
|
||||||
|
|
||||||
|
user = User().get_user_by_telegram_id(callback.from_user.id)
|
||||||
|
|
||||||
|
travels = user.get_user_travels()
|
||||||
|
|
||||||
|
if not travels or travels == []:
|
||||||
|
await callback.message.edit_text(messages.NO_TRAVELS)
|
||||||
|
else:
|
||||||
|
pages = (len(travels) + Config.PAGE_SIZE - 1) // Config.PAGE_SIZE
|
||||||
|
|
||||||
|
await callback.message.edit_text(
|
||||||
|
messages.TRAVELS,
|
||||||
|
reply_markup=travels_keyboard(
|
||||||
|
travels,
|
||||||
|
page,
|
||||||
|
pages,
|
||||||
|
user.telegram_id,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(
|
@router.callback_query(
|
||||||
F.data.startswith("travels_page"),
|
F.data.startswith("travels_page"),
|
||||||
RegisteredCallback(),
|
RegisteredCallback(),
|
||||||
@@ -71,3 +105,138 @@ async def travel_detail_callback(callback: CallbackQuery) -> None:
|
|||||||
travel.get_travel_text(),
|
travel.get_travel_text(),
|
||||||
reply_markup=get(travel_id),
|
reply_markup=get(travel_id),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.callback_query(
|
||||||
|
F.data.startswith("travel_change"),
|
||||||
|
RegisteredCallback(),
|
||||||
|
StateFilter(None),
|
||||||
|
)
|
||||||
|
async def travel_change_callback(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
state: FSMContext,
|
||||||
|
) -> None:
|
||||||
|
if (
|
||||||
|
callback.data is None
|
||||||
|
or callback.message is None
|
||||||
|
or not isinstance(callback.message, Message)
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
travel_id, column = callback.data.replace("travel_change_", "").split("_")
|
||||||
|
|
||||||
|
if column == "title":
|
||||||
|
message = await callback.message.answer(
|
||||||
|
f"{messages.INPUT_TRAVEL_TITLE}\n{messages.CANCEL_CHANGE}",
|
||||||
|
)
|
||||||
|
elif column == "description":
|
||||||
|
message = await callback.message.answer(
|
||||||
|
f"{messages.EDIT_TRAVEL_DESCRIPTION}\n{messages.CANCEL_CHANGE}",
|
||||||
|
)
|
||||||
|
|
||||||
|
await state.update_data(
|
||||||
|
column=column,
|
||||||
|
travel_message_id=callback.message.message_id,
|
||||||
|
input_message_id=message.message_id,
|
||||||
|
travel_id=travel_id,
|
||||||
|
)
|
||||||
|
await state.set_state(TravelAlteringState.value)
|
||||||
|
|
||||||
|
await callback.answer()
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(TravelAlteringState.value, F.text, Registered())
|
||||||
|
async def travel_change_entered(message: Message, state: FSMContext) -> None:
|
||||||
|
if (
|
||||||
|
message.text is None
|
||||||
|
or message.from_user is None
|
||||||
|
or message.bot is None
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
data = await state.get_data()
|
||||||
|
|
||||||
|
column = data["column"]
|
||||||
|
travel_id = data["travel_id"]
|
||||||
|
value = message.text.strip()
|
||||||
|
|
||||||
|
if value == "/cancel":
|
||||||
|
await message.answer(
|
||||||
|
messages.CHANGE_CANCELED,
|
||||||
|
)
|
||||||
|
|
||||||
|
await state.update_data(successfully=True)
|
||||||
|
await message.delete()
|
||||||
|
await delete_message_from_state(
|
||||||
|
state,
|
||||||
|
message.chat.id,
|
||||||
|
message.bot,
|
||||||
|
)
|
||||||
|
await state.clear()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
if column == "title":
|
||||||
|
try:
|
||||||
|
validated_title = Travel().validate_title(
|
||||||
|
key="title",
|
||||||
|
value=value,
|
||||||
|
)
|
||||||
|
except AssertionError as e:
|
||||||
|
await handle_validation_error(message, state, e)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
await state.update_data(value=validated_title, successfully=True)
|
||||||
|
elif column == "description":
|
||||||
|
if value == "/skip":
|
||||||
|
await state.update_data(value=None, successfully=True)
|
||||||
|
await delete_message_from_state(
|
||||||
|
state,
|
||||||
|
message.chat.id,
|
||||||
|
message.bot,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
validated_description = Travel().validate_description(
|
||||||
|
key="description", value=value,
|
||||||
|
)
|
||||||
|
except AssertionError as e:
|
||||||
|
await handle_validation_error(message, state, e)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
await state.update_data(
|
||||||
|
value=validated_description, successfully=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
await message.delete()
|
||||||
|
await delete_message_from_state(state, message.chat.id, message.bot)
|
||||||
|
|
||||||
|
state_data = await state.get_data()
|
||||||
|
|
||||||
|
travel = Travel().get_travel_queryset_by_id(travel_id)
|
||||||
|
|
||||||
|
data = {state_data["column"]: state_data["value"]}
|
||||||
|
travel.update(data)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
travel = travel.first()
|
||||||
|
session.refresh(travel)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await message.bot.edit_message_text(
|
||||||
|
travel.get_travel_text(),
|
||||||
|
message.chat.id,
|
||||||
|
state_data["travel_message_id"],
|
||||||
|
reply_markup=get(travel_id),
|
||||||
|
)
|
||||||
|
except TelegramBadRequest:
|
||||||
|
pass
|
||||||
|
|
||||||
|
await message.answer(
|
||||||
|
messages.TRAVEL_UPDATED,
|
||||||
|
)
|
||||||
|
|
||||||
|
await state.clear()
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ router = Router(name="travels_command")
|
|||||||
|
|
||||||
|
|
||||||
@router.message(Command("travels"), Registered(), StateFilter(None))
|
@router.message(Command("travels"), Registered(), StateFilter(None))
|
||||||
async def command_help_handler(message: Message) -> None:
|
async def command_travels_handler(message: Message) -> None:
|
||||||
page = 0
|
page = 0
|
||||||
|
|
||||||
if message.from_user is None:
|
if message.from_user is None:
|
||||||
|
|||||||
+11
-1
@@ -17,6 +17,16 @@ def get(travel_id: int):
|
|||||||
callback_data=f"travel_change_{travel_id}_description",
|
callback_data=f"travel_change_{travel_id}_description",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
builder.row(
|
||||||
|
types.InlineKeyboardButton(
|
||||||
|
text="🗺️ Locations",
|
||||||
|
callback_data=f"travel_locations_{travel_id}",
|
||||||
|
),
|
||||||
|
types.InlineKeyboardButton(
|
||||||
|
text="👤 Users",
|
||||||
|
callback_data=f"travel_users_{travel_id}",
|
||||||
|
),
|
||||||
|
)
|
||||||
builder.row(
|
builder.row(
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
text="➕ Add location",
|
text="➕ Add location",
|
||||||
@@ -30,7 +40,7 @@ def get(travel_id: int):
|
|||||||
builder.row(
|
builder.row(
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
text="⬅️",
|
text="⬅️",
|
||||||
callback_data="menu_travels",
|
callback_data="travels",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ NO_TRAVELS = "No travels yet. You can create one with /create_travel command."
|
|||||||
CREATE_TRAVEL = (
|
CREATE_TRAVEL = (
|
||||||
"🧳 Let's create new travel!\n<i>Enter /cancel to cancel creating.</i>"
|
"🧳 Let's create new travel!\n<i>Enter /cancel to cancel creating.</i>"
|
||||||
)
|
)
|
||||||
|
TRAVEL_UPDATED = "✅ Travel updated"
|
||||||
|
EDIT_TRAVEL_DESCRIPTION = "Enter travel description (enter /skip if you want to set it to None):\n<i>Maximum length: 100 characters</i>"
|
||||||
INPUT_TRAVEL_TITLE = (
|
INPUT_TRAVEL_TITLE = (
|
||||||
"Enter travel title:\n<i>Maximum length: 30 characters</i>"
|
"Enter travel title:\n<i>Maximum length: 30 characters</i>"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -74,13 +74,19 @@ class Travel(Base):
|
|||||||
def get_travel_text(self):
|
def get_travel_text(self):
|
||||||
return messages.TRAVEL_DETAIL.format(
|
return messages.TRAVEL_DETAIL.format(
|
||||||
title=self.title,
|
title=self.title,
|
||||||
description=self.description,
|
description=(
|
||||||
|
self.description if self.description else messages.NOT_SET
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_travel_by_id(cls, travel_id):
|
def get_travel_by_id(cls, travel_id):
|
||||||
return session.query(Travel).filter(Travel.id == travel_id).first()
|
return session.query(Travel).filter(Travel.id == travel_id).first()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_travel_queryset_by_id(cls, travel_id):
|
||||||
|
return session.query(Travel).filter(Travel.id == travel_id)
|
||||||
|
|
||||||
|
|
||||||
class Location(Base):
|
class Location(Base):
|
||||||
__tablename__ = "locations"
|
__tablename__ = "locations"
|
||||||
|
|||||||
+2
-1
@@ -98,7 +98,8 @@ class User(Base):
|
|||||||
return normalized_value
|
return normalized_value
|
||||||
|
|
||||||
def get_user_travels(self) -> list:
|
def get_user_travels(self) -> list:
|
||||||
return self.owned_travels + self.travels
|
all_travels = self.owned_travels + self.travels
|
||||||
|
return sorted(all_travels, key=lambda travel: travel.id)
|
||||||
|
|
||||||
def get_human_readable_datejoined(self) -> str:
|
def get_human_readable_datejoined(self) -> str:
|
||||||
return self.date_joined.strftime("%Y-%m-%d %H:%M:%S")
|
return self.date_joined.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|||||||
@@ -7,3 +7,13 @@ class TravelCreationState(StatesGroup):
|
|||||||
error_message_id = State()
|
error_message_id = State()
|
||||||
title = State()
|
title = State()
|
||||||
description = State()
|
description = State()
|
||||||
|
|
||||||
|
|
||||||
|
class TravelAlteringState(StatesGroup):
|
||||||
|
travel_message_id = State()
|
||||||
|
input_message_id = State()
|
||||||
|
error_message_id = State()
|
||||||
|
successfully = State()
|
||||||
|
travel_id = State()
|
||||||
|
column = State()
|
||||||
|
value = State()
|
||||||
|
|||||||
Reference in New Issue
Block a user