remove pycon folder, as we've transplanted sponsors
This commit is contained in:
parent
64fdf5147c
commit
53dfff3315
18 changed files with 0 additions and 939 deletions
|
@ -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)
|
|
@ -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(),
|
||||
}
|
||||
|
|
@ -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"
|
|
@ -1,5 +0,0 @@
|
|||
SPONSOR_COORDINATORS = "sponsor-coordinators"
|
||||
|
||||
AUTH_GROUPS = [
|
||||
SPONSOR_COORDINATORS
|
||||
]
|
|
@ -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)
|
|
@ -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"]
|
||||
)
|
|
@ -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)
|
|
@ -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"
|
||||
)
|
||||
)
|
|
@ -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()
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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"),
|
||||
)
|
|
@ -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")
|
Loading…
Reference in a new issue