Statistics
| Branch: | Tag: | Revision:

root / cloudcmsfaq / models.py @ cb88bc8d

History | View | Annotate | Download (7.4 kB)

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