Statistics
| Branch: | Tag: | Revision:

root / cloudcmsblog / models.py @ f6e90a2b

History | View | Annotate | Download (7.7 kB)

1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34

    
35
from datetime import datetime
36

    
37
from django.db import models
38
from django.conf import settings
39
from django.contrib.auth.models import User
40
from django.utils.translation import ugettext_lazy as _, ugettext, ungettext
41
from django.template.loader import render_to_string
42
from django.core import urlresolvers
43

    
44
from feincms import translations
45
from feincms.models import Base
46
from feincms.module.page.models import Page
47
from feincms.content.richtext.models import RichTextContent
48
from feincms.content.section.models import SectionContent
49
from feincms.content.application.models import reverse
50
from feincms.module.medialibrary.fields import MediaFileForeignKey
51
from feincms.module.medialibrary.models import MediaFile
52
from feincms.module.page.extensions.navigation import NavigationExtension
53
from feincms.module.page.extensions.navigation import PagePretender
54
from feincms.content.application.models import ApplicationContent
55

    
56
from cloudcms.models import Application
57

    
58
# monkeypatch django reverse (feincms 1.5+ solves this issue)
59
urlresolvers.reverse = reverse
60

    
61
class Category(models.Model, translations.TranslatedObjectMixin):
62
    """
63
    Blog entry category. Each blog post may belong to multiple categories.
64
    """
65

    
66
    ordering = models.SmallIntegerField(_('ordering'), default=0)
67
    display_on_menu = models.BooleanField(default=False)
68

    
69
    class Meta:
70
        verbose_name = _('category')
71
        verbose_name_plural = _('categories')
72
        ordering = ['-ordering',]
73

    
74
    objects = translations.TranslatedObjectManager()
75

    
76
    def __unicode__(self):
77
        trans = translations.TranslatedObjectMixin.__unicode__(self)
78
        return trans or _('Unnamed category')
79

    
80

    
81
class CategoryTranslation(translations.Translation(Category)):
82
    """
83
    Category translation
84
    """
85
    title = models.CharField(_('category title'), max_length=100)
86
    slug = models.SlugField(_('slug'), unique=True)
87
    description = models.CharField(_('description'), max_length=250, blank=True)
88

    
89
    class Meta:
90
        verbose_name = _('category translation')
91
        verbose_name_plural = _('category translations')
92
        ordering = ['title']
93

    
94
    def __unicode__(self):
95
        return self.title
96

    
97
    def get_absolute_url(self):
98
        return reverse('cloudcmsblog_entries_archive', 'cloudcmsblog.urls', (), {
99
            'category': self.slug,
100
        })
101

    
102
    def save(self, *args, **kwargs):
103
        if not self.slug:
104
            self.slug = slugify(self.title)
105

    
106
        super(CategoryTranslation, self).save(*args, **kwargs)
107

    
108

    
109
class EntryManager(models.Manager):
110

    
111
    def active(self):
112
        return self.filter(is_active=True)
113

    
114
    def latest(self, limit=3):
115
        return self.filter()[:limit]
116

    
117
class Entry(Base):
118
    """
119
    Blog post entry
120
    """
121
    is_active = models.BooleanField(_('is active'), default=True)
122
    is_featured = models.BooleanField(_('is featured'), default=False)
123

    
124
    title = models.CharField(_('title'), max_length=100)
125
    slug = models.SlugField(_('slug'), max_length=100, unique_for_date='published_on')
126
    author = models.ForeignKey(User, related_name='blogentries', verbose_name=_('author'))
127
    language = models.CharField(max_length=255, choices=settings.LANGUAGES)
128

    
129
    intro_text = models.TextField(max_length=255,
130
            help_text="Displayed in list views", blank=True)
131
    image = MediaFileForeignKey(MediaFile, null=True, blank=True)
132
    application = models.ManyToManyField(Application,
133
            related_name="blogentries",
134
            verbose_name=_('application'))
135

    
136
    published_on = models.DateTimeField(_('published on'), blank=True, null=True, default=datetime.now,
137
        help_text=_('Will be filled in automatically when entry gets published.'))
138
    last_changed = models.DateTimeField(_('last change'), auto_now=True, editable=False)
139

    
140
    categories = models.ManyToManyField(Category, verbose_name=_('categories'),
141
        related_name='blogentries', null=True, blank=True)
142

    
143
    objects = EntryManager()
144

    
145
    class Meta:
146
        get_latest_by = 'published_on'
147
        ordering = ['-published_on']
148
        verbose_name = _('entry')
149
        verbose_name_plural = _('entries')
150

    
151
    def __unicode__(self):
152
        return self.title
153

    
154
    def get_absolute_url(self):
155
        try:
156
            r = reverse('cloudcmsblog_entry_detail', 'cloudcmsblog.urls', (),
157
                    {
158
                    'year': self.published_on.strftime('%Y'),
159
                    'month': self.published_on.strftime('%m'),
160
                    'day': self.published_on.strftime('%d'),
161
                    'slug': self.slug,
162
                    })
163
        except Exception,e:
164
            pass
165

    
166
        # ugly hack to fix proper application reverse url
167
        BLOG_URL = ""
168
        try:
169
            AC = Page.content_type_for(ApplicationContent)
170
            blog_block = AC.objects.filter(urlconf_path="cloudcmsblog")[0]
171
            BLOG_URL = blog_block.parent.get_navigation_url()
172
        except Exception, e:
173
            print e
174
        if r.startswith(BLOG_URL):
175
            return r
176
        else:
177
            return BLOG_URL + r
178

    
179

    
180
# Feincms navigation extension
181
class BlogCategoriesNavigationExtension(NavigationExtension):
182
    """
183
    Navigation extension for FeinCMS which lists all categories that user
184
    wants to include in global site navigation.
185
    """
186

    
187
    name = _('blog categories')
188

    
189
    def children(self, page, **kwargs):
190
        for category in Category.objects.filter(display_on_menu=True):
191
            url='%scategory/%s/' % (page.get_absolute_url(), category.translation.slug)
192
            yield PagePretender(
193
                title=category.translation.title,
194
                tree_id=page.tree_id,
195
                url=url,
196
                lft=0,
197
                rght=0,
198
                slug=category.translation.slug,
199
            )
200

    
201

    
202
# Feincms content abstract models
203
class LatestEntries(models.Model):
204
    title = models.CharField(max_length=255)
205
    limit = models.PositiveIntegerField(default=3)
206
    display_text = models.BooleanField(default=False)
207

    
208
    class Meta:
209
        abstract = True
210
        verbose_name = _('Latest blog entries')
211
        verbose_name_plural = _('Latest blog entries')
212

    
213
    def render(self, **kwargs):
214
        return render_to_string(['content/latest_blog.html'], {'posts':
215
            Entry.objects.latest(self.limit), 'content': self})
216