Statistics
| Branch: | Tag: | Revision:

root / cloudcmsfaq / models.py @ 2a32f17b

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