Fix publication exception handling for notification. (#105)

This commit is contained in:
Giacomo Leidi 2021-11-27 23:31:44 +01:00 committed by GitHub
parent 1efa191771
commit f8bbd1df41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 45 additions and 60 deletions

View File

@ -114,7 +114,7 @@ class AbstractPlatform(ABC, LoggerMixin, ConfLoaderMixin):
class AbstractEventFormatter(LoggerMixin, ConfLoaderMixin):
@abstractmethod
def validate_event(self, message) -> None:
def _validate_event(self, event: MobilizonEvent) -> None:
"""
Validates publisher's event.
Should raise ``PublisherError`` (or one of its subclasses) if event
@ -122,6 +122,19 @@ class AbstractEventFormatter(LoggerMixin, ConfLoaderMixin):
"""
raise NotImplementedError # pragma: no cover
@abstractmethod
def _validate_message(self, message: str) -> None:
"""
Validates notifier's message.
Should raise ``PublisherError`` (or one of its subclasses) if message
is not valid.
"""
raise NotImplementedError # pragma: no cover
def validate_event(self, event: MobilizonEvent) -> None:
self._validate_event(event)
self._validate_message(self.get_message_from_event(event))
def _preprocess_event(self, event):
"""
Allows publishers to preprocess events before feeding them to the template
@ -142,15 +155,6 @@ class AbstractEventFormatter(LoggerMixin, ConfLoaderMixin):
template_path = self.conf.msg_template_path or self.default_template_path
return JINJA_ENV.get_template(template_path)
@abstractmethod
def validate_message(self, message: str) -> None:
"""
Validates notifier's message.
Should raise ``PublisherError`` (or one of its subclasses) if message
is not valid.
"""
raise NotImplementedError # pragma: no cover
def get_recap_header(self):
template_path = (
self.conf.recap_header_template_path

View File

@ -113,7 +113,6 @@ class PublisherCoordinator:
f(*args, **kwargs)
return reasons
except Exception as e:
logger.error(str(e))
return reasons + [str(e)]
def _validate(self):
@ -122,16 +121,12 @@ class PublisherCoordinator:
for publication in self.publications:
reasons = []
reasons = self._safe_run(
reasons, publication.publisher.validate_credentials,
reasons,
publication.publisher.validate_credentials,
)
reasons = self._safe_run(
reasons, publication.formatter.validate_event, publication.event
)
reasons = self._safe_run(
reasons,
publication.formatter.validate_message,
publication.formatter.get_message_from_event(publication.event),
)
if len(reasons) > 0:
errors.append(

View File

@ -29,12 +29,12 @@ class FacebookFormatter(AbstractEventFormatter):
"mobilizon_reshare.publishers.templates", "facebook_recap_header.tmpl.j2"
)
def validate_event(self, event: MobilizonEvent) -> None:
def _validate_event(self, event: MobilizonEvent) -> None:
text = event.description
if not (text and text.strip()):
self._log_error("No text was found", raise_error=InvalidEvent)
def validate_message(self, message) -> None:
def _validate_message(self, message) -> None:
pass

View File

@ -34,14 +34,14 @@ class MastodonFormatter(AbstractEventFormatter):
"mobilizon_reshare.publishers.templates", "mastodon_recap_header.tmpl.j2"
)
def validate_event(self, event: MobilizonEvent) -> None:
def _validate_event(self, event: MobilizonEvent) -> None:
text = event.description
if not (text and text.strip()):
self._log_error("No text was found", raise_error=InvalidEvent)
def validate_message(self, message) -> None:
def _validate_message(self, message) -> None:
if len(message.encode("utf-8")) >= self.conf.toot_length:
raise InvalidMessage("Message is too long")
self._log_error("Message is too long", raise_error=InvalidMessage)
class MastodonPlatform(AbstractPlatform):

View File

@ -65,14 +65,14 @@ class TelegramFormatter(AbstractEventFormatter):
return TelegramFormatter.restore_links(message)
def validate_event(self, event: MobilizonEvent) -> None:
def _validate_event(self, event: MobilizonEvent) -> None:
description = event.description
if not (description and description.strip()):
self._log_error("No description was found", raise_error=InvalidEvent)
def validate_message(self, message: str) -> None:
def _validate_message(self, message: str) -> None:
if len(message) >= 4096:
raise InvalidMessage("Message is too long")
self._log_error("Message is too long", raise_error=InvalidMessage)
def _preprocess_event(self, event: MobilizonEvent):
event.description = html_to_markdown(event.description)

View File

@ -13,6 +13,7 @@ from mobilizon_reshare.publishers.exceptions import (
InvalidCredentials,
InvalidEvent,
PublisherError,
InvalidMessage,
)
@ -31,16 +32,16 @@ class TwitterFormatter(AbstractEventFormatter):
"mobilizon_reshare.publishers.templates", "twitter_recap_header.tmpl.j2"
)
def validate_event(self, event: MobilizonEvent) -> None:
def _validate_event(self, event: MobilizonEvent) -> None:
text = event.description
if not (text and text.strip()):
self._log_error("No text was found", raise_error=InvalidEvent)
def validate_message(self, message) -> None:
def _validate_message(self, message) -> None:
# TODO this is not precise. It should count the characters according to Twitter's logic but
# Tweepy doesn't seem to support the validation client side
if len(message.encode("utf-8")) > 280:
raise PublisherError("Message is too long")
self._log_error("Message is too long", raise_error=InvalidMessage)
class TwitterPlatform(AbstractPlatform):
@ -65,7 +66,7 @@ class TwitterPlatform(AbstractPlatform):
try:
return self._get_api().update_status(message)
except TweepyException as e:
raise PublisherError(e.args[0])
self._log_error(e.args[0], raise_error=PublisherError)
def validate_credentials(self):
if not self._get_api().verify_credentials():

View File

@ -36,14 +36,14 @@ class ZulipFormatter(AbstractEventFormatter):
"mobilizon_reshare.publishers.templates", "zulip_recap_header.tmpl.j2"
)
def validate_event(self, event: MobilizonEvent) -> None:
def _validate_event(self, event: MobilizonEvent) -> None:
text = event.description
if not (text and text.strip()):
self._log_error("No text was found", raise_error=InvalidEvent)
def validate_message(self, message) -> None:
def _validate_message(self, message: str) -> None:
if len(message.encode("utf-8")) >= 10000:
raise InvalidMessage("Message is too long")
self._log_error("Message is too long", raise_error=InvalidMessage)
def _preprocess_event(self, event: MobilizonEvent):
event.description = html_to_markdown(event.description)

View File

@ -103,8 +103,12 @@ async def mock_publications(
@pytest.mark.parametrize("num_publications", [2])
@pytest.mark.asyncio
async def test_publication_coordinator_run_success(mock_publications,):
coordinator = PublisherCoordinator(publications=mock_publications,)
async def test_publication_coordinator_run_success(
mock_publications,
):
coordinator = PublisherCoordinator(
publications=mock_publications,
)
report = coordinator.run()
assert len(report.reports) == 2
assert report.successful, "\n".join(map(lambda rep: rep.reason, report.reports))
@ -123,10 +127,7 @@ async def test_publication_coordinator_run_failure(
report = coordinator.run()
assert len(report.reports) == 1
assert not report.successful
assert (
list(report.reports)[0].reason
== "credentials error, Invalid event error, Invalid message error"
)
assert list(report.reports)[0].reason == "credentials error, Invalid event error"
@pytest.mark.parametrize("num_publications", [1])

View File

@ -16,16 +16,14 @@ from mobilizon_reshare.publishers.platforms.mastodon import (
def test_message_length_success(event):
message = "a" * 200
event.name = message
message = MastodonFormatter().get_message_from_event(event)
MastodonFormatter().validate_message(message)
MastodonFormatter().validate_event(event)
def test_message_length_failure(event):
message = "a" * 500
event.name = message
message = MastodonFormatter().get_message_from_event(event)
with pytest.raises(InvalidMessage):
MastodonFormatter().validate_message(message)
MastodonFormatter().validate_event(event)
def test_event_validation(event):

View File

@ -15,12 +15,7 @@ from mobilizon_reshare.publishers.platforms.telegram import (
def test_message_length_success(event):
message = "a" * 500
event.description = message
assert (
TelegramFormatter().validate_message(
TelegramFormatter().get_message_from_event(event)
)
is None
)
assert TelegramFormatter().validate_event(event) is None
def test_message_length_failure(event):
@ -28,9 +23,7 @@ def test_message_length_failure(event):
event.description = message
with pytest.raises(InvalidMessage):
TelegramFormatter().validate_message(
TelegramFormatter().get_message_from_event(event)
)
TelegramFormatter().validate_event(event)
@pytest.mark.parametrize(

View File

@ -141,21 +141,14 @@ def test_event_validation(event):
def test_message_length_success(event):
message = "a" * 500
event.description = message
assert (
ZulipFormatter().validate_message(
ZulipFormatter().get_message_from_event(event)
)
is None
)
assert ZulipFormatter().validate_event(event) is None
def test_message_length_failure(event):
message = "a" * 10000
event.description = message
with pytest.raises(InvalidMessage):
ZulipFormatter().validate_message(
ZulipFormatter().get_message_from_event(event)
)
ZulipFormatter().validate_event(event)
def test_validate_response():