From b5fdbb32302055f28a6ba55d85442be58bb1906e Mon Sep 17 00:00:00 2001 From: Pc Date: Wed, 4 Jun 2025 19:50:18 +0200 Subject: [PATCH 1/4] Updating matches Updating players stats(not finished) Not tested --- FlaskWebProject/FlaskWebProject/fs_scraper.py | 51 +++++++++++++ FlaskWebProject/FlaskWebProject/lewy_db.py | 69 +++++++++++++++++- .../FlaskWebProject/lewy_globals.py | 4 +- FlaskWebProject/instance/lewangoalski.sqlite | Bin 0 -> 49152 bytes 4 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 FlaskWebProject/instance/lewangoalski.sqlite diff --git a/FlaskWebProject/FlaskWebProject/fs_scraper.py b/FlaskWebProject/FlaskWebProject/fs_scraper.py index f7b9178..070e247 100644 --- a/FlaskWebProject/FlaskWebProject/fs_scraper.py +++ b/FlaskWebProject/FlaskWebProject/fs_scraper.py @@ -4,6 +4,7 @@ import json import lewy_globals import requests import time +from sqlalchemy import func def safe_traverse(obj: dict, path: list, default=None): result = obj @@ -16,6 +17,21 @@ def safe_traverse(obj: dict, path: list, default=None): 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 = { @@ -97,6 +113,7 @@ class scraper: # Jeśli nie, dodaj go w podobny sposób, jak # w sample_data_init() (w lewy_db.py). + page = 0 match_num = 0 while not stop_scraping: @@ -141,8 +158,42 @@ 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), + + ) match_num += 1 + stats=safe_traverse(match, ["stats"], default=""), + + + self.db.increment_fields("sportowcy",zewnetrzne_id_sportowca, + ostatni_mecz= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca + ilosc_wystapien= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca + 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= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca + nieobronionych_interwencji_sum= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca + zoltych_kartek_sum= get_stat_value(stats, "599"), + czerwonych_kartek_sum= get_stat_value(stats, "600"), + wygranych_sum= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca + wynik_sum= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca + meczow_do_wynikow_sum= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca + ) # TODO: Zaktualizuj statystyki sportowca diff --git a/FlaskWebProject/FlaskWebProject/lewy_db.py b/FlaskWebProject/FlaskWebProject/lewy_db.py index 2bf2ee9..96a60f8 100644 --- a/FlaskWebProject/FlaskWebProject/lewy_db.py +++ b/FlaskWebProject/FlaskWebProject/lewy_db.py @@ -307,6 +307,72 @@ class baza(): return 0 #return 1 + @exit_gracefully + def increment_fields(self, entity_type, record_id, **increments): + """ + Dodaje wartości do istniejących pól (np. goli_sum += 2). + + 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__ + + 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())}] INCREMENT") + + 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, increment_value in increments.items(): + if hasattr(record, key): + 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.") + + self.session.commit() + return 0 + @exit_gracefully + def simple_update_one(self, entity_type, record_id, **kwargs): + """ + Użycie: + simple_update_one(ldb.kluby, "polska", pelna_nazwa="Nowa Nazwa", skrocona_nazwa="NN") + + Aktualizuje pojedynczy rekord w bazie danych na podstawie ID. + """ + 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())}] UPDATE") + + 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 + @exit_gracefully def sample_data_init(self, override_safety_check=False): """ @@ -388,4 +454,5 @@ class baza(): session.commit() return 0 - return 1 \ No newline at end of file + + return 1 diff --git a/FlaskWebProject/FlaskWebProject/lewy_globals.py b/FlaskWebProject/FlaskWebProject/lewy_globals.py index 855f869..a4ad172 100644 --- a/FlaskWebProject/FlaskWebProject/lewy_globals.py +++ b/FlaskWebProject/FlaskWebProject/lewy_globals.py @@ -1,4 +1,4 @@ -from git import Repo # hash ostatniego commitu +#from git import Repo # hash ostatniego commitu import os import time import toml @@ -155,4 +155,4 @@ config = {} configfile = "config.toml" version = getCommitWithFailsafe() apiVersion = "1" -randomly_generated_passcode = 0 \ No newline at end of file +randomly_generated_passcode = 0 diff --git a/FlaskWebProject/instance/lewangoalski.sqlite b/FlaskWebProject/instance/lewangoalski.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..8814ee63890b82443ba4e9828cf80fa432abce4f GIT binary patch literal 49152 zcmeI2&2Qs27QpR%_^VT-H(z;-i_QY={sCQ2s-#9dcH=k&2El@0WX7YBEPC`&MFM(g ziy5@(p@&|3+y83+k^;RfNlUV%P+BFx?7{m21d--FK9axp9v?}~<;B?WD7t0Nig@Vn zjZYfQX5$|SH5!c;|9!@PlOOSZki77}&CGMzW2^DE?|wZL%13_*oo7dXb?&?0AKrDI z@4Y?xv#c5X`_2-0f6!_7DQ(`Ld*sHV77aq|zO{G|V*X6*B_oz=8rWSk$76vW;sCFx z9ufWZV|2SGGi^B6(0uq}tf9xWM900ZvA_;BnX~ZGXfoH%v>BRA=V)>@9)E_UI3fXC z*oH}z3K0!#>N$~3F*hZK@1t*rvy-ofc|&|!E?zpJ(#VoohEhP>(DjrO!}h2XP+NaP z@r^@PCUGM52wi_g@K)WxHrceGO2ZMexP!Pk&s2{|k9fz7&$mJ+2$v4A)#C|54ilY@ zr$df8gZi7<=;d(s3Y}}O(DBwS1L20#=}a4)O@vH{QkM+SOgq(P+T=vLtl@fTciXsV zS>eli9SFBmbgXLM8@&6X)$Wf*&0lbJ8b~9h;VY%>dZ8WXF?6#TZ=5!pY36!^ z>vpTpM$Lv{FX&yoXcOOK@?9+7>ZM#p9{#*q-uYpDAT#2}>*|b6J0-1iN@V%ff2*t7yBI5jDm^89 zXt*X*3Ps((zQYy~wGE^=eb|Np!1W0)Zj00KY&2mk>f00e*l5C8%|00;m9`2G(u z00e*l5C8%|00;m9AOHk_01yBIKw$R?!1w>%_c6>62mk>f00e*l5C8%|00;m9AOHk_ z0DS+47ytr500;m9AOHk_01yBIKmZ5;0U)sZ1mOI?`#y#l0s$ZZ1b_e#00KY&2mk>f z00e*l5cs(BywN(mYkYKj^n3T;o%`U4BXhv|%GLJi$pi!9ZlTnt$WTL$daWOQ+* zsY9X|b~%jo0?xGjn@~oxc=8|QNXq?b=6VCZDflNFH5-P#pm*`2O?;2Zcd>k{mvR|- z`15Lc=ZE!y%!nVat208*vecH89@fil^0T+U}hzQCYcGp!ux!&H>s;O9@9?f%6@^S3XneUWZ@ zO5Kra?A7x~svkQgt#e9b`PF}`tJ=F5D}yRMC46YOCQ}MU-N3%X77?`#qEykN5EIi2 z13N@7rqi)DoaFo}!aGx1HetgpvVfNcrA5OMMML_Z1zhXCG5x5N7!E* ze0SsWafzj@APYjBmTYQbtC;WP@WSHzt+XBrqoPZ`kqh}|H{V+^a8o~26p_46HjZOl zPh0cFIJ3qSoaz})RtBE<**whJE<&znSQZyq^tN?2YxSWI>e-cxXhkv2d9R+yOp_!n zc{qx#>sG?6g1*=42N#d7vWdyCqB5j9`}}0r5vM!x{eQpvd*kR|&;H)@?{ri=$n^&BsVMUy1U?ldU*G=UJ{4WJpL9zs^Qq!4K*~G+0hkV9asU7T literal 0 HcmV?d00001 From 9a007f504c4aa0dee377ca7edc604c26cf9fbdff Mon Sep 17 00:00:00 2001 From: Pc Date: Wed, 4 Jun 2025 19:56:32 +0200 Subject: [PATCH 2/4] Wins update --- FlaskWebProject/FlaskWebProject/fs_scraper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FlaskWebProject/FlaskWebProject/fs_scraper.py b/FlaskWebProject/FlaskWebProject/fs_scraper.py index 070e247..f33b7f1 100644 --- a/FlaskWebProject/FlaskWebProject/fs_scraper.py +++ b/FlaskWebProject/FlaskWebProject/fs_scraper.py @@ -190,7 +190,7 @@ class scraper: nieobronionych_interwencji_sum= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca zoltych_kartek_sum= get_stat_value(stats, "599"), czerwonych_kartek_sum= get_stat_value(stats, "600"), - wygranych_sum= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca + wygranych_sum = 1 if safe_traverse(match, ["winLoseShort"], default=0) == "Z" else 0, wynik_sum= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca meczow_do_wynikow_sum= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca ) From 13f6e2e3b9bc2fc131bbb5320848bc2de471f062 Mon Sep 17 00:00:00 2001 From: Pc Date: Wed, 4 Jun 2025 20:34:26 +0200 Subject: [PATCH 3/4] Added rest of player updating code --- FlaskWebProject/FlaskWebProject/fs_scraper.py | 16 +++++++++------- FlaskWebProject/FlaskWebProject/lewy_db.py | 12 ++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/FlaskWebProject/FlaskWebProject/fs_scraper.py b/FlaskWebProject/FlaskWebProject/fs_scraper.py index f33b7f1..70f2cc9 100644 --- a/FlaskWebProject/FlaskWebProject/fs_scraper.py +++ b/FlaskWebProject/FlaskWebProject/fs_scraper.py @@ -1,3 +1,4 @@ +from flask import session from lewy_db import baza as ldb from lewy_globals import colors as c import json @@ -177,22 +178,23 @@ class scraper: 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= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca - ilosc_wystapien= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki 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= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca - nieobronionych_interwencji_sum= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca + 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, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca - meczow_do_wynikow_sum= safe_traverse(match, ["eventId"], default=0), #TODO: Zaktualizuj statystyki sportowca + 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 + ) # TODO: Zaktualizuj statystyki sportowca diff --git a/FlaskWebProject/FlaskWebProject/lewy_db.py b/FlaskWebProject/FlaskWebProject/lewy_db.py index 96a60f8..a68d69e 100644 --- a/FlaskWebProject/FlaskWebProject/lewy_db.py +++ b/FlaskWebProject/FlaskWebProject/lewy_db.py @@ -341,6 +341,18 @@ class baza(): self.session.commit() return 0 @exit_gracefully + def get_id_meczu_by_zewnetrzne_id(session: Session, 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() + return result + @exit_gracefully def simple_update_one(self, entity_type, record_id, **kwargs): """ Użycie: From c2568c86efcc196715f9aed69013f4eef7019b6c Mon Sep 17 00:00:00 2001 From: sherl Date: Thu, 5 Jun 2025 19:18:31 +0200 Subject: [PATCH 4/4] fix: scraper fixes, list matches --- FlaskWebProject/FlaskWebProject/fs_scraper.py | 139 ++++++++++++------ .../FlaskWebProject/lewy_api_v1.py | 9 +- FlaskWebProject/FlaskWebProject/lewy_db.py | 123 ++++++++++++++-- 3 files changed, 210 insertions(+), 61 deletions(-) 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