views.py 11.4 KB
Newer Older
1
2
3
4



import math
5
import json
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from datetime import datetime

from flask import (
    Flask, 
    render_template, 
    request, 
    session, 
    flash, 
    redirect, 
    url_for, 
    Blueprint
)

from sqlalchemy import and_ 
from flask_babel import _, lazy_gettext as _l

from app import db
from app.models import experiment
from app.models import page, question
from app.models import answer_set, answer 
from app.models import user, trial_randomization
27
from app.forms import Answers, TaskForm, ContinueTaskForm, StringForm
28
29
30
31
32
33
34

task_blueprint = Blueprint("task", __name__, 
                template_folder='templates',
                static_folder='static',
                url_prefix='/task')


35
def get_randomized_page(page_id):
36
37
38
39
40
41

    #this variable is feeded to the template as empty if trial randomization is set to "off"
    randomized_stimulus = ""

    #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
42
    randomized_page = trial_randomization.query.filter(and_(
43
            trial_randomization.answer_set_idanswer_set==session['answer_set'], 
44
45
            trial_randomization.page_idpage==page_id
            #trial_randomization.page_idpage==pages.items[0].idpage
46
47
        )).first()

48
    return randomized_page
49
50
51
52
53
54
55


def add_slider_answer(key, value, randomized_page_id):
    '''Insert slider value to database. If trial randomization is set to 'Off' 
    the values are inputted for session['current_idpage']. Otherwise the values 
    are set for the corresponding id found in the trial randomization table'''

56
    page_idpage = session['current_idpage'] if session['randomization'] == 'Off' else randomized_page_id
57
58
59
60
61
    participant_answer = answer(question_idquestion=key, answer_set_idanswer_set=session['answer_set'], answer=value, page_idpage=page_idpage)
    db.session.add(participant_answer)
    db.session.commit()


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def update_answer_set():
    the_time = datetime.now()
    the_time = the_time.replace(microsecond=0)

    update_answer_counter = answer_set.query.filter_by(idanswer_set=session['answer_set']).first()
    update_answer_counter.answer_counter = int(update_answer_counter.answer_counter) + 1 
    update_answer_counter.last_answer_time = the_time
    db.session.commit()


def slider_question_has_answers(user, page_id):
    '''This should return true IF there are questions from certain page and no answers'''

    answer_set_id = answer_set.query.filter_by(session=user).first().idanswer_set
    experiment_id = answer_set.query.filter_by(session=user).first().experiment_idexperiment

    if session['randomization'] == 'On':
        randomized_page_id = get_randomized_page(page_id).randomized_idpage
        answers = answer.query.filter_by(answer_set_idanswer_set=answer_set_id, page_idpage=randomized_page_id).all()
    else:
        answers = answer.query.filter_by(answer_set_idanswer_set=answer_set_id, page_idpage=page_id).all()

    questions = question.query.filter_by(experiment_idexperiment=experiment_id).all()

    return (True if (len(answers) == 0 and len(questions) > 0) else False)


@task_blueprint.route('/embody/<int:page_num>', methods=['POST'])
def task_embody(page_num):
    '''Save embody drawing to database'''

    form = StringForm(request.form)
    pages = page.query.filter_by(experiment_idexperiment=session['exp_id']).paginate(per_page=1, page=page_num, error_out=True)
    page_id = pages.items[0].idpage

    if form.validate():
        data = request.form.to_dict()
99
100
101
102
103
104
105
106
107

        coordinates = json.loads(data['coordinates'])
        print("x:",coordinates['x'])
        print("y:",coordinates['y'])



    # Test that everything OK
    return json.dumps(coordinates)
108
109
110
111
112
113
114
115
116
117
118
119
120

    # Check if there are unanswered slider questions
    if slider_question_has_answers(session['user'], page_id):
        return redirect( url_for('task.task', page_num=page_num, show_sliders=True))

    if not pages.has_next:
        return redirect ( url_for('task.completed'))

    # If user has answered to all questions, then move to next page
    return redirect( url_for('task.task', page_num=pages.next_num))


@task_blueprint.route('/question/<int:page_num>', methods=['POST'])
121
def task_answer(page_num):
122
    '''Save slider answers to database'''
123

124
    form = TaskForm(request.form)
125
    pages = page.query.filter_by(experiment_idexperiment=session['exp_id']).paginate(per_page=1, page=page_num, error_out=True)
126
    page_id = pages.items[0].idpage
127

128
    if form.validate():
129
130
131
        #Lets check if there are answers in database already for this page_id (eg. if user returned to previous page and tried to answer again)
        #If so flash ("Page has been answered already. Answers discarded"), else insert values in to db
        #this has to be done separately for trial randomization "on" and "off" situations        
132

133
        if session['randomization'] == 'On':
134
135
            randomized_page_id = get_randomized_page(page_id).randomized_idpage
            check_answer = answer.query.filter(and_(answer.answer_set_idanswer_set==session['answer_set'], answer.page_idpage==randomized_page_id)).first()
136
        else:
137
138
139
            check_answer = answer.query.filter(and_(answer.answer_set_idanswer_set==session['answer_set'], answer.page_idpage==session['current_idpage'])).first()

        if check_answer is None:
140
            update_answer_set()
141
142
143
        
            data = request.form.to_dict()
            for key, value in data.items():
144
                add_slider_answer(key, value, randomized_page_id)
145
146
147
148
149
150

        else:
            flash("Page has been answered already. Answers discarded")
        
        page_num=pages.next_num
        
