示例#1
0
文件: payment.py 项目: Paul2d/Website
    def bill_url(self, name):
        # TODO: check country
        bill_url = gocardless.client.new_bill_url(
            amount=self.amount,
            name=name,
            redirect_uri=external_url('gocardless_complete', payment_id=self.id),
            cancel_uri=external_url('gocardless_cancel', payment_id=self.id),
            currency=self.currency,
        )

        return bill_url
示例#2
0
    def bill_url(self, name):
        # TODO: check country
        bill_url = gocardless.client.new_bill_url(
            amount=self.amount,
            name=name,
            redirect_uri=external_url('gocardless_complete',
                                      payment_id=self.id),
            cancel_uri=external_url('gocardless_cancel', payment_id=self.id),
            currency=self.currency,
        )

        return bill_url
示例#3
0
def attach_tickets(msg, user):
    # Attach tickets to a mail Message
    page = render_receipt(user, pdf=True)
    url = external_url('tickets.receipt', user_id=user.id)
    pdf = render_pdf(url, page)

    msg.attach('EMF{}.pdf'.format(event_start().year), 'application/pdf', pdf.read())
示例#4
0
def tickets_receipt_qr(receipt):

    qrfile = StringIO()
    qr = qrcode.make(external_url('tickets_receipt', receipt=receipt), box_size=2)
    qr.save(qrfile, 'PNG')
    qrfile.seek(0)
    return send_file(qrfile, mimetype='image/png')
示例#5
0
文件: base.py 项目: emfcamp/Website
def message_batch():
    proposals, filtered = filter_proposal_request()

    form = SendMessageForm()
    if form.validate_on_submit():
        if form.send.data:
            for proposal in proposals:
                msg = CFPMessage()
                msg.is_to_admin = False
                msg.from_user_id = current_user.id
                msg.proposal_id = proposal.id
                msg.message = form.message.data

                db.session.add(msg)
                db.session.commit()

                app.logger.info('Sending message from %s to %s', current_user.id, proposal.user_id)

                msg_url = external_url('cfp.proposal_messages', proposal_id=proposal.id)
                msg = Message('New message about your EMF proposal',
                            sender=app.config['CONTENT_EMAIL'],
                            recipients=[proposal.user.email])
                msg.body = render_template('cfp_review/email/new_message.txt', url=msg_url,
                                        to_user=proposal.user, from_user=current_user,
                                        proposal=proposal)
                mail.send(msg)

            flash('Messaged %s proposals' % len(proposals), 'info')
            return redirect(url_for('.proposals', **request.args))

    return render_template('cfp_review/message_batch.html',
                           form=form, proposals=proposals)
示例#6
0
def add_event(room, event):
    url = external_url('schedule.line_up_proposal',
                       proposal_id=event['id'],
                       slug=event['slug'])

    event_node = etree.SubElement(room,
                                  'event',
                                  id=str(event['id']),
                                  guid=str(uuid5(NAMESPACE_URL, url)))

    _add_sub_with_text(event_node, 'room', room.attrib['name'])
    _add_sub_with_text(event_node, 'title', event['title'])
    _add_sub_with_text(event_node, 'type', event.get('type', 'talk'))
    _add_sub_with_text(event_node, 'date', event['start_date'].isoformat())

    # Start time
    _add_sub_with_text(event_node, 'start',
                       event['start_date'].strftime('%H:%M'))

    duration = get_duration(event['start_date'], event['end_date'])
    _add_sub_with_text(event_node, 'duration', duration)

    _add_sub_with_text(event_node, 'abstract', event['description'])
    _add_sub_with_text(event_node, 'description', event['description'])

    _add_sub_with_text(
        event_node, 'slug',
        'emf%s-%s-%s' % (event_start().year, event['id'], event['slug']))

    _add_sub_with_text(event_node, 'subtitle', '')
    _add_sub_with_text(event_node, 'track', '')

    add_persons(event_node, event)
    add_recording(event_node, event)
示例#7
0
def attach_tickets(msg, user):
    # Attach tickets to a mail Message
    page = render_receipt(user, pdf=True)
    url = external_url("tickets.receipt", user_id=user.id)
    pdf = render_pdf(url, page)

    msg.attach("EMF{}.pdf".format(event_year()), pdf.read(), "application/pdf")
示例#8
0
def add_event(room, event):
    url = external_url('schedule.line_up_proposal', proposal_id=event['id'], slug=event['slug'])

    event_node = etree.SubElement(room, 'event', id=str(event['id']),
                                                 guid=str(uuid5(NAMESPACE_URL, url)))

    _add_sub_with_text(event_node, 'room', room.attrib['name'])
    _add_sub_with_text(event_node, 'title', event['title'])
    _add_sub_with_text(event_node, 'type', event.get('type', 'talk'))
    _add_sub_with_text(event_node, 'date', event['start_date'].isoformat())

    # Start time
    _add_sub_with_text(event_node, 'start', event['start_date'].strftime('%H:%M'))

    duration = get_duration(event['start_date'], event['end_date'])
    _add_sub_with_text(event_node, 'duration', duration)

    _add_sub_with_text(event_node, 'abstract', event['description'])
    _add_sub_with_text(event_node, 'description', '')

    _add_sub_with_text(event_node, 'slug', 'emf%s-%s-%s' % (event_start().year, event['id'], event['slug']))

    _add_sub_with_text(event_node, 'subtitle', '')
    _add_sub_with_text(event_node, 'track', '')

    add_persons(event_node, event)
    add_recording(event_node, event)
示例#9
0
文件: tickets.py 项目: Jonty/Website
def tickets_receipt_qr(receipt):

    qrfile = StringIO()
    qr = qrcode.make(external_url('tickets_receipt', receipt=receipt), box_size=2)
    qr.save(qrfile, 'PNG')
    qrfile.seek(0)
    return send_file(qrfile, mimetype='image/png')
示例#10
0
def attach_tickets(msg, user):
    # Attach tickets to a mail Message
    page = render_receipt(user, pdf=True)
    url = external_url('tickets.receipt', user_id=user.id)
    pdf = render_pdf(url, page)

    msg.attach('EMF{}.pdf'.format(event_start().year), 'application/pdf',
               pdf.read())
示例#11
0
def user_tickets(user_id, ext=None):
    user = User.query.get_or_404(user_id)

    receipt = render_receipt(user)

    if ext == '.pdf':
        url = external_url('.user_tickets', user_id=user_id)
        return send_file(render_pdf(url, receipt), mimetype='application/pdf', cache_timeout=60)

    return receipt
示例#12
0
def _get_proposal_dict(proposal: Proposal, favourites_ids):
    res = {
        "id":
        proposal.id,
        "slug":
        proposal.slug,
        "start_date":
        event_tz.localize(proposal.start_date),
        "end_date":
        event_tz.localize(proposal.end_date) if proposal.end_date else None,
        "venue":
        proposal.scheduled_venue.name,
        "latlon":
        proposal.latlon,
        "map_link":
        proposal.map_link,
        "title":
        proposal.display_title,
        "speaker":
        proposal.published_names or proposal.user.name,
        "pronouns":
        proposal.published_pronouns,
        "user_id":
        proposal.user.id,
        "description":
        proposal.published_description or proposal.description,
        "type":
        proposal.type,
        "may_record":
        proposal.may_record,
        "is_fave":
        proposal.id in favourites_ids,
        "is_family_friendly":
        proposal.family_friendly,
        "is_from_cfp":
        not proposal.user_scheduled,
        "content_note":
        proposal.content_note,
        "source":
        "database",
        "link":
        external_url(
            ".item",
            year=event_year(),
            proposal_id=proposal.id,
            slug=proposal.slug,
        ),
    }
    if proposal.type in ["workshop", "youthworkshop"]:
        res["cost"] = proposal.display_cost
        res["equipment"] = proposal.display_participant_equipment
        res["age_range"] = proposal.display_age_range
        res["attendees"] = proposal.attendees
    return res
示例#13
0
文件: base.py 项目: emfcamp/Website
def message_proposer(proposal_id):
    form = SendMessageForm()
    proposal = Proposal.query.get_or_404(proposal_id)

    if form.validate_on_submit():
        if form.send.data:
            msg = CFPMessage()
            msg.is_to_admin = False
            msg.from_user_id = current_user.id
            msg.proposal_id = proposal_id
            msg.message = form.message.data

            db.session.add(msg)
            db.session.commit()

            app.logger.info(
                "Sending message from %s to %s", current_user.id, proposal.user_id
            )

            msg_url = external_url("cfp.proposal_messages", proposal_id=proposal_id)
            msg = EmailMessage(
                "New message about your EMF proposal",
                from_email=from_email("CONTENT_EMAIL"),
                to=[proposal.user.email],
            )
            msg.body = render_template(
                "cfp_review/email/new_message.txt",
                url=msg_url,
                to_user=proposal.user,
                from_user=current_user,
                proposal=proposal,
            )
            msg.send()

        count = proposal.mark_messages_read(current_user)
        db.session.commit()
        app.logger.info(
            "Marked %s messages to admin on proposal %s as read" % (count, proposal.id)
        )

        return redirect(url_for(".message_proposer", proposal_id=proposal_id))

    # Admin can see all messages sent in relation to a proposal
    messages = (
        CFPMessage.query.filter_by(proposal_id=proposal_id).order_by("created").all()
    )

    return render_template(
        "cfp_review/message_proposer.html",
        form=form,
        messages=messages,
        proposal=proposal,
    )
示例#14
0
def user_tickets(user_id, ext=None):
    user = User.query.get_or_404(user_id)

    receipt = render_receipt(user)

    if ext == ".pdf":
        url = external_url(".user_tickets", user_id=user_id)
        return send_file(
            render_pdf(url, receipt), mimetype="application/pdf", cache_timeout=60
        )

    return receipt
