2021-08-27 23:45:24 +02:00
|
|
|
import logging
|
2021-07-07 11:45:54 +02:00
|
|
|
from dataclasses import dataclass, field
|
2021-10-02 18:09:03 +02:00
|
|
|
from typing import List
|
2021-08-05 00:29:50 +02:00
|
|
|
from uuid import UUID
|
2021-07-07 11:45:54 +02:00
|
|
|
|
2021-08-16 10:49:52 +02:00
|
|
|
from mobilizon_reshare.models.publication import PublicationStatus
|
2021-10-02 18:09:03 +02:00
|
|
|
from mobilizon_reshare.publishers import get_active_notifiers
|
|
|
|
from mobilizon_reshare.publishers.abstract import EventPublication
|
2021-08-16 10:49:52 +02:00
|
|
|
from mobilizon_reshare.publishers.exceptions import PublisherError
|
2021-10-02 18:09:03 +02:00
|
|
|
from mobilizon_reshare.publishers.platforms.platform_mapping import get_notifier_class
|
2021-07-07 11:45:54 +02:00
|
|
|
|
2021-08-27 23:45:24 +02:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2021-07-07 11:45:54 +02:00
|
|
|
|
|
|
|
@dataclass
|
2021-08-05 00:29:50 +02:00
|
|
|
class PublicationReport:
|
|
|
|
status: PublicationStatus
|
2021-07-07 11:45:54 +02:00
|
|
|
reason: str
|
2021-08-27 23:45:24 +02:00
|
|
|
publication_id: UUID
|
2021-07-07 11:45:54 +02:00
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class PublisherCoordinatorReport:
|
2021-10-02 18:09:03 +02:00
|
|
|
publications: List[EventPublication]
|
2021-08-05 00:29:50 +02:00
|
|
|
reports: dict[UUID, PublicationReport] = field(default_factory={})
|
2021-07-07 11:45:54 +02:00
|
|
|
|
|
|
|
@property
|
|
|
|
def successful(self):
|
2021-08-05 00:29:50 +02:00
|
|
|
return all(
|
|
|
|
r.status == PublicationStatus.COMPLETED for r in self.reports.values()
|
|
|
|
)
|
2021-07-07 11:45:54 +02:00
|
|
|
|
|
|
|
|
2021-10-02 18:09:03 +02:00
|
|
|
class PublisherCoordinator:
|
|
|
|
def __init__(self, publications: List[EventPublication]):
|
|
|
|
self.publications = publications
|
2021-07-07 11:45:54 +02:00
|
|
|
|
|
|
|
def run(self) -> PublisherCoordinatorReport:
|
2021-08-05 00:29:50 +02:00
|
|
|
errors = self._validate()
|
2021-07-12 22:17:49 +02:00
|
|
|
if errors:
|
2021-08-27 23:45:24 +02:00
|
|
|
return PublisherCoordinatorReport(
|
2021-10-02 18:09:03 +02:00
|
|
|
reports=errors, publications=self.publications
|
2021-08-27 23:45:24 +02:00
|
|
|
)
|
2021-07-07 11:45:54 +02:00
|
|
|
|
2021-07-12 22:17:49 +02:00
|
|
|
return self._post()
|
2021-07-07 11:45:54 +02:00
|
|
|
|
2021-08-28 13:17:39 +02:00
|
|
|
def _make_successful_report(self, failed_ids):
|
2021-08-05 00:29:50 +02:00
|
|
|
return {
|
2021-10-02 18:09:03 +02:00
|
|
|
publication.id: PublicationReport(
|
2021-08-27 23:45:24 +02:00
|
|
|
status=PublicationStatus.COMPLETED,
|
|
|
|
reason="",
|
2021-10-02 18:09:03 +02:00
|
|
|
publication_id=publication.id,
|
2021-07-15 18:13:11 +02:00
|
|
|
)
|
2021-10-02 18:09:03 +02:00
|
|
|
for publication in self.publications
|
|
|
|
if publication.id not in failed_ids
|
2021-08-05 00:29:50 +02:00
|
|
|
}
|
2021-07-07 11:45:54 +02:00
|
|
|
|
|
|
|
def _post(self):
|
2021-08-05 00:29:50 +02:00
|
|
|
failed_publishers_reports = {}
|
2021-10-02 18:09:03 +02:00
|
|
|
|
|
|
|
for publication in self.publications:
|
|
|
|
|
2021-07-07 11:45:54 +02:00
|
|
|
try:
|
2021-10-02 18:09:03 +02:00
|
|
|
message = publication.formatter.get_message_from_event(
|
|
|
|
publication.event
|
|
|
|
)
|
|
|
|
publication.publisher.send(message)
|
2021-07-07 11:45:54 +02:00
|
|
|
except PublisherError as e:
|
2021-10-02 18:09:03 +02:00
|
|
|
failed_publishers_reports[publication.id] = PublicationReport(
|
2021-08-27 23:45:24 +02:00
|
|
|
status=PublicationStatus.FAILED,
|
|
|
|
reason=str(e),
|
2021-10-02 18:09:03 +02:00
|
|
|
publication_id=publication.id,
|
2021-07-07 11:45:54 +02:00
|
|
|
)
|
2021-08-27 23:45:24 +02:00
|
|
|
|
2021-08-28 13:17:39 +02:00
|
|
|
reports = failed_publishers_reports | self._make_successful_report(
|
|
|
|
failed_publishers_reports.keys()
|
|
|
|
)
|
2021-08-27 23:45:24 +02:00
|
|
|
return PublisherCoordinatorReport(
|
2021-10-02 18:09:03 +02:00
|
|
|
publications=self.publications, reports=reports
|
2021-08-27 23:45:24 +02:00
|
|
|
)
|
2021-07-07 11:45:54 +02:00
|
|
|
|
|
|
|
def _validate(self):
|
2021-08-05 00:29:50 +02:00
|
|
|
errors: dict[UUID, PublicationReport] = {}
|
2021-10-02 18:09:03 +02:00
|
|
|
|
|
|
|
for publication in self.publications:
|
|
|
|
|
2021-08-05 00:29:50 +02:00
|
|
|
reason = []
|
2021-10-02 18:09:03 +02:00
|
|
|
if not publication.publisher.are_credentials_valid():
|
2021-08-05 00:29:50 +02:00
|
|
|
reason.append("Invalid credentials")
|
2021-10-02 18:09:03 +02:00
|
|
|
if not publication.formatter.is_event_valid(publication.event):
|
2021-08-05 00:29:50 +02:00
|
|
|
reason.append("Invalid event")
|
2021-10-02 18:09:03 +02:00
|
|
|
if not publication.formatter.is_message_valid(publication.event):
|
2021-08-05 00:29:50 +02:00
|
|
|
reason.append("Invalid message")
|
|
|
|
|
|
|
|
if len(reason) > 0:
|
2021-10-02 18:09:03 +02:00
|
|
|
errors[publication.id] = PublicationReport(
|
2021-08-27 23:45:24 +02:00
|
|
|
status=PublicationStatus.FAILED,
|
|
|
|
reason=", ".join(reason),
|
2021-10-02 18:09:03 +02:00
|
|
|
publication_id=publication.id,
|
2021-07-07 11:45:54 +02:00
|
|
|
)
|
2021-08-05 00:29:50 +02:00
|
|
|
|
|
|
|
return errors
|
2021-08-27 23:45:24 +02:00
|
|
|
|
|
|
|
|
2021-10-02 18:09:03 +02:00
|
|
|
class AbstractNotifiersCoordinator:
|
|
|
|
def __init__(self, message: str, notifiers=None):
|
|
|
|
self.message = message
|
|
|
|
self.notifiers = notifiers or [
|
|
|
|
get_notifier_class(notifier)() for notifier in get_active_notifiers()
|
|
|
|
]
|
2021-08-27 23:45:24 +02:00
|
|
|
|
2021-10-02 18:09:03 +02:00
|
|
|
def send_to_all(self):
|
2021-08-27 23:45:24 +02:00
|
|
|
# TODO: failure to notify should fail safely and write to a dedicated log
|
2021-10-02 18:09:03 +02:00
|
|
|
for notifier in self.notifiers:
|
|
|
|
notifier.send(self.message)
|
2021-08-27 23:45:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
class PublicationFailureNotifiersCoordinator(AbstractNotifiersCoordinator):
|
2021-10-02 18:09:03 +02:00
|
|
|
def __init__(self, report: PublicationReport, notifiers=None):
|
|
|
|
self.report = report
|
|
|
|
super(PublicationFailureNotifiersCoordinator, self).__init__(
|
|
|
|
message=self.build_failure_message(), notifiers=notifiers
|
|
|
|
)
|
|
|
|
|
|
|
|
def build_failure_message(self):
|
|
|
|
report = self.report
|
2021-08-27 23:45:24 +02:00
|
|
|
return (
|
|
|
|
f"Publication {report.publication_id} failed with status: {report.status}.\n"
|
|
|
|
f"Reason: {report.reason}"
|
|
|
|
)
|
|
|
|
|
2021-10-02 18:09:03 +02:00
|
|
|
def notify_failure(self):
|
|
|
|
logger.info(
|
|
|
|
f"Sending failure notifications for publication: {self.report.publication_id}"
|
|
|
|
)
|
|
|
|
if self.report.status == PublicationStatus.FAILED:
|
|
|
|
self.send_to_all()
|