151
152
153
154
155
156
157
158
159
        if not pages.has_next:
            return redirect ( url_for('task.completed'))

    return redirect( url_for('task.task', page_num=pages.next_num))


@task_blueprint.route('/<int:page_num>', methods=['GET'])
def task(page_num):

160
161
162
163
164
165
166
167
    try:
        experiment_info = experiment.query.filter_by(idexperiment=session['exp_id']).first()
    except KeyError as err:
        print(err)
        flash("No valid session found")
        return redirect('/')


168
169
170
171
172
173
174
175
    rating_instruction = experiment_info.single_sentence_instruction
    stimulus_size = experiment_info.stimulus_size
    
    #for text stimuli the size needs to be calculated since the template element utilises h1-h6 tags.
    #A value of stimulus size 12 gives h1 and value of 1 gives h6
    stimulus_size_text = 7-math.ceil((int(stimulus_size)/2))

    pages = page.query.filter_by(experiment_idexperiment=session['exp_id']).paginate(per_page=1, page=page_num, error_out=True)
176
    page_id = pages.items[0].idpage
177
178
179
180
181
182
183
184
    progress_bar_percentage = round((pages.page/pages.pages)*100)

    #this variable is feeded to the template as empty if trial randomization is set to "off"
    randomized_stimulus = ""

    # 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
    if session['randomization'] == 'On':
185
186
        randomized_page_id = get_randomized_page(page_id).randomized_idpage
        randomized_stimulus = page.query.filter_by(idpage=randomized_page_id).first()
187
        
188
189
190
    for p in pages.items:
        session['current_idpage'] = p.idpage

191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
    print(session)

    # Select form type (TODO: question order is now harcoded to EMBODY -> SLIDERS
    # there should be more flexible solution if more question types are added...)
    if request.args.get('show_sliders', False) or not session['embody']:
        # Init slider form
        form = TaskForm()

        # Get sliders from this experiment
        categories = question.query.filter_by(experiment_idexperiment=session['exp_id']).all()

        categories_and_scales = {}
        for cat in categories:    
            scale_list = [(cat.left, cat.right)]
            categories_and_scales[cat.idquestion, cat.question]  = scale_list
        
        form.categories1 = categories_and_scales

    else:
        form = StringForm()
211

212
    return render_template(
213
214
215
216
217
218
219
220
221
222
223
        'task.html', 
        pages=pages, 
        page_num=page_num,
        progress_bar_percentage=progress_bar_percentage, 
        form=form, 
        randomized_stimulus=randomized_stimulus, 
        rating_instruction=rating_instruction, 
        stimulus_size=stimulus_size, 
        stimulus_size_text=stimulus_size_text,
        experiment_info=experiment_info
        )
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250


@task_blueprint.route('/completed')
def completed():
    
    session.pop('user', None)
    session.pop('exp_id', None)    
    session.pop('agree', None)
    session.pop('answer_set', None)
    session.pop('type', None)
    session.pop('randomization', None)

    return render_template('task_completed.html')


@task_blueprint.route('/continue', methods=['GET', 'POST'])
def continue_task():
    
    exp_id = request.args.get('exp_id', None)
    form = ContinueTaskForm()
    
    if form.validate_on_submit():
        
        #check if participant ID is found from db and that the answer set is linked to the correct experiment
        participant = answer_set.query.filter(and_(answer_set.session==form.participant_id.data, answer_set.experiment_idexperiment==exp_id)).first()
        if participant is None:
            flash('Invalid ID')
251
            return redirect(url_for('task.continue_task', exp_id=exp_id))        
252
253
254
255
256
257
258
259
260
        
        #flash('Login requested for participant {}'.format(form.participant_id.data))
        
        #if correct participant_id is found with the correct experiment ID; start session for that user
        session['exp_id'] = exp_id
        session['user'] = form.participant_id.data 
        session['answer_set'] = participant.idanswer_set
        mediatype = page.query.filter_by(experiment_idexperiment=session['exp_id']).first()
        
261
        exp = experiment.query.filter_by(idexperiment=session['exp_id']).first()
262
        
263
264
        session['randomization'] = exp.randomization
        session['embody'] = exp.embody_enabled
265
266
267
268
269
270
271
272
273
274
    
        if mediatype:
            session['type'] = mediatype.type
        else:
            flash('No pages or mediatype set for experiment')
            return redirect('/')

        #If participant has done just the registration redirect to the first page of the experiment        
        if participant.answer_counter == 0:
            #flash("Ei vastauksia ohjataan ekalle sivulle")
275
            return redirect( url_for('task.task', page_num=1))
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
        
        
        redirect_to_page = participant.answer_counter + 1
        
        #flash("redirect to page:")
        #flash(redirect_to_page)

        experiment_page_count = db.session.query(page).filter_by(experiment_idexperiment=session['exp_id']).count()
        
        #If participant has ansvered all pages allready redirect to task completed page
        if experiment_page_count == participant.answer_counter:
            
            return redirect( url_for('task.completed'))
        
        return redirect( url_for('task.task', page_num=redirect_to_page))
        
    return render_template('continue_task.html', exp_id=exp_id, form=form)


@task_blueprint.route('/quit')
def quit():
    
    user_id = session['user']
    session.pop('user', None)
    session.pop('exp_id', None)    
    session.pop('agree', None)
    session.pop('answer_set', None)
    session.pop('type', None)
    
    return render_template('quit_task.html', user_id=user_id)


# TODO: removable?
@task_blueprint.route('/create')
def create():
    return render_template('create_task.html')