127 lines
4.9 KiB
Python
127 lines
4.9 KiB
Python
import logging
|
|
import time
|
|
|
|
import pendulum
|
|
from aiohttp import ClientSession
|
|
from connectors import GestionSportsConnector
|
|
from models import BookingFilter, BookingOpening, Club, Court, User
|
|
from pendulum import DateTime
|
|
|
|
LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
class GestionSportsServices:
|
|
@staticmethod
|
|
async def book(
|
|
club: Club, user: User, booking_filter: BookingFilter
|
|
) -> Court | None:
|
|
"""
|
|
Perform a request for each court at the same time to increase the chances to get
|
|
a booking.
|
|
The gestion-sports backend does not allow several bookings at the same time
|
|
so there is no need to make each request one after the other
|
|
|
|
:param club: the club in which the booking will be made
|
|
:param user: the user that wants to book the court
|
|
:param booking_filter: the booking conditions to meet
|
|
:return: the booked court, or None if no court was booked
|
|
"""
|
|
connector = GestionSportsConnector(club)
|
|
LOGGER.info(
|
|
"Booking any available court from GestionSports API at %s",
|
|
connector.booking_url,
|
|
)
|
|
|
|
async with ClientSession() as session:
|
|
# use asyncio to request a booking on every court
|
|
# the gestion-sports backend is able to book only one court for a user
|
|
await connector.land(session)
|
|
await connector.login(session, user)
|
|
|
|
booking_opening = club.booking_platform.booking_opening
|
|
GestionSportsServices.wait_until_booking_time(
|
|
booking_filter, booking_opening
|
|
)
|
|
|
|
bookings = await connector.book_any_court(session, booking_filter)
|
|
|
|
LOGGER.debug("Booking results:\n'%s'", bookings)
|
|
return connector.get_booked_court(bookings, booking_filter.sport_name)
|
|
|
|
@staticmethod
|
|
async def has_user_available_slots(user: User, club: Club) -> bool:
|
|
connector = GestionSportsConnector(club)
|
|
async with ClientSession() as session:
|
|
await connector.land(session)
|
|
await connector.login(session, user)
|
|
bookings = await connector.get_ongoing_bookings(session)
|
|
|
|
return bool(bookings)
|
|
|
|
@staticmethod
|
|
async def cancel_booking(user: User, club: Club, booking_filter: BookingFilter):
|
|
connector = GestionSportsConnector(club)
|
|
async with ClientSession() as session:
|
|
await connector.land(session)
|
|
await connector.login(session, user)
|
|
await connector.cancel_booking(session, booking_filter)
|
|
|
|
@staticmethod
|
|
async def cancel_booking_id(user: User, club: Club, booking_id: int):
|
|
connector = GestionSportsConnector(club)
|
|
async with ClientSession() as session:
|
|
await connector.land(session)
|
|
await connector.login(session, user)
|
|
await connector.cancel_booking_id(session, booking_id)
|
|
|
|
@staticmethod
|
|
def wait_until_booking_time(
|
|
booking_filter: BookingFilter, booking_opening: BookingOpening
|
|
) -> None:
|
|
"""
|
|
Wait until the booking is open.
|
|
The booking filter contains the date and time of the booking.
|
|
The club has the information about when the booking is open for that date.
|
|
|
|
:param booking_opening:
|
|
:param booking_filter: the booking information
|
|
"""
|
|
LOGGER.info("Waiting for booking time")
|
|
booking_datetime = GestionSportsServices.build_booking_datetime(
|
|
booking_filter, booking_opening
|
|
)
|
|
now = pendulum.now()
|
|
duration_until_booking = booking_datetime - now
|
|
LOGGER.debug(f"Current time: {now}, Datetime to book: {booking_datetime}")
|
|
LOGGER.debug(
|
|
f"Time to wait before booking: {duration_until_booking.hours:0>2}"
|
|
f":{duration_until_booking.minutes:0>2}"
|
|
f":{duration_until_booking.seconds:0>2}"
|
|
)
|
|
|
|
while now < booking_datetime:
|
|
time.sleep(1)
|
|
now = pendulum.now()
|
|
LOGGER.info("It's booking time!")
|
|
|
|
@staticmethod
|
|
def build_booking_datetime(
|
|
booking_filter: BookingFilter, booking_opening: BookingOpening
|
|
) -> DateTime:
|
|
"""
|
|
Build the date and time when the booking is open for a given match date.
|
|
The booking filter contains the date and time of the booking.
|
|
The club has the information about when the booking is open for that date.
|
|
|
|
:param booking_opening:the booking opening conditions
|
|
:param booking_filter: the booking information
|
|
:return: the date and time when the booking is open
|
|
"""
|
|
date_to_book = booking_filter.date
|
|
booking_date = date_to_book.subtract(days=booking_opening.days_before)
|
|
|
|
opening_time = pendulum.parse(booking_opening.opening_time)
|
|
booking_hour = opening_time.hour
|
|
booking_minute = opening_time.minute
|
|
|
|
return booking_date.at(booking_hour, booking_minute)
|