def new_ticket_type(copy_id): form = NewTicketTypeForm() if form.validate_on_submit(): expires = form.expires.data if form.expires.data else None token = form.discount_token.data if form.discount_token.data else None description = form.description.data if form.description.data else None tt = TicketType(form.order.data, form.admits.data, form.name.data, form.type_limit.data, expires=expires, discount_token=token, description=description, personal_limit=form.personal_limit.data, has_badge=form.has_badge.data, is_transferable=form.is_transferable.data) tt.prices = [TicketPrice('GBP', form.price_gbp.data), TicketPrice('EUR', form.price_eur.data)] app.logger.info('%s adding new TicketType %s', current_user.name, tt) db.session.add(tt) db.session.commit() flash('Your new ticket type has been created') return redirect(url_for('.ticket_type_details', type_id=tt.id)) if copy_id != -1: form.init_with_ticket_type(TicketType.query.get(copy_id)) return render_template('admin/new-ticket-type.html', ticket_type_id=copy_id, form=form)
def test_ticket_creation(self): with self.app.app_context(): self.db.session.add(self.user) tt = TicketType.query.filter_by(fixed_id=0).one() ticket = Ticket(type=tt, user_id=self.user.id) self.db.session.add(ticket) self.db.session.commit() # A ticket without a payment isn't sold... assert sum(TicketType.get_ticket_sales().values()) == 0 assert ticket.id is not None ticket.paid = True self.db.session.flush() # ... but a paid one is assert sum(TicketType.get_ticket_sales().values()) == 1 ticket.expires = datetime.utcnow() - timedelta(minutes=1) self.db.session.flush() # Expired tickets still count towards capacity assert sum(TicketType.get_ticket_sales().values()) == 1 ticket.paid = False self.db.session.flush() assert sum(TicketType.get_ticket_sales().values()) == 0
def new_ticket_type(copy_id): form = NewTicketTypeForm() if form.validate_on_submit(): expires = form.expires.data if form.expires.data else None token = form.discount_token.data if form.discount_token.data else None description = form.description.data if form.description.data else None tt = TicketType(form.order.data, form.admits.data, form.name.data, form.type_limit.data, expires=expires, discount_token=token, description=description, personal_limit=form.personal_limit.data, has_badge=form.has_badge.data, is_transferable=form.is_transferable.data) tt.prices = [ TicketPrice('GBP', form.price_gbp.data), TicketPrice('EUR', form.price_eur.data) ] app.logger.info('%s adding new TicketType %s', current_user.name, tt) db.session.add(tt) db.session.commit() flash('Your new ticket type has been created') return redirect(url_for('.ticket_type_details', type_id=tt.id)) if copy_id != -1: form.init_with_ticket_type(TicketType.query.get(copy_id)) return render_template('admin/new-ticket-type.html', ticket_type_id=copy_id, form=form)
def calc_sales_state(date): if TicketType.get_tickets_remaining() < 1: # We've hit capacity - no more tickets will be sold return "sold-out" elif date > datetime(2016, 8, 7): return "sales-ended" elif TicketType.get_price_cheapest_full() is None: # Tickets not currently available, probably just for this round, but we haven't hit site capacity return "unavailable" else: return "available"
def ticket_types(): if current_user.admin: form = None if request.method == 'POST': form = NewTicketTypeForm() if form.validate(): tt = TicketType(form.name.data, form.capacity.data, form.limit.data) tt.prices = [TicketPrice('GBP', form.price_gbp), TicketPrice('EUR', form.price_eur)] db.session.add(tt) db.session.commit() return redirect(url_for('ticket_types')) types = TicketType.query.all() if not form: form = NewTicketTypeForm(formdata=None) return render_template('admin/admin_ticket_types.html', types=types, form=form) else: return(('', 404))
def main(): full_price = TicketType.get_price_cheapest_full() if not (feature_enabled('BANK_TRANSFER') or feature_enabled('GOCARDLESS')) and full_price is not None: # Only card payment left full_price += StripePayment.premium('GBP', full_price) state = get_site_state() if app.config.get('DEBUG'): state = request.args.get("site_state", state) return render_template('home/%s.html' % state, full_price=full_price)
def tickets_token(token=None): tts = TicketType.get_types_for_token(token) if tts: session['ticket_token'] = token else: if 'ticket_token' in session: del session['ticket_token'] flash('Ticket token was invalid') if any(tt.admits in ['full', 'kid'] for tt in tts): return redirect(url_for('tickets.choose')) return redirect(url_for('tickets.choose', flow='other'))
def ticket_types(): if current_user.admin: form = None if request.method == 'POST': form = NewTicketTypeForm() if form.validate(): tt = TicketType(form.name.data, form.capacity.data, form.limit.data) tt.prices = [ TicketPrice('GBP', form.price_gbp), TicketPrice('EUR', form.price_eur) ] db.session.add(tt) db.session.commit() return redirect(url_for('ticket_types')) types = TicketType.query.all() if not form: form = NewTicketTypeForm(formdata=None) return render_template('admin/admin_ticket_types.html', types=types, form=form) else: return (('', 404))
def choose(flow=None): token = session.get('ticket_token') sales_state = get_sales_state() if flow is None: admissions = True elif flow == 'other': admissions = False else: abort(404) if sales_state in ['unavailable', 'sold-out']: # For the main entry point, we assume people want admissions tickets, # but we still need to sell people e.g. parking tickets or tents until # the final cutoff (sales-ended). if not admissions: sales_state = 'available' # Allow people with valid discount tokens to buy tickets elif token is not None and TicketType.get_types_for_token(token): sales_state = 'available' if app.config.get('DEBUG'): sales_state = request.args.get("sales_state", sales_state) if sales_state == 'available': pass elif not current_user.is_anonymous() and current_user.has_permission( 'admin'): pass else: return render_template("tickets-cutoff.html") form = TicketAmountsForm() # If this is the main page, exclude tents and other paraphernalia. # For the non-admissions page, only exclude actual admissions tickets. # This means both pages show parking and caravan tickets. if admissions: tts = TicketType.query.filter(~TicketType.admits.in_(['other'])) else: tts = TicketType.query.filter(~TicketType.admits.in_(['full', 'kid'])) tts = tts.order_by(TicketType.order).all() limits = dict((tt.id, tt.user_limit(current_user, token)) for tt in tts) if request.method != 'POST': # Empty form - populate ticket types for tt in tts: form.types.append_entry() form.types[-1].type_id.data = tt.id tts = {tt.id: tt for tt in tts} for f in form.types: t_id = f.type_id.data f._type = tts[t_id] values = range(limits[t_id] + 1) f.amount.values = values f._any = any(values) if form.validate_on_submit(): if form.buy.data or form.buy_other.data: set_user_currency(form.currency_code.data) basket = [] for f in form.types: if f.amount.data: tt = f._type app.logger.info('Adding %s %s tickets to basket', f.amount.data, tt.name) basket += [tt.id] * f.amount.data if basket: session['basket'] = basket return redirect(url_for('tickets.pay', flow=flow)) elif admissions: flash("Please select at least one ticket to buy.") else: flash("Please select at least one item to buy.") if request.method == 'POST' and form.set_currency.data: if form.set_currency.validate(form): app.logger.info("Updating currency to %s only", form.set_currency.data) set_user_currency(form.set_currency.data) for field in form: field.errors = [] form.currency_code.data = get_user_currency() return render_template("tickets-choose.html", form=form, admissions=admissions)
def main(cfp_type="talk"): if cfp_type not in ["talk", "workshop", "installation"]: abort(404) ignore_closed = "closed" in request.args if app.config.get("CFP_CLOSED") and not ignore_closed: return render_template("cfp/closed.html") forms = [ TalkProposalForm(prefix="talk"), WorkshopProposalForm(prefix="workshop"), InstallationProposalForm(prefix="installation"), ] (form,) = [f for f in forms if f.type == cfp_type] form.active_cfp_type = cfp_type # If the user is already logged in set their name & email for the form if current_user.is_authenticated(): form.name.data = current_user.name form.email.data = current_user.email if request.method == "POST": app.logger.info("Checking %s proposal for %s (%s)", cfp_type, form.name.data, form.email.data) if form.validate_on_submit(): new_user = False if current_user.is_anonymous(): try: create_current_user(form.email.data, form.name.data) new_user = True except IntegrityError as e: app.logger.warn("Adding user raised %r, possible double-click", e) flash("An error occurred while creating an account for you. Please try again.") return redirect(url_for(".main")) if cfp_type == "talk": cfp = TalkProposal() cfp.length = form.length.data elif cfp_type == "workshop": cfp = WorkshopProposal() cfp.length = form.length.data cfp.attendees = form.attendees.data cfp.cost = form.cost.data elif cfp_type == "installation": cfp = InstallationProposal() cfp.size = form.size.data cfp.funds = form.funds.data cfp.user_id = current_user.id cfp.title = form.title.data cfp.requirements = form.requirements.data cfp.description = form.description.data cfp.notice_required = form.notice_required.data cfp.needs_help = form.needs_help.data db.session.add(cfp) db.session.commit() # Send confirmation message msg = Message( "Electromagnetic Field CFP Submission", sender=app.config["CONTENT_EMAIL"], recipients=[current_user.email] ) msg.body = render_template("emails/cfp-submission.txt", cfp=cfp, type=cfp_type, new_user=new_user) mail.send(msg) return redirect(url_for(".complete")) full_price = TicketType.get_price_cheapest_full() return render_template( "cfp/main.html", full_price=full_price, forms=forms, active_cfp_type=cfp_type, has_errors=bool(form.errors), ignore_closed=ignore_closed, )
def choose(flow=None): token = session.get('ticket_token') sales_state = get_sales_state() if flow is None: admissions = True elif flow == 'other': admissions = False else: abort(404) if sales_state in ['unavailable', 'sold-out']: # For the main entry point, we assume people want admissions tickets, # but we still need to sell people e.g. parking tickets or tents until # the final cutoff (sales-ended). if not admissions: sales_state = 'available' # Allow people with valid discount tokens to buy tickets elif token is not None and TicketType.get_types_for_token(token): sales_state = 'available' if app.config.get('DEBUG'): sales_state = request.args.get("sales_state", sales_state) if sales_state == 'available': pass elif not current_user.is_anonymous() and current_user.has_permission('admin'): pass else: return render_template("tickets-cutoff.html") form = TicketAmountsForm() # If this is the main page, exclude tents and other paraphernalia. # For the non-admissions page, only exclude actual admissions tickets. # This means both pages show parking and caravan tickets. if admissions: tts = TicketType.query.filter(~TicketType.admits.in_(['other'])) else: tts = TicketType.query.filter(~TicketType.admits.in_(['full', 'kid'])) tts = tts.order_by(TicketType.order).all() limits = dict((tt.id, tt.user_limit(current_user, token)) for tt in tts) if request.method != 'POST': # Empty form - populate ticket types for tt in tts: form.types.append_entry() form.types[-1].type_id.data = tt.id tts = {tt.id: tt for tt in tts} for f in form.types: t_id = f.type_id.data f._type = tts[t_id] values = range(limits[t_id] + 1) f.amount.values = values f._any = any(values) if form.validate_on_submit(): if form.buy.data or form.buy_other.data: set_user_currency(form.currency_code.data) basket = [] for f in form.types: if f.amount.data: tt = f._type app.logger.info('Adding %s %s tickets to basket', f.amount.data, tt.name) basket += [tt.id] * f.amount.data if basket: session['basket'] = basket return redirect(url_for('tickets.pay', flow=flow)) elif admissions: flash("Please select at least one ticket to buy.") else: flash("Please select at least one item to buy.") if request.method == 'POST' and form.set_currency.data: if form.set_currency.validate(form): app.logger.info("Updating currency to %s only", form.set_currency.data) set_user_currency(form.set_currency.data) for field in form: field.errors = [] form.currency_code.data = get_user_currency() return render_template("tickets-choose.html", form=form, admissions=admissions)
def tickets_choose(): form = TicketAmountsForm(request.form) if not form.types: for tt in TicketType.query.order_by(TicketType.order).all(): form.types.append_entry() form.types[-1].type_id.data = tt.id if current_user.is_authenticated(): prepays = current_user.tickets.filter_by(type=TicketType.bycode("prepay"), paid=True).count() fulls = current_user.tickets.join(TicketType).filter(TicketType.code.like("full%")).count() if fulls >= prepays: prepays = 0 else: prepays = 0 fulls = 0 token_tts = TicketToken.types(session.get("ticket_token")) token_only = ["full_ucl", "full_hs", "full_make", "full_adafruit", "full_hackaday", "full_boingboing", "full_dp"] for f in form.types: tt = TicketType.query.get(f.type_id.data) f._type = tt limit = tt.user_limit(current_user) values = range(limit + 1) if tt.code == "prepay": values = [] elif tt.code == "full_prepay": assert prepays <= limit values = [prepays] elif tt.code in token_only and tt not in token_tts: values = [] elif tt.code == "full": if token_tts: values = [] f.amount.values = values f._any = any(values) if request.method == "POST" and form.validate(): basket = [] for f in form.types: if f.amount.data: tt = f._type if tt.code in token_only and tt not in token_tts: if f.amount.data: flash("Ticket type %s is not currently available") return redirect(url_for("tickets_choose")) app.logger.info("Adding %s %s tickets to basket", f.amount.data, tt.name) basket += [tt.id] * f.amount.data if basket: session["basket"] = basket if current_user.is_authenticated(): return redirect(url_for("tickets_info")) else: return redirect(url_for("signup", next=url_for("tickets_info"))) return render_template("tickets-choose.html", form=form)
def tickets_choose(): if ticket_cutoff(): return render_template("tickets-cutoff.html") form = TicketAmountsForm(request.form) if not form.types: for tt in TicketType.query.order_by(TicketType.order).all(): form.types.append_entry() form.types[-1].type_id.data = tt.id if current_user.is_authenticated(): prepays = current_user.tickets. \ filter_by(type=TicketType.bycode('prepay'), paid=True). \ count() fulls = current_user.tickets.join(TicketType). \ filter(TicketType.code.like('full%')). \ count() if fulls >= prepays: prepays = 0 else: prepays = 0 fulls = 0 token_tts = TicketToken.types(session.get('ticket_token')) token_only = ['full_ucl', 'full_hs', 'full_make', 'full_adafruit', 'full_hackaday', 'full_boingboing', 'full_dp'] for f in form.types: tt = TicketType.query.get(f.type_id.data) f._type = tt limit = tt.user_limit(current_user) values = range(limit + 1) if tt.code == 'prepay': values = [] elif tt.code == 'full_prepay': assert prepays <= limit values = [prepays] elif tt.code in token_only and tt not in token_tts: values = [] elif tt.code == 'full': if token_tts: values = [] f.amount.values = values f._any = any(values) if request.method == 'POST' and form.validate(): basket = [] for f in form.types: if f.amount.data: tt = f._type if tt.code in token_only and tt not in token_tts: if f.amount.data: flash('Ticket type %s is not currently available') return redirect(url_for('tickets_choose')) app.logger.info('Adding %s %s tickets to basket', f.amount.data, tt.name) basket += [tt.id] * f.amount.data if basket: session['basket'] = basket if current_user.is_authenticated(): return redirect(url_for('tickets_info')) else: return redirect(url_for('signup', next=url_for('tickets_info'))) return render_template("tickets-choose.html", form=form)
def main(cfp_type='talk'): if cfp_type not in ['talk', 'workshop', 'installation']: abort(404) ignore_closed = 'closed' in request.args if app.config.get('CFP_CLOSED') and not ignore_closed: return render_template('cfp/closed.html') forms = [ TalkProposalForm(prefix="talk"), WorkshopProposalForm(prefix="workshop"), InstallationProposalForm(prefix="installation") ] (form, ) = [f for f in forms if f.type == cfp_type] form.active_cfp_type = cfp_type # If the user is already logged in set their name & email for the form if current_user.is_authenticated(): form.name.data = current_user.name form.email.data = current_user.email if request.method == 'POST': app.logger.info('Checking %s proposal for %s (%s)', cfp_type, form.name.data, form.email.data) if form.validate_on_submit(): new_user = False if current_user.is_anonymous(): try: create_current_user(form.email.data, form.name.data) new_user = True except IntegrityError as e: app.logger.warn('Adding user raised %r, possible double-click', e) flash( 'An error occurred while creating an account for you. Please try again.' ) return redirect(url_for('.main')) if cfp_type == 'talk': cfp = TalkProposal() cfp.length = form.length.data elif cfp_type == 'workshop': cfp = WorkshopProposal() cfp.length = form.length.data cfp.attendees = form.attendees.data cfp.cost = form.cost.data elif cfp_type == 'installation': cfp = InstallationProposal() cfp.size = form.size.data cfp.funds = form.funds.data cfp.user_id = current_user.id cfp.title = form.title.data cfp.requirements = form.requirements.data cfp.description = form.description.data cfp.notice_required = form.notice_required.data cfp.needs_help = form.needs_help.data db.session.add(cfp) db.session.commit() # Send confirmation message msg = Message('Electromagnetic Field CFP Submission', sender=app.config['CONTENT_EMAIL'], recipients=[current_user.email]) msg.body = render_template('emails/cfp-submission.txt', cfp=cfp, type=cfp_type, new_user=new_user) mail.send(msg) return redirect(url_for('.complete')) full_price = TicketType.get_price_cheapest_full() return render_template('cfp/main.html', full_price=full_price, forms=forms, active_cfp_type=cfp_type, has_errors=bool(form.errors), ignore_closed=ignore_closed)