home · contact · privacy
Add basic editing of Bookings, and file saving. master
authorChristian Heller <c.heller@plomlompom.de>
Wed, 22 Jan 2025 23:09:47 +0000 (00:09 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Wed, 22 Jan 2025 23:09:47 +0000 (00:09 +0100)
ledger.py
templates/_base.tmpl
templates/booking.tmpl

index 22e051aecc06ea17d5e636aa053f22eb0595a126..f4dde03af8ccb066953fde5f2ebd699f01d019fa 100755 (executable)
--- a/ledger.py
+++ b/ledger.py
@@ -221,31 +221,53 @@ class Handler(PlomHttpHandler):
 
     def do_POST(self) -> None:
         # pylint: disable=invalid-name,missing-function-docstring
 
     def do_POST(self) -> None:
         # pylint: disable=invalid-name,missing-function-docstring
-        if self.pagename == 'reload':
-            self.server.load()
-        self.redirect(Path(''))
+        if self.pagename == 'file':
+            if 'reload' in self.postvars.as_dict:
+                self.server.load()
+            elif 'save' in self.postvars.as_dict:
+                self.server.save()
+        elif self.pagename == 'edit':
+            id_ = int(self.path_toks[2])
+            old_booking = self.server.bookings[id_]
+            start_idx = self.server.dat_lines.index(old_booking.dat_lines[0])
+            end_idx = self.server.dat_lines.index(old_booking.dat_lines[-1])
+            new_dat_lines = [DatLine(line) for line
+                             in self.postvars.first('booking').splitlines()]
+            self.server.dat_lines = (self.server.dat_lines[:start_idx]
+                                     + new_dat_lines
+                                     + self.server.dat_lines[end_idx+1:])
+            self.server.load_bookings()
+            self.server.tainted = True
+            self.redirect(Path('/').joinpath('booking').joinpath(str(id_)))
+            return
+        self.redirect(Path('/'))
 
     def do_GET(self) -> None:
         # pylint: disable=invalid-name,missing-function-docstring
 
     def do_GET(self) -> None:
         # pylint: disable=invalid-name,missing-function-docstring
+        ctx = {'tainted': self.server.tainted}
+        if self.pagename in {'booking', 'edit'}:
+            ctx['id'] = int(self.path_toks[2])
+            ctx['dat_lines'] = self.server.bookings[ctx['id']].dat_lines
         if self.pagename == 'balance':
             valid, balance_roots = self.server.balance_roots
         if self.pagename == 'balance':
             valid, balance_roots = self.server.balance_roots
-            self.send_rendered(Path('balance.tmpl'), {'roots': balance_roots,
-                                                      'valid': valid})
+            self.send_rendered(Path('balance.tmpl'),
+                               ctx | {'roots': balance_roots, 'valid': valid})
         elif self.pagename == 'booking':
         elif self.pagename == 'booking':
-            self.send_rendered(
-                    Path('booking.tmpl'),
-                    {'dat_lines':
-                     self.server.bookings[int(self.path_toks[2])].dat_lines})
+            self.send_rendered(Path('booking.tmpl'), ctx)
+        elif self.pagename == 'edit':
+            self.send_rendered(Path('edit.tmpl'), ctx)
         elif self.pagename == 'raw':
             self.send_rendered(Path('raw.tmpl'),
         elif self.pagename == 'raw':
             self.send_rendered(Path('raw.tmpl'),
-                               {'dat_lines': self.server.dat_lines})
+                               ctx | {'dat_lines': self.server.dat_lines})
         else:
         else:
-            self.send_rendered(Path('index.tmpl'),
-                               {'dat_lines': self.server.dat_lines_sans_empty})
+            self.send_rendered(
+                    Path('index.tmpl'),
+                    ctx | {'dat_lines': self.server.dat_lines_sans_empty})
 
 
 class Server(PlomHttpServer):
     """Extends parent by loading .dat file into database for Handler."""
 
 
 class Server(PlomHttpServer):
     """Extends parent by loading .dat file into database for Handler."""
+    bookings: list[Booking]
 
     def __init__(self, path_dat: Path, *args, **kwargs) -> None:
         super().__init__(PATH_TEMPLATES, (SERVER_HOST, SERVER_PORT), Handler)
 
     def __init__(self, path_dat: Path, *args, **kwargs) -> None:
         super().__init__(PATH_TEMPLATES, (SERVER_HOST, SERVER_PORT), Handler)
@@ -257,7 +279,12 @@ class Server(PlomHttpServer):
         self.dat_lines = [
             DatLine(line)
             for line in self._path_dat.read_text(encoding='utf8').splitlines()]
         self.dat_lines = [
             DatLine(line)
             for line in self._path_dat.read_text(encoding='utf8').splitlines()]
-        self.bookings: list[Booking] = []
+        self.load_bookings()
+        self.tainted = False
+
+    def load_bookings(self) -> None:
+        """Read .dat_lines into Bookings / full ledger."""
+        self.bookings = []
         booking_lines: list[DatLine] = []
         last_date = ''
         for dat_line in self.dat_lines + [DatLine('')]:
         booking_lines: list[DatLine] = []
         last_date = ''
         for dat_line in self.dat_lines + [DatLine('')]:
@@ -272,6 +299,12 @@ class Server(PlomHttpServer):
                 self.bookings += [booking]
                 booking_lines = []
 
                 self.bookings += [booking]
                 booking_lines = []
 
+    def save(self) -> None:
+        """Save current state to ._path_dat."""
+        self._path_dat.write_text(
+            '\n'.join([line.raw for line in self.dat_lines]), encoding='utf8')
+        self.load()
+
     @property
     def dat_lines_sans_empty(self) -> list[DatLine]:
         """Return only those .data_lines with .code or .comment."""
     @property
     def dat_lines_sans_empty(self) -> list[DatLine]:
         """Return only those .data_lines with .code or .comment."""
index 5d80c44da221bf90bde3b85d5c28af1161480f14..a613a1bfe5381ed47641ece8c7fa3a98927ff946 100644 (file)
@@ -7,13 +7,13 @@
 body { background-color: white; font-family: sans-serif; }
 tr:nth-child(odd) { background-color: #dcdcdc; }
 td { text-align: left; vertical-align: top; }
 body { background-color: white; font-family: sans-serif; }
 tr:nth-child(odd) { background-color: #dcdcdc; }
 td { text-align: left; vertical-align: top; }
-table.warning tbody tr td, tr.warning td { background-color: #ff8888; }
+span.warning, table.warning tbody tr td, tr.warning td { background-color: #ff8888; }
 {% block css %}{% endblock %}
 </style>
 </head>
 <body>
 {% block css %}{% endblock %}
 </style>
 </head>
 <body>
-<form action="/reload" method="POST">
-<a href="/">home</a> · <a href="/raw">raw</a> · <a href="/balance">balance</a> · <input type="submit" value="reload" />
+<form action="/file" method="POST">
+<a href="/">home</a> · <a href="/raw">raw</a> · <a href="/balance">balance</a> · <input type="submit" name="reload" value="reload" />{% if tainted %} · <span class="warning">unsaved changes: <input type="submit" name="save" value="save"></span>{% endif %}
 </form>
 <hr />
 {% block content %}{% endblock %}
 </form>
 <hr />
 {% block content %}{% endblock %}
index 2e01a75c0e95326c0e3b11e8e6e762273c509888..9470c2736f72d7efe5b060ba31113f5a2f99c84d 100644 (file)
@@ -7,6 +7,7 @@
 {% endblock %}
 
 {% block content %}
 {% endblock %}
 
 {% block content %}
+<a href="/edit/{{id}}">edit</a>
+<hr />
 {{ macros.table_dat_lines(dat_lines, single=true, raw=false) }}
 {% endblock %}
 {{ macros.table_dat_lines(dat_lines, single=true, raw=false) }}
 {% endblock %}
-