from flask_wtf import FlaskForm, Recaptcha, RecaptchaField from flask import current_app from flask_user.forms import ( unique_email_validator, LoginForm, RegisterForm, ChangePasswordForm ) from flask_user import UserManager from wtforms.widgets import TextArea, NumberInput from wtforms import ( StringField, BooleanField, SubmitField, validators, IntegerField, SelectField, PasswordField ) from wtforms.validators import DataRequired, Optional from app.models import PlayKey def password_check(form, field): """ Validates that the password does not contain a colon, is between 6 and 40 characters long and has an uppercase letter, lowercase letter and a number """ error_msg = "Password must be between 6 and 40 characters long, contain a lowercase letter, an uppercase letter, a number, and cannot contain a colon" password = field.data pass_len = len(password) if pass_len < 6: raise validators.ValidationError(error_msg) if ':' in password: raise validators.ValidationError(error_msg) if not any(c.islower() for c in password): raise validators.ValidationError(error_msg) if not any(c.isupper() for c in password): raise validators.ValidationError(error_msg) if not any(c.isdigit() for c in password): raise validators.ValidationError(error_msg) if pass_len > 40: raise validators.ValidationError(error_msg) return True def validate_play_key(form, field): """Validates a field for a valid play kyey Args: form: REQUIRED, the field's parent form field: REQUIRED, the field with data Returns: None, raises ValidationError if failed """ # jank to get the foreign key that we need back into the field if current_app.config["REQUIRE_PLAY_KEY"]: field.data = PlayKey.key_is_valid(key_string=field.data) return True class CustomRecaptcha(Recaptcha): def __call__(self, form, field): if not current_app.config.get("RECAPTCHA_ENABLE", False): return True return super(CustomRecaptcha, self).__call__(form, field) class CustomUserManager(UserManager): def customize(self, app): self.RegisterFormClass = CustomRegisterForm self.LoginFormClass = CustomLoginForm self.ChangePasswordFormClass = ColonlessChangePasswordForm class CustomRegisterForm(RegisterForm): play_key_id = StringField( 'Play Key', validators=[validate_play_key] ) recaptcha = RecaptchaField( validators=[CustomRecaptcha()] ) password=PasswordField( 'Password', validators=[DataRequired(), password_check] ) class CustomLoginForm(LoginForm): recaptcha = RecaptchaField( validators=[CustomRecaptcha()] ) class CreatePlayKeyForm(FlaskForm): count = IntegerField( 'How many Play Keys to create', validators=[DataRequired()] ) uses = IntegerField( 'How many uses each new play key will have', validators=[DataRequired()] ) submit = SubmitField('Create!') class EditPlayKeyForm(FlaskForm): active = BooleanField( 'Active' ) uses = IntegerField( 'Play Key Uses' ) notes = StringField( 'Notes', widget=TextArea() ) submit = SubmitField('Submit') class EditGMLevelForm(FlaskForm): gm_level = IntegerField( 'GM Level', widget=NumberInput(min=0, max=9) ) submit = SubmitField('Submit') class EditEmailForm(FlaskForm): email = StringField( 'E-Mail', validators=[ Optional(), validators.Email('Invalid email address'), unique_email_validator, ] ) submit = SubmitField('Submit') class ResolveBugReportForm(FlaskForm): resolution = StringField( 'Resolution', widget=TextArea(), validators=[DataRequired()] ) submit = SubmitField('Submit') class SendMailForm(FlaskForm): recipient = SelectField( 'Recipient: ', coerce=str, choices=[ ("", ""), ("0", "All Characters"), ], validators=[validators.DataRequired()] ) subject = StringField( 'Subject', validators=[validators.DataRequired()] ) body = StringField( 'Body', widget=TextArea(), validators=[validators.DataRequired()] ) attachment = SelectField( "Attachment", coerce=str, choices=[(0, "No Attachment")] ) attachment_count = IntegerField( 'Attachment Count', default=0 ) submit = SubmitField('Submit') class RescueForm(FlaskForm): save_world = SelectField( 'Move to:', coerce=str, choices=[ ("", ""), ], validators=[validators.DataRequired()] ) submit = SubmitField('Submit') class RejectPropertyForm(FlaskForm): rejection_reason = StringField( 'Rejection Reason', widget=TextArea(), validators=[validators.DataRequired()] ) submit = SubmitField('Submit') class CharXMLUploadForm(FlaskForm): char_xml = StringField( 'Paste minified charxml here:', widget=TextArea(), validators=[validators.DataRequired()] ) submit = SubmitField('Submit') class ColonlessChangePasswordForm(ChangePasswordForm): new_password = PasswordField( 'New Password', validators=[validators.DataRequired(), password_check] )