Feature: Tagesmail — Action Items + neue Nutzer heute
This commit is contained in:
parent
d04110c2ae
commit
df8c4cc279
1 changed files with 67 additions and 4 deletions
|
|
@ -650,6 +650,34 @@ async def _job_ki_health_report():
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
def _action_items_html(metrics: dict) -> str:
|
||||||
|
items = [
|
||||||
|
("jobs_pending", "Bewerbungen offen"),
|
||||||
|
("breeder_pending", "Züchter-Anträge"),
|
||||||
|
("reports_open", "Forum-Meldungen"),
|
||||||
|
("fotos_pending", "Foto-Einreichungen"),
|
||||||
|
("poi_edits_pending", "POI-Korrekturen"),
|
||||||
|
]
|
||||||
|
open_items = [(label, metrics.get(key, 0)) for key, label in items if metrics.get(key, 0) > 0]
|
||||||
|
|
||||||
|
if not open_items:
|
||||||
|
body = '<span style="color:#16a34a;font-weight:700">✅ Alles erledigt — nichts offen</span>'
|
||||||
|
else:
|
||||||
|
pills = "".join(
|
||||||
|
f'<span style="display:inline-block;background:#fff3e0;color:#c45000;border:1px solid #e8a857;'
|
||||||
|
f'border-radius:999px;padding:3px 12px;font-size:12px;font-weight:700;margin:2px 4px 2px 0">'
|
||||||
|
f'{label} <strong style="background:#c45000;color:#fff;border-radius:999px;'
|
||||||
|
f'padding:0 7px;margin-left:4px">{count}</strong></span>'
|
||||||
|
for label, count in open_items
|
||||||
|
)
|
||||||
|
body = f'<div style="font-size:13px;font-weight:600;color:#c45000;margin-bottom:8px">⚠️ {len(open_items)} Punkt{"e" if len(open_items)!=1 else ""} brauchen deine Aufmerksamkeit</div>{pills}'
|
||||||
|
|
||||||
|
link = '<div style="margin-top:10px"><a href="https://banyaro.app/app/admin" style="font-size:12px;color:#C4843A">→ Admin-Panel öffnen</a></div>'
|
||||||
|
return f'<div style="padding:20px 28px;border-bottom:2px solid #e8a857;background:#fffbf5">' \
|
||||||
|
f'<div style="font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#C4843A;margin-bottom:10px">Heute zu erledigen</div>' \
|
||||||
|
f'{body}{link}</div>'
|
||||||
|
|
||||||
|
|
||||||
# JOB: Status-Report per Mail (täglich 06:00 Uhr)
|
# JOB: Status-Report per Mail (täglich 06:00 Uhr)
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
async def _job_status_report():
|
async def _job_status_report():
|
||||||
|
|
@ -677,6 +705,7 @@ async def _job_status_report():
|
||||||
|
|
||||||
# Community
|
# Community
|
||||||
metrics["users"] = conn.execute("SELECT COUNT(*) FROM users").fetchone()[0]
|
metrics["users"] = conn.execute("SELECT COUNT(*) FROM users").fetchone()[0]
|
||||||
|
metrics["users_today"] = conn.execute("SELECT COUNT(*) FROM users WHERE DATE(created_at)=DATE('now')").fetchone()[0]
|
||||||
metrics["dogs"] = conn.execute("SELECT COUNT(*) FROM dogs").fetchone()[0]
|
metrics["dogs"] = conn.execute("SELECT COUNT(*) FROM dogs").fetchone()[0]
|
||||||
metrics["diary_entries"] = conn.execute("SELECT COUNT(*) FROM diary").fetchone()[0]
|
metrics["diary_entries"] = conn.execute("SELECT COUNT(*) FROM diary").fetchone()[0]
|
||||||
metrics["poison_active"] = conn.execute("SELECT COUNT(*) FROM poison WHERE geloest=0").fetchone()[0]
|
metrics["poison_active"] = conn.execute("SELECT COUNT(*) FROM poison WHERE geloest=0").fetchone()[0]
|
||||||
|
|
@ -685,6 +714,28 @@ async def _job_status_report():
|
||||||
except Exception:
|
except Exception:
|
||||||
metrics["lost_active"] = 0
|
metrics["lost_active"] = 0
|
||||||
|
|
||||||
|
# Action Items
|
||||||
|
try:
|
||||||
|
metrics["jobs_pending"] = conn.execute("SELECT COUNT(*) FROM job_applications WHERE status IN ('pending','reviewing')").fetchone()[0]
|
||||||
|
except Exception:
|
||||||
|
metrics["jobs_pending"] = 0
|
||||||
|
try:
|
||||||
|
metrics["breeder_pending"] = conn.execute("SELECT COUNT(*) FROM users WHERE breeder_status='pending'").fetchone()[0]
|
||||||
|
except Exception:
|
||||||
|
metrics["breeder_pending"] = 0
|
||||||
|
try:
|
||||||
|
metrics["reports_open"] = conn.execute("SELECT COUNT(*) FROM forum_reports WHERE resolved=0").fetchone()[0]
|
||||||
|
except Exception:
|
||||||
|
metrics["reports_open"] = 0
|
||||||
|
try:
|
||||||
|
metrics["fotos_pending"] = conn.execute("SELECT COUNT(*) FROM wiki_foto_submissions WHERE status='pending'").fetchone()[0]
|
||||||
|
except Exception:
|
||||||
|
metrics["fotos_pending"] = 0
|
||||||
|
try:
|
||||||
|
metrics["poi_edits_pending"] = conn.execute("SELECT COUNT(*) FROM osm_poi_edits WHERE status='pending'").fetchone()[0]
|
||||||
|
except Exception:
|
||||||
|
metrics["poi_edits_pending"] = 0
|
||||||
|
|
||||||
# Wiki-Interesse
|
# Wiki-Interesse
|
||||||
try:
|
try:
|
||||||
metrics["interesse_hat"] = conn.execute("SELECT COUNT(*) FROM wiki_breed_interest WHERE typ='hat'").fetchone()[0]
|
metrics["interesse_hat"] = conn.execute("SELECT COUNT(*) FROM wiki_breed_interest WHERE typ='hat'").fetchone()[0]
|
||||||
|
|
@ -736,6 +787,9 @@ async def _job_status_report():
|
||||||
<div style="opacity:.88;font-size:13px">{now_str} Uhr</div>
|
<div style="opacity:.88;font-size:13px">{now_str} Uhr</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Items -->
|
||||||
|
{_action_items_html(metrics)}
|
||||||
|
|
||||||
<!-- Scheduler-Status -->
|
<!-- Scheduler-Status -->
|
||||||
<div style="padding:20px 28px;border-bottom:1px solid #f0e8dc">
|
<div style="padding:20px 28px;border-bottom:1px solid #f0e8dc">
|
||||||
<div style="font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#C4843A;margin-bottom:10px">Scheduler-Jobs</div>
|
<div style="font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#C4843A;margin-bottom:10px">Scheduler-Jobs</div>
|
||||||
|
|
@ -749,14 +803,14 @@ async def _job_status_report():
|
||||||
<div style="font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#C4843A;margin-bottom:10px">Community</div>
|
<div style="font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#C4843A;margin-bottom:10px">Community</div>
|
||||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">
|
||||||
{"".join(f'<div style="background:#fdf6ef;border-radius:8px;padding:10px 14px"><div style="font-size:20px;font-weight:800;color:#C4843A">{v}</div><div style="font-size:11px;color:#888">{k}</div></div>' for k,v in [
|
{"".join(f'<div style="background:#fdf6ef;border-radius:8px;padding:10px 14px"><div style="font-size:20px;font-weight:800;color:#C4843A">{v}</div><div style="font-size:11px;color:#888">{k}</div></div>' for k,v in [
|
||||||
("Nutzer",metrics["users"]),
|
("Nutzer gesamt",metrics["users"]),
|
||||||
|
("Neue Nutzer heute",metrics["users_today"]),
|
||||||
("Hunde",metrics["dogs"]),
|
("Hunde",metrics["dogs"]),
|
||||||
("Tagebuch-Einträge",metrics["diary_entries"]),
|
("Tagebuch-Einträge",metrics["diary_entries"]),
|
||||||
("Aktive Giftköder",metrics["poison_active"]),
|
("Aktive Giftköder",metrics["poison_active"]),
|
||||||
("Vermisste Hunde",metrics["lost_active"]),
|
("Vermisste Hunde",metrics["lost_active"]),
|
||||||
("'So einen hab ich'",metrics["interesse_hat"]),
|
("'So einen hab ich'",metrics["interesse_hat"]),
|
||||||
("'Interessiert mich'",metrics["interesse_will"]),
|
("'Interessiert mich'",metrics["interesse_will"]),
|
||||||
("Züchter (pending)",metrics["zuchter_pending"]),
|
|
||||||
])}
|
])}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -770,19 +824,28 @@ async def _job_status_report():
|
||||||
</body>
|
</body>
|
||||||
</html>"""
|
</html>"""
|
||||||
|
|
||||||
|
action_open = [l for k,l in [
|
||||||
|
("jobs_pending","Bewerbungen"),("breeder_pending","Züchter-Anträge"),
|
||||||
|
("reports_open","Meldungen"),("fotos_pending","Fotos"),("poi_edits_pending","POI-Korrekturen"),
|
||||||
|
] if metrics.get(k,0) > 0]
|
||||||
plain = f"""Ban Yaro Status-Report — {now_str}
|
plain = f"""Ban Yaro Status-Report — {now_str}
|
||||||
|
|
||||||
|
=== HEUTE ZU ERLEDIGEN ===
|
||||||
|
{"✅ Alles erledigt" if not action_open else "⚠️ " + ", ".join(f"{l} ({metrics[k]})" for k,l in [
|
||||||
|
("jobs_pending","Bewerbungen"),("breeder_pending","Züchter-Anträge"),
|
||||||
|
("reports_open","Meldungen"),("fotos_pending","Fotos"),("poi_edits_pending","POI-Korrekturen"),
|
||||||
|
] if metrics.get(k,0) > 0)}
|
||||||
|
|
||||||
=== Scheduler-Jobs ===
|
=== Scheduler-Jobs ===
|
||||||
{job_rows_txt}
|
{job_rows_txt}
|
||||||
=== Community ===
|
=== Community ===
|
||||||
Nutzer: {metrics['users']}
|
Nutzer gesamt: {metrics['users']} (+{metrics['users_today']} heute)
|
||||||
Hunde: {metrics['dogs']}
|
Hunde: {metrics['dogs']}
|
||||||
Tagebuch-Einträge: {metrics['diary_entries']}
|
Tagebuch-Einträge: {metrics['diary_entries']}
|
||||||
Aktive Giftköder: {metrics['poison_active']}
|
Aktive Giftköder: {metrics['poison_active']}
|
||||||
Vermisste Hunde: {metrics['lost_active']}
|
Vermisste Hunde: {metrics['lost_active']}
|
||||||
'So einen hab ich': {metrics['interesse_hat']}
|
'So einen hab ich': {metrics['interesse_hat']}
|
||||||
'Interessiert mich': {metrics['interesse_will']}
|
'Interessiert mich': {metrics['interesse_will']}
|
||||||
Züchter (pending): {metrics['zuchter_pending']}
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue