class Sponsor(models.Model): applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("applicant"), null=True) name = models.CharField(_("Sponsor Name"), max_length=100) display_url = models.URLField(_("display URL"), blank=True) 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) # Whether things are complete # True = complete, False = incomplate, Null = n/a for this sponsor level web_logo_benefit = models.NullBooleanField( help_text=_(u"Web logo benefit is complete")) print_logo_benefit = models.NullBooleanField( help_text=_(u"Print logo benefit is complete")) print_description_benefit = models.NullBooleanField( help_text=_(u"Print description benefit is complete")) company_description_benefit = models.NullBooleanField( help_text=_(u"Company description benefit is complete")) advertisement_benefit = models.NullBooleanField( help_text=_(u"Advertisement benefit is complete")) objects = SponsorManager() def __unicode__(self): return self.name class Meta: verbose_name = _("sponsor") verbose_name_plural = _("sponsors") ordering = ['name'] def save(self, *args, **kwargs): # Set fields related to benefits being complete for benefit in BENEFITS: field_name = benefit['field_name'] benefit_name = benefit['name'] setattr(self, field_name, self.benefit_is_complete(benefit_name)) super(Sponsor, self).save(*args, **kwargs) def get_absolute_url(self): if self.active: return reverse("sponsor_detail", kwargs={"pk": self.pk}) return reverse("sponsor_list") def get_display_url(self): if self.display_url: return self.display_url else: return self.external_url def render_email(self, text): """Replace special strings in text with values from the sponsor. %%NAME%% --> Sponsor name """ return text.replace("%%NAME%%", self.name) @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=8) 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 benefit_is_complete(self, name): """Return True - benefit is complete, False - benefit is not complete, or None - benefit not applicable for this sponsor's level """ if BenefitLevel.objects.filter(level=self.level, benefit__name=name).exists(): try: benefit = self.sponsor_benefits.get(benefit__name=name) except SponsorBenefit.DoesNotExist: return False else: return benefit.is_complete else: return None # Not an applicable benefit for this sponsor's level
class Sponsor(models.Model): applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("applicant"), null=True) name = models.CharField(_("Sponsor Name"), max_length=100) display_url = models.URLField(_("display URL"), blank=True) 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") def get_display_url(self): if self.display_url: return self.display_url else: return self.external_url @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=8) 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})
class Sponsor(models.Model): applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("applicant"), null=True, on_delete=SET_NULL) name = models.CharField(_("Sponsor Name"), max_length=100) display_url = models.URLField(_( "Link text - text to display on link to sponsor page, if different from the actual link" ), blank=True) external_url = models.URLField(_("Link to sponsor web page")) annotation = models.TextField(_("annotation"), blank=True) contact_name = models.CharField(_("Contact Name"), max_length=100) contact_emails = MultiEmailField( _(u"Contact Emails"), default='', help_text=_(u"Please enter one email address per line.")) contact_phone = models.CharField(_(u"Contact Phone"), max_length=32) contact_address = models.TextField(_(u"Contact Address")) level = models.ForeignKey(SponsorLevel, verbose_name=_("level")) added = models.DateTimeField(_("added"), default=datetime.datetime.now) active = models.BooleanField(_("active"), default=False) approval_time = models.DateTimeField(null=True, blank=True, editable=False) wants_table = models.BooleanField( _("Does your organization want a table at the job fair?"), default=False) wants_booth = models.BooleanField( _("Does your organization want a booth on the expo floor?"), default=False) # Whether things are complete # True = complete, False = incomplate, Null = n/a for this sponsor level print_logo_benefit = models.NullBooleanField( help_text=_(u"Print logo benefit is complete")) advertisement_benefit = models.NullBooleanField( help_text=_(u"Advertisement benefit is complete")) registration_promo_codes = models.CharField(max_length=200, blank=True, default='') booth_number = models.IntegerField(blank=True, null=True, default=None) job_fair_table_number = models.IntegerField(blank=True, null=True, default=None) web_description = models.TextField( _(u"Company description (to show on the web site)"), ) web_logo = models.ImageField( _(u"Company logo (to show on the web site)"), upload_to="sponsor_files", null=True, # This is nullable in case old data doesn't have a web logo # We enforce it on all new or edited sponsors though. ) objects = SponsorManager() def __unicode__(self): return self.name class Meta: verbose_name = _("sponsor") verbose_name_plural = _("sponsors") ordering = ['name'] def save(self, *args, **kwargs): # Set fields related to benefits being complete for benefit in BENEFITS: field_name = benefit['field_name'] benefit_name = benefit['name'] setattr(self, field_name, self.benefit_is_complete(benefit_name)) super(Sponsor, self).save(*args, **kwargs) def get_absolute_url(self): if self.active: return reverse("sponsor_detail", kwargs={"pk": self.pk}) return reverse("sponsor_list") def get_display_url(self): """ Return the text to display on the sponsor's link """ if self.display_url: return self.display_url else: return self.external_url def render_email(self, text): """Replace special strings in text with values from the sponsor. %%NAME%% --> Sponsor name %%REGISTRATION_PROMO_CODES%% --> Registration promo codes, or empty string %%BOOTH_NUMBER%% --> Booth number, or empty string if not set %%JOB_FAIR_TABLE_NUMBER%%" --> Job fair tabl number, or empty string if not set """ text = text.replace("%%NAME%%", self.name) text = text.replace("%%REGISTRATION_PROMO_CODES%%", self.registration_promo_codes) # The next two are numbers, or if not set, None. We don't want to # display "None" :-), but we might want to display "0". booth = str(self.booth_number) if self.booth_number is not None else "" text = text.replace("%%BOOTH_NUMBER%%", booth) table = str(self.job_fair_table_number ) if self.job_fair_table_number is not None else "" text = text.replace("%%JOB_FAIR_TABLE_NUMBER%%", table) return text @cached_property def website_logo_url(self): if self.web_logo: return self.web_logo.url @property def joblisting_text(self): if not hasattr(self, "_joblisting_text"): self._joblisting_text = None benefits = self.sponsor_benefits.filter(benefit__id=8) if benefits.count(): self._joblisting_text = benefits[0].text return self._joblisting_text @property def website_logo(self): return self.web_logo 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 benefit_is_complete(self, name): """Return True - benefit is complete, False - benefit is not complete, or None - benefit not applicable for this sponsor's level """ if BenefitLevel.objects.filter(level=self.level, benefit__name=name).exists(): try: benefit = self.sponsor_benefits.get(benefit__name=name) except SponsorBenefit.DoesNotExist: return False else: return benefit.is_complete else: return None # Not an applicable benefit for this sponsor's level
class Sponsor(models.Model): applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("applicant"), null=True, on_delete=SET_NULL) name = models.CharField(_("Sponsor Name"), max_length=100) display_url = models.CharField(_( "Link text - text to display on link to sponsor webpage, if different from the actual link" ), max_length=200, default='', blank=True) external_url = models.URLField( _("Link to sponsor webpage"), help_text=_("(Must include https:// or http://.)")) twitter_username = models.CharField( _("Twitter username"), blank=True, max_length=15, ) annotation = models.TextField(_("annotation"), blank=True) contact_name = models.CharField(_("Contact Name"), max_length=100) contact_emails = MultiEmailField( _(u"Contact Emails"), default='', help_text=_(u"Please enter one email address per line.")) contact_phone = models.CharField(_(u"Contact Phone"), max_length=32) contact_address = models.TextField(_(u"Contact Address")) level = models.ForeignKey(SponsorLevel, verbose_name=_("level")) packages = models.ManyToManyField(SponsorPackage, verbose_name=_("packages"), blank=True) added = models.DateTimeField(_("added"), default=datetime.datetime.now) active = models.BooleanField(_("active"), default=False) approval_time = models.DateTimeField(null=True, blank=True, editable=False) wants_table = models.BooleanField(_( 'Does your organization want a table at the job fair? ' '(See <a href="/2019/sponsors/fees/">Estimated Sponsor Fees</a> ' 'for costs that might be involved.)'), default=False) wants_booth = models.BooleanField(_( 'Does your organization want a booth on the expo floor? ' '(See <a href="/2019/sponsors/fees/">Estimated Sponsor Fees</a> ' 'for costs that might be involved.)'), default=False) small_entity_discount = models.BooleanField(_( 'Does your organization have fewer than 25 employees,' ' which qualifies you for our Small Entity Discount of 30%?'), default=False) # Whether things are complete # True = complete, False = incomplate, Null = n/a for this sponsor level print_logo_benefit = models.NullBooleanField( help_text=_(u"Print logo benefit is complete")) advertisement_benefit = models.NullBooleanField( help_text=_(u"Advertisement benefit is complete")) registration_promo_codes = models.CharField(max_length=200, blank=True, default='') expo_promo_codes = models.CharField(max_length=200, blank=True, default='') additional_discounted_registration_promo_codes = models.CharField( max_length=200, blank=True, default='') a_la_carte_registration_promo_codes = models.CharField(max_length=200, blank=True, default='') booth_number = models.CharField(max_length=5, blank=True, null=True, default=None) job_fair_participant = models.BooleanField(default=False) job_fair_table_number = models.CharField(max_length=5, blank=True, null=True, default=None) web_description = models.TextField( _(u"Company description (to show on the web site)"), ) web_logo = models.ImageField( _(u"Web logo"), help_text= _("For display on our sponsor webpage. High resolution PNG or JPG, smallest dimension no less than 256px" ), upload_to="sponsor_files", null=True, # This is nullable in case old data doesn't have a web logo # We enforce it on all new or edited sponsors though. ) print_logo = models.FileField( _(u"Print logo"), help_text=_( "For printed materials, signage, and projection. SVG or EPS"), upload_to="sponsor_files", blank=True, null= True, # This is nullable in case old data doesn't have a printed logo # We enforce it on all new or edited sponsors though. ) objects = SponsorManager() def __unicode__(self): return self.name class Meta: verbose_name = _("sponsor") verbose_name_plural = _("sponsors") ordering = ['name'] def save(self, *args, **kwargs): # Set fields related to benefits being complete for benefit in BENEFITS: field_name = benefit['field_name'] benefit_name = benefit['name'] setattr(self, field_name, self.benefit_is_complete(benefit_name)) super(Sponsor, self).save(*args, **kwargs) def get_absolute_url(self): if self.active: return reverse("sponsor_detail", kwargs={"pk": self.pk}) return reverse("sponsor_list") def get_display_url(self): """ Return the text to display on the sponsor's link """ if self.display_url: return self.display_url else: return self.external_url def render_email(self, text): """Replace special strings in text with values from the sponsor. %%NAME%% --> Sponsor name %%REGISTRATION_PROMO_CODES%% --> Registration promo codes, or empty string %%EXPO_PROMO_CODES%% --> Expo Hall only promo codes, or empty string %%ADDITIONAL_DISCOUNTED_REGISTRATION_PROMO_CODES%% --> Additional Discounted Registration promo codes, or empty string %%A_LA_CARTE_REGISTRATION_PROMO_CODES%% --> A la Carte Registration promo codes, or empty string %%BOOTH_NUMBER%% --> Booth number, or empty string if not set %%JOB_FAIR_TABLE_NUMBER%%" --> Job fair table number, or empty string if not set Flags: JOB_FAIR_PARTICIPANT: Use with {% if JOB_FAIR_PARTICIPANT %} block to include some content for Job Fair Participants """ text = text.replace("%%NAME%%", self.name) text = text.replace("%%REGISTRATION_PROMO_CODES%%", self.registration_promo_codes or 'N/A') text = text.replace("%%EXPO_PROMO_CODES%%", self.expo_promo_codes or 'N/A') text = text.replace( "%%ADDITIONAL_DISCOUNTED_REGISTRATION_PROMO_CODES%%", self.additional_discounted_registration_promo_codes or 'N/A') text = text.replace("%%A_LA_CARTE_REGISTRATION_PROMO_CODES%%", self.a_la_carte_registration_promo_codes or 'N/A') # The next two are numbers, or if not set, None. We don't want to # display "None" :-), but we might want to display "0". booth = str(self.booth_number) if self.booth_number is not None else "" text = text.replace("%%BOOTH_NUMBER%%", booth) table = str(self.job_fair_table_number ) if self.job_fair_table_number is not None else "" text = text.replace("%%JOB_FAIR_TABLE_NUMBER%%", table) email_template = Template(text) email_context = Context({ 'JOB_FAIR_PARTICIPANT': self.job_fair_participant, }) text = email_template.render(email_context) return text @cached_property def website_logo_url(self): if self.web_logo: return self.web_logo.url @property def joblisting_text(self): if not hasattr(self, "_joblisting_text"): self._joblisting_text = None benefits = self.sponsor_benefits.filter( benefit__name__startswith='Job Listing', ) if benefits.count(): self._joblisting_text = benefits[0].text return self._joblisting_text @property def website_logo(self): return self.web_logo 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 try: packages = self.packages except SponsorPackage.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) if packages: for package in packages.all(): for benefit_package in package.benefit_packages.all(): # Create all needed benefits if they don't exist already sponsor_benefit, created = SponsorBenefit.objects.get_or_create( sponsor=self, benefit=benefit_package.benefit) # and set to default limits for this level. sponsor_benefit.max_words = benefit_package.max_words sponsor_benefit.other_limits = benefit_package.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 benefit_is_complete(self, name): """Return True - benefit is complete, False - benefit is not complete, or None - benefit not applicable for this sponsor's level """ if BenefitLevel.objects.filter(level=self.level, benefit__name=name).exists(): try: benefit = self.sponsor_benefits.get(benefit__name=name) except SponsorBenefit.DoesNotExist: return False else: return benefit.is_complete else: return None # Not an applicable benefit for this sponsor's level