routes.py 13.5 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


import csv
import os
import random
import secrets
from datetime import datetime

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

from sqlalchemy import and_
from flask_login import current_user, login_user, logout_user, login_required
from flask_babel import Babel, _, lazy_gettext as _l

from app import app, db, babel
Timo Heikkilä's avatar
Timo Heikkilä committed
25
26
27
28
from app.models import background_question, experiment
from app.models import background_question_answer
from app.models import page, question
from app.models import background_question_option
Timo Heikkilä's avatar
Timo Heikkilä committed
29
from app.models import answer_set, answer, forced_id
Timo Heikkilä's avatar
Timo Heikkilä committed
30
from app.models import user, trial_randomization
31
from app.forms import LoginForm, RegisterForm, StartWithIdForm
Timo Heikkilä's avatar
Timo Heikkilä committed
32
33
34
35
36
37
38
39

#Stimuli upload folder setting
APP_ROOT = os.path.dirname(os.path.abspath(__file__))

@app.route('/')
@app.route('/index')
def index():
    experiments = experiment.query.all()
Timo Heikkilä's avatar
Timo Heikkilä committed
40
41
42
43
    
    if session:
        flash("")
    else:
Timo Heikkilä's avatar
Timo Heikkilä committed
44
45
        #flash("sessio ei voimassa")
        session['language'] = "English"
Timo Heikkilä's avatar
Timo Heikkilä committed
46
    
Timo Heikkilä's avatar
Timo Heikkilä committed
47
48
49
50
51
52
    return render_template('index.html', title='Home', experiments=experiments)


@app.route('/consent')
def consent():
    exp_id = request.args.get('exp_id', None)
Timo Heikkilä's avatar
Timo Heikkilä committed
53
54
    experiment_info = experiment.query.filter_by(idexperiment=exp_id).first()
    
55
56
57
58
59
    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>')
Timo Heikkilä's avatar
Timo Heikkilä committed
60
61
62
63

    if experiment_info.use_forced_id == 'On':
        return redirect(url_for('begin_with_id', exp_id=exp_id))

64
65
66
67
68
    return render_template('consent.html', 
                            exp_id=exp_id, 
                            experiment_info=experiment_info, 
                            instruction_paragraphs=instruction_paragraphs, 
                            consent_paragraphs=consent_paragraphs)
Timo Heikkilä's avatar
Timo Heikkilä committed
69
70


Timo Heikkilä's avatar
Timo Heikkilä committed
71
72
73
@app.route('/set_language')
def set_language():
    session['language'] = request.args.get('language', None)
Timo Heikkilä's avatar
Timo Heikkilä committed
74
75
    lang = request.args.get('lang', None)
    return redirect(url_for('index', lang=lang))
Timo Heikkilä's avatar
Timo Heikkilä committed
76

77

Timo Heikkilä's avatar
Timo Heikkilä committed
78
79
80
81
82
83
@app.route('/remove_language')
def remove_language():
    experiments = experiment.query.all()
    return render_template('index.html', title='Home', experiments=experiments)


Timo Heikkilä's avatar
Timo Heikkilä committed
84
85
@app.route('/session')
def participant_session():
86
    '''Set up session variables'''
87

Timo Heikkilä's avatar
Timo Heikkilä committed
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
    #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 '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']
        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
106

Timo Heikkilä's avatar
Timo Heikkilä committed
107
    #create answer set for the participant in the database
Timo Heikkilä's avatar
Timo Heikkilä committed
108
109
    the_time = datetime.now()
    the_time = the_time.replace(microsecond=0)
110
111
112
113
114
115
    participant_answer_set = answer_set(experiment_idexperiment=session['exp_id'],
                                        session=session['user'], 
                                        agreement = session['agree'], 
                                        answer_counter = '0', 
                                        registration_time=the_time, 
                                        last_answer_time=the_time)
Timo Heikkilä's avatar
Timo Heikkilä committed
116
117
    db.session.add(participant_answer_set)
    db.session.commit()
118
119
120

    # Set session status variables
    exp_status = experiment.query.filter_by(idexperiment=session['exp_id']).first()
Timo Heikkilä's avatar
Timo Heikkilä committed
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
    
    #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()
        original_id_order_list = [(int(o.idpage)) for o in experiment_pages]
        
        #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()
        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'])
            db.session.add(random_page)
            db.session.commit()
    
    if exp_status.randomization == "Off":
        session['randomization'] = "Off"

153
154
155
156
157
    if exp_status.embody_enabled:
        session['embody'] = True
    else:
        session['embody'] = False
    
Timo Heikkilä's avatar
Timo Heikkilä committed
158
159
160
161
    
    #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
162
163
164
165



    # TODO: this is unnecessary if experiment contains multiple stimulus types
Timo Heikkilä's avatar
Timo Heikkilä committed
166
167
168
169
170
171
172
173
    #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:
        flash('No pages or mediatype set for experiment')
        return redirect('/')
174

Timo Heikkilä's avatar
Timo Heikkilä committed
175
    
176
    # Redirect user to register page
Timo Heikkilä's avatar
Timo Heikkilä committed
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
    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
    
 
    form.questions1 = questions_and_options
    
    if request.method == 'POST'and form.validate():
    
        data = request.form.to_dict()
        for key, value in data.items():

            
            #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)
            db.session.add(participant_background_question_answers)
            db.session.commit()

        return redirect('/instructions')
   
    
    return render_template('register.html', form=form)



@app.route('/begin_with_id', methods=['GET', 'POST'])
def begin_with_id():
224
225
    '''Begin experiment with experiment ID. GET -method returns login page for starting the 
    experiment and POST -method verifys users ID before starting new experiment'''
Timo Heikkilä's avatar
Timo Heikkilä committed
226
227
228
    
    exp_id = request.args.get('exp_id', None)
    form = StartWithIdForm()
Timo Heikkilä's avatar
Timo Heikkilä committed
229
    experiment_info = experiment.query.filter_by(idexperiment=exp_id).first()
230
231
232
233
234
235
    
    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>')
Timo Heikkilä's avatar
Timo Heikkilä committed
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258

    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()
        
        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:
        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))        

            else:
                #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
259
                return render_template('consent.html', exp_id=exp_id, experiment_info=experiment_info, instruction_paragraphs=instruction_paragraphs, consent_paragraphs=consent_paragraphs)
Timo Heikkilä's avatar
Timo Heikkilä committed
260
261
262
263
264
265
266
267
268
269
270
        
    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()
Timo Heikkilä's avatar
Timo Heikkilä committed
271
272
273
274
275
276
277

    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()
        if participant is not None:
            flash('ID already in use')
Timo Heikkilä's avatar
Timo Heikkilä committed
278
            return redirect(url_for('admin_dryrun', exp_id=exp_id))        
Timo Heikkilä's avatar
Timo Heikkilä committed
279
280
281
282
283
        
        #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
            session['begin_with_id'] = form.participant_id.data
Timo Heikkilä's avatar
Timo Heikkilä committed
284
            return render_template('consent.html', exp_id=exp_id, experiment_info=experiment_info)
Timo Heikkilä's avatar
Timo Heikkilä committed
285
        
Timo Heikkilä's avatar
Timo Heikkilä committed
286
287
    return render_template('admin_dryrun.html', exp_id=exp_id, form=form)

Timo Heikkilä's avatar
Timo Heikkilä committed
288
289
290
291
292

@app.route('/instructions')
def instructions():
    
    participant_id = session['user']
293
294
295
296
297
298
    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)
Timo Heikkilä's avatar
Timo Heikkilä committed
299
300
301
302
303


@app.route('/researcher_login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
Timo Heikkilä's avatar
Timo Heikkilä committed
304
        #flash("allready logged in")
Timo Heikkilä's avatar
Timo Heikkilä committed
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
        return redirect(url_for('index'))
    form = LoginForm()
    if form.validate_on_submit():
        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)    
        return redirect(url_for('index'))
    
#        flash('Login requested for user {}, remember_me={}'.format(
#            form.username.data, form.remember_me.data))
#        return redirect('/index')
    return render_template('researcher_login.html', title='Sign In', form=form)


@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('index'))


327
328
@app.route('/view_research_notification')
def view_research_notification():
Timo Heikkilä's avatar
Timo Heikkilä committed
329
330
    
    exp_id = request.args.get('exp_id', None)
331
332
    image = experiment.query.filter_by(idexperiment=exp_id).first()
    research_notification_filename = image.research_notification_filename
Timo Heikkilä's avatar
Timo Heikkilä committed
333
    
334
    return render_template('view_research_notification.html', research_notification_filename=research_notification_filename)
Timo Heikkilä's avatar
Timo Heikkilä committed
335
336


337
338
339
@app.route('/download_csv')
@login_required
def download_csv():
Timo Heikkilä's avatar
Timo Heikkilä committed
340

341
    exp_id = request.args.get('exp_id', None)
Timo Heikkilä's avatar
Timo Heikkilä committed
342
343
    
    """
344
    with open('export_new.csv', 'w', newline='') as f:
Timo Heikkilä's avatar
Timo Heikkilä committed
345
        
346
        thewriter = csv.writer(f)
Timo Heikkilä's avatar
Timo Heikkilä committed
347
        
348
349
350
        thewriter.writerow(['1','2','3','4'])
        thewriter.writerow(['a','b','c','d'])
    """
Timo Heikkilä's avatar
Timo Heikkilä committed
351
    
352
    return redirect(url_for('experiment.statistics', exp_id=exp_id))
Timo Heikkilä's avatar
Timo Heikkilä committed
353
354


355
@app.route('/researcher_info')
Timo Heikkilä's avatar
Timo Heikkilä committed
356
@login_required
357
358
def researcher_info():
    return render_template('researcher_info.html')
Timo Heikkilä's avatar
Timo Heikkilä committed
359

Timo Heikkilä's avatar
Timo Heikkilä committed
360

361
# EOF