mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-04 12:22:47 +00:00 
			
		
		
		
	Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development
This commit is contained in:
		@@ -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'])
 | 
			
		||||
 
 | 
			
		||||
@@ -26,13 +26,12 @@ def add_corpus():
 | 
			
		||||
        try:
 | 
			
		||||
            os.makedirs(dir)
 | 
			
		||||
        except OSError:
 | 
			
		||||
            flash('[ERROR]: Could not add corpus!')
 | 
			
		||||
            flash('[ERROR]: Could not add corpus!', 'corpus')
 | 
			
		||||
            corpus.delete()
 | 
			
		||||
        else:
 | 
			
		||||
            corpus_url = url_for('corpora.corpus', corpus_id=corpus.id)
 | 
			
		||||
            flash('<i class="left material-icons">book</i>'
 | 
			
		||||
                  '[<a href="{}">{}</a>] added'.format(corpus_url,
 | 
			
		||||
                                                       corpus.title))
 | 
			
		||||
            url = url_for('corpora.corpus', corpus_id=corpus.id)
 | 
			
		||||
            flash('[<a href="{}">{}</a>] added'.format(url, corpus.title),
 | 
			
		||||
                  'corpus')
 | 
			
		||||
            return redirect(url_for('corpora.corpus', corpus_id=corpus.id))
 | 
			
		||||
    return render_template('corpora/add_corpus.html.j2',
 | 
			
		||||
                           add_corpus_form=add_corpus_form,
 | 
			
		||||
@@ -82,7 +81,7 @@ def delete_corpus(corpus_id):
 | 
			
		||||
    if not (corpus.creator == current_user or current_user.is_administrator()):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    tasks.delete_corpus(corpus_id)
 | 
			
		||||
    flash('Corpus deleted!')
 | 
			
		||||
    flash('Corpus deleted!', 'corpus')
 | 
			
		||||
    return redirect(url_for('main.dashboard'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -121,7 +120,7 @@ def add_corpus_file(corpus_id):
 | 
			
		||||
        db.session.add(corpus_file)
 | 
			
		||||
        corpus.status = 'unprepared'
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
        flash('Corpus file added!')
 | 
			
		||||
        flash('Corpus file added!', 'corpus')
 | 
			
		||||
        return make_response(
 | 
			
		||||
            {'redirect_url': url_for('corpora.corpus', corpus_id=corpus.id)},
 | 
			
		||||
            201)
 | 
			
		||||
@@ -141,7 +140,7 @@ def delete_corpus_file(corpus_id, corpus_file_id):
 | 
			
		||||
            or current_user.is_administrator()):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    tasks.delete_corpus_file(corpus_file_id)
 | 
			
		||||
    flash('Corpus file deleted!')
 | 
			
		||||
    flash('Corpus file deleted!', 'corpus')
 | 
			
		||||
    return redirect(url_for('corpora.corpus', corpus_id=corpus_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -188,7 +187,7 @@ def edit_corpus_file(corpus_id, corpus_file_id):
 | 
			
		||||
        corpus_file.title = edit_corpus_file_form.title.data
 | 
			
		||||
        corpus.status = 'unprepared'
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
        flash('Corpus file edited!')
 | 
			
		||||
        flash('Corpus file edited!', 'corpus')
 | 
			
		||||
        return redirect(url_for('corpora.corpus', corpus_id=corpus_id))
 | 
			
		||||
    # If no form is submitted or valid, fill out fields with current values
 | 
			
		||||
    edit_corpus_file_form.address.data = corpus_file.address
 | 
			
		||||
@@ -217,7 +216,7 @@ def prepare_corpus(corpus_id):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    if corpus.files.all():
 | 
			
		||||
        tasks.build_corpus(corpus_id)
 | 
			
		||||
        flash('Corpus gets build now.')
 | 
			
		||||
        flash('Corpus gets build now.', 'corpus')
 | 
			
		||||
    else:
 | 
			
		||||
        flash('Can not build corpus, please add corpus file(s).')
 | 
			
		||||
        flash('Can not build corpus, please add corpus file(s).', 'corpus')
 | 
			
		||||
    return redirect(url_for('corpora.corpus', corpus_id=corpus_id))
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ def create_message(recipient, subject, template, **kwargs):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@background
 | 
			
		||||
def send(app, msg):
 | 
			
		||||
def send(msg, *args, **kwargs):
 | 
			
		||||
    app = kwargs['app']
 | 
			
		||||
    with app.app_context():
 | 
			
		||||
        mail.send(msg)
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ def delete_job(job_id):
 | 
			
		||||
    if not (job.creator == current_user or current_user.is_administrator()):
 | 
			
		||||
        abort(403)
 | 
			
		||||
    tasks.delete_job(job_id)
 | 
			
		||||
    flash('Job has been deleted!')
 | 
			
		||||
    flash('Job has been deleted!', 'job')
 | 
			
		||||
    return redirect(url_for('main.dashboard'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,7 @@ def service(service):
 | 
			
		||||
            os.makedirs(absolut_dir)
 | 
			
		||||
        except OSError:
 | 
			
		||||
            job.delete()
 | 
			
		||||
            flash('Internal Server Error')
 | 
			
		||||
            flash('Internal Server Error', 'job')
 | 
			
		||||
            return make_response({'redirect_url': url_for('services.service',
 | 
			
		||||
                                                          service=service)},
 | 
			
		||||
                                 500)
 | 
			
		||||
@@ -74,9 +74,8 @@ def service(service):
 | 
			
		||||
                db.session.add(job_input)
 | 
			
		||||
            job.status = 'submitted'
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
            job_url = url_for('jobs.job', job_id=job.id)
 | 
			
		||||
            flash('<i class="left material-icons">work</i>'
 | 
			
		||||
                  '[<a href="{}">{}</a>] added'.format(job_url, job.title))
 | 
			
		||||
            url = url_for('jobs.job', job_id=job.id)
 | 
			
		||||
            flash('[<a href="{}">{}</a>] added'.format(url, job.title), 'job')
 | 
			
		||||
            return make_response(
 | 
			
		||||
                {'redirect_url': url_for('jobs.job', job_id=job.id)}, 201)
 | 
			
		||||
    return render_template('services/{}.html.j2'.format(service),
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,7 @@ class CorpusAnalysisClient {
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        errorText = `Error ${response.payload.code} - ${response.payload.msg}`;
 | 
			
		||||
        nopaque.flash("error", errorText);
 | 
			
		||||
        nopaque.flash(errorText, "error");
 | 
			
		||||
        if (this.displays.query.errorContainer != undefined)  {
 | 
			
		||||
          this.displays.query.errorContainer.innerHTML = `<p class="red-text">`+
 | 
			
		||||
                    `<i class="material-icons tiny">error</i> ${errorText}</p>`;
 | 
			
		||||
 
 | 
			
		||||
@@ -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(`[<a href="/jobs/${pathArray[0]}">${nopaque.jobs[pathArray[0]].title}</a>] New status: ${operation.value}`, "job");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    nopaque.jobs = jsonpatch.apply_patch(nopaque.jobs, patch);
 | 
			
		||||
    for (let subscriber of nopaque.jobsSubscribers) {subscriber._update(patch);}
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
@@ -188,23 +184,28 @@ nopaque.flash = function() {
 | 
			
		||||
      message = arguments[0];
 | 
			
		||||
      break;
 | 
			
		||||
    case 2:
 | 
			
		||||
      category = arguments[0];
 | 
			
		||||
      message = arguments[1];
 | 
			
		||||
      message = arguments[0];
 | 
			
		||||
      category = arguments[1];
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      console.error("Usage: nopaque.flash(message) or nopaque.flash(category, message)")
 | 
			
		||||
      console.error("Usage: nopaque.flash(message) or nopaque.flash(message, category)")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  switch (category) {
 | 
			
		||||
    case "corpus":
 | 
			
		||||
      message = `<i class="left material-icons">book</i>${message}`;
 | 
			
		||||
      break;
 | 
			
		||||
    case "error":
 | 
			
		||||
      classes = "red";
 | 
			
		||||
      message = `<i class="left material-icons red-text">error</i>${message}`;
 | 
			
		||||
      break;
 | 
			
		||||
    case "job":
 | 
			
		||||
      message = `<i class="left material-icons">work</i>${message}`;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      classes = "";
 | 
			
		||||
      message = `<i class="left material-icons">notifications</i>${message}`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toast = M.toast({classes: classes,
 | 
			
		||||
                   html: `<span>${message}</span>
 | 
			
		||||
  toast = M.toast({html: `<span>${message}</span>
 | 
			
		||||
                          <button data-action="close" class="btn-flat toast-action white-text">
 | 
			
		||||
                            <i class="material-icons">close</i>
 | 
			
		||||
                          </button>`});
 | 
			
		||||
@@ -229,7 +230,8 @@ document.addEventListener("DOMContentLoaded", function() {
 | 
			
		||||
  nopaque.Forms.init();
 | 
			
		||||
  nopaque.Navigation.init();
 | 
			
		||||
  while (nopaque.flashedMessages.length) {
 | 
			
		||||
    nopaque.flash(...nopaque.flashedMessages.shift());
 | 
			
		||||
    flashedMessage = nopaque.flashedMessages.shift();
 | 
			
		||||
    nopaque.flash(flashedMessage[1], flashedMessage[0]);
 | 
			
		||||
  }
 | 
			
		||||
  if (nopaque.user.isAuthenticated) {
 | 
			
		||||
    if (nopaque.user.settings.darkMode) {
 | 
			
		||||
 
 | 
			
		||||
@@ -378,7 +378,7 @@ class ResultsList extends List {
 | 
			
		||||
      if (expertModeSwitchElement.checked) {
 | 
			
		||||
        this.expertModeOn("query-display");  // page holds new result rows, so add new tooltips
 | 
			
		||||
      }
 | 
			
		||||
      nopaque.flash("Updated matches per page.")
 | 
			
		||||
      nopaque.flash("Updated matches per page.", "corpus")
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      // console.log(e);
 | 
			
		||||
      // console.log("resultsList has no results right now.");
 | 
			
		||||
@@ -394,7 +394,7 @@ class ResultsList extends List {
 | 
			
		||||
    let rc;
 | 
			
		||||
    try {
 | 
			
		||||
        if (event.type === "change") {
 | 
			
		||||
            nopaque.flash("Updated context per match!");
 | 
			
		||||
            nopaque.flash("Updated context per match!", "corpus");
 | 
			
		||||
        }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
    } finally {
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -16,27 +16,27 @@
 | 
			
		||||
            <p class="light">Activate dark mode to ease your eyes.</p>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="col s3 right-align">
 | 
			
		||||
            <div class="switch">
 | 
			
		||||
              <label>
 | 
			
		||||
                {{ edit_general_settings_form.dark_mode() }}
 | 
			
		||||
                <span class="lever"></span>
 | 
			
		||||
              </label>
 | 
			
		||||
            </div>
 | 
			
		||||
            {{ M.render_field(edit_general_settings_form.dark_mode, 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>Email notifications</p>
 | 
			
		||||
            <p class="light">Receive emails when a job completes.</p>
 | 
			
		||||
          <div class="col s12 m8">
 | 
			
		||||
            <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>
 | 
			
		||||
          <div class="col s12 m4 right-align">
 | 
			
		||||
            {{ 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 s12 m8">
 | 
			
		||||
            <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 s12 m4 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 ###
 | 
			
		||||
		Reference in New Issue
	
	Block a user