diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..b2d584f
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,2 @@
+expdj/experiment_repo
+static/
diff --git a/.gitignore b/.gitignore
index 1286136..2e98fa6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,3 +26,4 @@ compose/nginx/ssl*
*.cred
/expdj/experiment_repo/*
+postgres-data/
diff --git a/Dockerfile b/Dockerfile
index 4e6df8f..5ebf043 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,7 +6,8 @@ RUN apt-get update && apt-get install -y \
libhdf5-dev \
libgeos-dev \
openssl \
- wget
+ wget\
+ git
RUN mkdir /code
WORKDIR /code
diff --git a/expdj/apps/experiments/static/js/jquery_boostrap_modal_steps.js b/expdj/apps/experiments/static/js/jquery_boostrap_modal_steps.js
index 28c273f..f5253f6 100644
--- a/expdj/apps/experiments/static/js/jquery_boostrap_modal_steps.js
+++ b/expdj/apps/experiments/static/js/jquery_boostrap_modal_steps.js
@@ -8,7 +8,7 @@
btnCancelHtml: 'Cancel',
btnPreviousHtml: 'Previous',
btnNextHtml: 'Next',
- btnLastStepHtml: 'Start Experiment',
+ btnLastStepHtml: 'Next',
disableNextButton: false,
completeCallback: function(){
$("#start_experiment_button").click();
diff --git a/expdj/apps/experiments/views.py b/expdj/apps/experiments/views.py
index 8d12229..3f1c43a 100644
--- a/expdj/apps/experiments/views.py
+++ b/expdj/apps/experiments/views.py
@@ -322,11 +322,11 @@ def get_battery_intro(battery, show_advertisement=True):
if battery.advertisement is not None:
instruction_forms.append(
{"title": "Advertisement", "html": battery.advertisement})
- if battery.consent is not None:
- instruction_forms.append({"title": "Consent", "html": battery.consent})
if battery.instructions is not None:
instruction_forms.append(
{"title": "Instructions", "html": battery.instructions})
+ if battery.consent is not None:
+ instruction_forms.append({"title": "Consent", "html": battery.consent})
return instruction_forms
diff --git a/expdj/apps/turk/api_views.py b/expdj/apps/turk/api_views.py
index 5fa7eee..8a9c647 100644
--- a/expdj/apps/turk/api_views.py
+++ b/expdj/apps/turk/api_views.py
@@ -1,15 +1,48 @@
+from django.core.exceptions import ObjectDoesNotExist
+from django.http import Http404
from django.http.response import HttpResponseForbidden
-from rest_framework import exceptions, generics, permissions, viewsets
+from rest_framework import exceptions, generics, viewsets
+from rest_framework.permissions import AllowAny
+from rest_framework.views import APIView
+from rest_framework.response import Response
from expdj.apps.experiments.models import Battery
-from expdj.apps.turk.models import Result, Worker
+from expdj.apps.turk.models import Assignment, Result, Worker, HIT
from expdj.apps.turk.serializers import ResultSerializer
+from expdj.apps.turk.tasks import updated_assign_experiment_credit
+from expdj.apps.turk.utils import get_worker_experiments, get_connection, get_credentials
class BatteryResultAPIList(generics.ListAPIView):
serializer_class = ResultSerializer
def get_queryset(self):
battery_id = self.kwargs.get('bid')
- if (Battery.objects.get(pk=battery_id).owner is not self.request.user.pk):
+ if (Battery.objects.get(pk=battery_id).owner.id is not self.request.user.pk):
raise exceptions.PermissionDenied()
return Result.objects.filter(battery__id=battery_id)
+
+class WorkerExperiments(APIView):
+ permission_classes = (AllowAny,)
+ def get(self, request, worker_id, hit_id):
+ try:
+ hit = HIT.objects.get(mturk_id=hit_id)
+ worker = Worker.objects.get(id=worker_id)
+ # assignment = Assignment.objects.get(hit__mturk_id=hit_id)
+ all_assignments = Assignment.objects.filter(worker_id=worker_id, hit__battery_id=hit.battery_id)
+ except ObjectDoesNotExist:
+ raise Http404
+ exps = list(get_worker_experiments(worker, hit.battery))
+ exps = [x.template.name for x in exps]
+ submit = False
+ status = 'Not Submitted'
+
+ marked_complete = all_assignments.filter(completed=True).count() > 0
+
+ if len(exps) == 0 and not marked_complete:
+ all_assignments.filter(completed=False).update(completed=True)
+ submit = True
+ updated_assign_experiment_credit.apply_async([worker_id, hit.battery_id, hit_id], countdown=60)
+ elif len(exps) == 0 and marked_complete:
+ status = 'Submit Attempted'
+
+ return Response({'experiments': exps, 'assignment_status': status, 'submit': submit})
diff --git a/expdj/apps/turk/models.py b/expdj/apps/turk/models.py
index a9edf2c..2a86c67 100644
--- a/expdj/apps/turk/models.py
+++ b/expdj/apps/turk/models.py
@@ -3,13 +3,6 @@
import collections
import datetime
-import boto
-from boto.mturk.price import Price
-from boto.mturk.qualification import (AdultRequirement, LocaleRequirement,
- NumberHitsApprovedRequirement,
- PercentAssignmentsApprovedRequirement,
- Qualifications, Requirement)
-from boto.mturk.question import ExternalQuestion
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
@@ -23,7 +16,7 @@
from expdj.apps.turk.utils import (amazon_string_to_datetime, get_connection,
get_credentials, get_time_difference,
to_dict)
-from expdj.settings import BASE_DIR, DOMAIN_NAME
+from expdj.settings import DOMAIN_NAME
def init_connection_callback(sender, **signal_args):
@@ -301,7 +294,7 @@ def disable(self):
"""
# Check for new results and cache a copy in Django model
self.update(do_update_assignments=True)
- self.connection.dispose_hit(self.mturk_id)
+ self.connection.delete_hit(HITId=self.mturk_id)
def dispose(self):
"""Dispose of a HIT that is no longer needed.
@@ -339,34 +332,38 @@ def dispose(self):
self.mturk_id, assignment.mturk_id))
# Checks pass. Dispose of HIT and update status
- self.connection.dispose_hit(self.mturk_id)
+ self.connection.delete_hit(HITId=self.mturk_id)
self.update()
def expire(self):
"""Expire a HIT that is no longer needed as Mechanical Turk service"""
if not self.has_connection():
self.generate_connection()
- self.connection.expire_hit(self.mturk_id)
+ # expire hit no longer a function in boto3
+ # self.connection.expire_hit(self.mturk_id)
+ self.connection.update_expiration_for_hit(HITId=self.mturk_id, ExpireAt=datetime.datetime.now())
self.update()
+ ''' Does not appear to be in use currently
def extend(self, assignments_increment=None, expiration_increment=None):
- """Increase the maximum assignments or extend the expiration date"""
+ # Increase the maximum assignments or extend the expiration date
if not self.has_connection():
self.generate_connection()
- self.connection.extend_hit(self.mturk_id,
- assignments_increment=assignments_increment,
- expiration_increment=expiration_increment)
+ self.connection.update_expiration_for_hit(
+ HITId=self.mturk_id,
+ ExpireAt=self.
self.update()
+ '''
def set_reviewing(self, revert=None):
- """Toggle HIT status between Reviewable and Reviewing"""
+ """ Toggle HIT status between Reviewable and Reviewing """
if not self.has_connection():
self.generate_connection()
- self.connection.set_reviewing(self.mturk_id, revert=revert)
+ self.connection.update_hit_review_status(HITId=self.mturk_id, Revert=revert)
self.update()
def generate_connection(self):
- # Get the aws access id from the credentials file
+ """ Get the aws access id from the credentials file """
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY_ID = get_credentials(
battery=self.battery)
self.connection = get_connection(
@@ -378,76 +375,75 @@ def has_connection(self):
return False
def send_hit(self):
-
- # First check for qualifications
- qualifications = Qualifications()
+ """ Collect all the settings and call api to submit hit to aws """
+ qualifications = []
if self.qualification_adult:
- qualifications.add(AdultRequirement("EqualTo", 1))
- else:
- qualifications.add(AdultRequirement("EqualTo", 0))
- if self.qualification_custom not in [None, ""]:
- qualifications.add(
- Requirement(
- self.qualification_custom,
- self.qualification_custom_operator,
- self.qualification_custom_value,
- required_to_preview=True))
+ qualifications.append({
+ "QualificationTypeId": "00000000000000000060",
+ "Comparator": "EqualTo",
+ "IntegerValues": [1],
+ "ActionsGuarded": "DiscoverPreviewAndAccept"
+ })
if self.qualification_number_hits_approved is not None:
- qual_number_hits = NumberHitsApprovedRequirement(
- "GreaterThan", self.qualification_number_hits_approved)
- qualifications.add(qual_number_hits)
- if self.qualification_percent_assignments_approved is not None:
- qual_perc_approved = PercentAssignmentsApprovedRequirement(
- "GreaterThan", self.qualification_percent_assignments_approved)
- qualifications.add(qual_perc_approved)
+ qualifications.append({
+ "QualificationTypeId": "00000000000000000040",
+ "Comparator": "GreaterThanOrEqualTo",
+ "IntegerValues": [self.qualification_number_hits_approve],
+ "ActionsGuarded": "DiscoverPreviewAndAccept"
+ })
+ if self.qualification_custom not in [None, ""]:
+ qualifications.append({
+ "QualificationTypeId": self.qualification_custom,
+ "Comparator": self.qualification_custom_operator,
+ "IntegerValues": [self.qualification_custom_value],
+ "ActionsGuarded": "Accept"
+ })
if self.qualification_locale != 'None':
- qualifications.add(
- LocaleRequirement(
- "EqualTo",
- self.qualification_locale))
-
+ qualifications.append({
+ "QualificationTypeId": "00000000000000000071",
+ "Comparator": "EqualTo",
+ "LocaleValues": [{
+ "Country": self.qualification_locale,
+ }],
+ "ActionsGuarded": "DiscoverPreviewAndAccept"
+ })
+ if self.qualification_percent_assignments_approved is not None:
+ qualifications.append({
+ "QualificationTypeId": "000000000000000000L0",
+ "Comparator": "GreaterThanOrEqualTo",
+ "IntegerValues": [self.qualification_percent_assignments_approved],
+ "ActionsGuarded": "DiscoverPreviewAndAccept"
+ })
# Domain name must be https
url = "%s/turk/%s" % (DOMAIN_NAME, self.id)
frame_height = 900
- questionform = ExternalQuestion(url, frame_height)
-
- if len(qualifications.requirements) > 0:
- result = self.connection.create_hit(
- title=self.title,
- description=self.description,
- keywords=self.keywords,
- duration=datetime.timedelta(
- self.assignment_duration_in_hours / 24.0),
- lifetime=datetime.timedelta(
- self.lifetime_in_hours / 24.0),
- max_assignments=self.max_assignments,
- question=questionform,
- qualifications=qualifications,
- reward=Price(
- amount=self.reward),
- response_groups=(
- 'Minimal',
- 'HITDetail'))[0]
+ question_xml = '''
+