Exemple #1
0
def add_favourite():
    if not current_user.is_authenticated:
        abort(401)

    event_id = int(request.form["fave"])
    event_type = request.form["event_type"]
    if event_type == "proposal":
        proposal = Proposal.query.get_or_404(event_id)
        if proposal in current_user.favourites:
            current_user.favourites.remove(proposal)
        else:
            current_user.favourites.append(proposal)

        db.session.commit()
        return redirect(
            url_for(".main_year", year=event_year()) +
            "#proposal-{}".format(proposal.id))

    else:
        event = CalendarEvent.query.get_or_404(event_id)
        if event in current_user.calendar_favourites:
            current_user.calendar_favourites.remove(event)
        else:
            current_user.calendar_favourites.append(event)

        db.session.commit()
        return redirect(
            url_for(".main_year", year=event_year()) +
            "#event-{}".format(event.id))
Exemple #2
0
def make_root():
    root = etree.Element("schedule")

    _add_sub_with_text(root, "version", "1.0-public")

    conference = etree.SubElement(root, "conference")

    _add_sub_with_text(conference, "title",
                       "Electromagnetic Field {}".format(event_year()))
    _add_sub_with_text(conference, "acronym", "emf{}".format(event_year()))
    _add_sub_with_text(conference, "start", event_start().strftime("%Y-%m-%d"))
    _add_sub_with_text(conference, "end", event_end().strftime("%Y-%m-%d"))
    _add_sub_with_text(conference, "days", "3")
    _add_sub_with_text(conference, "timeslot_duration", "00:10")

    return root
Exemple #3
0
def favourites_ical():
    code = request.args.get("token", None)
    user = None
    if code:
        user = User.get_by_api_token(app.config.get("SECRET_KEY"), str(code))
    if not current_user.is_anonymous:
        user = current_user
    if not user:
        abort(404)

    schedule = _get_scheduled_proposals(request.args, override_user=user)
    title = "EMF {} Favourites for {}".format(event_year(), user.name)

    cal = Calendar()
    cal.add("summary", title)
    cal.add("X-WR-CALNAME", title)
    cal.add("X-WR-CALDESC", title)
    cal.add("version", "2.0")

    for event in schedule:
        if not event["is_fave"]:
            continue
        cal_event = Event()
        cal_event.add("uid", event["id"])
        cal_event.add("summary", event["title"])
        cal_event.add("description", _format_event_description(event))
        cal_event.add("location", event["venue"])
        cal_event.add("dtstart", event["start_date"])
        cal_event.add("dtend", event["end_date"])
        cal.add_component(cal_event)

    return Response(cal.to_ical(), mimetype="text/calendar")
Exemple #4
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")
def get_auth_tag():
    tag = "emf-{}-".format(event_year())
    msg = b"bar-training-" + tag.encode("utf-8")
    tag += hmac.new(
        app.config["SECRET_KEY"].encode("utf-8"), msg, digestmod=sha256
    ).hexdigest()
    return tag
Exemple #6
0
def schedule_json(year):
    if year != event_year():
        return feed_historic(year, "json")

    schedule = [
        _convert_time_to_str(p) for p in _get_scheduled_proposals(request.args)
    ]

    # NB this is JSON in a top-level array (security issue for low-end browsers)
    return Response(json.dumps(schedule), mimetype="application/json")
Exemple #7
0
def schedule_current():
    token = None
    if current_user.is_authenticated:
        token = generate_api_token(app.config["SECRET_KEY"], current_user.id)

    return render_template(
        "schedule/user_schedule.html",
        token=token,
        debug=app.config.get("DEBUG"),
        year=event_year(),
    )
Exemple #8
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
Exemple #9
0
def feed_redirect(fmt):
    routes = {
        "json": "schedule.schedule_json",
        "frab": "schedule.schedule_frab",
        "ical": "schedule.schedule_ical",
        "ics": "schedule.schedule_ical",
    }

    if fmt not in routes:
        abort(404)
    return redirect(url_for(routes[fmt], year=event_year()))
Exemple #10
0
def register():
    if current_user.village and current_user.village.admin:
        return redirect(
            url_for(".edit",
                    year=event_year(),
                    village_id=current_user.village.village.id))

    form = VillageForm()
    if form.validate_on_submit():
        if Village.get_by_name(form.name.data):
            flash(
                "A village already exists with that name, please choose another"
            )
            return redirect(url_for(".register"))

        village = Village(name=form.name.data,
                          description=form.description.data)

        member = VillageMember(village=village, user=current_user, admin=True)

        requirements = VillageRequirements(
            village=village,
            num_attendees=form.num_attendees.data,
            size_sqm=form.size_sqm.data,
            power_requirements=form.power_requirements.data,
            noise=form.noise.data,
            structures=form.structures.data,
        )
        db.session.add(village)
        db.session.add(member)
        db.session.add(requirements)
        db.session.commit()

        flash(
            "Your village registration has been received, thanks! You can edit it here."
        )
        return redirect(
            url_for(".edit", year=event_year(), village_id=village.id))

    return render_template("villages/register.html", form=form)
Exemple #11
0
def load_village(year, village_id, require_admin=False):
    """ Helper to return village or 404 """
    if year != event_year():
        abort(404)

    village = Village.get_by_id(village_id)
    if not village:
        abort(404)

    if require_admin and not (current_user.village.village == village
                              and current_user.village.admin):
        abort(404)
    return village
Exemple #12
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)
Exemple #13
0
def schedule_ical(year):
    if year != event_year():
        return feed_historic(year, "ics")

    schedule = _get_scheduled_proposals(request.args)
    title = "EMF {}".format(event_year())

    cal = Calendar()
    cal.add("summary", title)
    cal.add("X-WR-CALNAME", title)
    cal.add("X-WR-CALDESC", title)
    cal.add("version", "2.0")

    for event in schedule:
        cal_event = Event()
        cal_event.add("uid", event["id"])
        cal_event.add("summary", event["title"])
        cal_event.add("description", _format_event_description(event))
        cal_event.add("location", event["venue"])
        cal_event.add("dtstart", event["start_date"])
        cal_event.add("dtend", event["end_date"])
        cal.add_component(cal_event)

    return Response(cal.to_ical(), mimetype="text/calendar")
Exemple #14
0
def main_year(year):
    #  Do we want to show the current year's schedule from the DB,
    #  or a previous year's from the static archive?
    if year == event_year():
        if app.config.get("SCHEDULE"):
            # Schedule is ready, show it
            return schedule_current()
        elif app.config.get("LINE_UP"):
            # Show the lineup (list of talks without times/venues)
            return line_up()
        else:
            # No schedule should be shown yet.
            return render_template("schedule/no-schedule.html")
    else:
        return talks_historic(year)
Exemple #15
0
def schedule_frab(year):
    if year != event_year():
        return feed_historic(year, "frab")

    schedule = (Proposal.query.filter(
        Proposal.state.in_(["accepted", "finished"]),
        Proposal.scheduled_time.isnot(None),
        Proposal.scheduled_venue_id.isnot(None),
        Proposal.scheduled_duration.isnot(None),
    ).order_by(Proposal.scheduled_time).all())

    schedule = [_get_proposal_dict(p, []) for p in schedule]

    frab = export_frab(schedule)

    return Response(frab, mimetype="application/xml")
Exemple #16
0
def render_installation(installation: InstallationProposal):
    return {
        "id":
        installation.id,
        "name":
        installation.display_title,
        "url":
        url_for(
            "schedule.item",
            year=event_year(),
            proposal_id=installation.id,
            _external=True,
        ),
        "description":
        installation.published_description,
        "location":
        to_shape(installation.scheduled_venue.location).__geo_interface__
        if installation.scheduled_venue
        and installation.scheduled_venue.location else None,
    }
