Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
442 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.contrib import admin | ||
|
||
from symposion.boxes.models import Box | ||
|
||
|
||
admin.site.register(Box) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from django import forms | ||
|
||
from symposion.boxes.models import Box | ||
|
||
|
||
class BoxForm(forms.ModelForm): | ||
|
||
class Meta: | ||
model = Box | ||
fields = ["content"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
}) |
Oops, something went wrong.