From 934ec4af42b8f4be438d7b20fb0a9e8a6b7d24e0 Mon Sep 17 00:00:00 2001
From: Patrick Jentsch <p.jentsch@uni-bielefeld.de>
Date: Tue, 27 Oct 2020 14:23:23 +0100
Subject: [PATCH] Set default form values in view function. Use inheritance for
 admin forms

---
 web/app/admin/forms.py                        | 49 +++----------
 web/app/admin/views.py                        | 35 ++++++----
 web/app/settings/forms.py                     | 10 +--
 web/app/settings/views.py                     | 11 ++-
 .../admin/edit_general_settings.html.j2       | 70 +++++++++++++++++++
 web/app/templates/admin/edit_user.html.j2     | 35 ----------
 web/app/templates/admin/user.html.j2          |  2 +-
 7 files changed, 112 insertions(+), 100 deletions(-)
 create mode 100644 web/app/templates/admin/edit_general_settings.html.j2
 delete mode 100644 web/app/templates/admin/edit_user.html.j2

diff --git a/web/app/admin/forms.py b/web/app/admin/forms.py
index 90a9f640..42706bab 100644
--- a/web/app/admin/forms.py
+++ b/web/app/admin/forms.py
@@ -1,44 +1,15 @@
-from flask import current_app
-from flask_wtf import FlaskForm
-from wtforms import (BooleanField, SelectField, StringField, SubmitField,
-                     ValidationError)
-from wtforms.validators import DataRequired, Email, Length, Regexp
-from ..models import Role, User
+from flask_login import current_user
+from wtforms import BooleanField, SelectField
+from ..models import Role
+from ..settings.forms import EditGeneralSettingsForm
 
 
-class EditUserForm(FlaskForm):
-    email = StringField('Email', validators=[DataRequired(), Email()])
-    username = StringField(
-        'Username',
-        validators=[DataRequired(),
-                    Length(1, 64),
-                    Regexp(current_app.config['ALLOWED_USERNAME_REGEX'],
-                           message='Usernames must have only letters, numbers,'
-                                   ' dots or underscores')]
-    )
+class EditGeneralSettingsAdminForm(EditGeneralSettingsForm):
     confirmed = BooleanField('Confirmed')
-    role = SelectField(
-        'Role',
-        choices = [(role.id, role.name)
-                   for role in Role.query.order_by(Role.name).all()],
-        coerce=int
-    )
-    submit = SubmitField('Update Profile')
+    role = SelectField('Role', coerce=int)
 
-    def __init__(self, user, *args, **kwargs):
-        super().__init__(*args, **kwargs)
+    def __init__(self, user=current_user, *args, **kwargs):
+        super().__init__(*args, user=user, **kwargs)
+        self.role.choices = [(role.id, role.name)
+                             for role in Role.query.order_by(Role.name).all()]
         self.user = user
-        self.email.data = self.email.data or user.email
-        self.username.data = self.username.data or user.username
-        self.confirmed.data = self.confirmed.data or user.confirmed
-        self.role.data = self.role.data or user.role_id
-
-    def validate_email(self, field):
-        if (field.data != self.user.email
-                and User.query.filter_by(email=field.data).first()):
-            raise ValidationError('Email already registered.')
-
-    def validate_username(self, field):
-        if (field.data != self.user.username
-                and User.query.filter_by(username=field.data).first()):
-            raise ValidationError('Username already in use.')
diff --git a/web/app/admin/views.py b/web/app/admin/views.py
index 03083879..ce16c390 100644
--- a/web/app/admin/views.py
+++ b/web/app/admin/views.py
@@ -1,7 +1,7 @@
 from flask import flash, redirect, render_template, url_for
-from flask_login import login_required
+from flask_login import current_user, login_required
 from . import admin
-from .forms import EditUserForm
+from .forms import EditGeneralSettingsAdminForm
 from .. import db
 from ..decorators import admin_required
 from ..models import Role, User
@@ -39,22 +39,29 @@ def delete_user(user_id):
     return redirect(url_for('admin.index'))
 
 
-@admin.route('/users/<int:user_id>/edit', methods=['GET', 'POST'])
+@admin.route('/users/<int:user_id>/edit_general_settings',
+             methods=['GET', 'POST'])
 @login_required
 @admin_required
-def edit_user(user_id):
+def edit_general_settings(user_id):
     user = User.query.get_or_404(user_id)
-    edit_user_form = EditUserForm(user=user)
-    if edit_user_form.validate_on_submit():
-        user.email = edit_user_form.email.data
-        user.username = edit_user_form.username.data
-        user.confirmed = edit_user_form.confirmed.data
-        user.role = Role.query.get(edit_user_form.role.data)
+    form = EditGeneralSettingsAdminForm(user=user)
+    if form.validate_on_submit():
+        user.setting_dark_mode = form.dark_mode.data
+        user.email = form.email.data
+        user.username = form.username.data
+        user.confirmed = form.confirmed.data
+        user.role = Role.query.get(form.role.data)
         db.session.add(user)
         db.session.commit()
         flash('The profile has been updated.')
-        return redirect(url_for('admin.edit_user', user_id=user.id))
-    return render_template('admin/edit_user.html.j2',
-                           edit_user_form=edit_user_form,
-                           title='Edit user',
+        return redirect(url_for('admin.edit_general_settings', user_id=user.id))
+    form.confirmed.data = user.confirmed
+    form.dark_mode.data = user.setting_dark_mode
+    form.email.data = user.email
+    form.role.data = user.role_id
+    form.username.data = user.username
+    return render_template('admin/edit_general_settings.html.j2',
+                           form=form,
+                           title='General settings',
                            user=user)
diff --git a/web/app/settings/forms.py b/web/app/settings/forms.py
index 8cf96415..6f7abeef 100644
--- a/web/app/settings/forms.py
+++ b/web/app/settings/forms.py
@@ -4,6 +4,7 @@ from flask_wtf import FlaskForm
 from wtforms import (BooleanField, PasswordField, SelectField, StringField,
                      SubmitField, ValidationError)
 from wtforms.validators import DataRequired, Email, EqualTo, Length, Regexp
+from ..models import User
 
 
 class ChangePasswordForm(FlaskForm):
@@ -43,9 +44,6 @@ class EditGeneralSettingsForm(FlaskForm):
     def __init__(self, user=current_user, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.user = user
-        self.email.data = self.email.data or user.email
-        self.dark_mode.data = self.dark_mode.data or user.setting_dark_mode
-        self.username.data = self.username.data or user.username
 
     def validate_email(self, field):
         if (field.data != self.user.email
@@ -78,9 +76,3 @@ class EditNotificationSettingsForm(FlaskForm):
     def __init__(self, user=current_user, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.user = user
-        self.job_status_mail_notifications.data = \
-            self.job_status_mail_notifications.data \
-            or user.setting_job_status_mail_notifications
-        self.job_status_site_notifications.data = \
-            self.job_status_site_notifications.data \
-            or user.setting_job_status_site_notifications
diff --git a/web/app/settings/views.py b/web/app/settings/views.py
index 01d4d8f6..1bd4a07f 100644
--- a/web/app/settings/views.py
+++ b/web/app/settings/views.py
@@ -30,7 +30,7 @@ def change_password():
                            title='Change password')
 
 
-@settings.route('/edit_general_settings')
+@settings.route('/edit_general_settings', methods=['GET', 'POST'])
 @login_required
 def edit_general_settings():
     form = EditGeneralSettingsForm()
@@ -40,12 +40,15 @@ def edit_general_settings():
         current_user.username = form.username.data
         db.session.commit()
         flash('Your changes have been saved.')
+    form.dark_mode.data = current_user.setting_dark_mode
+    form.email.data = current_user.email
+    form.username.data = current_user.username
     return render_template('settings/edit_general_settings.html.j2',
                            form=form,
                            title='General settings')
 
 
-@settings.route('/edit_notification_settings')
+@settings.route('/edit_notification_settings', methods=['GET', 'POST'])
 @login_required
 def edit_notification_settings():
     form = EditNotificationSettingsForm()
@@ -56,6 +59,10 @@ def edit_notification_settings():
             form.job_status_site_notifications.data
         db.session.commit()
         flash('Your changes have been saved.')
+    form.job_status_mail_notifications.data = \
+        current_user.setting_job_status_mail_notifications
+    form.job_status_site_notifications.data = \
+        current_user.setting_job_status_site_notifications
     return render_template('settings/edit_notification_settings.html.j2',
                            form=form,
                            title='Notification settings')
diff --git a/web/app/templates/admin/edit_general_settings.html.j2 b/web/app/templates/admin/edit_general_settings.html.j2
new file mode 100644
index 00000000..929a867c
--- /dev/null
+++ b/web/app/templates/admin/edit_general_settings.html.j2
@@ -0,0 +1,70 @@
+{% extends "nopaque.html.j2" %}
+{% import 'materialize/wtf.html.j2' as wtf %}
+
+{% block page_content %}
+<div class="container">
+  <div class="row">
+    <div class="col s12">
+      <h1 id="title">Edit user</h1>
+    </div>
+
+    <div class="col s12 m4">
+      <h2>{{ user.username }}</h2>
+      <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,</p>
+      <a class="waves-effect waves-light btn" href="{{ url_for('.user', user_id=user.id) }}"><i class="material-icons left">arrow_back</i>Back to user administration</a>
+    </div>
+
+    <div class="col s12 m8">
+      <div class="card">
+        <form method="POST">
+          <div class="card-content">
+            {{ form.hidden_tag() }}
+            {{ wtf.render_field(form.username, data_length='64', material_icon='account_circle') }}
+            {{ wtf.render_field(form.email, class_='validate', material_icon='email', type='email') }}
+            {{ wtf.render_field(form.role, material_icon='swap_vert') }}
+            <div class="row">
+              <div class="col s12"><p>&nbsp;</p></div>
+              <div class="col s1">
+                <p><i class="material-icons">brightness_3</i></p>
+              </div>
+              <div class="col s8">
+                <p>{{ form.dark_mode.label.text }}</p>
+                <p class="light">Enable dark mode to ease your eyes.</p>
+              </div>
+              <div class="col s3 right-align">
+                <div class="switch">
+                  <label>
+                    {{ form.dark_mode() }}
+                    <span class="lever"></span>
+                  </label>
+                </div>
+              </div>
+              <div class="col s12"><p>&nbsp;</p></div>
+              <div class="col s12 divider"></div>
+              <div class="col s12"><p>&nbsp;</p></div>
+              <div class="col s1">
+                <p><i class="material-icons">check</i></p>
+              </div>
+              <div class="col s8">
+                <p>{{ form.confirmed.label.text }}</p>
+                <p class="light">Change confirmation status manually.</p>
+              </div>
+              <div class="col s3 right-align">
+                <div class="switch">
+                  <label>
+                    {{ form.confirmed() }}
+                    <span class="lever"></span>
+                  </label>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="card-action right-align">
+            {{ wtf.render_field(form.submit, material_icon='send') }}
+          </div>
+        </form>
+      </div>
+    </div>
+  </div>
+</div>
+{% endblock %}
diff --git a/web/app/templates/admin/edit_user.html.j2 b/web/app/templates/admin/edit_user.html.j2
deleted file mode 100644
index 6e47db5f..00000000
--- a/web/app/templates/admin/edit_user.html.j2
+++ /dev/null
@@ -1,35 +0,0 @@
-{% extends "nopaque.html.j2" %}
-{% import 'materialize/wtf.html.j2' as wtf %}
-
-{% block page_content %}
-<div class="container">
-  <div class="row">
-    <div class="col s12">
-      <h1 id="title">Edit user</h1>
-    </div>
-
-    <div class="col s12 m4">
-      <h2>{{ user.username }}</h2>
-      <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,</p>
-      <a class="waves-effect waves-light btn" href="{{ url_for('.user', user_id=user.id) }}"><i class="material-icons left">arrow_back</i>Back to user administration</a>
-    </div>
-
-    <div class="col s12 m8">
-      <div class="card">
-        <form method="POST">
-          <div class="card-content">
-            {{ edit_user_form.hidden_tag() }}
-            {{ wtf.render_field(edit_user_form.username, data_length='64', material_icon='account_circle') }}
-            {{ wtf.render_field(edit_user_form.email, class_='validate', material_icon='email', type='email') }}
-            {{ wtf.render_field(edit_user_form.role, material_icon='swap_vert') }}
-            {{ wtf.render_field(edit_user_form.confirmed, material_icon='check') }}
-          </div>
-          <div class="card-action right-align">
-            {{ wtf.render_field(edit_user_form.submit, material_icon='send') }}
-          </div>
-        </form>
-      </div>
-    </div>
-  </div>
-</div>
-{% endblock %}
diff --git a/web/app/templates/admin/user.html.j2 b/web/app/templates/admin/user.html.j2
index 81fc243a..570b6dd3 100644
--- a/web/app/templates/admin/user.html.j2
+++ b/web/app/templates/admin/user.html.j2
@@ -30,7 +30,7 @@
           </ul>
         </div>
         <div class="card-action right-align">
-          <a href="{{ url_for('.edit_user', user_id=user.id) }}" class="waves-effect waves-light btn"><i class="material-icons left">edit</i>Edit</a>
+          <a href="{{ url_for('.edit_general_settings', user_id=user.id) }}" class="waves-effect waves-light btn"><i class="material-icons left">edit</i>Edit</a>
           <a data-target="delete-user-modal" class="waves-effect waves-light btn red modal-trigger"><i class="material-icons left">delete</i>Delete</a>
         </div>
       </div>
-- 
GitLab