Mobilizon-Reshare-condividi.../mobilizon_reshare/publishers/coordinators/event_publishing/notify.py

127 lines
4.1 KiB
Python

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import List, Optional, Sequence
from mobilizon_reshare.dataclasses import PublicationNotification, EventPublication
from mobilizon_reshare.models.notification import NotificationStatus
from mobilizon_reshare.models.publication import PublicationStatus
from mobilizon_reshare.publishers import get_active_notifiers
from mobilizon_reshare.publishers.abstract import (
AbstractPlatform,
)
from mobilizon_reshare.publishers.coordinators import (
logger,
BasePublicationReport,
BaseCoordinatorReport,
)
from mobilizon_reshare.publishers.coordinators.event_publishing import (
EventPublicationReport,
)
from mobilizon_reshare.publishers.platforms.platform_mapping import (
get_notifier_class,
get_formatter_class,
)
@dataclass
class PublicationNotificationReport(BasePublicationReport):
status: NotificationStatus
notification: PublicationNotification
@property
def successful(self):
return self.status == NotificationStatus.COMPLETED
def get_failure_message(self):
if not self.reason:
logger.error("Report of failure without reason.", exc_info=True)
return (
f"Failed with status: {self.status.name}.\n"
f"Reason: {self.reason}\n"
f"Publisher: {self.notification.publisher.name}\n"
f"Publication: {self.notification.publication.id}"
)
@dataclass
class NotifierCoordinatorReport(BaseCoordinatorReport):
reports: Sequence[PublicationNotificationReport]
notifications: Sequence[PublicationNotification] = field(default_factory=list)
class Sender:
def __init__(
self,
message: str,
publication: EventPublication,
platforms: List[AbstractPlatform] = None,
):
self.message = message
self.platforms = platforms
self.publication = publication
def send_to_all(self) -> NotifierCoordinatorReport:
reports = []
notifications = []
for platform in self.platforms:
notification = PublicationNotification(
platform, get_formatter_class(platform.name)(), self.publication
)
try:
platform.send(self.message)
report = PublicationNotificationReport(
NotificationStatus.COMPLETED, self.message, notification
)
except Exception as e:
msg = f"[{platform.name}] Failed to notify failure of message:\n{self.message}"
logger.critical(msg)
logger.exception(e)
report = PublicationNotificationReport(
NotificationStatus.FAILED, msg, notification
)
notifications.append(notification)
reports.append(report)
return NotifierCoordinatorReport(reports=reports, notifications=notifications)
class AbstractNotifiersCoordinator(ABC):
def __init__(
self, report: BasePublicationReport, notifiers: List[AbstractPlatform] = None
):
self.platforms = notifiers or [
get_notifier_class(notifier)() for notifier in get_active_notifiers()
]
self.report = report
@abstractmethod
def notify_failure(self):
pass
class PublicationFailureNotifiersCoordinator(AbstractNotifiersCoordinator):
"""
Sends a notification of a failure report to the active platforms
"""
report: EventPublicationReport
platforms: List[AbstractPlatform]
def notify_failure(self) -> Optional[NotifierCoordinatorReport]:
logger.info("Sending failure notifications")
if self.report.status == PublicationStatus.FAILED:
return Sender(
self.report.get_failure_message(),
self.report.publication,
self.platforms,
).send_to_all()
class PublicationFailureLoggerCoordinator(PublicationFailureNotifiersCoordinator):
"""
Logs a report to console
"""
def notify_failure(self):
if self.report.status == PublicationStatus.FAILED:
logger.error(self.report.get_failure_message())