Compare commits
3 Commits
cd714ae430
...
aa5d55124d
| Author | SHA1 | Date | |
|---|---|---|---|
| aa5d55124d | |||
| 936f2e2fe3 | |||
| c4aac9740f |
@@ -3,6 +3,8 @@ import typing
|
|||||||
|
|
||||||
import peewee
|
import peewee
|
||||||
|
|
||||||
|
import wordlinator.utils
|
||||||
|
|
||||||
db = peewee.PostgresqlDatabase(
|
db = peewee.PostgresqlDatabase(
|
||||||
os.getenv("DB_NAME", "wordlegolf"),
|
os.getenv("DB_NAME", "wordlegolf"),
|
||||||
user=os.getenv("DB_USER", "wordlegolf"),
|
user=os.getenv("DB_USER", "wordlegolf"),
|
||||||
@@ -30,6 +32,12 @@ class User(BaseModel):
|
|||||||
class Game(BaseModel):
|
class Game(BaseModel):
|
||||||
game_id = peewee.AutoField()
|
game_id = peewee.AutoField()
|
||||||
game = peewee.IntegerField(null=False)
|
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):
|
class Hole(BaseModel):
|
||||||
@@ -65,11 +73,14 @@ class WordleDb:
|
|||||||
def add_user(self, username, user_id):
|
def add_user(self, username, user_id):
|
||||||
return User.create(username=username, twitter_id=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:
|
try:
|
||||||
return Game.get(Game.game == round_no)
|
return Game.get(Game.game == round_no)
|
||||||
except peewee.DoesNotExist:
|
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):
|
def get_or_create_hole(self, round_no, hole_no):
|
||||||
round = self.get_or_create_round(round_no)
|
round = self.get_or_create_round(round_no)
|
||||||
@@ -115,7 +126,13 @@ class WordleDb:
|
|||||||
|
|
||||||
def get_scores(self, round_no):
|
def get_scores(self, round_no):
|
||||||
round = self.get_or_create_round(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]):
|
def bulk_insert_scores(self, scores: typing.List[typing.Dict]):
|
||||||
with db.atomic():
|
with db.atomic():
|
||||||
@@ -131,15 +148,16 @@ class WordleDb:
|
|||||||
hole = self.get_or_create_hole(round_no, hole_no)
|
hole = self.get_or_create_hole(round_no, hole_no)
|
||||||
# Find users who *have* played in this round,
|
# Find users who *have* played in this round,
|
||||||
# but have no score on the current hole
|
# but have no score on the current hole
|
||||||
query_str = """SELECT username
|
query_str = """SELECT u.username, player.game_id
|
||||||
FROM user_tbl u
|
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 = {}
|
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(
|
""".format(
|
||||||
hole.hole_id, hole.game_id
|
hole.game_id, hole.hole_id
|
||||||
)
|
)
|
||||||
|
|
||||||
if tweetable:
|
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.db.pg as db
|
||||||
import wordlinator.twitter
|
import wordlinator.twitter
|
||||||
import wordlinator.utils
|
import wordlinator.utils
|
||||||
|
import wordlinator.utils.web
|
||||||
|
|
||||||
###################
|
###################
|
||||||
# Setup Functions #
|
# 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():
|
def get_scores():
|
||||||
score_list = scores_from_db()
|
score_list = scores_from_db()
|
||||||
scores_by_user = collections.defaultdict(list)
|
table_rows = wordlinator.utils.web.table_rows(score_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()
|
|
||||||
]
|
|
||||||
|
|
||||||
hole_columns = [
|
hole_columns = [
|
||||||
{"name": f"Hole {i}", "id": f"Hole {i}", "type": "numeric"}
|
{"name": f"Hole {i}", "id": f"Hole {i}", "type": "numeric"}
|
||||||
@@ -137,13 +78,22 @@ def get_scores():
|
|||||||
*hole_columns,
|
*hole_columns,
|
||||||
]
|
]
|
||||||
|
|
||||||
color_formatting = [
|
color_formatting = wordlinator.utils.web.column_formatting(hole_columns)
|
||||||
format_entry
|
|
||||||
for column_formats in [_column_formats(col) for col in hole_columns]
|
|
||||||
for format_entry in column_formats
|
|
||||||
]
|
|
||||||
formatting = [
|
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,
|
*color_formatting,
|
||||||
]
|
]
|
||||||
return dash.dash_table.DataTable(
|
return dash.dash_table.DataTable(
|
||||||
|
|||||||
Reference in New Issue
Block a user