gremmie@1: """ gremmie@1: Models for the news application. gremmie@1: """ bgneal@997: import datetime gremmie@1: bgneal@1002: from django.core.urlresolvers import reverse gremmie@1: from django.db import models bgneal@49: from django.contrib.auth.models import User gremmie@1: from tagging.fields import TagField gremmie@1: bgneal@997: from core.markup import site_markup bgneal@997: bgneal@997: bgneal@997: # News App versions bgneal@997: NEWS_VERSION = 2 bgneal@997: gremmie@1: gremmie@1: class Category(models.Model): bgneal@54: """News stories belong to categories""" bgneal@240: title = models.CharField(max_length=64) bgneal@240: slug = models.SlugField(max_length=64) bgneal@54: icon = models.ImageField(upload_to='news/categories/', blank=True) bgneal@1001: forum_slug = models.CharField( bgneal@1001: max_length=80, bgneal@1001: default='', bgneal@1001: blank=True, bgneal@1001: help_text=("Identifies the forum to create comment threads in for " bgneal@1001: "stories in this category. If blank, no comment threads " bgneal@1001: "will be created for stories in this category.")) gremmie@1: bgneal@54: def __unicode__(self): bgneal@54: return self.title gremmie@1: bgneal@54: def num_stories(self): bgneal@987: return Story.objects.filter(category=self.pk).count() gremmie@1: bgneal@54: class Meta: bgneal@54: verbose_name_plural = 'Categories' bgneal@54: ordering = ('title', ) gremmie@1: gremmie@1: bgneal@204: class StoryBase(models.Model): bgneal@204: """Abstract model to collect common fields.""" bgneal@54: title = models.CharField(max_length=255) bgneal@54: submitter = models.ForeignKey(User) bgneal@54: category = models.ForeignKey(Category) bgneal@999: short_text = models.TextField(default='', blank=True) bgneal@998: long_text = models.TextField(default='', blank=True) bgneal@204: date_submitted = models.DateTimeField(db_index=True) bgneal@54: allow_comments = models.BooleanField(default=True) bgneal@54: tags = TagField() bgneal@218: front_page_expiration = models.DateField(null=True, blank=True) bgneal@277: update_date = models.DateTimeField(db_index=True, blank=True) bgneal@462: priority = models.IntegerField(db_index=True, default=0, blank=True) bgneal@486: meta_description = models.TextField(blank=True) bgneal@1005: short_markup = models.TextField(default='', blank=True) bgneal@997: long_markup = models.TextField(default='', blank=True) bgneal@997: admin_content = models.TextField(default='', blank=True) bgneal@997: version = models.SmallIntegerField(default=NEWS_VERSION) gremmie@1: bgneal@204: class Meta: bgneal@204: abstract = True bgneal@204: bgneal@182: def save(self, *args, **kwargs): bgneal@204: if not self.pk: bgneal@997: self.date_submitted = datetime.datetime.now() bgneal@277: self.update_date = self.date_submitted bgneal@277: else: bgneal@277: self.update_date = datetime.datetime.now() bgneal@204: bgneal@1000: if self.version >= 2: bgneal@1000: self.short_text = kwargs.pop('short_text', '') bgneal@1000: if not self.short_text and self.short_markup: bgneal@1000: self.short_text = site_markup(self.short_markup) bgneal@997: bgneal@1000: self.long_text = kwargs.pop('long_text', '') bgneal@1000: if not self.long_text and self.long_markup: bgneal@1000: self.long_text = site_markup(self.long_markup) bgneal@997: bgneal@997: super(StoryBase, self).save(*args, **kwargs) bgneal@997: bgneal@997: bgneal@997: class PendingStory(StoryBase): bgneal@997: """Stories submitted by users are held pending admin approval""" gremmie@1: bgneal@54: def __unicode__(self): bgneal@54: return self.title gremmie@1: bgneal@54: class Meta: bgneal@997: ordering = ['-date_submitted'] bgneal@54: verbose_name_plural = 'Pending Stories' gremmie@1: gremmie@1: bgneal@204: class Story(StoryBase): bgneal@54: """Model for news stories""" bgneal@1001: forums_topic = models.OneToOneField('forums.Topic', blank=True, null=True, bgneal@1001: on_delete=models.SET_NULL, bgneal@1001: db_index=False, bgneal@1001: help_text="Forum topic used for comments") gremmie@1: bgneal@54: def get_absolute_url(self): bgneal@1002: return reverse('news-story', args=[str(self.id)]) gremmie@1: bgneal@54: def __unicode__(self): bgneal@54: return self.title gremmie@1: bgneal@54: class Meta: bgneal@997: ordering = ['-date_submitted'] bgneal@226: verbose_name = 'news story' bgneal@226: verbose_name_plural = 'news stories' gremmie@1: bgneal@54: def can_comment_on(self): bgneal@1001: # Only used for version 0 stories bgneal@54: now = datetime.datetime.now() bgneal@204: delta = now - self.date_submitted bgneal@204: return self.allow_comments and delta.days < 30 bgneal@220: bgneal@1001: def forums_comment_count(self): bgneal@1001: """Returns number of comments for V2 news stories.""" bgneal@1001: if self.forums_topic: bgneal@1001: return max(0, self.forums_topic.post_count - 1) bgneal@1001: return 0 bgneal@1001: bgneal@220: def search_title(self): bgneal@220: return self.title bgneal@220: bgneal@220: def search_summary(self): bgneal@220: return u"\n".join((self.short_text, self.long_text)) bgneal@484: bgneal@484: def ogp_tags(self): bgneal@484: """ bgneal@484: Returns a dict of Open Graph Protocol meta tags. bgneal@484: bgneal@484: """ bgneal@486: desc = self.meta_description.strip() bgneal@486: if not desc: bgneal@486: desc = 'News article submitted by %s on %s.' % ( bgneal@486: self.submitter.username, bgneal@486: self.date_submitted.strftime('%B %d, %Y')) bgneal@486: bgneal@484: return { bgneal@484: 'og:title': self.title, bgneal@484: 'og:type': 'article', bgneal@484: 'og:url': self.get_absolute_url(), bgneal@484: 'og:image': self.category.icon.url, bgneal@486: 'og:description': desc, bgneal@484: }