Merge pull request #109 from Tech-Workers-Coalition-Italia/inspect

cli: inspect: Refactor command.
This commit is contained in:
Simone Robutti 2021-12-11 11:17:59 +01:00 committed by GitHub
commit 94904a8917
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 160 additions and 50 deletions

View File

@ -1,5 +1,4 @@
import functools
from enum import Enum
import click
from arrow import Arrow
@ -8,98 +7,156 @@ from click import pass_context
from mobilizon_reshare.cli import safe_execution
from mobilizon_reshare.cli.commands.format.format import format_event
from mobilizon_reshare.cli.commands.inspect.inspect_event import inspect_events
from mobilizon_reshare.cli.commands.inspect.inspect_publication import (
inspect_publications,
)
from mobilizon_reshare.cli.commands.start.main import main as start_main
from mobilizon_reshare.cli.commands.recap.main import main as recap_main
from mobilizon_reshare.config.config import current_version
from mobilizon_reshare.config.publishers import publisher_names
from mobilizon_reshare.event.event import EventPublicationStatus
from mobilizon_reshare.models.publication import PublicationStatus
status_name_to_enum = {
"waiting": EventPublicationStatus.WAITING,
"completed": EventPublicationStatus.COMPLETED,
"failed": EventPublicationStatus.FAILED,
"partial": EventPublicationStatus.PARTIAL,
"all": None,
"event": {
"waiting": EventPublicationStatus.WAITING,
"completed": EventPublicationStatus.COMPLETED,
"failed": EventPublicationStatus.FAILED,
"partial": EventPublicationStatus.PARTIAL,
"all": None,
},
"publication": {
"completed": PublicationStatus.COMPLETED,
"failed": PublicationStatus.FAILED,
"all": None,
},
}
settings_file_option = click.option(
"-f",
"--settings-file",
type=click.Path(exists=True),
help="The path for the settings file. "
"Overrides the one specified in the environment variables.",
)
from_date_option = click.option(
"-b",
"--begin",
type=click.DateTime(),
expose_value=True,
help="Include only events that begin after this datetime",
help="Include only events that begin after this datetime.",
)
to_date_option = click.option(
"-e",
"--end",
type=click.DateTime(),
expose_value=True,
help="Include only events that begin before this datetime",
help="Include only events that begin before this datetime.",
)
event_status_option = click.option(
"-s",
"--status",
type=click.Choice(list(status_name_to_enum["event"].keys())),
default="all",
expose_value=True,
help="Include only events with the given STATUS.",
)
publication_status_option = click.option(
"-s",
"--status",
type=click.Choice(list(status_name_to_enum["publication"].keys())),
default="all",
expose_value=True,
help="Include only publications with the given STATUS.",
)
class InspectTarget(Enum):
ALL = "all"
WAITING = "waiting"
def __str__(self):
return self.value
def print_version(ctx, param, value):
if not value or ctx.resilient_parsing:
return
click.echo(current_version())
ctx.exit()
@click.group()
@click.option(
"--version", is_flag=True, callback=print_version, expose_value=False, is_eager=True
)
@pass_context
def mobilizon_reshare():
pass
@mobilizon_reshare.command(help="Synchronize and publish events")
@mobilizon_reshare.command(help="Synchronize and publish events.")
@settings_file_option
def start(settings_file):
safe_execution(start_main, settings_file=settings_file)
def start(ctx, settings):
ctx.ensure_object(dict)
safe_execution(start_main, settings_file=settings)
@mobilizon_reshare.command(help="Publish a recap of already published events")
@mobilizon_reshare.command(help="Publish a recap of already published events.")
@settings_file_option
def recap(settings_file):
safe_execution(recap_main, settings_file=settings_file)
def recap(settings):
safe_execution(recap_main, settings_file=settings)
@mobilizon_reshare.command(help="Print events in the database that are in STATUS")
@mobilizon_reshare.group(help="List objects in the database with different criteria.")
@from_date_option
@to_date_option
@click.argument(
"status", type=click.Choice(list(status_name_to_enum.keys())),
)
@pass_context
def inspect(ctx, begin, end):
ctx.ensure_object(dict)
ctx.obj["begin"] = Arrow.fromdatetime(begin) if begin else None
ctx.obj["end"] = Arrow.fromdatetime(end) if end else None
@inspect.command(help="Query for events in the database.")
@event_status_option
@settings_file_option
@pass_context
def inspect(ctx, status, begin, end, settings_file):
def event(ctx, status, settings):
ctx.ensure_object(dict)
begin = Arrow.fromdatetime(begin) if begin else None
end = Arrow.fromdatetime(end) if end else None
safe_execution(
functools.partial(
inspect_events, status_name_to_enum[status], frm=begin, to=end,
inspect_events,
status_name_to_enum["event"][status],
frm=ctx.obj["begin"],
to=ctx.obj["end"],
),
settings_file,
settings,
)
@inspect.command(help="Query for publications in the database.")
@publication_status_option
@settings_file_option
@pass_context
def publication(ctx, status, settings):
ctx.ensure_object(dict)
safe_execution(
functools.partial(
inspect_publications,
status_name_to_enum["publication"][status],
frm=ctx.obj["begin"],
to=ctx.obj["end"],
),
settings,
)
@mobilizon_reshare.command(
help="Format and print event with mobilizon id EVENT-ID using the publisher's format named"
"PUBLISHER"
help="Format and print event with EVENT-ID using the publisher's format named "
"PUBLISHER."
)
@settings_file_option
@click.argument("event-id", type=click.UUID)
@click.argument("publisher", type=click.Choice(publisher_names))
def format(settings_file, event_id, publisher):
@settings_file_option
def format(event_id, publisher, settings):
safe_execution(
functools.partial(format_event, event_id, publisher), settings_file,
functools.partial(format_event, event_id, publisher), settings,
)
if __name__ == "__main__":
mobilizon_reshare()
mobilizon_reshare(obj={})

