Exemple #1
0
class NewEmailAddressForm(forms.Form):
    email = forms.EmailField(
        __("Email address"),
        validators=[forms.validators.DataRequired(),
                    forms.ValidEmail()],
        widget_attrs={
            'autocorrect': 'none',
            'autocapitalize': 'none'
        })
    type = forms.RadioField(__("Type"),
                            coerce=nullunicode,
                            validators=[forms.validators.Optional()],
                            choices=[(__(u"Home"), __(u"Home")),
                                     (__(u"Work"), __(u"Work")),
                                     (__(u"Other"), __(u"Other"))])

    # TODO: Move to function and place before ValidEmail()
    def validate_email(self, field):
        field.data = field.data.lower()  # Convert to lowercase
        existing = UserEmail.get(email=field.data)
        if existing is not None:
            if existing.user == current_auth.user:
                raise forms.ValidationError(
                    _("You have already registered this email address"))
            else:
                raise forms.ValidationError(
                    _("This email address has already been claimed"))
        existing = UserEmailClaim.get(email=field.data, user=current_auth.user)
        if existing is not None:
            raise forms.ValidationError(
                _("This email address is pending verification"))
Exemple #2
0
class InvoiceForm(forms.Form):
    buyer_taxid = forms.StringField(__("GSTIN"), validators=[forms.validators.Optional(),
        forms.validators.Length(max=255), validate_gstin], filters=[forms.filters.strip(), forms.filters.none_if_empty()])
    invoicee_name = forms.StringField(__("Full name"), validators=[forms.validators.DataRequired(__("Please enter the buyer's full name")),
        forms.validators.Length(max=255)], filters=[forms.filters.strip()])
    invoicee_company = forms.StringField(__("Company"), validators=[forms.validators.Optional(),
        forms.validators.Length(max=255)], filters=[forms.filters.strip()])
    invoicee_email = forms.EmailField(__("Email"), validators=[forms.validators.DataRequired(__("Please enter an email address")),
        forms.validators.Length(min=5, max=80),
        forms.validators.ValidEmail(__("Please enter a valid email"))],
        filters=[forms.filters.strip()])
    street_address_1 = forms.StringField(__("Street address 1"), validators=[forms.validators.DataRequired(__("Please enter the street address")),
        forms.validators.Length(max=255)], filters=[forms.filters.strip()])
    street_address_2 = forms.StringField(__("Street address 2"), validators=[forms.validators.Optional(),
        forms.validators.Length(max=255)], filters=[forms.filters.strip()])
    city = forms.StringField(__("City"), validators=[forms.validators.DataRequired(__("Please enter the city")),
        forms.validators.Length(max=255)], filters=[forms.filters.strip()])
    country_code = forms.StringField(__("Country"), validators=[forms.validators.DataRequired(__("Please select a country")),
        forms.validators.Length(max=2)], filters=[forms.filters.strip()])
    state_code = forms.StringField(__("State code"), validators=[forms.validators.Length(max=4),
        validate_state_code], filters=[forms.filters.strip()])
    state = forms.StringField(__("State"), validators=[forms.validators.Optional(),
        forms.validators.Length(max=255)], filters=[forms.filters.strip(), forms.filters.none_if_empty()])
    postcode = forms.StringField(__("Postcode"), validators=[forms.validators.DataRequired(__("Please enter a postcode")),
        forms.validators.Length(max=8)], filters=[forms.filters.strip()])
Exemple #3
0
class ParticipantForm(forms.Form):
    fullname = forms.StringField(__("Full Name"),
                                 validators=[forms.validators.DataRequired()])
    email = forms.EmailField(__("Email"),
                             validators=[
                                 forms.validators.DataRequired(),
                                 forms.validators.Length(max=80)
                             ])
    phone = forms.StringField(__("Phone number"),
                              validators=[forms.validators.Length(max=80)])
    city = forms.StringField(__("City"),
                             validators=[forms.validators.Length(max=80)])
    company = forms.StringField(__("Company"),
                                validators=[forms.validators.Length(max=80)])
    job_title = forms.StringField(__("Job Title"),
                                  validators=[forms.validators.Length(max=80)])
    twitter = forms.StringField(__("Twitter"),
                                validators=[forms.validators.Length(max=15)])
    events = QuerySelectMultipleField(
        __("Events"),
        widget=ListWidget(),
        option_widget=CheckboxInput(),
        get_label='title',
        validators=[
            forms.validators.DataRequired(u"Select at least one event")
        ])
Exemple #4
0
class AssigneeForm(forms.Form):
    email = forms.EmailField(
        __("Email"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=254)
        ],
    )
    fullname = forms.StringField(__("Full Name"),
                                 validators=[forms.validators.DataRequired()])
    phone = forms.StringField(__("Phone number"),
                              validators=[forms.validators.DataRequired()])

    def validate_email(self, field):
        existing_assignees = (
            Assignee.query.join(LineItem).join(Item).join(Order).filter(
                LineItem.item_id == self.edit_parent.item_id).filter(
                    Order.status != ORDER_STATUS.CANCELLED).filter(
                        Assignee.current.is_(True)).filter(
                            Assignee.email == field.data))
        if self.edit_obj is not None:
            existing_assignees = existing_assignees.filter(
                Assignee.id != self.edit_obj.id)
        if existing_assignees.count() > 0:
            raise forms.ValidationError(
                __("Email address has been already used"))
Exemple #5
0
class ProfileForm(forms.Form):
    fullname = forms.StringField(__("Full name"),
        validators=[forms.validators.DataRequired(), forms.validators.Length(max=80)])
    email = forms.EmailField(__("Email address"),
        validators=[forms.validators.DataRequired(), forms.ValidEmail()],
        widget_attrs={'autocorrect': 'none', 'autocapitalize': 'none'})
    username = forms.AnnotatedTextField(__("Username"), validators=[forms.validators.DataRequired()],
        filters=[forms.filters.none_if_empty()],
        prefix=u"https://hasgeek.com/…",
        widget_attrs={'autocorrect': 'none', 'autocapitalize': 'none'})
    timezone = forms.SelectField(__("Timezone"), validators=[forms.validators.DataRequired()], choices=timezones)

    def validate_username(self, field):
        # # Usernames are now mandatory. This should be commented out:
        # if not field.data:
        #     field.data = None
        #     return
        field.data = field.data.lower()  # Usernames can only be lowercase
        if not valid_username(field.data):
            raise forms.ValidationError(_("Usernames can only have alphabets, numbers and dashes (except at the ends)"))
        if field.data in current_app.config.get('RESERVED_USERNAMES', []):
            raise forms.ValidationError(_("This name is reserved"))
        if not self.edit_user.is_valid_username(field.data):
            raise forms.ValidationError(_("This username is taken"))

    # TODO: Move to function and place before ValidEmail()
    def validate_email(self, field):
        field.data = field.data.lower()  # Convert to lowercase
        existing = UserEmail.get(email=field.data)
        if existing is not None and existing.user != self.edit_obj:
            raise forms.ValidationError(_("This email address has been claimed by another user"))
Exemple #6
0
class EmailPrimaryForm(forms.Form):
    email = forms.EmailField(
        __("Email address"),
        validators=[forms.validators.DataRequired()],
        widget_attrs={
            'autocorrect': 'none',
            'autocapitalize': 'none'
        },
    )
class ProfileForm(forms.Form):
    fullname = forms.StringField(
        __("Full name"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=User.__title_length__)
        ])
    email = forms.EmailField(
        __("Email address"),
        validators=[forms.validators.DataRequired(),
                    forms.ValidEmail()],
        widget_attrs={
            'autocorrect': 'none',
            'autocapitalize': 'none'
        })
    username = forms.AnnotatedTextField(
        __("Username"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=Name.__name_length__)
        ],
        filters=[forms.filters.none_if_empty()],
        prefix=u"https://hasgeek.com/",
        widget_attrs={
            'autocorrect': 'none',
            'autocapitalize': 'none'
        })
    timezone = forms.SelectField(__("Timezone"),
                                 validators=[forms.validators.DataRequired()],
                                 choices=timezones)

    def validate_username(self, field):
        if field.data.lower() in current_app.config['RESERVED_USERNAMES']:
            raise forms.ValidationError(
                _("This name is reserved"
                  ))  # To be deprecated in favour of one below

        reason = self.edit_obj.validate_name_candidate(field.data)
        if not reason:
            return  # Username is available
        if reason == 'invalid':
            raise forms.ValidationError(
                _("Usernames can only have alphabets, numbers and dashes (except at the ends)"
                  ))
        elif reason == 'reserved':
            raise forms.ValidationError(_("This username is reserved"))
        elif reason in ('user', 'org'):
            raise forms.ValidationError(_("This username has been taken"))
        else:
            raise forms.ValidationError(_("This username is not available"))

    # TODO: Move to function and place before ValidEmail()
    def validate_email(self, field):
        existing = UserEmail.get(email=field.data)
        if existing is not None and existing.user != self.edit_obj:
            raise forms.ValidationError(
                _("This email address has been claimed by another user"))
class BuyerForm(forms.Form):
    email = forms.EmailField(__("Email"),
                             validators=[
                                 forms.validators.DataRequired(),
                                 forms.validators.Length(max=80)
                             ])
    fullname = forms.StringField(__("Full name"),
                                 validators=[forms.validators.DataRequired()])
    phone = forms.StringField(__("Phone number"),
                              validators=[forms.validators.Length(max=16)])
Exemple #9
0
class RegisterForm(forms.Form):
    fullname = forms.StringField(__("Full name"),
                                 validators=[forms.validators.DataRequired()])
    email = forms.EmailField(__("Email address"),
                             validators=[
                                 forms.validators.DataRequired(),
                                 forms.validators.ValidEmail()
                             ],
                             widget_attrs={
                                 'autocorrect': 'none',
                                 'autocapitalize': 'none'
                             })
    username = forms.StringField(
        __("Username"),
        validators=[forms.validators.DataRequired()],
        description=__(
            "Single word that can contain letters, numbers and dashes"),
        widget_attrs={
            'autocorrect': 'none',
            'autocapitalize': 'none'
        })
    password = forms.PasswordField(
        __("Password"), validators=[forms.validators.DataRequired()])
    confirm_password = forms.PasswordField(
        __("Confirm password"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.EqualTo('password')
        ])
    recaptcha = wtf.RecaptchaField(
        __("Are you human?"),
        description=__(
            "Type both words into the text box to prove that you are a human and not a computer program"
        ))

    def validate_username(self, field):
        if field.data in current_app.config['RESERVED_USERNAMES']:
            raise forms.ValidationError, _("This name is reserved")
        if not valid_username(field.data):
            raise forms.ValidationError(
                _(u"Invalid characters in name. Names must be made of ‘a-z’, ‘0-9’ and ‘-’, without trailing dashes"
                  ))
        existing = User.get(username=field.data)
        if existing is not None:
            raise forms.ValidationError(_("This username is taken"))

    def validate_email(self, field):
        field.data = field.data.lower()  # Convert to lowercase
        existing = UserEmail.get(email=field.data)
        if existing is not None:
            raise forms.ValidationError(
                Markup(
                    _(u"This email address is already registered. Do you want to <a href=\"{loginurl}\">login</a> instead?"
                      ).format(loginurl=escape(url_for('.login')))))
Exemple #10
0
class BuyerForm(forms.Form):
    email = forms.EmailField(__("Email"),
                             validators=[
                                 forms.validators.DataRequired(
                                     __("Please enter an email address")),
                                 forms.validators.Length(min=5, max=80)
                             ])
    fullname = forms.StringField(
        __("Full name"),
        validators=[
            forms.validators.DataRequired(
                __("Please enter the buyer's full name")),
            forms.validators.Length(max=80)
        ])
    phone = forms.StringField(__("Phone number"),
                              validators=[
                                  forms.validators.DataRequired(
                                      __("Please enter a phone number")),
                                  forms.validators.Length(max=16)
                              ])
Exemple #11
0
class RegisterForm(forms.RecaptchaForm):
    __returns__ = ('password_strength', )  # Set by PasswordStrengthValidator

    fullname = forms.StringField(
        __("Full name"),
        description=__(
            "This account is for you as an individual. We’ll make one for your organization later"
        ),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=80)
        ],
    )
    email = forms.EmailField(
        __("Email address"),
        validators=[
            forms.validators.DataRequired(),
            EmailAddressAvailable(purpose='register'),
        ],
        widget_attrs={
            'autocorrect': 'none',
            'autocapitalize': 'none'
        },
    )
    password = forms.PasswordField(
        __("Password"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(min=8, max=40),
            PasswordStrengthValidator(user_input_fields=['fullname', 'email']),
        ],
    )
    confirm_password = forms.PasswordField(
        __("Confirm password"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(min=8, max=40),
            forms.validators.EqualTo('password'),
        ],
    )
