Skip to content

Commit

Permalink
Merge df3a231 into 105ec5c
Browse files Browse the repository at this point in the history
  • Loading branch information
arescope committed Oct 3, 2014
2 parents 105ec5c + df3a231 commit a978dc7
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 23 deletions.
20 changes: 1 addition & 19 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,25 +49,7 @@ And also in a custom layout:
.. image:: http://i.imgur.com/d7kZtr9.png


Installation
============
1. ``pip install django-user-sessions``
2. In ``INSTALLED_APPS`` replace ``'django.contrib.sessions'`` with
``'user_sessions'``.
3. In ``MIDDLEWARE_CLASSES`` replace
``'django.contrib.sessions.middleware.SessionMiddleware'`` with
``'user_sessions.middleware.SessionMiddleware'``.
4. Add ``SESSION_ENGINE = 'user_sessions.backends.db'``.
5. Add ``url(r'', include('user_sessions.urls', 'user_sessions')),`` to your
``urls.py``.
6. Run ``python manage.py syncdb`` (or ``migrate``) and browse to
``/account/sessions/``.

GeoIP
-----
You need to setup GeoIP for the location detection to work. See the Django
documentation on `installing GeoIP`_.

.. include:: docs/installation.rst

Contribute
==========
Expand Down
31 changes: 29 additions & 2 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,42 @@ Installation
3. In ``MIDDLEWARE_CLASSES`` replace
``'django.contrib.sessions.middleware.SessionMiddleware'`` with
``'user_sessions.middleware.SessionMiddleware'``.
4. Add ``SESSION_ENGINE = 'user_sessions.backends.db'``.
4. Setup ``SESSION_ENGINE`` setting: Please see `Session Engine`_ to choose the
best option for your project.
5. Add ``url(r'', include('user_sessions.urls', 'user_sessions')),`` to your
``urls.py``.
6. Run ``python manage.py syncdb`` (or ``migrate``) and start hacking!

GeoIP
-----
You need to setup GeoIP for the location detection to work. See the Django
documentation on `installing GeoIP`_.


Session Engine
--------------
``django-user-sessions`` supports two types of Session Engine.

database-backed
Sessions will be stored in the database::

SESSION_ENGINE = 'user_sessions.backends.db'

You will need to run ``python manage.py syncdb`` (or ``migrate``)

cached
Session data is stored using Django's cache system. Depending on the cache system can be
persistent or not::

SESSION_ENGINE = 'user_sessions.backends.db'

For configuring the Django's cache system, please read `configuring Cache`_.

For for information about sessions, see the Django documentation on `configuring SessionEngine`_.


.. _installing GeoIP:
https://docs.djangoproject.com/en/1.6/ref/contrib/gis/geoip/
.. _configuring SessionEngine:
https://docs.djangoproject.com/en/1.6/topics/http/sessions/
.. _configuring Cache:
https://docs.djangoproject.com/en/1.6/topics/cache/
5 changes: 3 additions & 2 deletions docs/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ Models

Session Backends
----------------
.. autoclass:: user_sessions.backends.db.SessionStore
.. autoclass:: user_sessions.backends.db.SessionStore..
.. autoclass:: user_sessions.backends.cache.SessionStore..

Template Tags
-------------
Expand All @@ -25,4 +26,4 @@ Views

Unit tests
----------
.. autoclass:: user_sessions.utils.tests.Client
.. autoclass:: user_sessions.utils.tests.Client
93 changes: 93 additions & 0 deletions user_sessions/backends/cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from django.conf import settings
from django.contrib import auth
from django.contrib.sessions.backends.base import SessionBase, CreateError
from django.core.cache import caches
from django.utils.six.moves import xrange

KEY_PREFIX = "user_sessions.cache"


class SessionStore(SessionBase):
"""
Implements cache-based session store.
"""
def __init__(self, user_agent, ip, session_key=None):
self._cache = caches[settings.SESSION_CACHE_ALIAS]
super(SessionStore, self).__init__(session_key)
self.user_agent, self.ip, self.user_id = user_agent, ip, None

def __setitem__(self, key, value):
if key == auth.SESSION_KEY:
self.user_id = value
super(SessionStore, self).__setitem__(key, value)

@property
def cache_key(self):
return KEY_PREFIX + self._get_or_create_session_key()

def load(self):
try:
s = self._cache.get(self.cache_key, None)
self.user_id = s['user_id']
# do not overwrite user_agent/ip, as those might have been updated
if self.user_agent != s['user_agent'] or self.ip != s['ip']:
self.modified = True
except Exception:
# Some backends (e.g. memcache) raise an exception on invalid
# cache keys. If this happens, reset the session. See #17810.
s = None
if s is not None:
return s['session_data']
self.create()
return {}

def exists(self, session_key):
return (KEY_PREFIX + session_key) in self._cache

def create(self):
# Because a cache can fail silently (e.g. memcache), we don't know if
# we are failing to create a new session because of a key collision or
# because the cache is missing. So we try for a (large) number of times
# and then raise an exception. That's the risk you shoulder if using
# cache backing.
for i in xrange(10000):
self._session_key = self._get_new_session_key()
try:
self.save(must_create=True)
except CreateError:
continue
self.modified = True
return
raise RuntimeError(
"Unable to create a new session key. "
"It is likely that the cache is unavailable.")

def save(self, must_create=False):
if must_create:
func = self._cache.add
else:
func = self._cache.set
result = func(self.cache_key, {
'session_data': self._get_session(no_load=must_create),
'user_agent': self.user_agent,
'user_id': self.user_id,
'ip': self.ip
},
self.get_expiry_age())
if must_create and not result:
raise CreateError

def clear(self):
super(SessionStore, self).clear()
self.user_id = None

def delete(self, session_key=None):
if session_key is None:
if self.session_key is None:
return
session_key = self.session_key
self._cache.delete(KEY_PREFIX + session_key)

@classmethod
def clear_expired(cls):
pass

0 comments on commit a978dc7

Please sign in to comment.