mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-11-14 16:55:42 +00:00
A lot of database changes and add options to change notification level
This commit is contained in:
parent
76e7d65017
commit
565274fce1
@ -17,10 +17,13 @@ def before_request():
|
||||
Checks if a user is unconfirmed when visiting specific sites. Redirects to
|
||||
unconfirmed view if user is unconfirmed.
|
||||
"""
|
||||
if (current_user.is_authenticated and not current_user.confirmed
|
||||
and request.blueprint != 'auth'
|
||||
and request.endpoint != 'static'):
|
||||
return redirect(url_for('auth.unconfirmed'))
|
||||
if current_user.is_authenticated:
|
||||
current_user.ping()
|
||||
if not current_user.confirmed \
|
||||
and request.endpoint \
|
||||
and request.blueprint != 'auth' \
|
||||
and request.endpoint != 'static':
|
||||
return redirect(url_for('auth.unconfirmed'))
|
||||
|
||||
|
||||
@auth.route('/login', methods=['GET', 'POST'])
|
||||
|
@ -106,13 +106,18 @@ class User(UserMixin, db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
# Fields
|
||||
confirmed = db.Column(db.Boolean, default=False)
|
||||
last_seen = db.Column(db.DateTime(), default=datetime.utcnow)
|
||||
email = db.Column(db.String(254), unique=True, index=True)
|
||||
password_hash = db.Column(db.String(128))
|
||||
registration_date = db.Column(db.DateTime(), default=datetime.utcnow)
|
||||
member_since = db.Column(db.DateTime(), default=datetime.utcnow)
|
||||
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
|
||||
username = db.Column(db.String(64), unique=True, index=True)
|
||||
# Setting Fields
|
||||
setting_dark_mode = db.Column(db.Boolean, default=False)
|
||||
setting_job_status_mail_notifications = db.Column(db.String(16),
|
||||
default='end')
|
||||
setting_job_status_site_notifications = db.Column(db.String(16),
|
||||
default='all')
|
||||
# Relationships
|
||||
corpora = db.relationship('Corpus', backref='creator', lazy='dynamic',
|
||||
cascade='save-update, merge, delete')
|
||||
@ -205,6 +210,10 @@ class User(UserMixin, db.Model):
|
||||
"""
|
||||
return self.can(Permission.ADMIN)
|
||||
|
||||
def ping(self):
|
||||
self.last_seen = datetime.utcnow()
|
||||
db.session.add(self)
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Delete the user and its corpora and jobs from database and filesystem.
|
||||
|
@ -1,6 +1,6 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import (BooleanField, PasswordField, StringField, SubmitField,
|
||||
ValidationError)
|
||||
from wtforms import (BooleanField, PasswordField, SelectField, StringField,
|
||||
SubmitField, ValidationError)
|
||||
from wtforms.validators import DataRequired, Email, EqualTo
|
||||
|
||||
|
||||
@ -11,6 +11,20 @@ class EditEmailForm(FlaskForm):
|
||||
|
||||
class EditGeneralSettingsForm(FlaskForm):
|
||||
dark_mode = BooleanField('Dark mode')
|
||||
job_status_mail_notifications = SelectField(
|
||||
'Job status mail notifications',
|
||||
choices=[('', 'Choose your option'),
|
||||
('all', 'Notify on all status changes'),
|
||||
('end', 'Notify only when a job ended'),
|
||||
('none', 'No status update notifications')],
|
||||
validators=[DataRequired()])
|
||||
job_status_site_notifications = SelectField(
|
||||
'Job status site notifications',
|
||||
choices=[('', 'Choose your option'),
|
||||
('all', 'Notify on all status changes'),
|
||||
('end', 'Notify only when a job ended'),
|
||||
('none', 'No status update notifications')],
|
||||
validators=[DataRequired()])
|
||||
save_settings = SubmitField('Save settings')
|
||||
|
||||
|
||||
|
@ -11,8 +11,7 @@ from .. import db
|
||||
def settings():
|
||||
edit_email_form = EditEmailForm(prefix='edit-email-form')
|
||||
edit_general_settings_form = EditGeneralSettingsForm(
|
||||
prefix='edit-general-settings-form'
|
||||
)
|
||||
prefix='edit-general-settings-form')
|
||||
edit_password_form = EditPasswordForm(prefix='edit-password-form',
|
||||
user=current_user)
|
||||
# Check if edit_email_form is submitted and valid
|
||||
@ -25,7 +24,12 @@ def settings():
|
||||
# Check if edit_settings_form is submitted and valid
|
||||
if (edit_general_settings_form.save_settings.data
|
||||
and edit_general_settings_form.validate_on_submit()):
|
||||
current_user.setting_dark_mode = edit_general_settings_form.dark_mode.data
|
||||
current_user.setting_dark_mode = \
|
||||
edit_general_settings_form.dark_mode.data
|
||||
current_user.setting_job_status_mail_notifications = \
|
||||
edit_general_settings_form.job_status_mail_notifications.data
|
||||
current_user.setting_job_status_site_notifications = \
|
||||
edit_general_settings_form.job_status_site_notifications.data
|
||||
db.session.add(current_user)
|
||||
db.session.commit()
|
||||
flash('Your settings have been updated.')
|
||||
@ -41,6 +45,10 @@ def settings():
|
||||
# If no form is submitted or valid, fill out fields with current values
|
||||
edit_email_form.email.data = current_user.email
|
||||
edit_general_settings_form.dark_mode.data = current_user.setting_dark_mode
|
||||
edit_general_settings_form.job_status_site_notifications.data = \
|
||||
current_user.setting_job_status_site_notifications
|
||||
edit_general_settings_form.job_status_mail_notifications.data = \
|
||||
current_user.setting_job_status_mail_notifications
|
||||
return render_template(
|
||||
'profile/settings.html.j2',
|
||||
edit_email_form=edit_email_form,
|
||||
|
@ -43,13 +43,6 @@ nopaque.socket.init = function() {
|
||||
var patch;
|
||||
|
||||
patch = JSON.parse(msg);
|
||||
for (operation of patch) {
|
||||
/* "/corpusId/valueName" -> ["corpusId", "valueName"] */
|
||||
pathArray = operation.path.split("/").slice(1);
|
||||
if (operation.op === "replace" && pathArray[1] === "status") {
|
||||
nopaque.flash(`<i class="left material-icons">book</i>[<a href="/jobs/${pathArray[0]}">${nopaque.corpora[pathArray[0]].title}</a>] New status: ${operation.value}`);
|
||||
}
|
||||
}
|
||||
nopaque.corpora = jsonpatch.apply_patch(nopaque.corpora, patch);
|
||||
for (let subscriber of nopaque.corporaSubscribers) {subscriber._update(patch);}
|
||||
});
|
||||
@ -58,14 +51,17 @@ nopaque.socket.init = function() {
|
||||
var patch;
|
||||
|
||||
patch = JSON.parse(msg);
|
||||
for (operation of patch) {
|
||||
/* "/jobId/valueName" -> ["jobId", "valueName"] */
|
||||
pathArray = operation.path.split("/").slice(1);
|
||||
if (operation.op === "replace" && pathArray[1] === "status") {
|
||||
nopaque.flash(`<i class="left material-icons">work</i>[<a href="/jobs/${pathArray[0]}">${nopaque.jobs[pathArray[0]].title}</a>] New status: ${operation.value}`);
|
||||
nopaque.jobs = jsonpatch.apply_patch(nopaque.jobs, patch);
|
||||
if (["all", "end"].includes(nopaque.user.settings.jobStatusSiteNotifications)) {
|
||||
for (operation of patch) {
|
||||
/* "/jobId/valueName" -> ["jobId", "valueName"] */
|
||||
pathArray = operation.path.split("/").slice(1);
|
||||
if (operation.op === "replace" && pathArray[1] === "status") {
|
||||
if (nopaque.user.settings.jobStatusSiteNotifications === "end" && !["complete", "failed"].includes(operation.value)) {continue;}
|
||||
nopaque.flash(`<i class="left material-icons">work</i>[<a href="/jobs/${pathArray[0]}">${nopaque.jobs[pathArray[0]].title}</a>] New status: ${operation.value}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
nopaque.jobs = jsonpatch.apply_patch(nopaque.jobs, patch);
|
||||
for (let subscriber of nopaque.jobsSubscribers) {subscriber._update(patch);}
|
||||
});
|
||||
|
||||
|
@ -15,8 +15,9 @@
|
||||
<li>Username: {{ user.username }}</li>
|
||||
<li>Email: {{ user.email }}</li>
|
||||
<li>ID: {{ user.id }}</li>
|
||||
<li>Registration date: {{ user.registration_date.strftime('%m/%d/%Y, %H:%M:%S %p') }}</li>
|
||||
<li>Member sinse: {{ user.member_since.strftime('%m/%d/%Y, %H:%M:%S %p') }}</li>
|
||||
<li>Confirmed status: {{ user.confirmed }}</li>
|
||||
<li>Last seen: {{ user.last_seen.strftime('%m/%d/%Y, %H:%M:%S %p') }}</li>
|
||||
<li>Role ID: {{ user.role_id }}</li>
|
||||
<li>Permissions as Int: {{ user.role.permissions }}</li>
|
||||
<li>Role name: {{ user.role.name }}</li>
|
||||
|
@ -175,7 +175,6 @@
|
||||
|
||||
for (let operation of patch) {
|
||||
/* "/jobId/valueName" -> ["jobId", "valueName"] */
|
||||
console.log(operation.value);
|
||||
pathArray = operation.path.split("/").slice(1);
|
||||
if (pathArray[0] != this.jobId) {continue;}
|
||||
switch(operation.op) {
|
||||
|
@ -29,12 +29,15 @@
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_boolean_field(field) %}
|
||||
{% set label = kwargs.pop('label', True) %}
|
||||
<div class="switch">
|
||||
{% if 'material_icon' in kwargs %}
|
||||
<i class="material-icons prefix">{{ kwargs.pop('material_icon') }}</i>
|
||||
{% endif %}
|
||||
<label>
|
||||
{% if label %}
|
||||
{{ field.label.text }}
|
||||
{% endif %}
|
||||
{{ field(*args, **kwargs) }}
|
||||
<span class="lever"></span>
|
||||
</label>
|
||||
@ -44,12 +47,6 @@
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_decimal_range_field(field) %}
|
||||
<p class="range-field">
|
||||
{{ field(*args, **kwargs) }}
|
||||
</p>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_file_field(field) %}
|
||||
{% set placeholder = kwargs.pop('placeholder', '') %}
|
||||
<div class="file-field input-field">
|
||||
@ -64,12 +61,15 @@
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_generic_field(field) %}
|
||||
{% set label = kwargs.pop('label', True) %}
|
||||
<div class="input-field">
|
||||
{% if 'material_icon' in kwargs %}
|
||||
<i class="material-icons prefix">{{ kwargs.pop('material_icon') }}</i>
|
||||
{% endif %}
|
||||
{{ field(*args, **kwargs) }}
|
||||
{% if label %}
|
||||
{{ field.label }}
|
||||
{% endif %}
|
||||
{% for error in field.errors %}
|
||||
<span class="helper-text red-text">{{ error }}</span>
|
||||
{% endfor %}
|
||||
|
@ -49,9 +49,15 @@
|
||||
<script src="{{ url_for('static', filename='js/nopaque.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/nopaque.lists.js') }}"></script>
|
||||
<script>
|
||||
nopaque.user.isAuthenticated = {{ current_user.is_authenticated|tojson }};
|
||||
nopaque.user.settings.darkMode = {{ (current_user.is_authenticated and current_user.setting_dark_mode)|tojson }};
|
||||
nopaque.flashedMessages = {{ get_flashed_messages(with_categories=true)|tojson }};
|
||||
{% if current_user.is_authenticated %}
|
||||
nopaque.user.isAuthenticated = true;
|
||||
nopaque.user.settings.darkMode = {{ current_user.setting_dark_mode|tojson }};
|
||||
nopaque.user.settings.jobStatusMailNotifications = {{ current_user.setting_job_status_mail_notifications|tojson }};
|
||||
nopaque.user.settings.jobStatusSiteNotifications = {{ current_user.setting_job_status_site_notifications|tojson }};
|
||||
{% else %}
|
||||
nopaque.user.isAuthenticated = false;
|
||||
{% endif %}
|
||||
nopaque.flashedMessages = {{ get_flashed_messages(with_categories=True)|tojson }};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -27,16 +27,21 @@
|
||||
<div class="col s12 divider"></div>
|
||||
<div class="col s12"><p> </p></div>
|
||||
<div class="col s9">
|
||||
<p><i class="material-icons left">notifications</i>Email notifications</p>
|
||||
<p class="light">Receive emails when a job completes.</p>
|
||||
<p><i class="material-icons left">notifications</i>Job status site notifications</p>
|
||||
<p class="light">Receive site notifications about job status changes.</p>
|
||||
</div>
|
||||
<div class="col s3 right-align">
|
||||
<div class="switch">
|
||||
<label>
|
||||
<input disabled type="checkbox">
|
||||
<span class="lever"></span>
|
||||
</label>
|
||||
</div>
|
||||
{{ M.render_field(edit_general_settings_form.job_status_site_notifications, label=False) }}
|
||||
</div>
|
||||
<div class="col s12"><p> </p></div>
|
||||
<div class="col s12 divider"></div>
|
||||
<div class="col s12"><p> </p></div>
|
||||
<div class="col s9">
|
||||
<p><i class="material-icons left">notifications</i>Job status mail notifications</p>
|
||||
<p class="light">Receive mail notifications about job status changes.</p>
|
||||
</div>
|
||||
<div class="col s3 right-align">
|
||||
{{ M.render_field(edit_general_settings_form.job_status_mail_notifications, label=False) }}
|
||||
</div>
|
||||
<!--
|
||||
Seperate each setting with the following two elements
|
||||
|
30
migrations/versions/099037c4aa06_.py
Normal file
30
migrations/versions/099037c4aa06_.py
Normal file
@ -0,0 +1,30 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: 099037c4aa06
|
||||
Revises: 66253783654f
|
||||
Create Date: 2020-04-27 09:17:15.039728
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '099037c4aa06'
|
||||
down_revision = '66253783654f'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('users', sa.Column('last_seen', sa.DateTime(), nullable=True))
|
||||
op.add_column('users', sa.Column('setting_site_job_status_notifications', sa.String(length=16), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('users', 'setting_site_job_status_notifications')
|
||||
op.drop_column('users', 'last_seen')
|
||||
# ### end Alembic commands ###
|
36
migrations/versions/49a42c69e523_.py
Normal file
36
migrations/versions/49a42c69e523_.py
Normal file
@ -0,0 +1,36 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: 49a42c69e523
|
||||
Revises: 099037c4aa06
|
||||
Create Date: 2020-04-27 11:18:32.999099
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '49a42c69e523'
|
||||
down_revision = '099037c4aa06'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('users', sa.Column('member_since', sa.DateTime(), nullable=True))
|
||||
op.add_column('users', sa.Column('setting_job_status_mail_notifications', sa.String(length=16), nullable=True))
|
||||
op.add_column('users', sa.Column('setting_job_status_site_notifications', sa.String(length=16), nullable=True))
|
||||
op.drop_column('users', 'setting_site_job_status_notifications')
|
||||
op.drop_column('users', 'registration_date')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('users', sa.Column('registration_date', postgresql.TIMESTAMP(), autoincrement=False, nullable=True))
|
||||
op.add_column('users', sa.Column('setting_site_job_status_notifications', sa.VARCHAR(length=16), autoincrement=False, nullable=True))
|
||||
op.drop_column('users', 'setting_job_status_site_notifications')
|
||||
op.drop_column('users', 'setting_job_status_mail_notifications')
|
||||
op.drop_column('users', 'member_since')
|
||||
# ### end Alembic commands ###
|
Loading…
Reference in New Issue
Block a user