Exemple #12
0
class NewEmailAddressForm(forms.RecaptchaForm):
    email = forms.EmailField(
        __("Email address"),
        validators=[
            forms.validators.DataRequired(),
            validate_emailclaim,
            EmailAddressAvailable(purpose='claim'),
        ],
        widget_attrs={
            'autocorrect': 'none',
            'autocapitalize': 'none'
        },
    )
    type = forms.RadioField(  # NOQA: A003
        __("Type"),
        coerce=nullstr,
        validators=[forms.validators.Optional()],
        choices=[
            (__("Home"), __("Home")),
            (__("Work"), __("Work")),
            (__("Other"), __("Other")),
        ],
    )
Exemple #13
0
class RegisterForm(forms.RecaptchaForm):
    fullname = forms.StringField(
        __("Full name"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=80)
        ],
    )
    email = forms.EmailField(
        __("Email address"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.ValidEmail()
        ],
        widget_attrs={
            'autocorrect': 'none',
            'autocapitalize': 'none'
        },
    )
    password = forms.PasswordField(
        __("Password"), validators=[forms.validators.DataRequired()])
    confirm_password = forms.PasswordField(
        __("Confirm password"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.EqualTo('password'),
        ],
    )

    def validate_email(self, field):
        field.data = field.data.lower()  # Convert to lowercase
        existing = UserEmail.get(email=field.data)
        if existing is not None:
            raise forms.ValidationError(
                Markup(
                    _("This email address is already registered. Do you want to <a href=\"{loginurl}\">login</a> instead?"
                      ).format(loginurl=escape(url_for('.login')))))
Exemple #14
0
class ProposalForm(forms.Form):
    speaking = forms.RadioField(
        __("Are you speaking?"),
        coerce=int,
        choices=[
            (1, __("I will be speaking")),
            (0, __("I’m proposing a topic for someone to speak on")),
        ],
    )
    title = forms.StringField(
        __("Title"),
        validators=[forms.validators.DataRequired()],
        filters=[forms.filters.strip()],
        description=__("The title of your session"),
    )
    abstract = forms.MarkdownField(
        __("Abstract"),
        validators=[forms.validators.DataRequired()],
        description=__(
            "A brief description of your session with target audience and key takeaways"
        ),
    )
    outline = forms.MarkdownField(
        __("Outline"),
        validators=[forms.validators.DataRequired()],
        description=__(
            "A detailed description of the session with the sequence of ideas to be presented"
        ),
    )
    requirements = forms.MarkdownField(
        __("Requirements"),
        description=__(
            "For workshops, what must participants bring to the session?"),
    )
    slides = forms.URLField(
        __("Slides"),
        validators=[
            forms.validators.Optional(),
            forms.validators.URL(),
            forms.validators.ValidUrl(),
        ],
        description=__(
            "Link to your slides. These can be just an outline initially. "
            "If you provide a Slideshare/Speakerdeck link, we'll embed slides in the page"
        ),
    )
    video_url = forms.URLField(
        __("Preview Video"),
        validators=[
            forms.validators.Optional(),
            forms.validators.URL(),
            forms.validators.ValidUrl(),
        ],
        description=__(
            "Link to your preview video. Use a video to engage the community and give them a better "
            "idea about what you are planning to cover in your session and why they should attend. "
            "If you provide a YouTube/Vimeo link, we'll embed it in the page"),
    )
    links = forms.TextAreaField(
        __("Links"),
        description=__(
            "Other links, one per line. Provide links to your profile and "
            "slides and videos from your previous sessions; anything that'll help "
            "folks decide if they want to attend your session"),
    )
    bio = forms.MarkdownField(
        __("Speaker bio"),
        validators=[forms.validators.DataRequired()],
        description=__(
            "Tell us why you are the best person to be taking this session"),
    )
    email = forms.EmailField(
        __("Your email address"),
        validators=[
            forms.validators.DataRequired(),
            EmailAddressAvailable(purpose='use'),
        ],
        description=__(
            "An email address we can contact you at. Not displayed anywhere"),
    )
    phone = forms.StringField(
        __("Phone number"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=80)
        ],
        description=__(
            "A phone number we can call you at to discuss your proposal, if required. "
            "Will not be displayed"),
    )
    location = forms.StringField(
        __("Your location"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=80)
        ],
        description=__(
            "Your location, to help plan for your travel if required"),
    )

    formlabels = forms.FormField(forms.Form, __("Labels"))

    def set_queries(self):
        label_form = proposal_label_form(project=self.edit_parent,
                                         proposal=self.edit_obj)
        if label_form is not None:
            self.formlabels.form = label_form
        else:
            del self.formlabels
Exemple #15
0
class ProposalForm(forms.Form):
    speaking = forms.RadioField(
        __("Are you speaking?"),
        coerce=int,
        choices=[(1, __(u"I will be speaking")),
                 (0, __(u"I’m proposing a topic for someone to speak on"))])
    title = forms.StringField(__("Title"),
                              validators=[forms.validators.DataRequired()],
                              description=__("The title of your session"))
    section = QuerySelectField(__("Section"),
                               get_label='title',
                               validators=[forms.validators.DataRequired()],
                               widget=forms.ListWidget(prefix_label=False),
                               option_widget=forms.RadioInput())
    objective = forms.MarkdownField(
        __("Objective"),
        validators=[forms.validators.DataRequired()],
        description=__(
            "What is the expected benefit for someone attending this?"))
    session_type = forms.RadioField(
        __("Session type"),
        validators=[forms.validators.DataRequired()],
        choices=[
            ('Lecture', __("Lecture")),
            ('Demo', __("Demo")),
            ('Tutorial', __("Tutorial")),
            ('Workshop', __("Workshop")),
            ('Discussion', __("Discussion")),
            ('Panel', __("Panel")),
        ])
    technical_level = forms.RadioField(
        __("Technical level"),
        validators=[forms.validators.DataRequired()],
        choices=[
            ('Beginner', __("Beginner")),
            ('Intermediate', __("Intermediate")),
            ('Advanced', __("Advanced")),
        ])
    description = forms.MarkdownField(
        __("Description"),
        validators=[forms.validators.DataRequired()],
        description=__("A detailed description of the session"))
    requirements = forms.MarkdownField(
        __("Requirements"),
        description=__(
            "For workshops, what must participants bring to the session?"))
    slides = forms.URLField(
        __("Slides"),
        validators=[forms.validators.Optional(),
                    forms.validators.URL()],
        description=__(
            "Link to your slides. These can be just an outline initially. "
            "If you provide a Slideshare/Speakerdeck link, we'll embed slides in the page"
        ))
    preview_video = forms.URLField(
        __("Preview Video"),
        validators=[forms.validators.Optional(),
                    forms.validators.URL()],
        description=__(
            "Link to your preview video. Use a video to engage the community and give them a better idea about what you are planning to cover in your session and why they should attend. "
            "If you provide a YouTube/Vimeo link, we'll embed it in the page"))
    links = forms.TextAreaField(
        __("Links"),
        description=__(
            "Other links, one per line. Provide links to your profile and "
            "slides and videos from your previous sessions; anything that'll help "
            "folks decide if they want to attend your session"))
    bio = forms.MarkdownField(
        __("Speaker bio"),
        validators=[forms.validators.DataRequired()],
        description=__(
            "Tell us why you are the best person to be taking this session"))
    email = forms.EmailField(__("Your email address"),
                             validators=[
                                 forms.validators.DataRequired(),
                                 forms.validators.Length(max=80)
                             ],
                             description=__(
                                 "An email address we can contact you at. "
                                 "Not displayed anywhere"))
    phone = forms.StringField(
        __("Phone number"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=80)
        ],
        description=__(
            "A phone number we can call you at to discuss your proposal, if required. "
            "Will not be displayed"))
    location = forms.StringField(
        __("Your location"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=80)
        ],
        description=__(
            "Your location, to help plan for your travel if required"))
Exemple #16
0
class ListingForm(forms.Form):
    """Form for new job posts"""

    job_headline = forms.StringField(
        __("Headline"),
        description=Markup(
            __(
                "A single-line summary. This goes to the front page and across the network. "
                """<a id="abtest" class="no-jshidden" href="#">A/B test it?</a>"""
            )
        ),
        validators=[
            forms.validators.DataRequired(__("A headline is required")),
            forms.validators.Length(
                min=1, max=100, message=__("%(max)d characters maximum")
            ),
            forms.validators.NoObfuscatedEmail(
                __("Do not include contact information in the post")
            ),
        ],
        filters=[forms.filters.strip()],
    )
    job_headlineb = forms.StringField(
        __("Headline B"),
        description=__(
            "An alternate headline that will be shown to 50%% of users. "
            "You’ll get a count of views per headline"
        ),
        validators=[
            forms.validators.Optional(),
            forms.validators.Length(
                min=1, max=100, message=__("%(max)d characters maximum")
            ),
            forms.validators.NoObfuscatedEmail(
                __("Do not include contact information in the post")
            ),
        ],
        filters=[forms.filters.strip(), forms.filters.none_if_empty()],
    )
    job_type = forms.RadioField(
        __("Type"),
        coerce=int,
        validators=[
            forms.validators.InputRequired(__("The job type must be specified"))
        ],
    )
    job_category = forms.RadioField(
        __("Category"),
        coerce=int,
        validators=[forms.validators.InputRequired(__("Select a category"))],
    )
    job_location = forms.StringField(
        __("Location"),
        description=__(
            '“Bangalore”, “Chennai”, “Pune”, etc or “Anywhere” (without quotes)'
        ),
        validators=[
            forms.validators.DataRequired(
                __("If this job doesn’t have a fixed location, use “Anywhere”")
            ),
            forms.validators.Length(
                min=3, max=80, message=__("%(max)d characters maximum")
            ),
        ],
        filters=[forms.filters.strip()],
    )
    job_relocation_assist = forms.BooleanField(__("Relocation assistance available"))
    job_description = forms.TinyMce4Field(
        __("Description"),
        content_css=content_css,
        description=__(
            "Don’t just describe the job, tell a compelling story for why someone should work for you"
        ),
        validators=[
            forms.validators.DataRequired(__("A description of the job is required")),
            forms.validators.AllUrlsValid(invalid_urls=invalid_urls),
            forms.validators.NoObfuscatedEmail(
                __("Do not include contact information in the post")
            ),
        ],
        tinymce_options={'convert_urls': True},
    )
    job_perks = forms.BooleanField(__("Job perks are available"))
    job_perks_description = forms.TinyMce4Field(
        __("Describe job perks"),
        content_css=content_css,
        description=__("Stock options, free lunch, free conference passes, etc"),
        validators=[
            forms.validators.AllUrlsValid(invalid_urls=invalid_urls),
            forms.validators.NoObfuscatedEmail(
                __("Do not include contact information in the post")
            ),
        ],
    )
    job_pay_type = forms.RadioField(
        __("What does this job pay?"),
        coerce=int,
        validators=[
            forms.validators.InputRequired(__("You need to specify what this job pays"))
        ],
        choices=list(PAY_TYPE.items()),
    )
    job_pay_currency = ListingPayCurrencyField(
        __("Currency"), choices=list(CURRENCY.items()), default=CURRENCY.INR
    )
    job_pay_cash_min = forms.StringField(__("Minimum"))
    job_pay_cash_max = forms.StringField(__("Maximum"))
    job_pay_equity = forms.BooleanField(__("Equity compensation is available"))
    job_pay_equity_min = forms.StringField(__("Minimum"))
    job_pay_equity_max = forms.StringField(__("Maximum"))
    job_how_to_apply = forms.TextAreaField(
        __("What should a candidate submit when applying for this job?"),
        description=__(
            "Example: “Include your LinkedIn and GitHub profiles.” "
            "We now require candidates to apply through the job board only. "
            "Do not include any contact information here. Candidates CANNOT "
            "attach resumes or other documents, so do not ask for that"
        ),
        validators=[
            forms.validators.DataRequired(
                __(
                    "We do not offer screening services. Please specify what candidates should submit"
                )
            ),
            forms.validators.NoObfuscatedEmail(
                __("Do not include contact information in the post")
            ),
        ],
    )
    company_name = forms.StringField(
        __("Employer name"),
        description=__(
            "The name of the organization where the position is. "
            "If your stealth startup doesn't have a name yet, use your own. "
            "We do not accept posts from third parties such as recruitment consultants. "
            "Such posts may be removed without notice"
        ),
        validators=[
            forms.validators.DataRequired(
                __(
                    "This is required. Posting any name other than that of the actual organization is a violation of the ToS"
                )
            ),
            forms.validators.Length(
                min=4,
                max=80,
                message=__("The name must be within %(min)d to %(max)d characters"),
            ),
        ],
        filters=[forms.filters.strip()],
    )
    company_logo = forms.FileField(
        __("Logo"),
        description=__(
            "Optional — Your organization’s logo will appear at the top of your post."
        ),
        # validators=[file_allowed(uploaded_logos, "That image type is not supported")])
    )
    company_logo_remove = forms.BooleanField(__("Remove existing logo"))
    company_url = forms.URLField(
        __("URL"),
        description=__("Your organization’s website"),
        validators=[
            forms.validators.DataRequired(),
            optional_url,
            forms.validators.Length(max=255, message=__("%(max)d characters maximum")),
            forms.validators.ValidUrl(),
        ],
        filters=[forms.filters.strip()],
    )
    hr_contact = forms.RadioField(
        __(
            "Is it okay for recruiters and other "
            "intermediaries to contact you about this post?"
        ),
        coerce=getbool,
        description=__("We’ll display a notice to this effect on the post"),
        default=0,
        choices=[
            (0, __("No, it is NOT OK")),
            (1, __("Yes, recruiters may contact me")),
        ],
    )
    # Deprecated 2013-11-20
    # poster_name = forms.StringField(__("Name"),
    #     description=__(u"This is your name, for our records. Will not be revealed to applicants"),
    #     validators=[forms.validators.DataRequired(__("We need your name"))])
    poster_email = forms.EmailField(
        __("Email"),
        description=Markup(
            __(
                "This is where we’ll send your confirmation email and all job applications. "
                "We recommend using a shared email address such as [email protected]. "
                "<strong>Listings are classified by your email domain,</strong> "
                "so use a work email address. "
                "Your email address will not be revealed to applicants until you respond"
            )
        ),
        validators=[
            forms.validators.DataRequired(
                __("We need to confirm your email address before the job can be listed")
            ),
            forms.validators.Length(
                min=5, max=80, message=__("%(max)d characters maximum")
            ),
            forms.validators.ValidEmail(
                __("This does not appear to be a valid email address")
            ),
        ],
        filters=[forms.filters.strip()],
    )
    twitter = forms.AnnotatedTextField(
        __("Twitter"),
        description=__(
            "Optional — your organization’s Twitter account. "
            "We’ll tweet mentioning you so you get included on replies"
        ),
        prefix='@',
        validators=[
            forms.validators.Optional(),
            forms.validators.Length(
                min=0,
                max=15,
                message=__("Twitter accounts can’t be over %(max)d characters long"),
            ),
        ],
        filters=[forms.filters.strip(), forms.filters.none_if_empty()],
    )
    collaborators = forms.UserSelectMultiField(
        __("Collaborators"),
        description=__(
            "If someone is helping you evaluate candidates, type their names here. "
            "They must have a Hasgeek account. They will not receive email notifications "
            "— use a shared email address above for that — but they will be able to respond "
            "to candidates who apply"
        ),
        usermodel=User,
        lastuser=lastuser,
    )

    def validate_twitter(self, field):
        if field.data.startswith('@'):
            field.data = field.data[1:]
        if INVALID_TWITTER_RE.search(field.data):
            raise forms.ValidationError(
                _("That does not appear to be a valid Twitter account")
            )

    def validate_poster_email(self, field):
        field.data = field.data.lower()

    def validate_job_type(self, field):
        # This validator exists primarily for this assignment, used later in the form by other validators
        self.job_type_ob = JobType.query.get(field.data)
        if not self.job_type_ob:
            raise forms.ValidationError(_("Please select a job type"))

    def validate_company_name(self, field):
        if len(field.data) > 6:
            caps = len(CAPS_RE.findall(field.data))

            # small = len(SMALL_RE.findall(field.data))  # deprecated on 30-11-2018
            # if small == 0 or caps / float(small) > 0.8:  # deprecated on 30-11-2018

            # For now, only 6 capital letters are allowed in company name
            if caps > 6:
                raise forms.ValidationError(
                    _("Surely your organization isn’t named in uppercase?")
                )

    def validate_company_logo(self, field):
        if not ('company_logo' in request.files and request.files['company_logo']):
            return
        try:
            g.company_logo = process_image(request.files['company_logo'])
        except IOError as e:
            raise forms.ValidationError(e.message)
        except KeyError:
            raise forms.ValidationError(_("Unknown file format"))
        except UploadNotAllowed:
            raise forms.ValidationError(
                _("Unsupported file format. We accept JPEG, PNG and GIF")
            )

    def validate_job_headline(self, field):
        if simplify_text(field.data) in (
            'awesome coder wanted at awesome company',
            'pragmatic programmer wanted at outstanding organisation',
            'pragmatic programmer wanted at outstanding organization',
        ) or (
            g.board
            and g.board.newjob_headline
            and simplify_text(field.data) == simplify_text(g.board.newjob_headline)
        ):
            raise forms.ValidationError(
                _(
                    "Come on, write your own headline. You aren’t just another run-of-the-mill employer, right?"
                )
            )
        caps = len(CAPS_RE.findall(field.data))
        small = len(SMALL_RE.findall(field.data))
        if small == 0 or caps / float(small) > 1.0:
            raise forms.ValidationError(
                _(
                    "No shouting, please. Reduce the number of capital letters in your headline"
                )
            )
        for word_list, message in app.config.get('BANNED_WORDS', []):
            for word in word_list:
                if word in field.data.lower():
                    raise forms.ValidationError(message)

    def validate_job_headlineb(self, field):
        return self.validate_job_headline(field)

    def validate_job_location(self, field):
        if QUOTES_RE.search(field.data) is not None:
            raise forms.ValidationError(_("Don’t use quotes in the location name"))

        caps = len(CAPS_RE.findall(field.data))
        small = len(SMALL_RE.findall(field.data))
        if small == 0 or caps / float(small) > 1.0:
            raise forms.ValidationError(
                _("Surely this location isn't named in uppercase?")
            )

    def validate_job_pay_cash_min(self, field):
        if self.job_pay_type.data in (PAY_TYPE.ONETIME, PAY_TYPE.RECURRING):
            data = field.data.strip()
            if not data:
                raise forms.ValidationError(_("Please specify what this job pays"))
            data = string_to_number(data)
            if data is None:
                raise forms.ValidationError(_("Unrecognised value %s") % field.data)
            else:
                field.data = data
        else:
            field.data = None

    def validate_job_pay_cash_max(self, field):
        if self.job_pay_type.data in (PAY_TYPE.ONETIME, PAY_TYPE.RECURRING):
            data = string_to_number(field.data.strip())
            if data is None:
                raise forms.ValidationError(_("Unrecognised value %s") % field.data)
            else:
                field.data = data
        else:
            field.data = None

    def validate_job_pay_equity_min(self, field):
        if self.job_pay_equity.data:
            data = field.data.strip()
            if data:
                if not data[-1].isdigit():
                    data = field.data[:-1]  # Remove % symbol
                data = data.replace(',', '').strip()  # Remove thousands separator
                try:
                    field.data = Decimal(data)
                except InvalidOperation:
                    raise forms.ValidationError(
                        _("Please enter a percentage between 0%% and 100%%")
                    )
            else:
                raise forms.ValidationError(_("Unrecognised value %s") % field.data)
        else:
            # Discard submission if equity checkbox is unchecked
            field.data = None

    def validate_job_pay_equity_max(self, field):
        if self.job_pay_equity.data:
            data = field.data.strip()
            if data:
                if not data[-1].isdigit():
                    data = field.data[:-1]  # Remove % symbol
                data = data.replace(',', '').strip()  # Remove thousands separator
                try:
                    field.data = Decimal(data)
                except InvalidOperation:
                    raise forms.ValidationError(
                        _("Please enter a percentage between 0%% and 100%%")
                    )
            else:
                raise forms.ValidationError(_("Unrecognised value %s") % field.data)
        else:
            # Discard submission if equity checkbox is unchecked
            field.data = None

    def validate(self):
        success = super(ListingForm, self).validate(send_signals=False)
        if success:
            if (
                not self.job_type_ob.nopay_allowed
            ) and self.job_pay_type.data == PAY_TYPE.NOCASH:
                self.job_pay_type.errors.append(
                    _("“%s” cannot pay nothing") % self.job_type_ob.title
                )
                success = False

            domain_name = get_email_domain(self.poster_email.data)
            domain = Domain.get(domain_name)
            if domain and domain.is_banned:
                self.poster_email.errors.append(
                    _("%s is banned from posting jobs on Hasjob") % domain_name
                )
                success = False
            elif (not self.job_type_ob.webmail_allowed) and is_public_email_domain(
                domain_name, default=False
            ):
                self.poster_email.errors.append(
                    _(
                        "Public webmail accounts like Gmail are not accepted. Please use your corporate email address"
                    )
                )
                success = False

            # Check for cash pay range
            if self.job_pay_type.data in (PAY_TYPE.ONETIME, PAY_TYPE.RECURRING):
                if self.job_pay_cash_min.data == 0:
                    if self.job_pay_cash_max.data == 10000000:
                        self.job_pay_cash_max.errors.append(_("Please select a range"))
                        success = False
                    else:
                        self.job_pay_cash_min.errors.append(
                            _("Please specify a minimum non-zero pay")
                        )
                        success = False
                else:
                    if self.job_pay_cash_max.data == 10000000:
                        if self.job_pay_currency.data == 'INR':
                            figure = _("1 crore")
                        else:
                            figure = _("10 million")
                        self.job_pay_cash_max.errors.append(
                            _(
                                "You’ve selected an upper limit of {figure}. That can’t be right"
                            ).format(figure=figure)
                        )
                        success = False
                    elif (
                        self.job_pay_type.data == PAY_TYPE.RECURRING
                        and self.job_pay_currency.data == 'INR'
                        and self.job_pay_cash_min.data < 60000
                    ):
                        self.job_pay_cash_min.errors.append(
                            _(
                                "That’s rather low. Did you specify monthly pay instead of annual pay? Multiply by 12"
                            )
                        )
                        success = False
                    elif self.job_pay_cash_max.data > self.job_pay_cash_min.data * 4:
                        self.job_pay_cash_max.errors.append(
                            _(
                                "Please select a narrower range, with maximum within 4× minimum"
                            )
                        )
                        success = False
            if self.job_pay_equity.data:
                if self.job_pay_equity_min.data == 0:
                    if self.job_pay_equity_max.data == 100:
                        self.job_pay_equity_max.errors.append(
                            _("Please select a range")
                        )
                        success = False
                else:
                    if self.job_pay_equity_min.data <= Decimal('1.0'):
                        multiplier = 10
                    elif self.job_pay_equity_min.data <= Decimal('2.0'):
                        multiplier = 8
                    elif self.job_pay_equity_min.data <= Decimal('3.0'):
                        multiplier = 6
                    else:
                        multiplier = 4

                    if (
                        self.job_pay_equity_max.data
                        > self.job_pay_equity_min.data * multiplier
                    ):
                        self.job_pay_equity_max.errors.append(
                            _(
                                "Please select a narrower range, with maximum within %d× minimum"
                            )
                            % multiplier
                        )
                        success = False
        self.send_signals()
        return success

    def populate_from(self, post):
        self.job_headline.data = post.headline
        self.job_headlineb.data = post.headlineb
        self.job_type.data = post.type_id
        self.job_category.data = post.category_id
        self.job_location.data = post.location
        self.job_relocation_assist.data = post.relocation_assist
        self.job_description.data = post.description
        self.job_perks.data = True if post.perks else False
        self.job_perks_description.data = post.perks
        self.job_how_to_apply.data = post.how_to_apply
        self.company_name.data = post.company_name
        self.company_url.data = post.company_url
        self.poster_email.data = post.email
        self.twitter.data = post.twitter
        self.hr_contact.data = int(post.hr_contact or False)
        self.collaborators.data = post.admins
        self.job_pay_type.data = post.pay_type
        if post.pay_type is None:
            # This kludge required because WTForms doesn't know how to handle None in forms
            self.job_pay_type.data = -1
        self.job_pay_currency.data = post.pay_currency
        self.job_pay_cash_min.data = post.pay_cash_min
        self.job_pay_cash_max.data = post.pay_cash_max
        self.job_pay_equity.data = bool(post.pay_equity_min and post.pay_equity_max)
        self.job_pay_equity_min.data = post.pay_equity_min
        self.job_pay_equity_max.data = post.pay_equity_max
Exemple #17
0
class AccountForm(forms.Form):
    fullname = forms.StringField(
        __("Full name"),
        description=__(
            "This is your name. We will make an account for your organization later"
        ),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=User.__title_length__),
        ],
    )
    email = forms.EmailField(
        __("Email address"),
        description=__(
            "Required for sending you tickets, invoices and notifications"),
        validators=[
            forms.validators.DataRequired(),
            EmailAddressAvailable(purpose='use'),
        ],
        widget_attrs={
            'autocorrect': 'none',
            'autocapitalize': 'none'
        },
    )
    username = forms.AnnotatedTextField(
        __("Username"),
        description=__(
            "Single word that can contain letters, numbers and dashes. "
            "You need a username to have a public profile"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.Length(max=Profile.__name_length__),
        ],
        filters=[forms.filters.none_if_empty()],
        prefix="https://hasgeek.com/",
        widget_attrs={
            'autocorrect': 'none',
            'autocapitalize': 'none'
        },
    )
    timezone = forms.SelectField(
        __("Timezone"),
        description=__(
            "Where in the world are you? Dates and times will be shown in your local "
            "timezone"),
        validators=[forms.validators.DataRequired()],
        choices=timezones,
        widget_attrs={},
    )
    auto_timezone = forms.BooleanField(__("Use your device’s timezone"))
    locale = forms.SelectField(
        __("Locale"),
        description=__("Your preferred UI language"),
        choices=list(supported_locales.items()),
    )
    auto_locale = forms.BooleanField(__("Use your device’s language"))

    def validate_username(self, field):
        reason = self.edit_obj.validate_name_candidate(field.data)
        if not reason:
            return  # Username is available
        raise_username_error(reason)
Exemple #18
0
class ListingForm(forms.Form):
    """Form for new job posts"""
    job_headline = forms.StringField(__("Headline"),
        description=Markup(__("A single-line summary. This goes to the front page and across the network. "
            """<a id="abtest" class="no-jshidden" href="#">A/B test it?</a>""")),
        validators=[forms.validators.DataRequired(__("A headline is required")),
            forms.validators.Length(min=1, max=100, message=__("%%(max)d characters maximum")),
            forms.validators.NoObfuscatedEmail(__(u"Do not include contact information in the post"))],
        filters=[forms.filters.strip()])
    job_headlineb = forms.StringField(__("Headline B"),
        description=__(u"An alternate headline that will be shown to 50%% of users. "
            u"You’ll get a count of views per headline"),
        validators=[forms.validators.Optional(),
            forms.validators.Length(min=1, max=100, message=__("%%(max)d characters maximum")),
            forms.validators.NoObfuscatedEmail(__(u"Do not include contact information in the post"))],
        filters=[forms.filters.strip(), forms.filters.none_if_empty()])
    job_type = forms.RadioField(__("Type"), coerce=int,
        validators=[forms.validators.InputRequired(__("The job type must be specified"))])
    job_category = forms.RadioField(__("Category"), coerce=int,
        validators=[forms.validators.InputRequired(__("Select a category"))])
    job_location = forms.StringField(__("Location"),
        description=__(u'“Bangalore”, “Chennai”, “Pune”, etc or “Anywhere” (without quotes)'),
        validators=[forms.validators.DataRequired(__(u"If this job doesn’t have a fixed location, use “Anywhere”")),
            forms.validators.Length(min=3, max=80, message=__("%%(max)d characters maximum"))],
        filters=[forms.filters.strip()])
    job_relocation_assist = forms.BooleanField(__("Relocation assistance available"))
    job_description = forms.TinyMce4Field(__("Description"),
        content_css=content_css,
        description=__(u"Don’t just describe the job, tell a compelling story for why someone should work for you"),
        validators=[forms.validators.DataRequired(__("A description of the job is required")),
            forms.validators.AllUrlsValid(invalid_urls=invalid_urls),
            forms.validators.NoObfuscatedEmail(__(u"Do not include contact information in the post"))],
        tinymce_options={'convert_urls': True})
    job_perks = forms.BooleanField(__("Job perks are available"))
    job_perks_description = forms.TinyMce4Field(__("Describe job perks"),
        content_css=content_css,
        description=__(u"Stock options, free lunch, free conference passes, etc"),
        validators=[forms.validators.AllUrlsValid(invalid_urls=invalid_urls),
            forms.validators.NoObfuscatedEmail(__(u"Do not include contact information in the post"))])
    job_pay_type = forms.RadioField(__("What does this job pay?"), coerce=int,
        validators=[forms.validators.InputRequired(__("You need to specify what this job pays"))],
        choices=PAY_TYPE.items())
    job_pay_currency = ListingPayCurrencyField(__("Currency"), choices=CURRENCY.items(), default=CURRENCY.INR)
    job_pay_cash_min = forms.StringField(__("Minimum"))
    job_pay_cash_max = forms.StringField(__("Maximum"))
    job_pay_equity = forms.BooleanField(__("Equity compensation is available"))
    job_pay_equity_min = forms.StringField(__("Minimum"))
    job_pay_equity_max = forms.StringField(__("Maximum"))
    job_how_to_apply = forms.TextAreaField(__("What should a candidate submit when applying for this job?"),
        description=__(u"Example: “Include your LinkedIn and GitHub profiles.” "
                       u"We now require candidates to apply through the job board only. "
                       u"Do not include any contact information here. Candidates CANNOT "
                       u"attach resumes or other documents, so do not ask for that"),
        validators=[
            forms.validators.DataRequired(__(u"We do not offer screening services. Please specify what candidates should submit")),
            forms.validators.NoObfuscatedEmail(__(u"Do not include contact information in the post"))])
    company_name = forms.StringField(__("Employer name"),
        description=__(u"The name of the organization where the position is. "
                       u"If your stealth startup doesn't have a name yet, use your own. "
                       u"We do not accept posts from third parties such as recruitment consultants. "
                       u"Such posts may be removed without notice"),
        validators=[forms.validators.DataRequired(__(u"This is required. Posting any name other than that of the actual organization is a violation of the ToS")),
            forms.validators.Length(min=4, max=80, message=__("The name must be within %%(min)d to %%(max)d characters"))],
        filters=[forms.filters.strip()])
    company_logo = forms.FileField(__("Logo"),
        description=__(u"Optional — Your organization’s logo will appear at the top of your post."),
        )  # validators=[file_allowed(uploaded_logos, "That image type is not supported")])
    company_logo_remove = forms.BooleanField(__("Remove existing logo"))
    company_url = forms.URLField(__("URL"),
        description=__(u"Your organization’s website"),
        validators=[forms.validators.DataRequired(), optional_url,
            forms.validators.Length(max=255, message=__("%%(max)d characters maximum")), forms.validators.ValidUrl()],
        filters=[forms.filters.strip()])
    hr_contact = forms.RadioField(__(u"Is it okay for recruiters and other "
        u"intermediaries to contact you about this post?"), coerce=getbool,
        description=__(u"We’ll display a notice to this effect on the post"),
        default=0,
        choices=[(0, __(u"No, it is NOT OK")), (1, __(u"Yes, recruiters may contact me"))])
    # Deprecated 2013-11-20
    # poster_name = forms.StringField(__("Name"),
    #     description=__(u"This is your name, for our records. Will not be revealed to applicants"),
    #     validators=[forms.validators.DataRequired(__("We need your name"))])
    poster_email = forms.EmailField(__("Email"),
        description=Markup(__(u"This is where we’ll send your confirmation email and all job applications. "
                    u"We recommend using a shared email address such as [email protected]. "
                    u"<strong>Listings are classified by your email domain,</strong> "
                    u"so use a work email address. "
                    u"Your email address will not be revealed to applicants until you respond")),
        validators=[
            forms.validators.DataRequired(__("We need to confirm your email address before the job can be listed")),
            forms.validators.Length(min=5, max=80, message=__("%%(max)d characters maximum")),
            forms.validators.ValidEmail(__("This does not appear to be a valid email address"))],
        filters=[forms.filters.strip()])
    twitter = forms.AnnotatedTextField(__("Twitter"),
        description=__(u"Optional — your organization’s Twitter account. "
            u"We’ll tweet mentioning you so you get included on replies"),
        prefix='@', validators=[
            forms.validators.Optional(),
            forms.validators.Length(min=0, max=15, message=__(u"Twitter accounts can’t be over %%(max)d characters long"))],
        filters=[forms.filters.strip(), forms.filters.none_if_empty()])
    collaborators = forms.UserSelectMultiField(__(u"Collaborators"),
        description=__(u"If someone is helping you evaluate candidates, type their names here. "
                       u"They must have a HasGeek account. They will not receive email notifications "
                       u"— use a shared email address above for that — but they will be able to respond "
                       u"to candidates who apply"),
        usermodel=User, lastuser=lastuser)

    def validate_twitter(self, field):
        if field.data.startswith('@'):
            field.data = field.data[1:]
        if INVALID_TWITTER_RE.search(field.data):
            raise forms.ValidationError(_("That does not appear to be a valid Twitter account"))

    def validate_poster_email(form, field):
        field.data = field.data.lower()

    def validate_job_type(form, field):
        # This validator exists primarily for this assignment, used later in the form by other validators
        form.job_type_ob = JobType.query.get(field.data)
        if not form.job_type_ob:
            raise forms.ValidationError(_("Please select a job type"))

    def validate_company_name(form, field):
        if len(field.data) > 6:
            caps = len(CAPS_RE.findall(field.data))

            # small = len(SMALL_RE.findall(field.data))  # deprecated on 30-11-2018
            # if small == 0 or caps / float(small) > 0.8:  # deprecated on 30-11-2018

            # For now, only 6 capital letters are allowed in company name
            if caps > 6:
                raise forms.ValidationError(_(u"Surely your organization isn’t named in uppercase?"))

    def validate_company_logo(form, field):
        if not ('company_logo' in request.files and request.files['company_logo']):
            return
        try:
            g.company_logo = process_image(request.files['company_logo'])
        except IOError, e:
            raise forms.ValidationError(e.message)
        except KeyError, e:
            raise forms.ValidationError(_("Unknown file format"))
