From a9523262c56036be25b2d4f806889dd47dcf01a5 Mon Sep 17 00:00:00 2001
From: Maximilian Moser <maximilian.moser@tuwien.ac.at>
Date: Wed, 28 Apr 2021 14:16:02 +0200
Subject: [PATCH] Update ownership management to InvenioRDM 2.0

---
 invenio_utilities_tuw/cli/drafts.py  | 21 +++++++-------
 invenio_utilities_tuw/cli/records.py | 14 ++++++----
 invenio_utilities_tuw/cli/utils.py   | 42 +++++++++++++++++-----------
 3 files changed, 44 insertions(+), 33 deletions(-)

diff --git a/invenio_utilities_tuw/cli/drafts.py b/invenio_utilities_tuw/cli/drafts.py
index 59a7790..937aaab 100644
--- a/invenio_utilities_tuw/cli/drafts.py
+++ b/invenio_utilities_tuw/cli/drafts.py
@@ -31,6 +31,7 @@ from .utils import (
     convert_to_recid,
     create_record_from_metadata,
     get_identity_for_user,
+    get_user_by_identifier,
     patch_metadata,
     read_metadata,
     set_creatibutor_names,
@@ -93,14 +94,9 @@ def create_draft(metadata_path, publish, user, owners, vanity_pid):
     """
     recid = None
     identity = get_identity_for_user(user)
-    if owners:
-        owners = [get_identity_for_user(owner) for owner in owners]
 
     if isfile(metadata_path):
         metadata = read_metadata(metadata_path)
-        if owners:
-            metadata = set_record_owners(metadata, owners)
-
         metadata = set_creatibutor_names(metadata)
         draft = create_record_from_metadata(metadata, identity, vanity_pid=vanity_pid)
         recid = draft["id"]
@@ -112,12 +108,10 @@ def create_draft(metadata_path, publish, user, owners, vanity_pid):
             raise Exception("metadata file does not exist: %s" % metadata_file_path)
 
         metadata = read_metadata(metadata_file_path)
-        if owners:
-            metadata = set_record_owners(metadata, owners)
-
         metadata = set_creatibutor_names(metadata)
         draft = create_record_from_metadata(metadata, identity)
         recid = draft["id"]
+
         file_names = []
         if isdir(deposit_files_path):
             exists = lambda fn: isfile(join(deposit_files_path, fn))
@@ -145,6 +139,11 @@ def create_draft(metadata_path, publish, user, owners, vanity_pid):
     else:
         raise Exception("neither a file nor a directory: %s" % metadata_path)
 
+    if owners:
+        actual_draft = draft._record if hasattr(draft, "_record") else draft
+        owners = [get_user_by_identifier(owner) for owner in owners]
+        set_record_owners(actual_draft, owners)
+
     if publish:
         service = get_record_service()
         service.publish(id_=recid, identity=identity)
@@ -199,8 +198,10 @@ def update_draft(metadata_file, pid, pid_type, user, patch, owners):
         metadata = patch_metadata(draft_data, metadata)
 
     if owners:
-        owners = [get_identity_for_user(owner) for owner in owners]
-        metadata = set_record_owners(metadata, owners)
+        draft = service.read_draft(id_=pid, identity=identity)
+        actual_draft = draft._record if hasattr(draft, "_record") else draft
+        owners = [get_user_by_identifier(owner) for owner in owners]
+        set_record_owners(actual_draft, owners)
 
     metadata = set_creatibutor_names(metadata)
     service.update_draft(id_=pid, identity=identity, data=metadata)
diff --git a/invenio_utilities_tuw/cli/records.py b/invenio_utilities_tuw/cli/records.py
index 3ec28d8..2cd49d2 100644
--- a/invenio_utilities_tuw/cli/records.py
+++ b/invenio_utilities_tuw/cli/records.py
@@ -13,7 +13,6 @@ 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
 
@@ -31,6 +30,7 @@ from .utils import (
     convert_to_recid,
     get_identity_for_user,
     get_object_uuid,
+    get_user_by_identifier,
     patch_metadata,
     set_creatibutor_names,
     set_record_owners,
@@ -109,7 +109,7 @@ def show_record(pid, pid_type, user, pretty_print, raw):
     help=(
         "circumvent the record service, and thus permission checks, "
         "and update the record directly (not recommended)"
-    )
+    ),
 )
 @option_owners
 @with_appcontext
@@ -124,10 +124,6 @@ def update_record(metadata_file, pid, pid_type, user, patch, owners, direct):
         record_data = service.read(id_=pid, identity=identity).data.copy()
         metadata = patch_metadata(record_data, metadata)
 
-    if owners:
-        owners = [get_identity_for_user(owner) for owner in owners]
-        metadata = set_record_owners(metadata, owners)
-
     metadata = set_creatibutor_names(metadata)
     if direct:
         record = service.read(id_=pid, identity=identity)._record
@@ -149,6 +145,12 @@ def update_record(metadata_file, pid, pid_type, user, patch, owners, direct):
             click.secho("trying with service.update()...", fg="yellow")
             service.update(id_=pid, identity=identity, data=metadata)
 
+    if owners:
+        record = service.read(id_=pid, identity=identity)
+        actual_record = record._record if hasattr(record, "_record") else record
+        owners = [get_user_by_identifier(owner) for owner in owners]
+        set_record_owners(actual_record, owners)
+
     click.secho(pid, fg="green")
 
 
diff --git a/invenio_utilities_tuw/cli/utils.py b/invenio_utilities_tuw/cli/utils.py
index 20e4a6f..e8d9c57 100644
--- a/invenio_utilities_tuw/cli/utils.py
+++ b/invenio_utilities_tuw/cli/utils.py
@@ -10,8 +10,6 @@
 
 import json
 
-from flask_principal import Identity
-from invenio_access import any_user
 from invenio_access.permissions import system_identity
 from invenio_access.utils import get_identity
 from invenio_accounts import current_accounts
@@ -81,16 +79,25 @@ def patch_metadata(metadata: dict, patch: dict) -> dict:
     return metadata
 
 
-def get_identity_for_user(user):
-    """Get the Identity for the user specified via email or ID."""
-    if user is not None:
+def get_user_by_identifier(id_or_email):
+    """Get the user specified via email or ID."""
+    if id_or_email is not None:
         # note: this seems like the canonical way to go
-        #       'as_user' can be either an integer (id) or email address
-        u = current_accounts.datastore.get_user(user)
+        #       'id_or_email' can be either an integer (id) or email address
+        u = current_accounts.datastore.get_user(id_or_email)
         if u is not None:
-            return get_identity(u)
+            return u
         else:
-            raise LookupError("user not found: %s" % user)
+            raise LookupError("user not found: %s" % id_or_email)
+
+    raise ValueError("id_or_email cannot be None")
+
+
+def get_identity_for_user(user):
+    """Get the Identity for the user specified via email or ID."""
+    if user is not None:
+        found_user = get_user_by_identifier(user)
+        return get_identity(found_user)
 
     return system_identity
 
@@ -119,16 +126,17 @@ def convert_to_recid(pid_value, pid_type):
     return pid_value
 
 
-def set_record_owners(record_metadata, owners):
-    """Set the record's owners, assuming an RDM-Records metadata schema."""
-    metadata = record_metadata.copy()
+def set_record_owners(record, owners, commit=True):
+    """Set the record's owners, assuming an RDMRecord-like record object."""
+    parent = record.parent
 
-    owners = [{"user": owner.id} for owner in owners]
-    if "access" not in metadata:
-        metadata["access"] = {}
+    parent.access.owners.clear()
+    for owner in owners:
+        parent.access.owners.add(owner)
 
-    metadata["access"]["owned_by"] = owners
-    return metadata
+    if commit:
+        parent.commit()
+        db.session.commit()
 
 
 def _set_creatibutor_name(creatibutor):
-- 
GitLab