61 lines
1.9 KiB
Python
61 lines
1.9 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime, time, timedelta
|
|
|
|
from ..models import TaskInstance, User
|
|
|
|
|
|
def _ics_escape(value: str | None) -> str:
|
|
text = (value or "").replace("\\", "\\\\")
|
|
text = text.replace(";", "\\;").replace(",", "\\,")
|
|
text = text.replace("\r\n", "\\n").replace("\n", "\\n").replace("\r", "\\n")
|
|
return text
|
|
|
|
|
|
def _format_date(value) -> str:
|
|
return value.strftime("%Y%m%d")
|
|
|
|
|
|
def _format_timestamp(value: datetime | None) -> str:
|
|
timestamp = value or datetime.now(UTC).replace(tzinfo=None)
|
|
return timestamp.strftime("%Y%m%dT%H%M%SZ")
|
|
|
|
|
|
def build_calendar_feed(user: User, base_url: str) -> str:
|
|
tasks = (
|
|
TaskInstance.query.filter_by(assigned_user_id=user.id)
|
|
.order_by(TaskInstance.due_date.asc(), TaskInstance.id.asc())
|
|
.all()
|
|
)
|
|
|
|
lines = [
|
|
"BEGIN:VCALENDAR",
|
|
"VERSION:2.0",
|
|
"PRODID:-//hnz.io//Putzliga//DE",
|
|
"CALSCALE:GREGORIAN",
|
|
"METHOD:PUBLISH",
|
|
f"X-WR-CALNAME:{_ics_escape(f'Putzliga - {user.name}')}",
|
|
f"X-WR-CALDESC:{_ics_escape('Persoenlicher Aufgabenfeed aus Putzliga')}",
|
|
]
|
|
|
|
for task in tasks:
|
|
due_end = task.due_date + timedelta(days=1)
|
|
description = _ics_escape(task.description)
|
|
lines.extend(
|
|
[
|
|
"BEGIN:VEVENT",
|
|
f"UID:taskinstance-{task.id}@putzliga",
|
|
f"DTSTAMP:{_format_timestamp(task.updated_at)}",
|
|
f"LAST-MODIFIED:{_format_timestamp(task.updated_at)}",
|
|
f"SUMMARY:{_ics_escape(task.title)}",
|
|
f"DESCRIPTION:{description}",
|
|
f"DTSTART;VALUE=DATE:{_format_date(task.due_date)}",
|
|
f"DTEND;VALUE=DATE:{_format_date(due_end)}",
|
|
f"URL:{_ics_escape(base_url)}",
|
|
"END:VEVENT",
|
|
]
|
|
)
|
|
|
|
lines.append("END:VCALENDAR")
|
|
return "\r\n".join(lines) + "\r\n"
|