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

Annotations post api #636

Merged
merged 2 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions project/annotation_project/annotation_project/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@

urlpatterns = [
path('admin/', admin.site.urls),
path('', include("annotations.urls"))

path('annotations/', include("annotations.urls")) # url must start with 'annotations/' according to the standard: https://www.w3.org/TR/annotation-protocol/#:~:text=5.2%20Suggesting%20an%20IRI%20for%20an%20Annotation
]
97 changes: 96 additions & 1 deletion project/annotation_project/annotations/tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.test import TestCase, Client
from django.urls import reverse
from datetime import datetime
import json

from .models import *

Expand All @@ -16,6 +17,14 @@ def setUp(self):
creator=creator,
created=datetime.now(),
)

def tearDown(self):
Annotation.objects.all().delete()
Selector.objects.all().delete()
Creator.objects.all().delete()
Body.objects.all().delete()
Source.objects.all().delete()
print("All Annotation Get API Tests Completed")

def test_get_annotation_by_id(self):
#Test the annotation response format
Expand All @@ -28,7 +37,7 @@ def test_get_annotation_by_id(self):

response = response.json()
self.assertEqual(response['@context'], 'http://www.w3.org/ns/anno.jsonld')
self.assertTrue(response['id'].endswith(f'annotation{self.annotation.id}'))
self.assertEqual(response['id'],f'http://13.51.55.11:8001/annotations/annotation/{self.annotation.id}')
self.assertEqual(response['type'], self.annotation.type)
self.assertEqual(response['body'], {
'type': self.annotation.body.type,
Expand All @@ -48,3 +57,89 @@ def test_get_annotation_by_id(self):
self.assertTrue(response['creator']['id'], self.annotation.creator.name)
self.assertIn('created', response)

class AnnotationPostTest(TestCase):
def setUp(self):
self.client = Client()
self.url = reverse('create_annotation')
self.headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
self.json = {
"@context": "http://www.w3.org/ns/anno.jsonld",
"type": "Annotation",
"body": {
"type": "TextualBody",
"format": "text/html",
"language": "en",
"value": "Turing machine is great!!!"
},
"target": {
"id": "http://13.51.205.39/node/55#theorem",
"type": "text",
"selector": {
"type": "TextPositionSelector",
"start": 30,
"end": 45
}
},
"creator": {
"id": "http://13.51.205.39/profile/cemsay@gmail.com",
"type": "Person"
}
}
self.body = {
"@context": "http://www.w3.org/ns/anno.jsonld",
"type": "Annotation",
"body": str(self.json['body']),
"target": str(self.json['target']),
"creator": str(self.json['creator'])
}
self.body_missing_body = {
"@context": "http://www.w3.org/ns/anno.jsonld",
"type": "Annotation",
"target": str(self.json['target']),
"creator": str(self.json['creator'])
}
self.body_missing_target = {
"@context": "http://www.w3.org/ns/anno.jsonld",
"type": "Annotation",
"body": str(self.json['body']),
"creator": str(self.json['creator'])
}
self.body_missing_creator = {
"@context": "http://www.w3.org/ns/anno.jsonld",
"type": "Annotation",
"body": str(self.json['body']),
"target": str(self.json['target']),
}

def tearDown(self):
Annotation.objects.all().delete()
Selector.objects.all().delete()
Creator.objects.all().delete()
Body.objects.all().delete()
Source.objects.all().delete()
print("All Annotation Post API Tests Completed")

def test_create_annotation(self):
response = self.client.post(self.url, data=self.body_missing_body, headers=self.headers)
self.assertEqual(response.status_code, 400, "Missing body field test failed. expected 400, got " + str(response.status_code))
response = self.client.post(self.url, data=self.body_missing_target, headers=self.headers)
self.assertEqual(response.status_code, 400, "Missing target field test failed. expected 400, got " + str(response.status_code))
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))

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)))

if records:
record = records[0]
data = response.json()
self.assertEqual(data['body'], self.json['body'], "Successful create annotation test (body) failed. expected " + str(self.json['body']) + ", got " + str(data['body']))
self.assertEqual(data['target'], self.json['target'], "Successful create annotation test (target) failed. expected " + str(self.json['target']) + ", got " + str(data['target']))
self.assertEqual(data['creator'], self.json['creator'], "Successful create annotation test (creator) failed. expected " + str(self.json['creator']) + ", got " + str(data['creator']))
self.assertEqual(data['id'], "http://13.51.55.11:8001/annotations/annotation/" + str(record.pk), "Successful create annotation test (id) failed. expected " + "http://13.51.55.11:8001/annotations/annotation/" + str(record.pk))
4 changes: 2 additions & 2 deletions project/annotation_project/annotations/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

