From c018936a82d6caa32affe9c01af8f1d68e568a70 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 16 Oct 2023 23:10:22 +0200 Subject: [PATCH] To ledger.py add structured next to free textarea editing of bookings. --- ledger.py | 97 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 79 insertions(+), 18 deletions(-) diff --git a/ledger.py b/ledger.py index 9fa9f14..412c27d 100755 --- a/ledger.py +++ b/ledger.py @@ -1,7 +1,8 @@ from http.server import BaseHTTPRequestHandler, HTTPServer import sys import os -from urllib.parse import parse_qs +import html +from urllib.parse import parse_qs, urlparse hostName = "localhost" serverPort = 8082 @@ -75,6 +76,7 @@ def parse_lines(lines): except IndexError: raise HandledException(f"{prefix} bad description: {description}") inside_booking = True + booking_lines += [non_comment] continue # otherwise, read as transfer data toks = non_comment.split() # ignore specification's allowance of single spaces in names @@ -158,7 +160,7 @@ class Booking: prefix = f"booking at line {self.start_line}" sums = {} empty_values = 0 - for line in self.lines: + for line in self.lines[1:]: if line == '': continue _, amount, currency = line @@ -186,7 +188,7 @@ class Booking: account_changes = {} debt = {} sink_account = None - for line in self.lines: + for line in self.lines[1:]: if line == '': continue account, amount, currency = line @@ -248,13 +250,31 @@ class Database: class MyServer(BaseHTTPRequestHandler): - header = 'ledger balance add
' + header = 'ledger balance add free add structured
' footer = '' def do_POST(self): length = int(self.headers['content-length']) postvars = parse_qs(self.rfile.read(length).decode(), keep_blank_values=1) - lines = postvars['booking'][0].splitlines() + parsed_url = urlparse(self.path) + + if '/add_structured' == parsed_url.path: + n_lines = int(len(postvars) / 4) + date = postvars['date'][0] + description = postvars['description'][0] + start_comment = postvars['line_0_comment'][0] + lines = [f'{date} {description} ; {start_comment}'] + for i in range(1, n_lines): + account = postvars[f'line_{i}_account'][0] + amount = postvars[f'line_{i}_amount'][0] + currency = postvars[f'line_{i}_currency'][0] + comment = postvars[f'line_{i}_comment'][0] + new_main = f'{account} {amount} {currency}' + if '' == new_main.rstrip() == comment.rstrip(): + continue + lines += [f'{new_main} ; {comment}'] + elif '/add_free' == parsed_url.path: + lines = postvars['booking'][0].splitlines() start = int(postvars['start'][0]) end = int(postvars['end'][0]) try: @@ -262,33 +282,37 @@ class MyServer(BaseHTTPRequestHandler): 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}" + page = f'{self.header}Success!{self.footer}' self.wfile.write(bytes(page, "utf-8")) except HandledException as e: self.send_response(400) self.end_headers() - page = f"{self.header}{e}{self.footer}" + page = f'{self.header}{e}{self.footer}' 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 + '' parsed_url = urlparse(self.path) + page = self.header + '' if parsed_url.path == '/balance': page += self.balance_as_html(db) - elif parsed_url.path == '/add': + elif parsed_url.path == '/add_free': + params = parse_qs(parsed_url.query) + start = int(params.get('start', ['0'])[0]) + end = int(params.get('end', ['0'])[0]) + page += self.add_free(db, start, end) + elif parsed_url.path == '/add_structured': 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) + bonus_lines = int(params.get('bonus_lines', ['0'])[0]) + page += self.add_structured(db, start, end) else: page += self.ledger_as_html(db) page += self.footer @@ -365,24 +389,61 @@ class MyServer(BaseHTTPRequestHandler): lines += [line + line_sep] for booking in db.bookings: i = booking.start_line - suffix = lines[i] # f" {lines[i]}" if len(lines[i]) > 0 else "" + suffix = lines[i] lines[i] = f'

{booking.date_string} {booking.description}{suffix}' - for booking_line in booking.lines: + for booking_line in booking.lines[1:]: 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}' - lines[i] = lines[i][:-len(line_sep)] + f'

edit
' + lines[i] = lines[i][:-len(line_sep)] + f'

edit: structured / free
' return '\n'.join(lines) - def add(self, db, start=0, end=0): + def add_free(self, db, start=0, end=0): if start == end == 0: content = '' else: - content = ''.join(db.real_lines[start:end]) - return f'
' + content = html.escape(''.join(db.real_lines[start:end])) + return f'
' + + def add_structured(self, db, start=0, end=0, bonus_lines=10): + if start == end == 0: + lines = [] + else: + lines= db.real_lines[start:end] + bookings, comments = parse_lines(lines) + if len(bookings) > 1: + raise HandledException('can only edit single Booking') + input_lines = '' + if len(bookings) == 0: + input_lines += f' ;
' + comments = [''] + else: + booking = bookings[0] + if booking.start_line != 0: + raise HandledException('need to start on first Booking line') + for i, comment in enumerate(comments): + if i == 0: + safe_date_string = html.escape(booking.date_string) + safe_description = html.escape(booking.description) + safe_comment = html.escape(comment) + input_lines += f' ;
' + continue + safe_account = safe_amount = safe_currency = '' + safe_comment = html.escape(comment) + if i < len(booking.lines): + main = booking.lines[i] + if main != '': + safe_account = html.escape(main[0]) + safe_amount = '' if main[1] is None else html.escape(str(main[1])) + safe_currency = '' if main[2] is None else html.escape(main[2]) + input_lines += f' ;
' + for j in range(bonus_lines): + i = j + len(comments) + input_lines += f' ;
' + return f'
{input_lines}
' db = Database() -- 2.30.2