diff --git a/mo/util.py b/mo/util.py index 790db555fc28e51c1fd33ea05670008d1d48f283..391097af852b5014aed763530dd1fd30e2e1e6ee 100644 --- a/mo/util.py +++ b/mo/util.py @@ -2,6 +2,7 @@ from dataclasses import dataclass import datetime +import decimal import dateutil.tz import email.message import email.headerregistry @@ -12,13 +13,14 @@ import re import secrets import subprocess import sys -from typing import Any, Optional, NoReturn +from typing import Any, Optional, NoReturn, Tuple import textwrap import urllib.parse import mo import mo.db as db import mo.config as config +from mo.util_format import format_decimal # Uživatel, který se uvádí jako pachatel v databázovém logu current_log_user: Optional[db.User] = None @@ -209,3 +211,35 @@ def normalize_grade(grade: str) -> int: return -1 except ValueError: return -1 + + +def parse_points( + raw_points: str, for_task: Optional[db.Task] = None, for_round: Optional[db.Round] = None, +) -> Tuple[Optional[decimal.Decimal], Optional[str]]: + """Naparsuje a zkontroluje body. Vrátí body (jako decimal.Decimal nebo None + při prázdných bodech) a případný error (None pokud nenastal, jinak text chyby).""" + if raw_points == "": + return None, None + try: + points = decimal.Decimal(raw_points.replace(',', '.')) + except decimal.InvalidOperation: + return 0, f"Hodnota '{raw_points}' není číslo" + + return points, check_points(points, for_task, for_round) + + +def check_points(points: decimal.Decimal, for_task: Optional[db.Task] = None, for_round: Optional[db.Round] = None) -> Optional[str]: + """Zkontroluje body. Pokud je vše ok, tak vrátí None, jinak vrátí text chyby.""" + if points < 0: + return f'Nelze zadat záporné body (zadáno {format_decimal(points)})' + if for_task and for_task.max_points is not None and points > for_task.max_points: + return f'Maximální počet bodů za úlohu je {format_decimal(for_task.max_points)}, nelze zadat více (zadáno {format_decimal(points)})' + if for_round and (points % for_round.master.points_step) != 0: + points_step = for_round.master.points_step + if points_step == 1: + return f'Podle nastavení kola lze zadat pouze celé body (hodnota {points} je neplatná)' + elif points_step == 0.5: + return f'Podle nastavení kola nelze zadat body s libovolnými desetinami, pouze půlbody (hodnota {points} je neplatná)' + else: + return f'Podle nastavení kola zadat body jen s krokem {points_step} (hodnota {points} je neplatná)' + return None