class StudyGroup(BasePage): """ StudyGroups Plugin. Similar to Pages with extra fields. """ mission = tinymce_models.HTMLField(null=True, blank=True) notes = tinymce_models.HTMLField(null=True, blank=True) contact_name = models.CharField(max_length=200, null=True, blank=True) contact_email = models.CharField(max_length=200, null=True, blank=True) join_link = models.CharField(max_length=200, null=True, blank=True) group = models.ForeignKey(Group) perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = StudyGroupManager() def __unicode__(self): return unicode(self.title) class Meta: permissions = (("view_studygroup", "Can view studygroup"), ) app_label = 'studygroups' @models.permalink def get_absolute_url(self): return ("studygroups.detail", [self.slug]) def get_meta(self, name): """ This method is standard across all models that are related to the Meta model. Used to generate dynamic meta information niche to this model. """ return StudyGroupMeta().get_meta(self, name) def officers(self): return Officer.objects.filter(study_group=self).order_by('pk')
class Committee(BasePage): """ Committees Plugin. Similar to Pages with extra fields. """ slug = SlugField(_('URL Path'), unique=True) mission = tinymce_models.HTMLField(null=True, blank=True) notes = tinymce_models.HTMLField(null=True, blank=True) sponsors = tinymce_models.HTMLField(blank=True, default='') contact_name = models.CharField(max_length=200, null=True, blank=True) contact_email = models.CharField(max_length=200, null=True, blank=True) join_link = models.CharField(max_length=200, null=True, blank=True) group = models.ForeignKey(Group, on_delete=models.CASCADE) perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = CommitteeManager() def __str__(self): return str(self.title) class Meta: # permissions = (("view_committee", "Can view committee"),) app_label = 'committees' def get_absolute_url(self): return reverse('committees.detail', args=[self.slug]) def get_meta(self, name): """ This method is standard across all models that are related to the Meta model. Used to generate dynamic meta information niche to this model. """ return CommitteeMeta().get_meta(self, name) def officers(self): return Officer.objects.filter(committee=self).order_by('pk')
class EmergencyAnnouncement(TendenciBaseModel): title = models.CharField(_('Title'), max_length=250) content = tinymce_models.HTMLField(_('Content')) enabled = models.BooleanField(_('Enabled'), default=True) perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = EmergencyAnnouncementManager() class Meta: # permissions = (("view_emergencyannouncement",_("Can view emergency announcement")),) verbose_name = _('Emergency Announcement') verbose_name_plural = _('Emergency Announcements') def __str__(self): return self.title
class HelpFile(TendenciBaseModel): """Question/Answer infromation""" LEVELS = ('basic', 'intermediate', 'advanced', 'expert') LEVEL_CHOICES = [(i, i) for i in LEVELS] slug = SlugField(_('URL Path'), unique=True) topics = models.ManyToManyField(Topic) question = models.CharField(max_length=500) answer = tinymce_models.HTMLField() level = models.CharField(choices=LEVEL_CHOICES, max_length=100, default='basic') is_faq = models.BooleanField(default=False) is_featured = models.BooleanField(default=False) is_video = models.BooleanField(default=False) syndicate = models.BooleanField(_('Include in RSS feed'), default=True) view_totals = models.PositiveIntegerField(default=0) group = models.ForeignKey(Group, null=True, default=get_default_group, on_delete=models.SET_NULL) perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = HelpFileManager() class Meta: permissions = (("view_helpfile", _("Can view help file")), ) app_label = 'help_files' @models.permalink def get_absolute_url(self): return ("help_file.details", [self.slug]) def __unicode__(self): return self.question def level_is(self): "Template helper: {% if file.level_is.basic %}..." return dict([i, self.level == i] for i in HelpFile.LEVELS)
class Box(OrderingBaseModel, TendenciBaseModel): title = models.CharField(max_length=500, blank=True) content = tinymce_models.HTMLField() tags = TagField(blank=True) group = models.ForeignKey(Group, null=True, default=get_default_group, on_delete=models.SET_NULL) perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = BoxManager() class Meta: # permissions = (("view_box",_("Can view box")),) verbose_name_plural = _("Boxes") ordering = ['position'] app_label = 'boxes' def __str__(self): return self.title def safe_content(self): return mark_safe(self.content) def save(self, *args, **kwargs): model = self.__class__ if self.position is None: # Append try: last = model.objects.order_by('-position')[0] self.ordering = last.ordering + 1 except IndexError: # First row self.ordering = 0 return super(Box, self).save(*args, **kwargs)
class Email(TendenciBaseModel): CONTENT_TYPE_HTML = 'text/html' CONTENT_TYPE_TEXT = 'text' CONTENT_TYPE_CHOICES = ( (CONTENT_TYPE_HTML, 'text/html'), (CONTENT_TYPE_TEXT, 'text'), ) guid = models.CharField(max_length=50) priority = models.IntegerField(default=0) subject = models.CharField(max_length=255) body = tinymce_models.HTMLField() # body = models.TextField() sender = models.CharField(max_length=255) sender_display = models.CharField(max_length=255) reply_to = models.CharField(max_length=255) recipient = models.CharField(max_length=255, blank=True, default='') recipient_display = models.CharField(max_length=255, blank=True, default='') recipient_cc = models.CharField(max_length=255, blank=True, default='') recipient_cc_display = models.CharField(max_length=255, blank=True, default='') recipient_bcc = models.CharField(max_length=255, blank=True, default='') attachments = models.CharField(max_length=500, blank=True, default='') content_type = models.CharField(max_length=255, default=CONTENT_TYPE_HTML, choices=CONTENT_TYPE_CHOICES) # create_dt = models.DateTimeField(auto_now_add=True) # status = models.NullBooleanField(default=True, choices=((True,'Active'),(False,'Inactive'),)) class Meta: app_label = 'emails' def get_absolute_url(self): return reverse('email.view', args=[self.pk]) def __unicode__(self): return self.subject @staticmethod def is_blocked(email_to_test): if not email_to_test or '@' not in email_to_test: return False email_to_test = email_to_test.lower() email_domain = email_to_test.split('@')[1] return EmailBlock.objects.filter( Q(email=email_to_test) | Q(email_domain=email_domain)).exists() def send(self, fail_silently=False, **kwargs): recipient_list = [] recipient_bcc_list = [] headers = kwargs.get('headers', {}) attachments = kwargs.get('attachments', []) if isinstance(self.recipient, str): recipient_list = self.recipient.split(',') recipient_list = [ recipient.strip() for recipient in recipient_list if recipient.strip() != '' ] else: recipient_list = list(self.recipient) if isinstance(self.recipient_cc, str): recipient_cc_list = self.recipient_cc.split(',') recipient_cc_list = [ recipient_cc.strip() for recipient_cc in recipient_cc_list if recipient_cc.strip() != '' ] recipient_list += recipient_cc_list else: recipient_list += list(self.recipient_cc) if isinstance(self.recipient_bcc, str): recipient_bcc_list = self.recipient_bcc.split(',') recipient_bcc_list = [ recipient_bcc.strip() for recipient_bcc in recipient_bcc_list if recipient_bcc.strip() != '' ] else: recipient_bcc_list = list(self.recipient_bcc) if self.reply_to: headers['Reply-To'] = self.reply_to if not self.sender: self.sender = get_setting( 'site', 'global', 'siteemailnoreplyaddress') or settings.DEFAULT_FROM_EMAIL if self.sender_display: # Add quotes around display name to prevent errors on sending # When display name contains comma or other control characters, headers['From'] = '"%s"<%s>' % (self.sender_display, self.sender) if self.priority and self.priority == 1: headers['X-Priority'] = '1' headers['X-MSMail-Priority'] = 'High' # remove blocked from recipient_list and recipient_bcc_list temp_recipient_list = copy.copy(recipient_list) for e in temp_recipient_list: if self.is_blocked(e): recipient_list.remove(e) temp_recipient_bcc_list = copy.copy(recipient_bcc_list) for e in temp_recipient_bcc_list: if self.is_blocked(e): recipient_bcc_list.remove(e) if recipient_list or recipient_bcc_list: msg = EmailMessage(self.subject, add_tendenci_footer(self.body), self.sender, recipient_list, recipient_bcc_list, headers=headers, connection=kwargs.get('connection', None)) if self.content_type == 'html' or self.content_type == self.CONTENT_TYPE_HTML: msg.content_subtype = 'html' if attachments: msg.attachments = attachments msg.send(fail_silently=fail_silently) def save(self, user=None, *args, **kwargs): if not self.id: self.guid = uuid.uuid1() if user and not user.is_anonymous: self.creator = user self.creator_username = user.username if user and not user.is_anonymous: self.owner = user self.owner_username = user.username super(Email, self).save(*args, **kwargs) # if this email allows view by user2_compare def allow_view_by(self, user2_compare): boo = False if user2_compare.profile.is_superuser: boo = True else: if user2_compare == self.creator or user2_compare == self.owner: if self.status: boo = True else: if user2_compare.has_perm('emails.view_email', self): if self.status == 1 and self.status_detail == 'active': boo = True return boo # if this email allows edit by user2_compare def allow_edit_by(self, user2_compare): boo = False if user2_compare.profile.is_superuser: boo = True else: if user2_compare == self.user: boo = True else: if user2_compare == self.creator or user2_compare == self.owner: if self.status: boo = True else: if user2_compare.has_perm('emails.edit_email', self): if self.status: boo = True return boo def template_body(self, email_d): """ build the email body from the template and variables passed in by a dictionary """ import os.path from django.template.loader import render_to_string template = email_d.get('template_path_name', '') # check if this template exists boo = False for dir in settings.TEMPLATE_DIRS: if os.path.isfile(os.path.join(dir, template)): boo = True break if not boo: # log an event # notify admin of missing template pass else: self.body = render_to_string(template_name=template) for key in email_d: # need to convert [blah] to %5Bblah%5D for replace line tmp_value = "%5B" + key[1:-1] + "%5D" if email_d[key] is not None: self.body = self.body.replace(key, email_d[key]) self.body = self.body.replace(tmp_value, email_d[key]) else: self.body = self.body.replace(key, '') self.body = self.body.replace(tmp_value, '') return boo
class BasePage(TendenciBaseModel): guid = models.CharField(max_length=40) title = models.CharField(max_length=500, blank=True) slug = SlugField(_('URL Path')) header_image = models.ForeignKey(HeaderImage, null=True, on_delete=models.SET_NULL) content = tinymce_models.HTMLField() view_contact_form = models.BooleanField(default=False) design_notes = models.TextField(_('Design Notes'), blank=True) syndicate = models.BooleanField(_('Include in RSS feed'), default=False) template = models.CharField(_('Template'), max_length=50, blank=True) tags = TagField(blank=True) meta = models.OneToOneField(MetaTags, null=True, on_delete=models.SET_NULL) categories = GenericRelation(CategoryItem, object_id_field="object_id", content_type_field="content_type") class Meta: abstract = True app_label = 'pages' def save(self, *args, **kwargs): if not self.guid: self.guid = str(uuid.uuid4()) super(BasePage, self).save(*args, **kwargs) if self.header_image: if self.is_public(): set_s3_file_permission(self.header_image.file, public=True) else: set_s3_file_permission(self.header_image.file, public=False) def __str__(self): return self.title def get_header_image_url(self): if not self.header_image: return '' if self.is_public(): return self.header_image.file.url return reverse('page.header_image', args=[self.id]) def is_public(self): return all([ self.allow_anonymous_view, self.status, self.status_detail in ['active'] ]) @property def category_set(self): items = {} for cat in self.categories.select_related('category', 'parent'): if cat.category: items["category"] = cat.category elif cat.parent: items["sub_category"] = cat.parent return items @property def version(self): if self.status and self.status_detail: return self.status_detail + '-' + str(self.pk) + ' ' + str( self.create_dt) elif not self.status: return 'deleted-' + str(self.pk) + ' ' + str(self.create_dt) return ''
class BaseJob(TendenciBaseModel): guid = models.CharField(max_length=40) title = models.CharField(max_length=250) slug = SlugField(_('URL Path'), unique=True) description = tinymce_models.HTMLField() list_type = models.CharField(max_length=50) # premium or regular code = models.CharField(max_length=50, blank=True) # internal job-code location = models.CharField(max_length=500, null=True, blank=True) # cannot be foreign, needs to be open 'Texas' 'All 50 States' 'US and International' skills = models.TextField(blank=True) experience = models.TextField(blank=True) education = models.TextField(blank=True) level = models.CharField(max_length=50, blank=True) # e.g. entry, part-time, permanent, contract period = models.CharField(max_length=50, blank=True) # full time, part time, contract is_agency = models.BooleanField(default=False) # defines if the job posting is by a third party agency contact_method = models.TextField(blank=True) # preferred method - email, phone, fax. leave open field for user to define position_reports_to = models.CharField(max_length=200, blank=True) # manager, CEO, VP, etc salary_from = models.CharField(max_length=50, blank=True) salary_to = models.CharField(max_length=50, blank=True) computer_skills = models.TextField(blank=True) # date related fields requested_duration = models.IntegerField() # 30, 60, 90 days - should be relational table pricing = models.ForeignKey('JobPricing', null=True, on_delete=models.SET_NULL) # selected pricing based on requested_duration activation_dt = models.DateTimeField(null=True, blank=True) # date job listing was activated post_dt = models.DateTimeField(null=True, blank=True) # date job was posted (same as create date?) expiration_dt = models.DateTimeField(null=True, blank=True) # date job expires based on activation date and duration start_dt = models.DateTimeField(null=True, blank=True) # date job starts(defined by job poster) job_url = models.CharField(max_length=300, blank=True) # link to other (fuller) job posting syndicate = models.BooleanField(_('Include in RSS feed'), blank=True, default=True) design_notes = models.TextField(blank=True) #TODO: foreign contact_company = models.CharField(max_length=300, blank=True) contact_name = models.CharField(max_length=150, blank=True) contact_address = models.CharField(max_length=50, blank=True) contact_address2 = models.CharField(max_length=50, blank=True) contact_city = models.CharField(max_length=50, blank=True) contact_state = models.CharField(max_length=50, blank=True) contact_zip_code = models.CharField(max_length=50, blank=True) contact_country = models.CharField(max_length=50, blank=True) contact_phone = models.CharField(max_length=50, blank=True) contact_fax = models.CharField(max_length=50, blank=True) contact_email = models.CharField(max_length=300, blank=True) contact_website = models.CharField(max_length=300, blank=True) meta = models.OneToOneField(MetaTags, null=True, on_delete=models.CASCADE) group = models.ForeignKey(Group, null=True, default=get_default_group, on_delete=models.SET_NULL) tags = TagField(blank=True) invoice = models.ForeignKey(Invoice, blank=True, null=True, on_delete=models.SET_NULL) payment_method = models.CharField(max_length=50, blank=True, default='') member_price = models.DecimalField(max_digits=20, decimal_places=2, blank=True, null=True) member_count = models.IntegerField(blank=True, null=True) non_member_price = models.DecimalField(max_digits=20, decimal_places=2, blank=True, null=True) non_member_count = models.IntegerField(blank=True, null=True) cat = models.ForeignKey(Category, verbose_name=_("Category"), related_name="job_cat", null=True, on_delete=models.SET_NULL) sub_cat = models.ForeignKey(Category, verbose_name=_("Sub Category"), related_name="job_subcat", null=True, on_delete=models.SET_NULL) # needed for migration 0003 categories = GenericRelation( CategoryItem, object_id_field="object_id", content_type_field="content_type" ) perms = GenericRelation( ObjectPermission, object_id_field="object_id", content_type_field="content_type" ) objects = JobManager() class Meta: abstract = True def save(self, *args, **kwargs): if not self.id: self.guid = str(uuid.uuid4()) super(BaseJob, self).save(*args, **kwargs) def __str__(self): return self.title # Called by payments_pop_by_invoice_user in Payment model. def get_payment_description(self, inv): """ The description will be sent to payment gateway and displayed on invoice. If not supplied, the default description will be generated. """ return 'Tendenci Invoice %d for Job: %s (%d).' % ( inv.id, self.title, inv.object_id, ) def make_acct_entries(self, user, inv, amount, **kwargs): """ Make the accounting entries for the job sale """ from tendenci.apps.accountings.models import Acct, AcctEntry, AcctTran from tendenci.apps.accountings.utils import make_acct_entries_initial, make_acct_entries_closing ae = AcctEntry.objects.create_acct_entry(user, 'invoice', inv.id) if not inv.is_tendered: make_acct_entries_initial(user, ae, amount) else: # payment has now been received make_acct_entries_closing(user, ae, amount) # #CREDIT job SALES acct_number = self.get_acct_number() acct = Acct.objects.get(account_number=acct_number) AcctTran.objects.create_acct_tran(user, ae, acct, amount * (-1)) def get_acct_number(self, discount=False): if discount: return 462500 else: return 402500 def auto_update_paid_object(self, request, payment): """ Update the object after online payment is received. """ if not request.user.profile.is_superuser: self.status_detail = 'paid - pending approval' self.activation_dt = datetime.now() self.expiration_dt = self.activation_dt + timedelta(days=self.requested_duration) self.save() @property def opt_app_label(self): return self._meta.app_label @property def opt_module_name(self): return self._meta.model_name
class Directory(TendenciBaseModel): guid = models.CharField(max_length=40) slug = SlugField(_('URL Path'), unique=True) timezone = TimeZoneField(_('Time Zone')) headline = models.CharField(max_length=200, blank=True) summary = models.TextField(blank=True) body = tinymce_models.HTMLField() source = models.CharField(max_length=300, blank=True) # logo = models.FileField(max_length=260, upload_to=file_directory, # help_text=_('Company logo. Only jpg, gif, or png images.'), # blank=True) logo_file = models.ForeignKey(File, null=True) first_name = models.CharField(_('First Name'), max_length=100, blank=True) last_name = models.CharField(_('Last Name'), max_length=100, blank=True) address = models.CharField(_('Address'), max_length=100, blank=True) address2 = models.CharField(_('Address 2'), max_length=100, blank=True) city = models.CharField(_('City'), max_length=50, blank=True) state = models.CharField(_('State'), max_length=50, blank=True) zip_code = models.CharField(_('Zip Code'), max_length=50, blank=True) country = models.CharField(_('Country'), max_length=50, blank=True) phone = models.CharField(max_length=50, blank=True) phone2 = models.CharField(_('Phone 2'), max_length=50, blank=True) fax = models.CharField(_('Fax'), max_length=50, blank=True) email = models.CharField(_('Email'), max_length=120, blank=True) email2 = models.CharField(_('Email 2'), max_length=120, blank=True) website = models.CharField(max_length=300, blank=True) renewal_notice_sent = models.BooleanField(default=False) list_type = models.CharField(_('List Type'), max_length=50, blank=True) requested_duration = models.IntegerField(_('Requested Duration'), default=0) pricing = models.ForeignKey('DirectoryPricing', null=True) activation_dt = models.DateTimeField(_('Activation Date/Time'), null=True, blank=True) expiration_dt = models.DateTimeField(_('Expiration Date/Time'), null=True, blank=True) invoice = models.ForeignKey(Invoice, blank=True, null=True) payment_method = models.CharField(_('Payment Method'), max_length=50, blank=True) syndicate = models.BooleanField(_('Include in RSS feed'), default=True) design_notes = models.TextField(_('Design Notes'), blank=True) admin_notes = models.TextField(_('Admin Notes'), blank=True) tags = TagField(blank=True) # for podcast feeds enclosure_url = models.CharField(_('Enclosure URL'), max_length=500, blank=True) enclosure_type = models.CharField(_('Enclosure Type'), max_length=120, blank=True) enclosure_length = models.IntegerField(_('Enclosure Length'), default=0) # html-meta tags meta = models.OneToOneField(MetaTags, null=True) categories = GenericRelation(CategoryItem, object_id_field="object_id", content_type_field="content_type") perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = DirectoryManager() class Meta: permissions = (("view_directory",_("Can view directory")),) verbose_name = _("Directory") verbose_name_plural = _("Directories") app_label = 'directories' def get_meta(self, name): """ This method is standard across all models that are related to the Meta model. Used to generate dynamic methods coupled to this instance. """ return DirectoryMeta().get_meta(self, name) @models.permalink def get_absolute_url(self): return ("directory", [self.slug]) @models.permalink def get_renew_url(self): return ("directory.renew", [self.id]) def __unicode__(self): return self.headline def save(self, *args, **kwargs): if not self.id: self.guid = str(uuid.uuid1()) super(Directory, self).save(*args, **kwargs) if self.logo: if self.is_public(): set_s3_file_permission(self.logo.name, public=True) else: set_s3_file_permission(self.logo.name, public=False) def is_public(self): return all([self.allow_anonymous_view, self.status, self.status_detail in ['active']]) @property def logo(self): """ This represents the logo FileField Originally this was a FileField, but later we added the attribute logo_file to leverage the File model. We then replaced the logo property with this convience method for backwards compatibility. """ if self.logo_file: return self.logo_file.file def get_logo_url(self): if not self.logo_file: return u'' return reverse('file', args=[self.logo_file.pk]) # Called by payments_pop_by_invoice_user in Payment model. def get_payment_description(self, inv): """ The description will be sent to payment gateway and displayed on invoice. If not supplied, the default description will be generated. """ return 'Tendenci Invoice %d for Directory: %s (%d).' % ( inv.id, self.headline, inv.object_id, ) def make_acct_entries(self, user, inv, amount, **kwargs): """ Make the accounting entries for the directory sale """ from tendenci.apps.accountings.models import Acct, AcctEntry, AcctTran from tendenci.apps.accountings.utils import make_acct_entries_initial, make_acct_entries_closing ae = AcctEntry.objects.create_acct_entry(user, 'invoice', inv.id) if not inv.is_tendered: make_acct_entries_initial(user, ae, amount) else: # payment has now been received make_acct_entries_closing(user, ae, amount) # #CREDIT directory SALES acct_number = self.get_acct_number() acct = Acct.objects.get(account_number=acct_number) AcctTran.objects.create_acct_tran(user, ae, acct, amount*(-1)) def get_acct_number(self, discount=False): if discount: return 464400 else: return 404400 def auto_update_paid_object(self, request, payment): """ Update the object after online payment is received. """ if not request.user.profile.is_superuser: self.status_detail = 'paid - pending approval' self.save() def age(self): return datetime.now() - self.create_dt @property def category_set(self): items = {} for cat in self.categories.select_related('category__name', 'parent__name'): if cat.category: items["category"] = cat.category elif cat.parent: items["sub_category"] = cat.parent return items def renew_window(self): days = get_setting('module', 'directories', 'renewaldays') days = int(days) if self.expiration_dt and datetime.now() + timedelta(days) > self.expiration_dt: return True else: return False
class Directory(TendenciBaseModel): guid = models.CharField(max_length=40) slug = SlugField(_('URL Path'), unique=True) entity = models.OneToOneField(Entity, blank=True, null=True, on_delete=models.SET_NULL,) timezone = TimeZoneField(verbose_name=_('Time Zone'), default='US/Central', choices=get_timezone_choices(), max_length=100) headline = models.CharField(_('Name'), max_length=200, blank=True) summary = models.TextField(blank=True) body = tinymce_models.HTMLField(_('Description')) source = models.CharField(max_length=300, blank=True) # logo = models.FileField(max_length=260, upload_to=file_directory, # help_text=_('Company logo. Only jpg, gif, or png images.'), # blank=True) logo_file = models.ForeignKey(File, null=True, on_delete=models.CASCADE) first_name = models.CharField(_('First Name'), max_length=100, blank=True) last_name = models.CharField(_('Last Name'), max_length=100, blank=True) address = models.CharField(_('Address'), max_length=100, blank=True) address2 = models.CharField(_('Address 2'), max_length=100, blank=True) city = models.CharField(_('City'), max_length=50, blank=True) state = models.CharField(_('State'), max_length=50, blank=True) zip_code = models.CharField(_('Zip Code'), max_length=50, blank=True) country = models.CharField(_('Country'), max_length=50, blank=True) region = models.ForeignKey(Region, blank=True, null=True, on_delete=models.SET_NULL) phone = models.CharField(max_length=50, blank=True) phone2 = models.CharField(_('Phone 2'), max_length=50, blank=True) fax = models.CharField(_('Fax'), max_length=50, blank=True) email = models.CharField(_('Email'), max_length=120, blank=True) email2 = models.CharField(_('Email 2'), max_length=120, blank=True) website = models.CharField(max_length=300, blank=True) renewal_notice_sent = models.BooleanField(default=False) list_type = models.CharField(_('List Type'), max_length=50, blank=True) requested_duration = models.IntegerField(_('Requested Duration'), default=0) pricing = models.ForeignKey('DirectoryPricing', null=True, on_delete=models.CASCADE) activation_dt = models.DateTimeField(_('Activation Date/Time'), null=True, blank=True) expiration_dt = models.DateTimeField(_('Expiration Date/Time'), null=True, blank=True) invoice = models.ForeignKey(Invoice, blank=True, null=True, on_delete=models.CASCADE) payment_method = models.CharField(_('Payment Method'), max_length=50, blank=True) # social media links linkedin = models.URLField(_('LinkedIn'), blank=True, default='') facebook = models.URLField(_('Facebook'), blank=True, default='') twitter = models.URLField(_('Twitter'), blank=True, default='') instagram = models.URLField(_('Instagram'), blank=True, default='') youtube = models.URLField(_('YouTube'), blank=True, default='') syndicate = models.BooleanField(_('Include in RSS feed'), default=True) design_notes = models.TextField(_('Design Notes'), blank=True) admin_notes = models.TextField(_('Admin Notes'), blank=True) tags = TagField(blank=True) # for podcast feeds enclosure_url = models.CharField(_('Enclosure URL'), max_length=500, blank=True) enclosure_type = models.CharField(_('Enclosure Type'), max_length=120, blank=True) enclosure_length = models.IntegerField(_('Enclosure Length'), default=0) # html-meta tags meta = models.OneToOneField(MetaTags, null=True, on_delete=models.SET_NULL) cat = models.ForeignKey(Category, verbose_name=_("Category"), related_name="directory_cat", null=True, on_delete=models.SET_NULL) sub_cat = models.ForeignKey(Category, verbose_name=_("Sub Category"), related_name="directory_subcat", null=True, on_delete=models.SET_NULL) cats = models.ManyToManyField(Category, verbose_name=_("Categories"), related_name="directory_cats",) sub_cats = models.ManyToManyField(Category, verbose_name=_("Sub Categories"), related_name="directory_subcats",) # legacy categories needed for data migration categories = GenericRelation(CategoryItem, object_id_field="object_id", content_type_field="content_type") perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") affiliates = models.ManyToManyField("Directory", through='Affiliateship') objects = DirectoryManager() class Meta: # permissions = (("view_directory",_("Can view directory")),) verbose_name = _("Directory") verbose_name_plural = _("Directories") app_label = 'directories' def get_meta(self, name): """ This method is standard across all models that are related to the Meta model. Used to generate dynamic methods coupled to this instance. """ return DirectoryMeta().get_meta(self, name) def __str__(self): return self.headline def get_absolute_url(self): return reverse('directory', args=[self.slug]) def get_renew_url(self): return reverse('directory.renew', args=[self.id]) def set_slug(self): if not self.slug: slug = slugify(self.headline) count = str(Directory.objects.count()) if len(slug) + len(count) >= 99: self.slug = '%s-%s' % (slug[:99-len(count)], count) else: self.slug = '%s-%s' % (slug, count) def save(self, *args, **kwargs): if not self.id: self.guid = str(uuid.uuid4()) super(Directory, self).save(*args, **kwargs) if self.logo: if self.is_public(): set_s3_file_permission(self.logo.name, public=True) else: set_s3_file_permission(self.logo.name, public=False) def is_public(self): return all([self.allow_anonymous_view, self.status, self.status_detail in ['active']]) def has_social_media(self): return any([self.linkedin, self.facebook, self.twitter, self.instagram, self.youtube]) @property def logo(self): """ This represents the logo FileField Originally this was a FileField, but later we added the attribute logo_file to leverage the File model. We then replaced the logo property with this convience method for backwards compatibility. """ if self.logo_file: return self.logo_file.file def get_logo_url(self): if not self.logo_file: return u'' return reverse('file', args=[self.logo_file.pk]) # Called by payments_pop_by_invoice_user in Payment model. def get_payment_description(self, inv): """ The description will be sent to payment gateway and displayed on invoice. If not supplied, the default description will be generated. """ return 'Tendenci Invoice %d for Directory: %s (%d).' % ( inv.id, self.headline, inv.object_id, ) def make_acct_entries(self, user, inv, amount, **kwargs): """ Make the accounting entries for the directory sale """ from tendenci.apps.accountings.models import Acct, AcctEntry, AcctTran from tendenci.apps.accountings.utils import make_acct_entries_initial, make_acct_entries_closing ae = AcctEntry.objects.create_acct_entry(user, 'invoice', inv.id) if not inv.is_tendered: make_acct_entries_initial(user, ae, amount) else: # payment has now been received make_acct_entries_closing(user, ae, amount) # #CREDIT directory SALES acct_number = self.get_acct_number() acct = Acct.objects.get(account_number=acct_number) AcctTran.objects.create_acct_tran(user, ae, acct, amount*(-1)) def get_acct_number(self, discount=False): if discount: return 464400 else: return 404400 def auto_update_paid_object(self, request, payment): """ Update the object after online payment is received. """ if not request.user.profile.is_superuser: self.status_detail = 'paid - pending approval' self.save() def age(self): return datetime.now() - self.create_dt def cats_list(self): items = [] for cat in self.cats.all(): sub_cats = self.sub_cats.filter(parent=cat) items.append((cat, list(sub_cats))) return items @property def category_set(self): items = {} for cat in self.categories.select_related('category', 'parent'): if cat.category: items["category"] = cat.category elif cat.parent: items["sub_category"] = cat.parent return items def renew_window(self): days = get_setting('module', 'directories', 'renewaldays') days = int(days) if self.expiration_dt and datetime.now() + timedelta(days) > self.expiration_dt: return True else: return False def has_membership_with(self, this_user): """ Check if this directory is associated with a membership or a corporate membership that this user owns. Return ``True`` if this directory is associated with an active membership or corporate membership, and this_user owns the membership or is a representative of the corporate membership, or is the ``creator`` or ``owner`` of this directory. """ [m] = self.membershipdefault_set.filter(status_detail='active')[:1] or [None] if m: if any([this_user==self.creator, this_user==self.owner, this_user==m.user]): return True if hasattr(self, 'corpprofile'): corp_membership = self.corpprofile.corp_membership if corp_membership and corp_membership.status_detail == 'active': if any([this_user==self.creator, this_user==self.owner, self.corpprofile.is_rep(this_user)]): return True return False def get_owner_emails_list(self): """ Returns a list of owner's email addresses. It's tricky because directory doesn't have a clear owner. Since the owner field can be changed to whoever last edited, we'll check the creator, the email address field, member or reps if it is created from memberships and corp memberships, respectively. """ emails_list = [] # creator if self.creator and validate_email(self.creator.email): emails_list.append(self.creator.email) # the email field if validate_email(self.email): emails_list.append(self.email) # member [m] = self.membershipdefault_set.filter(status_detail='active')[:1] or [None] if m and validate_email(m.user.email): emails_list.append(m.user.email) # corp reps if hasattr(self, 'corpprofile'): corp_reps = self.corpprofile.reps.all() for rep in corp_reps: if validate_email(rep.user.email): emails_list.append(rep.user.email) return list(set(emails_list)) def get_corp_profile(self): if hasattr(self, 'corpprofile'): return self.corpprofile def get_corp_type(self): """ Returns the corporate membership type that associates with the directory. """ corp_profile = self.get_corp_profile() if corp_profile: corp_membership = corp_profile.corp_membership if corp_membership: return corp_membership.corporate_membership_type def get_membership(self): [membership] = list(self.membershipdefault_set.filter(status_detail='active'))[:1] or [None] return membership def get_member_type(self): """ Returns the membership type that associates with the directory. """ membership = self.get_membership() if membership: return membership.membership_type def is_owner(self, user_this): if not user_this or not user_this.is_authenticated: return False # is creator or owner if user_this == self.creator or user_this == self.owner: return True # is corp rep if hasattr(self, 'corpprofile'): if self.corpprofile.reps.filter(user__in=[user_this]): return True # member membership = self.get_membership() if membership and membership.user == user_this: return True return False def can_connect_from(self, directory_from=None, directory_from_cat=None): """ Check if this directory can be connected from ``directory_from``. """ affliated_cats = self.get_affliated_cats() if directory_from_cat: return directory_from_cat in affliated_cats if directory_from: for cat in directory_from.cats.all(): if cat in affliated_cats: return True return False def get_affliated_cats(self): """ Get a list of categories that are allowed to connect with the categories of this directory. """ affliated_cats = [] for cat in self.cats.all(): if hasattr(cat, 'connections'): if cat.connections.affliated_cats.count() > 0: affliated_cats += list(cat.connections.affliated_cats.all()) return affliated_cats def get_parent_cats(self): """ Get a list of parent categories that this directory can associate to. """ parent_cats = [] for cat in self.cats.all(): connections = cat.allowed_connections.all() for c in connections: if not c.cat in parent_cats: parent_cats.append(c.cat) return parent_cats def get_list_affiliates(self): """ Return a sorted list of list of affiliate directories, grouped by category. ex: [(category_name, [d1, d2, ..]),...] """ affiliates_dict = {} affliated_cats = self.get_affliated_cats() for affiliateship in Affiliateship.objects.filter(directory=self): affiliate = affiliateship.affiliate if affiliate.status_detail =='active': cat = affiliateship.connected_as if cat in affliated_cats: if cat in affiliates_dict: affiliates_dict[cat].append(affiliate) else: affiliates_dict[cat] = [affiliate] return sorted(list(affiliates_dict.items()), key=lambda item: item[0].position) def get_list_parent_directories(self): """ Return a sorted list of list of parent directories, grouped by category, ex: [(category_name, [d1, d2, ..]),...] """ parents_dict = {} parent_cats = self.get_parent_cats() for affiliateship in Affiliateship.objects.filter(affiliate=self): parent_d = affiliateship.directory if parent_d.status_detail =='active': connected_cat = affiliateship.connected_as for cat in parent_d.cats.all(): if cat in parent_cats and connected_cat in cat.connections.affliated_cats.all(): if cat in parents_dict: parents_dict[cat].append(parent_d) else: parents_dict[cat] = [parent_d] return sorted(list(parents_dict.items()), key=lambda item: item[0].position) def allow_associate_by(self, user_this): """ Check if user_this is allowed to submit affiliate requests. If the connection is limited to the allowed connection, this user will need to have a valid membership with the membership type is in the allowed types. """ affliated_cats = self.get_affliated_cats() if affliated_cats: if user_this.is_superuser: return True # check if user_this is the owner of a directory with the category in affliated_cats for directory in Directory.objects.filter(cats__in=affliated_cats): if directory.is_owner(user_this): return True def allow_approve_affiliations_by(self, user_this): """ Check if user_this is allowed to approve affiliate requests. Superuser or the directory owner can approve. The directory owners include creator, owner, and associated corp reps. """ if not user_this or not user_this.is_authenticated: return False if user_this.is_superuser: return True # is creator or owner if user_this == self.creator or user_this == self.owner: return True # is a corp rep if hasattr(self, 'corpprofile'): if self.corpprofile.reps.filter(user__in=[user_this]): return True return False def allow_reject_affiliations_by(self, user_this): """ Check if user_this is allowed to reject affiliate requests. Superuser or the directory owner can reject. The directory owners include creator, owner, and associated corp reps. """ return self.allow_approve_affiliations_by(user_this)
class News(TendenciBaseModel): CONTRIBUTOR_AUTHOR = 1 CONTRIBUTOR_PUBLISHER = 2 CONTRIBUTOR_CHOICES = ((CONTRIBUTOR_AUTHOR, _('Author')), (CONTRIBUTOR_PUBLISHER, _('Publisher'))) guid = models.CharField(max_length=40) slug = SlugField(_('URL Path'), unique=True) timezone = TimeZoneField(_('Time Zone')) headline = models.CharField(max_length=200, blank=True) summary = models.TextField(blank=True) body = tinymce_models.HTMLField() source = models.CharField(max_length=300, blank=True) first_name = models.CharField(_('First Name'), max_length=100, blank=True) last_name = models.CharField(_('Last Name'), max_length=100, blank=True) contributor_type = models.IntegerField(choices=CONTRIBUTOR_CHOICES, default=CONTRIBUTOR_AUTHOR) google_profile = models.URLField(_('Google+ URL'), blank=True) phone = models.CharField(max_length=50, blank=True) fax = models.CharField(max_length=50, blank=True) email = models.CharField(max_length=120, blank=True) website = models.CharField(max_length=300, blank=True) thumbnail = models.ForeignKey( 'NewsImage', default=None, null=True, help_text= _('The thumbnail image can be used on your homepage or sidebar if it is setup in your theme. The thumbnail image will not display on the news page.' )) release_dt = models.DateTimeField(_('Release Date/Time'), null=True, blank=True) # used for better performance when retrieving a list of released news release_dt_local = models.DateTimeField(null=True, blank=True) syndicate = models.BooleanField(_('Include in RSS feed'), default=True) design_notes = models.TextField(_('Design Notes'), blank=True) groups = models.ManyToManyField(Group, default=get_default_group, related_name='group_news') tags = TagField(blank=True) uploaded_wechat_mp = models.BooleanField(default=False) #for podcast feeds enclosure_url = models.CharField(_('Enclosure URL'), max_length=500, blank=True) # for podcast feeds enclosure_type = models.CharField(_('Enclosure Type'), max_length=120, blank=True) # for podcast feeds enclosure_length = models.IntegerField(_('Enclosure Length'), default=0) # for podcast feeds use_auto_timestamp = models.BooleanField(_('Auto Timestamp'), default=False) # html-meta tags meta = models.OneToOneField(MetaTags, null=True) categories = GenericRelation(CategoryItem, object_id_field="object_id", content_type_field="content_type") perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = NewsManager() class Meta: permissions = (("view_news", _("Can view news")), ) verbose_name_plural = _("News") app_label = 'news' def get_meta(self, name): """ This method is standard across all models that are related to the Meta model. Used to generate dynamic meta information niche to this model. """ return NewsMeta().get_meta(self, name) @models.permalink def get_absolute_url(self): return ("news.detail", [self.slug]) def __unicode__(self): return self.headline def save(self, *args, **kwargs): if not self.id: self.guid = str(uuid.uuid1()) self.assign_release_dt_local() photo_upload = kwargs.pop('photo', None) super(News, self).save(*args, **kwargs) if photo_upload and self.pk: image = NewsImage(object_id=self.pk, creator=self.creator, creator_username=self.creator_username, owner=self.owner, owner_username=self.owner_username) photo_upload.file.seek(0) image.file.save(photo_upload.name, photo_upload) # save file row image.save() # save image row if self.thumbnail: self.thumbnail.delete() # delete image and file row self.thumbnail = image # set image self.save() if self.thumbnail: if self.is_public(): set_s3_file_permission(self.thumbnail.file, public=True) else: set_s3_file_permission(self.thumbnail.file, public=False) @property def category_set(self): items = {} for cat in self.categories.select_related('category__name', 'parent__name'): if cat.category: items["category"] = cat.category elif cat.parent: items["sub_category"] = cat.parent return items def is_public(self): return all([ self.allow_anonymous_view, self.status, self.status_detail in ['active'] ]) @property def is_released(self): return self.release_dt_local <= datetime.now() @property def has_google_author(self): return self.contributor_type == self.CONTRIBUTOR_AUTHOR @property def has_google_publisher(self): return self.contributor_type == self.CONTRIBUTOR_PUBLISHER def assign_release_dt_local(self): """ convert release_dt to the corresponding local time example: if release_dt: 2014-05-09 03:30:00 timezone: US/Pacific settings.TIME_ZONE: US/Central then the corresponding release_dt_local will be: 2014-05-09 05:30:00 """ now = datetime.now() now_with_tz = adjust_datetime_to_timezone(now, settings.TIME_ZONE) if self.timezone and self.release_dt and self.timezone.zone != settings.TIME_ZONE: time_diff = adjust_datetime_to_timezone( now, self.timezone) - now_with_tz self.release_dt_local = self.release_dt + time_diff else: self.release_dt_local = self.release_dt
class ReliefAssessment(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) # Additional Personal Information id_number = models.CharField(_('ID number'), max_length=50, blank=True, null=True) issuing_authority = models.CharField(_('issuing authority'), max_length=100, blank=True, null=True) health_insurance = models.BooleanField(_('health insurance'), default=False) insurance_provider = models.CharField(_('insurance provider'), max_length=100, blank=True, null=True) # Disaster Area Address address = models.CharField(_('address'), max_length=150) address2 = models.CharField(_('address2'), max_length=100, blank=True, null=True) city = models.CharField(_('city'), max_length=50) state = models.CharField(_('state'), max_length=50) zipcode = models.CharField(_('ZIP'), max_length=50) country = models.CharField(_('country'), max_length=50) # Alternate Address alt_address = models.CharField(_('address'), max_length=150, blank=True, null=True) alt_address2 = models.CharField(_('address2'), max_length=100, blank=True, null=True) alt_city = models.CharField(_('city'), max_length=50, blank=True, null=True) alt_state = models.CharField(_('state'), max_length=50, blank=True, null=True) alt_zipcode = models.CharField(_('ZIP'), max_length=50, blank=True, null=True) alt_country = models.CharField(_('country'), max_length=50, blank=True, null=True) # Ethnicity ethnicity = models.CharField("", max_length=10, choices=ETHNICITY_CHOICES, blank=True, null=True) other_ethnicity = models.CharField("", max_length=50, blank=True, null=True, help_text="Specify here if your ethnicity is not included above.") # Household below_2 = models.IntegerField(_('0 - 2 yrs'), blank=True, null=True) between_3_11 = models.IntegerField(_('3 - 11 yrs'), blank=True, null=True) between_12_18 = models.IntegerField(_('12 - 18 yrs'), blank=True, null=True) between_19_59 = models.IntegerField(_('19 - 59 yrs'), blank=True, null=True) above_60 = models.IntegerField(_('over 60 yrs'), blank=True, null=True) # Services ssa = models.BooleanField(_('social security administration'), default=False, help_text="current recipient of Social Security") dhs = models.BooleanField(_('department human services'), default=False, help_text="food stamps, WIC, TANF") children_needs = models.BooleanField( _('children needs'), default=False, help_text="school supplies, uniforms, clothing, child care, diapers, wipes") toiletries = models.BooleanField(_('toiletries'), default=False) employment = models.BooleanField(_('employment'), default=False) training = models.BooleanField(_('training'), default=False) food = models.BooleanField(_('food'), default=False) gas = models.BooleanField(_('gas'), default=False) prescription = models.BooleanField(_('prescription care'), default=False) other_service = models.CharField(_('other'), max_length=100, blank=True, null=True, help_text="Specify additional services needed.") # Internal case_notes = tinymce_models.HTMLField(_('case notes'), blank=True, null=True) items_provided = tinymce_models.HTMLField(_('items provided'), blank=True, null=True) loc = models.PointField(blank=True, null=True) def get_absolute_url(self): return reverse('social-services.relief_area', args=[self.pk]) def get_ethnicity(self): if self.ethnicity == 'other': return self.other_ethnicity return self.ethnicity def get_address(self): return "%s %s %s, %s %s %s" % ( self.address, self.address2, self.city, self.state, self.zipcode, self.country ) def save(self, *args, **kwargs): params = {'format': 'json', 'street': self.address, 'city': self.city, 'country': self.country} url = 'http://nominatim.openstreetmap.org/search' result = requests.get(url, params=params).json() if result: lat = result[0]['lat'] lng = result[0]['lon'] self.loc = "POINT(%s %s)" % (lng, lat) super(ReliefAssessment, self).save(*args, **kwargs)
class Chapter(BasePage): """ Chapters module. Similar to Pages with extra fields. """ entity = models.OneToOneField( Entity, null=True, on_delete=models.SET_NULL, ) mission = tinymce_models.HTMLField(null=True, blank=True) notes = tinymce_models.HTMLField(null=True, blank=True) sponsors = tinymce_models.HTMLField(blank=True, default='') featured_image = models.ForeignKey( File, null=True, default=None, related_name='chapters', help_text=_('Only jpg, gif, or png images.'), on_delete=models.SET_NULL) contact_name = models.CharField(max_length=200, null=True, blank=True) contact_email = models.CharField(max_length=200, null=True, blank=True) join_link = models.CharField(max_length=200, null=True, blank=True) group = models.ForeignKey(Group, on_delete=models.CASCADE) perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = ChapterManager() def __str__(self): return str(self.title) class Meta: app_label = 'chapters' def get_absolute_url(self): return reverse('chapters.detail', args=[self.slug]) def get_meta(self, name): """ This method is standard across all models that are related to the Meta model. Used to generate dynamic meta information niche to this model. """ return ChapterMeta().get_meta(self, name) def officers(self): return Officer.objects.filter(chapter=self).order_by('pk') def save(self, *args, **kwargs): photo_upload = kwargs.pop('photo', None) super(Chapter, self).save(*args, **kwargs) if photo_upload and self.pk: image = File(content_type=ContentType.objects.get_for_model( self.__class__), object_id=self.pk, creator=self.creator, creator_username=self.creator_username, owner=self.owner, owner_username=self.owner_username) photo_upload.file.seek(0) image.file.save(photo_upload.name, photo_upload) image.save() self.featured_image = image self.save()
class Video(TendenciBaseModel): """ Videos plugin to add embedding based on video url. Uses embed.ly """ title = models.CharField(max_length=200) slug = models.SlugField(unique=True, max_length=200) category = models.ForeignKey(Category) video_type = models.ForeignKey(VideoType, null=True, blank=True) image = models.ImageField(upload_to='uploads/videos/%y/%m', blank=True) video_url = models.CharField(max_length=500, help_text='Youtube, Vimeo, etc..') description = tinymce_models.HTMLField() tags = TagField(blank=True, help_text='Tag 1, Tag 2, ...') ordering = models.IntegerField(blank=True, null=True) perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = VideoManager() def __unicode__(self): return self.title def save(self, *args, **kwargs): model = self.__class__ if self.ordering is None: # Append try: last = model.objects.order_by('-ordering')[0] self.ordering = last.ordering + 1 except IndexError: # First row self.ordering = 0 return super(Video, self).save(*args, **kwargs) class Meta: permissions = (("view_video", "Can view video"), ) ordering = ('ordering', ) verbose_name = get_setting('module', 'videos', 'label') or "Video" verbose_name_plural = get_setting('module', 'videos', 'label_plural') or "Videos" app_label = 'videos' @models.permalink def get_absolute_url(self): return ("video.details", [self.slug]) def video_embed_url(self): """ Returns a youtube embed URL Attempts to convert common YouTube URL patterns to the URL embed pattern. TODO: Contribute more video service embed URL's """ import re url_pattern = r'http:\/\/www\.youtube\.com\/watch\?v=(\w+)' share_pattern = r'http:\/\/youtu\.be\/(\w+)' repl = lambda x: 'http://www.youtube.com/embed/%s' % x.group(1) if re.match(url_pattern, self.video_url): return re.sub(url_pattern, repl, self.video_url) if re.match(share_pattern, self.video_url): return re.sub(share_pattern, repl, self.video_url) return self.video_url def embed_code(self, **kwargs): width = kwargs.get('width') or 600 return get_oembed_code(self.video_url, width, 400) def thumbnail(self): return get_oembed_thumbnail(self.video_url, 600, 400)
class Article(TendenciBaseModel): CONTRIBUTOR_AUTHOR = 1 CONTRIBUTOR_PUBLISHER = 2 CONTRIBUTOR_CHOICES = ((CONTRIBUTOR_AUTHOR, _('Author')), (CONTRIBUTOR_PUBLISHER, _('Publisher'))) guid = models.CharField(max_length=40) slug = SlugField(_('URL Path'), unique=True) timezone = TimeZoneField(verbose_name=_('Time Zone'), default='US/Central', choices=get_timezone_choices(), max_length=100) headline = models.CharField(max_length=200, blank=True) summary = models.TextField(blank=True) body = tinymce_models.HTMLField() source = models.CharField(max_length=300, blank=True) first_name = models.CharField(_('First Name'), max_length=100, blank=True) last_name = models.CharField(_('Last Name'), max_length=100, blank=True) contributor_type = models.IntegerField(choices=CONTRIBUTOR_CHOICES, default=CONTRIBUTOR_AUTHOR) phone = models.CharField(max_length=50, blank=True) fax = models.CharField(max_length=50, blank=True) email = models.CharField(max_length=120, blank=True) website = models.CharField(max_length=300, blank=True) thumbnail = models.ForeignKey(File, null=True, on_delete=models.SET_NULL, help_text=_('The thumbnail image can be used on your homepage ' + 'or sidebar if it is setup in your theme. The thumbnail image ' + 'will not display on the news page.')) release_dt = models.DateTimeField(_('Release Date/Time'), null=True, blank=True) # used for better performance when retrieving a list of released articles release_dt_local = models.DateTimeField(null=True, blank=True) syndicate = models.BooleanField(_('Include in RSS feed'), default=True) featured = models.BooleanField(default=False) design_notes = models.TextField(_('Design Notes'), blank=True) group = models.ForeignKey(Group, null=True, default=get_default_group, on_delete=models.SET_NULL) tags = TagField(blank=True) # for podcast feeds enclosure_url = models.CharField(_('Enclosure URL'), max_length=500, blank=True) enclosure_type = models.CharField(_('Enclosure Type'), max_length=120, blank=True) enclosure_length = models.IntegerField(_('Enclosure Length'), default=0) not_official_content = models.BooleanField(_('Official Content'), blank=True, default=True) # html-meta tags meta = models.OneToOneField(MetaTags, null=True, on_delete=models.SET_NULL) categories = GenericRelation(CategoryItem, object_id_field="object_id", content_type_field="content_type") perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = ArticleManager() class Meta: # permissions = (("view_article", _("Can view article")),) verbose_name = _("Article") verbose_name_plural = _("Articles") app_label = 'articles' def get_meta(self, name): """ This method is standard across all models that are related to the Meta model. Used to generate dynamic methods coupled to this instance. """ return ArticleMeta().get_meta(self, name) def get_absolute_url(self): return reverse('article', args=[self.slug]) def get_version_url(self, hash): return reverse('article.version', args=[hash]) def __str__(self): return self.headline def get_thumbnail_url(self): if not self.thumbnail: return u'' return reverse('file', args=[self.thumbnail.pk]) def save(self, *args, **kwargs): if not self.id: self.guid = str(uuid.uuid4()) self.assign_release_dt_local() super(Article, self).save(*args, **kwargs) def assign_release_dt_local(self): """ convert release_dt to the corresponding local time example: if release_dt: 2014-05-09 03:30:00 timezone: US/Pacific settings.TIME_ZONE: US/Central then the corresponding release_dt_local will be: 2014-05-09 05:30:00 """ now = datetime.now() now_with_tz = adjust_datetime_to_timezone(now, settings.TIME_ZONE) if self.timezone and self.release_dt and self.timezone.zone != settings.TIME_ZONE: time_diff = adjust_datetime_to_timezone(now, self.timezone) - now_with_tz self.release_dt_local = self.release_dt + time_diff else: self.release_dt_local = self.release_dt def age(self): return datetime.now() - self.create_dt @property def category_set(self): items = {} for cat in self.categories.select_related('category', 'parent'): if cat.category: items["category"] = cat.category elif cat.parent: items["sub_category"] = cat.parent return items @property def has_google_author(self): return self.contributor_type == self.CONTRIBUTOR_AUTHOR @property def has_google_publisher(self): return self.contributor_type == self.CONTRIBUTOR_PUBLISHER
class Resume(TendenciBaseModel): guid = models.CharField(max_length=40) title = models.CharField(max_length=250) slug = SlugField(_('URL Path'), unique=True) description = tinymce_models.HTMLField() location = models.CharField( max_length=500, blank=True ) # cannot be foreign, needs to be open 'Texas' 'All 50 States' 'US and International' skills = models.TextField(blank=True) experience = models.TextField(blank=True) awards = models.TextField(_('Awards and Certifications'), blank=True) education = models.TextField(blank=True) is_agency = models.BooleanField( default=False ) # defines if the resume posting is by a third party agency #TODO: do we need these fields? #desiredlocationstate = models.CharField(max_length=50) #desiredlocationcountry = models.CharField(max_length=50) #willingtorelocate = models.NullBooleanField() #workschedulepreferred = models.CharField(max_length=100) #compensationdesired = models.CharField(max_length=50) #licenses = models.CharField(max_length=100) #certifications = models.CharField(max_length=100) #expertise = models.CharField(max_length=800) #languages = models.CharField(max_length=120) # date related fields list_type = models.CharField(max_length=50, default='regular') # premium or regular requested_duration = models.IntegerField(default=30) activation_dt = models.DateTimeField( null=True, blank=True) # date resume listing was activated expiration_dt = models.DateTimeField( null=True, blank=True ) # date resume expires based on activation date and duration resume_url = models.CharField( max_length=300, blank=True) # link to other (fuller) resume posting resume_file = models.FileField(_('Upload your resume here'), max_length=260, upload_to=file_directory, blank=True, default="") syndicate = models.BooleanField(_('Include in RSS feed'), blank=True, default=False) #TODO: foreign contact_name = models.CharField(max_length=150, blank=True) contact_address = models.CharField(max_length=50, blank=True) contact_address2 = models.CharField(max_length=50, blank=True) contact_city = models.CharField(max_length=50, blank=True) contact_state = models.CharField(max_length=50, blank=True) contact_zip_code = models.CharField(max_length=50, blank=True) contact_country = models.CharField(max_length=50, blank=True) contact_phone = models.CharField(max_length=50, blank=True) contact_phone2 = models.CharField(max_length=50, blank=True) contact_fax = models.CharField(max_length=50, blank=True) contact_email = models.CharField(max_length=300, blank=True) contact_website = models.CharField(max_length=300, blank=True) # authority fields # allow_anonymous_view = models.NullBooleanField(_("Public can view")) # allow_user_view = models.NullBooleanField(_("Signed in user can view")) # allow_member_view = models.NullBooleanField() # allow_anonymous_edit = models.NullBooleanField() # allow_user_edit = models.NullBooleanField(_("Signed in user can change")) # allow_member_edit = models.NullBooleanField() # create_dt = models.DateTimeField(auto_now_add=True) # update_dt = models.DateTimeField(auto_now=True) # creator = models.ForeignKey(User, related_name="%(class)s_creator", editable=False, null=True, on_delete=models.SET_NULL) # creator_username = models.CharField(max_length=50, null=True) # owner = models.ForeignKey(User, related_name="%(class)s_owner", null=True, on_delete=models.SET_NULL) # owner_username = models.CharField(max_length=50, null=True) # status = models.NullBooleanField("Active", default=True) # status_detail = models.CharField(max_length=50, default='active') meta = models.OneToOneField(MetaTags, null=True, on_delete=models.SET_NULL) tags = TagField(blank=True) perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = ResumeManager() class Meta: permissions = (("view_resume", _("Can view resume")), ) app_label = 'resumes' def get_meta(self, name): """ This method is standard across all models that are related to the Meta model. Used to generate dynamic meta information niche to this model. """ return ResumeMeta().get_meta(self, name) def get_absolute_url(self): return reverse('resume', args=[self.slug]) def save(self, *args, **kwargs): self.guid = self.guid or uuid.uuid4() super(Resume, self).save(*args, **kwargs) def __str__(self): return self.title def is_pending(self): return self.status == 0 and self.status_detail == 'pending'
class Video(OrderingBaseModel, TendenciBaseModel): """ Videos plugin to add embedding based on video url. Uses embed.ly """ title = models.CharField(max_length=200) slug = models.SlugField(_('URL Path'), unique=True, max_length=200) category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL) video_type = models.ForeignKey(VideoType, null=True, blank=True, on_delete=models.SET_NULL) image = models.ImageField(upload_to='uploads/videos/%y/%m', blank=True) video_url = models.CharField(max_length=500, help_text='Youtube, Vimeo, etc..') description = tinymce_models.HTMLField() release_dt = models.DateTimeField(_("Release Date"), null=True) tags = TagField(blank=True, help_text='Tag 1, Tag 2, ...') perms = GenericRelation(ObjectPermission, object_id_field="object_id", content_type_field="content_type") objects = VideoManager() def __str__(self): return self.title def save(self, *args, **kwargs): model = self.__class__ if self.pk is None: # Append try: last = model.objects.order_by('-position')[0] self.position = last.position + 1 except IndexError: # First row self.position = 0 return super(Video, self).save(*args, **kwargs) class Meta: #permissions = (("view_video","Can view video"),) ordering = ('position', ) verbose_name = get_setting('module', 'videos', 'label') or "Video" verbose_name_plural = get_setting('module', 'videos', 'label_plural') or "Videos" app_label = 'videos' def get_absolute_url(self): return reverse('video.details', args=[self.slug]) def video_embed_url(self): """ Returns a youtube embed URL Attempts to convert common YouTube URL patterns to the URL embed pattern. TODO: Contribute more video service embed URL's """ url_pattern = r'https:\/\/www\.youtube\.com\/watch\?v=(\w+)' share_pattern = r'https:\/\/youtu\.be\/(\w+)' def repl(x): return 'https://www.youtube.com/embed/%s' % x.group(1) if re.match(url_pattern, self.video_url): return re.sub(url_pattern, repl, self.video_url) if re.match(share_pattern, self.video_url): return re.sub(share_pattern, repl, self.video_url) return self.video_url def embed_code(self, **kwargs): width = kwargs.get('width') or 600 height = kwargs.get('height') or 400 return get_oembed_code(self.video_url, width, height) def thumbnail(self): return get_oembed_thumbnail(self.video_url, 600, 400) def is_youtube_video(self): return 'www.youtube.com' in self.video_url def youtube_video_id(self): if self.is_youtube_video(): return get_embed_ready_url(self.video_url).replace( 'https://www.youtube.com/embed/', '') return None
class Email(TendenciBaseModel): guid = models.CharField(max_length=50) priority = models.IntegerField(default=0) subject =models.CharField(max_length=255) body = tinymce_models.HTMLField() #body = models.TextField() sender = models.CharField(max_length=255) sender_display = models.CharField(max_length=255) reply_to = models.CharField(max_length=255) recipient = models.CharField(max_length=255, blank=True, default='') recipient_dispaly = models.CharField(max_length=255, blank=True, default='') recipient_cc = models.CharField(max_length=255, blank=True, default='') recipient_cc_display = models.CharField(max_length=255, blank=True, default='') recipient_bcc = models.CharField(max_length=255, blank=True, default='') attachments = models.CharField(max_length=500, blank=True, default='') content_type = models.CharField(max_length=255, default='text/html', choices=(('text/html','text/html'),('text','text'),)) #create_dt = models.DateTimeField(auto_now_add=True) #status = models.NullBooleanField(default=True, choices=((True,'Active'),(False,'Inactive'),)) class Meta: app_label = 'emails' @models.permalink def get_absolute_url(self): return ("email.view", [self.pk]) def __unicode__(self): return self.subject def send(self, fail_silently=False, **kwargs): recipient_list = [] recipient_bcc_list = [] headers = kwargs.get('headers', {}) attachments = kwargs.get('attachments', []) if isinstance(self.recipient, basestring): recipient_list = self.recipient.split(',') recipient_list = [recipient.strip() for recipient in recipient_list \ if recipient.strip() <> ''] else: recipient_list = list(self.recipient) if isinstance(self.recipient_cc, basestring): recipient_cc_list = self.recipient_cc.split(',') recipient_cc_list = [recipient_cc.strip() for recipient_cc in recipient_cc_list if \ recipient_cc.strip() <> ''] recipient_list += recipient_cc_list else: recipient_list += list(self.recipient_cc) if isinstance(self.recipient_bcc, basestring): recipient_bcc_list = self.recipient_bcc.split(',') recipient_bcc_list = [recipient_bcc.strip() for recipient_bcc in recipient_bcc_list if \ recipient_bcc.strip() <> ''] else: recipient_bcc_list = list(self.recipient_bcc) if self.reply_to: headers['Reply-To'] = self.reply_to if not self.sender: self.sender = get_setting('site', 'global', 'siteemailnoreplyaddress') or settings.DEFAULT_FROM_EMAIL if self.sender_display: headers['From'] = '%s<%s>' % (self.sender_display, self.sender) if self.priority and self.priority == 1: headers['X-Priority'] = '1' headers['X-MSMail-Priority'] = 'High' if recipient_list or recipient_bcc_list: msg = EmailMessage(self.subject, self.body, self.sender, recipient_list, recipient_bcc_list, headers=headers, connection=kwargs.get('connection', None)) if self.content_type == 'html' or self.content_type == 'text/html': msg.content_subtype = 'html' if attachments: msg.attachments = attachments msg.send(fail_silently=fail_silently) def save(self, user=None, *args, **kwargs): if not self.id: self.guid = uuid.uuid1() if user and not user.is_anonymous(): self.creator=user self.creator_username=user.username if user and not user.is_anonymous(): self.owner=user self.owner_username=user.username super(Email, self).save(*args, **kwargs) # if this email allows view by user2_compare def allow_view_by(self, user2_compare): boo = False if user2_compare.profile.is_superuser: boo = True else: if user2_compare == self.creator or user2_compare == self.owner: if self.status: boo = True else: if user2_compare.has_perm('emails.view_email', self): if self.status == 1 and self.status_detail=='active': boo = True return boo # if this email allows edit by user2_compare def allow_edit_by(self, user2_compare): boo = False if user2_compare.profile.is_superuser: boo = True else: if user2_compare == self.user: boo = True else: if user2_compare == self.creator or user2_compare == self.owner: if self.status: boo = True else: if user2_compare.has_perm('emails.edit_email', self): if self.status: boo = True return boo def template_body(self, email_d): """ build the email body from the template and variables passed in by a dictionary """ import os.path from django.template.loader import render_to_string template = email_d.get('template_path_name', '') # check if this template exists boo = False for dir in settings.TEMPLATE_DIRS: if os.path.isfile(os.path.join(dir, template)): boo = True break if not boo: # log an event # notify admin of missing template pass else: self.body = render_to_string(template) for key in email_d.keys(): # need to convert [blah] to %5Bblah%5D for replace line tmp_value = "%5B" + key[1:-1] + "%5D" if email_d[key] <> None: self.body = self.body.replace(key, email_d[key]) self.body = self.body.replace(tmp_value, email_d[key]) else: self.body = self.body.replace(key, '') self.body = self.body.replace(tmp_value, '') return boo