Skip to content

CLI

enforce_retention(repository, days)

Remove the events that are older than the retention period.

Meant to be scheduled, e.g. from cron. Exits with an error if the repository can't remove events by time range.

PARAMETER DESCRIPTION
repository

The repository name. If not provided, the active repository will be used.

TYPE: str | None

days

Remove events older than this many days. If not provided, the ckanext.event_audit.retention_days option is used.

TYPE: int | None

Example

$ ckan event-audit enforce-retention

$ ckan event-audit enforce-retention --days=90

Source code in ckanext/event_audit/cli.py
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
@event_audit.command()
@click.option("--repository", required=False, help="The repository name")
@click.option(
    "--days",
    required=False,
    type=click.IntRange(min=1),
    help=(
        "Remove events older than this many days. "
        "Defaults to the `ckanext.event_audit.retention_days` option."
    ),
)
def enforce_retention(repository: str | None, days: int | None):
    """Remove the events that are older than the retention period.

    Meant to be scheduled, e.g. from cron. Exits with an error if the
    repository can't remove events by time range.

    Args:
        repository (str | None): The repository name. If not provided, the
            active repository will be used.
        days (int | None): Remove events older than this many days. If not
            provided, the `ckanext.event_audit.retention_days` option is used.

    Example:
        $ ckan event-audit enforce-retention

        $ ckan event-audit enforce-retention --days=90
    """
    try:
        repo = utils.get_repo(repository) if repository else utils.get_active_repo()
    except ValueError as e:
        raise click.ClickException(f"Unknown repository: {repository}") from e

    result = utils.enforce_retention(repo, days)

    if not result.status:
        raise click.ClickException(result.message or "Retention wasn't enforced.")

    click.secho(result.message, fg="green")

export_data(exporter_name, start, end, config)

Export data using the specified exporter.

PARAMETER DESCRIPTION
exporter_name

The name of the exporter.

TYPE: str

start

The start date string in %Y-%m-%d format.

TYPE: str

end

The end date string in %Y-%m-%d format.

TYPE: str | None

config

The exporter config in JSON format. See the exporter's documentation for args details.

TYPE: str | None

RETURNS DESCRIPTION
None

The exported data will be printed to the standard output.

Example

$ ckan event-audit export-data csv --start=2024-11-11 > report.csv

$ ckan event-audit export-data json --start=2024-11-11 | jq '[.[] | {id, category, action}]'

$ ckan event-audit export-data xlsx --start=2024-11-11 --config='{"file_path": "/tmp/test.xlsx"}'

Source code in ckanext/event_audit/cli.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
@event_audit.command()
@click.argument("exporter_name", type=str)
@click.option(
    "--start",
    required=True,
    type=click.DateTime(formats=["%Y-%m-%d"]),
    help="ISO format start date",
)
@click.option(
    "--end",
    required=False,
    type=click.DateTime(formats=["%Y-%m-%d"]),
    help="ISO format end date",
)
@click.option("--config", required=False, type=str, help="Custom config in JSON format")
def export_data(
    exporter_name: str, start: dt, end: dt | None, config: str | None
) -> None:
    """Export data using the specified exporter.

    Args:
        exporter_name (str): The name of the exporter.
        start (str): The start date string in %Y-%m-%d format.
        end (str | None): The end date string in %Y-%m-%d format.
        config (str | None): The exporter config in JSON format. See the exporter's
            documentation for args details.

    Returns:
        The exported data will be printed to the standard output.

    Example:
        $ ckan event-audit export-data csv --start=2024-11-11 > report.csv

        $ ckan event-audit export-data json --start=2024-11-11 | jq '[.[] |
            {id, category, action}]'

        $ ckan event-audit export-data xlsx --start=2024-11-11
            --config='{"file_path": "/tmp/test.xlsx"}'
    """
    start = UTC.localize(start) if start else None
    end = UTC.localize(end) if end else None

    try:
        config_dict = json.loads(config or "{}")
    except json.JSONDecodeError:
        return click.secho("Invalid JSON format for config.")

    try:
        exporter = utils.get_exporter(exporter_name)(**config_dict)
    except TypeError as e:
        return click.secho(f"Invalid exporter config: {config}. Error: {e}", fg="red")
    except ValueError as e:
        return click.secho(e, fg="red")

    if start and end and start > end:
        return click.secho("Start date must be before the end date.", fg="red")

    click.echo(exporter.from_filters(types.Filters(time_from=start, time_to=end)))

remove_events(repository, start, end, yes)

Remove events from the repository by time range.

Without --start and --end all the events are removed, after a confirmation unless --yes is given. Not every repository can remove by time range. For CloudWatch, removing all the events deletes the log group and creates it again.

PARAMETER DESCRIPTION
repository

The repository name. If not provided, the active repository will be used.

TYPE: str | None

start

The start date string in %Y-%m-%d format.

TYPE: str

end

The end date string in %Y-%m-%d format.

TYPE: str | None

yes

Skip the confirmation prompt when deleting all events.

TYPE: bool

Example

$ ckan event-audit remove-events --start=2024-11-11 --end=2024-11-12

Source code in ckanext/event_audit/cli.py
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
@event_audit.command()
@click.option("--repository", required=False, help="The repository name")
@click.option(
    "--start",
    required=False,
    type=click.DateTime(formats=["%Y-%m-%d"]),
    help="ISO format start date",
)
@click.option(
    "--end",
    required=False,
    type=click.DateTime(formats=["%Y-%m-%d"]),
    help="ISO format end date",
)
@click.option(
    "--yes",
    is_flag=True,
    default=False,
    help="Skip the confirmation prompt when deleting all events.",
)
def remove_events(  # noqa: PLR0911
    repository: str | None, start: dt | None, end: dt | None, yes: bool
):
    """Remove events from the repository by time range.

    Without `--start` and `--end` **all** the events are removed, after a
    confirmation unless `--yes` is given. Not every repository can remove by
    time range. For CloudWatch, removing all the events deletes the log group
    and creates it again.

    Args:
        repository (str | None): The repository name. If not provided, the
            active repository will be used.
        start (str): The start date string in %Y-%m-%d format.
        end (str | None): The end date string in %Y-%m-%d format.
        yes (bool): Skip the confirmation prompt when deleting all events.

    Example:
        $ ckan event-audit remove-events --start=2024-11-11 --end=2024-11-12
    """
    start = UTC.localize(start) if start else None
    end = UTC.localize(end) if end else None

    if start and end and start > end:
        return click.secho("Start date must be before the end date.", fg="red")

    try:
        repo = utils.get_repo(repository) if repository else utils.get_active_repo()
    except ValueError:
        return click.secho(f"Unknown repository: {repository}", fg="red")

    deleting_everything = not (start or end)

    if deleting_everything and not isinstance(repo, repositories.RemoveAll):
        return click.secho(
            f"Repository {repo.get_name()} does not support removing events.",
            fg="red",
        )

    if (
        deleting_everything
        and not yes
        and not click.confirm(
            f"This will delete ALL events from the '{repo.get_name()}' "
            "repository. Continue?"
        )
    ):
        return click.secho("Aborted.", fg="yellow")

    if not isinstance(repo, repositories.RemoveFiltered):
        if start or end:
            return click.secho(
                (
                    f"Repository {repo.get_name()} does not support removing events "
                    "by time range. "
                    "Please remove the --start and --end flags to delete all events."
                ),
                fg="red",
            )

        return repo.remove_all_events()

    return repo.remove_events(types.Filters(time_from=start, time_to=end))