class CampaignContentForm(forms.Form): subject = forms.NullTextField( __("Subject"), description=__("A subject title shown to viewers"), validators=[ forms.validators.Optional(), forms.validators.StripWhitespace() ]) blurb = forms.TinyMce4Field( __("Blurb"), description=__( "Teaser to introduce the campaign and convince users to interact"), content_css=content_css, validators=[ forms.validators.Optional(), forms.validators.AllUrlsValid() ]) description = forms.TinyMce4Field( __("Description"), description=__( "Optional additional content to follow after the blurb"), content_css=content_css, validators=[ forms.validators.Optional(), forms.validators.AllUrlsValid() ]) banner_image = forms.URLField( __("Banner image URL"), validators=[forms.validators.Optional()], # TODO: Use ImgeeField description=__("An image to illustrate your campaign")) banner_location = forms.RadioField( __("Banner location"), choices=BANNER_LOCATION.items(), coerce=int, description=__("Where should this banner appear relative to text?"))
class DomainForm(forms.Form): title = forms.StringField( __(u"Common name"), validators=[ forms.validators.DataRequired(), forms.validators.StripWhitespace() ], description=__( "The name of your organization, excluding legal suffixes like Pvt Ltd" )) legal_title = forms.NullTextField( __("Legal name"), validators=[forms.validators.Optional()], description=__(u"Optional — The full legal name of your organization")) logo_url = forms.URLField( __("Logo URL"), validators=[forms.validators.Optional()], # TODO: Use ImgeeField description=__(u"Optional — Your organization’s logo")) description = forms.TinyMce4Field( __("Description"), description=__( "Who are you and why should someone work for you? Tell your story" ), content_css=content_css, validators=[ forms.validators.AllUrlsValid(invalid_urls=invalid_urls), forms.validators.NoObfuscatedEmail( u"Do not include contact information here") ])
class DomainForm(forms.Form): title = forms.StringField(__(u"Common name"), validators=[forms.validators.DataRequired(), forms.validators.StripWhitespace(), forms.validators.Length(min=1, max=250, message=__("%(max)d characters maximum"))], description=__("The name of your organization, excluding legal suffixes like Pvt Ltd")) legal_title = forms.NullTextField(__("Legal name"), validators=[forms.validators.Optional(), forms.validators.Length(min=1, max=250, message=__("%%(max)d characters maximum"))], description=__(u"Optional — The full legal name of your organization")) logo_url = forms.URLField(__("Logo URL"), # TODO: Use ImgeeField validators=[forms.validators.Optional(), forms.validators.Length(min=0, max=250, message=__("%%(max)d characters maximum"))], description=Markup(__(u"Optional — Your organization’s logo. " u"Upload at <a target='_blank' href='https://images.hasgeek.com/'>images.hasgeek.com</a> " u"and use the Direct Link URL"))) description = forms.TinyMce4Field(__("Description"), description=__("Who are you and why should someone work for you? Tell your story"), content_css=content_css, validators=[ forms.validators.AllUrlsValid(invalid_urls=invalid_urls), forms.validators.NoObfuscatedEmail(__("Do not include contact information here"))])
class CampaignActionForm(forms.Form): title = forms.StringField( __("Title"), description=__("Contents of the call to action button"), validators=[ forms.validators.DataRequired("You must provide some text"), forms.validators.StripWhitespace() ]) icon = forms.NullTextField( __("Icon"), validators=[forms.validators.Optional()], description=__("Optional Font-Awesome icon name")) public = forms.BooleanField(__("This action is live")) type = forms.RadioField( __("Type"), choices=CAMPAIGN_ACTION.items(), validators=[forms.validators.DataRequired(__("This is required"))]) group = forms.NullTextField( __("RSVP group"), validators=[forms.validators.Optional()], description=__( "If you have multiple RSVP actions, add an optional group name")) category = forms.RadioField( __("Category"), validators=[forms.validators.DataRequired(__("This is required"))], widget=forms.InlineListWidget(class_='button-bar', class_prefix='btn btn-'), choices=[ (u'default', __(u"Default")), (u'primary', __(u"Primary")), (u'success', __(u"Success")), (u'info', __(u"Info")), (u'warning', __(u"Warning")), (u'danger', __(u"Danger")), ]) message = forms.TinyMce4Field( __("Message"), description=__( "Message shown after the user has performed an action (for forms and RSVP type)" ), content_css=content_css, validators=[ forms.validators.Optional(), forms.validators.AllUrlsValid() ]) link = forms.URLField( __("Link"), description=__(u"URL to redirect to, if type is “follow link”"), validators=[ forms.validators.StripWhitespace(), optional_url, forms.validators.Length(min=0, max=250, message=__("%%(max)d characters maximum")), forms.validators.ValidUrl() ]) form = forms.TextAreaField( __("Form JSON"), description=__("Form definition (for form type)"), validators=[forms.validators.Optional()]) seq = forms.IntegerField( __("Sequence #"), validators=[forms.validators.DataRequired(__("This is required"))], description=__( "Sequence number for displaying this action when multiple actions are available to the user" ))
class BoardOptionsForm(forms.Form): restrict_listing = forms.BooleanField( __(u"Restrict direct posting on this board to owners and the following users" ), default=True, description=__( u"As the owner of this board, you can always cross-add jobs from other boards on Hasjob" )) posting_users = forms.UserSelectMultiField( __(u"Allowed users"), description=__( u"These users will be allowed to post jobs on this board under the following terms" ), usermodel=User, lastuser=lastuser) # Allow turning this off only in siteadmin-approved boards (deleted in the view for non-siteadmins) require_pay = forms.BooleanField( __(u"Require pay data for posting on this board?"), default=True, description=__( u"Hasjob requires employers to reveal what they intend to pay, " u"but you can make it optional for jobs posted from this board. " u"Pay data is used to match candidates to jobs. We recommend you collect it" )) newjob_headline = forms.NullTextField( __(u"Headline"), description=__( u"Optional – The sample headline shown to employers when posting a job" ), validators=[ forms.validators.StripWhitespace(), forms.validators.Length(min=0, max=100, message=__("%%(max)d characters maximum")) ]) newjob_blurb = forms.TinyMce4Field( __(u"Posting instructions"), description=__( u"Optional – What should we tell employers when they post a job on your board? " u"Leave blank to use the default text"), content_css=content_css, validators=[forms.validators.AllUrlsValid()]) types = QuerySelectMultipleField( __("Job types"), widget=ListWidget(), option_widget=CheckboxInput(), query_factory=lambda: JobType.query.filter_by(private=False).order_by( 'seq'), get_label=jobtype_label, validators=[ forms.validators.DataRequired( __(u"You need to select at least one job type")) ], description=__( u"Jobs listed directly on this board can use one of the types enabled here" )) categories = QuerySelectMultipleField( __("Job categories"), widget=ListWidget(), option_widget=CheckboxInput(), query_factory=lambda: JobCategory.query.filter_by(private=False ).order_by('seq'), get_label='title', validators=[ forms.validators.DataRequired( __(u"You need to select at least one category")) ], description=__( u"Jobs listed directly on this board can use one of the categories enabled here" ))
class BoardForm(forms.Form): """ Edit board settings. """ title = forms.StringField( __("Title"), validators=[ forms.validators.DataRequired(__("The board needs a name")), forms.validators.StripWhitespace(), forms.validators.Length(min=1, max=80, message=__("%%(max)d characters maximum")) ]) caption = forms.NullTextField( __("Caption"), validators=[ forms.validators.Optional(), forms.validators.StripWhitespace(), forms.validators.Length(min=0, max=80, message=__("%%(max)d characters maximum")) ], description=__( "The title and caption appear at the top of the page. Keep them concise" )) name = forms.AnnotatedTextField( __("URL Name"), prefix='https://', suffix=u'.hasjob.co', description=__(u"Optional — Will be autogenerated if blank"), validators=[ forms.validators.ValidName(), forms.validators.Length(min=0, max=63, message=__("%%(max)d characters maximum")), AvailableName(__(u"This name has been taken by another board"), model=Board) ]) description = forms.TinyMce4Field( __(u"Description"), description=__( u"The description appears at the top of the board, above all jobs. " u"Use it to introduce your board and keep it brief"), content_css=content_css, validators=[ forms.validators.DataRequired( __("A description of the job board is required")), forms.validators.AllUrlsValid() ]) userid = forms.RadioField( __(u"Owner"), validators=[forms.validators.DataRequired(__("Select an owner"))], description=__( u"Select the user or organization who owns this board. " "Owners can add jobs to the board and edit these settings")) require_login = forms.BooleanField( __(u"Prompt users to login"), default=True, description=__( u"If checked, users must login to see all jobs available. " u"Logging in provides users better filtering for jobs that may be of interest to them, " u"and allows employers to understand how well their post is performing" )) options = forms.FormField(BoardOptionsForm, __(u"Direct posting options")) autotag = forms.FormField(BoardTaggingForm, __(u"Automatic posting options")) def validate_name(self, field): if field.data: if field.data in Board.reserved_names: raise forms.ValidationError( _(u"This name is reserved. Please use another name"))
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.StripWhitespace(), forms.validators.Length(min=1, max=100, message="%(max)d characters maximum"), forms.validators.NoObfuscatedEmail( u"Do not include contact information in the post") ]) job_headlineb = forms.NullTextField( "Headline B", description= u"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.StripWhitespace(), forms.validators.Length(min=1, max=100, message="%(max)d characters maximum"), forms.validators.NoObfuscatedEmail( u"Do not include contact information in the post") ]) 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.StripWhitespace(), forms.validators.Length(min=3, max=80, message="%(max)d characters maximum") ]) 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()) 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( "Name", description=u"The name of the organization where the position is. " u"No intermediaries or unnamed stealth startups. Use your own real name if the organization isn’t named " u"yet. We do not accept posts from third parties such as recruitment consultants. Such posts " u"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.StripWhitespace(), forms.validators.Length( min=4, max=80, message="The name must be within %(min)d to %(max)d characters" ) ]) 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(), forms.validators.StripWhitespace(), optional_url, forms.validators.Length(max=255, message="%(max)d characters maximum"), forms.validators.ValidUrl() ]) 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.StripWhitespace(), 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") ]) twitter = forms.AnnotatedNullTextField( "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.StripWhitespace(), forms.validators.Length( min=0, max=15, message= u"Twitter accounts can’t be over %(max)d characters long") ]) 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)) if small == 0 or caps / float(small) > 0.8: raise forms.ValidationError( u"Surely your organization isn’t named in uppercase?") def validate_company_logo(form, field): if not 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 RegisterClientForm(forms.Form): """ Register a new OAuth client application """ title = forms.StringField(__("Application title"), validators=[forms.validators.DataRequired()], description=__("The name of your application")) description = forms.TextAreaField(__("Description"), validators=[forms.validators.DataRequired()], description=__("A description to help users recognize your application")) client_owner = forms.RadioField(__("Owner"), validators=[forms.validators.DataRequired()], description=__("User or organization that owns this application. Changing the owner " "will revoke all currently assigned permissions for this app")) website = forms.URLField(__("Application website"), validators=[forms.validators.DataRequired(), forms.validators.URL()], description=__("Website where users may access this application")) namespace = forms.NullTextField(__("Client namespace"), validators=[forms.validators.Optional()], description=Markup(__(u"A dot-based namespace that uniquely identifies your client application. " u"For example, if your client website is <code>https://auth.hasgeek.com</code>, " u"use <code>com.hasgeek.auth</code>. Only required if your client app provides resources")), widget_attrs={'autocorrect': 'none', 'autocapitalize': 'none'}) redirect_uri = forms.URLField(__("Redirect URL"), validators=[forms.validators.Optional(), forms.validators.URL()], description=__("OAuth2 Redirect URL")) notification_uri = forms.URLField(__("Notification URL"), validators=[forms.validators.Optional(), forms.validators.URL()], description=__("When the user's data changes, Lastuser will POST a notice to this URL. " "Other notices may be posted too")) iframe_uri = forms.URLField(__("IFrame URL"), validators=[forms.validators.Optional(), forms.validators.URL()], description=__("Front-end notifications URL. This is loaded in a hidden iframe to notify the app that the " "user updated their profile in some way (not yet implemented)")) allow_any_login = forms.BooleanField(__("Allow anyone to login"), default=True, description=__("If your application requires access to be restricted to specific users, uncheck this, " "and only users who have been assigned a permission to the app will be able to login")) team_access = forms.BooleanField(__("Requires access to teams"), default=False, description=__("If your application is capable of assigning access permissions to teams, check this. " "Organization owners will then able to grant access to teams in their organizations")) def validate_client_owner(self, field): if field.data == self.edit_user.userid: self.user = self.edit_user self.org = None else: orgs = [org for org in self.edit_user.organizations_owned() if org.userid == field.data] if len(orgs) != 1: raise forms.ValidationError(_("Invalid owner")) self.user = None self.org = orgs[0] def _urls_match(self, url1, url2): p1 = urlparse(url1) p2 = urlparse(url2) return (p1.netloc == p2.netloc) and (p1.scheme == p2.scheme) and ( p1.username == p2.username) and (p1.password == p2.password) def validate_redirect_uri(self, field): if not self._urls_match(self.website.data, field.data): raise forms.ValidationError(_("The scheme, domain and port must match that of the website URL")) def validate_notification_uri(self, field): if not self._urls_match(self.website.data, field.data): raise forms.ValidationError(_("The scheme, domain and port must match that of the website URL")) def validate_resource_uri(self, field): if not self._urls_match(self.website.data, field.data): raise forms.ValidationError(_("The scheme, domain and port must match that of the website URL")) def validate_namespace(self, field): if field.data: if not domain_namespace_match(self.website.data, field.data): raise forms.ValidationError(_(u"The namespace should be derived from your application’s website domain")) client = self.edit_model.get(namespace=field.data) if client: if client == self.edit_obj: return raise forms.ValidationError(_("This namespace has been claimed by another client app"))