From 98cef3603c2c2b3c25762462a577a7bfd26839e7 Mon Sep 17 00:00:00 2001 From: Yarne Coppens Date: Fri, 2 Aug 2024 12:48:35 +0200 Subject: [PATCH] Added the abililty to retrieve all plays --- src/classes/play_classes.py | 5 ++- src/main.py | 11 ++++- src/modules/bgg_connection.py | 75 +++++++++++++++++++++++++++++++++-- 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/classes/play_classes.py b/src/classes/play_classes.py index ad69161..045dacc 100644 --- a/src/classes/play_classes.py +++ b/src/classes/play_classes.py @@ -1,17 +1,18 @@ from pydantic import BaseModel +from typing import Union from datetime import date class PlayPlayer(BaseModel): name: str username: str - score: float + score: Union[float, None] first_play : bool has_won : bool class Play(BaseModel): boardgame_id: int players: list[PlayPlayer] - playdate: date + play_date: date duration: int #In minutes ignore_for_stats : bool location: str \ No newline at end of file diff --git a/src/main.py b/src/main.py index 8f025e5..6d94cea 100644 --- a/src/main.py +++ b/src/main.py @@ -1,7 +1,7 @@ from typing import Union from fastapi import FastAPI -from src.classes import boardgame_classes +from src.classes import boardgame_classes, play_classes from src.modules import bgg_connection app = FastAPI() @@ -25,4 +25,11 @@ def get_owned_collection(): @app.get("/wishlist", response_model=list[boardgame_classes.WishlistBoardGame]) def get_wishlist_collection(): requested_collection: list[boardgame_classes.WishlistBoardGame] = bgg_connection.get_user_wishlist_collection() - return requested_collection \ No newline at end of file + return requested_collection + + + +@app.get("/plays", response_model=list[play_classes.Play]) +def get_plays(): + requested_plays: list[play_classes.Play] = bgg_connection.get_plays() + return requested_plays \ No newline at end of file diff --git a/src/modules/bgg_connection.py b/src/modules/bgg_connection.py index 5bc023a..e966b92 100644 --- a/src/modules/bgg_connection.py +++ b/src/modules/bgg_connection.py @@ -4,10 +4,11 @@ from pydantic import HttpUrl import requests from datetime import datetime import time +import math -from src.classes import boardgame_classes +from src.classes import boardgame_classes, play_classes from src.modules import auth_manager - +from src.config import definitions authenticated_session: requests.Session = requests.Session() @@ -33,7 +34,7 @@ def get_boardgame(boardgame_id: int) -> boardgame_classes.BoardGame: def get_multiple_boardgames(boardgame_ids: list[int]) -> list[boardgame_classes.BoardGame]: - def divide_list_in_chunks(list_to_divide: list[int], chunk_size: int = 20): + def divide_list_in_chunks(list_to_divide: list[int], chunk_size: int = definitions.BGG_MAX_THING_BOARDGAMES): for i in range(0, len(list_to_divide), chunk_size): yield list_to_divide[i:i + chunk_size] @@ -181,6 +182,51 @@ def convert_collection_xml_to_wishlist_boardgame(boardgame_extra_info: boardgame return boardgame +def convert_playplayer_xml_to_playplayer(playplayer_xml: ET.Element) -> play_classes.PlayPlayer: + + score = playplayer_xml.get('score') + if score == '': + score = None + else: + score = float(score) + + playplayer_dict = { + "name" : playplayer_xml.get('name'), + "username" : playplayer_xml.get('username'), + "score" : score, + "first_play" : bool(int(playplayer_xml.get('new'))), + "has_won" : bool(int(playplayer_xml.get('win'))) + } + + playplayer = play_classes.PlayPlayer(**playplayer_dict) + + return playplayer + +def convert_play_xml_to_play(play_xml: ET.Element) -> play_classes.Play: + + date_string = play_xml.get('date') + play_date = datetime.strptime(date_string, '%Y-%m-%d').date() + + playplayer_list: list[play_classes.PlayPlayer] = [] + + for play_player_xml in play_xml.find('players'): + playplayer_list.append(convert_playplayer_xml_to_playplayer(play_player_xml)) + + play_dict = { + "boardgame_id" : int(play_xml.find('item').get('objectid')), + "players" : playplayer_list, + "play_date" : play_date, + "duration" : int(play_xml.get('length')), + "ignore_for_stats" : bool(play_xml.get('nowinstats')), + "location" : play_xml.get('location') + } + + play = play_classes.Play(**play_dict) + + return play + + + #Creates list of board games from a collection '/collection' URL def get_boardgames_from_collection_url(collection_url: str, boardgame_type: boardgame_classes.BoardgameType) -> list[boardgame_classes.BoardGame]: collection_xml = url_to_xml_object(collection_url) @@ -239,6 +285,29 @@ def get_user_wishlist_collection() -> list[boardgame_classes.BoardGame]: return wishlisted_boardgames + +def get_plays() -> list[play_classes.Play]: + first_page_url = 'https://boardgamegeek.com/xmlapi2/plays?username={}'.format(auth_manager.username) + plays_first_page_xml_object = url_to_xml_object(first_page_url) + + amount_of_plays_total = float(plays_first_page_xml_object.get('total')) + + amount_of_pages_needed = math.ceil(amount_of_plays_total/definitions.BGG_PLAY_PAGE_SIZE) + + all_plays : list[play_classes.Play] = [] + + for page in range(amount_of_pages_needed): + url = 'https://boardgamegeek.com/xmlapi2/plays?username={}&page={}'.format(auth_manager.username, page) + plays_page_xml_object = url_to_xml_object(url) + for play_xml in plays_page_xml_object: + new_play = convert_play_xml_to_play(play_xml) + all_plays.append(new_play) + + return all_plays + + + + def load_authenticated_bgg_session(username: str, password: str) -> requests.Session: global authenticated_session