Mango /

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

import hashlib

import disqus

from django import http
from django.conf import settings
from django.core.mail import EmailMultiAlternatives, send_mail
from django.shortcuts import render_to_response
from django.template import RequestContext, loader
from django.template.defaultfilters import slugify

import mango
from mango.settings import *
from mango.exceptions import EmptySettingError
from mango.forms import CommentForm, ContactForm
from mango.main import Category, Document
    from mango.models import Subscription
from mango.templatetags.mango_extras import _convert
from mango.utils import logger, primary_author_email

def _defaults(request, context=None):
    if context is None:
        context = {}

    # make Mango's settings accessible to templates
    for key, value in mango.settings.__dict__.items():
        if not key.startswith('_'):
            context[key] = value

    # Django settings
    context['settings'] = settings

    # set top-level category
    toplevel = Category.toplevel()

    context['archives'] = toplevel.archives()
    context['posts'] = toplevel.descendants()
    context['tags'] = toplevel.tags()

    context['stylesheets'] = CSS
    context['scripts'] = JS

    return RequestContext(request, context)

def archives(request):
    context = _defaults(request)
    return render_to_response('archives.dhtml', context_instance=context)

def category(request, category):
    context = _defaults(request, context={'category': category})
    return render_to_response('category.dhtml', context)

def contact(request, message_sent=False):
    if message_sent:
        context = _defaults(request)
        return render_to_response('contact.dhtml', context_instance=context)

    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            sender = u'%s <%s>' % (form.cleaned_data['sender_name'], form.cleaned_data['sender_email'])

                recipients = [primary_author_email()]
            except EmptySettingError, error:
                return http.HttpResponseServerError(error.html())

            if form.cleaned_data['cc_sender']:

            send_mail(subject, message, sender, recipients, fail_silently=False)
            return http.HttpResponseRedirect('thanks/')
        form = ContactForm()

    context = _defaults(request, context={'form': form})
    return render_to_response('contact.dhtml', context_instance=context)

def index(request):
    context = _defaults(request)
    return render_to_response('index.dhtml', context_instance=context)

def page_not_found(request):
    t = loader.get_template('404.dhtml')
    return http.HttpResponseNotFound(t.render(_defaults(request,
            {'request_path': request.path})))

def post(request, path, view_source=False):
    path = u'/%s/' % path
    found = Category.toplevel().find_match(path)
    if not isinstance(found, (Category, Document)):
        return page_not_found(request)

    if isinstance(found, Category):
        if view_source or path != found.urls['canon']['rel']:
            return http.HttpResponseRedirect(found.urls['canon']['abs'])
        return category(request, found)

    document = found # we've confirmed that the we're to serve a Document

    if path != document.urls['canon']['rel']:
        url = document.urls['canon']['abs']
        url = url + 'm/' if view_source else url
        return http.HttpResponseRedirect(url)

    if view_source:
        return http.HttpResponse(document.body, content_type=PLAIN)

    thread = document._thread

    comment = request.session.pop('comment', None) if thread else None
    if comment is not None:
        comment = loader.render_to_string('comment.dhtml', {'comment': comment})

    while True: # avoids excessive indentation
        form = CommentForm()
        if request.method != 'POST': break

        form = CommentForm(request.POST, request=request)
        if not form.is_valid(): break

        author_name = form.cleaned_data['author_name']
        author_email = form.cleaned_data['author_email']
        author_url = form.cleaned_data['author_url']
        message = form.cleaned_data['message']
        subscribe = form.cleaned_data['subscribe']

        if subscribe and SUBSCRIPTIONS: # don't assume that SUBSCRIPTIONS is True
            subscriptions = Subscription.objects.filter(
                    subscriber_email=author_email, url=document.urls['canon']['abs'])
            if not subscriptions:
                subscription = Subscription(subscriber_name=author_name,
                        subscriber_email=author_email, url=document.urls['canon']['abs'])
            logger.debug('%s is %s subscribed to comments on %s' % (author_name,
                    'already' if subscriptions else 'now', document.title))

        if not thread: break

            # send request to Disqus
            comment = DISQUS.create_post(FORUM, thread,
        except disqus.APIError, error:
            logger.warning('Disqus API error: %s' % error)

        # store comment so that it can be displayed to
        # its author even if withheld for moderation
        comment.html = _convert(comment.message)
        request.session['comment'] = comment

        # send e-mail notification
        author = u'%s <%s>' % (author_name, author_email)
        subject = u'[%s] Comment: "%s"' % (SITE_TITLE, document.title)
        context = {
            'commenter': author,
            'comment': message,
            'base_url': BASE_URL,
            'path': path,
            'api_key': hashlib.sha1(DISQUS_API_KEY).hexdigest(),
            recipient = primary_author_email()
        except EmptySettingError, error:
            return http.HttpResponseServerError(error.html())

        msg = EmailMultiAlternatives(subject, loader.render_to_string('email/moderator.dtext', context),
                to=[recipient], headers={'Reply-To': author})
        msg.attach_alternative(loader.render_to_string('email/moderator.dhtml', context), 'text/html')

        return http.HttpResponseRedirect('redirect/#%s' %

    context = _defaults(request, context={
        'comments': document.comments(),
        'document': document,
        'form': form,
        'new_comment': comment,
        'thread': thread,
    return render_to_response('%s.dhtml' % document.type, context_instance=context)

def search(request):
    query = request.GET.get('query')
    if not query:
        message = 'Please submit a GET request with a parameter named "query".'
        return http.HttpResponseBadRequest(message, content_type=PLAIN)

    # convert query to a list of search terms
    terms = []
    for index, fragment in enumerate(query.strip().lower().split('"')):
        if index % 2: # every second fragment is quoted
            for word in fragment.split():

    # determine which documents match the search terms
    results = {'pages': [], 'posts': []}
    for document in Category.toplevel().descendants(pages=True):
        for term in terms:
            if document.body.lower().find(term) == -1:
            if document.type == 'page':

    context = _defaults(request, context={'results': results, 'terms': terms})
    return render_to_response('searchresults.dhtml', context_instance=context)

def tagged_as(request, tag):
    tag = slugify(tag)
    documents = []
    for document in Category.toplevel().descendants(pages=True):
        if tag in [slugify(t) for t in document.meta.get('tags', [])]:
    context = _defaults(request, context={'tag': tag, 'documents': documents})
    return render_to_response('tag.dhtml', context_instance=context)

def tags(request):
    context = _defaults(request)
    return render_to_response('tags.dhtml', context_instance=context)