mirror of
https://github.com/Tech-Workers-Coalition-Italia/mobilizon-reshare.git
synced 2025-02-19 05:00:52 +01:00
Merge pull request #109 from Tech-Workers-Coalition-Italia/inspect
cli: inspect: Refactor command.
This commit is contained in:
commit
94904a8917
@ -1,5 +1,4 @@
|
|||||||
import functools
|
import functools
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
import click
|
import click
|
||||||
from arrow import Arrow
|
from arrow import Arrow
|
||||||
@ -8,98 +7,156 @@ from click import pass_context
|
|||||||
from mobilizon_reshare.cli import safe_execution
|
from mobilizon_reshare.cli import safe_execution
|
||||||
from mobilizon_reshare.cli.commands.format.format import format_event
|
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_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.start.main import main as start_main
|
||||||
from mobilizon_reshare.cli.commands.recap.main import main as recap_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.config.publishers import publisher_names
|
||||||
|
|
||||||
from mobilizon_reshare.event.event import EventPublicationStatus
|
from mobilizon_reshare.event.event import EventPublicationStatus
|
||||||
|
from mobilizon_reshare.models.publication import PublicationStatus
|
||||||
|
|
||||||
status_name_to_enum = {
|
status_name_to_enum = {
|
||||||
"waiting": EventPublicationStatus.WAITING,
|
"event": {
|
||||||
"completed": EventPublicationStatus.COMPLETED,
|
"waiting": EventPublicationStatus.WAITING,
|
||||||
"failed": EventPublicationStatus.FAILED,
|
"completed": EventPublicationStatus.COMPLETED,
|
||||||
"partial": EventPublicationStatus.PARTIAL,
|
"failed": EventPublicationStatus.FAILED,
|
||||||
"all": None,
|
"partial": EventPublicationStatus.PARTIAL,
|
||||||
|
"all": None,
|
||||||
|
},
|
||||||
|
"publication": {
|
||||||
|
"completed": PublicationStatus.COMPLETED,
|
||||||
|
"failed": PublicationStatus.FAILED,
|
||||||
|
"all": None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
settings_file_option = click.option(
|
settings_file_option = click.option(
|
||||||
|
"-f",
|
||||||
"--settings-file",
|
"--settings-file",
|
||||||
type=click.Path(exists=True),
|
type=click.Path(exists=True),
|
||||||
help="The path for the settings file. "
|
help="The path for the settings file. "
|
||||||
"Overrides the one specified in the environment variables.",
|
"Overrides the one specified in the environment variables.",
|
||||||
)
|
)
|
||||||
from_date_option = click.option(
|
from_date_option = click.option(
|
||||||
|
"-b",
|
||||||
"--begin",
|
"--begin",
|
||||||
type=click.DateTime(),
|
type=click.DateTime(),
|
||||||
expose_value=True,
|
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(
|
to_date_option = click.option(
|
||||||
|
"-e",
|
||||||
"--end",
|
"--end",
|
||||||
type=click.DateTime(),
|
type=click.DateTime(),
|
||||||
expose_value=True,
|
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):
|
def print_version(ctx, param, value):
|
||||||
ALL = "all"
|
if not value or ctx.resilient_parsing:
|
||||||
WAITING = "waiting"
|
return
|
||||||
|
click.echo(current_version())
|
||||||
def __str__(self):
|
ctx.exit()
|
||||||
return self.value
|
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
|
@click.option(
|
||||||
|
"--version", is_flag=True, callback=print_version, expose_value=False, is_eager=True
|
||||||
|
)
|
||||||
|
@pass_context
|
||||||
def mobilizon_reshare():
|
def mobilizon_reshare():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@mobilizon_reshare.command(help="Synchronize and publish events")
|
@mobilizon_reshare.command(help="Synchronize and publish events.")
|
||||||
@settings_file_option
|
@settings_file_option
|
||||||
def start(settings_file):
|
def start(ctx, settings):
|
||||||
safe_execution(start_main, settings_file=settings_file)
|
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
|
@settings_file_option
|
||||||
def recap(settings_file):
|
def recap(settings):
|
||||||
safe_execution(recap_main, settings_file=settings_file)
|
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
|
@from_date_option
|
||||||
@to_date_option
|
@to_date_option
|
||||||
@click.argument(
|
@pass_context
|
||||||
"status", type=click.Choice(list(status_name_to_enum.keys())),
|
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
|
@settings_file_option
|
||||||
@pass_context
|
@pass_context
|
||||||
def inspect(ctx, status, begin, end, settings_file):
|
def event(ctx, status, settings):
|
||||||
ctx.ensure_object(dict)
|
ctx.ensure_object(dict)
|
||||||
begin = Arrow.fromdatetime(begin) if begin else None
|
|
||||||
end = Arrow.fromdatetime(end) if end else None
|
|
||||||
|
|
||||||
safe_execution(
|
safe_execution(
|
||||||
functools.partial(
|
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(
|
@mobilizon_reshare.command(
|
||||||
help="Format and print event with mobilizon id EVENT-ID using the publisher's format named"
|
help="Format and print event with EVENT-ID using the publisher's format named "
|
||||||
"PUBLISHER"
|
"PUBLISHER."
|
||||||
)
|
)
|
||||||
@settings_file_option
|
|
||||||
@click.argument("event-id", type=click.UUID)
|
@click.argument("event-id", type=click.UUID)
|
||||||
@click.argument("publisher", type=click.Choice(publisher_names))
|
@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(
|
safe_execution(
|
||||||
functools.partial(format_event, event_id, publisher), settings_file,
|
functools.partial(format_event, event_id, publisher), settings,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
mobilizon_reshare()
|
mobilizon_reshare(obj={})
|
||||||
|
@ -27,8 +27,8 @@ def show_events(events: Iterable[MobilizonEvent]):
|
|||||||
|
|
||||||
def pretty(event: MobilizonEvent):
|
def pretty(event: MobilizonEvent):
|
||||||
return (
|
return (
|
||||||
f"{event.name}|{click.style(event.status.name, fg=status_to_color[event.status])}"
|
f"{event.name : ^40}{click.style(event.status.name, fg=status_to_color[event.status]) : ^22}"
|
||||||
f"|{event.mobilizon_id}|{event.begin_datetime.isoformat()}->{event.end_datetime.isoformat()}"
|
f"{str(event.mobilizon_id) : <40}{event.begin_datetime.isoformat() : <29}{event.end_datetime.isoformat()}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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}")
|
@ -13,9 +13,7 @@ class Publication(Model):
|
|||||||
id = fields.UUIDField(pk=True)
|
id = fields.UUIDField(pk=True)
|
||||||
status = fields.IntEnumField(PublicationStatus)
|
status = fields.IntEnumField(PublicationStatus)
|
||||||
|
|
||||||
# When a Publication's status is WAITING
|
timestamp = fields.DatetimeField()
|
||||||
# we don't need a timestamp nor a reason
|
|
||||||
timestamp = fields.DatetimeField(null=True)
|
|
||||||
reason = fields.TextField(null=True)
|
reason = fields.TextField(null=True)
|
||||||
|
|
||||||
event = fields.ForeignKeyField("models.Event", related_name="publications")
|
event = fields.ForeignKeyField("models.Event", related_name="publications")
|
||||||
|
@ -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(
|
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]:
|
||||||
@ -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(
|
def _add_date_window(
|
||||||
query,
|
query,
|
||||||
field_name: str,
|
field_name: str,
|
||||||
@ -93,7 +109,7 @@ async def publications_with_status(
|
|||||||
event_mobilizon_id: Optional[UUID] = None,
|
event_mobilizon_id: Optional[UUID] = None,
|
||||||
from_date: Optional[Arrow] = None,
|
from_date: Optional[Arrow] = None,
|
||||||
to_date: Optional[Arrow] = None,
|
to_date: Optional[Arrow] = None,
|
||||||
) -> dict[UUID, Publication]:
|
) -> Iterable[Publication]:
|
||||||
query = Publication.filter(status=status)
|
query = Publication.filter(status=status)
|
||||||
|
|
||||||
if event_mobilizon_id:
|
if event_mobilizon_id:
|
||||||
@ -101,12 +117,9 @@ async def publications_with_status(
|
|||||||
event__mobilizon_id=event_mobilizon_id
|
event__mobilizon_id=event_mobilizon_id
|
||||||
)
|
)
|
||||||
|
|
||||||
query = _add_date_window(query, "timestamp", from_date, to_date)
|
return await prefetch_publication_relations(
|
||||||
|
_add_date_window(query, "timestamp", from_date, to_date)
|
||||||
publications_list = (
|
|
||||||
await query.prefetch_related("publisher").order_by("timestamp").distinct()
|
|
||||||
)
|
)
|
||||||
return {pub.id: pub for pub in publications_list}
|
|
||||||
|
|
||||||
|
|
||||||
async def events_without_publications(
|
async def events_without_publications(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from datetime import timedelta
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -18,6 +19,7 @@ from mobilizon_reshare.publishers.coordinator import (
|
|||||||
PublicationFailureNotifiersCoordinator,
|
PublicationFailureNotifiersCoordinator,
|
||||||
RecapCoordinator,
|
RecapCoordinator,
|
||||||
)
|
)
|
||||||
|
from tests import today
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
@ -91,7 +93,7 @@ async def mock_publications(
|
|||||||
id=UUID(int=i + 1),
|
id=UUID(int=i + 1),
|
||||||
event=event,
|
event=event,
|
||||||
publisher=publisher,
|
publisher=publisher,
|
||||||
timestamp=None,
|
timestamp=today + timedelta(hours=i),
|
||||||
reason=None,
|
reason=None,
|
||||||
)
|
)
|
||||||
publication = EventPublication.from_orm(publication, test_event)
|
publication = EventPublication.from_orm(publication, test_event)
|
||||||
|
@ -5,7 +5,6 @@ import arrow
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mobilizon_reshare.event.event import MobilizonEvent, EventPublicationStatus
|
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.models.publication import PublicationStatus
|
||||||
from mobilizon_reshare.storage.query.read import (
|
from mobilizon_reshare.storage.query.read import (
|
||||||
get_published_events,
|
get_published_events,
|
||||||
@ -83,7 +82,7 @@ async def test_publications_with_status(
|
|||||||
to_date=to_date,
|
to_date=to_date,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert publications == {pub.id: pub for pub in expected_result}
|
assert publications == expected_result
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
Loading…
x
Reference in New Issue
Block a user