Skip to content

Commit

Permalink
Implement better stats
Browse files Browse the repository at this point in the history
  • Loading branch information
hackenbergstefan committed Jul 27, 2024
1 parent 118d303 commit 4675de7
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 45 deletions.
2 changes: 1 addition & 1 deletion coffeebuddy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def create_app(config=None):
else:
logging.getLogger(__name__).info('Using config file "config"')
app.config.from_object("config")
# app.config['SQLALCHEMY_ECHO'] = True
# app.config["SQLALCHEMY_ECHO"] = True
if config:
app.config.update(config)

Expand Down
98 changes: 90 additions & 8 deletions coffeebuddy/model.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import datetime
import calendar
import socket
from typing import Optional
from datetime import date, datetime, timedelta
from typing import List, Optional

import flask
import sqlalchemy
from sqlalchemy import text


def weekday(column):
"""Helper to extract weekday for different database backends"""
if flask.current_app.db.engine.name == "postgresql":
return sqlalchemy.func.extract("dow", column)
else:
return sqlalchemy.func.strftime("%w", column)


class Serializer:
@staticmethod
def escape(obj):
Expand Down Expand Up @@ -58,9 +67,7 @@ def by_tag(tag):
def drinks_today(self):
return (
Drink.query.filter(Drink.user == self)
.filter(
flask.current_app.db.func.Date(Drink.timestamp) == datetime.date.today()
)
.filter(flask.current_app.db.func.Date(Drink.timestamp) == date.today())
.all()
)

Expand Down Expand Up @@ -131,6 +138,81 @@ def count_selected_manually(self, host: Optional[str] = None) -> int:
host = host or socket.gethostname()
return sum(d.selected_manually for d in self.drinks if d.host == host)

def drinks_this_week(self) -> List[int]:
now = date.today()
start_of_week = datetime.combine(
now - timedelta(now.weekday()), datetime.min.time()
)

data = tuple(
zip(
*flask.current_app.db.session.query(
weekday(Drink.timestamp).label("weekday"),
flask.current_app.db.func.count(
flask.current_app.db.func.Date(Drink.timestamp)
),
)
.filter(self.id == Drink.userid)
.filter(Drink.timestamp >= start_of_week)
.group_by("weekday")
.order_by("weekday")
.all()
)
)
if not data:
return [], []
return [calendar.day_name[int(i)] for i in data[0]], list(data[1])

def drinks_avg_week(self):
number_of_weeks = (
datetime.now()
- flask.current_app.db.session.query(sqlalchemy.func.min(Drink.timestamp))
.filter(self.id == Drink.userid)
.first()[0]
).days / 7
data = tuple(
zip(
*flask.current_app.db.session.query(
weekday(Drink.timestamp).label("weekday"),
flask.current_app.db.func.count(
flask.current_app.db.func.Date(Drink.timestamp)
)
/ number_of_weeks,
)
.filter(self.id == Drink.userid)
.group_by("weekday")
.order_by("weekday")
.all()
)
)
return [calendar.day_name[int(i)] for i in data[0]], list(data[1])

@staticmethod
def drinks_avg_week_all():
number_of_weeks = (
datetime.now()
- flask.current_app.db.session.query(
sqlalchemy.func.min(Drink.timestamp)
).first()[0]
).days / 7
number_of_active_users = User.query.filter(User.enabled).count()
data = tuple(
zip(
*flask.current_app.db.session.query(
weekday(Drink.timestamp).label("weekday"),
flask.current_app.db.func.count(
flask.current_app.db.func.Date(Drink.timestamp)
)
/ number_of_weeks
/ number_of_active_users,
)
.group_by("weekday")
.order_by("weekday")
.all()
)
)
return [calendar.day_name[int(i)] for i in data[0]], list(data[1])


class Drink(flask.current_app.db.Model):
id = flask.current_app.db.Column(flask.current_app.db.Integer, primary_key=True)
Expand All @@ -148,7 +230,7 @@ class Drink(flask.current_app.db.Model):

def __init__(self, *args, **kwargs):
if "timestamp" not in kwargs:
kwargs["timestamp"] = datetime.datetime.now()
kwargs["timestamp"] = datetime.now()
if "host" not in kwargs:
kwargs["host"] = socket.gethostname()
super().__init__(*args, **kwargs)
Expand All @@ -162,7 +244,7 @@ def drinks_vs_days(timedelta):
),
flask.current_app.db.func.Date(Drink.timestamp),
)
.filter(Drink.timestamp > datetime.datetime.now() - timedelta)
.filter(Drink.timestamp > datetime.now() - timedelta)
.order_by(sqlalchemy.asc(flask.current_app.db.func.Date(Drink.timestamp)))
.group_by(flask.current_app.db.func.Date(Drink.timestamp))
.all()
Expand All @@ -184,7 +266,7 @@ class Pay(flask.current_app.db.Model):

