mirror of
https://github.com/skoelle/icloud-contacts-sync.git
synced 2026-09-17 15:30:24 +00:00
birthday unknown year filter
This commit is contained in:
@@ -24,6 +24,7 @@ from api.auth import get_current_user, resolve_account_for_user
|
||||
from api.schemas import ContactListResponse, ContactOut, SyncRunOut
|
||||
from config import Config
|
||||
from mailer import build_message, fetch_birthdays_for_date, send_message
|
||||
from utils import fmt_birthday_age, fmt_birthday_short
|
||||
|
||||
logging.basicConfig(level=Config.LOG_LEVEL, format="%(asctime)s [%(levelname)s] %(message)s")
|
||||
logger = logging.getLogger("api")
|
||||
@@ -33,6 +34,8 @@ app.add_middleware(SessionMiddleware, secret_key=secrets.token_hex(32), session_
|
||||
app.mount("/static", StaticFiles(directory="api/static"), name="static")
|
||||
templates = Jinja2Templates(directory="api/templates")
|
||||
templates.env.filters["urlquote"] = lambda s: quote_plus(s or "")
|
||||
templates.env.filters["fmt_birthday"] = fmt_birthday_short
|
||||
templates.env.filters["fmt_age"] = fmt_birthday_age
|
||||
|
||||
|
||||
def _fmt_ts(dt) -> str | None:
|
||||
|
||||
@@ -332,7 +332,7 @@
|
||||
{% if contact.birthday %}
|
||||
<div class="section">
|
||||
<div class="birthday-highlight">
|
||||
🎂 {{ contact.birthday }}
|
||||
🎂 {{ contact.birthday|fmt_birthday }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -367,7 +367,7 @@
|
||||
<div class="birthday-organization">{{ b.organization }}</div>
|
||||
{% endif %}
|
||||
<div class="birthday-date">
|
||||
{{ b.birthday.strftime('%d.%m.') }}{% if b.birthday.year and b.birthday.year < current_year %} · {{ current_year - b.birthday.year }} Jahre{% endif %}
|
||||
{{ b.birthday|fmt_birthday }}{% if b.birthday|fmt_age %} · {{ b.birthday|fmt_age(current_year) }} Jahre{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if b.photo_url %}
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
<div class="contact-organization">{{ c.organization }}</div>
|
||||
{% endif %}
|
||||
{% if c.birthday %}
|
||||
<div class="contact-birthday">{{ c.birthday }}</div>
|
||||
<div class="contact-birthday">{{ c.birthday|fmt_birthday }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:column;align-items:center;gap:0.3rem">
|
||||
|
||||
+9
-6
@@ -13,6 +13,7 @@ from email.message import EmailMessage
|
||||
|
||||
import db
|
||||
from config import Config
|
||||
from utils import fmt_birthday_age, fmt_birthday_short
|
||||
|
||||
logging.basicConfig(level=Config.LOG_LEVEL, format="%(asctime)s [%(levelname)s] %(message)s")
|
||||
logger = logging.getLogger("mailer")
|
||||
@@ -68,9 +69,10 @@ def build_message(birthdays: list[dict], target_date: date | None = None) -> Ema
|
||||
|
||||
plain_lines = [f"Heutige Geburtstage ({today.isoformat()}):", ""]
|
||||
for b in birthdays:
|
||||
age = today.year - b["birthday"].year
|
||||
date_str = b["birthday"].strftime("%d.%m.")
|
||||
line = f"- {b['full_name']} · {date_str} · {age} Jahre"
|
||||
date_str = fmt_birthday_short(b["birthday"])
|
||||
age = fmt_birthday_age(b["birthday"], today)
|
||||
age_str = f" · {age} Jahre" if age is not None else ""
|
||||
line = f"- {b['full_name']} · {date_str}{age_str}"
|
||||
if b.get("organization"):
|
||||
line += f" ({b['organization']})"
|
||||
if Config.WEB_URL:
|
||||
@@ -82,8 +84,9 @@ def build_message(birthdays: list[dict], target_date: date | None = None) -> Ema
|
||||
|
||||
cards_html = ""
|
||||
for b in birthdays:
|
||||
age = today.year - b["birthday"].year
|
||||
date_str = b["birthday"].strftime("%d.%m.")
|
||||
date_str = fmt_birthday_short(b["birthday"])
|
||||
age = fmt_birthday_age(b["birthday"], today)
|
||||
age_str = f" · {age} Jahre" if age is not None else ""
|
||||
contact_link = f"{Config.WEB_URL.rstrip('/')}/contacts/{b['id']}" if Config.WEB_URL else ""
|
||||
name_html = f'<a href="{contact_link}" style="color:#222;text-decoration:none;">{b["full_name"]}</a>' if contact_link else b["full_name"]
|
||||
is_today = b["birthday"].month == today.month and b["birthday"].day == today.day
|
||||
@@ -99,7 +102,7 @@ def build_message(birthdays: list[dict], target_date: date | None = None) -> Ema
|
||||
<div>
|
||||
<div style="font-size:18px;font-weight:600;color:#222;">{name_html}</div>
|
||||
{org_html}
|
||||
<div style="font-size:14px;color:#888;margin-top:4px;">🎂 {date_str} · {age} Jahre</div>
|
||||
<div style="font-size:14px;color:#888;margin-top:4px;">🎂 {date_str}{age_str}</div>
|
||||
</div>
|
||||
{photo_html}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de)
|
||||
# Licensed under the MIT License. See LICENSE file in project root for details.
|
||||
from datetime import date
|
||||
|
||||
UNKNOWN_YEARS = frozenset({0, 1604, 1900})
|
||||
|
||||
|
||||
def is_unknown_year(birthday: date) -> bool:
|
||||
return birthday.year in UNKNOWN_YEARS
|
||||
|
||||
|
||||
def fmt_birthday_short(birthday: date) -> str:
|
||||
if is_unknown_year(birthday):
|
||||
return birthday.strftime("%d.%m.")
|
||||
return birthday.strftime("%d.%m.%Y")
|
||||
|
||||
|
||||
def fmt_birthday_age(birthday: date, reference) -> int | None:
|
||||
if is_unknown_year(birthday):
|
||||
return None
|
||||
ref_year = reference if isinstance(reference, int) else reference.year
|
||||
return ref_year - birthday.year
|
||||
Reference in New Issue
Block a user