def newjob(): form = forms.ListingForm() archived_post = None if not g.user: return redirect(url_for('login', next=url_for('newjob'), message=u"Hasjob now requires you to login before posting a job. Please login as yourself." u" We'll add details about your company later")) else: if g.user.blocked: flash("Your account has been blocked from posting jobs", category='info') return redirect(url_for('index'), code=303) if g.board: if 'new-job' not in g.board.permissions(g.user): abort(403) if g.board and not g.board.require_pay: form.job_pay_type.choices = [(-1, u'Confidential')] + PAY_TYPE.items() form.job_type.choices = JobType.choices(g.board) form.job_category.choices = JobCategory.choices(g.board) if request.method == 'GET': if g.user: # form.poster_name.data = g.user.fullname # Deprecated 2013-11-20 form.poster_email.data = g.user.email # Job Reposting if request.method == 'GET' and request.args.get('template'): archived_post = JobPost.get(request.args['template']) if not archived_post: abort(404) if not archived_post.admin_is(g.user): abort(403) if not archived_post.is_old(): flash("This post is currently active and cannot be posted again.") return redirect(archived_post.url_for(), code=303) form.populate_from(archived_post) if form.validate_on_submit(): # POST request from new job page, with successful validation # Move it to the editjob page for handling here forward newpost = { 'hashid': unique_hash(JobPost), 'ipaddr': request.environ['REMOTE_ADDR'], 'useragent': request.user_agent.string, 'user': g.user } return editjob(hashid=None, key=None, form=form, validated=True, newpost=newpost) elif form.errors: # POST request from new job page, with errors flash("Please review the indicated issues", category='interactive') # Render page. Execution reaches here under three conditions: # 1. GET request, page loaded for the first time # 2. POST request from this page, with errors return render_template('postjob.html', form=form, no_removelogo=True, archived_post=archived_post)
def newjob(): form = forms.ListingForm() if not g.user: if request.method == 'POST' and request.form.get('form.id') == 'newheadline': session['headline'] = form.job_headline.data return redirect(url_for('login', next=url_for('newjob'), message=u"Hasjob now requires you to login before listing a job. Please login as yourself." u" We'll add details about your company later")) else: if g.user.blocked: flash("Your account has been blocked from listing jobs", category='info') return redirect(url_for('index'), code=303) if 'headline' in session: if request.method == 'GET': form.job_headline.data = session.pop('headline') else: session.pop('headline') if g.board: if 'new-job' not in g.board.permissions(g.user): abort(403) if g.board and not g.board.require_pay: form.job_pay_type.choices = [(-1, u'Confidential')] + PAY_TYPE.items() form.job_type.choices = JobType.choices(g.board) form.job_category.choices = JobCategory.choices(g.board) if request.method == 'GET' or (request.method == 'POST' and request.form.get('form.id') == 'newheadline'): if g.user: # form.poster_name.data = g.user.fullname # Deprecated 2013-11-20 form.poster_email.data = g.user.email if request.method == 'POST' and request.form.get('form.id') != 'newheadline' and form.validate(): # POST request from new job page, with successful validation # Move it to the editjob page for handling here forward post = JobPost(hashid=unique_hash(JobPost), ipaddr=request.environ['REMOTE_ADDR'], useragent=request.user_agent.string, user=g.user) db.session.add(post) if g.board: post.add_to(g.board) return editjob(post.hashid, post.edit_key, form, post, validated=True) elif request.method == 'POST' and request.form.get('form.id') != 'newheadline': # POST request from new job page, with errors flash("Please correct the indicated errors", category='interactive') # Render page. Execution reaches here under three conditions: # 1. GET request, page loaded for the first time # 2. POST request from main page's Post a Job box # 3. POST request from this page, with errors return render_template('postjob.html', form=form, no_removelogo=True)
def editjob(hashid, key, domain=None, form=None, validated=False, newpost=None): if form is None: form = forms.ListingForm(request.form) form.job_type.choices = JobType.choices(g.board) form.job_category.choices = JobCategory.choices(g.board) if g.board and not g.board.require_pay: form.job_pay_type.choices = [(-1, u'Confidential')] + PAY_TYPE.items() post = None no_email = False if not newpost: post = JobPost.query.filter_by(hashid=hashid).first_or_404() if not ((key is None and g.user is not None and post.admin_is(g.user)) or (key == post.edit_key)): abort(403) # Once this post is published, require editing at /domain/<hashid>/edit if not key and post.status not in POSTSTATUS.UNPUBLISHED and post.email_domain != domain: return redirect(post.url_for('edit'), code=301) # Don't allow editing jobs that aren't on this board as that may be a loophole when # the board allows no pay (except in the 'www' root board, where editing is always allowed) with db.session.no_autoflush: if g.board and g.board.not_root and post.link_to_board(g.board) is None and request.method == 'GET': blink = post.postboards.first() if blink: return redirect(post.url_for('edit', subdomain=blink.board.name, _external=True)) else: return redirect(post.url_for('edit', subdomain=None, _external=True)) # Don't allow email address to be changed once it's confirmed if post.status in POSTSTATUS.POSTPENDING: no_email = True if request.method == 'POST' and post and post.status in POSTSTATUS.POSTPENDING: # del form.poster_name # Deprecated 2013-11-20 form.poster_email.data = post.email if request.method == 'POST' and (validated or form.validate()): form_description = bleach.linkify(bleach.clean(form.job_description.data, tags=ALLOWED_TAGS)) form_perks = bleach.linkify(bleach.clean(form.job_perks_description.data, tags=ALLOWED_TAGS)) if form.job_perks.data else '' form_how_to_apply = form.job_how_to_apply.data form_email_domain = get_email_domain(form.poster_email.data) form_words = get_word_bag(u' '.join((form_description, form_perks, form_how_to_apply))) similar = False with db.session.no_autoflush: for oldpost in JobPost.query.filter(db.or_( db.and_( JobPost.email_domain == form_email_domain, JobPost.status.in_(POSTSTATUS.POSTPENDING)), JobPost.status == POSTSTATUS.SPAM)).filter( JobPost.datetime > datetime.utcnow() - agelimit).all(): if not post or (oldpost.id != post.id): if oldpost.words: s = SequenceMatcher(None, form_words, oldpost.words) if s.ratio() > 0.6: similar = True break if similar: flash("This post is very similar to an earlier post. You may not repost the same job " "in less than %d days." % agelimit.days, category='interactive') else: if newpost: post = JobPost(**newpost) db.session.add(post) if g.board: post.add_to(g.board) if g.board.not_root: post.add_to('www') post.headline = form.job_headline.data post.headlineb = form.job_headlineb.data post.type_id = form.job_type.data post.category_id = form.job_category.data post.location = form.job_location.data post.relocation_assist = form.job_relocation_assist.data post.description = form_description post.perks = form_perks post.how_to_apply = form_how_to_apply post.company_name = form.company_name.data post.company_url = form.company_url.data post.hr_contact = form.hr_contact.data post.twitter = form.twitter.data post.pay_type = form.job_pay_type.data if post.pay_type == -1: post.pay_type = None if post.pay_type is not None and post.pay_type != PAY_TYPE.NOCASH: post.pay_currency = form.job_pay_currency.data post.pay_cash_min = form.job_pay_cash_min.data post.pay_cash_max = form.job_pay_cash_max.data else: post.pay_currency = None post.pay_cash_min = None post.pay_cash_max = None if form.job_pay_equity.data: post.pay_equity_min = form.job_pay_equity_min.data post.pay_equity_max = form.job_pay_equity_max.data else: post.pay_equity_min = None post.pay_equity_max = None post.admins = form.collaborators.data # Allow name and email to be set only on non-confirmed posts if not no_email: # post.fullname = form.poster_name.data # Deprecated 2013-11-20 if post.email != form.poster_email.data: # Change the email_verify_key if the email changes post.email_verify_key = random_long_key() post.email = form.poster_email.data post.email_domain = form_email_domain post.md5sum = md5sum(post.email) with db.session.no_autoflush: # This is dependent on the domain's DNS validity already being confirmed # by the form's email validator post.domain = Domain.get(post.email_domain, create=True) # To protect from gaming, don't allow words to be removed in edited posts once the post # has been confirmed. Just add the new words. if post.status in POSTSTATUS.POSTPENDING: prev_words = post.words or u'' else: prev_words = u'' post.words = get_word_bag(u' '.join((prev_words, form_description, form_perks, form_how_to_apply))) post.language, post.language_confidence = identify_language(post) if post.status == POSTSTATUS.MODERATED: post.status = POSTSTATUS.CONFIRMED if request.files['company_logo']: # The form's validator saved the processed logo in g.company_logo. thumbnail = g.company_logo logofilename = uploaded_logos.save(thumbnail, name='%s.' % post.hashid) post.company_logo = logofilename else: if form.company_logo_remove.data: post.company_logo = None db.session.commit() tag_jobpost.delay(post.id) # Keywords tag_locations.delay(post.id) # Locations post.uncache_viewcounts('pay_label') session.pop('userkeys', None) # Remove legacy userkeys dict session.permanent = True return redirect(post.url_for(), code=303) elif request.method == 'POST': flash("Please review the indicated issues", category='interactive') elif request.method == 'GET': form.populate_from(post) return render_template('postjob.html', form=form, no_email=no_email)
def editjob(hashid, key, form=None, post=None, validated=False): if form is None: form = forms.ListingForm(request.form) form.job_type.choices = JobType.choices(g.board) form.job_category.choices = JobCategory.choices(g.board) if g.board and not g.board.require_pay: form.job_pay_type.choices = [(-1, u'Confidential')] + PAY_TYPE.items() if post is None: post = JobPost.query.filter_by(hashid=hashid).first_or_404() if not ((key is None and g.user is not None and post.admin_is(g.user)) or (key == post.edit_key)): abort(403) # Don't allow editing jobs that aren't on this board as that may be a loophole when # the board allows no pay. if g.board and post.link_to_board(g.board) is None and request.method == 'GET': blink = post.postboards.first() if blink: return redirect(url_for('editjob', hashid=post.hashid, subdomain=blink.board.name, _external=True)) else: return redirect(url_for('editjob', hashid=post.hashid, subdomain=None, _external=True)) # Don't allow email address to be changed once it's confirmed if post.status in POSTSTATUS.POSTPENDING: no_email = True else: no_email = False if request.method == 'POST' and post.status in POSTSTATUS.POSTPENDING: # del form.poster_name # Deprecated 2013-11-20 form.poster_email.data = post.email if request.method == 'POST' and (validated or form.validate()): form_description = bleach.linkify(bleach.clean(form.job_description.data, tags=ALLOWED_TAGS)) form_perks = bleach.linkify(bleach.clean(form.job_perks_description.data, tags=ALLOWED_TAGS)) if form.job_perks.data else '' form_how_to_apply = form.job_how_to_apply.data form_email_domain = get_email_domain(form.poster_email.data) form_words = get_word_bag(u' '.join((form_description, form_perks, form_how_to_apply))) similar = False for oldpost in JobPost.query.filter(db.or_( db.and_( JobPost.email_domain == form_email_domain, JobPost.status.in_(POSTSTATUS.POSTPENDING)), JobPost.status == POSTSTATUS.SPAM)).filter( JobPost.datetime > datetime.utcnow() - agelimit).all(): if oldpost.id != post.id: if oldpost.words: s = SequenceMatcher(None, form_words, oldpost.words) if s.ratio() > 0.6: similar = True break if similar: flash("This listing is very similar to an earlier listing. You may not relist the same job " "in less than %d days." % agelimit.days, category='interactive') else: post.headline = form.job_headline.data post.type_id = form.job_type.data post.category_id = form.job_category.data post.location = form.job_location.data post.relocation_assist = form.job_relocation_assist.data post.description = form_description post.perks = form_perks post.how_to_apply = form_how_to_apply post.company_name = form.company_name.data post.company_url = form.company_url.data post.hr_contact = form.hr_contact.data post.pay_type = form.job_pay_type.data if post.pay_type == -1: post.pay_type = None if post.pay_type is not None and post.pay_type != PAY_TYPE.NOCASH: post.pay_currency = form.job_pay_currency.data post.pay_cash_min = form.job_pay_cash_min.data post.pay_cash_max = form.job_pay_cash_max.data else: post.pay_currency = None post.pay_cash_min = None post.pay_cash_max = None if form.job_pay_equity.data: post.pay_equity_min = form.job_pay_equity_min.data post.pay_equity_max = form.job_pay_equity_max.data else: post.pay_equity_min = None post.pay_equity_max = None post.admins = form.collaborators.data # Allow name and email to be set only on non-confirmed posts if not no_email: # post.fullname = form.poster_name.data # Deprecated 2013-11-20 post.email = form.poster_email.data post.email_domain = form_email_domain post.md5sum = md5sum(post.email) # To protect from gaming, don't allow words to be removed in edited listings once the post # has been confirmed. Just add the new words. if post.status in POSTSTATUS.POSTPENDING: prev_words = post.words or u'' else: prev_words = u'' post.words = get_word_bag(u' '.join((prev_words, form_description, form_perks, form_how_to_apply))) post.language = identify_language(post) if post.status == POSTSTATUS.MODERATED: post.status = POSTSTATUS.CONFIRMED if request.files['company_logo']: # The form's validator saved the processed logo in g.company_logo. thumbnail = g.company_logo logofilename = uploaded_logos.save(thumbnail, name='%s.' % post.hashid) post.company_logo = logofilename else: if form.company_logo_remove.data: post.company_logo = None db.session.commit() tag_locations.delay(post.id) userkeys = session.get('userkeys', []) userkeys.append(post.edit_key) session['userkeys'] = userkeys session.permanent = True return redirect(url_for('jobdetail', hashid=post.hashid), code=303) elif request.method == 'POST': flash("Please correct the indicated errors", category='interactive') elif request.method == 'GET': # Populate form from model form.job_headline.data = post.headline form.job_type.data = post.type_id form.job_category.data = post.category_id form.job_location.data = post.location form.job_relocation_assist.data = post.relocation_assist form.job_description.data = post.description form.job_perks.data = True if post.perks else False form.job_perks_description.data = post.perks form.job_how_to_apply.data = post.how_to_apply form.company_name.data = post.company_name form.company_url.data = post.company_url # form.poster_name.data = post.fullname # Deprecated 2013-11-20 form.poster_email.data = post.email form.hr_contact.data = int(post.hr_contact or False) form.collaborators.data = post.admins form.job_pay_type.data = post.pay_type if post.pay_type is None: # This kludge required because WTForms doesn't know how to handle None in forms form.job_pay_type.data = -1 form.job_pay_currency.data = post.pay_currency form.job_pay_cash_min.data = post.pay_cash_min form.job_pay_cash_max.data = post.pay_cash_max form.job_pay_equity.data = bool(post.pay_equity_min and post.pay_equity_max) form.job_pay_equity_min.data = post.pay_equity_min form.job_pay_equity_max.data = post.pay_equity_max return render_template('postjob.html', form=form, no_email=no_email)
def editjob(hashid, key, domain=None, form=None, validated=False, newpost=None): if form is None: form = forms.ListingForm(request.form) form.job_type.choices = JobType.choices(g.board) form.job_category.choices = JobCategory.choices(g.board) if g.board and not g.board.require_pay: form.job_pay_type.choices = [(-1, u'Confidential') ] + PAY_TYPE.items() post = None no_email = False if not newpost: post = JobPost.query.filter_by(hashid=hashid).first_or_404() if not ((key is None and g.user is not None and post.admin_is(g.user)) or (key == post.edit_key)): abort(403) # Once this post is published, require editing at /domain/<hashid>/edit if not key and post.status not in POSTSTATUS.UNPUBLISHED and post.email_domain != domain: return redirect(post.url_for('edit'), code=301) # Don't allow editing jobs that aren't on this board as that may be a loophole when # the board allows no pay (except in the 'www' root board, where editing is always allowed) with db.session.no_autoflush: if g.board and g.board.not_root and post.link_to_board( g.board) is None and request.method == 'GET': blink = post.postboards.first() if blink: return redirect( post.url_for('edit', subdomain=blink.board.name, _external=True)) else: return redirect( post.url_for('edit', subdomain=None, _external=True)) # Don't allow email address to be changed once it's confirmed if post.status in POSTSTATUS.POSTPENDING: no_email = True if request.method == 'POST' and post and post.status in POSTSTATUS.POSTPENDING: # del form.poster_name # Deprecated 2013-11-20 form.poster_email.data = post.email if request.method == 'POST' and (validated or form.validate()): form_description = bleach.linkify( bleach.clean(form.job_description.data, tags=ALLOWED_TAGS)) form_perks = bleach.linkify( bleach.clean(form.job_perks_description.data, tags=ALLOWED_TAGS)) if form.job_perks.data else '' form_how_to_apply = form.job_how_to_apply.data form_email_domain = get_email_domain(form.poster_email.data) form_words = get_word_bag(u' '.join( (form_description, form_perks, form_how_to_apply))) similar = False with db.session.no_autoflush: for oldpost in JobPost.query.filter( db.or_( db.and_(JobPost.email_domain == form_email_domain, JobPost.status.in_(POSTSTATUS.POSTPENDING)), JobPost.status == POSTSTATUS.SPAM)).filter( JobPost.datetime > datetime.utcnow() - agelimit).all(): if not post or (oldpost.id != post.id): if oldpost.words: s = SequenceMatcher(None, form_words, oldpost.words) if s.ratio() > 0.6: similar = True break if similar: flash( "This post is very similar to an earlier post. You may not repost the same job " "in less than %d days." % agelimit.days, category='interactive') else: if newpost: post = JobPost(**newpost) db.session.add(post) if g.board: post.add_to(g.board) if g.board.not_root: post.add_to('www') post.headline = form.job_headline.data post.headlineb = form.job_headlineb.data post.type_id = form.job_type.data post.category_id = form.job_category.data post.location = form.job_location.data post.relocation_assist = form.job_relocation_assist.data post.description = form_description post.perks = form_perks post.how_to_apply = form_how_to_apply post.company_name = form.company_name.data post.company_url = form.company_url.data post.hr_contact = form.hr_contact.data post.twitter = form.twitter.data post.pay_type = form.job_pay_type.data if post.pay_type == -1: post.pay_type = None if post.pay_type is not None and post.pay_type != PAY_TYPE.NOCASH: post.pay_currency = form.job_pay_currency.data post.pay_cash_min = form.job_pay_cash_min.data post.pay_cash_max = form.job_pay_cash_max.data else: post.pay_currency = None post.pay_cash_min = None post.pay_cash_max = None if form.job_pay_equity.data: post.pay_equity_min = form.job_pay_equity_min.data post.pay_equity_max = form.job_pay_equity_max.data else: post.pay_equity_min = None post.pay_equity_max = None post.admins = form.collaborators.data # Allow name and email to be set only on non-confirmed posts if not no_email: # post.fullname = form.poster_name.data # Deprecated 2013-11-20 post.email = form.poster_email.data post.email_domain = form_email_domain post.md5sum = md5sum(post.email) with db.session.no_autoflush: # This is dependent on the domain's DNS validity already being confirmed # by the form's email validator post.domain = Domain.get(post.email_domain, create=True) # To protect from gaming, don't allow words to be removed in edited posts once the post # has been confirmed. Just add the new words. if post.status in POSTSTATUS.POSTPENDING: prev_words = post.words or u'' else: prev_words = u'' post.words = get_word_bag(u' '.join( (prev_words, form_description, form_perks, form_how_to_apply))) post.language, post.language_confidence = identify_language(post) if post.status == POSTSTATUS.MODERATED: post.status = POSTSTATUS.CONFIRMED if request.files['company_logo']: # The form's validator saved the processed logo in g.company_logo. thumbnail = g.company_logo logofilename = uploaded_logos.save(thumbnail, name='%s.' % post.hashid) post.company_logo = logofilename else: if form.company_logo_remove.data: post.company_logo = None db.session.commit() tag_jobpost.delay(post.id) # Keywords tag_locations.delay(post.id) # Locations post.uncache_viewcounts('pay_label') session.pop('userkeys', None) # Remove legacy userkeys dict session.permanent = True return redirect(post.url_for(), code=303) elif request.method == 'POST': flash("Please review the indicated issues", category='interactive') elif request.method == 'GET': # Populate form from model form.job_headline.data = post.headline form.job_headlineb.data = post.headlineb form.job_type.data = post.type_id form.job_category.data = post.category_id form.job_location.data = post.location form.job_relocation_assist.data = post.relocation_assist form.job_description.data = post.description form.job_perks.data = True if post.perks else False form.job_perks_description.data = post.perks form.job_how_to_apply.data = post.how_to_apply form.company_name.data = post.company_name form.company_url.data = post.company_url # form.poster_name.data = post.fullname # Deprecated 2013-11-20 form.poster_email.data = post.email form.twitter.data = post.twitter form.hr_contact.data = int(post.hr_contact or False) form.collaborators.data = post.admins form.job_pay_type.data = post.pay_type if post.pay_type is None: # This kludge required because WTForms doesn't know how to handle None in forms form.job_pay_type.data = -1 form.job_pay_currency.data = post.pay_currency form.job_pay_cash_min.data = post.pay_cash_min form.job_pay_cash_max.data = post.pay_cash_max form.job_pay_equity.data = bool(post.pay_equity_min and post.pay_equity_max) form.job_pay_equity_min.data = post.pay_equity_min form.job_pay_equity_max.data = post.pay_equity_max return render_template('postjob.html', form=form, no_email=no_email)
def newjob(): form = forms.ListingForm() if not g.user: if request.method == 'POST' and request.form.get( 'form.id') == 'newheadline': session['headline'] = form.job_headline.data return redirect( url_for( 'login', next=url_for('newjob'), message= u"Hasjob now requires you to login before posting a job. Please login as yourself." u" We'll add details about your company later")) else: if g.user.blocked: flash("Your account has been blocked from posting jobs", category='info') return redirect(url_for('index'), code=303) if 'headline' in session: if request.method == 'GET': form.job_headline.data = session.pop('headline') else: session.pop('headline') if g.board: if 'new-job' not in g.board.permissions(g.user): abort(403) if g.board and not g.board.require_pay: form.job_pay_type.choices = [(-1, u'Confidential')] + PAY_TYPE.items() form.job_type.choices = JobType.choices(g.board) form.job_category.choices = JobCategory.choices(g.board) if request.method == 'GET' or (request.method == 'POST' and request.form.get('form.id') == 'newheadline'): if g.user: # form.poster_name.data = g.user.fullname # Deprecated 2013-11-20 form.poster_email.data = g.user.email if request.method == 'POST' and request.form.get( 'form.id') != 'newheadline' and form.validate(): # POST request from new job page, with successful validation # Move it to the editjob page for handling here forward newpost = { 'hashid': unique_hash(JobPost), 'ipaddr': request.environ['REMOTE_ADDR'], 'useragent': request.user_agent.string, 'user': g.user } return editjob(hashid=None, key=None, form=form, validated=True, newpost=newpost) elif request.method == 'POST' and request.form.get( 'form.id') != 'newheadline': # POST request from new job page, with errors flash("Please review the indicated issues", category='interactive') # Render page. Execution reaches here under three conditions: # 1. GET request, page loaded for the first time # 2. POST request from main page's Post a Job box # 3. POST request from this page, with errors return render_template('postjob.html', form=form, no_removelogo=True)