Pave the way for using only EventPublications outside of storage module. (#149)
* Move `EventPublication.from_orm` to `storage.query.converter`. Co-authored-by: Simone Robutti <simone.robutti@protonmail.com>
This commit is contained in:
parent
bda4b8ee0d
commit
529f83825e
|
@ -2,7 +2,7 @@ import click
|
|||
|
||||
from mobilizon_reshare.models.event import Event
|
||||
from mobilizon_reshare.publishers.platforms.platform_mapping import get_formatter_class
|
||||
from mobilizon_reshare.storage.query.event_converter import from_model
|
||||
from mobilizon_reshare.storage.query.converter import event_from_model
|
||||
|
||||
|
||||
async def format_event(event_id, publisher_name: str):
|
||||
|
@ -12,6 +12,6 @@ async def format_event(event_id, publisher_name: str):
|
|||
if not event:
|
||||
click.echo(f"Event with mobilizon_id {event_id} not found.")
|
||||
return
|
||||
event = from_model(event)
|
||||
event = event_from_model(event)
|
||||
message = get_formatter_class(publisher_name)().get_message_from_event(event)
|
||||
click.echo(message)
|
||||
|
|
|
@ -5,12 +5,12 @@ from dataclasses import dataclass
|
|||
from typing import List, Optional
|
||||
from uuid import UUID
|
||||
|
||||
import arrow
|
||||
from dynaconf.utils.boxing import DynaBox
|
||||
from jinja2 import Environment, FileSystemLoader, Template
|
||||
|
||||
from mobilizon_reshare.config.config import get_settings
|
||||
from mobilizon_reshare.event.event import MobilizonEvent
|
||||
from mobilizon_reshare.models.publication import Publication as PublicationModel
|
||||
from .exceptions import InvalidAttribute
|
||||
|
||||
JINJA_ENV = Environment(loader=FileSystemLoader("/"))
|
||||
|
@ -188,18 +188,6 @@ class EventPublication(BasePublication):
|
|||
event: MobilizonEvent
|
||||
id: UUID
|
||||
|
||||
@classmethod
|
||||
def from_orm(cls, model: PublicationModel, event: MobilizonEvent):
|
||||
# imported here to avoid circular dependencies
|
||||
from mobilizon_reshare.publishers.platforms.platform_mapping import (
|
||||
get_publisher_class,
|
||||
get_formatter_class,
|
||||
)
|
||||
|
||||
publisher = get_publisher_class(model.publisher.name)()
|
||||
formatter = get_formatter_class(model.publisher.name)()
|
||||
return cls(publisher, formatter, event, model.id,)
|
||||
|
||||
|
||||
@dataclass
|
||||
class RecapPublication(BasePublication):
|
||||
|
|
|
@ -7,11 +7,12 @@ import tortoise.timezone
|
|||
from mobilizon_reshare.event.event import EventPublicationStatus, MobilizonEvent
|
||||
from mobilizon_reshare.models.event import Event
|
||||
from mobilizon_reshare.models.publication import Publication, PublicationStatus
|
||||
from mobilizon_reshare.publishers.abstract import EventPublication
|
||||
|
||||
|
||||
def from_model(event: Event, tz: str = "UTC"):
|
||||
def event_from_model(event: Event, tz: str = "UTC"):
|
||||
|
||||
publication_status = compute_status(list(event.publications))
|
||||
publication_status = compute_event_status(list(event.publications))
|
||||
publication_time = {}
|
||||
|
||||
for pub in event.publications:
|
||||
|
@ -41,7 +42,7 @@ def from_model(event: Event, tz: str = "UTC"):
|
|||
)
|
||||
|
||||
|
||||
def to_model(event: MobilizonEvent, db_id: Optional[UUID] = None) -> Event:
|
||||
def event_to_model(event: MobilizonEvent, db_id: Optional[UUID] = None) -> Event:
|
||||
kwargs = {
|
||||
"name": event.name,
|
||||
"description": event.description,
|
||||
|
@ -60,7 +61,7 @@ def to_model(event: MobilizonEvent, db_id: Optional[UUID] = None) -> Event:
|
|||
return Event(**kwargs)
|
||||
|
||||
|
||||
def compute_status(publications: list[Publication]) -> EventPublicationStatus:
|
||||
def compute_event_status(publications: list[Publication]) -> EventPublicationStatus:
|
||||
if not publications:
|
||||
return EventPublicationStatus.WAITING
|
||||
|
||||
|
@ -75,3 +76,20 @@ def compute_status(publications: list[Publication]) -> EventPublicationStatus:
|
|||
return EventPublicationStatus[unique_statuses.pop().name]
|
||||
|
||||
raise ValueError(f"Illegal combination of PublicationStatus: {unique_statuses}")
|
||||
|
||||
|
||||
def publication_from_orm(model: Publication, event: MobilizonEvent):
|
||||
# imported here to avoid circular dependencies
|
||||
from mobilizon_reshare.publishers.platforms.platform_mapping import (
|
||||
get_publisher_class,
|
||||
get_formatter_class,
|
||||
)
|
||||
|
||||
publisher = get_publisher_class(model.publisher.name)()
|
||||
formatter = get_formatter_class(model.publisher.name)()
|
||||
return EventPublication(
|
||||
publisher,
|
||||
formatter,
|
||||
event,
|
||||
model.id,
|
||||
)
|
|
@ -15,7 +15,11 @@ from mobilizon_reshare.models.publisher import Publisher
|
|||
from mobilizon_reshare.publishers import get_active_publishers
|
||||
from mobilizon_reshare.publishers.abstract import EventPublication
|
||||
from mobilizon_reshare.storage.query import CONNECTION_NAME
|
||||
from mobilizon_reshare.storage.query.event_converter import from_model, compute_status
|
||||
from mobilizon_reshare.storage.query.converter import (
|
||||
event_from_model,
|
||||
compute_event_status,
|
||||
publication_from_orm,
|
||||
)
|
||||
from mobilizon_reshare.storage.query.exceptions import EventNotFound
|
||||
|
||||
|
||||
|
@ -45,13 +49,13 @@ async def events_with_status(
|
|||
def _filter_event_with_status(event: Event) -> bool:
|
||||
# This computes the status client-side instead of running in the DB. It shouldn't pose a performance problem
|
||||
# in the short term, but should be moved to the query if possible.
|
||||
event_status = compute_status(list(event.publications))
|
||||
event_status = compute_event_status(list(event.publications))
|
||||
return event_status in status
|
||||
|
||||
query = Event.all()
|
||||
|
||||
return map(
|
||||
from_model,
|
||||
event_from_model,
|
||||
filter(
|
||||
_filter_event_with_status,
|
||||
await prefetch_event_relations(
|
||||
|
@ -63,7 +67,7 @@ async def events_with_status(
|
|||
|
||||
async def get_all_publications(
|
||||
from_date: Optional[Arrow] = None, to_date: Optional[Arrow] = None,
|
||||
) -> Iterable[Publication]:
|
||||
) -> Iterable[EventPublication]:
|
||||
return await prefetch_publication_relations(
|
||||
_add_date_window(Publication.all(), "timestamp", from_date, to_date)
|
||||
)
|
||||
|
@ -73,7 +77,7 @@ async def get_all_events(
|
|||
from_date: Optional[Arrow] = None, to_date: Optional[Arrow] = None,
|
||||
) -> Iterable[MobilizonEvent]:
|
||||
return map(
|
||||
from_model,
|
||||
event_from_model,
|
||||
await prefetch_event_relations(
|
||||
_add_date_window(Event.all(), "begin_datetime", from_date, to_date)
|
||||
),
|
||||
|
@ -118,7 +122,7 @@ async def publications_with_status(
|
|||
event_mobilizon_id: Optional[UUID] = None,
|
||||
from_date: Optional[Arrow] = None,
|
||||
to_date: Optional[Arrow] = None,
|
||||
) -> Iterable[Publication]:
|
||||
) -> Iterable[EventPublication]:
|
||||
query = Publication.filter(status=status)
|
||||
|
||||
if event_mobilizon_id:
|
||||
|
@ -138,7 +142,7 @@ async def events_without_publications(
|
|||
events = await prefetch_event_relations(
|
||||
_add_date_window(query, "begin_datetime", from_date, to_date)
|
||||
)
|
||||
return list(map(from_model, events))
|
||||
return list(map(event_from_model, events))
|
||||
|
||||
|
||||
async def get_event(event_mobilizon_id: UUID) -> Event:
|
||||
|
@ -170,9 +174,7 @@ async def build_publications(event: MobilizonEvent) -> list[EventPublication]:
|
|||
await event_model.build_publication_by_publisher_name(name)
|
||||
for name in get_active_publishers()
|
||||
]
|
||||
return list(
|
||||
EventPublication.from_orm(m, dataclasses.replace(event)) for m in models
|
||||
)
|
||||
return list(publication_from_orm(m, dataclasses.replace(event)) for m in models)
|
||||
|
||||
|
||||
@atomic(CONNECTION_NAME)
|
||||
|
@ -188,9 +190,7 @@ async def get_failed_publications_for_event(
|
|||
)
|
||||
for p in failed_publications:
|
||||
await p.fetch_related("publisher")
|
||||
return list(
|
||||
map(partial(EventPublication.from_orm, event=event), failed_publications)
|
||||
)
|
||||
return list(map(partial(publication_from_orm, event=event), failed_publications))
|
||||
|
||||
|
||||
@atomic(CONNECTION_NAME)
|
||||
|
@ -201,8 +201,6 @@ async def get_publication(publication_id):
|
|||
)
|
||||
# TODO: this is redundant but there's some prefetch problem otherwise
|
||||
publication.event = await get_event(publication.event.mobilizon_id)
|
||||
return EventPublication.from_orm(
|
||||
publication, event=from_model(publication.event)
|
||||
)
|
||||
return publication_from_orm(event=event_from_model(publication.event))
|
||||
except DoesNotExist:
|
||||
return None
|
||||
|
|
|
@ -10,7 +10,7 @@ from mobilizon_reshare.models.publication import Publication
|
|||
from mobilizon_reshare.models.publisher import Publisher
|
||||
from mobilizon_reshare.publishers.coordinator import PublisherCoordinatorReport
|
||||
from mobilizon_reshare.storage.query import CONNECTION_NAME
|
||||
from mobilizon_reshare.storage.query.event_converter import to_model
|
||||
from mobilizon_reshare.storage.query.converter import event_to_model
|
||||
from mobilizon_reshare.storage.query.read import (
|
||||
events_without_publications,
|
||||
is_known,
|
||||
|
@ -78,12 +78,12 @@ async def create_unpublished_events(
|
|||
for event in events_from_mobilizon:
|
||||
if not await is_known(event):
|
||||
# Either an event is unknown
|
||||
await to_model(event).save()
|
||||
await event_to_model(event).save()
|
||||
else:
|
||||
# Or it's known and changed
|
||||
event_model = await get_event(event.mobilizon_id)
|
||||
if event.last_update_time > event_model.last_update_time:
|
||||
await to_model(event=event, db_id=event_model.id).save(
|
||||
await event_to_model(event=event, db_id=event_model.id).save(
|
||||
force_update=True
|
||||
)
|
||||
# Or it's known and unchanged, in which case we do nothing.
|
||||
|
|
|
@ -7,13 +7,13 @@ from mobilizon_reshare.publishers.platforms.platform_mapping import (
|
|||
get_formatter_class,
|
||||
name_to_formatter_class,
|
||||
)
|
||||
from mobilizon_reshare.storage.query.event_converter import to_model
|
||||
from mobilizon_reshare.storage.query.converter import event_to_model
|
||||
|
||||
|
||||
@pytest.mark.parametrize("publisher_name", name_to_formatter_class.keys())
|
||||
@pytest.mark.asyncio
|
||||
async def test_format_event(runner, event, capsys, publisher_name):
|
||||
event_model = to_model(event)
|
||||
event_model = event_to_model(event)
|
||||
await event_model.save()
|
||||
await format_event(
|
||||
event_id=str(event_model.mobilizon_id), publisher_name=publisher_name
|
||||
|
|
|
@ -4,7 +4,7 @@ from logging import DEBUG, INFO
|
|||
import arrow
|
||||
import pytest
|
||||
|
||||
from mobilizon_reshare.storage.query.event_converter import from_model, to_model
|
||||
from mobilizon_reshare.storage.query.converter import event_from_model, event_to_model
|
||||
from mobilizon_reshare.storage.query.read import get_all_events
|
||||
from tests.commands.conftest import simple_event_element
|
||||
from mobilizon_reshare.event.event import EventPublicationStatus
|
||||
|
@ -74,7 +74,7 @@ async def test_start_new_event(
|
|||
assert p.status == PublicationStatus.COMPLETED
|
||||
|
||||
# the derived status for the event should be COMPLETED
|
||||
assert from_model(all_events[0]).status == EventPublicationStatus.COMPLETED
|
||||
assert event_from_model(all_events[0]).status == EventPublicationStatus.COMPLETED
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
@ -93,7 +93,7 @@ async def test_start_event_from_db(
|
|||
event_generator,
|
||||
):
|
||||
event = event_generator()
|
||||
event_model = to_model(event)
|
||||
event_model = event_to_model(event)
|
||||
await event_model.save()
|
||||
|
||||
with caplog.at_level(DEBUG):
|
||||
|
@ -116,7 +116,7 @@ async def test_start_event_from_db(
|
|||
assert p.status == PublicationStatus.COMPLETED
|
||||
|
||||
# the derived status for the event should be COMPLETED
|
||||
assert from_model(event_model).status == EventPublicationStatus.COMPLETED
|
||||
assert event_from_model(event_model).status == EventPublicationStatus.COMPLETED
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
@ -136,7 +136,7 @@ async def test_start_publisher_failure(
|
|||
mock_notifier_config,
|
||||
):
|
||||
event = event_generator()
|
||||
event_model = to_model(event)
|
||||
event_model = event_to_model(event)
|
||||
await event_model.save()
|
||||
|
||||
with caplog.at_level(DEBUG):
|
||||
|
@ -163,14 +163,14 @@ async def test_start_publisher_failure(
|
|||
for _ in range(2)
|
||||
] # 2 publications failed * 2 notifiers
|
||||
# the derived status for the event should be FAILED
|
||||
assert from_model(event_model).status == EventPublicationStatus.FAILED
|
||||
assert event_from_model(event_model).status == EventPublicationStatus.FAILED
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def published_event(event_generator):
|
||||
|
||||
event = event_generator()
|
||||
event_model = to_model(event)
|
||||
event_model = event_to_model(event)
|
||||
await event_model.save()
|
||||
assert await start() is None
|
||||
await event_model.refresh_from_db()
|
||||
|
|
|
@ -22,7 +22,7 @@ from mobilizon_reshare.publishers.abstract import (
|
|||
AbstractEventFormatter,
|
||||
)
|
||||
from mobilizon_reshare.publishers.exceptions import PublisherError, InvalidResponse
|
||||
from mobilizon_reshare.storage.query.event_converter import to_model
|
||||
from mobilizon_reshare.storage.query.converter import event_to_model
|
||||
from mobilizon_reshare.storage.query.write import get_publisher_by_name
|
||||
from tests import today
|
||||
|
||||
|
@ -114,7 +114,7 @@ def event() -> MobilizonEvent:
|
|||
|
||||
@pytest.fixture
|
||||
async def stored_event(event):
|
||||
model = to_model(event)
|
||||
model = event_to_model(event)
|
||||
await model.save()
|
||||
await model.fetch_related("publications")
|
||||
return model
|
||||
|
|
|
@ -8,10 +8,10 @@ import tortoise.timezone
|
|||
from mobilizon_reshare.event.event import EventPublicationStatus
|
||||
from mobilizon_reshare.models.event import Event
|
||||
from mobilizon_reshare.models.publication import PublicationStatus
|
||||
from mobilizon_reshare.storage.query.event_converter import (
|
||||
from_model,
|
||||
to_model,
|
||||
compute_status,
|
||||
from mobilizon_reshare.storage.query.converter import (
|
||||
event_from_model,
|
||||
event_to_model,
|
||||
compute_event_status,
|
||||
)
|
||||
|
||||
|
||||
|
@ -93,7 +93,7 @@ async def test_event_sort_by_date(event_model_generator):
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mobilizon_event_to_model(event):
|
||||
event_model = to_model(event)
|
||||
event_model = event_to_model(event)
|
||||
await event_model.save()
|
||||
|
||||
event_db = await Event.all().first()
|
||||
|
@ -141,7 +141,7 @@ async def test_mobilizon_event_from_model(
|
|||
.prefetch_related("publications__publisher")
|
||||
.first()
|
||||
)
|
||||
event = from_model(event=event_db, tz="CET")
|
||||
event = event_from_model(event=event_db, tz="CET")
|
||||
|
||||
begin_date_utc = arrow.Arrow(year=2021, month=1, day=1, hour=11, minute=30)
|
||||
|
||||
|
@ -196,4 +196,4 @@ async def test_mobilizon_event_compute_status_partial(
|
|||
)
|
||||
await publication.save()
|
||||
publications.append(publication)
|
||||
assert compute_status(publications) == expected_result
|
||||
assert compute_event_status(publications) == expected_result
|
||||
|
|
|
@ -19,7 +19,10 @@ from mobilizon_reshare.publishers.coordinator import (
|
|||
PublicationFailureNotifiersCoordinator,
|
||||
RecapCoordinator,
|
||||
)
|
||||
from mobilizon_reshare.storage.query.event_converter import to_model
|
||||
from mobilizon_reshare.storage.query.converter import (
|
||||
event_to_model,
|
||||
publication_from_orm,
|
||||
)
|
||||
from tests import today
|
||||
|
||||
|
||||
|
@ -89,7 +92,7 @@ async def mock_publications(
|
|||
):
|
||||
result = []
|
||||
for i in range(num_publications):
|
||||
event = to_model(test_event)
|
||||
event = event_to_model(test_event)
|
||||
await event.save()
|
||||
publisher = Publisher(name="telegram")
|
||||
await publisher.save()
|
||||
|
@ -100,7 +103,7 @@ async def mock_publications(
|
|||
timestamp=today + timedelta(hours=i),
|
||||
reason=None,
|
||||
)
|
||||
publication = EventPublication.from_orm(publication, test_event)
|
||||
publication = publication_from_orm(publication, test_event)
|
||||
publication.publisher = mock_publisher_valid
|
||||
publication.formatter = mock_formatter_valid
|
||||
result.append(publication)
|
||||
|
@ -109,8 +112,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))
|
||||
|
|
|
@ -13,7 +13,7 @@ from mobilizon_reshare.publishers.exceptions import (
|
|||
HTTPResponseError,
|
||||
)
|
||||
from mobilizon_reshare.publishers.platforms.zulip import ZulipFormatter, ZulipPublisher
|
||||
from mobilizon_reshare.storage.query.event_converter import to_model
|
||||
from mobilizon_reshare.storage.query.converter import event_to_model
|
||||
from mobilizon_reshare.storage.query.read import build_publications
|
||||
|
||||
api_uri = "https://zulip.twc-italia.org/api/v1/"
|
||||
|
@ -103,7 +103,7 @@ async def setup_db(
|
|||
@pytest.fixture
|
||||
@pytest.mark.asyncio
|
||||
async def unsaved_publications(event):
|
||||
await to_model(event).save()
|
||||
await event_to_model(event).save()
|
||||
return await build_publications(event)
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ from uuid import UUID
|
|||
|
||||
import pytest
|
||||
|
||||
from mobilizon_reshare.storage.query.event_converter import to_model
|
||||
from mobilizon_reshare.storage.query.converter import event_to_model
|
||||
from mobilizon_reshare.storage.query.read import get_all_events
|
||||
|
||||
|
||||
|
@ -12,6 +12,6 @@ async def test_get_all_events(event_generator):
|
|||
event_generator(mobilizon_id=UUID(int=i), published=False) for i in range(4)
|
||||
]
|
||||
for e in all_events:
|
||||
await to_model(e).save()
|
||||
await event_to_model(e).save()
|
||||
|
||||
assert list(await get_all_events()) == all_events
|
||||
|
|
Loading…
Reference in New Issue