prototoolagain/app/forms.py

144 lines
4.4 KiB
Python

"""WTForms for the application."""
from flask_wtf import FlaskForm
from wtforms import (
StringField,
PasswordField,
SubmitField,
IntegerField,
DateField,
TextAreaField,
SelectField,
FileField,
BooleanField,
RadioField,
)
import os
from werkzeug.utils import secure_filename
from wtforms.validators import (
DataRequired,
Length,
Email,
ValidationError,
)
from flask_login import current_user
def validate_unique_username(username):
from app.models import User
if User.query.filter_by(username=username).first():
raise ValidationError("Username already taken.")
def validate_unique_email(email):
from app.models import User
if User.query.filter_by(email=email).first():
raise ValidationError("Email already registered.")
class LoginForm(FlaskForm):
"""Login form."""
username = StringField(
"Username", validators=[DataRequired(), Length(min=1, max=64)]
)
password = PasswordField("Password", validators=[DataRequired()])
submit = SubmitField("Login")
class UserForm(FlaskForm):
"""User creation and edit form."""
username = StringField(
"Username", validators=[DataRequired(), Length(min=1, max=64)]
)
full_name = StringField(
"Full Name", validators=[DataRequired(), Length(min=1, max=120)]
)
email = StringField("Email", validators=[DataRequired(), Email(), Length(max=120)])
password = PasswordField("Password")
is_admin = BooleanField("Admin")
submit = SubmitField("Submit")
def validate_username(self, field):
if current_user and current_user.id != field.data:
validate_unique_username(field.data)
def validate_email(self, field):
if current_user and current_user.id != field.data:
validate_unique_email(field.data)
class InspectionForm(FlaskForm):
"""Inspection report form."""
installation_name = StringField(
"Installation Name", validators=[DataRequired(), Length(max=120)]
)
location = StringField("Location", validators=[DataRequired(), Length(max=120)])
inspection_date = DateField("Date of Inspection", validators=[DataRequired()])
reference_number = IntegerField("Reference Number", validators=[DataRequired()])
observations = TextAreaField("Observations", validators=[DataRequired()])
conclusion_text = TextAreaField("Conclusion Comments", validators=[DataRequired()])
conclusion_status = RadioField(
"Conclusion Status",
choices=[
("ok", "OK for operation in current state"),
(
"minor",
"Minor comments — Remedial actions required for continued operation",
),
(
"major",
"Major comments — Operation suspended until resolution and satisfactory follow-up inspection",
),
],
default="ok",
)
# Inspectors (multiple) as a field of selectable users and free-text names
inspectors = SelectField("Inspectors", coerce=int, validators=[DataRequired()])
# Photo upload field
photos = FileField(
"Photos", validators=[DataRequired(), validate_photo_upload], multiple=True
)
submit = SubmitField("Complete Report")
class PhotoForm(FlaskForm):
"""Photo upload form."""
caption = StringField("Caption", validators=[Length(max=255)])
action_required = RadioField(
"Action Required",
choices=[
("none", "No action required"),
("urgent", "Urgent action required"),
("before_next", "Action required before next inspection"),
],
default="none",
)
submit = SubmitField("Upload")
def validate_photo_upload(form, field):
from wtforms.validators import ValidationError
allowed_extensions = {"jpg", "jpeg", "png", "gif", "webp"}
max_size_mb = 10
for file in field.data:
if file:
ext = file.filename.rsplit(".", 1)[-1].lower()
if ext not in allowed_extensions:
raise ValidationError(
"Invalid file type. Allowed types: jpg, jpeg, png, gif, webp."
)
# Check file size
file.seek(0, 2) # seek to end
size = file.tell()
file.seek(0) # reset to start
if size > max_size_mb * 1024 * 1024: # 10MB in bytes
raise ValidationError("File size must be <= 10MB.")