home · contact · privacy
Add ledger editing to ledger.py.
authorChristian Heller <c.heller@plomlompom.de>
Fri, 13 Oct 2023 03:00:20 +0000 (05:00 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Fri, 13 Oct 2023 03:00:20 +0000 (05:00 +0200)
ledger.py

index c3f0ab9c22d028d92b1c2741e7c411a4d9efa499..9fa9f14a5ae7d1816175148d96b06de029d8346b 100755 (executable)
--- a/ledger.py
+++ b/ledger.py
@@ -1,6 +1,7 @@
 from http.server import BaseHTTPRequestHandler, HTTPServer
 import sys
 import os
+from urllib.parse import parse_qs
 hostName = "localhost"
 serverPort = 8082
 
@@ -32,6 +33,7 @@ def parse_lines(lines):
     start_line = 0
     bookings = []
     comments = []
+    lines += [''] # to ensure a booking-ending last line
     for i, line in enumerate(lines):
         prefix = f"line {i}"
         # we start with the case of an utterly empty line
@@ -205,17 +207,32 @@ class Booking:
 
 class Database:
 
-    def __init__(self, load_from_file=True):
+    def __init__(self):
         db_name = "_ledger"
         self.db_file = db_name + ".json"
         self.lock_file = db_name+ ".lock"
         self.bookings = []
         self.comments = []
-        if load_from_file and os.path.exists(self.db_file):
+        self.real_lines = []
+        if os.path.exists(self.db_file):
             with open(self.db_file, "r") as f:
-                ret = parse_lines(f.readlines())
-                self.bookings += ret[0]
-                self.comments += ret[1]
+                self.real_lines += f.readlines()
+        ret = parse_lines(self.real_lines)
+        self.bookings += ret[0]
+        self.comments += ret[1]
+
+    def replace(self, start, end, lines):
+        import shutil
+        if os.path.exists(self.lock_file):
+            raise HandledException('Sorry, lock file!')
+        if os.path.exists(self.db_file):
+            shutil.copy(self.db_file, self.db_file + ".bak")
+        f = open(self.lock_file, 'w+')
+        f.close()
+        text = ''.join(self.real_lines[:start]) + '\n'.join(lines) + ''.join(self.real_lines[end:])
+        with open(self.db_file, 'w') as f:
+            f.write(text);
+        os.remove(self.lock_file)
 
     def append(self, lines):
         import shutil
@@ -235,13 +252,18 @@ class MyServer(BaseHTTPRequestHandler):
     footer = '</body><html>'
 
     def do_POST(self):
-        from urllib.parse import parse_qs
         length = int(self.headers['content-length'])
         postvars = parse_qs(self.rfile.read(length).decode(), keep_blank_values=1)
         lines = postvars['booking'][0].splitlines()
+        start = int(postvars['start'][0])
+        end = int(postvars['end'][0])
         try:
-            bookings, comments = parse_lines(lines)
-            db.append(lines)
+            _, _ = parse_lines(lines)
+            if start == end == 0:
+                db.append(lines)
+            else:
+                # raise HandledException(f'would write from {start} to {end}')
+                db.replace(start, end, lines)
             self.send_response(200)
             self.end_headers()
             page = f"{self.header}Success!{self.footer}"
@@ -253,15 +275,20 @@ class MyServer(BaseHTTPRequestHandler):
             self.wfile.write(bytes(page, "utf-8"))
 
     def do_GET(self):
+        from urllib.parse import urlparse
         self.send_response(200)
         self.send_header("Content-type", "text/html")
         self.end_headers()
         db = Database()
         page = self.header + ''
-        if self.path == '/balance':
+        parsed_url = urlparse(self.path)
+        if parsed_url.path == '/balance':
             page += self.balance_as_html(db)
-        elif self.path == '/add':
-            page += self.add()
+        elif parsed_url.path == '/add':
+            params = parse_qs(parsed_url.query)
+            start = int(params.get('start', ['0'])[0])
+            end = int(params.get('end', ['0'])[0])
+            page += self.add(db, start, end)
         else:
             page += self.ledger_as_html(db)
         page += self.footer
@@ -332,28 +359,34 @@ class MyServer(BaseHTTPRequestHandler):
 
     def ledger_as_html(self, db):
         lines = []
+        line_sep = '<br />'
         for comment in db.comments:
-            lines += [f"; {comment}" if comment != '' else '']
+            line = f'; {comment}' if comment != '' else ''
+            lines += [line + line_sep]
         for booking in db.bookings:
             i = booking.start_line
-            suffix = f" {lines[i]}" if len(lines[i]) > 0 else ""
-            lines[i] = f"{booking.date_string} {booking.description}{suffix}"
+            suffix = lines[i] # f" {lines[i]}" if len(lines[i]) > 0 else ""
+            lines[i] = f'<p>{booking.date_string} {booking.description}{suffix}'
             for booking_line in booking.lines:
                 i += 1
                 if booking_line == '':
                     continue
-                suffix = f" {lines[i]}" if len(lines[i]) > 0 else ""
-                value = f" {booking_line[1]} {booking_line[2]}" if booking_line[1] else ""
-                lines[i] = f"{booking_line[0]}{value}{suffix}"
-        content = "\n".join(lines)
-        return f"<pre>{content}</pre>"
+                suffix = f' {lines[i]}' if len(lines[i]) > 0 else ''
+                value = f' {booking_line[1]} {booking_line[2]}' if booking_line[1] else ''
+                lines[i] = f'{booking_line[0]}{value}{suffix}'
+            lines[i] = lines[i][:-len(line_sep)] + f'</p><a href="/add?start={booking.start_line}&end={i+1}">edit</a><br />'
+        return '\n'.join(lines)
 
-    def add(self):
-        return '<form method="POST" action="/"><textarea name="booking" rows="8" cols="80"></textarea><input type="submit"></form>'
+    def add(self, db, start=0, end=0):
+        if start == end == 0:
+            content = ''
+        else:
+            content = ''.join(db.real_lines[start:end])
+        return f'<form method="POST" action="/"><textarea name="booking" rows="8" cols="80">{content}</textarea><input type="hidden" name="start" value={start} /><input type="hidden" name="end" value={end} /><input type="submit"></form>'
 
 
 db = Database()
-if __name__ == "__main__":      
+if __name__ == "__main__":     
     webServer = HTTPServer((hostName, serverPort), MyServer)
     print(f"Server started http://{hostName}:{serverPort}")
     try: