views.py 11.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25



import math
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
26
from app.forms import Answers, TaskForm, ContinueTaskForm, StringForm
27
28
29
30
31
32
33

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


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

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

47
    return randomized_page
48
49
50
51
52
53
54


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'''

55
    page_idpage = session['current_idpage'] if session['randomization'] == 'Off' else randomized_page_id
56
57
58
59
60
    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()


61
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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()
        for key, value in data.items():
            print(key)
            print(value)

    # 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'])
114
def task_answer(page_num):
115
    '''Save slider answers to database'''
116

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

121
    if form.validate():
122
123
124
        #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        
125

126
        if session['randomization'] == 'On':
127
128
            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()
129
        else:
130
131
132
            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:
133
            update_answer_set()
134
135
136
        
            data = request.form.to_dict()
            for key, value in data.items():
137
                add_slider_answer(key, value, randomized_page_id)
138
139
140
141
142
143

        else:
            flash("Page has been answered already. Answers discarded")
        
        page_num=pages.next_num
        
144
145
146
147
148
149
150
151
152
        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):

153
154
155
156
157
158
159
160
    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('/')


161
162
163
164
165
166
167
168
    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)
169
    page_id = pages.items[0].idpage
170
171
172
173
174
175
176
177
    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':
178
179
        randomized_page_id = get_randomized_page(page_id).randomized_idpage
        randomized_stimulus = page.query.filter_by(idpage=randomized_page_id).first()
180
        
181
182
183
    for p in pages.items:
        session['current_idpage'] = p.idpage

184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
    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()
204

205
    return render_template(
206
207
208
209
210
211
212
213
214
215
216
        '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
        )
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243


@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')
244
            return redirect(url_for('task.continue_task', exp_id=exp_id))        
245
246
247
248
249
250
251
252
253
        
        #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()
        
254
        exp = experiment.query.filter_by(idexperiment=session['exp_id']).first()
255
        
256
257
        session['randomization'] = exp.randomization
        session['embody'] = exp.embody_enabled
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
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
    
        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")
            return redirect( url_for('task', page_num=1))
        
        
        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')