示例#15
0
def invoice(payment_id):
    payment = get_user_payment_or_abort(payment_id, allow_admin=True)

    form = InvoiceForm()

    if form.validate_on_submit():
        current_user.company = form.company.data
        db.session.commit()

        flash('Company name updated')
        return redirect(url_for('.invoice', payment_id=payment_id))

    if request.method != 'POST':
        form.company.data = current_user.company

    edit_company = bool(request.args.get('edit_company'))
    if request.args.get('js') == '0':
        flash("Please use your browser's print feature or download the PDF")

    invoice_lines = Purchase.query.filter_by(payment_id=payment_id).join(PriceTier, Product) \
        .with_entities(PriceTier, func.count(Purchase.price_tier_id)) \
        .group_by(PriceTier, Product.name).order_by(Product.name).all()

    ticket_sum = sum(pt.get_price(payment.currency).value_ex_vat * count for pt, count in invoice_lines)
    if payment.provider == 'stripe':
        premium = payment.__class__.premium(payment.currency, ticket_sum)
    else:
        premium = Decimal(0)

    subtotal = ticket_sum + premium
    vat = subtotal * Decimal('0.2')
    app.logger.debug('Invoice subtotal %s + %s = %s', ticket_sum, premium, subtotal)

    # FIXME: we should use a currency-specific quantization here (or rounder numbers)
    if subtotal + vat - payment.amount > Decimal('0.01'):
        app.logger.error('Invoice total mismatch: %s + %s - %s = %s', subtotal, vat,
                         payment.amount, subtotal + vat - payment.amount)
        flash('Your invoice cannot currently be displayed')
        return redirect(url_for('users.purchases'))

    app.logger.debug('Invoice total: %s + %s = %s', subtotal, vat, payment.amount)

    page = render_template('invoice.html', payment=payment, invoice_lines=invoice_lines, form=form,
                           premium=premium, subtotal=subtotal, vat=vat, edit_company=edit_company)

    if request.args.get('pdf'):
        url = external_url('.invoice', payment_id=payment_id)
        return send_file(render_pdf(url, page), mimetype='application/pdf', cache_timeout=60)

    return page
示例#16
0
def invoice(payment_id):
    payment = get_user_payment_or_abort(payment_id, allow_admin=True)

    form = InvoiceForm()

    if form.validate_on_submit():
        current_user.company = form.company.data
        db.session.commit()

        flash('Company name updated')
        return redirect(url_for('.invoice', payment_id=payment_id))

    if request.method != 'POST':
        form.company.data = current_user.company

    edit_company = bool(request.args.get('edit_company'))
    if request.args.get('js') == '0':
        flash("Please use your browser's print feature")

    invoice_lines = Purchase.query.filter_by(payment_id=payment_id).join(PriceTier, Product) \
        .with_entities(PriceTier, func.count(Purchase.price_tier_id)) \
        .group_by(PriceTier, Product.name).order_by(Product.name).all()

    ticket_sum = sum(pt.get_price(payment.currency).value_ex_vat * count for pt, count in invoice_lines)
    if payment.provider == 'stripe':
        premium = payment.__class__.premium(payment.currency, ticket_sum)
    else:
        premium = Decimal(0)

    subtotal = ticket_sum + premium
    vat = subtotal * Decimal('0.2')
    app.logger.debug('Invoice subtotal %s + %s = %s', ticket_sum, premium, subtotal)

    # FIXME: we should use a currency-specific quantization here (or rounder numbers)
    if subtotal + vat - payment.amount > Decimal('0.01'):
        app.logger.error('Invoice total mismatch: %s + %s - %s = %s', subtotal, vat,
                         payment.amount, subtotal + vat - payment.amount)
        flash('Your invoice cannot currently be displayed')
        return redirect(url_for('users.purchases'))

    app.logger.debug('Invoice total: %s + %s = %s', subtotal, vat, payment.amount)

    page = render_template('invoice.html', payment=payment, invoice_lines=invoice_lines, form=form,
                           premium=premium, subtotal=subtotal, vat=vat, edit_company=edit_company)

    if request.args.get('pdf'):
        url = external_url('.invoice', payment_id=payment_id)
        return send_file(render_pdf(url, page), mimetype='application/pdf')

    return page
示例#17
0
def create_bar_training_webhook():
    # This doesn't work, despite documentation and consistent return value

    _, form_id = app.config['BAR_TRAINING_FORM'].rsplit('/', 1)

    webhook_url = TYPEFORM_BASE + '/forms/{}/webhooks/{}'.format(form_id, get_auth_tag())
    response = requests.get(webhook_url, headers=typeform_headers())
    if response.status_code == 404:
        url = external_url('volunteer.bar_training_webhook', tag=get_auth_tag())
        args = {"url": url, "enabled": True}
        response = requests.put(webhook_url, json.dumps(args), headers=typeform_headers())

    response.raise_for_status()
    if response.status_code == 200:
        return response.json()["id"]
示例#18
0
def attach_tickets(msg, user):
    # Attach tickets to a mail Message
    page = render_receipt(user, pdf=True)
    url = external_url('tickets.receipt', user_id=user.id)
    pdf = render_pdf(url, page)

    receipt_types = ['admissions', 'campervan', 'parking', 'merchandise']

    tickets = Ticket.query.filter_by(owner_id=user.id, is_paid_for=True) \
                    .options(joinedload(Ticket.product).joinedload(Product.parent)) \
                    .filter(ProductGroup.type.in_(receipt_types))

    plural = (tickets.count() != 1 and 's' or '')
    msg.attach('Ticket%s.pdf' % plural, 'application/pdf', pdf.read())

    for t in tickets:
        t.set_state('receipt-emailed')
示例#19
0
文件: base.py 项目: dominicgs/Website
def message_proposer(proposal_id):
    form = SendMessageForm()
    proposal = Proposal.query.get_or_404(proposal_id)

    if request.method == 'POST':
        if form.send.data and form.message.data:
            msg = CFPMessage()
            msg.is_to_admin = False
            msg.from_user_id = current_user.id
            msg.proposal_id = proposal_id
            msg.message = form.message.data

            db.session.add(msg)
            db.session.commit()

            app.logger.info('Sending message from %s to %s', current_user.id,
                            proposal.user_id)

            msg_url = external_url('cfp.proposal_messages',
                                   proposal_id=proposal_id)
            msg = Message('New message about your EMF proposal',
                          sender=app.config['CONTENT_EMAIL'],
                          recipients=[proposal.user.email])
            msg.body = render_template('cfp_review/email/new_message.txt',
                                       url=msg_url,
                                       to_user=proposal.user,
                                       from_user=current_user,
                                       proposal=proposal)
            mail.send(msg)

        if form.mark_read.data or form.send.data:
            count = proposal.mark_messages_read(current_user)
            app.logger.info(
                'Marked %s messages to admin on proposal %s as read' %
                (count, proposal.id))

        return redirect(url_for('.message_proposer', proposal_id=proposal_id))

    # Admin can see all messages sent in relation to a proposal
    messages = CFPMessage.query.filter_by(
        proposal_id=proposal_id).order_by('created').all()

    return render_template('cfp_review/message_proposer.html',
                           form=form,
                           messages=messages,
                           proposal=proposal)
示例#20
0
def attach_tickets(msg, user):
    # Attach tickets to a mail Message
    page = render_receipt(user, pdf=True)
    url = external_url('tickets.receipt', user_id=user.id)
    pdf = render_pdf(url, page)

    # Types of product groups we include on receipts
    receipt_types = ['admissions', 'campervan', 'parking', 'tees']
    tickets = user.owned_tickets.filter(
        Purchase.type.in_(receipt_types),
        Purchase.is_paid_for == True,  # noqa: E712
    )

    plural = (tickets.count() != 1 and 's' or '')
    msg.attach('Ticket%s.pdf' % plural, 'application/pdf', pdf.read())

    for t in tickets:
        t.set_state('receipt-emailed')
示例#21
0
def _get_ical_dict(event, favourites_ids):
    return {
        'id': -event.id,
        'start_date': event_tz.localize(event.start_dt),
        'end_date': event_tz.localize(event.end_dt),
        'venue': event.location or '(Unknown)',
        'latlon': event.latlon,
        'map_link': event.map_link,
        'title': event.summary,
        'speaker': '',
        'user_id': None,
        'description': event.description,
        'type': 'talk',
        'may_record': False,
        'is_fave': event.id in favourites_ids,
        'source': 'external',
        'link': external_url('.line_up_external', event_id=event.id),
    }
示例#22
0
def receipt(user_id=None):
    if current_user.has_permission('admin') and user_id is not None:
        user = User.query.get(user_id)
    else:
        user = current_user

    if not user.owned_purchases.filter_by(is_paid_for=True).all():
        abort(404)

    png = bool(request.args.get('png'))
    pdf = bool(request.args.get('pdf'))

    page = render_receipt(user, png, pdf)
    if pdf:
        url = external_url('tickets.receipt', user_id=user_id)
        return send_file(render_pdf(url, page), mimetype='application/pdf', cache_timeout=60)

    return page
示例#23
0
def attach_tickets(msg, user):
    # Attach tickets to a mail Message
    page = render_receipt(user, pdf=True)
    url = external_url('tickets.receipt', user_id=user.id)
    pdf = render_pdf(url, page)

    msg.attach('EMF{}.pdf'.format(event_start().year), 'application/pdf',
               pdf.read())

    purchases = user.owned_purchases.filter_by(is_paid_for=True, state='paid') \
                                    .join(PriceTier, Product, ProductGroup) \
                                    .filter(ProductGroup.type.in_(RECEIPT_TYPES)) \
                                    .with_entities(Purchase) \
                                    .group_by(Purchase) \
                                    .order_by(Purchase.id)

    for p in purchases:
        p.set_state('receipt-emailed')
示例#24
0
def _get_ical_dict(event, favourites_ids):
    return {
        'id': -event.id,
        'start_date': event_tz.localize(event.start_dt),
        'end_date': event_tz.localize(event.end_dt),
        'venue': event.location or '(Unknown)',
        'latlon': event.latlon,
        'map_link': event.map_link,
        'title': event.summary,
        'speaker': '',
        'user_id': None,
        'description': event.description,
        'type': 'talk',
        'may_record': False,
        'is_fave': event.id in favourites_ids,
        'source': 'external',
        'link': external_url('.line_up_external', event_id=event.id),
    }
示例#25
0
def receipt(user_id=None):
    if current_user.has_permission('admin') and user_id is not None:
        user = User.query.get(user_id)
    else:
        user = current_user

    if not user.owned_tickets.filter_by(is_paid_for=True).all():
        abort(404)

    png = bool(request.args.get('png'))
    pdf = bool(request.args.get('pdf'))

    page = render_receipt(user, png, pdf)
    if pdf:
        url = external_url('tickets.receipt', user_id=user_id)
        return send_file(render_pdf(url, page), mimetype='application/pdf')

    return page
示例#26
0
def create_bar_training_webhook():
    # This doesn't work, despite documentation and consistent return value

    _, form_id = app.config['BAR_TRAINING_FORM'].rsplit('/', 1)

    webhook_url = TYPEFORM_BASE + '/forms/{}/webhooks/{}'.format(
        form_id, get_auth_tag())
    response = requests.get(webhook_url, headers=typeform_headers())
    if response.status_code == 404:
        url = external_url('volunteer.bar_training_webhook',
                           tag=get_auth_tag())
        args = {"url": url, "enabled": True}
        response = requests.put(webhook_url,
                                json.dumps(args),
                                headers=typeform_headers())

    response.raise_for_status()
    if response.status_code == 200:
        return response.json()["id"]
