From 4d4ca621a5874383e4c757847c4dd3e2fca8746f Mon Sep 17 00:00:00 2001
From: Maximilian Moser <maximilian.moser@tuwien.ac.at>
Date: Wed, 3 Mar 2021 18:19:24 +0100
Subject: [PATCH] Update methods for performing record metadata updates

* per default, try the more modern approach of updating the draft that
  is associated with the record's recid (service.update_draft() followed
  by service.publish()), and only in case of error fall back to
  service.update()
* add a "direct" variant of updating metadata, which circumvents the
  record service and directly modifies the record's metadata
* this is not recommended, but can come in handy when more direct access
  is required than the record service allows
---
 invenio_utilities_tuw/cli/records.py | 35 ++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/invenio_utilities_tuw/cli/records.py b/invenio_utilities_tuw/cli/records.py
index d656d59..0363e27 100644
--- a/invenio_utilities_tuw/cli/records.py
+++ b/invenio_utilities_tuw/cli/records.py
@@ -13,6 +13,8 @@ import sys
 
 import click
 from flask.cli import with_appcontext
+from invenio_accounts import current_accounts
+from invenio_db import db
 from invenio_files_rest.models import ObjectVersion
 
 from ..utils import get_record_file_service, get_record_service
@@ -99,9 +101,19 @@ def show_record(pid, pid_type, user, pretty_print, raw):
         "(default: replace)"
     ),
 )
+@click.option(
+    "--direct",
+    "-d",
+    default=False,
+    is_flag=True,
+    help=(
+        "circumvent the record service, and thus permission checks, "
+        "and update the record directly (not recommended)"
+    )
+)
 @option_owners
 @with_appcontext
-def update_record(metadata_file, pid, pid_type, user, patch, owners):
+def update_record(metadata_file, pid, pid_type, user, patch, owners, direct):
     """Update the specified draft's metadata."""
     pid = convert_to_recid(pid, pid_type)
     identity = get_identity_for_user(user)
@@ -117,7 +129,26 @@ def update_record(metadata_file, pid, pid_type, user, patch, owners):
         metadata = set_record_owners(metadata, owners)
 
     metadata = set_creatibutor_names(metadata)
-    service.update(id_=pid, identity=identity, data=metadata)
+    if direct:
+        record = service.read(id_=pid, identity=identity)._record
+        record.update(metadata)
+        # the refresh is required because the access system field takes precedence
+        # over the record's data in 'record.commit()'
+        record.access.refresh_from_dict(record["access"])
+        record.commit()
+        db.session.commit()
+        service.indexer.index(record)
+    else:
+        try:
+            # first, try the modern approach of updating records (March 2021)
+            service.update_draft(id_=pid, identity=identity, data=metadata)
+            service.publish(id_=pid, identity=identity)
+        except Exception as e:
+            # if that fails, try the good old plain update
+            click.secho("error: {}".format(e), fg="yellow")
+            click.secho("trying with service.update()...", fg="yellow")
+            service.update(id_=pid, identity=identity, data=metadata)
+
     click.secho(pid, fg="green")
 
 
-- 
GitLab