Changeset - 2665fd575869
requirements/base.txt
Show inline comments
...
 
@@ -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
symposion/boxes/__init__.py
Show inline comments
 
new file 100644
symposion/boxes/admin.py
Show inline comments
 
new file 100644
 
from django.contrib import admin
 

	
 
from symposion.boxes.models import Box
 

	
 

	
 
admin.site.register(Box)
...
 
\ No newline at end of file
symposion/boxes/authorization.py
Show inline comments
 
new file 100644
 
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)
symposion/boxes/forms.py
Show inline comments
 
new file 100644
 
from django import forms
 

	
 
from symposion.boxes.models import Box
 

	
 

	
 
class BoxForm(forms.ModelForm):
 
    
 
    class Meta:
 
        model = Box
 
        fields = ["content"]
symposion/boxes/models.py
Show inline comments
 
new file 100644
 
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"
symposion/boxes/templatetags/__init__.py
Show inline comments
 
new file 100644
symposion/boxes/templatetags/boxes_tags.py
Show inline comments
 
new file 100644
 
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,
 
    }
symposion/boxes/urls.py
Show inline comments
 
new file 100644
 
from django.conf.urls.defaults import url, patterns
 

	
 

	
 
urlpatterns = patterns("symposion.boxes.views",
 
    url(r"^([-\w]+)/edit/$", "box_edit", name="box_edit"),
 
)
...
 
\ No newline at end of file
symposion/boxes/utils.py
Show inline comments
 
new file 100644
 
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
symposion/boxes/views.py
Show inline comments
 
new file 100644
 
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)
symposion/cms/admin.py
Show inline comments
 
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)
symposion/cms/forms.py
Show inline comments
 
new file 100644
 
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(),
 
        }
symposion/cms/managers.py
Show inline comments
 
new file 100644
 
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())
symposion/cms/models.py
Show inline comments
 
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 _
 

	
...
 
@@ -7,59 +10,44 @@ 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)
symposion/cms/urls.py
Show inline comments
 
new file 100644
 
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"),
 
)
symposion/cms/views.py
Show inline comments
 
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
 
    })
symposion/settings.py
Show inline comments
...
 
@@ -155,7 +155,6 @@ INSTALLED_APPS = [
 
    "metron",
 
    "markitup",
 
    "taggit",
 
    "cms",
 
    "mptt",
 
    "reversion",
 
    "easy_thumbnails",
...
 
@@ -168,6 +167,8 @@ INSTALLED_APPS = [
 
    "symposion.about",
 
    "symposion.sponsorship",
 
    "symposion.conference",
 
    "symposion.cms",
 
    "symposion.boxes",
 
]
 

	
 
FIXTURE_DIRS = [
...
 
@@ -201,8 +202,13 @@ DEBUG_TOOLBAR_CONFIG = {
 
}
 

	
 
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:
symposion/templates/boxes/box.html
Show inline comments
 
new file 100644
 
{% 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>
symposion/templates/cms/page_detail.html
Show inline comments
 
{% extends "subnav_base.html" %}
 
{% extends "site_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>
 
{% 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 %}
 
    <h1>{{ page.title }}</h1>
 
    {{ page.body }}
 
{% endblock %}
...
 
\ No newline at end of file
symposion/templates/cms/page_edit.html
Show inline comments
 
new file 100644
 
{% 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 %}
...
 
\ No newline at end of file
symposion/templates/site_base.html
Show inline comments
...
 
@@ -3,20 +3,43 @@
 
{% 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 "root" include "trunk" %}
 
    {% 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_script %}
 
{% block script_base %}
 
    {% analytics %}
 
    {% block extra_body %}{% endblock %}
 
{% endblock %}
...
 
\ No newline at end of file
 
    <script src="{% static "bootstrap/js/bootstrap.js" %}"></script>
 
    <script src="{% static "pinax/js/theme.js" %}"></script>
 
    {% block extra_script %}{% endblock %}
 
{% endblock %}
symposion/templates/sitetree/breadcrumbs.html
Show inline comments
 
new file 100644
 
{% 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 %}
symposion/templates/sitetree/menu.html
Show inline comments
 
{% 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>
...
 
\ No newline at end of file
 
    {% 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>
symposion/templates/sitetree/submenu.html
Show inline comments
 
new file 100644
 
{% 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>
symposion/templates/sitetree/tree.html
Show inline comments
 
new file 100644
 
{% 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 %}
symposion/urls.py
Show inline comments
...
 
@@ -20,9 +20,11 @@ urlpatterns = patterns("",
 
    url(r"^account/", include("account.urls")),
 
    # url(r"^openid/", include(PinaxConsumer().urls)),
 
    
 
    url(r"^(?P<slug>%s)/$" % WIKI_SLUG, "cms.views.page", name="cms_page"),
 
    url(r"^boxes/", include("symposion.boxes.urls")),
 
    url(r"^markitup/", include("markitup.urls")),
 
    
 
    url(r"^", include("symposion.cms.urls")),
 
)
 

	
 

	
 
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
...
 
\ No newline at end of file
 
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
0 comments (0 inline, 0 general)