diff --git a/invenio_utilities_tuw/cli/drafts.py b/invenio_utilities_tuw/cli/drafts.py index 45b386b1aefbb7cc1bfa06d767a68683b55b4c4e..14800e5afcbcf496dd70dc3839ec1faea5a97b19 100644 --- a/invenio_utilities_tuw/cli/drafts.py +++ b/invenio_utilities_tuw/cli/drafts.py @@ -11,6 +11,8 @@ import json import os import sys +from collections import namedtuple +from datetime import datetime, timedelta from os.path import basename, isdir, isfile, join import click @@ -430,3 +432,56 @@ def verify_files(pid, pid_type): err=True, ) sys.exit(1) + + +@drafts.command("list-stale") +@click.option( + "--days", + "-d", + "num_days", + help="threshold after how many days a draft is considered stale", + default=30, + type=int, +) +@with_appcontext +def list_stale_drafts(num_days): + """List all drafts that haven't been updated for a while.""" + service = get_record_service() + dc, mc = service.draft_cls, service.draft_cls.model_cls + cutoff_date = datetime.utcnow() - timedelta(days=abs(num_days)) + + # `draft.status` uses the system field: + # `invenio_rdm_records.records.systemfields.draft_status.DraftStatus` + stale_drafts = [ + draft + for draft in ( + dc(model.data, model=model) + for model in mc.query.filter(mc.updated <= cutoff_date).all() + ) + if draft and draft.status in ["new_version_draft", "draft"] + ] + + # collect infos about stale drafts + draft_info = namedtuple("DraftInfo", ["recid", "title", "uploader", "updated"]) + stale_draft_infos = [] + for draft in stale_drafts: + recid = draft.pid.pid_value + title = draft.metadata.get("title", "[UNNAMED]") + + # InvenioRDM v11 still supports several record owners + uploader = draft.parent.access.owned_by + if isinstance(uploader, list): + if uploader: + uploader = uploader[0] + else: + uploader = None + + uploader_email = uploader.resolve().email if uploader else "[N/A]" + updated = draft.updated.date() if draft.updated else "[N/A]" + stale_draft_infos.append(draft_info(recid, title, uploader_email, updated)) + + # print the info about stale drafts, sorted by the owner's email address + max_email_len = max((len(di.uploader) for di in stale_draft_infos)) + for info in sorted(stale_draft_infos, key=lambda di: di.uploader): + email = info.uploader.rjust(max_email_len) + click.echo(f'{info.recid} - {email} @ {info.updated} - "{info.title}"')