Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

It's been long enough, get 0.2 merged and let's focus on getting to 1.0 #1

Merged
merged 15 commits into from Feb 27, 2013
3 changes: 2 additions & 1 deletion MANIFEST.in
@@ -1 +1,2 @@
include README.rst include README.rst
recursive-include boxes/templates *
8 changes: 7 additions & 1 deletion boxes/admin.py
@@ -1,6 +1,12 @@
from django.contrib import admin from django.contrib import admin


import reversion

from boxes.models import Box from boxes.models import Box




admin.site.register(Box) class BoxAdmin(reversion.VersionAdmin):
search_fields = ["content"]


admin.site.register(Box, BoxAdmin)
20 changes: 0 additions & 20 deletions boxes/authorization.py

This file was deleted.

3 changes: 2 additions & 1 deletion boxes/models.py
Expand Up @@ -8,10 +8,11 @@
class Box(models.Model): class Box(models.Model):


label = models.CharField(max_length=100, db_index=True) 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") created_by = models.ForeignKey(User, related_name="boxes")
last_updated_by = models.ForeignKey(User, related_name="updated_boxes") last_updated_by = models.ForeignKey(User, related_name="updated_boxes")
last_updated = models.DateTimeField(default=datetime.datetime.now)


def __unicode__(self): def __unicode__(self):
return self.label return self.label
Expand Down
26 changes: 26 additions & 0 deletions 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>
103 changes: 22 additions & 81 deletions boxes/templatetags/boxes_tags.py
@@ -1,94 +1,35 @@
from django import template from django import template
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import reverse 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.models import Box
from boxes.authorization import load_can_edit from boxes.forms import BoxForm




register = template.Library() 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 request = context["request"]
def handle(cls, parser, token): can_edit = request.user.has_perm("boxes.change_box")
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)


def __init__(self, label, args, kwargs): try:
self.label = label box = Box.objects.get(label=label)
self.args = args except Box.DoesNotExist:
self.kwargs = kwargs box = None


def render(self, context): if can_edit and show_edit:
try: form = BoxForm(instance=box, prefix=label)
request = context["request"] form_action = reverse("box_edit", args=[label])
except KeyError: else:
raise ImproperlyConfigured('django-boxes requires the use of "django.core.context_processors.request" in TEMPLATE_CONTEXT_PROCESSORS') form = None

form_action = None
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] %}


All args/kwargs are passed directly to callable defined in the setting return {
BOXES_CAN_EDIT_CALLABLE which returns True or False to determine if the "request": request,
box can be edited. "label": label,
""" "box": box,
return BoxNode.handle(parser, token) "form": form,
"form_action": form_action,
}
5 changes: 2 additions & 3 deletions boxes/urls.py
Expand Up @@ -2,6 +2,5 @@




urlpatterns = patterns("boxes.views", urlpatterns = patterns("boxes.views",
url(r"^([-\w]+)/create/$", "box_create", name="box_create"), url(r"^([-\w]+)/edit/$", "box_edit", name="box_edit"),
url(r"^(\d+)/edit/$", "box_edit", name="box_edit"), )
)
19 changes: 0 additions & 19 deletions boxes/utils.py

This file was deleted.

90 changes: 40 additions & 50 deletions boxes/views.py
@@ -1,61 +1,51 @@
from django.http import HttpResponseForbidden import datetime
from django.shortcuts import get_object_or_404, render_to_response 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 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.forms import BoxForm
from boxes.models import Box 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 @require_POST
def get_auth_vars(request): def box_edit(request, label):
auth_vars = {}
if request.method == "POST": if not request.user.has_perm("boxes.change_box"):
keys = [k for k in request.POST.keys() if k.startswith("boxes_auth_")] return HttpResponseForbidden()
for key in keys:
auth_vars[key.replace("boxes_auth_", "")] = request.POST.get(key) next = request.GET.get("next")
auth_vars["user"] = request.user
return auth_vars try:

box = Box.objects.get(label=label)

except Box.DoesNotExist:
def box_edit(request, pk): box = None
box = get_object_or_404(Box, pk=pk)
if request.method == "POST": form = BoxForm(request.POST, instance=box, prefix=label)
#if not load_can_edit()(request, **get_auth_vars(request)):
# return HttpResponseForbidden() if form.is_valid():

if box is None:
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():
box = form.save(commit=False) box = form.save(commit=False)
box.label = label box.label = label
box.created_by = request.user box.created_by = request.user
box.last_updated_by = request.user box.last_updated_by = request.user
box.last_updated = datetime.datetime.now()
box.save() box.save()
return render_to_response("boxes/refresh.html", {}) else:
else: form.save()
form = BoxForm()
ctx = { if request.is_ajax():
"form": form, data = {
"label": label "html": render_to_string("boxes/box.html", {
} "label": label,
ctx = RequestContext(request, ctx) "form": BoxForm(instance=box, prefix=label),
return render_to_response("boxes/box_create.html", ctx) "box": box,
"form_action": reverse("box_edit", args=[label])
}, context_instance=RequestContext(request))
}
return HttpResponse(json.dumps(data), mimetype="application/json")
return redirect(next)
5 changes: 4 additions & 1 deletion setup.py
Expand Up @@ -3,13 +3,16 @@


setup( setup(
name = "django-boxes", name = "django-boxes",
version = "1.0b1.dev2", version = "2.0b1.dev1",
author = "Eldarion", author = "Eldarion",
author_email = "development@eldarion.com", author_email = "development@eldarion.com",
description = "a reusable Django content-boxes application", description = "a reusable Django content-boxes application",
long_description = open("README.rst").read(), long_description = open("README.rst").read(),
license = "BSD", license = "BSD",
url = "http://github.com/eldarion/boxes", url = "http://github.com/eldarion/boxes",
install_requires = [
"django-reversion",
],
packages = [ packages = [
"boxes", "boxes",
"boxes.templatetags", "boxes.templatetags",
Expand Down