Added docstrings
This commit is contained in:
parent
5434a74d0f
commit
ccd019eb4c
4 changed files with 174 additions and 21 deletions
|
@ -14,6 +14,14 @@ LOGGER = logging.getLogger(__name__)
|
|||
|
||||
|
||||
def wait_until_booking_time(club: Club, booking_filter: BookingFilter):
|
||||
"""
|
||||
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 club: the club where to book a court
|
||||
:param booking_filter: the booking information
|
||||
"""
|
||||
LOGGER.info("Waiting booking time")
|
||||
booking_datetime = build_booking_datetime(booking_filter, club)
|
||||
now = pendulum.now()
|
||||
|
@ -23,6 +31,15 @@ def wait_until_booking_time(club: Club, booking_filter: BookingFilter):
|
|||
|
||||
|
||||
def build_booking_datetime(booking_filter: BookingFilter, club: Club) -> 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_filter: the booking information
|
||||
:param club: the club where to book a court
|
||||
:return: the date and time when the booking is open
|
||||
"""
|
||||
date_to_book = booking_filter.date
|
||||
booking_date = date_to_book.subtract(days=club.booking_open_days_before)
|
||||
|
||||
|
@ -33,15 +50,28 @@ def build_booking_datetime(booking_filter: BookingFilter, club: Club) -> DateTim
|
|||
|
||||
|
||||
async def book(club: Club, user: User, booking_filter: BookingFilter) -> int | None:
|
||||
"""
|
||||
Book a court for a user to a club following a booking filter
|
||||
|
||||
:param club: the club where to book a court
|
||||
:param user: the user information
|
||||
:param booking_filter: the information related to the booking
|
||||
:return: the id of the booked court, or None if no court was booked
|
||||
"""
|
||||
async with ClientSession() as session:
|
||||
platform = GestionSportsConnector(session, club.url)
|
||||
await platform.connect()
|
||||
await platform.land()
|
||||
await platform.login(user, club)
|
||||
wait_until_booking_time(club, booking_filter)
|
||||
return await platform.book(booking_filter, club)
|
||||
|
||||
|
||||
def main() -> int | None:
|
||||
"""
|
||||
Main function used to book a court
|
||||
|
||||
:return: the id of the booked court, or None if no court was booked
|
||||
"""
|
||||
user = config.get_user()
|
||||
booking_filter = config.get_booking_filter()
|
||||
club = config.get_club()
|
||||
|
|
|
@ -13,6 +13,12 @@ load_dotenv()
|
|||
|
||||
|
||||
def get_club() -> Club:
|
||||
"""
|
||||
Read the environment variables related to the current club
|
||||
and build the Club object
|
||||
|
||||
:return: the club
|
||||
"""
|
||||
club_url = os.environ.get("CLUB_URL")
|
||||
court_ids_tmp = os.environ.get("COURT_IDS") or ""
|
||||
court_ids = (
|
||||
|
@ -34,6 +40,12 @@ def get_club() -> Club:
|
|||
|
||||
|
||||
def get_booking_filter() -> BookingFilter:
|
||||
"""
|
||||
Read the environment variables related to the current booking filter
|
||||
and build the BookingFilter object
|
||||
|
||||
:return: the club
|
||||
"""
|
||||
sport_id_tmp = os.environ.get("SPORT_ID")
|
||||
sport_id = int(sport_id_tmp) if sport_id_tmp else None
|
||||
date_time_tmp = os.environ.get("DATE_TIME")
|
||||
|
@ -42,12 +54,24 @@ def get_booking_filter() -> BookingFilter:
|
|||
|
||||
|
||||
def get_user() -> User:
|
||||
"""
|
||||
Read the environment variables related to the current user
|
||||
and build the User object
|
||||
|
||||
:return: the club
|
||||
"""
|
||||
login = os.environ.get("LOGIN")
|
||||
password = os.environ.get("PASSWORD")
|
||||
return User(login=login, password=password)
|
||||
|
||||
|
||||
def get_post_headers(platform_id: str) -> dict:
|
||||
"""
|
||||
Get the headers for the POST endpoint related to a specific booking platform
|
||||
|
||||
:param platform_id: the platform to which the headers apply
|
||||
:return: the headers as a dictionary
|
||||
"""
|
||||
root_path = Path(__file__).parent
|
||||
headers_file = Path(root_path, "resources", platform_id, "post-headers.json")
|
||||
with headers_file.open(mode="r", encoding="utf-8") as f:
|
||||
|
@ -57,6 +81,9 @@ def get_post_headers(platform_id: str) -> dict:
|
|||
|
||||
|
||||
def init_log_config():
|
||||
"""
|
||||
Read the logging.yaml file to initialize the logging configuration
|
||||
"""
|
||||
root_dir = os.path.realpath(os.path.dirname(__file__))
|
||||
logging_file = root_dir + "/logging.yaml"
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ POST_HEADERS = config.get_post_headers("gestion-sports")
|
|||
|
||||
|
||||
class GestionSportsConnector:
|
||||
"""
|
||||
Handle the specific booking requests to Gestion-Sports
|
||||
"""
|
||||
|
||||
def __init__(self, session: ClientSession, url: str):
|
||||
LOGGER.info("Initializing connection to GestionSports API")
|
||||
|
@ -26,24 +29,49 @@ class GestionSportsConnector:
|
|||
self.payload_builder = GestionSportsPayloadBuilder()
|
||||
|
||||
@property
|
||||
def connection_url(self) -> str:
|
||||
def landing_url(self) -> str:
|
||||
"""
|
||||
Get the URL to the landing page of Gestion-Sports
|
||||
|
||||
:return: the URL to the landing page
|
||||
"""
|
||||
return urljoin(self.url, "/connexion.php?")
|
||||
|
||||
@property
|
||||
def login_url(self) -> str:
|
||||
"""
|
||||
Get the URL to the connection login of Gestion-Sports
|
||||
|
||||
:return: the URL to the login page
|
||||
"""
|
||||
return urljoin(self.url, "/connexion.php?")
|
||||
|
||||
@property
|
||||
def booking_url(self) -> str:
|
||||
"""
|
||||
Get the URL to the booking page of Gestion-Sports
|
||||
|
||||
:return: the URL to the booking page
|
||||
"""
|
||||
return urljoin(self.url, "/membre/reservation.html?")
|
||||
|
||||
async def connect(self) -> ClientResponse:
|
||||
async def land(self) -> ClientResponse:
|
||||
"""
|
||||
Perform the request to the landing page in order to get the cookie PHPSESSIONID
|
||||
|
||||
:return: the response from the landing page
|
||||
"""
|
||||
LOGGER.info("Connecting to GestionSports API")
|
||||
async with self.session.get(self.connection_url) as response:
|
||||
async with self.session.get(self.landing_url) as response:
|
||||
await response.text()
|
||||
return response
|
||||
|
||||
async def login(self, user: User, club: Club) -> ClientResponse:
|
||||
"""
|
||||
Perform the request to the log in the user
|
||||
|
||||
:return: the response from the login
|
||||
"""
|
||||
payload = (
|
||||
self.payload_builder.login(user.login)
|
||||
.password(user.password)
|
||||
|
@ -58,6 +86,15 @@ class GestionSportsConnector:
|
|||
return response
|
||||
|
||||
async def book(self, booking_filter: BookingFilter, club: Club) -> int | 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 booking_filter: the booking information
|
||||
:param club: the club where to book the court
|
||||
:return: the booked court, or None if no court was booked
|
||||
"""
|
||||
# use asyncio to request a booking on every court
|
||||
# the gestion-sports backend is able to book only one court for a user
|
||||
bookings = await asyncio.gather(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue