from typing import Optional from flask_wtf import FlaskForm from pytz import all_timezones from wtforms import BooleanField, FileField, SelectField, StringField, PasswordField, SubmitField, IntegerField, DateTimeLocalField from wtforms.validators import DataRequired, Length, EqualTo, ValidationError, Email, Optional, NumberRange from app.models import User from datetime import datetime class SignupForm(FlaskForm): username = StringField( 'Username', validators=[ DataRequired(), Length(min=4, max=20, message="Username must be between 4 and 20 characters.") ] ) password = PasswordField( 'Password', validators=[ DataRequired(), Length(min=6, message="Password must be at least 6 characters long.") ] ) confirm_password = PasswordField( 'Confirm Password', validators=[ DataRequired(), EqualTo('password', message="Passwords must match.") ] ) submit = SubmitField('Sign Up') # Custom validator to check if username is already taken def validate_username(self, username): user = User.query.filter_by(username=username.data).first() if user: raise ValidationError("Username is already taken. Please choose a different one.") class LoginForm(FlaskForm): username = StringField( 'Username', validators=[DataRequired(message="Username is required.")] ) password = PasswordField( 'Password', validators=[DataRequired(message="Password is required.")] ) submit = SubmitField('Login') class ReadingForm(FlaskForm): timestamp = DateTimeLocalField( 'Timestamp', format='%Y-%m-%dT%H:%M', default=datetime.now, # Set default to current time validators=[DataRequired(message="Timestamp is required.")] ) systolic = IntegerField( 'Systolic (mmHg)', validators=[ DataRequired(), NumberRange(min=50, max=250, message="Systolic pressure must be between 50 and 250 mmHg.") ] ) diastolic = IntegerField( 'Diastolic (mmHg)', validators=[ DataRequired(), NumberRange(min=30, max=150, message="Diastolic pressure must be between 30 and 150 mmHg.") ] ) heart_rate = IntegerField( 'Heart Rate (bpm)', validators=[ DataRequired(), NumberRange(min=30, max=200, message="Heart rate must be between 30 and 200 bpm.") ] ) submit = SubmitField('Save Reading') def validate_timestamp(self, field): from flask_login import current_user from pytz import timezone, AmbiguousTimeError, NonExistentTimeError if not field.data: return if not 1900 <= field.data.year <= 2100: raise ValidationError('Choose a date between 1900 and 2100.') profile = current_user.profile tz = timezone(profile.timezone if profile and profile.timezone else 'UTC') try: tz.localize(field.data.replace(tzinfo=None), is_dst=None) except (AmbiguousTimeError, NonExistentTimeError): raise ValidationError('This local time is ambiguous or skipped by daylight saving. Choose an unambiguous local time.') class DeleteForm(FlaskForm): submit = SubmitField('Delete') class ProfileForm(FlaskForm): name = StringField('Name', validators=[Optional()]) email = StringField('Email', validators=[Optional(), Email()]) profile_pic = FileField('Profile Picture (optional)') timezone = SelectField('Timezone', choices=[(tz, tz) for tz in all_timezones]) systolic_threshold = IntegerField( 'Systolic Threshold (mmHg)', validators=[Optional(), NumberRange(min=90, max=200)] ) diastolic_threshold = IntegerField( 'Diastolic Threshold (mmHg)', validators=[Optional(), NumberRange(min=60, max=120)] ) dark_mode = BooleanField('Enable Dark Mode') submit = SubmitField('Save Settings')