Skip to content

Commit

Permalink
update cms/boxes to pycon parity
Browse files Browse the repository at this point in the history
  • Loading branch information
lukeman committed Jul 10, 2012
1 parent 1b04b7a commit 2665fd5
Show file tree
Hide file tree
Showing 27 changed files with 442 additions and 82 deletions.
2 changes: 1 addition & 1 deletion requirements/base.txt
Expand Up @@ -25,7 +25,7 @@ django_compressor==1.2a1

django-mptt==0.5.2
django-taggit==0.9.3
django-reversion==1.5.1
django-reversion==1.6.1
django-markitup==1.0.0
markdown==2.1.1
django-sitetree==0.6
Empty file added symposion/boxes/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions symposion/boxes/admin.py
@@ -0,0 +1,6 @@
from django.contrib import admin

from symposion.boxes.models import Box


admin.site.register(Box)
20 changes: 20 additions & 0 deletions symposion/boxes/authorization.py
@@ -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 changes: 10 additions & 0 deletions symposion/boxes/forms.py
@@ -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 changes: 22 additions & 0 deletions symposion/boxes/models.py
@@ -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"
Empty file.
41 changes: 41 additions & 0 deletions symposion/boxes/templatetags/boxes_tags.py
@@ -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 changes: 6 additions & 0 deletions symposion/boxes/urls.py
@@ -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 changes: 19 additions & 0 deletions symposion/boxes/utils.py
@@ -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 changes: 45 additions & 0 deletions symposion/boxes/views.py
@@ -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)
10 changes: 2 additions & 8 deletions symposion/cms/admin.py
@@ -1,12 +1,6 @@
from django.contrib import admin

from mptt.admin import MPTTModelAdmin
from .models import Page

from cms.models import Page


class PageAdmin(MPTTModelAdmin):
prepopulated_fields = {"slug": ("title",)}
list_display = ("title", "published", "status")

admin.site.register(Page, PageAdmin)
admin.site.register(Page)
16 changes: 16 additions & 0 deletions symposion/cms/forms.py
@@ -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 changes: 9 additions & 0 deletions symposion/cms/managers.py
@@ -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())
60 changes: 24 additions & 36 deletions symposion/cms/models.py
@@ -1,65 +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

from mptt.models import MPTTModel, TreeForeignKey
from mptt.utils import drilldown_tree_for_node

import reversion

from .managers import PublishedPageManager


class ContentBase(models.Model):
class Page(models.Model):

STATUS_CHOICES = (
(1, _("Draft")),
(2, _("Public")),
)

title = models.CharField(max_length=100)
slug = models.CharField(max_length=100, blank=True, null=True)
path = models.CharField(max_length=100, unique=True)
body = MarkupField()

tags = TaggableManager(blank=True)

status = models.IntegerField(choices=STATUS_CHOICES, default=2)
published = models.DateTimeField(default=datetime.now)
publish_date = 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)

tags = TaggableManager(blank=True)

published = PublishedPageManager()

def __unicode__(self):
return self.title

def save(self, calculate_path=True, *args, **kwargs):

@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)
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)
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 /"),]})

class MPTTMeta:
order_insertion_by = ["ordering", "title"]

reversion.register(Page)
8 changes: 8 additions & 0 deletions symposion/cms/urls.py
@@ -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"),
)
60 changes: 52 additions & 8 deletions symposion/cms/views.py
@@ -1,15 +1,59 @@
from django.shortcuts import render_to_response, get_object_or_404
from django.http import Http404
from django.shortcuts import render, redirect
from django.template import RequestContext

from cms.models import Page
from .models import Page
from .forms import PageForm


def page(request, slug):
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):

page = get_object_or_404(Page, path=slug)
siblings = page.get_siblings(include_self=True)
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_to_response("cms/page_detail.html", {
return render(request, "cms/page_detail.html", {
"page": page,
"siblings": siblings,
}, context_instance=RequestContext(request))
"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
})

0 comments on commit 2665fd5

Please sign in to comment.