diff --git a/requiremnts.txt b/requiremnts.txt index dae88df..623b37c 100644 --- a/requiremnts.txt +++ b/requiremnts.txt @@ -1,16 +1,20 @@ attrs==22.1.0 beautifulsoup4==4.11.1 +blinker==1.6.2 certifi==2023.7.22 charset-normalizer==3.2.0 +click==8.1.7 colorama==0.4.6 coloredlogs==15.0.1 coverage==6.5.0 debugpy==1.6.7 distlib==0.3.7 exceptiongroup==1.0.1 +Flask==2.3.3 humanfriendly==10.0 idna==3.4 iniconfig==1.1.1 +itsdangerous==2.1.2 Jinja2==3.1.2 MarkupSafe==2.1.3 packaging==21.3 @@ -26,4 +30,5 @@ soupsieve==2.3.2.post1 tabulate==0.9.0 tomli==2.0.1 urllib3==2.0.5 +Werkzeug==2.3.7 yarg==0.1.9 diff --git a/src/main.py b/src/main.py index 0d00a39..a65f696 100644 --- a/src/main.py +++ b/src/main.py @@ -15,11 +15,17 @@ def main(): l = __initLogging() cli = solo_turnier.cli.Cli(l) + batchWorker = solo_turnier.batch.BatchWorker(cli) + if cli.showGUI(): raise Exception('Not yet implemented') + elif cli.startFlaskServer(): + solo_turnier.flask.startFlask(batchWorker, cli.getLogLevel() > 0) else: - batchWorker = solo_turnier.batch.BatchWorker(cli) - batchWorker.run() + combinedData = batchWorker.run() + + consoleOutputtter = solo_turnier.output.ConsoleOutputter() + consoleOutputtter.output(combinedData) if __name__ == '__main__': main() diff --git a/src/solo_turnier/__init__.py b/src/solo_turnier/__init__.py index a6913e4..e06c62f 100644 --- a/src/solo_turnier/__init__.py +++ b/src/solo_turnier/__init__.py @@ -13,3 +13,4 @@ from . import worker from . import output from . import batch +from . import flask diff --git a/src/solo_turnier/batch.py b/src/solo_turnier/batch.py index 23d8e4e..8260d63 100644 --- a/src/solo_turnier/batch.py +++ b/src/solo_turnier/batch.py @@ -14,7 +14,7 @@ class BatchWorker: self.l = logging.getLogger('solo_turnier.batch') self.config = config - def run(self): + def run(self, removeFilteredParicipants=True): self.l.debug(self.config.__dict__) locator = solo_turnier.html_locator.HtmlLocator() @@ -30,7 +30,6 @@ class BatchWorker: combinedData = worker.combineData(importedData) if not self.config.showAllParticipants(): - worker.filterOutFinalists(combinedData) + worker.filterOutFinalists(combinedData, removeFilteredParicipants) - consoleOutputtter = solo_turnier.output.ConsoleOutputter() - consoleOutputtter.output(combinedData) + return combinedData diff --git a/src/solo_turnier/cli.py b/src/solo_turnier/cli.py index fe869d4..1708cbb 100644 --- a/src/solo_turnier/cli.py +++ b/src/solo_turnier/cli.py @@ -6,7 +6,8 @@ import debugpy class Cli: def __init__(self, l: logging.Logger): parser = argparse.ArgumentParser() - parser.add_argument('--gui', help='Show the GUI', action='store_true') + # parser.add_argument('--gui', help='Show the GUI', action='store_true') + parser.add_argument('--no-flask', action='store_false', dest='flask', help='Disable the internal flask web server') parser.add_argument('html', help='The path from where to look for HTML export files', nargs=1, default=['.']) parser.add_argument('-o', '--output', help='Set the output path of the script', nargs=1, default=[None]) @@ -31,8 +32,12 @@ class Cli: l.setLevel(logLevel) def showGUI(self): - return self.__args.gui + # return self.__args.gui + return False + def startFlaskServer(self): + return self.__args.flask + def importHtmlPath(self): return self.__args.html[0] diff --git a/src/solo_turnier/flask.py b/src/solo_turnier/flask.py new file mode 100644 index 0000000..5f6d0df --- /dev/null +++ b/src/solo_turnier/flask.py @@ -0,0 +1,13 @@ +import flask +import solo_turnier + +def startFlask(batchWorker: solo_turnier.batch.BatchWorker, debug: bool = False): + app = flask.Flask(__name__) + + @app.route('/') + def index(): + combinedData = batchWorker.run(False) + + return flask.render_template('index.html', data=combinedData) + + app.run(host='0.0.0.0', port=8082, debug=debug) diff --git a/src/solo_turnier/static/style.css b/src/solo_turnier/static/style.css new file mode 100644 index 0000000..5158548 --- /dev/null +++ b/src/solo_turnier/static/style.css @@ -0,0 +1,47 @@ + +.tab-summary { + width: 100%; + border-collapse: collapse; +} + +.tab-summary tr:nth-of-type(even) { + background-color: cyan; +} + +.tab-summary td { + text-align: center; +} + +.tab-summary td .competition-place { + font-size: smaller; + font-weight: 300; + font-style: italic; +} + +.tab-summary .no-finalist { + color: gray; +} + +@media print { + @page { + size: landscape; + } + @page portrait { + size: portrait; + } + /* body { + size: landscape; + page-orientation: rotate-right; + } */ + + .section, + .section table tr, + .section table td + { + page-break-inside: avoid; + } + + .tab-summary .no-finalist { + color: gray; + } +} diff --git a/src/solo_turnier/templates/index.html b/src/solo_turnier/templates/index.html new file mode 100644 index 0000000..aadb5f9 --- /dev/null +++ b/src/solo_turnier/templates/index.html @@ -0,0 +1,56 @@ + + + + + Solo Turnier Auswertung + {# #} + + + + + {#

Finalauswertung Solo-Turniere

#} + {% for group in data.groups %} + {% block groupBlk scoped %} +
+

Auswertung Gruppe {{ group.name }}

+ + + + {% for dance in data.results[group].dances %} + + {% endfor %} + + {% set activeGroup = data.results[group].results %} + {% for participant, results in activeGroup|dictsort() %} + {% block participantGrp scoped %} + {% set rowCls = "" %} + {% if not participant.finalist %} + {% set rowCls = "no-finalist" %} + {% endif %} + + + {% for dance in data.results[group].dances %} + {% block danceResult scoped %} + {% set res = activeGroup[participant][loop.index0] %} + + {% endblock %} + {% endfor %} + + {% endblock %} + {% endfor %} +
Teilnehmer{{ dance }}
{{ participant.name }} ({{ participant.id }}) + {% if res is not none %} + {% if not participant.finalist %} + Kein/e Finalist/in + {% endif %} + {{ res.getNativePlace() }} ({{ res.nativeClass }})
+ + {{ res.getPlace() }} in {{ res.competitionClass }} + + {% endif %} +
+
+ {% endblock %} + {% endfor %} + + diff --git a/src/solo_turnier/types.py b/src/solo_turnier/types.py index 3ed57b3..94f08ac 100644 --- a/src/solo_turnier/types.py +++ b/src/solo_turnier/types.py @@ -26,6 +26,7 @@ class HtmlPreviewParticipant: self.id = id groupParser = group.GroupParser() self.group = groupParser.parseClass(group_) + self.finalist = None def __eq__(self, o): if type(o) != HtmlPreviewParticipant: @@ -39,6 +40,9 @@ class HtmlPreviewParticipant: def __hash__(self): return hash((self.id, self.name, self.group)) + def __gt__(self, other): + return self.id >= other.id + class HtmlParticipant: def __init__(self, name, id): self.name = name @@ -201,6 +205,18 @@ class SingleParticipantResult: return f'SR[{self.place} in {self.dance} {self.competitionClass} ({self.placeNative}-{self.placeNativeTo}, {self.nativeClass}){asFinalist}]' return f'SR[{self.place}-{self.placeTo} in {self.dance} {self.competitionClass} ({self.placeNative}-{self.placeNativeTo}, {self.nativeClass}){asFinalist}]' + + def getPlace(self): + if self.placeTo is None: + return f'{self.place}.' + else: + return f'{self.place}.-{self.placeTo}.' + + def getNativePlace(self): + if self.placeNativeTo is None: + return f'{self.placeNative}.' + else: + return f'{self.placeNative}.-{self.placeNativeTo}.' class TotalGroupResult: def __init__(self, dances: list[str], results: dict[HtmlPreviewParticipant, list[SingleParticipantResult]]): diff --git a/src/solo_turnier/worker.py b/src/solo_turnier/worker.py index 8324b23..cd6b0a1 100644 --- a/src/solo_turnier/worker.py +++ b/src/solo_turnier/worker.py @@ -651,7 +651,7 @@ class Worker: # self.l.log(5, '(Partially) fixed places: %s', (data)) - def filterOutFinalists(self, data: types.State4): + def filterOutFinalists(self, data: types.State4, filterOut: bool): for group in data.results: self.l.debug('Cleaning up group %s', group.name) participants = data.results[group].results.keys() @@ -668,10 +668,13 @@ class Worker: finalist = True in mapped self.l.log(5,'Check for finalist (in dances %s): %s', mapped, finalist) - if not finalist: + if finalist: + participant.finalist = True + else: + participant.finalist = False self.l.warning('Dropping %s from the output as no finalist', participant) droppedParticipants.append(participant) - for droppedParticipant in droppedParticipants: - data.results[group].results.pop(droppedParticipant) - pass + if filterOut: + for droppedParticipant in droppedParticipants: + data.results[group].results.pop(droppedParticipant)