diff --git a/.gitignore b/.gitignore index 2e28ad5c0cdf2eac18bc3644fa331556ae875457..e11292b357d59504d3b69fbd2c1accaf1b183985 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ __pycache__/ -/migrations /venv -app.db cmd.txt DB_inserts.txt dumb.sql diff --git a/app.db b/app.db new file mode 100644 index 0000000000000000000000000000000000000000..bf4690f3e45b7cc6ab8cc1930c9254191e8060ef Binary files /dev/null and b/app.db differ diff --git a/app/routes.py b/app/routes.py index b29fcd3785e3bf061be9bdbbb6da026485b7040f..0153d1c65cca4775852c7300c99ebdd3f6f52465 100644 --- a/app/routes.py +++ b/app/routes.py @@ -49,16 +49,21 @@ 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("set lang") + session['language'] = "All" + return render_template('index.html', title='Home', experiments=experiments) @@ -69,6 +74,29 @@ def consent(): return render_template('consent.html', exp_id=exp_id, experiments=experiments) +@app.route('/set_language') +def set_language(): + + session['language'] = request.args.get('language', None) + + + + + return redirect(url_for('index')) + +@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(): diff --git a/app/templates/base.html b/app/templates/base.html index aa3814adfdf321c1d9dd79f01e502a7707d79880..3675532579503a389069aa8dc9b2a5e440bfd423 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -29,7 +29,11 @@ {% if pages %} <a class="navbar-brand pl-5 font-weight-light">Participant ID: <span class="text-success font-weight-bold">{{ session['user']}}</span></a> {% else %} - <a class="navbar-brand pl-3 text-success font-weight-light" href="{{ url_for('index') }}" class="nav-link">MEGA-fMRI Stimulus Rating Tool</a> + + + <a class="navbar-brand pl-3 text-success font-weight-light" href="{{ url_for('index') }}" class="nav-link">Onni</a> + + {% endif %} </div> <div class="col-6 navbar-nav"> @@ -48,11 +52,47 @@ {% endwith %} {% endblock %} {% if current_user.is_authenticated %} - <a class="nav-item" href="{{ url_for('researcher_info') }}" class="nav-link">Data preparation info |</a> - <a class="nav-item" href="{{ url_for('create_experiment') }}" class="nav-link">Create experiment |</a> + <a class="nav-item" href="{{ url_for('researcher_info') }}" class="nav-link">Info |</a> + + + + <a class="nav-item dropdown"> + <a class="nav-item dropdown-toggle text-align-right" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + Language + </a> + <div class="dropdown-menu" aria-labelledby="navbarDropdown"> + + <a class="dropdown-item" href="{{ url_for('set_language', language='Finnish') }}">Finnish</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='English') }}">English</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='Persian') }}">Persian</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='Greek') }}">Greek</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='Italian') }}">Italian</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='Chinese') }}">Chinese</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='All') }}">Show all languages</a> + </div> + + <a class="nav-item" href="{{ url_for('create_experiment') }}" class="nav-link">| Create experiment |</a> + {% endif %} {% if current_user.is_anonymous %} - <a class="nav-item" href="{{ url_for('login') }}" class="nav-link">Researcher login</a> + <a class="nav-item" href="{{ url_for('login') }}" class="nav-link">Researcher login |</a> + + <a class="nav-item dropdown"> + <a class="nav-item dropdown-toggle text-align-right" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + Language + </a> + <div class="dropdown-menu" aria-labelledby="navbarDropdown"> + + <a class="dropdown-item" href="{{ url_for('set_language', language='Finnish') }}">Finnish</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='English') }}">English</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='Persian') }}">Persian</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='Greek') }}">Greek</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='Italian') }}">Italian</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='Chinese') }}">Chinese</a> + <a class="dropdown-item" href="{{ url_for('set_language', language='All') }}">Show all languages</a> + </div> + + {% else %} <a class="nav-item" href="{{ url_for('logout') }}" class="nav-link">Logout</a> {% endif %} diff --git a/app/templates/consent.html b/app/templates/consent.html index ee2743f84f3df1234de439cbecb676103f61b559..c6b5b6a3c536f658636d46c65a1a3d66baadc96a 100644 --- a/app/templates/consent.html +++ b/app/templates/consent.html @@ -5,11 +5,14 @@ <br> <h4>Lue tutkimustiedote <a href="tiedote.pdf">tästä.</a></h4> <br/> -<p class="lead">Ennen tämän suostumuksen antamista olen lukenut ja ymmärtänyt saamani tutkimustiedotteen, sekä saanut riittävästi tietoa tutkimuksen kulusta. Minulle on selvitetty, että minusta kerättäviä tutkimustietoja tullaan käsittelemään luottamuksellisina siten, että niistä ei voida tunnistaa henkilöllisyyttäni. Ymmärrän, että osallistumiseni tutkimukseen on täysin vapaaehtoista ja että voin missä tutkimuksen vaiheessa tahansa keskeyttää tutkimuksen antamatta perustetta. Minulle on lisäksi selvitetty, että halutessani saan tutkimustiedotteessa nimetyltä tutkijalta lisätietoja tutkimuksen yleisistä periaatteista ja edistymisestä. Ymmärrän, että aineistoa kerätään pelkästään tieteellistä tutkimusta varten eikä sitä luovuteta osittainkaan koehenkilölle itselleen, ja että tietokoneeni IP-osoitetta tai muita tunnistetietoja ei tallenneta. +<p class="lead">Prior to giving the consent I have read and understood the Experiment/ Research Bulletin I received, and I have received sufficient information about the course of the experiment. I have been clarified that the experiment data collected from me will be treated confidentially in such way that my identity can not be identified. I understand that my participation in the study is completely voluntary and that I can stop the experiment at any stage of the experiment without giving any reason. Furthermore, I have been clarified that I will receive further information about the general principles and the progress of the experiment from the researcher mentioned at the Experiment/ Research Bulletin, if I wish to do so. I understand that the data is collected only for purposes of the scientific research and it is not even partially disclosed to the participant himself/ herself and that my IP address or other identifying information will not be saved. + </p> -<p class="lead">Klikkaamalla alla olevaa painiketta annan suostumukseni tutkimuksen yhteydessä tapahtuvaan tietojen keräämiseen ja niiden käsittelyyn tiedotteessa kuvatulla tavalla. +<p class="lead">By clicking on the button below, I give my consent to the collection and processing of the data in this experiment, as described in the Experiment/ Research Bulletin. + </p> -<p class="lead">Tästä elektronisesta suostumuksesta säilytetään digitaalinen merkintä tutkimuksesta vastaavan tutkijan tiedostoissa. +<p class="lead">Of this electronical consent, there will be a digital entry saved in the files of the researcher responsible for the experiment. + </p> <p> <a class="btn btn-primary" href="{{ url_for('participant_session', exp_id=exp_id, agree='true') }}" role="button">Agree</a> diff --git a/app/templates/create_experiment.html b/app/templates/create_experiment.html index d8ca0c7eecb319b09568159c8d7dae999bb3d1b3..97c32750bc5003430c0edb997beb6ef618302be4 100644 --- a/app/templates/create_experiment.html +++ b/app/templates/create_experiment.html @@ -31,7 +31,7 @@ <option value="Bulgarian">Bulgarian</option> <option value="Catalan">Catalan</option> <option value="Cambodian">Cambodian</option> - <option value="Chinese (Mandarin)">Chinese (Mandarin)</option> + <option value="Chinese">Chinese</option> <option value="Croation">Croation</option> <option value="Czech">Czech</option> <option value="Danish">Danish</option> diff --git a/app/templates/index.html b/app/templates/index.html index 55823d0e92d837f5afaf30283bf7a8028d28e1c9..5aa7c8c65c8b958484e6cf0e230bf65e2d64e450 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -2,17 +2,22 @@ {% block content %} - <h1 class="container mt-5 display-4 text-center"><br>{{ _('Welcome') }}</h1> + <h1 class="container mt-5 display-4 text-center"><br>{{ _('Welcome to Onni') }}</h1> <br> - <p class="lead">This is the Human Emotion Systems laboratorys stimulus rating tool. If you have previously started a rating task you can continue that task on this page. If you are a researcher you can create new rating tasks by <a href="{{ url_for('login') }}">logging in.</a> - Or you can start a new rating task and start rating by selecting a rating task from the database list below.</p> + <br> + <p class="lead text-center">This is the Human Emotion Systems laboratorys stimulus rating tool. If you have previously started a rating task you can continue that task on this page. If you are a researcher you can create new rating tasks by <a href="{{ url_for('login') }}">logging in.</a> + Or you can start a new rating task and start rating by selecting a task from the database list below. + <br> + <br> + You can choose the language suitable for you from the language menu in the upper right corner + </p> <div class="row"> <div class="col mt-5"> <h3>List of experiments in database:</h3> {% block attributes %} {% for exp in experiments %} - {% if exp.status == 'Public' %} + {% if exp.status == 'Public' and session['language'] == exp.language %} <ul class="list-group mb-4"> <li class="list-group-item active"><span class="font-weight-bold">Name:</span> {{ exp.name }} </li> @@ -39,14 +44,50 @@ <a class="btn btn-outline-info" href="{{ url_for('view_experiment', exp_id=exp.idexperiment) }}" role="button">View / Edit</a> {% endif %} - + </ul> <br> <br> {% endif %} - {% if (exp.status == 'Hidden') and (current_user.is_authenticated) %} + + {% if exp.status == 'Public' and session['language'] == "All" %} + + <ul class="list-group mb-4"> + <li class="list-group-item active"><span class="font-weight-bold">Name:</span> {{ exp.name }} </li> + <li class="list-group-item"><span class="font-weight-bold">Instruction:</span> {{ exp.instruction }}</li> + {% if current_user.is_authenticated %} + <li class="list-group-item"><span class="font-weight-bold">ID number:</span> {{ exp.idexperiment }} </li> + <li class="list-group-item"><span class="font-weight-bold">Language:</span> {{ exp.language }}</li> + <li class="list-group-item"><span class="font-weight-bold">Status:</span> {{ exp.status }}</li> + {% endif %} + <li class="list-group-item"> + <button class="btn btn-outline-success dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + Begin task + </button> + <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> + <a class="dropdown-item" href="{{ url_for('consent', exp_id=exp.idexperiment) }}">As a new participant</a> + <a class="dropdown-item" href="{{ url_for('begin_with_id', exp_id=exp.idexperiment) }}">I have received an ID to use for this task</a> + </div> + <a class="btn btn-outline-success" href="{{ url_for('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('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> + + {% endif %} + + + </ul> + <br> + <br> + {% endif %} + + + {% if (exp.status == 'Hidden') and (current_user.is_authenticated) and session['language'] == exp.language %} <br> <h3>Unpublished experiment:</h3> <ul class="list-group mb-4"> @@ -80,7 +121,38 @@ {% endif %} - + {% if (exp.status == 'Hidden') and (current_user.is_authenticated) and session['language'] == "All" %} + <br> + <h3>Unpublished experiment:</h3> + <ul class="list-group mb-4"> + <li class="list-group-item list-group-item-dark"><span class="font-weight-bold">Name:</span> {{ exp.name }} </li> + <li class="list-group-item"><span class="font-weight-bold">Instruction:</span> {{ exp.instruction }}</li> + {% if current_user.is_authenticated %} + <li class="list-group-item"><span class="font-weight-bold">ID number:</span> {{ exp.idexperiment }} </li> + <li class="list-group-item"><span class="font-weight-bold">Language:</span> {{ exp.language }}</li> + <li class="list-group-item"><span class="font-weight-bold">Status:</span> {{ exp.status }}</li> + {% endif %} + <li class="list-group-item"> + <button class="btn btn-outline-success dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + Begin task + </button> + <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> + <a class="dropdown-item" href="{{ url_for('consent', exp_id=exp.idexperiment) }}">As a new participant</a> + <a class="dropdown-item" href="{{ url_for('begin_with_id', exp_id=exp.idexperiment) }}">I have received an ID to use for this task</a> + </div> + <a class="btn btn-outline-success" href="{{ url_for('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('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> + + + {% endif %} + </li> + </ul> + + {% endif %} {% endfor %} {% endblock %} diff --git a/config.py b/config.py index 1b0d9356cbbbf4f52771b93dcff024c4c8880d8f..ce6f05c6ad42b45e175f50ec0706eac598162a72 100644 --- a/config.py +++ b/config.py @@ -5,7 +5,23 @@ class Config(object): #seret key is set in __ini__.py #SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess' + + + + + #SQLITE3 connection settings: + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'app.db') SQLALCHEMY_TRACK_MODIFICATIONS = False + + #MariaDB mysql database settings + """ + 'mysql+pymysql://'+MYSQL_USER+':'+MYSQL_PASSWORD+'@'+MYSQL_SERVER+'/'+MYSQL_DB+'?charset=utf8mb4' + + MYSQL_USER rating + MYSQL_PASSWORD timotimo + MYSQL_SERVER localhost + MYSQL_DB rating_tool_db + """ \ No newline at end of file diff --git a/migrations/README b/migrations/README new file mode 100644 index 0000000000000000000000000000000000000000..98e4f9c44effe479ed38c66ba922e7bcc672916f --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 0000000000000000000000000000000000000000..f8ed4801f78bcb83cc6acb589508c1b24eda297a --- /dev/null +++ b/migrations/alembic.ini @@ -0,0 +1,45 @@ +# A generic, single database configuration. + +[alembic] +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 0000000000000000000000000000000000000000..23663ff2f54e6c4425953537976b175246c8a9e6 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,87 @@ +from __future__ import with_statement +from alembic import context +from sqlalchemy import engine_from_config, pool +from logging.config import fileConfig +import logging + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger('alembic.env') + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +from flask import current_app +config.set_main_option('sqlalchemy.url', + current_app.config.get('SQLALCHEMY_DATABASE_URI')) +target_metadata = current_app.extensions['migrate'].db.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure(url=url) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + engine = engine_from_config(config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool) + + connection = engine.connect() + context.configure(connection=connection, + target_metadata=target_metadata, + process_revision_directives=process_revision_directives, + **current_app.extensions['migrate'].configure_args) + + try: + with context.begin_transaction(): + context.run_migrations() + finally: + connection.close() + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 0000000000000000000000000000000000000000..2c0156303a8df3ffdc9de87765bf801bf6bea4a5 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/migrations/versions/75ace1b8b1e0_.py b/migrations/versions/75ace1b8b1e0_.py new file mode 100644 index 0000000000000000000000000000000000000000..d34fc9a96ca801f6e97cfd38edfa9f893addd82f --- /dev/null +++ b/migrations/versions/75ace1b8b1e0_.py @@ -0,0 +1,137 @@ +"""empty message + +Revision ID: 75ace1b8b1e0 +Revises: +Create Date: 2018-11-04 18:40:37.722652 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '75ace1b8b1e0' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('background_question', + sa.Column('idbackground_question', sa.Integer(), nullable=False), + sa.Column('background_question', sa.String(length=120), nullable=True), + sa.Column('experiment_idexperiment', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('idbackground_question') + ) + op.create_table('experiment', + sa.Column('idexperiment', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=120), nullable=True), + sa.Column('instruction', sa.String(length=120), nullable=True), + sa.Column('directoryname', sa.String(length=120), nullable=True), + sa.Column('language', sa.String(length=120), nullable=True), + sa.Column('status', sa.String(length=120), nullable=True), + sa.Column('randomization', sa.String(length=120), nullable=True), + sa.PrimaryKeyConstraint('idexperiment') + ) + op.create_index(op.f('ix_experiment_directoryname'), 'experiment', ['directoryname'], unique=True) + op.create_index(op.f('ix_experiment_instruction'), 'experiment', ['instruction'], unique=False) + op.create_index(op.f('ix_experiment_name'), 'experiment', ['name'], unique=False) + op.create_table('trial_randomization', + sa.Column('idtrial_randomization', sa.Integer(), nullable=False), + sa.Column('page_idpage', sa.Integer(), nullable=True), + sa.Column('randomized_idpage', sa.Integer(), nullable=True), + sa.Column('answer_set_idanswer_set', sa.Integer(), nullable=True), + sa.Column('experiment_idexperiment', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('idtrial_randomization') + ) + op.create_table('user', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('username', sa.String(length=64), nullable=True), + sa.Column('email', sa.String(length=120), nullable=True), + sa.Column('password_hash', sa.String(length=128), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_user_email'), 'user', ['email'], unique=True) + op.create_index(op.f('ix_user_username'), 'user', ['username'], unique=True) + op.create_table('answer_set', + sa.Column('idanswer_set', sa.Integer(), nullable=False), + sa.Column('experiment_idexperiment', sa.Integer(), nullable=True), + sa.Column('session', sa.String(length=120), nullable=True), + sa.Column('agreement', sa.String(length=120), nullable=True), + sa.Column('answer_counter', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['experiment_idexperiment'], ['experiment.idexperiment'], ), + sa.PrimaryKeyConstraint('idanswer_set') + ) + op.create_table('background_question_option', + sa.Column('idbackground_question_option', sa.Integer(), nullable=False), + sa.Column('background_question_idbackground_question', sa.Integer(), nullable=True), + sa.Column('option', sa.String(length=120), nullable=True), + sa.ForeignKeyConstraint(['background_question_idbackground_question'], ['background_question.idbackground_question'], ), + sa.PrimaryKeyConstraint('idbackground_question_option') + ) + op.create_table('page', + sa.Column('idpage', sa.Integer(), nullable=False), + sa.Column('experiment_idexperiment', sa.Integer(), nullable=True), + sa.Column('type', sa.String(length=120), nullable=True), + sa.Column('text', sa.String(length=120), nullable=True), + sa.Column('media', sa.String(length=120), nullable=True), + sa.ForeignKeyConstraint(['experiment_idexperiment'], ['experiment.idexperiment'], ), + sa.PrimaryKeyConstraint('idpage') + ) + op.create_index(op.f('ix_page_media'), 'page', ['media'], unique=False) + op.create_index(op.f('ix_page_text'), 'page', ['text'], unique=False) + op.create_index(op.f('ix_page_type'), 'page', ['type'], unique=False) + op.create_table('question', + sa.Column('idquestion', sa.Integer(), nullable=False), + sa.Column('experiment_idexperiment', sa.Integer(), nullable=True), + sa.Column('question', sa.String(length=120), nullable=True), + sa.Column('left', sa.String(length=120), nullable=True), + sa.Column('right', sa.String(length=120), nullable=True), + sa.ForeignKeyConstraint(['experiment_idexperiment'], ['experiment.idexperiment'], ), + sa.PrimaryKeyConstraint('idquestion') + ) + op.create_table('answer', + sa.Column('idanswer', sa.Integer(), nullable=False), + sa.Column('question_idquestion', sa.Integer(), nullable=True), + sa.Column('answer_set_idanswer_set', sa.Integer(), nullable=True), + sa.Column('answer', sa.String(length=120), nullable=True), + sa.Column('page_idpage', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['answer_set_idanswer_set'], ['answer_set.idanswer_set'], ), + sa.ForeignKeyConstraint(['page_idpage'], ['page.idpage'], ), + sa.ForeignKeyConstraint(['question_idquestion'], ['question.idquestion'], ), + sa.PrimaryKeyConstraint('idanswer') + ) + op.create_table('background_question_answer', + sa.Column('idbackground_question_answer', sa.Integer(), nullable=False), + sa.Column('answer_set_idanswer_set', sa.Integer(), nullable=True), + sa.Column('answer', sa.String(length=120), nullable=True), + sa.Column('background_question_idbackground_question', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['answer_set_idanswer_set'], ['answer_set.idanswer_set'], ), + sa.ForeignKeyConstraint(['background_question_idbackground_question'], ['background_question.idbackground_question'], ), + sa.PrimaryKeyConstraint('idbackground_question_answer') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('background_question_answer') + op.drop_table('answer') + op.drop_table('question') + op.drop_index(op.f('ix_page_type'), table_name='page') + op.drop_index(op.f('ix_page_text'), table_name='page') + op.drop_index(op.f('ix_page_media'), table_name='page') + op.drop_table('page') + op.drop_table('background_question_option') + op.drop_table('answer_set') + op.drop_index(op.f('ix_user_username'), table_name='user') + op.drop_index(op.f('ix_user_email'), table_name='user') + op.drop_table('user') + op.drop_table('trial_randomization') + op.drop_index(op.f('ix_experiment_name'), table_name='experiment') + op.drop_index(op.f('ix_experiment_instruction'), table_name='experiment') + op.drop_index(op.f('ix_experiment_directoryname'), table_name='experiment') + op.drop_table('experiment') + op.drop_table('background_question') + # ### end Alembic commands ###