示例#27
0
def gocardless_start(payment):
    logger.info("Starting GoCardless flow for payment %s", payment.id)

    prefilled_customer = {
        "email": payment.user.email,
    }
    match = re.match(r'^ *([^ ,]+) +([^ ,]+) *$', payment.user.name)
    if match:
        prefilled_customer.update({
            "given_name": match.group(1),
            "family_name": match.group(2),
        })

    params = {
        "description":
        "Electromagnetic Field",
        "session_token":
        str(payment.id),
        "success_redirect_url":
        external_url('payments.gocardless_complete', payment_id=payment.id),
        "prefilled_customer":
        prefilled_customer,
    }
    if payment.currency == 'GBP':
        params["scheme"] = "bacs"
    elif payment.currency == 'EUR':
        # sepa_cor1 isn't an option, so let's hope it upgrades automatically
        params["scheme"] = "sepa_core"

    redirect_flow = gocardless_client.redirect_flows.create(params=params)

    logger.debug('GoCardless redirect ID: %s', redirect_flow.id)
    assert payment.redirect_id is None
    payment.redirect_id = redirect_flow.id

    # "Redirect flows expire 30 minutes after they are first created. You cannot complete an expired redirect flow."
    # https://developer.gocardless.com/api-reference/#core-endpoints-redirect-flows
    payment.expires = datetime.utcnow() + timedelta(minutes=30)

    db.session.commit()

    return redirect(redirect_flow.redirect_url)
示例#28
0
def attach_tickets(msg, user):
    # Attach tickets to a mail Message
    page = render_receipt(user, pdf=True)
    url = external_url('tickets.receipt', user_id=user.id)
    pdf = render_pdf(url, page)

    # Types of product groups we include on receipts
    # TODO: `user.owned_tickets` has changed here, there's some oddness with type...
    assert False
    receipt_types = ['admissions', 'campervan', 'parking', 'tees']
    tickets = user.owned_tickets.filter(
        Purchase.type.in_(receipt_types),
        Purchase.is_paid_for == True,  # noqa: E712
    )

    plural = (tickets.count() != 1 and 's' or '')
    msg.attach('Ticket%s.pdf' % plural, 'application/pdf', pdf.read())

    for t in tickets:
        t.set_state('receipt-emailed')
示例#29
0
def receipt(user_id=None):
    if current_user.has_permission("admin") and user_id is not None:
        user = User.query.get(user_id)
    else:
        user = current_user

    if not user.owned_purchases.filter_by(is_paid_for=True).all():
        abort(404)

    png = bool(request.args.get("png"))
    pdf = bool(request.args.get("pdf"))

    page = render_receipt(user, png, pdf)
    if pdf:
        url = external_url("tickets.receipt", user_id=user_id)
        return send_file(
            render_pdf(url, page), mimetype="application/pdf", cache_timeout=60
        )

    return page
示例#30
0
def _get_ical_dict(event, favourites_ids):
    res = {
        "id":
        -event.id,
        "start_date":
        event_tz.localize(event.start_dt),
        "end_date":
        event_tz.localize(event.end_dt),
        "venue":
        event.location or "(Unknown)",
        "latlon":
        event.latlon,
        "map_link":
        event.map_link,
        "title":
        event.summary,
        "speaker":
        "",
        "user_id":
        None,
        "description":
        event.description,
        "type":
        "talk",
        "may_record":
        False,
        "is_fave":
        event.id in favourites_ids,
        "source":
        "external",
        "link":
        external_url(".item_external",
                     year=event_year(),
                     slug=event.slug,
                     event_id=event.id),
    }
    if event.type in ["workshop", "youthworkshop"]:
        res["cost"] = event.display_cost
        res["equipment"] = event.display_participant_equipment
        res["age_range"] = event.display_age_range
    return res
示例#31
0
文件: base.py 项目: emfcamp/Website
def message_batch():
    proposals, filtered = filter_proposal_request()

    form = SendMessageForm()
    if form.validate_on_submit():
        if form.send.data:
            for proposal in proposals:
                msg = CFPMessage()
                msg.is_to_admin = False
                msg.from_user_id = current_user.id
                msg.proposal_id = proposal.id
                msg.message = form.message.data

                db.session.add(msg)
                db.session.commit()

                app.logger.info(
                    "Sending message from %s to %s", current_user.id, proposal.user_id
                )

                msg_url = external_url("cfp.proposal_messages", proposal_id=proposal.id)
                msg = EmailMessage(
                    "New message about your EMF proposal",
                    from_email=from_email("CONTENT_EMAIL"),
                    to=[proposal.user.email],
                )
                msg.body = render_template(
                    "cfp_review/email/new_message.txt",
                    url=msg_url,
                    to_user=proposal.user,
                    from_user=current_user,
                    proposal=proposal,
                )
                msg.send()

            flash("Messaged %s proposals" % len(proposals), "info")
            return redirect(url_for(".proposals", **request.args))

    return render_template(
        "cfp_review/message_batch.html", form=form, proposals=proposals
    )
