blob: 432caf94bf217e9f5e46cb7735a2821e697e9beb [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
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
from django.contrib.auth.views import password_reset, password_reset_confirm
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 elasticsearch import Elasticsearch
from xdata.settings import ALE_URL
import achievements
import exp_portal
import datetime
from op_tasks.models import Product, UserProfile, TaskListItem, Experiment
import exceptions
import hashlib
import logging
#import zlib
#import sqlite
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':
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:
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()
# 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()
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())
else:
current_tasklistitem.exit_active = False
current_tasklistitem.exit_complete = True
userprofile.save()
current_tasklistitem.save()
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
return render(request, 'task.html', {'tasklistitem':tasklistitem})
def task_launch(request, task_pk):
tasklistitem = TaskListItem.objects.get(pk=task_pk)
return render(request, 'task_launch.html', {'tasklistitem': tasklistitem})
# cretaes 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.
registered = 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 = User(username=request.POST['username'])
user.set_password(request.POST['password'])
user.email = user.username
user.save()
# 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='fandf_experiment_2015')
userprofile.experiment = Experiment.objects.get(name='fandf_experiment_2015')
# 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.
registered = True
# add some logic to log events, log in users directly
print "successful registration of " + request.POST['username'] +" "+ 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'] = 'successful registration'
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', {'registered': registered}, context)
def logout_participant(request):
"""
Log users out and re-direct them to the main page.
"""
logout(request)
return HttpResponseRedirect('/')
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 and password provided by the user.
# This information is obtained from the login form.
username = request.POST['username']
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(username=username, 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(username, 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'))
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()])
return render(request, 'task_list.html',
{'userprofile': userprofile, 'all_complete': all_complete})
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
if userprofile.exp_inst_complete and userprofile.portal_inst_complete:
first_task = userprofile.tasklistitem_set.all()[0]
first_task.task_active = True
first_task.save()
return render(request, 'instruction_home.html', {'user': request.user, 'product': product})
def exp_instruct(request):
return render(request, 'instructions/exp_instructions.html', {'user': request.user})
def portal_instruct(request):
return render(request, 'instructions/portal_instructions.html', {'user': request.user})
def product_instruct(request):
return render(request, 'instructions/product_instructions.html', {'user': request.user})
def view_profile(request):
return render(request, 'user_profile.html', {'user': request.user})