Exemple #1
0
    def __get_kontaktdaten(self, modus: Modus) -> dict:
        """
        Ladet die Kontakdaten aus dem in der GUI hinterlegten Pfad

        Args:
            modus (Modus): Abhängig vom Modus werden nicht alle Daten benötigt.

        Returns:
            dict: Kontakdaten
        """
        if not os.path.isfile(self.pfad_kontaktdaten):
            if not self.kontaktdaten_erstellen(modus):
                return {}

        kontaktdaten = kontak_tools.get_kontaktdaten(self.pfad_kontaktdaten)
        kontak_tools.check_kontaktdaten(kontaktdaten, modus)

        if modus == Modus.TERMIN_SUCHEN:
            if not self.__check_old_kontakt_version(kontaktdaten):
                raise ValidationError("\"zeitrahmen\" fehlt -> Alte Version")

            if "codes" in kontaktdaten:
                if "XXXX-XXXX-XXXX" in kontaktdaten["codes"]:
                    raise ValidationError(
                        "Der Code is ungültig. Bitte trage einen korrekten Code ein!"
                    )

        return kontaktdaten
Exemple #2
0
def validate_kontaktdaten(kontaktdaten: dict):
    """
    Validiert Kontaktdaten.
    Leere Werte werden als Fehler angesehen.

    :raise ValidationError: Typ ist nicht dict
    :raise ValidationError: Einer der enthaltenen Keys ist unbekannt
    :raise ValidationError: Eine der enthaltenen Values ist ungültig
    """

    if not isinstance(kontaktdaten, dict):
        raise ValidationError("Muss ein Dictionary sein")

    for key, value in kontaktdaten.items():
        try:
            if key == "code":
                validate_code(value)
            elif key == "plz_impfzentren":
                validate_plz_impfzentren(value)
            elif key == "kontakt":
                validate_kontakt(value)
            elif key == "zeitrahmen":
                validate_zeitrahmen(value)
            else:
                raise ValidationError(f"Nicht unterstützter Key")
        except ValidationError as exc:
            raise ValidationError(
                f"Ungültiger Key {json.dumps(key)}:\n{str(exc)}")
Exemple #3
0
def validate_pushover_app_token(pushover_app_token: str):
    """
    Validiert den Pushover App Token.

    :raise ValidationError: Typ ist nicht str
    :raise ValidationError: Der Wert istz nicht genau 30 Zeichen lang
    """
    if not isinstance(pushover_app_token, str):
        raise ValidationError("Muss eine Zeichenkette sein")
    if len(pushover_app_token) != 30:
        raise ValidationError("Der Pushover APP Token muss genau 30 Zeichen lang sein")
Exemple #4
0
def validate_telegram_chat_id(telegram_chat_id: str):
    """
    Validiert die Telegram Chat ID.

    :raise ValidationError: Typ ist nicht str
    :raise ValidationError: Die ID ist zu kurz (Länge der IDs variiert)
    """

    if not isinstance(telegram_chat_id, str):
        raise ValidationError("Muss eine Zeichenkette sein")
    if len(telegram_chat_id) < 4:
        raise ValidationError("Die Chat ID ist zu kurz.")
Exemple #5
0
def validate_telegram_api_token(telegram_api_token: str):
    """
    Validiert den Telegram API Token.

    :raise ValidationError: Typ ist nicht str
    :raise ValidationError: Entspricht nicht dem Format \w+:\w+
    """

    if not isinstance(telegram_api_token, str):
        raise ValidationError("Muss eine Zeichenkette sein")
    if not re.search(r"\w+:\w+", telegram_api_token):
        raise ValidationError("Der Telegram API-Token besteht aus zwei Teilen welche durch \":\" getrennt sind.")
