diff --git a/lumi2/templates/usermanager/user_detail.html b/lumi2/templates/usermanager/user_detail.html
index 87e298a..8b5d013 100644
--- a/lumi2/templates/usermanager/user_detail.html
+++ b/lumi2/templates/usermanager/user_detail.html
@@ -4,18 +4,29 @@
User: {{ user.username }}
{% endblock content %}
diff --git a/lumi2/usermanager.py b/lumi2/usermanager.py
index 57ce00a..646a502 100644
--- a/lumi2/usermanager.py
+++ b/lumi2/usermanager.py
@@ -4,9 +4,13 @@ from pathlib import Path
from tempfile import TemporaryDirectory
from flask import (
- Blueprint, render_template, abort, request, flash
+ Blueprint, render_template, abort, request, flash, redirect
)
from PIL import Image, UnidentifiedImageError
+from flask_wtf import FlaskForm
+from flask_wtf.file import FileField, FileAllowed
+from wtforms import ValidationError, StringField, PasswordField
+from wtforms.validators import InputRequired, Email, EqualTo
import lumi2.ldap as ldap
from lumi2.usermodel import User, Group
@@ -22,52 +26,39 @@ def index():
return render_template('usermanager/index.html')
-class InvalidImageException(Exception):
- """Raised when an image's filename or contents are invalid."""
- pass
+class UserEditForm(FlaskForm):
+ @staticmethod
+ def validate_name(form, field) -> None:
+ if not User.is_valid_person_name(field.data):
+ raise ValidationError("Invalid name.")
-
-def _get_image_from_uploaded_file(file) -> Image.Image:
- """Extracts a JPEG image from a file submitted via POST request.
-
- The file's file extension and content is checked for validity as a JPEG image.
-
- Parameters
- ----------
- file
- A file object taken from a POST request.
-
- Returns
- -------
- PIL.Image.Image
- A valid JPEG Image object.
-
- Raises
- ------
- InvalidImageException
- When the file's file extension or contents are not valid for a JPEG image.
- """
-
- def _file_extension_is_valid(filename: str):
- allowed_extensions = ["jpg", "jpeg"]
- if '.' not in filename:
- return False
- if filename.rsplit('.', 1)[1].lower() not in allowed_extensions:
- return False
- return True
-
- if not _file_extension_is_valid(file.filename):
- raise InvalidImageException("Invalid file extension.")
-
- with TemporaryDirectory() as tempdir:
- path_to_file = Path(tempdir) / "upload.jpg"
- file.save(path_to_file)
- try:
- return Image.open(path_to_file, formats=['JPEG'])
- except UnidentifiedImageError:
- raise InvalidImageException(
- "Image is either not a JPEG, or its contents are corrupted."
- )
+ email = StringField(
+ 'Email',
+ [InputRequired(), Email()]
+ )
+ first_name = StringField(
+ 'First Name',
+ [InputRequired(), validate_name]
+ )
+ last_name = StringField(
+ 'Last Name',
+ [InputRequired(), validate_name]
+ )
+ display_name = StringField(
+ 'Nick Name',
+ [InputRequired(), validate_name]
+ )
+ password = PasswordField(
+ 'Password',
+ [EqualTo('password_confirmation', message='Passwords must match')],
+ )
+ password_confirmation = PasswordField(
+ 'Password (repeat)',
+ )
+ picture = FileField(
+ 'Picture',
+ [FileAllowed(['jpg', 'jpeg'], 'JPEG images only.')]
+ )
@bp.route("/user/", methods=("GET", "POST"))
@@ -87,52 +78,19 @@ def user_detail(username: str):
user._generate_static_images()
- if request.method == 'POST':
- form_is_valid = True
+ # data = {
+ # "email": user.email,
+ # "first_name": user.first_name,
+ # "last_name": user.last_name,
+ # "display_name": user.display_name,
+ # }
- if request.form['email']:
- user.email = request.form['email']
- if not User.is_valid_email(user.email):
- flash("Invalid email address.")
- form_is_valid = False
+ form = UserEditForm(obj=user)
+ if form.validate_on_submit():
+ conn.unbind()
- if request.form['first_name']:
- user.first_name = request.form['first_name']
- if not User.is_valid_person_name(user.first_name):
- flash("Invalid first name.")
- form_is_valid = False
-
- if request.form['last_name']:
- user.last_name = request.form['last_name']
- if not User.is_valid_person_name(user.last_name):
- flash("Invalid last name.")
- form_is_valid = False
-
- if request.form['display_name']:
- user.display_name = request.form['display_name']
- if not User.is_valid_person_name(user.display_name):
- flash("Invalid nickname.")
- form_is_valid = False
-
- if request.form['password']:
- user.password_hash = User.generate_password_hash(request.form['password'])
-
- new_picture = None
- if 'picture' in request.files:
- file = request.files['picture']
- if len(file.filename):
- try:
- new_picture = _get_image_from_uploaded_file(file)
- user.picture = new_picture
- except InvalidImageException as e:
- flash(f"Invalid picture: {e}")
- form_is_valid = False
-
- if form_is_valid:
- ldap.update_user(conn, user)
- flash("User information was updated!")
- if new_picture is not None:
- ldap.get_user(conn, user.username)._generate_static_images(force=True)
+ # TODO update user
+ return redirect(request.url)
conn.unbind()
- return render_template('usermanager/user_detail.html', user=user)
+ return render_template('usermanager/user_detail.html', form=form, user=user)
diff --git a/requirements.txt b/requirements.txt
index 65b5d78..4452050 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,3 +3,6 @@ ldap3==2.9.1
pytest==7.2.0
coverage==6.5.0
Pillow==9.3.0
+WTForms==3.0.1
+wtforms[email]==3.0.1
+Flask-WTF==1.0.1