示例#32
0
def _get_proposal_dict(proposal, favourites_ids):
    res = {
        'id': proposal.id,
        'start_date': event_tz.localize(proposal.scheduled_time),
        'end_date': event_tz.localize(proposal.end_date),
        'venue': proposal.scheduled_venue.name,
        'latlon': proposal.latlon,
        'map_link': proposal.map_link,
        'title': proposal.title,
        'speaker': proposal.published_names or proposal.user.name,
        'user_id': proposal.user.id,
        'description': proposal.description,
        'type': proposal.type,
        'may_record': proposal.may_record,
        'is_fave': proposal.id in favourites_ids,
        'source': 'database',
        'link': external_url('.line_up_proposal', proposal_id=proposal.id),
    }
    if proposal.type == 'workshop':
        res['cost'] = proposal.cost
    return res
示例#33
0
def _get_proposal_dict(proposal, favourites_ids):
    res = {
        'id': proposal.id,
        'start_date': event_tz.localize(proposal.scheduled_time),
        'end_date': event_tz.localize(proposal.end_date),
        'venue': proposal.scheduled_venue.name,
        'latlon': proposal.latlon,
        'map_link': proposal.map_link,
        'title': proposal.title,
        'speaker': proposal.published_names or proposal.user.name,
        'user_id': proposal.user.id,
        'description': proposal.description,
        'type': proposal.type,
        'may_record': proposal.may_record,
        'is_fave': proposal.id in favourites_ids,
        'source': 'database',
        'link': external_url('.line_up_proposal', proposal_id=proposal.id),
    }
    if proposal.type == 'workshop':
        res['cost'] = proposal.cost
    return res
示例#34
0
def message_proposer(proposal_id):
    form = SendMessageForm()
    proposal = Proposal.query.get_or_404(proposal_id)

    if request.method == "POST":
        if form.send.data and form.message.data:
            msg = CFPMessage()
            msg.is_to_admin = False
            msg.from_user_id = current_user.id
            msg.proposal_id = proposal_id
            msg.message = form.message.data

            db.session.add(msg)
            db.session.commit()

            app.logger.info("Sending message from %s to %s", current_user.id, proposal.user_id)

            msg_url = external_url("cfp.proposal_messages", proposal_id=proposal_id)
            send_template_email(
                "New message about your EMF proposal",
                proposal.user.email,
                app.config["CONTENT_EMAIL"],
                "cfp_review/email/new_message.txt",
                url=msg_url,
                to_user=proposal.user,
                from_user=current_user,
                proposal=proposal,
            )

        if form.mark_read.data or form.send.data:
            count = proposal.mark_messages_read(current_user)
            app.logger.info("Marked %s messages to admin on proposal %s as read" % (count, proposal.id))

        return redirect(url_for(".message_proposer", proposal_id=proposal_id))

    # Admin can see all messages sent in relation to a proposal
    messages = CFPMessage.query.filter_by(proposal_id=proposal_id).order_by("created").all()

    return render_template("cfp_review/message_proposer.html", form=form, messages=messages, proposal=proposal)
示例#35
0
文件: base.py 项目: emfcamp/Website
def message_proposer(proposal_id):
    form = SendMessageForm()
    proposal = Proposal.query.get_or_404(proposal_id)

    if form.validate_on_submit():
        if form.send.data:
            msg = CFPMessage()
            msg.is_to_admin = False
            msg.from_user_id = current_user.id
            msg.proposal_id = proposal_id
            msg.message = form.message.data

            db.session.add(msg)
            db.session.commit()

            app.logger.info('Sending message from %s to %s', current_user.id, proposal.user_id)

            msg_url = external_url('cfp.proposal_messages', proposal_id=proposal_id)
            msg = Message('New message about your EMF proposal',
                          sender=app.config['CONTENT_EMAIL'],
                          recipients=[proposal.user.email])
            msg.body = render_template('cfp_review/email/new_message.txt', url=msg_url,
                                       to_user=proposal.user, from_user=current_user,
                                       proposal=proposal)
            mail.send(msg)

        count = proposal.mark_messages_read(current_user)
        db.session.commit()
        app.logger.info('Marked %s messages to admin on proposal %s as read' % (count, proposal.id))

        return redirect(url_for('.message_proposer', proposal_id=proposal_id))

    # Admin can see all messages sent in relation to a proposal
    messages = CFPMessage.query.filter_by(
        proposal_id=proposal_id
    ).order_by('created').all()

    return render_template('cfp_review/message_proposer.html',
                           form=form, messages=messages, proposal=proposal)
示例#36
0
def gocardless_start(payment):
    logger.info("Starting GoCardless flow for payment %s", payment.id)

    prefilled_customer = {
        "email": payment.user.email,
    }
    match = re.match(r'^ *([^ ,]+) +([^ ,]+) *$', payment.user.name)
    if match:
        prefilled_customer.update({
            "given_name": match.group(1),
            "family_name": match.group(2),
        })

    params = {
        "description": "Electromagnetic Field",
        "session_token": str(payment.id),
        "success_redirect_url": external_url('payments.gocardless_complete', payment_id=payment.id),
        "prefilled_customer": prefilled_customer,
    }
    if payment.currency == 'GBP':
        params["scheme"] = "bacs"
    elif payment.currency == 'EUR':
        # sepa_cor1 isn't an option, so let's hope it upgrades automatically
        params["scheme"] = "sepa_core"

    redirect_flow = gocardless_client.redirect_flows.create(params=params)

    logger.debug('GoCardless redirect ID: %s', redirect_flow.id)
    assert payment.redirect_id is None
    payment.redirect_id = redirect_flow.id

    # "Redirect flows expire 30 minutes after they are first created. You cannot complete an expired redirect flow."
    # https://developer.gocardless.com/api-reference/#core-endpoints-redirect-flows
    payment.expires = datetime.utcnow() + timedelta(minutes=30)

    db.session.commit()

    return redirect(redirect_flow.redirect_url)