Exemple #6
0
def validate_pushover_user_key(pushover_user_key: str):
    """
    Validiert den Pushover User Key.

    :raise ValidationError: Typ ist nicht str
    :raise ValidationError: Der Wert istz nicht genau 30 Zeichen lang
    """

    if not isinstance(pushover_user_key, str):
        raise ValidationError("Muss eine Zeichenkette sein")
    if len(pushover_user_key) != 30:
        raise ValidationError("Der Pushover User Key muss genau 30 Zeichen lang sein")
Exemple #7
0
def validate_einhalten_bei(einhalten_bei: str):
    """
    Validiert "zeitrahmen"."einhalten_bei"-Key aus Kontaktdaten.
    Erlaubte Parameter sind: "1", "2", "beide"

    :raise ValidationError: Parameter ist nicht erlaubt (s.o.)
    """

    if not isinstance(einhalten_bei, str):
        raise ValidationError("Muss eine Zeichenkette sein")

    if einhalten_bei not in ["1", "2", "beide"]:
        raise ValidationError('Erlaubt sind: "1", "2", "beide"')
Exemple #8
0
def validate_zeitrahmen(zeitrahmen: dict):
    """
    Validiert "zeitrahmen"-Key aus Kontaktdaten.

    :raise ValidationError: Typ ist nicht dict
    :raise ValidationError: Einer der enthaltenen Keys ist unbekannt
    :raise ValidationError: Eine der enthaltenen Values ist ungültig
    """

    if not isinstance(zeitrahmen, dict):
        raise ValidationError("Muss ein Dictionary sein")

    if zeitrahmen == {}:
        return

    # Ein ganz leerer Zeitrahmen ist zulässig (s.o.), aber ansonsten muss der
    # Key "einhalten_bei" vorhanden sein.
    if "einhalten_bei" not in zeitrahmen:
        raise ValidationError(
            'Ein gesetzter Zeitrahmen braucht zwingend den Key "einhalten_bei"'
        )

    for key, value in zeitrahmen.items():
        try:
            if key in ["von_datum", "bis_datum"]:
                validate_datum(value)
            elif key in ["von_uhrzeit", "bis_uhrzeit"]:
                validate_uhrzeit(value)
            elif key == "wochentage":
                if not isinstance(value, list):
                    raise ValidationError("Muss eine Liste sein")
                if not value:
                    raise ValidationError("Darf keine leere Liste sein")
                for weekday in value:
                    validate_wochentag(weekday)
            elif key == "einhalten_bei":
                validate_einhalten_bei(value)
            else:
                raise ValidationError(f"Nicht unterstützter Key")
        except ValidationError as exc:
            raise ValidationError(
                f"Ungültiger Key {json.dumps(key)}:\n{str(exc)}")

    if "von_datum" in zeitrahmen and "bis_datum" in zeitrahmen:
        von_datum = datetime.datetime.strptime(zeitrahmen["von_datum"],
                                               "%d.%m.%Y")
        bis_datum = datetime.datetime.strptime(zeitrahmen["bis_datum"],
                                               "%d.%m.%Y")
        if von_datum > bis_datum:
            raise ValidationError("Ungültige Kombination von Datums: "
                                  'von_datum" liegt nach "bis_datum"')

    if "von_uhrzeit" in zeitrahmen and "bis_uhrzeit" in zeitrahmen:
        von_uhrzeit = datetime.datetime.strptime(zeitrahmen["von_uhrzeit"],
                                                 "%H:%M")
        bis_uhrzeit = datetime.datetime.strptime(zeitrahmen["bis_uhrzeit"],
                                                 "%H:%M")
        if von_uhrzeit > bis_uhrzeit:
            raise ValidationError("Ungültige Kombination von Uhrzeiten: "
                                  '"von_uhrzeit" liegt nach "bis_uhrzeit"')
