def test_return_task_assignment(self): user = User.objects.create_user('testuser', password='******') task_assignment = TaskAssignment(assigned_to=user, task=self.task) task_assignment.save() client = django.test.Client() client.login(username='******', password='******') response = client.get( reverse('return_task_assignment', kwargs={ 'task_id': self.task.id, 'task_assignment_id': task_assignment.id })) self.assertEqual(response.status_code, 302) self.assertEqual(response['Location'], reverse('index'))
def accept_task(request, batch_id, task_id): """ Accept task from preview Security behavior: - If the user does not have permission to access the Batch+Task, they are redirected to the index page with an error message. """ try: batch = Batch.objects.get(id=batch_id) except ObjectDoesNotExist: messages.error(request, u'Cannot find Task Batch with ID {}'.format(batch_id)) return redirect(index) try: task = Task.objects.get(id=task_id) except ObjectDoesNotExist: messages.error(request, u'Cannot find Task with ID {}'.format(task_id)) return redirect(index) try: with transaction.atomic(): # Lock access to the specified Task Task.objects.filter(id=task_id).select_for_update() # Will throw ObjectDoesNotExist exception if Task no longer available batch.available_tasks_for(request.user).get(id=task_id) ha = TaskAssignment() if request.user.is_authenticated: ha.assigned_to = request.user else: ha.assigned_to = None ha.task = task ha.save() if request.user.is_authenticated: logger.info('User(%i) accepted Task(%i)', request.user.id, task.id) else: logger.info('Anonymous user accepted Task(%i)', task.id) except ObjectDoesNotExist: messages.error( request, u'The Task with ID {} is no longer available'.format(task_id)) return redirect(index) return redirect(task_assignment, task.id, ha.id)
def test_accept_next_task__no_more_tasks(self): User.objects.create_user('testuser', password='******') task_assignment = TaskAssignment(completed=True, task=self.task) task_assignment.save() self.assertEqual(self.task.taskassignment_set.count(), 1) client = django.test.Client() client.login(username='******', password='******') response = client.get( reverse('accept_next_task', kwargs={'batch_id': self.batch.id})) self.assertEqual(response.status_code, 302) self.assertEqual(response['Location'], reverse('index')) self.assertEqual(self.task.taskassignment_set.count(), 1) messages = list(get_messages(response.wsgi_request)) self.assertEqual(len(messages), 1) self.assertEqual( str(messages[0]), 'No more Tasks available for Batch {}'.format(self.batch.name))
def setUp(self): project = Project(name='foo', html_template='<p>${foo}: ${bar}</p>') project.save() self.batch = Batch(project=project, name='foo', filename='foo.csv') self.batch.save() task = Task(batch=self.batch, input_csv_fields={ 'foo': 'fufu', 'bar': 'baba' }) task.save() TaskAssignment(answers={ 'a1': 'sauce' }, assigned_to=None, completed=True, task=task).save()
def test_available_tasks_for__aph_is_1(self): batch = Batch(assignments_per_task=1, project=self.project) batch.save() self.assertEqual(batch.total_available_tasks_for(self.user), 0) self.assertEqual(batch.next_available_task_for(self.user), None) task = Task(batch=batch, ) task.save() self.assertEqual(batch.total_available_tasks_for(self.user), 1) self.assertEqual(batch.next_available_task_for(self.user), task) task_assignment = TaskAssignment( assigned_to=self.user, completed=False, task=task, ) task_assignment.save() self.assertEqual(batch.total_available_tasks_for(self.user), 0) self.assertEqual(batch.next_available_task_for(self.user), None)
def accept_next_task(request, batch_id): """ Accept task from index or auto accept next task Security behavior: - If the user does not have permission to access the Batch+Task, they are redirected to the index page with an error message. """ try: with transaction.atomic(): batch = Batch.objects.get(id=batch_id) # Lock access to all Tasks available to current user in the batch batch.available_task_ids_for(request.user).select_for_update() task_id = _skip_aware_next_available_task_id(request, batch) if task_id: ha = TaskAssignment() if request.user.is_authenticated: ha.assigned_to = request.user else: ha.assigned_to = None ha.task_id = task_id ha.save() if request.user.is_authenticated: logger.info('User(%i) accepted Task(%i)', request.user.id, task_id) else: logger.info('Anonymous user accepted Task(%i)', task_id) except ObjectDoesNotExist: messages.error(request, u'Cannot find Task Batch with ID {}'.format(batch_id)) return redirect(index) if task_id: return redirect(task_assignment, task_id, ha.id) else: messages.error( request, u'No more Tasks available for Batch {}'.format(batch.name)) return redirect(index)
def test_return_task_assignment__anon_user_returns_other_users_task(self): user = User.objects.create_user('testuser', password='******') task_assignment = TaskAssignment(assigned_to=user, task=self.task) task_assignment.save() client = django.test.Client() response = client.get( reverse('return_task_assignment', kwargs={ 'task_id': self.task.id, 'task_assignment_id': task_assignment.id })) self.assertEqual(response.status_code, 302) self.assertEqual(response['Location'], reverse('index')) messages = list(get_messages(response.wsgi_request)) self.assertEqual(len(messages), 1) self.assertEqual( str(messages[0]), 'The Task you are trying to return belongs to another user')
def test_accept_claimed_task(self): User.objects.create_superuser('admin', '*****@*****.**', 'secret') other_user = User.objects.create_user('testuser', password='******') TaskAssignment(assigned_to=other_user, task=self.task).save() self.assertEqual(self.task.taskassignment_set.count(), 1) client = django.test.Client() client.login(username='******', password='******') response = client.get( reverse('accept_task', kwargs={ 'batch_id': self.batch.id, 'task_id': self.task.id })) self.assertEqual(response.status_code, 302) self.assertEqual(response['Location'], reverse('index')) messages = list(get_messages(response.wsgi_request)) self.assertEqual(len(messages), 1) self.assertEqual( str(messages[0]), 'The Task with ID {} is no longer available'.format(self.task.id))
def test_expire_all_abandoned__dont_delete_completed(self): t = timezone.now() dt = datetime.timedelta(hours=2) past = t - dt project = Project(login_required=False) project.save() batch = Batch(allotted_assignment_time=1, project=project) batch.save() task = Task(batch=batch) task.save() ha = TaskAssignment( completed=True, expires_at=past, task=task, ) # Bypass TaskAssignment's save(), which updates expires_at super(TaskAssignment, ha).save() self.assertEqual(TaskAssignment.objects.count(), 1) TaskAssignment.expire_all_abandoned() self.assertEqual(TaskAssignment.objects.count(), 1)
def test_task_marked_as_completed(self): # When assignment_per_task==1, completing 1 Assignment marks Task as complete project = Project(name='test', html_template='<p>${number} - ${letter}</p>') project.save() batch = Batch(project=project) batch.save() task = Task(batch=batch, input_csv_fields={ 'number': '1', 'letter': 'a' }) task.save() self.assertEqual(batch.assignments_per_task, 1) self.assertFalse(task.completed) TaskAssignment(assigned_to=None, completed=True, task=task).save() task.refresh_from_db() self.assertTrue(task.completed)
def test_return_completed_task_assignment(self): user = User.objects.create_user('testuser', password='******') task_assignment = TaskAssignment(assigned_to=user, completed=True, task=self.task) task_assignment.save() client = django.test.Client() client.login(username='******', password='******') response = client.get( reverse('return_task_assignment', kwargs={ 'task_id': self.task.id, 'task_assignment_id': task_assignment.id })) self.assertEqual(response.status_code, 302) self.assertEqual(response['Location'], reverse('index')) messages = list(get_messages(response.wsgi_request)) self.assertEqual(len(messages), 1) self.assertEqual( str(messages[0]), "The Task can't be returned because it has been completed")
def test_skip_and_accept_next_task(self): client = django.test.Client() ha_one = TaskAssignment(task=self.task_one) ha_one.save() # Skip task_one response = client.post( reverse('skip_and_accept_next_task', kwargs={ 'batch_id': self.batch.id, 'task_id': self.task_one.id, 'task_assignment_id': ha_one.id })) self.assertEqual(response.status_code, 302) self.assertEqual( response['Location'], reverse('accept_next_task', kwargs={'batch_id': self.batch.id})) # Verify that task_one has been skipped response = client.get( reverse('accept_next_task', kwargs={'batch_id': self.batch.id})) self.assertEqual(response.status_code, 302) self.assertTrue( '{}/assignment/'.format(self.task_two.id) in response['Location']) # Skip task_two ha_two = self.task_two.taskassignment_set.first() response = client.post( reverse('skip_and_accept_next_task', kwargs={ 'batch_id': self.batch.id, 'task_id': self.task_two.id, 'task_assignment_id': ha_two.id })) self.assertEqual(response.status_code, 302) self.assertEqual( response['Location'], reverse('accept_next_task', kwargs={'batch_id': self.batch.id})) # Verify that task_two has been skipped response = client.get( reverse('accept_next_task', kwargs={'batch_id': self.batch.id})) self.assertEqual(response.status_code, 302) self.assertTrue('{}/assignment/'.format(self.task_three.id) in response['Location']) # Skip task_three ha_three = self.task_three.taskassignment_set.first() response = client.post( reverse('skip_and_accept_next_task', kwargs={ 'batch_id': self.batch.id, 'task_id': self.task_three.id, 'task_assignment_id': ha_three.id })) self.assertEqual(response.status_code, 302) self.assertEqual( response['Location'], reverse('accept_next_task', kwargs={'batch_id': self.batch.id})) # Verify that, with all existing Tasks skipped, we have been redirected back to # task_one and that info message is displayed about only skipped Tasks remaining response = client.get( reverse('accept_next_task', kwargs={'batch_id': self.batch.id})) self.assertEqual(response.status_code, 302) self.assertTrue( '{}/assignment/'.format(self.task_one.id) in response['Location']) messages = list(get_messages(response.wsgi_request)) self.assertEqual(len(messages), 1) self.assertEqual(str(messages[0]), 'Only previously skipped Tasks are available') # Skip task_one for a second time ha_one = self.task_one.taskassignment_set.first() response = client.post( reverse('skip_and_accept_next_task', kwargs={ 'batch_id': self.batch.id, 'task_id': self.task_one.id, 'task_assignment_id': ha_one.id })) self.assertEqual(response.status_code, 302) self.assertEqual( response['Location'], reverse('accept_next_task', kwargs={'batch_id': self.batch.id})) # Verify that task_one has been skipped for a second time response = client.get( reverse('accept_next_task', kwargs={'batch_id': self.batch.id})) self.assertEqual(response.status_code, 302) self.assertTrue( '{}/assignment/'.format(self.task_two.id) in response['Location'])
def setUp(self): """ Sets up Project, Task objects, and saves them to the DB. The Project form HTML only displays the one input variable. The Task has inputs and answers and refers to the Project form. """ admin = User.objects.create_superuser('admin', '*****@*****.**', 'secret') project = Project(name='test', html_template="<p>${foo}</p><textarea>") project.created_by = admin project.updated_by = admin save_model(project) batch = Batch(name='test', project=project, filename='test.csv') batch.created_by = admin batch.updated_by = admin save_model(batch) task = Task( batch=batch, input_csv_fields={'foo': 'bar'}, completed=True, ) task.save() self.task = task self.task_assignment = TaskAssignment(answers={ "comment": "\u221e", "userDisplayLanguage": "", "sentence_textbox_3_verb1": "", "city": "", "sentence_textbox_1_verb6": "", "sentence_textbox_1_verb7": "", "sentence_textbox_1_verb4": "", "sentence_textbox_1_verb5": "", "sentence_textbox_1_verb2": "", "sentence_textbox_1_verb3": "", "sentence_textbox_1_verb1": "", "sentence_textbox_2_verb4": "", "csrfmiddlewaretoken": "7zxQ9Yyug6Nsnm4nLky9p8ObJwNipdu8", "sentence_drop_2_verb3": "foo", "sentence_drop_2_verb2": "foo", "sentence_drop_2_verb1": "foo", "sentence_textbox_2_verb1": "", "sentence_textbox_2_verb3": "", "sentence_drop_2_verb4": "foo", "sentence_textbox_2_verb2": "", "submitit": "Submit", "browserInfo": "", "sentence_drop_1_verb1": "foo", "sentence_drop_1_verb2": "foo", "sentence_drop_1_verb3": "foo", "sentence_drop_1_verb4": "foo", "sentence_drop_1_verb5": "foo", "sentence_drop_1_verb6": "foo", "sentence_drop_1_verb7": "foo", "country": "", "sentence_drop_3_verb1": "foo", "ipAddress": "", "region": "" }, assigned_to=None, completed=True, task=task) self.task_assignment.save()