home · contact · privacy
Allow Todo adoptions to be un-done in Todo view.
authorChristian Heller <c.heller@plomlompom.de>
Mon, 22 Apr 2024 00:13:39 +0000 (02:13 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Mon, 22 Apr 2024 00:13:39 +0000 (02:13 +0200)
plomtask/http.py
plomtask/todos.py
templates/todo.html
tests/todos.py

index e541057ed793ebe2a53c55b50a11be7133c5884f..b5a6c167b98f36c5b4ffb6e0c3d0ea14869101a7 100644 (file)
@@ -205,8 +205,15 @@ class TaskHandler(BaseHTTPRequestHandler):
         """Update Todo and its children."""
         id_ = self.params.get_int('id')
         todo = Todo.by_id(self.conn, id_)
-        child_id = self.form_data.get_int_or_none('adopt')
-        if child_id is not None:
+        adopted_child_ids = self.form_data.get_all_int('adopt')
+        for child in todo.children:
+            if child.id_ not in adopted_child_ids:
+                assert isinstance(child.id_, int)
+                child = Todo.by_id(self.conn, child.id_)
+                todo.remove_child(child)
+        for child_id in adopted_child_ids:
+            if child_id in [c.id_ for c in todo.children]:
+                continue
             child = Todo.by_id(self.conn, child_id)
             todo.add_child(child)
         todo.set_conditions(self.conn, self.form_data.get_all_int('condition'))
index 336ec0350830ce5dfbdf5e85a92b3945608835d9..cf4c33048ba779fb2145e21a4f325f55b6bfe024 100644 (file)
@@ -170,7 +170,7 @@ class Todo(BaseModel, ConditionsRelations):
         return node
 
     def add_child(self, child: Todo) -> None:
-        """Add child to self.children, guard against recursion"""
+        """Add child to self.children, avoid recursion, update parenthoods."""
         def walk_steps(node: Todo) -> None:
             if node.id_ == self.id_:
                 raise BadFormatException('bad child choice causes recursion')
@@ -186,6 +186,13 @@ class Todo(BaseModel, ConditionsRelations):
         self.children += [child]
         child.parents += [self]
 
+    def remove_child(self, child: Todo) -> None:
+        """Remove child from self.children, update counter relations."""
+        if child not in self.children:
+            raise HandledException('Cannot remove un-parented child.')
+        self.children.remove(child)
+        child.parents.remove(self)
+
     def save(self, db_conn: DatabaseConnection) -> None:
         """Write self and children to DB and its cache."""
         if self.process.id_ is None:
index 92b065734c97b22fb6ff9e2f499f9460448797b1..9debffc0ad96db9d661dde5fcd343e3554d1aba5 100644 (file)
@@ -65,7 +65,8 @@ add disables: <input name="disables" list="condition_candidates" autocomplete="o
 <h4>children</h4>
 <ul>
 {% for child in todo.children %}
-<li><a href="todo?id={{child.id_}}">{{child.process.title.newest|e}}</a>
+<li><input type="checkbox" name="adopt" value="{{child.id_}}" checked />
+<a href="todo?id={{child.id_}}">{{child.process.title.newest|e}}</a>
 {% endfor %}
 </ul>
 adopt: <input name="adopt" list="todo_candidates" autocomplete="off" />
index 52363c07b7ddbd49ba8a2ee8e4f09adda68fb16e..4ab34abe2d2c92f3121688ee9ccea7bf30944332 100644 (file)
@@ -270,9 +270,9 @@ class TestsWithServer(TestCaseWithServer):
             return Todo.by_date(self.db_conn, '2024-01-01')[0]
         # test minimum
         form_data = {'title': '', 'description': '', 'effort': 1}
-        self.check_post(form_data, '/process', 302, '/')
+        self.check_post(form_data, '/process', 302)
         form_data = {'comment': '', 'new_todo': 1}
-        self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
+        self.check_post(form_data, '/day?date=2024-01-01', 302)
         # test posting to bad URLs
         form_data = {}
         self.check_post(form_data, '/todo=', 404)
@@ -301,7 +301,7 @@ class TestsWithServer(TestCaseWithServer):
         self.check_post(form_data, '/todo?id=1', 404)
         # test posting second todo of same process
         form_data = {'comment': '', 'new_todo': 1}
-        self.check_post(form_data, '/day?date=2024-01-01', 302, '/')
+        self.check_post(form_data, '/day?date=2024-01-01', 302)
         # test todo 1 adopting todo 2
         form_data = {'adopt': 2}
         todo1 = post_and_reload(form_data)
@@ -310,12 +310,18 @@ class TestsWithServer(TestCaseWithServer):
         self.assertEqual(todo1.parents, [])
         self.assertEqual(todo2.children, [])
         self.assertEqual(todo2.parents, [todo1])
-        # test failure of re-adopting same child
-        self.check_post(form_data, '/todo?id=1', 400, '/')
         # test todo1 cannot be set done with todo2 not done yet
-        form_data = {'done': ''}
+        form_data = {'done': '', 'adopt': 2}
         todo1 = post_and_reload(form_data, 400)
         self.assertEqual(todo1.is_done, False)
+        # test todo1 un-adopting todo 2 by just not sending an adopt
+        form_data = {}
+        todo1 = post_and_reload(form_data, 302)
+        todo2 = Todo.by_date(self.db_conn, '2024-01-01')[1]
+        self.assertEqual(todo1.children, [])
+        self.assertEqual(todo1.parents, [])
+        self.assertEqual(todo2.children, [])
+        self.assertEqual(todo2.parents, [])
 
     def test_do_GET_todo(self) -> None:
         """Test GET /todo response codes."""