There will be a short maintenance break on Wed 27.10. at 12:00. Estimated time 30 minutes.

Commit c433a793 authored by Ossi Laine's avatar Ossi Laine
Browse files

Merge branch 'feat-user-groups' into 'master'

Feat user groups

See merge request tithei/pet-rating!9
parents 9968f630 dc85793f
{% extends "base.html" %} {% extends "base.html" %} {% block content %}
{% block content %} <h1 class="container mt-5 display-4 text-center">
<h1 class="container mt-5 display-4 text-center"><br>Create new experiment: (1/4)</h1> <br />Create new experiment: (1/4)
<br> </h1>
<br> <br />
<p class="lead">Please input the following information. All fields are required. <br />
</p> <p class="lead">
{% from "_formhelpers.html" import render_field %} Please input the following information. All fields are required.
<div class=container"><br> </p>
<div class="row align-items-center justify-content-center"> {% from "_formhelpers.html" import render_field %} <div class=container"><br />
<div class="col-12"> <div class="row align-items-center justify-content-center">
<form action="" method="post" role="form"> <div class="col-12">
<div class="form-group"> <form action="" method="post" role="form">
<label for="name">Your name:</label> <div class="form-group">
<input required type="text" class="form-control" id="creator_name" name="creator_name" placeholder="Creator name?"> <label for="name">Your name:</label>
<br> <input
<label for="name">Name of the experiment:</label> required
<input required type="text" class="form-control" id="name" name="name" placeholder="Experiment name?"> type="text"
<br> class="form-control"
id="creator_name"
<div class="form-group"> name="creator_name"
<label for="language">Select a language for the experiment:</label> placeholder="Creator name?"
<select class="form-control" id="language" name="language"> />
<option disabled selected value></option> <br />
<option value="Afrikanns">Afrikanns</option> {% for group in groups %} {{ group }} {% endfor %}
<option value="Albanian">Albanian</option> <label for="research-group">Group:</label>
<option value="Arabic">Arabic</option> <select class="form-control" id="group" name="group">
<option value="Armenian">Armenian</option> {% for group in valid_groups %}
<option value="Basque">Basque</option> <option value="{{group.id}}">{{ group.name }}</option>
<option value="Bengali">Bengali</option> {% endfor %}
<option value="Bulgarian">Bulgarian</option> </select>
<option value="Catalan">Catalan</option>
<option value="Cambodian">Cambodian</option>
<option value="Chinese">Chinese</option>
<option value="Croation">Croation</option>
<option value="Czech">Czech</option>
<option value="Danish">Danish</option>
<option value="Dutch">Dutch</option>
<option value="English">English</option>
<option value="Estonian">Estonian</option>
<option value="Fiji">Fiji</option>
<option value="Finnish">Finnish</option>
<option value="French">French</option>
<option value="Georgian">Georgian</option>
<option value="German">German</option>
<option value="Greek">Greek</option>
<option value="Gujarati">Gujarati</option>
<option value="Hebrew">Hebrew</option>
<option value="Hindi">Hindi</option>
<option value="Hungarian">Hungarian</option>
<option value="Icelandic">Icelandic</option>
<option value="Indonesian">Indonesian</option>
<option value="Irish">Irish</option>
<option value="Italian">Italian</option>
<option value="Japanese">Japanese</option>
<option value="Javanese">Javanese</option>
<option value="Korean">Korean</option>
<option value="Latin">Latin</option>
<option value="Latvian">Latvian</option>
<option value="Lithuanian">Lithuanian</option>
<option value="Macedonian">Macedonian</option>
<option value="Malay">Malay</option>
<option value="Malayalam">Malayalam</option>
<option value="Maltese">Maltese</option>
<option value="Maori">Maori</option>
<option value="Marathi">Marathi</option>
<option value="Mongolian">Mongolian</option>
<option value="Nepali">Nepali</option>
<option value="Norwegian">Norwegian</option>
<option value="Persian">Persian</option>
<option value="Polish">Polish</option>
<option value="Portuguese">Portuguese</option>
<option value="Punjabi">Punjabi</option>
<option value="Quechua">Quechua</option>
<option value="Romanian">Romanian</option>
<option value="Russian">Russian</option>
<option value="Samoan">Samoan</option>
<option value="Serbian">Serbian</option>
<option value="Slovak">Slovak</option>
<option value="Slovenian">Slovenian</option>
<option value="Spanish">Spanish</option>
<option value="Swahili">Swahili</option>
<option value="Swedish ">Swedish </option>
<option value="Tamil">Tamil</option>
<option value="Tatar">Tatar</option>
<option value="Telugu">Telugu</option>
<option value="Thai">Thai</option>
<option value="Tibetan">Tibetan</option>
<option value="Tonga">Tonga</option>
<option value="Turkish">Turkish</option>
<option value="Ukranian">Ukranian</option>
<option value="Urdu">Urdu</option>
<option value="Uzbek">Uzbek</option>
<option value="Vietnamese">Vietnamese</option>
<option value="Welsh">Welsh</option>
<option value="Xhosa">Xhosa</option>
</select>
<br> <br />
<p>Instructions for the experiment come in three forms: <label for="name">Name of the experiment:</label>
<br> (1) A single sentence instruction that is shown during the rating task above the sliders. <input
<br> (2) A short general description of the task that is shown on the experiment listing on Onni's front page and on the informed consent page. required
<br> (3) a longer detailed explanation of the instructions that is shown to the participant after the consent and before the rating task begins. type="text"
<br> Please input all three types of instructions below: class="form-control"
</p> id="name"
name="name"
<label for="single_sentence_instruction">(1) Single sentence:</label> placeholder="Experiment name?"
<input required type="text" class="form-control" id="single_sentence_instruction" name="single_sentence_instruction" placeholder="Input here" required> />
<br> <br />
<label for="short_instruction">(2) Short description:</label>
<textarea class="form-control" rows="5" id="short_instruction" name="short_instruction" placeholder="Input here" required></textarea>
<br>
<div class="form-group">
<label for="language">Select a language for the experiment:</label>
<select class="form-control" id="language" name="language">
<!--<option disabled selected value></option>-->
<option value="Afrikanns">Afrikanns</option>
<option value="Albanian">Albanian</option>
<option value="Arabic">Arabic</option>
<option value="Armenian">Armenian</option>
<option value="Basque">Basque</option>
<option value="Bengali">Bengali</option>
<option value="Bulgarian">Bulgarian</option>
<option value="Catalan">Catalan</option>
<option value="Cambodian">Cambodian</option>
<option value="Chinese">Chinese</option>
<option value="Croation">Croation</option>
<option value="Czech">Czech</option>
<option value="Danish">Danish</option>
<option value="Dutch">Dutch</option>
<option selected value="English">English</option>
<option value="Estonian">Estonian</option>
<option value="Fiji">Fiji</option>
<option value="Finnish">Finnish</option>
<option value="French">French</option>
<option value="Georgian">Georgian</option>
<option value="German">German</option>
<option value="Greek">Greek</option>
<option value="Gujarati">Gujarati</option>
<option value="Hebrew">Hebrew</option>
<option value="Hindi">Hindi</option>
<option value="Hungarian">Hungarian</option>
<option value="Icelandic">Icelandic</option>
<option value="Indonesian">Indonesian</option>
<option value="Irish">Irish</option>
<option value="Italian">Italian</option>
<option value="Japanese">Japanese</option>
<option value="Javanese">Javanese</option>
<option value="Korean">Korean</option>
<option value="Latin">Latin</option>
<option value="Latvian">Latvian</option>
<option value="Lithuanian">Lithuanian</option>
<option value="Macedonian">Macedonian</option>
<option value="Malay">Malay</option>
<option value="Malayalam">Malayalam</option>
<option value="Maltese">Maltese</option>
<option value="Maori">Maori</option>
<option value="Marathi">Marathi</option>
<option value="Mongolian">Mongolian</option>
<option value="Nepali">Nepali</option>
<option value="Norwegian">Norwegian</option>
<option value="Persian">Persian</option>
<option value="Polish">Polish</option>
<option value="Portuguese">Portuguese</option>
<option value="Punjabi">Punjabi</option>
<option value="Quechua">Quechua</option>
<option value="Romanian">Romanian</option>
<option value="Russian">Russian</option>
<option value="Samoan">Samoan</option>
<option value="Serbian">Serbian</option>
<option value="Slovak">Slovak</option>
<option value="Slovenian">Slovenian</option>
<option value="Spanish">Spanish</option>
<option value="Swahili">Swahili</option>
<option value="Swedish ">Swedish</option>
<option value="Tamil">Tamil</option>
<option value="Tatar">Tatar</option>
<option value="Telugu">Telugu</option>
<option value="Thai">Thai</option>
<option value="Tibetan">Tibetan</option>
<option value="Tonga">Tonga</option>
<option value="Turkish">Turkish</option>
<option value="Ukranian">Ukranian</option>
<option value="Urdu">Urdu</option>
<option value="Uzbek">Uzbek</option>
<option value="Vietnamese">Vietnamese</option>
<option value="Welsh">Welsh</option>
<option value="Xhosa">Xhosa</option>
</select>
<label for="instruction">(3) Longer version:</label> <br />
<textarea class="form-control" rows="15" id="instruction" name="instruction" placeholder="Input here" required></textarea> <p>
<br> Instructions for the experiment come in three forms: <br />
(1) A single sentence instruction that is shown during the rating
task above the sliders. <br />
(2) A short general description of the task that is shown on the
experiment listing on Onni's front page and on the informed consent
page. <br />
(3) a longer detailed explanation of the instructions that is shown
to the participant after the consent and before the rating task
begins. <br />
Please input all three types of instructions below:
</p>
<label for="instruction">Please input consent form text</label> <label for="single_sentence_instruction">(1) Single sentence:</label>
<textarea class="form-control" rows="15" id="consent_text" name="consent_text" placeholder="Input here" required></textarea> <input
<br> required
type="text"
class="form-control"
id="single_sentence_instruction"
name="single_sentence_instruction"
placeholder="Input here"
required
/>
<br />
<label for="short_instruction">(2) Short description:</label>
<textarea
class="form-control"
rows="5"
id="short_instruction"
name="short_instruction"
placeholder="Input here"
required
></textarea>
<br />
<label for="instruction">(3) Longer version:</label>
<textarea
class="form-control"
rows="15"
id="instruction"
name="instruction"
placeholder="Input here"
required
></textarea>
<br />
<label for="instruction">Please input consent form text</label>
<textarea
class="form-control"
rows="15"
id="consent_text"
name="consent_text"
placeholder="Input here"
required
></textarea>
<br />
</div>
</div> </div>
</div> <br />
<br> <button type="submit" class="btn btn-primary">Submit</button>
<button type="submit" class="btn btn-primary">Submit</button> </form>
</form>
{% endblock %} {% endblock %}
\ No newline at end of file </div>
</div>
...@@ -16,12 +16,7 @@ from flask_login import login_required ...@@ -16,12 +16,7 @@ from flask_login import login_required
from app.routes import APP_ROOT from app.routes import APP_ROOT
from app import app, db from app import app, db
from app.models import background_question, experiment from app.models import background_question, experiment, background_question_answer, page, question, background_question_option, answer_set, answer, forced_id, user, trial_randomization, research_group, user_in_group
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 ( from app.forms import (
CreateExperimentForm, CreateBackgroundQuestionForm, CreateExperimentForm, CreateBackgroundQuestionForm,
CreateQuestionForm, UploadStimuliForm CreateQuestionForm, UploadStimuliForm
...@@ -39,20 +34,32 @@ def create_experiment(): ...@@ -39,20 +34,32 @@ def create_experiment():
form = CreateExperimentForm(request.form) form = CreateExperimentForm(request.form)
user_groups = user_in_group.query.filter_by(
iduser=session['user_id']).all()
if user_groups:
user_groups = [ug.idgroup for ug in user_groups]
valid_groups = research_group.query.filter(
research_group.id.in_(user_groups)).all()
else:
valid_groups = []
if request.method == 'POST' and form.validate(): if request.method == 'POST' and form.validate():
the_time = datetime.now() the_time = datetime.now()
the_time = the_time.replace(microsecond=0) 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'], 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') 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', group_id=request.form['group'])
db.session.add(new_exp) db.session.add(new_exp)
db.session.commit() db.session.commit()
exp_id = new_exp.idexperiment exp_id = new_exp.idexperiment
return redirect(url_for('create.experiment_bgquestions', exp_id=exp_id)) return redirect(url_for('create.experiment_bgquestions', exp_id=exp_id))
return render_template('create_experiment.html', form=form) return render_template('create_experiment.html', form=form, valid_groups=valid_groups)
@create_blueprint.route('/experiment_bgquestions', methods=['GET', 'POST']) @create_blueprint.route('/experiment_bgquestions', methods=['GET', 'POST'])
......
...@@ -58,6 +58,11 @@ ...@@ -58,6 +58,11 @@
<td>{{ exp.creator_name }} - {{ exp.creation_time }}</td> <td>{{ exp.creator_name }} - {{ exp.creation_time }}</td>
<td nowrap></td> <td nowrap></td>
</tr> </tr>
<tr>
<td nowrap>Group:</td>
<td>{{ group_info.name }}</td>
<td nowrap></td>
</tr>
<tr> <tr>
<td nowrap>Language:</td> <td nowrap>Language:</td>
<td>{{ exp.language }}</td> <td>{{ exp.language }}</td>
......
...@@ -20,13 +20,7 @@ from flask import ( ...@@ -20,13 +20,7 @@ from flask import (
from app import app, db, socketio from app import app, db, socketio
from app.routes import APP_ROOT from app.routes import APP_ROOT
from app.models import background_question, experiment from app.models import background_question, experiment, background_question_answer, page, question, background_question_option, answer_set, answer, forced_id, trial_randomization, embody_answer, embody_question, research_group
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 trial_randomization
from app.models import embody_answer, embody_question
from app.forms import ( from app.forms import (
CreateBackgroundQuestionForm, CreateBackgroundQuestionForm,
CreateQuestionForm, UploadStimuliForm, EditBackgroundQuestionForm, CreateQuestionForm, UploadStimuliForm, EditBackgroundQuestionForm,
...@@ -62,6 +56,9 @@ def view(): ...@@ -62,6 +56,9 @@ def view():
# experiment info # experiment info
experiment_info = experiment.query.filter_by(idexperiment=exp_id).all() experiment_info = experiment.query.filter_by(idexperiment=exp_id).all()
group_info = research_group.query.filter_by(
id=experiment_info[0].group_id).first()
# background questions # background questions
questions_and_options = {} questions_and_options = {}
questions = background_question.query.filter_by( questions = background_question.query.filter_by(
...@@ -93,7 +90,7 @@ def view(): ...@@ -93,7 +90,7 @@ def view():
embody_pictures = embody_question.query.filter_by( embody_pictures = embody_question.query.filter_by(
experiment_idexperiment=exp_id).all() experiment_idexperiment=exp_id).all()
return render_template('view_experiment.html', exp_id=exp_id, media=media, mtype=mtype, experiment_info=experiment_info, categories1=categories1, questions1=questions1, embody_pictures=embody_pictures) return render_template('view_experiment.html', exp_id=exp_id, media=media, mtype=mtype, experiment_info=experiment_info, categories1=categories1, questions1=questions1, embody_pictures=embody_pictures, group_info=group_info)
# Experiment info: # Experiment info:
......
...@@ -10,6 +10,52 @@ from app import login ...@@ -10,6 +10,52 @@ from app import login
from datetime import datetime from datetime import datetime
class user(UserMixin, db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
def __repr__(self):
return '<user {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
@login.user_loader
def load_user(id):
return user.query.get(int(id))
class research_group(db.Model):
__tablename__ = "research_group"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text)
tag = db.Column(db.Text)
description = db.Column(db.Text)
def __repr__(self):
return "<id= '%s', name= '%s', tag= '%s', description= '%s' >" % (self.id, self.name, self.tag, self.description)
class user_in_group (db.Model):
__tablename__ = "user_in_group"
__table_args__ = (
db.PrimaryKeyConstraint('idgroup', 'iduser'),
)
idgroup = db.Column(
db.Integer, db.ForeignKey('research_group.id'))
iduser = db.Column(
db.Integer, db.ForeignKey('user.id'))
role = db.Column(db.Text)
class background_question(db.Model): class background_question(db.Model):
__tablename__ = "background_question" __tablename__ = "background_question"
idbackground_question = db.Column(db.Integer, primary_key=True) idbackground_question = db.Column(db.Integer, primary_key=True)
...@@ -53,6 +99,9 @@ class experiment (db.Model): ...@@ -53,6 +99,9 @@ class experiment (db.Model):
use_forced_id = db.Column(db.String(120)) use_forced_id = db.Column(db.String(120))
embody_enabled = db.Column(db.Boolean, unique=False, default=False) embody_enabled = db.Column(db.Boolean, unique=False, default=False)
group_id = db.Column(
db.Integer, db.ForeignKey('research_group.id'))
def __repr__(self): def __repr__(self):
return "<idexperiment = '%s', name='%s', instruction='%s', directoryname='%s', language='%s', status='%s', randomization='%s', short_instruction='%s', single_sentence_instruction='%s', is_archived='%s', creator_name='%s', research_notification_filename='%s', creation_time='%s', stimulus_size='%s', consent_text='%s', use_forced_id='%s', embody_enabled='%s'>" % (self.idexperiment, self.name, self.instruction, self.directoryname, self.language, self.status, self.randomization, self.short_instruction, self.single_sentence_instruction, self.is_archived, self.creator_name, self.research_notification_filename, self.creation_time, self.stimulus_size, self.consent_text, self.use_forced_id, self.embody_enabled) return "<idexperiment = '%s', name='%s', instruction='%s', directoryname='%s', language='%s', status='%s', randomization='%s', short_instruction='%s', single_sentence_instruction='%s', is_archived='%s', creator_name='%s', research_notification_filename='%s', creation_time='%s', stimulus_size='%s', consent_text='%s', use_forced_id='%s', embody_enabled='%s'>" % (self.idexperiment, self.name, self.instruction, self.directoryname, self.language, self.status, self.randomization, self.short_instruction, self.single_sentence_instruction, self.is_archived, self.creator_name, self.research_notification_filename, self.creation_time, self.stimulus_size, self.consent_text, self.use_forced_id, self.embody_enabled)
...@@ -207,25 +256,3 @@ class forced_id (db.Model): ...@@ -207,25 +256,3 @@ class forced_id (db.Model):
def __repr__(self): def __repr__(self):
return "<idforced_id = '%s', experiment_idexperiment = '%s', pregenerated_id = '%s'>" % (self.idforced_id, self.experiment_idexperiment, self.pregenerated_id) return "<idforced_id = '%s', experiment_idexperiment = '%s', pregenerated_id = '%s'>" % (self.idforced_id, self.experiment_idexperiment, self.pregenerated_id)
class user(UserMixin, db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
def __repr__(self):
return '<user {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
@login.user_loader
def load_user(id):
return user.query.get(int(id))
...@@ -3,22 +3,13 @@ import random ...@@ -3,22 +3,13 @@ import random
import secrets import secrets
from datetime import datetime from datetime import datetime
from flask import (render_template, from flask import render_template, request, session, flash, redirect, url_for
request,
session,
flash,
redirect,
url_for)
from sqlalchemy import and_ from sqlalchemy import and_
from flask_login import current_user, login_user, logout_user, login_required from flask_login import current_user, login_user, logout_user, login_required
from app import app, db from app import app, db
from app.models import background_question, experiment from app.models import (background_question, experiment, background_question_answer, page,
from app.models import background_question_answer background_question_option, answer_set, forced_id, user, trial_randomization, research_group)
from app.models import page
from app.models import background_question_option
from app.models import answer_set, forced_id
from app.models import user, trial_randomization
from app.forms import LoginForm, RegisterForm, StartWithIdForm from app.forms import LoginForm, RegisterForm, StartWithIdForm
# Stimuli upload folder setting # Stimuli upload folder setting
...@@ -28,15 +19,33 @@ APP_ROOT = os.path.dirname(os.path.abspath(__file__)) ...@@ -28,15 +19,33 @@ APP_ROOT = os.path.dirname(os.path.abspath(__file__))
@app.route('/') @app.route('/')
@app.route('/index') @app.route('/index')
def index(): def index():
experiments = experiment.query.all() groups = research_group.query.all()
session['group'] = None
if 'language' not in session:
session['language'] = "All"
return render_template('home.html', title='Home', groups=groups)
@app.route('/<group_tag>')
def group_page(group_tag):
#experiments = experiment.query.all()
if session: group = research_group.query.filter_by(tag=group_tag).first()
flash("")