def __init__(self, *args, **kwargs):
if "timestamp" not in kwargs:
kwargs["timestamp"] = datetime.datetime.now()
kwargs["timestamp"] = datetime.now()
if "host" not in kwargs:
kwargs["host"] = socket.gethostname()
super().__init__(*args, **kwargs)
Expand Down
2 changes: 2 additions & 0 deletions coffeebuddy/route_coffee.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ def init():
def coffee():
flask.current_app.events.fire("route_coffee")
user: User = User.by_tag(escapefromhex(flask.request.args["tag"]))
print("drinks_this_week", user.drinks_this_week())
print("drinks_avg_week", user.drinks_avg_week())
if user is None:
return flask.render_template(
"cardnotfound.html", uuid=flask.request.args["tag"]
Expand Down
23 changes: 2 additions & 21 deletions coffeebuddy/templates/coffee.html
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@
width: 300px;
height: 300px;
}

</style>
</head>

Expand Down Expand Up @@ -157,6 +156,7 @@ <h1 id="user-name">{{ user.prename }} {{ user.name }}</h1>
<code class="h5">{{ hexstr(user.tag) }}</code>
</div>
<div class="my-auto">
<div id="stats" class="flex-grow-1"></div>
<form method="post">
<button id="btn-coffee" type="submit" class="btn-coffee" name="coffee" value="coffee">
<div id="btn-coffee-icon" class="display-1 fas fa-coffee"></div>
Expand All @@ -165,26 +165,7 @@ <h1 id="user-name">{{ user.prename }} {{ user.name }}</h1>
</form>
</div>
</div>
<div class="d-flex m-4" style="width: 100px;">
<div class="position-relative h-100 w-100">
<div class="coffeemeter-title">
COFFEEMETER
</div>
<div class="coffeemeter-tag">
{{ len(user.drinks_today) }}
</div>
<div class="d-flex flex-column h-100">
<div class="display-2 fas {{ coffee_state[min(len(coffee_state) - 1, len(user.drinks_today))] }}"
style="{{ 'color: var(--danger);' if len(user.drinks_today) >= len(coffee_state) }}">
</div>
<div class="d-flex flex-column justify-content-end h-100 border mt-2 px-2">
<div id="coffeemeter-bar" class="bg-engineering-dark m-1 rounded"
style="height: {{ len(user.drinks_today) / len(coffee_state) * 100 | round }}%;
{{ 'background: var(--danger); color: white;' if len(user.drinks_today) >= len(coffee_state) }}">
</div>
</div>
</div>
</div>
<div class="d-flex m-4" style="width: 500px;">
</div>
</div>
<canvas id="matrix"></canvas>
Expand Down
45 changes: 30 additions & 15 deletions coffeebuddy/templates/stats.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="{{ url_for('static', filename='coffeebuddy.css') }}">

<script src="https://cdnjs.cloudflare.com/ajax/libs/plotly.js/2.3.0/plotly-basic.min.js" integrity="sha512-94titNdENTKSvhQZbcdBcW6kMstfKZsWqGBRCAF0UUmzPx2DKYRHIsAxXJnXxiyvbBD3eMxwotX9rccAjgkVPg==" crossorigin="anonymous" referrerpolicy="no-referrer" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/plotly.js/2.34.0/plotly.min.js" integrity="sha512-pH45RLZKz14g8UuQC8days10TDtKG3vXHpDH0UHjnF9HKxGYGzKELe1ship9QXFekhfRfRFEcpemtSvqT5E4oQ==" crossorigin="anonymous" referrerpolicy="no-referrer" defer></script>
<script src="{{ url_for('static', filename='autologout.js') }}" defer></script>
<script>
{% if not config['NOTIMEOUT'] %}
Expand All @@ -18,22 +18,37 @@
});
{% endif %}

$.getScript("https://cdnjs.cloudflare.com/ajax/libs/plotly.js/2.3.0/plotly-basic.min.js", () => {
data = {{ datasets|tojson }};
$.getScript("https://cdnjs.cloudflare.com/ajax/libs/plotly.js/2.34.0/plotly.min.js", () => {
const drinks_this_week = {{ user.drinks_this_week() | tojson }};
const drinks_avg_week = {{ user.drinks_avg_week() | tojson }};
const drinks_avg_week_all = {{ user.drinks_avg_week_all() | tojson }};
const data = [
{
x: drinks_avg_week_all[0],
y: drinks_avg_week_all[1],
type: 'bar',
name: 'All avg week',
},
{
x: drinks_avg_week[0],
y: drinks_avg_week[1],
type: 'bar',
name: 'Yours avg week',
},
{
x: drinks_this_week[0],
y: drinks_this_week[1],
type: 'bar',
name: 'Yours this week',
},
];
layout = {
title: "Your Coffee Stats",
showlegend: false,
xaxis: {
tickfont: {
size: 16,
}
},
yaxis: {
tickformat: '%H:%M',
tickfont: {
size: 16,
}
title: 'Your Coffee Stats',
showlegend: true,
legend: {
orientation: 'h',
},
barcornerradius: 10,
plot_bgcolor: 'rgba(0,0,0,0)',
paper_bgcolor: 'rgba(0,0,0,0)',
margin: {
Expand Down

0 comments on commit 4675de7

Please sign in to comment.