diff --git a/Procfile b/Procfile index e60f4f01b85c6fc30c6d2d9cef9d7e2d54b6b0ed..50e3a4b730e9fd5f0c861fa517dd82149fe1c68c 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: gunicorn pinaxcon.wsgi --log-file - +web: gunicorn pinaxcon.wsgi --timeout 30 --log-file - diff --git a/pinaxcon/monkey_patch.py b/pinaxcon/monkey_patch.py index 64e7b3bedfb5247263c81973673886061ab69250..ca0f403871dfc0b772a85aaa1339b2ab8c3ae00c 100644 --- a/pinaxcon/monkey_patch.py +++ b/pinaxcon/monkey_patch.py @@ -1,4 +1,5 @@ from django.conf import settings +from django.contrib.auth.models import User from django.core.mail import EmailMultiAlternatives from functools import wraps @@ -12,6 +13,7 @@ class MonkeyPatchMiddleware(object): def do_monkey_patch(): patch_stripe_card_defaults() + patch_conference_schedule() # Remove this function from existence global do_monkey_patch @@ -24,9 +26,80 @@ def patch_stripe_card_defaults(): old_sync_card = sources.sync_card + @wraps(old_sync_card) def sync_card(customer, source): d = defaultdict(str) d.update(source) return old_sync_card(customer, d) sources.sync_card = sync_card + + +def patch_conference_schedule(): + from symposion.schedule import views as sv + from symposion.schedule import models as sm + + old_schedule_json = sv._schedule_json + + @wraps(old_schedule_json) + def schedule_json(request): + schedule = old_schedule_json(request) + + for slot_data in schedule: + slot = sm.Slot.objects.get(id=slot_data["conf_key"]) + presentation = slot.content + if presentation is not None: + update_presentation(request, slot_data, presentation) + elif slot.kind.label.lower() == "keynote": + update_keynote(request, slot_data) + elif slot.kind.label.lower() == "housekeeping": + update_housekeeping(request, slot_data) + else: + pass + + return schedule + + def update_presentation(request, slot_data, presentation): + try: + slot_data["reviewers"] = ( + presentation.speaker.conferencespeaker.reviewer + if request.user.is_staff else ["redacted"] + ) + slot_data["license"] = "CC BY-SA" + slot_data["released"] = presentation.proposal_base.talkproposal.recording_release + slot_data["twitter_id"] = presentation.speaker.conferencespeaker.twitter_username + except Exception as e: + print e + + def update_keynote(request, slot_data): + keynotes = { + "Brandon Rhodes": (User.objects.get(username="brandon").email, "brandon_rhodes"), + "Carina C. Zona": (User.objects.get(username="cczona").email, "cczona"), + } + for speaker, values in keynotes.items(): + print speaker + if speaker in slot_data["name"]: + author_name = speaker + author_email, author_twitter_id = values + + slot_data["name"] = "Keynote" + slot_data["authors"] = [author_name] + slot_data["contact"] = [ + author_email + ] if request.user.is_staff else ["redacted"] + slot_data["abstract"] = "Keynote presentation from North Bay Python 2017 by " + author_name + slot_data["description"] = "Keynote presentation from North Bay Python 2017 by " + author_name + slot_data["conf_url"] = "https://2017.northbaypython.org" + slot_data["cancelled"] = False + slot_data["reviewers"] = "" + slot_data["license"] = "CC BY-SA" + slot_data["twitter_id"] = author_twitter_id + slot_data["released"] = True + + def update_housekeeping(request, slot_data): + slot_data["contact"] = [ + "spam@northbaypython.org" + ] if request.user.is_staff else ["redacted"] + + + sv._schedule_json = schedule_json diff --git a/pinaxcon/proposals/migrations/0006_conferencespeaker_reviewer.py b/pinaxcon/proposals/migrations/0006_conferencespeaker_reviewer.py new file mode 100644 index 0000000000000000000000000000000000000000..9677fbdcbce793792bcf72f755ea329e8d55e7b6 --- /dev/null +++ b/pinaxcon/proposals/migrations/0006_conferencespeaker_reviewer.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-16 00:37 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('proposals', '0005_auto_20170917_2031'), + ] + + operations = [ + migrations.AddField( + model_name='conferencespeaker', + name='reviewer', + field=models.EmailField(blank=True, help_text='Include the e-mail address of someone who can watch a video of your talk, shortly after the video is produced, to ensure quality.', max_length=254, null=True, verbose_name='E-mail of video reviewer'), + ), + ] diff --git a/pinaxcon/proposals/models.py b/pinaxcon/proposals/models.py index 004360f03768dbe78f9dad1a3fd8e56cf6e153af..6229c73f37a98b59cac2b3db8e2dab4fea2f02e4 100644 --- a/pinaxcon/proposals/models.py +++ b/pinaxcon/proposals/models.py @@ -74,6 +74,15 @@ class ConferenceSpeaker(SpeakerBase): "these here. Your response is optional."), ) + reviewer = models.EmailField( + blank=True, + null=True, + verbose_name=_("E-mail of video reviewer"), + help_text=_("Include the e-mail address of someone who can watch a " + "video of your talk, shortly after the video is produced, " + "to ensure quality."), + ) + code_of_conduct = models.BooleanField( default=False, help_text=_("I have read and, in the event that my proposal is " diff --git a/pinaxcon/settings.py b/pinaxcon/settings.py index ed450c6b193180afa3abf70b35698af2d9dbfea8..ef557aa6f29299d77f8af63ce1408c41606e1161 100644 --- a/pinaxcon/settings.py +++ b/pinaxcon/settings.py @@ -229,6 +229,8 @@ INSTALLED_APPS = [ # stylesheets and js 'compressor', + + 'email_log', ] # A sample logging configuration. The only tangible logging @@ -270,7 +272,8 @@ FIXTURE_DIRS = [ # Heroku: Get email configuration from environment variables. -EMAIL_BACKEND = os.environ.get("DJANGO_EMAIL_BACKEND", "django.core.mail.backends.console.EmailBackend") # noqa +EMAIL_BACKEND = "email_log.backends.EmailBackend" +EMAIL_LOG_BACKEND = os.environ.get("DJANGO_EMAIL_BACKEND", "django.core.mail.backends.console.EmailBackend") # noqa EMAIL_HOST = os.environ.get("DJANGO_EMAIL_HOST", "") EMAIL_PORT = int(os.environ.get("DJANGO_EMAIL_PORT", 25)) EMAIL_HOST_USER = os.environ.get("DJANGO_EMAIL_HOST_USER", "") diff --git a/pinaxcon/templates/registrasion/badge.svg b/pinaxcon/templates/registrasion/badge.svg index 499ac6dbadf37296911a9ada27f4fdcbaa923af6..941a414c07e6988ac5f42596b575fedbcdb8d50e 100644 --- a/pinaxcon/templates/registrasion/badge.svg +++ b/pinaxcon/templates/registrasion/badge.svg @@ -1,158 +1,14 @@ - - +{% spaceless %} - +{% load nbpy_tags %} +{% name_split user.attendee.attendeeprofilebase.attendeeprofile.name as split_name %} +{% ticket_type as ticket %} +{% affiliation ticket user as aff %} +{% company_split aff as split_affiliation %} +{% special user as special %} - - - - - - - image/svg+xml - - - - - - - {{ user.attendee.attendeeprofilebase.attendeeprofile.name }}{{ user.attendee.attendeeprofilebase.attendeeprofile.company }}{{ user.attendee.attendeeprofilebase.attendeeprofile.free_text_1 }}{{ user.attendee.attendeeprofilebase.attendeeprofile.free_text_2 }}{% if user.attendee.attendeeprofilebase.attendeeprofile.of_legal_age %}18+?{% else %}MINOR{% endif %}DINNER: {{ dinner_count }}BREAKFAST: {{ breakfast_count }}TICKET: {% for ticket in ticket %}{{ ticket.product.name }}{% endfor %} - - - +{% with name1=split_name.first name2=split_name.last affiliation1=split_affiliation.first affiliation2=split_affiliation.last %} + {% include "registrasion/badge_outer.svg" %} +{% endwith %} + +{% endspaceless %} diff --git a/pinaxcon/templates/registrasion/badge_outer.svg b/pinaxcon/templates/registrasion/badge_outer.svg new file mode 100644 index 0000000000000000000000000000000000000000..e69c328191fb66bdfdb5ea1d4db92aed7044dcf8 --- /dev/null +++ b/pinaxcon/templates/registrasion/badge_outer.svg @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + {{ name1 }}{{ name2 }} + {{ affiliation1 }}{{ affiliation2 }} + {{ special }} + + + + + + + + + + + {{ name1 }}{{ name2 }} + {{ affiliation1 }}{{ affiliation2 }} + {{ special }} + + + + diff --git a/pinaxcon/templates/static_pages/homepage.html b/pinaxcon/templates/static_pages/homepage.html index 8fe7d51cd9e925c87aa213827548ee2a5dac0ca4..d957d4225c6b53eb49cd10d340567fad62432214 100644 --- a/pinaxcon/templates/static_pages/homepage.html +++ b/pinaxcon/templates/static_pages/homepage.html @@ -138,7 +138,7 @@
diff --git a/pinaxcon/templatetags/nbpy_tags.py b/pinaxcon/templatetags/nbpy_tags.py index e5ccdafd3623ee0b9bae46e7b16831270132dfa4..4bbf3206106df97cca2633937c1f0bb7bd63c6ba 100644 --- a/pinaxcon/templatetags/nbpy_tags.py +++ b/pinaxcon/templatetags/nbpy_tags.py @@ -1,6 +1,7 @@ from registrasion.models import commerce from registrasion.controllers.category import CategoryController from registrasion.controllers.item import ItemController +from registrasion.templatetags import registrasion_tags from decimal import Decimal from django import template @@ -42,3 +43,75 @@ def donation_income(context, invoice): donation = max(Decimal('0'), (invoice.value - sum(rbi))) return donation.quantize(Decimal('.01')) + + +# TODO: include van/de/van der/de la/etc etc etc + +@register.simple_tag +def name_split(name, split_characters=None): + + tokens = name.split() + if split_characters is None or len(name) > split_characters: + even_split = int((len(tokens) + 1) / 2) # Round up. + else: + even_split = len(tokens) + + return { + "first" : " ".join(tokens[:even_split]), + "last" : " ".join(tokens[even_split:]), + } + +@register.simple_tag +def company_split(name): + f = name_split(name, 18) + return f + + +@register.simple_tag(takes_context=True) +def special(context, user): + organiser = user.groups.filter(name='Conference organisers').exists() + try: + speaker = user.speaker_profile.presentations.count() != 0 + except Exception: + speaker = False + volunteer = "Volunteer" in ticket_type(context) + + if organiser: + return "Organizer" + elif speaker: + return "Speaker" + elif volunteer: + return "Staff" + else: + return "" + + +CLEARED = set([ + "BeeWare Project", + "Project Jupyter", + "PSF Packaging WG / PyCon 2018 Chair", + "PyCon Ukraine", + "PyLadies PDX", + "Recovered Silver", + "Twisted", + "@vmbrasseur", +]) + +@register.simple_tag +def affiliation(ticket, user): + aff = user.attendee.attendeeprofilebase.attendeeprofile.company + if "Individual" not in ticket or "Sponsor" in ticket: + return aff + elif ticket == "Individual Supporter" and aff in CLEARED: + return aff + else: + return "" + + +@register.simple_tag(takes_context=True) +def ticket_type(context): + + items = registrasion_tags.items_purchased(context) + for item in items: + if item.product.category.name == "Ticket": + return item.product.name diff --git a/requirements/base.txt b/requirements/base.txt index 94f429e82e3ffe530849e51bfb7e938515b795c6..a5d6b4e29939d987703712f606560c05fa517cc1 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -18,7 +18,7 @@ easy-thumbnails==2.4.1 django-timezone-field==2.0 django-model-utils==3.0.0 wiki==0.3b3 - +django-email-log==0.2.0 # For testing django-nose==1.4.4