Fix PublisherCoordinatorReport generation. (#54)
* Fix PublisherCoordinatorReport generation. Without this patch we are given *either* the failed or the successful publication reports. We actually need both, this patch implements the merge. * Reformat Co-authored-by: Giacomo Leidi <goodoldpaul@autistici.org>
This commit is contained in:
parent
2197e07213
commit
489e3d66ad
|
@ -51,7 +51,11 @@ def inspect(ctx, begin, end):
|
||||||
@pass_obj
|
@pass_obj
|
||||||
def all(obj, settings_file):
|
def all(obj, settings_file):
|
||||||
safe_execution(
|
safe_execution(
|
||||||
functools.partial(inspect_events, frm=obj["begin"], to=obj["end"],),
|
functools.partial(
|
||||||
|
inspect_events,
|
||||||
|
frm=obj["begin"],
|
||||||
|
to=obj["end"],
|
||||||
|
),
|
||||||
settings_file,
|
settings_file,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,8 @@ async def main():
|
||||||
if event:
|
if event:
|
||||||
|
|
||||||
waiting_publications = await publications_with_status(
|
waiting_publications = await publications_with_status(
|
||||||
status=PublicationStatus.WAITING, event_mobilizon_id=event.mobilizon_id,
|
status=PublicationStatus.WAITING,
|
||||||
|
event_mobilizon_id=event.mobilizon_id,
|
||||||
)
|
)
|
||||||
logger.debug(f"Event to publish found: {event.name}")
|
logger.debug(f"Event to publish found: {event.name}")
|
||||||
report = PublisherCoordinator(event, waiting_publications).run()
|
report = PublisherCoordinator(event, waiting_publications).run()
|
||||||
|
|
|
@ -64,7 +64,11 @@ def build_and_validate_settings(settings_files: List[str] = None):
|
||||||
base_validators = [
|
base_validators = [
|
||||||
# strategy to decide events to publish
|
# strategy to decide events to publish
|
||||||
Validator(
|
Validator(
|
||||||
"publishing.window.begin", must_exist=True, is_type_of=int, gte=0, lte=24,
|
"publishing.window.begin",
|
||||||
|
must_exist=True,
|
||||||
|
is_type_of=int,
|
||||||
|
gte=0,
|
||||||
|
lte=24,
|
||||||
),
|
),
|
||||||
Validator(
|
Validator(
|
||||||
"publishing.window.end", must_exist=True, is_type_of=int, gte=0, lte=24
|
"publishing.window.end", must_exist=True, is_type_of=int, gte=0, lte=24
|
||||||
|
|
|
@ -93,7 +93,8 @@ STRATEGY_NAME_TO_STRATEGY_CLASS = {"next_event": SelectNextEventStrategy}
|
||||||
|
|
||||||
|
|
||||||
def select_event_to_publish(
|
def select_event_to_publish(
|
||||||
published_events: List[MobilizonEvent], unpublished_events: List[MobilizonEvent],
|
published_events: List[MobilizonEvent],
|
||||||
|
unpublished_events: List[MobilizonEvent],
|
||||||
):
|
):
|
||||||
|
|
||||||
strategy = STRATEGY_NAME_TO_STRATEGY_CLASS[
|
strategy = STRATEGY_NAME_TO_STRATEGY_CLASS[
|
||||||
|
|
|
@ -62,7 +62,7 @@ class PublisherCoordinator(BuildPublisherMixin):
|
||||||
|
|
||||||
return self._post()
|
return self._post()
|
||||||
|
|
||||||
def _make_successful_report(self):
|
def _make_successful_report(self, failed_ids):
|
||||||
return {
|
return {
|
||||||
publication_id: PublicationReport(
|
publication_id: PublicationReport(
|
||||||
status=PublicationStatus.COMPLETED,
|
status=PublicationStatus.COMPLETED,
|
||||||
|
@ -70,6 +70,7 @@ class PublisherCoordinator(BuildPublisherMixin):
|
||||||
publication_id=publication_id,
|
publication_id=publication_id,
|
||||||
)
|
)
|
||||||
for publication_id in self.publishers_by_publication_id
|
for publication_id in self.publishers_by_publication_id
|
||||||
|
if publication_id not in failed_ids
|
||||||
}
|
}
|
||||||
|
|
||||||
def _post(self):
|
def _post(self):
|
||||||
|
@ -84,7 +85,9 @@ class PublisherCoordinator(BuildPublisherMixin):
|
||||||
publication_id=publication_id,
|
publication_id=publication_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
reports = failed_publishers_reports or self._make_successful_report()
|
reports = failed_publishers_reports | self._make_successful_report(
|
||||||
|
failed_publishers_reports.keys()
|
||||||
|
)
|
||||||
return PublisherCoordinatorReport(
|
return PublisherCoordinatorReport(
|
||||||
publishers=self.publishers_by_publication_id, reports=reports
|
publishers=self.publishers_by_publication_id, reports=reports
|
||||||
)
|
)
|
||||||
|
|
|
@ -54,7 +54,8 @@ class TelegramPublisher(AbstractPublisher):
|
||||||
err.append("username")
|
err.append("username")
|
||||||
if err:
|
if err:
|
||||||
self._log_error(
|
self._log_error(
|
||||||
", ".join(err) + " is/are missing", raise_error=InvalidCredentials,
|
", ".join(err) + " is/are missing",
|
||||||
|
raise_error=InvalidCredentials,
|
||||||
)
|
)
|
||||||
|
|
||||||
res = requests.get(f"https://api.telegram.org/bot{token}/getMe")
|
res = requests.get(f"https://api.telegram.org/bot{token}/getMe")
|
||||||
|
@ -62,7 +63,8 @@ class TelegramPublisher(AbstractPublisher):
|
||||||
|
|
||||||
if not username == data.get("result", {}).get("username"):
|
if not username == data.get("result", {}).get("username"):
|
||||||
self._log_error(
|
self._log_error(
|
||||||
"Found a different bot than the expected one", raise_error=InvalidBot,
|
"Found a different bot than the expected one",
|
||||||
|
raise_error=InvalidBot,
|
||||||
)
|
)
|
||||||
|
|
||||||
def validate_event(self) -> None:
|
def validate_event(self) -> None:
|
||||||
|
@ -75,7 +77,8 @@ class TelegramPublisher(AbstractPublisher):
|
||||||
res.raise_for_status()
|
res.raise_for_status()
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
self._log_error(
|
self._log_error(
|
||||||
f"Server returned invalid data: {str(e)}", raise_error=InvalidResponse,
|
f"Server returned invalid data: {str(e)}",
|
||||||
|
raise_error=InvalidResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -88,7 +91,8 @@ class TelegramPublisher(AbstractPublisher):
|
||||||
|
|
||||||
if not data.get("ok"):
|
if not data.get("ok"):
|
||||||
self._log_error(
|
self._log_error(
|
||||||
f"Invalid request (response: {data})", raise_error=InvalidResponse,
|
f"Invalid request (response: {data})",
|
||||||
|
raise_error=InvalidResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -94,7 +94,8 @@ async def events_with_status(
|
||||||
|
|
||||||
|
|
||||||
async def get_all_events(
|
async def get_all_events(
|
||||||
from_date: Optional[Arrow] = None, to_date: Optional[Arrow] = None,
|
from_date: Optional[Arrow] = None,
|
||||||
|
to_date: Optional[Arrow] = None,
|
||||||
) -> Iterable[MobilizonEvent]:
|
) -> Iterable[MobilizonEvent]:
|
||||||
|
|
||||||
return map(
|
return map(
|
||||||
|
@ -153,7 +154,9 @@ async def create_publisher(name: str, account_ref: Optional[str] = None) -> None
|
||||||
|
|
||||||
|
|
||||||
@atomic(CONNECTION_NAME)
|
@atomic(CONNECTION_NAME)
|
||||||
async def update_publishers(names: Iterable[str],) -> None:
|
async def update_publishers(
|
||||||
|
names: Iterable[str],
|
||||||
|
) -> None:
|
||||||
names = set(names)
|
names = set(names)
|
||||||
known_publisher_names = set(p.name for p in await get_publishers())
|
known_publisher_names = set(p.name for p in await get_publishers())
|
||||||
for name in names.difference(known_publisher_names):
|
for name in names.difference(known_publisher_names):
|
||||||
|
@ -168,7 +171,9 @@ async def save_publication(
|
||||||
|
|
||||||
publisher = await get_publishers(publisher_name)
|
publisher = await get_publishers(publisher_name)
|
||||||
await Publication.create(
|
await Publication.create(
|
||||||
status=status, event_id=event_model.id, publisher_id=publisher.id,
|
status=status,
|
||||||
|
event_id=event_model.id,
|
||||||
|
publisher_id=publisher.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,9 @@ def event_model_generator():
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def publisher_model_generator():
|
def publisher_model_generator():
|
||||||
def _publisher_model_generator(idx=1,):
|
def _publisher_model_generator(
|
||||||
|
idx=1,
|
||||||
|
):
|
||||||
return Publisher(name=f"publisher_{idx}", account_ref=f"account_ref_{idx}")
|
return Publisher(name=f"publisher_{idx}", account_ref=f"account_ref_{idx}")
|
||||||
|
|
||||||
return _publisher_model_generator
|
return _publisher_model_generator
|
||||||
|
|
|
@ -109,7 +109,9 @@ def test_window_simple_event_found(
|
||||||
@pytest.mark.parametrize("current_hour", [15])
|
@pytest.mark.parametrize("current_hour", [15])
|
||||||
@pytest.mark.parametrize("strategy_name", ["next_event"])
|
@pytest.mark.parametrize("strategy_name", ["next_event"])
|
||||||
def test_window_simple_no_published_events(
|
def test_window_simple_no_published_events(
|
||||||
event_generator, set_strategy, mock_arrow_now,
|
event_generator,
|
||||||
|
set_strategy,
|
||||||
|
mock_arrow_now,
|
||||||
):
|
):
|
||||||
"Testing that if no event is published, the function takes the first available unpublished event"
|
"Testing that if no event is published, the function takes the first available unpublished event"
|
||||||
unpublished_events = [
|
unpublished_events = [
|
||||||
|
@ -130,7 +132,9 @@ def test_window_simple_no_published_events(
|
||||||
@pytest.mark.parametrize("current_hour", [15])
|
@pytest.mark.parametrize("current_hour", [15])
|
||||||
@pytest.mark.parametrize("strategy_name", ["next_event"])
|
@pytest.mark.parametrize("strategy_name", ["next_event"])
|
||||||
def test_window_simple_event_too_recent(
|
def test_window_simple_event_too_recent(
|
||||||
event_generator, set_strategy, mock_arrow_now,
|
event_generator,
|
||||||
|
set_strategy,
|
||||||
|
mock_arrow_now,
|
||||||
):
|
):
|
||||||
"Testing that if an event has been published too recently, no event is selected for publication"
|
"Testing that if an event has been published too recently, no event is selected for publication"
|
||||||
unpublished_events = [
|
unpublished_events = [
|
||||||
|
|
|
@ -15,7 +15,10 @@ def mock_mobilizon_success_answer(mobilizon_answer, mobilizon_url):
|
||||||
with responses.RequestsMock() as rsps:
|
with responses.RequestsMock() as rsps:
|
||||||
|
|
||||||
rsps.add(
|
rsps.add(
|
||||||
responses.POST, mobilizon_url, json=mobilizon_answer, status=200,
|
responses.POST,
|
||||||
|
mobilizon_url,
|
||||||
|
json=mobilizon_answer,
|
||||||
|
status=200,
|
||||||
)
|
)
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
@ -26,6 +29,8 @@ def mock_mobilizon_failure_answer(mobilizon_url):
|
||||||
with responses.RequestsMock() as rsps:
|
with responses.RequestsMock() as rsps:
|
||||||
|
|
||||||
rsps.add(
|
rsps.add(
|
||||||
responses.POST, mobilizon_url, status=500,
|
responses.POST,
|
||||||
|
mobilizon_url,
|
||||||
|
status=500,
|
||||||
)
|
)
|
||||||
yield
|
yield
|
||||||
|
|
|
@ -35,7 +35,9 @@ def test_publication_report_successful(statuses, successful):
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def mock_publication(test_event: MobilizonEvent,):
|
async def mock_publication(
|
||||||
|
test_event: MobilizonEvent,
|
||||||
|
):
|
||||||
event = test_event.to_model()
|
event = test_event.to_model()
|
||||||
await event.save()
|
await event.save()
|
||||||
publisher = Publisher(name="telegram")
|
publisher = Publisher(name="telegram")
|
||||||
|
|
|
@ -5,7 +5,12 @@ from mobilizon_reshare.models.publication import Publication
|
||||||
from mobilizon_reshare.models.publication import PublicationStatus
|
from mobilizon_reshare.models.publication import PublicationStatus
|
||||||
|
|
||||||
today = datetime(
|
today = datetime(
|
||||||
year=2021, month=6, day=6, hour=5, minute=0, tzinfo=timezone(timedelta(hours=2)),
|
year=2021,
|
||||||
|
month=6,
|
||||||
|
day=6,
|
||||||
|
hour=5,
|
||||||
|
minute=0,
|
||||||
|
tzinfo=timezone(timedelta(hours=2)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,9 @@ async def test_get_unpublished_events(specification, expected_result, generate_m
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_create_unpublished_events(
|
async def test_create_unpublished_events(
|
||||||
expected_result, generate_models, event_generator,
|
expected_result,
|
||||||
|
generate_models,
|
||||||
|
event_generator,
|
||||||
):
|
):
|
||||||
await generate_models(complete_specification)
|
await generate_models(complete_specification)
|
||||||
event_3 = event_generator(begin_date=arrow.get(today + timedelta(days=6)))
|
event_3 = event_generator(begin_date=arrow.get(today + timedelta(days=6)))
|
||||||
|
@ -130,7 +132,9 @@ async def test_create_unpublished_events(
|
||||||
|
|
||||||
events_from_internet = [MobilizonEvent.from_model(models[0]), event_3, event_4]
|
events_from_internet = [MobilizonEvent.from_model(models[0]), event_3, event_4]
|
||||||
|
|
||||||
await create_unpublished_events(unpublished_mobilizon_events=events_from_internet,)
|
await create_unpublished_events(
|
||||||
|
unpublished_mobilizon_events=events_from_internet,
|
||||||
|
)
|
||||||
unpublished_events = list(await get_unpublished_events())
|
unpublished_events = list(await get_unpublished_events())
|
||||||
|
|
||||||
assert len(unpublished_events) == 4
|
assert len(unpublished_events) == 4
|
||||||
|
@ -169,7 +173,9 @@ async def test_get_mobilizon_event_publications(generate_models):
|
||||||
[[None, {"telegram", "twitter", "mastodon"}], ["telegram", {"telegram"}]],
|
[[None, {"telegram", "twitter", "mastodon"}], ["telegram", {"telegram"}]],
|
||||||
)
|
)
|
||||||
async def test_get_publishers(
|
async def test_get_publishers(
|
||||||
name, expected_result, generate_models,
|
name,
|
||||||
|
expected_result,
|
||||||
|
generate_models,
|
||||||
):
|
):
|
||||||
await generate_models(complete_specification)
|
await generate_models(complete_specification)
|
||||||
result = await get_publishers(name)
|
result = await get_publishers(name)
|
||||||
|
@ -232,7 +238,12 @@ async def test_get_publishers(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_publications_with_status(
|
async def test_publications_with_status(
|
||||||
status, mobilizon_id, from_date, to_date, expected_result, generate_models,
|
status,
|
||||||
|
mobilizon_id,
|
||||||
|
from_date,
|
||||||
|
to_date,
|
||||||
|
expected_result,
|
||||||
|
generate_models,
|
||||||
):
|
):
|
||||||
await generate_models(complete_specification)
|
await generate_models(complete_specification)
|
||||||
publications = await publications_with_status(
|
publications = await publications_with_status(
|
||||||
|
|
|
@ -48,7 +48,10 @@ two_publishers_specification = {"publisher": ["telegram", "twitter"]}
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_update_publishers(
|
async def test_update_publishers(
|
||||||
specification, names, expected_result, generate_models,
|
specification,
|
||||||
|
names,
|
||||||
|
expected_result,
|
||||||
|
generate_models,
|
||||||
):
|
):
|
||||||
await generate_models(specification)
|
await generate_models(specification)
|
||||||
await update_publishers(names)
|
await update_publishers(names)
|
||||||
|
@ -107,12 +110,17 @@ async def test_update_publishers(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_save_publication_report(
|
async def test_save_publication_report(
|
||||||
specification, report, event, expected_result, generate_models,
|
specification,
|
||||||
|
report,
|
||||||
|
event,
|
||||||
|
expected_result,
|
||||||
|
generate_models,
|
||||||
):
|
):
|
||||||
await generate_models(specification)
|
await generate_models(specification)
|
||||||
|
|
||||||
publications = await publications_with_status(
|
publications = await publications_with_status(
|
||||||
status=PublicationStatus.WAITING, event_mobilizon_id=event.mobilizon_id,
|
status=PublicationStatus.WAITING,
|
||||||
|
event_mobilizon_id=event.mobilizon_id,
|
||||||
)
|
)
|
||||||
await save_publication_report(report, publications)
|
await save_publication_report(report, publications)
|
||||||
publication_ids = set(report.reports.keys())
|
publication_ids = set(report.reports.keys())
|
||||||
|
|
Loading…
Reference in New Issue