# DEPRECATED: Django has cookie based messages since version 1.2
#
# -*- coding: iso-8859-1 -*-
# $Id: sessionutils.py 322 2009-04-22 10:53:04Z tguettler $
# $HeadURL: svn+ssh://svnserver/svn/djangotools/trunk/utils/sessionutils.py $

u'''

http://www.djangosnippets.org/snippets/1459/

Modify the Session class of django. Create some extra methods.
This way of hacking django is easier than running a modified version.

MessageCookieMiddleware Usage:

def view(request):
    if request.method=='POST':
        ....
        request.session.create_message(u'Your changes have been saved.')
        return django.http.ResponseRedirect(...)

In the code or template where you create your HTML head, you need to insert:
    request.session.get_and_delete_messages()
'''

# Python
import os
import sys
import random
from hashlib import sha1
import pickle

# Django
from django.utils.html import mark_safe
from django.utils.html import conditional_escape as escape
from django.utils.encoding import StrAndUnicode

# Project
from django.conf import settings

KNOWN_LOGLEVELS=['info', 'error']
COOKIE_NAME='%s_messages' % (settings.SESSION_COOKIE_NAME)

class MessageCookieMiddleware(object):
    def process_request(self, request):
        session=getattr(request, 'session', None)
        if session is None:
            return
        cookie=request.COOKIES.get(COOKIE_NAME)
        if cookie:
            session._messages=decode(cookie)
        else:
            session._messages=Messages()
        session._messages_modified=False

    def process_response(self, request, response):
        session=getattr(request, 'session', None)
        if session is None:
            return response
        messages=getattr(session, '_messages', None)
        if messages is None:
            return response
        if not session._messages_modified:
            return response
        if not messages:
            response.delete_cookie(COOKIE_NAME)
        else:
            response.set_cookie(COOKIE_NAME, encode(messages))
        return response

def get_messages(self):
    u'Normaly not needed. Use get_and_delete_messages()'
    messages=getattr(self, '_messages', None)
    if messages is None:
        raise AttributeError('session has no attribute _messages. MessageCookieMiddleware in settings.MIDDLEWARE_CLASSES?')
    return messages

def get_and_delete_messages(self):
    messages=self.get_messages()
    if messages:
        messages=Messages(messages) # copy
        self._messages=Messages()
        self._messages_modified=True
    return messages

class Messages(list, StrAndUnicode):
    def __unicode__(self):
        if not self:
            return u''
        return mark_safe(u'<ul class="messages">%s</ul>' % u''.join([unicode(m) for m in self]))
    def __repr__(self):
        return '<%s object %s messages: %s>' % (self.__class__.__name__, len(self),
                                                u'; '.join([m.message for m in self]))
class Message(object):
    def __init__(self, message, loglevel='info'):
        self.message=message
        assert loglevel in KNOWN_LOGLEVELS, loglevel
        self.loglevel=loglevel
    def __unicode__(self):
        return mark_safe(u'<li class="message-%s">%s</li>' % (self.loglevel, escape(self.message)))

def create_message(self, message, loglevel='info'):
    messages=self.get_messages()
    messages.append(Message(message, loglevel)) 
    self._messages_modified = True


# encode and decode based on from http://www.djangosnippets.org/snippets/1064/
def encode(value):
    assert value
    value = pickle.dumps(value)
    hash = sha1(value + settings.SECRET_KEY)
    return '%s$%s' % (hash.hexdigest(), value)

def decode(cookie):
    u'''
    unpickling of untrusted data is dangerous. Uses settings.SECRET_KEY to
    create a sha1 signature.
    '''
    assert cookie
    s = cookie.split('$', 1)
    hash, value = s
    should = sha1(value + settings.SECRET_KEY).hexdigest() 
    if should != hash:
        raise Exception('verify of sha1 signed cookie failed. should!=hash (%s!=%s)' % (
                should, hash))
    return pickle.loads(value) 

def get_dir(self):
    session_dir=os.path.join(settings.MEDIA_ROOT, 'sessions', self.session_key)
    if not os.path.exists(session_dir):
        os.mkdir(session_dir)
    return session_dir

def get_tempfile(self, extension='', basename=None):
    u'''
    extensions: txt, png, pdf, ...
    '''
    if not basename:
        if extension:
            dot='.'
        else:
            dot=''
        basename='%s%s%s' % (random.randint(0, sys.maxint), dot, extension)
    path=os.path.join(self.get_dir(), basename)
    url='%ssessions/%s/%s' % (settings.MEDIA_URL, self.session_key, basename)
    return (path, url)


# Start Hacking Django
from django.contrib.sessions.backends.base import SessionBase
SessionBase.get_messages=get_messages
SessionBase.get_and_delete_messages=get_and_delete_messages
SessionBase.create_message=create_message
SessionBase.get_dir=get_dir
SessionBase.get_tempfile=get_tempfile
# End Hacking Django