Skip to content

Commit

Permalink
Merge pull request #288 from RockefellerArchiveCenter/issue-287
Browse files Browse the repository at this point in the history
Allow parsing of multiple URIs in single request
  • Loading branch information
helrond authored Jun 22, 2023
2 parents dc7671a + 89edb25 commit 5abcb3f
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
dist: bionic
dist: focal
language: python
python:
"3.10"
Expand Down
23 changes: 22 additions & 1 deletion process_request/routines.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def is_submittable(self, item):
return submit, reason

def parse_item(self, uri, baseurl):
"""Parses requested items to determine which are submittable. Adds a
"""Parses requested item to determine if it is submittable. Adds a
`submit` and `submit_reason` attribute to each item.
Args:
Expand All @@ -131,6 +131,27 @@ def parse_item(self, uri, baseurl):
submit, reason = self.is_submittable(data[0])
return {"uri": uri, "submit": submit, "submit_reason": reason}

def parse_batch(self, uris, baseurl):
"""Parses requested items to determine which are submittable. Adds a
`submit` and `submit_reason` attribute to each item.
Args:
uris (str): A list of AS archival object URIs.
baseurl (str): base URL for links to objects in DIMES
Returns:
parsed (list): A list of dicts containing parsed item information.
"""
parsed = []
data = self.get_data(uris, baseurl)
for item in data:
submit, reason = self.is_submittable(data[0])
parsed.append({"uri": item["uri"], "submit": submit, "submit_reason": reason})
missing_uris = [m for m in uris if m not in [p["uri"] for p in parsed]]
for uri in missing_uris:
parsed.append({"uri": uri, "submit": False, "submit_reason": "This item is currently unavailable for request. It will not be included in request. Reason: This item cannot be found."})
return parsed


class Mailer(object):
"""Email delivery class."""
Expand Down
54 changes: 51 additions & 3 deletions process_request/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from .test_helpers import json_from_fixture, random_list, random_string
from .views import (DeliverDuplicationRequestView,
DeliverReadingRoomRequestView, DownloadCSVView, MailerView,
ParseRequestView)
ParseBatchRequestView, ParseItemRequestView)

aspace_vcr = vcr.VCR(
serializer='json',
Expand Down Expand Up @@ -284,6 +284,45 @@ def test_parse_item(self, mock_get_data):
self.assertEqual(parsed["submit"], False)
self.assertEqual(parsed["submit_reason"], "This item is currently unavailable for request. It will not be included in request. Reason: This item cannot be found.")

@patch("process_request.routines.Processor.get_data")
def test_parse_batch(self, mock_get_data):
item = json_from_fixture("as_data.json")
mock_get_data.return_value = [item]

# Ensure objects return correct messages
for restrictions, text, submit, reason in [
("closed", "foo", False, "This item is currently unavailable for request. It will not be included in request. Reason: foo"),
("open", "bar", True, None),
("conditional", "foobar", True, "This item may be currently unavailable for request. It will be included in request. Reason: foobar")]:
mock_get_data.return_value[0]["restrictions"] = restrictions
mock_get_data.return_value[0]["restrictions_text"] = text
parsed = Processor().parse_batch([mock_get_data.return_value[0]["uri"]], "https://dimes.rockarch.org")
self.assertIsInstance(parsed, list)
self.assertEqual(len(parsed), 1)
item = parsed[0]
self.assertIsInstance(item, dict)
self.assertEqual(item["submit"], submit)
self.assertEqual(item["submit_reason"], reason)

# Ensure objects with attached digital objects return correct message
for format, submit in [
("Digital", True), ("digital_object", False), ("Mixed materials", True), ("microfilm", True)]:
mock_get_data.return_value[0]["preferred_instance"]["format"] = format
item = Processor().parse_batch([item["uri"]], "https://dimes.rockarch.org")[0]
self.assertEqual(item["submit"], submit)

# Ensure objects without instances return correct message
mock_get_data.return_value[0]["preferred_instance"] = {"format": None, "container": None,
"subcontainer": None, "location": None, "barcode": None, "uri": None}
item = Processor().parse_batch([item["uri"]], "https://dimes.rockarch.org")[0]
self.assertEqual(item["submit"], False)
self.assertEqual(item["submit_reason"], "This item is currently unavailable for request. It will not be included in request. Reason: Required information about the physical container of this item is not available.")

mock_get_data.return_value = []
parsed = Processor().parse_batch([item["uri"]], "https://dimes.rockarch.org")[0]
self.assertEqual(parsed["submit"], False)
self.assertEqual(parsed["submit_reason"], "This item is currently unavailable for request. It will not be included in request. Reason: This item cannot be found.")

@patch("process_request.routines.Processor.get_data")
def test_deliver_email(self, mock_get_data):
mock_get_data.return_value = [json_from_fixture("as_data.json")]
Expand Down Expand Up @@ -391,9 +430,18 @@ def test_parse_request_view(self, mock_parse):
parsed = {"foo": "bar"}
mock_parse.return_value = parsed
self.assert_handles_routine(
{"item": random_string()}, "parse-request", ParseRequestView)
{"item": random_string()}, "parse-individual", ParseItemRequestView)
self.assert_handles_exceptions(
mock_parse, "bar", "parse-individual", ParseItemRequestView)

