diff --git a/pinaxcon/proposals/forms.py b/pinaxcon/proposals/forms.py index b8d52ad..b2a3337 100644 --- a/pinaxcon/proposals/forms.py +++ b/pinaxcon/proposals/forms.py @@ -1,9 +1,34 @@ from django import forms +from symposion.proposals.forms import ProposalMixIn -from .models import TalkProposal +from .models import ConferenceSpeaker, TalkProposal -class ProposalForm(forms.ModelForm): +class ConferenceSpeakerForm(forms.ModelForm): + + class Meta: + model = ConferenceSpeaker + exclude = [ + 'user', + 'biography_html', + 'experience_html', + 'invite_email', + 'invite_token', + 'annotation', + ] + + def __init__(self, *a, **k): + super(ConferenceSpeakerForm, self).__init__(*a, **k) + self.fields['code_of_conduct'].required = True + + + +class ProposalForm(forms.ModelForm, ProposalMixIn): + + def __init__(self, *a, **k): + super(ProposalForm, self).__init__(*a, **k) + self.description_required() + self.abstract_required() def clean_description(self): value = self.cleaned_data["description"] @@ -20,9 +45,12 @@ class TalkProposalForm(ProposalForm): model = TalkProposal fields = [ "title", - "audience_level", "description", "abstract", + "new_presentation", + "extended_presentation", "additional_notes", + "extra_av", + "slides_release", "recording_release", ] diff --git a/pinaxcon/proposals/migrations/0002_conferencespeaker.py b/pinaxcon/proposals/migrations/0002_conferencespeaker.py new file mode 100644 index 0000000..52f1657 --- /dev/null +++ b/pinaxcon/proposals/migrations/0002_conferencespeaker.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-08-13 18:45 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('symposion_speakers', '0007_auto_20170810_1651'), + ('proposals', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='ConferenceSpeaker', + fields=[ + ('speakerbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='symposion_speakers.SpeakerBase')), + ('twitter_username', models.CharField(blank=True, help_text='Your Twitter account', max_length=15)), + ('first_time', models.BooleanField(help_text='')), + ('experience', models.TextField(blank=True, help_text="List any past speaking experience you have. Edit using Markdown.", verbose_name='Past speaking experience')), + ('experience_html', models.TextField(blank=True)), + ('travel_assistance', models.BooleanField(help_text='Check this field if you require travel assistance to get to North Bay Python in Petaluma, California.')), + ('lodging_assistance', models.BooleanField(help_text='Check this field if you require lodging assistance in Petaluma, California during North Bay Python.')), + ('home_city', models.CharField(blank=True, help_text='Which city (and state, and country) will you be traveling from to get to North Bay Python?', max_length=127)), + ('minority_group', models.CharField(blank=True, help_text='If you are a member of one or more groups that are underrepresented in the tech industry, you may list these here. Your response is optional.', max_length=256, verbose_name='Diversity statement')), + ('code_of_conduct', models.BooleanField(help_text="I have read and, in the event that my proposal is accepted, agree that I will comply with the Code of Conduct.")), + ], + bases=('symposion_speakers.speakerbase',), + ), + ] diff --git a/pinaxcon/proposals/migrations/0003_auto_20170813_1945.py b/pinaxcon/proposals/migrations/0003_auto_20170813_1945.py new file mode 100644 index 0000000..0642b22 --- /dev/null +++ b/pinaxcon/proposals/migrations/0003_auto_20170813_1945.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-08-13 19:45 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('proposals', '0002_conferencespeaker'), + ] + + operations = [ + migrations.RemoveField( + model_name='talkproposal', + name='audience_level', + ), + migrations.AddField( + model_name='talkproposal', + name='extended_presentation', + field=models.BooleanField(default=False, help_text='Most talks at North Bay Python go for 30 minutes. We have some openings for 45-minute talks. If you check this field, please explain in your additional notes how you would use the extra 15 minutes.', verbose_name='Optionally consider this proposal for a 45-minute slot'), + ), + migrations.AddField( + model_name='talkproposal', + name='extra_av', + field=models.TextField(blank=True, help_text='We will provide you with a projector with HDMI connection, an audio connection, and one microphone per speaker. If you need anything more than this to present this talk, please list them here.', verbose_name='Extra tech and A/V requirements'), + ), + migrations.AddField( + model_name='talkproposal', + name='new_presentation', + field=models.BooleanField(default=False, help_text='Check this box if North Bay Python will be the first time this talk is presented at a technical conference.', verbose_name='This is a new presentation'), + ), + migrations.AddField( + model_name='talkproposal', + name='slides_release', + field=models.BooleanField(default=True, help_text='I authorize North Bay Python to release a copy of my slides and related materials under the Creative Commons Attribution-ShareAlike 3.0 United States licence, and certify that I have the authority to do so.'), + ), + migrations.AlterField( + model_name='conferencespeaker', + name='experience', + field=models.TextField(blank=True, help_text="List any past speaking experience you have. This can include user groups, meetups, or presentations at work or school. Edit using Markdown.", verbose_name='Past speaking experience'), + ), + migrations.AlterField( + model_name='conferencespeaker', + name='first_time', + field=models.BooleanField(help_text='Check this field if this is your first time speaking at a technical conference.', verbose_name='First-time speaker?'), + ), + migrations.AlterField( + model_name='conferencespeaker', + name='lodging_assistance', + field=models.BooleanField(help_text='Check this field if you require lodging assistance in Petaluma, California during North Bay Python.', verbose_name='Lodging assistance required?'), + ), + migrations.AlterField( + model_name='conferencespeaker', + name='minority_group', + field=models.CharField(blank=True, help_text='If you are a member of one or more groups that are under-represented in the tech industry, you may list these here. Your response is optional.', max_length=256, verbose_name='Diversity statement'), + ), + migrations.AlterField( + model_name='conferencespeaker', + name='travel_assistance', + field=models.BooleanField(help_text='Check this field if you require travel assistance to get to North Bay Python in Petaluma, California.', verbose_name='Travel assistance required?'), + ), + migrations.AlterField( + model_name='talkproposal', + name='recording_release', + field=models.BooleanField(default=True, help_text='I authorize North Bay Python to release a recording of my talk under the Creative Commons Attribution-ShareAlike 3.0 United States licence.'), + ), + ] diff --git a/pinaxcon/proposals/models.py b/pinaxcon/proposals/models.py index 2da49d8..d0f81af 100644 --- a/pinaxcon/proposals/models.py +++ b/pinaxcon/proposals/models.py @@ -1,25 +1,121 @@ from django.db import models +from django.utils.translation import ugettext_lazy as _ +from symposion.markdown_parser import parse from symposion.proposals.models import ProposalBase +from symposion.speakers.models import SpeakerBase + + + +class ConferenceSpeaker(SpeakerBase): + + def clean_twitter_username(self): + value = self.twitter_username + if value.startswith("@"): + value = value[1:] + return value + + def save(self, *args, **kwargs): + self.experience_html = parse(self.experience) + self.twitter_username = self.clean_twitter_username() + return super(ConferenceSpeaker, self).save(*args, **kwargs) + + twitter_username = models.CharField( + max_length=15, + blank=True, + help_text=_(u"Your Twitter account") + ) + + first_time = models.BooleanField( + blank=True, + verbose_name=_("First-time speaker?"), + help_text=_("Check this field if this is your first time speaking " + "at a technical conference."), + ) + + experience = models.TextField(blank=True, help_text=_ + ("List any past speaking experience you have. This can include " + "user groups, meetups, or presentations at work or school. Edit " + "using " + "Markdown."), + verbose_name=_("Past speaking experience"), + ) + experience_html = models.TextField(blank=True) + + travel_assistance = models.BooleanField( + blank=True, + verbose_name=_("Travel assistance required?"), + help_text=_("Check this field if you require travel assistance to get " + "to North Bay Python in Petaluma, California."), + ) + + lodging_assistance = models.BooleanField( + blank=True, + verbose_name=_("Lodging assistance required?"), + help_text=_("Check this field if you require lodging assistance in " + "Petaluma, California during North Bay Python."), + ) + + home_city = models.CharField( + blank=True, + max_length=127, + help_text=_("Which city (and state, and country) will you be " + "traveling from to get to North Bay Python?"), + ) + + minority_group = models.CharField(blank=True, max_length=256, + verbose_name=_("Diversity statement"), + help_text=_("If you are a member of one or more groups that are " + "under-represented in the tech industry, you may list " + "these here. Your response is optional."), + ) + + code_of_conduct = models.BooleanField( + help_text=_("I have read and, in the event that my proposal is " + "accepted, agree that I will comply with the " + "Code of Conduct."), + ) class Proposal(ProposalBase): - AUDIENCE_LEVEL_NOVICE = 1 - AUDIENCE_LEVEL_EXPERIENCED = 2 - AUDIENCE_LEVEL_INTERMEDIATE = 3 - - AUDIENCE_LEVELS = [ - (AUDIENCE_LEVEL_NOVICE, "Novice"), - (AUDIENCE_LEVEL_INTERMEDIATE, "Intermediate"), - (AUDIENCE_LEVEL_EXPERIENCED, "Experienced"), - ] - - audience_level = models.IntegerField(choices=AUDIENCE_LEVELS) - + extended_presentation = models.BooleanField( + default=False, + verbose_name=_("Optionally consider this proposal for a 45-minute " + "slot"), + help_text=_("Most talks at North Bay Python go for 30 minutes. We " + "have some openings for 45-minute talks. If you check this " + "field, please explain in your additional notes how you " + "would use the extra 15 minutes."), + ) + extra_av = models.TextField( + blank=True, + verbose_name=_("Extra tech and A/V requirements"), + help_text=_("We will provide you with a projector with HDMI " + "connection, an audio connection, and one microphone per " + "speaker. If you need anything more than this to present " + "this talk, please list them here."), + ) + new_presentation = models.BooleanField( + default=False, + verbose_name=_("This is a new presentation"), + help_text=_("Check this box if North Bay Python will be the first " + "time this talk is presented at a technical conference."), + ) + slides_release = models.BooleanField( + default=True, + help_text=_("I authorize North Bay Python to release a copy of my " + "slides and related materials under the Creative Commons " + "Attribution-ShareAlike 3.0 United States licence, and " + "certify that I have the authority to do so."), + ) recording_release = models.BooleanField( default=True, - help_text="By submitting your proposal, you agree to give permission to the conference organizers to record, edit, and release audio and/or video of your presentation. If you do not agree to this, please uncheck this box." + help_text=_("I authorize North Bay Python to release a recording of " + "my talk under the Creative Commons " + "Attribution-ShareAlike 3.0 United States licence."), + ) class Meta: diff --git a/pinaxcon/settings.py b/pinaxcon/settings.py index d1e0f0f..f403c4b 100644 --- a/pinaxcon/settings.py +++ b/pinaxcon/settings.py @@ -256,6 +256,9 @@ PINAX_STRIPE_PUBLIC_KEY = os.environ.get("STRIPE_PUBLIC_KEY", "your test public PINAX_STRIPE_SECRET_KEY = os.environ.get("STRIPE_SECRET_KEY", "your test secret key") PINAX_STRIPE_SEND_EMAIL_RECEIPTS = False +SYMPOSION_SPEAKER_MODEL = "pinaxcon.proposals.models.ConferenceSpeaker" +SYMPOSION_SPEAKER_FORM = "pinaxcon.proposals.forms.ConferenceSpeakerForm" + # Registrasion Attendee profile model ATTENDEE_PROFILE_MODEL = "pinaxcon.registrasion.models.AttendeeProfile" # Registrasion attendee profile form -- must act on ATTENDEE_PROFILE_FORM diff --git a/requirements/base.txt b/requirements/base.txt index 2fb7510..b182309 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -13,6 +13,7 @@ django-sitetree==1.8.0 django-countries==4.6.1 easy-thumbnails==2.4.1 django-timezone-field==2.0 +django-mode-utils==3.0.0 # For testing @@ -21,6 +22,6 @@ coverage==4.0.3 # Registrasion https://github.com/chrisjrn/registrasion/tarball/master#egg=registrasion -https://github.com/pinax/symposion/tarball/ad81810#egg=symposion +https://github.com/chrisjrn/symposion/tarball/northbaypython#egg=symposion https://github.com/chrisjrn/registrasion-stripe/tarball/master#egg=registrasion-stripe https://github.com/chrisjrn/symposion-bootstrap-templates/tarball/master#egg=symposion-bootstrap-templates