urlpatterns = [
path('get_annotation/', matched_annotations_get_view, name='get_annotation'),
path('annotation<annotation_id>/', get_annotation_by_id, name='get_annotation_by_id'),

path('annotation/<annotation_id>/', get_annotation_by_id, name='get_annotation_by_id'),
path('create_annotation/', create_annotation, name='create_annotation'),
]


120 changes: 113 additions & 7 deletions project/annotation_project/annotations/views.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json

from .models import *


def serialize_annotation(annotation, scheme, host):
def serialize_annotation(annotation):
return {
'@context': 'http://www.w3.org/ns/anno.jsonld',
'id': f'{scheme}://{host}/annotation{annotation.id}',
'id': f'http://13.51.55.11:8001/annotations/annotation/{annotation.id}',
'type': annotation.type,
'body': {
'type': annotation.body.type,
Expand All @@ -25,7 +25,7 @@ def serialize_annotation(annotation, scheme, host):
},
},
'creator': {
'id': f'http://13.51.205.39/profile/{annotation.creator.name}',
'id': annotation.creator.name,
'type': annotation.creator.type,
},
'created': annotation.created,
Expand All @@ -49,7 +49,7 @@ def matched_annotations_get_view(request):
return JsonResponse({'message': 'No annotation found!'}, status=404)

matched_data = [
serialize_annotation(annotation, request.scheme, request.get_host()) for annotation in matched_annotations
serialize_annotation(annotation) for annotation in matched_annotations
]

return JsonResponse(matched_data, status=200, safe=False)
Expand All @@ -63,6 +63,112 @@ def get_annotation_by_id(request, annotation_id):

if not annotation:
return JsonResponse({'message': 'No annotation found!'}, status=404)
return JsonResponse(data = serialize_annotation(annotation, request.scheme, request.get_host()), status=200)
return JsonResponse(data = serialize_annotation(annotation), status=200)
except Exception as e:
return JsonResponse({'message': str(e)}, status=500)

@csrf_exempt
def create_annotation(request):
try:
body = request.POST.get('body')
if not body:
return JsonResponse({'message': 'body must be given!'}, status=400)
body = json.loads(body)

value = body.get('value')
if not value:
return JsonResponse({'message': 'body value must be given!'}, status=400)

body_type = body.get('type')
body_format = body.get('format')
body_language = body.get('language')

target = request.POST.get('target')
if not target:
return JsonResponse({'message': 'target must be given!'}, status=400)
target = json.loads(target)

target_id = target.get('id')
if not target_id:
return JsonResponse({'message': 'target id must be given!'}, status=400)

selector = target.get('selector')
if not selector:
return JsonResponse({'message': 'target selector must be given!'}, status=400)

selector_type = selector.get('type')
selector_start = selector.get('start')
if not selector_start:
return JsonResponse({'message': 'selector start must be given!'}, status=400)

selector_end = selector.get('end')
if not selector_end:
return JsonResponse({'message': 'selector end must be given!'}, status=400)

creator = request.POST.get('creator')
if not creator:
return JsonResponse({'message': 'creator must be given!'}, status=400)
creator = json.loads(creator)

creator_id = creator.get('id')
if not creator_id:
return JsonResponse({'message': 'creator id must be given!'}, status=400)

creator_type = creator.get('type')

body_object = Body.objects.create(
value=value
)

if body_type:
body_object.type = body_type

if body_format:
body_object.format = body_format

if body_language:
body_object.language = body_language

body_object.save()

source_object, created = Source.objects.get_or_create(
uri=target_id
)

selector_object = Selector.objects.create(
start=selector_start,
end=selector_end,
source=source_object
)

if selector_type:
selector_object.type = selector_type

selector_object.save()

creator_object = Creator.objects.create(
name=creator_id
)

if creator_type:
creator_object.type = creator_type

creator_object.save()

annotation_type = request.POST.get('type')
annotation_object = Annotation.objects.create(
body=body_object,
target=selector_object,
creator=creator_object
)

if annotation_type:
annotation_object.type = annotation_type

annotation_object.save()

return JsonResponse(data = serialize_annotation(annotation_object), status=200)
except Exception as e:
if "duplicate key value violates unique constraint" in str(e):
return JsonResponse({'message': 'Annotation already exists!'}, status=400)
return JsonResponse({'message': "Internal server error"}, status=500)