| from django.shortcuts import render, redirect, render_to_response |
| from django.http import HttpResponseRedirect, HttpResponse |
| from django.contrib.auth.decorators import login_required |
| from django.contrib.auth import authenticate, login, logout, get_user_model |
| from django.contrib.auth.views import password_reset, password_reset_confirm |
| from django.contrib.sites.shortcuts import get_current_site |
| from django.core.urlresolvers import reverse |
| from django.template import RequestContext |
| from django.conf import settings |
| #from django.contrib.auth.models import User |
| from django.utils import timezone |
| from django.db import IntegrityError |
| from elasticsearch import Elasticsearch |
| from base import ALE_URL |
| from axes.decorators import watch_login |
| from surveyMongoUpdate import sm_request_update, SM_QUESTION_NAME, SM_EXPERIMENT_NAME |
| import achievements |
| import tasksUtil |
| import exp_portal |
| import datetime |
| |
| import exceptions |
| import logging |
| #import zlib |
| #import sqlite |
| |
| import mechanicalTurk |
| |
| from op_tasks.models import Dataset, Product, OpTask, UserProfile, TaskListItem, Experiment |
| |
| logger = logging.getLogger('op_tasks') |
| |
| def set_cookie(response, key, value, days_expire = 7): |
| if days_expire is None: |
| max_age = 365 * 24 * 60 * 60 #one year |
| else: |
| max_age = days_expire * 24 * 60 * 60 |
| expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=max_age), "%a, %d-%b-%Y %H:%M:%S GMT") |
| response.set_cookie(key, value, |
| max_age=max_age, |
| expires=expires, |
| domain=settings.SESSION_COOKIE_DOMAIN, |
| secure=None) |
| |
| # connects with User-ALE to count activities. |
| def count_activities(session_id): |
| XDATA_INDEX="xdata_v3" |
| |
| es = Elasticsearch(ALE_URL) |
| |
| queryData = {} |
| fieldFilter = ["timestamp", "sessionID", "parms.desc"] |
| |
| queryData["query"] = { "match": { "sessionID" : session_id } } |
| results = es.search(index=XDATA_INDEX, body=queryData, fields=fieldFilter, size=1000)['hits'] |
| timestamps = [d['fields']['timestamp'] for d in results['hits']] |
| return len(timestamps) |
| |
| # manages which prodct is delivered to the current user |
| @login_required(login_url='/tasking/login') |
| def product(request, task_pk): |
| if request.method == 'POST': |
| sm_update = False |
| user = request.user |
| userprofile = user.userprofile |
| |
| print 'Task primary key: ', task_pk, ' completed' |
| try: |
| # get current sequence from user, this ensures that current user |
| # can only get sequences assigned to him/her |
| current_tasklistitem = userprofile.tasklistitem_set.get(pk=task_pk) |
| except: |
| sm_request_update(SM_QUESTION_NAME, SM_EXPERIMENT_NAME) |
| return HttpResponseRedirect("/tasking/task_list") |
| |
| tasklist_length = len(userprofile.tasklistitem_set.all()) |
| |
| if userprofile.experiment.sequential_tasks == True: |
| |
| # if it's not the last task, make the next task active |
| if current_tasklistitem.index < (tasklist_length - 1): |
| next_tasklistitem = userprofile.tasklistitem_set.get(index=current_tasklistitem.index+1) |
| |
| # if you got here because you just completed a task, |
| # then set it complete and make the exit task active |
| if current_tasklistitem.task_complete == False: |
| current_tasklistitem.task_complete = True |
| current_tasklistitem.task_active = False |
| current_tasklistitem.exit_active = True |
| current_tasklistitem.date_complete = timezone.localtime(timezone.now()) |
| sessionID = '%s::%s' % (userprofile.user_hash, current_tasklistitem.pk) |
| try: |
| current_tasklistitem.activity_count = 0 |
| # current_tasklistitem.activity_count = count_activities(sessionID) |
| except Exception as inst: |
| # print inst |
| current_tasklistitem.activity_count = 0 |
| userprofile.progress += 20 |
| print 'task complete', timezone.now() |
| sm_update = True |
| |
| # you likely got here because you just completed an exit task |
| # so mark it complete and move |
| else: |
| current_tasklistitem.exit_active = False |
| current_tasklistitem.exit_complete = True |
| print 'survey complete', current_tasklistitem.index |
| userprofile.progress += 15 |
| if current_tasklistitem.index < tasklist_length - 1: |
| next_tasklistitem.task_active = True |
| next_tasklistitem.save() |
| else: |
| current_tasklistitem.save() |
| sm_update = True |
| |
| elif userprofile.experiment.sequential_tasks == False: |
| print "no sequencing" |
| |
| if current_tasklistitem.task_complete == False: |
| current_tasklistitem.task_complete = True |
| current_tasklistitem.exit_active = True |
| current_tasklistitem.date_complete = timezone.localtime(timezone.now()) |
| print timezone.localtime(timezone.now()) |
| sm_update = True |
| |
| else: |
| current_tasklistitem.exit_active = False |
| current_tasklistitem.exit_complete = True |
| |
| userprofile.save() |
| current_tasklistitem.save() |
| if sm_update == True: |
| sm_request_update(SM_QUESTION_NAME, SM_EXPERIMENT_NAME) |
| return HttpResponseRedirect("/tasking/task_list") |
| |
| # if method is GET just show the product page |
| user = request.user |
| userprofile = user.userprofile |
| tasklistitem = TaskListItem.objects.get(pk=task_pk) |
| current_task = tasklistitem.op_task |
| request.session['current_optask'] = current_task.pk |
| |
| response = render(request, 'product.html', { |
| 'product': tasklistitem.product, |
| 'task_pk': task_pk, |
| 'product_url': tasklistitem.product.url + ('?USID=%s::%s' % (userprofile.user_hash, tasklistitem.pk)), |
| 'op_task': current_task |
| }) |
| set_cookie(response, 'USID', '%s::%s' % (userprofile.user_hash, tasklistitem.pk)) |
| return response |
| |
| |
| def product_test(request, task_pk): |
| user = request.user |
| userprofile = user.userprofile |
| tasklistitem = TaskListItem.objects.get(pk=task_pk) |
| current_task = tasklistitem.op_task |
| request.session['current_optask'] = current_task.pk |
| |
| response = redirect(tasklistitem.product.url + ('?USID=%s::%s' % (userprofile.user_hash, tasklistitem.pk) ) ) |
| set_cookie(response, 'USID', '%s::%s' % (userprofile.user_hash, tasklistitem.pk)) |
| return response |
| |
| |
| def task_test(request, task_pk): |
| user = request.user |
| userprofile = user.userprofile |
| tasklistitem = TaskListItem.objects.get(pk=task_pk) |
| current_task = tasklistitem.op_task |
| request.session['current_optask'] = current_task.pk |
| userAleUrl = settings.ALE_URL |
| |
| return render(request, 'task.html', {'tasklistitem':tasklistitem, 'userAleUrl': userAleUrl}) |
| |
| |
| def task_launch(request, task_pk): |
| tasklistitem = TaskListItem.objects.get(pk=task_pk) |
| userAleUrl = settings.ALE_URL |
| |
| return render(request, 'task_launch.html', {'tasklistitem': tasklistitem, 'userAleUrl': userAleUrl}) |
| |
| # creates a new user and assigns tasks |
| def register(request): |
| # TODO : add logging back in. Good practice!! |
| # Like before, get the request's context. |
| context = RequestContext(request) |
| |
| # A boolean value for telling the template whether the registration was successful. |
| # Set to False initially. Code changes value to True when registration succeeds. |
| registrationSuccessful = False |
| userExists = False |
| error = False |
| |
| # If it's a HTTP POST, we're interested in processing form data. |
| if request.method == 'POST': |
| |
| # Now we hash the password with the set_password method. |
| # Once hashed, we can update the user object. |
| user = get_user_model()(email=request.POST['email']) |
| user.set_password(request.POST['password']) |
| user.last_login = '1970-01-01 00:00' |
| |
| if not user.email or not request.POST['password']: |
| error = True |
| return render_to_response('registration/register.html', {'registrationSuccessful': registrationSuccessful, 'userExists': userExists, 'error': error}, context) |
| |
| try: |
| user.save() |
| except IntegrityError: |
| userExists = True |
| return render_to_response('registration/register.html', {'registrationSuccessful': registrationSuccessful, 'userExists': userExists, 'error': error}, context) |
| |
| # Now sort out the UserProfile instance. |
| # Since we need to set the user attribute ourselves, we set commit=False. |
| # This delays saving the model until we're ready to avoid integrity problems. |
| userprofile = UserProfile() |
| userprofile.user = user |
| |
| # TODO: change this from default experiment |
| saved_experiments = Experiment.objects.get(name='2015_public_xdataonline') |
| userprofile.experiment = Experiment.objects.get(name='2015_public_xdataonline') |
| |
| # Now we save the UserProfile model instance. |
| userprofile.save() |
| |
| # Finally we assign tasks to the new user |
| # Get a random product, get a random order of tasks |
| # And save them to the task list |
| product = Product.objects.filter(is_active=True).order_by('?')[0] |
| dataset = product.dataset |
| tasks = dataset.optask_set.filter(is_active=True).order_by('?') |
| |
| for index, task in enumerate(tasks): |
| TaskListItem(userprofile=userprofile, op_task=task, product=product, |
| index=index, task_active=False).save() |
| |
| |
| # Update our variable to tell the template registration was successful. |
| registrationSuccessful = True |
| |
| # add some logic to log events, log in users directly |
| print "successful registration of " + request.POST['email'] +" "+ datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
| request.POST['email_to'] = user.email |
| request.POST['email_subject'] = 'Welcome to XDATA Online' |
| request.POST['email_message'] = 'Your registration was successful!\n\nIn case you forget your password, please go to the following page and reset your password:\n\nhttps://' + get_current_site(request).domain + '/tasking/reset/\n\nYour username, in case you\'ve forgotten, is the email address this message was sent to.\n\nThanks for using our site!\n\nThe ' + get_current_site(request).name + ' team' |
| exp_portal.email.send_email(request) |
| |
| # login_participant(request) |
| # return render(request, 'instructions/exp_instructions.html', {'user': request.user}) |
| |
| # Not a HTTP POST, so we render our form using two ModelForm instances. |
| # These forms will be blank, ready for user input. |
| # else: |
| # print "register without POST" |
| # not sure what code belongs here yet but the two lines below are legacy... |
| # user_form = UserForm() |
| # profile_form = UserProfileForm() |
| |
| # Render the template depending on the context. |
| # possibly change this to render task list - see notes above |
| return render_to_response('registration/register.html', {'registrationSuccessful': registrationSuccessful, 'userExists': userExists, 'error': error}, context) |
| |
| |
| def logout_participant(request): |
| """ |
| Log users out and re-direct them to the main page. |
| """ |
| logout(request) |
| return HttpResponseRedirect('/') |
| |
| |
| @watch_login |
| def login_participant(request): |
| # Like before, obtain the context for the user's request. |
| context = RequestContext(request) |
| |
| # If the request is a HTTP POST, try to pull out the relevant information. |
| if request.method == 'POST': |
| # Gather the username (email) and password provided by the user. |
| # This information is obtained from the login form. |
| email = request.POST['email'] |
| password = request.POST['password'] |
| # print "Login attempt by " + username + " at " + datetime |
| |
| # Use Django's machinery to attempt to see if the username/password |
| # combination is valid - a User object is returned if it is. |
| user = authenticate(email=email, password=password) |
| |
| # If we have a User object, the details are correct. |
| # If None (Python's way of representing the absence of a value), no user |
| # with matching credentials was found. |
| if user: |
| # Is the account active? It could have been disabled. |
| if user.is_active: |
| # If the account is valid and active, we can log the user in. |
| # We'll send the user back to the homepage. |
| login(request, user) |
| return HttpResponseRedirect('/tasking/task_list') |
| # return render(request, 'task_list.html', {'user': user}) |
| else: |
| # An inactive account was used - no logging in! |
| return HttpResponse("Your XDATA account is disabled.") |
| else: |
| # Bad login details were provided. So we can't log the user in. |
| print "Invalid login details: {0}, {1}".format(email, password) |
| return HttpResponse("Invalid login details supplied.") |
| |
| # The request is not a HTTP POST, so display the login form. |
| # This scenario would most likely be a HTTP GET. |
| else: |
| # No context variables to pass to the template system, hence the |
| # blank dictionary object... |
| # experiment_title = title |
| return render(request, 'registration/login.html') |
| # return render(request, 'registration/login.html', {'experiment_title': experiment_title}) |
| |
| |
| # return login_view(request, authentication_form=MyAuthForm) |
| |
| |
| def reset_confirm(request, uidb64=None, token=None): |
| return password_reset_confirm(request, template_name='registration/reset_password_confirm.html', |
| uidb64=uidb64, token=token, |
| post_reset_redirect=reverse('op_tasks:login')) |
| |
| |
| def reset(request): |
| return password_reset(request, template_name='registration/reset_password_form.html', |
| email_template_name='registration/reset_password_email.html', |
| post_reset_redirect=reverse('op_tasks:reset_sent'), |
| from_email=settings.EMAIL_FROM_NOMINAL_ADDRESS) |
| |
| |
| def reset_sent(request): |
| return render(request, 'registration/reset_password_done.html') |
| |
| |
| @login_required(login_url='/tasking/login') |
| def task_list(request): |
| # print [x.both_complete for x in userprofile.tasklistitem_set.all()] |
| user = request.user |
| userprofile = user.userprofile |
| all_complete = all([x.both_complete for x in userprofile.tasklistitem_set.all()]) |
| # handling for instructions & intake, transition to first OpTask when ready |
| if userprofile.tasklistitem_set.all().count() > 0: |
| first_task = userprofile.tasklistitem_set.all()[0] |
| if userprofile.exp_inst_complete and userprofile.portal_inst_complete and not first_task.task_complete: |
| if userprofile.experiment.has_intake: |
| if userprofile.intake_complete: |
| first_task.task_active = True |
| first_task.save() |
| else: |
| if userprofile.experiment.sequential_tasks: |
| first_task.task_active = True |
| first_task.save() |
| else: |
| for task in userprofile.tasklistitem_set.all(): |
| task.task_active = True |
| task.save() |
| |
| # On visiting the task_list page, run check achievements logic |
| # TODO this isn't scalable... need a better strategy here |
| achievements.checkAchievements(request) |
| |
| mtcode = mechanicalTurk.generateCode(userprofile.user.id,userprofile.user_hash) |
| sm_request_update(SM_QUESTION_NAME, SM_EXPERIMENT_NAME) |
| |
| return render(request, 'task_list.html', |
| {'userprofile': userprofile, 'all_complete': all_complete, 'mtcode':mtcode, |
| 'hasTasksCompleteOneAchievement': achievements.hasTasksCompleteOneAchievement(user), |
| 'hasTasksCompleteTwoAchievement': achievements.hasTasksCompleteTwoAchievement(user), |
| 'hasFreePlayAchievement': achievements.hasFreePlayAchievement(user)}) |
| |
| |
| def activate_free_play(request): |
| """ |
| In "Free Play" mode, the user has access to all of the tasks in the system |
| for the products they are applicable to. The "buffet" style of tasking. |
| """ |
| user = request.user |
| userprofile = user.userprofile |
| |
| """ |
| First, award the Free Play achievement, if the user doesn't already have it. |
| """ |
| achievements.awardFreePlayAchievement(user) |
| |
| """ |
| Then append the buffet of taskings to the user's task list. |
| """ |
| tasksUtil.appendAllTasks(user) |
| |
| # Then follow the same logic as displaying the task_list page |
| return task_list(request) |
| |
| |
| def intro(request, process=None): |
| if process == 'register': |
| next_page = '/tasking/register' |
| elif process == 'login': |
| next_page = '/tasking/login' |
| return render(request, 'intro.html', {'user': request.user, 'next_page': next_page}) |
| |
| |
| def safety(request): |
| return redirect('http://www.xdataonline.com') |
| |
| |
| def instruct(request, read=None): |
| user = request.user |
| userprofile = user.userprofile |
| |
| if read == 'experiment': |
| if not userprofile.exp_inst_complete: |
| userprofile.exp_inst_complete = True |
| userprofile.progress += 15 |
| |
| elif read == 'portal': |
| if not userprofile.portal_inst_complete: |
| userprofile.portal_inst_complete = True |
| userprofile.progress += 15 |
| |
| elif read == 'product': |
| if not userprofile.task_inst_complete: |
| user.userprofile.task_inst_complete = True |
| userprofile.progress += 10 |
| |
| userprofile.save() |
| product = userprofile.tasklistitem_set.all()[0].product |
| |
| return render(request, 'instruction_home.html', |
| {'user': request.user, 'product': product, |
| 'hasTasksCompleteOneAchievement': achievements.hasTasksCompleteOneAchievement(user), |
| 'hasTasksCompleteTwoAchievement': achievements.hasTasksCompleteTwoAchievement(user), |
| 'hasFreePlayAchievement': achievements.hasFreePlayAchievement(user)}) |
| |
| |
| def intake(request): |
| # TODO: not great, but a simple solution for now... we will |
| # instantly mark the intake questionnaire as complete on view of the page |
| user = request.user |
| userprofile = user.userprofile |
| userprofile.intake_complete = True |
| userprofile.save() |
| return render(request, 'intake.html', {'user': request.user}) |
| |
| |
| def exp_instruct(request): |
| user = request.user |
| return render(request, 'instructions/exp_instructions.html', |
| {'user': request.user, |
| 'hasTasksCompleteOneAchievement': achievements.hasTasksCompleteOneAchievement(user), |
| 'hasTasksCompleteTwoAchievement': achievements.hasTasksCompleteTwoAchievement(user), |
| 'hasFreePlayAchievement': achievements.hasFreePlayAchievement(user)}) |
| |
| |
| def portal_instruct(request): |
| user = request.user |
| return render(request, 'instructions/portal_instructions.html', |
| {'user': request.user, |
| 'hasTasksCompleteOneAchievement': achievements.hasTasksCompleteOneAchievement(user), |
| 'hasTasksCompleteTwoAchievement': achievements.hasTasksCompleteTwoAchievement(user), |
| 'hasFreePlayAchievement': achievements.hasFreePlayAchievement(user)}) |
| |
| |
| def product_instruct(request): |
| user = request.user |
| return render(request, 'instructions/product_instructions.html', |
| {'user': request.user, |
| 'hasTasksCompleteOneAchievement': achievements.hasTasksCompleteOneAchievement(user), |
| 'hasTasksCompleteTwoAchievement': achievements.hasTasksCompleteTwoAchievement(user), |
| 'hasFreePlayAchievement': achievements.hasFreePlayAchievement(user)}) |
| |
| |
| def view_profile(request): |
| user = request.user |
| return render(request, 'user_profile.html', |
| {'user': request.user, |
| 'hasTasksCompleteOneAchievement': achievements.hasTasksCompleteOneAchievement(user), |
| 'hasTasksCompleteTwoAchievement': achievements.hasTasksCompleteTwoAchievement(user), |
| 'hasFreePlayAchievement': achievements.hasFreePlayAchievement(user)}) |