Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Credentials for get requests #11

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 100 additions & 10 deletions api.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
" \n",
" def __init__(self, api_url, key_identity=None, key_credential=None, use_cache=True):\n",
" self.api_url = api_url\n",
" self.params = {\n",
" self.credentials = {\n",
" 'key_identity': key_identity,\n",
" 'key_credential': key_credential\n",
" }\n",
Expand Down Expand Up @@ -116,7 +116,8 @@
" * `total_results` - number of matching resources\n",
" * `results` - a list of dicts, each containing a JSON-LD formatted representation of a resource\n",
" '''\n",
" response = self.s.get(f'{self.api_url}/{resource_type}/', params=kwargs)\n",
" kwargsWithCredentials = kwargs | self.credentials#credential offers to get non-public (hidden) data\n",
" response = self.s.get(f'{self.api_url}/{resource_type}/', params=kwargsWithCredentials)\n",
" data = self.process_response(response)\n",
" return {'total_results': int(response.headers['Omeka-S-Total-Results']), 'results': data}\n",
" \n",
Expand Down Expand Up @@ -151,7 +152,7 @@
" Returns\n",
" * a dict containing a JSON-LD formatted representation of the resource\n",
" '''\n",
" response = self.s.get(f'{self.api_url}/{resource_type}/{resource_id}')\n",
" response = self.s.get(f'{self.api_url}/{resource_type}/{resource_id}/', params=self.credentials)\n",
" data = self.process_response(response)\n",
" return data\n",
"\n",
Expand Down Expand Up @@ -205,6 +206,50 @@
" resource = self.get_resource_by_term(term=term)\n",
" if resource:\n",
" return resource['o:id']\n",
" \n",
" def get_class_id(self, term):\n",
" '''\n",
" Get the numeric identifier associated with the supplied class term.\n",
"\n",
" Parameters:\n",
" * `term` - class label qualified with vocabulary prefix (eg: 'crm:E65_Creation')\n",
"\n",
" Returns:\n",
" * numeric identifier\n",
" '''\n",
" resource = self.get_resource_by_term(term=term, resource_type='resource_classes')\n",
" if resource:\n",
" return resource['o:id']\n",
"\n",
" def get_template_id(self, label):\n",
" '''\n",
" Get the numeric identifier associated with the supplied template label.\n",
"\n",
" Parameters:\n",
" * `label` - template label used in the omeka instance (eg: 'creation')\n",
"\n",
" Returns:\n",
" * numeric identifier\n",
" '''\n",
" resource = self.get_template_by_label(label)\n",
" if resource:\n",
" return resource['o:id']\n",
"\n",
" def get_itemset_id(self, label):\n",
" '''\n",
" Get the numeric identifier associated with the supplied item-set label.\n",
" \n",
" Parameters:\n",
" * `label` - item-set label as recorded in omeka (eg: 'my collection')\n",
" \n",
" Returns:\n",
" * numeric identifier\n",
" '''\n",
" resource = self.get_resource('item_sets', search=label)\n",
" if resource:\n",
" return resource['o:id']\n",
"\n",
"\n",
"\n",
" def filter_items(self, params, **extra_filters):\n",
" for filter_type in ['resource_template_id', 'resource_class_id', 'item_set_id', 'is_public']:\n",
Expand Down Expand Up @@ -336,8 +381,12 @@
" property_value['@id'] = f'{self.api_url}/items/{value[\"value\"]}'\n",
" property_value['value_resource_id'] = value['value']\n",
" property_value['value_resource_name'] = 'items'\n",
" elif data_type == 'numeric:timestamp':\n",
" property_value['@value'] = value['value']\n",
" elif data_type == 'uri':\n",
" property_value['@id'] = value['value']\n",
" if value['label']:\n",
" property_value['o:label'] = value['label']\n",
" else:\n",
" property_value['@value'] = value['value']\n",
" return property_value\n",
Expand Down Expand Up @@ -368,9 +417,9 @@
" payload['o:item_set'] = self.format_resource_id(item_set_id, 'item_sets')\n",
" if media_files:\n",
" files = self.add_media_to_payload(payload, media_files)\n",
" response = self.s.post(f'{self.api_url}/items', files=files, params=self.params)\n",
" response = self.s.post(f'{self.api_url}/items', files=files, params=self.credentials)\n",
" else:\n",
" response = self.s.post(f'{self.api_url}/items', json=payload, params=self.params)\n",
" response = self.s.post(f'{self.api_url}/items', json=payload, params=self.credentials)\n",
" #print(response.text)\n",
" data = self.process_response(response)\n",
" return data\n",
Expand Down Expand Up @@ -490,7 +539,7 @@
" Returns:\n",
" * dict with JSON-LD representation of the deleted resource\n",
" '''\n",
" response = self.s.delete(f'{self.api_url}/{resource_type}/{resource_id}', params=self.params)\n",
" response = self.s.delete(f'{self.api_url}/{resource_type}/{resource_id}', params=self.credentials)\n",
" data = self.process_response(response)\n",
" return data\n",
" \n",
Expand All @@ -505,7 +554,7 @@
" To avoid problems, it's generally easiest to retrieve the resource first,\n",
" make your desired changes to it, then submit the updated resource as your payload.\n",
" '''\n",
" response = self.s.put(f'{self.api_url}/{resource_type}/{payload[\"o:id\"]}', json=payload, params=self.params)\n",
" response = self.s.put(f'{self.api_url}/{resource_type}/{payload[\"o:id\"]}', json=payload, params=self.credentials)\n",
" data = self.process_response(response)\n",
" return data\n",
" \n",
Expand Down Expand Up @@ -550,7 +599,7 @@
" payload.update(file_data)\n",
" files[f'file[0]'] = path.read_bytes()\n",
" files['data'] = (None, json.dumps(payload), 'application/json')\n",
" response = self.s.post(f'{self.api_url}/media', files=files, params=self.params)\n",
" response = self.s.post(f'{self.api_url}/media', files=files, params=self.credentials)\n",
" data = self.process_response(response)\n",
" return data\n",
" \n",
Expand Down Expand Up @@ -686,7 +735,7 @@
" * dict containing a JSON-LD representation of the uploaded template\n",
" '''\n",
" # Upload the template payload\n",
" response = self.s.post(f'{self.api_url}/resource_templates/', params=self.params, json=template_payload)\n",
" response = self.s.post(f'{self.api_url}/resource_templates/', params=self.credentials, json=template_payload)\n",
" data = self.process_response(response)\n",
" return data\n",
" \n",
Expand Down Expand Up @@ -729,7 +778,7 @@
" }\n",
" if media_id:\n",
" marker_payload['o:media'] = {'o:id': media_id}\n",
" response = self.s.post(f'{self.api_url}/mapping_markers/', json=marker_payload, params=self.params)\n",
" response = self.s.post(f'{self.api_url}/mapping_markers/', json=marker_payload, params=self.credentials)\n",
" data = self.process_response(response)\n",
" return data\n"
]
Expand Down Expand Up @@ -1883,6 +1932,47 @@
"assert title != updated_item['schema:name'][0]['@value']"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Adding a new property to an existing item. \n",
"It's easier to use `OmekaAPIClient.prepare_property_value`. \n",
"The existing payload should be kept. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Get a random item from a list of items\n",
"data = omeka_auth.filter_items_by_property(filter_property='schema:name', filter_type='ex')\n",
"random_item = random.choice(data['results'])\n",
"\n",
"# New property with URI data (label and URI, as proposed in omeka UI)\n",
"new_propTerm = 'crm:P45_consists_of'\n",
"new_propId = omeka_auth.get_property_id(new_propTerm)\n",
"new_propValue = {'value': 'http://vocab.getty.edu/aat/300010814', 'type': 'uri', 'label': 'crystal (AAT)'}\n",
"formatted_new_prop = omeka_auth.prepare_property_value(new_propValue, new_propId)\n",
"\n",
"# Copy and update the original item\n",
"new_item = deepcopy(random_item)\n",
"new_item[new_propTerm] = [formatted_new_prop,]\n",
"# note: this overwrites values in `new_propTerm` if it already exists in item (manage exceptions by you own with tests)\n",
"\n",
"# Update the item \n",
"updated_item = omeka_auth.update_resource(new_item, 'items')\n",
"\n",
"# The id of the original and upated items should be the same\n",
"assert random_item['o:id'] == updated_item['o:id']\n",
"\n",
"# But the new property has been added to the updated item\n",
"assert new_propTerm in updated_item"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down
68 changes: 57 additions & 11 deletions omeka_s_tools/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class OmekaAPIClient(object):