示例#37
0
def _get_ical_dict(event, favourites_ids):
    res = {
        'id': -event.id,
        'start_date': event_tz.localize(event.start_dt),
        'end_date': event_tz.localize(event.end_dt),
        'venue': event.location or '(Unknown)',
        'latlon': event.latlon,
        'map_link': event.map_link,
        'title': event.summary,
        'speaker': '',
        'user_id': None,
        'description': event.description,
        'type': 'talk',
        'may_record': False,
        'is_fave': event.id in favourites_ids,
        'source': 'external',
        'link': external_url('.line_up_external', event_id=event.id),
    }
    if event.type in ['workshop', 'youthworkshop']:
        res['cost'] = event.display_cost
        res['equipment'] = event.display_participant_equipment
        res['age_range'] = event.display_age_range
    return res
示例#38
0
def add_event(room, event):
    url = external_url("schedule.item",
                       year=event_year(),
                       proposal_id=event["id"],
                       slug=event["slug"])

    event_node = etree.SubElement(room,
                                  "event",
                                  id=str(event["id"]),
                                  guid=str(uuid5(NAMESPACE_URL, url)))

    _add_sub_with_text(event_node, "room", room.attrib["name"])
    _add_sub_with_text(event_node, "title", event["title"])
    _add_sub_with_text(event_node, "type", event.get("type", "talk"))
    _add_sub_with_text(event_node, "date", event["start_date"].isoformat())

    # Start time
    _add_sub_with_text(event_node, "start",
                       event["start_date"].strftime("%H:%M"))

    duration = get_duration(event["start_date"], event["end_date"])
    _add_sub_with_text(event_node, "duration", duration)

    _add_sub_with_text(event_node, "abstract", event["description"])
    _add_sub_with_text(event_node, "description", "")

    _add_sub_with_text(
        event_node,
        "slug",
        "emf%s-%s-%s" % (event_year(), event["id"], event["slug"]),
    )

    _add_sub_with_text(event_node, "subtitle", "")
    _add_sub_with_text(event_node, "track", "")

    add_persons(event_node, event)
    add_recording(event_node, event)
示例#39
0
def message_batch():
    proposals, filtered = filter_proposal_request()

    form = SendMessageForm()
    if form.validate_on_submit():
        if form.send.data:
            for proposal in proposals:
                msg = CFPMessage()
                msg.is_to_admin = False
                msg.from_user_id = current_user.id
                msg.proposal_id = proposal.id
                msg.message = form.message.data

                db.session.add(msg)
                db.session.commit()

                app.logger.info('Sending message from %s to %s',
                                current_user.id, proposal.user_id)

                msg_url = external_url('cfp.proposal_messages',
                                       proposal_id=proposal.id)
                msg = Message('New message about your EMF proposal',
                              sender=app.config['CONTENT_EMAIL'],
                              recipients=[proposal.user.email])
                msg.body = render_template('cfp_review/email/new_message.txt',
                                           url=msg_url,
                                           to_user=proposal.user,
                                           from_user=current_user,
                                           proposal=proposal)
                mail.send(msg)

            flash('Messaged %s proposals' % len(proposals), 'info')
            return redirect(url_for('.proposals', **request.args))

    return render_template('cfp_review/message_batch.html',
                           form=form,
                           proposals=proposals)
示例#40
0
def _get_proposal_dict(proposal, favourites_ids):
    res = {
        "id": proposal.id,
        "slug": proposal.slug,
        "start_date": event_tz.localize(proposal.start_date),
        "end_date": event_tz.localize(proposal.end_date),
        "venue": proposal.scheduled_venue.name,
        "latlon": proposal.latlon,
        "map_link": proposal.map_link,
        "title": proposal.display_title,
        "speaker": proposal.published_names or proposal.user.name,
        "user_id": proposal.user.id,
        "description": proposal.published_description or proposal.description,
        "type": proposal.type,
        "may_record": proposal.may_record,
        "is_fave": proposal.id in favourites_ids,
        "source": "database",
        "link": external_url(".line_up_proposal", proposal_id=proposal.id),
    }
    if proposal.type in ["workshop", "youthworkshop"]:
        res["cost"] = proposal.display_cost
        res["equipment"] = proposal.display_participant_equipment
        res["age_range"] = proposal.display_age_range
    return res
示例#41
0
def _get_proposal_dict(proposal, favourites_ids):
    res = {
        'id': proposal.id,
        'slug': proposal.slug,
        'start_date': event_tz.localize(proposal.start_date),
        'end_date': event_tz.localize(proposal.end_date),
        'venue': proposal.scheduled_venue.name,
        'latlon': proposal.latlon,
        'map_link': proposal.map_link,
        'title': proposal.display_title,
        'speaker': proposal.published_names or proposal.user.name,
        'user_id': proposal.user.id,
        'description': proposal.published_description or proposal.description,
        'type': proposal.type,
        'may_record': proposal.may_record,
        'is_fave': proposal.id in favourites_ids,
        'source': 'database',
        'link': external_url('.line_up_proposal', proposal_id=proposal.id),
    }
    if proposal.type in ['workshop', 'youthworkshop']:
        res['cost'] = proposal.display_cost
        res['equipment'] = proposal.display_participant_equipment
        res['age_range'] = proposal.display_age_range
    return res
