home · contact · privacy
Add foreign key restraints, expand and fix tests, add deletion and forking.
[misc] / energy_tracker.py
1 from http.server import BaseHTTPRequestHandler, HTTPServer
2 import os
3 import json
4
5
6
7 def build_page(entries):
8     return """<html>
9 <meta charset="UTF-8">
10 <style>
11 .energy_cell {
12   text-align: center;
13 }
14 </style>
15 <body>
16 <form action="/" method="POST">
17 energy level:
18 <input type="submit" name="energy ---" value="---" />
19 <input type="submit" name="energy --" value="--" />
20 <input type="submit" name="energy -" value="-" />
21 <input type="submit" name="energy +" value="+" />
22 <input type="submit" name="energy ++" value="++" />
23 <input type="submit" name="energy +++" value="+++" />
24 comment:
25 <input name="comment" type="text" />
26 minutes ago:
27 <input name="backdate" type="number" value="0" min="0" step="5" />
28 </form>""" + f"""
29 <details>
30 <summary>
31 [tracking]
32 </summary>
33 <table>
34 <tr><th>datetime</th><th>energy level</th><th>comment</th></tr>
35 {entries}
36 </table>""" + """
37 </details>
38 </body>
39 </html>"""
40
41
42
43 class Database: 
44
45     def __init__(self):
46         db_name = "energy_tracker"
47         self.db_file = db_name + ".json"
48         self.lock_file = db_name+ ".lock"
49         self.entries = {}
50         if os.path.exists(self.db_file):
51             with open(self.db_file, "r") as f:
52                 self.from_dict(json.load(f))
53
54     def from_dict(self, d):
55         self.entries = d
56
57     def to_dict(self):
58         return self.entries 
59
60     def write(self):
61         import shutil
62         if os.path.exists(self.lock_file):
63             raise LockFileDetected
64         if os.path.exists(self.db_file):
65             shutil.copy(self.db_file, self.db_file + ".bak")
66         f = open(self.lock_file, "w+")
67         f.close()
68         with open(self.db_file, "w") as f:
69             json.dump(self.to_dict(), f)
70         os.remove(self.lock_file)
71
72
73
74 class MyServer(BaseHTTPRequestHandler):
75
76     def do_POST(self):
77         import datetime
78         from urllib.parse import parse_qs
79         length = int(self.headers['content-length'])
80         postvars = parse_qs(self.rfile.read(length), keep_blank_values=1)
81         db = Database()
82         for val in ('---', '--', '-', '+', '++', '+++'):
83             val_name = 'energy ' + val
84             if val_name.encode() in postvars.keys():
85                 time = datetime.datetime.now() - datetime.timedelta(minutes=int(postvars[b'backdate'][0].decode()))
86                 db.entries[str(time)[:19]] = [val, postvars[b'comment'][0].decode()]
87                 break
88         try:
89             db.write()
90             self.send_response(302)
91             self.send_header('Location', '/')
92             self.end_headers()
93         except LockFileDetected:
94             self.send_response(400)
95             self.end_headers()
96             self.wfile.write(bytes("Sorry, lock file!", "utf-8"))
97
98     def do_GET(self):
99         self.send_response(200)
100         self.send_header("Content-type", "text/html")
101         self.end_headers()
102         db = Database()
103         entries = ""
104         for datetime, data in db.entries.items():
105             entries = "<tr><td>%s</td><td class=\"energy_cell\">%s</td><td>%s</td></tr>\n" % (datetime, data[0], data[1]) + entries
106         page = build_page(entries)
107         self.wfile.write(bytes(page, "utf-8"))
108
109
110
111 hostName = "localhost"
112 serverPort = 8080
113 if __name__ == "__main__":        
114     webServer = HTTPServer((hostName, serverPort), MyServer)
115     print("Server started http://%s:%s" % (hostName, serverPort))
116     try:
117         webServer.serve_forever()
118     except KeyboardInterrupt:
119         pass
120     webServer.server_close()
121     print("Server stopped.")