def __init__(self, api_url, key_identity=None, key_credential=None, use_cache=True):
self.api_url = api_url
self.params = {
self.credentials = {
'key_identity': key_identity,
'key_credential': key_credential
}
Expand Down Expand Up @@ -78,7 +78,8 @@ def get_resources(self, resource_type, **kwargs):
* `total_results` - number of matching resources
* `results` - a list of dicts, each containing a JSON-LD formatted representation of a resource
'''
response = self.s.get(f'{self.api_url}/{resource_type}/', params=kwargs)
kwargsWithCredentials = kwargs | self.credentials#credential offers to get non-public (hidden) data
response = self.s.get(f'{self.api_url}/{resource_type}/', params=kwargsWithCredentials)
data = self.process_response(response)
return {'total_results': int(response.headers['Omeka-S-Total-Results']), 'results': data}

Expand All @@ -93,7 +94,6 @@ def get_resource(self, resource_type, **kwargs):
Returns
* a dict containing a JSON-LD formatted representation of the resource
'''

data = self.get_resources(resource_type, **kwargs)
try:
resource = data['results'][0]
Expand All @@ -113,7 +113,7 @@ def get_resource_by_id(self, resource_id, resource_type='items'):
Returns
* a dict containing a JSON-LD formatted representation of the resource
'''
response = self.s.get(f'{self.api_url}/{resource_type}/{resource_id}')
response = self.s.get(f'{self.api_url}/{resource_type}/{resource_id}/', params=self.credentials)
data = self.process_response(response)
return data

Expand Down Expand Up @@ -167,6 +167,48 @@ def get_property_id(self, term):
resource = self.get_resource_by_term(term=term)
if resource:
return resource['o:id']

def get_template_id(self, label):
'''
Get the numeric identifier associated with the supplied template label.

Parameters:
* `label` - template label used in the omeka instance (eg: 'creation')

Returns:
* numeric identifier
'''
resource = self.get_template_by_label(label)
if resource:
return resource['o:id']

def get_class_id(self, term):
'''
Get the numeric identifier associated with the supplied class term.

Parameters:
* `term` - class label qualified with vocabulary prefix (eg: 'crm:E65_Creation')

Returns:
* numeric identifier
'''
resource = self.get_resource_by_term(term=term, resource_type='resource_classes')
if resource:
return resource['o:id']

def get_itemset_id(self, label):
'''
Get the numeric identifier associated with the supplied item-set label.

Parameters:
* `label` - item-set label as recorded in omeka (eg: 'my collection')

Returns:
* numeric identifier
'''
resource = self.get_resource('item_sets', search=label)
if resource:
return resource['o:id']

def filter_items(self, params, **extra_filters):
for filter_type in ['resource_template_id', 'resource_class_id', 'item_set_id', 'is_public']:
Expand Down Expand Up @@ -298,8 +340,12 @@ def prepare_property_value(self, value, property_id):
property_value['@id'] = f'{self.api_url}/items/{value["value"]}'
property_value['value_resource_id'] = value['value']
property_value['value_resource_name'] = 'items'
elif data_type == 'numeric:timestamp':
property_value['@value'] = value['value']
elif data_type == 'uri':
property_value['@id'] = value['value']
if value['label']:
property_value['o:label'] = value['label']
else:
property_value['@value'] = value['value']
return property_value
Expand Down Expand Up @@ -330,9 +376,9 @@ def add_item(self, payload, media_files=None, template_id=None, class_id=None, i
payload['o:item_set'] = self.format_resource_id(item_set_id, 'item_sets')
if media_files:
files = self.add_media_to_payload(payload, media_files)
response = self.s.post(f'{self.api_url}/items', files=files, params=self.params)
response = self.s.post(f'{self.api_url}/items', files=files, params=self.credentials)
else:
response = self.s.post(f'{self.api_url}/items', json=payload, params=self.params)
response = self.s.post(f'{self.api_url}/items', json=payload, params=self.credentials)
#print(response.text)
data = self.process_response(response)
return data
Expand Down Expand Up @@ -452,7 +498,7 @@ def delete_resource(self, resource_id, resource_type):
Returns:
* dict with JSON-LD representation of the deleted resource
'''
response = self.s.delete(f'{self.api_url}/{resource_type}/{resource_id}', params=self.params)
response = self.s.delete(f'{self.api_url}/{resource_type}/{resource_id}', params=self.credentials)
data = self.process_response(response)
return data

Expand All @@ -467,7 +513,7 @@ def update_resource(self, payload, resource_type='items'):
To avoid problems, it's generally easiest to retrieve the resource first,
make your desired changes to it, then submit the updated resource as your payload.
'''
response = self.s.put(f'{self.api_url}/{resource_type}/{payload["o:id"]}', json=payload, params=self.params)
response = self.s.put(f'{self.api_url}/{resource_type}/{payload["o:id"]}', json=payload, params=self.credentials)
data = self.process_response(response)
return data

Expand Down Expand Up @@ -512,7 +558,7 @@ def add_media_to_item(self, item_id, media_file, payload={}, template_id=None, c
payload.update(file_data)
files[f'file[0]'] = path.read_bytes()
files['data'] = (None, json.dumps(payload), 'application/json')
response = self.s.post(f'{self.api_url}/media', files=files, params=self.params)
response = self.s.post(f'{self.api_url}/media', files=files, params=self.credentials)
data = self.process_response(response)
return data

Expand Down Expand Up @@ -648,7 +694,7 @@ def upload_template(self, template_payload):
* dict containing a JSON-LD representation of the uploaded template
'''
# Upload the template payload
response = self.s.post(f'{self.api_url}/resource_templates/', params=self.params, json=template_payload)
response = self.s.post(f'{self.api_url}/resource_templates/', params=self.credentials, json=template_payload)
data = self.process_response(response)
return data

Expand Down Expand Up @@ -691,6 +737,6 @@ def add_marker_to_item(self, item_id, coords=None, terms=None, label=None, media
}
if media_id:
marker_payload['o:media'] = {'o:id': media_id}
response = self.s.post(f'{self.api_url}/mapping_markers/', json=marker_payload, params=self.params)
response = self.s.post(f'{self.api_url}/mapping_markers/', json=marker_payload, params=self.credentials)
data = self.process_response(response)
return data