diff --git a/.gitignore b/.gitignore index 32b42d4e9754651c3b45e7b605fde3b9132e0ee2..876e85fbed66158652992281c4869c87a9daf489 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ scrap_script.py config.py *.pyc *.db +/embody diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..f2923ec477fc5d74d21784e5062bd3ef1da50fdc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "embody"] + path = embody + url = https://version.aalto.fi/gitlab/eglerean/embody.git diff --git a/app/__init__.py b/app/__init__.py index 4051a1c904b83abfa146777bcc5b2f672c252e70..aefa4b3e1a5dc62ae1e1d6b53b0b8232d56ee8bc 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,16 +1,18 @@ -from flask import Flask + +import pymysql + +from flask import Flask, request, session, flash + from flask_bootstrap import Bootstrap -from config import Config from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from flask_login import LoginManager from flask_babel import Babel -from flask import request -from flask import session -from flask import flash -import pymysql + +from config import Config app = Flask(__name__) + #app.config['BABEL_DEFAULT_LOCALE'] = 'fin' #app.config['BABEL_TRANSLATION_DIRECTORIES'] ='C:/Users/Timo/git/pet-rating/app/translations' babel = Babel(app) @@ -38,13 +40,10 @@ def get_locale(): if session['lang'] == 'zh': session['language'] = 'Chinese' - - return session.get('lang', 'en') - """ @babel.localeselector def get_locale(): @@ -73,6 +72,14 @@ migrate = Migrate(app, db) login = LoginManager(app) login.login_view = 'login' +# Register blueprints +from .task.views import task_blueprint +from .experiment.views import experiment_blueprint +from .create.views import create_blueprint + +app.register_blueprint(task_blueprint) +app.register_blueprint(experiment_blueprint) +app.register_blueprint(create_blueprint) app.secret_key = 'random string' """app.secret_key = os.urandom(24)""" diff --git a/app/templates/create_experiment.html b/app/create/templates/create_experiment.html similarity index 100% rename from app/templates/create_experiment.html rename to app/create/templates/create_experiment.html diff --git a/app/templates/create_experiment_bgquestions.html b/app/create/templates/create_experiment_bgquestions.html similarity index 100% rename from app/templates/create_experiment_bgquestions.html rename to app/create/templates/create_experiment_bgquestions.html diff --git a/app/templates/create_experiment_questions.html b/app/create/templates/create_experiment_questions.html similarity index 100% rename from app/templates/create_experiment_questions.html rename to app/create/templates/create_experiment_questions.html diff --git a/app/templates/create_experiment_upload_stimuli.html b/app/create/templates/create_experiment_upload_stimuli.html similarity index 99% rename from app/templates/create_experiment_upload_stimuli.html rename to app/create/templates/create_experiment_upload_stimuli.html index 979ed4a6d0a939d08bea1cc8fbf4d488ad7ff0a7..9a7d9e3af8b02d44d7afc50c79784ca63bc6346b 100644 --- a/app/templates/create_experiment_upload_stimuli.html +++ b/app/create/templates/create_experiment_upload_stimuli.html @@ -42,6 +42,7 @@ Audio </label> </div> + </fieldset> <div class="form-group"> diff --git a/app/create/views.py b/app/create/views.py new file mode 100644 index 0000000000000000000000000000000000000000..bca9240ea44536d4b0f7d1e9d94e5370d293956e --- /dev/null +++ b/app/create/views.py @@ -0,0 +1,203 @@ +import os +from datetime import datetime + +from flask import ( + Flask, + render_template, + request, + session, + flash, + redirect, + url_for, + Blueprint +) + +from flask_login import login_required + +from app.routes import APP_ROOT +from app import app, db +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 +from app.models import answer_set, answer, forced_id +from app.models import user, trial_randomization +from app.forms import ( + CreateExperimentForm, CreateBackgroundQuestionForm, + CreateQuestionForm, UploadStimuliForm +) + +create_blueprint = Blueprint("create", __name__, + template_folder='templates', + #static_folder='static', + url_prefix='/create') + +@create_blueprint.route('/experiment', methods=['GET', 'POST']) +@login_required +def create_experiment(): + + form = CreateExperimentForm(request.form) + + if request.method == 'POST' and form.validate(): + + the_time = datetime.now() + the_time = the_time.replace(microsecond=0) + + new_exp = experiment(name=request.form['name'], instruction=request.form['instruction'], language=request.form['language'], status='Hidden', randomization='Off', single_sentence_instruction=request.form['single_sentence_instruction'], short_instruction=request.form['short_instruction'], creator_name=request.form['creator_name'], is_archived='False', creation_time=the_time, stimulus_size='7', consent_text=request.form['consent_text'], use_forced_id='Off') + db.session.add(new_exp) + db.session.commit() + exp_id = new_exp.idexperiment + + #data = request.form.to_dict() + #for key, value in data.items(): + #tähän db insertit + + #flash(key) + #flash(value) + #flash('{}'.format(form.name.data)) + + #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(url_for('create.experiment_bgquestions', exp_id=exp_id)) + + return render_template('create_experiment.html', form=form) + + +@create_blueprint.route('/experiment_bgquestions', methods=['GET', 'POST']) +@login_required +def experiment_bgquestions(): + + exp_id = request.args.get('exp_id', None) + form = CreateBackgroundQuestionForm(request.form) + + if request.method == 'POST' and form.validate(): + str = form.bg_questions_and_options.data + + #Split the form data into a list that separates questions followed by the corresponding options + str_list = str.split('/n') + + #Iterate through the questions and options list + for a in range(len(str_list)): + + #Split the list cells further into questions and options + list = str_list[a].split(';') + + #Input the first item of the list as a question in db and the items followed by that as options for that question + for x in range(len(list)): + + if x == 0: + add_bgquestion = background_question(background_question=list[x], experiment_idexperiment=exp_id) + db.session.add(add_bgquestion) + db.session.commit() + + else: + add_bgq_option = background_question_option(background_question_idbackground_question=add_bgquestion.idbackground_question, option=list[x]) + db.session.add(add_bgq_option) + db.session.commit() + + return redirect(url_for('create.experiment_questions', exp_id=exp_id)) + + return render_template('create_experiment_bgquestions.html', form=form, exp_id=exp_id) + + +@create_blueprint.route('/experiment_questions', methods=['GET', 'POST']) +@login_required +def experiment_questions(): + + # TODO: add embody -type here + + exp_id = request.args.get('exp_id', None) + form = CreateQuestionForm(request.form) + + if request.method == 'POST' and form.validate(): + + str = form.questions_and_options.data + str_list = str.split('/n') + + for a in range(len(str_list)): + + list = str_list[a].split(';') + + #If there are the wrong amount of values for any of the the slider input values + #redirect back to the form + if len(list) != 3: + + flash("Error Each slider must have 3 parameters separated by ; Some slider has:") + flash(len(list)) + + return redirect(url_for('create.experiment_questions', exp_id=exp_id)) + + #If all the slider inputs were of length 3 items + #we can input them to db + for a in range(len(str_list)): + + list = str_list[a].split(';') + + add_question = question(experiment_idexperiment=exp_id, question=list[0], left=list[1], right=list[2]) + db.session.add(add_question) + db.session.commit() + + return redirect(url_for('create.experiment_upload_stimuli', exp_id=exp_id)) + + return render_template('create_experiment_questions.html', form=form) + + +@create_blueprint.route('/experiment_upload_stimuli', methods=['GET', 'POST']) +@login_required +def experiment_upload_stimuli(): + + exp_id = request.args.get('exp_id', None) + form = UploadStimuliForm(request.form) + + if request.method == 'POST' and form.validate(): + + #If stimulus type is text lets parse the information and insert it to database + if form.type.data == 'text': + string = form.text.data + str_list = string.split('/n') + + for a in range(len(str_list)): + add_text_stimulus = page(experiment_idexperiment=exp_id, type='text', text=str_list[a], media='none') + db.session.add(add_text_stimulus) + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + else: + #Upload stimuli into /static/experiment_stimuli/exp_id folder + #Create the pages for the stimuli by inserting experiment_id, stimulus type, text and names of the stimulus files (as a path to the folder) + + path = 'static/experiment_stimuli/' + str(exp_id) + target = os.path.join(APP_ROOT, path) + + if not os.path.isdir(target): + os.mkdir(target) + + #This returns a list of filenames: request.files.getlist("file") + for file in request.files.getlist("file"): + + #save files in the correct folder + filename = file.filename + destination = "/".join([target, filename]) + file.save(destination) + + #add pages to the db + db_path = path + str('/') + str(filename) + new_page = page(experiment_idexperiment=exp_id, type=form.type.data, media=db_path) + + db.session.add(new_page) + db.session.commit() + + #flash("Succes!") + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return redirect(url_for('create.experiment_upload_stimuli', exp_id=exp_id)) + + return render_template('create_experiment_upload_stimuli.html', form=form) + + +# EOF \ No newline at end of file diff --git a/app/experiment/__init__.py b/app/experiment/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/templates/edit_bg_question.html b/app/experiment/edit_bg_question.html similarity index 100% rename from app/templates/edit_bg_question.html rename to app/experiment/edit_bg_question.html diff --git a/app/templates/add_bg_question.html b/app/experiment/templates/add_bg_question.html similarity index 100% rename from app/templates/add_bg_question.html rename to app/experiment/templates/add_bg_question.html diff --git a/app/templates/add_questions.html b/app/experiment/templates/add_questions.html similarity index 100% rename from app/templates/add_questions.html rename to app/experiment/templates/add_questions.html diff --git a/app/templates/add_stimuli.html b/app/experiment/templates/add_stimuli.html similarity index 94% rename from app/templates/add_stimuli.html rename to app/experiment/templates/add_stimuli.html index 334ce1f1196c89369d75dded195ed2f8dcb935e3..113b8286f786b94250bd82da16f849130bbb3247 100644 --- a/app/templates/add_stimuli.html +++ b/app/experiment/templates/add_stimuli.html @@ -19,24 +19,15 @@ </div> <div class="custom-file"> <input type="file" class="custom-file-input" id="file" name="file" accept="audio/*,image/*, .mp4" multiple> + + <!-- TODO add hidden type field { stimulus_type } else this will be None!! --> + <label class="custom-file-label" for="upload_file">Choose file</label> </div> </div> {% endif %} - - - - - - - - - - - - <br> <button type="submit" class="btn btn-primary">Submit</button> <a class="btn btn-primary" href="{{ request.referrer }}" role="button">Cancel</a> diff --git a/app/templates/edit_experiment.html b/app/experiment/templates/edit_experiment.html similarity index 94% rename from app/templates/edit_experiment.html rename to app/experiment/templates/edit_experiment.html index daac53719a8f2fd972c0e23ce31b30ad88bb1686..72174f735dff65edb9cffcf33460c6d369b9e7d7 100644 --- a/app/templates/edit_experiment.html +++ b/app/experiment/templates/edit_experiment.html @@ -44,7 +44,7 @@ </div> <br> <button type="submit" class="btn btn-primary">Update</button> - <a class="btn btn-primary" href="{{ url_for('view_experiment', exp_id=exp_id) }}" role="button">Cancel</a> + <a class="btn btn-primary" href="{{ url_for('experiment.view', exp_id=exp_id) }}" role="button">Cancel</a> </form> diff --git a/app/templates/edit_question.html b/app/experiment/templates/edit_question.html similarity index 100% rename from app/templates/edit_question.html rename to app/experiment/templates/edit_question.html diff --git a/app/templates/edit_stimuli.html b/app/experiment/templates/edit_stimuli.html similarity index 100% rename from app/templates/edit_stimuli.html rename to app/experiment/templates/edit_stimuli.html diff --git a/app/templates/experiment_statistics.html b/app/experiment/templates/experiment_statistics.html similarity index 100% rename from app/templates/experiment_statistics.html rename to app/experiment/templates/experiment_statistics.html diff --git a/app/templates/remove_experiment.html b/app/experiment/templates/remove_experiment.html similarity index 88% rename from app/templates/remove_experiment.html rename to app/experiment/templates/remove_experiment.html index 03af89c36a56925b3d1cbdfe4fcbdaefb7666af8..fddf761d12484d48306dcea2aec106b1113b0bba 100644 --- a/app/templates/remove_experiment.html +++ b/app/experiment/templates/remove_experiment.html @@ -19,7 +19,7 @@ <input type="text" class="form-control" id="remove" name="remove" required> <br> <button type="submit" class="btn btn-primary">Remove</button> - <a class="btn btn-primary" href="{{ url_for('view_experiment', exp_id=exp_id) }}" role="button">Cancel</a> + <a class="btn btn-primary" href="{{ url_for('experiment.view', exp_id=exp_id) }}" role="button">Cancel</a> </form> diff --git a/app/templates/upload_research_notification.html b/app/experiment/templates/upload_research_notification.html similarity index 100% rename from app/templates/upload_research_notification.html rename to app/experiment/templates/upload_research_notification.html diff --git a/app/templates/view_experiment.html b/app/experiment/templates/view_experiment.html similarity index 85% rename from app/templates/view_experiment.html rename to app/experiment/templates/view_experiment.html index 5553b58ff654407d084c7dce6f9a49ff88968ec5..15744719537fb6828b582d9152da51819c300bf3 100644 --- a/app/templates/view_experiment.html +++ b/app/experiment/templates/view_experiment.html @@ -32,7 +32,7 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> - <a class="btn btn-primary" href="{{ url_for('remove_experiment', exp_id=exp.idexperiment) }}" role="button">Yes, remove</a> + <a class="btn btn-primary" href="{{ url_for('experiment.remove', exp_id=exp.idexperiment) }}" role="button">Yes, remove</a> </div> </div> </div> @@ -45,12 +45,12 @@ <td>{{ exp.status }}</td> <td> {% if exp.status == 'Hidden' %} - <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('publish_experiment', exp_id=exp.idexperiment) }}" role="button">Publish (visible)</a> - <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('private_experiment', exp_id=exp.idexperiment) }}" role="button">Publish (private)</a> + <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('experiment.publish', exp_id=exp.idexperiment) }}" role="button">Publish (visible)</a> + <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('experiment.private', exp_id=exp.idexperiment) }}" role="button">Publish (private)</a> </td> {% endif %} {% if exp.status != 'Hidden' %} - <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('hide_experiment', exp_id=exp.idexperiment) }}" role="button">Unpublish</a></td> + <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('experiment.hide', exp_id=exp.idexperiment) }}" role="button">Unpublish</a></td> {% endif %} </tr> @@ -81,10 +81,10 @@ <td>{{ exp.randomization }}</td> <td nowrap> {% if exp.randomization == 'Off' %} - <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('enable_randomization', exp_id=exp.idexperiment) }}" role="button">Enable</a></td> + <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('experiment.randomization', exp_id=exp.idexperiment, set='On') }}" role="button">Enable</a></td> {% endif %} {% if exp.randomization == 'On' %} - <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('disable_randomization', exp_id=exp.idexperiment) }}" role="button">Disable</a></td> + <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('experiment.randomization', exp_id=exp.idexperiment, set='Off') }}" role="button">Disable</a></td> {% endif %} </td> @@ -93,13 +93,13 @@ <td>{{ exp.use_forced_id }}</td> <td nowrap> {% if exp.use_forced_id == 'Off' %} - <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('enable_forced_id', exp_id=exp.idexperiment) }}" role="button">Enable</a> + <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('experiment.set_forced_id', exp_id=exp.idexperiment, set='On') }}" role="button">Enable</a> {% endif %} {% if exp.use_forced_id == 'On' %} - <a class="btn btn-primary w-50 btn-sm btn-info" href="{{ url_for('disable_forced_id', exp_id=exp.idexperiment) }}" role="button">Disable</a> - <a class="btn btn-primary w-50 btn-sm btn-info" href="{{ url_for('view_forced_id_list', exp_id=exp.idexperiment) }}" role="button">Check ID</a> + <a class="btn btn-primary w-50 btn-sm btn-info" href="{{ url_for('experiment.set_forced_id', exp_id=exp.idexperiment, set='Off') }}" role="button">Disable</a> + <a class="btn btn-primary w-50 btn-sm btn-info" href="{{ url_for('experiment.view_forced_id_list', exp_id=exp.idexperiment) }}" role="button">Check ID</a> {% endif %} </td> @@ -108,9 +108,9 @@ <td> Research bulletin:</td> <td> {{ exp.research_notification_filename }}</td> {% if exp.research_notification_filename %} - <td> <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('remove_research_notification', exp_id=exp.idexperiment) }}" role="button">Remove</a></td> + <td> <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('experiment.remove_research_notification', exp_id=exp.idexperiment) }}" role="button">Remove</a></td> {% else %} - <td> <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('upload_research_notification', exp_id=exp.idexperiment) }}" role="button">Upload</a></td> + <td> <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('experiment.upload_research_notification', exp_id=exp.idexperiment) }}" role="button">Upload</a></td> {% endif %} </tr> @@ -121,7 +121,7 @@ <td class="text-justify">{{ exp.instruction }}</td> <td nowrap> - <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('edit_experiment', exp_id=exp.idexperiment) }}" role="button">Edit properties</a> + <a class="btn btn-primary btn-block btn-sm btn-info" href="{{ url_for('experiment.edit', exp_id=exp.idexperiment) }}" role="button">Edit properties</a> </td> </tr> <tr> @@ -190,12 +190,12 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> - <a class="btn btn-primary" href="{{ url_for('remove_bg_question', idbackground_question=options[0], exp_id=exp_id) }}" role="button">Yes, remove</a> + <a class="btn btn-primary" href="{{ url_for('experiment.remove_bg_question', idbackground_question=options[0], exp_id=exp_id) }}" role="button">Yes, remove</a> </div> </div> </div> </div> - <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('edit_bg_question', idbackground_question=options[0]) }}" role="button">Edit</a> + <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('experiment.edit_bg_question', idbackground_question=options[0]) }}" role="button">Edit</a> </td> </tr> @@ -206,7 +206,7 @@ <table class="table"> <tbody> <td class="text-nowrap align-bottom text-right col-8"> - <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('add_bg_question', exp_id=exp_id) }}" role="button">Add more</a> + <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('experiment.add_bg_question', exp_id=exp_id) }}" role="button">Add more</a> </td> </tbody> </table> @@ -214,6 +214,9 @@ <h1 class="container mt-5 display-4 text-left"><br>Rating set:</h1> + +<hr> +TODO: add embody tool <hr> <br> {% for category in categories1 %} @@ -247,12 +250,12 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> - <a class="btn btn-primary" href="{{ url_for('remove_question', idquestion=category[0], exp_id=exp_id) }}" role="button">Yes, remove</a> + <a class="btn btn-primary" href="{{ url_for('experiment.remove_question', idquestion=category[0], exp_id=exp_id) }}" role="button">Yes, remove</a> </div> </div> </div> </div> - <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('edit_question', idquestion=category[0]) }}" role="button">Edit</a> + <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('experiment.edit_question', idquestion=category[0]) }}" role="button">Edit</a> </div> @@ -264,7 +267,7 @@ <table class="table"> <tbody> <td class="text-nowrap align-bottom text-right col-8"> - <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('add_questions', exp_id=exp_id) }}" role="button">Add more</a> + <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('experiment.add_questions', exp_id=exp_id) }}" role="button">Add more</a> </td> </tbody> </table> @@ -304,12 +307,12 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> - <a class="btn btn-primary" href="{{ url_for('remove_page', idpage=page.idpage, exp_id=exp_id) }}" role="button">Yes, remove</a> + <a class="btn btn-primary" href="{{ url_for('experiment.remove_stimuli', idpage=page.idpage, exp_id=exp_id) }}" role="button">Yes, remove</a> </div> </div> </div> </div> - <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('edit_stimuli', idpage=page.idpage, exp_id=exp_id) }}" role="button">Edit</a> + <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('experiment.edit_stimuli', idpage=page.idpage, exp_id=exp_id) }}" role="button">Edit</a> </td> </tr> {% endfor %} @@ -317,7 +320,7 @@ <table class="table"> <tbody> <td class="text-nowrap align-bottom text-right col-8"> - <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('add_stimuli', exp_id=exp_id, stimulus_type=mtype.type) }}" role="button">Add more</a> + <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('experiment.add_stimuli', exp_id=exp_id, stimulus_type=mtype.type) }}" role="button">Add more</a> </td> </tbody> </table> @@ -346,12 +349,12 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> - <a class="btn btn-primary" href="{{ url_for('remove_page', idpage=page.idpage, exp_id=exp_id) }}" role="button">Yes, remove</a> + <a class="btn btn-primary" href="{{ url_for('experiment.remove_stimuli', idpage=page.idpage, exp_id=exp_id) }}" role="button">Yes, remove</a> </div> </div> </div> </div> - <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('edit_stimuli', idpage=page.idpage, exp_id=exp_id) }}" role="button">Replace</a> + <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('experiment.edit_stimuli', idpage=page.idpage, exp_id=exp_id) }}" role="button">Replace</a> </td> </tr> @@ -360,7 +363,8 @@ <table class="table"> <tbody> <td class="text-nowrap align-bottom text-right col-8"> - <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('add_stimuli', exp_id=exp_id, stimulus_type=mtype.type) }}" role="button">Add more</a> + {{ mtype }} + <a class="btn btn-primary btn-sm btn-info" href="{{ url_for('experiment.add_stimuli', exp_id=exp_id, stimulus_type=mtype.type) }}" role="button">Add more</a> </td> </tbody> </table> diff --git a/app/templates/view_forced_id_list.html b/app/experiment/templates/view_forced_id_list.html similarity index 100% rename from app/templates/view_forced_id_list.html rename to app/experiment/templates/view_forced_id_list.html diff --git a/app/experiment/views.py b/app/experiment/views.py new file mode 100644 index 0000000000000000000000000000000000000000..360f7ec0b48c874045da12fa42b8d265d16734e5 --- /dev/null +++ b/app/experiment/views.py @@ -0,0 +1,953 @@ + + +import os +import secrets + +from flask import ( + Flask, + render_template, + request, + session, + flash, + redirect, + url_for, + Blueprint +) + +from wtforms import Form +from sqlalchemy import and_, update +from flask_login import login_required + +from app import app, db +from app.routes import APP_ROOT +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 +from app.models import answer_set, answer, forced_id +from app.models import user, trial_randomization +from app.forms import ( + CreateBackgroundQuestionForm, + CreateQuestionForm, UploadStimuliForm, EditBackgroundQuestionForm, + EditQuestionForm, EditExperimentForm, UploadResearchBulletinForm, + EditPageForm, RemoveExperimentForm, GenerateIdForm +) + +#Stimuli upload folder setting +#APP_ROOT = os.path.dirname(os.path.abspath(__file__)) + +experiment_blueprint = Blueprint("experiment", __name__, + template_folder='templates', + #static_folder='static', + url_prefix='/experiment') + + +@experiment_blueprint.route('/view') +@login_required +def view(): + + #crap:3lines + exp_id = request.args.get('exp_id', None) + media = page.query.filter_by(experiment_idexperiment=exp_id).all() + + ## TODO: mtype can be multiple! + ## is this even necessary anymore? + mtype = page.query.filter_by(experiment_idexperiment=exp_id).first() + + #experiment info + experiment_info = experiment.query.filter_by(idexperiment = exp_id).all() + + #background questions + questions_and_options = {} + questions = background_question.query.filter_by(experiment_idexperiment=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 + + questions1 = questions_and_options + + #sliderset + categories_and_scales = {} + categories = question.query.filter_by(experiment_idexperiment=exp_id).all() + + for cat in categories: + + scale_list = [(cat.left, cat.right)] + categories_and_scales[cat.idquestion, cat.question] = scale_list + + categories1 = categories_and_scales + + return render_template('view_experiment.html', exp_id=exp_id, media=media, mtype=mtype, experiment_info=experiment_info, categories1=categories1, questions1=questions1) + + + + + + + + + +# Experiment info: + +@experiment_blueprint.route('/remove', methods=['GET', 'POST']) +@login_required +def remove(): + + exp_id = request.args.get('exp_id', None) + exp_status = experiment.query.filter_by(idexperiment=exp_id).first() + + if exp_status.status != 'Hidden': + + flash("Experiment is public. Cannot modify structure.") + return redirect(url_for('experiment.view', exp_id=exp_id)) + + else: + + form = RemoveExperimentForm(request.form) + + if request.method == 'POST' and form.validate(): + + if form.remove.data == 'DELETE': + + #This removes all experiment data from the database! + + #Remove research bulletin if it exists + empty_filevariable = experiment.query.filter_by(idexperiment=exp_id).first() + + if empty_filevariable.research_notification_filename is not None: + target = os.path.join(APP_ROOT, empty_filevariable.research_notification_filename) + + if os.path.exists(target): + os.remove(target) + + #Tables + remove_forced_id = forced_id.query.filter_by(experiment_idexperiment=exp_id).all() + + for b in range(len(remove_forced_id)): + db.session.delete(remove_forced_id[b]) + db.session.commit() + + #background_question_option & background_question & background question answers: + remove_background_question = background_question.query.filter_by(experiment_idexperiment=exp_id).all() + + #cycle through all bg questions and delete their options + for a in range(len(remove_background_question)): + + remove_background_question_option = background_question_option.query.filter_by(background_question_idbackground_question=remove_background_question[a].idbackground_question).all() + + for b in range(len(remove_background_question_option)): + + db.session.delete(remove_background_question_option[b]) + db.session.commit() + + #Remove all background questions and all answers given to each bg question + for a in range(len(remove_background_question)): + + remove_background_question_answers = background_question_answer.query.filter_by(background_question_idbackground_question=remove_background_question[a].idbackground_question).all() + + for b in range(len(remove_background_question_answers)): + db.session.delete(remove_background_question_answers[b]) + db.session.commit() + + db.session.delete(remove_background_question[a]) + db.session.commit() + + #Remove all questions and answers + remove_question = question.query.filter_by(experiment_idexperiment=exp_id).all() + + for a in range(len(remove_question)): + + remove_question_answers = answer.query.filter_by(question_idquestion=remove_question[a].idquestion).all() + + for b in range(len(remove_question_answers)): + db.session.delete(remove_question_answers[b]) + db.session.commit() + + db.session.delete(remove_question[a]) + db.session.commit() + + #Remove all pages and datafiles + remove_pages = page.query.filter_by(experiment_idexperiment=exp_id).all() + + for a in range(len(remove_pages)): + if remove_pages[a].type == 'text': + db.session.delete(remove_pages[a]) + db.session.commit() + else: + target = os.path.join(APP_ROOT, remove_pages[a].media) + + if os.path.exists(target): + os.remove(target) + + #Now that the files are removed we can delete the page + db.session.delete(remove_pages[a]) + db.session.commit() + + #Remove all answer_sets and trial_randomization orders + remove_answer_set = answer_set.query.filter_by(experiment_idexperiment=exp_id).all() + + for a in range(len(remove_answer_set)): + remove_trial_randomizations = trial_randomization.query.filter_by(answer_set_idanswer_set=remove_answer_set[a].idanswer_set).all() + + for b in range(len(remove_trial_randomizations)): + db.session.delete(remove_trial_randomizations[b]) + db.session.commit() + + db.session.delete(remove_answer_set[a]) + db.session.commit() + + #Remove experiment table + remove_experiment = experiment.query.filter_by(idexperiment=exp_id).first() + db.session.delete(remove_experiment) + db.session.commit() + + flash("Experiment was removed from database!") + return redirect(url_for('index')) + + else: + flash("Experiment was not removed!") + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return render_template('remove_experiment.html', form=form, exp_id=exp_id) + + +@experiment_blueprint.route('/publish') +@login_required +def publish(): + exp_id = request.args.get('exp_id', None) + publish_experiment = experiment.query.filter_by(idexperiment = exp_id).first() + publish_experiment.status = 'Public' + flash("Changed status to Public") + db.session.commit() + return redirect(url_for('experiment.view', exp_id=exp_id)) + + +@experiment_blueprint.route('/hide') +@login_required +def hide(): + exp_id = request.args.get('exp_id', None) + hide_experiment = experiment.query.filter_by(idexperiment = exp_id).first() + hide_experiment.status = 'Hidden' + flash("Changed status to Hidden") + db.session.commit() + return redirect(url_for('experiment.view', exp_id=exp_id)) + + +@experiment_blueprint.route('/private') +@login_required +def private(): + exp_id = request.args.get('exp_id', None) + private_experiment = experiment.query.filter_by(idexperiment = exp_id).first() + private_experiment.status = 'Private' + flash("Changed status to Private") + db.session.commit() + return redirect(url_for('experiment.view', exp_id=exp_id)) + + +@experiment_blueprint.route('/randomization') +@login_required +def randomization(): + exp_id = request.args.get('exp_id', None) + status = request.args.get('set') + + if status == 'On': + flash("Enabled trial randomization") + elif status == 'Off': + flash("Disabled trial randomization") + + experiment.query.filter_by(idexperiment = exp_id).first().randomization = status + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + +@experiment_blueprint.route('/set_forced_id') +@login_required +def set_forced_id(): + '''By using forced ID login subjects can only participate to a rating task + by logging in with a pregenerated ID.''' + + exp_id = request.args.get('exp_id', None) + status = request.args.get('set') + + if status == 'On': + flash("Enabled forced ID login") + elif status == 'Off': + flash("Disabled forced ID login") + + experiment.query.filter_by(idexperiment = exp_id).first().use_forced_id = status + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + +@experiment_blueprint.route('/view_forced_id_list', methods=['GET', 'POST']) +@login_required +def view_forced_id_list(): + '''Forced ID login for participants''' + + exp_id = request.args.get('exp_id', None) + id_list = forced_id.query.filter_by(experiment_idexperiment=exp_id).all() + form = GenerateIdForm(request.form) + + if request.method == 'POST' and form.validate(): + + for i in range(int(request.form['number'])): + random_id = str(request.form['string']) + str(secrets.token_hex(3)) + check_answer_set = answer_set.query.filter_by(session=random_id).first() + check_forced_id = forced_id.query.filter_by(pregenerated_id=random_id).first() + + #here we check if the generated id is found from given answers from the whole database in answer_set table + #or from forced_id table. If so another id is generated instead to avoid a duplicate + if check_answer_set is not None or check_forced_id is not None: + + #flash("ID already existed; generated a new one") + random_id = secrets.token_hex(3) + check_answer_set = answer_set.query.filter_by(session=random_id).first() + check_forced_id = forced_id.query.filter_by(pregenerated_id=random_id).first() + + input_id = forced_id(experiment_idexperiment=exp_id, pregenerated_id=random_id) + db.session.add(input_id) + db.session.commit() + + return redirect(url_for('view_forced_id_list', exp_id=exp_id)) + + return render_template('view_forced_id_list.html', exp_id=exp_id, id_list=id_list) + + +@experiment_blueprint.route('/upload_research_notification', methods=['GET', 'POST']) +@login_required +def upload_research_notification(): + '''Upload research bulletin''' + + exp_id = request.args.get('exp_id', None) + form = UploadResearchBulletinForm(request.form) + + if request.method == 'POST': + path = 'static/experiment_stimuli/' + str(exp_id) + target = os.path.join(APP_ROOT, path) + + if not os.path.isdir(target): + os.mkdir(target) + + #This returns a list of filenames: request.files.getlist("file") + for file in request.files.getlist("file"): + #save files in the correct folder + filename = file.filename + destination = "/".join([target, filename]) + file.save(destination) + + #add pages to the db + db_path = path + str('/') + str(filename) + bulletin = experiment.query.filter_by(idexperiment=exp_id).first() + bulletin.research_notification_filename = db_path + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return render_template('upload_research_notification.html', exp_id=exp_id, form=form) + + +@experiment_blueprint.route('/remove_research_notification') +@login_required +def remove_research_notification(): + '''Remove research bulletin''' + + exp_id = request.args.get('exp_id', None) + empty_filevariable = experiment.query.filter_by(idexperiment=exp_id).first() + target = os.path.join(APP_ROOT, empty_filevariable.research_notification_filename) + + if os.path.exists(target): + os.remove(target) + + empty_filevariable.research_notification_filename = None + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + +@experiment_blueprint.route('/edit', methods=['GET', 'POST']) +@login_required +def edit(): + '''Edit experiment details''' + + exp_id = request.args.get('exp_id', None) + current_experiment = experiment.query.filter_by(idexperiment=exp_id).first() + + form = EditExperimentForm(request.form, obj=current_experiment) + form.language.default = current_experiment.language + + if request.method == 'POST' and form.validate(): + + form.populate_obj(current_experiment) + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return render_template('edit_experiment.html', form=form, exp_id=exp_id) + + + + + +# Background questions: + +@experiment_blueprint.route('/add_bg_question', methods=['GET', 'POST']) +@login_required +def add_bg_question(): + + exp_id = request.args.get('exp_id', None) + exp_status = experiment.query.filter_by(idexperiment=exp_id).first() + + if exp_status.status != 'Hidden': + + flash("Experiment is public. Cannot modify structure.") + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + else: + + form = CreateBackgroundQuestionForm(request.form) + + if request.method == 'POST' and form.validate(): + + str = form.bg_questions_and_options.data + + #Split the form data into a list that separates questions followed by the corresponding options + str_list = str.split('/n') + + #Iterate through the questions and options list + for a in range(len(str_list)): + + #Split the list cells further into questions and options + list = str_list[a].split(';') + + #Input the first item of the list as a question in db and the items followed by that as options for that question + for x in range(len(list)): + + if x == 0: + #flash("Kysymys") + #flash(list[x]) + add_bgquestion = background_question(background_question=list[x], experiment_idexperiment=exp_id) + db.session.add(add_bgquestion) + db.session.commit() + + else: + #flash("optio") + #flash(list[x]) + add_bgq_option = background_question_option(background_question_idbackground_question=add_bgquestion.idbackground_question, option=list[x]) + db.session.add(add_bgq_option) + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return render_template('add_bg_question.html', form=form) + + +@experiment_blueprint.route('/edit_bg_question', methods=['GET', 'POST']) +@login_required +def edit_bg_question(): + + bg_question_id = request.args.get('idbackground_question', None) + + #Search for the right question and for the right options. Form a string of those separated with ";" and insert the + #formed string into the edit form + current_bg_question = background_question.query.filter_by(idbackground_question=bg_question_id).first() + exp_id=current_bg_question.experiment_idexperiment + question_string = current_bg_question.background_question + options = background_question_option.query.filter_by(background_question_idbackground_question=bg_question_id).all() + + for o in range(len(options)): + + question_string = str(question_string) + str("; ") + str(options[o].option) + + form = EditBackgroundQuestionForm(request.form) + form.bg_questions_and_options.data = question_string + + #After user chooses to update the question and options lets replace the old question and options with the ones from the form + if request.method == 'POST' and form.validate(): + + + #Explode the string with new values from the form + form_values = form.new_values.data + form_values_list = form_values.split(';') + + #Check and remove possible whitespaces from string beginnings with lstrip + for x in range(len(form_values_list)): + + form_values_list[x] = form_values_list[x].lstrip() + + #Cycle through strings and update db + for x in range(len(form_values_list)): + + #Replace question and update the object to database + if x == 0: + + #flash("delete kys:") + #flash(current_bg_question.background_question) + #flash("insert kys:") + current_bg_question.background_question = form_values_list[x] + #flash(current_bg_question.background_question) + #flash(current_bg_question.idbackground_question) + #flash(current_bg_question.experiment_idexperiment) + + db.session.commit() + + #Delete old options from db + for o in options: + + db.session.delete(o) + db.session.commit() + + #Insert new options to db + else: + + #flash("insert opt:") + #flash(form_values_list[x]) + new_option = background_question_option(background_question_idbackground_question=current_bg_question.idbackground_question, option=form_values_list[x]) + db.session.add(new_option) + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return render_template('edit_bg_question.html', form=form, exp_id=exp_id) + + +@experiment_blueprint.route('/remove_bg_question') +@login_required +def remove_bg_question(): + + exp_id = request.args.get('exp_id', None) + exp_status = experiment.query.filter_by(idexperiment=exp_id).first() + + if exp_status.status != 'Hidden': + + flash("Experiment is public. Cannot modify structure.") + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + else: + + remove_id = request.args.get('idbackground_question', None) + remove_options = background_question_option.query.filter_by(background_question_idbackground_question=remove_id).all() + + for a in range(len(remove_options)): + + #flash(remove_options[a].idbackground_question_option) + + db.session.delete(remove_options[a]) + db.session.commit() + + + remove_question = background_question.query.filter_by(idbackground_question=remove_id).first() + + db.session.delete(remove_question) + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + + + + + +# Rating set: + +@experiment_blueprint.route('/add_questions', methods=['GET', 'POST']) +@login_required +def add_questions(): + + exp_id = request.args.get('exp_id', None) + exp_status = experiment.query.filter_by(idexperiment=exp_id).first() + + if exp_status.status != 'Hidden': + + flash("Experiment is public. Cannot modify structure.") + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + else: + + form = CreateQuestionForm(request.form) + + if request.method == 'POST' and form.validate(): + + str = form.questions_and_options.data + str_list = str.split('/n') + + for a in range(len(str_list)): + + list = str_list[a].split(';') + + #If there are the right amount of values for the slider input values + if len(list) == 3: + + #flash("Question:") + #flash(list[0]) + #flash("Left:") + #flash(list[1]) + #flash("Right:") + #flash(list[2]) + + add_question = question(experiment_idexperiment=exp_id, question=list[0], left=list[1], right=list[2]) + db.session.add(add_question) + db.session.commit() + + #If slider has too many or too litlle parameters give an error and redirect back to input form + else: + flash("Error Each slider must have 3 parameters separated by ; Some slider has:") + flash(len(list)) + + return redirect(url_for('create.experiment_questions', exp_id=exp_id)) + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return render_template('add_questions.html', form=form) + + +@experiment_blueprint.route('/edit_question', methods=['GET', 'POST']) +@login_required +def edit_question(): + + question_id = request.args.get('idquestion', None) + current_question = question.query.filter_by(idquestion=question_id).first() + form = EditQuestionForm(request.form, obj=current_question) + + if request.method == 'POST' and form.validate(): + + form.populate_obj(current_question) + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=current_question.experiment_idexperiment)) + + return render_template('edit_question.html', form=form) + + +@experiment_blueprint.route('/remove_question') +@login_required +def remove_question(): + + exp_id = request.args.get('exp_id', None) + exp_status = experiment.query.filter_by(idexperiment=exp_id).first() + + if exp_status.status != 'Hidden': + flash("Experiment is public. Cannot modify structure.") + return redirect(url_for('experiment.view', exp_id=exp_id)) + + else: + + remove_id = request.args.get('idquestion', None) + remove_question = question.query.filter_by(idquestion=remove_id).first() + + db.session.delete(remove_question) + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + + + + +# Stimuli: + +@experiment_blueprint.route('/add_stimuli', methods=['GET', 'POST']) +@login_required +def add_stimuli(): + + exp_id = request.args.get('exp_id', None) + exp_status = experiment.query.filter_by(idexperiment=exp_id).first() + + if exp_status.status != 'Hidden': + flash("Experiment is public. Cannot modify structure.") + return redirect(url_for('experiment.view', exp_id=exp_id)) + else: + #If there are no pages set for the experiment lets reroute user to create experiment stimuli upload instead + + is_there_any_stimuli = page.query.filter_by(experiment_idexperiment = exp_id).first() + + if is_there_any_stimuli is None: + return redirect(url_for('create.experiment_upload_stimuli', exp_id=exp_id)) + + stimulus_type = request.args.get('stimulus_type', None) + form = UploadStimuliForm(request.form) + + if request.method == 'POST': + if stimulus_type == 'text': + + #flash("db insert text") + + string = form.text.data + str_list = string.split('/n') + + for a in range(len(str_list)): + + #flash("lisättiin:") + #flash(str_list[a]) + add_text_stimulus = page(experiment_idexperiment=exp_id, type='text', text=str_list[a], media='none') + db.session.add(add_text_stimulus) + db.session.commit() + + #flash("Succes!") + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + else: + #Upload stimuli into /static/experiment_stimuli/exp_id folder + #Create the pages for the stimuli by inserting experiment_id, stimulus type, text and names of the stimulus files (as a path to the folder) + path = 'static/experiment_stimuli/' + str(exp_id) + target = os.path.join(APP_ROOT, path) + + if not os.path.isdir(target): + os.mkdir(target) + #flash("make dir") + + #This returns a list of filenames: request.files.getlist("file") + + for file in request.files.getlist("file"): + + #save files in the correct folder + #flash(file.filename) + filename = file.filename + destination = "/".join([target, filename]) + #flash("destination") + #flash(destination) + file.save(destination) + + #add pages to the db + db_path = path + str('/') + str(filename) + + #flash("db path") + #flash(db_path) + + new_page = page(experiment_idexperiment=exp_id, type=form.type.data, media=db_path) + + db.session.add(new_page) + db.session.commit() + + #flash("Succes!") + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return render_template('add_stimuli.html', form=form, stimulus_type=stimulus_type) + + +@experiment_blueprint.route('/edit_stimuli', methods=['GET', 'POST']) +@login_required +def edit_stimuli(): + + exp_id = request.args.get('exp_id', None) + page_id = request.args.get('idpage', None) + edit_page = page.query.filter_by(idpage=page_id).first() + form = EditPageForm(request.form, obj=edit_page) + + if request.method == 'POST' and form.validate(): + + #If the stimulus type is not text, then the old stimulus file is deleted from os and replaced + if edit_page.type != 'text': + + #remove old file + target = os.path.join(APP_ROOT, edit_page.media) + #flash("Remove:") + #flash(target) + os.remove(target) + + #upload new file + + path = 'static/experiment_stimuli/' + str(exp_id) + target = os.path.join(APP_ROOT, path) + #flash(target) + + if not os.path.isdir(target): + os.mkdir(target) + #flash("make dir") + + #This returns a list of filenames: request.files.getlist("file") + + for file in request.files.getlist("file"): + #save files in the correct folder + #flash(file.filename) + filename = file.filename + destination = "/".join([target, filename]) + #flash("destination") + #flash(destination) + file.save(destination) + + #update db object + db_path = path + str('/') + str(filename) + + #flash("db path") + #flash(db_path) + + edit_page.media=db_path + + db.session.commit() + + #flash("Succes!") + + #If editing text stimulus no need for filehandling + else: + form.populate_obj(edit_page) + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return render_template('edit_stimuli.html', form=form, edit_page=edit_page) + + +@experiment_blueprint.route('/remove_stimuli') +@login_required +def remove_stimuli(): + + exp_id = request.args.get('exp_id', None) + exp_status = experiment.query.filter_by(idexperiment=exp_id).first() + + if exp_status.status != 'Hidden': + + flash("Experiment is public. Cannot modify structure.") + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + else: + + remove_id = request.args.get('idpage', None) + remove_page = page.query.filter_by(idpage=remove_id).first() + experiment_pages = page.query.filter_by(experiment_idexperiment=exp_id).all() + + #if stimulustype is text, the stimulus itself is text on the database, other stimulus types are real files + #on the server and need to be deleted + if remove_page.type != 'text': + + #helper variable + do_not_delete_file = 'False' + + #if the file to be deleted is in duplicate use of another page then we won't delete the file + for a in range(len(experiment_pages)): + if experiment_pages[a].media == remove_page.media and experiment_pages[a].idpage != remove_page.idpage: + do_not_delete_file = 'True' + + #If no other page is using the file then lets remove it + if do_not_delete_file == 'False': + target = os.path.join(APP_ROOT, remove_page.media) + os.remove(target) + + db.session.delete(remove_page) + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + if remove_page.type == 'text': + + db.session.delete(remove_page) + db.session.commit() + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + return redirect(url_for('experiment.view', exp_id=exp_id)) + + + +# Misc: + +@experiment_blueprint.route('/statistics') +@login_required +def statistics(): + + exp_id = request.args.get('exp_id', None) + + experiment_info = experiment.query.filter_by(idexperiment = exp_id).all() + participants = answer_set.query.filter_by(experiment_idexperiment= exp_id).all() + + + #Rating task headers + question_headers = question.query.filter_by(experiment_idexperiment=exp_id).all() + stimulus_headers = page.query.filter_by(experiment_idexperiment=exp_id).all() + + pages = page.query.filter_by(experiment_idexperiment=exp_id).all() + questions = question.query.filter_by(experiment_idexperiment=exp_id).all() + pages_and_questions = {} + + for p in pages: + + questions_list = [(p.idpage, a.idquestion) for a in questions] + pages_and_questions[p.idpage] = questions_list + + #List of answers per participant in format question Stimulus ID/Question ID + #those are in answer table as page_idpage and question_idquestion respectively + + + + """ + pages = page.query.filter_by(experiment_idexperiment=exp_id).all() + + participants_and_answers = {} + + #participants on kaikki expin osallistujat + for participant in participants: + + #kaikki yhden khn vastaukset ko experimentille koska answer_setin id matchaa answereiden kanssa + flash(participant.session) + for p in pages: + + answers = answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all() + #kaikki yhden participantin vastaukset pagelle + answers_for_page = answer.query.filter(and_(answer.answer_set_idanswer_set==participant.idanswer_set, answer.page_idpage==p.idpage)).all() + + for ans in answers: + if ans.page_idpage == p.idpage: + #flash(ans.page_idpage) + flash("X") + else: + flash("NA") + + #pages on kaikki experimentin paget + + for a in answers: + if p.idpage == a.page_idpage: + flash("match") + else: + flash("no match") + flash("participant:") + flash(participant.session) + flash("stimulus:") + flash(a.page_idpage) + flash("Kysymys") + flash(a.question_idquestion) + flash("vastaus:") + flash(a.answer) + + #answers_list = (a.idanswer, a.question_idquestion, a.answer_set_idanswer_set, a.answer, a.page_idpage) + #participants_and_answers[participant.session] = answers_list + """ + + participants_and_answers = {} + + for participant in participants: + + answers = answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all() + answers_list = [(a.idanswer, a.question_idquestion, a.answer_set_idanswer_set, a.answer, a.page_idpage) for a in answers] + participants_and_answers[participant.session] = answers_list + + #Background question answers + + bg_questions = background_question.query.filter_by(experiment_idexperiment=exp_id).all() + bg_answers_for_participants = {} + + for participant in participants: + + bg_answers = background_question_answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all() + bg_answers_list = [(a.answer) for a in bg_answers] + bg_answers_for_participants[participant.session] = bg_answers_list + + #started and finished ratings counters + started_ratings = answer_set.query.filter_by(experiment_idexperiment=exp_id).count() + experiment_page_count = page.query.filter_by(experiment_idexperiment=exp_id).count() + finished_ratings = answer_set.query.filter(and_(answer_set.answer_counter==experiment_page_count, answer_set.experiment_idexperiment==exp_id)).count() + + return render_template('experiment_statistics.html', experiment_info=experiment_info, participants_and_answers=participants_and_answers, pages_and_questions=pages_and_questions, bg_questions=bg_questions, bg_answers_for_participants=bg_answers_for_participants, started_ratings=started_ratings, finished_ratings=finished_ratings, question_headers=question_headers, stimulus_headers=stimulus_headers) + + diff --git a/app/routes.py b/app/routes.py index 5b6bf45eddc4b97f0b7003384d87827567a9fb10..faec69b7a0452a30ddc09707b54de03d711b9e76 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,69 +1,46 @@ -from app import app, db -from flask import render_template, request + + +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 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 from app.models import answer_set, answer, forced_id -from flask import session -from app.forms import LoginForm, RegisterForm -from flask import flash, redirect -from flask import url_for -from wtforms_sqlalchemy.fields import QuerySelectField -from app.forms import Answers, Questions -from flask_bootstrap import Bootstrap -from flask_sqlalchemy import SQLAlchemy, BaseQuery -from app.forms import BackgroundQuestionForm -from wtforms import Form, TextField, TextAreaField, validators, StringField, SubmitField -from app.forms import TestForm, TestForm1, TestForm2, TaskForm -from collections import OrderedDict -from sqlalchemy import func, desc -from app.forms import ContinueTaskForm -from sqlalchemy import and_ from app.models import user, trial_randomization -from flask_login import current_user, login_user -from flask_login import logout_user -from flask_login import login_required -from sqlalchemy import update -from app.forms import StartWithIdForm -import secrets -from app.forms import CreateExperimentForm, CreateBackgroundQuestionForm, CreateQuestionForm, UploadStimuliForm, EditBackgroundQuestionForm, EditQuestionForm, EditExperimentForm, UploadResearchBulletinForm -from app.forms import EditPageForm, RemoveExperimentForm -import os -import random -from flask import Flask, make_response -import pyexcel as pe -import io -from io import BytesIO -import csv -from flask import send_file -from flask import make_response -from flask_babel import Babel -from app import babel -from datetime import datetime -from app.forms import GenerateIdForm -import math -from flask_babel import _ -from flask_babel import lazy_gettext as _l +from app.forms import LoginForm, RegisterForm, StartWithIdForm #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" @@ -73,7 +50,6 @@ def index(): @app.route('/consent') 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) @@ -81,86 +57,68 @@ def consent(): 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') def set_language(): - session['language'] = request.args.get('language', None) - lang = request.args.get('lang', None) - - return redirect(url_for('index', lang=lang)) + @app.route('/remove_language') def remove_language(): - - experiments = experiment.query.all() - - return render_template('index.html', title='Home', experiments=experiments) - - - @app.route('/session') def participant_session(): + # TODO: too long method? + #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: - #flash("ID already existed; generated a new one") random_id = secrets.token_hex(3) check_id = answer_set.query.filter_by(session=random_id).first() - - session['user'] = random_id - #create answer set for the participant in the database the_time = datetime.now() the_time = the_time.replace(microsecond=0) - 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) + 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) + 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 @@ -177,10 +135,8 @@ def participant_session(): experiment_pages = page.query.filter_by(experiment_idexperiment=session['exp_id']).all() original_id_order_list = [(int(o.idpage)) for o in experiment_pages] - #flash("original Page id order:") #for a in range(len(original_id_order_list)): - #flash(original_id_order_list[a]) #create a randomized page id list @@ -188,29 +144,22 @@ def participant_session(): 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" - - - #store participants session id in session list as answer_set #old: was missing experiment id so made duplicates @@ -230,7 +179,6 @@ def participant_session(): flash('No pages or mediatype set for experiment') return redirect('/') - if 'user' in session: user = session['user'] #flash('Session started for user {}'.format(user)) @@ -242,7 +190,6 @@ def participant_session(): @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() @@ -277,83 +224,11 @@ def register(): return render_template('register.html', form=form) -@app.route('/task_completed') -def task_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') - - -@app.route('/continue_task', 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') - return redirect(url_for('continue_task', exp_id=exp_id)) - - #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() - - rand = experiment.query.filter_by(idexperiment=session['exp_id']).first() - - session['randomization'] = rand.randomization - - 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', page_num=redirect_to_page)) - - return render_template('continue_task.html', exp_id=exp_id, 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() @@ -364,8 +239,6 @@ def begin_with_id(): consent_paragraphs = str(experiment_info.consent_text) consent_paragraphs = consent_paragraphs.split('<br>') - - if form.validate_on_submit(): @@ -383,13 +256,10 @@ def begin_with_id(): 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 return render_template('consent.html', exp_id=exp_id, experiment_info=experiment_info, instruction_paragraphs=instruction_paragraphs, consent_paragraphs=consent_paragraphs) @@ -401,7 +271,6 @@ def begin_with_id(): @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() @@ -419,17 +288,10 @@ def admin_dryrun(): #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('/create_task') -def create_task(): - return render_template('create_task.html') - - @app.route('/instructions') def instructions(): @@ -438,148 +300,10 @@ def instructions(): instruction_paragraphs = str(instructions.instruction) instruction_paragraphs = instruction_paragraphs.split('<br>') - - return render_template('instructions.html', instruction_paragraphs=instruction_paragraphs, participant_id=participant_id) -@app.route('/task/<int:page_num>', methods=['GET', 'POST']) -def task(page_num): - - - experiment_info = experiment.query.filter_by(idexperiment=session['exp_id']).first() - 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) - 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': - - - randomized_page_id = trial_randomization.query.filter(and_(trial_randomization.answer_set_idanswer_set==session['answer_set'], trial_randomization.page_idpage==pages.items[0].idpage)).first() - #answer.query.filter(and_(answer.answer_set_idanswer_set==session['answer_set'], answer.page_idpage==session['current_idpage'])).first() - #flash("randomized page:") - #flash(randomized_page_id.randomized_idpage) - #set the stimulus to be shown if randomization is on - randomized_stimulus = page.query.filter_by(idpage=randomized_page_id.randomized_idpage).first() - - - - for p in pages.items: - session['current_idpage'] = p.idpage - - #slider set - form = TaskForm(request.form) - categories_and_scales = {} - categories = question.query.filter_by(experiment_idexperiment=session['exp_id']).all() - - for cat in categories: - - scale_list = [(cat.left, cat.right)] - categories_and_scales[cat.idquestion, cat.question] = scale_list - - form.categories1 = categories_and_scales - - - #slider set form handling - if request.method == 'POST'and form.validate(): - - - #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 - - if session['randomization'] == 'On': - - check_answer = answer.query.filter(and_(answer.answer_set_idanswer_set==session['answer_set'], answer.page_idpage==randomized_page_id.randomized_idpage)).first() - - if session['randomization'] == 'Off': - - 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: - - 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 - - #flash("vastauksia:") - #flash(update_answer_counter.answer_counter) - db.session.commit() - - data = request.form.to_dict() - for key, value in data.items(): - - #flash(key) - #flash(value) - #flash(session['current_idpage']) - - - #Insert slider values 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 - - if session['randomization'] == 'Off': - - participant_answer = answer(question_idquestion=key, answer_set_idanswer_set=session['answer_set'], answer=value, page_idpage=session['current_idpage']) - db.session.add(participant_answer) - db.session.commit() - - else: - - participant_answer = answer(question_idquestion=key, answer_set_idanswer_set=session['answer_set'], answer=value, page_idpage=randomized_page_id.randomized_idpage) - db.session.add(participant_answer) - db.session.commit() - - - else: - flash("Page has been answered already. Answers discarded") - - page_num=pages.next_num - - if pages.has_next: - return redirect( url_for('task', page_num=pages.next_num)) - - return redirect ( url_for('task_completed')) - - - return render_template('task.html', pages=pages, 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) - - - -@app.route('/quit_task') -def quit_task(): - - 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) - - @app.route('/researcher_login', methods=['GET', 'POST']) def login(): if current_user.is_authenticated: @@ -606,1408 +330,38 @@ def logout(): return redirect(url_for('index')) -@app.route('/experiment_statistics') -@login_required -def experiment_statistics(): +@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 - experiment_info = experiment.query.filter_by(idexperiment = exp_id).all() - participants = answer_set.query.filter_by(experiment_idexperiment= exp_id).all() - - - #Rating task headers - question_headers = question.query.filter_by(experiment_idexperiment=exp_id).all() - stimulus_headers = page.query.filter_by(experiment_idexperiment=exp_id).all() - - - - - - pages = page.query.filter_by(experiment_idexperiment=exp_id).all() - questions = question.query.filter_by(experiment_idexperiment=exp_id).all() - pages_and_questions = {} - - for p in pages: - - questions_list = [(p.idpage, a.idquestion) for a in questions] - pages_and_questions[p.idpage] = questions_list + return render_template('view_research_notification.html', research_notification_filename=research_notification_filename) +@app.route('/download_csv') +@login_required +def download_csv(): - - #List of answers per participant in format question Stimulus ID/Question ID - #those are in answer table as page_idpage and question_idquestion respectively - - + exp_id = request.args.get('exp_id', None) """ - pages = page.query.filter_by(experiment_idexperiment=exp_id).all() - - participants_and_answers = {} - - #participants on kaikki expin osallistujat - for participant in participants: - - - #kaikki yhden khn vastaukset ko experimentille koska answer_setin id matchaa answereiden kanssa - - - flash(participant.session) - for p in pages: - - answers = answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all() - #kaikki yhden participantin vastaukset pagelle - answers_for_page = answer.query.filter(and_(answer.answer_set_idanswer_set==participant.idanswer_set, answer.page_idpage==p.idpage)).all() - - - for ans in answers: - - - - if ans.page_idpage == p.idpage: - - #flash(ans.page_idpage) - flash("X") - - - - - else: - - flash("NA") - - #pages on kaikki experimentin paget - - - - for a in answers: - - if p.idpage == a.page_idpage: - flash("match") - - else: - flash("no match") - flash("participant:") - flash(participant.session) - flash("stimulus:") - flash(a.page_idpage) - flash("Kysymys") - flash(a.question_idquestion) - flash("vastaus:") - flash(a.answer) - - - - - #answers_list = (a.idanswer, a.question_idquestion, a.answer_set_idanswer_set, a.answer, a.page_idpage) - - #participants_and_answers[participant.session] = answers_list - - - """ - - participants_and_answers = {} - - for participant in participants: - - answers = answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all() - answers_list = [(a.idanswer, a.question_idquestion, a.answer_set_idanswer_set, a.answer, a.page_idpage) for a in answers] - participants_and_answers[participant.session] = answers_list - - - - #Background question answers + with open('export_new.csv', 'w', newline='') as f: - bg_questions = background_question.query.filter_by(experiment_idexperiment=exp_id).all() - bg_answers_for_participants = {} - - for participant in participants: + thewriter = csv.writer(f) - bg_answers = background_question_answer.query.filter_by(answer_set_idanswer_set=participant.idanswer_set).all() - bg_answers_list = [(a.answer) for a in bg_answers] - bg_answers_for_participants[participant.session] = bg_answers_list - - - #started and finished ratings counters - started_ratings = answer_set.query.filter_by(experiment_idexperiment=exp_id).count() - experiment_page_count = page.query.filter_by(experiment_idexperiment=exp_id).count() - finished_ratings = answer_set.query.filter(and_(answer_set.answer_counter==experiment_page_count, answer_set.experiment_idexperiment==exp_id)).count() - - - - return render_template('experiment_statistics.html', experiment_info=experiment_info, participants_and_answers=participants_and_answers, pages_and_questions=pages_and_questions, bg_questions=bg_questions, bg_answers_for_participants=bg_answers_for_participants, started_ratings=started_ratings, finished_ratings=finished_ratings, question_headers=question_headers, stimulus_headers=stimulus_headers) - - - -#EDIT FUNCTIONS - -@app.route('/create_experiment', methods=['GET', 'POST']) -@login_required -def create_experiment(): + thewriter.writerow(['1','2','3','4']) + thewriter.writerow(['a','b','c','d']) + """ - form = CreateExperimentForm(request.form) - - - if request.method == 'POST' and form.validate(): - - - the_time = datetime.now() - the_time = the_time.replace(microsecond=0) - - new_exp = experiment(name=request.form['name'], instruction=request.form['instruction'], language=request.form['language'], status='Hidden', randomization='Off', single_sentence_instruction=request.form['single_sentence_instruction'], short_instruction=request.form['short_instruction'], creator_name=request.form['creator_name'], is_archived='False', creation_time=the_time, stimulus_size='7', consent_text=request.form['consent_text'], use_forced_id='Off') - db.session.add(new_exp) - db.session.commit() - - #flash("lol") - #flash(new_exp.idexperiment) - - exp_id = new_exp.idexperiment - - #data = request.form.to_dict() - #for key, value in data.items(): - #tähän db insertit - - #flash(key) - #flash(value) - #flash('{}'.format(form.name.data)) - - #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(url_for('create_experiment_bgquestions', exp_id=exp_id)) - - return render_template('create_experiment.html', form=form) - + return redirect(url_for('experiment.statistics', exp_id=exp_id)) -@app.route('/create_experiment_bgquestions', methods=['GET', 'POST']) +@app.route('/researcher_info') @login_required -def create_experiment_bgquestions(): - - exp_id = request.args.get('exp_id', None) - form = CreateBackgroundQuestionForm(request.form) - - if request.method == 'POST' and form.validate(): - - #data = request.form.to_dict() - - #flash(data) - #flash(form.bg_questions_and_options.data) - - - str = form.bg_questions_and_options.data - - #Split the form data into a list that separates questions followed by the corresponding options - str_list = str.split('/n') +def researcher_info(): + return render_template('researcher_info.html') - #Iterate through the questions and options list - for a in range(len(str_list)): - - #Split the list cells further into questions and options - list = str_list[a].split(';') - - #flash(list[0]) - #flash("id oikein?") - #flash(add_bgquestion.idbackground_question) - - - #Input the first item of the list as a question in db and the items followed by that as options for that question - for x in range(len(list)): - - if x == 0: - #flash("Kysymys") - #flash(list[x]) - add_bgquestion = background_question(background_question=list[x], experiment_idexperiment=exp_id) - db.session.add(add_bgquestion) - db.session.commit() - - else: - #flash("optio") - #flash(list[x]) - add_bgq_option = background_question_option(background_question_idbackground_question=add_bgquestion.idbackground_question, option=list[x]) - db.session.add(add_bgq_option) - db.session.commit() - - return redirect(url_for('create_experiment_questions', exp_id=exp_id)) - - return render_template('create_experiment_bgquestions.html', form=form, exp_id=exp_id) - - -@app.route('/create_experiment_questions', methods=['GET', 'POST']) -@login_required -def create_experiment_questions(): - - exp_id = request.args.get('exp_id', None) - - form = CreateQuestionForm(request.form) - - if request.method == 'POST' and form.validate(): - - str = form.questions_and_options.data - - str_list = str.split('/n') - - for a in range(len(str_list)): - - list = str_list[a].split(';') - - #If there are the wrong amount of values for any of the the slider input values - #redirect back to the form - if len(list) != 3: - - - flash("Error Each slider must have 3 parameters separated by ; Some slider has:") - flash(len(list)) - - return redirect(url_for('create_experiment_questions', exp_id=exp_id)) - - #If all the slider inputs were of length 3 items - #we can input them to db - for a in range(len(str_list)): - - list = str_list[a].split(';') - - #flash("Question:") - #flash(list[0]) - #flash("Left:") - #flash(list[1]) - #flash("Right:") - #flash(list[2]) - - add_question = question(experiment_idexperiment=exp_id, question=list[0], left=list[1], right=list[2]) - db.session.add(add_question) - db.session.commit() - - - return redirect(url_for('create_experiment_upload_stimuli', exp_id=exp_id)) - - return render_template('create_experiment_questions.html', form=form) - - -@app.route('/create_experiment_upload_stimuli', methods=['GET', 'POST']) -@login_required -def create_experiment_upload_stimuli(): - - exp_id = request.args.get('exp_id', None) - - form = UploadStimuliForm(request.form) - - if request.method == 'POST' and form.validate(): - - #flash("validated") - #flash(form.type.data) - #flash(form.text.data) - - - #If stimulus type is text lets parse the information and insert it to database - - if form.type.data == 'text': - - #flash("db insert text") - - string = form.text.data - str_list = string.split('/n') - - for a in range(len(str_list)): - - #flash("lisättiin:") - #flash(str_list[a]) - add_text_stimulus = page(experiment_idexperiment=exp_id, type='text', text=str_list[a], media='none') - db.session.add(add_text_stimulus) - db.session.commit() - - #flash("Succes!") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - - - else: - - #Upload stimuli into /static/experiment_stimuli/exp_id folder - #Create the pages for the stimuli by inserting experiment_id, stimulus type, text and names of the stimulus files (as a path to the folder) - path = 'static/experiment_stimuli/' + str(exp_id) - - target = os.path.join(APP_ROOT, path) - #flash(target) - - if not os.path.isdir(target): - os.mkdir(target) - #flash("make dir") - - - #This returns a list of filenames: request.files.getlist("file") - - for file in request.files.getlist("file"): - - #save files in the correct folder - #flash(file.filename) - filename = file.filename - destination = "/".join([target, filename]) - #flash("destination") - #flash(destination) - file.save(destination) - - #add pages to the db - db_path = path + str('/') + str(filename) - - #flash("db path") - #flash(db_path) - - new_page = page(experiment_idexperiment=exp_id, type=form.type.data, media=db_path) - - db.session.add(new_page) - db.session.commit() - - #flash("Succes!") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - return redirect(url_for('create_experiment_upload_stimuli', exp_id=exp_id)) - - return render_template('create_experiment_upload_stimuli.html', form=form) - - -@app.route('/view_experiment') -@login_required -def view_experiment(): - - #crap:3lines - exp_id = request.args.get('exp_id', None) - media = page.query.filter_by(experiment_idexperiment=exp_id).all() - mtype = page.query.filter_by(experiment_idexperiment=exp_id).first() - - #experiment info - experiment_info = experiment.query.filter_by(idexperiment = exp_id).all() - - #background questions - questions_and_options = {} - questions = background_question.query.filter_by(experiment_idexperiment=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 - - questions1 = questions_and_options - - #sliderset - categories_and_scales = {} - categories = question.query.filter_by(experiment_idexperiment=exp_id).all() - - for cat in categories: - - scale_list = [(cat.left, cat.right)] - categories_and_scales[cat.idquestion, cat.question] = scale_list - - categories1 = categories_and_scales - - - return render_template('view_experiment.html', exp_id=exp_id, media=media, mtype=mtype, experiment_info=experiment_info, categories1=categories1, questions1=questions1) - - -@app.route('/edit_experiment', methods=['GET', 'POST']) -@login_required -def edit_experiment(): - - exp_id = request.args.get('exp_id', None) - - current_experiment = experiment.query.filter_by(idexperiment=exp_id).first() - - form = EditExperimentForm(request.form, obj=current_experiment) - form.language.default = current_experiment.language - - if request.method == 'POST' and form.validate(): - - form.populate_obj(current_experiment) - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - - return render_template('edit_experiment.html', form=form, exp_id=exp_id) - - - - - -@app.route('/edit_bg_question', methods=['GET', 'POST']) -@login_required -def edit_bg_question(): - - - bg_question_id = request.args.get('idbackground_question', None) - - - #Search for the right question and for the right options. Form a string of those separated with ";" and insert the - #formed string into the edit form - current_bg_question = background_question.query.filter_by(idbackground_question=bg_question_id).first() - exp_id=current_bg_question.experiment_idexperiment - question_string = current_bg_question.background_question - options = background_question_option.query.filter_by(background_question_idbackground_question=bg_question_id).all() - - for o in range(len(options)): - - question_string = str(question_string) + str("; ") + str(options[o].option) - - form = EditBackgroundQuestionForm(request.form) - form.bg_questions_and_options.data = question_string - - #After user chooses to update the question and options lets replace the old question and options with the ones from the form - if request.method == 'POST' and form.validate(): - - - #Explode the string with new values from the form - form_values = form.new_values.data - form_values_list = form_values.split(';') - - #Check and remove possible whitespaces from string beginnings with lstrip - for x in range(len(form_values_list)): - - form_values_list[x] = form_values_list[x].lstrip() - - #Cycle through strings and update db - for x in range(len(form_values_list)): - - #Replace question and update the object to database - if x == 0: - - - #flash("delete kys:") - #flash(current_bg_question.background_question) - #flash("insert kys:") - current_bg_question.background_question = form_values_list[x] - #flash(current_bg_question.background_question) - #flash(current_bg_question.idbackground_question) - #flash(current_bg_question.experiment_idexperiment) - - db.session.commit() - - #Delete old options from db - for o in options: - - db.session.delete(o) - db.session.commit() - - #Insert new options to db - else: - - - #flash("insert opt:") - #flash(form_values_list[x]) - new_option = background_question_option(background_question_idbackground_question=current_bg_question.idbackground_question, option=form_values_list[x]) - db.session.add(new_option) - db.session.commit() - - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - - return render_template('edit_bg_question.html', form=form, exp_id=exp_id) - - - -@app.route('/edit_question', methods=['GET', 'POST']) -@login_required -def edit_question(): - - - question_id = request.args.get('idquestion', None) - - current_question = question.query.filter_by(idquestion=question_id).first() - - form = EditQuestionForm(request.form, obj=current_question) - - - if request.method == 'POST' and form.validate(): - - form.populate_obj(current_question) - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=current_question.experiment_idexperiment)) - - return render_template('edit_question.html', form=form) - - - -@app.route('/add_bg_question', methods=['GET', 'POST']) -@login_required -def add_bg_question(): - - exp_id = request.args.get('exp_id', None) - exp_status = experiment.query.filter_by(idexperiment=exp_id).first() - - if exp_status.status != 'Hidden': - - flash("Experiment is public. Cannot modify structure.") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - else: - - - - form = CreateBackgroundQuestionForm(request.form) - - if request.method == 'POST' and form.validate(): - - str = form.bg_questions_and_options.data - - #Split the form data into a list that separates questions followed by the corresponding options - str_list = str.split('/n') - - #Iterate through the questions and options list - for a in range(len(str_list)): - - #Split the list cells further into questions and options - list = str_list[a].split(';') - - #Input the first item of the list as a question in db and the items followed by that as options for that question - for x in range(len(list)): - - if x == 0: - #flash("Kysymys") - #flash(list[x]) - add_bgquestion = background_question(background_question=list[x], experiment_idexperiment=exp_id) - db.session.add(add_bgquestion) - db.session.commit() - - else: - #flash("optio") - #flash(list[x]) - add_bgq_option = background_question_option(background_question_idbackground_question=add_bgquestion.idbackground_question, option=list[x]) - db.session.add(add_bgq_option) - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - return render_template('add_bg_question.html', form=form) - - - -@app.route('/add_questions', methods=['GET', 'POST']) -@login_required -def add_questions(): - - exp_id = request.args.get('exp_id', None) - exp_status = experiment.query.filter_by(idexperiment=exp_id).first() - - if exp_status.status != 'Hidden': - - flash("Experiment is public. Cannot modify structure.") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - else: - - form = CreateQuestionForm(request.form) - - if request.method == 'POST' and form.validate(): - - str = form.questions_and_options.data - str_list = str.split('/n') - - for a in range(len(str_list)): - - list = str_list[a].split(';') - - #If there are the right amount of values for the slider input values - if len(list) == 3: - - #flash("Question:") - #flash(list[0]) - #flash("Left:") - #flash(list[1]) - #flash("Right:") - #flash(list[2]) - - add_question = question(experiment_idexperiment=exp_id, question=list[0], left=list[1], right=list[2]) - db.session.add(add_question) - db.session.commit() - - #If slider has too many or too litlle parameters give an error and redirect back to input form - else: - flash("Error Each slider must have 3 parameters separated by ; Some slider has:") - flash(len(list)) - - return redirect(url_for('create_experiment_questions', exp_id=exp_id)) - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - return render_template('add_questions.html', form=form) - - - -#Remove functions - - -@app.route('/remove_bg_question') -@login_required -def remove_bg_question(): - - exp_id = request.args.get('exp_id', None) - - - exp_status = experiment.query.filter_by(idexperiment=exp_id).first() - - if exp_status.status != 'Hidden': - - flash("Experiment is public. Cannot modify structure.") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - else: - - - remove_id = request.args.get('idbackground_question', None) - - remove_options = background_question_option.query.filter_by(background_question_idbackground_question=remove_id).all() - - for a in range(len(remove_options)): - - #flash(remove_options[a].idbackground_question_option) - - db.session.delete(remove_options[a]) - db.session.commit() - - - remove_question = background_question.query.filter_by(idbackground_question=remove_id).first() - - db.session.delete(remove_question) - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - - - -@app.route('/remove_question') -@login_required -def remove_question(): - - exp_id = request.args.get('exp_id', None) - exp_status = experiment.query.filter_by(idexperiment=exp_id).first() - - if exp_status.status != 'Hidden': - - flash("Experiment is public. Cannot modify structure.") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - else: - - - remove_id = request.args.get('idquestion', None) - remove_question = question.query.filter_by(idquestion=remove_id).first() - - db.session.delete(remove_question) - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - -@app.route('/remove_experiment', methods=['GET', 'POST']) -@login_required -def remove_experiment(): - - exp_id = request.args.get('exp_id', None) - exp_status = experiment.query.filter_by(idexperiment=exp_id).first() - - if exp_status.status != 'Hidden': - - flash("Experiment is public. Cannot modify structure.") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - else: - - - - form = RemoveExperimentForm(request.form) - - if request.method == 'POST' and form.validate(): - - if form.remove.data == 'DELETE': - - - #This removes all experiment data from the database! - - - #Remove research bulletin if it exists - empty_filevariable = experiment.query.filter_by(idexperiment=exp_id).first() - - if empty_filevariable.research_notification_filename is not None: - - target = os.path.join(APP_ROOT, empty_filevariable.research_notification_filename) - - if os.path.exists(target): - os.remove(target) - - - - - #Tables - - - remove_forced_id = forced_id.query.filter_by(experiment_idexperiment=exp_id).all() - - for b in range(len(remove_forced_id)): - db.session.delete(remove_forced_id[b]) - db.session.commit() - - - #background_question_option & background_question & background question answers: - remove_background_question = background_question.query.filter_by(experiment_idexperiment=exp_id).all() - - #cycle through all bg questions and delete their options - for a in range(len(remove_background_question)): - - remove_background_question_option = background_question_option.query.filter_by(background_question_idbackground_question=remove_background_question[a].idbackground_question).all() - - for b in range(len(remove_background_question_option)): - - db.session.delete(remove_background_question_option[b]) - db.session.commit() - - - #Remove all background questions and all answers given to each bg question - for a in range(len(remove_background_question)): - - remove_background_question_answers = background_question_answer.query.filter_by(background_question_idbackground_question=remove_background_question[a].idbackground_question).all() - - for b in range(len(remove_background_question_answers)): - - db.session.delete(remove_background_question_answers[b]) - db.session.commit() - - db.session.delete(remove_background_question[a]) - db.session.commit() - - - - #Remove all questions and answers - remove_question = question.query.filter_by(experiment_idexperiment=exp_id).all() - - for a in range(len(remove_question)): - - remove_question_answers = answer.query.filter_by(question_idquestion=remove_question[a].idquestion).all() - - for b in range(len(remove_question_answers)): - - db.session.delete(remove_question_answers[b]) - db.session.commit() - - db.session.delete(remove_question[a]) - db.session.commit() - - - #Remove all pages and datafiles - remove_pages = page.query.filter_by(experiment_idexperiment=exp_id).all() - - for a in range(len(remove_pages)): - - if remove_pages[a].type == 'text': - - db.session.delete(remove_pages[a]) - db.session.commit() - - else: - - target = os.path.join(APP_ROOT, remove_pages[a].media) - - if os.path.exists(target): - os.remove(target) - - #Now that the files are removed we can delete the page - db.session.delete(remove_pages[a]) - db.session.commit() - - - #Remove all answer_sets and trial_randomization orders - remove_answer_set = answer_set.query.filter_by(experiment_idexperiment=exp_id).all() - - for a in range(len(remove_answer_set)): - - remove_trial_randomizations = trial_randomization.query.filter_by(answer_set_idanswer_set=remove_answer_set[a].idanswer_set).all() - - for b in range(len(remove_trial_randomizations)): - - db.session.delete(remove_trial_randomizations[b]) - db.session.commit() - - db.session.delete(remove_answer_set[a]) - db.session.commit() - - - #Remove experiment table - remove_experiment = experiment.query.filter_by(idexperiment=exp_id).first() - db.session.delete(remove_experiment) - db.session.commit() - - - flash("Experiment was removed from database!") - - return redirect(url_for('index')) - - else: - - flash("Experiment was not removed!") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - - - return render_template('remove_experiment.html', form=form, exp_id=exp_id) - - - -@app.route('/remove_page') -@login_required -def remove_page(): - - exp_id = request.args.get('exp_id', None) - exp_status = experiment.query.filter_by(idexperiment=exp_id).first() - - if exp_status.status != 'Hidden': - - flash("Experiment is public. Cannot modify structure.") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - else: - - - remove_id = request.args.get('idpage', None) - remove_page = page.query.filter_by(idpage=remove_id).first() - experiment_pages = page.query.filter_by(experiment_idexperiment=exp_id).all() - - #if stimulustype is text, the stimulus itself is text on the database, other stimulus types are real files - #on the server and need to be deleted - if remove_page.type != 'text': - - #helper variable - do_not_delete_file = 'False' - - #if the file to be deleted is in duplicate use of another page then we won't delete the file - for a in range(len(experiment_pages)): - - #flash("in da for") - - if experiment_pages[a].media == remove_page.media and experiment_pages[a].idpage != remove_page.idpage: - - #flash("in da if") - do_not_delete_file = 'True' - - #If no other page is using the file then lets remove it - if do_not_delete_file == 'False': - #remove old file - target = os.path.join(APP_ROOT, remove_page.media) - #flash("Remove:") - #flash(target) - os.remove(target) - - db.session.delete(remove_page) - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - if remove_page.type == 'text': - - db.session.delete(remove_page) - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - -@app.route('/publish_experiment') -@login_required -def publish_experiment(): - - exp_id = request.args.get('exp_id', None) - - publish_experiment = experiment.query.filter_by(idexperiment = exp_id).first() - - publish_experiment.status = 'Public' - - flash("Changed status to Public") - - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - -@app.route('/hide_experiment') -@login_required -def hide_experiment(): - - exp_id = request.args.get('exp_id', None) - - hide_experiment = experiment.query.filter_by(idexperiment = exp_id).first() - - hide_experiment.status = 'Hidden' - - flash("Changed status to Hidden") - - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - -@app.route('/private_experiment') -@login_required -def private_experiment(): - - exp_id = request.args.get('exp_id', None) - - private_experiment = experiment.query.filter_by(idexperiment = exp_id).first() - - private_experiment.status = 'Private' - - flash("Changed status to Private") - - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - - -@app.route('/enable_randomization') -@login_required -def enable_randomization(): - - exp_id = request.args.get('exp_id', None) - - enable_randomization = experiment.query.filter_by(idexperiment = exp_id).first() - - enable_randomization.randomization = 'On' - - flash("Enabled trial randomization") - - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - -@app.route('/disable_randomization') -@login_required -def disable_randomization(): - - exp_id = request.args.get('exp_id', None) - - disable_randomization = experiment.query.filter_by(idexperiment = exp_id).first() - - disable_randomization.randomization = 'Off' - - flash("Disabled trial randomization") - - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - -@app.route('/enable_forced_id') -@login_required -def enable_forced_id(): - - exp_id = request.args.get('exp_id', None) - - enable_forced_id = experiment.query.filter_by(idexperiment = exp_id).first() - - enable_forced_id.use_forced_id = 'On' - - flash("Enabled forced ID login") - - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - -@app.route('/disable_forced_id') -@login_required -def disable_forced_id(): - - exp_id = request.args.get('exp_id', None) - - disable_forced_id = experiment.query.filter_by(idexperiment = exp_id).first() - - disable_forced_id.use_forced_id = 'Off' - - flash("Disabled forced ID login") - - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - -@app.route('/view_forced_id_list', methods=['GET', 'POST']) -@login_required -def view_forced_id_list(): - - exp_id = request.args.get('exp_id', None) - - id_list = forced_id.query.filter_by(experiment_idexperiment=exp_id).all() - - - form = GenerateIdForm(request.form) - - if request.method == 'POST' and form.validate(): - - - for i in range(int(request.form['number'])): - - random_id = str(request.form['string']) + str(secrets.token_hex(3)) - check_answer_set = answer_set.query.filter_by(session=random_id).first() - check_forced_id = forced_id.query.filter_by(pregenerated_id=random_id).first() - - - #here we check if the generated id is found from given answers from the whole database in answer_set table - #or from forced_id table. If so another id is generated instead to avoid a duplicate - if check_answer_set is not None or check_forced_id is not None: - - #flash("ID already existed; generated a new one") - random_id = secrets.token_hex(3) - check_answer_set = answer_set.query.filter_by(session=random_id).first() - check_forced_id = forced_id.query.filter_by(pregenerated_id=random_id).first() - - input_id = forced_id(experiment_idexperiment=exp_id, pregenerated_id=random_id) - db.session.add(input_id) - db.session.commit() - - - - - return redirect(url_for('view_forced_id_list', exp_id=exp_id)) - - - - - - - - return render_template('view_forced_id_list.html', exp_id=exp_id, id_list=id_list) - - - - - - - - - - -@app.route('/edit_stimuli', methods=['GET', 'POST']) -@login_required -def edit_stimuli(): - - exp_id = request.args.get('exp_id', None) - page_id = request.args.get('idpage', None) - edit_page = page.query.filter_by(idpage=page_id).first() - - - - form = EditPageForm(request.form, obj=edit_page) - - if request.method == 'POST' and form.validate(): - - - #If the stimulus type is not text, then the old stimulus file is deleted from os and replaced - if edit_page.type != 'text': - - #remove old file - target = os.path.join(APP_ROOT, edit_page.media) - #flash("Remove:") - #flash(target) - os.remove(target) - - #upload new file - - path = 'static/experiment_stimuli/' + str(exp_id) - - target = os.path.join(APP_ROOT, path) - #flash(target) - - if not os.path.isdir(target): - os.mkdir(target) - #flash("make dir") - - - #This returns a list of filenames: request.files.getlist("file") - - for file in request.files.getlist("file"): - - #save files in the correct folder - #flash(file.filename) - filename = file.filename - destination = "/".join([target, filename]) - #flash("destination") - #flash(destination) - file.save(destination) - - #update db object - db_path = path + str('/') + str(filename) - - #flash("db path") - #flash(db_path) - - edit_page.media=db_path - - db.session.commit() - - #flash("Succes!") - - - #If editing text stimulus no need for filehandling - else: - - form.populate_obj(edit_page) - db.session.commit() - - - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - return render_template('edit_stimuli.html', form=form, edit_page=edit_page) - - -@app.route('/add_stimuli', methods=['GET', 'POST']) -@login_required -def add_stimuli(): - - exp_id = request.args.get('exp_id', None) - - - exp_status = experiment.query.filter_by(idexperiment=exp_id).first() - - - if exp_status.status != 'Hidden': - - flash("Experiment is public. Cannot modify structure.") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - else: - - - #If there are no pages set for the experiment lets reroute user to create experiment stimuli upload instead - - is_there_any_stimuli = page.query.filter_by(experiment_idexperiment = exp_id).first() - - if is_there_any_stimuli is None: - - return redirect(url_for('create_experiment_upload_stimuli', exp_id=exp_id)) - - - - stimulus_type = request.args.get('stimulus_type', None) - - form = UploadStimuliForm(request.form) - - if request.method == 'POST': - - - if stimulus_type == 'text': - - #flash("db insert text") - - string = form.text.data - str_list = string.split('/n') - - for a in range(len(str_list)): - - #flash("lisättiin:") - #flash(str_list[a]) - add_text_stimulus = page(experiment_idexperiment=exp_id, type='text', text=str_list[a], media='none') - db.session.add(add_text_stimulus) - db.session.commit() - - #flash("Succes!") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - - - else: - - #Upload stimuli into /static/experiment_stimuli/exp_id folder - #Create the pages for the stimuli by inserting experiment_id, stimulus type, text and names of the stimulus files (as a path to the folder) - path = 'static/experiment_stimuli/' + str(exp_id) - - target = os.path.join(APP_ROOT, path) - #flash(target) - - if not os.path.isdir(target): - os.mkdir(target) - #flash("make dir") - - - #This returns a list of filenames: request.files.getlist("file") - - for file in request.files.getlist("file"): - - #save files in the correct folder - #flash(file.filename) - filename = file.filename - destination = "/".join([target, filename]) - #flash("destination") - #flash(destination) - file.save(destination) - - #add pages to the db - db_path = path + str('/') + str(filename) - - #flash("db path") - #flash(db_path) - - new_page = page(experiment_idexperiment=exp_id, type=form.type.data, media=db_path) - - db.session.add(new_page) - db.session.commit() - - #flash("Succes!") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - - return render_template('add_stimuli.html', form=form, stimulus_type=stimulus_type) - - - -@app.route('/upload_research_notification', methods=['GET', 'POST']) -@login_required -def upload_research_notification(): - - exp_id = request.args.get('exp_id', None) - - form = UploadResearchBulletinForm(request.form) - - if request.method == 'POST': - - path = 'static/experiment_stimuli/' + str(exp_id) - - target = os.path.join(APP_ROOT, path) - #flash(target) - - if not os.path.isdir(target): - os.mkdir(target) - #flash("make dir") - - - #This returns a list of filenames: request.files.getlist("file") - - for file in request.files.getlist("file"): - - #save files in the correct folder - #flash(file.filename) - filename = file.filename - destination = "/".join([target, filename]) - #flash("destination") - #flash(destination) - file.save(destination) - - #add pages to the db - db_path = path + str('/') + str(filename) - - #flash("db path") - #flash(db_path) - - - bulletin = experiment.query.filter_by(idexperiment=exp_id).first() - - bulletin.research_notification_filename = db_path - db.session.commit() - - #flash("Succes!") - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - - return render_template('upload_research_notification.html', exp_id=exp_id, form=form) - - -@app.route('/remove_research_notification') -@login_required -def remove_research_notification(): - - exp_id = request.args.get('exp_id', None) - - empty_filevariable = experiment.query.filter_by(idexperiment=exp_id).first() - - target = os.path.join(APP_ROOT, empty_filevariable.research_notification_filename) - - if os.path.exists(target): - os.remove(target) - - - empty_filevariable.research_notification_filename = None - - db.session.commit() - - return redirect(url_for('view_experiment', exp_id=exp_id)) - - - -@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) - - - - - - -@app.route('/download_csv') -@login_required -def download_csv(): - - exp_id = request.args.get('exp_id', None) - - """ - with open('export_new.csv', 'w', newline='') as f: - - thewriter = csv.writer(f) - - thewriter.writerow(['1','2','3','4']) - thewriter.writerow(['a','b','c','d']) - """ - - - - return redirect(url_for('experiment_statistics', exp_id=exp_id)) - - -@app.route('/researcher_info') -@login_required -def researcher_info(): - - - return render_template('researcher_info.html') - - - - - -#TEST PAGE - -@app.route('/test_page') -def test_page(): - - flash('Please log in to access this page.') - - session.clear() - - return render_template('test_page.html') +# EOF \ No newline at end of file diff --git a/app/static/img/dummyG.png b/app/static/img/dummyG.png new file mode 100644 index 0000000000000000000000000000000000000000..9e6ed7c1092e2f8db50c3ba03b923f8798bdf6c4 Binary files /dev/null and b/app/static/img/dummyG.png differ diff --git a/app/task/__init__.py b/app/task/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/templates/continue_task.html b/app/task/templates/continue_task.html similarity index 100% rename from app/templates/continue_task.html rename to app/task/templates/continue_task.html diff --git a/app/templates/quit_task.html b/app/task/templates/quit_task.html similarity index 100% rename from app/templates/quit_task.html rename to app/task/templates/quit_task.html diff --git a/app/templates/task.html b/app/task/templates/task.html similarity index 94% rename from app/templates/task.html rename to app/task/templates/task.html index 8eeaf5c4fb0cdb07131c158c606caa15f5b1f347..77cdddd664a346cd54be103f19866c2c0bb7cf15 100644 --- a/app/templates/task.html +++ b/app/task/templates/task.html @@ -1,11 +1,13 @@ {% extends "base.html" %} {% block content %} - <br> {% if session['randomization']=='Off' %} - + +<!-- TODO change session['type'] TO stimulus['type'] + because session should have multiple type of stimuli!!! + --> {% if session['type']=='text' %} <div class="container text-center mt-5 pt-5"> @@ -16,7 +18,6 @@ <br><br> {% endif %} - {% if session['type']=='picture' %} <div class="container stimulus col-{{stimulus_size}} mt-5 pt-5"> {% for page in pages.items %} @@ -25,13 +26,8 @@ </div> {% endif %} - {% if session['type']=='video' %} <div class="col-{{stimulus_size}} container stimulus mt-5 pt-5"> - - - - {% for page in pages.items %} <div class="embed-responsive embed-responsive-16by9"> <iframe class="embed-responsive-item" src="/{{ page.media }}" allowfullscreen></iframe> @@ -40,14 +36,8 @@ </div> {% endif %} - {% if session['type']=='audio' %} - <div class="col-{{stimulus_size}} container stimulus mt-5 pt-5"> - - - - {% for page in pages.items %} <div class="embed-responsive embed-responsive-16by9"> <iframe class="embed-responsive-item" src="/{{ page.media }}" allowfullscreen></iframe> @@ -56,11 +46,8 @@ </div> {% endif %} - {% else %} - - {% if session['type']=='text' %} <div class="container text-center mt-5 pt-5"> {% for page in pages.items %} @@ -70,7 +57,6 @@ <br><br> {% endif %} - {% if session['type']=='picture' %} <div class="container stimulus col-{{stimulus_size}} mt-5 pt-5"> {% for page in pages.items %} @@ -79,13 +65,8 @@ </div> {% endif %} - {% if session['type']=='video' %} <div class="col-{{stimulus_size}} container stimulus mt-5 pt-5"> - - - - {% for page in pages.items %} <div class="embed-responsive embed-responsive-16by9"> <iframe class="embed-responsive-item" src="/{{ randomized_stimulus.media }}" allowfullscreen></iframe> @@ -94,12 +75,8 @@ </div> {% endif %} - {% if session['type']=='audio' %} <div class="col-{{stimulus_size}} container stimulus mt-5 pt-5"> - - - {% for page in pages.items %} <div class="embed-responsive embed-responsive-16by9"> <iframe class="embed-responsive-item" src="/{{ randomized_stimulus.media }}" allowfullscreen></iframe> @@ -108,12 +85,9 @@ </div> {% endif %} - {% endif %} - - - <br> +<br> @@ -140,7 +114,7 @@ {% endfor %} <div class="form-row text-center"> <div class="col-12"> - <a class="btn btn-primary" href={{ url_for('quit_task') }} role="button">{{ _('Quit task') }}</a> + <a class="btn btn-primary" href={{ url_for('task.quit') }} role="button">{{ _('Quit task') }}</a> <button type="submit" class="btn btn-primary">{{ _('Next page') }}</button> </div> <div class="col-12"> diff --git a/app/templates/task_completed.html b/app/task/templates/task_completed.html similarity index 100% rename from app/templates/task_completed.html rename to app/task/templates/task_completed.html diff --git a/app/task/views.py b/app/task/views.py new file mode 100644 index 0000000000000000000000000000000000000000..0c0ccf261fa0ba19ccd940b001e2b594717ef7ac --- /dev/null +++ b/app/task/views.py @@ -0,0 +1,220 @@ + + + +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 +from app.forms import Answers, TaskForm, ContinueTaskForm + +task_blueprint = Blueprint("task", __name__, + template_folder='templates', + static_folder='static', + url_prefix='/task') + +@task_blueprint.route('/<int:page_num>', methods=['GET', 'POST']) +def task(page_num): + + experiment_info = experiment.query.filter_by(idexperiment=session['exp_id']).first() + 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)) + + print(stimulus_size_text) + + pages = page.query.filter_by(experiment_idexperiment=session['exp_id']).paginate(per_page=1, page=page_num, error_out=True) + 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': + randomized_page_id = trial_randomization.query.filter(and_(trial_randomization.answer_set_idanswer_set==session['answer_set'], trial_randomization.page_idpage==pages.items[0].idpage)).first() + #answer.query.filter(and_(answer.answer_set_idanswer_set==session['answer_set'], answer.page_idpage==session['current_idpage'])).first() + #flash("randomized page:") + #flash(randomized_page_id.randomized_idpage) + #set the stimulus to be shown if randomization is on + randomized_stimulus = page.query.filter_by(idpage=randomized_page_id.randomized_idpage).first() + + for p in pages.items: + session['current_idpage'] = p.idpage + + #slider set + form = TaskForm(request.form) + categories_and_scales = {} + categories = question.query.filter_by(experiment_idexperiment=session['exp_id']).all() + + for cat in categories: + scale_list = [(cat.left, cat.right)] + categories_and_scales[cat.idquestion, cat.question] = scale_list + + form.categories1 = categories_and_scales + + #slider set form handling + if request.method == 'POST'and form.validate(): + #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 + + if session['randomization'] == 'On': + check_answer = answer.query.filter(and_(answer.answer_set_idanswer_set==session['answer_set'], answer.page_idpage==randomized_page_id.randomized_idpage)).first() + + if session['randomization'] == 'Off': + 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: + + 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 + + #flash("vastauksia:") + #flash(update_answer_counter.answer_counter) + db.session.commit() + + data = request.form.to_dict() + for key, value in data.items(): + #flash(key) + #flash(value) + #flash(session['current_idpage']) + + #Insert slider values 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 + + if session['randomization'] == 'Off': + participant_answer = answer(question_idquestion=key, answer_set_idanswer_set=session['answer_set'], answer=value, page_idpage=session['current_idpage']) + db.session.add(participant_answer) + db.session.commit() + else: + participant_answer = answer(question_idquestion=key, answer_set_idanswer_set=session['answer_set'], answer=value, page_idpage=randomized_page_id.randomized_idpage) + db.session.add(participant_answer) + db.session.commit() + + else: + flash("Page has been answered already. Answers discarded") + + page_num=pages.next_num + + if pages.has_next: + return redirect( url_for('task.task', page_num=pages.next_num)) + + return redirect ( url_for('task.completed')) + + return render_template('task.html', pages=pages, 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) + + +@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') + return redirect(url_for('task.continue', exp_id=exp_id)) + + #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() + + rand = experiment.query.filter_by(idexperiment=session['exp_id']).first() + + session['randomization'] = rand.randomization + + 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') + + diff --git a/app/templates/base.html b/app/templates/base.html index c8b4c59e28e16f00c42ce42391bb448fd1427edf..b6f03500f9305a8df30a243b8c987874e9a3e156 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -75,7 +75,7 @@ <a class="nav-item" href="{{ url_for('researcher_info') }}" class="nav-link">Info |</a> - <a class="nav-item" href="{{ url_for('create_experiment') }}" class="nav-link">Create |</a> + <a class="nav-item" href="{{ url_for('create.create_experiment') }}" class="nav-link">Create |</a> <a class="nav-item" href="" class="nav-link">Archives |</a> <a class="nav-item" href="{{ url_for('logout') }}" class="nav-link">Logout |</a> diff --git a/app/templates/index.html b/app/templates/index.html index d034db342ac2e32c2c8be791b995886e59013971..e8480f804f988e7cdaee61023040d762aa956db9 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -54,13 +54,13 @@ <a class="btn btn-outline-primary" href="{{ url_for('consent', exp_id=exp.idexperiment) }}" role="button">{{ _('Begin task') }}</a> - <a class="btn btn-outline-primary" href="{{ url_for('continue_task', exp_id=exp.idexperiment) }}" role="button">{{ _('Continue task') }}</a> + <a class="btn btn-outline-primary" href="{{ url_for('task.continue_task', exp_id=exp.idexperiment) }}" role="button">{{ _('Continue task') }}</a> {% if current_user.is_authenticated %} <span class="text-right"> <a class="btn btn-outline-info" href="{{ url_for('admin_dryrun', exp_id=exp.idexperiment) }}" role="button">{{ _('AdminRun') }}</a> - <a class="btn btn-outline-info" href="{{ url_for('experiment_statistics', exp_id=exp.idexperiment) }}" role="button">{{ _('Statistics') }}</a> - <a class="btn btn-outline-info" href="{{ url_for('view_experiment', exp_id=exp.idexperiment) }}" role="button">{{ _('View / Edit') }}</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.statistics', exp_id=exp.idexperiment) }}" role="button">{{ _('Statistics') }}</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.view', exp_id=exp.idexperiment) }}" role="button">{{ _('View / Edit') }}</a> {% endif %} @@ -97,13 +97,13 @@ <li class="list-group-item"> <a class="btn btn-outline-primary" href="{{ url_for('consent', exp_id=exp.idexperiment) }}" role="button">{{ _('Begin task') }}</a> - <a class="btn btn-outline-primary" href="{{ url_for('continue_task', exp_id=exp.idexperiment) }}" role="button">{{ _('Continue task') }}</a + <a class="btn btn-outline-primary" href="{{ url_for('task.continue_task', exp_id=exp.idexperiment) }}" role="button">{{ _('Continue task') }}</a {% if current_user.is_authenticated %} <span class="text-right"> <a class="btn btn-outline-info" href="{{ url_for('admin_dryrun', exp_id=exp.idexperiment) }}" role="button">{{ _('AdminRun') }}</a> - <a class="btn btn-outline-info" href="{{ url_for('experiment_statistics', exp_id=exp.idexperiment) }}" role="button">{{ _('Statistics') }}</a> - <a class="btn btn-outline-info" href="{{ url_for('view_experiment', exp_id=exp.idexperiment) }}" role="button">{{ _('View / Edit') }}</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.statistics', exp_id=exp.idexperiment) }}" role="button">{{ _('Statistics') }}</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.view', exp_id=exp.idexperiment) }}" role="button">{{ _('View / Edit') }}</a> {% endif %} @@ -147,12 +147,12 @@ <li class="list-group-item"> <a class="btn btn-outline-primary" href="{{ url_for('consent', exp_id=exp.idexperiment) }}" role="button">Begin task</a> - <a class="btn btn-outline-primary" href="{{ url_for('continue_task', exp_id=exp.idexperiment) }}" role="button">Continue task</a> + <a class="btn btn-outline-primary" href="{{ url_for('task.continue_task', exp_id=exp.idexperiment) }}" role="button">Continue task</a> {% if current_user.is_authenticated %} <a class="btn btn-outline-info" href="{{ url_for('admin_dryrun', exp_id=exp.idexperiment) }}" role="button">AdminRun</a> - <a class="btn btn-outline-info" href="{{ url_for('experiment_statistics', exp_id=exp.idexperiment) }}" role="button">Statistics</a> - <a class="btn btn-outline-info" href="{{ url_for('view_experiment', exp_id=exp.idexperiment) }}" role="button">View / Edit</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.statistics', exp_id=exp.idexperiment) }}" role="button">Statistics</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.view', exp_id=exp.idexperiment) }}" role="button">View / Edit</a> {% endif %} @@ -187,12 +187,12 @@ <li class="list-group-item"> <a class="btn btn-outline-primary" href="{{ url_for('consent', exp_id=exp.idexperiment) }}" role="button">Begin task</a> - <a class="btn btn-outline-primary" href="{{ url_for('continue_task', exp_id=exp.idexperiment) }}" role="button">Continue task</a> + <a class="btn btn-outline-primary" href="{{ url_for('task.continue_task', exp_id=exp.idexperiment) }}" role="button">Continue task</a> {% if current_user.is_authenticated %} <a class="btn btn-outline-info" href="{{ url_for('admin_dryrun', exp_id=exp.idexperiment) }}" role="button">AdminRun</a> - <a class="btn btn-outline-info" href="{{ url_for('experiment_statistics', exp_id=exp.idexperiment) }}" role="button">Statistics</a> - <a class="btn btn-outline-info" href="{{ url_for('view_experiment', exp_id=exp.idexperiment) }}" role="button">View / Edit</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.statistics', exp_id=exp.idexperiment) }}" role="button">Statistics</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.view', exp_id=exp.idexperiment) }}" role="button">View / Edit</a> {% endif %} @@ -249,12 +249,12 @@ <li class="list-group-item"> <a class="btn btn-outline-primary" href="{{ url_for('consent', exp_id=exp.idexperiment) }}" role="button">Begin task</a> - <a class="btn btn-outline-primary" href="{{ url_for('continue_task', exp_id=exp.idexperiment) }}" role="button">Continue task</a> + <a class="btn btn-outline-primary" href="{{ url_for('task.continue_task', exp_id=exp.idexperiment) }}" role="button">Continue task</a> {% if current_user.is_authenticated %} <a class="btn btn-outline-info" href="{{ url_for('admin_dryrun', exp_id=exp.idexperiment) }}" role="button">AdminRun</a> - <a class="btn btn-outline-info" href="{{ url_for('experiment_statistics', exp_id=exp.idexperiment) }}" role="button">Statistics</a> - <a class="btn btn-outline-info" href="{{ url_for('view_experiment', exp_id=exp.idexperiment) }}" role="button">View / Edit</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.statistics', exp_id=exp.idexperiment) }}" role="button">Statistics</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.view', exp_id=exp.idexperiment) }}" role="button">View / Edit</a> {% endif %} @@ -289,12 +289,12 @@ <li class="list-group-item"> <a class="btn btn-outline-primary" href="{{ url_for('consent', exp_id=exp.idexperiment) }}" role="button">Begin task</a> - <a class="btn btn-outline-primary" href="{{ url_for('continue_task', exp_id=exp.idexperiment) }}" role="button">Continue task</a> + <a class="btn btn-outline-primary" href="{{ url_for('task.continue_task', exp_id=exp.idexperiment) }}" role="button">Continue task</a> {% if current_user.is_authenticated %} <a class="btn btn-outline-info" href="{{ url_for('admin_dryrun', exp_id=exp.idexperiment) }}" role="button">AdminRun</a> - <a class="btn btn-outline-info" href="{{ url_for('experiment_statistics', exp_id=exp.idexperiment) }}" role="button">Statistics</a> - <a class="btn btn-outline-info" href="{{ url_for('view_experiment', exp_id=exp.idexperiment) }}" role="button">View / Edit</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.statistics', exp_id=exp.idexperiment) }}" role="button">Statistics</a> + <a class="btn btn-outline-info" href="{{ url_for('experiment.view', exp_id=exp.idexperiment) }}" role="button">View / Edit</a> {% endif %} diff --git a/app/templates/test_page.html b/app/templates/test_page.html deleted file mode 100644 index f204c39477795dadca6e12d1f1f75ea5fe1315f6..0000000000000000000000000000000000000000 --- a/app/templates/test_page.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "base.html" %} -{% block content %} - -<h1 class="container mt-5">moro</h1> - - -<h1 class="container mt-5">{{ _('File Not Found') }}</h1> - -{% endblock %} - - - diff --git a/config.py b/config.py index f5a8ed48b4356b1a6536a19085d85e4b0fe5b46f..542e7012df0c8d6d898d08651706580cdd7cf2c5 100644 --- a/config.py +++ b/config.py @@ -18,14 +18,13 @@ class Config(object): """ #MariaDB mysql database settings - MYSQL_USER = 'rating' - MYSQL_PASSWORD = 'timotimo' + MYSQL_PASSWORD = 'rating_passwd' MYSQL_SERVER = 'localhost' - MYSQL_DB = 'rating_tool_db' + MYSQL_DB = 'rating_db' SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://'+MYSQL_USER+':'+MYSQL_PASSWORD+'@'+MYSQL_SERVER+'/'+MYSQL_DB+'?charset=utf8mb4' SQLALCHEMY_TRACK_MODIFICATIONS = False - \ No newline at end of file + diff --git a/create_rating_db.txt b/create_rating_db.txt index 1eaafe77ab7083b3d1897ff5dfb89c9b19076357..7d522481ad7afd6ba9d2f31d51ec7a22ae50d379 100644 --- a/create_rating_db.txt +++ b/create_rating_db.txt @@ -7,19 +7,19 @@ CREATE TABLE background_question ( CREATE TABLE experiment ( idexperiment INTEGER NOT NULL AUTO_INCREMENT, name VARCHAR(120), - instruction TEXT, + instruction MEDIUMTEXT, directoryname VARCHAR(120), language VARCHAR(120), status VARCHAR(120), randomization VARCHAR(120), - short_instruction TEXT, - single_sentence_instruction TEXT, + short_instruction MEDIUMTEXT, + single_sentence_instruction MEDIUMTEXT, is_archived VARCHAR(120), creator_name VARCHAR(120), research_notification_filename VARCHAR(120), creation_time DATETIME, stimulus_size VARCHAR(120), - consent_text TEXT, + consent_text MEDIUMTEXT, use_forced_id VARCHAR(120), PRIMARY KEY (idexperiment) );