Source

superwiki / superwiki / views.py

# -*- coding: utf-8 -*-

from django.conf import settings
from django.shortcuts import redirect, get_object_or_404, render_to_response
from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404, HttpResponseForbidden, HttpResponse
from django.utils.translation import ugettext as _
from django.template import RequestContext

from annoying.decorators import render_to
from reversion.models import Version
from notify import notify_user

from common import bind_getter, url_getter, write_perm_check
from models import WikiPage, ContentType
from forms import WikiPageForm
import signals
from html_diff import html_diff


def wiki_bind_getter(fn):
    def wrap(request, *args, **kwargs):
        if 'url' in kwargs:
            if kwargs['url'].endswith('/'):
                return redirect(request.path.rstrip('/'))
        bind, kw = bind_getter(request, *args, **kwargs)
        return fn(request, bind, **kw)
    return wrap


def get_wiki_page(bind, **kwargs):
    bind_content_type = ContentType.objects.get_for_model(type(bind))
    if 'url' in kwargs:
        kwargs['url'] = kwargs['url'].lower()
    return WikiPage.objects.get(content_type=bind_content_type,
                                object_id=bind.pk, **kwargs)


def filter_wiki_pages(bind, **kwargs):
    bind_content_type = ContentType.objects.get_for_model(type(bind))
    return WikiPage.objects.filter(content_type=bind_content_type,
                                   object_id=bind.pk, **kwargs)


def require_write_perm(fn):
    def wrap(request, bind, **kwargs):
        if not write_perm_check(request, bind):
            return HttpResponseForbidden('forbidden')
        return fn(request, bind, **kwargs)
    return wrap


@render_to('wiki/show.html')
@wiki_bind_getter
def show(request, bind, url):
    exists = False
    try:
        page = get_wiki_page(bind, url=url)
        exists = True
    except ObjectDoesNotExist:
        page = None
    versions = []
    if exists:
        versions = Version.objects.get_for_object(page).order_by('-pk')[:5]
    edit_allowed = write_perm_check(request, bind)
    return {'page': page, 'versions': versions, 'exists': exists, 'url': url,
            'bind': bind, 'edit_allowed': edit_allowed}


@render_to('wiki/index.html')
@wiki_bind_getter
def index(request, bind):
    return {'bind': bind}


@render_to('wiki/edit.html')
@wiki_bind_getter
@require_write_perm
def edit(request, bind, url):
    try:
        page = get_wiki_page(bind, url=url)
    except ObjectDoesNotExist:
        raise Http404, 'page not found'
    if request.method == 'POST':
        frm = WikiPageForm(request.POST, instance=page)
        body, rendered_body, title = page.body, page.rendered_body, page.title
        if frm.is_valid():
            if title != frm.cleaned_data['title'] or body != frm.cleaned_data['body']:
                frm.save()
                signals.wikipage_changed.send(
                                      sender=request.user,
                                      page=page,
                                      created=False,
                                      old_data=dict(
                                        rendered_body=rendered_body,
                                        title=title),
                                      new_data=dict(
                                        rendered_body=page.rendered_body,
                                        title=page.title
                                      ))
                msg = _('Page saved')
            else:
                msg = _('Nothing changed')
            return notify_user.success(request, url_getter(bind, url), msg)

    else:
        frm = WikiPageForm(instance=page)
    return {'page': page, 'bind': bind, 'frm': frm}


@render_to('wiki/create.html')
@wiki_bind_getter
@require_write_perm
def create(request, bind, url):
    if request.method == 'POST':
        frm = WikiPageForm(request.POST)
        if frm.is_valid():
            page = frm.save(commit=False)
            page.author = request.user
            page.bind_to = bind
            page.url = url.lower()
            page.save()
            signals.wikipage_changed.send(
                                  sender=request.user,
                                  page=page,
                                  created=True,
                                  old_data=None,
                                  new_data=dict(
                                    rendered_body=page.rendered_body,
                                    title=page.title
                                  ))
            return notify_user.success(request, url_getter(bind, url),
                                       _('Page successfully created'))
    else:
        frm = WikiPageForm()
    return {'frm': frm, 'url': url, 'bind': bind}


@render_to('wiki/delete.html')
@wiki_bind_getter
def delete(request, bind, url):
    try:
        page = get_wiki_page(bind, url=url)
    except ObjectDoesNotExist:
        raise Http404, 'page not found'
    if request.method == 'POST' and 'confirm' in request.POST:
        page.delete()
        return notify_user.success(request, url_getter(bind, 'home'),
                                   _('Page successfully deleted'))
    return {'page': page, 'bind': bind}


@render_to('wiki/history.html')
@wiki_bind_getter
def history(request, bind, url):
    try:
        page = get_wiki_page(bind, url=url)
    except ObjectDoesNotExist:
        raise Http404, 'page not found'
    versions = Version.objects.get_for_object(page).order_by('pk')
    return {'page': page, 'versions': versions, 'url': url, 'bind': bind}


@wiki_bind_getter
def diff(request, bind, url, ver, ver_b=None):
    try:
        page = get_wiki_page(bind, url=url)
    except ObjectDoesNotExist:
        raise Http404, 'page not found'
    if not ver_b:
        versions = list(Version.objects.get_for_object(page).filter(pk=ver))
        if not versions:
            raise Http404, 'version not found'
        version = versions[0]
        previous_version = None
        pk_lt = version.pk
        while not previous_version:
            v = list(Version.objects.get_for_object(page).filter(pk__lt=pk_lt).order_by('-pk')[:1])
            if not v:
                break
            pk_lt = v[0].pk
            if v[0].object_version.object.rendered_body != version.object_version.object.rendered_body:
                previous_version = v[0]
        template = 'wiki/diff-inline.html'
    else:
        try:
            previous_version = Version.objects.get_for_object(page).get(pk=ver)
            version =  Version.objects.get_for_object(page).get(pk=ver_b)
        except ObjectDoesNotExist:
            raise Http404, 'version not found'
        template = 'wiki/diff2.html'
    if not previous_version:
        diff, text_changes = _('There is no previous version with different body'), True
    else:
        diff, text_changes = html_diff(previous_version.object_version.object.rendered_body, version.object_version.object.rendered_body)
        if not text_changes:
            diff = _('Only formatting differences')
    
    return render_to_response(template, RequestContext(request, {'diff': diff}))