From d7c035ef9a98ebe3c6fc52f0b48b3d5170efd8ff Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Fri, 2 Aug 2024 11:29:43 +0200 Subject: [PATCH] Ensure POST /day "new_todo" item order commutative. --- plomtask/http.py | 23 ++++++++++++++--------- plomtask/todos.py | 28 +++++++++------------------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/plomtask/http.py b/plomtask/http.py index 15c17db..36a5d78 100644 --- a/plomtask/http.py +++ b/plomtask/http.py @@ -596,7 +596,7 @@ class TaskHandler(BaseHTTPRequestHandler): except NotFoundException as e: raise BadFormatException from e old_todos = self._form_data.get_all_int('todo_id') - new_todos = self._form_data.get_all_int('new_todo') + new_todos_by_process = self._form_data.get_all_int('new_todo') comments = self._form_data.get_all_str('comment') efforts = self._form_data.get_all_floats_or_nones('effort') done_todos = self._form_data.get_all_int('done') @@ -611,13 +611,15 @@ class TaskHandler(BaseHTTPRequestHandler): day = Day.by_id_or_create(self.conn, date) day.comment = day_comment day.save(self.conn) - for process_id in sorted(new_todos): - if 'empty' == make_type: - process = Process.by_id(self.conn, process_id) - todo = Todo(None, process, False, date) - todo.save(self.conn) - else: - Todo.create_with_children(self.conn, process_id, date) + new_todos = [] + for process_id in sorted(new_todos_by_process): + process = Process.by_id(self.conn, process_id) + todo = Todo(None, process, False, date) + todo.save(self.conn) + new_todos += [todo] + if 'full' == make_type: + for todo in new_todos: + todo.ensure_children(self.conn) for i, todo_id in enumerate(old_todos): todo = Todo.by_id(self.conn, todo_id) todo.is_done = is_done[i] @@ -679,7 +681,10 @@ class TaskHandler(BaseHTTPRequestHandler): made.save(self.conn) todo.add_child(made) for process_id in processes_to_make_full: - made = Todo.create_with_children(self.conn, process_id, todo.date) + process = Process.by_id(self.conn, process_id) + made = Todo(None, process, False, todo.date) + made.save(self.conn) + made.ensure_children(self.conn) todo.add_child(made) todo.set_condition_relations(self.conn, *cond_rel_id_lists) todo.update_attrs(**to_update) diff --git a/plomtask/todos.py b/plomtask/todos.py index 03c454c..5782df0 100644 --- a/plomtask/todos.py +++ b/plomtask/todos.py @@ -117,23 +117,15 @@ class Todo(BaseModel[int], ConditionsRelations): todos, _, _ = cls.by_date_range_with_limits(db_conn, date_range) return todos - @classmethod - def create_with_children(cls, db_conn: DatabaseConnection, - process_id: int, date: str) -> Todo: - """Create Todo of process for date, ensure children demanded by chain. - - At minimum creates Todo of process_id, but checks the respective - Process for its step tree, and walks down that to provide the initial - Todo with all descendants defined there, either adopting existing - Todos, or creating them where necessary. - """ + def ensure_children(self, db_conn: DatabaseConnection) -> None: + """Ensure Todo children (create or adopt) demanded by Process chain.""" def key_order_func(n: ProcessStepsNode) -> int: assert isinstance(n.process.id_, int) return n.process.id_ def walk_steps(parent: Todo, step_node: ProcessStepsNode) -> Todo: - adoptables = [t for t in cls.by_date(db_conn, date) + adoptables = [t for t in Todo.by_date(db_conn, parent.date) if (t not in parent.children) and (t != parent) and step_node.process == t.process] @@ -142,7 +134,7 @@ class Todo(BaseModel[int], ConditionsRelations): satisfier = adoptable break if not satisfier: - satisfier = cls(None, step_node.process, False, date) + satisfier = Todo(None, step_node.process, False, parent.date) satisfier.save(db_conn) sub_step_nodes = list(step_node.steps.values()) sub_step_nodes.sort(key=key_order_func) @@ -160,16 +152,13 @@ class Todo(BaseModel[int], ConditionsRelations): satisfier.save(db_conn) return satisfier - process = Process.by_id(db_conn, process_id) - todo = cls(None, process, False, date) - todo.save(db_conn) + process = Process.by_id(db_conn, self.process_id) steps_tree = process.get_steps(db_conn) for step_node in steps_tree.values(): if step_node.is_suppressed: continue - todo.add_child(walk_steps(todo, step_node)) - todo.save(db_conn) - return todo + self.add_child(walk_steps(self, step_node)) + self.save(db_conn) @classmethod def from_table_row(cls, db_conn: DatabaseConnection, @@ -241,8 +230,9 @@ class Todo(BaseModel[int], ConditionsRelations): return 0 @property - def process_id(self) -> int | str | None: + def process_id(self) -> int: """Needed for super().save to save Processes as attributes.""" + assert isinstance(self.process.id_, int) return self.process.id_ @property -- 2.30.2