View File

@ -27,8 +27,8 @@ def show_events(events: Iterable[MobilizonEvent]):
def pretty(event: MobilizonEvent):
return (
f"{event.name}|{click.style(event.status.name, fg=status_to_color[event.status])}"
f"|{event.mobilizon_id}|{event.begin_datetime.isoformat()}->{event.end_datetime.isoformat()}"
f"{event.name : ^40}{click.style(event.status.name, fg=status_to_color[event.status]) : ^22}"
f"{str(event.mobilizon_id) : <40}{event.begin_datetime.isoformat() : <29}{event.end_datetime.isoformat()}"
)

View File

@ -0,0 +1,41 @@
from typing import Iterable
import click
from arrow import Arrow
from mobilizon_reshare.models.publication import Publication, PublicationStatus
from mobilizon_reshare.storage.query.read import (
get_all_publications,
publications_with_status,
)
status_to_color = {
PublicationStatus.COMPLETED: "green",
PublicationStatus.FAILED: "red",
}
def show_publications(publications: Iterable[Publication]):
click.echo_via_pager("\n".join(map(pretty, publications)))
def pretty(publication: Publication):
return (
f"{str(publication.id) : <40}{publication.timestamp.isoformat() : <36}"
f"{click.style(publication.status.name, fg=status_to_color[publication.status]) : <22}"
f"{publication.publisher.name : <12}{str(publication.event.id)}"
)
async def inspect_publications(
status: PublicationStatus = None, frm: Arrow = None, to: Arrow = None
):
if status is None:
publications = await get_all_publications(from_date=frm, to_date=to)
else:
publications = await publications_with_status(status, from_date=frm, to_date=to)
if publications:
show_publications(list(publications))
else:
click.echo(f"No publication found with status: {status}")

View File

@ -13,9 +13,7 @@ class Publication(Model):
id = fields.UUIDField(pk=True)
status = fields.IntEnumField(PublicationStatus)
# When a Publication's status is WAITING
# we don't need a timestamp nor a reason
timestamp = fields.DatetimeField(null=True)
timestamp = fields.DatetimeField()
reason = fields.TextField(null=True)
event = fields.ForeignKeyField("models.Event", related_name="publications")

View File

@ -55,6 +55,14 @@ async def events_with_status(
)
async def get_all_publications(
from_date: Optional[Arrow] = None, to_date: Optional[Arrow] = None,
) -> Iterable[Publication]:
return await prefetch_publication_relations(
_add_date_window(Publication.all(), "timestamp", from_date, to_date)
)
async def get_all_events(
from_date: Optional[Arrow] = None, to_date: Optional[Arrow] = None,
) -> Iterable[MobilizonEvent]:
@ -74,6 +82,14 @@ async def prefetch_event_relations(queryset: QuerySet[Event]) -> list[Event]:
)
async def prefetch_publication_relations(queryset: QuerySet[Publication]) -> list[Publication]:
return (
await queryset.prefetch_related("publisher", "event")
.order_by("timestamp")
.distinct()
)
def _add_date_window(
query,
field_name: str,
@ -93,7 +109,7 @@ async def publications_with_status(
event_mobilizon_id: Optional[UUID] = None,
from_date: Optional[Arrow] = None,
to_date: Optional[Arrow] = None,
) -> dict[UUID, Publication]:
) -> Iterable[Publication]:
query = Publication.filter(status=status)
if event_mobilizon_id:
@ -101,12 +117,9 @@ async def publications_with_status(
event__mobilizon_id=event_mobilizon_id
)
query = _add_date_window(query, "timestamp", from_date, to_date)
publications_list = (
await query.prefetch_related("publisher").order_by("timestamp").distinct()
return await prefetch_publication_relations(
_add_date_window(query, "timestamp", from_date, to_date)
)
return {pub.id: pub for pub in publications_list}
async def events_without_publications(

View File

@ -1,4 +1,5 @@
import logging
from datetime import timedelta
from uuid import UUID
import pytest
@ -18,6 +19,7 @@ from mobilizon_reshare.publishers.coordinator import (
PublicationFailureNotifiersCoordinator,
RecapCoordinator,
)
from tests import today
@pytest.fixture()
@ -91,7 +93,7 @@ async def mock_publications(
id=UUID(int=i + 1),
event=event,
publisher=publisher,
timestamp=None,
timestamp=today + timedelta(hours=i),
reason=None,
)
publication = EventPublication.from_orm(publication, test_event)

View File

@ -5,7 +5,6 @@ import arrow
import pytest
from mobilizon_reshare.event.event import MobilizonEvent, EventPublicationStatus
from mobilizon_reshare.models.event import Event
from mobilizon_reshare.models.publication import PublicationStatus
from mobilizon_reshare.storage.query.read import (
get_published_events,
@ -83,7 +82,7 @@ async def test_publications_with_status(
to_date=to_date,
)
assert publications == {pub.id: pub for pub in expected_result}
assert publications == expected_result
@pytest.mark.asyncio