From c4aac9740fe8dcc61df933491155c1415f95c7c0 Mon Sep 17 00:00:00 2001 From: Brad Brown Date: Wed, 8 Jun 2022 17:09:01 -0500 Subject: [PATCH] refactor some utils, new columns, better missing user logic --- wordlinator/db/pg.py | 26 +++++-- wordlinator/{utils.py => utils/__init__.py} | 0 wordlinator/utils/web.py | 76 +++++++++++++++++++++ wordlinator/web/__init__.py | 69 +------------------ 4 files changed, 98 insertions(+), 73 deletions(-) rename wordlinator/{utils.py => utils/__init__.py} (100%) create mode 100644 wordlinator/utils/web.py diff --git a/wordlinator/db/pg.py b/wordlinator/db/pg.py index 0a10399..42a5ea7 100644 --- a/wordlinator/db/pg.py +++ b/wordlinator/db/pg.py @@ -3,6 +3,8 @@ import typing import peewee +import wordlinator.utils + db = peewee.PostgresqlDatabase( os.getenv("DB_NAME", "wordlegolf"), user=os.getenv("DB_USER", "wordlegolf"), @@ -30,6 +32,12 @@ class User(BaseModel): class Game(BaseModel): game_id = peewee.AutoField() game = peewee.IntegerField(null=False) + start_date = peewee.DateField(null=False) + + +class Player(BaseModel): + user_id = peewee.ForeignKeyField(User, "user_id", null=False) + game_id = peewee.ForeignKeyField(Game, "game_id", null=False) class Hole(BaseModel): @@ -65,11 +73,14 @@ class WordleDb: def add_user(self, username, user_id): return User.create(username=username, twitter_id=user_id) - def get_or_create_round(self, round_no): + def get_or_create_round(self, round_no, start_date=None): try: return Game.get(Game.game == round_no) except peewee.DoesNotExist: - return Game.create(game=round_no) + start_date = ( + start_date or wordlinator.utils.WORDLE_GOLF_ROUND_DATES[round_no - 1] + ) + return Game.create(game=round_no, start_date=start_date) def get_or_create_hole(self, round_no, hole_no): round = self.get_or_create_round(round_no) @@ -131,15 +142,16 @@ class WordleDb: hole = self.get_or_create_hole(round_no, hole_no) # Find users who *have* played in this round, # but have no score on the current hole - query_str = """SELECT username + query_str = """SELECT u.username, player.game_id FROM user_tbl u - WHERE NOT EXISTS ( + JOIN player ON player.user_id = u.user_id + WHERE ( + player.game_id = {} + ) AND NOT EXISTS ( SELECT FROM score WHERE score.user_id = u.user_id AND score.hole_id = {} - ) AND EXISTS ( - SELECT FROM score WHERE score.user_id = u.user_id AND score.game_id = {} ) """.format( - hole.hole_id, hole.game_id + hole.game_id, hole.hole_id ) if tweetable: diff --git a/wordlinator/utils.py b/wordlinator/utils/__init__.py similarity index 100% rename from wordlinator/utils.py rename to wordlinator/utils/__init__.py diff --git a/wordlinator/utils/web.py b/wordlinator/utils/web.py new file mode 100644 index 0000000..f29e4ef --- /dev/null +++ b/wordlinator/utils/web.py @@ -0,0 +1,76 @@ +import collections +import typing + + +def golf_score(score_list: typing.List) -> int: + scores = [s.score for s in score_list] + score_count = len(scores) + score = sum(scores) - (score_count * 4) + return score + + +def get_user_scorelist( + username: str, scores: typing.List +) -> typing.Dict[str, typing.Any]: + scores = list(sorted(scores, key=lambda s: s.hole_id.hole)) + return { + "Name": username, + "Score": golf_score(scores), + **{f"Hole {s.hole_id.hole}": s.score for s in scores}, + } + + +def format_string(col, condition): + return "{" + col["id"] + "}" + f" {condition}" + + +def column_formats(col): + return [ + { + "if": { + "column_id": col["id"], + "filter_query": format_string(col, "> 4"), + }, + "backgroundColor": "red", + }, + { + "if": { + "column_id": col["id"], + "filter_query": format_string(col, "= 4"), + }, + "backgroundColor": "orange", + }, + { + "if": { + "column_id": col["id"], + "filter_query": format_string(col, "< 4"), + }, + "backgroundColor": "green", + }, + { + "if": { + "column_id": col["id"], + "filter_query": format_string(col, "is nil"), + }, + "backgroundColor": "white", + }, + ] + + +def table_rows(score_list): + scores_by_user = collections.defaultdict(list) + for score in score_list: + scores_by_user[score.user_id.username].append(score) + + return [ + get_user_scorelist(username, scores) + for username, scores in scores_by_user.items() + ] + + +def column_formatting(hole_columns): + return [ + entry + for format_list in [column_formats(hole) for hole in hole_columns] + for entry in format_list + ] diff --git a/wordlinator/web/__init__.py b/wordlinator/web/__init__.py index 9ea8715..2b73a8f 100644 --- a/wordlinator/web/__init__.py +++ b/wordlinator/web/__init__.py @@ -13,6 +13,7 @@ import plotly.graph_objs import wordlinator.db.pg as db import wordlinator.twitter import wordlinator.utils +import wordlinator.utils.web ################### # Setup Functions # @@ -63,69 +64,9 @@ def scores_from_db(): ################# -def _golf_score(score_list): - scores = [s.score for s in score_list] - score_count = len(scores) - score = sum(scores) - (score_count * 4) - return score - - -def _get_user_scorelist(username, scores): - scores = list(sorted(scores, key=lambda s: s.hole_id.hole)) - return { - "Name": username, - "Score": _golf_score(scores), - **{f"Hole {s.hole_id.hole}": s.score for s in scores}, - } - - -def _format_string(col, condition): - return "{" + col["id"] + "}" + f" {condition}" - - -def _column_formats(col): - return [ - { - "if": { - "column_id": col["id"], - "filter_query": _format_string(col, "> 4"), - }, - "backgroundColor": "red", - }, - { - "if": { - "column_id": col["id"], - "filter_query": _format_string(col, "= 4"), - }, - "backgroundColor": "orange", - }, - { - "if": { - "column_id": col["id"], - "filter_query": _format_string(col, "< 4"), - }, - "backgroundColor": "green", - }, - { - "if": { - "column_id": col["id"], - "filter_query": _format_string(col, "is nil"), - }, - "backgroundColor": "white", - }, - ] - - def get_scores(): score_list = scores_from_db() - scores_by_user = collections.defaultdict(list) - for score in score_list: - scores_by_user[score.user_id.username].append(score) - - table_rows = [ - _get_user_scorelist(username, scores) - for username, scores in scores_by_user.items() - ] + table_rows = wordlinator.utils.web.table_rows(score_list) hole_columns = [ {"name": f"Hole {i}", "id": f"Hole {i}", "type": "numeric"} @@ -137,11 +78,7 @@ def get_scores(): *hole_columns, ] - color_formatting = [ - format_entry - for column_formats in [_column_formats(col) for col in hole_columns] - for format_entry in column_formats - ] + color_formatting = wordlinator.utils.web.column_formatting(hole_columns) formatting = [ {"if": {"column_id": "Name"}, "textAlign": "center"}, *color_formatting,