Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: pinax/symposion
...
head fork: pinax/symposion
  • 10 commits
  • 36 files changed
  • 0 commit comments
  • 1 contributor
Showing with 221 additions and 1,076 deletions.
  1. 0  pycon/__init__.py
  2. +0 −8 pycon/admin.py
  3. +0 −84 pycon/forms.py
  4. +0 −68 pycon/models.py
  5. +0 −5 pycon/sponsorship/__init__.py
  6. +0 −69 pycon/sponsorship/admin.py
  7. +0 −72 pycon/sponsorship/forms.py
  8. 0  pycon/sponsorship/management/__init__.py
  9. 0  pycon/sponsorship/management/commands/__init__.py
  10. +0 −12 pycon/sponsorship/management/commands/create_sponsors_groups.py
  11. +0 −80 pycon/sponsorship/management/commands/export_sponsors_data.py
  12. +0 −38 pycon/sponsorship/management/commands/reset_sponsor_benefits.py
  13. +0 −38 pycon/sponsorship/managers.py
  14. +0 −266 pycon/sponsorship/models.py
  15. 0  pycon/sponsorship/templatetags/__init__.py
  16. +0 −74 pycon/sponsorship/templatetags/sponsorship_tags.py
  17. +0 −10 pycon/sponsorship/urls.py
  18. +0 −115 pycon/sponsorship/views.py
  19. +1 −1  symposion/speakers/admin.py
  20. +0 −2  symposion/speakers/fixture_gen.py
  21. +0 −21 symposion/speakers/forms.py
  22. +0 −11 symposion/speakers/models.py
  23. +2 −2 symposion/sponsorship/views.py
  24. +1 −1  symposion_project/static/symposion/css/symposion.css
  25. +90 −2 symposion_project/static/symposion/less/custom.less
  26. +109 −90 symposion_project/templates/dashboard.html
  27. +5 −0 symposion_project/templates/proposals/base.html
  28. +1 −1  symposion_project/templates/proposals/document_create.html
  29. +1 −1  symposion_project/templates/proposals/proposal_cancel.html
  30. +1 −1  symposion_project/templates/proposals/proposal_speaker_manage.html
  31. +1 −1  symposion_project/templates/proposals/proposal_submit.html
  32. +1 −1  symposion_project/templates/proposals/proposal_submit_kind.html
  33. +5 −0 symposion_project/templates/site_base_onecolumn.html
  34. +1 −0  symposion_project/templates/speakers/base.html
  35. +1 −1  symposion_project/templates/speakers/speaker_create.html
  36. +1 −1  symposion_project/templates/speakers/speaker_edit.html
