X-Git-Url: https://plomlompom.com/repos/?p=misc;a=blobdiff_plain;f=calories.py;h=9951ce5c98896ef91319282143b2925b657ec280;hp=7a4846acdf40b5304fc5cc4ba088de48d16830da;hb=HEAD;hpb=35fe0ad6b60640e86add740c3b49dff05c75a240 diff --git a/calories.py b/calories.py index 7a4846a..9951ce5 100644 --- a/calories.py +++ b/calories.py @@ -1,57 +1,90 @@ -from http.server import BaseHTTPRequestHandler, HTTPServer import os import json import datetime +import jinja2 +from plomlib import PlomDB, PlomException, run_server, PlomHandler -def build_page(eatable_rows, consumption_rows, eatables_selection, day_rows): - return """ - +db_path = '/home/plom/org/calories_db.json' + +server_port = 8081 + +tmpl = """ """ + f""" +table { margin-bottom: 2em; } +th, td { text-align: left; } +td.number { text-align: right; } +input[type="number"] { text-align: right; } + -
+ -{consumption_rows} +{% for c in consumptions %} + + + + + + + + +{% endfor %} - - + +
eatableunit countunit weight (g)caloriessugar (g)
{{c.title}}{{c.cals}}{{c.sugar}}
add from DB:
+ + + + + -{day_rows} +{% for d in days %} + + + + + +{% endfor %}
today:archive?
+{{db.today.calories}}{{db.today.sugar_g}}
daycaloriessugar (g)
{{d.date_short|e}}{{d.cals}}{{d.sugar}}
-{eatable_rows} +{% for e in eatables %} + + + + + + + +{% endfor %} - - - + + +
titlecaloriessugar (g)standard weight (g)commentsdelete
+ +
add:
- """ -class LockFileDetected(Exception): - pass class Eatable: @@ -91,6 +121,7 @@ class Eatable: "popularity": self.popularity } + class Consumption: def __init__(self, eatable_key, unit_count=None, keep_visible=0): @@ -105,6 +136,7 @@ class Consumption: "keep_visible": self.keep_visible } + class Day: def __init__(self, calories, sugar_g): @@ -117,20 +149,22 @@ class Day: "sugar_g": self.sugar_g, } -class Database: + +class CaloriesDB(PlomDB): def __init__(self, load_from_file=True): - db_name = "calories_db" - self.db_file = db_name + ".json" - self.lock_file = db_name+ ".lock" + self.load_from_file = load_from_file self.eatables = {} self.consumptions = [] self.days = {} self.today = Day(0, 0) self.today_date = "" - if load_from_file and os.path.exists(self.db_file): - with open(self.db_file, "r") as f: - self.from_dict(json.load(f)) + super().__init__(db_path) + + def read_db_file(self, f): + if not self.load_from_file: + return + self.from_dict(json.load(f)) def from_dict(self, d): self.set_today_date(d["today_date"]) @@ -155,19 +189,19 @@ class Database: eatable = self.eatables[c.eatable_key] calories = eatable.cals * c.unit_count sugar_g = eatable.sugar_g * c.unit_count - # calories = float(eatable.cals / eatable.standard_g) * c.unit_count * c.unit_weight - # sugar_g = float(eatable.sugar_g / eatable.standard_g) * c.unit_count * c.unit_weight self.today.calories += calories self.today.sugar_g += sugar_g return {"cals": calories, "sugar": sugar_g } - def eatables_selection(self, selection=None): - html = '' + def eatables_selection(self): + options = [] + already_selected = [c.eatable_key for c in self.consumptions] for k, v in sorted(self.eatables.items(), key=lambda item: item[1].title): + if k in already_selected: + continue v = self.eatables[k] - selected = ' selected' if k==selection else '' - html += '' % (k, selected, v.title) - return html + options += [(k, v.title)] + return options def add_eatable(self, id_, eatable): self.eatables[id_] = eatable @@ -187,26 +221,26 @@ class Database: del self.eatables[id_] def write(self): - import shutil - if os.path.exists(self.lock_file): - raise LockFileDetected - if os.path.exists(self.db_file): - shutil.copy(self.db_file, self.db_file + ".bak") - f = open(self.lock_file, "w+") - f.close() - with open(self.db_file, "w") as f: - json.dump(self.to_dict(), f) - os.remove(self.lock_file) + self.write_text_to_db(json.dumps(self.to_dict())) -class MyServer(BaseHTTPRequestHandler): +class ConsumptionsHandler(PlomHandler): + + def app_init(self, handler): + default_path = '/consumptions' + handler.add_route('GET', default_path, self.show_db) + handler.add_route('POST', default_path, self.write_db) + return 'consumptions', default_path def do_POST(self): + self.try_do(self.write_db) + + def write_db(self): from uuid import uuid4 from urllib.parse import parse_qs length = int(self.headers['content-length']) postvars = parse_qs(self.rfile.read(length).decode(), keep_blank_values=1) - db = Database(False) + db = CaloriesDB(False) def decode(key, i, is_num=True): if is_num: return float(postvars[key][i]) @@ -217,12 +251,11 @@ class MyServer(BaseHTTPRequestHandler): to_delete += [target] i = 0 if 'eatable_uuid' in postvars.keys(): - for uuid_encoded in postvars['eatable_uuid']: - uuid = uuid_encoded + for uuid in postvars['eatable_uuid']: if uuid not in to_delete: e = Eatable(decode("title", i, False), decode("cals", i), decode("sugar_g", i), decode("standard_g", i), decode("comments", i, False)) db.add_eatable(uuid, e) - i += 1 + i += 1 if 'title' in postvars.keys() and len(postvars['title'][i]) > 0: e = Eatable(decode("title", i, False), decode("cals", i), decode("sugar_g", i), decode("standard_g", i), decode("comments", i, False)) db.add_eatable(str(uuid4()), e) @@ -250,78 +283,61 @@ class MyServer(BaseHTTPRequestHandler): if c.unit_count > 0: db.eatables[c.eatable_key].popularity += 1 db.consumptions = [] - default_slots = 7 + default_slots = 10 for k, v in sorted(db.eatables.items(), key=lambda item: -item[1].popularity): db.add_consumption(Consumption(k, 0)) default_slots -= 1 if (default_slots <= 0): break - try: - db.write() - self.send_response(302) - self.send_header('Location', '/') - self.end_headers() - except LockFileDetected: - self.send_response(400) - self.end_headers() - self.wfile.write(bytes("Sorry, lock file!", "utf-8")) + db.write() + homepage = self.apps['consumptions'] if hasattr(self, 'apps') else self.homepage + self.redirect(homepage) def do_GET(self): - self.send_response(200) - self.send_header("Content-type", "text/html") - self.end_headers() - db = Database() + self.try_do(self.show_db) - eatables = "" + def show_db(self): + db = CaloriesDB() + eatable_rows = [] for k,v in db.eatables.items(): - eatables += ""\ - ""\ - ""\ - ""\ - ""\ - ""\ - ""\ - ""\ - "" % (k, v.title, v.cals, v.sugar_g, v.standard_g, v.comments, k) - consumptions = "" + eatable_rows += [{ + 'uuid': k, + 'title': v.title, + 'cals': f'{v.cals:.1f}', + 'sugar_g': f'{v.sugar_g:.1f}', + 'standard_g': f'{v.standard_g:.1f}', + 'comments': v.comments + }] + db.consumptions = sorted(db.consumptions, key=lambda x: db.eatables[x.eatable_key].title) + consumption_rows = [] for c in db.consumptions: r = db.calc_consumption(c) - consumptions += ""\ - ""\ - ""\ - ""\ - ""\ - "%.1f"\ - "%.1f"\ - "" % (db.eatables_selection(c.eatable_key), c.unit_count, r["cals"], r["sugar"]) - day_rows = "" - for date, day in db.days.items(): - day_rows = ""\ - "%s"\ - "%.1f"\ - "%.1f"\ - "" % (date, date[:10], day.calories, day.calories, day.sugar_g, day.sugar_g) + day_rows - day_rows = ""\ - "today:archive?"\ - ""\ - ""\ - ""\ - "%.1f"\ - "%.1f"\ - ""\ - "" % (db.today_date, db.today.calories, db.today.calories, db.today.sugar_g, db.today.sugar_g) + day_rows - page = build_page(eatables, consumptions, db.eatables_selection(), day_rows) - self.wfile.write(bytes(page, "utf-8")) - - -hostName = "localhost" -serverPort = 8081 -if __name__ == "__main__": - webServer = HTTPServer((hostName, serverPort), MyServer) - print("Server started http://%s:%s" % (hostName, serverPort)) - try: - webServer.serve_forever() - except KeyboardInterrupt: - pass - webServer.server_close() - print("Server stopped.") + consumption_rows += [{ + 'key': c.eatable_key, + 'count': c.unit_count, + 'title': db.eatables[c.eatable_key].title, + 'cals': r['cals'], + 'sugar': r['sugar'] + }] + day_rows = [] + for date in reversed(sorted(db.days.keys())): + day = db.days[date] + day_rows += [{ + 'date': date, + 'date_short': date[:10], + 'cals': f'{day.calories:.1f}', + 'sugar': f'{day.sugar_g:.1f}', + }] + homepage = self.apps['consumptions'] if hasattr(self, 'apps') else self.homepage + page = jinja2.Template(tmpl).render( + homepage = homepage, + db=db, + days=day_rows, + consumptions=consumption_rows, + eatables=eatable_rows, + eatables_selection=db.eatables_selection()) + self.send_HTML(page) + + +if __name__ == "__main__": + run_server(server_port, ConsumptionsHandler)