From 931ef907b8e9aff303eefcdb85bc9cd95f381ffe Mon Sep 17 00:00:00 2001 From: jordan Date: Mon, 16 May 2011 21:05:42 +0000 Subject: [PATCH] Adding a separate option that allows administrators to choose whether to store if the greeting message has been shown in a cookie or in the session. This way users won't see the greeting message when they simply logout, because the greeting_set boolean is stored not in the session, but in a cookie. Separate middleware has been added that handles the Django cookies and passes all keys from the request.COOKIES object to the response object. This way the session cookies are stored as real HTTP cookies. git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@1040 0cfe37f9-358a-4d5e-be75-b63607b5c754 --- forum/middleware/anon_user.py | 12 +++- forum/middleware/django_cookies.py | 102 +++++++++++++++++++++++++++++ forum/settings/users.py | 5 ++ settings.py | 2 + 4 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 forum/middleware/django_cookies.py diff --git a/forum/middleware/anon_user.py b/forum/middleware/anon_user.py index 26c138c..25f192a 100644 --- a/forum/middleware/anon_user.py +++ b/forum/middleware/anon_user.py @@ -1,4 +1,4 @@ -from django.http import HttpResponseRedirect +from django.http import HttpResponseRedirect, HttpResponse from forum.forms import get_next_url from django.utils.translation import ugettext as _ from forum.user_messages import create_message, get_and_delete_messages @@ -31,5 +31,13 @@ class ConnectToSessionMessagesMiddleware(object): #also set the first greeting one time per session only if 'greeting_set' not in request.session: request.session['greeting_set'] = True + msg = _('First time here? Check out the FAQ!') % reverse('faq') - request.user.message_set.create(message=msg) + + # If the store greeting in cookie setting is activated make sure that the greeting_set cookies isn't set + if (settings.STORE_GREETING_IN_COOKIE and not request.COOKIES.has_key('greeting_set')) or \ + not settings.STORE_GREETING_IN_COOKIE: + request.user.message_set.create(message=msg) + + if settings.STORE_GREETING_IN_COOKIE: + request.COOKIES.set(key='greeting_set', value=True) diff --git a/forum/middleware/django_cookies.py b/forum/middleware/django_cookies.py new file mode 100644 index 0000000..5e5277e --- /dev/null +++ b/forum/middleware/django_cookies.py @@ -0,0 +1,102 @@ +""" +A two-part middleware which modifies request.COOKIES and adds a set and delete method. + + `set` matches django.http.HttpResponse.set_cookie + `delete` matches django.http.HttpResponse.delete_cookie + +MIDDLEWARE_CLASSES = ( + 'django_cookies.CookiePreHandlerMiddleware', + ... + 'django_cookies.CookiePostHandlerMiddleware', +) + +def my_view(request): + request.COOKIES.set([args]) + ... + return response +""" + +from Cookie import SimpleCookie, Morsel +from django.utils.encoding import smart_unicode, smart_str +import copy + +class CookiePreHandlerMiddleware(object): + """ + This middleware modifies request.COOKIES and adds a set and delete method. + + `set` matches django.http.HttpResponse.set_cookie + `delete` matches django.http.HttpResponse.delete_cookie + + This should be the first middleware you load. + """ + def process_request(self, request): + cookies = CookieHandler() + for k, v in request.COOKIES.iteritems(): + cookies[k] = str(v) + request.COOKIES = cookies + request._orig_cookies = copy.deepcopy(request.COOKIES) + +class CookiePostHandlerMiddleware(object): + """ + This middleware modifies updates the response will all modified cookies. + + This should be the last middleware you load. + """ + def process_response(self, request, response): + if hasattr(request, '_orig_cookies') and request.COOKIES != request._orig_cookies: + for k,v in request.COOKIES.iteritems(): + if request._orig_cookies.get(k) != v: + dict.__setitem__(response.cookies, k, v) + return response + +class StringMorsel(Morsel): + def __str__(self): + return smart_str(self.value) + + def __eq__(self, a): + if isinstance(a, str): + return smart_str(self) == a + elif isinstance(a, Morsel): + return a.output() == self.output() + return False + + def __ne__(self, a): + if isinstance(a, str): + return smart_str(self) != a + elif isinstance(a, Morsel): + return a.output() != self.output() + return True + + def __repr__(self): + return smart_unicode(self) + + def decode(self, *args): + return self.__repr__() + +class CookieHandler(SimpleCookie): + def __set(self, key, real_value, coded_value): + """Private method for setting a cookie's value""" + M = self.get(key, StringMorsel()) + M.set(key, real_value, coded_value) + dict.__setitem__(self, key, M) + + def __setitem__(self, key, value): + """Dictionary style assignment.""" + rval, cval = self.value_encode(value) + self.__set(key, rval, cval) + + def set(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None): + self[key] = value + for var in ('max_age', 'path', 'domain', 'secure', 'expires'): + val = locals()[var] + if val is not None: + self[key][var.replace('_', '-')] = val + + def delete(self, key, path='/', domain=None): + self[key] = '' + if path is not None: + self[key]['path'] = path + if domain is not None: + self[key]['domain'] = domain + self[key]['expires'] = 0 + self[key]['max-age'] = 0 diff --git a/forum/settings/users.py b/forum/settings/users.py index cceaf57..3d7a9f3 100644 --- a/forum/settings/users.py +++ b/forum/settings/users.py @@ -6,6 +6,11 @@ from django.utils.translation import ugettext as _ USERS_SET = SettingSet('users', _('Users settings'), _("General settings for the OSQA users."), 20) +STORE_GREETING_IN_COOKIE = Setting('STORE_GREETING_IN_COOKIE', True, USERS_SET, dict( +label = _("Store greeting in cookie"), +help_text = _("If you check this the greeting will be stored in a cookie and the users won't be notified on logout."), +required=False)) + EDITABLE_SCREEN_NAME = Setting('EDITABLE_SCREEN_NAME', False, USERS_SET, dict( label = _("Editable screen name"), help_text = _("Allow users to alter their screen name."), diff --git a/settings.py b/settings.py index 471b549..f1c6f6b 100644 --- a/settings.py +++ b/settings.py @@ -15,6 +15,7 @@ TEMPLATE_LOADERS = [ ] MIDDLEWARE_CLASSES = [ + 'forum.middleware.django_cookies.CookiePreHandlerMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'forum.middleware.extended_user.ExtendedUser', @@ -23,6 +24,7 @@ MIDDLEWARE_CLASSES = [ 'forum.middleware.cancel.CancelActionMiddleware', 'forum.middleware.admin_messages.AdminMessagesMiddleware', 'django.middleware.transaction.TransactionMiddleware', + 'forum.middleware.django_cookies.CookiePostHandlerMiddleware', ] # Backwards compatibility. If we fail to import the CSRF middle-ware from the location # where it is supposed to be, we add the old middle-ware classes to the classes list. -- 2.39.5