From 0b591c38571c560786d5be5d0c4d871a90ae1f61 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Tue, 25 May 2021 23:52:06 +0200
Subject: [PATCH 01/25] init commit
---
tools/kontaktdaten.ui | 348 ++++++++++++++++++++++++++++++++++++++
tools/uhrzeiten.ui | 385 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 733 insertions(+)
create mode 100644 tools/kontaktdaten.ui
create mode 100644 tools/uhrzeiten.ui
diff --git a/tools/kontaktdaten.ui b/tools/kontaktdaten.ui
new file mode 100644
index 00000000..62bdaf07
--- /dev/null
+++ b/tools/kontaktdaten.ui
@@ -0,0 +1,348 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 541
+ 383
+
+
+
+ MainWindow
+
+
+
+ -
+
+
-
+
+
+ Automatische Terminbuchung für den Corona Impfterminservice
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ vaccipy
+
+
+ Qt::AlignHCenter|Qt::AlignTop
+
+
+
+
+
+ -
+
+
-
+
+
+ PLZ's der Impfzentren:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ Beispiel: 68163, 69124, 69469
+
+
+ true
+
+
+
+ -
+
+
+ Code:
+
+
+
+ -
+
+
+ NNNN-NNNN-NNNN
+
+
+ --
+
+
+ A1C3-D2FG-4IJK
+
+
+ false
+
+
+
+ -
+
+
+ Anrede:
+
+
+
+ -
+
+
+ false
+
+
+ Bitte Wählen
+
+
+ QComboBox::NoInsert
+
+
-
+
+ Bitte Wählen
+
+
+ -
+
+ Frau
+
+
+ -
+
+ Herr
+
+
+ -
+
+ ...
+
+
+
+
+ -
+
+
+ Vorname:
+
+
+
+ -
+
+
+ Max
+
+
+ true
+
+
+
+ -
+
+
+ Nachname:
+
+
+
+ -
+
+
+ Mustermann
+
+
+ true
+
+
+
+ -
+
+
+ Straße:
+
+
+
+ -
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+ Hausnummer:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ true
+
+
+
+ -
+
+
+
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ PLZ Wohnort:
+
+
+
+ -
+
+
-
+
+
+ true
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+ Wohnort:
+
+
+
+ -
+
+
+ 99999
+
+
+ 88045
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ Telefonnummer:
+
+
+
+ -
+
+
+ +4\9
+
+
+
+
+
+ false
+
+
+
+ -
+
+
+ Mail:
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Reset
+
+
+ false
+
+
+
+
+
+
+
+
+
diff --git a/tools/uhrzeiten.ui b/tools/uhrzeiten.ui
new file mode 100644
index 00000000..7000c25f
--- /dev/null
+++ b/tools/uhrzeiten.ui
@@ -0,0 +1,385 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 513
+ 398
+
+
+
+ MainWindow
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Hier kannst du Uhrzeiten und Tage eingrenzen, an dem ein Termin gebucht werden soll
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+ QFrame::Box
+
+
+ QFrame::Plain
+
+
+
-
+
+
+ 0
+
+
-
+
+
+ 1. Termin
+
+
+ true
+
+
+
+ -
+
+
+ 2. Termin
+
+
+ true
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Nur Uhrzeiten zwischen
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+ Start:
+
+
+
+ -
+
+
+ Ende:
+
+
+
+ -
+
+
-
+
+
+
+
+
+
+ -
+
+
+ Uhr
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+
+
+ -
+
+
-
+
+
+ QDateTimeEdit::HourSection
+
+
+ false
+
+
+
+
+
+
+ -
+
+
+ Uhr
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+
+
+
+
+ -
+
+
+ Bei welchen Terminen sollen die Bedingungen gelten?
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+ Termin fühestens ab:
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ QAbstractSpinBox::UpDownArrows
+
+
+
+
+
+
+
+
+ QDateTimeEdit::DaySection
+
+
+ true
+
+
+
+ 2021
+ 5
+ 25
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+
+ -
+
+
+ vaccipy
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::Box
+
+
+ QFrame::Plain
+
+
+
-
+
+
+ Dienstags
+
+
+ true
+
+
+
+ -
+
+
+ Montags
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Donnerstags
+
+
+ true
+
+
+
+ -
+
+
+ Samstags
+
+
+ true
+
+
+
+ -
+
+
+ Sonntags
+
+
+ true
+
+
+
+ -
+
+
+ Mittwochs
+
+
+ true
+
+
+
+ -
+
+
+ Nur an folgenden Tagen:
+
+
+
+ -
+
+
+ Freitags
+
+
+ true
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+
+
+ -
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Reset
+
+
+
+
+
+
+
+
+
From d29328eb9dd1d081746976994fa02b5a742dde06 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Tue, 25 May 2021 23:54:17 +0200
Subject: [PATCH 02/25] init commit
---
requirements.txt | 3 +
tools/{ => gui}/kontaktdaten.ui | 0
tools/gui/qttimer.py | 186 ++++++++++++++++++++++++++++++++
tools/{ => gui}/uhrzeiten.ui | 0
tools/its.py | 77 +++++++++----
5 files changed, 247 insertions(+), 19 deletions(-)
rename tools/{ => gui}/kontaktdaten.ui (100%)
create mode 100644 tools/gui/qttimer.py
rename tools/{ => gui}/uhrzeiten.ui (100%)
diff --git a/requirements.txt b/requirements.txt
index 2bb55f52..8d89be49 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,3 +6,6 @@ urllib3>=1.26.4
pyinstaller>=4.3
plyer>=2.0.0
cloudscraper>=1.2.52
+PyQt5==5.15.4
+PyQt5-Qt5==5.15.2
+PyQt5-sip==12.9.0
\ No newline at end of file
diff --git a/tools/kontaktdaten.ui b/tools/gui/kontaktdaten.ui
similarity index 100%
rename from tools/kontaktdaten.ui
rename to tools/gui/kontaktdaten.ui
diff --git a/tools/gui/qttimer.py b/tools/gui/qttimer.py
new file mode 100644
index 00000000..5dd2397d
--- /dev/null
+++ b/tools/gui/qttimer.py
@@ -0,0 +1,186 @@
+import os
+import json
+from PyQt5 import QtWidgets, uic
+from PyQt5.QtCore import QTime
+
+# Folgende Widgets stehen zur Verfügung:
+
+### Checkboxes ###
+# mo_check_box
+# di_check_box
+# mi_check_box
+# do_check_box
+# fr_check_box
+# so_check_box
+# sa_check_box
+# erster_termin_check_box
+# zweiter_termin_check_box
+
+### QTimeEdit ###
+# start_time
+# end_time
+
+### Buttons ###
+# pushButton
+
+### Labels ###
+# header_label
+# wochentage_label
+# termine_anwenden_label
+# uhr_header_label
+# uhr_start_label
+# uhr_end_label
+# und_label
+
+PATH = os.path.dirname(os.path.realpath(__file__))
+
+# TODO: [ ] Wenn das Fenster geschlossen wir soll was passieren...? nicht speichern, aber Programm fortfahren
+# TODO: [ ] .icon adden
+# TODO: [X] Fenstergröße sollte man nicht verändern können
+# TODO: [X] Fenster in den Vordergund bringen
+# TODO: [X] Docstrings
+# TODO: [X] Rückmeldung für erfolgreiches speichern
+
+
+class QtTimer(QtWidgets.QMainWindow):
+ """
+ Klasse für das erstellen einer zeitspanne.json mithilfe einer GUI / PyQt5
+ Diese erbt von QtWidgets.QMainWindow
+ """
+
+ def __init__(self, pfad_zeitspanne: str, pfad_fenster_layout: str):
+ """
+ Ladet das angegebene Layout (wurde mit QT Designer erstellt https://www.qt.io/download)
+ Das Fenster wird automtaisch nach dem erstellen der Klasse geöffnet
+
+ Args:
+ pfad_zeitspanne (str): Speicherpfad für zeitspanne.json
+ pfad_fester_layout (str): Speicherort der .ui - Datei
+ """
+
+ super(QtTimer, self).__init__()
+
+ # Laden der .ui Datei und Anpassungen
+ uic.loadUi(pfad_fenster_layout, self)
+ self.setFixedSize(self.size())
+
+ # self.bestaetigen() soll beim Klicken auf Bestätigen aufgerufen werden
+ self.pushButton.clicked.connect(self.bestaetigt)
+
+ # Setzte leere Werte
+ self.aktive_wochentage = list()
+ self.start_uhrzeit: QTime = None
+ self.end_uhrzeit: QTime = None
+ self.aktive_termine = list()
+ self.speicherpfad = pfad_zeitspanne
+
+ # GUI anzeigen
+ self.show()
+ # Workaround, damit das Fenster hoffentlich im Vordergrund ist
+ self.activateWindow()
+
+ @staticmethod
+ def start(pfad_zeitspanne: str, pfad_fenster_layout=os.path.join(PATH, "qttimer.ui")):
+ """
+ Öffnet eine GUI in dem der User seine Parameter angeben kann
+ Diese werden bei Bestätigung direkt in den mit übergebenen Pfad gespeichert
+ Anschließend schließt sich das Fenster
+
+ Args:
+ pfad_zeitspanne (str): Speicherpfad für zeitspanne.json
+ pfad_fester_layout (str): Speicherort der .ui - Datei. Default: .\\qttimer.ui
+ """
+
+ app = QtWidgets.QApplication(list())
+ window = QtTimer(pfad_zeitspanne, pfad_fenster_layout)
+ app.exec_()
+
+ def bestaetigt(self):
+ """
+ Aktuallisiert alle Werte und Speichert gleichzeig die Aktuellen Werte
+ """
+
+ # Alle Werte von aus der GUI aktuallisieren
+ self.__aktuallisiere_aktive_wochentage()
+ self.__aktuallisiere_aktive_termine()
+
+ if not self.__aktuallisiere_uhrzeiten():
+ QtWidgets.QMessageBox.critical(self, "Ungültige Eingabe!", "Start-Uhrzeit ist später als End-Uhrzeit!")
+ return
+
+ # Speichert alle Werte ab
+ self.speicher_einstellungen()
+
+ self.close()
+
+ def speicher_einstellungen(self):
+ """
+ Speichert alle Werte in der entsprechenden JSON-Formatierung
+ Speicherpfad wurde beim erstellen der Klasse mit übergeben
+ """
+
+ data = {
+ "wochentage": self.aktive_wochentage,
+ "startzeit": {
+ "h": self.start_uhrzeit.hour(),
+ "m": self.start_uhrzeit.minute()
+ },
+ "endzeit": {
+ "h": self.end_uhrzeit.hour(),
+ "m": self.end_uhrzeit.minute()
+ },
+ "einhalten_bei": self.aktive_termine
+ }
+
+ with open(self.speicherpfad, 'w', encoding='utf-8') as f:
+ try:
+ json.dump(data, f, ensure_ascii=False, indent=4)
+ QtWidgets.QMessageBox.information(self, "Gepseichert", "Daten erfolgreich gespeichert")
+
+ except (TypeError, IOError, FileNotFoundError) as error:
+ QtWidgets.QMessageBox.critical(self, "Fehler!", "Daten konnten nicht gespeichert werden.")
+ raise error
+
+ def __aktuallisiere_aktive_wochentage(self):
+ """
+ Alle "checked" Wochentage in der GUI werden gesichert
+ """
+ # Zur sicherheit alte Werte löschen
+ self.aktive_wochentage.clear()
+
+ # Alle Checkboxen der GUI selektieren und durchgehen
+ # BUG: Wenn die reihenfolge im Layout geändert wird, stimmen die Wochentage nicht mehr 0 = Mo ... 6 = So
+ checkboxes = self.mo_check_box.parent().findChildren(QtWidgets.QCheckBox)
+ for num, checkboxe in enumerate(checkboxes, 0):
+ if checkboxe.isChecked():
+ self.aktive_wochentage.append(num)
+
+ def __aktuallisiere_uhrzeiten(self) -> bool:
+ """
+ Aktuallisert die eingegebenen Uhrzeiten der GUI
+ """
+
+ if self.start_time.time() < self.end_time.time():
+ self.start_uhrzeit = self.start_time.time()
+ self.end_uhrzeit = self.end_time.time()
+
+ return True
+ else:
+ return False
+
+ def __aktuallisiere_aktive_termine(self):
+ """
+ Aktuallisert die eingegebenen Uhrzeiten der GUI
+ """
+
+ # Zur sicherheit alte Werte löschen
+ self.aktive_termine.clear()
+
+ if self.erster_termin_check_box.isChecked():
+ self.aktive_termine.append(1)
+ if self.zweiter_termin_check_box.isChecked():
+ self.aktive_termine.append(2)
+
+
+if __name__ == "__main__":
+ QtTimer.start(f"{PATH}\\..\\zeitspanne.json")
diff --git a/tools/uhrzeiten.ui b/tools/gui/uhrzeiten.ui
similarity index 100%
rename from tools/uhrzeiten.ui
rename to tools/gui/uhrzeiten.ui
diff --git a/tools/its.py b/tools/its.py
index d864a39f..e1dcdff9 100644
--- a/tools/its.py
+++ b/tools/its.py
@@ -4,12 +4,14 @@
import time
from base64 import b64encode
from datetime import datetime
+from datetime import time as dtime
from random import choice
from typing import Dict, List
import cloudscraper
+
from selenium.webdriver import ActionChains
from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
@@ -481,7 +483,7 @@ def login(self):
@retry_on_failure()
- def termin_suchen(self, plz):
+ def termin_suchen(self, plz: int, zeitspanne: dict):
"""Es wird nach einen verfügbaren Termin in der gewünschten PLZ gesucht.
Ausgewählt wird der erstbeste Termin (!).
Zurückgegeben wird das Ergebnis der Abfrage und der Status-Code.
@@ -515,22 +517,59 @@ def termin_suchen(self, plz):
res_json = res.json()
terminpaare = res_json.get("termine")
if terminpaare:
- # Auswahl des erstbesten Terminpaares
- self.terminpaar = choice(terminpaare)
- self.plz_termin = plz
- self.log.success(f"Terminpaar gefunden!")
- self.impfzentrum = self.verfuegbare_impfzentren.get(plz)
- self.log.success("'{}' in {} {}".format(
- self.impfzentrum.get("Zentrumsname").strip(),
- self.impfzentrum.get("PLZ"),
- self.impfzentrum.get("Ort")))
- for num, termin in enumerate(self.terminpaar, 1):
- ts = datetime.fromtimestamp(termin["begin"] / 1000).strftime(
- '%d.%m.%Y um %H:%M Uhr')
- self.log.success(f"{num}. Termin: {ts}")
- if ENABLE_BEEPY:
- beepy.beep('coin')
- return True, 200
+ # Checken ob verfügbare terminpaare in angegebener Zeitspanne liegt
+ if zeitspanne["einhalten_bei"]:
+ terminpaare_in_zeitspanne = list()
+
+ # Alle Terminpaare durchgehen
+ for terminpaar in terminpaare:
+ termine_in_zeitspanne = True
+
+ # Einzelne Termine druchgehen
+ for num, termin in enumerate(terminpaar, 1):
+
+ # Soll einer der Beiden Termine überprüft werden
+ if num in zeitspanne["einhalten_bei"]:
+ startzeit = dtime(zeitspanne["startzeit"]["h"], zeitspanne["startzeit"]["m"])
+ endzeit = dtime(zeitspanne["endzeit"]["h"], zeitspanne["endzeit"]["m"])
+ wochentage = zeitspanne["wochentage"]
+
+ termin_zeit = datetime.fromtimestamp(int(termin["begin"])/1000)
+
+ # Termin inherhalb der Zeitspanne und im Wochentag
+ if not ((startzeit <= termin_zeit.time() <= endzeit) and (termin_zeit.weekday() in wochentage)):
+ termine_in_zeitspanne = False
+
+ # Beide Termine sind in der Zeitspanne
+ if termine_in_zeitspanne:
+ terminpaare_in_zeitspanne.append(terminpaar)
+ else:
+ self.log.info("Termin gefunden - jedoch nicht im entsprechenden Zeitraum")
+ for num, terminpaar in enumerate(terminpaar, 1):
+ ts = datetime.fromtimestamp(terminpaar["begin"] / 1000).strftime(
+ '%d.%m.%Y um %H:%M Uhr')
+ self.log.info(f"{num}. Termin: {ts}")
+ else:
+ # Keine Bedingungen, alle Terminpaare zugelassen
+ terminpaare_in_zeitspanne = terminpaare
+
+ if terminpaare_in_zeitspanne:
+ # Auswahl des erstbesten Terminpaares
+ self.terminpaar = choice(terminpaare_in_zeitspanne)
+ self.plz_termin = plz
+ self.log.success(f"Terminpaar gefunden!")
+ self.impfzentrum = self.verfuegbare_impfzentren.get(plz)
+ self.log.success("'{}' in {} {}".format(
+ self.impfzentrum.get("Zentrumsname").strip(),
+ self.impfzentrum.get("PLZ"),
+ self.impfzentrum.get("Ort")))
+ for num, termin in enumerate(self.terminpaar, 1):
+ ts = datetime.fromtimestamp(termin["begin"] / 1000).strftime(
+ '%d.%m.%Y um %H:%M Uhr')
+ self.log.success(f"{num}. Termin: {ts}")
+ if ENABLE_BEEPY:
+ beepy.beep('coin')
+ return True, 200
else:
self.log.info(f"Keine Termine verfügbar in {plz}")
else:
@@ -650,7 +689,7 @@ def code_bestaetigen(self, token, sms_pin):
return False
@staticmethod
- def terminsuche(code: str, plz_impfzentren: list, kontakt: dict,PATH:str, check_delay: int = 30):
+ def terminsuche(code: str, plz_impfzentren: list, kontakt: dict, PATH:str, zeitspanne: dict, check_delay: int = 30):
"""
Workflow für die Terminbuchung.
@@ -673,7 +712,7 @@ def terminsuche(code: str, plz_impfzentren: list, kontakt: dict,PATH:str, check_
# durchlaufe jede eingegebene PLZ und suche nach Termin
for plz in its.plz_impfzentren:
- termin_gefunden, status_code = its.termin_suchen(plz)
+ termin_gefunden, status_code = its.termin_suchen(plz, zeitspanne)
# Durchlauf aller PLZ unterbrechen, wenn Termin gefunden wurde
if termin_gefunden:
From 83fd8c2e678812c151e7866300c30fb561ee6f29 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Wed, 26 May 2021 19:55:31 +0200
Subject: [PATCH 03/25] Init commit
---
gui.py | 137 +++++
tools/gui/main.py | 116 ++++
tools/gui/main.ui | 192 +++++++
tools/gui/qtkontakt.py | 31 ++
tools/gui/{qttimer.py => qtzeiten.py} | 101 ++--
tools/gui/uhrzeiten.ui | 757 +++++++++++++-------------
6 files changed, 902 insertions(+), 432 deletions(-)
create mode 100644 gui.py
create mode 100644 tools/gui/main.py
create mode 100644 tools/gui/main.ui
create mode 100644 tools/gui/qtkontakt.py
rename tools/gui/{qttimer.py => qtzeiten.py} (63%)
diff --git a/gui.py b/gui.py
new file mode 100644
index 00000000..1ce5dd1e
--- /dev/null
+++ b/gui.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+import json
+
+from PyQt5 import QtWidgets, uic
+from tools.gui.qtzeiten import QtZeiten
+from tools.its import ImpfterminService
+
+PATH = os.path.dirname(os.path.realpath(__file__))
+
+
+class HauptGUI(QtWidgets.QMainWindow):
+
+ # Folgende Widgets stehen zur Verfügung:
+
+ ### QLineEdit ###
+ # i_kontaktdaten_pfad
+ # i_zeitspanne_pfad
+
+ ### Buttons ###
+ # b_termin_suchen
+ # b_code_generieren
+ # b_dateien_kontaktdaten
+ # b_dateien_zeitspanne
+ # b_neue_kontaktdaten
+ # b_neue_zeitspanne
+
+ def __init__(self, pfad_fenster_layout=os.path.join(PATH, "tools/gui/main.ui")):
+ super().__init__()
+
+ # Laden der .ui Datei und Anpassungen
+ uic.loadUi(pfad_fenster_layout, self)
+
+ # Funktionen den Buttons zuweisen
+ self.b_termin_suchen.clicked.connect(self.__termin_suchen)
+ self.b_code_generieren.clicked.connect(self.__code_generieren)
+ self.b_dateien_kontaktdaten.clicked.connect(lambda: self.__oeffne_file_dialog("kontaktdaten"))
+ self.b_dateien_zeitspanne.clicked.connect(lambda: self.__oeffne_file_dialog("zeitspanne"))
+ self.b_neue_kontaktdaten.clicked.connect(self.kontaktdaten_erstellen)
+ self.b_neue_zeitspanne.clicked.connect(self.zeitspanne_erstellen)
+
+ # Standard Pfade
+ self.pfad_kontaktdaten: str = os.path.join(PATH, "data", "kontaktdaten.json")
+ self.pfad_zeitspanne: str = os.path.join(PATH, "data", "zeitspanne.json")
+
+ # Pfade in der GUI anzeigen
+ self.i_kontaktdaten_pfad.setText(self.pfad_kontaktdaten)
+ self.i_zeitspanne_pfad.setText(self.pfad_zeitspanne)
+
+ # Events für Eingabefelder
+ self.i_kontaktdaten_pfad.textChanged.connect(self.__update_pfade)
+ self.i_zeitspanne_pfad.textChanged.connect(self.__update_pfade)
+
+ # GUI anzeigen
+ self.show()
+
+ # Workaround, damit das Fenster hoffentlich im Vordergrund ist
+ self.activateWindow()
+
+
+ def __termin_suchen(self):
+ kontaktdaten = self.__get_kontaktdaten()
+ zeitspanne = self.__get_zeitspanne()
+
+ kontakt = kontaktdaten["kontakt"]
+ code = kontaktdaten["code"]
+ plz_impfzentren = kontaktdaten["plz_impfzentren"]
+
+ ImpfterminService.terminsuche(code=code, plz_impfzentren=plz_impfzentren, kontakt=kontakt, zeitspanne=zeitspanne, PATH=PATH)
+
+
+ def __code_generieren(self):
+ pass
+
+
+ def __get_kontaktdaten(self) -> dict:
+
+ if not os.path.isfile(self.pfad_kontaktdaten):
+ self.kontaktdaten_erstellen()
+ pass
+
+ with open(self.pfad_kontaktdaten, "r", encoding='utf-8') as f:
+ kontaktdaten = json.load(f)
+
+ return kontaktdaten
+
+
+ def __get_zeitspanne(self) -> dict:
+ if not os.path.isfile(self.pfad_zeitspanne):
+ self.zeitspanne_erstellen()
+
+ with open(self.pfad_zeitspanne, "r", encoding='utf-8') as f:
+ zeitspanne = json.load(f)
+
+ return zeitspanne
+
+
+ def __oeffne_file_dialog(self, datei: str):
+ datei_data = QtWidgets.QFileDialog.getOpenFileName(self, datei, os.path.join(PATH, "data"), "JSON Files (*.json)")
+ dateipfad = datei_data[0]
+
+ if datei == "kontaktdaten":
+ self.i_kontaktdaten_pfad.setText(dateipfad)
+ else:
+ self.i_zeitspanne_pfad.setText(dateipfad)
+
+
+ def __update_pfade(self):
+ self.pfad_kontaktdaten = self.i_kontaktdaten_pfad.text()
+ self.pfad_zeitspanne = self.i_zeitspanne_pfad.text()
+
+ @staticmethod
+ def start_gui():
+ app = QtWidgets.QApplication(list())
+ window = HauptGUI()
+ app.exec_()
+
+
+ def kontaktdaten_erstellen(self):
+ pass
+
+
+ def zeitspanne_erstellen(self):
+ dialog = QtZeiten()
+ dialog.show()
+ dialog.exec_()
+
+
+
+def main():
+ HauptGUI.start_gui()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/gui/main.py b/tools/gui/main.py
new file mode 100644
index 00000000..ce8a7b08
--- /dev/null
+++ b/tools/gui/main.py
@@ -0,0 +1,116 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file '.\tools\gui\main.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.4
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("MainWindow")
+ MainWindow.resize(470, 270)
+ self.centralwidget = QtWidgets.QWidget(MainWindow)
+ self.centralwidget.setObjectName("centralwidget")
+ self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
+ self.gridLayout_2.setObjectName("gridLayout_2")
+ self.gridLayout = QtWidgets.QGridLayout()
+ self.gridLayout.setObjectName("gridLayout")
+ spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.gridLayout.addItem(spacerItem, 5, 0, 1, 1)
+ self.b_termin_suchen = QtWidgets.QPushButton(self.centralwidget)
+ self.b_termin_suchen.setAutoDefault(False)
+ self.b_termin_suchen.setDefault(True)
+ self.b_termin_suchen.setFlat(False)
+ self.b_termin_suchen.setObjectName("b_termin_suchen")
+ self.gridLayout.addWidget(self.b_termin_suchen, 6, 1, 1, 1)
+ self.header_label = QtWidgets.QLabel(self.centralwidget)
+ font = QtGui.QFont()
+ font.setPointSize(14)
+ self.header_label.setFont(font)
+ self.header_label.setAlignment(QtCore.Qt.AlignCenter)
+ self.header_label.setObjectName("header_label")
+ self.gridLayout.addWidget(self.header_label, 0, 0, 1, 2)
+ self.b_code_generieren = QtWidgets.QPushButton(self.centralwidget)
+ self.b_code_generieren.setObjectName("b_code_generieren")
+ self.gridLayout.addWidget(self.b_code_generieren, 6, 0, 1, 1)
+ self.line = QtWidgets.QFrame(self.centralwidget)
+ self.line.setFrameShape(QtWidgets.QFrame.HLine)
+ self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.line.setObjectName("line")
+ self.gridLayout.addWidget(self.line, 1, 0, 1, 1)
+ self.line_2 = QtWidgets.QFrame(self.centralwidget)
+ self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
+ self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.line_2.setObjectName("line_2")
+ self.gridLayout.addWidget(self.line_2, 1, 1, 1, 1)
+ self.pfad_layout = QtWidgets.QFormLayout()
+ self.pfad_layout.setObjectName("pfad_layout")
+ self.kontaktdaten_label = QtWidgets.QLabel(self.centralwidget)
+ self.kontaktdaten_label.setObjectName("kontaktdaten_label")
+ self.pfad_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.kontaktdaten_label)
+ self.gridLayout_3 = QtWidgets.QGridLayout()
+ self.gridLayout_3.setObjectName("gridLayout_3")
+ self.i_kontaktdaten_pfad = QtWidgets.QLineEdit(self.centralwidget)
+ self.i_kontaktdaten_pfad.setObjectName("i_kontaktdaten_pfad")
+ self.gridLayout_3.addWidget(self.i_kontaktdaten_pfad, 0, 0, 1, 1)
+ self.b_dateien_kontaktdaten = QtWidgets.QPushButton(self.centralwidget)
+ self.b_dateien_kontaktdaten.setObjectName("b_dateien_kontaktdaten")
+ self.gridLayout_3.addWidget(self.b_dateien_kontaktdaten, 0, 1, 1, 1)
+ self.pfad_layout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.gridLayout_3)
+ self.zeitspanne_label = QtWidgets.QLabel(self.centralwidget)
+ self.zeitspanne_label.setObjectName("zeitspanne_label")
+ self.pfad_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.zeitspanne_label)
+ self.gridLayout_4 = QtWidgets.QGridLayout()
+ self.gridLayout_4.setObjectName("gridLayout_4")
+ self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
+ self.lineEdit.setObjectName("lineEdit")
+ self.gridLayout_4.addWidget(self.lineEdit, 0, 0, 1, 1)
+ self.b_dateien_zeitspanne = QtWidgets.QPushButton(self.centralwidget)
+ self.b_dateien_zeitspanne.setObjectName("b_dateien_zeitspanne")
+ self.gridLayout_4.addWidget(self.b_dateien_zeitspanne, 0, 1, 1, 1)
+ self.pfad_layout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4)
+ self.gridLayout.addLayout(self.pfad_layout, 4, 0, 1, 2)
+ self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtWidgets.QMenuBar(MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 470, 21))
+ self.menubar.setObjectName("menubar")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QtWidgets.QStatusBar(MainWindow)
+ self.statusbar.setObjectName("statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+
+ self.retranslateUi(MainWindow)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+ def retranslateUi(self, MainWindow):
+ _translate = QtCore.QCoreApplication.translate
+ MainWindow.setWindowTitle(_translate("MainWindow", "vaccipy"))
+ self.b_termin_suchen.setText(_translate("MainWindow", "Termin suchen"))
+ self.header_label.setText(_translate("MainWindow", "Vaccipy\n"
+"\n"
+"Willkommen bei der automatische Terminbuchung\n"
+"für den Corona Impfterminservice "))
+ self.b_code_generieren.setText(_translate("MainWindow", "Impf-Code generieren"))
+ self.kontaktdaten_label.setText(_translate("MainWindow", "Pfad Kontakdaten:"))
+ self.i_kontaktdaten_pfad.setText(_translate("MainWindow", "./data/kontaktdaten.json"))
+ self.b_dateien_kontaktdaten.setText(_translate("MainWindow", "Dateien"))
+ self.zeitspanne_label.setText(_translate("MainWindow", "Pfad Zeitspanne:"))
+ self.lineEdit.setText(_translate("MainWindow", "./data/zeitspanne.json"))
+ self.b_dateien_zeitspanne.setText(_translate("MainWindow", "Dateien"))
+
+
+if __name__ == "__main__":
+ import sys
+ app = QtWidgets.QApplication(sys.argv)
+ MainWindow = QtWidgets.QMainWindow()
+ ui = Ui_MainWindow()
+ ui.setupUi(MainWindow)
+ MainWindow.show()
+ sys.exit(app.exec_())
diff --git a/tools/gui/main.ui b/tools/gui/main.ui
new file mode 100644
index 00000000..d0e55428
--- /dev/null
+++ b/tools/gui/main.ui
@@ -0,0 +1,192 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 549
+ 382
+
+
+
+ vaccipy
+
+
+
+ -
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Termin suchen
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ -
+
+
+
+ 14
+
+
+
+ Vaccipy
+
+Willkommen bei der automatische Terminbuchung
+für den Corona Impfterminservice
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Impf-Code generieren
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
-
+
+
+ Pfad Kontakdaten:
+
+
+
+ -
+
+
-
+
+
+
+
+
+ true
+
+
+
+ -
+
+
+ Dateien
+
+
+
+
+
+ -
+
+
+ Pfad Zeitspanne:
+
+
+
+ -
+
+
-
+
+
+
+
+
+ true
+
+
+
+ -
+
+
+ Dateien
+
+
+
+
+
+
+
+ -
+
+
+ Kontakdaten erstellen
+
+
+
+ -
+
+
+ Zeitspanne erstellen
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/gui/qtkontakt.py b/tools/gui/qtkontakt.py
new file mode 100644
index 00000000..14159993
--- /dev/null
+++ b/tools/gui/qtkontakt.py
@@ -0,0 +1,31 @@
+
+from PyQt5 import QtWidgets, uic
+from PyQt5.QtCore import QTime
+
+
+# Folgende Widgets stehen zur Verfügung:
+
+### QLineEdit ####
+# i_plz_impfzentren
+# i_code_impfzentren
+# i_vorname
+# i_nachname
+# i_strasse
+# i_hausnummer
+# i_wohnort
+# i_plz_wohnort
+# i_telefon
+# i_mail
+
+### QComboBox ###
+# i_anrede_combo_box
+
+### QDialogButtonBox ###
+# buttonBox
+# Apply
+# Cancel
+# Reset
+
+class QtKontakt(QtWidgets.QMainWindow):
+ def __init__(self):
+ super().__init__()
\ No newline at end of file
diff --git a/tools/gui/qttimer.py b/tools/gui/qtzeiten.py
similarity index 63%
rename from tools/gui/qttimer.py
rename to tools/gui/qtzeiten.py
index 5dd2397d..19db9440 100644
--- a/tools/gui/qttimer.py
+++ b/tools/gui/qtzeiten.py
@@ -1,99 +1,67 @@
import os
import json
from PyQt5 import QtWidgets, uic
-from PyQt5.QtCore import QTime
+from PyQt5.QtCore import QTime, QDateTime
# Folgende Widgets stehen zur Verfügung:
### Checkboxes ###
-# mo_check_box
-# di_check_box
-# mi_check_box
-# do_check_box
-# fr_check_box
-# so_check_box
-# sa_check_box
-# erster_termin_check_box
-# zweiter_termin_check_box
+# i_mo_check_box
+# i_di_check_box
+# i_mi_check_box
+# i_do_check_box
+# i_fr_check_box
+# i_so_check_box
+# i_sa_check_box
+# i_erster_termin_check_box
+# i_zweiter_termin_check_box
### QTimeEdit ###
-# start_time
-# end_time
+# i_start_time_qtime
+# i_end_time_qtime
-### Buttons ###
-# pushButton
+### QDateEdit ###
+# i_start_datum_qdate
-### Labels ###
-# header_label
-# wochentage_label
-# termine_anwenden_label
-# uhr_header_label
-# uhr_start_label
-# uhr_end_label
-# und_label
+### QDialogButtonBox ###
+# buttonBox
+# Apply
+# Cancel
+# Reset
PATH = os.path.dirname(os.path.realpath(__file__))
-# TODO: [ ] Wenn das Fenster geschlossen wir soll was passieren...? nicht speichern, aber Programm fortfahren
-# TODO: [ ] .icon adden
-# TODO: [X] Fenstergröße sollte man nicht verändern können
-# TODO: [X] Fenster in den Vordergund bringen
-# TODO: [X] Docstrings
-# TODO: [X] Rückmeldung für erfolgreiches speichern
-
-class QtTimer(QtWidgets.QMainWindow):
+class QtZeiten(QtWidgets.QDialog):
"""
Klasse für das erstellen einer zeitspanne.json mithilfe einer GUI / PyQt5
- Diese erbt von QtWidgets.QMainWindow
+ Diese erbt von QtWidgets.QDialog
"""
- def __init__(self, pfad_zeitspanne: str, pfad_fenster_layout: str):
+ def __init__(self, pfad_fenster_layout = os.path.join(PATH, "uhrzeiten.ui")):
"""
Ladet das angegebene Layout (wurde mit QT Designer erstellt https://www.qt.io/download)
Das Fenster wird automtaisch nach dem erstellen der Klasse geöffnet
Args:
- pfad_zeitspanne (str): Speicherpfad für zeitspanne.json
pfad_fester_layout (str): Speicherort der .ui - Datei
"""
- super(QtTimer, self).__init__()
+ super(QtZeiten, self).__init__()
# Laden der .ui Datei und Anpassungen
uic.loadUi(pfad_fenster_layout, self)
- self.setFixedSize(self.size())
+ self.i_start_datum_qdate.setMinimumDateTime(QDateTime.currentDateTime())
- # self.bestaetigen() soll beim Klicken auf Bestätigen aufgerufen werden
- self.pushButton.clicked.connect(self.bestaetigt)
+ # Funktionen den Buttons zuweisen
+ self.buttonBox.accepted
# Setzte leere Werte
self.aktive_wochentage = list()
self.start_uhrzeit: QTime = None
self.end_uhrzeit: QTime = None
self.aktive_termine = list()
- self.speicherpfad = pfad_zeitspanne
-
- # GUI anzeigen
- self.show()
- # Workaround, damit das Fenster hoffentlich im Vordergrund ist
- self.activateWindow()
-
- @staticmethod
- def start(pfad_zeitspanne: str, pfad_fenster_layout=os.path.join(PATH, "qttimer.ui")):
- """
- Öffnet eine GUI in dem der User seine Parameter angeben kann
- Diese werden bei Bestätigung direkt in den mit übergebenen Pfad gespeichert
- Anschließend schließt sich das Fenster
-
- Args:
- pfad_zeitspanne (str): Speicherpfad für zeitspanne.json
- pfad_fester_layout (str): Speicherort der .ui - Datei. Default: .\\qttimer.ui
- """
- app = QtWidgets.QApplication(list())
- window = QtTimer(pfad_zeitspanne, pfad_fenster_layout)
- app.exec_()
def bestaetigt(self):
"""
@@ -119,6 +87,8 @@ def speicher_einstellungen(self):
Speicherpfad wurde beim erstellen der Klasse mit übergeben
"""
+ speicherpfad = self.__oeffne_file_dialog()
+
data = {
"wochentage": self.aktive_wochentage,
"startzeit": {
@@ -132,7 +102,7 @@ def speicher_einstellungen(self):
"einhalten_bei": self.aktive_termine
}
- with open(self.speicherpfad, 'w', encoding='utf-8') as f:
+ with open(speicherpfad, 'w', encoding='utf-8') as f:
try:
json.dump(data, f, ensure_ascii=False, indent=4)
QtWidgets.QMessageBox.information(self, "Gepseichert", "Daten erfolgreich gespeichert")
@@ -141,6 +111,7 @@ def speicher_einstellungen(self):
QtWidgets.QMessageBox.critical(self, "Fehler!", "Daten konnten nicht gespeichert werden.")
raise error
+
def __aktuallisiere_aktive_wochentage(self):
"""
Alle "checked" Wochentage in der GUI werden gesichert
@@ -150,7 +121,7 @@ def __aktuallisiere_aktive_wochentage(self):
# Alle Checkboxen der GUI selektieren und durchgehen
# BUG: Wenn die reihenfolge im Layout geändert wird, stimmen die Wochentage nicht mehr 0 = Mo ... 6 = So
- checkboxes = self.mo_check_box.parent().findChildren(QtWidgets.QCheckBox)
+ checkboxes = self.i_mo_check_box.parent().findChildren(QtWidgets.QCheckBox)
for num, checkboxe in enumerate(checkboxes, 0):
if checkboxe.isChecked():
self.aktive_wochentage.append(num)
@@ -181,6 +152,14 @@ def __aktuallisiere_aktive_termine(self):
if self.zweiter_termin_check_box.isChecked():
self.aktive_termine.append(2)
+ def __oeffne_file_dialog(self) -> str:
+ datei_data = QtWidgets.QFileDialog.saveFileContent(self, "Zeitspanne", os.path.join(PATH, "data"), "JSON Files (*.json)")
+ dateipfad = datei_data[0]
+ return dateipfad
+
if __name__ == "__main__":
- QtTimer.start(f"{PATH}\\..\\zeitspanne.json")
+ app = QtWidgets.QApplication(list())
+ window = QtZeiten()
+ window.show()
+ app.exec_()
diff --git a/tools/gui/uhrzeiten.ui b/tools/gui/uhrzeiten.ui
index 7000c25f..f9790753 100644
--- a/tools/gui/uhrzeiten.ui
+++ b/tools/gui/uhrzeiten.ui
@@ -1,384 +1,399 @@
- MainWindow
-
+ Zeitspanne_Dialog
+
0
0
- 513
- 398
+ 764
+ 489
- MainWindow
+ vaccipy - Zeitspanne
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- Hier kannst du Uhrzeiten und Tage eingrenzen, an dem ein Termin gebucht werden soll
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
- QFrame::Box
-
-
- QFrame::Plain
-
-
-
-
-
-
- 0
-
-
-
-
-
- 1. Termin
-
-
- true
-
-
-
- -
-
-
- 2. Termin
-
-
- true
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- Nur Uhrzeiten zwischen
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
- Start:
-
-
-
- -
-
-
- Ende:
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- Uhr
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
-
-
- -
-
-
-
-
-
- QDateTimeEdit::HourSection
-
-
- false
-
-
-
-
-
-
- -
-
-
- Uhr
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
-
-
-
-
- -
-
-
- Bei welchen Terminen sollen die Bedingungen gelten?
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
- Termin fühestens ab:
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
- QAbstractSpinBox::UpDownArrows
-
-
-
-
-
-
-
-
- QDateTimeEdit::DaySection
-
-
- true
-
-
-
- 2021
- 5
- 25
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
-
-
-
-
-
- -
-
-
- vaccipy
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- QFrame::Box
-
-
- QFrame::Plain
-
-
-
-
-
-
- Dienstags
-
-
- true
-
-
-
- -
-
-
- Montags
-
-
- true
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- Donnerstags
-
-
- true
-
-
-
- -
-
-
- Samstags
-
-
- true
-
-
-
- -
-
-
- Sonntags
-
-
- true
-
-
-
- -
-
-
- Mittwochs
-
-
- true
-
-
-
- -
-
-
- Nur an folgenden Tagen:
-
-
-
- -
-
-
- Freitags
-
-
- true
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
-
-
- -
-
-
- QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Reset
-
-
-
-
-
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Reset
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ Hier kannst du Uhrzeiten und Tage eingrenzen, an dem ein Termin gebucht werden soll
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+ QFrame::Box
+
+
+ QFrame::Plain
+
+
+
-
+
+
+ 0
+
+
-
+
+
+ 1. Termin
+
+
+ true
+
+
+
+ -
+
+
+ 2. Termin
+
+
+ true
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Nur Uhrzeiten zwischen
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+ Start:
+
+
+
+ -
+
+
+ Ende:
+
+
+
+ -
+
+
-
+
+
+
+
+
+
+ -
+
+
+ Uhr
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+
+
+ -
+
+
-
+
+
+ QDateTimeEdit::HourSection
+
+
+ false
+
+
+
+
+
+
+ -
+
+
+ Uhr
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+
+
+
+
+ -
+
+
+ Bei welchen Terminen sollen die Bedingungen gelten?
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+ Termin fühestens ab:
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ QAbstractSpinBox::UpDownArrows
+
+
+
+
+
+
+
+
+ QDateTimeEdit::DaySection
+
+
+ true
+
+
+
+ 2021
+ 5
+ 25
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 14
+
+
+
+ vaccipy
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::Box
+
+
+ QFrame::Plain
+
+
+
-
+
+
+ Dienstags
+
+
+ true
+
+
+
+ -
+
+
+ Montags
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Donnerstags
+
+
+ true
+
+
+
+ -
+
+
+ Samstags
+
+
+ true
+
+
+
+ -
+
+
+ Sonntags
+
+
+ true
+
+
+
+ -
+
+
+ Mittwochs
+
+
+ true
+
+
+
+ -
+
+
+ Nur an folgenden Tagen:
+
+
+
+ -
+
+
+ Freitags
+
+
+ true
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
From c65270787975d0160dd67cefa1e15d8f318ec586 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Wed, 26 May 2021 21:02:58 +0200
Subject: [PATCH 04/25] umstrukturierung
---
tools/gui/qtzeiten.py | 164 +++++++++++++++++++++++++++---------------
1 file changed, 105 insertions(+), 59 deletions(-)
diff --git a/tools/gui/qtzeiten.py b/tools/gui/qtzeiten.py
index 19db9440..1a4252e7 100644
--- a/tools/gui/qtzeiten.py
+++ b/tools/gui/qtzeiten.py
@@ -38,7 +38,7 @@ class QtZeiten(QtWidgets.QDialog):
Diese erbt von QtWidgets.QDialog
"""
- def __init__(self, pfad_fenster_layout = os.path.join(PATH, "uhrzeiten.ui")):
+ def __init__(self, standard_speicherpfad:str, pfad_fenster_layout=os.path.join(PATH, "uhrzeiten.ui")):
"""
Ladet das angegebene Layout (wurde mit QT Designer erstellt https://www.qt.io/download)
Das Fenster wird automtaisch nach dem erstellen der Klasse geöffnet
@@ -49,58 +49,40 @@ def __init__(self, pfad_fenster_layout = os.path.join(PATH, "uhrzeiten.ui")):
super(QtZeiten, self).__init__()
+ self.standard_speicherpfad = standard_speicherpfad
+ self.pfad_fenster_layout = pfad_fenster_layout
+
# Laden der .ui Datei und Anpassungen
- uic.loadUi(pfad_fenster_layout, self)
+ uic.loadUi(self.pfad_fenster_layout, self)
self.i_start_datum_qdate.setMinimumDateTime(QDateTime.currentDateTime())
- # Funktionen den Buttons zuweisen
- self.buttonBox.accepted
-
- # Setzte leere Werte
- self.aktive_wochentage = list()
- self.start_uhrzeit: QTime = None
- self.end_uhrzeit: QTime = None
- self.aktive_termine = list()
+ # Funktionen für Buttonbox zuweisen
+ self.buttonBox.clicked.connect(self.__button_clicked)
def bestaetigt(self):
"""
Aktuallisiert alle Werte und Speichert gleichzeig die Aktuellen Werte
"""
- # Alle Werte von aus der GUI aktuallisieren
- self.__aktuallisiere_aktive_wochentage()
- self.__aktuallisiere_aktive_termine()
-
- if not self.__aktuallisiere_uhrzeiten():
+ try:
+ self.speicher_einstellungen()
+ self.close()
+ except ValueError as error:
QtWidgets.QMessageBox.critical(self, "Ungültige Eingabe!", "Start-Uhrzeit ist später als End-Uhrzeit!")
- return
-
- # Speichert alle Werte ab
- self.speicher_einstellungen()
-
- self.close()
+ except (TypeError, IOError, FileNotFoundError) as error:
+ QtWidgets.QMessageBox.critical(self, "Fehler beim Speichern!", "Bitte erneut versuchen!")
+
def speicher_einstellungen(self):
"""
Speichert alle Werte in der entsprechenden JSON-Formatierung
- Speicherpfad wurde beim erstellen der Klasse mit übergeben
+ Speicherpfad wird vom User abgefragt
"""
speicherpfad = self.__oeffne_file_dialog()
- data = {
- "wochentage": self.aktive_wochentage,
- "startzeit": {
- "h": self.start_uhrzeit.hour(),
- "m": self.start_uhrzeit.minute()
- },
- "endzeit": {
- "h": self.end_uhrzeit.hour(),
- "m": self.end_uhrzeit.minute()
- },
- "einhalten_bei": self.aktive_termine
- }
+ data = self.__get_alle_werte()
with open(speicherpfad, 'w', encoding='utf-8') as f:
try:
@@ -111,55 +93,119 @@ def speicher_einstellungen(self):
QtWidgets.QMessageBox.critical(self, "Fehler!", "Daten konnten nicht gespeichert werden.")
raise error
+ def __button_clicked(self, button):
+ clicked_button = self.buttonBox.standardButton(button)
+ if clicked_button == QtWidgets.QDialogButtonBox.Apply:
+ self.bestaetigt()
+ if clicked_button == QtWidgets.QDialogButtonBox.Reset:
+ self.__reset()
+ elif clicked_button == QtWidgets.QDialogButtonBox.Cancel:
+ self.close()
+
+ def __get_alle_werte(self) -> dict:
+ """
+ Gibt alle nötigen Daten richtig formatiert zum abspeichern
+
+ Returns:
+ dict: alle Daten
+ """
+
+ aktive_wochentage = self.__get_aktive_wochentage()
+ uhrzeiten = self.__get_uhrzeiten()
+ termine = self.__get_aktive_termine()
+
+ zeitspanne = {
+ "wochentage": aktive_wochentage,
+ "startzeit": uhrzeiten["startzeit"],
+ "endzeiten": uhrzeiten["endzeit"],
+ "einhalten_bei": termine
+ }
+ return zeitspanne
- def __aktuallisiere_aktive_wochentage(self):
+ def __get_aktive_wochentage(self) -> list:
"""
- Alle "checked" Wochentage in der GUI werden gesichert
+ Alle "checked" Wochentage in der GUI
+
+ Returns:
+ list: Alle aktiven Wochentage
"""
- # Zur sicherheit alte Werte löschen
- self.aktive_wochentage.clear()
+
+ # Leere liste
+ aktive_wochentage = list()
# Alle Checkboxen der GUI selektieren und durchgehen
# BUG: Wenn die reihenfolge im Layout geändert wird, stimmen die Wochentage nicht mehr 0 = Mo ... 6 = So
checkboxes = self.i_mo_check_box.parent().findChildren(QtWidgets.QCheckBox)
for num, checkboxe in enumerate(checkboxes, 0):
if checkboxe.isChecked():
- self.aktive_wochentage.append(num)
+ aktive_wochentage.append(num)
- def __aktuallisiere_uhrzeiten(self) -> bool:
- """
- Aktuallisert die eingegebenen Uhrzeiten der GUI
+ return aktive_wochentage
+
+ def __get_uhrzeiten(self) -> dict:
+ """
+ Erstellt ein Dict mit ensprechenden start und endzeiten
+
+ Raises:
+ ValueError: start uhrzeit < end uhrzeit
+
+ Returns:
+ dict: fertiges dict zum speichern mit startzeit und endzeit
"""
- if self.start_time.time() < self.end_time.time():
- self.start_uhrzeit = self.start_time.time()
- self.end_uhrzeit = self.end_time.time()
+ start_uhrzeit: QTime = self.i_start_time_qtime.time()
+ end_uhrzeit: QTime = self.i_end_time_qtime.time()
+
+ if start_uhrzeit >= end_uhrzeit:
+ raise ValueError
- return True
- else:
- return False
+ uhrzeiten = {
+ "startzeit": {
+ "h": start_uhrzeit.hour(),
+ "m": start_uhrzeit.minute()
+ },
+ "endzeit": {
+ "h": end_uhrzeit.hour(),
+ "m": end_uhrzeit.minute()
+ }
+ }
+ return uhrzeiten
- def __aktuallisiere_aktive_termine(self):
+ def __get_aktive_termine(self) -> list:
"""
- Aktuallisert die eingegebenen Uhrzeiten der GUI
+ Liste mit den aktiven Terminen 1 = 1. Termin 2 = 2. Termin
+
+ Returns:
+ list: Termine
"""
- # Zur sicherheit alte Werte löschen
- self.aktive_termine.clear()
+ aktive_termine = list()
- if self.erster_termin_check_box.isChecked():
- self.aktive_termine.append(1)
- if self.zweiter_termin_check_box.isChecked():
- self.aktive_termine.append(2)
+ if self.i_erster_termin_check_box.isChecked():
+ aktive_termine.append(1)
+ if self.i_zweiter_termin_check_box.isChecked():
+ aktive_termine.append(2)
+ return aktive_termine
def __oeffne_file_dialog(self) -> str:
- datei_data = QtWidgets.QFileDialog.saveFileContent(self, "Zeitspanne", os.path.join(PATH, "data"), "JSON Files (*.json)")
- dateipfad = datei_data[0]
+ """
+ Öffnet einen File Dialog, der den Speicherort festlegt
+
+ Returns:
+ str: Speicherpfad
+ """
+
+ datei_data = QtWidgets.QFileDialog.getSaveFileName(self, "Zeitspanne", self.standard_speicherpfad, "JSON Files (*.json)")
+ dateipfad = datei_data[0] # (Pfad, Dateityp)
return dateipfad
+ def __reset(self):
+ #TODO: Reset
+ pass
+
if __name__ == "__main__":
app = QtWidgets.QApplication(list())
- window = QtZeiten()
+ window = QtZeiten(".\\zeitspanne.json")
window.show()
app.exec_()
From f0c1f54745914d59c24709d7b7373c6a5f4670ce Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Wed, 26 May 2021 22:10:46 +0200
Subject: [PATCH 05/25] kontaktdaten implementriert
---
gui.py | 9 +-
tools/gui/kontaktdaten.ui | 664 ++++++++++++++++++++------------------
tools/gui/qtkontakt.py | 112 ++++++-
tools/gui/qtzeiten.py | 4 +-
tools/gui/uhrzeiten.ui | 2 +-
5 files changed, 462 insertions(+), 329 deletions(-)
diff --git a/gui.py b/gui.py
index 1ce5dd1e..2b531a6b 100644
--- a/gui.py
+++ b/gui.py
@@ -6,6 +6,7 @@
from PyQt5 import QtWidgets, uic
from tools.gui.qtzeiten import QtZeiten
+from tools.gui.qtkontakt import QtKontakt
from tools.its import ImpfterminService
PATH = os.path.dirname(os.path.realpath(__file__))
@@ -68,6 +69,7 @@ def __termin_suchen(self):
code = kontaktdaten["code"]
plz_impfzentren = kontaktdaten["plz_impfzentren"]
+ #TODO: starte es in einem extra thread, sonst hängt sich die GUI auf
ImpfterminService.terminsuche(code=code, plz_impfzentren=plz_impfzentren, kontakt=kontakt, zeitspanne=zeitspanne, PATH=PATH)
@@ -79,7 +81,6 @@ def __get_kontaktdaten(self) -> dict:
if not os.path.isfile(self.pfad_kontaktdaten):
self.kontaktdaten_erstellen()
- pass
with open(self.pfad_kontaktdaten, "r", encoding='utf-8') as f:
kontaktdaten = json.load(f)
@@ -119,11 +120,13 @@ def start_gui():
def kontaktdaten_erstellen(self):
- pass
+ dialog = QtKontakt(self.pfad_kontaktdaten)
+ dialog.show()
+ dialog.exec_()
def zeitspanne_erstellen(self):
- dialog = QtZeiten()
+ dialog = QtZeiten(self.pfad_zeitspanne)
dialog.show()
dialog.exec_()
diff --git a/tools/gui/kontaktdaten.ui b/tools/gui/kontaktdaten.ui
index 62bdaf07..2141bd1b 100644
--- a/tools/gui/kontaktdaten.ui
+++ b/tools/gui/kontaktdaten.ui
@@ -1,347 +1,371 @@
- MainWindow
-
+ Dialog
+
0
0
- 541
- 383
+ 715
+ 428
- MainWindow
+ vaccipy - Kontaktdaten
-
-
- -
-
-
-
-
-
- Automatische Terminbuchung für den Corona Impfterminservice
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- vaccipy
-
-
- Qt::AlignHCenter|Qt::AlignTop
-
-
-
-
-
- -
-
-
-
-
-
- PLZ's der Impfzentren:
-
-
-
- -
-
-
-
-
-
-
-
-
- Beispiel: 68163, 69124, 69469
-
-
- true
-
-
-
- -
-
-
- Code:
-
-
-
- -
-
-
- NNNN-NNNN-NNNN
-
-
- --
-
-
- A1C3-D2FG-4IJK
-
-
- false
-
-
-
- -
-
-
- Anrede:
-
-
-
- -
-
-
- false
-
-
- Bitte Wählen
-
-
- QComboBox::NoInsert
-
-
-
+
+
-
+
+
+
+ 14
+
+
+
+ vaccipy
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
- Bitte Wählen
+ PLZ's der Impfzentren:
+
+
+
+ -
+
+
+
-
- -
- Frau
+
+
+
+ Beispiel: 68163, 69124, 69469
+
+
+ true
-
- -
+
+
+ -
+
- Herr
+ Code:
+
+
+
+ -
+
+
+ NNNN-NNNN-NNNN
-
- -
- ...
+ --
-
-
-
- -
-
-
- Vorname:
-
-
-
- -
-
-
- Max
-
-
- true
-
-
-
- -
-
-
- Nachname:
-
-
-
- -
-
-
- Mustermann
-
-
- true
-
-
-
- -
-
-
- Straße:
-
-
-
- -
-
-
-
-
-
-
- 100
- 0
-
-
+
+ A1C3-D2FG-4IJK
+
+
+ true
+
+
+
+ -
+
+
+ Anrede:
+
+
+
+ -
+
+
+ false
+
+
+ Bitte Wählen
+
+
+ QComboBox::NoInsert
+
+
-
- Hausnummer:
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- true
-
-
-
- -
-
-
-
-
-
- true
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
- PLZ Wohnort:
-
-
-
- -
-
-
-
-
-
- true
-
-
-
- -
-
-
-
- 100
- 0
-
+ Bitte Wählen
+
+ -
- Wohnort:
-
-
-
- -
-
-
- 99999
+ Frau
-
- 88045
-
-
- true
-
-
-
- -
-
-
- Qt::Horizontal
+
+ -
+
+ Herr
-
-
- 40
- 20
-
+
+ -
+
+ ...
-
-
-
-
- -
-
-
- Telefonnummer:
-
-
-
- -
-
-
- +4\9
-
-
-
-
-
- false
-
-
-
- -
-
-
- Mail:
-
-
-
- -
-
-
- true
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Reset
-
-
- false
-
-
-
-
-
+
+
+
+ -
+
+
+ Vorname:
+
+
+
+ -
+
+
+ Max
+
+
+ false
+
+
+
+ -
+
+
+ Nachname:
+
+
+
+ -
+
+
+ Mustermann
+
+
+ false
+
+
+
+ -
+
+
+ Straße:
+
+
+
+ -
+
+
-
+
+
+
+ 100
+ 0
+
+
+
+ Hausnummer:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ false
+
+
+
+ -
+
+
+
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ PLZ Wohnort:
+
+
+
+ -
+
+
-
+
+
+ false
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+ Wohnort:
+
+
+
+ -
+
+
+ 99999
+
+
+ 88045
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ Telefonnummer:
+
+
+
+ -
+
+
+
+
+
+ +49
+
+
+ +4917299334455
+
+
+ false
+
+
+
+ -
+
+
+ Mail:
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ Gebe Bitte deine Persöhnliche Daten ein
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Reset|QDialogButtonBox::Save
+
+
+
+
diff --git a/tools/gui/qtkontakt.py b/tools/gui/qtkontakt.py
index 14159993..4fda0c39 100644
--- a/tools/gui/qtkontakt.py
+++ b/tools/gui/qtkontakt.py
@@ -1,3 +1,5 @@
+import os
+import json
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QTime
@@ -26,6 +28,110 @@
# Cancel
# Reset
-class QtKontakt(QtWidgets.QMainWindow):
- def __init__(self):
- super().__init__()
\ No newline at end of file
+PATH = os.path.dirname(os.path.realpath(__file__))
+
+
+class QtKontakt(QtWidgets.QDialog):
+ def __init__(self, standard_speicherpfad:str, pfad_fenster_layout=os.path.join(PATH, "kontaktdaten.ui")):
+ super().__init__()
+
+ self.standard_speicherpfad = standard_speicherpfad
+
+ # Laden der .ui Datei
+ uic.loadUi(pfad_fenster_layout, self)
+
+ # Funktionen für Buttonbox zuweisen
+ self.buttonBox.clicked.connect(self.__button_clicked)
+
+ def bestaetigt(self):
+ try:
+ self.speicher_einstellungen()
+ self.close()
+ except (TypeError, IOError, FileNotFoundError) as error:
+ QtWidgets.QMessageBox.critical(self, "Fehler beim Speichern!", "Bitte erneut versuchen!")
+ print(error)
+
+ def speicher_einstellungen(self):
+ """
+ Speichert alle Werte in der entsprechenden JSON-Formatierung
+ Speicherpfad wird vom User abgefragt
+ """
+
+ speicherpfad = self.__oeffne_file_dialog()
+
+ data = self.__get_alle_werte()
+
+ with open(speicherpfad, 'w', encoding='utf-8') as f:
+ try:
+ json.dump(data, f, ensure_ascii=False, indent=4)
+ QtWidgets.QMessageBox.information(self, "Gepseichert", "Daten erfolgreich gespeichert")
+
+ except (TypeError, IOError, FileNotFoundError) as error:
+ QtWidgets.QMessageBox.critical(self, "Fehler!", "Daten konnten nicht gespeichert werden.")
+ raise error
+
+ def __button_clicked(self, button):
+ clicked_button = self.buttonBox.standardButton(button)
+ if clicked_button == QtWidgets.QDialogButtonBox.Save:
+ self.bestaetigt()
+ if clicked_button == QtWidgets.QDialogButtonBox.Reset:
+ self.__reset()
+ elif clicked_button == QtWidgets.QDialogButtonBox.Cancel:
+ self.close()
+
+ def __get_alle_werte(self) -> dict:
+ plz_zentrum_raw = self.i_plz_impfzentren.text()
+ code = self.i_code_impfzentren.text().strip()
+ anrede = self.i_anrede_combo_box.currentText().strip()
+ vorname = self.i_vorname.text().strip()
+ nachname = self.i_nachname.text().strip()
+ strasse = self.i_strasse.text().strip()
+ hausnummer = self.i_hausnummer.text().strip()
+ wohnort = self.i_wohnort.text().strip()
+ plz_wohnort = self.i_plz_wohnort.text().strip()
+ telefon = self.i_telefon.text().strip()
+ mail = self.i_mail.text().strip()
+
+ # PLZ der Zentren in liste und "strippen"
+ plz_zentren = plz_zentrum_raw.split(",")
+ plz_zentren = [plz.strip() for plz in plz_zentren]
+
+ kontaktdaten = {
+ "plz_impfzentren": plz_zentren,
+ "code": code,
+ "kontakt": {
+ "anrede": anrede,
+ "vorname": vorname,
+ "nachname": nachname,
+ "strasse": strasse,
+ "hausnummer": hausnummer,
+ "plz": plz_wohnort,
+ "ort": wohnort,
+ "phone": telefon,
+ "notificationChannel": "email",
+ "notificationReceiver": mail
+ }
+ }
+ return kontaktdaten
+
+ def __oeffne_file_dialog(self) -> str:
+ """
+ Öffnet einen File Dialog, der den Speicherort festlegt
+
+ Returns:
+ str: Speicherpfad
+ """
+
+ datei_data = QtWidgets.QFileDialog.getSaveFileName(self, "Kontaktdaten", self.standard_speicherpfad, "JSON Files (*.json)")
+ dateipfad = datei_data[0] # (Pfad, Dateityp)
+ return dateipfad
+
+ def __reset(self):
+ pass
+
+
+if __name__ == "__main__":
+ app = QtWidgets.QApplication(list())
+ window = QtKontakt("./kontaktdaten.json")
+ window.show()
+ app.exec_()
diff --git a/tools/gui/qtzeiten.py b/tools/gui/qtzeiten.py
index 1a4252e7..770210db 100644
--- a/tools/gui/qtzeiten.py
+++ b/tools/gui/qtzeiten.py
@@ -62,7 +62,7 @@ def __init__(self, standard_speicherpfad:str, pfad_fenster_layout=os.path.join(P
def bestaetigt(self):
"""
- Aktuallisiert alle Werte und Speichert gleichzeig die Aktuellen Werte
+ Speichert die aktuellen Werte
"""
try:
@@ -95,7 +95,7 @@ def speicher_einstellungen(self):
def __button_clicked(self, button):
clicked_button = self.buttonBox.standardButton(button)
- if clicked_button == QtWidgets.QDialogButtonBox.Apply:
+ if clicked_button == QtWidgets.QDialogButtonBox.Save:
self.bestaetigt()
if clicked_button == QtWidgets.QDialogButtonBox.Reset:
self.__reset()
diff --git a/tools/gui/uhrzeiten.ui b/tools/gui/uhrzeiten.ui
index f9790753..9c6887e5 100644
--- a/tools/gui/uhrzeiten.ui
+++ b/tools/gui/uhrzeiten.ui
@@ -22,7 +22,7 @@
Qt::Horizontal
- QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Reset
+ QDialogButtonBox::Cancel|QDialogButtonBox::Reset|QDialogButtonBox::Save
From 6069a24fd6fbabd6e0df1b9036db41ff581ff267 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Wed, 26 May 2021 22:24:47 +0200
Subject: [PATCH 06/25] added docstrings
---
gui.py | 112 +++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 81 insertions(+), 31 deletions(-)
diff --git a/gui.py b/gui.py
index 2b531a6b..6d7d9972 100644
--- a/gui.py
+++ b/gui.py
@@ -28,7 +28,15 @@ class HauptGUI(QtWidgets.QMainWindow):
# b_neue_kontaktdaten
# b_neue_zeitspanne
- def __init__(self, pfad_fenster_layout=os.path.join(PATH, "tools/gui/main.ui")):
+ # TODO: Ausgabe der cmd in der GUI wiederspiegelen - wenn sowas überhaupt geht
+ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main.ui")):
+ """
+ Main der GUI Anwendung
+
+ Args:
+ pfad_fenster_layout (str, optional): Ort der main.ui. Defaults to os.path.join(PATH, "tools/gui/main.ui").
+ """
+
super().__init__()
# Laden der .ui Datei und Anpassungen
@@ -60,8 +68,39 @@ def __init__(self, pfad_fenster_layout=os.path.join(PATH, "tools/gui/main.ui")):
# Workaround, damit das Fenster hoffentlich im Vordergrund ist
self.activateWindow()
+ @staticmethod
+ def start_gui():
+ """
+ Startet die GUI Anwendung
+ """
+
+ app = QtWidgets.QApplication(list())
+ window = HauptGUI()
+ app.exec_()
+
+ def kontaktdaten_erstellen(self):
+ """
+ Ruft den Dialog für die Kontaktdaten auf
+ """
+
+ dialog = QtKontakt(self.pfad_kontaktdaten)
+ dialog.show()
+ dialog.exec_()
+
+ def zeitspanne_erstellen(self):
+ """
+ Ruft den Dialog für die Zeitspanne auf
+ """
+
+ dialog = QtZeiten(self.pfad_zeitspanne)
+ dialog.show()
+ dialog.exec_()
def __termin_suchen(self):
+ """
+ Startet den Prozess der terminsuche mit Impfterminservice.terminsuche
+ """
+
kontaktdaten = self.__get_kontaktdaten()
zeitspanne = self.__get_zeitspanne()
@@ -69,15 +108,24 @@ def __termin_suchen(self):
code = kontaktdaten["code"]
plz_impfzentren = kontaktdaten["plz_impfzentren"]
- #TODO: starte es in einem extra thread, sonst hängt sich die GUI auf
+ # TODO: starte es in einem extra thread, sonst hängt sich die GUI auf
ImpfterminService.terminsuche(code=code, plz_impfzentren=plz_impfzentren, kontakt=kontakt, zeitspanne=zeitspanne, PATH=PATH)
-
def __code_generieren(self):
- pass
+ """
+ Startet den Prozess der Codegenerierung
+ """
+ # TODO: code generierung implementieren
+ pass
def __get_kontaktdaten(self) -> dict:
+ """
+ Ladet die Kontakdaten aus dem in der GUI hinterlegten Pfad
+
+ Returns:
+ dict: Kontakdaten
+ """
if not os.path.isfile(self.pfad_kontaktdaten):
self.kontaktdaten_erstellen()
@@ -87,8 +135,14 @@ def __get_kontaktdaten(self) -> dict:
return kontaktdaten
-
def __get_zeitspanne(self) -> dict:
+ """
+ Ladet die Zeitspanne aus dem in der GUI hinterlegtem Pfad
+
+ Returns:
+ dict: Zeitspanne
+ """
+
if not os.path.isfile(self.pfad_zeitspanne):
self.zeitspanne_erstellen()
@@ -97,42 +151,38 @@ def __get_zeitspanne(self) -> dict:
return zeitspanne
-
def __oeffne_file_dialog(self, datei: str):
- datei_data = QtWidgets.QFileDialog.getOpenFileName(self, datei, os.path.join(PATH, "data"), "JSON Files (*.json)")
- dateipfad = datei_data[0]
+ """
+ Öffnet einen "File-Picker", der entsprechende Werte für die kontaktdaten / zeitspanne einliest
- if datei == "kontaktdaten":
- self.i_kontaktdaten_pfad.setText(dateipfad)
- else:
- self.i_zeitspanne_pfad.setText(dateipfad)
+ Args:
+ datei (str): Startpfad vom File-Picker
+ """
+ # Öffnet den "File-Picker" vom System um ein bereits existierende Datei auszuwählen
+ datei_data = QtWidgets.QFileDialog.getOpenFileName(self, datei, os.path.join(PATH, "data"), "JSON Files (*.json)")
+ dateipfad = datei_data[0] # (pfad, typ)
+
+ if dateipfad:
+ if datei == "kontaktdaten":
+ self.i_kontaktdaten_pfad.setText(dateipfad)
+ else:
+ self.i_zeitspanne_pfad.setText(dateipfad)
def __update_pfade(self):
+ """
+ Wird ein Pfad in der GUI verändert, so werden die entsprechende Attribute angepasst
+ """
+
self.pfad_kontaktdaten = self.i_kontaktdaten_pfad.text()
self.pfad_zeitspanne = self.i_zeitspanne_pfad.text()
- @staticmethod
- def start_gui():
- app = QtWidgets.QApplication(list())
- window = HauptGUI()
- app.exec_()
-
-
- def kontaktdaten_erstellen(self):
- dialog = QtKontakt(self.pfad_kontaktdaten)
- dialog.show()
- dialog.exec_()
-
-
- def zeitspanne_erstellen(self):
- dialog = QtZeiten(self.pfad_zeitspanne)
- dialog.show()
- dialog.exec_()
-
-
def main():
+ """
+ Startet die GUI-Anwendung
+ """
+
HauptGUI.start_gui()
From 4688a0fb53d234dbb109085408c87f3a62dcc707 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Wed, 26 May 2021 22:35:02 +0200
Subject: [PATCH 07/25] Added docstring / comments
---
gui.py | 3 ++-
tools/gui/qtkontakt.py | 32 +++++++++++++++++++++++++++++++-
tools/gui/qtzeiten.py | 29 +++++++++++++++++++----------
3 files changed, 52 insertions(+), 12 deletions(-)
diff --git a/gui.py b/gui.py
index 6d7d9972..1871e043 100644
--- a/gui.py
+++ b/gui.py
@@ -34,7 +34,8 @@ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main
Main der GUI Anwendung
Args:
- pfad_fenster_layout (str, optional): Ort der main.ui. Defaults to os.path.join(PATH, "tools/gui/main.ui").
+ pfad_fenster_layout (str, optional): Ladet das angegebene Layout (wurde mit QT Designer erstellt https://www.qt.io/download).
+ Defaults to os.path.join(PATH, "tools/gui/main.ui").
"""
super().__init__()
diff --git a/tools/gui/qtkontakt.py b/tools/gui/qtkontakt.py
index 4fda0c39..a77f02fd 100644
--- a/tools/gui/qtkontakt.py
+++ b/tools/gui/qtkontakt.py
@@ -44,6 +44,10 @@ def __init__(self, standard_speicherpfad:str, pfad_fenster_layout=os.path.join(P
self.buttonBox.clicked.connect(self.__button_clicked)
def bestaetigt(self):
+ """
+ Versucht die Daten zu speichern und schließt sich anschließend selbst
+ """
+
try:
self.speicher_einstellungen()
self.close()
@@ -71,6 +75,13 @@ def speicher_einstellungen(self):
raise error
def __button_clicked(self, button):
+ """
+ Zuweisung der einzelnen Funktionen der Buttons in der ButtonBox
+
+ Args:
+ button (PyQt5.QtWidgets.QPushButton): Button welcher gedrückt wurde
+ """
+
clicked_button = self.buttonBox.standardButton(button)
if clicked_button == QtWidgets.QDialogButtonBox.Save:
self.bestaetigt()
@@ -80,6 +91,13 @@ def __button_clicked(self, button):
self.close()
def __get_alle_werte(self) -> dict:
+ """
+ Holt sich alle Werte aus der GUI und gibt diese fertig zum speichern zurück
+
+ Returns:
+ dict: User eingaben
+ """
+
plz_zentrum_raw = self.i_plz_impfzentren.text()
code = self.i_code_impfzentren.text().strip()
anrede = self.i_anrede_combo_box.currentText().strip()
@@ -118,18 +136,30 @@ def __oeffne_file_dialog(self) -> str:
"""
Öffnet einen File Dialog, der den Speicherort festlegt
+ Raises:
+ FileNotFoundError: Wird geworfen, wenn kein Pfad angegeben wurde
+
Returns:
- str: Speicherpfad
+ str: speicherpfad
"""
datei_data = QtWidgets.QFileDialog.getSaveFileName(self, "Kontaktdaten", self.standard_speicherpfad, "JSON Files (*.json)")
dateipfad = datei_data[0] # (Pfad, Dateityp)
+
+ if not dateipfad:
+ raise FileNotFoundError
+
return dateipfad
def __reset(self):
+ """
+ Setzt alle Werte in der GUI zurück
+ """
+
pass
+# Zum schnellen einzeltesten
if __name__ == "__main__":
app = QtWidgets.QApplication(list())
window = QtKontakt("./kontaktdaten.json")
diff --git a/tools/gui/qtzeiten.py b/tools/gui/qtzeiten.py
index 770210db..7fb21017 100644
--- a/tools/gui/qtzeiten.py
+++ b/tools/gui/qtzeiten.py
@@ -38,17 +38,18 @@ class QtZeiten(QtWidgets.QDialog):
Diese erbt von QtWidgets.QDialog
"""
- def __init__(self, standard_speicherpfad:str, pfad_fenster_layout=os.path.join(PATH, "uhrzeiten.ui")):
+ def __init__(self, standard_speicherpfad: str, pfad_fenster_layout=os.path.join(PATH, "uhrzeiten.ui")):
"""
- Ladet das angegebene Layout (wurde mit QT Designer erstellt https://www.qt.io/download)
- Das Fenster wird automtaisch nach dem erstellen der Klasse geöffnet
+ Eingabe der Zeitkonfigurationen
Args:
- pfad_fester_layout (str): Speicherort der .ui - Datei
+ standard_speicherpfad (str): standard speicherpfad der JSON-Datei
+ pfad_fenster_layout (str, optional): Layout des Dialogs. Defaults to os.path.join(PATH, "uhrzeiten.ui").
"""
super(QtZeiten, self).__init__()
+ # Startwerte setzten
self.standard_speicherpfad = standard_speicherpfad
self.pfad_fenster_layout = pfad_fenster_layout
@@ -56,13 +57,12 @@ def __init__(self, standard_speicherpfad:str, pfad_fenster_layout=os.path.join(P
uic.loadUi(self.pfad_fenster_layout, self)
self.i_start_datum_qdate.setMinimumDateTime(QDateTime.currentDateTime())
-
# Funktionen für Buttonbox zuweisen
self.buttonBox.clicked.connect(self.__button_clicked)
def bestaetigt(self):
"""
- Speichert die aktuellen Werte
+ Speichert die aktuellen Werte und schließt anschließend den Dialog
"""
try:
@@ -72,7 +72,6 @@ def bestaetigt(self):
QtWidgets.QMessageBox.critical(self, "Ungültige Eingabe!", "Start-Uhrzeit ist später als End-Uhrzeit!")
except (TypeError, IOError, FileNotFoundError) as error:
QtWidgets.QMessageBox.critical(self, "Fehler beim Speichern!", "Bitte erneut versuchen!")
-
def speicher_einstellungen(self):
"""
@@ -81,7 +80,6 @@ def speicher_einstellungen(self):
"""
speicherpfad = self.__oeffne_file_dialog()
-
data = self.__get_alle_werte()
with open(speicherpfad, 'w', encoding='utf-8') as f:
@@ -94,9 +92,16 @@ def speicher_einstellungen(self):
raise error
def __button_clicked(self, button):
+ """
+ Zuweisung der einzelnen Funktionen der Buttons in der ButtonBox
+
+ Args:
+ button (PyQt5.QtWidgets.QPushButton): Button welcher gedrückt wurde
+ """
+
clicked_button = self.buttonBox.standardButton(button)
if clicked_button == QtWidgets.QDialogButtonBox.Save:
- self.bestaetigt()
+ self.bestaetigt()
if clicked_button == QtWidgets.QDialogButtonBox.Reset:
self.__reset()
elif clicked_button == QtWidgets.QDialogButtonBox.Cancel:
@@ -109,7 +114,7 @@ def __get_alle_werte(self) -> dict:
Returns:
dict: alle Daten
"""
-
+
aktive_wochentage = self.__get_aktive_wochentage()
uhrzeiten = self.__get_uhrzeiten()
termine = self.__get_aktive_termine()
@@ -197,6 +202,10 @@ def __oeffne_file_dialog(self) -> str:
datei_data = QtWidgets.QFileDialog.getSaveFileName(self, "Zeitspanne", self.standard_speicherpfad, "JSON Files (*.json)")
dateipfad = datei_data[0] # (Pfad, Dateityp)
+
+ if not dateipfad:
+ raise FileNotFoundError
+
return dateipfad
def __reset(self):
From d16aca056d777607b6ed70864a287cf84bee7e78 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Wed, 26 May 2021 22:51:00 +0200
Subject: [PATCH 08/25] =?UTF-8?q?Fr=C3=BCheste=20Terminbuchung=20implement?=
=?UTF-8?q?iert?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
tools/gui/qtzeiten.py | 18 +++++++++++++++---
tools/its.py | 12 +++++++-----
2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/tools/gui/qtzeiten.py b/tools/gui/qtzeiten.py
index 7fb21017..c0be3595 100644
--- a/tools/gui/qtzeiten.py
+++ b/tools/gui/qtzeiten.py
@@ -1,7 +1,7 @@
import os
import json
from PyQt5 import QtWidgets, uic
-from PyQt5.QtCore import QTime, QDateTime
+from PyQt5.QtCore import QTime, QDate ,QDateTime
# Folgende Widgets stehen zur Verfügung:
@@ -118,12 +118,18 @@ def __get_alle_werte(self) -> dict:
aktive_wochentage = self.__get_aktive_wochentage()
uhrzeiten = self.__get_uhrzeiten()
termine = self.__get_aktive_termine()
+ start_datum = self.__get_start_datum()
zeitspanne = {
"wochentage": aktive_wochentage,
"startzeit": uhrzeiten["startzeit"],
- "endzeiten": uhrzeiten["endzeit"],
- "einhalten_bei": termine
+ "endzeit": uhrzeiten["endzeit"],
+ "einhalten_bei": termine,
+ "startdatum": {
+ "jahr": start_datum.year(),
+ "monat": start_datum.month(),
+ "tag": start_datum.day()
+ },
}
return zeitspanne
@@ -176,6 +182,12 @@ def __get_uhrzeiten(self) -> dict:
}
return uhrzeiten
+ def __get_start_datum(self) -> QDate:
+ """
+ Aktuallisiert das Startdatum
+ """
+ return self.i_start_datum_qdate.date()
+
def __get_aktive_termine(self) -> list:
"""
Liste mit den aktiven Terminen 1 = 1. Termin 2 = 2. Termin
diff --git a/tools/its.py b/tools/its.py
index e1dcdff9..e67edef9 100644
--- a/tools/its.py
+++ b/tools/its.py
@@ -3,7 +3,7 @@
import sys
import time
from base64 import b64encode
-from datetime import datetime
+from datetime import datetime, date
from datetime import time as dtime
from random import choice
@@ -485,7 +485,7 @@ def login(self):
@retry_on_failure()
def termin_suchen(self, plz: int, zeitspanne: dict):
"""Es wird nach einen verfügbaren Termin in der gewünschten PLZ gesucht.
- Ausgewählt wird der erstbeste Termin (!).
+ Ausgewählt wird der erstbeste Termin, welcher im entsprechenden Zeitraum liegt (!).
Zurückgegeben wird das Ergebnis der Abfrage und der Status-Code.
Bei Status-Code > 400 müssen die Cookies erneuert werden.
@@ -518,7 +518,8 @@ def termin_suchen(self, plz: int, zeitspanne: dict):
terminpaare = res_json.get("termine")
if terminpaare:
# Checken ob verfügbare terminpaare in angegebener Zeitspanne liegt
- if zeitspanne["einhalten_bei"]:
+ # Falls daten nicht vorhanden - einfach alle aktzeptieren
+ if zeitspanne.get("einhalten_bei"):
terminpaare_in_zeitspanne = list()
# Alle Terminpaare durchgehen
@@ -530,6 +531,7 @@ def termin_suchen(self, plz: int, zeitspanne: dict):
# Soll einer der Beiden Termine überprüft werden
if num in zeitspanne["einhalten_bei"]:
+ startdatum = date(zeitspanne["startdatum"]["jahr"], zeitspanne["startdatum"]["monat"], zeitspanne["startdatum"]["tag"])
startzeit = dtime(zeitspanne["startzeit"]["h"], zeitspanne["startzeit"]["m"])
endzeit = dtime(zeitspanne["endzeit"]["h"], zeitspanne["endzeit"]["m"])
wochentage = zeitspanne["wochentage"]
@@ -537,7 +539,7 @@ def termin_suchen(self, plz: int, zeitspanne: dict):
termin_zeit = datetime.fromtimestamp(int(termin["begin"])/1000)
# Termin inherhalb der Zeitspanne und im Wochentag
- if not ((startzeit <= termin_zeit.time() <= endzeit) and (termin_zeit.weekday() in wochentage)):
+ if not ((startzeit <= termin_zeit.time() <= endzeit) and termin_zeit.date() >= startdatum and (termin_zeit.weekday() in wochentage)):
termine_in_zeitspanne = False
# Beide Termine sind in der Zeitspanne
@@ -689,7 +691,7 @@ def code_bestaetigen(self, token, sms_pin):
return False
@staticmethod
- def terminsuche(code: str, plz_impfzentren: list, kontakt: dict, PATH:str, zeitspanne: dict, check_delay: int = 30):
+ def terminsuche(code: str, plz_impfzentren: list, kontakt: dict, PATH:str, zeitspanne: dict = dict(), check_delay: int = 30):
"""
Workflow für die Terminbuchung.
From 19177d5afc701e2ee0e3ec72f8e8e22f565e9441 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Wed, 26 May 2021 22:56:35 +0200
Subject: [PATCH 09/25] updated
---
.gitignore | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index 71965ce5..4ff42511 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,8 +9,9 @@ log/
# data
kontaktdaten.json
+zeitspanne.json
# pyinstaller
# temporary building files:
-build/
\ No newline at end of file
+build/
From a2acec4373fdc9bc3024e02a73908194df4840ad Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Thu, 27 May 2021 18:19:58 +0200
Subject: [PATCH 10/25] terminsuche startet in eigenem Thread
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
somit hängt sich die GUI nicht mehr auf nach
---
gui.py | 36 ++++++++++++++++++++++++++++++++++--
tools/gui/uhrzeiten.ui | 2 +-
2 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/gui.py b/gui.py
index 1871e043..921b3a9c 100644
--- a/gui.py
+++ b/gui.py
@@ -3,6 +3,7 @@
import sys
import os
import json
+import threading
from PyQt5 import QtWidgets, uic
from tools.gui.qtzeiten import QtZeiten
@@ -63,6 +64,9 @@ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main
self.i_kontaktdaten_pfad.textChanged.connect(self.__update_pfade)
self.i_zeitspanne_pfad.textChanged.connect(self.__update_pfade)
+ # Speichert alle termin_suchen Threads
+ self.such_threads = list()
+
# GUI anzeigen
self.show()
@@ -99,17 +103,45 @@ def zeitspanne_erstellen(self):
def __termin_suchen(self):
"""
- Startet den Prozess der terminsuche mit Impfterminservice.terminsuche
+ Startet den Prozess der terminsuche mit Impfterminservice.terminsuche in einem neuen Thread
+ Dieser wird in self.such_threads hinzugefügt.
+ Alle Threads sind deamon Thread (Sofort töten sobald der Bot beendet wird)
"""
kontaktdaten = self.__get_kontaktdaten()
zeitspanne = self.__get_zeitspanne()
+ terminsuche_thread = threading.Thread(target=self.__start_terminsuche, args=(kontaktdaten, zeitspanne), daemon=True)
+ terminsuche_thread.setName(kontaktdaten["code"])
+
+ try:
+
+ terminsuche_thread.start()
+ if not terminsuche_thread.is_alive():
+ raise RuntimeError(
+ f"Terminsuche wurde gestartet, lebt aber nicht mehr!\n\nTermin mit Code: {terminsuche_thread.getName()}\nBitte Daten Prüfen!"
+ )
+
+ except Exception as error:
+ QtWidgets.QMessageBox.critical(self, "Fehler - Suche nicht gestartet!", str(error))
+
+ else:
+ self.such_threads.append(terminsuche_thread)
+
+ def __start_terminsuche(self, kontaktdaten: dict, zeitspanne: dict):
+ """
+ Startet die Terminsuche. Dies nur mit einem Thread starten, da die GUI sonst hängt
+
+ Args:
+ kontaktdaten (dict): kontakdaten aus kontaktdaten.json
+ zeitspanne (dict): zeitspanne aus zeitspanne.json
+ """
+
kontakt = kontaktdaten["kontakt"]
code = kontaktdaten["code"]
plz_impfzentren = kontaktdaten["plz_impfzentren"]
- # TODO: starte es in einem extra thread, sonst hängt sich die GUI auf
+ # Startet das eigentliche suchen
ImpfterminService.terminsuche(code=code, plz_impfzentren=plz_impfzentren, kontakt=kontakt, zeitspanne=zeitspanne, PATH=PATH)
def __code_generieren(self):
diff --git a/tools/gui/uhrzeiten.ui b/tools/gui/uhrzeiten.ui
index 9c6887e5..02004d5f 100644
--- a/tools/gui/uhrzeiten.ui
+++ b/tools/gui/uhrzeiten.ui
@@ -194,7 +194,7 @@
-
- Termin fühestens ab:
+ Termin frühestens ab:
Qt::AlignCenter
From f525b038f05ff091edaa005990e270eeed607961 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Thu, 27 May 2021 18:30:16 +0200
Subject: [PATCH 11/25] "Tab-Order" angepasst
---
tools/gui/kontaktdaten.ui | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/tools/gui/kontaktdaten.ui b/tools/gui/kontaktdaten.ui
index 2141bd1b..f2627efa 100644
--- a/tools/gui/kontaktdaten.ui
+++ b/tools/gui/kontaktdaten.ui
@@ -101,7 +101,7 @@
-
- false
+ true
Bitte Wählen
@@ -124,11 +124,6 @@
Herr
- -
-
- ...
-
-
-
@@ -367,6 +362,19 @@
+
+ i_plz_impfzentren
+ i_code_impfzentren
+ i_anrede_combo_box
+ i_vorname
+ i_nachname
+ i_strasse
+ i_hausnummer
+ i_plz_wohnort
+ i_wohnort
+ i_telefon
+ i_mail
+
From d0b055b3f7ea3e5c7b3aee1409dde6fa242413a4 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Thu, 27 May 2021 19:43:52 +0200
Subject: [PATCH 12/25] =?UTF-8?q?Reset=20Button=20nun=20funktionsf=C3=A4hi?=
=?UTF-8?q?g?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
tools/gui/qtkontakt.py | 11 +++++++++--
tools/gui/qtzeiten.py | 32 +++++++++++++++++++++++++++-----
tools/gui/uhrzeiten.ui | 14 ++++++++++++++
3 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/tools/gui/qtkontakt.py b/tools/gui/qtkontakt.py
index a77f02fd..59cbdb67 100644
--- a/tools/gui/qtkontakt.py
+++ b/tools/gui/qtkontakt.py
@@ -28,11 +28,14 @@
# Cancel
# Reset
+### Layouts ###
+# kontakdaten_layout
+
PATH = os.path.dirname(os.path.realpath(__file__))
class QtKontakt(QtWidgets.QDialog):
- def __init__(self, standard_speicherpfad:str, pfad_fenster_layout=os.path.join(PATH, "kontaktdaten.ui")):
+ def __init__(self, standard_speicherpfad: str, pfad_fenster_layout=os.path.join(PATH, "kontaktdaten.ui")):
super().__init__()
self.standard_speicherpfad = standard_speicherpfad
@@ -156,7 +159,11 @@ def __reset(self):
Setzt alle Werte in der GUI zurück
"""
- pass
+ for widget in self.children():
+ if isinstance(widget, QtWidgets.QLineEdit):
+ widget.setText("")
+ elif isinstance(widget, QtWidgets.QComboBox):
+ widget.setCurrentText("Bitte Wählen")
# Zum schnellen einzeltesten
diff --git a/tools/gui/qtzeiten.py b/tools/gui/qtzeiten.py
index c0be3595..696bdaeb 100644
--- a/tools/gui/qtzeiten.py
+++ b/tools/gui/qtzeiten.py
@@ -1,7 +1,7 @@
import os
import json
from PyQt5 import QtWidgets, uic
-from PyQt5.QtCore import QTime, QDate ,QDateTime
+from PyQt5.QtCore import QTime, QDate, QDateTime
# Folgende Widgets stehen zur Verfügung:
@@ -29,6 +29,9 @@
# Cancel
# Reset
+### QFrame ###
+# tage_frame
+
PATH = os.path.dirname(os.path.realpath(__file__))
@@ -146,7 +149,7 @@ def __get_aktive_wochentage(self) -> list:
# Alle Checkboxen der GUI selektieren und durchgehen
# BUG: Wenn die reihenfolge im Layout geändert wird, stimmen die Wochentage nicht mehr 0 = Mo ... 6 = So
- checkboxes = self.i_mo_check_box.parent().findChildren(QtWidgets.QCheckBox)
+ checkboxes = self.tage_frame.findChildren(QtWidgets.QCheckBox)
for num, checkboxe in enumerate(checkboxes, 0):
if checkboxe.isChecked():
aktive_wochentage.append(num)
@@ -220,9 +223,28 @@ def __oeffne_file_dialog(self) -> str:
return dateipfad
- def __reset(self):
- #TODO: Reset
- pass
+ def __reset(self, widgets: list = None):
+ """
+ Setzt alle Werte in der GUI zurück
+ """
+
+ if widgets == None:
+ self.__reset(self.children())
+ return
+
+ for widget in widgets:
+ if isinstance(widget, QtWidgets.QCheckBox):
+ widget.setChecked(True)
+ elif isinstance(widget, QtWidgets.QDateEdit):
+ widget.setDate(QDateTime.currentDateTime().date())
+ elif isinstance(widget, QtWidgets.QTimeEdit):
+ if widget == self.i_start_time_qtime:
+ widget.setTime(QTime(0, 1))
+ else:
+ widget.setTime(QTime(23, 59))
+ elif isinstance(widget, QtWidgets.QFrame):
+ self.__reset(widget.children())
+
if __name__ == "__main__":
diff --git a/tools/gui/uhrzeiten.ui b/tools/gui/uhrzeiten.ui
index 02004d5f..b4d3bd53 100644
--- a/tools/gui/uhrzeiten.ui
+++ b/tools/gui/uhrzeiten.ui
@@ -395,6 +395,20 @@
+
+ i_mo_check_box
+ i_di_check_box
+ i_mi_check_box
+ i_do_check_box
+ i_fr_check_box
+ i_sa_check_box
+ i_so_check_box
+ i_start_datum_qdate
+ i_start_time_qtime
+ i_end_time_qtime
+ i_erster_termin_check_box
+ i_zweiter_termin_check_box
+
From 300d2cd1bc88235fa4a2140c1a5d7c100a0ec548 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Thu, 27 May 2021 20:29:39 +0200
Subject: [PATCH 13/25] Code ausgelagert
---
gui.py | 46 +++++++++++-----------------
tools/gui/__init__.py | 68 ++++++++++++++++++++++++++++++++++++++++++
tools/gui/qtkontakt.py | 33 +++-----------------
tools/gui/qtzeiten.py | 35 +++++-----------------
4 files changed, 96 insertions(+), 86 deletions(-)
create mode 100644 tools/gui/__init__.py
diff --git a/gui.py b/gui.py
index 921b3a9c..1227a155 100644
--- a/gui.py
+++ b/gui.py
@@ -6,6 +6,7 @@
import threading
from PyQt5 import QtWidgets, uic
+from tools.gui import *
from tools.gui.qtzeiten import QtZeiten
from tools.gui.qtkontakt import QtKontakt
from tools.its import ImpfterminService
@@ -47,8 +48,8 @@ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main
# Funktionen den Buttons zuweisen
self.b_termin_suchen.clicked.connect(self.__termin_suchen)
self.b_code_generieren.clicked.connect(self.__code_generieren)
- self.b_dateien_kontaktdaten.clicked.connect(lambda: self.__oeffne_file_dialog("kontaktdaten"))
- self.b_dateien_zeitspanne.clicked.connect(lambda: self.__oeffne_file_dialog("zeitspanne"))
+ self.b_dateien_kontaktdaten.clicked.connect(self.__update_kontaktdaten_pfad)
+ self.b_dateien_zeitspanne.clicked.connect(self.__update_zeitspanne_pfad)
self.b_neue_kontaktdaten.clicked.connect(self.kontaktdaten_erstellen)
self.b_neue_zeitspanne.clicked.connect(self.zeitspanne_erstellen)
@@ -61,8 +62,8 @@ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main
self.i_zeitspanne_pfad.setText(self.pfad_zeitspanne)
# Events für Eingabefelder
- self.i_kontaktdaten_pfad.textChanged.connect(self.__update_pfade)
- self.i_zeitspanne_pfad.textChanged.connect(self.__update_pfade)
+ self.i_kontaktdaten_pfad.textChanged.connect(self.__update_kontaktdaten_pfad)
+ self.i_zeitspanne_pfad.textChanged.connect(self.__update_zeitspanne_pfad)
# Speichert alle termin_suchen Threads
self.such_threads = list()
@@ -184,32 +185,19 @@ def __get_zeitspanne(self) -> dict:
return zeitspanne
- def __oeffne_file_dialog(self, datei: str):
- """
- Öffnet einen "File-Picker", der entsprechende Werte für die kontaktdaten / zeitspanne einliest
-
- Args:
- datei (str): Startpfad vom File-Picker
- """
-
- # Öffnet den "File-Picker" vom System um ein bereits existierende Datei auszuwählen
- datei_data = QtWidgets.QFileDialog.getOpenFileName(self, datei, os.path.join(PATH, "data"), "JSON Files (*.json)")
- dateipfad = datei_data[0] # (pfad, typ)
-
- if dateipfad:
- if datei == "kontaktdaten":
- self.i_kontaktdaten_pfad.setText(dateipfad)
- else:
- self.i_zeitspanne_pfad.setText(dateipfad)
-
- def __update_pfade(self):
- """
- Wird ein Pfad in der GUI verändert, so werden die entsprechende Attribute angepasst
- """
-
- self.pfad_kontaktdaten = self.i_kontaktdaten_pfad.text()
- self.pfad_zeitspanne = self.i_zeitspanne_pfad.text()
+ def __update_kontaktdaten_pfad(self):
+ try:
+ pfad = oeffne_file_dialog_select(self, "Kontakdaten", self.pfad_kontaktdaten)
+ self.pfad_kontaktdaten = pfad
+ except FileNotFoundError:
+ pass
+ def __update_zeitspanne_pfad(self):
+ try:
+ pfad = oeffne_file_dialog_select(self, "Zeitspanne", self.pfad_zeitspanne)
+ self.pfad_zeitspanne = pfad
+ except FileNotFoundError:
+ pass
def main():
"""
diff --git a/tools/gui/__init__.py b/tools/gui/__init__.py
new file mode 100644
index 00000000..a3da201f
--- /dev/null
+++ b/tools/gui/__init__.py
@@ -0,0 +1,68 @@
+import json
+from PyQt5 import QtWidgets
+
+
+def oeffne_file_dialog_save(parent_widged: QtWidgets.QWidget, titel: str, standard_speicherpfad: str, dateityp="JSON Files (*.json)") -> str:
+ """
+ Öffnet ein File Dialog, der entsprechend einen Pfad zurück gibt, wohin gespeichert werden soll
+
+ Args:
+ parent_widged (PyQt5.QtWidgets.QWidget):
+ titel (str): Titel des Dialogs
+ standard_speicherpfad (str): Pfad welcher direkt geöffnet wird als Vorschlag
+ dateityp (str, optional): selectedFilter example: "Images (*.png *.xpm *.jpg)". Defaults to "JSON Files (*.json)".
+
+ Raises:
+ FileNotFoundError: Wird geworfen, wenn der Dateipfad leer ist
+
+ Returns:
+ str: Vollständiger Pfad
+ """
+
+ datei_data = QtWidgets.QFileDialog.getSaveFileName(parent_widged, titel, standard_speicherpfad, dateityp)
+ dateipfad = datei_data[0] # (Pfad, Dateityp)
+
+ if not dateipfad:
+ raise FileNotFoundError
+
+ return dateipfad
+
+
+def oeffne_file_dialog_select(parent_widged: QtWidgets.QWidget, titel: str, standard_oeffnungspfad: str, dateityp="JSON Files (*.json)") -> str:
+ """
+ Öffnet einen File Dialog um eine existierende Datei auszuwählen
+
+ Args:
+ parent_widged (QtWidgets.QWidget): Parent QWidget an das der Dialog gehängt werden soll
+ titel (str): Titel des Dialogs
+ standard_oeffnungspfad (str): Pfad welcher direkt geöffnet wird als Vorschlag
+ dateityp (str, optional): selectedFilter example: "Images (*.png *.xpm *.jpg)". Defaults to "JSON Files (*.json)".
+
+ Raises:
+ FileNotFoundError: Wird geworfen, wenn der Dateipfad leer ist
+
+ Returns:
+ str: Vollständiger Pfad zur Datei
+ """
+
+ # Öffnet den "File-Picker" vom System um ein bereits existierende Datei auszuwählen
+ datei_data = QtWidgets.QFileDialog.getOpenFileName(parent_widged, titel, standard_oeffnungspfad, "JSON Files (*.json)")
+ dateipfad = datei_data[0] # (pfad, typ)
+
+ if not dateipfad:
+ raise FileNotFoundError
+
+ return dateipfad
+
+
+def speichern(speicherpfad: str, data: dict):
+ """
+ Speichert die Daten mittels json.dump an den entsprechenden Ort
+
+ Args:
+ speicherpfad (str): speicherort
+ data (dict): Speicherdaten
+ """
+
+ with open(speicherpfad, 'w', encoding='utf-8') as f:
+ json.dump(data, f, ensure_ascii=False, indent=4)
diff --git a/tools/gui/qtkontakt.py b/tools/gui/qtkontakt.py
index 59cbdb67..10016bb5 100644
--- a/tools/gui/qtkontakt.py
+++ b/tools/gui/qtkontakt.py
@@ -4,6 +4,7 @@
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QTime
+from tools.gui import *
# Folgende Widgets stehen zur Verfügung:
@@ -53,6 +54,7 @@ def bestaetigt(self):
try:
self.speicher_einstellungen()
+ QtWidgets.QMessageBox.information(self, "Gepseichert", "Daten erfolgreich gespeichert")
self.close()
except (TypeError, IOError, FileNotFoundError) as error:
QtWidgets.QMessageBox.critical(self, "Fehler beim Speichern!", "Bitte erneut versuchen!")
@@ -64,18 +66,10 @@ def speicher_einstellungen(self):
Speicherpfad wird vom User abgefragt
"""
- speicherpfad = self.__oeffne_file_dialog()
-
+ speicherpfad = oeffne_file_dialog_save(self, "Kontaktdaten", self.standard_speicherpfad)
data = self.__get_alle_werte()
- with open(speicherpfad, 'w', encoding='utf-8') as f:
- try:
- json.dump(data, f, ensure_ascii=False, indent=4)
- QtWidgets.QMessageBox.information(self, "Gepseichert", "Daten erfolgreich gespeichert")
-
- except (TypeError, IOError, FileNotFoundError) as error:
- QtWidgets.QMessageBox.critical(self, "Fehler!", "Daten konnten nicht gespeichert werden.")
- raise error
+ speichern(speicherpfad, data)
def __button_clicked(self, button):
"""
@@ -135,25 +129,6 @@ def __get_alle_werte(self) -> dict:
}
return kontaktdaten
- def __oeffne_file_dialog(self) -> str:
- """
- Öffnet einen File Dialog, der den Speicherort festlegt
-
- Raises:
- FileNotFoundError: Wird geworfen, wenn kein Pfad angegeben wurde
-
- Returns:
- str: speicherpfad
- """
-
- datei_data = QtWidgets.QFileDialog.getSaveFileName(self, "Kontaktdaten", self.standard_speicherpfad, "JSON Files (*.json)")
- dateipfad = datei_data[0] # (Pfad, Dateityp)
-
- if not dateipfad:
- raise FileNotFoundError
-
- return dateipfad
-
def __reset(self):
"""
Setzt alle Werte in der GUI zurück
diff --git a/tools/gui/qtzeiten.py b/tools/gui/qtzeiten.py
index 696bdaeb..beff8e13 100644
--- a/tools/gui/qtzeiten.py
+++ b/tools/gui/qtzeiten.py
@@ -3,6 +3,8 @@
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QTime, QDate, QDateTime
+from tools.gui import *
+
# Folgende Widgets stehen zur Verfügung:
### Checkboxes ###
@@ -70,9 +72,10 @@ def bestaetigt(self):
try:
self.speicher_einstellungen()
+ QtWidgets.QMessageBox.information(self, "Gepseichert", "Daten erfolgreich gespeichert")
self.close()
except ValueError as error:
- QtWidgets.QMessageBox.critical(self, "Ungültige Eingabe!", "Start-Uhrzeit ist später als End-Uhrzeit!")
+ QtWidgets.QMessageBox.critical(self, "Ungültige Eingabe!", str(error))
except (TypeError, IOError, FileNotFoundError) as error:
QtWidgets.QMessageBox.critical(self, "Fehler beim Speichern!", "Bitte erneut versuchen!")
@@ -82,17 +85,10 @@ def speicher_einstellungen(self):
Speicherpfad wird vom User abgefragt
"""
- speicherpfad = self.__oeffne_file_dialog()
+ speicherpfad = oeffne_file_dialog_save(self, "Zeitspanne", self.standard_speicherpfad)
data = self.__get_alle_werte()
- with open(speicherpfad, 'w', encoding='utf-8') as f:
- try:
- json.dump(data, f, ensure_ascii=False, indent=4)
- QtWidgets.QMessageBox.information(self, "Gepseichert", "Daten erfolgreich gespeichert")
-
- except (TypeError, IOError, FileNotFoundError) as error:
- QtWidgets.QMessageBox.critical(self, "Fehler!", "Daten konnten nicht gespeichert werden.")
- raise error
+ speichern(speicherpfad, data)
def __button_clicked(self, button):
"""
@@ -171,7 +167,7 @@ def __get_uhrzeiten(self) -> dict:
end_uhrzeit: QTime = self.i_end_time_qtime.time()
if start_uhrzeit >= end_uhrzeit:
- raise ValueError
+ raise ValueError("Start Uhrzeit is später als Enduhrzeit")
uhrzeiten = {
"startzeit": {
@@ -207,22 +203,6 @@ def __get_aktive_termine(self) -> list:
aktive_termine.append(2)
return aktive_termine
- def __oeffne_file_dialog(self) -> str:
- """
- Öffnet einen File Dialog, der den Speicherort festlegt
-
- Returns:
- str: Speicherpfad
- """
-
- datei_data = QtWidgets.QFileDialog.getSaveFileName(self, "Zeitspanne", self.standard_speicherpfad, "JSON Files (*.json)")
- dateipfad = datei_data[0] # (Pfad, Dateityp)
-
- if not dateipfad:
- raise FileNotFoundError
-
- return dateipfad
-
def __reset(self, widgets: list = None):
"""
Setzt alle Werte in der GUI zurück
@@ -244,7 +224,6 @@ def __reset(self, widgets: list = None):
widget.setTime(QTime(23, 59))
elif isinstance(widget, QtWidgets.QFrame):
self.__reset(widget.children())
-
if __name__ == "__main__":
From f7f515b1efa0b9f0ed8876c08ef1beb3e3f6fc6c Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Thu, 27 May 2021 22:03:51 +0200
Subject: [PATCH 14/25] verbesserte Datenabfrage
---
gui.py | 28 ++++++++++++-----
tools/gui/__init__.py | 69 ++++++++++++++++++++++++++++++++++++++++++
tools/gui/qtkontakt.py | 31 +++++++++++++++++--
3 files changed, 119 insertions(+), 9 deletions(-)
diff --git a/gui.py b/gui.py
index 1227a155..46f297cc 100644
--- a/gui.py
+++ b/gui.py
@@ -50,7 +50,7 @@ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main
self.b_code_generieren.clicked.connect(self.__code_generieren)
self.b_dateien_kontaktdaten.clicked.connect(self.__update_kontaktdaten_pfad)
self.b_dateien_zeitspanne.clicked.connect(self.__update_zeitspanne_pfad)
- self.b_neue_kontaktdaten.clicked.connect(self.kontaktdaten_erstellen)
+ self.b_neue_kontaktdaten.clicked.connect(lambda: self.kontaktdaten_erstellen(Modus.TERMIN_SUCHEN))
self.b_neue_zeitspanne.clicked.connect(self.zeitspanne_erstellen)
# Standard Pfade
@@ -84,12 +84,15 @@ def start_gui():
window = HauptGUI()
app.exec_()
- def kontaktdaten_erstellen(self):
+ def kontaktdaten_erstellen(self, modus: Modus = Modus.TERMIN_SUCHEN):
"""
Ruft den Dialog für die Kontaktdaten auf
+
+ Args:
+ modus (Modus): Abhängig vom Modus werden nicht alle Daten benötigt. Defalut TERMIN_SUCHEN
"""
- dialog = QtKontakt(self.pfad_kontaktdaten)
+ dialog = QtKontakt(modus, self.pfad_kontaktdaten)
dialog.show()
dialog.exec_()
@@ -109,9 +112,15 @@ def __termin_suchen(self):
Alle Threads sind deamon Thread (Sofort töten sobald der Bot beendet wird)
"""
- kontaktdaten = self.__get_kontaktdaten()
+ kontaktdaten = self.__get_kontaktdaten(Modus.TERMIN_SUCHEN)
zeitspanne = self.__get_zeitspanne()
+ try:
+ check_alle_kontakt_daten_da(Modus.TERMIN_SUCHEN, kontaktdaten)
+ except FehlendeDatenException as error:
+ QtWidgets.QMessageBox.critical(self, "Daten unvollständig!", f"Es fehlen Daten in der JSON Datei\n\n{error}")
+ return
+
terminsuche_thread = threading.Thread(target=self.__start_terminsuche, args=(kontaktdaten, zeitspanne), daemon=True)
terminsuche_thread.setName(kontaktdaten["code"])
@@ -151,18 +160,21 @@ def __code_generieren(self):
"""
# TODO: code generierung implementieren
- pass
+ QtWidgets.QMessageBox.information(self, "Noch nicht verfügbar", "Funktion nur über Konsole verfügbar")
- def __get_kontaktdaten(self) -> dict:
+ 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()
+ self.kontaktdaten_erstellen(modus)
with open(self.pfad_kontaktdaten, "r", encoding='utf-8') as f:
kontaktdaten = json.load(f)
@@ -183,6 +195,8 @@ def __get_zeitspanne(self) -> dict:
with open(self.pfad_zeitspanne, "r", encoding='utf-8') as f:
zeitspanne = json.load(f)
+ #TODO: Prüfen ob Daten vollständig
+
return zeitspanne
def __update_kontaktdaten_pfad(self):
diff --git a/tools/gui/__init__.py b/tools/gui/__init__.py
index a3da201f..3cebd0ea 100644
--- a/tools/gui/__init__.py
+++ b/tools/gui/__init__.py
@@ -1,7 +1,76 @@
import json
+from enum import Enum, auto
from PyQt5 import QtWidgets
+class Modus(Enum):
+ CODE_GENERIEREN = auto()
+ TERMIN_SUCHEN = auto()
+
+
+class FehlendeDatenException(Exception):
+ pass
+
+
+def check_alle_kontakt_daten_da(modus: Modus, data: dict):
+ """
+ Nur für Kontaktdaten!
+ Überprüft ob alle Key vorhanden sind und ob die Values kein leeren String enthalten
+
+ Args:
+ modus (Modus): Entsprechend werden Daten überprüft
+ data (dict): Inhalt der JSON
+
+ Raises:
+ FehlendeDatenException: Es wird ein Key oder Value vermisst
+ """
+
+ if modus == Modus.TERMIN_SUCHEN:
+ try:
+ # Daten vorhanden
+ data["plz_impfzentren"]
+ data["code"]
+ data["kontakt"]["anrede"]
+ data["kontakt"]["vorname"]
+ data["kontakt"]["nachname"]
+ data["kontakt"]["strasse"]
+ data["kontakt"]["hausnummer"]
+ data["kontakt"]["plz"]
+ data["kontakt"]["ort"]
+ data["kontakt"]["phone"]
+ data["kontakt"]["notificationChannel"]
+ data["kontakt"]["notificationReceiver"]
+
+ # Daten enthalten kein leerer String
+ # PLZ
+ for plz in data["plz_impfzentren"]:
+ if not plz.strip():
+ raise FehlendeDatenException("Wert fuer \"plz_impfzentren\" fehlerhaft!")
+ if not data["code"].strip():
+ raise FehlendeDatenException("Wert fuer \"code\" fehlt!")
+ # 2. Ebene
+ for key, value in data["kontakt"].items():
+ if not value.strip():
+ raise FehlendeDatenException(f"Wert fuer \"{key}\" fehlt!")
+ except KeyError as error:
+ raise FehlendeDatenException("Schluesselwort Fehlt!") from error
+
+ elif modus == Modus.CODE_GENERIEREN:
+ try:
+ # Daten vorhanden
+ data["plz_impfzentren"]
+ data["kontakt"]["phone"]
+ data["kontakt"]["notificationChannel"]
+ data["kontakt"]["notificationReceiver"]
+
+ # Daten enthalten kein leerer String
+ for key, values in data.items():
+ if values.strip() == "":
+ raise FehlendeDatenException(f"Wert fuer \"{key}\" fehlt!")
+ except KeyError as error:
+ raise FehlendeDatenException("Schluesselwort Fehlt!") from error
+
+
def oeffne_file_dialog_save(parent_widged: QtWidgets.QWidget, titel: str, standard_speicherpfad: str, dateityp="JSON Files (*.json)") -> str:
"""
Öffnet ein File Dialog, der entsprechend einen Pfad zurück gibt, wohin gespeichert werden soll
diff --git a/tools/gui/qtkontakt.py b/tools/gui/qtkontakt.py
index 10016bb5..c2c7be50 100644
--- a/tools/gui/qtkontakt.py
+++ b/tools/gui/qtkontakt.py
@@ -36,17 +36,29 @@
class QtKontakt(QtWidgets.QDialog):
- def __init__(self, standard_speicherpfad: str, pfad_fenster_layout=os.path.join(PATH, "kontaktdaten.ui")):
+ def __init__(self, modus: Modus, standard_speicherpfad: str, pfad_fenster_layout=os.path.join(PATH, "kontaktdaten.ui")):
super().__init__()
self.standard_speicherpfad = standard_speicherpfad
# Laden der .ui Datei
uic.loadUi(pfad_fenster_layout, self)
+ self.setup(modus)
# Funktionen für Buttonbox zuweisen
self.buttonBox.clicked.connect(self.__button_clicked)
+ def setup(self, modus: Modus):
+ if modus == Modus.TERMIN_SUCHEN:
+ # Default - Alle Felder aktiv
+ pass
+ elif modus == Modus.CODE_GENERIEREN:
+ # Benötig wird: PLZ's der Impfzentren, Telefonnummer, Mail
+ # Alles andere wird daher deaktiviert
+ self.readonly_alle_line_edits(("i_plz_impfzentren", "i_telefon", "i_mail"))
+ else:
+ raise RuntimeError("Modus ungueltig!")
+
def bestaetigt(self):
"""
Versucht die Daten zu speichern und schließt sich anschließend selbst
@@ -58,7 +70,6 @@ def bestaetigt(self):
self.close()
except (TypeError, IOError, FileNotFoundError) as error:
QtWidgets.QMessageBox.critical(self, "Fehler beim Speichern!", "Bitte erneut versuchen!")
- print(error)
def speicher_einstellungen(self):
"""
@@ -129,6 +140,22 @@ def __get_alle_werte(self) -> dict:
}
return kontaktdaten
+ def readonly_alle_line_edits(self, ausgeschlossen: list):
+ """
+ Setzt alle QLineEdit auf "read only", ausgeschlossen der Widgets in ausgeschlossen.
+ Setzt zudem den PlacholderText auf "Daten werden nicht benötigt"
+
+ Args:
+ ausgeschlossen (list): Liste mit den ObjectNamen der Widgets die ausgeschlossen werden sollen
+ """
+
+ line_edits = self.findChildren(QtWidgets.QLineEdit)
+
+ for line_edit in line_edits:
+ if line_edit.objectName() not in ausgeschlossen:
+ line_edit.setReadOnly(True)
+ line_edit.setPlaceholderText("Daten werden nicht benötigt")
+
def __reset(self):
"""
Setzt alle Werte in der GUI zurück
From 6e63aa49911d0e0b0970352d68c3c178be1bfc8d Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Thu, 27 May 2021 23:30:57 +0200
Subject: [PATCH 15/25] Terminsuche in Threads und Managebar
---
gui.py | 100 ++++++++++++++++++++++++++++++++++++----------
tools/gui/main.ui | 59 +++++++++++++++++----------
2 files changed, 117 insertions(+), 42 deletions(-)
diff --git a/gui.py b/gui.py
index 46f297cc..fd855f4e 100644
--- a/gui.py
+++ b/gui.py
@@ -3,7 +3,9 @@
import sys
import os
import json
+import time
import threading
+import multiprocessing
from PyQt5 import QtWidgets, uic
from tools.gui import *
@@ -30,6 +32,9 @@ class HauptGUI(QtWidgets.QMainWindow):
# b_neue_kontaktdaten
# b_neue_zeitspanne
+ ### Layouts ###
+ # prozesse_layout
+
# TODO: Ausgabe der cmd in der GUI wiederspiegelen - wenn sowas überhaupt geht
def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main.ui")):
"""
@@ -65,8 +70,12 @@ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main
self.i_kontaktdaten_pfad.textChanged.connect(self.__update_kontaktdaten_pfad)
self.i_zeitspanne_pfad.textChanged.connect(self.__update_zeitspanne_pfad)
- # Speichert alle termin_suchen Threads
- self.such_threads = list()
+ # Speichert alle termin_suchen Prozesse
+ self.such_prozesse = list()
+
+ # Überwachnung der Prozesse
+ self.prozess_bewacher = threading.Thread(target=self.__check_status_der_prozesse, daemon=True)
+ self.prozess_bewacher.start()
# GUI anzeigen
self.show()
@@ -121,22 +130,7 @@ def __termin_suchen(self):
QtWidgets.QMessageBox.critical(self, "Daten unvollständig!", f"Es fehlen Daten in der JSON Datei\n\n{error}")
return
- terminsuche_thread = threading.Thread(target=self.__start_terminsuche, args=(kontaktdaten, zeitspanne), daemon=True)
- terminsuche_thread.setName(kontaktdaten["code"])
-
- try:
-
- terminsuche_thread.start()
- if not terminsuche_thread.is_alive():
- raise RuntimeError(
- f"Terminsuche wurde gestartet, lebt aber nicht mehr!\n\nTermin mit Code: {terminsuche_thread.getName()}\nBitte Daten Prüfen!"
- )
-
- except Exception as error:
- QtWidgets.QMessageBox.critical(self, "Fehler - Suche nicht gestartet!", str(error))
-
- else:
- self.such_threads.append(terminsuche_thread)
+ self.__start_terminsuche(kontaktdaten, zeitspanne)
def __start_terminsuche(self, kontaktdaten: dict, zeitspanne: dict):
"""
@@ -151,8 +145,26 @@ def __start_terminsuche(self, kontaktdaten: dict, zeitspanne: dict):
code = kontaktdaten["code"]
plz_impfzentren = kontaktdaten["plz_impfzentren"]
- # Startet das eigentliche suchen
- ImpfterminService.terminsuche(code=code, plz_impfzentren=plz_impfzentren, kontakt=kontakt, zeitspanne=zeitspanne, PATH=PATH)
+ terminsuche_prozess = multiprocessing.Process(target=ImpfterminService.terminsuche, name=f"{code}-{len(self.such_prozesse)}", daemon=True, kwargs={
+ "code": code,
+ "plz_impfzentren": plz_impfzentren,
+ "kontakt": kontakt,
+ "zeitspanne": zeitspanne,
+ "PATH": PATH})
+ try:
+ terminsuche_prozess.start()
+ if not terminsuche_prozess.is_alive():
+ raise RuntimeError(
+ f"Terminsuche wurde gestartet, lebt aber nicht mehr!\n\nTermin mit Code: {terminsuche_prozess.getName()}\nBitte Daten Prüfen!"
+ )
+
+ except Exception as error:
+ QtWidgets.QMessageBox.critical(self, "Fehler - Suche nicht gestartet!", str(error))
+
+ else:
+ QtWidgets.QMessageBox.information(self, "Suche gestartet", "Terminsuche wurde gestartet!\nWeitere Infos in der Konsole")
+ self.such_prozesse.append(terminsuche_prozess)
+ self.__add_prozess_in_gui(terminsuche_prozess)
def __code_generieren(self):
"""
@@ -195,7 +207,7 @@ def __get_zeitspanne(self) -> dict:
with open(self.pfad_zeitspanne, "r", encoding='utf-8') as f:
zeitspanne = json.load(f)
- #TODO: Prüfen ob Daten vollständig
+ # TODO: Prüfen ob Daten vollständig
return zeitspanne
@@ -213,6 +225,52 @@ def __update_zeitspanne_pfad(self):
except FileNotFoundError:
pass
+ def __add_prozess_in_gui(self, prozess: multiprocessing.Process):
+ """
+ Die Prozesse werden in der GUI in dem prozesse_layout angezeigt
+ """
+ # addRow(label, field)
+ label = QtWidgets.QLabel(f"Prozess: {prozess.name}")
+ button = QtWidgets.QPushButton("Stoppen")
+ button.setObjectName(prozess.name)
+ button.clicked.connect(lambda: self.__stop_prozess(prozess))
+
+ self.prozesse_layout.addRow(label, button)
+
+ def __stop_prozess(self, prozess: multiprocessing.Process):
+ """
+ Stopped den übergebenen Prozess und löscht diesen aus der GUI
+
+ Args:
+ prozess (multiprocessing.Process): Prozess welcher getötet werden soll
+ """
+ prozess.kill()
+ self.such_prozesse.remove(prozess)
+
+ def __remove_prozess_von_gui(self, prozess: multiprocessing.Process):
+ """
+ Entfernt die Anzeige des Prozesses aus der GUI
+
+ Args:
+ prozess (multiprocessing.Process): Prozess welcher entfernt werden soll
+ warnung (bool, optional): Warnung an den User ausgeben, dass der Prozess weg ist. Defaults to False.
+ """
+
+ button = self.findChild(QtWidgets.QPushButton, prozess.name)
+ self.prozesse_layout.removeRow(button)
+
+ def __check_status_der_prozesse(self):
+ """
+ Wird von einem Thread dauerhaft durchlaufen um zu prüfen ob ein Prozess sich beendet hat
+ """
+
+ while True:
+ for prozess in self.such_prozesse:
+ if not prozess.is_alive():
+ self.__remove_prozess_von_gui(prozess)
+ time.sleep(5)
+
+
def main():
"""
Startet die GUI-Anwendung
diff --git a/tools/gui/main.ui b/tools/gui/main.ui
index d0e55428..6986bd25 100644
--- a/tools/gui/main.ui
+++ b/tools/gui/main.ui
@@ -29,20 +29,7 @@
6
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
+
-
Termin suchen
@@ -58,6 +45,19 @@
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
-
@@ -76,13 +76,6 @@ für den Corona Impfterminservice
- -
-
-
- Impf-Code generieren
-
-
-
-
@@ -90,6 +83,13 @@ für den Corona Impfterminservice
+ -
+
+
+ Impf-Code generieren
+
+
+
-
@@ -171,6 +171,23 @@ für den Corona Impfterminservice
+ -
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
From 711b0b674e3fae8264b7534bf75ce386bf9bacf6 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Fri, 28 May 2021 21:59:42 +0200
Subject: [PATCH 16/25] Terminsuche implementiert
---
gui.py | 26 ++---
tools/gui/__init__.py | 3 +-
tools/gui/main.ui | 44 ++++----
tools/gui/qtterminsuche.py | 199 +++++++++++++++++++++++++++++++++++++
tools/gui/terminsuche.ui | 147 +++++++++++++++++++++++++++
5 files changed, 383 insertions(+), 36 deletions(-)
create mode 100644 tools/gui/qtterminsuche.py
create mode 100644 tools/gui/terminsuche.ui
diff --git a/gui.py b/gui.py
index fd855f4e..296314bf 100644
--- a/gui.py
+++ b/gui.py
@@ -11,6 +11,7 @@
from tools.gui import *
from tools.gui.qtzeiten import QtZeiten
from tools.gui.qtkontakt import QtKontakt
+from tools.gui.qtterminsuche import QtTerminsuche
from tools.its import ImpfterminService
PATH = os.path.dirname(os.path.realpath(__file__))
@@ -71,7 +72,8 @@ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main
self.i_zeitspanne_pfad.textChanged.connect(self.__update_zeitspanne_pfad)
# Speichert alle termin_suchen Prozesse
- self.such_prozesse = list()
+ self.such_prozesse = list(list())
+ self.prozesse_counter = 0
# Überwachnung der Prozesse
self.prozess_bewacher = threading.Thread(target=self.__check_status_der_prozesse, daemon=True)
@@ -141,16 +143,11 @@ def __start_terminsuche(self, kontaktdaten: dict, zeitspanne: dict):
zeitspanne (dict): zeitspanne aus zeitspanne.json
"""
- kontakt = kontaktdaten["kontakt"]
code = kontaktdaten["code"]
- plz_impfzentren = kontaktdaten["plz_impfzentren"]
-
- terminsuche_prozess = multiprocessing.Process(target=ImpfterminService.terminsuche, name=f"{code}-{len(self.such_prozesse)}", daemon=True, kwargs={
- "code": code,
- "plz_impfzentren": plz_impfzentren,
- "kontakt": kontakt,
+ terminsuche_prozess = multiprocessing.Process(target=QtTerminsuche.start_suche, name=f"{code}-{self.prozesse_counter}", daemon=True, kwargs={
+ "kontaktdaten": kontaktdaten,
"zeitspanne": zeitspanne,
- "PATH": PATH})
+ "ROOT_PATH": PATH})
try:
terminsuche_prozess.start()
if not terminsuche_prozess.is_alive():
@@ -162,9 +159,10 @@ def __start_terminsuche(self, kontaktdaten: dict, zeitspanne: dict):
QtWidgets.QMessageBox.critical(self, "Fehler - Suche nicht gestartet!", str(error))
else:
- QtWidgets.QMessageBox.information(self, "Suche gestartet", "Terminsuche wurde gestartet!\nWeitere Infos in der Konsole")
+ # QtWidgets.QMessageBox.information(self, "Suche gestartet", "Terminsuche wurde gestartet!\nWeitere Infos in der Konsole")
self.such_prozesse.append(terminsuche_prozess)
self.__add_prozess_in_gui(terminsuche_prozess)
+ self.prozesse_counter += 1
def __code_generieren(self):
"""
@@ -172,7 +170,7 @@ def __code_generieren(self):
"""
# TODO: code generierung implementieren
- QtWidgets.QMessageBox.information(self, "Noch nicht verfügbar", "Funktion nur über Konsole verfügbar")
+ QtWidgets.QMessageBox.information(self, "Noch nicht verfügbar", "Funktion nur über Konsolenanwendung verfügbar")
def __get_kontaktdaten(self, modus: Modus) -> dict:
"""
@@ -246,6 +244,7 @@ def __stop_prozess(self, prozess: multiprocessing.Process):
"""
prozess.kill()
self.such_prozesse.remove(prozess)
+ self.__remove_prozess_von_gui(prozess)
def __remove_prozess_von_gui(self, prozess: multiprocessing.Process):
"""
@@ -268,14 +267,15 @@ def __check_status_der_prozesse(self):
for prozess in self.such_prozesse:
if not prozess.is_alive():
self.__remove_prozess_von_gui(prozess)
- time.sleep(5)
+ self.such_prozesse.remove(prozess)
+ time.sleep(2)
def main():
"""
Startet die GUI-Anwendung
"""
-
+ multiprocessing.freeze_support()
HauptGUI.start_gui()
diff --git a/tools/gui/__init__.py b/tools/gui/__init__.py
index 3cebd0ea..573a5a1b 100644
--- a/tools/gui/__init__.py
+++ b/tools/gui/__init__.py
@@ -1,6 +1,7 @@
import json
from enum import Enum, auto
-from PyQt5 import QtWidgets
+from PyQt5 import QtWidgets, uic
+from PyQt5.QtWidgets import QMessageBox
class Modus(Enum):
diff --git a/tools/gui/main.ui b/tools/gui/main.ui
index 6986bd25..206894c8 100644
--- a/tools/gui/main.ui
+++ b/tools/gui/main.ui
@@ -29,7 +29,21 @@
6
- -
+
-
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Laufende Prozesse:
+
+
+
+ -
Termin suchen
@@ -45,7 +59,7 @@
- -
+
-
Qt::Vertical
@@ -76,27 +90,13 @@ für den Corona Impfterminservice
- -
-
-
- Qt::Horizontal
-
-
-
- -
+
-
Impf-Code generieren
- -
-
-
- Qt::Horizontal
-
-
-
-
-
@@ -171,18 +171,18 @@ für den Corona Impfterminservice
- -
+
-
- -
-
+
-
+
Qt::Horizontal
- -
-
+
-
+
Qt::Horizontal
diff --git a/tools/gui/qtterminsuche.py b/tools/gui/qtterminsuche.py
new file mode 100644
index 00000000..c7d7d475
--- /dev/null
+++ b/tools/gui/qtterminsuche.py
@@ -0,0 +1,199 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+import json
+import time
+import ctypes
+import threading
+import multiprocessing
+
+from io import StringIO
+
+from PyQt5 import QtWidgets, uic, QtCore, QtGui
+from PyQt5.QtCore import QObject, QThread, pyqtSignal
+from tools.gui import *
+from tools.its import ImpfterminService
+
+PATH = os.path.dirname(os.path.realpath(__file__))
+
+
+class EigenerStream(QtCore.QObject):
+ """
+ Klasse wenn auf write() zugegriffen wird, dann wird das Siganl textWritten ausgelöst
+ """
+
+ # Signal welches ausgelöst werden kann
+ text_schreiben = pyqtSignal(str)
+
+ def write(self, stream):
+ """
+ Löst das Signal text_schreiben aus und übergibt das Argumet text weiter
+ """
+ self.text_schreiben.emit(str(stream))
+
+
+class Worker(QObject):
+ """
+ Worker, der nichts anderes macht, als den Termin mithilfe its.py zu suchen
+ sobald die Suche beendet wurde, wird ein "fertig" Signal geworfen, welches den Rückgabewert von its übergibt
+ """
+
+ # Signal wenn suche abgeschlossen
+ fertig = pyqtSignal(bool)
+
+ def __init__(self, kontaktdaten: dict, zeitspanne: dict, ROOT_PATH: str):
+ """
+ Args:
+ kontaktdaten (dict): kontakdaten aus kontaktdaten.json
+ zeitspanne (dict): zeitspanne aus zeitspanne.json
+ ROOT_PATH (str): Pfad zur main.py / gui.py
+ """
+ super().__init__()
+
+ self.kontaktdaten = kontaktdaten
+ self.zeitspanne = zeitspanne
+ self.ROOT_PATH = ROOT_PATH
+
+ def suchen(self):
+ """
+ Startet die Terminsuche. Dies nur mit einem Thread starten, da die GUI sonst hängt
+ """
+
+ kontakt = self.kontaktdaten["kontakt"]
+ code = self.kontaktdaten["code"]
+ plz_impfzentren = self.kontaktdaten["plz_impfzentren"]
+
+ erfolgreich = ImpfterminService.terminsuche(code=code, plz_impfzentren=plz_impfzentren, kontakt=kontakt,
+ PATH=self.ROOT_PATH, zeitspanne=self.zeitspanne)
+
+ self.fertig.emit(erfolgreich)
+
+
+class QtTerminsuche(QtWidgets.QMainWindow):
+
+ # Folgende Widgets stehen zur Verfügung:
+
+ ### QLabel ###
+ # code_label
+ # vorname_label
+ # nachname_label
+
+ ### ButtonBox ###
+ # buttonBox
+ # Close
+
+ ### QTextEdit (readonly) ###
+ # console_text_edit
+
+ def __init__(self, kontaktdaten: dict, zeitspanne: dict, ROOT_PATH: str, pfad_fenster_layout=os.path.join(PATH, "terminsuche.ui")):
+
+ super().__init__()
+
+ # Laden der .ui Datei und Anpassungen
+ uic.loadUi(pfad_fenster_layout, self)
+
+ # Attribute erstellen
+ self.erfolgreich: bool = None
+ self.kontaktdaten = kontaktdaten
+ self.zeitspanne = zeitspanne
+ self.ROOT_PATH = ROOT_PATH
+
+ # std.out & error umleiten auf das Textfeld
+ sys.stdout = EigenerStream(text_schreiben=self.update_ausgabe)
+ sys.stderr = EigenerStream(text_schreiben=self.update_ausgabe)
+
+ # Entsprechend Konfigurieren
+ self.setup_thread()
+
+ # Infos setzten
+ self.setup_infos()
+
+ # GUI anzeigen
+ self.show()
+
+ # Terminsuche starten
+ self.thread.start()
+
+
+ @staticmethod
+ def start_suche(kontaktdaten: dict, zeitspanne: dict, ROOT_PATH: str):
+ """
+ Startet die Suche in einem eigenen Fenster mit umlenkung der Konsolenausgabe in das Fenster
+
+ Args:
+ kontaktdaten (dict): kontaktdaten aus JSON
+ zeitspanne (dict): zeitspanne aus JSON
+ ROOT_PATH (str): Pfad zum Root Ordner, damit dieser an its übergeben werden kann
+ """
+ app = QtWidgets.QApplication(list())
+ window = QtTerminsuche(kontaktdaten, zeitspanne, ROOT_PATH)
+ app.exec_()
+
+ def setup_infos(self):
+ self.code_label.setText(self.kontaktdaten["code"])
+ self.vorname_label.setText(self.kontaktdaten["kontakt"]["vorname"])
+ self.nachname_label.setText(self.kontaktdaten["kontakt"]["nachname"])
+
+ def setup_thread(self):
+ """
+ Thread + Worker erstellen und Konfigurieren
+ """
+
+ self.thread = QThread(parent=self)
+ self.worker = Worker(self.kontaktdaten, self.zeitspanne, self.ROOT_PATH)
+
+ # Worker und Thread verbinden
+ self.worker.moveToThread(self.thread)
+
+ # Signale setzten
+ self.worker.fertig.connect(self.suche_beendet)
+ self.worker.fertig.connect(self.thread.quit)
+ self.worker.fertig.connect(self.worker.deleteLater)
+
+ self.thread.started.connect(self.worker.suchen)
+ self.thread.finished.connect(self.thread.deleteLater)
+
+ def update_ausgabe(self, text):
+ """
+ Fügt den übergeben Text dem console_text_edit hinzu
+
+ Args:
+ text (str): Text welcher hinzukommen soll
+ """
+
+ cursor = self.console_text_edit.textCursor()
+ cursor.movePosition(QtGui.QTextCursor.End)
+ cursor.insertText(str(text))
+ self.console_text_edit.setTextCursor(cursor)
+ self.console_text_edit.ensureCursorVisible()
+
+ def suche_beendet(self, erfolgreich: bool):
+ """
+ Wird aufgerufen, sobald die Suche vom Worker beendet wurde
+
+ Args:
+ erfolgreich (bool): Bei erfolgreichen Beenden Hinweis ausgeben
+ """
+
+ if erfolgreich:
+ QtWidgets.QMessageBox.information(self, "Termin gefunden!", "Die Suche wird beendet!\nVorher Ausgabe prüfen!")
+
+ def closeEvent(self, event):
+ """
+ Wird aufgerufen, wenn die Anwendung geschlossen wird
+
+ Args:
+ event: Schließen Event von QT
+ """
+
+ if self.thread.isRunning():
+ self.thread.quit()
+
+ if self.erfolgreich == None:
+ QtWidgets.QMessageBox.warning(self, "Suche beenden", "Die Suche wird beendet!\nVorher Ausgabe Prüfen!")
+
+ # Streams wieder korrigieren, damit kein Fehler kommt
+ sys.stdout = sys.__stdout__
+ sys.stderr = sys.__stderr__
+ super().closeEvent(event)
diff --git a/tools/gui/terminsuche.ui b/tools/gui/terminsuche.ui
new file mode 100644
index 00000000..ecadccf6
--- /dev/null
+++ b/tools/gui/terminsuche.ui
@@ -0,0 +1,147 @@
+
+
+ terminsuche_window
+
+
+
+ 0
+ 0
+ 616
+ 489
+
+
+
+ vaccipy - Terminuche
+
+
+
+
-
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ QDialogButtonBox::Close
+
+
+
+ -
+
+
+
+ 14
+
+
+
+ Terminsuche
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+
+ 12
+
+
+
+ Code:
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ XXXX-XXXX-XXXX
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ Vorname:
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ Max
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ Nachname:
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ Mustermann
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+
+
+
+
+
From 17108e631c27941c2afdd3abca45803d6af752a9 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Fri, 28 May 2021 22:25:40 +0200
Subject: [PATCH 17/25] Fehlerbeseitigung
---
gui.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/gui.py b/gui.py
index 296314bf..dd7fd360 100644
--- a/gui.py
+++ b/gui.py
@@ -123,11 +123,15 @@ def __termin_suchen(self):
Alle Threads sind deamon Thread (Sofort töten sobald der Bot beendet wird)
"""
- kontaktdaten = self.__get_kontaktdaten(Modus.TERMIN_SUCHEN)
- zeitspanne = self.__get_zeitspanne()
-
try:
+ kontaktdaten = self.__get_kontaktdaten(Modus.TERMIN_SUCHEN)
+ zeitspanne = self.__get_zeitspanne()
+
check_alle_kontakt_daten_da(Modus.TERMIN_SUCHEN, kontaktdaten)
+
+ except FileNotFoundError as error:
+ QtWidgets.QMessageBox.critical(self, "Datei nicht gefunden!", f"Datei zum Laden konnte nicht gefunden werden\n\nBitte erstellen")
+ return
except FehlendeDatenException as error:
QtWidgets.QMessageBox.critical(self, "Daten unvollständig!", f"Es fehlen Daten in der JSON Datei\n\n{error}")
return
From 9458bc76cb4d17354e8d5726da7c72de157c8680 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Fri, 28 May 2021 22:28:57 +0200
Subject: [PATCH 18/25] init commit
---
specs/windows-terminservice-gui.spec | 38 ++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 specs/windows-terminservice-gui.spec
diff --git a/specs/windows-terminservice-gui.spec b/specs/windows-terminservice-gui.spec
new file mode 100644
index 00000000..f7c4d69d
--- /dev/null
+++ b/specs/windows-terminservice-gui.spec
@@ -0,0 +1,38 @@
+# -*- mode: python ; coding: utf-8 -*-
+
+
+block_cipher = None
+
+
+a = Analysis(['..\\gui.py'],
+ pathex=['specs//'],
+ binaries=[('..\\tools\\chromedriver\\chromedriver-windows.exe', 'tools\\chromedriver\\'), ('..\\tools\\gui\\kontaktdaten.ui', 'tools\\gui\\'), ('..\\tools\\gui\\main.ui', 'tools\\gui\\'), ('..\\tools\\gui\\terminsuche.ui', 'tools\\gui\\'), ('..\\tools\\gui\\uhrzeiten.ui', 'tools\\gui\\'), ('..\\images\\spritze.ico', 'images\\')],
+ datas=[('../tools/cloudscraper', './cloudscraper/')],
+ hiddenimports=['plyer.platforms.win.notification', 'cloudscraper'],
+ hookspath=[],
+ runtime_hooks=[],
+ excludes=[],
+ win_no_prefer_redirects=False,
+ win_private_assemblies=False,
+ cipher=block_cipher,
+ noarchive=False)
+pyz = PYZ(a.pure, a.zipped_data,
+ cipher=block_cipher)
+exe = EXE(pyz,
+ a.scripts,
+ [],
+ exclude_binaries=True,
+ name='windows-terminservice-gui',
+ debug=False,
+ bootloader_ignore_signals=False,
+ strip=False,
+ upx=True,
+ console=True , icon='..\\images\\spritze.ico')
+coll = COLLECT(exe,
+ a.binaries,
+ a.zipfiles,
+ a.datas,
+ strip=False,
+ upx=True,
+ upx_exclude=[],
+ name='windows-terminservice-gui')
From eb41ea2e0d235846b0d8efc201a24cb1729173f4 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Fri, 28 May 2021 22:49:33 +0200
Subject: [PATCH 19/25] added icon
---
gui.py | 6 ++++--
specs/windows-terminservice-gui.spec | 2 +-
tools/gui/qtkontakt.py | 4 +++-
tools/gui/qtterminsuche.py | 5 ++---
tools/gui/qtzeiten.py | 4 +++-
5 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/gui.py b/gui.py
index dd7fd360..353a3f97 100644
--- a/gui.py
+++ b/gui.py
@@ -8,6 +8,7 @@
import multiprocessing
from PyQt5 import QtWidgets, uic
+from PyQt5.QtGui import QIcon
from tools.gui import *
from tools.gui.qtzeiten import QtZeiten
from tools.gui.qtkontakt import QtKontakt
@@ -50,6 +51,7 @@ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main
# Laden der .ui Datei und Anpassungen
uic.loadUi(pfad_fenster_layout, self)
+ self.setWindowIcon(QIcon(os.path.join(PATH, "images/spritze.ico")))
# Funktionen den Buttons zuweisen
self.b_termin_suchen.clicked.connect(self.__termin_suchen)
@@ -103,7 +105,7 @@ def kontaktdaten_erstellen(self, modus: Modus = Modus.TERMIN_SUCHEN):
modus (Modus): Abhängig vom Modus werden nicht alle Daten benötigt. Defalut TERMIN_SUCHEN
"""
- dialog = QtKontakt(modus, self.pfad_kontaktdaten)
+ dialog = QtKontakt(modus, self.pfad_kontaktdaten, PATH)
dialog.show()
dialog.exec_()
@@ -112,7 +114,7 @@ def zeitspanne_erstellen(self):
Ruft den Dialog für die Zeitspanne auf
"""
- dialog = QtZeiten(self.pfad_zeitspanne)
+ dialog = QtZeiten(self.pfad_zeitspanne, PATH)
dialog.show()
dialog.exec_()
diff --git a/specs/windows-terminservice-gui.spec b/specs/windows-terminservice-gui.spec
index f7c4d69d..219c990b 100644
--- a/specs/windows-terminservice-gui.spec
+++ b/specs/windows-terminservice-gui.spec
@@ -27,7 +27,7 @@ exe = EXE(pyz,
bootloader_ignore_signals=False,
strip=False,
upx=True,
- console=True , icon='..\\images\\spritze.ico')
+ console=False , icon='..\\images\\spritze.ico')
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
diff --git a/tools/gui/qtkontakt.py b/tools/gui/qtkontakt.py
index c2c7be50..8f163b82 100644
--- a/tools/gui/qtkontakt.py
+++ b/tools/gui/qtkontakt.py
@@ -3,6 +3,7 @@
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QTime
+from PyQt5.QtGui import QIcon
from tools.gui import *
@@ -36,13 +37,14 @@
class QtKontakt(QtWidgets.QDialog):
- def __init__(self, modus: Modus, standard_speicherpfad: str, pfad_fenster_layout=os.path.join(PATH, "kontaktdaten.ui")):
+ def __init__(self, modus: Modus, standard_speicherpfad: str, ROOT_PATH: str, pfad_fenster_layout=os.path.join(PATH, "kontaktdaten.ui")):
super().__init__()
self.standard_speicherpfad = standard_speicherpfad
# Laden der .ui Datei
uic.loadUi(pfad_fenster_layout, self)
+ self.setWindowIcon(QIcon(os.path.join(ROOT_PATH, "images/spritze.ico")))
self.setup(modus)
# Funktionen für Buttonbox zuweisen
diff --git a/tools/gui/qtterminsuche.py b/tools/gui/qtterminsuche.py
index c7d7d475..4088a5b1 100644
--- a/tools/gui/qtterminsuche.py
+++ b/tools/gui/qtterminsuche.py
@@ -4,14 +4,12 @@
import os
import json
import time
-import ctypes
-import threading
-import multiprocessing
from io import StringIO
from PyQt5 import QtWidgets, uic, QtCore, QtGui
from PyQt5.QtCore import QObject, QThread, pyqtSignal
+from PyQt5.QtGui import QIcon
from tools.gui import *
from tools.its import ImpfterminService
@@ -92,6 +90,7 @@ def __init__(self, kontaktdaten: dict, zeitspanne: dict, ROOT_PATH: str, pfad_fe
# Laden der .ui Datei und Anpassungen
uic.loadUi(pfad_fenster_layout, self)
+ self.setWindowIcon(QIcon(os.path.join(ROOT_PATH, "images/spritze.ico")))
# Attribute erstellen
self.erfolgreich: bool = None
diff --git a/tools/gui/qtzeiten.py b/tools/gui/qtzeiten.py
index beff8e13..1c9b6e90 100644
--- a/tools/gui/qtzeiten.py
+++ b/tools/gui/qtzeiten.py
@@ -2,6 +2,7 @@
import json
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QTime, QDate, QDateTime
+from PyQt5.QtGui import QIcon
from tools.gui import *
@@ -43,7 +44,7 @@ class QtZeiten(QtWidgets.QDialog):
Diese erbt von QtWidgets.QDialog
"""
- def __init__(self, standard_speicherpfad: str, pfad_fenster_layout=os.path.join(PATH, "uhrzeiten.ui")):
+ def __init__(self, standard_speicherpfad: str, ROOT_PATH: str, pfad_fenster_layout=os.path.join(PATH, "uhrzeiten.ui")):
"""
Eingabe der Zeitkonfigurationen
@@ -60,6 +61,7 @@ def __init__(self, standard_speicherpfad: str, pfad_fenster_layout=os.path.join(
# Laden der .ui Datei und Anpassungen
uic.loadUi(self.pfad_fenster_layout, self)
+ self.setWindowIcon(QIcon(os.path.join(ROOT_PATH, "images/spritze.ico")))
self.i_start_datum_qdate.setMinimumDateTime(QDateTime.currentDateTime())
# Funktionen für Buttonbox zuweisen
From 0eac40c5df325a1e5f41dc9db638680a253fc9de Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Fri, 28 May 2021 22:56:36 +0200
Subject: [PATCH 20/25] Button war ohne Funktion
---
tools/gui/qtterminsuche.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/gui/qtterminsuche.py b/tools/gui/qtterminsuche.py
index 4088a5b1..78d2792e 100644
--- a/tools/gui/qtterminsuche.py
+++ b/tools/gui/qtterminsuche.py
@@ -92,6 +92,8 @@ def __init__(self, kontaktdaten: dict, zeitspanne: dict, ROOT_PATH: str, pfad_fe
uic.loadUi(pfad_fenster_layout, self)
self.setWindowIcon(QIcon(os.path.join(ROOT_PATH, "images/spritze.ico")))
+ self.buttonBox.rejected.connect(self.close)
+
# Attribute erstellen
self.erfolgreich: bool = None
self.kontaktdaten = kontaktdaten
From 6c66093f732c002d4babda88277aee94d6ea03ae Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Fri, 28 May 2021 23:52:50 +0200
Subject: [PATCH 21/25] added gui build
---
docs/distribution.md | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/docs/distribution.md b/docs/distribution.md
index 76450399..15ca3047 100644
--- a/docs/distribution.md
+++ b/docs/distribution.md
@@ -52,7 +52,7 @@ Schritte zum Erstellen einer Distribution:
Nachdem mit pyinstaller die Distribution erstellt wurde, ist diese in im `dist/` folder zu finden.
-#### Windows
+#### Windows Konsolenanwendung
.spec Datei erstellen und anschließend Distribution erstellen:
```shell
@@ -60,6 +60,13 @@ pyi-makespec main.py --specpath "specs//" --add-binary "..\tools\chromedriver\ch
pyinstaller --clean specs/windows-terminservice.spec
```
+#### Windows GUI
+
+```shell
+pyi-makespec gui.py --specpath "specs//" --add-binary "..\tools\chromedriver\chromedriver-windows.exe;tools\chromedriver\" --add-binary "..\tools\gui\kontaktdaten.ui;tools\gui\" --add-binary "..\tools\gui\main.ui;tools\gui\" --add-binary "..\tools\gui\terminsuche.ui;tools\gui\" --add-binary "..\tools\gui\uhrzeiten.ui;tools\gui\" --add-binary "..\images\spritze.ico;images\" --name windows-terminservice-gui --hidden-import plyer.platforms.win.notification --hidden-import cloudscraper --add-data "../tools/cloudscraper;./cloudscraper/" --icon "..\images\spritze.ico" --windowed
+
+pyinstaller --clean specs/windows-terminservice-gui.spec
+```
#### Linux
```shell
From c2df7a52472659d99a6cf68b243d70ab6f3e43b7 Mon Sep 17 00:00:00 2001
From: Floskinner <58706771+Floskinner@users.noreply.github.com>
Date: Fri, 28 May 2021 23:53:04 +0200
Subject: [PATCH 22/25] fixes FileDialog Bug
---
gui.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/gui.py b/gui.py
index 353a3f97..8e6f9edb 100644
--- a/gui.py
+++ b/gui.py
@@ -69,10 +69,6 @@ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main
self.i_kontaktdaten_pfad.setText(self.pfad_kontaktdaten)
self.i_zeitspanne_pfad.setText(self.pfad_zeitspanne)
- # Events für Eingabefelder
- self.i_kontaktdaten_pfad.textChanged.connect(self.__update_kontaktdaten_pfad)
- self.i_zeitspanne_pfad.textChanged.connect(self.__update_zeitspanne_pfad)
-
# Speichert alle termin_suchen Prozesse
self.such_prozesse = list(list())
self.prozesse_counter = 0
@@ -219,6 +215,7 @@ def __update_kontaktdaten_pfad(self):
try:
pfad = oeffne_file_dialog_select(self, "Kontakdaten", self.pfad_kontaktdaten)
self.pfad_kontaktdaten = pfad
+ self.i_kontaktdaten_pfad.setText(self.pfad_kontaktdaten)
except FileNotFoundError:
pass
@@ -226,6 +223,7 @@ def __update_zeitspanne_pfad(self):
try:
pfad = oeffne_file_dialog_select(self, "Zeitspanne", self.pfad_zeitspanne)
self.pfad_zeitspanne = pfad
+ self.i_zeitspanne_pfad.setText(self.pfad_zeitspanne)
except FileNotFoundError:
pass
From 5fb3b6dbbc5a0864cb70e25ee2a8807b395bdec1 Mon Sep 17 00:00:00 2001
From: Florian Glaser
Date: Sat, 29 May 2021 00:35:28 +0200
Subject: [PATCH 23/25] some unix fixes
---
gui.py | 5 +++--
tools/gui/__init__.py | 8 ++++++--
tools/gui/qtkontakt.py | 4 ++--
tools/gui/qtterminsuche.py | 1 +
4 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/gui.py b/gui.py
index 8e6f9edb..ca7575c9 100644
--- a/gui.py
+++ b/gui.py
@@ -7,7 +7,7 @@
import threading
import multiprocessing
-from PyQt5 import QtWidgets, uic
+from PyQt5 import QtCore, QtWidgets, uic
from PyQt5.QtGui import QIcon
from tools.gui import *
from tools.gui.qtzeiten import QtZeiten
@@ -90,6 +90,7 @@ def start_gui():
"""
app = QtWidgets.QApplication(list())
+ app.setAttribute(QtCore.Qt.AA_X11InitThreads)
window = HauptGUI()
app.exec_()
@@ -101,7 +102,7 @@ def kontaktdaten_erstellen(self, modus: Modus = Modus.TERMIN_SUCHEN):
modus (Modus): Abhängig vom Modus werden nicht alle Daten benötigt. Defalut TERMIN_SUCHEN
"""
- dialog = QtKontakt(modus, self.pfad_kontaktdaten, PATH)
+ dialog = QtKontakt(self, modus, self.pfad_kontaktdaten, PATH)
dialog.show()
dialog.exec_()
diff --git a/tools/gui/__init__.py b/tools/gui/__init__.py
index 573a5a1b..633f1bd9 100644
--- a/tools/gui/__init__.py
+++ b/tools/gui/__init__.py
@@ -89,7 +89,9 @@ def oeffne_file_dialog_save(parent_widged: QtWidgets.QWidget, titel: str, standa
str: Vollständiger Pfad
"""
- datei_data = QtWidgets.QFileDialog.getSaveFileName(parent_widged, titel, standard_speicherpfad, dateityp)
+ options = QtWidgets.QFileDialog.Options()
+ options |= QtWidgets.QFileDialog.DontUseNativeDialog
+ datei_data = QtWidgets.QFileDialog.getSaveFileName(parent=parent_widged, caption=titel, directory=standard_speicherpfad, filter="JSON Files (*.json)", options=options)
dateipfad = datei_data[0] # (Pfad, Dateityp)
if not dateipfad:
@@ -116,7 +118,9 @@ def oeffne_file_dialog_select(parent_widged: QtWidgets.QWidget, titel: str, stan
"""
# Öffnet den "File-Picker" vom System um ein bereits existierende Datei auszuwählen
- datei_data = QtWidgets.QFileDialog.getOpenFileName(parent_widged, titel, standard_oeffnungspfad, "JSON Files (*.json)")
+ options = QtWidgets.QFileDialog.Options()
+ options |= QtWidgets.QFileDialog.DontUseNativeDialog
+ datei_data = QtWidgets.QFileDialog.getOpenFileName(parent=parent_widged, caption=titel, directory=standard_oeffnungspfad, filter="JSON Files (*.json)", options=options)
dateipfad = datei_data[0] # (pfad, typ)
if not dateipfad:
diff --git a/tools/gui/qtkontakt.py b/tools/gui/qtkontakt.py
index 8f163b82..629c9971 100644
--- a/tools/gui/qtkontakt.py
+++ b/tools/gui/qtkontakt.py
@@ -37,8 +37,8 @@
class QtKontakt(QtWidgets.QDialog):
- def __init__(self, modus: Modus, standard_speicherpfad: str, ROOT_PATH: str, pfad_fenster_layout=os.path.join(PATH, "kontaktdaten.ui")):
- super().__init__()
+ def __init__(self, parent: QtWidgets.QWidget, modus: Modus, standard_speicherpfad: str, ROOT_PATH: str, pfad_fenster_layout=os.path.join(PATH, "kontaktdaten.ui")):
+ super().__init__(parent=parent)
self.standard_speicherpfad = standard_speicherpfad
diff --git a/tools/gui/qtterminsuche.py b/tools/gui/qtterminsuche.py
index 78d2792e..2548f9e0 100644
--- a/tools/gui/qtterminsuche.py
+++ b/tools/gui/qtterminsuche.py
@@ -128,6 +128,7 @@ def start_suche(kontaktdaten: dict, zeitspanne: dict, ROOT_PATH: str):
ROOT_PATH (str): Pfad zum Root Ordner, damit dieser an its übergeben werden kann
"""
app = QtWidgets.QApplication(list())
+ app.setAttribute(QtCore.Qt.AA_X11InitThreads)
window = QtTerminsuche(kontaktdaten, zeitspanne, ROOT_PATH)
app.exec_()
From 25360dd68c5e2ab19692f7abf615f41cbdd8cd10 Mon Sep 17 00:00:00 2001
From: JuliusJacobitz
Date: Sat, 29 May 2021 20:00:12 +0200
Subject: [PATCH 24/25] create missing dirs in init
---
gui.py | 5 ++++-
tools/__init__.py | 0
2 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 tools/__init__.py
diff --git a/gui.py b/gui.py
index ca7575c9..fec25268 100644
--- a/gui.py
+++ b/gui.py
@@ -14,6 +14,7 @@
from tools.gui.qtkontakt import QtKontakt
from tools.gui.qtterminsuche import QtTerminsuche
from tools.its import ImpfterminService
+from tools.utils import create_missing_dirs
PATH = os.path.dirname(os.path.realpath(__file__))
@@ -48,7 +49,9 @@ def __init__(self, pfad_fenster_layout: str = os.path.join(PATH, "tools/gui/main
"""
super().__init__()
-
+
+ create_missing_dirs()
+
# Laden der .ui Datei und Anpassungen
uic.loadUi(pfad_fenster_layout, self)
self.setWindowIcon(QIcon(os.path.join(PATH, "images/spritze.ico")))
diff --git a/tools/__init__.py b/tools/__init__.py
new file mode 100644
index 00000000..e69de29b
From 996a6ca3b13508a48fcdc9ef66bbee887e758333 Mon Sep 17 00:00:00 2001
From: JuliusJacobitz
Date: Sat, 29 May 2021 20:45:19 +0200
Subject: [PATCH 25/25] inno setup for windows gui
---
.github/workflows/build.yaml | 2 ++
.github/workflows/deploy.yaml | 41 +++++++++++++++++----
specs/windows-terminservice-gui.iss | 55 +++++++++++++++++++++++++++++
specs/windows-terminservice.iss | 1 +
4 files changed, 93 insertions(+), 6 deletions(-)
create mode 100644 specs/windows-terminservice-gui.iss
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 482d252a..ddb122b6 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -22,6 +22,8 @@ jobs:
pip install -r requirements.txt
- name: Build Windows
run: pyinstaller --clean --noconfirm specs/windows-terminservice.spec
+ - name: Build Windows GUI
+ run: pyinstaller --clean --noconfirm specs/windows-terminservice-gui.spec
build-linux:
runs-on: ubuntu-latest
steps:
diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml
index bf4e4191..8efa7197 100644
--- a/.github/workflows/deploy.yaml
+++ b/.github/workflows/deploy.yaml
@@ -16,6 +16,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
+ - name: tagname
+ uses: olegtarasov/get-tag@v2.1
+
- name: Setup Python
uses: actions/setup-python@v2.2.2
with:
@@ -24,33 +27,57 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
+
- name: Build Windows
run: pyinstaller --clean --noconfirm specs/windows-terminservice.spec
+ - name: Build Windows GUI
+ run: pyinstaller --clean --noconfirm specs/windows-terminservice-gui.spec
+
- name: Chocolatey install innosetup
uses: crazy-max/ghaction-chocolatey@v1.5.0
with:
# Arguments to pass to Chocolatey
args: install innosetup --install-arguments="'/DIR=../innosetup'" --force
- - name: tagname
- uses: olegtarasov/get-tag@v2.1
- - name: Run innosetup
+
+ - name: Innosetup windows-terminservice
# Run innosetup and set application version to git tag
run: ../innosetup/ISCC.exe specs/windows-terminservice.iss /DApplicationVersion=${{ env.GIT_TAG_NAME }}
- - name: Zip
+ - name: Innosetup windows-terminservice-gui
+ # Run innosetup and set application version to git tag
+ run: ../innosetup/ISCC.exe specs/windows-terminservice-gui.iss /DApplicationVersion=${{ env.GIT_TAG_NAME }}
+
+ - name: Zip Windows
uses: papeloto/action-zip@v1
with:
- files: dist/
+ files: dist/windows-terminservice
dest: vaccipy-windows.zip
+ - name: Zip Windows gui
+ uses: papeloto/action-zip@v1
+ with:
+ files: dist/windows-terminservice-gui
+ dest: vaccipy-windows-gui.zip
+
- name: Store windows zip as build artifact
uses: actions/upload-artifact@v2
with:
name: vaccipy-windows
path: vaccipy-windows.zip
+ - name: Store windows gui zip as build artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: vaccipy-windows-gui
+ path: vaccipy-windows-gui.zip
+
- name: Store windows installer as build artifact
uses: actions/upload-artifact@v2
with:
name: vaccipy-windows-installer
path: installers/vaccipy_installer.exe
+ - name: Store windows gui installer as build artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: vaccipy-windows-gui-installer
+ path: installers/vaccipy_gui_installer.exe
build-linux:
runs-on: ubuntu-latest
@@ -72,7 +99,7 @@ jobs:
with:
files: dist/
dest: vaccipy-ubuntu.zip
- - name: Store windows build artifact
+ - name: Store ubuntu build artifact
uses: actions/upload-artifact@v2
with:
name: vaccipy-ubuntu
@@ -90,5 +117,7 @@ jobs:
prerelease: false
files: |
vaccipy-windows-installer/vaccipy_installer.exe
+ vaccipy-windows-gui-installer/vaccipy_gui_installer.exe
vaccipy-windows/vaccipy-windows.zip
+ vaccipy-windows-gui/vaccipy-windows-gui.zip
vaccipy-ubuntu/vaccipy-ubuntu.zip
diff --git a/specs/windows-terminservice-gui.iss b/specs/windows-terminservice-gui.iss
new file mode 100644
index 00000000..8ba3be8b
--- /dev/null
+++ b/specs/windows-terminservice-gui.iss
@@ -0,0 +1,55 @@
+; Script generated by the Inno Script Studio Wizard.
+; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
+
+#define MyAppName "Vaccipy GUI"
+
+#ifndef ApplicationVersion
+#define ApplicationVersion "0.1"
+#endif
+
+#define MyAppPublisher "vaccipy"
+#define MyAppURL "https://github.com/iamnotturner/vaccipy"
+#define MyAppExeName "windows-terminservice-gui.exe"
+
+[Setup]
+; NOTE: The value of AppId uniquely identifies this application.
+; Do not use the same AppId value in installers for other applications.
+; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
+AppId={{E8DD1F42-66E8-47F6-8B1F-CBC47CDC78BE}
+AppName={#MyAppName}
+AppVersion={#ApplicationVersion}
+;AppVerName={#MyAppName} {#ApplicationVersion}
+AppPublisher={#MyAppPublisher}
+AppPublisherURL={#MyAppURL}
+AppSupportURL={#MyAppURL}
+AppUpdatesURL={#MyAppURL}
+DefaultDirName={pf}\vaccipy_gui
+DisableDirPage=yes
+DefaultGroupName={#MyAppName}
+OutputDir=../installers
+OutputBaseFilename=vaccipy_gui_installer
+SetupIconFile=../images/spritze.ico
+Compression=lzma
+SolidCompression=yes
+
+[Languages]
+Name: "german"; MessagesFile: "compiler:Languages\German.isl"
+
+[Tasks]
+Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
+
+[Files]
+Source: "..\dist\windows-terminservice-gui\windows-terminservice-gui.exe"; DestDir: "{app}"; Flags: ignoreversion
+Source: "..\dist\windows-terminservice-gui\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
+; NOTE: Don't use "Flags: ignoreversion" on any shared system files
+
+[Icons]
+Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
+Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
+
+[Run]
+Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
+
+[Dirs]
+Name: "{app}\data"; Flags: uninsalwaysuninstall; Permissions: users-modify
+Name: "{app}\tools\log"; Flags: uninsalwaysuninstall; Permissions: users-modify
\ No newline at end of file
diff --git a/specs/windows-terminservice.iss b/specs/windows-terminservice.iss
index 32895d06..2caf1416 100644
--- a/specs/windows-terminservice.iss
+++ b/specs/windows-terminservice.iss
@@ -27,6 +27,7 @@ DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputDir=../installers
OutputBaseFilename=vaccipy_installer
+SetupIconFile=../images/spritze.ico
Compression=lzma
SolidCompression=yes