Statistics
| Branch: | Tag: | Revision:

root / cloudcmsblog / models.py @ bd2ee623

History | View | Annotate | Download (7.8 kB)

1 52271184 Kostas Papadimitriou
# Copyright 2012 GRNET S.A. All rights reserved.
2 52271184 Kostas Papadimitriou
#
3 52271184 Kostas Papadimitriou
# Redistribution and use in source and binary forms, with or
4 52271184 Kostas Papadimitriou
# without modification, are permitted provided that the following
5 52271184 Kostas Papadimitriou
# conditions are met:
6 52271184 Kostas Papadimitriou
#
7 52271184 Kostas Papadimitriou
#   1. Redistributions of source code must retain the above
8 52271184 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
9 52271184 Kostas Papadimitriou
#      disclaimer.
10 52271184 Kostas Papadimitriou
#
11 52271184 Kostas Papadimitriou
#   2. Redistributions in binary form must reproduce the above
12 52271184 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
13 52271184 Kostas Papadimitriou
#      disclaimer in the documentation and/or other materials
14 52271184 Kostas Papadimitriou
#      provided with the distribution.
15 52271184 Kostas Papadimitriou
#
16 52271184 Kostas Papadimitriou
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 52271184 Kostas Papadimitriou
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 52271184 Kostas Papadimitriou
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 52271184 Kostas Papadimitriou
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 52271184 Kostas Papadimitriou
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 52271184 Kostas Papadimitriou
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 52271184 Kostas Papadimitriou
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 52271184 Kostas Papadimitriou
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 52271184 Kostas Papadimitriou
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 52271184 Kostas Papadimitriou
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 52271184 Kostas Papadimitriou
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 52271184 Kostas Papadimitriou
# POSSIBILITY OF SUCH DAMAGE.
28 52271184 Kostas Papadimitriou
#
29 52271184 Kostas Papadimitriou
# The views and conclusions contained in the software and
30 52271184 Kostas Papadimitriou
# documentation are those of the authors and should not be
31 52271184 Kostas Papadimitriou
# interpreted as representing official policies, either expressed
32 52271184 Kostas Papadimitriou
# or implied, of GRNET S.A.
33 52271184 Kostas Papadimitriou
34 52271184 Kostas Papadimitriou
35 c1468bcc Kostas Papadimitriou
from datetime import datetime
36 c1468bcc Kostas Papadimitriou
37 c1468bcc Kostas Papadimitriou
from django.db import models
38 c1468bcc Kostas Papadimitriou
from django.conf import settings
39 c1468bcc Kostas Papadimitriou
from django.contrib.auth.models import User
40 c1468bcc Kostas Papadimitriou
from django.utils.translation import ugettext_lazy as _, ugettext, ungettext
41 f6e90a2b Kostas Papadimitriou
from django.template.loader import render_to_string
42 f6e90a2b Kostas Papadimitriou
from django.core import urlresolvers
43 c1468bcc Kostas Papadimitriou
44 c1468bcc Kostas Papadimitriou
from feincms import translations
45 c1468bcc Kostas Papadimitriou
from feincms.models import Base
46 f6e90a2b Kostas Papadimitriou
from feincms.module.page.models import Page
47 c1468bcc Kostas Papadimitriou
from feincms.content.richtext.models import RichTextContent
48 c1468bcc Kostas Papadimitriou
from feincms.content.section.models import SectionContent
49 f6e90a2b Kostas Papadimitriou
from feincms.content.application.models import reverse
50 c1468bcc Kostas Papadimitriou
from feincms.module.medialibrary.fields import MediaFileForeignKey
51 c1468bcc Kostas Papadimitriou
from feincms.module.medialibrary.models import MediaFile
52 c1468bcc Kostas Papadimitriou
from feincms.module.page.extensions.navigation import NavigationExtension
53 c1468bcc Kostas Papadimitriou
from feincms.module.page.extensions.navigation import PagePretender
54 f6e90a2b Kostas Papadimitriou
from feincms.content.application.models import ApplicationContent
55 c1468bcc Kostas Papadimitriou
56 c1468bcc Kostas Papadimitriou
from cloudcms.models import Application
57 719d8d08 Kostas Papadimitriou
from cloudcms.cms_utils import get_app_page
58 c1468bcc Kostas Papadimitriou
59 f6e90a2b Kostas Papadimitriou
# monkeypatch django reverse (feincms 1.5+ solves this issue)
60 f6e90a2b Kostas Papadimitriou
urlresolvers.reverse = reverse
61 c1468bcc Kostas Papadimitriou
62 c1468bcc Kostas Papadimitriou
class Category(models.Model, translations.TranslatedObjectMixin):
63 c1468bcc Kostas Papadimitriou
    """
64 c1468bcc Kostas Papadimitriou
    Blog entry category. Each blog post may belong to multiple categories.
65 c1468bcc Kostas Papadimitriou
    """
66 c1468bcc Kostas Papadimitriou
67 c1468bcc Kostas Papadimitriou
    ordering = models.SmallIntegerField(_('ordering'), default=0)
68 c1468bcc Kostas Papadimitriou
    display_on_menu = models.BooleanField(default=False)
69 c1468bcc Kostas Papadimitriou
70 c1468bcc Kostas Papadimitriou
    class Meta:
71 c1468bcc Kostas Papadimitriou
        verbose_name = _('category')
72 c1468bcc Kostas Papadimitriou
        verbose_name_plural = _('categories')
73 c1468bcc Kostas Papadimitriou
        ordering = ['-ordering',]
74 c1468bcc Kostas Papadimitriou
75 c1468bcc Kostas Papadimitriou
    objects = translations.TranslatedObjectManager()
76 c1468bcc Kostas Papadimitriou
77 c1468bcc Kostas Papadimitriou
    def __unicode__(self):
78 c1468bcc Kostas Papadimitriou
        trans = translations.TranslatedObjectMixin.__unicode__(self)
79 c1468bcc Kostas Papadimitriou
        return trans or _('Unnamed category')
80 c1468bcc Kostas Papadimitriou
81 c1468bcc Kostas Papadimitriou
82 c1468bcc Kostas Papadimitriou
class CategoryTranslation(translations.Translation(Category)):
83 c1468bcc Kostas Papadimitriou
    """
84 c1468bcc Kostas Papadimitriou
    Category translation
85 c1468bcc Kostas Papadimitriou
    """
86 c1468bcc Kostas Papadimitriou
    title = models.CharField(_('category title'), max_length=100)
87 c1468bcc Kostas Papadimitriou
    slug = models.SlugField(_('slug'), unique=True)
88 c1468bcc Kostas Papadimitriou
    description = models.CharField(_('description'), max_length=250, blank=True)
89 c1468bcc Kostas Papadimitriou
90 c1468bcc Kostas Papadimitriou
    class Meta:
91 c1468bcc Kostas Papadimitriou
        verbose_name = _('category translation')
92 c1468bcc Kostas Papadimitriou
        verbose_name_plural = _('category translations')
93 c1468bcc Kostas Papadimitriou
        ordering = ['title']
94 c1468bcc Kostas Papadimitriou
95 c1468bcc Kostas Papadimitriou
    def __unicode__(self):
96 c1468bcc Kostas Papadimitriou
        return self.title
97 c1468bcc Kostas Papadimitriou
98 c1468bcc Kostas Papadimitriou
    def get_absolute_url(self):
99 f6e90a2b Kostas Papadimitriou
        return reverse('cloudcmsblog_entries_archive', 'cloudcmsblog.urls', (), {
100 c1468bcc Kostas Papadimitriou
            'category': self.slug,
101 f6e90a2b Kostas Papadimitriou
        })
102 c1468bcc Kostas Papadimitriou
103 c1468bcc Kostas Papadimitriou
    def save(self, *args, **kwargs):
104 c1468bcc Kostas Papadimitriou
        if not self.slug:
105 c1468bcc Kostas Papadimitriou
            self.slug = slugify(self.title)
106 c1468bcc Kostas Papadimitriou
107 c1468bcc Kostas Papadimitriou
        super(CategoryTranslation, self).save(*args, **kwargs)
108 c1468bcc Kostas Papadimitriou
109 c1468bcc Kostas Papadimitriou
110 c1468bcc Kostas Papadimitriou
class EntryManager(models.Manager):
111 c1468bcc Kostas Papadimitriou
112 c1468bcc Kostas Papadimitriou
    def active(self):
113 c1468bcc Kostas Papadimitriou
        return self.filter(is_active=True)
114 c1468bcc Kostas Papadimitriou
115 f6e90a2b Kostas Papadimitriou
    def latest(self, limit=3):
116 f6e90a2b Kostas Papadimitriou
        return self.filter()[:limit]
