first pass at merging pycon's sponsorship app with more basic symposion one
This commit is contained in:
parent
32c8c0ce50
commit
3ffcc4da7c
6 changed files with 305 additions and 8 deletions
|
@ -1,7 +1,69 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from symposion.sponsorship.models import SponsorLevel, Sponsor
|
||||
from symposion.sponsorship.models import SponsorLevel, Sponsor, Benefit, BenefitLevel, SponsorBenefit
|
||||
|
||||
|
||||
admin.site.register(SponsorLevel)
|
||||
admin.site.register(Sponsor, list_display=("name", "level", "added", "active"), list_filter = ("level", ))
|
||||
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)
|
||||
|
|
72
symposion/sponsorship/forms.py
Normal file
72
symposion/sponsorship/forms.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
from django import forms
|
||||
from django.forms.models import inlineformset_factory, BaseInlineFormSet
|
||||
|
||||
from django.contrib.admin.widgets import AdminFileWidget
|
||||
|
||||
from symposion.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"]
|
||||
)
|
7
symposion/sponsorship/managers.py
Normal file
7
symposion/sponsorship/managers.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class SponsorManager(models.Manager):
|
||||
|
||||
def active(self):
|
||||
return self.get_query_set().filter(active=True).order_by("level")
|
|
@ -1,17 +1,24 @@
|
|||
import datetime
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from symposion.conference.models import Conference
|
||||
|
||||
from symposion.sponsorship.managers import SponsorManager
|
||||
|
||||
|
||||
class SponsorLevel(models.Model):
|
||||
|
||||
conference = models.ForeignKey(Conference, verbose_name=_("conference"))
|
||||
name = models.CharField(_("name"), max_length=100)
|
||||
order = models.IntegerField(_("order"), default=0)
|
||||
description = models.TextField(_("description"), blank=True)
|
||||
cost = models.PositiveIntegerField(_("cost"))
|
||||
description = models.TextField(_("description"), blank=True, help_text=_("This is private."))
|
||||
|
||||
class Meta:
|
||||
ordering = ["conference", "order"]
|
||||
|
@ -27,19 +34,101 @@ class SponsorLevel(models.Model):
|
|||
|
||||
class Sponsor(models.Model):
|
||||
|
||||
name = models.CharField(_("name"), max_length=100)
|
||||
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 e\u2011mail"))
|
||||
logo = models.ImageField(_("logo"), upload_to="sponsor_logos/")
|
||||
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")
|
||||
|
||||
|
||||
BENEFIT_TYPE_CHOICES = [
|
||||
("text", "Text"),
|
||||
("file", "File"),
|
||||
("weblogo", "Web Logo"),
|
||||
("simple", "Simple")
|
||||
]
|
||||
|
||||
|
||||
class Benefit(models.Model):
|
||||
|
||||
name = models.CharField(_("name"), max_length=100)
|
||||
description = models.TextField(_("description"), blank=True)
|
||||
type = models.CharField(_("type"), choices=BENEFIT_TYPE_CHOICES, 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"))
|
||||
|
||||
# default limits for this benefit at given 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 []
|
||||
|
|
9
symposion/sponsorship/urls.py
Normal file
9
symposion/sponsorship/urls.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from django.conf.urls.defaults import patterns, url
|
||||
from django.views.generic.simple import direct_to_template
|
||||
|
||||
|
||||
urlpatterns = patterns("symposion.sponsorship.views",
|
||||
url(r"^$", direct_to_template, {"template": "sponsorship/list.html"}, name="sponsor_list"),
|
||||
url(r"^apply/$", "sponsor_apply", name="sponsor_apply"),
|
||||
url(r"^(?P<pk>\d+)/$", "sponsor_detail", name="sponsor_detail"),
|
||||
)
|
58
symposion/sponsorship/views.py
Normal file
58
symposion/sponsorship/views.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
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.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))
|
Loading…
Reference in a new issue