View
0  pycon/__init__.py
No changes.
View
8 pycon/admin.py
@@ -1,8 +0,0 @@
-from django.contrib import admin
-
-from pycon.models import PyConProposalCategory, PyConTalkProposal, PyConTutorialProposal, PyConPosterProposal
-
-admin.site.register(PyConProposalCategory)
-admin.site.register(PyConTalkProposal)
-admin.site.register(PyConTutorialProposal)
-admin.site.register(PyConPosterProposal)
View
84 pycon/forms.py
@@ -1,84 +0,0 @@
-from django import forms
-
-from markitup.widgets import MarkItUpWidget
-
-from pycon.models import PyConProposalCategory, PyConTalkProposal, PyConTutorialProposal, PyConPosterProposal
-
-
-class PyConProposalForm(forms.ModelForm):
-
- def __init__(self, *args, **kwargs):
- super(PyConProposalForm, self).__init__(*args, **kwargs)
- self.fields["category"] = forms.ModelChoiceField(
- queryset = PyConProposalCategory.objects.order_by("name")
- )
-
- def clean_description(self):
- value = self.cleaned_data["description"]
- if len(value) > 400:
- raise forms.ValidationError(
- u"The description must be less than 400 characters"
- )
- return value
-
-
-class PyConTalkProposalForm(PyConProposalForm):
-
- class Meta:
- model = PyConTalkProposal
- fields = [
- "title",
- "category",
- "audience_level",
- "extreme",
- "duration",
- "description",
- "abstract",
- "additional_notes",
- "recording_release",
- ]
- widgets = {
- "abstract": MarkItUpWidget(),
- "additional_notes": MarkItUpWidget(),
- }
-
-
-class PyConTutorialProposalForm(PyConProposalForm):
-
- class Meta:
- model = PyConTutorialProposal
- fields = [
- "title",
- "category",
- "audience_level",
- "description",
- "abstract",
- "additional_notes",
- "recording_release",
-
- ]
- widgets = {
- "abstract": MarkItUpWidget(),
- "additional_notes": MarkItUpWidget(),
- }
-
-
-class PyConPosterProposalForm(PyConProposalForm):
-
- class Meta:
- model = PyConPosterProposal
- fields = [
- "title",
- "category",
- "audience_level",
- "description",
- "abstract",
- "additional_notes",
- "recording_release",
-
- ]
- widgets = {
- "abstract": MarkItUpWidget(),
- "additional_notes": MarkItUpWidget(),
- }
-
View
68 pycon/models.py
@@ -1,68 +0,0 @@
-from django.db import models
-
-from symposion.proposals.models import ProposalBase
-
-
-class PyConProposalCategory(models.Model):
-
- name = models.CharField(max_length=100)
- slug = models.SlugField()
-
- def __unicode__(self):
- return self.name
-
- class Meta:
- verbose_name = "PyCon proposal category"
- verbose_name_plural = "PyCon proposal categories"
-
-
-class PyConProposal(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"),
- ]
-
- category = models.ForeignKey(PyConProposalCategory)
- audience_level = models.IntegerField(choices=AUDIENCE_LEVELS)
-
- recording_release = models.BooleanField(
- default=True,
- help_text="By submitting your talk proposal, you agree to give permission to the Python Software Foundation to record, edit, and release audio and/or video of your presentation. If you do not agree to this, please uncheck this box. See <a href='https://us.pycon.org/2013/speaking/recording/' target='_blank'>PyCon 2013 Recording Release</a> for details."
- )
-
- class Meta:
- abstract = True
-
-
-class PyConTalkProposal(PyConProposal):
-
- DURATION_CHOICES = [
- (0, "No preference"),
- (1, "I prefer a 30 minute slot"),
- (2, "I prefer a 45 minute slot"),
- ]
-
- extreme = models.BooleanField(
- default=False,
- help_text="'Extreme' talks are advanced talks with little or no introductory material. See <a href='http://us.pycon.org/2013/speaker/extreme/' target='_blank'>Extreme Talks</a> for details."
- )
- duration = models.IntegerField(choices=DURATION_CHOICES)
-
- class Meta:
- verbose_name = "PyCon talk proposal"
-
-
-class PyConTutorialProposal(PyConProposal):
- class Meta:
- verbose_name = "PyCon tutorial proposal"
-
-
-class PyConPosterProposal(PyConProposal):
- class Meta:
- verbose_name = "PyCon poster proposal"
View
5 pycon/sponsorship/__init__.py
@@ -1,5 +0,0 @@
-SPONSOR_COORDINATORS = "sponsor-coordinators"
-
-AUTH_GROUPS = [
- SPONSOR_COORDINATORS
-]
View
69 pycon/sponsorship/admin.py
@@ -1,69 +0,0 @@
-from django.contrib import admin
-
-from pycon.sponsorship.models import SponsorLevel, Sponsor, Benefit, BenefitLevel, SponsorBenefit
-
-
-class BenefitLevelInline(admin.TabularInline):
- model = BenefitLevel
- extra = 0
-
-
-class SponsorBenefitInline(admin.StackedInline):
- model = SponsorBenefit
- extra = 0
- fieldsets = [
- (None, {
- "fields": [
- ("benefit", "active"),
- ("max_words", "other_limits"),
- "text",
- "upload",
- ]
- })
- ]
-
-
-class SponsorAdmin(admin.ModelAdmin):
-
- save_on_top = True
- fieldsets = [
- (None, {
- "fields": [
- ("name", "applicant"),
- ("level", "active"),
- "external_url",
- "annotation",
- ("contact_name", "contact_email")
- ]
- }),
- ("Metadata", {
- "fields": ["added"],
- "classes": ["collapse"]
- })
- ]
- inlines = [SponsorBenefitInline]
-
- def get_form(self, *args, **kwargs):
- # @@@ kinda ugly but using choices= on NullBooleanField is broken
- form = super(SponsorAdmin, self).get_form(*args, **kwargs)
- form.base_fields["active"].widget.choices = [
- (u"1", "unreviewed"),
- (u"2", "approved"),
- (u"3", "rejected")
- ]
- return form
-
-
-class BenefitAdmin(admin.ModelAdmin):
-
- inlines = [BenefitLevelInline]
-
-
-class SponsorLevelAdmin(admin.ModelAdmin):
-
- inlines = [BenefitLevelInline]
-
-
-admin.site.register(SponsorLevel, SponsorLevelAdmin)
-admin.site.register(Sponsor, SponsorAdmin)
-admin.site.register(Benefit, BenefitAdmin)
View
72 pycon/sponsorship/forms.py
@@ -1,72 +0,0 @@
-from django import forms
-from django.forms.models import inlineformset_factory, BaseInlineFormSet
-
-from django.contrib.admin.widgets import AdminFileWidget
-
-from pycon.sponsorship.models import Sponsor, SponsorBenefit
-
-
-class SponsorApplicationForm(forms.ModelForm):
- def __init__(self, *args, **kwargs):
- self.user = kwargs.pop("user")
- kwargs.update({
- "initial": {
- "contact_name": self.user.get_full_name,
- "contact_email": self.user.email,
- }
- })
- super(SponsorApplicationForm, self).__init__(*args, **kwargs)
-
- class Meta:
- model = Sponsor
- fields = ["name", "contact_name", "contact_email", "level"]
-
- def save(self, commit=True):
- obj = super(SponsorApplicationForm, self).save(commit=False)
- obj.applicant = self.user
- if commit:
- obj.save()
- return obj
-
-
-class SponsorDetailsForm(forms.ModelForm):
- class Meta:
- model = Sponsor
- fields = [
- "name",
- "external_url",
- "contact_name",
- "contact_email"
- ]
-
-
-class SponsorBenefitsInlineFormSet(BaseInlineFormSet):
-
- def _construct_form(self, i, **kwargs):
- form = super(SponsorBenefitsInlineFormSet, self)._construct_form(i, **kwargs)
-
- # only include the relevant data fields for this benefit type
- fields = form.instance.data_fields()
- form.fields = dict((k, v) for (k, v) in form.fields.items() if k in fields + ["id"])
-
- for field in fields:
- # don't need a label, the form template will label it with the benefit name
- form.fields[field].label = ""
-
- # provide word limit as help_text
- if form.instance.benefit.type == "text" and form.instance.max_words:
- form.fields[field].help_text = u"maximum %s words" % form.instance.max_words
-
- # use admin file widget that shows currently uploaded file
- if field == "upload":
- form.fields[field].widget = AdminFileWidget()
-
- return form
-
-
-SponsorBenefitsFormSet = inlineformset_factory(
- Sponsor, SponsorBenefit,
- formset=SponsorBenefitsInlineFormSet,
- can_delete=False, extra=0,
- fields=["text", "upload"]
-)
View
0  pycon/sponsorship/management/__init__.py
No changes.
View
0  pycon/sponsorship/management/commands/__init__.py
No changes.
View
12 pycon/sponsorship/management/commands/create_sponsors_groups.py
@@ -1,12 +0,0 @@
-from django.core.management.base import BaseCommand
-
-from django.contrib.auth.models import Group
-
-from pycon.sponsorship import AUTH_GROUPS
-
-
-class Command(BaseCommand):
-
- def handle(self, *args, **options):
- for group in AUTH_GROUPS:
- Group.objects.get_or_create(name=group)
View
80 pycon/sponsorship/management/commands/export_sponsors_data.py
@@ -1,80 +0,0 @@
-import csv
-import os
-import shutil
-import zipfile
-
-from contextlib import closing
-
-from django.core.management.base import BaseCommand, CommandError
-from django.template.defaultfilters import slugify
-
-from pycon.sponsorship.models import Sponsor
-
-
-def zipdir(basedir, archivename):
- assert os.path.isdir(basedir)
- with closing(zipfile.ZipFile(archivename, "w", zipfile.ZIP_DEFLATED)) as z:
- for root, dirs, files in os.walk(basedir):
- #NOTE: ignore empty directories
- for fn in files:
- absfn = os.path.join(root, fn)
- zfn = absfn[len(basedir)+len(os.sep):] #XXX: relative path
- z.write(absfn, zfn)
-
-
-class Command(BaseCommand):
-
- def handle(self, *args, **options):
- try:
- os.makedirs(os.path.join(os.getcwd(), "build"))
- except:
- pass
-
- csv_file = csv.writer(
- open(os.path.join(os.getcwd(), "build", "sponsors.csv"), "wb")
- )
- csv_file.writerow(["Name", "URL", "Level", "Description"])
-
- for sponsor in Sponsor.objects.all():
- path = os.path.join(os.getcwd(), "build", slugify(sponsor.name))
- try:
- os.makedirs(path)
- except:
- pass
-
- data = {
- "name": sponsor.name,
- "url": sponsor.external_url,
- "level": sponsor.level.name,
- "description": "",
- }
- for sponsor_benefit in sponsor.sponsor_benefits.all():
- if sponsor_benefit.benefit_id == 2:
- data["description"] = sponsor_benefit.text
- if sponsor_benefit.benefit_id == 1:
- if sponsor_benefit.upload:
- data["ad"] = sponsor_benefit.upload.path
- if sponsor_benefit.benefit_id == 7:
- if sponsor_benefit.upload:
- data["logo"] = sponsor_benefit.upload.path
-
- if "ad" in data:
- ad_path = data.pop("ad")
- shutil.copy(ad_path, path)
- if "logo" in data:
- logo_path = data.pop("logo")
- shutil.copy(logo_path, path)
-
- csv_file.writerow([
- data["name"].encode("utf-8"),
- data["url"].encode("utf-8"),
- data["level"].encode("utf-8"),
- data["description"].encode("utf-8")
- ])
-
- zipdir(
- os.path.join(
- os.getcwd(), "build"),
- os.path.join(os.getcwd(), "sponsors.zip"
- )
- )
View
38 pycon/sponsorship/management/commands/reset_sponsor_benefits.py
@@ -1,38 +0,0 @@
-from django.core.management.base import BaseCommand
-
-from django.contrib.auth.models import Group
-
-from pycon.sponsorship.models import Sponsor, SponsorBenefit
-
-
-class Command(BaseCommand):
-
- def handle(self, *args, **options):
- for sponsor in Sponsor.objects.all():
- level = None
- try:
- level = sponsor.level
- except SponsorLevel.DoesNotExist:
- pass
- if level:
- for benefit_level in level.benefit_levels.all():
- # Create all needed benefits if they don't exist already
- sponsor_benefit, created = SponsorBenefit.objects.get_or_create(
- sponsor=sponsor, benefit=benefit_level.benefit)
-
- if created:
- print "created", sponsor_benefit, "for", sponsor
-
- # and set to default limits for this level.
- sponsor_benefit.max_words = benefit_level.max_words
- sponsor_benefit.other_limits = benefit_level.other_limits
-
- # and set to active
- sponsor_benefit.active = True
-
- # @@@ We don't call sponsor_benefit.clean here. This means
- # that if the sponsorship level for a sponsor is adjusted
- # downwards, an existing too-long text entry can remain,
- # and won't raise a validation error until it's next
- # edited.
- sponsor_benefit.save()
View
38 pycon/sponsorship/managers.py
@@ -1,38 +0,0 @@
-from django.db import models
-
-
-class SponsorManager(models.Manager):
-
- def active(self):
- return self.get_query_set().filter(active=True).order_by("level")
-
- def with_weblogo(self):
- queryset = self.raw("""
- SELECT DISTINCT
- "sponsorship_sponsor"."id",
- "sponsorship_sponsor"."applicant_id",
- "sponsorship_sponsor"."name",
- "sponsorship_sponsor"."external_url",
- "sponsorship_sponsor"."annotation",
- "sponsorship_sponsor"."contact_name",
- "sponsorship_sponsor"."contact_email",
- "sponsorship_sponsor"."level_id",
- "sponsorship_sponsor"."added",
- "sponsorship_sponsor"."active",
- "sponsorship_sponsorlevel"."order"
- FROM
- "sponsorship_sponsor"
- INNER JOIN
- "sponsorship_sponsorbenefit" ON ("sponsorship_sponsor"."id" = "sponsorship_sponsorbenefit"."sponsor_id")
- INNER JOIN
- "sponsorship_benefit" ON ("sponsorship_sponsorbenefit"."benefit_id" = "sponsorship_benefit"."id")
- LEFT OUTER JOIN
- "sponsorship_sponsorlevel" ON ("sponsorship_sponsor"."level_id" = "sponsorship_sponsorlevel"."id")
- WHERE (
- "sponsorship_sponsor"."active" = 't' AND
- "sponsorship_benefit"."type" = 'weblogo' AND
- "sponsorship_sponsorbenefit"."upload" != ''
- )
- ORDER BY "sponsorship_sponsorlevel"."order" ASC, "sponsorship_sponsor"."added" ASC
- """)
- return queryset
View
266 pycon/sponsorship/models.py
@@ -1,266 +0,0 @@
-import datetime
-
-from django.core.exceptions import ValidationError
-from django.core.urlresolvers import reverse
-from django.db import models
-from django.db.models.signals import post_init, post_save
-from django.utils.translation import ugettext_lazy as _
-
-from django.contrib.auth.models import User
-
-from symposion.conference.models import Conference
-
-from pycon.sponsorship import SPONSOR_COORDINATORS
-from pycon.sponsorship.managers import SponsorManager
-# from symposion.utils.mail import send_email
-
-
-class SponsorLevel(models.Model):
-
- conference = models.ForeignKey(Conference, verbose_name=_("conference"))
- name = models.CharField(_("name"), max_length=100)
- order = models.IntegerField(_("order"), default=0)
- cost = models.PositiveIntegerField(_("cost"))
- description = models.TextField(_("description"), blank=True, help_text=_("This is private."))
-
- class Meta:
- ordering = ["conference", "order"]
- verbose_name = _("sponsor level")
- verbose_name_plural = _("sponsor levels")
-
- def __unicode__(self):
- return u"%s %s" % (self.conference, self.name)
-
- def sponsors(self):
- return self.sponsor_set.filter(active=True).order_by("added")
-
-
-class Sponsor(models.Model):
-
- applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("applicant"), null=True)
-
- name = models.CharField(_("Sponsor Name"), max_length=100)
- external_url = models.URLField(_("external URL"))
- annotation = models.TextField(_("annotation"), blank=True)
- contact_name = models.CharField(_("Contact Name"), max_length=100)
- contact_email = models.EmailField(_(u"Contact Email"))
- level = models.ForeignKey(SponsorLevel, verbose_name=_("level"))
- added = models.DateTimeField(_("added"), default=datetime.datetime.now)
- active = models.BooleanField(_("active"), default=False)
-
- # Denormalization (this assumes only one logo)
- sponsor_logo = models.ForeignKey("SponsorBenefit", related_name="+", null=True, blank=True, editable=False)
-
- objects = SponsorManager()
-
- def __unicode__(self):
- return self.name
-
- class Meta:
- verbose_name = _("sponsor")
- verbose_name_plural = _("sponsors")
-
- def get_absolute_url(self):
- if self.active:
- return reverse("sponsor_detail", kwargs={"pk": self.pk})
- return reverse("sponsor_list")
-
- @property
- def website_logo_url(self):
- if not hasattr(self, "_website_logo_url"):
- self._website_logo_url = None
- benefits = self.sponsor_benefits.filter(benefit__type="weblogo", upload__isnull=False)
- if benefits.exists():
- # @@@ smarter handling of multiple weblogo benefits?
- # shouldn't happen
- if benefits[0].upload:
- self._website_logo_url = benefits[0].upload.url
- return self._website_logo_url
-
- @property
- def listing_text(self):
- if not hasattr(self, "_listing_text"):
- self._listing_text = None
- benefits = self.sponsor_benefits.filter(benefit__id=7)
- if benefits.count():
- self._listing_text = benefits[0].text
- return self._listing_text
-
- @property
- def joblisting_text(self):
- if not hasattr(self, "_joblisting_text"):
- self._joblisting_text = None
- benefits = self.sponsor_benefits.filter(benefit__id=21)
- if benefits.count():
- self._joblisting_text = benefits[0].text
- return self._joblisting_text
-
- @property
- def website_logo(self):
- if self.sponsor_logo is None:
- benefits = self.sponsor_benefits.filter(benefit__type="weblogo", upload__isnull=False)[:1]
- if benefits.count():
- if benefits[0].upload:
- self.sponsor_logo = benefits[0]
- self.save()
- return self.sponsor_logo.upload
-
- def reset_benefits(self):
- """
- Reset all benefits for this sponsor to the defaults for their
- sponsorship level.
- """
- level = None
-
- try:
- level = self.level
- except SponsorLevel.DoesNotExist:
- pass
-
- allowed_benefits = []
- if level:
- for benefit_level in level.benefit_levels.all():
- # Create all needed benefits if they don't exist already
- sponsor_benefit, created = SponsorBenefit.objects.get_or_create(
- sponsor=self, benefit=benefit_level.benefit)
-
- # and set to default limits for this level.
- sponsor_benefit.max_words = benefit_level.max_words
- sponsor_benefit.other_limits = benefit_level.other_limits
-
- # and set to active
- sponsor_benefit.active = True
-
- # @@@ We don't call sponsor_benefit.clean here. This means
- # that if the sponsorship level for a sponsor is adjusted
- # downwards, an existing too-long text entry can remain,
- # and won't raise a validation error until it's next
- # edited.
- sponsor_benefit.save()
-
- allowed_benefits.append(sponsor_benefit.pk)
-
- # Any remaining sponsor benefits that don't normally belong to
- # this level are set to inactive
- self.sponsor_benefits.exclude(pk__in=allowed_benefits).update(active=False, max_words=None, other_limits="")
-
- # @@@ should this just be done centrally?
- def send_coordinator_emails(self):
- for user in User.objects.filter(groups__name=SPONSOR_COORDINATORS):
- send_email(
- [user.email], "sponsor_signup",
- context = {"sponsor": self}
- )
-
-
-def _store_initial_level(sender, instance, **kwargs):
- if instance:
- instance._initial_level_id = instance.level_id
-post_init.connect(_store_initial_level, sender=Sponsor)
-
-
-def _check_level_change(sender, instance, created, **kwargs):
- if instance and (created or instance.level_id != instance._initial_level_id):
- instance.reset_benefits()
-post_save.connect(_check_level_change, sender=Sponsor)
-
-
-def _send_sponsor_notification_emails(sender, instance, created, **kwargs):
- if instance and created:
- instance.send_coordinator_emails()
-post_save.connect(_send_sponsor_notification_emails, sender=Sponsor)
-
-
-class Benefit(models.Model):
-
- name = models.CharField(_("name"), max_length=100)
- description = models.TextField(_("description"), blank=True)
- type = models.CharField(
- _("type"),
- choices=[
- ("text", "Text"),
- ("file", "File"),
- ("weblogo", "Web Logo"),
- ("simple", "Simple")
- ],
- max_length=10,
- default="simple"
- )
-
- def __unicode__(self):
- return self.name
-
-
-class BenefitLevel(models.Model):
-
- benefit = models.ForeignKey(
- Benefit,
- related_name="benefit_levels",
- verbose_name=_("benefit")
- )
- level = models.ForeignKey(
- SponsorLevel,
- related_name="benefit_levels",
- verbose_name=_("level")
- )
- max_words = models.PositiveIntegerField(_("max words"), blank=True, null=True)
- other_limits = models.CharField(_("other limits"), max_length=200, blank=True)
-
- class Meta:
- ordering = ["level"]
-
- def __unicode__(self):
- return u"%s - %s" % (self.level, self.benefit)
-
-
-class SponsorBenefit(models.Model):
-
- sponsor = models.ForeignKey(
- Sponsor,
- related_name="sponsor_benefits",
- verbose_name=_("sponsor")
- )
- benefit = models.ForeignKey(Benefit,
- related_name="sponsor_benefits",
- verbose_name=_("benefit")
- )
- active = models.BooleanField(default=True)
-
- # Limits: will initially be set to defaults from corresponding BenefitLevel
- max_words = models.PositiveIntegerField(_("max words"), blank=True, null=True)
- other_limits = models.CharField(_("other limits"), max_length=200, blank=True)
-
- # Data: zero or one of these fields will be used, depending on the
- # type of the Benefit (text, file, or simple)
- text = models.TextField(_("text"), blank=True)
- upload = models.FileField(_("file"), blank=True, upload_to="sponsor_files")
-
- class Meta:
- ordering = ['-active']
-
- def __unicode__(self):
- return u"%s - %s" % (self.sponsor, self.benefit)
-
- def clean(self):
- if self.max_words and len(self.text.split()) > self.max_words:
- raise ValidationError("Sponsorship level only allows for %s words." % self.max_words)
-
- def data_fields(self):
- """
- Return list of data field names which should be editable for
- this ``SponsorBenefit``, depending on its ``Benefit`` type.
- """
- if self.benefit.type == "file" or self.benefit.type == "weblogo":
- return ["upload"]
- elif self.benefit.type == "text":
- return ["text"]
- return []
-
-
-def _denorm_weblogo(sender, instance, created, **kwargs):
- if instance:
- if instance.benefit.type == "weblogo" and instance.upload:
- sponsor = instance.sponsor
- sponsor.sponsor_logo = instance
- sponsor.save()
-post_save.connect(_denorm_weblogo, sender=SponsorBenefit)
View
0  pycon/sponsorship/templatetags/__init__.py
No changes.
View
74 pycon/sponsorship/templatetags/sponsorship_tags.py
@@ -1,74 +0,0 @@
-from django import template
-
-from symposion.conference.models import current_conference
-from pycon.sponsorship.models import Sponsor, SponsorLevel
-
-
-register = template.Library()
-
-
-class SponsorsNode(template.Node):
-
- @classmethod
- def handle_token(cls, parser, token):
- bits = token.split_contents()
- if len(bits) == 3 and bits[1] == "as":
- return cls(bits[2])
- elif len(bits) == 4 and bits[2] == "as":
- return cls(bits[3], bits[1])
- else:
- raise template.TemplateSyntaxError("%r takes 'as var' or 'level as var'" % bits[0])
-
- def __init__(self, context_var, level=None):
- if level:
- self.level = template.Variable(level)
- else:
- self.level = None
- self.context_var = context_var
-
- def render(self, context):
- conference = current_conference()
- if self.level:
- level = self.level.resolve(context)
- queryset = Sponsor.objects.filter(level__conference = conference, level__name__iexact = level, active = True).order_by("added")
- else:
- queryset = Sponsor.objects.filter(level__conference = conference, active = True).order_by("level__order", "added")
- context[self.context_var] = queryset
- return u""
-
-
-class SponsorLevelNode(template.Node):
-
- @classmethod
- def handle_token(cls, parser, token):
- bits = token.split_contents()
- if len(bits) == 3 and bits[1] == "as":
- return cls(bits[2])
- else:
- raise template.TemplateSyntaxError("%r takes 'as var'" % bits[0])
-
- def __init__(self, context_var):
- self.context_var = context_var
-
- def render(self, context):
- conference = current_conference()
- context[self.context_var] = SponsorLevel.objects.filter(conference=conference)
- return u""
-
-
-@register.tag
-def sponsors(parser, token):
- """
- {% sponsors as all_sponsors %}
- or
- {% sponsors "gold" as gold_sponsors %}
- """
- return SponsorsNode.handle_token(parser, token)
-
-
-@register.tag
-def sponsor_levels(parser, token):
- """
- {% sponsor_levels as levels %}
- """
- return SponsorLevelNode.handle_token(parser, token)
View
10 pycon/sponsorship/urls.py
@@ -1,10 +0,0 @@
-from django.conf.urls.defaults import patterns, url
-from django.views.generic.simple import direct_to_template
-
-
-urlpatterns = patterns("pycon.sponsorship.views",
- url(r"^$", direct_to_template, {"template": "sponsorship/list.html"}, name="sponsor_list"),
- # url(r"^jobs/$", direct_to_template, {"template": "sponsors/jobs.html"}, name="sponsor_jobs"),
- url(r"^apply/$", "sponsor_apply", name="sponsor_apply"),
- url(r"^(?P<pk>\d+)/$", "sponsor_detail", name="sponsor_detail"),
-)
View
115 pycon/sponsorship/views.py
@@ -1,115 +0,0 @@
-import itertools
-
-from functools import wraps
-
-from django.http import HttpResponse
-from django.shortcuts import render_to_response, redirect, get_object_or_404
-from django.template import RequestContext
-
-from django.contrib import messages
-from django.contrib.admin.views.decorators import staff_member_required
-from django.contrib.auth.decorators import login_required
-
-from pycon.sponsorship.forms import SponsorApplicationForm, SponsorDetailsForm, SponsorBenefitsFormSet
-from pycon.sponsorship.models import Sponsor, SponsorBenefit
-
-
-@login_required
-def sponsor_apply(request):
- if request.method == "POST":
- form = SponsorApplicationForm(request.POST, user=request.user)
- if form.is_valid():
- form.save()
- return redirect("dashboard")
- else:
- form = SponsorApplicationForm(user=request.user)
-
- return render_to_response("sponsorship/apply.html", {
- "form": form,
- }, context_instance=RequestContext(request))
-
-
-@login_required
-def sponsor_detail(request, pk):
- sponsor = get_object_or_404(Sponsor, pk=pk)
-
- if not sponsor.active or sponsor.applicant != request.user:
- return redirect("sponsor_list")
-
- formset_kwargs = {
- "instance": sponsor,
- "queryset": SponsorBenefit.objects.filter(active=True)
- }
-
- if request.method == "POST":
-
- form = SponsorDetailsForm(request.POST, instance=sponsor)
- formset = SponsorBenefitsFormSet(request.POST, request.FILES, **formset_kwargs)
-
- if form.is_valid() and formset.is_valid():
- form.save()
- formset.save()
-
- messages.success(request, "Your sponsorship application has been submitted!")
-
- return redirect(request.path)
- else:
- form = SponsorDetailsForm(instance=sponsor)
- formset = SponsorBenefitsFormSet(**formset_kwargs)
-
- return render_to_response("sponsorship/detail.html", {
- "sponsor": sponsor,
- "form": form,
- "formset": formset,
- }, context_instance=RequestContext(request))
-
-
-@staff_member_required
-def sponsor_export_data(request):
- sponsors = []
- data = ""
-
- for sponsor in Sponsor.objects.order_by("added"):
- d = {
- "name": sponsor.name,
- "url": sponsor.external_url,
- "level": (sponsor.level.order, sponsor.level.name),
- "description": "",
- }
- for sponsor_benefit in sponsor.sponsor_benefits.all():
- if sponsor_benefit.benefit_id == 2:
- d["description"] = sponsor_benefit.text
- sponsors.append(d)
-
- def izip_longest(*args):
- fv = None
- def sentinel(counter=([fv]*(len(args)-1)).pop):
- yield counter()
- iters = [itertools.chain(it, sentinel(), itertools.repeat(fv)) for it in args]
- try:
- for tup in itertools.izip(*iters):
- yield tup
- except IndexError:
- pass
- def pairwise(iterable):
- a, b = itertools.tee(iterable)
- b.next()
- return izip_longest(a, b)
-
- def level_key(s):
- return s["level"]
-
- for level, level_sponsors in itertools.groupby(sorted(sponsors, key=level_key), level_key):
- data += "%s\n" % ("-" * (len(level[1])+4))
- data += "| %s |\n" % level[1]
- data += "%s\n\n" % ("-" * (len(level[1])+4))
- for sponsor, next in pairwise(level_sponsors):
- description = sponsor["description"].strip()
- description = description if description else "-- NO DESCRIPTION FOR THIS SPONSOR --"
- data += "%s\n\n%s" % (sponsor["name"], description)
- if next is not None:
- data += "\n\n%s\n\n" % ("-"*80)
- else:
- data += "\n\n"
-
- return HttpResponse(data, content_type="text/plain;charset=utf-8")
View
2  symposion/speakers/admin.py
@@ -4,6 +4,6 @@
admin.site.register(Speaker,
- list_display = ["name", "email", "twitter_username", "sessions_preference", "created"],
+ list_display = ["name", "email", "created"],
search_fields = ["name"],
)
View
2  symposion/speakers/fixture_gen.py
@@ -15,14 +15,12 @@ def speakers():
user=guido,
name="Guido van Rossum",
biography="I wrote Python, and named it after Monty Python",
- twitter_username="gvanrossum",
)
Speaker.objects.create(
user=matz,
name="Yukihiro Matsumoto",
biography="I wrote Ruby, and named it after the rare gem Ruby, a pun "
"on Perl/pearl.",
- twitter_username="yukihiro_matz"
)
Speaker.objects.create(
user=larry,
View
21 symposion/speakers/forms.py
@@ -7,34 +7,13 @@
class SpeakerForm(forms.ModelForm):
- sessions_preference = forms.ChoiceField(
- widget=forms.RadioSelect(),
- choices=Speaker.SESSION_COUNT_CHOICES,
- required=False,
- help_text="If you've submitted multiple proposals, please let us know if you only want to give one or if you'd like to give two talks."
- )
-
class Meta:
model = Speaker
fields = [
"name",
"biography",
"photo",
- "twitter_username",
- "sessions_preference"
]
widgets = {
"biography": MarkItUpWidget(),
}
-
- def clean_twitter_username(self):
- value = self.cleaned_data["twitter_username"]
- if value.startswith("@"):
- value = value[1:]
- return value
-
- def clean_sessions_preference(self):
- value = self.cleaned_data["sessions_preference"]
- if not value:
- return None
- return int(value)
View
11 symposion/speakers/models.py
@@ -19,11 +19,6 @@ class Speaker(models.Model):
name = models.CharField(max_length=100, help_text="As you would like it to appear in the conference program.")
biography = MarkupField(blank=True, help_text="A little bit about you. Edit using <a href='http://warpedvisions.org/projects/markdown-cheat-sheet/' target='_blank'>Markdown</a>.")
photo = models.ImageField(upload_to="speaker_photos", blank=True)
- twitter_username = models.CharField(
- max_length = 15,
- blank = True,
- help_text = "Your Twitter account"
- )
annotation = models.TextField() # staff only
invite_email = models.CharField(max_length=200, unique=True, null=True, db_index=True)
invite_token = models.CharField(max_length=40, db_index=True)
@@ -31,12 +26,6 @@ class Speaker(models.Model):
default = datetime.datetime.now,
editable = False
)
- sessions_preference = models.IntegerField(
- choices=SESSION_COUNT_CHOICES,
- null=True,
- blank=True,
- help_text="If you've submitted multiple proposals, please let us know if you only want to give one or if you'd like to give two talks. You may submit more than two proposals."
- )
def __unicode__(self):
if self.user:
View
4 symposion/sponsorship/views.py
@@ -4,8 +4,8 @@
from django.contrib import messages
from django.contrib.auth.decorators import login_required
-from pycon.sponsorship.forms import SponsorApplicationForm, SponsorDetailsForm, SponsorBenefitsFormSet
-from pycon.sponsorship.models import Sponsor, SponsorBenefit
+from symposion.sponsorship.forms import SponsorApplicationForm, SponsorDetailsForm, SponsorBenefitsFormSet
+from symposion.sponsorship.models import Sponsor, SponsorBenefit
@login_required
View
2  symposion_project/static/symposion/css/symposion.css
1 addition, 1 deletion not shown
View
92 symposion_project/static/symposion/less/custom.less
@@ -70,11 +70,99 @@ div.box-content .markItUpEditor {
left: -20px;
}
-.widget {
+.dashboard-panel {
position: relative;
clear: both;
width: auto;
margin-bottom: 2em;
overflow: hidden;
-}
+
+ .dashboard-panel-header {
+
+
+ position: relative;
+ height: 40px;
+ line-height: 40px;
+ #gradient > .vertical(@navbarBackgroundHighlight, @navbarBackground);
+ border: 1px solid #D5D5D5;
+ .border-radius(4px 4px 0 0);
+ -webkit-background-clip: padding-box;
+
+ .header-actions {
+ padding-right: 10px;
+ }
+
+ h3 {
+ position: relative;
+ top: 2px;
+ left: 10px;
+ display: inline-block;
+ margin-right: 3em;
+ font-size: 14px;
+ font-weight: 600;
+ color: @grayDark;
+ line-height: 18px;
+ text-shadow: 1px 1px 2px rgba(255,255,255,.5);
+ }
+
+ > [class^="icon-"], > [class*=" icon-"] {
+ display: inline-block;
+ margin-left: 13px;
+ margin-right: -2px;
+ font-size: 16px;
+ color: @grayDark;
+ vertical-align: middle;
+ }
+ }
+
+ .dashboard-panel-content {
+ padding: 40px 15px 15px;
+ border: 1px solid #D5D5D5;
+ .border-radius(5px);
+ .box-shadow(0 1px 1px rgba(0, 0, 0, 0.1));
+
+ h3 {
+ font-size:@baseFontSize + 6;
+ font-weight: 800;
+ line-height: 20px;
+ margin-bottom:20px;
+ }
+
+ .actions {
+ .action {
+ width: 22.50%;
+ display: inline-block;
+ padding: 12px 0;
+ margin: 0 .9% 1em;
+ vertical-align: top;
+ text-decoration: none;
+ background: #F3F3F3;
+ border-radius: 5px;
+ text-align:center;
+ .widget-icon {
+ margin-top: .25em;
+ margin-bottom: .25em;
+ font-size: 32px;
+ color: #888;
+ }
+
+ .widget-label {
+ display: block;
+ font-weight: 400;
+ color: #666;
+ }
+ }
+
+ .action:hover {
+ background: #E8E8E8;
+ }
+ }
+ }
+
+ .dashboard-panel-header + .dashboard-panel-content {
+ border-top: none;
+ padding-top: 20px;
+ .border-radius(0 0 4px 4px);
+ }
+}
View
199 symposion_project/templates/dashboard.html
@@ -8,98 +8,117 @@
{% block body_class %}auth{% endblock %}
{% block body %}
- <h2>{% trans "Dashboard" %}</h2>
-
- <section id="dashboard_speakers" class="dashboard-section well">
- <h3>{% trans "Speaking" %}</h3>
- {% if not user.speaker_profile %}
- <p>To submit a proposal, you must first create a speaker profile.</p>
- <a href="{% url speaker_create %}" class="btn">
- Create a speaker profile
- </a>
-
- {% else %}
- <a href="{% url speaker_edit %}" class="btn">
- Edit your speaker profile
- </a>
-
- <a href="{% url proposal_submit %}" class="btn">
- Submit a new proposal
- </a>
-
- <h4>Your Proposals</h4>
- {% if user.speaker_profile.proposals.exists %}
- <table class="table">
- <tr>
- <th>Title</th>
- <th>Session type</th>
- <th>Status</th>
- <th>Actions</th>
- </tr>
- {% for proposal in user.speaker_profile.proposals.all %}
- {% include "proposals/_proposal_row.html" %}
- {% endfor %}
- </table>
- {% else %}
- <p>No proposals submitted yet.</p>
- {% endif %}
+ <div class="dashboard-panel">
+ <div class="dashboard-panel-header">
+ <i class="icon-bullhorn"></i>
+ <h3>{% trans "Speaking" %}</h3>
+ <div class="pull-right header-actions">
+ {% if not user.speaker_profile %}
+ <a href="{% url speaker_create %}" class="btn">
+ <i class="icon-plus-sign"></i> Create a speaker profile
+ </a>
+ {% else %}
+ <a href="{% url speaker_edit %}" class="btn">
+ <i class="icon-pencil"></i> Edit your speaker profile
+ </a>
+ <a href="{% url proposal_submit %}" class="btn">
+ <i class="icon-plus-sign"></i> Submit a new proposal
+ </a>
+ {% endif %}
+ </div>
+ </div>
- {% associated_proposals as associated_proposals %}
- {% if associated_proposals %}
- <h4>Proposals you have joined as an additional speaker</h4>
- <table class="table">
- <tr>
- <th>Title</th>
- <th>Session type</th>
- <th>Status</th>
- <th>Actions</th>
- </tr>
- {% for proposal in associated_proposals %}
- {% include "proposals/_proposal_row.html" %}
- {% endfor %}
- </table>
- {% endif %}
+ <div class="dashboard-panel-content">
+ {% if not user.speaker_profile %}
+ <p>To submit a proposal, you must first <a href="{% url speaker_create %}">create a speaker profile</a>.</p>
+ {% else %}
+ <h4>Your Proposals</h4>
+ {% if user.speaker_profile.proposals.exists %}
+ <table class="table">
+ <tr>
+ <th>Title</th>
+ <th>Session type</th>
+ <th>Status</th>
+ <th>Actions</th>
+ </tr>
+ {% for proposal in user.speaker_profile.proposals.all %}
+ {% include "proposals/_proposal_row.html" %}
+ {% endfor %}
+ </table>
+ {% else %}
+ <p>No proposals submitted yet.</p>
+ {% endif %}
- {% pending_proposals as pending_proposals %}
- {% if pending_proposals %}
- <h4>Proposals you have been invited to join</h4>
- <table class="table">
- <tr>
- <th>Title</th>
- <th>Session type</th>
- <th>Status</th>
- <th>Actions</th>
- </tr>
- {% for proposal in pending_proposals %}
- {% include "proposals/_pending_proposal_row.html" %}
- {% endfor %}
- </table>
+ {% associated_proposals as associated_proposals %}
+ {% if associated_proposals %}
+ <h4>Proposals you have joined as an additional speaker</h4>
+ <table class="table">
+ <tr>
+ <th>Title</th>
+ <th>Session type</th>
+ <th>Status</th>
+ <th>Actions</th>
+ </tr>
+ {% for proposal in associated_proposals %}
+ {% include "proposals/_proposal_row.html" %}
+ {% endfor %}
+ </table>
+ {% endif %}
+
+ {% pending_proposals as pending_proposals %}
+ {% if pending_proposals %}
+ <h4>Proposals you have been invited to join</h4>
+ <table class="table">
+ <tr>
+ <th>Title</th>
+ <th>Session type</th>
+ <th>Status</th>
+ <th>Actions</th>
+ </tr>
+ {% for proposal in pending_proposals %}
+ {% include "proposals/_pending_proposal_row.html" %}
+ {% endfor %}
+ </table>
+ {% endif %}
{% endif %}
- {% endif %}
- </section>
+ </div>
+ </div>
- <section id="dashboard_sponsorship" class="dashboard-section well">
- <h3>{% trans "Sponsorship" %}</h3>
- {% if not user.sponsorships.exists %}
- <a href="{% url sponsor_apply %}" class="btn">
- Apply to be a sponsor
- </a>
- {% else %}
- <h4>Your Sponsorship</h4>
- <ul>
- {% for sponsorship in user.sponsorships.all %}
- <li>
- {% if sponsorship.active %}
- <a href="{% url sponsor_detail sponsorship.pk %}"><b>{{ sponsorship.name }}</b></a>
- ({{ sponsorship.level }})
- {% else %}
- <b>{{ sponsorship.name }}</b>
- ({{ sponsorship.level }})
- <span class="label label-warning">awaiting approval</span>
- {% endif %}
- </li>
- {% endfor %}
- </ul>
- {% endif %}
- </section>
+ <div class="dashboard-panel">
+ <div class="dashboard-panel-header">
+ <i class="icon-briefcase"></i>
+ <h3>{% trans "Sponsorship" %}</h3>
+ <div class="pull-right header-actions">
+ {% if not user.sponsorships.exists %}
+ <a href="{% url sponsor_apply %}" class="btn">
+ <i class="icon-plus-sign"></i> Apply to be a sponsor
+ </a>
+ {% endif %}
+ </div>
+ </div>
+
+ <div class="dashboard-panel-content">
+ <p>
+ {% if not user.sponsorships.exists %}
+ <p>If you or your organization would be interested in sponsorship opportunities, <a href="{% url sponsor_apply %}">use our online form to apply to be a sponsor</a>.
+ {% else %}
+ <h4>Your Sponsorship</h4>
+ <ul>
+ {% for sponsorship in user.sponsorships.all %}
+ <li>
+ {% if sponsorship.active %}
+ <a href="{% url sponsor_detail sponsorship.pk %}"><b>{{ sponsorship.name }}</b></a>
+ ({{ sponsorship.level }})
+ {% else %}
+ <b>{{ sponsorship.name }}</b>
+ ({{ sponsorship.level }})
+ <span class="label label-warning">awaiting approval</span>
+ {% endif %}
+ </li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+ </p>
+ </div>
+ </div>
{% endblock %}
View
5 symposion_project/templates/proposals/base.html
@@ -0,0 +1,5 @@
+{% extends "site_base_onecolumn.html" %}
+
+{% block body_outer %}
+ {% block body %}{% endblock %}
+{% endblock %}
View
2  symposion_project/templates/proposals/document_create.html
@@ -1,4 +1,4 @@
-{% extends "site_base.html" %}
+{% extends "proposals/base.html" %}
{% load bootstrap_tags %}
View
2  symposion_project/templates/proposals/proposal_cancel.html
@@ -1,4 +1,4 @@
-{% extends "site_base.html" %}
+{% extends "proposals/base.html" %}
{% load bootstrap_tags %}
View
2  symposion_project/templates/proposals/proposal_speaker_manage.html
@@ -1,4 +1,4 @@
-{% extends "site_base.html" %}
+{% extends "proposals/base.html" %}
{% load bootstrap_tags %}
View
2  symposion_project/templates/proposals/proposal_submit.html
@@ -1,4 +1,4 @@
-{% extends "site_base.html" %}
+{% extends "proposals/base.html" %}
{% load boxes_tags %}
{% load i18n %}
View
2  symposion_project/templates/proposals/proposal_submit_kind.html
@@ -1,4 +1,4 @@
-{% extends "site_base.html" %}
+{% extends "proposals/base.html" %}
{% load bootstrap_tags %}
{% load boxes_tags %}
View
5 symposion_project/templates/site_base_onecolumn.html
@@ -0,0 +1,5 @@
+{% extends "site_base.html" %}
+
+{% block body_outer %}
+ {% block body %}{% endblock %}
+{% endblock %}
View
1  symposion_project/templates/speakers/base.html
@@ -0,0 +1 @@
+{% extends "site_base_onecolumn.html" %}
View
2  symposion_project/templates/speakers/speaker_create.html
@@ -1,4 +1,4 @@
-{% extends "site_base.html" %}
+{% extends "speakers/base.html" %}
{% load bootstrap_tags %}
{% load i18n %}
View
2  symposion_project/templates/speakers/speaker_edit.html
@@ -1,4 +1,4 @@
-{% extends "site_base.html" %}
+{% extends "speakers/base.html" %}
{% load bootstrap_tags %}
{% load i18n %}

No commit comments for this range

Something went wrong with that request. Please try again.