148 lines
4.1 KiB
Python
148 lines
4.1 KiB
Python
# API is expected to return a tuple of:
|
|
# - HTTP status code,
|
|
# - human-readable status message,
|
|
# - json with appropriate data
|
|
from datetime import datetime
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
from fs_scraper import scraper
|
|
from functools import wraps
|
|
from lewy_globals import getDb, colors as c
|
|
import flask, json, time
|
|
import lewy_db as ldb
|
|
import lewy_globals
|
|
|
|
def require_authentication(func):
|
|
"""
|
|
Ten dekorator służy do wymuszenia parametru "token"
|
|
podczas obsługi zapytania. Powinien on zostać doklejony
|
|
do żądania, np. /api/v1/halt?token=XXX...
|
|
Wartość tokenu jest pobierana z pola api_key w config.toml.
|
|
Jeżeli skrypt jej tam nie znajdzie, jest generowana losowo
|
|
na starcie i drukowana w terminalu.
|
|
"""
|
|
@wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
token = kwargs["r"].args.get('token')
|
|
if token == lewy_globals.config['api']['api_key']:
|
|
try:
|
|
status, received, data = func(*args, **kwargs)
|
|
return status, received, data
|
|
except:
|
|
raise AssertionError(f"Function \"{func.__name__}\" does not return status, code, and data as it should!")
|
|
else:
|
|
increment_bad_requests()
|
|
return 401, "error", {'error_msg': "Unauthorized"}
|
|
return wrapper
|
|
|
|
def increment_bad_requests():
|
|
"""
|
|
Zwiększa globalny, tymczasowy licznik nieprawidłowych zapytań.
|
|
"""
|
|
lewy_globals.apiFailedRequests += 1
|
|
|
|
def not_implemented(data):
|
|
"""
|
|
Zwraca kod 501 wraz z endpointem, który wywołał błąd.
|
|
|
|
:param data: Ścieżka zapytania
|
|
:type data: list
|
|
"""
|
|
# TODO: change list to string -> data, not data[0]
|
|
return 501, f"not recognised/implemented: {data[0]}", []
|
|
|
|
# GET /api/v1
|
|
def stub_hello():
|
|
"""
|
|
Prosta funkcja witająca użytkowników w /api/v1
|
|
"""
|
|
return 200, 'hello from v1! stats are at /api/v1/stats', []
|
|
|
|
def epoch_to_date(epoch):
|
|
"""
|
|
Zamienia Unix'owy epoch na lokalny czas,
|
|
w formacie przypominającym format ISO.
|
|
|
|
:param epoch: Epoch - sekundy po 1. stycznia 1970
|
|
:type epoch: int
|
|
"""
|
|
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(epoch))
|
|
|
|
# GET /api/v1/
|
|
# GET /api/v1/stats
|
|
def stats():
|
|
"""
|
|
Zwraca ogólne statystyki serwera.
|
|
"""
|
|
data_to_send = {
|
|
"start_time": lewy_globals.starttime,
|
|
"uptime": lewy_globals.getUptime(),
|
|
"real_uptime": lewy_globals.realUptime,
|
|
"total_api_requests": lewy_globals.apiRequests,
|
|
"failed_api_requests": lewy_globals.apiFailedRequests,
|
|
"outside_api_requests": lewy_globals.outsideApiHits,
|
|
"local_api_requests": lewy_globals.apiRequests - lewy_globals.outsideApiHits
|
|
}
|
|
return 200, "ok", data_to_send
|
|
|
|
# GET /api/v1/matches
|
|
def get_matches(r):
|
|
"""
|
|
TODO: Zwraca mecze.
|
|
"""
|
|
pass
|
|
|
|
# GET /api/v1/debugger_halt?token=XXX...
|
|
@require_authentication
|
|
def debugger_halt(r):
|
|
"""
|
|
Zatrzymuje wykonywanie skryptu, aby pozwolić
|
|
administratorowi na wykonywanie dowolnego polecenia z konsoli.
|
|
"""
|
|
if lewy_globals.config['general']['is_proxied']:
|
|
print(f"{c.WARNING}[{epoch_to_date(time.time())}]{c.ENDC} {r.headers['X-Forwarded-For']} triggered a debugger halt!")
|
|
else:
|
|
print(f"{c.WARNING}[{epoch_to_date(time.time())}]{c.ENDC} {r.remote_addr} triggered a debugger halt!")
|
|
breakpoint()
|
|
return 200, "ok", []
|
|
|
|
def last_goal_for(sportowiec: str = "MVC8zHZD"):
|
|
"""
|
|
Pobierz klub, dla którego sportowiec (domyślnie Robert) oddał ostatni gol.
|
|
|
|
:returns: Klub, lub None
|
|
:rtype: kluby | None
|
|
"""
|
|
|
|
sportowiec = getDb().simple_select_all("sportowcy", zewnetrzne_id_zawodnika=sportowiec)
|
|
if sportowiec != []:
|
|
return sportowiec[0].ostatni_gol_dla
|
|
|
|
return None
|
|
|
|
def lookup(data, request):
|
|
"""
|
|
Obsługuje zapytania zwrócone do /api/v1/...
|
|
|
|
:param data: Lista ze ścieżką zapytania
|
|
:type data: list
|
|
:param request: Zapytanie
|
|
:type request: flask.request
|
|
|
|
:returns: Wartość zwróconą przez którąś z przywołanych funkcji.
|
|
"""
|
|
if data == []:
|
|
return stub_hello()
|
|
match data[0].lower():
|
|
case 'stats' | '':
|
|
return stats()
|
|
case 'user':
|
|
return stub_hello()
|
|
case 'info':
|
|
return stub_hello()
|
|
case 'halt':
|
|
return debugger_halt(r = request)
|
|
case 'matches':
|
|
get_matches(r = request)
|
|
case _:
|
|
increment_bad_requests()
|
|
return not_implemented(data) |