Commit 4310403b by ehtesham

[TNL-4029] user can't add more than maximum number of allowed annotations

parent 05dba592
......@@ -18,6 +18,7 @@ from rest_framework.test import APITestCase
from .helpers import get_id_token
TEST_USER = "test_user_id"
TEST_OTHER_USER = "test_other_user_id"
if not settings.ES_DISABLED:
import haystack
......@@ -65,6 +66,16 @@ class BaseAnnotationViewTests(APITestCase):
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
return response.data.copy()
def _create_annotation_without_assert(self, **kwargs):
"""
Create annotation but do not check for 201
"""
opts = self.payload.copy()
opts.update(kwargs)
url = reverse('api:v1:annotations')
response = self.client.post(url, opts, format='json')
return response
def _do_annotation_update(self, data, updated_fields):
"""
Helper method for updating an annotation.
......@@ -98,7 +109,7 @@ class BaseAnnotationViewTests(APITestCase):
result = self.client.get(url, data=data)
return result.data
@ddt.ddt
class AnnotationListViewTests(BaseAnnotationViewTests):
"""
Test annotation creation and listing by user and course
......@@ -222,6 +233,62 @@ class AnnotationListViewTests(BaseAnnotationViewTests):
del annotation['created']
self.assertEqual(annotation, note)
@ddt.data(
(6, False),
(4, True)
)
@ddt.unpack
def test_create_maximum_allowed(self, num_notes, should_create):
"""
Tests user can not create more than allowed notes/annotations per course
"""
for i in xrange(num_notes - 1):
kwargs = {'text': 'Foo_{}'.format(i)}
self._create_annotation(**kwargs)
# Creating more notes should result in 400 error
kwargs = {'text': 'Foo_{}'.format(num_notes)}
response = self._create_annotation_without_assert(**kwargs)
if not should_create:
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, 'Creating more than allowed notes')
self.assertEqual(
response.data['error_msg'],
u'You can create up to {0} notes.'
u' You must remove some notes before you can add new ones.'.format(settings.MAX_ANNOTATIONS_PER_COURSE)
)
else:
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
def test_create_maximum_allowed_other(self):
# if user tries to create notes in another course it should succeed
for i in xrange(5):
kwargs = {'text': 'Foo_{}'.format(i)}
self._create_annotation(**kwargs)
# Creating more notes should result in 400 error
kwargs = {'text': 'Foo_{}'.format(6)}
response = self._create_annotation_without_assert(**kwargs)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, 'Creating more than allowed notes')
self.assertEqual(
response.data['error_msg'],
u'You can create up to {0} notes.'
u' You must remove some notes before you can add new ones.'.format(settings.MAX_ANNOTATIONS_PER_COURSE)
)
# if user tries to create note in a different course it should succeed
kwargs = {'course_id': 'test-course-id-2'}
response = self._create_annotation(**kwargs)
self.assertFalse(hasattr(response, 'data'))
# if another user to tries to create note in first course it should succeed
token = get_id_token(TEST_OTHER_USER)
self.client.credentials(HTTP_X_ANNOTATOR_AUTH_TOKEN=token)
self.headers = {'user': TEST_OTHER_USER}
kwargs = {'user': TEST_OTHER_USER}
response = self._create_annotation(**kwargs)
self.assertFalse(hasattr(response, 'data'))
def test_read_all_no_annotations(self):
"""
Tests list all annotations endpoint when no annotations are present in database.
......
......@@ -5,6 +5,7 @@ from django.conf import settings
from django.core.urlresolvers import reverse
from django.core.exceptions import ValidationError
from django.db.models import Q
from django.utils.translation import ugettext_noop
from rest_framework import status
from rest_framework.response import Response
......@@ -20,6 +21,13 @@ if not settings.ES_DISABLED:
log = logging.getLogger(__name__)
class AnnotationsLimitReachedError(Exception):
"""
Exception when trying to create more than allowed annotations
"""
pass
class AnnotationSearchView(APIView):
"""
Search annotations.
......@@ -117,20 +125,35 @@ class AnnotationListView(APIView):
Returns 400 request if bad payload is sent or it was empty object.
"""
if 'id' in self.request.data:
if not self.request.data or 'id' in self.request.data:
return Response(status=status.HTTP_400_BAD_REQUEST)
try:
if Note.objects.filter(
user_id=self.request.data['user'], course_id=self.request.data['course_id']
).count() >= settings.MAX_ANNOTATIONS_PER_COURSE:
raise AnnotationsLimitReachedError
note = Note.create(self.request.data)
note.full_clean()
except ValidationError as error:
log.debug(error, exc_info=True)
return Response(status=status.HTTP_400_BAD_REQUEST)
except AnnotationsLimitReachedError:
error_message = ugettext_noop(
u'You can create up to {max_num_annotations_per_course} notes.'
u' You must remove some notes before you can add new ones.'
).format(max_num_annotations_per_course=settings.MAX_ANNOTATIONS_PER_COURSE)
log.info(
u'Attempted to create more than %s annotations',
settings.MAX_ANNOTATIONS_PER_COURSE
)
return Response({
'error_msg': error_message
}, status=status.HTTP_400_BAD_REQUEST)
note.save()
location = reverse('api:v1:annotations_detail', kwargs={'annotation_id': note.id})
return Response(note.as_dict(), status=status.HTTP_201_CREATED, headers={'Location': location})
......
......@@ -80,3 +80,6 @@ CORS_ALLOW_HEADERS = (
TEMPLATE_DIRS = (
'templates',
)
### Maximum number of allowed notes per course ###
MAX_ANNOTATIONS_PER_COURSE = 500
......@@ -42,3 +42,6 @@ LOGGING = {
}
},
}
### Maximum number of allowed notes per course ###
MAX_ANNOTATIONS_PER_COURSE = 5
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment