home · contact · privacy
On POSTing new Todos on Day view, ensure possible adoptions within them.
authorChristian Heller <c.heller@plomlompom.de>
Wed, 15 May 2024 02:10:27 +0000 (04:10 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Wed, 15 May 2024 02:10:27 +0000 (04:10 +0200)
plomtask/http.py
plomtask/todos.py
templates/day.html
tests/todos.py

index a1f85fdd6519dabefa9acc795d43d8720c5024af..d411124c475f9378e3622083eb9bb5fc706ea14e 100644 (file)
@@ -196,14 +196,21 @@ class TaskHandler(BaseHTTPRequestHandler):
         day = Day.by_id(self.conn, date, create=True)
         day.comment = self.form_data.get_str('comment')
         day.save(self.conn)
-        existing_todos = Todo.by_date(self.conn, date)
+        new_todos = []
         for process_id in self.form_data.get_all_int('new_todo'):
             process = Process.by_id(self.conn, process_id)
             todo = Todo(None, process, False, day.date)
             todo.save(self.conn)
-            todo.adopt_from(existing_todos)
-            todo.make_missing_children(self.conn)
-            todo.save(self.conn)
+            new_todos += [todo]
+        adopted = True
+        while adopted:
+            adopted = False
+            existing_todos = Todo.by_date(self.conn, date)
+            for todo in new_todos:
+                if todo.adopt_from(existing_todos):
+                    adopted = True
+                todo.make_missing_children(self.conn)
+                todo.save(self.conn)
         for todo_id in self.form_data.get_all_int('done'):
             todo = Todo.by_id(self.conn, todo_id)
             todo.is_done = True
index e42c484a56e56e5bcf35b3c8a0c801270619f5bf..4e3a4dba247bd88e5ba3bbf1a33fac49b779bd94 100644 (file)
@@ -126,13 +126,16 @@ class Todo(BaseModel[int], ConditionsRelations):
                 for condition in self.disables:
                     condition.is_active = False
 
-    def adopt_from(self, todos: list[Todo]) -> None:
+    def adopt_from(self, todos: list[Todo]) -> bool:
         """As far as possible, fill unsatisfied dependencies from todos."""
+        adopted = False
         for process_id in self.unsatisfied_dependencies:
             for todo in [t for t in todos if t.process.id_ == process_id
                          and t not in self.children]:
                 self.add_child(todo)
+                adopted = True
                 break
+        return adopted
 
     def make_missing_children(self, db_conn: DatabaseConnection) -> None:
         """Fill unsatisfied dependencies with new Todos."""
index f13eb5c309750d01a7f366c2a85255ccb44d4bd9..167b70394963e552ec270a05384ccf47e32259af 100644 (file)
@@ -38,7 +38,7 @@ td.todo_line {
 {% endfor %}
 
 <td class="todo_line">-&gt;</td>
-<td class="todo_line"><input type="checkbox" {% if node.todo.is_done %}checked disabled{% endif %} {% if not node.todo.is_doable %}disabled{% endif %}/></td>
+<td class="todo_line"><input name="done" type="checkbox" {% if node.todo.is_done %}checked disabled{% endif %} {% if not node.todo.is_doable %}disabled{% endif %}/></td>
 <td class="todo_line">
 {% for i in range(indent) %}&nbsp; {% endfor %} +
 {% if node.seen %}({% endif %}<a href="todo?id={{node.todo.id_}}">{{node.todo.process.title.newest|e}}</a>{% if node.seen %}){% endif %}
index a8219fa7506a8c4c7649dd4eb4952948dd14c9f8..5e9f4b88c28974143d060b9a552214e2454fd39d 100644 (file)
@@ -324,6 +324,39 @@ class TestsWithServer(TestCaseWithServer):
         self.assertEqual(todo2.children, [todo1])
         self.assertEqual(todo2.parents, [])
 
+    def test_do_POST_day_todo_multiple(self) -> None:
+        """Test multiple Todos can be posted to Day view."""
+        form_data = self.post_process()
+        form_data = self.post_process(2)
+        form_data = {'comment': '', 'new_todo': [1, 2]}
+        self.check_post(form_data, '/day?date=2024-01-01', 302)
+        todo1 = Todo.by_date(self.db_conn, '2024-01-01')[0]
+        todo2 = Todo.by_date(self.db_conn, '2024-01-01')[1]
+        self.assertEqual(todo1.process.id_, 1)
+        self.assertEqual(todo2.process.id_, 2)
+
+    def test_do_POST_day_todo_multiple_inner_adoption(self) -> None:
+        """Test multiple Todos can be posted to Day view w. inner adoption."""
+        form_data = self.post_process()
+        form_data = self.post_process(2, form_data | {'new_top_step': 1})
+        form_data = {'comment': '', 'new_todo': [1, 2]}
+        self.check_post(form_data, '/day?date=2024-01-01', 302)
+        todo1 = Todo.by_date(self.db_conn, '2024-01-01')[0]
+        todo2 = Todo.by_date(self.db_conn, '2024-01-01')[1]
+        self.assertEqual(todo1.children, [])
+        self.assertEqual(todo1.parents, [todo2])
+        self.assertEqual(todo2.children, [todo1])
+        self.assertEqual(todo2.parents, [])
+        # check process ID order does not affect end result
+        form_data = {'comment': '', 'new_todo': [2, 1]}
+        self.check_post(form_data, '/day?date=2024-01-02', 302)
+        todo1 = Todo.by_date(self.db_conn, '2024-01-02')[1]
+        todo2 = Todo.by_date(self.db_conn, '2024-01-02')[0]
+        self.assertEqual(todo1.children, [])
+        self.assertEqual(todo1.parents, [todo2])
+        self.assertEqual(todo2.children, [todo1])
+        self.assertEqual(todo2.parents, [])
+
     def test_do_GET_todo(self) -> None:
         """Test GET /todo response codes."""
         self.post_process()