Exemple #9
0
def validate_email(email: str):
    """
    Validiert eine E-Mail-Adresse.

    :raise ValidationError: Typ ist nicht str
    :raise ValidationError: Zeichenkette ist offensichtlich keine gültige E-Mail-Adresse
    """

    if not isinstance(email, str):
        raise ValidationError("Muss eine Zeichenkette sein")

    # https://stackoverflow.com/a/14485817/7350842
    if '@' not in parseaddr(email)[1]:
        raise ValidationError(f"Ungültige E-Mail-Adresse {json.dumps(email)}")
Exemple #10
0
def validate_datum(date: str):
    """
    Validiert ein Datum im erwarteten Format "30.11.1970".

    :raise ValidationError: Typ ist nicht str
    :raise ValidationError: Zeichenkette hat nicht das richtige Format
    """

    if not isinstance(date, str):
        raise ValidationError("Muss eine Zeichenkette sein")

    try:
        datetime.datetime.strptime(date, "%d.%m.%Y")
    except ValueError as exc:
        raise ValidationError(str(exc)) from exc
Exemple #11
0
def validate_uhrzeit(time: str):
    """
    Validiert eine Uhrzeit im erwarteten Format "14:35".

    :raise ValidationError: Typ ist nicht str
    :raise ValidationError: Zeichenkette hat nicht das richtige Format
    """

    if not isinstance(time, str):
        raise ValidationError("Muss eine Zeichenkette sein")

    try:
        datetime.datetime.strptime(time, "%H:%M")
    except ValueError as exc:
        raise ValidationError(str(exc)) from exc
Exemple #12
0
def validate_telegram(telegram: dict):
    if not isinstance(telegram, dict):
        raise ValidationError("Muss ein Dictionary sein")

    for key, value in telegram.items():
        try:
            if key == "api_token":
                validate_telegram_api_token(value)
            elif key == "chat_id":
                validate_telegram_chat_id(value)
            else:
                raise ValidationError(f"Nicht unterstützter Key")
        except ValidationError as exc:
            raise ValidationError(
                f"Ungültiger Key {json.dumps(key)}:\n{str(exc)}")
Exemple #13
0
def validate_pushover(pushover: dict):
    if not isinstance(pushover, dict):
        raise ValidationError("Muss ein Dictionary sein")

    for key, value in pushover.items():
        try:
            if key == "app_token":
                validate_pushover_app_token(value)
            elif key == "user_key":
                validate_pushover_user_key(value)
            else:
                raise ValidationError(f"Nicht unterstützter Key")
        except ValidationError as exc:
            raise ValidationError(
                f"Ungültiger Key {json.dumps(key)}:\n{str(exc)}")
Exemple #14
0
def validate_notifications(notifications: dict):
    if not isinstance(notifications, dict):
        raise ValidationError("Muss ein Dictionary sein")

    for key, value in notifications.items():
        try:
            if key == "pushover":
                validate_pushover(value)
            elif key == "telegram":
                validate_telegram(value)
            else:
                raise ValidationError(f"Nicht unterstützter Key")
        except ValidationError as exc:
            raise ValidationError(
                f"Ungültiger Key {json.dumps(key)}:\n{str(exc)}")
Exemple #15
0
    def __check_werte(self, kontaktdaten: dict):
        """
        Prüft mithilfe von den kontakt_tools ob alle Daten da und gültig sind

        Args:
            kontaktdaten (dict): Kontaktdaten

        Raises:
            ValidationError: Daten Fehlerhaft
            MissingValuesError: Daten Fehlen
        """

        kontakt_tools.check_kontaktdaten(kontaktdaten, self.modus)

        if self.modus == Modus.TERMIN_SUCHEN:
            kontakt_tools.validate_kontaktdaten(kontaktdaten)
        elif self.modus == Modus.CODE_GENERIEREN:
            kontakt_tools.validate_plz_impfzentren(
                kontaktdaten["plz_impfzentren"])
            kontakt_tools.validate_email(
                kontaktdaten["kontakt"]["notificationReceiver"])
            try:
                kontakt_tools.validate_phone(kontaktdaten["kontakt"]["phone"])
            except ValidationError as error:
                raise ValidationError(
                    "Telefonnummer: +49 nicht vergessen") from error
Exemple #16
0
def validate_phone(phone: str):
    """
    Validiert Telefonnummer auf: Typ, Präfix, "leer"

    Args:
        phone (str): Telefonnummer

    Raises:
        ValidationError: Typ ist nicht str
        ValidationError: Telefonnummer ungültig
    """

    if not isinstance(phone, str):
        raise ValidationError("Muss eine Zeichenkette sein")

    if not re.match(r"^\+49[1-9][0-9]+$", phone):
        raise ValidationError(f"Ungültige Telefonnummer {json.dumps(phone)}")
Exemple #17
0
def validate_wochentag(wochentag: str):
    """
    Validiert einen Wochentag.
    Erlaubt sind "Montag" bis "Sonntag".
    Es sind auch Präfixe vom Wochentag-Namen zulässig, solange diese mindestens
    zwei Zeichen lang sind, z. B. "Mo", "Mon", "Mont", usw.

    :raise ValidationError: Typ ist nicht str
    :raise ValidationError: Zeichenkette hat nicht das richtige Format
    """

    if not isinstance(wochentag, str):
        raise ValidationError("Muss eine Zeichenkette sein")

    try:
        decode_wochentag(wochentag)
    except ValueError as exc:
        raise ValidationError(str(exc)) from exc
Exemple #18
0
def validate_plz(plz: str):
    """
    Validiert die PLZ auf: Typ, Länge, "leer"

    Args:
        plz (str): PLZ

    Raises:
        ValidationError: PLZ ist kein String
        ValidationError: Besteht nicht aus genau 5 Ziffern
    """

    if not isinstance(plz, str):
        raise ValidationError("Muss eine Zeichenkette sein")

    if not re.match(f"^{5 * '[0-9]'}$", plz):
        raise ValidationError(
            f"Ungültige PLZ {json.dumps(plz)} - muss aus genau 5 Ziffern bestehen")
Exemple #19
0
def validate_code(code: str):
    """
    Überprüft, ob der Code Valide ist

    Args:
        code (str): impf-code

    Raises:
        ValidationError: Code ist keine Zeichenkette oder entspricht nicht dem Schema
    """

    if not isinstance(code, str):
        raise ValidationError("Muss eine Zeichenkette sein")

    c = "[0-9a-zA-Z]"
    if not re.match(f"^{4 * c}-{4 * c}-{4 * c}$", code):
        raise ValidationError(
            f"{json.dumps(code)} entspricht nicht dem Schema \"XXXX-XXXX-XXXX\""
        )
Exemple #20
0
def validate_email(email: str):
    """
    Validiert eine E-Mail-Adresse.

    :raise ValidationError: Typ ist nicht str
    :raise ValidationError: Zeichenkette ist offensichtlich keine gültige E-Mail-Adresse
    """

    if not isinstance(email, str):
        raise ValidationError("Muss eine Zeichenkette sein")

    # https://stackoverflow.com/a/14485817/7350842
    parsed_email = parseaddr(email)[1]
    if '@' not in parsed_email:
        raise ValidationError(f"Ungültige E-Mail-Adresse {json.dumps(email)}")

    # Gmail erlaubt Plus-Zeichen (https://support.google.com/a/users/answer/9308648?hl=en),
    # der Impfterminservice leider nicht.
    if '+' in parsed_email:
        raise ValidationError(
            f"Ungültige E-Mail-Adresse {json.dumps(email)} (Plus-Zeichen nicht möglich)")