示例#42
0
def invoice(payment_id, fmt=None):
    pdf = False
    if fmt == "pdf":
        pdf = True
    elif fmt:
        abort(404)

    payment = get_user_payment_or_abort(payment_id, allow_admin=True)

    form = InvoiceForm()

    if form.validate_on_submit():
        current_user.company = form.company.data
        payment.issue_vat_invoice_number()
        db.session.commit()

        flash("Company name updated")
        return redirect(url_for(".invoice", payment_id=payment_id))

    if request.method != "POST":
        form.company.data = current_user.company

    edit_company = bool(request.args.get("edit_company"))
    if request.args.get("js") == "0":
        flash("Please use your browser's print feature or download the PDF")

    invoice_lines = (
        Purchase.query.filter_by(payment_id=payment_id)
        .join(PriceTier, Product)
        .with_entities(PriceTier, func.count(Purchase.price_tier_id))
        .group_by(PriceTier, Product.name)
        .order_by(Product.name)
        .all()
    )

    ticket_sum = sum(
        pt.get_price(payment.currency).value_ex_vat * count
        for pt, count in invoice_lines
    )
    if payment.provider == "stripe":
        premium = payment.__class__.premium(payment.currency, ticket_sum)
    else:
        premium = Decimal(0)

    subtotal = ticket_sum + premium
    vat = subtotal * Decimal("0.2")

    # FIXME: we should use a currency-specific quantization here (or rounder numbers)
    if subtotal + vat - payment.amount > Decimal("0.01"):
        app.logger.error(
            "Invoice total mismatch: %s + %s - %s = %s",
            subtotal,
            vat,
            payment.amount,
            subtotal + vat - payment.amount,
        )
        flash("Your invoice cannot currently be displayed")
        return redirect(url_for("users.purchases"))

    if payment.vat_invoice_number:
        mode = "invoice"
        invoice_number = payment.issue_vat_invoice_number()
    else:
        mode = "receipt"
        invoice_number = None

    page = render_template(
        "payments/invoice.html",
        mode=mode,
        payment=payment,
        invoice_lines=invoice_lines,
        form=form,
        premium=premium,
        subtotal=subtotal,
        vat=vat,
        edit_company=edit_company,
        invoice_number=invoice_number,
    )

    url = external_url(".invoice", payment_id=payment_id)

    if pdf:
        return send_file(
            render_pdf(url, page),
            mimetype="application/pdf",
            cache_timeout=60,
            attachment_filename=f"emf_{mode}.pdf",
            as_attachment=True,
        )

    if mode == "invoice":
        invoice_dir = "/vat_invoices"
        if not os.path.exists(invoice_dir):
            logger.warn(
                "Not exporting VAT invoice as directory (%s) does not exist",
                invoice_dir,
            )
            return page

        with open(os.path.join(invoice_dir, f"{invoice_number}.pdf"), "wb") as f:
            shutil.copyfileobj(render_pdf(url, page), f)

    return page
示例#43
0
def product_view_bulk_add_vouchers_by_email(view_id):
    view = ProductView.query.get_or_404(view_id)
    form = BulkVoucherEmailForm()

    if not form.validate_on_submit() or form.preview.data:
        preview = None
        if form.preview.data:
            preview = format_trusted_html_email(
                form.text.data,
                form.subject.data,
                voucher_url="http://VOUCHER_URL_PLACEHOLDER",
                expiry=form.expires.data,
                reason=form.reason.data,
            )

        return render_template(
            "admin/products/view-bulk-add-voucher.html",
            view=view,
            form=form,
            preview=preview,
        )

    emails = set(e.strip() for e in re.split(r"[\s,]+", form.emails.data))

    if len(emails) >= 250:
        flash("More than 250 emails provided. Please submit <250 at a time.")
        return redirect(
            url_for(".product_view_bulk_add_vouchers_by_email",
                    view_id=view_id))

    added = existing = sent_total = 0

    with mail.get_connection() as conn:
        for email in emails:
            if Voucher.query.filter_by(email=email).first():
                existing += 1
                continue

            voucher = Voucher(
                view,
                code=random_voucher(),
                email=email,
                expiry=form.expires.data,
                purchases_remaining=form.num_purchases.data,
                tickets_remaining=form.num_tickets.data,
            )

            voucher_url = external_url("tickets.tickets_voucher",
                                       voucher_code=voucher.code)

            plaintext = format_trusted_plaintext_email(
                form.text.data,
                voucher_url=voucher_url,
                expiry=form.expires.data)
            html = format_trusted_html_email(
                form.text.data,
                form.subject.data,
                voucher_url=voucher_url,
                expiry=form.expires.data,
                reason=form.reason.data,
            )

            app.logger.info("Emailing %s volunteer voucher: %s", email,
                            voucher.code)
            sent_count = mail.send_mail(
                subject=form.subject.data,
                message=plaintext,
                from_email=from_email("TICKETS_EMAIL"),
                recipient_list=[email],
                fail_silently=True,
                connection=conn,
                html_message=html,
            )
            db.session.commit()
            sent_total += sent_count
            added += 1

    flash(
        f"{added} vouchers added, {sent_total} emails sent, {existing} duplicates skipped."
    )

    return redirect(
        url_for(".product_view_bulk_add_vouchers_by_email", view_id=view_id))