You've already forked Travel-Agent
feat: Added notes creation, view and deletion, added route planning, added location list with current weather and nearby locations, code improvements and fixes
This commit is contained in:
@@ -7,258 +7,25 @@ from aiogram.exceptions import TelegramBadRequest
|
||||
from aiogram.filters import StateFilter
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.types import CallbackQuery, Message
|
||||
import sqlalchemy as sa
|
||||
|
||||
from app import messages, session
|
||||
from app.config import Config
|
||||
from app.filters.user import Registered, RegisteredCallback
|
||||
from app.keyboards.builders import travels_keyboard
|
||||
from app.keyboards.builders import locations_keyboard, sights_keyboard
|
||||
from app.keyboards.confirm_location import get as confirm_location_get
|
||||
from app.keyboards.travel import get as travel_get
|
||||
from app.keyboards.location import get as location_get
|
||||
from app.models.travel import Location, Travel
|
||||
from app.models.user import User
|
||||
from app.states.travel import CreateLocationState, TravelAlteringState
|
||||
from app.states.travel import (
|
||||
CreateLocationState,
|
||||
)
|
||||
from app.utils.geo import get_location_by_name
|
||||
from app.utils.sights import find_trips, get_info_by_xid
|
||||
from app.utils.states import delete_message_from_state, handle_validation_error
|
||||
from app.utils.weather import get_current_weather
|
||||
|
||||
|
||||
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 == []:
|
||||
try:
|
||||
await callback.message.edit_text(messages.NO_TRAVELS)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
else:
|
||||
pages = (len(travels) + Config.PAGE_SIZE - 1) // Config.PAGE_SIZE
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
messages.TRAVELS,
|
||||
reply_markup=travels_keyboard(
|
||||
travels,
|
||||
page,
|
||||
pages,
|
||||
user.telegram_id,
|
||||
),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travels_page"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travels_callback(callback: CallbackQuery) -> None:
|
||||
if callback.data is None or not isinstance(callback.message, Message):
|
||||
return
|
||||
|
||||
page = int(callback.data.replace("travels_page_", ""))
|
||||
|
||||
user = User().get_user_by_telegram_id(callback.from_user.id)
|
||||
|
||||
travels = user.get_user_travels()
|
||||
|
||||
if not travels or travels == []:
|
||||
try:
|
||||
await callback.message.edit_text(messages.NO_TRAVELS)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
else:
|
||||
pages = (len(travels) + Config.PAGE_SIZE - 1) // Config.PAGE_SIZE
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
messages.TRAVELS,
|
||||
reply_markup=travels_keyboard(
|
||||
travels,
|
||||
page,
|
||||
pages,
|
||||
user.telegram_id,
|
||||
),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
|
||||
@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=travel_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("_")
|
||||
|
||||
travel = Travel().get_travel_by_id(travel_id)
|
||||
|
||||
if not travel:
|
||||
return
|
||||
|
||||
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=travel_get(travel_id),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
await message.answer(
|
||||
messages.TRAVEL_UPDATED,
|
||||
)
|
||||
|
||||
await state.clear()
|
||||
router = Router(name="location_callback")
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
@@ -525,8 +292,6 @@ async def location_date_end_entered(
|
||||
|
||||
return
|
||||
|
||||
await delete_message_from_state(state, message.chat.id, message.bot)
|
||||
|
||||
await state.update_data(
|
||||
date_end=datetime.datetime.strftime(
|
||||
validated_date_end,
|
||||
@@ -536,6 +301,35 @@ async def location_date_end_entered(
|
||||
|
||||
data = await state.get_data()
|
||||
|
||||
overlapping_location = (
|
||||
session.query(Location)
|
||||
.filter(
|
||||
sa.and_(
|
||||
Location.travel_id == data["travel_id"],
|
||||
Location.date_start < data["date_end"],
|
||||
Location.date_end > data["date_start"],
|
||||
),
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if overlapping_location:
|
||||
await handle_validation_error(
|
||||
message,
|
||||
state,
|
||||
messages.OVERLAPPING_LOCATION,
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
await message.answer(
|
||||
messages.INPUT_TRAVEL_CALLBACK.format(
|
||||
key="end date",
|
||||
value=date_end,
|
||||
),
|
||||
)
|
||||
|
||||
await delete_message_from_state(state, message.chat.id, message.bot)
|
||||
|
||||
if "temp_location" in data:
|
||||
del data["temp_location"]
|
||||
|
||||
@@ -566,26 +360,241 @@ async def location_date_end_entered(
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_delete"),
|
||||
F.data.startswith("travel_locations_page"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def delete_travel_callback(
|
||||
async def travel_locations_page_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if callback.data is None or not isinstance(callback.message, Message):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
travel_id = int(callback.data.replace("travel_delete_", ""))
|
||||
travel_id, page = map(
|
||||
int,
|
||||
callback.data.replace("travel_locations_page_", "").split("_"),
|
||||
)
|
||||
|
||||
travel = Travel.get_travel_queryset_by_id(travel_id)
|
||||
travel = Travel.get_travel_by_id(travel_id)
|
||||
|
||||
travel.delete()
|
||||
if not travel or travel == []:
|
||||
return
|
||||
|
||||
locations = Travel.get_sorted_locations(travel)
|
||||
|
||||
pages = (len(locations) + Config.PAGE_SIZE - 1) // Config.PAGE_SIZE
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
messages.LOCATIONS,
|
||||
reply_markup=locations_keyboard(
|
||||
locations,
|
||||
page,
|
||||
pages,
|
||||
travel_id,
|
||||
),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_location_detail"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_detail_location_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
location_id = int(callback.data.replace("travel_location_detail_", ""))
|
||||
|
||||
location = Location.get_location_by_id(location_id)
|
||||
|
||||
if not location or location == []:
|
||||
return
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
location.get_location_text(),
|
||||
reply_markup=location_get(location.travel.id, location.id),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_locationdelete"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_locations_delete_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
location_id = int(callback.data.replace("travel_locationdelete_", ""))
|
||||
|
||||
location_queryset = Location.get_location_queryset_by_id(location_id)
|
||||
|
||||
if not location_queryset or location_queryset == []:
|
||||
return
|
||||
|
||||
travel = location_queryset.first().travel
|
||||
|
||||
location_queryset.delete()
|
||||
|
||||
session.commit()
|
||||
|
||||
await callback.message.answer(messages.DELETED_TRAVEL)
|
||||
locations = Travel.get_sorted_locations(travel)
|
||||
|
||||
await callback.message.delete()
|
||||
pages = (len(locations) + Config.PAGE_SIZE - 1) // Config.PAGE_SIZE
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
messages.LOCATIONS,
|
||||
reply_markup=locations_keyboard(
|
||||
locations,
|
||||
0,
|
||||
pages,
|
||||
travel.id,
|
||||
),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
await callback.message.answer(
|
||||
messages.LOCATION_DELETED,
|
||||
)
|
||||
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_locationsights"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_locationsights_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
location_id = int(callback.data.replace("travel_locationsights_", ""))
|
||||
|
||||
location = Location.get_location_by_id(location_id)
|
||||
|
||||
if not location or location == []:
|
||||
return
|
||||
|
||||
geocode = get_location_by_name(location.location)
|
||||
|
||||
sights = find_trips(geocode[1].raw.get("lat"), geocode[1].raw.get("lon"))
|
||||
|
||||
if sights is None or len(sights) == 0:
|
||||
await callback.message.answer(
|
||||
messages.NO_SIGHTS_FOUND.format(
|
||||
location=location.location,
|
||||
distance=Config.NEARBY_SIGHTS_RADIUS,
|
||||
),
|
||||
)
|
||||
else:
|
||||
await callback.message.answer(
|
||||
messages.SIGHTS_HEADER
|
||||
+ messages.SIGHTS_FOOTER.format(
|
||||
location=location.location,
|
||||
sights_count=len(sights),
|
||||
distance=Config.NEARBY_SIGHTS_RADIUS,
|
||||
),
|
||||
reply_markup=sights_keyboard(sights[:20]),
|
||||
)
|
||||
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_sight_detail"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_sight_detail_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
sight_xid = callback.data.replace("travel_sight_detail_", "")
|
||||
|
||||
await get_info_by_xid(callback, sight_xid)
|
||||
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_locationweather"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_locationweather_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
location_id = int(callback.data.replace("travel_locationweather_", ""))
|
||||
|
||||
location = Location.get_location_by_id(location_id)
|
||||
|
||||
if not location or location == []:
|
||||
return
|
||||
|
||||
geocode = get_location_by_name(location.location)
|
||||
|
||||
weather = get_current_weather(
|
||||
geocode[1].raw.get("lat"),
|
||||
geocode[1].raw.get("lon"),
|
||||
)
|
||||
|
||||
await callback.message.answer(
|
||||
messages.LOCATION_WEATHER.format(
|
||||
location=location.location,
|
||||
weather_main=weather.get("weather")[0].get("main"),
|
||||
temp=weather.get("main").get("temp"),
|
||||
feels_like=weather.get("main").get("feels_like"),
|
||||
temp_min=weather.get("main").get("temp_min"),
|
||||
temp_max=weather.get("main").get("temp_max"),
|
||||
pressure=weather.get("main").get("pressure"),
|
||||
humidity=weather.get("main").get("humidity"),
|
||||
),
|
||||
reply_to_message_id=callback.message.message_id,
|
||||
)
|
||||
|
||||
await callback.answer()
|
||||
@@ -91,3 +91,16 @@ async def travels_callback(
|
||||
)
|
||||
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data == "menu_help",
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def help_callback(callback: CallbackQuery) -> None:
|
||||
if not isinstance(callback.message, Message):
|
||||
return
|
||||
|
||||
await callback.message.answer(messages.HELP_MESSAGE)
|
||||
await callback.answer()
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
__all__ = ("router",)
|
||||
|
||||
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
|
||||
|
||||
from app import messages, session
|
||||
from app.config import Config
|
||||
from app.filters.user import RegisteredCallback
|
||||
from app.keyboards.builders import notes_keyboard
|
||||
from app.keyboards.note import get as notes_get
|
||||
from app.models.travel import Note, Travel
|
||||
from app.states.travel import (
|
||||
CreateNoteState,
|
||||
)
|
||||
|
||||
|
||||
router = Router(name="menu_callback")
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_add_note"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_add_note_callback(
|
||||
callback: CallbackQuery,
|
||||
state: FSMContext,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
travel_id = int(callback.data.replace("travel_add_note_", ""))
|
||||
|
||||
travel = Travel.get_travel_by_id(travel_id)
|
||||
|
||||
if not travel or travel == []:
|
||||
return
|
||||
|
||||
await state.set_state(CreateNoteState.file_id)
|
||||
await state.update_data(travel_id=travel_id)
|
||||
await callback.message.answer(
|
||||
messages.ADD_NOTE,
|
||||
)
|
||||
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.message(
|
||||
CreateNoteState.file_id,
|
||||
)
|
||||
async def create_note_file_id(message: Message, state: FSMContext):
|
||||
if message.from_user is None:
|
||||
return
|
||||
|
||||
if message.text == "/cancel":
|
||||
await message.answer(
|
||||
messages.ACTION_CANCELED,
|
||||
)
|
||||
|
||||
await state.update_data()
|
||||
await message.delete()
|
||||
await state.clear()
|
||||
|
||||
return
|
||||
|
||||
if message.photo is None and message.document is None:
|
||||
return
|
||||
|
||||
if message.photo is not None:
|
||||
await state.update_data(
|
||||
file_type="photo",
|
||||
file_id=message.photo[-1].file_id,
|
||||
file_name="photo",
|
||||
)
|
||||
|
||||
# await message.answer_photo(message.photo[-1].file_id)
|
||||
|
||||
elif message.document is not None:
|
||||
await state.update_data(
|
||||
file_type="document",
|
||||
file_id=message.document.file_id,
|
||||
file_name=message.document.file_name,
|
||||
)
|
||||
|
||||
# await message.answer_document(message.document.file_id)
|
||||
|
||||
data = await state.get_data()
|
||||
|
||||
data["author_id"] = message.from_user.id
|
||||
|
||||
session.add(Note(**data))
|
||||
|
||||
session.commit()
|
||||
|
||||
await message.answer(
|
||||
messages.NOTE_ADDED.format(file_name=data["file_name"]),
|
||||
)
|
||||
|
||||
await state.clear()
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_notes_page"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_notes_page_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
travel_id, page = map(
|
||||
int,
|
||||
callback.data.replace("travel_notes_page_", "").split("_"),
|
||||
)
|
||||
|
||||
travel = Travel.get_travel_queryset_by_id(travel_id)
|
||||
|
||||
if not travel or travel == []:
|
||||
return
|
||||
|
||||
travel = travel.first()
|
||||
|
||||
notes = Travel().get_notes(callback.from_user.id, travel, public=False)
|
||||
|
||||
pages = (len(notes) + Config.PAGE_SIZE - 1) // Config.PAGE_SIZE
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
messages.NOTES,
|
||||
reply_markup=notes_keyboard(notes, page, pages, travel.id),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_note_detail"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_note_detail_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
note_id = int(callback.data.replace("travel_note_detail_", ""))
|
||||
|
||||
note = Note.get_note_by_id(note_id)
|
||||
|
||||
if not note or note == []:
|
||||
return
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
note.get_note_text(),
|
||||
reply_markup=notes_get(travel_id=note.travel.id, note=note),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_notesend"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_notesend_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
note_id = int(callback.data.replace("travel_notesend_", ""))
|
||||
|
||||
note = Note.get_note_by_id(note_id)
|
||||
|
||||
if not note or note == []:
|
||||
return
|
||||
|
||||
if note.file_type == "photo":
|
||||
await callback.message.answer_photo(
|
||||
note.file_id,
|
||||
reply_to_message_id=callback.message.message_id,
|
||||
)
|
||||
|
||||
elif note.file_type == "document":
|
||||
await callback.message.answer_document(
|
||||
note.file_id,
|
||||
reply_to_message_id=callback.message.message_id,
|
||||
)
|
||||
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_note_change_privacy"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_note_change_privacy_callback(
|
||||
callback: CallbackQuery,
|
||||
state: FSMContext,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
note_id = int(callback.data.replace("travel_note_change_privacy_", ""))
|
||||
|
||||
note = Note().get_note_by_id(note_id)
|
||||
|
||||
if not note or note == []:
|
||||
return
|
||||
|
||||
if note.public:
|
||||
note.public = False
|
||||
else:
|
||||
note.public = True
|
||||
|
||||
session.commit()
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
note.get_note_text(),
|
||||
reply_markup=notes_get(travel_id=note.travel.id, note=note),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_notedelete"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travel_notedelete_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if (
|
||||
callback.message is None
|
||||
or callback.data is None
|
||||
or not isinstance(callback.message, Message)
|
||||
):
|
||||
return
|
||||
|
||||
note_id = int(callback.data.replace("travel_notedelete_", ""))
|
||||
|
||||
note = Note().get_note_queryset_by_id(note_id)
|
||||
|
||||
note_first = note.first()
|
||||
file_name = note_first.file_name
|
||||
travel = note_first.travel
|
||||
|
||||
if not note or note == []:
|
||||
return
|
||||
|
||||
note.delete()
|
||||
|
||||
session.commit()
|
||||
|
||||
notes = Travel().get_notes(callback.from_user.id, travel, public=False)
|
||||
|
||||
pages = (len(notes) + Config.PAGE_SIZE - 1) // Config.PAGE_SIZE
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
messages.NOTES,
|
||||
reply_markup=notes_keyboard(notes, 0, pages, travel.id),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
await callback.message.answer(
|
||||
messages.NOTE_DELETED.format(file_name=file_name),
|
||||
)
|
||||
@@ -22,7 +22,7 @@ router = Router(name="profile_callback")
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("profile_change_"),
|
||||
F.data.startswith("profile_change"),
|
||||
StateFilter(None),
|
||||
RegisteredCallback(),
|
||||
)
|
||||
@@ -227,8 +227,12 @@ async def profile_change_entered(message: Message, state: FSMContext) -> None:
|
||||
state_data = await state.get_data()
|
||||
|
||||
user = User.get_user_queryset_by_telegram_id(message.from_user.id)
|
||||
user_first = user.first()
|
||||
|
||||
if isinstance(state_data["value"], list):
|
||||
old_value = user_first.country + ", " + user_first.city
|
||||
new_value = state_data["value"][0] + ", " + state_data["value"][1]
|
||||
|
||||
user.update(
|
||||
{
|
||||
"country": state_data["value"][0],
|
||||
@@ -241,6 +245,9 @@ async def profile_change_entered(message: Message, state: FSMContext) -> None:
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
else:
|
||||
old_value = getattr(user.first(), str(column))
|
||||
new_value = state_data["value"]
|
||||
|
||||
data = {state_data["column"]: state_data["value"]}
|
||||
user.update(data)
|
||||
|
||||
@@ -260,7 +267,11 @@ async def profile_change_entered(message: Message, state: FSMContext) -> None:
|
||||
pass
|
||||
|
||||
await message.answer(
|
||||
messages.PROFILE_UPDATED,
|
||||
messages.PROFILE_UPDATED.format(
|
||||
key=state_data["column"],
|
||||
old_value=old_value if old_value else messages.NOT_SET,
|
||||
new_value=(new_value if new_value else messages.NOT_SET),
|
||||
),
|
||||
reply_markup=ReplyKeyboardRemove(),
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
__all__ = ("router",)
|
||||
|
||||
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
|
||||
|
||||
from app import messages, session
|
||||
from app.config import Config
|
||||
from app.filters.user import Registered, RegisteredCallback
|
||||
from app.keyboards.builders import travels_keyboard
|
||||
from app.keyboards.travel import get as travel_get
|
||||
from app.models.travel import Travel
|
||||
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.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 == []:
|
||||
try:
|
||||
await callback.message.edit_text(messages.NO_TRAVELS)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
else:
|
||||
pages = (len(travels) + Config.PAGE_SIZE - 1) // Config.PAGE_SIZE
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
messages.TRAVELS,
|
||||
reply_markup=travels_keyboard(
|
||||
travels,
|
||||
page,
|
||||
pages,
|
||||
user.telegram_id,
|
||||
),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travels_page"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def travels_callback(callback: CallbackQuery) -> None:
|
||||
if callback.data is None or not isinstance(callback.message, Message):
|
||||
return
|
||||
|
||||
page = int(callback.data.replace("travels_page_", ""))
|
||||
|
||||
user = User().get_user_by_telegram_id(callback.from_user.id)
|
||||
|
||||
travels = user.get_user_travels()
|
||||
|
||||
if not travels or travels == []:
|
||||
try:
|
||||
await callback.message.edit_text(messages.NO_TRAVELS)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
else:
|
||||
pages = (len(travels) + Config.PAGE_SIZE - 1) // Config.PAGE_SIZE
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
messages.TRAVELS,
|
||||
reply_markup=travels_keyboard(
|
||||
travels,
|
||||
page,
|
||||
pages,
|
||||
user.telegram_id,
|
||||
),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
|
||||
@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
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
travel.get_travel_text(),
|
||||
reply_markup=travel_get(travel),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
|
||||
@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("_")
|
||||
|
||||
travel = Travel().get_travel_by_id(travel_id)
|
||||
|
||||
if not travel:
|
||||
return
|
||||
|
||||
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=travel_get(travel),
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
pass
|
||||
|
||||
await message.answer(
|
||||
messages.TRAVEL_UPDATED,
|
||||
)
|
||||
|
||||
await state.clear()
|
||||
|
||||
|
||||
@router.callback_query(
|
||||
F.data.startswith("travel_delete"),
|
||||
RegisteredCallback(),
|
||||
StateFilter(None),
|
||||
)
|
||||
async def delete_travel_callback(
|
||||
callback: CallbackQuery,
|
||||
):
|
||||
if callback.data is None or not isinstance(callback.message, Message):
|
||||
return
|
||||
|
||||
travel_id = int(callback.data.replace("travel_delete_", ""))
|
||||
|
||||
user = User().get_user_by_telegram_id(callback.from_user.id)
|
||||
|
||||
travel = Travel.get_travel_queryset_by_id(travel_id)
|
||||
|
||||
travel.delete()
|
||||
|
||||
session.commit()
|
||||
|
||||
travels = user.get_user_travels()
|
||||
|
||||
pages = (len(travels) + Config.PAGE_SIZE - 1) // Config.PAGE_SIZE
|
||||
|
||||
await callback.message.answer(messages.DELETED_TRAVEL)
|
||||
|
||||
await callback.message.edit_text(
|
||||
messages.TRAVELS,
|
||||
reply_markup=travels_keyboard(
|
||||
travels,
|
||||
0,
|
||||
pages,
|
||||
callback.from_user.id,
|
||||
),
|
||||
)
|
||||
|
||||
await callback.answer()
|
||||
Reference in New Issue
Block a user