Merge branch 'cms-features'
* cms-features: update theme and dua update cms/boxes to pycon parity update debug toolbar adding in basic nav get object or 404 on page objects move cms slug down to root url remove menu add side nav with sibling pages rename block add sibling pages to context add django-mptt to requirements remove mptt driven menu hook up django reversion adding menu context processor and hooking up template add ordering to menus and pages adding prototype cms app with pages and menu
This commit is contained in:
		
						commit
						0430f166fe
					
				
					 34 changed files with 632 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -23,4 +23,9 @@ django_compressor==1.2a1
 | 
			
		|||
-e git+git://github.com/pinax/pinax-theme-bootstrap-account.git@8fc34ba4309fc1edd12e5836cc1398c3f9597e6d#egg=pinax-theme-bootstrap-account
 | 
			
		||||
-e git+git://github.com/pinax/django-user-accounts.git@fd08c676ae71d0b9d7353ddee123deb751d6ee15#egg=django-user-accounts
 | 
			
		||||
 | 
			
		||||
django-forms-bootstrap==2.0.3.post1
 | 
			
		||||
django-mptt==0.5.2
 | 
			
		||||
django-taggit==0.9.3
 | 
			
		||||
django-reversion==1.6.1
 | 
			
		||||
django-markitup==1.0.0
 | 
			
		||||
markdown==2.1.1
 | 
			
		||||
django-sitetree==0.6
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										0
									
								
								symposion/boxes/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								symposion/boxes/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										6
									
								
								symposion/boxes/admin.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								symposion/boxes/admin.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
from django.contrib import admin
 | 
			
		||||
 | 
			
		||||
from symposion.boxes.models import Box
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
admin.site.register(Box)
 | 
			
		||||
							
								
								
									
										20
									
								
								symposion/boxes/authorization.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								symposion/boxes/authorization.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
from django.conf import settings
 | 
			
		||||
 | 
			
		||||
from symposion.boxes.utils import load_path_attr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def default_can_edit(request, *args, **kwargs):
 | 
			
		||||
    """
 | 
			
		||||
    This is meant to be overridden in your project per domain specific
 | 
			
		||||
    requirements.
 | 
			
		||||
    """
 | 
			
		||||
    return request.user.is_staff or request.user.is_superuser
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def load_can_edit():
 | 
			
		||||
    import_path = getattr(settings, "BOXES_CAN_EDIT_CALLABLE", None)
 | 
			
		||||
    
 | 
			
		||||
    if import_path is None:
 | 
			
		||||
        return default_can_edit
 | 
			
		||||
    
 | 
			
		||||
    return load_path_attr(import_path)
 | 
			
		||||
							
								
								
									
										10
									
								
								symposion/boxes/forms.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								symposion/boxes/forms.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
from django import forms
 | 
			
		||||
 | 
			
		||||
from symposion.boxes.models import Box
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BoxForm(forms.ModelForm):
 | 
			
		||||
    
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Box
 | 
			
		||||
        fields = ["content"]
 | 
			
		||||
							
								
								
									
										22
									
								
								symposion/boxes/models.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								symposion/boxes/models.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
import datetime
 | 
			
		||||
 | 
			
		||||
from django.db import models
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
 | 
			
		||||
from markitup.fields import MarkupField
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Box(models.Model):
 | 
			
		||||
    
 | 
			
		||||
    label = models.CharField(max_length=100, db_index=True)
 | 
			
		||||
    content = MarkupField(blank=True)
 | 
			
		||||
    
 | 
			
		||||
    created_by = models.ForeignKey(User, related_name="boxes")
 | 
			
		||||
    last_updated_by = models.ForeignKey(User, related_name="updated_boxes")
 | 
			
		||||
    
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return self.label
 | 
			
		||||
    
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name_plural = "boxes"
 | 
			
		||||
							
								
								
									
										0
									
								
								symposion/boxes/templatetags/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								symposion/boxes/templatetags/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										41
									
								
								symposion/boxes/templatetags/boxes_tags.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								symposion/boxes/templatetags/boxes_tags.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
from django import template
 | 
			
		||||
from django.core.exceptions import ImproperlyConfigured
 | 
			
		||||
from django.core.urlresolvers import reverse
 | 
			
		||||
from django.utils.safestring import mark_safe
 | 
			
		||||
