From 7ab7e125189b5f9a167e51d10552eccf02bdfd95 Mon Sep 17 00:00:00 2001
From: osmala <ossi.laine@utu.fi>
Date: Wed, 20 May 2020 18:46:30 +0300
Subject: [PATCH] Fixed randomization issues while exporting results

---
 app/experiment/views.py     |   4 +-
 app/models.py               |  83 +++++----
 app/routes.py               | 324 ++++++++++++++++++++----------------
 app/static/js/getDrawing.js |   5 +
 app/task/views.py           |   5 +-
 embody_plot.py              |   4 -
 6 files changed, 245 insertions(+), 180 deletions(-)

diff --git a/app/experiment/views.py b/app/experiment/views.py
index 1571725..7a08b88 100644
--- a/app/experiment/views.py
+++ b/app/experiment/views.py
@@ -921,7 +921,9 @@ def statistics():
     slider_answers = {}
     for participant in participants:
         if participant.answer_counter > 0:
-            answers = answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all()     
+            answers = answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set)\
+                .order_by(answer.page_idpage)\
+                .all()     
             slider_answers[participant.session] = [ a.answer for a in answers]     
 
     slider_answers['mean'] = get_mean_from_slider_answers(slider_answers)
diff --git a/app/models.py b/app/models.py
index 6920ffa..ed4669c 100644
--- a/app/models.py
+++ b/app/models.py
@@ -1,7 +1,9 @@
+from sqlalchemy import and_
+from flask import session
 from app import db
 from sqlalchemy import Column, Integer, String, Text, Boolean
 from flask_wtf import FlaskForm
-from wtforms_sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField 
+from wtforms_sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField
 from werkzeug.security import generate_password_hash, check_password_hash
 from flask_login import UserMixin
 from app import login
@@ -15,9 +17,10 @@ class background_question(db.Model):
     __tablename__ = "background_question"
     idbackground_question = db.Column(db.Integer, primary_key=True)
     background_question = db.Column(db.String(120))
-    answers = db.relationship('background_question_answer', backref='question', lazy='dynamic')
+    answers = db.relationship(
+        'background_question_answer', backref='question', lazy='dynamic')
     experiment_idexperiment = db.Column(db.Integer)
-    
+
     def __repr__(self):
         return "<idbackground_question = '%s', background_question = '%s'>" % (self.idbackground_question, self.background_question)
 
@@ -25,11 +28,12 @@ class background_question(db.Model):
 class background_question_option(db.Model):
     __tablename__ = "background_question_option"
     idbackground_question_option = db.Column(db.Integer, primary_key=True)
-    background_question_idbackground_question = db.Column(db.Integer, db.ForeignKey('background_question.idbackground_question'))
+    background_question_idbackground_question = db.Column(
+        db.Integer, db.ForeignKey('background_question.idbackground_question'))
     option = db.Column(db.String(120))
-    
+
     def __repr__(self):
-        return "<idbackground_question_option = '%s', background_question_idbackground_question = '%s',  option = '%s'>" % (self.idbackground_question_option, self.background_question_idbackground_question, self.option) 
+        return "<idbackground_question_option = '%s', background_question_idbackground_question = '%s',  option = '%s'>" % (self.idbackground_question_option, self.background_question_idbackground_question, self.option)
 
 
 class experiment (db.Model):
@@ -51,7 +55,7 @@ class experiment (db.Model):
     consent_text = db.Column(db.Text, index=True)
     use_forced_id = db.Column(db.String(120))
     embody_enabled = db.Column(db.Boolean, unique=False, default=False)
-    
+
     def __repr__(self):
         return "<idexperiment = '%s', name='%s', instruction='%s', directoryname='%s', language='%s', status='%s', randomization='%s', short_instruction='%s', single_sentence_instruction='%s', is_archived='%s', creator_name='%s', research_notification_filename='%s', creation_time='%s', stimulus_size='%s', consent_text='%s', use_forced_id='%s', embody_enabled='%s'>" % (self.idexperiment, self.name, self.instruction, self.directoryname, self.language, self.status, self.randomization, self.short_instruction, self.single_sentence_instruction, self.is_archived, self.creator_name, self.research_notification_filename, self.creation_time, self.stimulus_size, self.consent_text, self.use_forced_id, self.embody_enabled)
 
@@ -59,13 +63,16 @@ class experiment (db.Model):
 class answer_set (db.Model):
     __tablename__ = "answer_set"
     idanswer_set = db.Column(db.Integer, primary_key=True)
-    experiment_idexperiment = db.Column(db.Integer, db.ForeignKey('experiment.idexperiment'))
+    experiment_idexperiment = db.Column(
+        db.Integer, db.ForeignKey('experiment.idexperiment'))
     session = db.Column(db.String(120))
     agreement = db.Column(db.String(120))
     answer_counter = db.Column(db.Integer)
     answer_type = db.Column(db.String(120))
-    registration_time = db.Column(db.DateTime, index=True, default=datetime.utcnow)
-    last_answer_time = db.Column(db.DateTime, index=True, default=datetime.utcnow)
+    registration_time = db.Column(
+        db.DateTime, index=True, default=datetime.utcnow)
+    last_answer_time = db.Column(
+        db.DateTime, index=True, default=datetime.utcnow)
 
     def __repr__(self):
         return "<idanswer_set = '%s', experiment_idexperiment = '%s', session = '%s', agreement = '%s', answer_counter = '%s', registration_time = '%s', last_answer_time = '%s'>" % (self.idanswer_set, self.experiment_idexperiment, self.session, self.agreement, self.answer_counter, self.registration_time, self.last_answer_time)
@@ -74,17 +81,20 @@ class answer_set (db.Model):
 class background_question_answer(db.Model):
     __tablename__ = "background_question_answer"
     idbackground_question_answer = db.Column(db.Integer, primary_key=True)
-    answer_set_idanswer_set = db.Column(db.Integer, db.ForeignKey('answer_set.idanswer_set'))
+    answer_set_idanswer_set = db.Column(
+        db.Integer, db.ForeignKey('answer_set.idanswer_set'))
     answer = db.Column(db.String(120))
-    background_question_idbackground_question = db.Column(db.Integer, db.ForeignKey('background_question.idbackground_question'))
+    background_question_idbackground_question = db.Column(
+        db.Integer, db.ForeignKey('background_question.idbackground_question'))
 
     def __repr__(self):
-        return "<idbackground_question_answer = '%s', answer_set_idanswer_set = '%s', answer = '%s', background_question_idbackground_question = '%s'>" % (self.idbackground_question_answer, self.answer_set_idanswer_set, self.answer, self.background_question_idbackground_question) 
+        return "<idbackground_question_answer = '%s', answer_set_idanswer_set = '%s', answer = '%s', background_question_idbackground_question = '%s'>" % (self.idbackground_question_answer, self.answer_set_idanswer_set, self.answer, self.background_question_idbackground_question)
 
 
 def background_question_answer_query():
     return background_question_answer.query
 
