- id_ = self.params.get_int('id')
- for _ in self.form_data.get_all_str('delete'):
- todo = Todo .by_id(self.conn, id_)
- todo.remove(self.conn)
- return '/'
- todo = Todo.by_id(self.conn, id_)
- adopted_child_ids = self.form_data.get_all_int('adopt')
- processes_to_make_full = self.form_data.get_all_int('make_full')
- processes_to_make_empty = self.form_data.get_all_int('make_empty')
- fill_fors = self.form_data.get_first_strings_starting('fill_for_')
- for v in fill_fors.values():
- if v.startswith('make_empty_'):
- processes_to_make_empty += [int(v[11:])]
- elif v.startswith('make_full_'):
- processes_to_make_full += [int(v[10:])]
- elif v != 'ignore':
- adopted_child_ids += [int(v)]
- to_remove = []
- for child in todo.children:
- assert isinstance(child.id_, int)
- if child.id_ not in adopted_child_ids:
- to_remove += [child.id_]
- for id_ in to_remove:
- child = Todo.by_id(self.conn, 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)
- for process_id in processes_to_make_empty:
- process = Process.by_id(self.conn, process_id)
- made = Todo(None, process, False, todo.date)
- 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)
- todo.add_child(made)
- effort = self.form_data.get_str('effort', ignore_strict=True)
- todo.effort = float(effort) if effort else None
- todo.set_conditions(self.conn,
- self.form_data.get_all_int('condition'))
- todo.set_blockers(self.conn, self.form_data.get_all_int('blocker'))
- todo.set_enables(self.conn, self.form_data.get_all_int('enables'))
- todo.set_disables(self.conn, self.form_data.get_all_int('disables'))
- todo.is_done = len(self.form_data.get_all_str('done')) > 0
- todo.calendarize = len(self.form_data.get_all_str('calendarize')) > 0
- todo.comment = self.form_data.get_str('comment', ignore_strict=True)
- todo.save(self.conn)
- for condition in todo.enables:
- condition.save(self.conn)
- for condition in todo.disables:
- condition.save(self.conn)
- return f'/todo?id={todo.id_}'
-
- def _do_POST_versioned_timestamps(self, cls: Any, attr_name: str) -> str:
- """Update history timestamps for VersionedAttribute."""
- id_ = self.params.get_int_or_none('id')
- item = cls.by_id(self.conn, id_)
- attr = getattr(item, attr_name)
- for k, v in self.form_data.get_first_strings_starting('at:').items():
- old = k[3:]
- if old[19:] != v:
- attr.reset_timestamp(old, f'{v}.0')
- attr.save(self.conn)
- cls_name = cls.__name__.lower()
- return f'/{cls_name}_{attr_name}s?id={item.id_}'
+ # pylint: disable=too-many-statements
+ assert todo.id_ is not None
+ adoptees = [(id_, todo.id_) for id_ in self._form.get_all_int('adopt')]
+ to_make = {'full': [(id_, todo.id_)
+ for id_ in self._form.get_all_int('make_full')],
+ 'empty': [(id_, todo.id_)
+ for id_ in self._form.get_all_int('make_empty')]}
+ step_fillers_to = self._form.get_all_of_key_prefixed('step_filler_to_')
+ to_update: dict[str, Any] = {
+ 'comment': self._form.get_str_or_fail('comment', '')}
+ for k in ('is_done', 'calendarize'):
+ v = self._form.get_bool_or_none(k)
+ if v is not None:
+ to_update[k] = v
+ cond_rels = [self._form.get_all_int(name) for name in
+ ['conditions', 'blockers', 'enables', 'disables']]
+ effort_or_not = self._form.get_str('effort')
+ if effort_or_not is not None:
+ if effort_or_not == '':
+ to_update['effort'] = None
+ else:
+ try:
+ to_update['effort'] = float(effort_or_not)
+ except ValueError as e:
+ msg = 'cannot float form field value for key: effort'
+ raise BadFormatException(msg) from e
+ for k, fillers in step_fillers_to.items():
+ try:
+ parent_id = int(k)
+ except ValueError as e:
+ msg = f'bad step_filler_to_ key: {k}'
+ raise BadFormatException(msg) from e
+ for filler in [f for f in fillers if f != 'ignore']:
+ target_id: int
+ prefix = 'make_'
+ to_int = filler[5:] if filler.startswith(prefix) else filler
+ try:
+ target_id = int(to_int)
+ except ValueError as e:
+ msg = f'bad fill_for target: {filler}'
+ raise BadFormatException(msg) from e
+ if filler.startswith(prefix):
+ to_make['empty'] += [(target_id, parent_id)]
+ else:
+ adoptees += [(target_id, parent_id)]
+ #
+ todo.set_condition_relations(self._conn, *cond_rels)
+ for parent in [Todo.by_id(self._conn, a[1])
+ for a in adoptees] + [todo]:
+ for child in parent.children:
+ if child not in [t[0] for t in adoptees
+ if t[0] == child.id_ and t[1] == parent.id_]:
+ parent.remove_child(child)
+ parent.save(self._conn)
+ for child_id, parent_id in adoptees:
+ parent = Todo.by_id(self._conn, parent_id)
+ if child_id not in [c.id_ for c in parent.children]:
+ parent.add_child(Todo.by_id(self._conn, child_id))
+ parent.save(self._conn)
+ todo.update_attrs(**to_update)
+ for approach, make_data in to_make.items():
+ for process_id, parent_id in make_data:
+ parent = Todo.by_id(self._conn, parent_id)
+ process = Process.by_id(self._conn, process_id)
+ made = Todo(None, process, False, todo.date)
+ made.save(self._conn)
+ if 'full' == approach:
+ made.ensure_children(self._conn)
+ parent.add_child(made)
+ parent.save(self._conn)
+ # todo.save() may destroy Todo if .effort < 0, so retrieve .id_ early
+ url = f'/todo?id={todo.id_}'
+ todo.save(self._conn)
+ return url