Exemple #17
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
Exemple #18
0
def item_json(year, proposal_id, slug=None):
    if year != event_year():
        abort(404)
    proposal = Proposal.query.get_or_404(proposal_id)
    if proposal.state not in ("accepted", "finished"):
        abort(404)

    if not current_user.is_anonymous:
        favourites_ids = [f.id for f in current_user.favourites]
    else:
        favourites_ids = []

    data = _get_proposal_dict(proposal, favourites_ids)

    data["start_date"] = data["start_date"].strftime("%Y-%m-%d %H:%M:%S")
    data["end_date"] = data["end_date"].strftime("%Y-%m-%d %H:%M:%S")
    # Remove unnecessary data for now
    del data["link"]
    del data["source"]
    del data["id"]

    return data
Exemple #19
0
def item_external(year, event_id, slug=None):
    if year != event_year():
        abort(404)

    event = CalendarEvent.query.get_or_404(event_id)

    if not current_user.is_anonymous:
        is_fave = event in current_user.calendar_favourites
    else:
        is_fave = False

    if (request.method == "POST") and not current_user.is_anonymous:
        if is_fave:
            current_user.calendar_favourites.remove(event)
            msg = 'Removed "%s" from favourites' % event.title
        else:
            current_user.calendar_favourites.append(event)
            msg = 'Added "%s" to favourites' % event.title
        db.session.commit()
        flash(msg)
        return redirect(
            url_for(".item_external",
                    year=year,
                    event_id=event.id,
                    slug=event.slug))

    if slug != event.slug:
        return redirect(
            url_for(".item_external",
                    year=year,
                    event_id=event.id,
                    slug=event.slug))

    return render_template(
        "schedule/item-external.html",
        event=event,
        is_fave=is_fave,
        venue_name=event.venue,
    )
Exemple #20
0
def export_db():
    """Export data from the DB to disk.

    This command is run as a last step before wiping the DB after an event, to export
    all the data we want to save. It saves a private and a public export to the
    exports directory.

    Model classes should implement get_export_data, which returns a dict with keys:
        public   Public data to save in git
        private  Private data that should be stored for a limited amount of time
        tables   Tables this method exported, used to sanity check the export process

    Alternatively, add __export_data__ = False to a class to state that get_export_data
    shouldn't be called, and that its associated table doesn't need to be checked.
    """

    # As we go, we check against the list of all tables, in case we forget about some
    # new object type (e.g. association table).

    # Exclude tables we know will never be exported
    ignore = ["alembic_version", "transaction"]

    all_model_classes = {
        cls
        for cls in db.Model._decl_class_registry.values()
        if isinstance(cls, type) and issubclass(cls, db.Model)
    }

    all_version_classes = {
        version_class(c)
        for c in all_model_classes if is_versioned(c)
    }

    seen_model_classes = set()
    remaining_tables = set(db.metadata.tables)

    year = event_year()
    path = os.path.join("exports", str(year))
    for dirname in ["public", "private"]:
        os.makedirs(os.path.join(path, dirname), exist_ok=True)

    for model_class in all_model_classes:
        if model_class in seen_model_classes:
            continue

        seen_model_classes.add(model_class)

        table = model_class.__table__.name
        model = model_class.__name__

        if table in ignore:
            app.logger.debug("Ignoring %s", model)
            remaining_tables.remove(table)
            continue

        if not getattr(model_class, "__export_data__", True):
            # We don't remove the version table, as we want
            # to be explicit about chucking away edit stats
            app.logger.debug("Skipping %s", model)
            remaining_tables.remove(table)
            continue

        if model_class in all_version_classes:
            # Version tables are explicitly dumped by their parents,
            # as they don't make sense to be exported on their own
            app.logger.debug("Ignoring version model %s", model)
            continue

        if hasattr(model_class, "get_export_data"):
            try:
                export = model_class.get_export_data()
                for dirname in ["public", "private"]:
                    if dirname in export:
                        filename = os.path.join(path, dirname,
                                                "{}.json".format(model))
                        simplejson.dump(
                            export[dirname],
                            open(filename, "w"),
                            indent=4,
                            cls=ExportEncoder,
                        )
                        app.logger.info("Exported data from %s to %s", model,
                                        filename)

            except Exception as e:
                app.logger.error("Error exporting %s", model)
                raise

            exported_tables = export.get("tables", [table])
            remaining_tables -= set(exported_tables)

    if remaining_tables:
        app.logger.warning("Remaining tables: %s", ", ".join(remaining_tables))

    data = {
        "timestamp": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"),
        "remaining_tables": sorted(list(remaining_tables)),
    }
    filename = os.path.join(path, "export.json")
    simplejson.dump(data, open(filename, "w"), indent=4, cls=ExportEncoder)

    with app.test_client() as client:
        for schedule in ["schedule.frab", "schedule.json", "schedule.ics"]:
            resp = client.get("/{}".format(schedule))
            with open(os.path.join(path, "public", schedule), "wb") as f:
                f.write(resp.data)

    app.logger.info("Export complete, summary written to %s", filename)