@patch("process_request.routines.Processor.parse_batch")
def test_parse_batch_view(self, mock_parse):
parsed = [{"foo": "bar"}]
mock_parse.return_value = parsed
self.assert_handles_routine(
{"item": [random_string()]}, "parse-batch", ParseBatchRequestView)
self.assert_handles_exceptions(
mock_parse, "bar", "parse-request", ParseRequestView)
mock_parse, "bar", "parse-batch", ParseBatchRequestView)

@patch("process_request.routines.AeonRequester.get_request_data")
def test_deliver_readingroomrequest_view(self, mock_send):
Expand Down
11 changes: 10 additions & 1 deletion process_request/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def post(self, request, format=None):
return Response({"detail": str(e)}, status=500)


class ParseRequestView(BaseRequestView):
class ParseItemRequestView(BaseRequestView):
"""Parses an item to determine whether or not it is submittable."""

def get_response_data(self, request):
Expand All @@ -35,6 +35,15 @@ def get_response_data(self, request):
return Processor().parse_item(uri, baseurl)


class ParseBatchRequestView(BaseRequestView):
"""Parses multiple items to determine whether or not they are submittable."""

def get_response_data(self, request):
uris = request.data.get("items")
baseurl = request.META.get("HTTP_ORIGIN", settings.DIMES_BASEURL)
return Processor().parse_batch(uris, baseurl)


class MailerView(BaseRequestView):
"""Delivers email messages containing data."""

Expand Down
6 changes: 4 additions & 2 deletions request_broker/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
from process_request.views import (DeliverDuplicationRequestView,
DeliverReadingRoomRequestView,
DownloadCSVView, LinkResolverView,
MailerView, ParseRequestView, PingView)
MailerView, ParseBatchRequestView,
ParseItemRequestView, PingView)

urlpatterns = [
path("admin/", admin.site.urls),
path("api/deliver-request/email", MailerView.as_view(), name="deliver-email"),
path("api/deliver-request/duplication", DeliverDuplicationRequestView.as_view(), name="deliver-duplication"),
path("api/deliver-request/reading-room", DeliverReadingRoomRequestView.as_view(), name="deliver-readingroom"),
path("api/process-request/parse", ParseRequestView.as_view(), name="parse-request"),
path("api/process-request/parse", ParseItemRequestView.as_view(), name="parse-individual"),
path("api/process-request/parse_multiple", ParseBatchRequestView.as_view(), name="parse-batch"),
path("api/process-request/resolve", LinkResolverView.as_view(), name="resolve-request"),
path("api/download-csv/", DownloadCSVView.as_view(), name="download-csv"),
path("api/status/", PingView.as_view(), name="ping")
Expand Down

0 comments on commit 5abcb3f

Please sign in to comment.