117 f6e90a2b Kostas Papadimitriou
118 719d8d08 Kostas Papadimitriou
119 719d8d08 Kostas Papadimitriou
def get_blog_page():
120 719d8d08 Kostas Papadimitriou
    """
121 719d8d08 Kostas Papadimitriou
    Returns Page model that has been associated with blog application
122 719d8d08 Kostas Papadimitriou
    """
123 719d8d08 Kostas Papadimitriou
    return get_app_page(Page, "cloudcmsblog")
124 719d8d08 Kostas Papadimitriou
125 c1468bcc Kostas Papadimitriou
class Entry(Base):
126 c1468bcc Kostas Papadimitriou
    """
127 c1468bcc Kostas Papadimitriou
    Blog post entry
128 c1468bcc Kostas Papadimitriou
    """
129 c1468bcc Kostas Papadimitriou
    is_active = models.BooleanField(_('is active'), default=True)
130 c1468bcc Kostas Papadimitriou
    is_featured = models.BooleanField(_('is featured'), default=False)
131 c1468bcc Kostas Papadimitriou
132 c1468bcc Kostas Papadimitriou
    title = models.CharField(_('title'), max_length=100)
133 c1468bcc Kostas Papadimitriou
    slug = models.SlugField(_('slug'), max_length=100, unique_for_date='published_on')
134 c1468bcc Kostas Papadimitriou
    author = models.ForeignKey(User, related_name='blogentries', verbose_name=_('author'))
135 c1468bcc Kostas Papadimitriou
    language = models.CharField(max_length=255, choices=settings.LANGUAGES)
136 c1468bcc Kostas Papadimitriou
137 c1468bcc Kostas Papadimitriou
    intro_text = models.TextField(max_length=255,
138 c1468bcc Kostas Papadimitriou
            help_text="Displayed in list views", blank=True)
139 c1468bcc Kostas Papadimitriou
    image = MediaFileForeignKey(MediaFile, null=True, blank=True)
140 c1468bcc Kostas Papadimitriou
    application = models.ManyToManyField(Application,
141 c1468bcc Kostas Papadimitriou
            related_name="blogentries",
142 c1468bcc Kostas Papadimitriou
            verbose_name=_('application'))
143 c1468bcc Kostas Papadimitriou
144 c1468bcc Kostas Papadimitriou
    published_on = models.DateTimeField(_('published on'), blank=True, null=True, default=datetime.now,
145 c1468bcc Kostas Papadimitriou
        help_text=_('Will be filled in automatically when entry gets published.'))
146 c1468bcc Kostas Papadimitriou
    last_changed = models.DateTimeField(_('last change'), auto_now=True, editable=False)
147 c1468bcc Kostas Papadimitriou
148 c1468bcc Kostas Papadimitriou
    categories = models.ManyToManyField(Category, verbose_name=_('categories'),
149 c1468bcc Kostas Papadimitriou
        related_name='blogentries', null=True, blank=True)
150 c1468bcc Kostas Papadimitriou
151 c1468bcc Kostas Papadimitriou
    objects = EntryManager()
152 c1468bcc Kostas Papadimitriou
153 c1468bcc Kostas Papadimitriou
    class Meta:
154 c1468bcc Kostas Papadimitriou
        get_latest_by = 'published_on'
155 c1468bcc Kostas Papadimitriou
        ordering = ['-published_on']
156 c1468bcc Kostas Papadimitriou
        verbose_name = _('entry')
157 c1468bcc Kostas Papadimitriou
        verbose_name_plural = _('entries')
158 c1468bcc Kostas Papadimitriou
159 c1468bcc Kostas Papadimitriou
    def __unicode__(self):
160 c1468bcc Kostas Papadimitriou
        return self.title
161 c1468bcc Kostas Papadimitriou
162 c1468bcc Kostas Papadimitriou
    def get_absolute_url(self):
163 f6e90a2b Kostas Papadimitriou
        try:
164 f6e90a2b Kostas Papadimitriou
            r = reverse('cloudcmsblog_entry_detail', 'cloudcmsblog.urls', (),
165 f6e90a2b Kostas Papadimitriou
                    {
166 f6e90a2b Kostas Papadimitriou
                    'year': self.published_on.strftime('%Y'),
167 f6e90a2b Kostas Papadimitriou
                    'month': self.published_on.strftime('%m'),
168 f6e90a2b Kostas Papadimitriou
                    'day': self.published_on.strftime('%d'),
169 f6e90a2b Kostas Papadimitriou
                    'slug': self.slug,
170 f6e90a2b Kostas Papadimitriou
                    })
171 f6e90a2b Kostas Papadimitriou
        except Exception,e:
172 f6e90a2b Kostas Papadimitriou
            pass
173 f6e90a2b Kostas Papadimitriou
174 f6e90a2b Kostas Papadimitriou
        # ugly hack to fix proper application reverse url
175 f6e90a2b Kostas Papadimitriou
        BLOG_URL = ""
176 f6e90a2b Kostas Papadimitriou
        try:
177 719d8d08 Kostas Papadimitriou
            BLOG_URL = get_blog_page().get_navigation_url()
178 f6e90a2b Kostas Papadimitriou
        except Exception, e:
179 f6e90a2b Kostas Papadimitriou
            print e
180 64ef316d Kostas Papadimitriou
181 f6e90a2b Kostas Papadimitriou
        if r.startswith(BLOG_URL):
182 f6e90a2b Kostas Papadimitriou
            return r
183 f6e90a2b Kostas Papadimitriou
        else:
184 64ef316d Kostas Papadimitriou
            return BLOG_URL + r.lstrip('/')
185 c1468bcc Kostas Papadimitriou
186 aa8ce0dc Kostas Papadimitriou
    def back_url(self):
187 719d8d08 Kostas Papadimitriou
        return get_blog_page().get_navigation_url()
188 aa8ce0dc Kostas Papadimitriou
189 c1468bcc Kostas Papadimitriou
190 c1468bcc Kostas Papadimitriou
# Feincms navigation extension
191 c1468bcc Kostas Papadimitriou
class BlogCategoriesNavigationExtension(NavigationExtension):
192 c1468bcc Kostas Papadimitriou
    """
193 c1468bcc Kostas Papadimitriou
    Navigation extension for FeinCMS which lists all categories that user
194 c1468bcc Kostas Papadimitriou
    wants to include in global site navigation.
195 c1468bcc Kostas Papadimitriou
    """
196 c1468bcc Kostas Papadimitriou
197 c1468bcc Kostas Papadimitriou
    name = _('blog categories')
198 c1468bcc Kostas Papadimitriou
199 c1468bcc Kostas Papadimitriou
    def children(self, page, **kwargs):
200 c1468bcc Kostas Papadimitriou
        for category in Category.objects.filter(display_on_menu=True):
201 c1468bcc Kostas Papadimitriou
            url='%scategory/%s/' % (page.get_absolute_url(), category.translation.slug)
202 c1468bcc Kostas Papadimitriou
            yield PagePretender(
203 c1468bcc Kostas Papadimitriou
                title=category.translation.title,
204 c1468bcc Kostas Papadimitriou
                tree_id=page.tree_id,
205 c1468bcc Kostas Papadimitriou
                url=url,
206 c1468bcc Kostas Papadimitriou
                lft=0,
207 c1468bcc Kostas Papadimitriou
                rght=0,
208 c1468bcc Kostas Papadimitriou
                slug=category.translation.slug,
209 c1468bcc Kostas Papadimitriou
            )
210 c1468bcc Kostas Papadimitriou
211 f6e90a2b Kostas Papadimitriou
212 f6e90a2b Kostas Papadimitriou
# Feincms content abstract models
213 f6e90a2b Kostas Papadimitriou
class LatestEntries(models.Model):
214 f6e90a2b Kostas Papadimitriou
    title = models.CharField(max_length=255)
215 f6e90a2b Kostas Papadimitriou
    limit = models.PositiveIntegerField(default=3)
216 f6e90a2b Kostas Papadimitriou
    display_text = models.BooleanField(default=False)
217 f6e90a2b Kostas Papadimitriou
218 f6e90a2b Kostas Papadimitriou
    class Meta:
219 f6e90a2b Kostas Papadimitriou
        abstract = True
220 f6e90a2b Kostas Papadimitriou
        verbose_name = _('Latest blog entries')
221 f6e90a2b Kostas Papadimitriou
        verbose_name_plural = _('Latest blog entries')
222 f6e90a2b Kostas Papadimitriou
223 f6e90a2b Kostas Papadimitriou
    def render(self, **kwargs):
224 f6e90a2b Kostas Papadimitriou
        return render_to_string(['content/latest_blog.html'], {'posts':
225 f6e90a2b Kostas Papadimitriou
            Entry.objects.latest(self.limit), 'content': self})