Compare commits
3 Commits
cd714ae430
...
aa5d55124d
| Author | SHA1 | Date | |
|---|---|---|---|
| aa5d55124d | |||
| 936f2e2fe3 | |||
| c4aac9740f |
@@ -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)
|
||||
@@ -115,7 +126,13 @@ class WordleDb:
|
||||
|
||||
def get_scores(self, round_no):
|
||||
round = self.get_or_create_round(round_no)
|
||||
return list(Score.select().filter(Score.game_id == round.game_id))
|
||||
res = (
|
||||
Score.select(Score, Player.game_id)
|
||||
.join(Player, on=(Score.user_id == Player.user_id))
|
||||
.filter(Player.game_id == round.game_id)
|
||||
.filter(Score.game_id == round.game_id)
|
||||
)
|
||||
return list(res)
|
||||
|
||||
def bulk_insert_scores(self, scores: typing.List[typing.Dict]):
|
||||
with db.atomic():
|
||||
@@ -131,15 +148,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:
|
||||
|
||||
83
wordlinator/utils/web.py
Normal file
83
wordlinator/utils/web.py
Normal file
@@ -0,0 +1,83 @@
|
||||
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, pct):
|
||||
return [
|
||||
{
|
||||
"if": {"column_id": col["id"]},
|
||||
"maxWidth": f"{pct}%",
|
||||
"width": f"{pct}%",
|
||||
"minWidth": f"{pct}%",
|
||||
},
|
||||
{
|
||||
"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):
|
||||
pct = round((100 - (10 + 5)) / len(hole_columns), 2)
|
||||
return [
|
||||
entry
|
||||
for format_list in [column_formats(hole, pct) for hole in hole_columns]
|
||||
for entry in format_list
|
||||
]
|
||||
@@ -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,13 +78,22 @@ 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"},
|
||||
{
|
||||
"if": {"column_id": "Name"},
|
||||
"textAlign": "center",
|
||||
"width": "10%",
|
||||
"maxWidth": "10%",
|
||||
"minWidth": "10%",
|
||||
},
|
||||
{
|
||||
"if": {"column_id": "Score"},
|
||||
"textAlign": "center",
|
||||
"width": "5%",
|
||||
"maxWidth": "5%",
|
||||
"minWidth": "5%",
|
||||
},
|
||||
*color_formatting,
|
||||
]
|
||||
return dash.dash_table.DataTable(
|
||||
|
||||
Reference in New Issue
Block a user