Statistics
| Branch: | Tag: | Revision:

root / cloudcmsfaq / models.py @ bd9ce789

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 916841de Kostas Papadimitriou
    class Meta:
73 916841de Kostas Papadimitriou
        verbose_name = _('category')
74 916841de Kostas Papadimitriou
        verbose_name_plural = _('categories')
75 36d49217 Olga Brani
        ordering = ['ordering',]
76 916841de Kostas Papadimitriou
77 916841de Kostas Papadimitriou
    objects = translations.TranslatedObjectManager()
78 36d49217 Olga Brani
 
79 36d49217 Olga Brani
        
80 916841de Kostas Papadimitriou
    def __unicode__(self):
81 916841de Kostas Papadimitriou
        trans = translations.TranslatedObjectMixin.__unicode__(self)
82 916841de Kostas Papadimitriou
        return trans or _('Unnamed category')
83 916841de Kostas Papadimitriou
84 916841de Kostas Papadimitriou
85 916841de Kostas Papadimitriou
class CategoryTranslation(translations.Translation(Category)):
86 916841de Kostas Papadimitriou
    """
87 916841de Kostas Papadimitriou
    Category translation
88 916841de Kostas Papadimitriou
    """
89 916841de Kostas Papadimitriou
    title = models.CharField(_('category title'), max_length=100)
90 916841de Kostas Papadimitriou
    slug = models.SlugField(_('slug'), unique=True)
91 916841de Kostas Papadimitriou
    description = models.CharField(_('description'), max_length=250, blank=True)
92 916841de Kostas Papadimitriou
93 916841de Kostas Papadimitriou
    class Meta:
94 916841de Kostas Papadimitriou
        verbose_name = _('category translation')
95 916841de Kostas Papadimitriou
        verbose_name_plural = _('category translations')
96 916841de Kostas Papadimitriou
        ordering = ['title']
97 916841de Kostas Papadimitriou
98 916841de Kostas Papadimitriou
    def __unicode__(self):
99 916841de Kostas Papadimitriou
        return self.title
100 916841de Kostas Papadimitriou
101 916841de Kostas Papadimitriou
    def save(self, *args, **kwargs):
102 916841de Kostas Papadimitriou
        if not self.slug:
103 916841de Kostas Papadimitriou
            self.slug = slugify(self.title)
104 916841de Kostas Papadimitriou
105 916841de Kostas Papadimitriou
        super(CategoryTranslation, self).save(*args, **kwargs)
106 916841de Kostas Papadimitriou
107 916841de Kostas Papadimitriou
108 916841de Kostas Papadimitriou
class QuestionManager(models.Manager):
109 916841de Kostas Papadimitriou
110 916841de Kostas Papadimitriou
    def active(self):
111 916841de Kostas Papadimitriou
        return self.filter(is_active=True)
112 916841de Kostas Papadimitriou
113 916841de Kostas Papadimitriou
    def latest(self, limit=3):
114 916841de Kostas Papadimitriou
        return self.filter()[:limit]
115 916841de Kostas Papadimitriou
116 916841de Kostas Papadimitriou
117 916841de Kostas Papadimitriou
def get_faq_page():
118 916841de Kostas Papadimitriou
    """
119 916841de Kostas Papadimitriou
    Returns Page model that has been associated with faq application
120 916841de Kostas Papadimitriou
    """
121 916841de Kostas Papadimitriou
    return get_app_page(Page, "cloudcmsfaq")
122 916841de Kostas Papadimitriou
123 916841de Kostas Papadimitriou
class Question(Base):
124 916841de Kostas Papadimitriou
    """
125 916841de Kostas Papadimitriou
    Question/answer entry
126 916841de Kostas Papadimitriou
    """
127 916841de Kostas Papadimitriou
    is_active = models.BooleanField(_('is active'), default=True)
128 916841de Kostas Papadimitriou
    is_featured = models.BooleanField(_('is featured'), default=False)
129 916841de Kostas Papadimitriou
130 916841de Kostas Papadimitriou
    title = models.CharField(_('title'), max_length=100)
131 916841de Kostas Papadimitriou
    slug = models.SlugField(_('slug'), max_length=100, unique_for_date='published_on')
132 916841de Kostas Papadimitriou
    author = models.ForeignKey(User, related_name='faqs', verbose_name=_('author'))
133 916841de Kostas Papadimitriou
    language = models.CharField(max_length=255, choices=settings.LANGUAGES)
134 916841de Kostas Papadimitriou
135 916841de Kostas Papadimitriou
    application = models.ManyToManyField(Application,
136 916841de Kostas Papadimitriou
            related_name="faqs",
137 916841de Kostas Papadimitriou
            verbose_name=_('application'))
138 916841de Kostas Papadimitriou
139 36d49217 Olga Brani
    published_on = models.DateTimeField(_('published on'), blank=True, null=False, default=datetime.now,
140 916841de Kostas Papadimitriou
        help_text=_('Will be filled in automatically when question gets published.'))
141 916841de Kostas Papadimitriou
    last_changed = models.DateTimeField(_('last change'), auto_now=True, editable=False)
142 916841de Kostas Papadimitriou
143 2a32f17b Kostas Papadimitriou
    service = models.ForeignKey('cloudcms.Service', verbose_name=_('service'),
144 2a32f17b Kostas Papadimitriou
        related_name='faqs', null=True, blank=False)
145 2a32f17b Kostas Papadimitriou
146 f1ff020b Kostas Papadimitriou
    category = models.ForeignKey(Category, verbose_name=_('category'),
147 916841de Kostas Papadimitriou
        related_name='faqs', null=False, blank=False)
148 916841de Kostas Papadimitriou
149 916841de Kostas Papadimitriou
    objects = QuestionManager()
150 916841de Kostas Papadimitriou
151 36d49217 Olga Brani
152 916841de Kostas Papadimitriou
    class Meta:
153 916841de Kostas Papadimitriou
        get_latest_by = 'published_on'
154 36d49217 Olga Brani
        ordering = ['service', 'category__ordering', 'published_on']
155 916841de Kostas Papadimitriou
        verbose_name = _('faq')
156 916841de Kostas Papadimitriou
        verbose_name_plural = _('faqs')
157 916841de Kostas Papadimitriou
158 916841de Kostas Papadimitriou
    def __unicode__(self):
159 916841de Kostas Papadimitriou
        return self.title
160 916841de Kostas Papadimitriou
161 36d49217 Olga Brani
    def get_next(self):
162 36d49217 Olga Brani
        return self.get_next_by_published_on(category=self.category, service=self.service)
163 36d49217 Olga Brani
164 36d49217 Olga Brani
    def get_previous(self):
165 36d49217 Olga Brani
        return self.get_previous_by_published_on(category=self.category, service=self.service)
166 36d49217 Olga Brani
    
167 916841de Kostas Papadimitriou
    def get_absolute_url(self):
168 916841de Kostas Papadimitriou
        try:
169 916841de Kostas Papadimitriou
            r = reverse('cloudcmsfaq_question_detail', 'cloudcmsfaq.urls', (),
170 916841de Kostas Papadimitriou
                    {
171 2a32f17b Kostas Papadimitriou
                     'service': self.service.translation.slug,
172 916841de Kostas Papadimitriou
                     'slug': self.slug,
173 916841de Kostas Papadimitriou
                    })
174 916841de Kostas Papadimitriou
        except Exception, e:
175 916841de Kostas Papadimitriou
            pass
176 916841de Kostas Papadimitriou
177 916841de Kostas Papadimitriou
        # ugly hack to fix proper application reverse url
178 916841de Kostas Papadimitriou
        FAQ_URL = ""
179 916841de Kostas Papadimitriou
        try:
180 916841de Kostas Papadimitriou
            FAQ_URL = get_faq_page().get_navigation_url()
181 916841de Kostas Papadimitriou
        except Exception, e:
182 916841de Kostas Papadimitriou
            pass
183 916841de Kostas Papadimitriou
184 916841de Kostas Papadimitriou
        if r.startswith(FAQ_URL):
185 916841de Kostas Papadimitriou
            return r
186 916841de Kostas Papadimitriou
        else:
187 916841de Kostas Papadimitriou
            return FAQ_URL + r.lstrip('/')
188 916841de Kostas Papadimitriou
189 916841de Kostas Papadimitriou
    def back_url(self):
190 916841de Kostas Papadimitriou
        return get_faq_page().get_navigation_url()
191 916841de Kostas Papadimitriou
192 916841de Kostas Papadimitriou
193 916841de Kostas Papadimitriou
# Feincms navigation extension
194 2a32f17b Kostas Papadimitriou
class FaqServicesNavigationExtension(NavigationExtension):
195 916841de Kostas Papadimitriou
    """
196 916841de Kostas Papadimitriou
    Navigation extension for FeinCMS which lists all categories that user
197 916841de Kostas Papadimitriou
    wants to include in global site navigation.
198 916841de Kostas Papadimitriou
    """
199 916841de Kostas Papadimitriou
200 916841de Kostas Papadimitriou
    name = _('faq categories')
201 916841de Kostas Papadimitriou
202 916841de Kostas Papadimitriou
    def children(self, page, **kwargs):
203 2a32f17b Kostas Papadimitriou
        from cloudcms.models import Service
204 2a32f17b Kostas Papadimitriou
205 2a32f17b Kostas Papadimitriou
        for service in Service.objects.filter(display_on_menu=True):
206 2a32f17b Kostas Papadimitriou
            url='%sservice/%s/' % (page.get_absolute_url(), service.translation.slug)
207 916841de Kostas Papadimitriou
            yield PagePretender(
208 2a32f17b Kostas Papadimitriou
                title=service.translation.title,
209 916841de Kostas Papadimitriou
                tree_id=page.tree_id,
210 916841de Kostas Papadimitriou
                url=url,
211 916841de Kostas Papadimitriou
                lft=0,
212 916841de Kostas Papadimitriou
                rght=0,
213 916841de Kostas Papadimitriou
                slug=category.translation.slug,
214 916841de Kostas Papadimitriou
            )