Payloads are now built with Jinja templates

This commit is contained in:
Stanislas Jouffroy 2024-02-20 10:23:29 +01:00
parent ccd019eb4c
commit badced0a30
12 changed files with 222 additions and 175 deletions

View file

@ -90,3 +90,7 @@ def init_log_config():
with open(logging_file, "r") as f:
logging_config = yaml.safe_load(f.read())
logging.config.dictConfig(logging_config)
ROOT_PATH = Path(__file__).parent.resolve()
RESOURCES_DIR = Path(ROOT_PATH, "resources")

View file

@ -0,0 +1,7 @@
from pathlib import Path
import config
RESOURCES_DIR = Path(config.RESOURCES_DIR, "gestion-sports")
BOOKING_TEMPLATE = Path(RESOURCES_DIR, "booking-payload.txt")
LOGIN_TEMPLATE = Path(RESOURCES_DIR, "login-payload.txt")

View file

@ -6,7 +6,10 @@ from urllib.parse import urljoin
from aiohttp import ClientResponse, ClientSession
import config
from gestion_sports.gestion_sports_payload_builder import GestionSportsPayloadBuilder
from gestion_sports.payload_builders import (
GestionSportsLoginPayloadBuilder,
GestionSportsBookingPayloadBuilder,
)
from models import BookingFilter, Club, User
DATE_FORMAT = "%d/%m/%Y"
@ -26,7 +29,6 @@ class GestionSportsConnector:
LOGGER.info("Initializing connection to GestionSports API")
self.url = url
self.session = session
self.payload_builder = GestionSportsPayloadBuilder()
@property
def landing_url(self) -> str:
@ -72,12 +74,8 @@ class GestionSportsConnector:
:return: the response from the login
"""
payload = (
self.payload_builder.login(user.login)
.password(user.password)
.club_id(club.id)
.build_login_payload()
)
payload_builder = GestionSportsLoginPayloadBuilder()
payload = payload_builder.user(user).club(club).build()
async with self.session.post(
self.login_url, data=payload, headers=POST_HEADERS
@ -105,10 +103,11 @@ class GestionSportsConnector:
return_exceptions=True,
)
return await self.get_booked_court(bookings)
return self.get_booked_court(bookings)
@staticmethod
async def get_booked_court(bookings):
def get_booked_court(bookings):
LOGGER.info(bookings)
for court, is_booked in bookings:
if is_booked:
return court
@ -117,23 +116,23 @@ class GestionSportsConnector:
async def book_one_court(
self, booking_filter: BookingFilter, court_id: int
) -> tuple[int, bool]:
payload_builder = GestionSportsBookingPayloadBuilder()
payload = (
self.payload_builder.date(booking_filter.date.date().strftime(DATE_FORMAT))
.time(booking_filter.date.time().strftime(TIME_FORMAT))
.sport_id(booking_filter.sport_id)
.court_id(court_id)
.build_booking_payload()
payload_builder.booking_filter(booking_filter).court_id(court_id).build()
)
return court_id, await self.is_court_booked(payload)
LOGGER.info(payload)
async def is_court_booked(self, payload: str) -> bool:
async with self.session.post(
self.booking_url, data=payload, headers=POST_HEADERS
) as response:
return self.is_response_status_ok(await response.text())
resp_json = await response.text()
return court_id, self.is_response_status_ok(resp_json)
@staticmethod
def is_response_status_ok(response: str) -> bool:
LOGGER.info(response)
formatted_result = response.removeprefix('"').removesuffix('"')
result_json = json.loads(formatted_result)
return result_json["status"] == "ok"

View file

@ -1,69 +0,0 @@
from exceptions import ArgumentMissing
class GestionSportsPayloadBuilder:
def __init__(self):
self._login = None
self._password = None
self._club_id = None
self._date = None
self._time = None
self._sport_id = None
self._court_id = None
def login(self, login: str):
self._login = login
return self
def password(self, password: str):
self._password = password
return self
def club_id(self, club_id: str):
self._club_id = club_id
return self
def date(self, date: str):
self._date = date
return self
def time(self, time: str):
self._time = time
return self
def sport_id(self, sport_id: int):
self._sport_id = sport_id
return self
def court_id(self, court_id: int):
self._court_id = court_id
return self
def build_login_payload(self):
if self._login is None:
raise ArgumentMissing("Login not provided")
if self.password is None:
raise ArgumentMissing("Password not provided")
if self._club_id is None:
raise ArgumentMissing("Club ID not provided")
return (
f"ajax=connexionUser&id_club={self._club_id}&email={self._login}&form_ajax=1&pass={self._password}&compte"
f"=user&playeridonesignal=0&identifiant=identifiant&externCo=true"
).encode("utf-8")
def build_booking_payload(self):
if self._date is None:
raise ArgumentMissing("Date not provided")
if self._time is None:
raise ArgumentMissing("Time not provided")
if self._sport_id is None:
raise ArgumentMissing("Sport ID not provided")
if self._court_id is None:
raise ArgumentMissing("Court ID not provided")
return (
f"ajax=addResa&date={self._date}&hour={self._time}&duration=90&partners=null|null|null"
f"&paiement=facultatif&idSport={self._sport_id}&creaPartie=false&idCourt={self._court_id}"
f"&pay=false&token=undefined&totalPrice=44&saveCard=0&foodNumber=0"
).encode("utf-8")

View file

@ -0,0 +1,59 @@
from jinja2 import Environment, FileSystemLoader
from exceptions import ArgumentMissing
from gestion_sports.gestion_sports_config import LOGIN_TEMPLATE, BOOKING_TEMPLATE
from models import User, Club, BookingFilter
class GestionSportsLoginPayloadBuilder:
def __init__(self):
self._user: User | None = None
self._club: Club | None = None
self._template = LOGIN_TEMPLATE
def user(self, user: User):
self._user = user
return self
def club(self, club: Club):
self._club = club
return self
def build(self):
if self._user is None:
raise ArgumentMissing("No user was provided")
if self._club is None:
raise ArgumentMissing("No club was provided")
environment = Environment(loader=FileSystemLoader(self._template.parent))
template = environment.get_template(self._template.name)
return template.render(club=self._club, user=self._user)
class GestionSportsBookingPayloadBuilder:
def __init__(self):
self._booking_filter: BookingFilter | None = None
self._court_id: int | None = None
self._template = BOOKING_TEMPLATE
def booking_filter(self, booking_filter: BookingFilter):
self._booking_filter = booking_filter
return self
def court_id(self, court_id: int):
self._court_id = court_id
return self
def build(self):
if self._booking_filter is None:
raise ArgumentMissing("No booking filter was provided")
if self.court_id is None:
raise ArgumentMissing("No court id was provided")
environment = Environment(loader=FileSystemLoader(self._template.parent))
template = environment.get_template(self._template.name)
return template.render(
court_id=self._court_id, booking_filter=self._booking_filter
)

View file

@ -0,0 +1 @@
ajax=addResa&date={{ booking_filter.date.date().strftime("%d/%m/%Y") }}&hour={{ booking_filter.date.time().strftime("%H:%M") }}&duration=90&partners=null|null|null&paiement=facultatif&idSport={{ booking_filter.sport_id }}&creaPartie=false&idCourt={{ court_id }}&pay=false&token=undefined&totalPrice=44&saveCard=0&foodNumber=0

View file

@ -0,0 +1 @@
ajax=connexionUser&id_club={{ club.id }}&email={{ user.login }}&form_ajax=1&pass={{ user.password }}&compte=user&playeridonesignal=0&identifiant=identifiant&externCo=true