temporarily include pycon module containing advanced sponsorship app
This commit is contained in:
		
							parent
							
								
									7596922f4d
								
							
						
					
					
						commit
						6d9c1c2e5f
					
				
					 18 changed files with 939 additions and 0 deletions
				
			
		
							
								
								
									
										0
									
								
								pycon/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								pycon/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										8
									
								
								pycon/admin.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								pycon/admin.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
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)
 | 
			
		||||
							
								
								
									
										84
									
								
								pycon/forms.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								pycon/forms.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
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(),
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										68
									
								
								pycon/models.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								pycon/models.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,68 @@
 | 
			
		|||
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"
 | 
			
		||||
							
								
								
									
										5
									
								
								pycon/sponsorship/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								pycon/sponsorship/__init__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
SPONSOR_COORDINATORS = "sponsor-coordinators"
 | 
			
		||||
 | 
			
		||||
AUTH_GROUPS = [
 | 
			
		||||
    SPONSOR_COORDINATORS
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										69
									
								
								pycon/sponsorship/admin.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								pycon/sponsorship/admin.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
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)
 | 
			
		||||
							
								
								
									
										72
									
								
								pycon/sponsorship/forms.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								pycon/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 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"]
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										0
									
								
								pycon/sponsorship/management/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								pycon/sponsorship/management/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								pycon/sponsorship/management/commands/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								pycon/sponsorship/management/commands/__init__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
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)
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,80 @@
 | 
			
		|||
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"
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
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()
 | 
			
		||||
							
								
								
									
										38
									
								
								pycon/sponsorship/managers.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								pycon/sponsorship/managers.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
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
 | 
			
		||||
							
								
								
									
										266
									
								
								pycon/sponsorship/models.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								pycon/sponsorship/models.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,266 @@
 | 
			
		|||
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)
 | 
			
		||||
							
								
								
									
										0
									
								
								pycon/sponsorship/templatetags/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								pycon/sponsorship/templatetags/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										74
									
								
								pycon/sponsorship/templatetags/sponsorship_tags.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								pycon/sponsorship/templatetags/sponsorship_tags.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
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)
 | 
			
		||||
							
								
								
									
										10
									
								
								pycon/sponsorship/urls.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								pycon/sponsorship/urls.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
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"),
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										115
									
								
								pycon/sponsorship/views.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								pycon/sponsorship/views.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,115 @@
 | 
			
		|||
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…
	
	Add table
		
		Reference in a new issue