feat: show tasks completed today
This commit is contained in:
+18
-4
@@ -1024,6 +1024,8 @@ async def list_tasks(
|
||||
completed: bool | None = None,
|
||||
due_from: datetime | None = None,
|
||||
due_to: datetime | None = None,
|
||||
completed_from: datetime | None = None,
|
||||
completed_to: datetime | None = None,
|
||||
cursor: str | None = None,
|
||||
page: int | None = Query(default=None, ge=1),
|
||||
page_size: int | None = Query(default=None, ge=1, le=100),
|
||||
@@ -1048,10 +1050,20 @@ async def list_tasks(
|
||||
query = query.where(Task.list_id == list_id)
|
||||
if completed is not None:
|
||||
query = query.where(Task.completed.is_(completed))
|
||||
if due_from is not None:
|
||||
query = query.where(Task.due_at >= due_from)
|
||||
if due_to is not None:
|
||||
query = query.where(Task.due_at < due_to)
|
||||
if due_from is not None and due_to is not None and completed_from is not None and completed_to is not None:
|
||||
query = query.where(or_(
|
||||
and_(Task.due_at >= due_from, Task.due_at < due_to),
|
||||
and_(Task.completed_at >= completed_from, Task.completed_at < completed_to),
|
||||
))
|
||||
else:
|
||||
if due_from is not None:
|
||||
query = query.where(Task.due_at >= due_from)
|
||||
if due_to is not None:
|
||||
query = query.where(Task.due_at < due_to)
|
||||
if completed_from is not None:
|
||||
query = query.where(Task.completed_at >= completed_from)
|
||||
if completed_to is not None:
|
||||
query = query.where(Task.completed_at < completed_to)
|
||||
if q:
|
||||
pattern = f"%{q}%"
|
||||
list_match = exists(
|
||||
@@ -1355,6 +1367,8 @@ async def batch_update_tasks(
|
||||
if payload.soft_delete:
|
||||
changes["deleted_at"] = utcnow()
|
||||
if changes:
|
||||
if changes.get("completed") is False:
|
||||
changes["completed_at"] = None
|
||||
changes["version"] = Task.version + 1
|
||||
changes["updated_at"] = utcnow()
|
||||
target_ids = set(task_ids)
|
||||
|
||||
@@ -133,6 +133,7 @@ class Task(Base):
|
||||
description: Mapped[str] = mapped_column(Text, default="")
|
||||
priority: Mapped[int] = mapped_column(Integer, default=0)
|
||||
completed: Mapped[bool] = mapped_column(Boolean, default=False, index=True)
|
||||
completed_at: Mapped[datetime | None] = mapped_column(UTCDateTime(), nullable=True, index=True)
|
||||
due_at: Mapped[datetime | None] = mapped_column(UTCDateTime(), nullable=True)
|
||||
due_has_time: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
version: Mapped[int] = mapped_column(Integer, default=1)
|
||||
|
||||
+2
-1
@@ -1301,7 +1301,7 @@ def _export_payload(folders, lists, tasks, recurrences, habits, countdowns, memo
|
||||
"exported_at": utcnow().isoformat(),
|
||||
"folders": [serialize(x, ["id", "name", "position", "deleted_at"]) for x in folders],
|
||||
"lists": [serialize(x, ["id", "folder_id", "name", "is_inbox", "position", "deleted_at"]) for x in lists],
|
||||
"tasks": [serialize(x, ["id", "list_id", "parent_id", "title", "description", "priority", "completed", "due_at", "due_has_time", "external_id", "deleted_at"]) for x in tasks],
|
||||
"tasks": [serialize(x, ["id", "list_id", "parent_id", "title", "description", "priority", "completed", "completed_at", "due_at", "due_has_time", "external_id", "deleted_at"]) for x in tasks],
|
||||
"recurrences": [serialize(x, ["id", "task_id", "rrule", "starts_at", "ends_at", "trigger_mode", "after_completion_days", "last_completed_at"]) for x in recurrences],
|
||||
"habits": [serialize(x, ["id", "name", "kind", "target", "max_value", "schedule_type", "weekdays", "month_days", "interval_days", "start_date", "archived_at", "position"]) for x in habits],
|
||||
"countdowns": [serialize(x, ["id", "title", "event_date", "calendar_mode", "lunar_month", "lunar_day", "ignore_year", "kind", "repeat_rule", "icon", "pinned", "archived_at", "created_at", "updated_at"]) for x in countdowns],
|
||||
@@ -1487,6 +1487,7 @@ async def restore_json(payload: dict, mode: str = Query("merge", pattern="^(merg
|
||||
description=raw.get("description", ""),
|
||||
priority=raw.get("priority", 0),
|
||||
completed=raw.get("completed", False),
|
||||
completed_at=datetime.fromisoformat(raw["completed_at"]) if raw.get("completed_at") else None,
|
||||
due_at=datetime.fromisoformat(raw["due_at"]) if raw.get("due_at") else None,
|
||||
due_has_time=raw.get("due_has_time", True),
|
||||
external_id=ext,
|
||||
|
||||
@@ -96,6 +96,10 @@ async def apply_task_changes(
|
||||
recurrence.starts_at = changes["due_at"]
|
||||
|
||||
now = utcnow()
|
||||
if changes.get("completed") is True and not task.completed:
|
||||
changes["completed_at"] = now
|
||||
elif changes.get("completed") is False:
|
||||
changes["completed_at"] = None
|
||||
result = await db.execute(
|
||||
update(Task)
|
||||
.where(
|
||||
@@ -120,6 +124,6 @@ async def apply_task_changes(
|
||||
Task.deleted_at.is_(None),
|
||||
Task.completed.is_(True),
|
||||
)
|
||||
.values(completed=False, version=Task.version + 1, updated_at=now)
|
||||
.values(completed=False, completed_at=None, version=Task.version + 1, updated_at=now)
|
||||
)
|
||||
return updated_task, changed
|
||||
|
||||
@@ -198,6 +198,7 @@ class TaskOut(BaseModel):
|
||||
description: str
|
||||
priority: int
|
||||
completed: bool
|
||||
completed_at: datetime | None
|
||||
due_at: datetime | None
|
||||
due_has_time: bool
|
||||
version: int
|
||||
|
||||
Reference in New Issue
Block a user