Browse files

Merge pull request #1 from eldarion/dev

It's been long enough, get 0.2 merged and let's focus on getting to 1.0
  • Loading branch information...
2 parents 59f158f + 5ee97a9 commit fcba29569cd847672f987bcc82bb183a1113ddd8 @paltman paltman committed Feb 27, 2013
Showing with 105 additions and 177 deletions.
  1. +2 −1 MANIFEST.in
  2. +7 −1 boxes/admin.py
  3. +0 −20 boxes/authorization.py
  4. +2 −1 boxes/models.py
  5. +26 −0 boxes/templates/boxes/box.html
  6. +22 −81 boxes/templatetags/boxes_tags.py
  7. +2 −3 boxes/urls.py
  8. +0 −19 boxes/utils.py
  9. +40 −50 boxes/views.py
  10. +4 −1 setup.py
View
3 MANIFEST.in
@@ -1 +1,2 @@
-include README.rst
+include README.rst
+recursive-include boxes/templates *
View
8 boxes/admin.py
@@ -1,6 +1,12 @@
from django.contrib import admin
+import reversion
+
from boxes.models import Box
-admin.site.register(Box)
+class BoxAdmin(reversion.VersionAdmin):
+ search_fields = ["content"]
+
+
+admin.site.register(Box, BoxAdmin)
View
20 boxes/authorization.py
@@ -1,20 +0,0 @@
-from django.conf import settings
-
-from 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
-
-
-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)
View
3 boxes/models.py
@@ -8,10 +8,11 @@
class Box(models.Model):
label = models.CharField(max_length=100, db_index=True)
- content = models.TextField()
+ content = models.TextField(blank=True)
created_by = models.ForeignKey(User, related_name="boxes")
last_updated_by = models.ForeignKey(User, related_name="updated_boxes")
+ last_updated = models.DateTimeField(default=datetime.datetime.now)
def __unicode__(self):
return self.label
View
26 boxes/templates/boxes/box.html
@@ -0,0 +1,26 @@
+{% 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 }}
+ </div>
+ <div class="form-actions">
+ <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> Edit this content</a>
+ {% endif %}
+ {{ box.content|safe }}
+</div>
View
103 boxes/templatetags/boxes_tags.py
@@ -1,94 +1,35 @@
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 boxes.models import Box
-from boxes.authorization import load_can_edit
+from boxes.forms import BoxForm
register = template.Library()
-class BoxNode(template.Node):
+@register.inclusion_tag("boxes/box.html", takes_context=True)
+def box(context, label, show_edit=True, *args, **kwargs):
- @classmethod
- def handle(cls, parser, token):
- bits = token.split_contents()
- if len(bits) < 2:
- raise template.TemplateSyntaxError(
- "'box' takes at least one argument (label of the content to display)"
- )
- args = []
- kwargs = {}
- label = parser.compile_filter(bits[1])
- bits = bits[2:]
- if len(bits):
- for bit in bits:
- match = kwarg_re.match(bit)
- if not match:
- raise template.TemplateSyntaxError("Malformed arguments to 'box' tag")
- name, value = match.groups()
- if name:
- kwargs[name] = parser.compile_filter(value)
- else:
- args.append(parser.compile_filter(value))
- return cls(label, args, kwargs)
+ request = context["request"]
+ can_edit = request.user.has_perm("boxes.change_box")
- def __init__(self, label, args, kwargs):
- self.label = label
- self.args = args
- self.kwargs = kwargs
+ try:
+ box = Box.objects.get(label=label)
+ except Box.DoesNotExist:
+ box = None
- def render(self, context):
- try:
- request = context["request"]
- except KeyError:
- raise ImproperlyConfigured('django-boxes requires the use of "django.core.context_processors.request" in TEMPLATE_CONTEXT_PROCESSORS')
-
- label = self.label.resolve(context)
- args = [arg.resolve(context) for arg in self.args]
- kwargs = dict([
- (smart_str(k, "ascii"), v.resolve(context))
- for k, v in self.kwargs.items()
- ])
-
- show_edit_link = load_can_edit()(request, *args, **kwargs)
-
- try:
- box = Box.objects.get(label=label)
- content = box.content.strip()
- except Box.DoesNotExist:
- box = None
- content = ""
-
- if len(content) == 0:
- content = _("<p>No content for this box has been created yet.</p>")
-
- # @@@ encode args/kwargs into querystring
- if show_edit_link:
- if box is None:
- url = reverse("box_create", args=[label])
- link_text = unicode(_("Create"))
- else:
- url = reverse("box_edit", args=[box.pk])
- link_text = unicode(_("Edit"))
-
- content += " <a href=\"%s\" class=\"boxes-edit-link\" rel=\"facebox\">%s</a>" % (url, link_text)
-
- return mark_safe(content)
-
-
-@register.tag
-def box(parser, token):
- """
- {% box label [args] [kwargs] %}
+ 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
- All args/kwargs are passed directly to callable defined in the setting
- BOXES_CAN_EDIT_CALLABLE which returns True or False to determine if the
- box can be edited.
- """
- return BoxNode.handle(parser, token)
+ return {
+ "request": request,
+ "label": label,
+ "box": box,
+ "form": form,
+ "form_action": form_action,
+ }
View
5 boxes/urls.py
@@ -2,6 +2,5 @@
urlpatterns = patterns("boxes.views",
- url(r"^([-\w]+)/create/$", "box_create", name="box_create"),
- url(r"^(\d+)/edit/$", "box_edit", name="box_edit"),
-)
+ url(r"^([-\w]+)/edit/$", "box_edit", name="box_edit"),
+)
View
19 boxes/utils.py
@@ -1,19 +0,0 @@
-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
View
90 boxes/views.py
@@ -1,61 +1,51 @@
-from django.http import HttpResponseForbidden
-from django.shortcuts import get_object_or_404, render_to_response
+import datetime
+import json
+
+from django.core.urlresolvers import reverse
+from django.http import HttpResponse, HttpResponseForbidden
+from django.shortcuts import redirect
from django.template import RequestContext
+from django.template.loader import render_to_string
+from django.views.decorators.http import require_POST
-from boxes.authorization import load_can_edit
from boxes.forms import BoxForm
from 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
-
-
-def box_edit(request, pk):
- box = get_object_or_404(Box, pk=pk)
- if request.method == "POST":
- #if not load_can_edit()(request, **get_auth_vars(request)):
- # return HttpResponseForbidden()
-
- form = BoxForm(request.POST, instance=box)
- if form.is_valid():
- form.save()
- return render_to_response("boxes/refresh.html", {})
- else:
- form = BoxForm(instance=box)
- ctx = {
- "form": form,
- "box": box,
- }
- ctx = RequestContext(request, ctx)
- return render_to_response("boxes/box_edit.html", ctx)
-
-
-def box_create(request, label):
- if request.method == "POST":
- #if not load_can_edit()(request, **get_auth_vars(request)):
- # return HttpResponseForbidden()
-
- form = BoxForm(request.POST)
- if form.is_valid():
+@require_POST
+def box_edit(request, label):
+
+ if not request.user.has_perm("boxes.change_box"):
+ 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.last_updated = datetime.datetime.now()
box.save()
- return render_to_response("boxes/refresh.html", {})
- else:
- form = BoxForm()
- ctx = {
- "form": form,
- "label": label
- }
- ctx = RequestContext(request, ctx)
- return render_to_response("boxes/box_create.html", ctx)
+ else:
+ form.save()
+
+ if request.is_ajax():
+ data = {
+ "html": render_to_string("boxes/box.html", {
+ "label": label,
+ "form": BoxForm(instance=box, prefix=label),
+ "box": box,
+ "form_action": reverse("box_edit", args=[label])
+ }, context_instance=RequestContext(request))
+ }
+ return HttpResponse(json.dumps(data), mimetype="application/json")
+ return redirect(next)
View
5 setup.py
@@ -3,13 +3,16 @@
setup(
name = "django-boxes",
- version = "1.0b1.dev2",
+ version = "2.0b1.dev1",
author = "Eldarion",
author_email = "development@eldarion.com",
description = "a reusable Django content-boxes application",
long_description = open("README.rst").read(),
license = "BSD",
url = "http://github.com/eldarion/boxes",
+ install_requires = [
+ "django-reversion",
+ ],
packages = [
"boxes",
"boxes.templatetags",

0 comments on commit fcba295

Please sign in to comment.