diff --git a/project/annotation_project/annotations/tests.py b/project/annotation_project/annotations/tests.py index 04a22eb2..da0558f4 100644 --- a/project/annotation_project/annotations/tests.py +++ b/project/annotation_project/annotations/tests.py @@ -9,7 +9,7 @@ class AnnotationGetTest(TestCase): def setUp(self): source = Source.objects.create(uri='http://example.com/source1') body = Body.objects.create(value='Annotation Test Content') - creator = Creator.objects.create(name='testcreator@example.com') + creator = Creator.objects.create(name='http://13.51.205.39/profile/testcreator@example.com') selector = Selector.objects.create(start=0, end=5, source=source) self.annotation = Annotation.objects.create( body=body, @@ -17,6 +17,17 @@ def setUp(self): creator=creator, created=datetime.now(), ) + + source2 = Source.objects.create(uri='http://example.com/source2') + body2 = Body.objects.create(value='Annotation Test Content2') + creator2 = Creator.objects.create(name='http://13.51.205.39/profile/testcreator2@example.com') + selector2 = Selector.objects.create(start=0, end=5, source=source2) + self.annotation2 = Annotation.objects.create( + body=body2, + target=selector2, + creator=creator2, + created=datetime.now(), + ) def tearDown(self): Annotation.objects.all().delete() @@ -26,6 +37,61 @@ def tearDown(self): Source.objects.all().delete() print("All Annotation Get API Tests Completed") + #TODO: update matched annotations test + + def test_get_matched_annotations(self): + client = Client() + + url = reverse('get_annotation') + multicreator_data = { + 'creator': [ + 'http://13.51.205.39/profile/testcreator@example.com', + 'http://13.51.205.39/profile/testcreator2@example.com'] + } + multisource_data = { + 'source' : [ + 'http://example.com/source1', + 'http://example.com/source2' + ] + } + + data = { + 'source' : 'http://example.com/source2', + 'creator': 'http://13.51.205.39/profile/testcreator2@example.com' + } + + response = client.get(url, multicreator_data, format='json') + self.assertEqual(response.status_code, 200, response.json()) + self.assertEqual(len(response.json()), 2) + + response = client.get(url, multisource_data, format='json') + self.assertEqual(response.status_code, 200, response.json()) + self.assertEqual(len(response.json()), 2) + + response = client.get(url, data, format='json') + self.assertEqual(response.status_code, 200, response.json()) + response = response.json()[0] + self.assertEqual(response['@context'], 'http://www.w3.org/ns/anno.jsonld') + self.assertEqual(response['id'],f'http://13.51.55.11:8001/annotations/annotation/{self.annotation2.id}') + self.assertEqual(response['type'], self.annotation2.type) + self.assertEqual(response['body'], { + 'type': self.annotation2.body.type, + 'format': self.annotation2.body.format, + 'language': self.annotation2.body.language, + 'value': self.annotation2.body.value, + }) + self.assertEqual(response['target'], { + 'id': self.annotation2.target.source.uri, + 'type': 'text', + 'selector': { + 'type': self.annotation2.target.type, + 'start': self.annotation2.target.start, + 'end': self.annotation2.target.end, + } + }) + self.assertTrue(response['creator']['id'], self.annotation2.creator.name) + self.assertIn('created', response) + def test_get_annotation_by_id(self): #Test the annotation response format client = Client() @@ -130,8 +196,8 @@ def test_create_annotation(self): response = self.client.post(self.url, data=self.body_missing_creator, headers=self.headers) self.assertEqual(response.status_code, 400, "Missing creator field test failed. expected 400, got " + str(response.status_code)) - response = self.client.post(self.url, data=self.body, headers=self.headers, content_type='application/json') - self.assertEqual(response.status_code, 200, "Successful create annotation test failed. expected 200, got " + str(response.status_code)) + response = self.client.post(self.url, data=self.body) + self.assertEqual(response.status_code, 201, "Successful create annotation test failed. expected 201, got " + str(response.status_code)) records = Annotation.objects.filter(id=response.json()['id']) self.assertEqual(len(records), 1, "Successful create annotation test (database insertion) failed. expected 1 row, got " + str(len(records))) diff --git a/project/annotation_project/annotations/views.py b/project/annotation_project/annotations/views.py index ff0748b6..de6a8075 100644 --- a/project/annotation_project/annotations/views.py +++ b/project/annotation_project/annotations/views.py @@ -1,6 +1,9 @@ from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.http import require_http_methods, etag +from django.views.decorators.vary import vary_on_headers import json +import hashlib from .models import * @@ -31,41 +34,57 @@ def serialize_annotation(annotation): 'created': annotation.created, } - +@csrf_exempt +@require_http_methods(['GET', 'HEAD']) +@vary_on_headers('Accept') def matched_annotations_get_view(request): - source_uri = request.GET.get('source') - creator_name = request.GET.get('creator') - + source_uris = request.GET.getlist('source') + creator_names = request.GET.getlist('creator') filtering_conditions = {} - if source_uri: - filtering_conditions['target__source__uri__iexact'] = source_uri - if creator_name: - filtering_conditions['creator__name__iexact'] = creator_name + if len(source_uris) > 0: + filtering_conditions['target__source__uri__in'] = source_uris + if len(creator_names) > 0: + filtering_conditions['creator__name__in'] = creator_names try: matched_annotations = Annotation.objects.filter(**filtering_conditions) + response = JsonResponse({'message': 'No annotation found!'}, status=404) + if len(matched_annotations) > 0: + matched_data = [ + serialize_annotation(annotation) for annotation in matched_annotations + ] + response = JsonResponse(matched_data, status=200, safe=False) + response['ETag'] = '"_{}"'.format(hashlib.md5(response.content).hexdigest()) - if len(matched_annotations) == 0: - return JsonResponse({'message': 'No annotation found!'}, status=404) - - matched_data = [ - serialize_annotation(annotation) for annotation in matched_annotations - ] - - return JsonResponse(matched_data, status=200, safe=False) except Exception as e: - return JsonResponse({'message': str(e)}, status=500) - + response = JsonResponse({'message': str(e)}, status=500) + finally: + response.headers['Content-Type'] = 'application/ld+json; profile="http://www.w3.org/ns/anno.jsonld"' + response.headers['Link'] = '; rel="type"' + response['Allow'] = 'GET,OPTIONS,HEAD' + response['Vary'] = 'Accept' + return response +@csrf_exempt +@require_http_methods(['GET', 'HEAD']) +@vary_on_headers('Accept') def get_annotation_by_id(request, annotation_id): try: annotation = Annotation.objects.get(id=annotation_id) + response = JsonResponse({'message': 'No annotation found!'}, status=404) + if annotation: + response_data = serialize_annotation(annotation) + response = JsonResponse(response_data, status=200) + response['ETag'] = '"_{}"'.format(hashlib.md5(response.content).hexdigest()) - if not annotation: - return JsonResponse({'message': 'No annotation found!'}, status=404) - return JsonResponse(data = serialize_annotation(annotation), status=200) except Exception as e: - return JsonResponse({'message': str(e)}, status=500) + response = JsonResponse({'message': str(e)}, status=500) + finally: + response.headers['Content-Type'] = 'application/ld+json; profile="http://www.w3.org/ns/anno.jsonld"' + response.headers['Link'] = '; rel="type"' + response['Allow'] = 'GET,OPTIONS,HEAD' + response['Vary'] = 'Accept' + return response @csrf_exempt def create_annotation(request): @@ -167,7 +186,7 @@ def create_annotation(request): annotation_object.save() - return JsonResponse(data = serialize_annotation(annotation_object), status=200) + return JsonResponse(data = serialize_annotation(annotation_object), status=201) except Exception as e: if "duplicate key value violates unique constraint" in str(e): return JsonResponse({'message': 'Annotation already exists!'}, status=400)