from django.utils.encoding import smart_str
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
from django.template.defaulttags import kwarg_re
 | 
			
		||||
 | 
			
		||||
from symposion.boxes.models import Box
 | 
			
		||||
from symposion.boxes.forms import BoxForm
 | 
			
		||||
from symposion.boxes.authorization import load_can_edit
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
register = template.Library()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register.inclusion_tag("boxes/box.html", takes_context=True)
 | 
			
		||||
def box(context, label, show_edit=True, *args, **kwargs):
 | 
			
		||||
    
 | 
			
		||||
    request = context["request"]
 | 
			
		||||
    can_edit = load_can_edit()(request, *args, **kwargs)
 | 
			
		||||
    
 | 
			
		||||
    try:
 | 
			
		||||
        box = Box.objects.get(label=label)
 | 
			
		||||
    except Box.DoesNotExist:
 | 
			
		||||
        box = None
 | 
			
		||||
    
 | 
			
		||||
    if can_edit and show_edit:
 | 
			
		||||
        form = BoxForm(instance=box, prefix=label)
 | 
			
		||||
        form_action = reverse("box_edit", args=[label])
 | 
			
		||||
    else:
 | 
			
		||||
        form = None
 | 
			
		||||
        form_action = None
 | 
			
		||||
    
 | 
			
		||||
    return {
 | 
			
		||||
        "request": request,
 | 
			
		||||
        "label": label,
 | 
			
		||||
        "box": box,
 | 
			
		||||
        "form": form,
 | 
			
		||||
        "form_action": form_action,
 | 
			
		||||
    }
 | 
			
		||||
							
								
								
									
										6
									
								
								symposion/boxes/urls.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								symposion/boxes/urls.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
