Initial commit of userguide app
authorKostas Papadimitriou <kpap@grnet.gr>
Thu, 12 Jul 2012 14:41:06 +0000 (17:41 +0300)
committerKostas Papadimitriou <kpap@grnet.gr>
Thu, 12 Jul 2012 14:41:06 +0000 (17:41 +0300)
cloudcmsguide/__init__.py [new file with mode: 0644]
cloudcmsguide/admin.py [new file with mode: 0644]
cloudcmsguide/models.py [new file with mode: 0644]
cloudcmsguide/sitemap.py [new file with mode: 0644]
cloudcmsguide/templates/cloudcmsguide/archive.html [new file with mode: 0644]
cloudcmsguide/templates/cloudcmsguide/detail.html [new file with mode: 0644]
cloudcmsguide/tests.py [new file with mode: 0644]
cloudcmsguide/urls.py [new file with mode: 0644]
cloudcmsguide/views.py [new file with mode: 0644]

diff --git a/cloudcmsguide/__init__.py b/cloudcmsguide/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/cloudcmsguide/admin.py b/cloudcmsguide/admin.py
new file mode 100644 (file)
index 0000000..d0594f4
--- /dev/null
@@ -0,0 +1,75 @@
+# Copyright 2012 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials
+#      provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
+
+from django.contrib import admin
+from django.utils.translation import ugettext_lazy as _
+
+from feincms.translations import admin_translationinline, short_language_code
+from feincms.admin import tree_editor, item_editor
+
+from cloudcmsguide.models import UserGuideEntry
+
+
+class UserGuideEntryAdmin(item_editor.ItemEditor, tree_editor.TreeEditor):
+
+    date_hierarchy = 'published_on'
+    list_display = ['title', 'is_active', 'published_on', 'service', 'author']
+    list_editable = ['is_active']
+    list_filter = ['is_active', 'is_featured', 'author']
+    search_fields = ['title', 'slug']
+    raw_id_fields = ['parent']
+
+    prepopulated_fields = {
+        'slug': ('title',),
+        }
+
+    fieldsets = [
+        [None, {
+            'fields': [
+                ('is_active', 'published_on'),
+                ('title', 'slug'),
+                'parent',
+                'service',
+                'author',
+            ]
+        }],
+        item_editor.FEINCMS_CONTENT_FIELDSET,
+    ]
+
+    def import_from_sphinx(self, request):
+        return import_from_sphinx(request)
+
+
+admin.site.register(UserGuideEntry, UserGuideEntryAdmin)
+
diff --git a/cloudcmsguide/models.py b/cloudcmsguide/models.py
new file mode 100644 (file)
index 0000000..60be618
--- /dev/null
@@ -0,0 +1,148 @@
+# Copyright 2012 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials
+#      provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
+
+from datetime import datetime
+
+from django.db import models
+from django.conf import settings
+from django.contrib.auth.models import User
+from django.utils.translation import ugettext_lazy as _, ugettext, ungettext
+from django.template.loader import render_to_string
+from django.core import urlresolvers
+
+from feincms import translations
+from feincms.models import Base
+from feincms.module.page.models import Page
+from feincms.content.application.models import reverse
+from feincms.content.richtext.models import RichTextContent
+from feincms.content.section.models import SectionContent
+from feincms.module.medialibrary.fields import MediaFileForeignKey
+from feincms.module.medialibrary.models import MediaFile
+from feincms.module.page.extensions.navigation import NavigationExtension
+from feincms.module.page.extensions.navigation import PagePretender
+from feincms.content.application.models import ApplicationContent
+from feincms.models import Base, create_base_model
+
+from cloudcms.cms_utils import get_app_page
+
+class UserGuideEntryManager(models.Manager):
+
+    def active(self):
+        return self.filter(is_active=True)
+
+    def latest(self, limit=3):
+        return self.filter()[:limit]
+
+
+def get_guide_page():
+    """
+    Returns Page model that has been associated with userguide application
+    """
+    return get_app_page(Page, "cloudcmsguide")
+
+
+try:
+    # MPTT 0.4
+    from mptt.models import MPTTModel
+    mptt_register = False
+    Base = create_base_model(MPTTModel)
+except ImportError:
+    # MPTT 0.3
+    mptt_register = True
+
+class UserGuideEntry(Base):
+    """
+    User guide entry
+    """
+    is_active = models.BooleanField(_('is active'), default=True)
+    is_featured = models.BooleanField(_('is featured'), default=False)
+
+    title = models.CharField(_('title'), max_length=100)
+    slug = models.SlugField(_('slug'), max_length=100, unique_for_date='published_on')
+    author = models.ForeignKey(User, related_name='guide_pages', verbose_name=_('author'))
+    language = models.CharField(max_length=255, choices=settings.LANGUAGES)
+
+    published_on = models.DateTimeField(_('published on'), blank=True, null=True, default=datetime.now,
+        help_text=_('Will be filled in automatically when entry gets published.'))
+    last_changed = models.DateTimeField(_('last change'), auto_now=True, editable=False)
+
+    service = models.ForeignKey('cloudcms.Service', verbose_name=_('service'),
+        related_name='userguideentries', null=True, blank=False)
+
+    parent = models.ForeignKey('self', verbose_name=_('Parent'), blank=True, null=True, related_name='children')
+
+    objects = UserGuideEntryManager()
+
+    class Meta:
+        get_latest_by = 'published_on'
+        ordering = ['service', '-published_on']
+        verbose_name = _('User guide entry')
+        verbose_name_plural = _('User guide entries')
+
+    def __unicode__(self):
+        return self.title
+
+    def get_absolute_url(self):
+        try:
+            r = reverse('cloudcmsguide_entry_detail', 'cloudcmsguide.urls', (),
+                    {
+                     'service': self.service.translation.slug,
+                     'slug': self.slug,
+                    })
+        except Exception, e:
+            print e
+            return ""
+
+        # ugly hack to fix proper application reverse url
+        GUIDE_URL = ""
+        try:
+            GUIDE_URL = get_guide_page().get_navigation_url()
+        except Exception, e:
+            pass
+
+        if r.startswith(GUIDE_URL):
+            return r
+        else:
+            return GUIDE_URL + r.lstrip('/')
+
+    def back_url(self):
+        return get_guide_page().get_navigation_url()
+
+if mptt_register: # MPTT 0.3 legacy support
+    mptt.register(Page)
+
+UserGuideEntry.register_extensions(
+    'changedate',
+    'seo'
+)
diff --git a/cloudcmsguide/sitemap.py b/cloudcmsguide/sitemap.py
new file mode 100644 (file)
index 0000000..45a2170
--- /dev/null
@@ -0,0 +1,43 @@
+# Copyright 2012 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials
+#      provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
+
+from django.db.models import Max
+from django.contrib.sitemaps import Sitemap
+from cloudcmsguide.models import UserGuideEntry
+
+class UserGuideSitemap(Sitemap):
+
+    def items(self):
+        return UserGuideEntry.objects.filter(is_active=True)
+
diff --git a/cloudcmsguide/templates/cloudcmsguide/archive.html b/cloudcmsguide/templates/cloudcmsguide/archive.html
new file mode 100644 (file)
index 0000000..9b51662
--- /dev/null
@@ -0,0 +1,16 @@
+{% load applicationcontent_tags pagination_tags i18n %}
+
+<div class="guide">
+    {% for service in services %}
+    <div class="guide-category">
+        <h2>{{ service.translation.title|upper }}</h2>
+        <ul>
+            {% for e in service.userguideentries.active %}
+            <li {% if e == entry %}class="current"{% endif %}>
+                <a href="{{ e.get_absolute_url }}">{{ e.title }}</a>
+            </li>
+            {% endfor %}
+        </ul>
+    </div>
+    {% endfor %}
+</div>
diff --git a/cloudcmsguide/templates/cloudcmsguide/detail.html b/cloudcmsguide/templates/cloudcmsguide/detail.html
new file mode 100644 (file)
index 0000000..c420732
--- /dev/null
@@ -0,0 +1,19 @@
+{% load applicationcontent_tags i18n %}
+
+{% fragment request "sidecol" %}
+{% include "cloudcmsguide/archive.html" %}
+{% endfragment %}
+
+{% fragment request "maincol" %}
+<div class="user-guide-entry">
+    <h2>{{ entry.title|upper }}</h2>
+    <div class="content">
+        {% for content in entry.content.main %}
+            {{ content.render }}
+        {% endfor %}
+    </div>
+    <div class="bottom-content backlink">
+        <a href="{{ entry.back_url }}">{% trans "&lt; Back to User guide" %}</a>
+    </div>
+</div>
+{% endfragment %}
diff --git a/cloudcmsguide/tests.py b/cloudcmsguide/tests.py
new file mode 100644 (file)
index 0000000..ba67af7
--- /dev/null
@@ -0,0 +1,57 @@
+# Copyright 2012 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials
+#      provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
+
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
diff --git a/cloudcmsguide/urls.py b/cloudcmsguide/urls.py
new file mode 100644 (file)
index 0000000..9e3d07e
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright 2012 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials
+#      provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
+
+from django.conf.urls.defaults import patterns, include, url
+from django.conf import settings
+from django.contrib import admin
+
+admin.autodiscover()
+
+urlpatterns = patterns('cloudcmsguide.views',
+    url(r'^$', 'index', name='cloudcmsguide_entries_archive'),
+    url(r'^(?P<service>[\w]+)-(?P<slug>[-\w]+)/$',
+        'detail', name='cloudcmsguide_entry_detail'),
+)
+
diff --git a/cloudcmsguide/views.py b/cloudcmsguide/views.py
new file mode 100644 (file)
index 0000000..ea50662
--- /dev/null
@@ -0,0 +1,64 @@
+# Copyright 2012 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials
+#      provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
+
+from django.conf import settings
+from django.views.generic.simple import direct_to_template
+from django.http import HttpResponseRedirect, Http404
+
+from cloudcms.models import Service
+from cloudcmsguide.models import UserGuideEntry
+
+def index(request):
+    return archive(request)
+
+def archive(request):
+    """
+    Display entries list
+    """
+    services = Service.objects.all()
+
+    return direct_to_template(request,
+            "cloudcmsguide/archive.html", {'services': services})
+
+def detail(request, service, slug):
+    """
+    Display detailed entry.
+    """
+    entry = UserGuideEntry.objects.get(slug=slug)
+    services = Service.objects.all()
+
+    return direct_to_template(request,
+            "cloudcmsguide/detail.html", {'entry': entry,
+                                        'services': services})
+