Exemple #21
0
def validate_hausnummer(hausnummer: str):
    """
    Validiert Hausnummer auf: Typ, Länge, "leer"

    Args:
        hausnummer (str): hausnummer

    Raises:
        ValidationError: Typ ist nicht str
        ValidationError: Zeichenkette ist länger als 20 Zeichen
        ValidationError: Zeichenkette ist leer
    """

    if not isinstance(hausnummer, str):
        raise ValidationError("Muss eine Zeichenkette sein")

    if len(hausnummer) > 20:
        raise ValidationError(
            f"Hausnummer {json.dumps(hausnummer)} ist zu lang - maximal 20 Zeichen erlaubt")

    if hausnummer.strip() == "":
        raise ValidationError("Hausnummer ist leer")
Exemple #22
0
def validate_codes(codes: list):
    """
    Validiert eine Liste an Vermittlungscodes vom Schema XXXX-XXXX-XXXX

    :raise ValidationError: Typ ist nicht list
    :raise ValidationError: Liste ist leer
    :raise ValidationError: Liste enthält vom Schema abweichendes Element
    """

    if not isinstance(codes, list):
        raise ValidationError("Muss eine Liste sein")

    if len(codes) == 0:
        raise ValidationError("Darf keine leere Liste sein")

    for code in codes:
        if not isinstance(code, str):
            raise ValidationError("Darf nur Zeichenketten enthalten")
        c = "[0-9a-zA-Z]"
        if not re.match(f"^{4 * c}-{4 * c}-{4 * c}$", code):
            raise ValidationError(
                f"{json.dumps(code)} entspricht nicht dem Schema \"XXXX-XXXX-XXXX\"")
Exemple #23
0
def validate_plz_impfzentren(plz_impfzentren: list):
    """
    Validiert eine Gruppe von PLZs mithilfe con validate_plz

    Args:
        plz_impfzentren (dict): PLZs

    Raises:
        ValidationError: PLZs ist keine Liste
    """

    if not isinstance(plz_impfzentren, list):
        raise ValidationError("Muss eine Liste sein")

    for plz in plz_impfzentren:
        validate_plz(plz)
Exemple #24
0
    def __get_kontaktdaten(self, modus: Modus) -> dict:
        """
        Ladet die Kontakdaten aus dem in der GUI hinterlegten Pfad

        Args:
            modus (Modus): Abhängig vom Modus werden nicht alle Daten benötigt.

        Returns:
            dict: Kontakdaten
        """

        if not os.path.isfile(self.pfad_kontaktdaten):
            self.kontaktdaten_erstellen(modus)

        kontaktdaten = kontak_tools.get_kontaktdaten(self.pfad_kontaktdaten)
        if not self.__check_old_kontakt_version(kontaktdaten):
            raise ValidationError("\"zeitrahmen\" fehlt -> Alte Version")

        return kontaktdaten
Exemple #25
0
def validate_kontakt(kontakt: dict):
    """
    Validiert "kontakt"-Key aus Kontaktdaten.
    Leere Werte werden als Fehler angesehen.

    :raise ValidationError: Typ ist nicht dict
    :raise ValidationError: Einer der enthaltenen Keys ist unbekannt
    :raise ValidationError: Eine der enthaltenen Values ist ungültig
    """

    if not isinstance(kontakt, dict):
        raise ValidationError("Muss ein Dictionary sein")

    for key, value in kontakt.items():
        try:
            if key in ["anrede", "vorname", "nachname", "strasse", "ort"]:
                if not isinstance(value, str):
                    raise ValidationError("Muss eine Zeichenkette sein")
                if value.strip() == "":
                    raise ValidationError(f"Darf nicht leer sein")
            elif key == "plz":
                validate_plz(value)
            elif key == "hausnummer":
                validate_hausnummer(value)
            elif key == "phone":
                validate_phone(value)
            elif key == "notificationChannel":
                if value != "email":
                    raise ValidationError("Muss auf \"email\" gesetzt werden")
            elif key == "notificationReceiver":
                validate_email(value)
            else:
                raise ValidationError(f"Nicht unterstützter Key")
        except ValidationError as exc:
            raise ValidationError(
                f"Ungültiger Key {json.dumps(key)}:\n{str(exc)}")