Exemple #21
0
def create_gc_payment(payment):
    try:
        logger.info("Creating GC payment for %s (%s)", payment.id, payment.mandate)

        # The idempotency key identifies a unique payment to GoCardless.
        # In production this is the event year and payment ID but in dev, payment
        # IDs get reused when the DB is reset, so don't use idempotency keys in dev.
        headers = {"Idempotency-Key": f"{event_year()}-{payment.id}"}
        if app.config.get("DEBUG"):
            headers = {}

        gc_payment = gocardless_client.payments.create(
            params={
                "amount": payment.amount_int,
                "currency": payment.currency,
                "links": {"mandate": payment.mandate},
                "metadata": {
                    "payment_id": str(payment.id),
                    "event_year": str(event_year()),
                },
            },
            headers=headers,
        )

        payment.gcid = gc_payment.id
        payment.state = "inprogress"

    except gocardless_pro.errors.ValidationFailedError as exc:
        currency_errors = [e for e in exc.errors if e["field"] == "currency"]
        if currency_errors:
            # e['message'] will be one of:
            #   'must be GBP for a bacs mandate'
            #   'must be EUR for a sepa_core mandate'
            logger.error("Currency exception %r confirming payment", exc)
            flash(
                "Your account cannot be used for {} payments".format(payment.currency)
            )
        else:
            logger.error("Exception %r confirming payment", exc)
            flash(
                "An error occurred with your payment, please contact {}".format(
                    app.config["TICKETS_EMAIL"][1]
                )
            )

        return redirect(url_for("users.purchases"))

    except Exception as e:
        logger.error("Exception %r confirming payment", e)
        flash(
            "An error occurred with your payment, please contact {}".format(
                app.config["TICKETS_EMAIL"][1]
            )
        )
        return redirect(url_for("users.purchases"))

    # We need to make sure of a 5 working days grace
    # for gocardless payments, so push the payment expiry forwards
    payment.expires = datetime.utcnow() + timedelta(
        days=app.config["EXPIRY_DAYS_GOCARDLESS"]
    )
    for purchase in payment.purchases:
        purchase.set_state("payment-pending")

    db.session.commit()
    logger.info("Reset expiry for payment %s", payment.id)

    # FIXME: determine whether these are tickets or generic products
    msg = Message(
        "Your EMF ticket purchase",
        sender=app.config["TICKETS_EMAIL"],
        recipients=[payment.user.email],
    )
    msg.body = render_template(
        "emails/tickets-purchased-email-gocardless.txt",
        user=payment.user,
        payment=payment,
    )
    mail.send(msg)

    return redirect(url_for(".gocardless_waiting", payment_id=payment.id))
Exemple #22
0
def abort_if_invalid_year(year):
    if not 2012 <= year < event_year():
        abort(404)
Exemple #23
0
def main(year):
    if year != event_year():
        abort(404)

    villages = Village.query.all()
    return render_template("villages/villages.html", villages=villages)
Exemple #24
0
def villages_redirect():
    return redirect(url_for(".main", year=event_year()))
Exemple #25
0
def main():
    return redirect(url_for(".main_year", year=event_year()))
Exemple #26
0
def item(year, proposal_id, slug=None):
    """ Display a detail page for a schedule item """
    if year == event_year():
        return item_current(year, proposal_id, slug)
    else:
        return item_historic(year, proposal_id, slug)