from django.conf.urls.defaults import url, patterns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
urlpatterns = patterns("symposion.boxes.views",
 | 
			
		||||
    url(r"^([-\w]+)/edit/$", "box_edit", name="box_edit"),
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										19
									
								
								symposion/boxes/utils.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								symposion/boxes/utils.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
from django.core.exceptions import ImproperlyConfigured
 | 
			
		||||
try:
 | 
			
		||||
    from django.utils.importlib import import_module
 | 
			
		||||
except ImportError:
 | 
			
		||||
    from importlib import import_module
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def load_path_attr(path):
 | 
			
		||||
    i = path.rfind(".")
 | 
			
		||||
    module, attr = path[:i], path[i+1:]
 | 
			
		||||
    try:
 | 
			
		||||
        mod = import_module(module)
 | 
			
		||||
    except ImportError, e:
 | 
			
		||||
        raise ImproperlyConfigured("Error importing %s: '%s'" % (module, e))
 | 
			
		||||
    try:
 | 
			
		||||
        attr = getattr(mod, attr)
 | 
			
		||||
    except AttributeError:
 | 
			
		||||
        raise ImproperlyConfigured("Module '%s' does not define a '%s'" % (module, attr))
 | 
			
		||||
    return attr
 | 
			
		||||
							
								
								
									
										45
									
								
								symposion/boxes/views.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								symposion/boxes/views.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
from django.http import HttpResponseForbidden
 | 
			
		||||
from django.shortcuts import redirect
 | 
			
		||||
from django.views.decorators.http import require_POST
 | 
			
		||||
 | 
			
		||||
from symposion.boxes.authorization import load_can_edit
 | 
			
		||||
from symposion.boxes.forms import BoxForm
 | 
			
		||||
from symposion.boxes.models import Box
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# @@@ problem with this is that the box_edit.html and box_create.html won't have domain objects in context
 | 
			
		||||
def get_auth_vars(request):
 | 
			
		||||
    auth_vars = {}
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        keys = [k for k in request.POST.keys() if k.startswith("boxes_auth_")]
 | 
			
		||||
        for key in keys:
 | 
			
		||||
            auth_vars[key.replace("boxes_auth_", "")] = request.POST.get(key)
 | 
			
		||||
        auth_vars["user"] = request.user
 | 
			
		||||
    return auth_vars
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@require_POST
 | 
			
		||||
def box_edit(request, label):
 | 
			
		||||
    
 | 
			
		||||
    if not load_can_edit()(request, **get_auth_vars(request)):
 | 
			
		||||
        return HttpResponseForbidden()
 | 
			
		||||
    
 | 
			
		||||
    next = request.GET.get("next")
 | 
			
		||||
    
 | 
			
		||||
    try:
 | 
			
		||||
        box = Box.objects.get(label=label)
 | 
			
		||||
    except Box.DoesNotExist:
 | 
			
		||||
        box = None
 | 
			
		||||
    
 | 
			
		||||
    form = BoxForm(request.POST, instance=box, prefix=label)
 | 
			
		||||
 | 
			
		||||
    if form.is_valid():
 | 
			
		||||
        if box is None:
 | 
			
		||||
            box = form.save(commit=False)
 | 
			
		||||
            box.label = label
 | 
			
		||||
            box.created_by = request.user
 | 
			
		||||
            box.last_updated_by = request.user
 | 
			
		||||
            box.save()
 | 
			
		||||
        else:
 | 
			
		||||
            form.save()
 | 
			
		||||
        return redirect(next)
 | 
			
		||||
							
								
								
									
										0
									
								
								symposion/cms/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								symposion/cms/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										6
									
								
								symposion/cms/admin.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								symposion/cms/admin.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
from django.contrib import admin
 | 
			
		||||
 | 
			
		||||
from .models import Page
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
admin.site.register(Page)
 | 
			
		||||
							
								
								
									
										16
									
								
								symposion/cms/forms.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								symposion/cms/forms.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
from django import forms
 | 
			
		||||
 | 
			
		||||
from markitup.widgets import MarkItUpWidget
 | 
			
		||||
 | 
			
		||||
from .models import Page
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PageForm(forms.ModelForm):
 | 
			
		||||
    
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Page
 | 
			
		||||
        fields = ["title", "body", "path"]
 | 
			
		||||
        widgets = {
 | 
			
		||||
            "body": MarkItUpWidget(),
 | 
			
		||||
            "path": forms.HiddenInput(),
 | 
			
		||||
        }
 | 
			
		||||
							
								
								
									
										9
									
								
								symposion/cms/managers.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								symposion/cms/managers.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from django.db import models
 | 
			
		||||
 | 
			
		||||
class PublishedPageManager(models.Manager):
 | 
			
		||||
    
 | 
			
		||||
    def get_query_set(self):
 | 
			
		||||
        qs = super(PublishedPageManager, self).get_query_set()
 | 
			
		||||
        return qs.filter(publish_date__lte=datetime.now())
 | 
			
		||||
							
								
								
									
										53
									
								
								symposion/cms/models.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								symposion/cms/models.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
import re
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from markitup.fields import MarkupField
 | 
			
		||||
 | 
			
		||||
from taggit.managers import TaggableManager
 | 
			
		||||
 | 
			
		||||
import reversion
 | 
			
		||||
 | 
			
		||||
from .managers import PublishedPageManager
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Page(models.Model):
 | 
			
		||||
    
 | 
			
		||||
    STATUS_CHOICES = (
 | 
			
		||||
        (1, _("Draft")),
 | 
			
		||||
        (2, _("Public")),
 | 
			
		||||
    )
 | 
			
		||||
    
 | 
			
		||||
    title = models.CharField(max_length=100)
 | 
			
		||||
    path = models.CharField(max_length=100, unique=True)
 | 
			
		||||
    body = MarkupField()
 | 
			
		||||
    status = models.IntegerField(choices=STATUS_CHOICES, default=2)
 | 
			
		||||
    publish_date = models.DateTimeField(default=datetime.now)
 | 
			
		||||
    created = models.DateTimeField(editable=False, default=datetime.now)
 | 
			
		||||
    updated = models.DateTimeField(editable=False, default=datetime.now)
 | 
			
		||||
    tags = TaggableManager(blank=True)
 | 
			
		||||
    
 | 
			
		||||
    published = PublishedPageManager()
 | 
			
		||||
    
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return self.title
 | 
			
		||||
    
 | 
			
		||||
    @models.permalink
 | 
			
		||||
    def get_absolute_url(self):
 | 
			
		||||
        return ("cms_page", [self.path])
 | 
			
		||||
    
 | 
			
		||||
    def save(self, *args, **kwargs):
 | 
			
		||||
        self.updated = datetime.now()
 | 
			
		||||
        super(Page, self).save(*args, **kwargs)
 | 
			
		||||
    
 | 
			
		||||
    def clean_fields(self, exclude=None):
 | 
			
		||||
        super(Page, self).clean_fields(exclude)
 | 
			
		||||
        if not re.match(settings.SYMPOSION_PAGE_REGEX, self.path):
 | 
			
		||||
            raise ValidationError({"path": [_("Path can only contain letters, numbers and hyphens and end with /"),]})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
reversion.register(Page)
 | 
			
		||||
							
								
								
									
										8
									
								
								symposion/cms/urls.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								symposion/cms/urls.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
from django.conf.urls.defaults import url, patterns
 | 
			
		||||
 | 
			
		||||
PAGE_RE = r"(([\w-]{1,})(/[\w-]{1,})*)/"
 | 
			
		||||
 | 
			
		||||
urlpatterns = patterns("symposion.cms.views",
 | 
			
		||||
    url(r"^(?P<path>%s)_edit/$" % PAGE_RE, "page_edit", name="cms_page_edit"),
 | 
			
		||||
    url(r"^(?P<path>%s)$" % PAGE_RE, "page", name="cms_page"),
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										59
									
								
								symposion/cms/views.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								symposion/cms/views.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
from django.http import Http404
 | 
			
		||||
from django.shortcuts import render, redirect
 | 
			
		||||
from django.template import RequestContext
 | 
			
		||||
 | 
			
		||||
from .models import Page
 | 
			
		||||
from .forms import PageForm
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def can_edit(user):
 | 
			
		||||
    if user.is_staff or user.is_superuser:
 | 
			
		||||
        return True
 | 
			
		||||
    if user.has_perm("cms.change_page"):
 | 
			
		||||
        return True
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def page(request, path):
 | 
			
		||||
    
 | 
			
		||||
    editable = can_edit(request.user)
 | 
			
		||||
    try:
 | 
			
		||||
        page = Page.published.get(path=path)
 | 
			
		||||
    except Page.DoesNotExist:
 | 
			
		||||
        if editable:
 | 
			
		||||
            return redirect("cms_page_edit", path=path)
 | 
			
		||||
        else:
 | 
			
		||||
            raise Http404
 | 
			
		||||
    
 | 
			
		||||
    return render(request, "cms/page_detail.html", {
 | 
			
		||||
        "page": page,
 | 
			
		||||
        "editable": editable,
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def page_edit(request, path):
 | 
			
		||||
    
 | 
			
		||||
    if not can_edit(request.user):
 | 
			
		||||
        raise Http404
 | 
			
		||||
    
 | 
			
		||||
    try:
 | 
			
		||||
        page = Page.published.get(path=path)
 | 
			
		||||
    except Page.DoesNotExist:
 | 
			
		||||
        page = None
 | 
			
		||||
    
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        form = PageForm(request.POST, instance=page)
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            page = form.save(commit=False)
 | 
			
		||||
            page.path = path
 | 
			
		||||
            page.save()
 | 
			
		||||
            return redirect(page)
 | 
			
		||||
        else:
 | 
			
		||||
            print form.errors
 | 
			
		||||
    else:
 | 
			
		||||
        form = PageForm(instance=page, initial={"path": path})
 | 
			
		||||
    
 | 
			
		||||
    return render(request, "cms/page_edit.html", {
 | 
			
		||||
        "path": path,
 | 
			
		||||
        "form": form
 | 
			
		||||
    })
 | 
			
		||||
| 
						 | 
				
			
			@ -106,6 +106,8 @@ MIDDLEWARE_CLASSES = [
 | 
			
		|||
    "django.contrib.auth.middleware.AuthenticationMiddleware",
 | 
			
		||||
    "django_openid.consumer.SessionConsumer",
 | 
			
		||||
    "django.contrib.messages.middleware.MessageMiddleware",
 | 
			
		||||
    "django.middleware.transaction.TransactionMiddleware",
 | 
			
		||||
    "reversion.middleware.RevisionMiddleware",
 | 
			
		||||
    "debug_toolbar.middleware.DebugToolbarMiddleware",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +153,12 @@ INSTALLED_APPS = [
 | 
			
		|||
    "django_openid",
 | 
			
		||||
    "timezones",
 | 
			
		||||
    "metron",
 | 
			
		||||
    "markitup",
 | 
			
		||||
    "taggit",
 | 
			
		||||
    "mptt",
 | 
			
		||||
    "reversion",
 | 
			
		||||
    "easy_thumbnails",
 | 
			
		||||
    "sitetree",
 | 
			
		||||
    
 | 
			
		||||
    # Pinax
 | 
			
		||||
    "account",
 | 
			
		||||
| 
						 | 
				
			
			@ -160,6 +167,8 @@ INSTALLED_APPS = [
 | 
			
		|||
    "symposion.about",
 | 
			
		||||
    "symposion.sponsorship",
 | 
			
		||||
    "symposion.conference",
 | 
			
		||||
    "symposion.cms",
 | 
			
		||||
    "symposion.boxes",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
FIXTURE_DIRS = [
 | 
			
		||||
| 
						 | 
				
			
			@ -192,8 +201,14 @@ DEBUG_TOOLBAR_CONFIG = {
 | 
			
		|||
    "INTERCEPT_REDIRECTS": False,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MARKITUP_FILTER = ("markdown.markdown", {"safe_mode": True})
 | 
			
		||||
MARKITUP_SET = "markitup/sets/markdown"
 | 
			
		||||
MARKITUP_SKIN = "markitup/skins/simple"
 | 
			
		||||
 | 
			
		||||
CONFERENCE_ID = 1
 | 
			
		||||
 | 
			
		||||
SYMPOSION_PAGE_REGEX = r"(([\w-]{1,})(/[\w-]{1,})*)/"
 | 
			
		||||
 | 
			
		||||
# local_settings.py can be used to override environment-specific settings
 | 
			
		||||
# like database and email that differ between development and production.
 | 
			
		||||
try:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										31
									
								
								symposion/templates/boxes/box.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								symposion/templates/boxes/box.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
{% load markitup_tags %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
{% if form %}
 | 
			
		||||
    <div id="edit_{{ label }}" class="modal fade hide">
 | 
			
		||||
        <form id="edit_form_{{ label }}" accept-charset="UTF-8" class="modal-form" method="POST" action="{{ form_action }}?next={{ request.path }}">
 | 
			
		||||
            <div class="modal-header">
 | 
			
		||||
                <button type="button" class="close" data-dismiss="modal">×</button>
 | 
			
		||||
                <h3>{% trans "Editing content:" %} {{ label }}</h3>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="modal-body">
 | 
			
		||||
                {% csrf_token %}
 | 
			
		||||
                {{ form.content }}
 | 
			
		||||
 | 
			
		||||
                {% markitup_editor form.content.auto_id %}
 | 
			
		||||
                
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="modal-footer">
 | 
			
		||||
                <a href="#" class="btn" data-dismiss="modal">Close</a>
 | 
			
		||||
                <button type="submit" class="btn btn-primary">Save changes</a>
 | 
			
		||||
            </div>
 | 
			
		||||
        </form>
 | 
			
		||||
    </div>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
<div id="content_{{ label }}" class="content-box {% if form %}editable{% endif %}">
 | 
			
		||||
    {% if form %}
 | 
			
		||||
        <a href="#edit_{{ label }}" data-toggle="modal" class="btn edit-toggle"><i class="icon-pencil"></i></a>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    {{ box.content|safe }}
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										22
									
								
								symposion/templates/cms/page_detail.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								symposion/templates/cms/page_detail.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
{% extends "site_base.html" %}
 | 
			
		||||
 | 
			
		||||
{% load sitetree %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
{% block body_class %}cms-page{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block head_title %}{{ page.title }}{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block page_title %}
 | 
			
		||||
    {{ page.title }}
 | 
			
		||||
    {% if editable %}
 | 
			
		||||
        <div class="pull-right">
 | 
			
		||||
            <a href="{% url cms_page_edit page.path %}" class="btn"><i class="icon-pencil icon-large"></i></a>
 | 
			
		||||
        </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
{% block breadcrumbs %}{% sitetree_breadcrumbs from "main" %}{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block body %}
 | 
			
		||||
    {{ page.body }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										22
									
								
								symposion/templates/cms/page_edit.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								symposion/templates/cms/page_edit.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
{% extends "site_base.html" %}
 | 
			
		||||
 | 
			
		||||
{% load sitetree %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
{% load bootstrap_tags %}
 | 
			
		||||
 | 
			
		||||
{% block body_class %}cms-page{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block head_title %}Create Page{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block page_title %}{% trans "Edit page at:" %} {{ path }}{% endblock %}
 | 
			
		||||
{% block breadcrumbs %}{% sitetree_breadcrumbs from "main" %}{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block body %}
 | 
			
		||||
    <form method="POST" action="">
 | 
			
		||||
        {% csrf_token %}
 | 
			
		||||
        {{ form|as_bootstrap }}
 | 
			
		||||
        <div class="form-actions">
 | 
			
		||||
            <input class="btn btn-primary" type="submit" value="Save" />
 | 
			
		||||
        </div>
 | 
			
		||||
    </form>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,16 +2,44 @@
 | 
			
		|||
 | 
			
		||||
{% load metron_tags %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
{% load sitetree %}
 | 
			
		||||
{% load markitup_tags %}
 | 
			
		||||
{% load static %}
 | 
			
		||||
 | 
			
		||||
{% block extra_head_base %}
 | 
			
		||||
    <link href="{{ STATIC_URL }}img/favicon.ico" rel="shortcut icon" />
 | 
			
		||||
    <script src="{% block jquery_src %}{% static "pinax/js/jquery.js" %}{% endblock %}"></script>
 | 
			
		||||
    {% markitup_media "no-jquery" %}
 | 
			
		||||
    {% block extra_head %}{% endblock %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block nav %}
 | 
			
		||||
    {% sitetree_menu from "main" include "trunk" %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block body_base %}
 | 
			
		||||
    <div class="container">
 | 
			
		||||
        {% include "_messages.html" %}
 | 
			
		||||
        
 | 
			
		||||
        {% block breadcrumbs %}
 | 
			
		||||
            {% sitetree_breadcrumbs from "main" %}
 | 
			
		||||
        {% endblock %}
 | 
			
		||||
        
 | 
			
		||||
        {% block page_title %}
 | 
			
		||||
        {% endblock %}
 | 
			
		||||
        
 | 
			
		||||
        {% block body %}
 | 
			
		||||
        {% endblock %}
 | 
			
		||||
    </div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block footer %}
 | 
			
		||||
    {% include "_footer.html" %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block extra_body_base %}
 | 
			
		||||
{% block script_base %}
 | 
			
		||||
    {% analytics %}
 | 
			
		||||
    {% block extra_body %}{% endblock %}
 | 
			
		||||
    <script src="{% static "bootstrap/js/bootstrap.js" %}"></script>
 | 
			
		||||
    <script src="{% static "pinax/js/theme.js" %}"></script>
 | 
			
		||||
    {% block extra_script %}{% endblock %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										17
									
								
								symposion/templates/sitetree/breadcrumbs.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								symposion/templates/sitetree/breadcrumbs.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
{% load sitetree %}
 | 
			
		||||
{% if sitetree_items %}
 | 
			
		||||
    <ul class="breadcrumb">
 | 
			
		||||
        {% for item in sitetree_items %}
 | 
			
		||||
            {% if not forloop.last %}
 | 
			
		||||
                <li>
 | 
			
		||||
                    <a href="{% sitetree_url for item %}" {% if item.hint %}title="{{ item.hint }}"{% endif %}>{{ item.title_resolved }}</a>
 | 
			
		||||
                    <span class="divider">/</span>
 | 
			
		||||
                </li>
 | 
			
		||||
            {% else %}
 | 
			
		||||
                <li class="active">{{ item.title_resolved }}</li>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
    </ul>
 | 
			
		||||
{% else %}
 | 
			
		||||
 | 
			
		||||
{% endif %}
 | 
			
		||||
							
								
								
									
										16
									
								
								symposion/templates/sitetree/menu.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								symposion/templates/sitetree/menu.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
{% load sitetree %}
 | 
			
		||||
<ul class="nav">
 | 
			
		||||
    {% for item in sitetree_items %}
 | 
			
		||||
    <li class="{{ item.is_current|yesno:"active ," }}{% if item.has_children %}dropdown{% endif %}">
 | 
			
		||||
        {% if item.has_children %}
 | 
			
		||||
            <a href="#" class="dropdown-toggle" data-toggle="dropdown" title="{{ item.hint|default:"" }}">
 | 
			
		||||
                {{ item.title_resolved }}
 | 
			
		||||
                <b class="caret"></b>
 | 
			
		||||
            </a>
 | 
			
		||||
            {% sitetree_children of item for menu template "sitetree/submenu.html" %}
 | 
			
		||||
        {% else %}
 | 
			
		||||
            <a href="{% sitetree_url for item %}" title="{{ item.hint|default:"" }}">{{ item.title_resolved }}</a>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </li>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
</ul>
 | 
			
		||||
							
								
								
									
										8
									
								
								symposion/templates/sitetree/submenu.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								symposion/templates/sitetree/submenu.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
{% load sitetree %}
 | 
			
		||||
<ul class="dropdown-menu">
 | 
			
		||||
    {% for item in sitetree_items %}
 | 
			
		||||
    <li>
 | 
			
		||||
        <a href="{% sitetree_url for item %}" title="{{ item.hint|default:"" }}">{{ item.title_resolved }}</a>
 | 
			
		||||
    </li>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
</ul>
 | 
			
		||||
							
								
								
									
										15
									
								
								symposion/templates/sitetree/tree.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								symposion/templates/sitetree/tree.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
{% load sitetree %}
 | 
			
		||||
{% if sitetree_items %}
 | 
			
		||||
<ul>
 | 
			
		||||
    {% for item in sitetree_items %}
 | 
			
		||||
        {% if item.insitetree  %}
 | 
			
		||||
            <li>
 | 
			
		||||
                <a href="{% sitetree_url for item %}" {% if item.hint %}title="{{ item.hint }}"{% endif %}>{{ item.title_resolved }}</a>
 | 
			
		||||
                {% if item.has_children %}
 | 
			
		||||
                    {% sitetree_children of item for sitetree template "sitetree/tree.html" %}
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </li>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
</ul>
 | 
			
		||||
{% endif %}
 | 
			
		||||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ admin.autodiscover()
 | 
			
		|||
 | 
			
		||||
# from pinax.apps.account.openid_consumer import PinaxConsumer
 | 
			
		||||
 | 
			
		||||
WIKI_SLUG = r"(([\w-]{2,})(/[\w-]{2,})*)"
 | 
			
		||||
 | 
			
		||||
urlpatterns = patterns("",
 | 
			
		||||
    url(r"^$", direct_to_template, {
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +19,11 @@ urlpatterns = patterns("",
 | 
			
		|||
    url(r"^about/", include("symposion.about.urls")),
 | 
			
		||||
    url(r"^account/", include("account.urls")),
 | 
			
		||||
    # url(r"^openid/", include(PinaxConsumer().urls)),
 | 
			
		||||
    
 | 
			
		||||
    url(r"^boxes/", include("symposion.boxes.urls")),
 | 
			
		||||
    url(r"^markitup/", include("markitup.urls")),
 | 
			
		||||
    
 | 
			
		||||
    url(r"^", include("symposion.cms.urls")),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										0
									
								
								symposion_project/apps/cms/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								symposion_project/apps/cms/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										12
									
								
								symposion_project/apps/cms/admin.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								symposion_project/apps/cms/admin.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
from django.contrib import admin
 | 
			
		||||
 | 
			
		||||
from mptt.admin import MPTTModelAdmin
 | 
			
		||||
 | 
			
		||||
from cms.models import Page
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PageAdmin(MPTTModelAdmin):
 | 
			
		||||
    prepopulated_fields = {"slug": ("title",)}
 | 
			
		||||
    list_display = ("title", "published", "status")
 | 
			
		||||
 | 
			
		||||
admin.site.register(Page, PageAdmin)
 | 
			
		||||
							
								
								
									
										65
									
								
								symposion_project/apps/cms/models.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								symposion_project/apps/cms/models.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,65 @@
 | 
			
		|||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from markitup.fields import MarkupField
 | 
			
		||||
 | 
			
		||||
from taggit.managers import TaggableManager
 | 
			
		||||
 | 
			
		||||
from mptt.models import MPTTModel, TreeForeignKey
 | 
			
		||||
from mptt.utils import drilldown_tree_for_node
 | 
			
		||||
 | 
			
		||||
import reversion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ContentBase(models.Model):
 | 
			
		||||
    
 | 
			
		||||
    STATUS_CHOICES = (
 | 
			
		||||
        (1, _("Draft")),
 | 
			
		||||
        (2, _("Public")),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    title = models.CharField(max_length=100)
 | 
			
		||||
    slug = models.CharField(max_length=100, blank=True, null=True)
 | 
			
		||||
    body = MarkupField()
 | 
			
		||||
 | 
			
		||||
    tags = TaggableManager(blank=True)
 | 
			
		||||
 | 
			
		||||
    status = models.IntegerField(choices=STATUS_CHOICES, default=2)
 | 
			
		||||
    published = models.DateTimeField(default=datetime.now)
 | 
			
		||||
    created = models.DateTimeField(editable=False, default=datetime.now)
 | 
			
		||||
    updated = models.DateTimeField(editable=False, default=datetime.now)
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Page(MPTTModel, ContentBase):
 | 
			
		||||
 | 
			
		||||
    parent = TreeForeignKey("self", null=True, blank=True, related_name="children")
 | 
			
		||||
    ordering = models.PositiveIntegerField(default=1)
 | 
			
		||||
    path = models.TextField(blank=True, editable=False)
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return self.title
 | 
			
		||||
 | 
			
		||||
    def save(self, calculate_path=True, *args, **kwargs):
 | 
			
		||||
        super(Page, self).save(*args, **kwargs)
 | 
			
		||||
        if calculate_path:
 | 
			
		||||
            self.calculate_path()
 | 
			
		||||
    
 | 
			
		||||
    def calculate_path(self):
 | 
			
		||||
        self.path = ""
 | 
			
		||||
        for page in drilldown_tree_for_node(self):
 | 
			
		||||
            if page == self:
 | 
			
		||||
                self.path += page.slug
 | 
			
		||||
                break
 | 
			
		||||
            else:
 | 
			
		||||
                self.path += "%s/" % page.slug
 | 
			
		||||
        self.save(calculate_path=False)
 | 
			
		||||
 | 
			
		||||
    class MPTTMeta:
 | 
			
		||||
        order_insertion_by = ["ordering", "title"]
 | 
			
		||||
 | 
			
		||||
reversion.register(Page)
 | 
			
		||||
							
								
								
									
										15
									
								
								symposion_project/apps/cms/views.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								symposion_project/apps/cms/views.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
from django.shortcuts import render_to_response, get_object_or_404
 | 
			
		||||
from django.template import RequestContext
 | 
			
		||||
 | 
			
		||||
from cms.models import Page
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def page(request, slug):
 | 
			
		||||
    
 | 
			
		||||
    page = get_object_or_404(Page, path=slug)
 | 
			
		||||
    siblings = page.get_siblings(include_self=True)
 | 
			
		||||
    
 | 
			
		||||
    return render_to_response("cms/page_detail.html", {
 | 
			
		||||
        "page": page,
 | 
			
		||||
        "siblings": siblings,
 | 
			
		||||
    }, context_instance=RequestContext(request))
 | 
			
		||||
							
								
								
									
										19
									
								
								symposion_project/templates/cms/page_detail.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								symposion_project/templates/cms/page_detail.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
{% extends "subnav_base.html" %}
 | 
			
		||||
 | 
			
		||||
{% block subnav %}
 | 
			
		||||
    <ul class="nav nav-list">
 | 
			
		||||
        <li class="nav-header">{{ page.parent }}</li>
 | 
			
		||||
        {% for sibling in siblings %}
 | 
			
		||||
            {% if sibling == page %}
 | 
			
		||||
                <li>{{ sibling }}</li>
 | 
			
		||||
            {% else %}
 | 
			
		||||
                <li><a href="{% url cms_page sibling.path %}">{{ sibling }}</a>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
    </ul>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block body %}
 | 
			
		||||
    <h1>{{ page.title }}</h1>
 | 
			
		||||
    {{ page.body }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										11
									
								
								symposion_project/templates/sitetree/menu.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								symposion_project/templates/sitetree/menu.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
{% load sitetree %}
 | 
			
		||||
<ul class="nav">
 | 
			
		||||
	{% for item in sitetree_items %}
 | 
			
		||||
	<li class="{{ item.is_current|yesno:"active ," }}">
 | 
			
		||||
        <a href="{% sitetree_url for item %}" title="{{ item.hint|default:"" }}">{{ item.title_resolved }}</a>
 | 
			
		||||
		{% if item.has_children %}
 | 
			
		||||
			{% sitetree_children of item for menu template "sitetree/menu.html" %}
 | 
			
		||||
		{% endif %}
 | 
			
		||||
	</li>
 | 
			
		||||
	{% endfor %}
 | 
			
		||||
</ul>
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue