# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ CommCoach Scheduler Service. Handles daily reminders and scheduled email summaries. """ import logging import html from typing import Dict, Any, List logger = logging.getLogger(__name__) def _buildReminderHtmlBlock(contextTitles: List[str], streakDays: int) -> str: rows = "".join( '' '•' f'{html.escape(title)}' '' for title in contextTitles[:3] ) topicsBlock = ( '' '
' '
Aktive Coaching-Themen
' f'{rows}
' '
' ) streakBlock = ( '' '
' '
Dein Rhythmus
' f'
Aktueller Streak: ' f'{int(streakDays or 0)} Tage
' '
' ) return topicsBlock + streakBlock def registerScheduledJobs(eventManagement): """Register CommCoach scheduled jobs with the event management system.""" try: eventManagement.registerCron( jobId="commcoach_daily_reminder", func=_runDailyReminders, cronKwargs={"hour": 8, "minute": 0}, ) logger.info("CommCoach scheduler: daily reminder job registered at 08:00") except Exception as e: logger.error(f"CommCoach scheduler: failed to register jobs: {e}") async def _runDailyReminders(): """Send daily coaching reminders to users who have opted in.""" try: from modules.shared.configuration import APP_CONFIG from modules.connectors.connectorDbPostgre import DatabaseConnector from .datamodelCommcoach import CoachingUserProfile, CoachingContextStatus from modules.interfaces.interfaceMessaging import getInterface as getMessagingInterface from modules.shared.notifyMandateAdmins import _renderHtmlEmail, _resolveMandateName dbHost = APP_CONFIG.get("DB_HOST", "_no_config_default_data") db = DatabaseConnector( dbHost=dbHost, dbDatabase="poweron_commcoach", dbUser=APP_CONFIG.get("DB_USER"), dbPassword=APP_CONFIG.get("DB_PASSWORD_SECRET"), dbPort=int(APP_CONFIG.get("DB_PORT", 5432)), userId="system", ) profiles = db.getRecordset(CoachingUserProfile, recordFilter={"dailyReminderEnabled": True}) if not profiles: return messaging = getMessagingInterface() from modules.interfaces.interfaceDbApp import getRootInterface rootInterface = getRootInterface() sentCount = 0 for profile in profiles: try: userId = profile.get("userId") user = rootInterface.getUser(userId) if not user or not user.email: continue # Check if user has active contexts from .datamodelCommcoach import CoachingContext contexts = db.getRecordset(CoachingContext, recordFilter={ "userId": userId, "status": CoachingContextStatus.ACTIVE.value, }) if not contexts: continue contextTitles = [c.get("title", "Unbenannt") for c in contexts[:3]] contextList = ", ".join(contextTitles) subject = "Dein tägliches Coaching wartet" mandateName = _resolveMandateName(profile.get("mandateId")) htmlMessage = _renderHtmlEmail( "Zeit für dein tägliches Coaching", [ f"Du hast aktuell {len(contexts)} aktive Coaching-Themen.", "Schon 10 Minuten reichen oft, um einen Gedanken zu klären, eine nächste Aktion festzulegen oder ein Gespräch vorzubereiten.", f"Im Fokus: {contextList}", ], mandateName, footerNote="Diese Erinnerung wurde automatisch auf Basis deiner CommCoach-Einstellungen versendet.", rawHtmlBlock=_buildReminderHtmlBlock(contextTitles, int(profile.get("streakDays", 0) or 0)), ) messaging.send("email", user.email, subject, htmlMessage) sentCount += 1 except Exception as e: logger.warning(f"Failed to send reminder to user {profile.get('userId')}: {e}") if sentCount > 0: logger.info(f"CommCoach scheduler: sent {sentCount} daily reminders") except Exception as e: logger.error(f"CommCoach daily reminders failed: {e}")