diff --git a/FlaskWebProject/FlaskWebProject/fs_scraper.py b/FlaskWebProject/FlaskWebProject/fs_scraper.py index 70f2cc9..cceab1a 100644 --- a/FlaskWebProject/FlaskWebProject/fs_scraper.py +++ b/FlaskWebProject/FlaskWebProject/fs_scraper.py @@ -14,25 +14,10 @@ def safe_traverse(obj: dict, path: list, default=None): result = result[x] except KeyError: result = default - # print(f"error reading: {' -> '.join(path)} - returning: {default}") + print(f"safe_traverse: error reading {' -> '.join(path)} - returning: {default}") finally: return result -def get_stat_value(stats: dict, stat_id: str, field: str = "value", default=None): - """ - Bezpiecznie pobiera wartość z pola 'value' lub 'type' dla danego stat_id w strukturze 'stats'. - - :param stats: słownik ze statystykami - :param stat_id: ID statystyki jako string, np. "595" - :param field: 'value' lub 'type' - :param default: wartość domyślna zwracana, jeśli coś pójdzie nie tak - :return: wartość z pola lub default - """ - try: - return stats[stat_id][field] - except (KeyError, TypeError): - return default - class scraper: headers = { @@ -62,6 +47,17 @@ class scraper: else: return False + def to_iso_compatible_date(self, dmy_date: str): + """ + Zamienia datę z formatu DD.MM.YY na YYYY-MM-DD + + :param dmy_date: Data w formacie DD.MM.YY + :type dmy_date: str + """ + day, month, year = dmy_date.split(".") + return f"{2000 + int(year)}-{month}-{day}" + + def czy_mecz_istnieje(self, zewnetrzne_id_meczu: str): # mecz = db.simple_select_all(ldb.mecze, zewnetrzne_id_meczu=zewnetrzne_id_meczu) # if mecz is not None and mecz != []: @@ -114,6 +110,8 @@ class scraper: # Jeśli nie, dodaj go w podobny sposób, jak # w sample_data_init() (w lewy_db.py). + id_zawodnika = self.db.get_id_zawodnika_by_zewnetrzne_id(zewnetrzne_id_sportowca) + zawodnik = self.db.simple_select_all("sportowcy", zewnetrzne_id_zawodnika=zewnetrzne_id_sportowca)[0] page = 0 match_num = 0 @@ -160,42 +158,87 @@ class scraper: # TODO: dodaj obiekt mecz do bazy (simple_insert_one(), simple_insert_many()) print(f"{c.OKCYAN}Nowy mecz ({match_num}){c.ENDC}: {match}") - self.db.simple_insert_one("mecze", - zewnetrzne_id_meczu= safe_traverse(match, ["eventId"], default=""), - data= safe_traverse(match, ["eventStartTime"], default=func.now()), - gospodarze_id= safe_traverse(match, ["homeParticipant3CharName"], default=0), - gospodarze= safe_traverse(match, ["homeParticipantName"], default=""), - goscie_id= safe_traverse(match, ["awayParticipant3CharName"], default=0), - goscie= safe_traverse(match, ["awayParticipantName"], default=""), - gosp_wynik= safe_traverse(match, ["homeScore"], default=0), - gosc_wynik= safe_traverse(match, ["awayScore"], default=0), - sezon= safe_traverse(match, ["tournamentSeason"], default=""), - nazwa_turnieju= safe_traverse(match, ["tournamentTitle"], default=""), - skrocona_nazwa_turnieju=safe_traverse(match, ["tournamentTemplateShortCode"], default=""), - flaga= safe_traverse(match, ["flagId"], default=0), + iso_converted_date = self.to_iso_compatible_date(safe_traverse(match, ["eventStartTime"], default="1970-01-01")) + self.db.simple_insert_one("mecze", + zewnetrzne_id_meczu = safe_traverse(match, ["eventEncodedId"], default=""), + data = iso_converted_date, + gospodarze_id = home_club_id, + gospodarze = self.db.simple_select_all("kluby", id_klubu=home_club_id)[0], + goscie_id = away_club_id, + goscie = self.db.simple_select_all("kluby", id_klubu=away_club_id)[0], + gosp_wynik = safe_traverse(match, ["homeScore"], default=0), + gosc_wynik = safe_traverse(match, ["awayScore"], default=0), + sezon = safe_traverse(match, ["tournamentSeason"], default=""), + nazwa_turnieju = safe_traverse(match, ["tournamentTitle"], default=""), + skrocona_nazwa_turnieju = safe_traverse(match, ["tournamentTemplateShortCode"], default=""), + flaga = safe_traverse(match, ["flagId"], default=0), ) match_num += 1 - stats=safe_traverse(match, ["stats"], default=""), - zewnetrzne_id_meczu= safe_traverse(match, ["eventId"], default=""), - - self.db.increment_fields("sportowcy",zewnetrzne_id_sportowca, - ostatni_mecz= self.db.get_id_meczu_by_zewnetrzne_id(self.db, zewnetrzne_id_meczu), - ilosc_wystapien= 1 if get_stat_value(stats, "595") > 0 else 0 , - minut_gry= get_stat_value(stats, "595"), - gier_sum= 1 if get_stat_value(stats, "595") > 0 else 0 , - goli_sum= get_stat_value(stats, "596"), - asyst_sum= get_stat_value(stats, "541"), - interwencji_sum= 0, - nieobronionych_interwencji_sum= 0, - zoltych_kartek_sum= get_stat_value(stats, "599"), - czerwonych_kartek_sum= get_stat_value(stats, "600"), - wygranych_sum = 1 if safe_traverse(match, ["winLoseShort"], default=0) == "Z" else 0, - wynik_sum= safe_traverse(match, ["rating"], default=0), - meczow_do_wynikow_sum= 1 if (rating := safe_traverse(match, ["rating"], default=0)) not in (0, None) else None + stats = safe_traverse(match, ["stats"], default="") + zewnetrzne_id_meczu = safe_traverse(match, ["eventEncodedId"], default="") - ) + if stats != False: # gdy sportowiec był aktywny w meczu + print("todo :)") + # # TODO: + # self.db.simple_insert_one("sportowcy_w_meczach", + # id_zawodnika = id_zawodnika, + # zawodnik = zawodnik, + # zewnetrzne_id_meczu = zewnetrzne_id_meczu, + # # ODTĄD SIĘ NIE POKRYWA!!! POLA POWINNY SIĘ ZGADZAĆ Z TYM, CO JEST W LEWY_DB (konkretnie klasie sportowcy_w_meczach) + # ostatni_mecz = self.db.get_id_meczu_by_zewnetrzne_id(zewnetrzne_id_meczu), + # ilosc_wystapien = 1 if int(safe_traverse(stats, ["595", "value"], default="0").rstrip("'")) > 0 else 0, + # minut_gry = int(safe_traverse(stats, ["595", "value"], default="0").rstrip("'")), + # gier_sum = 1 if int(safe_traverse(stats, ["595", "value"], default="0").rstrip("'")) > 0 else 0, + # goli_sum = int(safe_traverse(stats, ["596", "value"], default="0")), + # asyst_sum = int(safe_traverse(stats, ["541", "value"], default="0")), + # interwencji_sum = 0, + # nieobronionych_interwencji_sum = 0, + # zoltych_kartek_sum = int(safe_traverse(stats, ["599", "value"], default="0")), + # czerwonych_kartek_sum = int(safe_traverse(stats, ["600", "value"], default="0")), + # wygranych_sum = 1 if safe_traverse(match, ["winLoseShort"], default="") == "Z" else 0, + # wynik_sum = safe_traverse(match, ["rating"], default=0), + # meczow_do_wynikow_sum = 1 if safe_traverse(match, ["rating"], default=0) not in (0, None) else None + # ) + + # # analogicznie zinkrementuj statystyki_sportowcow: + # # UWAGA! NIE ZADZIAŁA DLA NIKOGO INNEGO, NIŻ ROBERCIKA (bo nie mamy innych sportowców w bazie, trzeba dodać ich ręcznie w lewy_db sample_data_init()) + # self.db.simple_insert_one("statystyki_sportowcow", + # sportowiec = zawodnik, + # ostatni_mecz = self.db.get_id_meczu_by_zewnetrzne_id(zewnetrzne_id_meczu), + # ilosc_wystapien = 1 if int(safe_traverse(stats, ["595", "value"], default="0").rstrip("'")) > 0 else 0, + # minut_gry = int(safe_traverse(stats, ["595", "value"], default="0").rstrip("'")), + # gier_sum = 1 if int(safe_traverse(stats, ["595", "value"], default="0").rstrip("'")) > 0 else 0, + # goli_sum = int(safe_traverse(stats, ["596", "value"], default="0")), + # asyst_sum = int(safe_traverse(stats, ["541", "value"], default="0")), + # interwencji_sum = 0, + # nieobronionych_interwencji_sum = 0, + # zoltych_kartek_sum = int(safe_traverse(stats, ["599", "value"], default="0")), + # czerwonych_kartek_sum = int(safe_traverse(stats, ["600", "value"], default="0")), + # wygranych_sum = 1 if safe_traverse(match, ["winLoseShort"], default="") == "Z" else 0, + # wynik_sum = safe_traverse(match, ["rating"], default=0), + # meczow_do_wynikow_sum = 1 if safe_traverse(match, ["rating"], default=0) not in (0, None) else None + # ) + + else: + print("też todo :)") + # # TODO: TU TEŻ TRZEBA POPRAWIĆ ANALOGICZNIE DO TEGO, CO JEST WEWNĄTRZ IF'A + # self.db.simple_insert_one("sportowcy_w_meczach", id_zawodnika, + # ostatni_mecz = self.db.get_id_meczu_by_zewnetrzne_id(zewnetrzne_id_meczu), + # ilosc_wystapien = 0, + # minut_gry = 0, + # gier_sum = 0, + # goli_sum = 0, + # asyst_sum = 0, + # interwencji_sum = 0, + # nieobronionych_interwencji_sum = 0, + # zoltych_kartek_sum = 0, + # czerwonych_kartek_sum = 0, + # wygranych_sum = 1 if safe_traverse(match, ["winLoseShort"], default="") == "Z" else 0, + # wynik_sum = safe_traverse(match, ["rating"], default=0), + # meczow_do_wynikow_sum = 1 if safe_traverse(match, ["rating"], default=0) not in (0, None) else None + # ) # TODO: Zaktualizuj statystyki sportowca @@ -208,7 +251,7 @@ class scraper: # rate limita. - sherl page += 1 - time.sleep(15) + #time.sleep(15) def aktualizuj_dane(self): diff --git a/FlaskWebProject/FlaskWebProject/lewy_api_v1.py b/FlaskWebProject/FlaskWebProject/lewy_api_v1.py index 7e71515..58b2cc7 100644 --- a/FlaskWebProject/FlaskWebProject/lewy_api_v1.py +++ b/FlaskWebProject/FlaskWebProject/lewy_api_v1.py @@ -89,7 +89,12 @@ def get_matches(r): """ TODO: Zwraca mecze. """ - pass + response_json = [] + mecze = getDb().simple_select_all("mecze") + for mecz in mecze: + response_json.append(mecz.jsonify()) + print(response_json) + return 200, "ok", response_json # GET /api/v1/debugger_halt?token=XXX... @require_authentication @@ -142,7 +147,7 @@ def lookup(data, request): case 'halt': return debugger_halt(r = request) case 'matches': - get_matches(r = request) + return get_matches(r = request) case _: increment_bad_requests() return not_implemented(data) \ No newline at end of file diff --git a/FlaskWebProject/FlaskWebProject/lewy_db.py b/FlaskWebProject/FlaskWebProject/lewy_db.py index a68d69e..b6277be 100644 --- a/FlaskWebProject/FlaskWebProject/lewy_db.py +++ b/FlaskWebProject/FlaskWebProject/lewy_db.py @@ -119,6 +119,8 @@ class baza(): zoltych_kartek_sum: Mapped[ int] = mapped_column() czerwonych_kartek_sum: Mapped[ int] = mapped_column() wygranych_sum: Mapped[ int] = mapped_column() + przegranych_sum: Mapped[ int] = mapped_column() + remisow_sum: Mapped[ int] = mapped_column() wynik_sum: Mapped[ int] = mapped_column() meczow_do_wynikow_sum: Mapped[ int] = mapped_column() @@ -155,6 +157,23 @@ class baza(): def __repr__(self): return f"" + def jsonify(self): + return { + "id_meczu": self.id_meczu, + "zewnetrzne_id_meczu": self.zewnetrzne_id_meczu, + "data": self.data.strftime("%Y-%m-%d"), + "gospodarze_id": self.gospodarze_id, + "gospodarze": self.gospodarze.skrocona_nazwa, + "goscie_id": self.goscie_id, + "goscie": self.goscie.skrocona_nazwa, + "gosp_wynik": self.gosp_wynik, + "gosc_wynik": self.gosc_wynik, + "sezon": self.sezon, + "nazwa_turnieju": self.nazwa_turnieju, + "skrocona_nazwa_turnieju": self.skrocona_nazwa_turnieju, + "flaga": self.flaga + } + self.entities = { 'sportowcy': sportowcy, 'trofea': trofea, @@ -236,7 +255,7 @@ class baza(): special_args[arg] = kwargs[arg] del kwargs[arg] - print(f"[{round(time.time())}] SELECT") + print(f"[{round(time.time())}] SELECT {entity_type}") results = ( self.session. @@ -283,7 +302,7 @@ class baza(): f"Aby naprawić dodawanie z autoinkrementującym kluczem zobacz {c.WARNING}https://stackoverflow.com/a/8745101{c.ENDC}\n" f"Zostałeś ostrzeżony!") - print(f"[{round(time.time())}] INSERT") + print(f"[{round(time.time())}] INSERT {entity_type}") obj = self.entities[entity_type](**kwargs) #with Session(self.db.engine) as session: @@ -315,6 +334,7 @@ class baza(): Użycie: increment_fields(ldb.statystyki_sportowcow, 123, goli_sum=2, asyst_sum=1) """ + if not isinstance(entity_type, str): entity_type = entity_type.__name__ @@ -324,7 +344,7 @@ class baza(): model_class = self.entities[entity_type] - print(f"[{round(time.time())}] INCREMENT") + print(f"[{round(time.time())}] INCREMENT {entity_type}") record = self.session.get(model_class, record_id) if not record: @@ -336,22 +356,35 @@ class baza(): current_value = getattr(record, key, 0) setattr(record, key, current_value + increment_value) else: - print(f"⚠️ Pole '{key}' nie istnieje w modelu '{entity_type}' – pomijam.") + print(f"⚠️ Pole '{key}' nie istnieje w modelu '{entity_type}' - pomijam.") self.session.commit() return 0 + @exit_gracefully - def get_id_meczu_by_zewnetrzne_id(session: Session, external_id: str) -> int | None: + def get_id_meczu_by_zewnetrzne_id(self, external_id: str) -> int | None: """ Zwraca id_meczu na podstawie zewnetrzne_id_meczu. - :param session: aktywna sesja SQLAlchemy :param external_id: zewnętrzne ID meczu :return: id_meczu lub None jeśli nie znaleziono """ stmt = select(mecze.id_meczu).where(mecze.zewnetrzne_id_meczu == external_id) - result = session.execute(stmt).scalar_one_or_none() + result = self.session.execute(stmt).scalar_one_or_none() return result + + @exit_gracefully + def get_id_zawodnika_by_zewnetrzne_id(self, external_id: str) -> int | None: + """ + Zwraca id_zawodnika na podstawie zewnetrzne_id_zawodnika. + + :param external_id: zewnętrzne ID meczu + :return: id_zawodnika lub None jeśli nie znaleziono + """ + stmt = select(sportowcy.id_zawodnika).where(sportowcy.zewnetrzne_id_zawodnika == external_id) + result = self.session.execute(stmt).scalar_one_or_none() + return result + @exit_gracefully def simple_update_one(self, entity_type, record_id, **kwargs): """ @@ -369,7 +402,7 @@ class baza(): model_class = self.entities[entity_type] - print(f"[{round(time.time())}] UPDATE") + print(f"[{round(time.time())}] UPDATE {entity_type}") record = self.session.get(model_class, record_id) if not record: @@ -380,7 +413,40 @@ class baza(): if hasattr(record, key): setattr(record, key, value) else: - print(f"⚠️ Pole '{key}' nie istnieje w modelu '{entity_type}' – pomijam.") + print(f"⚠️ Pole '{key}' nie istnieje w modelu '{entity_type}' - pomijam.") + + self.session.commit() + return 0 + + @exit_gracefully + def dodaj_sportowca_w_meczu(self, entity_type, record_id, **kwargs): + """ + Użycie: + dodaj_sportowca_w_meczu(ldb.sportowcy_w_meczu, ...) + + Dodaje pojedynczy rekord w bazie danych. + """ + if not isinstance(entity_type, str): + entity_type = entity_type.__name__ + + if entity_type not in self.entities: + print(f"Nieznany typ encji: {entity_type}") + return -1 + + model_class = self.entities[entity_type] + + print(f"[{round(time.time())}] INSERT {entity_type}") + + record = self.session.get(model_class, record_id) + if not record: + print(f"Rekord z ID {record_id} nie istnieje w tabeli {entity_type}") + return -1 + + for key, value in kwargs.items(): + if hasattr(record, key): + setattr(record, key, value) + else: + print(f"⚠️ Pole '{key}' nie istnieje w modelu '{entity_type}' - pomijam.") self.session.commit() return 0 @@ -418,7 +484,7 @@ class baza(): goscie_id="undefined", gosp_wynik=0, gosc_wynik=0, - sezon="1970/1970", + sezon="1970-1970", nazwa_turnieju="Nieznany turniej", skrocona_nazwa_turnieju="N/A", flaga=0) @@ -434,6 +500,8 @@ class baza(): zoltych_kartek_sum=0, czerwonych_kartek_sum=0, wygranych_sum=0, + przegranych_sum=0, + remisow_sum=0, wynik_sum=0, meczow_do_wynikow_sum=0) @@ -452,7 +520,7 @@ class baza(): wycena=64_940_000) trofeum = trofea( nazwa="Nieznane trofeum", - sezon="0000/0000", + sezon="0000-0000", rok=1970) session.add(sportowiec) @@ -464,6 +532,39 @@ class baza(): trofeum.zawodnik = sportowiec sportowiec.ostatnie_trofeum = trofeum + # MIEJSCE NA DANE KOLEJNYCH SPORTOWCÓW + # TRZEBA ZROBIĆ TO RĘCZNIE, ZGODNIE ZE SCHEMATEM: + # self.simple_insert_one(statystyki_sportowcow, + # ostatni_mecz=1, + # ilosc_wystapien=0, + # minut_gry=0, + # gier_sum=0, + # goli_sum=0, + # asyst_sum=0, + # interwencji_sum=0, + # nieobronionych_interwencji_sum=0, + # zoltych_kartek_sum=0, + # czerwonych_kartek_sum=0, + # wygranych_sum=0, + # przegranych_sum=0, + # remisow_sum=0, + # wynik_sum=0, + # meczow_do_wynikow_sum=0) + + # self.simple_insert_one(sportowcy, + # zewnetrzne_id_zawodnika="...", + # imie="...", + # nazwisko="...", + # data_urodzenia="...", + # czy_aktywny=True, # NIE WSZYSCY SĄ AKTYWNI! + # klub_id="undefined", + # narodowosc="...", + # ilosc_trofeow=0, + # pierwszy_mecz_id=1, + # ostatni_gol_dla_id="undefined", + # statystyki_id=2, # itd... + # wycena=...) # w złotówkach + session.commit() return 0