Exemple #19
0
class TicketParticipantForm(forms.Form):
    __returns__ = ('user', )

    fullname = forms.StringField(
        __("Fullname"),
        validators=[forms.validators.DataRequired()],
        filters=[forms.filters.strip()],
    )
    email = forms.EmailField(
        __("Email"),
        validators=[
            forms.validators.DataRequired(),
            forms.validators.ValidEmail()
        ],
        filters=[forms.filters.strip()],
    )
    phone = forms.StringField(
        __("Phone number"),
        validators=[forms.validators.Length(max=80)],
        filters=[forms.filters.strip()],
    )
    city = forms.StringField(
        __("City"),
        validators=[forms.validators.Length(max=80)],
        filters=[forms.filters.strip()],
    )
    company = forms.StringField(
        __("Company"),
        validators=[forms.validators.Length(max=80)],
        filters=[forms.filters.strip()],
    )
    job_title = forms.StringField(
        __("Job title"),
        validators=[forms.validators.Length(max=80)],
        filters=[forms.filters.strip()],
    )
    twitter = forms.StringField(
        __("Twitter"),
        validators=[forms.validators.Length(max=15)],
        filters=[forms.filters.strip()],
    )
    badge_printed = forms.BooleanField(__("Badge is printed"))
    ticket_events = QuerySelectMultipleField(
        __("Events"),
        widget=ListWidget(),
        option_widget=CheckboxInput(),
        get_label='title',
        validators=[
            forms.validators.DataRequired("Select at least one event")
        ],
    )

    def set_queries(self):
        if self.edit_parent is not None:
            self.ticket_events.query = self.edit_parent.ticket_events

    def validate(self):
        result = super().validate()
        with db.session.no_autoflush:
            useremail = UserEmail.get(email=self.email.data)
            if useremail:
                self.user = useremail.user
            else:
                self.user = None
        return result