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"))
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()])
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") ])
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"))
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"))
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)])
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')))))
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) ])
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'), ], )
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")), ], )
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')))))
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
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"))
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
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)
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"))
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