Skip to content

Commit

Permalink
Changes for invenioRDM v12
Browse files Browse the repository at this point in the history
  • Loading branch information
vgranata committed May 3, 2024
1 parent 2511f86 commit 9b81dce
Show file tree
Hide file tree
Showing 12 changed files with 219 additions and 117 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,6 @@ output/*

# Secret environment variables
*.env

# Test code
mycode
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ source /home/<username>/.virtualenvs/<virtual_env_name>/bin/activate
pip install wheel
```

4. Install the `big-map-archive-api-client` package along with its dependencies in the virtual environment:
4. Install the `big-map-archive-api-client` package along with its dependencies in the virtual environment.
Install version 1.2.0 for the latest version of the BIG-MAP Archive:

```bash
pip install big-map-archive-api-client
pip install big-map-archive-api-client==1.2.0
```

5. [Optional] Once installed, check that the executable file associated with `bma` is indeed located in the virtual environment:
Expand Down Expand Up @@ -126,6 +127,11 @@ Please comply with the following rules:

The command option `--data-files` should point to the directory where the files to be uploaded and attached to the new record are located. We usually place such a folder in our project directory and name it `upload`.

### Community

To publish a record to a community you need to specify the community `slug`.
Login at `https://<archive_domain_name>`. The list of communities you have access to is at the link `https://<archive_domain_name>/api/communities`. Look for the value slug, you will need to add this value when publishing a record to the community. Example: for the BIG-MAP community the slug is bigmap, for BATTERY2030 the slug is battery2030.

## Usage

You may want to test a command against a [demo instance](https://big-map-archive-demo.materialscloud.org/), before executing it against the [main data repository](https://archive.big-map.eu/).
Expand Down Expand Up @@ -254,6 +260,8 @@ Options:
to be uploaded and linked to the record. See
data/input/example/create_record/upload in the
GitHub repository. [required]
--slug TEXT Community slug of the record. Example: for the BIG-
MAP community the slug is bigmap. [required]
--publish Publish the created record.
--help Show this message and exit.
```
Expand Down Expand Up @@ -338,6 +346,9 @@ Options:
This is discouraged in production. If you
select this option, either publish or delete
the newly created draft, e.g., via the GUI.
--slug TEXT Community slug of the record. Example: for
the BIG-MAP community the slug is bigmap.
[required]
--help Show this message and exit.
````

Expand Down
83 changes: 66 additions & 17 deletions big_map_archive_api_client/client/api_client.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import json
import os
from datetime import date
import requests

from big_map_archive_api_client.client.rest_api_connection import RestAPIConnection
from big_map_archive_api_client.utils import (generate_full_metadata,
change_metadata,
get_name_to_checksum_for_files_in_upload_dir)

from big_map_archive_api_client.client.rest_api_connection import \
RestAPIConnection
from big_map_archive_api_client.utils import (
change_metadata, generate_full_metadata,
get_name_to_checksum_for_files_in_upload_dir)


class ArchiveAPIClientError(Exception):
"""ArchiveAPIClient exceptions"""
pass


class ArchiveAPIClient:
"""
Class to interact with BMA's API
"""

def __init__(self, domain_name, token):
def __init__(self, domain_name, port, token):
"""
Initialize internal variables
"""
self._connection = RestAPIConnection(domain_name)
self._connection = RestAPIConnection(domain_name, port)
self._token = token

def post_records(self, base_dir_path, metadata_file_path):
Expand Down Expand Up @@ -97,6 +103,57 @@ def put_draft(self, record_id, metadata):
response.raise_for_status()
return response.json()

def get_community_id(self, slug):
"""
Get community id
Raises an HTTPError exception if the request fails
@param slug: slug of the community
@returns: community uuid for given slug
"""
resource_path = f'/api/communities?q=slug:{slug}'
response = self._connection.get(resource_path, self._token)
response.raise_for_status()
result = response.json()
try:
assert result["hits"]["total"] == 1
except Exception:
raise ArchiveAPIClientError(f"There is no community '{slug}' or you do not have permissions to create a record for community '{slug}'")

return result["hits"]["hits"][0]["id"]

def put_draft_community(self, record_id, community_id):
"""
Attribute draft to community - create a review in parent
Raises an HTTPError exception if the request fails
@param record_id: record id
@param community_id: community uuid
@returns: json of review
"""
review = {
"receiver": {
"community": community_id
},
"type": "community-submission"
}
resource_path = f'/api/records/{record_id}/draft/review'
payload = json.dumps(review)
response = self._connection.put(resource_path, self._token, payload)
response.raise_for_status()
return response.json()

def post_review(self, record_id):
"""
Submit review to community - create a request to include a record in the community
(that is equivalent to publish the record if the review policy is open)
Raises an HTTPError exception if the request fails
@param record_id: record id
@returns: json of request
"""
resource_path = f'/api/records/{record_id}/draft/actions/submit-review'
response = self._connection.post(resource_path, self._token)
response.raise_for_status()
return response.json()

def delete_draft(self, record_id):
"""
Deletes a draft
Expand All @@ -118,6 +175,7 @@ def post_publish(self, record_id):
"""
Publishes a draft to the archive (i.e., shares a record with all archive users)
Raises an HTTPError exception if the request fails
Note: starting from invenioRDM v12 this api call is replaced by post_review
"""
resource_path = f'/api/records/{record_id}/draft/actions/publish'
response = self._connection.post(resource_path, self._token)
Expand Down Expand Up @@ -270,7 +328,7 @@ def get_changed_content_files(self, record_id, base_dir_path, upload_dir_path):

# How many files in the upload directory with the same name but a different content are there?
same_name_different_content_files = [f for f in files_in_upload_dir
if (f['name'] == name and f['checksum'] != checksum)]
if (f['name'] == name and f['checksum'] != checksum)]

if len(same_name_different_content_files) == 1:
filenames.append(name)
Expand Down Expand Up @@ -313,7 +371,6 @@ def get_user_records(self, all_versions, response_size):
response.raise_for_status()
return response.json()


def get_latest_versions(self):
"""
Gets the ids and the statuses of the latest version of all entries belonging to a user
Expand All @@ -325,7 +382,6 @@ def get_latest_versions(self):
latest_versions = [{'id': v['id'], 'is_published': v['is_published']} for v in latest_versions]
return latest_versions


def get_published_user_records_with_given_title(self, title):
"""
Gets the ids of the records owned by the user that are published and have a given title
Expand All @@ -338,7 +394,6 @@ def get_published_user_records_with_given_title(self, title):

return record_ids


def exists_and_is_published(self, record_id):
"""
Returns True if the record id corresponds to a published record on the BIG-MAP Archive that is owned by the user, False otherwise
Expand All @@ -352,7 +407,6 @@ def exists_and_is_published(self, record_id):

return True if record_id in record_ids else False


def get_record_title(self, record_id):
"""
Returns the title of a published record
Expand All @@ -361,8 +415,3 @@ def get_record_title(self, record_id):
title = response['metadata']['title']

return title





7 changes: 5 additions & 2 deletions big_map_archive_api_client/client/client_config.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from pydantic import BaseModel
import yaml

from big_map_archive_api_client.client.api_client import ArchiveAPIClient
from pydantic import BaseModel


class ClientConfig(BaseModel):
"""Configuration data for a BMA API's client."""

domain_name: str
port: int
token: str

@classmethod
Expand All @@ -25,4 +28,4 @@ def create_client(self):
Creates a client to interact with BMA's API
Initializes internal fields
"""
return ArchiveAPIClient(self.domain_name, self.token)
return ArchiveAPIClient(self.domain_name, self.port, self.token)
16 changes: 14 additions & 2 deletions big_map_archive_api_client/client/rest_api_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
class RestAPIConnection:
"""Internal auxiliary class that handles the base connection."""

def __init__(self, domain_name):
def __init__(self, domain_name, port):
"""
Initializes internal fields
"""
self._base_url = f'https://{domain_name}:{443}'
self.domain_name = domain_name
if domain_name=='127.0.0.1':
self._base_url = f'https://{domain_name}:{port}'
else:
self._base_url = f'https://{domain_name}'

def get(self, resource_path, token):
"""
Expand All @@ -24,6 +28,8 @@ def get(self, resource_path, token):
}
kwargs['headers'] = request_headers
kwargs['verify'] = True
if self.domain_name == "127.0.0.1":
kwargs['verify'] = False

response = requests.get(url, **kwargs)
return response
Expand All @@ -46,6 +52,8 @@ def post(self, resource_path, token, payload=None):
}
kwargs['headers'] = request_headers
kwargs['verify'] = True
if self.domain_name == "127.0.0.1":
kwargs['verify'] = False

response = requests.post(url, **kwargs)
return response
Expand All @@ -68,6 +76,8 @@ def put(self, resource_path, token, payload=None, content_type='application/json
}
kwargs['headers'] = request_headers
kwargs['verify'] = True
if self.domain_name == "127.0.0.1":
kwargs['verify'] = False

response = requests.put(url, **kwargs)
return response
Expand All @@ -87,6 +97,8 @@ def delete(self, resource_path, token):
}
kwargs['headers'] = request_headers
kwargs['verify'] = True
if self.domain_name == "127.0.0.1":
kwargs['verify'] = False

response = requests.delete(url, **kwargs)
return response
15 changes: 5 additions & 10 deletions big_map_archive_api_client/utils/requests.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
import datetime
import hashlib
import json
import os
import hashlib
import datetime
import shutil

import yaml



def generate_full_metadata(base_dir_path, metadata_file_path):
"""
Generates a record's full metadata from a YAML file containing only partial metadata
"""
full_metadata = {
'access': {
'files': 'public',
'record': 'public',
'status': 'open'
},
'files': {
'enabled': True
},
Expand Down Expand Up @@ -157,7 +151,7 @@ def insert_subjects(full_metadata, partial_metadata):
"""
Inserts subjects (i.e., keywords) that were extracted from a 'partial' metadata into a 'full' metadata
"""
full_metadata ['metadata']['subjects'] = [{'subject': keyword} for keyword in partial_metadata['keywords']]
full_metadata['metadata']['subjects'] = [{'subject': keyword} for keyword in partial_metadata['keywords']]

return full_metadata

Expand Down Expand Up @@ -234,7 +228,6 @@ def get_name_to_checksum_for_files_in_upload_dir(base_dir_path, upload_dir_path)
Gets the names and md5 hashes of all files in the upload folder
"""
upload_dir_path = os.path.join(base_dir_path, upload_dir_path)

filenames = [
f for f in os.listdir(upload_dir_path)
if os.path.isfile(os.path.join(upload_dir_path, f))
Expand Down Expand Up @@ -281,6 +274,7 @@ def get_title_from_metadata_file(base_dir_path, metadata_file_path):

return title


def create_directory(base_dir_path, dir_path):
"""
Creates a folder if it does not exist
Expand All @@ -290,6 +284,7 @@ def create_directory(base_dir_path, dir_path):
if not os.path.exists(dir_path):
os.makedirs(dir_path)


def recreate_directory(base_dir_path, dir_path):
"""
Creates a folder if it does not exist, otherwise recreates it.
Expand Down
3 changes: 2 additions & 1 deletion bma_config.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
domain_name: big-map-archive-demo.materialscloud.org # Other values: archive.big-map.eu, big-map-archive-demo-public.materialscloud.org
domain_name: big-map-archive-demo.materialscloud.org # Other values: archive.big-map.eu, big-map-archive-demo-public.materialscloud.org, archive-nextgen.big-map.eu, 127.0.0.1
port: 5000
token: <replace>
Loading

0 comments on commit 9b81dce

Please sign in to comment.