+
 """
 class ChoiceForm(FlaskForm):
     opts = QuerySelectField(query_factory=background_question_answer_query, allow_blank=True)
@@ -98,30 +108,33 @@ vastaukset = u.answers.all()
 class question (db.Model):
     __tablename__ = "question"
     idquestion = db.Column(db.Integer, primary_key=True)
-    experiment_idexperiment = db.Column(db.Integer, db.ForeignKey('experiment.idexperiment'))
+    experiment_idexperiment = db.Column(
+        db.Integer, db.ForeignKey('experiment.idexperiment'))
     question = db.Column(db.String(120))
     left = db.Column(db.String(120))
     right = db.Column(db.String(120))
 
     def __repr__(self):
-        return "<idquestion = '%s', experiment_idexperiment = '%s', question = '%s', left = '%s', right = '%s'>" % (self.idquestion, self.experiment_idexperiment, self.question, self.left, self.right) 
+        return "<idquestion = '%s', experiment_idexperiment = '%s', question = '%s', left = '%s', right = '%s'>" % (self.idquestion, self.experiment_idexperiment, self.question, self.left, self.right)
 
 
 class embody_question (db.Model):
     __tablename__ = "embody_question"
     idembody = db.Column(db.Integer, primary_key=True)
-    experiment_idexperiment = db.Column(db.Integer, db.ForeignKey('experiment.idexperiment'))
+    experiment_idexperiment = db.Column(
+        db.Integer, db.ForeignKey('experiment.idexperiment'))
     picture = db.Column(db.Text)
     question = db.Column(db.Text)
 
     def __repr__(self):
-        return "<idembody = '%s', experiment_idexperiment = '%s', picture = '%s', question = '%s'>" % (self.idembody, self.experiment_idexperiment, self.picture, self.question )
+        return "<idembody = '%s', experiment_idexperiment = '%s', picture = '%s', question = '%s'>" % (self.idembody, self.experiment_idexperiment, self.picture, self.question)
 
 
 class page (db.Model):
     __tablename__ = "page"
     idpage = db.Column(db.Integer, primary_key=True)
-    experiment_idexperiment = db.Column(db.Integer, db.ForeignKey('experiment.idexperiment'))
+    experiment_idexperiment = db.Column(
+        db.Integer, db.ForeignKey('experiment.idexperiment'))
     type = db.Column(db.String(120), index=True)
     text = db.Column(db.Text)
     media = db.Column(db.String(120), index=True)
@@ -133,8 +146,10 @@ class page (db.Model):
 class answer (db.Model):
     __tablename__ = "answer"
     idanswer = db.Column(db.Integer, primary_key=True)
-    question_idquestion = db.Column(db.Integer, db.ForeignKey('question.idquestion'))
-    answer_set_idanswer_set = db.Column(db.Integer, db.ForeignKey('answer_set.idanswer_set'))
+    question_idquestion = db.Column(
+        db.Integer, db.ForeignKey('question.idquestion'))
+    answer_set_idanswer_set = db.Column(
+        db.Integer, db.ForeignKey('answer_set.idanswer_set'))
     answer = db.Column(db.String(120))
     page_idpage = db.Column(db.Integer, db.ForeignKey('page.idpage'))
 
@@ -145,9 +160,11 @@ class answer (db.Model):
 class embody_answer (db.Model):
     __tablename__ = "embody_answer"
     idanswer = db.Column(db.Integer, primary_key=True)
-    answer_set_idanswer_set = db.Column(db.Integer, db.ForeignKey('answer_set.idanswer_set'))
+    answer_set_idanswer_set = db.Column(
+        db.Integer, db.ForeignKey('answer_set.idanswer_set'))
     page_idpage = db.Column(db.Integer, db.ForeignKey('page.idpage'))
-    embody_question_idembody = db.Column(db.Integer, db.ForeignKey('embody_question.idembody'))
+    embody_question_idembody = db.Column(
+        db.Integer, db.ForeignKey('embody_question.idembody'))
     coordinates = db.Column(db.Text)
 
     def __repr__(self):
@@ -161,17 +178,24 @@ class trial_randomization (db.Model):
     randomized_idpage = db.Column(db.Integer)
     answer_set_idanswer_set = db.Column(db.Integer)
     experiment_idexperiment = db.Column(db.Integer)
-    
+
     def __repr__(self):
         return "<idtrial_randomization = '%s', page_idpage = '%s', randomized_idpage = '%s', answer_set_idanswer_set = '%s', experiment_idexperiment = '%s'>" % (self.idtrial_randomization, self.page_idpage, self.randomized_idpage, self.answer_set_idanswer_set, self.experiment_idexperiment)
 
+    @classmethod
+    def get_randomized_page(cls, page_id):
+        return cls.query.filter(and_(
+            cls.answer_set_idanswer_set == session['answer_set'],
+            cls.page_idpage == page_id)).first()
+
 
 class forced_id (db.Model):
     __tablename__ = "forced_id"
     idforced_id = db.Column(db.Integer, primary_key=True)
-    experiment_idexperiment = db.Column(db.Integer, db.ForeignKey('experiment.idexperiment'))
-    pregenerated_id = db.Column(db.String(120))     
-        
+    experiment_idexperiment = db.Column(
+        db.Integer, db.ForeignKey('experiment.idexperiment'))
+    pregenerated_id = db.Column(db.String(120))
+
     def __repr__(self):
         return "<idforced_id = '%s', experiment_idexperiment = '%s', pregenerated_id = '%s'>" % (self.idforced_id, self.experiment_idexperiment, self.pregenerated_id)
 
@@ -184,16 +208,15 @@ class user(UserMixin, db.Model):
     password_hash = db.Column(db.String(128))
 
     def __repr__(self):
-        return '<user {}>'.format(self.username) 
-    
+        return '<user {}>'.format(self.username)
+
     def set_password(self, password):
         self.password_hash = generate_password_hash(password)
 
     def check_password(self, password):
         return check_password_hash(self.password_hash, password)
 
-    
+
 @login.user_loader
 def load_user(id):
     return user.query.get(int(id))
-    
\ No newline at end of file
diff --git a/app/routes.py b/app/routes.py
index 8324481..e3dfd9d 100644
--- a/app/routes.py
+++ b/app/routes.py
@@ -4,18 +4,18 @@ import csv
 import os
 import random
 import secrets
-from datetime import datetime
+from datetime import datetime, date
 import tempfile
 import json
 
 from flask import (
-    Flask, 
-    render_template, 
-    request, 
-    session, 
-    flash, 
-    redirect, 
-    url_for, 
+    Flask,
+    render_template,
+    request,
+    session,
+    flash,
+    redirect,
+    url_for,
     Blueprint,
     send_file
 )
@@ -33,20 +33,21 @@ from app.models import answer_set, answer, forced_id
 from app.models import user, trial_randomization
 from app.forms import LoginForm, RegisterForm, StartWithIdForm
 
-#Stimuli upload folder setting
+# Stimuli upload folder setting
 APP_ROOT = os.path.dirname(os.path.abspath(__file__))
 
+
 @app.route('/')
 @app.route('/index')
 def index():
     experiments = experiment.query.all()
-    
+
     if session:
         flash("")
     else:
         #flash("sessio ei voimassa")
         session['language'] = "English"
-    
+
     return render_template('index.html', title='Home', experiments=experiments)
 
 
@@ -54,21 +55,21 @@ def index():
 def consent():
     exp_id = request.args.get('exp_id', None)
     experiment_info = experiment.query.filter_by(idexperiment=exp_id).first()
-    
+
     instruction_paragraphs = str(experiment_info.short_instruction)
     instruction_paragraphs = instruction_paragraphs.split('<br>')
-    
+
     consent_paragraphs = str(experiment_info.consent_text)
     consent_paragraphs = consent_paragraphs.split('<br>')
 
     if experiment_info.use_forced_id == 'On':
         return redirect(url_for('begin_with_id', exp_id=exp_id))
 
-    return render_template('consent.html', 
-                            exp_id=exp_id, 
-                            experiment_info=experiment_info, 
-                            instruction_paragraphs=instruction_paragraphs, 
-                            consent_paragraphs=consent_paragraphs)
+    return render_template('consent.html',
+                           exp_id=exp_id,
+                           experiment_info=experiment_info,
+                           instruction_paragraphs=instruction_paragraphs,
+                           consent_paragraphs=consent_paragraphs)
 
 
 @app.route('/set_language')
@@ -88,28 +89,28 @@ def remove_language():
 def participant_session():
     '''Set up session variables and create answer_set (database level sessions)'''
 
-    #start session
+    # start session
     session['exp_id'] = request.args.get('exp_id', None)
     session['agree'] = request.args.get('agree', None)
-  
-    #If user came via the route for "I have already a participant ID that I wish to use, Use that ID, otherwise generate a random ID
+
+    # If user came via the route for "I have already a participant ID that I wish to use, Use that ID, otherwise generate a random ID
     if 'begin_with_id' in session:
         session['user'] = session['begin_with_id']
         session.pop('begin_with_id', None)
     else:
-        #lets generate a random id. If the same id is allready in db, lets generate a new one and finally use that in session['user']
+        # lets generate a random id. If the same id is allready in db, lets generate a new one and finally use that in session['user']
         random_id = secrets.token_hex(3)
         check_id = answer_set.query.filter_by(session=random_id).first()
 
         while check_id is not None:
             random_id = secrets.token_hex(3)
             check_id = answer_set.query.filter_by(session=random_id).first()
-        
+
         session['user'] = random_id
 
     # Set session status variables
-    exp_status = experiment.query.filter_by(idexperiment=session['exp_id']).first()
-
+    exp_status = experiment.query.filter_by(
+        idexperiment=session['exp_id']).first()
 
     # Create answer set for the participant in the database
     the_time = datetime.now()
@@ -121,55 +122,57 @@ def participant_session():
         answer_set_type = 'embody'
 
     participant_answer_set = answer_set(experiment_idexperiment=session['exp_id'],
-                                        session=session['user'], 
-                                        agreement = session['agree'], 
-                                        answer_counter = '0', 
-                                        answer_type = answer_set_type, 
-                                        registration_time=the_time, 
+                                        session=session['user'],
+                                        agreement=session['agree'],
+                                        answer_counter='0',
+                                        answer_type=answer_set_type,
+                                        registration_time=the_time,
                                         last_answer_time=the_time)
     db.session.add(participant_answer_set)
     db.session.commit()
 
-    
-    #If trial randomization is set to 'On' for the experiment, create a randomized trial order for this participant
-    #identification is based on the uniquie answer set id
+    # If trial randomization is set to 'On' for the experiment, create a randomized trial order for this participant
+    # identification is based on the uniquie answer set id
     if exp_status.randomization == 'On':
-    
+
         session['randomization'] = 'On'
-        
-        #create a list of page id:s for the experiment
-        experiment_pages = page.query.filter_by(experiment_idexperiment=session['exp_id']).all()
+
+        # create a list of page id:s for the experiment
+        experiment_pages = page.query.filter_by(
+            experiment_idexperiment=session['exp_id']).all()
         original_id_order_list = [(int(o.idpage)) for o in experiment_pages]
-        
-        #create a randomized page id list    
-        helper_list = original_id_order_list 
+
+        # create a randomized page id list
+        helper_list = original_id_order_list
         randomized_order_list = []
-    
+
         for i in range(len(helper_list)):
             element = random.choice(helper_list)
             helper_list.remove(element)
             randomized_order_list.append(element)
-        
-        #Input values into trial_randomization table where the original page_ids have a corresponding randomized counterpart
-        experiment_pages = page.query.filter_by(experiment_idexperiment=session['exp_id']).all()
+
+        # Input values into trial_randomization table where the original page_ids have a corresponding randomized counterpart
+        experiment_pages = page.query.filter_by(
+            experiment_idexperiment=session['exp_id']).all()
         original_id_order_list = [(int(o.idpage)) for o in experiment_pages]
-        
+
         for c in range(len(original_id_order_list)):
-            random_page = trial_randomization(page_idpage=original_id_order_list[c], randomized_idpage=randomized_order_list[c], answer_set_idanswer_set = participant_answer_set.idanswer_set, experiment_idexperiment = session['exp_id'])
+            random_page = trial_randomization(page_idpage=original_id_order_list[c], randomized_idpage=randomized_order_list[
+                                              c], answer_set_idanswer_set=participant_answer_set.idanswer_set, experiment_idexperiment=session['exp_id'])
             db.session.add(random_page)
             db.session.commit()
-    
+
     if exp_status.randomization == "Off":
         session['randomization'] = "Off"
 
-    #store participants session id in session list as answer_set, based on experiment id and session id
-    session_id_for_participant = answer_set.query.filter(and_(answer_set.session==session['user'], answer_set.experiment_idexperiment==session['exp_id'])).first()
+    # store participants session id in session list as answer_set, based on experiment id and session id
+    session_id_for_participant = answer_set.query.filter(and_(
+        answer_set.session == session['user'], answer_set.experiment_idexperiment == session['exp_id'])).first()
     session['answer_set'] = session_id_for_participant.idanswer_set
-
-
-    #collect experiments mediatype from db to session['type']. 
-    #This is later used in task.html to determine page layout based on stimulus type
-    mediatype = page.query.filter_by(experiment_idexperiment=session['exp_id']).first()
+    # collect experiments mediatype from db to session['type'].
+    # This is later used in task.html to determine page layout based on stimulus type
+    mediatype = page.query.filter_by(
+        experiment_idexperiment=session['exp_id']).first()
     if mediatype:
         session['type'] = mediatype.type
     else:
@@ -180,124 +183,129 @@ def participant_session():
     if 'user' in session:
         user = session['user']
         return redirect('/register')
-      
+
     return "Session start failed return <a href = '/login'></b>" + "Home</b></a>"
 
 
 @app.route('/register', methods=['GET', 'POST'])
 def register():
-    
+
     form = RegisterForm(request.form)
     questions_and_options = {}
-    questions = background_question.query.filter_by(experiment_idexperiment=session['exp_id']).all()
-
-    for q in questions:    
-    
-        options = background_question_option.query.filter_by(background_question_idbackground_question=q.idbackground_question).all()
-        options_list = [(o.option, o.idbackground_question_option) for o in options]
-        questions_and_options[q.idbackground_question, q.background_question]  = options_list
-    
- 
+    questions = background_question.query.filter_by(
+        experiment_idexperiment=session['exp_id']).all()
+
+    for q in questions:
+
+        options = background_question_option.query.filter_by(
+            background_question_idbackground_question=q.idbackground_question).all()
+        options_list = [(o.option, o.idbackground_question_option)
+                        for o in options]
+        questions_and_options[q.idbackground_question,
+                              q.background_question] = options_list
+
     form.questions1 = questions_and_options
-    
-    if request.method == 'POST'and form.validate():
-    
+
+    if request.method == 'POST' and form.validate():
+
         data = request.form.to_dict()
         for key, value in data.items():
 
-            
-            #tähän db insertit
+            # tähän db insertit
 
-            #flash(key)
-            #flash(value)
-            #Input registration page answers to database
-            participant_background_question_answers = background_question_answer(answer_set_idanswer_set=session['answer_set'], answer=value, background_question_idbackground_question=key)
+            # flash(key)
+            # flash(value)
+            # Input registration page answers to database
+            participant_background_question_answers = background_question_answer(
+                answer_set_idanswer_set=session['answer_set'], answer=value, background_question_idbackground_question=key)
             db.session.add(participant_background_question_answers)
             db.session.commit()
 
         return redirect('/instructions')
-   
-    
-    return render_template('register.html', form=form)
 
+    return render_template('register.html', form=form)
 
 
 @app.route('/begin_with_id', methods=['GET', 'POST'])
 def begin_with_id():
     '''Begin experiment with experiment ID. GET -method returns login page for starting the 
     experiment and POST -method verifys users ID before starting new experiment'''
-    
+
     exp_id = request.args.get('exp_id', None)
     form = StartWithIdForm()
     experiment_info = experiment.query.filter_by(idexperiment=exp_id).first()
-    
+
     instruction_paragraphs = str(experiment_info.short_instruction)
     instruction_paragraphs = instruction_paragraphs.split('<br>')
-    
+
     consent_paragraphs = str(experiment_info.consent_text)
     consent_paragraphs = consent_paragraphs.split('<br>')
 
     if form.validate_on_submit():
-        
+
         variable = form.participant_id.data
-        
-        #check if participant ID is found from db with this particular ID. If a match is found inform about error
-        participant = answer_set.query.filter(and_(answer_set.session==variable, answer_set.experiment_idexperiment==exp_id)).first()
-        is_id_valid = forced_id.query.filter(and_(forced_id.pregenerated_id==variable, forced_id.experiment_idexperiment==exp_id)).first()
-        
+
+        # check if participant ID is found from db with this particular ID. If a match is found inform about error
+        participant = answer_set.query.filter(and_(
+            answer_set.session == variable, answer_set.experiment_idexperiment == exp_id)).first()
+        is_id_valid = forced_id.query.filter(and_(
+            forced_id.pregenerated_id == variable, forced_id.experiment_idexperiment == exp_id)).first()
+
         if participant is not None:
             flash(_('ID already in use'))
-            return redirect(url_for('begin_with_id', exp_id=exp_id))        
-        
-        #if there was not a participant already in DB:
+            return redirect(url_for('begin_with_id', exp_id=exp_id))
+
+        # if there was not a participant already in DB:
         if participant is None:
-    
+
             if is_id_valid is None:
                 flash(_('No such ID set for this experiment'))
-                return redirect(url_for('begin_with_id', exp_id=exp_id))        
+                return redirect(url_for('begin_with_id', exp_id=exp_id))
 
             else:
-                #save the participant ID in session list for now, this is deleted after the session has been started in participant_session-view
+                # save the participant ID in session list for now, this is deleted after the session has been started in participant_session-view
                 session['begin_with_id'] = form.participant_id.data
                 return render_template('consent.html', exp_id=exp_id, experiment_info=experiment_info, instruction_paragraphs=instruction_paragraphs, consent_paragraphs=consent_paragraphs)
-        
+
     return render_template('begin_with_id.html', exp_id=exp_id, form=form)
 
 
 @app.route('/admin_dryrun', methods=['GET', 'POST'])
 @login_required
 def admin_dryrun():
-    
+
     exp_id = request.args.get('exp_id', None)
     form = StartWithIdForm()
     experiment_info = experiment.query.filter_by(idexperiment=exp_id).first()
 
     if form.validate_on_submit():
-        
-        #check if participant ID is found from db with this particular ID. If a match is found inform about error
-        participant = answer_set.query.filter(and_(answer_set.session==form.participant_id.data, answer_set.experiment_idexperiment==exp_id)).first()
+
+        # check if participant ID is found from db with this particular ID. If a match is found inform about error
+        participant = answer_set.query.filter(and_(
+            answer_set.session == form.participant_id.data, answer_set.experiment_idexperiment == exp_id)).first()
         if participant is not None:
             flash('ID already in use')
-            return redirect(url_for('admin_dryrun', exp_id=exp_id))        
-        
-        #if there was not a participant already in DB:
+            return redirect(url_for('admin_dryrun', exp_id=exp_id))
+
+        # if there was not a participant already in DB:
         if participant is None:
-            #save the participant ID in session list for now, this is deleted after the session has been started in participant_session-view
+            # save the participant ID in session list for now, this is deleted after the session has been started in participant_session-view
             session['begin_with_id'] = form.participant_id.data
             return render_template('consent.html', exp_id=exp_id, experiment_info=experiment_info)
-        
+
     return render_template('admin_dryrun.html', exp_id=exp_id, form=form)
 
 
 @app.route('/instructions')
 def instructions():
-    
+
     participant_id = session['user']
-    instructions = experiment.query.filter_by(idexperiment = session['exp_id']).first()
-    
+    instructions = experiment.query.filter_by(
+        idexperiment=session['exp_id']).first()
+
     instruction_paragraphs = str(instructions.instruction)
     instruction_paragraphs = instruction_paragraphs.split('<br>')
-    
+
     return render_template('instructions.html', instruction_paragraphs=instruction_paragraphs, participant_id=participant_id)
 
 
@@ -308,13 +316,14 @@ def login():
         return redirect(url_for('index'))
     form = LoginForm()
     if form.validate_on_submit():
-        user_details = user.query.filter_by(username=form.username.data).first()
+        user_details = user.query.filter_by(
+            username=form.username.data).first()
         if user_details is None or not user_details.check_password(form.password.data):
             flash('Invalid username or password')
             return redirect(url_for('login'))
-        login_user(user_details, remember=form.remember_me.data)    
+        login_user(user_details, remember=form.remember_me.data)
         return redirect(url_for('index'))
-    
+
 #        flash('Login requested for user {}, remember_me={}'.format(
 #            form.username.data, form.remember_me.data))
 #        return redirect('/index')
@@ -329,11 +338,11 @@ def logout():
 
 @app.route('/view_research_notification')
 def view_research_notification():
-    
+
     exp_id = request.args.get('exp_id', None)
     image = experiment.query.filter_by(idexperiment=exp_id).first()
     research_notification_filename = image.research_notification_filename
-    
+
     return render_template('view_research_notification.html', research_notification_filename=research_notification_filename)
 
 
@@ -342,10 +351,13 @@ def view_research_notification():
 def download_csv():
 
     exp_id = request.args.get('exp_id', None)
-    experiment_info = experiment.query.filter_by(idexperiment = exp_id).all()
+    experiment_info = experiment.query.filter_by(idexperiment=exp_id).all()
+
+    print(experiment_info)
 
     # answer sets with participant ids
-    participants = answer_set.query.filter_by(experiment_idexperiment= exp_id).all()
+    participants = answer_set.query.filter_by(
+        experiment_idexperiment=exp_id).all()
 
     # pages aka stimulants
     pages = page.query.filter_by(experiment_idexperiment=exp_id).all()
@@ -358,21 +370,25 @@ def download_csv():
     questions = question.query.filter_by(experiment_idexperiment=exp_id).all()
 
     # embody questions
-    embody_questions = embody_question.query.filter_by(experiment_idexperiment=exp_id).all()
+    embody_questions = embody_question.query.filter_by(
+        experiment_idexperiment=exp_id).all()
 
     csv = ''
 
     # create CSV-header
     header = 'participant id;'
-    header += ';'.join([str(count) +'. bg_question: '+ question.background_question.strip() for count,question in enumerate(bg_questions, 1)])
+    header += ';'.join([str(count) + '. bg_question: ' + question.background_question.strip()
+                        for count, question in enumerate(bg_questions, 1)])
 
-    for idx in range(1,len(pages) + 1):
+    for idx in range(1, len(pages) + 1):
         if len(questions) > 0:
-            header += ';' + ';'.join(['page' + str(idx) + '_' + str(count) +'. slider_question: ' + question.question.strip() for count,question in enumerate(questions, 1)]) 
+            header += ';' + ';'.join(['page' + str(idx) + '_' + str(count) + '. slider_question: ' +
+                                      question.question.strip() for count, question in enumerate(questions, 1)])
 
-    for idx in range(1,len(pages) + 1):
+    for idx in range(1, len(pages) + 1):
         if len(embody_questions) > 0:
-            header += ';' + ';'.join(['page' + str(idx) + '_' + str(count) +'. embody_question: '+ question.picture.strip() for count,question in enumerate(embody_questions, 1)])
+            header += ';' + ';'.join(['page' + str(idx) + '_' + str(count) + '. embody_question: ' +
+                                      question.picture.strip() for count, question in enumerate(embody_questions, 1)])
 
     csv += header + '\r\n'
     answer_row = ''
@@ -385,43 +401,63 @@ def download_csv():
                 answer_row += participant.session + ';'
 
                 # append background question answers
-                bg_answers = background_question_answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all()
-                bg_answers_list = [ str(a.answer).strip() for a in bg_answers]
+                bg_answers = background_question_answer.query.filter_by(
+                    answer_set_idanswer_set=participant.idanswer_set).all()
+                bg_answers_list = [str(a.answer).strip() for a in bg_answers]
                 answer_row += ';'.join(bg_answers_list) + ';'
 
-                # append slider answers 
-                slider_answers = answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all()     
-                answers_list = [ str(a.answer).strip() for a in slider_answers]    
-                answer_row += ';'.join(answers_list) + ';' if slider_answers else len(questions) * len(pages) * ';'
+                # append slider answers
+                slider_answers = answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set)\
+                    .order_by(answer.page_idpage)\
+                    .all()
+
+                answers_list = [str(a.answer).strip() for a in slider_answers]
+                answer_row += ';'.join(answers_list) + \
+                    ';' if slider_answers else len(
+                        questions) * len(pages) * ';'
 
                 # append embody answers (coordinates)
-                # save embody answers as bitmap images  
-                embody_answers = embody_answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all()     
-                answers_list = []
+                # save embody answers as bitmap images
+                embody_answers = embody_answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set)\
+                    .order_by(embody_answer.page_idpage)\
+                    .all()
 
-                # TODO: check randomization
+                answers_list = []
 
-                for embody_answer_data in embody_answers:
+                for answer_data in embody_answers:
 
                     try:
-                        embody_answer_data = json.loads(embody_answer_data.coordinates)
-                        coordinates_to_bitmap = [[0 for x in range(embody_answer_data['height'] + 2)] for y in range(embody_answer_data['width'] + 2)] 
+                        coordinates = json.loads(answer_data.coordinates)
+                        em_height = coordinates.get('height', 600) + 2
+                        em_width = coordinates.get('width', 200) + 2
+
+                        coordinates_to_bitmap = [
+                            [0 for x in range(em_height)] for y in range(em_width)]
 
-                        for point in list(zip( embody_answer_data['x'], embody_answer_data['y'] )):
+                        coordinates = list(
+                            zip(coordinates.get('x'), coordinates.get('y')))
+
+                        for point in coordinates:
 
                             try:
-                                 coordinates_to_bitmap[point[0]][point[1]] += 0.1
+                                # for every brush stroke, increment the pixel 
+                                # value for every brush stroke
+                                coordinates_to_bitmap[point[0]][point[1]] += 0.1
                             except IndexError:
-                                 continue
+                                continue
 
                         answers_list.append(json.dumps(coordinates_to_bitmap))
-  
+
                     except ValueError as err:
-                        app.logger.info(err)
+                        app.logger(err)
+
+                answer_row += ';'.join(answers_list) if embody_answers else \
+                    len(embody_questions) * len(pages) * ';'
 
                 # old way to save only visited points:
-                # answers_list = [ json.dumps(list(zip( json.loads(a.coordinates)['x'], json.loads(a.coordinates)['y']))) for a in embody_answers]    
-                answer_row += ';'.join(answers_list) if embody_answers else len(embody_questions) * len(pages) * ';'
+                # answers_list = [json.dumps(
+                #   list(zip( json.loads(a.coordinates)['x'],
+                #   json.loads(a.coordinates)['y']))) for a in embody_answers]
 
             except TypeError as err:
                 print(err)
@@ -431,15 +467,21 @@ def download_csv():
 
     try:
         fd, path = tempfile.mkstemp()
+
         with os.fdopen(fd, 'w') as tmp:
             tmp.write(csv)
             tmp.flush()
 
-            return send_file(path, mimetype='text/csv')
+            cur_date = date.today().strftime("%Y-%m-%d")
+            filename = "experiment_{}_{}.csv".format(exp_id, cur_date)
 
+            return send_file(path,
+                             mimetype='text/csv',
+                             as_attachment=True,
+                             attachment_filename=filename)
     finally:
         os.remove(path)
-    
+
 
 @app.route('/researcher_info')
 @login_required
diff --git a/app/static/js/getDrawing.js b/app/static/js/getDrawing.js
index 919c727..4504eb3 100644
--- a/app/static/js/getDrawing.js
+++ b/app/static/js/getDrawing.js
@@ -48,6 +48,11 @@ $(document).ready(function()  {
         // 
         var pageId = this.dataset.value.split('-')[0]
         var embodyId = this.dataset.value.split('-')[1]
+
+        console.log(pageId)
+        console.log(embodyId)
+
+
         socket.emit('draw', {page:pageId, embody:embodyId})
         progressBarContainer.removeClass("hidden")
 
diff --git a/app/task/views.py b/app/task/views.py
index c7815a3..7e559e7 100644
--- a/app/task/views.py
+++ b/app/task/views.py
@@ -37,10 +37,7 @@ task_blueprint = Blueprint("task", __name__,
 def get_randomized_page(page_id):
     """if trial randomization is on we will still use the same functionality that is used otherwise
     but we will pass the randomized pair of the page_id from trial randomization table to the task.html"""
-    return trial_randomization.query.filter(and_(
-            trial_randomization.answer_set_idanswer_set==session['answer_set'], 
-            trial_randomization.page_idpage==page_id
-        )).first()
+    return trial_randomization.get_randomized_page(page_id)
 
 
 def add_slider_answer(key, value, page_id=None):
diff --git a/embody_plot.py b/embody_plot.py
index e72e065..0d61fad 100644
--- a/embody_plot.py
+++ b/embody_plot.py
@@ -119,13 +119,11 @@ def timeit(method):
 
     return timed
 
-import sys
 
 @timeit
 def get_coordinates(idpage, idembody=None, select_clause=SELECT_BY_PAGE_AND_PICTURE):
     """Select all drawn points from certain stimulus and plot them onto 
     the human body"""
-
     db = MyDB()
     db.query(select_clause, (idpage,idembody))
 
@@ -138,13 +136,11 @@ def get_coordinates(idpage, idembody=None, select_clause=SELECT_BY_PAGE_AND_PICT
         image_path = db._db_cur.fetchone()[0]
         image_path = './app' + image_path
 
-
         # Draw image
         plt = plot_coordinates(coordinates, image_path)
     else:
         plt = plot_coordinates(coordinates, DEFAULT_IMAGE_PATH)
 
-
     # Save image to ./app/static/ 
     img_filename = 'PAGE-' + str(idpage) + '-' + DATE_STRING + '.png'
     plt.savefig(STATIC_PATH + img_filename)
-- 
GitLab