From 99e4d37a9a4442adb1c8f5a1878dbcc0fdd58dc0 Mon Sep 17 00:00:00 2001 From: Raulillo <36534958+r4ulill0@users.noreply.github.com> Date: Sun, 19 Feb 2023 21:29:24 +0100 Subject: [PATCH] Implement undo solving pimutils/todoman#505 --- todoman/cli.py | 24 ++++++++++++++++++++++++ todoman/model.py | 21 +++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/todoman/cli.py b/todoman/cli.py index 774c4f40..ce7bef16 100644 --- a/todoman/cli.py +++ b/todoman/cli.py @@ -467,6 +467,30 @@ def done(ctx, todos): click.echo(ctx.formatter.detailed(todo)) +@cli.command() +@pass_ctx +@click.argument( + "todos", + nargs=-1, + required=True, + type=click.IntRange(0), + callback=_validate_todos, +) +# @catch_errors +def undo(ctx, todos): + """Undo one or more tasks.""" + toremove = [] + for todo in todos: + removable = todo.undo() + if removable: + toremove.append(removable) + ctx.db.save(todo) + click.echo(ctx.formatter.detailed(todo)) + + for todo in toremove: + ctx.db.delete(todo) + + @cli.command() @pass_ctx @click.argument( diff --git a/todoman/model.py b/todoman/model.py index bb4044a3..a14a2448 100644 --- a/todoman/model.py +++ b/todoman/model.py @@ -252,6 +252,27 @@ def complete(self) -> None: self.percent_complete = 100 self.status = "COMPLETED" + def undo(self) -> Todo | None: + """ + Immediately restores this todo. Marks it as needs action, resets the + percentage to 0 and deletes the completed_at datetime. + + If this todo belongs to a series, the one created at completion will + be deleted. + + Returns the todo that will be deleted. + """ + original = None + if self.is_recurring and self.related: + original = self.related.pop() + self.rrule = original.rrule + + self.completed_at = None + self.percent_complete = 0 + self.status = "NEEDS-ACTION" + + return original + @cached_property def path(self) -> str: if not self.list: