def validate_amount(form, field): requested_refund_amount = field.data order = form.edit_parent if not order.paid_amount: raise StopValidation(__("Refunds can only be issued for paid orders")) if (order.refunded_amount + requested_refund_amount) > order.paid_amount: raise StopValidation(__("Invalid refund amount! Must be lesser than {amount}, the net amount paid for the order".format(amount=order.net_amount)))
def available_seq(form, field): basequery = db.session.query(Category.id).filter( Category.item_collection == form.edit_parent, Category.seq == field.data) if form.edit_obj: basequery = basequery.filter(Category.id != form.edit_obj.id) if basequery.scalar() is not None: raise StopValidation(__("This sequence number has already been used. Please pick a different number"))
def validate_gstin(form, field): """ Raise a StopValidation exception if the supplied field's data is not a valid GSTIN. Checks if the data is: - 15 characters in length - First two characters form a valid short code for an Indian state - Contains a PAN (alphanumeric sub-string ranging from the 2nd to the 11th character) - Last character is an alphanumeric Reference: https://cleartax.in/s/know-your-gstin """ # 15 length, first 2 digits, valid pan, checksum if len(field.data) != 15 or int(field.data[:2]) not in short_codes or not field.data[2:12].isalnum() or not field.data[-1].isalnum(): raise forms.validators.StopValidation(__("This does not appear to be a valid GSTIN"))
def proposal_label_form(project, proposal): """ Returns a label form for the given project and proposal. """ class ProposalLabelForm(forms.Form): pass for label in project.labels: if label.has_options and not label.archived and not label.restricted: setattr(ProposalLabelForm, label.name, forms.RadioField( label.form_label_text, description=label.description, validators=[forms.validators.DataRequired(__("Please select one"))] if label.required else [], choices=[(option.name, option.title) for option in label.options if not option.archived] )) return ProposalLabelForm(obj=proposal.formlabels if proposal else None, meta={'csrf': False})
class RenderProposalSubmittedNotification(RenderNotification): """Notify the proposer that their proposal has been submitted.""" aliases = {'document': 'proposal'} emoji_prefix = "📤 " reason = __( "You are receiving this because you have submitted this proposal") def web(self): return render_template( 'notifications/proposal_submitted_web.html.jinja2', view=self, proposal=self.proposal, project=self.proposal.project, ) def email_subject(self): return self.emoji_prefix + _( "Proposal submitted to {project}: {proposal}").format( project=self.proposal.project.joined_title(), proposal=self.proposal.title) def email_content(self): return render_template( 'notifications/proposal_submitted_email.html.jinja2', view=self, proposal=self.proposal, project=self.proposal.project, ) def sms(self): return _("Your proposal has been submitted to {project} {url}").format( project=self.proposal.project.joined_title('>'), url=shortlink( self.proposal.url_for(_external=True, **self.tracking_tags('sms'))), )
class EMPLOYER_RESPONSE(LabeledEnum): # NOQA: N801 #: New application NEW = (0, 'new', __("New")) #: Employer viewed on website PENDING = (1, 'pending', __("Pending")) #: Dismissed as not worth responding to IGNORED = (2, 'ignored', __("Ignored")) #: Employer replied to candidate REPLIED = (3, 'replied', __("Replied")) #: Employer reported a spammer FLAGGED = (4, 'flagged', __("Flagged")) #: Admin marked this as spam SPAM = (5, 'spam', __("Spam")) #: Employer rejected candidate with a message REJECTED = (6, 'rejected', __("Rejected")) __order__ = (NEW, PENDING, IGNORED, REPLIED, FLAGGED, SPAM, REJECTED) CAN_REPLY = {NEW, PENDING, IGNORED} CAN_REJECT = CAN_REPLY CAN_IGNORE = {NEW, PENDING} CAN_REPORT = {NEW, PENDING, IGNORED, REJECTED}
class RenderOrganizationAdminMembershipNotification(RenderShared, RenderNotification): """Notify organization admins of new admins and role changes.""" aliases = {'document': 'organization', 'fragment': 'membership'} reason = __( "You are receiving this because you are an admin of this organization") fragments_order_by = [OrganizationMembership.granted_at.desc()] def activity_template(self, membership=None): """ Returns a returns a Python string template with an appropriate message. Accepts an optional membership object for use in rollups. """ if not membership: membership = self.membership for df in decision_factors: if df.match( # LHS = user object, RHS = role proxy, so compare uuid self.user_notification.user.uuid == membership.user.uuid, self.record_type, membership, ): return df.template def web(self): return render_template( 'notifications/organization_membership_granted_web.html.jinja2', view=self) def email_content(self): return render_template( 'notifications/organization_membership_granted_email.html.jinja2', view=self)
def proposal_label_admin_form(project, proposal): """ Returns a label form to use in admin panel for given project and proposal """ class ProposalLabelAdminForm(forms.Form): pass for label in project.labels: if not label.archived and (label.restricted or not label.has_options): form_kwargs = {} if label.has_options: FieldType = forms.RadioField form_kwargs['choices'] = [(option.name, option.title) for option in label.options if not option.archived] else: FieldType = forms.BooleanField setattr(ProposalLabelAdminForm, label.name, FieldType( label.form_label_text, description=label.description, validators=[forms.validators.DataRequired(__("Please select one"))] if label.required else [], **form_kwargs )) return ProposalLabelAdminForm(obj=proposal.formlabels if proposal else None, meta={'csrf': False})
class DiscountPolicyForm(forms.Form): title = forms.StringField(__("Discount title"), validators=[ forms.validators.DataRequired( __("Please specify a discount title")), forms.validators.Length(max=250) ], filters=[forms.filters.strip()]) discount_type = forms.RadioField(__("Discount type"), choices=list(DISCOUNT_TYPE.items()), coerce=int, default=DISCOUNT_TYPE.COUPON) is_price_based = forms.RadioField(__("Price based discount"), coerce=getbool, default=1, choices=[ (1, __("Special price discount")), (0, __("Percentage based discount")) ])
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 VenueRoomForm(Form): title = wtforms.TextField(__("Name"), description=__("Name of the room"), validators=[ wtforms.validators.Required(), wtforms.validators.length(max=250) ]) description = MarkdownField( __("Description"), description=__("An optional note about the room")) bgcolor = wtforms.TextField( __("Event Color"), validators=[ wtforms.validators.Required(), wtforms.validators.length(max=6) ], description=__( "RGB Color for the event. Enter without the '#'. E.g. CCCCCC."), default=u"CCCCCC") def validate_bgcolor(self, field): if not valid_color_re.match(field.data): raise wtforms.ValidationError("Please enter a valid color code")
class ResourceActionForm(forms.Form): """ Edit an action associated with a resource """ name = forms.StringField(__("Action name"), validators=[forms.validators.DataRequired()], description=__("Name of the action as a single word in lower case. " "This is provided by applications as part of the scope in the form " "'resource/action' when requesting access to a user's resources. " "Read actions are implicit when applications request just 'resource' " "in the scope and do not need to be specified as an explicit action"), widget_attrs={'autocorrect': 'none', 'autocapitalize': 'none'}) title = forms.StringField(__("Title"), validators=[forms.validators.DataRequired()], description=__("Action title that is displayed to users")) description = forms.TextAreaField(__("Description"), description=__("An optional description of what the action is")) def validate_name(self, field): field.data = field.data.lower() if not valid_username(field.data): raise forms.ValidationError(_("Name contains invalid characters")) existing = self.edit_resource.get_action(field.data) if existing and existing.id != self.edit_id: raise forms.ValidationError(_("An action with that name already exists for this resource"))
class INVOICE_STATUS(LabeledEnum): # NOQA: N801 DRAFT = (0, __("Draft")) FINAL = (1, __("Final"))
class PROPOSALSTATUS(LabeledEnum): # Draft-state for future use, so people can save their proposals and submit only when ready DRAFT = (0, __("Draft")) SUBMITTED = (1, __("Submitted")) CONFIRMED = (2, __("Confirmed")) WAITLISTED = (3, __("Waitlisted")) SHORTLISTED = (4, __("Shortlisted")) REJECTED = (5, __("Rejected")) CANCELLED = (6, __("Cancelled")) AWAITING_DETAILS = (7, __("Awaiting details")) UNDER_EVALUATION = (8, __("Under evaluation")) SHORTLISTED_FOR_REHEARSAL = (9, __("Shortlisted for rehearsal")) REHEARSAL = (10, __("Rehearsal ongoing"))
def get_currency_choices(): choices = [('', __('None'))] choices.extend(CURRENCY.items()) return choices
def validate_json(form, field): try: json.loads(field.data) except ValueError: raise forms.validators.StopValidation(__("Invalid JSON"))
class CAMPAIGN_STATE(LabeledEnum): # NOQA: N801 DISABLED = (False, 'disabled', __("Disabled")) ENABLED = (True, 'enabled', __("Enabled"))
class UserFlags(object): """ A collection of bi-directional flags to (a) set on a user or (b) find matching users. This is a convenience class, meant only to be an easy way to look up contents. """ # Is a new user (under a day, a month) is_new_since_day = UserFlag( 'user', __("Is a new user (joined <= a day ago)"), lambda user: user.created_at >= utcnow() - newlimit, lambda: db.session.query(User.id).filter( User.created_at >= utcnow() - newlimit ), ) is_new_since_month = UserFlag( 'user', __("Is a new user (joined <= a month ago)"), lambda user: user.created_at >= utcnow() - agelimit, lambda: db.session.query(User.id).filter( User.created_at >= utcnow() - agelimit ), ) is_not_new = UserFlag( 'user', __("Is not a new user (joined > a month ago)"), lambda user: user.created_at < utcnow() - agelimit, lambda: db.session.query(User.id).filter(User.created_at < utcnow() - agelimit), ) # Is a candidate (all time, new, recent, past) is_candidate_alltime = UserFlag( 'candidate', __("Is a candidate (applied at any time)"), lambda user: JobApplication.query.filter( JobApplication.user == user ).notempty(), lambda: db.session.query(distinct(JobApplication.user_id).label('id')), ) is_candidate_day = UserFlag( 'candidate', __("Is a candidate (applied <= a day ago)"), lambda user: JobApplication.query.filter( JobApplication.user == user, JobApplication.created_at >= utcnow() - newlimit, ).notempty(), lambda: db.session.query(distinct(JobApplication.user_id).label('id')).filter( JobApplication.created_at >= utcnow() - newlimit ), ) is_candidate_month = UserFlag( 'candidate', __("Is a candidate (applied <= a month ago)"), lambda user: JobApplication.query.filter( JobApplication.user == user, JobApplication.created_at >= utcnow() - agelimit, ).notempty(), lambda: db.session.query(distinct(JobApplication.user_id).label('id')).filter( JobApplication.created_at >= utcnow() - agelimit ), ) is_candidate_past = UserFlag( 'candidate', __("Is a candidate (applied > a month ago)"), lambda user: JobApplication.query.filter( JobApplication.user == user, JobApplication.created_at < utcnow() - agelimit ).notempty(), lambda: db.session.query(distinct(JobApplication.user_id).label('id')).filter( JobApplication.created_at < utcnow() - agelimit ), ) # Is a candidate who got a response from an employer has_jobapplication_response_alltime = UserFlag( 'candidate', __("Is a candidate who received a response (at any time)"), lambda user: JobApplication.query.filter( JobApplication.user == user, JobApplication.response.REPLIED ).notempty(), lambda: db.session.query(distinct(JobApplication.user_id).label('id')).filter( JobApplication.response.REPLIED ), ) has_jobapplication_response_day = UserFlag( 'candidate', __("Is a candidate who received a response (in <= a day)"), lambda user: JobApplication.query.filter( JobApplication.user == user, JobApplication.replied_at >= utcnow() - newlimit, JobApplication.response.REPLIED, ).notempty(), lambda: db.session.query(distinct(JobApplication.user_id).label('id')).filter( JobApplication.response.REPLIED, JobApplication.replied_at >= utcnow() - newlimit, ), ) has_jobapplication_response_month = UserFlag( 'candidate', __("Is a candidate who received a response (in <= a month)"), lambda user: JobApplication.query.filter( JobApplication.user == user, JobApplication.replied_at >= utcnow() - agelimit, JobApplication.response.REPLIED, ).notempty(), lambda: db.session.query(distinct(JobApplication.user_id).label('id')).filter( JobApplication.response.REPLIED, JobApplication.replied_at >= utcnow() - agelimit, ), ) has_jobapplication_response_past = UserFlag( 'candidate', __("Is a candidate who received a response (in > a month)"), lambda user: JobApplication.query.filter( JobApplication.user == user, JobApplication.replied_at < utcnow() - agelimit, JobApplication.response.REPLIED, ).notempty(), lambda: db.session.query(distinct(JobApplication.user_id).label('id')).filter( JobApplication.response.REPLIED, JobApplication.replied_at < utcnow() - agelimit, ), ) # Is an employer (not including collaborators) (all time, new, recent, past) is_employer_alltime = UserFlag( 'employer', __("Is an employer (posted at any time)"), lambda user: JobPost.query.filter( JobPost.user == user, ~(JobPost.state.UNPUBLISHED) ).notempty(), lambda: db.session.query(db.distinct(JobPost.user_id).label('id')).filter( ~(JobPost.state.UNPUBLISHED) ), ) is_employer_day = UserFlag( 'employer', __("Is an employer (posted <= a day ago)"), lambda user: JobPost.query.filter( JobPost.user == user, JobPost.state.NEW, ~(JobPost.state.UNPUBLISHED) ).notempty(), lambda: db.session.query(db.distinct(JobPost.user_id).label('id')).filter( JobPost.state.NEW, ~(JobPost.state.UNPUBLISHED) ), ) is_employer_month = UserFlag( 'employer', __("Is an employer (posted <= a month ago)"), lambda user: JobPost.query.filter( JobPost.user == user, JobPost.state.LISTED, ~(JobPost.state.UNPUBLISHED) ).notempty(), lambda: db.session.query(db.distinct(JobPost.user_id).label('id')).filter( JobPost.state.LISTED, ~(JobPost.state.UNPUBLISHED) ), ) is_employer_past = UserFlag( 'employer', __("Is an employer (posted > a month ago)"), lambda user: JobPost.query.filter( JobPost.user == user, JobPost.datetime < utcnow() - agelimit, ~(JobPost.state.UNPUBLISHED), ).notempty(), lambda: db.session.query(db.distinct(JobPost.user_id).label('id')).filter( JobPost.datetime < utcnow() - agelimit, ~(JobPost.state.UNPUBLISHED) ), ) # Employer who didn't confirm a listing has_jobpost_unconfirmed_alltime = UserFlag( 'employer', __("Is an employer who did not confirm a post (at any time)"), lambda user: JobPost.query.filter( JobPost.user == user, JobPost.state.UNPUBLISHED ).notempty(), lambda: db.session.query(db.distinct(JobPost.user_id).label('id')).filter( ~(JobPost.state.UNPUBLISHED) ), ) has_jobpost_unconfirmed_day = UserFlag( 'employer', __("Is an employer who did not confirm a post (posted <= a day ago)"), lambda user: JobPost.query.filter( JobPost.user == user, JobPost.state.NEW, JobPost.state.UNPUBLISHED ).notempty(), lambda: db.session.query(db.distinct(JobPost.user_id).label('id')).filter( JobPost.state.NEW, ~(JobPost.state.UNPUBLISHED) ), ) has_jobpost_unconfirmed_month = UserFlag( 'employer', __("Is an employer who did not confirm a post (posted <= a month ago)"), lambda user: JobPost.query.filter( JobPost.user == user, JobPost.state.LISTED, JobPost.state.UNPUBLISHED ).notempty(), lambda: db.session.query(db.distinct(JobPost.user_id).label('id')).filter( JobPost.state.LISTED, ~(JobPost.state.UNPUBLISHED) ), ) # Employer who responded to a candidate has_responded_candidate_alltime = UserFlag( 'candidate', __("Is an employer who responded to a candidate (at any time)"), lambda user: JobApplication.query.filter( JobApplication.replied_by == user, JobApplication.response.REPLIED ).notempty(), lambda: db.session.query( distinct(JobApplication.replied_by_id).label('id') ).filter(JobApplication.response.REPLIED), ) has_responded_candidate_day = UserFlag( 'candidate', __("Is an employer who responded to a candidate (in <= a day)"), lambda user: JobApplication.query.filter( JobApplication.replied_by == user, JobApplication.replied_at >= utcnow() - newlimit, JobApplication.response.REPLIED, ).notempty(), lambda: db.session.query( distinct(JobApplication.replied_by_id).label('id') ).filter( JobApplication.response.REPLIED, JobApplication.replied_at >= utcnow() - newlimit, ), ) has_responded_candidate_month = UserFlag( 'candidate', __("Is an employer who responded to a candidate (in <= a month)"), lambda user: JobApplication.query.filter( JobApplication.replied_by == user, JobApplication.replied_at >= utcnow() - agelimit, JobApplication.response.REPLIED, ).notempty(), lambda: db.session.query( distinct(JobApplication.replied_by_id).label('id') ).filter( JobApplication.response.REPLIED, JobApplication.replied_at >= utcnow() - agelimit, ), ) has_responded_candidate_past = UserFlag( 'candidate', __("Is an employer who responded to a candidate (in > a month)"), lambda user: JobApplication.query.filter( JobApplication.replied_by == user, JobApplication.replied_at < utcnow() - agelimit, JobApplication.response.REPLIED, ).notempty(), lambda: db.session.query( distinct(JobApplication.replied_by_id).label('id') ).filter( JobApplication.response.REPLIED, JobApplication.replied_at < utcnow() - agelimit, ), ) # Account created in <= a day is_new_lurker_within_day = UserFlag( 'lurker', __("Is a lurker (joined <= a day ago)"), lambda user: user.created_at >= utcnow() - newlimit and (not JobPost.query.filter(JobPost.user == user).notempty()) or (not JobApplication.query.filter(JobApplication.user == user).notempty()) or ( not JobApplication.query.filter( JobApplication.replied_by == user ).notempty() ), lambda: db.session.query(User.id).filter( User.created_at >= utcnow() - newlimit, ~User.id.in_( db.session.query(JobApplication.user_id).filter( JobApplication.user_id.isnot(None) ) ), ~User.id.in_( db.session.query(JobApplication.replied_by_id).filter( JobApplication.replied_by_id.isnot(None) ) ), ~User.id.in_( db.session.query(JobPost.user_id).filter(JobPost.user_id.isnot(None)) ), ), ) # Account created in <= a month is_new_lurker_within_month = UserFlag( 'lurker', __("Is a lurker (joined <= a month ago)"), lambda user: user.created_at >= utcnow() - agelimit and (not JobPost.query.filter(JobPost.user == user).notempty()) or (not JobApplication.query.filter(JobApplication.user == user).notempty()) or ( not JobApplication.query.filter( JobApplication.replied_by == user ).notempty() ), lambda: db.session.query(User.id).filter( User.created_at >= utcnow() - agelimit, ~User.id.in_( db.session.query(JobApplication.user_id).filter( JobApplication.user_id.isnot(None) ) ), ~User.id.in_( db.session.query(JobApplication.replied_by_id).filter( JobApplication.replied_by_id.isnot(None) ) ), ~User.id.in_( db.session.query(JobPost.user_id).filter(JobPost.user_id.isnot(None)) ), ), ) # Account created > a month ago is_lurker_since_past = UserFlag( 'lurker', __("Is a lurker (joined > a month ago)"), lambda user: user.created_at < utcnow() - agelimit and (not JobPost.query.filter(JobPost.user == user).notempty()) or (not JobApplication.query.filter(JobApplication.user == user).notempty()) or ( not JobApplication.query.filter( JobApplication.replied_by == user ).notempty() ), lambda: db.session.query(User.id).filter( User.created_at < utcnow() - agelimit, ~User.id.in_( db.session.query(JobApplication.user_id).filter( JobApplication.user_id.isnot(None) ) ), ~User.id.in_( db.session.query(JobApplication.replied_by_id).filter( JobApplication.replied_by_id.isnot(None) ) ), ~User.id.in_( db.session.query(JobPost.user_id).filter(JobPost.user_id.isnot(None)) ), ), # NOQA ) # Has always been a lurker is_lurker_since_alltime = UserFlag( 'lurker', __("Is a lurker"), lambda user: (not JobPost.query.filter(JobPost.user == user).notempty()) or (not JobApplication.query.filter(JobApplication.user == user).notempty()) or ( not JobApplication.query.filter( JobApplication.replied_by == user ).notempty() ), lambda: db.session.query(User.id).filter( ~User.id.in_( db.session.query(JobApplication.user_id).filter( JobApplication.user_id.isnot(None) ) ), ~User.id.in_( db.session.query(JobApplication.replied_by_id).filter( JobApplication.replied_by_id.isnot(None) ) ), ~User.id.in_( db.session.query(JobPost.user_id).filter(JobPost.user_id.isnot(None)) ), ), ) # Has been lurking for a day+ is_inactive_since_day = UserFlag( 'lurker', __("Is inactive (for a day+)"), lambda user: ( not JobPost.query.filter( JobPost.user == user, JobPost.created_at >= utcnow() - newlimit ).notempty() ) or ( not JobApplication.query.filter( JobApplication.user == user, JobApplication.created_at >= utcnow() - newlimit, ).notempty() ) or ( not JobApplication.query.filter( JobApplication.replied_by == user, JobApplication.replied_at >= utcnow() - newlimit, ).notempty() ), lambda: db.session.query(User.id).filter( ~User.id.in_( db.session.query(JobApplication.user_id).filter( JobApplication.user_id.isnot(None), JobApplication.created_at >= utcnow() - newlimit, ) ), ~User.id.in_( db.session.query(JobApplication.replied_by_id).filter( JobApplication.replied_by_id.isnot(None), JobApplication.replied_at >= utcnow() - newlimit, ) ), ~User.id.in_( db.session.query(JobPost.user_id).filter( JobPost.user_id.isnot(None), JobPost.created_at >= utcnow() - newlimit, ) ), ), ) # Has been lurking for a month+ is_inactive_since_month = UserFlag( 'lurker', __("Is inactive (for a month+)"), lambda user: ( not JobPost.query.filter( JobPost.user == user, JobPost.created_at >= utcnow() - agelimit ).notempty() ) or ( not JobApplication.query.filter( JobApplication.user == user, JobApplication.created_at >= utcnow() - agelimit, ).notempty() ) or ( not JobApplication.query.filter( JobApplication.replied_by == user, JobApplication.replied_at >= utcnow() - agelimit, ).notempty() ), lambda: db.session.query(User.id).filter( ~User.id.in_( db.session.query(JobApplication.user_id).filter( JobApplication.user_id.isnot(None), JobApplication.created_at >= utcnow() - agelimit, ) ), ~User.id.in_( db.session.query(JobApplication.replied_by_id).filter( JobApplication.replied_by_id.isnot(None), JobApplication.replied_at >= utcnow() - agelimit, ) ), ~User.id.in_( db.session.query(JobPost.user_id).filter( JobPost.user_id.isnot(None), JobPost.created_at >= utcnow() - newlimit, ) ), ), ) # One-way flags (no elegant way to do a reverse query) has_boards = UserFlag( 'admin', __("Has a sub-board"), lambda user: Board.query.filter( Board.userid.in_(user.allowner_ids()) ).notempty(), None, )
class JobPost(BaseMixin, db.Model): __tablename__ = 'jobpost' # Metadata user_id = db.Column(None, db.ForeignKey('user.id'), nullable=True, index=True) user = db.relationship(User, primaryjoin=user_id == User.id, backref=db.backref('jobposts', lazy='dynamic')) hashid = db.Column(db.String(5), nullable=False, unique=True) datetime = db.Column(db.DateTime, default=db.func.utcnow(), nullable=False, index=True) # Published closed_datetime = db.Column(db.DateTime, nullable=True) # If withdrawn or rejected # Pinned on the home page. Boards use the BoardJobPost.pinned column sticky = db.Column(db.Boolean, nullable=False, default=False) pinned = db.synonym('sticky') # Job description headline = db.Column(db.Unicode(100), nullable=False) headlineb = db.Column(db.Unicode(100), nullable=True) type_id = db.Column(None, db.ForeignKey('jobtype.id'), nullable=False) type = db.relation(JobType, primaryjoin=type_id == JobType.id) category_id = db.Column(None, db.ForeignKey('jobcategory.id'), nullable=False) category = db.relation(JobCategory, primaryjoin=category_id == JobCategory.id) location = db.Column(db.Unicode(80), nullable=False) parsed_location = db.Column(JsonDict) # remote_location tracks whether the job is work-from-home/work-from-anywhere remote_location = db.Column(db.Boolean, default=False, nullable=False) relocation_assist = db.Column(db.Boolean, default=False, nullable=False) description = db.Column(db.UnicodeText, nullable=False) perks = db.Column(db.UnicodeText, nullable=False) how_to_apply = db.Column(db.UnicodeText, nullable=False) hr_contact = db.Column(db.Boolean, nullable=True) # Compensation details pay_type = db.Column(db.SmallInteger, nullable=True) # Value in models.PAY_TYPE pay_currency = db.Column(db.CHAR(3), nullable=True) pay_cash_min = db.Column(db.Integer, nullable=True) pay_cash_max = db.Column(db.Integer, nullable=True) pay_equity_min = db.Column(db.Numeric, nullable=True) pay_equity_max = db.Column(db.Numeric, nullable=True) # Company details company_name = db.Column(db.Unicode(80), nullable=False) company_logo = db.Column(db.Unicode(255), nullable=True) company_url = db.Column(db.Unicode(255), nullable=False, default=u'') twitter = db.Column(db.Unicode(15), nullable=True) fullname = db.Column( db.Unicode(80), nullable=True) # Deprecated field, used before user_id was introduced email = db.Column(db.Unicode(80), nullable=False) email_domain = db.Column(db.Unicode(80), nullable=False, index=True) domain_id = db.Column(None, db.ForeignKey('domain.id'), nullable=False) md5sum = db.Column(db.String(32), nullable=False, index=True) # Payment, audit and workflow fields words = db.Column( db.UnicodeText, nullable=True) # All words in description, perks and how_to_apply promocode = db.Column(db.String(40), nullable=True) ipaddr = db.Column(db.String(45), nullable=False) useragent = db.Column(db.Unicode(250), nullable=True) edit_key = db.Column(db.String(40), nullable=False, default=random_long_key) email_verify_key = db.Column(db.String(40), nullable=False, default=random_long_key) email_sent = db.Column(db.Boolean, nullable=False, default=False) email_verified = db.Column(db.Boolean, nullable=False, default=False) payment_value = db.Column(db.Integer, nullable=False, default=0) payment_received = db.Column(db.Boolean, nullable=False, default=False) reviewer_id = db.Column(None, db.ForeignKey('user.id'), nullable=True, index=True) reviewer = db.relationship(User, primaryjoin=reviewer_id == User.id, backref="reviewed_posts") review_datetime = db.Column(db.DateTime, nullable=True) review_comments = db.Column(db.Unicode(250), nullable=True) search_vector = deferred(db.Column(TSVECTOR, nullable=True)) _state = db.Column('status', db.Integer, StateManager.check_constraint('status', POST_STATE), default=POST_STATE.DRAFT, nullable=False) state = StateManager('_state', POST_STATE, doc="Current state of the job post") # Metadata for classification language = db.Column(db.CHAR(2), nullable=True) language_confidence = db.Column(db.Float, nullable=True) admins = db.relationship(User, lazy='dynamic', secondary=lambda: jobpost_admin_table, backref=db.backref('admin_of', lazy='dynamic')) starred_by = db.relationship(User, lazy='dynamic', secondary=starred_job_table, backref=db.backref('starred_jobs', lazy='dynamic')) #: Quick lookup locations this post is referring to geonameids = association_proxy('locations', 'geonameid', creator=lambda l: JobLocation(geonameid=l)) _defercols = [ defer('user_id'), defer('closed_datetime'), defer('parsed_location'), defer('relocation_assist'), defer('description'), defer('perks'), defer('how_to_apply'), defer('hr_contact'), defer('company_logo'), defer('company_url'), defer('fullname'), defer('email'), defer('words'), defer('promocode'), defer('ipaddr'), defer('useragent'), defer('edit_key'), defer('email_verify_key'), defer('email_sent'), defer('email_verified'), defer('payment_value'), defer('payment_received'), defer('reviewer_id'), defer('review_datetime'), defer('review_comments'), defer('language'), defer('language_confidence'), # These are defined below JobApplication defer('new_applications'), defer('replied_applications'), defer('viewcounts_viewed'), defer('viewcounts_opened'), defer('viewcounts_applied'), # defer('pay_type'), # defer('pay_currency'), # defer('pay_cash_min'), # defer('pay_cash_max'), # defer('pay_equity_min'), # defer('pay_equity_max'), ] @classmethod def get(cls, hashid): return cls.query.filter_by(hashid=hashid).one_or_none() @classmethod def fetch(cls, hashid): """Returns a SQLAlchemy query object for JobPost""" return cls.query.filter_by(hashid=hashid).options( load_only('id', 'headline', 'headlineb', 'hashid', 'datetime', '_state', 'email_domain', 'review_comments', 'company_url')) @classmethodproperty def query_listed(cls): """Returns a SQLAlchemy query for listed jobposts""" return cls.query.filter(JobPost.state.LISTED).options( db.load_only('id', 'hashid')) def __repr__(self): return '<JobPost {hashid} "{headline}">'.format( hashid=self.hashid, headline=self.headline.encode('utf-8')) def admin_is(self, user): if user is None: return False return user == self.user or bool( self.admins.options( db.load_only('id')).filter_by(id=user.id).count()) @property def expiry_date(self): return self.datetime + agelimit @property def after_expiry_date(self): return self.expiry_date + timedelta(days=1) # NEW = Posted within last 24 hours state.add_conditional_state( 'NEW', state.PUBLIC, lambda jobpost: jobpost.datetime >= datetime.utcnow() - newlimit, label=('new', __("New!"))) # LISTED = Posted within last 30 days state.add_conditional_state( 'LISTED', state.PUBLIC, lambda jobpost: jobpost.datetime >= datetime.utcnow() - agelimit, label=('listed', __("Listed"))) # OLD = Posted more than 30 days ago state.add_conditional_state('OLD', state.PUBLIC, lambda jobpost: not jobpost.state.LISTED, label=('old', __("Old"))) # Checks if current user has the permission to confirm the jobpost state.add_conditional_state( 'CONFIRMABLE', state.UNPUBLISHED, lambda jobpost: jobpost.current_permissions.edit, label=('confirmable', __("Confirmable"))) @state.transition(state.PUBLIC, state.WITHDRAWN, title=__("Withdraw"), message=__("This job post has been withdrawn"), type='danger') def withdraw(self): self.closed_datetime = db.func.utcnow() @state.transition(state.PUBLIC, state.CLOSED, title=__("Close"), message=__("This job post has been closed"), type='danger') def close(self): self.closed_datetime = db.func.utcnow() @state.transition(state.UNPUBLISHED_OR_MODERATED, state.CONFIRMED, title=__("Confirm"), message=__("This job post has been confirmed"), type='success') def confirm(self): self.email_verified = True self.datetime = db.func.utcnow() @state.transition(state.CLOSED, state.CONFIRMED, title=__("Reopen"), message=__("This job post has been reopened"), type='success') def reopen(self): pass @state.transition(state.PUBLIC, state.SPAM, title=__("Mark as spam"), message=__("This job post has been marked as spam"), type='danger') def mark_spam(self, reason, user): self.closed_datetime = db.func.utcnow() self.review_datetime = db.func.utcnow() self.review_comments = reason self.reviewer = user @state.transition( state.DRAFT, state.PENDING, title=__("Mark as pending"), message=__("This job post is awaiting email verification"), type='danger') def mark_pending(self): pass @state.transition(state.PUBLIC, state.REJECTED, title=__("Reject"), message=__("This job post has been rejected"), type='danger') def reject(self, reason, user): self.closed_datetime = db.func.utcnow() self.review_datetime = db.func.utcnow() self.review_comments = reason self.reviewer = user @state.transition(state.PUBLIC, state.MODERATED, title=__("Moderate"), message=__("This job post has been moderated"), type='primary') def moderate(self, reason, user): self.closed_datetime = db.func.utcnow() self.review_datetime = db.func.utcnow() self.review_comments = reason self.reviewer = user def url_for(self, action='view', _external=False, **kwargs): if self.state.UNPUBLISHED and action in ('view', 'edit'): domain = None else: domain = self.email_domain # A/B test flag for permalinks if 'b' in kwargs: if kwargs['b'] is not None: kwargs['b'] = unicode(int(kwargs['b'])) else: kwargs.pop('b') if action == 'view': return url_for('jobdetail', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'reveal': return url_for('revealjob', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'apply': return url_for('applyjob', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'edit': return url_for('editjob', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'withdraw': return url_for('withdraw', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'close': return url_for('close', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'viewstats': return url_for('job_viewstats', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'related_posts': return url_for('job_related_posts', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'reopen': return url_for('reopen', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'moderate': return url_for('moderatejob', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'pin': return url_for('pinnedjob', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'reject': return url_for('rejectjob', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'confirm': return url_for('confirm', hashid=self.hashid, _external=_external, **kwargs) elif action == 'logo': return url_for('logoimage', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'confirm-link': return url_for('confirm_email', hashid=self.hashid, domain=domain, key=self.email_verify_key, _external=True, **kwargs) elif action == 'star': return url_for('starjob', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'manage': return url_for('managejob', hashid=self.hashid, domain=domain, _external=_external, **kwargs) elif action == 'browse': if is_public_email_domain(self.email_domain, default=False): return url_for('browse_by_email', md5sum=self.md5sum, _external=_external, **kwargs) else: return url_for('browse_by_domain', domain=self.email_domain, _external=_external, **kwargs) def permissions(self, user, inherited=None): perms = super(JobPost, self).permissions(user, inherited) if self.state.PUBLIC: perms.add('view') if self.admin_is(user): if self.state.UNPUBLISHED: perms.add('view') perms.add('edit') perms.add('manage') perms.add('withdraw') return perms @property def from_webmail_domain(self): return is_public_email_domain(self.email_domain, default=False) @property def company_url_domain_zone(self): if not self.company_url: return u'' else: r = tldextract.extract(self.company_url) return u'.'.join([r.domain, r.suffix]) @property def pays_cash(self): if self.pay_type is None: # Legacy record from before `pay_type` was mandatory return True return self.pay_type != PAY_TYPE.NOCASH and self.pay_cash_min is not None and self.pay_cash_max is not None @property def pays_equity(self): return self.pay_equity_min is not None and self.pay_equity_max is not None def pay_label(self): if self.pay_type is None: return u"NA" elif self.pay_type == PAY_TYPE.NOCASH: cash = None suffix = "" else: if self.pay_type == PAY_TYPE.RECURRING: suffix = "pa" else: suffix = "" indian = False if self.pay_currency == "INR": indian = True symbol = u"₹" elif self.pay_currency == "USD": symbol = u"$" elif self.pay_currency == "EUR": symbol = u"€" elif self.pay_currency == "GBP": symbol = u"£" else: symbol = u"¤" if self.pay_cash_min == self.pay_cash_max: cash = symbol + number_abbreviate(self.pay_cash_min, indian) else: cash = symbol + number_abbreviate( self.pay_cash_min, indian) + "-" + number_abbreviate( self.pay_cash_max, indian) if suffix: cash = cash + " " + suffix if self.pays_equity: if self.pay_equity_min == self.pay_equity_max: equity = str(self.pay_equity_min) + "%" else: equity = str(self.pay_equity_min) + "-" + str( self.pay_equity_max) + "%" else: equity = None if cash: if equity: return ", ".join([cash, equity]) else: return cash else: if equity: return equity else: return "No pay" def tag_content(self): return Markup('\n').join( (Markup('<div>') + Markup(escape(self.headline)) + Markup('</div>'), Markup('<div>') + Markup(self.description) + Markup('</div>'), Markup('<div>') + Markup(self.perks) + Markup('</div>'))) @staticmethod def viewcounts_key(jobpost_id): if isinstance(jobpost_id, (list, tuple)): return ['hasjob/viewcounts/%d' % post_id for post_id in jobpost_id] return 'hasjob/viewcounts/%d' % jobpost_id def uncache_viewcounts(self, key=None): cache_key = JobPost.viewcounts_key(self.id) if not key: redis_store.delete(cache_key) else: redis_store.hdel(cache_key, key) @cached_property def ab_impressions(self): results = {'NA': 0, 'A': 0, 'B': 0} counts = db.session.query(JobImpression.bgroup.label('bgroup'), db.func.count('*').label('count')).filter( JobImpression.jobpost == self).group_by( JobImpression.bgroup) for row in counts: if row.bgroup is False: results['A'] = row.count elif row.bgroup is True: results['B'] = row.count else: results['NA'] = row.count return results @cached_property def ab_views(self): results = { 'C_NA': 0, 'C_A': 0, 'C_B': 0, # Conversions (cointoss=True, crosstoss=False) 'E_NA': 0, 'E_A': 0, 'E_B': 0, # External (cointoss=False, crosstoss=True OR False [do sum]) 'X_NA': 0, 'X_A': 0, 'X_B': 0, # Cross toss (cointoss=True, crosstoss=True) } counts = db.session.query(JobViewSession.bgroup.label('bgroup'), JobViewSession.cointoss.label('cointoss'), JobViewSession.crosstoss.label('crosstoss'), db.func.count('*').label('count')).filter( JobViewSession.jobpost == self).group_by( JobViewSession.bgroup, JobViewSession.cointoss, JobViewSession.crosstoss) for row in counts: if row.cointoss is True and row.crosstoss is False: prefix = 'C' elif row.cointoss is False: prefix = 'E' elif row.cointoss is True and row.crosstoss is True: prefix = 'X' if row.bgroup is False: results[prefix + '_A'] += row.count elif row.bgroup is True: results[prefix + '_B'] += row.count else: results[prefix + '_NA'] += row.count return results @property def sort_score(self): """ Sort with a gravity of 1.8 using the HackerNews algorithm """ viewcounts = self.viewcounts opened = int(viewcounts['opened']) applied = int(viewcounts['applied']) age = datetime.utcnow() - self.datetime hours = age.days * 24 + age.seconds / 3600 return ((applied * 3) + (opened - applied)) / pow((hours + 2), 1.8) @cached_property # For multiple accesses in a single request def viewstats(self): now = datetime.utcnow() delta = now - self.datetime hourly_stat_limit = 2 # days if delta.days < hourly_stat_limit: # Less than {limit} days return 'h', viewstats_by_id_hour(self.id, hourly_stat_limit * 24) else: return 'd', viewstats_by_id_day(self.id, 30) def reports(self): if not self.flags: return [] counts = {} for flag in self.flags: counts[flag.reportcode] = counts.setdefault(flag.reportcode, 0) + 1 return [{ 'count': i[2], 'title': i[1] } for i in sorted([(k.seq, k.title, v) for k, v in counts.items()])]
def validate_date_upto(self, field): if field.data and field.data.year < 1900: raise forms.ValidationError(__("Please enter a year after 1900"))
return render_redirect(url_for('.reset', expired=1, username=loginform.username.data)) elif request.method == 'POST' and formid in service_forms: form = service_forms[formid]['form'] if form.validate(): return set_loginmethod_cookie(login_registry[formid].do(form=form), formid) elif request.method == 'POST': abort(500) iframe_block = {'X-Frame-Options': 'SAMEORIGIN'} if request.is_xhr and formid == 'passwordlogin': return render_template('loginform.html.jinja2', loginform=loginform, Markup=Markup), 200, iframe_block else: return render_template('login.html.jinja2', loginform=loginform, lastused=loginmethod, service_forms=service_forms, Markup=Markup, login_registry=login_registry), 200, iframe_block logout_errormsg = __("We detected a possibly unauthorized attempt to log you out. " "If you really did intend to logout, please click on the logout link again") def logout_user(): """ User-initiated logout """ if not request.referrer or (urlparse.urlsplit(request.referrer).netloc != urlparse.urlsplit(request.url).netloc): # TODO: present a logout form flash(current_app.config.get('LOGOUT_UNAUTHORIZED_MESSAGE') or logout_errormsg, 'danger') return redirect(url_for('index')) else: logout_internal() db.session.commit() flash(_("You are now logged out"), category='info') return redirect(get_next_url())
def validate_end_at(self, field): if field.data <= self.start_at.data: raise forms.ValidationError(__(u"The campaign can’t end before it starts"))
if g.user: token = client.authtoken_for(g.user) else: token = None response = jsonify({ 'hastoken': True if token else False }) response.headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT' response.headers['Cache-Control'] = 'private, max-age=300' return response # --- Token-based resource endpoints ------------------------------------------ @lastuser_oauth.route('/api/1/id') @resource_registry.resource('id', __(u"Read your name and basic profile data")) def resource_id(authtoken, args, files=None): """ Return user's id """ if 'all' in args and getbool(args['all']): return get_userinfo(authtoken.user, authtoken.client, scope=authtoken.scope, get_permissions=True) else: return get_userinfo(authtoken.user, authtoken.client, scope=['id'], get_permissions=False) @csrf.exempt @lastuser_oauth.route('/api/1/session/verify', methods=['POST']) @resource_registry.resource('session/verify', __(u"Verify user session"), scope='id') def session_verify(authtoken, args, files=None): sessionid = args['sessionid']
class DISCOUNT_TYPE(LabeledEnum): # NOQA: N801 AUTOMATIC = (0, __("Automatic")) COUPON = (1, __("Coupon"))
class MEMBERSHIP_RECORD_TYPE(LabeledEnum): # NOQA: N801 INVITE = (0, 'invite', __("Invite")) ACCEPT = (1, 'accept', __("Accept")) DIRECT_ADD = (2, 'direct_add', __("Direct add")) AMEND = (3, 'amend', __("Amend"))
class AdminFiltersetView(UrlForView, ModelView): model = Filterset def loader(self, name=None): if name: return Filterset.get(g.board, name) @route('new', methods=['GET', 'POST']) @viewdata(title=__("New")) def new(self): if 'edit-filterset' not in g.board.current_permissions: abort(403) form = FiltersetForm(parent=g.board) if form.validate_on_submit(): filterset = Filterset(board=g.board, title=form.title.data) form.populate_obj(filterset) try: db.session.add(filterset) db.session.commit() flash("Created a filterset", 'success') return render_redirect(filterset.url_for(), code=303) except ValueError: db.session.rollback() flash( "There already exists a filterset with the selected criteria", 'interactive', ) return render_form( form=form, title="Create a filterset…", submit="Create", formid="filterset_new", ajax=False, ) @route('<name>/edit', methods=['GET', 'POST']) @viewdata(title=__("Edit")) def edit(self): if 'edit-filterset' not in g.board.current_permissions: abort(403) form = FiltersetForm(obj=self.obj) if form.validate_on_submit(): form.populate_obj(self.obj) try: db.session.commit() flash("Updated filterset", 'success') return render_redirect(self.obj.url_for(), code=303) except ValueError: db.session.rollback() flash( "There already exists a filterset with the selected criteria", 'interactive', ) return render_form( form=form, title="Edit filterset…", submit="Update", formid="filterset_edit", ajax=False, )
class CampaignForm(forms.Form): title = forms.StringField( __("Title"), description=__("A reference name for looking up this campaign again"), validators=[ forms.validators.DataRequired(__("A title is required")), forms.validators.StripWhitespace() ]) start_at = forms.DateTimeField(__("Start at"), timezone=lambda: g.user.timezone if g.user else None) end_at = forms.DateTimeField(__("End at"), timezone=lambda: g.user.timezone if g.user else None) public = forms.BooleanField(__("This campaign is live")) position = forms.RadioField(__("Display position"), choices=CAMPAIGN_POSITION.items(), coerce=int) priority = forms.IntegerField( __("Priority"), default=0, description=__( "A larger number is higher priority when multiple campaigns are running on the " "same dates. 0 implies lowest priority")) boards = QuerySelectMultipleField( __("Boards"), widget=ListWidget(), option_widget=CheckboxInput(), query_factory=lambda: Board.query.order_by('featured desc, title'), get_label='title_and_name', validators=[forms.validators.Optional()], description=__(u"Select the boards this campaign is active on")) geonameids = forms.GeonameSelectMultiField( "Locations", description=__( "This campaign will be targetted at users and jobs with matching locations" )) user_required = forms.RadioField( __("User is required"), coerce=getbool, choices=[(None, __(u"N/A – Don’t target by login status")), (True, __(u"Yes – Show to logged in users only")), (False, __(u"No – Show to anonymous users only"))]) flags = forms.RadioMatrixField( "Flags", coerce=getbool, fields=Campaign.flag_choices, description=__( "All selected flags must match the logged in user for the campaign to be shown" ), choices=[('None', __(u"N/A")), ('True', __(u"True")), ('False', __(u"False"))]) content = forms.FormField(CampaignContentForm, __("Campaign content")) def validate_geonameids(self, field): field.data = [int(x) for x in field.data if x.isdigit()] def validate_end_at(self, field): if field.data <= self.start_at.data: raise forms.ValidationError( _(u"The campaign can’t end before it starts"))
class Campaign(BaseNameMixin, db.Model): """ A campaign runs in the header or sidebar of Hasjob's pages and prompts the user towards some action. Unlike announcements, campaigns sit outside the content area of listings. """ __tablename__ = 'campaign' # Campaign metadata columns #: User who created this campaign user_id = db.Column(None, db.ForeignKey('user.id'), nullable=False) user = db.relationship(User, backref='campaigns') #: When does this campaign go on air? start_at = db.Column(db.TIMESTAMP(timezone=True), nullable=False, index=True) #: When does it go off air? end_at = db.Column(db.TIMESTAMP(timezone=True), nullable=False, index=True) #: Is this campaign live? public = db.Column(db.Boolean, nullable=False, default=False) #: StateManager for campaign's state state = StateManager('public', CAMPAIGN_STATE) #: Position to display campaign in position = db.Column( db.SmallInteger, nullable=False, default=CAMPAIGN_POSITION.HEADER ) #: Boards to run this campaign on boards = db.relationship(Board, secondary=board_campaign_table) #: Quick lookup locations to run this campaign in geonameids = association_proxy( 'locations', 'geonameid', creator=lambda l: CampaignLocation(geonameid=l) ) #: Is this campaign location-based? geotargeted = db.Column(db.Boolean, nullable=False, default=False) #: Is a user required? None = don't care, True = user required, False = no user user_required = db.Column(db.Boolean, nullable=True, default=None) #: Priority, lower = less priority priority = db.Column(db.Integer, nullable=False, default=0) # Campaign content columns #: Subject (user-facing, unlike the title) subject = db.Column(db.Unicode(250), nullable=True) #: Call to action text (for header campaigns) blurb = db.Column(db.UnicodeText, nullable=False, default='') #: Full text (for read more click throughs) description = db.Column(db.UnicodeText, nullable=False, default='') #: Banner image banner_image = db.Column(db.Unicode(250), nullable=True) #: Banner location banner_location = db.Column( db.SmallInteger, nullable=False, default=BANNER_LOCATION.TOP ) # Flags flag_is_new_since_day = db.Column(db.Boolean, nullable=True) flag_is_new_since_month = db.Column(db.Boolean, nullable=True) flag_is_not_new = db.Column(db.Boolean, nullable=True) flag_is_candidate_alltime = db.Column(db.Boolean, nullable=True) flag_is_candidate_day = db.Column(db.Boolean, nullable=True) flag_is_candidate_month = db.Column(db.Boolean, nullable=True) flag_is_candidate_past = db.Column(db.Boolean, nullable=True) flag_has_jobapplication_response_alltime = db.Column(db.Boolean, nullable=True) flag_has_jobapplication_response_day = db.Column(db.Boolean, nullable=True) flag_has_jobapplication_response_month = db.Column(db.Boolean, nullable=True) flag_has_jobapplication_response_past = db.Column(db.Boolean, nullable=True) flag_is_employer_alltime = db.Column(db.Boolean, nullable=True) flag_is_employer_day = db.Column(db.Boolean, nullable=True) flag_is_employer_month = db.Column(db.Boolean, nullable=True) flag_is_employer_past = db.Column(db.Boolean, nullable=True) flag_has_jobpost_unconfirmed_alltime = db.Column(db.Boolean, nullable=True) flag_has_jobpost_unconfirmed_day = db.Column(db.Boolean, nullable=True) flag_has_jobpost_unconfirmed_month = db.Column(db.Boolean, nullable=True) flag_has_responded_candidate_alltime = db.Column(db.Boolean, nullable=True) flag_has_responded_candidate_day = db.Column(db.Boolean, nullable=True) flag_has_responded_candidate_month = db.Column(db.Boolean, nullable=True) flag_has_responded_candidate_past = db.Column(db.Boolean, nullable=True) flag_is_new_lurker_within_day = db.Column(db.Boolean, nullable=True) flag_is_new_lurker_within_month = db.Column(db.Boolean, nullable=True) flag_is_lurker_since_past = db.Column(db.Boolean, nullable=True) flag_is_lurker_since_alltime = db.Column(db.Boolean, nullable=True) flag_is_inactive_since_day = db.Column(db.Boolean, nullable=True) flag_is_inactive_since_month = db.Column(db.Boolean, nullable=True) # Sessions this campaign has been viewed in session_views = db.relationship( EventSession, secondary=campaign_event_session_table, backref='campaign_views', order_by=campaign_event_session_table.c.created_at, lazy='dynamic', ) __table_args__ = ( db.CheckConstraint('end_at > start_at', name='campaign_start_at_end_at'), ) # Campaign conditional states state.add_conditional_state( 'LIVE', state.ENABLED, lambda obj: obj.start_at <= utcnow() < obj.end_at, lambda cls: db.and_( cls.start_at <= db.func.utcnow(), cls.end_at > db.func.utcnow() ), label=('live', __("Live")), ) state.add_conditional_state( 'CURRENT', state.ENABLED, lambda obj: obj.start_at <= obj.start_at <= utcnow() < obj.end_at <= utcnow() + timedelta(days=30), lambda cls: db.and_( cls.start_at <= db.func.utcnow(), cls.end_at > db.func.utcnow(), cls.end_at <= utcnow() + timedelta(days=30), ), label=('current', __("Current")), ) state.add_conditional_state( 'LONGTERM', state.ENABLED, lambda obj: obj.start_at <= obj.start_at <= utcnow() < utcnow() + timedelta(days=30) < obj.end_at, lambda cls: db.and_( cls.start_at <= utcnow(), cls.end_at > utcnow() + timedelta(days=30) ), label=('longterm', __("Long term")), ) state.add_conditional_state( 'OFFLINE', state.ENABLED, lambda obj: obj.start_at > utcnow() or obj.end_at <= utcnow(), lambda cls: db.or_( cls.start_at > db.func.utcnow(), cls.end_at <= db.func.utcnow() ), label=('offline', __("Offline")), ) @property def content(self): """Form helper method""" return self @property def flags(self): """Form helper method""" return self def __repr__(self): return '<Campaign %s "%s" %s:%s>' % ( self.name, self.title, self.start_at.strftime('%Y-%m-%d'), self.end_at.strftime('%Y-%m-%d'), ) def useractions(self, user): if user is not None: return { cua.action.name: cua for cua in CampaignUserAction.query.filter_by(user=user) .filter(CampaignUserAction.action_id.in_([a.id for a in self.actions])) .all() } else: return {} def view_for(self, user=None, anon_user=None): if user: return CampaignView.get(campaign=self, user=user) elif anon_user: return CampaignAnonView.get(campaign=self, anon_user=anon_user) def subject_for(self, user): return self.subject.format(user=user) def blurb_for(self, user): return Markup(self.blurb).format(user=user) def description_for(self, user): return Markup(self.description).format(user=user) def estimated_reach(self): """ Returns the number of users this campaign could potentially reach (assuming users are all active) """ plus_userids = set() minus_userids = set() for flag in Campaign.supported_flags: setting = getattr(self, 'flag_' + flag) if setting is True or setting is False: query = getattr(UserFlags, flag).user_ids() if setting is True: userids = set(query.all()) if plus_userids: plus_userids = plus_userids.intersection(userids) else: plus_userids = userids elif setting is False: userids = set(db.session.query(~User.id.in_(query)).all()) if minus_userids: minus_userids = minus_userids.union(userids) else: minus_userids = userids if not plus_userids and not minus_userids: return None return len(plus_userids - minus_userids) def form(self): """Convenience method for action form CSRF""" return Form() @classmethod def for_context( cls, position, board=None, user=None, anon_user=None, geonameids=None ): """ Return a campaign suitable for this board, user and locations (as geonameids). """ basequery = cls.query.filter(cls.state.LIVE, cls.position == position) if board: basequery = basequery.filter(cls.boards.any(id=board.id)) if user: # Look for campaigns that don't target by user or require a user basequery = basequery.filter( db.or_(cls.user_required.is_(None), cls.user_required.is_(True)) ) else: # Look for campaigns that don't target by user or require no user basequery = basequery.filter( db.or_(cls.user_required.is_(None), cls.user_required.is_(False)) ) if geonameids: # TODO: The query for CampaignLocation.campaign_id here does not consider # if the campaign id is currently live. This will become inefficient as the # number of location-targeted campaigns grows. This should be cached. basequery = basequery.filter( db.or_( cls.geotargeted.is_(False), db.and_( cls.geotargeted.is_(True), cls.id.in_( db.session.query(CampaignLocation.campaign_id).filter( CampaignLocation.geonameid.in_(geonameids) ) ), ), ) ) # In the following simpler version, a low priority geotargeted campaign returns above a high priority # non-geotargeted campaign, which isn't the intended behaviour. We've therefore commented it out and # left it here for reference. # basequery = basequery.join(CampaignLocation).filter(db.or_( # cls.geotargeted.is_(False), # db.and_( # cls.geotargeted.is_(True), # CampaignLocation.geonameid.in_(geonameids) # ))) else: basequery = basequery.filter(cls.geotargeted.is_(False)) # Don't show campaigns that (a) the user has dismissed or (b) the user has encountered on >2 event sessions if user is not None: # TODO: The more campaigns we run, the more longer this list gets. Find something more efficient basequery = basequery.filter( ~cls.id.in_( db.session.query(CampaignView.campaign_id).filter( CampaignView.user == user, db.or_( CampaignView.dismissed.is_(True), CampaignView.session_count > 2, ), ) ) ) # Filter by user flags for flag, value in user.flags.items(): if flag in cls.supported_flags: col = getattr(cls, 'flag_' + flag) basequery = basequery.filter(db.or_(col.is_(None), col == value)) else: if anon_user: basequery = basequery.filter( ~cls.id.in_( db.session.query(CampaignAnonView.campaign_id).filter( CampaignAnonView.anon_user == anon_user, db.or_( CampaignAnonView.dismissed.is_(True), CampaignAnonView.session_count > 2, ), ) ) ) # Don't show user-targeted campaigns if there's no user basequery = basequery.filter_by( **{'flag_' + flag: None for flag in cls.supported_flags} ) return basequery.order_by(cls.priority.desc()).first() @classmethod def get(cls, name): return cls.query.filter_by(name=name).one_or_none()
class TransferProposal(forms.Form): userid = forms.UserSelectField( __("Transfer to"), validators=[forms.validators.DataRequired()])
class VenueForm(Form): title = wtforms.TextField(__("Name"), description=__("Name of the venue"), validators=[ wtforms.validators.Required(), wtforms.validators.length(max=250) ]) description = MarkdownField( __("Description"), description=__("An optional note about the venue")) address1 = wtforms.TextField(__("Address (line 1)"), validators=[ wtforms.validators.Optional(), wtforms.validators.length(max=160) ]) address2 = wtforms.TextField(__("Address (line 2)"), validators=[ wtforms.validators.Optional(), wtforms.validators.length(max=160) ]) city = wtforms.TextField(__("City"), validators=[ wtforms.validators.Optional(), wtforms.validators.length(max=30) ]) state = wtforms.TextField(__("State"), validators=[ wtforms.validators.Optional(), wtforms.validators.length(max=30) ]) postcode = wtforms.TextField(__("Post code"), validators=[ wtforms.validators.Optional(), wtforms.validators.length(max=20) ]) country = wtforms.SelectField(__("Country"), validators=[ wtforms.validators.Optional(), wtforms.validators.length(max=2) ], choices=country_codes, default="IN") latitude = wtforms.DecimalField(__("Latitude"), places=None, validators=[ wtforms.validators.Optional(), wtforms.validators.NumberRange( -90, 90) ]) longitude = wtforms.DecimalField(__("Longitude"), places=None, validators=[ wtforms.validators.Optional(), wtforms.validators.NumberRange( -180, 180) ])
def validate_unique_discount_coupon_code(form, field): if DiscountCoupon.query.filter(DiscountCoupon.discount_policy == form.edit_parent, DiscountCoupon.code == field.data).notempty(): raise StopValidation(__("This discount coupon code already exists. Please enter a different coupon code"))
class DiscountPriceForm(forms.Form): title = forms.StringField( __("Discount price title"), validators=[ forms.validators.DataRequired( __("Please specify a title for the discount price")), forms.validators.Length(max=250) ], filters=[forms.filters.strip()]) amount = forms.IntegerField(__("Amount"), validators=[ forms.validators.DataRequired( __("Please specify an amount")) ]) currency = forms.RadioField(__("Currency"), validators=[ forms.validators.DataRequired( __("Please select the currency")) ], choices=list(CURRENCY.items()), default=CURRENCY.INR) start_at = forms.DateTimeField( __("Price start date"), validators=[ forms.validators.DataRequired( __("Please specify a start date and time")) ], naive=False) end_at = forms.DateTimeField( __("Price end date"), validators=[ forms.validators.DataRequired( __("Please specify an end date and time")), forms.validators.GreaterThan( 'start_at', __("Please specify an end date for the price that is greater than the start date" )) ], naive=False) item = QuerySelectField( __("Item"), get_label='title', validators=[ forms.validators.DataRequired( __("Please select a item for which the discount is to be applied" )) ]) def set_queries(self): self.item.query = Item.query.join(ItemCollection).filter( ItemCollection.organization == self.edit_parent.organization).options(db.load_only('id', 'title'))
if request.is_xhr and formid == 'passwordlogin': return render_template('loginform.html.jinja2', loginform=loginform, Markup=Markup), 200, iframe_block else: return render_template( 'login.html.jinja2', loginform=loginform, lastused=loginmethod, service_forms=service_forms, Markup=Markup, login_registry=login_registry), 200, iframe_block logout_errormsg = __( "We detected a possibly unauthorized attempt to log you out. " "If you really did intend to logout, please click on the logout link again" ) def logout_user(): """ User-initiated logout """ if not request.referrer or (urlparse.urlsplit(request.referrer).netloc != urlparse.urlsplit(request.url).netloc): # TODO: present a logout form flash( current_app.config.get('LOGOUT_UNAUTHORIZED_MESSAGE') or logout_errormsg, 'danger') return redirect(url_for('index')) else:
class JobApplication(BaseMixin, db.Model): __tablename__ = 'job_application' #: Hash id (to hide database ids) hashid = db.Column(db.String(40), nullable=False, unique=True) #: User who applied for this post user_id = db.Column(None, db.ForeignKey('user.id'), nullable=True, index=True) # TODO: add unique=True user = db.relationship(User, foreign_keys=user_id) #: Full name of the user (as it was at the time of the application) fullname = db.Column(db.Unicode(250), nullable=False) #: Job post they applied to jobpost_id = db.Column(None, db.ForeignKey('jobpost.id'), nullable=False, index=True) # jobpost relationship is below, outside the class definition #: User's email address email = db.Column(db.Unicode(80), nullable=False) #: User's phone number phone = db.Column(db.Unicode(80), nullable=False) #: User's message message = db.Column(db.UnicodeText, nullable=False) #: User opted-in to experimental features optin = db.Column(db.Boolean, default=False, nullable=False) #: Employer's response code _response = db.Column('response', db.Integer, StateManager.check_constraint( 'response', EMPLOYER_RESPONSE), nullable=False, default=EMPLOYER_RESPONSE.NEW) response = StateManager('_response', EMPLOYER_RESPONSE, doc="Employer's response") #: Employer's response message response_message = db.Column(db.UnicodeText, nullable=True) #: Bag of words, for spam analysis words = db.Column(db.UnicodeText, nullable=True) #: Jobpost admin who replied to this candidate replied_by_id = db.Column(None, db.ForeignKey('user.id'), nullable=True, index=True) replied_by = db.relationship(User, foreign_keys=replied_by_id) #: When they replied replied_at = db.Column(db.DateTime, nullable=True) candidate_feedback = db.Column(db.SmallInteger, nullable=True) def __init__(self, **kwargs): super(JobApplication, self).__init__(**kwargs) if self.hashid is None: self.hashid = unique_long_hash() @response.transition(response.NEW, response.PENDING, title=__("Mark read"), message=__("This job application has been read"), type='success') def mark_read(self): pass @response.transition( response.CAN_REPLY, response.REPLIED, title=__("Reply"), message=__("This job application has been replied to"), type='success') def reply(self, message, user): self.response_message = message self.replied_by = user self.replied_at = db.func.utcnow() @response.transition(response.CAN_REJECT, response.REJECTED, title=__("Reject"), message=__("This job application has been rejected"), type='danger') def reject(self, message, user): self.response_message = message self.replied_by = user self.replied_at = db.func.utcnow() @response.transition(response.CAN_IGNORE, response.IGNORED, title=__("Ignore"), message=__("This job application has been ignored"), type='danger') def ignore(self): pass @response.transition(response.CAN_REPORT, response.FLAGGED, title=__("Report"), message=__("This job application has been reported"), type='danger') def flag(self): pass @response.transition(response.FLAGGED, response.PENDING, title=__("Unflag"), message=__("This job application has been unflagged"), type='success') def unflag(self): pass def application_count(self): """Number of jobs candidate has applied to around this one""" if not self.user: # Kiosk submission, no data available return { 'count': 0, 'ignored': 0, 'replied': 0, 'flagged': 0, 'spam': 0, 'rejected': 0 } date_min = self.created_at - timedelta(days=7) date_max = self.created_at + timedelta(days=7) grouped = JobApplication.response.group( JobApplication.query.filter( JobApplication.user == self.user).filter( JobApplication.created_at > date_min, JobApplication.created_at < date_max).options( db.load_only('id'))) counts = {k.label.name: len(v) for k, v in grouped.items()} counts['count'] = sum(counts.values()) return counts def url_for(self, action='view', _external=False, **kwargs): domain = self.jobpost.email_domain if action == 'view': return url_for('view_application', hashid=self.jobpost.hashid, domain=domain, application=self.hashid, _external=_external, **kwargs) elif action == 'process': return url_for('process_application', hashid=self.jobpost.hashid, domain=domain, application=self.hashid, _external=_external, **kwargs) elif action == 'track-open': return url_for('view_application_email_gif', hashid=self.jobpost.hashid, domain=domain, application=self.hashid, _external=_external, **kwargs)
def validate_state_code(form, field): # Note: state_code is only a required field if the chosen country is India if form.country_code.data == "IN": if field.data.upper() not in indian_states_dict: raise forms.validators.StopValidation(__("Please select a state"))
'is_active', } } #: Make obj.user from a referring object falsy def __bool__(self): return False def __init__(self, representation): self.fullname = self.title = self.pickername = representation def __str__(self): return self.pickername deleted_user = DuckTypeUser(__("[deleted]")) removed_user = DuckTypeUser(__("[removed]")) # --- Organizations and teams ------------------------------------------------- team_membership = db.Table( 'team_membership', db.Model.metadata, db.Column('user_id', None, db.ForeignKey('user.id'), nullable=False, primary_key=True), db.Column('team_id', None, db.ForeignKey('team.id'),
class ProposalSubspaceForm(ProposalSpaceForm): inherit_sections = forms.BooleanField( __("Inherit sections from parent space?"), default=True)
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 EventForm(forms.Form): title = forms.StringField(__("Title"), validators=[forms.validators.DataRequired()])
def tag_locations(project_id): if app.config.get('HASCORE_SERVER'): with app.test_request_context(): project = Project.query.get(project_id) if not project.location: return url = urljoin(app.config['HASCORE_SERVER'], '/1/geo/parse_locations') response = requests.get( url, params={ 'q': project.location, 'bias': ['IN', 'US'], 'special': ['Internet', 'Online', __('Internet'), __('Online')], }, ).json() if response.get('status') == 'ok': results = response.get('result', []) geonames = defaultdict(dict) tokens = [] for item in results: geoname = item.get('geoname', {}) if geoname: geonames[geoname['geonameid']]['geonameid'] = geoname[ 'geonameid'] geonames[geoname['geonameid']]['primary'] = geonames[ geoname['geonameid']].get('primary', True) for gtype, related in geoname.get('related', {}).items(): if gtype in [ 'admin2', 'admin1', 'country', 'continent' ]: geonames[related['geonameid']][ 'geonameid'] = related['geonameid'] geonames[ related['geonameid']]['primary'] = False tokens.append({ 'token': item.get('token', ''), 'geoname': { 'name': geoname['name'], 'geonameid': geoname['geonameid'], }, }) else: tokens.append({'token': item.get('token', '')}) project.parsed_location = {'tokens': tokens} for locdata in geonames.values(): loc = ProjectLocation.query.get( (project_id, locdata['geonameid'])) if loc is None: loc = ProjectLocation(project=project, geonameid=locdata['geonameid']) db.session.add(loc) db.session.flush() loc.primary = locdata['primary'] for location in project.locations: if location.geonameid not in geonames: db.session.delete(location) db.session.commit()
class ProposalSpaceForm(forms.Form): name = forms.StringField(__("URL name"), validators=[ forms.validators.DataRequired(), forms.ValidName(), AvailableName() ]) title = forms.StringField(__("Title"), validators=[forms.validators.DataRequired()]) datelocation = forms.StringField(__("Date and Location"), validators=[ forms.validators.DataRequired(), forms.validators.Length(max=50) ]) date = forms.DateField( __("Start date (for sorting)"), validators=[forms.validators.DataRequired(__("This is required"))]) date_upto = forms.DateField( __("End date (for sorting)"), validators=[forms.validators.DataRequired(__("This is required"))]) tagline = forms.StringField( __("Tagline"), validators=[forms.validators.DataRequired()], description=__("This is displayed on the card on the homepage")) website = forms.URLField(__("Website"), validators=[forms.validators.Optional()]) description = forms.MarkdownField( __("Description"), validators=[forms.validators.DataRequired()], description=__("About Event")) timezone = forms.SelectField( __("Timezone"), description=__("The timezone in which this event occurs"), validators=[forms.validators.DataRequired()], choices=sorted_timezones(), default=u'UTC') bg_image = forms.URLField( __("Background image URL"), description=u"Background image for the mobile app", validators=[forms.validators.Optional()]) bg_color = forms.StringField( __("Background color"), description=__( "RGB color for the event, shown on the mobile app. Enter without the '#'. E.g. CCCCCC." ), validators=[ forms.validators.Optional(), forms.validators.Length(max=6) ], default=u"CCCCCC") explore_url = forms.URLField( __("Explore tab URL"), description=__( u"Page containing the explore tab’s contents, for the mobile app"), validators=[forms.validators.Optional()]) parent_space = QuerySelectField(__(u"Parent space"), get_label='title', allow_blank=True, blank_text=__(u"None")) status = forms.SelectField( __("Status"), coerce=int, choices=[ (0, __("Draft")), (1, __("Open")), (2, __("Voting")), (3, __("Jury selection")), (4, __("Feedback")), (5, __("Closed")), (6, __("Withdrawn")), ], description=__(u"Proposals can only be submitted in the “Open” state. " u"“Closed” and “Withdrawn” are hidden from homepage")) admin_team = QuerySelectField( u"Admin Team", validators=[ forms.validators.DataRequired(__(u"Please select a team")) ], query_factory=profile_teams, get_label='title', allow_blank=False, description=__(u"The administrators of this proposal space")) review_team = QuerySelectField( u"Review Team", validators=[ forms.validators.DataRequired(__(u"Please select a team")) ], query_factory=profile_teams, get_label='title', allow_blank=False, description=__( u"Reviewers can see contact details of proposers, but can’t change settings" )) allow_rsvp = forms.BooleanField( __("Allow site visitors to RSVP (login required)")) buy_tickets_url = forms.URLField(__("URL to buy tickets"), description=__(u"Eg: Explara, Instamojo"), validators=[forms.validators.Optional()]) def validate_date_upto(self, date_upto): if self.date_upto.data < self.date.data: raise forms.ValidationError( _("End date cannot be before start date")) def validate_bg_color(self, field): if not valid_color_re.match(field.data): raise forms.ValidationError("Please enter a valid color code")
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"))
abort(404) if current_auth.is_authenticated: token = auth_client.authtoken_for(current_auth.user) else: token = None response = jsonify({'hastoken': True if token else False}) response.headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT' response.headers['Cache-Control'] = 'private, max-age=300' return response # --- Token-based resource endpoints ------------------------------------------ @lastuser_oauth.route('/api/1/id') @resource_registry.resource('id', __("Read your name and basic profile data")) def resource_id(authtoken, args, files=None): """ Return user's id """ if 'all' in args and getbool(args['all']): return get_userinfo( authtoken.user, authtoken.auth_client, scope=authtoken.effective_scope, get_permissions=True, ) else: return get_userinfo(authtoken.user, authtoken.auth_client, scope=['id'],