From 45d39a616cebccf604c34fcc396d69f717a2ac29 Mon Sep 17 00:00:00 2001 From: Bogdan Klichuk Date: Mon, 22 Aug 2011 19:17:01 +0300 Subject: [PATCH 01/49] Resolved problem with circ dep (app_directories.Loader) --- tracking/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tracking/__init__.py b/tracking/__init__.py index 16a93c5..550df86 100644 --- a/tracking/__init__.py +++ b/tracking/__init__.py @@ -21,12 +21,14 @@ def get_version(): if settings.ADMIN_MEDIA_PREFIX: prefixes.append(settings.ADMIN_MEDIA_PREFIX) + """ try: # finally, don't track requests to the tracker update pages prefixes.append(reverse('tracking-refresh-active-users')) except NoReverseMatch: # django-tracking hasn't been included in the URLconf if we get here pass + """ prefixes.append('!!initialized!!') From 5c090ebbffd5e67db785c4626982a768d9d5e284 Mon Sep 17 00:00:00 2001 From: Bogdan Klichuk Date: Mon, 22 Aug 2011 19:24:08 +0300 Subject: [PATCH 02/49] Added south migrations --- tracking/migrations/0001_initial.py | 121 ++++++++++++++++++++++++++++ tracking/migrations/__init__.py | 0 2 files changed, 121 insertions(+) create mode 100644 tracking/migrations/0001_initial.py create mode 100644 tracking/migrations/__init__.py diff --git a/tracking/migrations/0001_initial.py b/tracking/migrations/0001_initial.py new file mode 100644 index 0000000..0054cee --- /dev/null +++ b/tracking/migrations/0001_initial.py @@ -0,0 +1,121 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'Visitor' + db.create_table('tracking_visitor', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('session_key', self.gf('django.db.models.fields.CharField')(max_length=40)), + ('ip_address', self.gf('django.db.models.fields.CharField')(max_length=20)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True)), + ('user_agent', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('referrer', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('url', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('page_views', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('session_start', self.gf('django.db.models.fields.DateTimeField')()), + ('last_update', self.gf('django.db.models.fields.DateTimeField')()), + )) + db.send_create_signal('tracking', ['Visitor']) + + # Adding unique constraint on 'Visitor', fields ['session_key', 'ip_address'] + db.create_unique('tracking_visitor', ['session_key', 'ip_address']) + + # Adding model 'UntrackedUserAgent' + db.create_table('tracking_untrackeduseragent', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('keyword', self.gf('django.db.models.fields.CharField')(max_length=100)), + )) + db.send_create_signal('tracking', ['UntrackedUserAgent']) + + # Adding model 'BannedIP' + db.create_table('tracking_bannedip', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('ip_address', self.gf('django.db.models.fields.IPAddressField')(max_length=15)), + )) + db.send_create_signal('tracking', ['BannedIP']) + + + def backwards(self, orm): + + # Removing unique constraint on 'Visitor', fields ['session_key', 'ip_address'] + db.delete_unique('tracking_visitor', ['session_key', 'ip_address']) + + # Deleting model 'Visitor' + db.delete_table('tracking_visitor') + + # Deleting model 'UntrackedUserAgent' + db.delete_table('tracking_untrackeduseragent') + + # Deleting model 'BannedIP' + db.delete_table('tracking_bannedip') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'tracking.bannedip': { + 'Meta': {'ordering': "('ip_address',)", 'object_name': 'BannedIP'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}) + }, + 'tracking.untrackeduseragent': { + 'Meta': {'ordering': "('keyword',)", 'object_name': 'UntrackedUserAgent'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'keyword': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'tracking.visitor': { + 'Meta': {'ordering': "('-last_update',)", 'unique_together': "(('session_key', 'ip_address'),)", 'object_name': 'Visitor'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'last_update': ('django.db.models.fields.DateTimeField', [], {}), + 'page_views': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'referrer': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'session_start': ('django.db.models.fields.DateTimeField', [], {}), + 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'user_agent': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['tracking'] diff --git a/tracking/migrations/__init__.py b/tracking/migrations/__init__.py new file mode 100644 index 0000000..e69de29 From 69ab8d2fddcc872f8749cdcf3a7d0de6b4a01fb4 Mon Sep 17 00:00:00 2001 From: Alexander Artemenko Date: Sat, 21 Apr 2012 12:34:42 -0500 Subject: [PATCH 03/49] added visitor to admin interface to capture IPs for banning --- tracking/admin.py | 7 +++++-- tracking/models.py | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tracking/admin.py b/tracking/admin.py index f92994f..31c2906 100644 --- a/tracking/admin.py +++ b/tracking/admin.py @@ -1,5 +1,8 @@ from django.contrib import admin -from tracking.models import BannedIP, UntrackedUserAgent +from tracking.models import Visitor, VisitorManager, BannedIP, UntrackedUserAgent +class VisitorAdmin(admin.ModelAdmin): + search_fields = ['username'] +admin.site.register(Visitor, VisitorAdmin) admin.site.register(BannedIP) -admin.site.register(UntrackedUserAgent) \ No newline at end of file +admin.site.register(UntrackedUserAgent) diff --git a/tracking/models.py b/tracking/models.py index 1c69735..d0daf5f 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -99,6 +99,12 @@ def _get_geoip_data_json(self): return clean geoip_data_json = property(_get_geoip_data_json) + def __unicode__(self): + return u'{0} at {1} '.format( + self.user.username, + self.ip_address + ) + class Meta: ordering = ('-last_update',) From 41488a5e2f872a3b05674dc13ae410f925f99866 Mon Sep 17 00:00:00 2001 From: Jesse Michelsen Date: Sat, 21 Apr 2012 12:34:42 -0500 Subject: [PATCH 04/49] added visitor to admin interface to capture IPs for banning --- tracking/admin.py | 7 +++++-- tracking/models.py | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tracking/admin.py b/tracking/admin.py index f92994f..31c2906 100644 --- a/tracking/admin.py +++ b/tracking/admin.py @@ -1,5 +1,8 @@ from django.contrib import admin -from tracking.models import BannedIP, UntrackedUserAgent +from tracking.models import Visitor, VisitorManager, BannedIP, UntrackedUserAgent +class VisitorAdmin(admin.ModelAdmin): + search_fields = ['username'] +admin.site.register(Visitor, VisitorAdmin) admin.site.register(BannedIP) -admin.site.register(UntrackedUserAgent) \ No newline at end of file +admin.site.register(UntrackedUserAgent) diff --git a/tracking/models.py b/tracking/models.py index 1c69735..d0daf5f 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -99,6 +99,12 @@ def _get_geoip_data_json(self): return clean geoip_data_json = property(_get_geoip_data_json) + def __unicode__(self): + return u'{0} at {1} '.format( + self.user.username, + self.ip_address + ) + class Meta: ordering = ('-last_update',) From 2f9cfe918950836fbf0df765abdda80ff5fe17ca Mon Sep 17 00:00:00 2001 From: Joseph Spiros Date: Wed, 19 Sep 2012 01:57:42 -0400 Subject: [PATCH 05/49] Added support for Django 1.4+ time-zone-aware datetimes by using django.utils.timezone.now() in place of datetime.datetime.now() where available. --- tracking/middleware.py | 9 +++++++-- tracking/models.py | 7 ++++++- tracking/views.py | 7 ++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tracking/middleware.py b/tracking/middleware.py index ab35308..229db57 100644 --- a/tracking/middleware.py +++ b/tracking/middleware.py @@ -13,6 +13,11 @@ from tracking import utils from tracking.models import Visitor, UntrackedUserAgent, BannedIP +try: + from django.utils.timezone import now as right_now +except ImportError: + right_now = datetime.now + title_re = re.compile('(.*?)') log = logging.getLogger('tracking.middleware') @@ -93,7 +98,7 @@ def process_request(self, request): # if we get here, the URL needs to be tracked # determine what time it is - now = datetime.now() + now = right_now() attrs = { 'session_key': session_key, @@ -159,7 +164,7 @@ def process_request(self, request): if str(timeout).isdigit(): log.debug('Cleaning up visitors older than %s hours' % timeout) - timeout = datetime.now() - timedelta(hours=int(timeout)) + timeout = right_now() - timedelta(hours=int(timeout)) Visitor.objects.filter(last_update__lte=timeout).delete() class BannedIPMiddleware: diff --git a/tracking/models.py b/tracking/models.py index 1c69735..a24663c 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -13,6 +13,11 @@ from django.utils.translation import ugettext, ugettext_lazy as _ from tracking import utils +try: + from django.utils.timezone import now as right_now +except ImportError: + right_now = datetime.now + USE_GEOIP = getattr(settings, 'TRACKING_USE_GEOIP', False) CACHE_TYPE = getattr(settings, 'GEOIP_CACHE_TYPE', 4) @@ -27,7 +32,7 @@ def active(self, timeout=None): if not timeout: timeout = utils.get_timeout() - now = datetime.now() + now = right_now() cutoff = now - timedelta(minutes=timeout) return self.get_query_set().filter(last_update__gte=cutoff) diff --git a/tracking/views.py b/tracking/views.py index 3e7b2ef..f113517 100644 --- a/tracking/views.py +++ b/tracking/views.py @@ -12,6 +12,11 @@ from tracking.models import Visitor from tracking.utils import u_clean as uc +try: + from django.utils.timezone import now as right_now +except ImportError: + right_now = datetime.now + DEFAULT_TRACKING_TEMPLATE = getattr(settings, 'DEFAULT_TRACKING_TEMPLATE', 'tracking/visitor_map.html') log = logging.getLogger('tracking.views') @@ -49,7 +54,7 @@ def get_active_users(request): """ if request.is_ajax(): active = Visitor.objects.active().reverse() - now = datetime.now() + now = right_now() # we don't put the session key or IP address here for security reasons try: From a292a378a1eda30753c6e6856dfe80f098577e09 Mon Sep 17 00:00:00 2001 From: Daryl Antony Date: Sat, 27 Oct 2012 15:26:37 +1100 Subject: [PATCH 06/49] settings.AUTH_USER_MODEL --- tracking/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/models.py b/tracking/models.py index 1c69735..3836703 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -35,7 +35,7 @@ def active(self, timeout=None): class Visitor(models.Model): session_key = models.CharField(max_length=40) ip_address = models.CharField(max_length=20) - user = models.ForeignKey(User, null=True) + user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True) user_agent = models.CharField(max_length=255) referrer = models.CharField(max_length=255) url = models.CharField(max_length=255) From 3e21cf1cdd865c0ee265f7080eb15813e5329177 Mon Sep 17 00:00:00 2001 From: Daryl Antony Date: Sun, 28 Oct 2012 12:36:28 +1100 Subject: [PATCH 07/49] hardcode tracking version --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index e9bd326..6a0a4c1 100644 --- a/setup.py +++ b/setup.py @@ -3,11 +3,11 @@ from setuptools import setup, find_packages import sys, os -import tracking +# import tracking setup( name='django-tracking', - version=tracking.get_version(), + version='1.0',#tracking.get_version(), description="Basic visitor tracking and blacklisting for Django", long_description=open('README.rst', 'r').read(), keywords='django, tracking, visitors', From fbec0f9e9d6d94d4fc6d7689b49a3a4ba7c28f07 Mon Sep 17 00:00:00 2001 From: Nathan Keilar Date: Mon, 3 Jun 2013 13:58:28 -0700 Subject: [PATCH 08/49] listeners depends on Django which isn't installed for in fres environment --- tracking/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tracking/__init__.py b/tracking/__init__.py index 0c0d993..98d6fb3 100644 --- a/tracking/__init__.py +++ b/tracking/__init__.py @@ -1,5 +1,3 @@ -import listeners - VERSION = (0, 4, 0) def get_version(): From 1fe23403f9db8c1691b4d8dfb6350e0e2d61c415 Mon Sep 17 00:00:00 2001 From: Patrick Craston Date: Wed, 6 Nov 2013 15:44:01 +0000 Subject: [PATCH 09/49] Make compatible with Django 1.6 --- tracking/models.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tracking/models.py b/tracking/models.py index 1c69735..a7ac44e 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -2,11 +2,7 @@ import logging import traceback -from django.contrib.gis.utils import HAS_GEOIP - -if HAS_GEOIP: - from django.contrib.gis.utils import GeoIP, GeoIPException - +from django.contrib.gis.geoip import GeoIP, GeoIPException from django.conf import settings from django.contrib.auth.models import User from django.db import models From e140fb252d71a95d5da0edb6f6d3efa76a63b0d8 Mon Sep 17 00:00:00 2001 From: Patrick Craston Date: Wed, 6 Nov 2013 15:48:57 +0000 Subject: [PATCH 10/49] Port compatibility fix for Django 1.5 from https://bitbucket.org/romanalexander/django-tracking --- tracking/models.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tracking/models.py b/tracking/models.py index a7ac44e..cfc2da1 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -3,8 +3,12 @@ import traceback from django.contrib.gis.geoip import GeoIP, GeoIPException -from django.conf import settings -from django.contrib.auth.models import User +try: + from django.conf import settings + User = settings.AUTH_USER_MODEL +except AttributeError: + from django.conf import settings + from django.contrib.auth.models import User from django.db import models from django.utils.translation import ugettext, ugettext_lazy as _ from tracking import utils From 10a593f5ac99e4dc97422f4ac9a24fc7947db06e Mon Sep 17 00:00:00 2001 From: Patrick Craston Date: Wed, 6 Nov 2013 16:15:40 +0000 Subject: [PATCH 11/49] Make compatible with latest Django from https://bitbucket.org/romanalexander/django-tracking --- tracking/__init__.py | 2 +- tracking/listeners.py | 11 ++++++++++- tracking/middleware.py | 4 ++++ tracking/views.py | 5 ++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/tracking/__init__.py b/tracking/__init__.py index 0c0d993..58d447d 100644 --- a/tracking/__init__.py +++ b/tracking/__init__.py @@ -1,6 +1,6 @@ import listeners -VERSION = (0, 4, 0) +VERSION = (0, 4, 2) def get_version(): "Returns the version as a human-format string." diff --git a/tracking/listeners.py b/tracking/listeners.py index ece1367..3daadcc 100644 --- a/tracking/listeners.py +++ b/tracking/listeners.py @@ -2,12 +2,21 @@ log = logging.getLogger('tracking.listeners') +importing_exceptions = (ImportError, ) +#Try to have the ImproperlyConfigured error available to catch that error during package installation +#...looks like newer versions of Django might have broken only receiving an ImportError +try: + from django.core.exceptions import ImproperlyConfigured + importing_exceptions = (ImportError, ImproperlyConfigured) +except ImportError: + pass + try: from django.core.cache import cache from django.db.models.signals import post_save, post_delete from tracking.models import UntrackedUserAgent, BannedIP -except ImportError: +except importing_exceptions: pass else: diff --git a/tracking/middleware.py b/tracking/middleware.py index ab35308..7db9557 100644 --- a/tracking/middleware.py +++ b/tracking/middleware.py @@ -94,6 +94,10 @@ def process_request(self, request): # if we get here, the URL needs to be tracked # determine what time it is now = datetime.now() + if getattr(settings, 'USE_TZ', False): + import pytz + tz = pytz.timezone(settings.TIME_ZONE) + now = tz.localize(now) attrs = { 'session_key': session_key, diff --git a/tracking/views.py b/tracking/views.py index 3e7b2ef..2839e55 100644 --- a/tracking/views.py +++ b/tracking/views.py @@ -6,7 +6,10 @@ from django.http import Http404, HttpResponse from django.shortcuts import render_to_response from django.template import RequestContext, Context, loader -from django.utils.simplejson import JSONEncoder +try: + from json import JSONEncoder #Python 2.6 +except ImportError: + from django.utils.simplejson import JSONEncoder #Older Django from django.utils.translation import ungettext from django.views.decorators.cache import never_cache from tracking.models import Visitor From 1f56494862393cab5750e96bf73a6c7d59d74162 Mon Sep 17 00:00:00 2001 From: Patrick Craston Date: Wed, 6 Nov 2013 16:43:08 +0000 Subject: [PATCH 12/49] update changes --- CHANGES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index 778b1b4..eb8e476 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,11 @@ django-tracking changes ======================= +0.4.2 +----- + +- Fixes for Django 1.6 + 0.3.5 ----- From 88865bb13cd22d9ff60aeab77fca749ee886e7c2 Mon Sep 17 00:00:00 2001 From: "Stephen J. Fuhry" Date: Fri, 24 Jan 2014 12:34:39 -0500 Subject: [PATCH 13/49] gitignore --- .gitignore | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..50a8726 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +bin/ +build/ +develop-eggs/ +dist/ +eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.mo + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# Rope +.ropeproject + +# Django stuff: +*.log +*.pot + +# Sphinx documentation +docs/_build/ + From d69833afb49791b87529bae55fc95c534f4f99b7 Mon Sep 17 00:00:00 2001 From: "Stephen J. Fuhry" Date: Fri, 24 Jan 2014 12:34:53 -0500 Subject: [PATCH 14/49] don't need this import --- tracking/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tracking/__init__.py b/tracking/__init__.py index 0c0d993..31abb08 100644 --- a/tracking/__init__.py +++ b/tracking/__init__.py @@ -1,4 +1,3 @@ -import listeners VERSION = (0, 4, 0) From 9444460c0135d9ad4cb7dd216904ac0f1d724723 Mon Sep 17 00:00:00 2001 From: "Stephen J. Fuhry" Date: Fri, 24 Jan 2014 12:35:15 -0500 Subject: [PATCH 15/49] HAS_GEOIP doesn't seem to exist anymore --- tracking/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tracking/models.py b/tracking/models.py index 1c69735..c22627d 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -2,10 +2,11 @@ import logging import traceback -from django.contrib.gis.utils import HAS_GEOIP - -if HAS_GEOIP: +try: from django.contrib.gis.utils import GeoIP, GeoIPException + HAS_GEOIP = True +except ImportError: + HAS_GEOIP = False from django.conf import settings from django.contrib.auth.models import User From 092c42a36137b97be364299f3746fdf68f6df6a0 Mon Sep 17 00:00:00 2001 From: jonykwa Date: Mon, 30 Jun 2014 08:41:15 +0700 Subject: [PATCH 16/49] Fixed Django 1.6 error: cannot import name HAS_GEOIP --- tracking/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/models.py b/tracking/models.py index 1c69735..b729c60 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -2,7 +2,7 @@ import logging import traceback -from django.contrib.gis.utils import HAS_GEOIP +from django.contrib.gis.geoip import HAS_GEOIP if HAS_GEOIP: from django.contrib.gis.utils import GeoIP, GeoIPException From 177a469c12e2f1018d36947c73dce09050df314b Mon Sep 17 00:00:00 2001 From: jonykwa Date: Mon, 30 Jun 2014 09:30:05 +0700 Subject: [PATCH 17/49] Fixed TypeError: can't compare offset-naive and offset-aware datetimes --- tracking/middleware.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tracking/middleware.py b/tracking/middleware.py index ab35308..7db9557 100644 --- a/tracking/middleware.py +++ b/tracking/middleware.py @@ -94,6 +94,10 @@ def process_request(self, request): # if we get here, the URL needs to be tracked # determine what time it is now = datetime.now() + if getattr(settings, 'USE_TZ', False): + import pytz + tz = pytz.timezone(settings.TIME_ZONE) + now = tz.localize(now) attrs = { 'session_key': session_key, From 57058d9cf8fd298e900554ce6eda03679e3c059d Mon Sep 17 00:00:00 2001 From: jonykwa Date: Tue, 15 Jul 2014 12:40:03 +0700 Subject: [PATCH 18/49] Update urls.py compatibility with Django1.6 --- tracking/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/urls.py b/tracking/urls.py index 08fce6d..dac67e4 100644 --- a/tracking/urls.py +++ b/tracking/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import * +from django.conf.urls import patterns, url, include from django.conf import settings from tracking import views From dd3a666f7882d4041586b19690ac7d2df809f48b Mon Sep 17 00:00:00 2001 From: jlachowski Date: Wed, 23 Jul 2014 17:09:39 +0200 Subject: [PATCH 19/49] catch Integrity exception added --- tracking/middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/middleware.py b/tracking/middleware.py index 7db9557..b9da90b 100644 --- a/tracking/middleware.py +++ b/tracking/middleware.py @@ -152,7 +152,7 @@ def process_request(self, request): visitor.last_update = now try: visitor.save() - except DatabaseError: + except (DatabaseError, IntegrityError): log.error('There was a problem saving visitor information:\n%s\n\n%s' % (traceback.format_exc(), locals())) class VisitorCleanUpMiddleware: From f22e5df93caddab8ca042bdda94c729e18fbb480 Mon Sep 17 00:00:00 2001 From: jlachowski Date: Wed, 23 Jul 2014 17:26:47 +0200 Subject: [PATCH 20/49] missing import added --- tracking/middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/middleware.py b/tracking/middleware.py index b9da90b..a00b21b 100644 --- a/tracking/middleware.py +++ b/tracking/middleware.py @@ -7,7 +7,7 @@ from django.contrib.auth.models import AnonymousUser from django.core.cache import cache from django.core.urlresolvers import reverse, NoReverseMatch -from django.db.utils import DatabaseError +from django.db.utils import DatabaseError, IntegrityError from django.http import Http404 from tracking import utils From bf247a236bb0c071fd16555403e823e60e30fff3 Mon Sep 17 00:00:00 2001 From: jlachowski Date: Wed, 23 Jul 2014 17:58:24 +0200 Subject: [PATCH 21/49] rollback & safe point added --- tracking/middleware.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tracking/middleware.py b/tracking/middleware.py index a00b21b..39e66b7 100644 --- a/tracking/middleware.py +++ b/tracking/middleware.py @@ -9,6 +9,7 @@ from django.core.urlresolvers import reverse, NoReverseMatch from django.db.utils import DatabaseError, IntegrityError from django.http import Http404 +from django.db import transaction from tracking import utils from tracking.models import Visitor, UntrackedUserAgent, BannedIP @@ -54,6 +55,7 @@ def prefixes(self): return self._prefixes + def process_request(self, request): # don't process AJAX requests if request.is_ajax(): return @@ -151,8 +153,12 @@ def process_request(self, request): visitor.page_views += 1 visitor.last_update = now try: + sid = transaction.savepoint() visitor.save() - except (DatabaseError, IntegrityError): + transaction.savepoint_commit(sid) + except IntegrityError: + transaction.savepoint_rollback(sid) + except DatabaseError: log.error('There was a problem saving visitor information:\n%s\n\n%s' % (traceback.format_exc(), locals())) class VisitorCleanUpMiddleware: From 5fbb3c6159d8cf996a8acf6a3dcc6e389c84855f Mon Sep 17 00:00:00 2001 From: jlachowski Date: Tue, 12 Aug 2014 20:02:35 +0200 Subject: [PATCH 22/49] pip install update --- README.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.rst b/README.rst index 621fdb5..e3e2d92 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,10 @@ +This is a clone of ``django-tracking`` is at http://bitbucket.org/codekoala/django-tracking + ``django-tracking`` is a simple attempt at keeping track of visitors to Django-powered Web sites. It also offers basic blacklisting capabilities. -The offial repository for ``django-tracking`` is at -http://bitbucket.org/codekoala/django-tracking. Please file any tickets there. +The offial and original repository for ``django-tracking`` is at +http://bitbucket.org/codekoala/django-tracking. Features ======== @@ -55,29 +57,27 @@ pip --- You can download the package from the `CheeseShop -`_ or use:: +`_ or use:: - pip install django-tracking + pip install django-tracking-jl to download and install ``django-tracking``. easy_install ------------ -You can download the package from the `CheeseShop `_ or use:: +You can download the package from the `CheeseShop `_ or use:: - easy_install django-tracking + easy_install django-tracking-jl to download and install ``django-tracking``. -Checkout from BitBucket/GitHub/Google Code ------------------------------------------- +Checkout from GitHub +-------------------- Use one of the following commands:: - hg clone http://bitbucket.org/codekoala/django-tracking - git clone http://github.com/codekoala/django-tracking.git - hg clone http://django-tracking.googlecode.com/hg/ django-tracking + git clone http://github.com/jlachowski/django-tracking.git Package Download ================ From af14719af682184137c32decbb00ed8ad873a46e Mon Sep 17 00:00:00 2001 From: jlachowski Date: Tue, 12 Aug 2014 20:04:37 +0200 Subject: [PATCH 23/49] version bump --- tracking/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/__init__.py b/tracking/__init__.py index 58d447d..bf5b3e8 100644 --- a/tracking/__init__.py +++ b/tracking/__init__.py @@ -1,6 +1,6 @@ import listeners -VERSION = (0, 4, 2) +VERSION = (0, 5, 0) def get_version(): "Returns the version as a human-format string." From b7b4793c27c2a8ca4b92c3c6009f70c016d0cd99 Mon Sep 17 00:00:00 2001 From: Jaroslaw Lachowski Date: Tue, 12 Aug 2014 20:05:16 +0200 Subject: [PATCH 24/49] packet name change --- setup.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index e9bd326..aff53f1 100644 --- a/setup.py +++ b/setup.py @@ -2,18 +2,17 @@ # -*- coding: utf-8 -*- from setuptools import setup, find_packages -import sys, os import tracking setup( - name='django-tracking', + name='django-tracking-jl', version=tracking.get_version(), description="Basic visitor tracking and blacklisting for Django", long_description=open('README.rst', 'r').read(), keywords='django, tracking, visitors', - author='Josh VanderLinden', - author_email='codekoala at gmail dot com', - url='http://bitbucket.org/codekoala/django-tracking', + author='Jaroslaw Lachowski', + author_email='jalachowski@gmail.com', + url='https://github.com/jlachowski/django-tracking', license='MIT', package_dir={'tracking': 'tracking'}, include_package_data=True, From 63129a5e951698890edb6bf435fab9bc1d0c18be Mon Sep 17 00:00:00 2001 From: ramusus Date: Thu, 26 Feb 2015 16:29:36 +0700 Subject: [PATCH 25/49] merged with 0.4.1 version from bitbucket --- README.rst | 2 +- tracking/__init__.py | 2 +- tracking/listeners.py | 11 +++- tracking/middleware.py | 30 +++------ tracking/migrations/0001_initial.py | 64 +++++++++++++++++++ .../migrations/0002_auto_20141023_0732.py | 25 ++++++++ .../migrations/0003_auto_20141023_0834.py | 24 +++++++ tracking/migrations/__init__.py | 0 tracking/models.py | 34 +++++++--- tracking/urls.py | 5 +- tracking/views.py | 5 +- 11 files changed, 168 insertions(+), 34 deletions(-) create mode 100644 tracking/migrations/0001_initial.py create mode 100644 tracking/migrations/0002_auto_20141023_0732.py create mode 100644 tracking/migrations/0003_auto_20141023_0834.py create mode 100644 tracking/migrations/__init__.py diff --git a/README.rst b/README.rst index 621fdb5..10e0f93 100644 --- a/README.rst +++ b/README.rst @@ -200,7 +200,7 @@ If you also want to show how many people are looking at the same page:: {% visitors_on_page as same_page %}

{{ same_page }} of {{ visitors }} active user{{ visitors|pluralize }} - {{ same_page|pluralize:"is,are" }} reading this page + {% ifequal same_page 1 %}is{% else %}are{% endifequal %} reading this page

If you don't want particular areas of your site to be tracked, you may define a diff --git a/tracking/__init__.py b/tracking/__init__.py index 0c0d993..c6f1b3c 100644 --- a/tracking/__init__.py +++ b/tracking/__init__.py @@ -1,6 +1,6 @@ import listeners -VERSION = (0, 4, 0) +VERSION = (0, 4, 1) def get_version(): "Returns the version as a human-format string." diff --git a/tracking/listeners.py b/tracking/listeners.py index ece1367..601b12f 100644 --- a/tracking/listeners.py +++ b/tracking/listeners.py @@ -2,12 +2,21 @@ log = logging.getLogger('tracking.listeners') +importing_exceptions = (ImportError, ) +#Try to have the ImproperlyConfigured error available to catch that error during package installation +#...looks like newer versions of Django might have broken only receiving an ImportError +try: + from django.core.exceptions import ImproperlyConfigured + importing_exceptions = (ImportError, ImproperlyConfigured) +except ImportError: + pass + try: from django.core.cache import cache from django.db.models.signals import post_save, post_delete from tracking.models import UntrackedUserAgent, BannedIP -except ImportError: +except importing_exceptions: pass else: diff --git a/tracking/middleware.py b/tracking/middleware.py index 7db9557..8aa5df2 100644 --- a/tracking/middleware.py +++ b/tracking/middleware.py @@ -1,4 +1,5 @@ -from datetime import datetime, timedelta +from datetime import timedelta +from django.utils import timezone import logging import re import traceback @@ -55,9 +56,6 @@ def prefixes(self): return self._prefixes def process_request(self, request): - # don't process AJAX requests - if request.is_ajax(): return - # create some useful variables ip_address = utils.get_ip(request) user_agent = unicode(request.META.get('HTTP_USER_AGENT', '')[:255], errors='ignore') @@ -77,13 +75,9 @@ def process_request(self, request): log.debug('Not tracking UA "%s" because of keyword: %s' % (user_agent, ua.keyword)) return - if hasattr(request, 'session') and request.session.session_key: - # use the current session key if we can - session_key = request.session.session_key - else: - # otherwise just fake a session key - session_key = '%s:%s' % (ip_address, user_agent) - session_key = session_key[:40] + if not request.session.session_key: + request.session.save() + session_key = request.session.session_key # ensure that the request.path does not begin with any of the prefixes for prefix in self.prefixes: @@ -93,11 +87,7 @@ def process_request(self, request): # if we get here, the URL needs to be tracked # determine what time it is - now = datetime.now() - if getattr(settings, 'USE_TZ', False): - import pytz - tz = pytz.timezone(settings.TIME_ZONE) - now = tz.localize(now) + now = timezone.now() attrs = { 'session_key': session_key, @@ -122,9 +112,9 @@ def process_request(self, request): visitor.session_key = session_key log.debug('Using existing visitor for IP %s / UA %s: %s' % (ip_address, user_agent, visitor.id)) else: - # it's probably safe to assume that the visitor is brand new - visitor = Visitor(**attrs) - log.debug('Created a new visitor: %s' % attrs) + visitor, created = Visitor.objects.get_or_create(**attrs) + if created: + log.debug('Created a new visitor: %s' % attrs) except: return @@ -163,7 +153,7 @@ def process_request(self, request): if str(timeout).isdigit(): log.debug('Cleaning up visitors older than %s hours' % timeout) - timeout = datetime.now() - timedelta(hours=int(timeout)) + timeout = timezone.now() - timedelta(hours=int(timeout)) Visitor.objects.filter(last_update__lte=timeout).delete() class BannedIPMiddleware: diff --git a/tracking/migrations/0001_initial.py b/tracking/migrations/0001_initial.py new file mode 100644 index 0000000..c1e924c --- /dev/null +++ b/tracking/migrations/0001_initial.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='BannedIP', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('ip_address', models.IPAddressField(help_text='The IP address that should be banned', verbose_name=b'IP Address')), + ], + options={ + 'ordering': ('ip_address',), + 'verbose_name': 'Banned IP', + 'verbose_name_plural': 'Banned IPs', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='UntrackedUserAgent', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('keyword', models.CharField(help_text='Part or all of a user-agent string. For example, "Googlebot" here will be found in "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" and that visitor will not be tracked.', max_length=100, verbose_name='keyword')), + ], + options={ + 'ordering': ('keyword',), + 'verbose_name': 'Untracked User-Agent', + 'verbose_name_plural': 'Untracked User-Agents', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Visitor', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('session_key', models.CharField(max_length=40)), + ('ip_address', models.CharField(max_length=20)), + ('user_agent', models.CharField(max_length=255)), + ('referrer', models.CharField(max_length=255)), + ('url', models.CharField(max_length=255)), + ('page_views', models.PositiveIntegerField(default=0)), + ('session_start', models.DateTimeField()), + ('last_update', models.DateTimeField()), + ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True)), + ], + options={ + 'ordering': ('-last_update',), + }, + bases=(models.Model,), + ), + migrations.AlterUniqueTogether( + name='visitor', + unique_together=set([('session_key', 'ip_address')]), + ), + ] diff --git a/tracking/migrations/0002_auto_20141023_0732.py b/tracking/migrations/0002_auto_20141023_0732.py new file mode 100644 index 0000000..825b110 --- /dev/null +++ b/tracking/migrations/0002_auto_20141023_0732.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import datetime + + +class Migration(migrations.Migration): + + dependencies = [ + ('tracking', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='visitor', + name='last_update', + field=models.DateTimeField(default=datetime.datetime(2014, 10, 23, 7, 32, 14, 787217)), + ), + migrations.AlterField( + model_name='visitor', + name='session_start', + field=models.DateTimeField(default=datetime.datetime(2014, 10, 23, 7, 32, 14, 787119)), + ), + ] diff --git a/tracking/migrations/0003_auto_20141023_0834.py b/tracking/migrations/0003_auto_20141023_0834.py new file mode 100644 index 0000000..4dd6a35 --- /dev/null +++ b/tracking/migrations/0003_auto_20141023_0834.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('tracking', '0002_auto_20141023_0732'), + ] + + operations = [ + migrations.AlterField( + model_name='visitor', + name='last_update', + field=models.DateTimeField(), + ), + migrations.AlterField( + model_name='visitor', + name='session_start', + field=models.DateTimeField(), + ), + ] diff --git a/tracking/migrations/__init__.py b/tracking/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tracking/models.py b/tracking/models.py index b729c60..8c4bba6 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -1,14 +1,25 @@ -from datetime import datetime, timedelta +from datetime import timedelta +from django.utils import timezone import logging import traceback -from django.contrib.gis.geoip import HAS_GEOIP - -if HAS_GEOIP: - from django.contrib.gis.utils import GeoIP, GeoIPException - -from django.conf import settings -from django.contrib.auth.models import User +try: + # Django < 1.6 + from django.contrib.gis.utils import HAS_GEOIP + if HAS_GEOIP: + from django.contrib.gis.utils import GeoIP, GeoIPException +except ImportError: + # Django 1.6+ + from django.contrib.gis.geoip import HAS_GEOIP + if HAS_GEOIP: + from django.contrib.gis.geoip import GeoIP, GeoIPException + +try: + from django.conf import settings + User = settings.AUTH_USER_MODEL +except AttributeError: + from django.conf import settings + from django.contrib.auth.models import User from django.db import models from django.utils.translation import ugettext, ugettext_lazy as _ from tracking import utils @@ -27,7 +38,7 @@ def active(self, timeout=None): if not timeout: timeout = utils.get_timeout() - now = datetime.now() + now = timezone.now() cutoff = now - timedelta(minutes=timeout) return self.get_query_set().filter(last_update__gte=cutoff) @@ -45,6 +56,11 @@ class Visitor(models.Model): objects = VisitorManager() + def __init__(self, *args, **kwargs): + super(Visitor, self).__init__(*args, **kwargs) + self.session_start = timezone.now() + self.last_update = timezone.now() + def _time_on_site(self): """ Attempts to determine the amount of time a visitor has spent on the diff --git a/tracking/urls.py b/tracking/urls.py index dac67e4..d5ded8e 100644 --- a/tracking/urls.py +++ b/tracking/urls.py @@ -1,4 +1,7 @@ -from django.conf.urls import patterns, url, include +try: + from django.conf.urls import patterns, url, include +except ImportError: # Pre-Django 1.4 version + from django.conf.urls.defaults import patterns, url, include from django.conf import settings from tracking import views diff --git a/tracking/views.py b/tracking/views.py index 3e7b2ef..2839e55 100644 --- a/tracking/views.py +++ b/tracking/views.py @@ -6,7 +6,10 @@ from django.http import Http404, HttpResponse from django.shortcuts import render_to_response from django.template import RequestContext, Context, loader -from django.utils.simplejson import JSONEncoder +try: + from json import JSONEncoder #Python 2.6 +except ImportError: + from django.utils.simplejson import JSONEncoder #Older Django from django.utils.translation import ungettext from django.views.decorators.cache import never_cache from tracking.models import Visitor From 1697b56f354b700826ef7abcf437ddd5a6436d6d Mon Sep 17 00:00:00 2001 From: Anand B Pillai Date: Wed, 22 Apr 2015 19:53:11 +0530 Subject: [PATCH 26/49] Fixing the issue with timezone aware timestamps --- tracking/middleware.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tracking/middleware.py b/tracking/middleware.py index ab35308..a0bc418 100644 --- a/tracking/middleware.py +++ b/tracking/middleware.py @@ -9,6 +9,7 @@ from django.core.urlresolvers import reverse, NoReverseMatch from django.db.utils import DatabaseError from django.http import Http404 +from django.utils import timezone from tracking import utils from tracking.models import Visitor, UntrackedUserAgent, BannedIP @@ -93,7 +94,7 @@ def process_request(self, request): # if we get here, the URL needs to be tracked # determine what time it is - now = datetime.now() + now=timezone.localtime(timezone.now()) attrs = { 'session_key': session_key, @@ -159,7 +160,7 @@ def process_request(self, request): if str(timeout).isdigit(): log.debug('Cleaning up visitors older than %s hours' % timeout) - timeout = datetime.now() - timedelta(hours=int(timeout)) + timeout = timezone.localtime(timezone.now()) - timedelta(hours=int(timeout)) Visitor.objects.filter(last_update__lte=timeout).delete() class BannedIPMiddleware: From 27345aade6861c160be48a7d5480ff05a1ff1707 Mon Sep 17 00:00:00 2001 From: Anand B Pillai Date: Wed, 22 Apr 2015 19:53:30 +0530 Subject: [PATCH 27/49] Fixing tracking pkg dependency error --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index e9bd326..940cecb 100644 --- a/setup.py +++ b/setup.py @@ -3,11 +3,11 @@ from setuptools import setup, find_packages import sys, os -import tracking +import version setup( name='django-tracking', - version=tracking.get_version(), + version=version.get_version(), description="Basic visitor tracking and blacklisting for Django", long_description=open('README.rst', 'r').read(), keywords='django, tracking, visitors', From 784fd7bf878b06f3233cdc95d0a1e963696afe1d Mon Sep 17 00:00:00 2001 From: Anand B Pillai Date: Wed, 22 Apr 2015 19:53:40 +0530 Subject: [PATCH 28/49] version.py for versioning --- version.py | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 version.py diff --git a/version.py b/version.py new file mode 100644 index 0000000..3b58f6c --- /dev/null +++ b/version.py @@ -0,0 +1,5 @@ +VERSION = (0, 4, 0) + +def get_version(): + "Returns the version as a human-format string." + return '.'.join([str(i) for i in VERSION]) From f16b0090ec15f51f47a9e0c8a499c3dd2276f3bf Mon Sep 17 00:00:00 2001 From: Ben Keating Date: Tue, 5 May 2015 13:34:18 -0500 Subject: [PATCH 29/49] ``get_query_set`` is now ``get_queryset`` --- tracking/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/models.py b/tracking/models.py index cfc2da1..e805568 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -30,7 +30,7 @@ def active(self, timeout=None): now = datetime.now() cutoff = now - timedelta(minutes=timeout) - return self.get_query_set().filter(last_update__gte=cutoff) + return self.get_queryset().filter(last_update__gte=cutoff) class Visitor(models.Model): session_key = models.CharField(max_length=40) From 4e8d0dd1199dca0df2baa46a74b3495dc6c5cef1 Mon Sep 17 00:00:00 2001 From: Ben Keating Date: Tue, 5 May 2015 14:00:44 -0500 Subject: [PATCH 30/49] ``IPAddressField`` is now ``GenericIPAddressField`` --- tracking/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tracking/models.py b/tracking/models.py index e805568..52d8344 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -66,7 +66,7 @@ def _time_on_site(self): def _get_geoip_data(self): """ Attempts to retrieve MaxMind GeoIP data based upon the visitor's IP - """ + """A if not HAS_GEOIP or not USE_GEOIP: # go no further when we don't need to @@ -116,7 +116,7 @@ class Meta: verbose_name_plural = _('Untracked User-Agents') class BannedIP(models.Model): - ip_address = models.IPAddressField('IP Address', help_text=_('The IP address that should be banned')) + ip_address = models.GenericIPAddressField('IP Address', help_text=_('The IP address that should be banned')) def __unicode__(self): return self.ip_address From 8c9dda7a56dfd05efdcffbd8067abbf55976bdf8 Mon Sep 17 00:00:00 2001 From: Ben Keating Date: Mon, 20 Jul 2015 10:43:56 -0500 Subject: [PATCH 31/49] Removed rogue character --- tracking/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/models.py b/tracking/models.py index 52d8344..ac4367a 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -66,7 +66,7 @@ def _time_on_site(self): def _get_geoip_data(self): """ Attempts to retrieve MaxMind GeoIP data based upon the visitor's IP - """A + """ if not HAS_GEOIP or not USE_GEOIP: # go no further when we don't need to From 89a2116630823d2b6e6220d5950dc670a286df42 Mon Sep 17 00:00:00 2001 From: bashu Date: Wed, 5 Aug 2015 11:17:19 +0600 Subject: [PATCH 32/49] add badges --- README.rst | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/README.rst b/README.rst index 621fdb5..eed6431 100644 --- a/README.rst +++ b/README.rst @@ -1,21 +1,31 @@ -``django-tracking`` is a simple attempt at keeping track of visitors to -Django-powered Web sites. It also offers basic blacklisting capabilities. +``django-tracking`` is a simple attempt at keeping track of visitors +to django-powered Web sites. It also offers basic blacklisting +capabilities. -The offial repository for ``django-tracking`` is at -http://bitbucket.org/codekoala/django-tracking. Please file any tickets there. +Authored by `Josh VanderLinden `_, and some great +`contributors `_. +.. image:: https://img.shields.io/pypi/v/django-tracking.svg + :target: https://pypi.python.org/pypi/django-tracking/ + +.. image:: https://img.shields.io/pypi/dm/django-tracking.svg + :target: https://pypi.python.org/pypi/django-tracking/ + +.. image:: https://img.shields.io/github/license/bashu/django-tracking.svg + :target: https://pypi.python.org/pypi/django-tracking/ + Features -======== +-------- * Tracks the following information about your visitors: - * Session key - * IP address - * User agent - * Whether or not they are a registered user and logged in - * Where they came from (http-referer) - * What page on your site they last visited - * How many pages on your site they have visited + * Session key + * IP address + * User agent + * Whether or not they are a registered user and logged in + * Where they came from (HTTP-REFERER) + * What page on your site they last visited + * How many pages on your site they have visited * Allows user-agent filtering for visitor tracking * Automatic clean-up of old visitor records @@ -24,17 +34,18 @@ Features * The ability to have a live feed of active users on your website * Template tags to: - * display how many active users there are on your site - * determine how many active users are on the same page within your site + * display how many active users there are on your site + * determine how many active users are on the same page within your site * Optional "Active Visitors Map" to see where visitors are in the world Requirements -============ +------------ -As far as I am aware, the only requirement for django-tracking to work is a -modern version of Django. I developed the project on Django 1.0 alpha 2 and -beta 1. It is designed to work with the newforms-admin functionality. +As far as I am aware, the only requirement for ``django-tracking`` to +work is a modern version of Django. I developed the project on Django +1.0 alpha 2 and beta 1. It is designed to work with the +newforms-admin functionality. If you wish to use a Google Map to display where your visitors are probably at, you must have a `Google Maps API key From d35992bbb7d45e8f380673b64f7fd7233feefd7b Mon Sep 17 00:00:00 2001 From: bashu Date: Wed, 5 Aug 2015 11:17:57 +0600 Subject: [PATCH 33/49] update LICENSE --- LICENSE | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/LICENSE b/LICENSE index b862916..5bea623 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,7 @@ -Copyright (c) 2008-2009 Josh VanderLinden +The MIT License (MIT) + +Copyright (c) 2008-2015 Josh VanderLinden +Copyright (c) 2015 Basil Shubin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -7,13 +10,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 1114456ab747756aab6253cbd9a2f2b5b7679425 Mon Sep 17 00:00:00 2001 From: bashu Date: Wed, 5 Aug 2015 11:21:40 +0600 Subject: [PATCH 34/49] cleanup README --- README.rst | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.rst b/README.rst index eed6431..f9e6608 100644 --- a/README.rst +++ b/README.rst @@ -13,7 +13,7 @@ Authored by `Josh VanderLinden `_, and some great .. image:: https://img.shields.io/github/license/bashu/django-tracking.svg :target: https://pypi.python.org/pypi/django-tracking/ - + Features -------- @@ -42,11 +42,6 @@ Features Requirements ------------ -As far as I am aware, the only requirement for ``django-tracking`` to -work is a modern version of Django. I developed the project on Django -1.0 alpha 2 and beta 1. It is designed to work with the -newforms-admin functionality. - If you wish to use a Google Map to display where your visitors are probably at, you must have a `Google Maps API key `_, which is free. You From daaec80606a31df1323dbcf53bcc0aaa1d75ca8c Mon Sep 17 00:00:00 2001 From: bashu Date: Wed, 5 Aug 2015 11:28:08 +0600 Subject: [PATCH 35/49] add .gitignore --- .gitignore | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..886028b --- /dev/null +++ b/.gitignore @@ -0,0 +1,53 @@ +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ From b03fa8d917fd58f6e9a1271b45c27ef8ba9ee1a8 Mon Sep 17 00:00:00 2001 From: bashu Date: Wed, 5 Aug 2015 11:34:18 +0600 Subject: [PATCH 36/49] update setup.py --- setup.py | 34 +++++++++++++++++++++------------- tracking/__init__.py | 4 +--- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/setup.py b/setup.py index e9bd326..b78231c 100644 --- a/setup.py +++ b/setup.py @@ -1,23 +1,30 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - +import os from setuptools import setup, find_packages -import sys, os -import tracking + +README = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read() + +# allow setup.py to be run from any path +os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) + +from tracking import __version__ setup( name='django-tracking', - version=tracking.get_version(), + version=__version__, + packages=find_packages(exclude=['example']), + include_package_data=True, + license='MIT License', description="Basic visitor tracking and blacklisting for Django", - long_description=open('README.rst', 'r').read(), + long_description=README, keywords='django, tracking, visitors', + url='http://github.com/bashu/django-tracking/', author='Josh VanderLinden', - author_email='codekoala at gmail dot com', - url='http://bitbucket.org/codekoala/django-tracking', - license='MIT', - package_dir={'tracking': 'tracking'}, - include_package_data=True, - packages=find_packages(), + author_email='codekoala@gmail.com', + maintainer='Basil Shubin', + maintainer_email='basil.shubin@gmail.com', + install_requires=[ + 'django>=1.4', + ], classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", @@ -30,6 +37,7 @@ "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Internet :: Log Analysis", + 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', "Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Page Counters", "Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware", "Topic :: Security", diff --git a/tracking/__init__.py b/tracking/__init__.py index 0c0d993..536bb9f 100644 --- a/tracking/__init__.py +++ b/tracking/__init__.py @@ -2,7 +2,5 @@ VERSION = (0, 4, 0) -def get_version(): - "Returns the version as a human-format string." - return '.'.join([str(i) for i in VERSION]) +__version__ = '.'.join([str(n) for n in VERSION]) From 95bf908c9ff6a4b7c8a9bf849a49d2dfbb905adf Mon Sep 17 00:00:00 2001 From: Basil Shubin Date: Wed, 5 Aug 2015 16:57:42 +0500 Subject: [PATCH 37/49] Update README.rst --- README.rst | 195 ----------------------------------------------------- 1 file changed, 195 deletions(-) diff --git a/README.rst b/README.rst index f9e6608..527741c 100644 --- a/README.rst +++ b/README.rst @@ -13,7 +13,6 @@ Authored by `Josh VanderLinden `_, and some great .. image:: https://img.shields.io/github/license/bashu/django-tracking.svg :target: https://pypi.python.org/pypi/django-tracking/ - Features -------- @@ -37,197 +36,3 @@ Features * display how many active users there are on your site * determine how many active users are on the same page within your site -* Optional "Active Visitors Map" to see where visitors are in the world - -Requirements ------------- - -If you wish to use a Google Map to display where your visitors are probably at, -you must have a `Google Maps API key -`_, which is free. You -are required to have the `GeoIP C API library -`_ installed. -You might want to grab the `GeoLite City binary -`_ unless you are a paying MaxMind -customer. This is the data file that ``django-tracking`` uses to translate an -IP into a location on the planet. Configuring this feature is discussed later. - -Installation -============ - -Download ``django-tracking`` using *one* of the following methods: - -pip ---- - -You can download the package from the `CheeseShop -`_ or use:: - - pip install django-tracking - -to download and install ``django-tracking``. - -easy_install ------------- - -You can download the package from the `CheeseShop `_ or use:: - - easy_install django-tracking - -to download and install ``django-tracking``. - -Checkout from BitBucket/GitHub/Google Code ------------------------------------------- - -Use one of the following commands:: - - hg clone http://bitbucket.org/codekoala/django-tracking - git clone http://github.com/codekoala/django-tracking.git - hg clone http://django-tracking.googlecode.com/hg/ django-tracking - -Package Download -================ - -Download the latest ``.tar.gz`` file from the downloads section and extract it -somewhere you'll remember. - -Configuration -============= - -First of all, you must add this project to your list of ``INSTALLED_APPS`` in -``settings.py``:: - - INSTALLED_APPS = ( - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - ... - 'tracking', - ... - ) - -Run ``manage.py syncdb``. This creates a few tables in your database that are -necessary for operation. - -Depending on how you wish to use this application, you have a few options: - -Visitor Tracking ----------------- - -Add ``tracking.middleware.VisitorTrackingMiddleware`` to your -``MIDDLEWARE_CLASSES`` in ``settings.py``. It must be underneath the -``AuthenticationMiddleware``, so that ``request.user`` exists. - -Automatic Visitor Clean-Up -++++++++++++++++++++++++++ - -If you want to have Django automatically clean past visitor information out -your database, put ``tracking.middleware.VisitorCleanUpMiddleware`` in your -``MIDDLEWARE_CLASSES``. - -IP Banning ----------- - -Add ``tracking.middleware.BannedIPMiddleware`` to your ``MIDDLEWARE_CLASSES`` -in ``settings.py``. I would recommend making this the very first item in -``MIDDLEWARE_CLASSES`` so your banned users do not have to drill through any -other middleware before Django realizes they don't belong on your site. - -Visitors on Page (template tag) -------------------------------- - -Make sure that ``django.core.context_processors.request`` is somewhere in your -``TEMPLATE_CONTEXT_PROCESSORS`` tuple. This context processor makes the -``request`` object accessible to your templates. This application uses the -``request`` object to determine what page the user is looking at in a template -tag. - -Active Visitors Map -=================== - -If you're interested in seeing where your visitors are at a given point in -time, you might enjoy the active visitor map feature. Be sure you have added a -line to your main URLconf, as follows:: - - from django.conf.urls.defaults import * - - urlpatterns = patterns('', - .... - (r'^tracking/', include('tracking.urls')), - .... - ) - -Next, set a couple of settings in your ``settings.py``: - -* ``GOOGLE_MAPS_KEY``: Your very own Google Maps API key -* ``TRACKING_USE_GEOIP``: set this to ``True`` if you want to see markers on - the map -* ``GEOIP_PATH``: set this to the absolute path on the filesystem of your - ``GeoIP.dat`` or ``GeoIPCity.dat`` or whatever file. It's usually something - like ``/usr/local/share/GeoIP.dat`` or ``/usr/share/GeoIP/GeoIP.dat``. -* ``GEOIP_CACHE_TYPE``: The type of caching to use when dealing with GeoIP data: - - * ``0``: read database from filesystem, uses least memory. - * ``1``: load database into memory, faster performance but uses more - memory. - * ``2``: check for updated database. If database has been updated, reload - filehandle and/or memory cache. - * ``4``: just cache the most frequently accessed index portion of the - database, resulting in faster lookups than ``GEOIP_STANDARD``, but less - memory usage than ``GEOIP_MEMORY_CACHE`` - useful for larger databases - such as GeoIP Organization and GeoIP City. Note, for GeoIP Country, - Region and Netspeed databases, ``GEOIP_INDEX_CACHE`` is equivalent to - ``GEOIP_MEMORY_CACHE``. *default* - -* ``DEFAULT_TRACKING_TEMPLATE``: The template to use when generating the - visitor map. Defaults to ``tracking/visitor_map.html``. - -When that's done, you should be able to go to ``/tracking/map/`` on your site -(replacing ``tracking`` with whatever prefix you chose to use in your URLconf, -obviously). The default template relies upon jQuery for its awesomeness, but -you're free to use whatever you would like. - -Usage -===== - -To display the number of active users there are in one of your templates, make -sure you have ``{% load tracking_tags %}`` somewhere in your template and do -something like this:: - - {% visitors_on_site as visitors %} -

- {{ visitors }} active user{{ visitors|pluralize }} -

- -If you also want to show how many people are looking at the same page:: - - {% visitors_on_page as same_page %} -

- {{ same_page }} of {{ visitors }} active user{{ visitors|pluralize }} - {{ same_page|pluralize:"is,are" }} reading this page -

- -If you don't want particular areas of your site to be tracked, you may define a -list of prefixes in your ``settings.py`` using the ``NO_TRACKING_PREFIXES``. For -example, if you didn't want visits to the ``/family/`` section of your website, -set ``NO_TRACKING_PREFIXES`` to ``['/family/']``. - -If you don't want to count certain user-agents, such as Yahoo!'s Slurp and -Google's Googlebot, you may add keywords to your visitor tracking in your -Django administration interface. Look for "Untracked User-Agents" and add a -keyword that distinguishes a particular user-agent. Any visitors with the -keyword in their user-agent string will not be tracked. - -By default, active users include any visitors within the last 10 minutes. If -you would like to override that setting, just set ``TRACKING_TIMEOUT`` to however -many minutes you want in your ``settings.py``. - -For automatic visitor clean-up, any records older than 24 hours are removed by -default. If you would like to override that setting, set -``TRACKING_CLEANUP_TIMEOUT`` to however many hours you want in your -``settings.py``. - -Good luck! Please contact me with any questions or concerns you have with the -project! From fe7aa16f7d72ad551a7019d5c2901b490637703e Mon Sep 17 00:00:00 2001 From: Basil Shubin Date: Thu, 6 Aug 2015 10:33:07 +0500 Subject: [PATCH 38/49] Create .landscape.yaml --- .landscape.yaml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .landscape.yaml diff --git a/.landscape.yaml b/.landscape.yaml new file mode 100644 index 0000000..28db37d --- /dev/null +++ b/.landscape.yaml @@ -0,0 +1,3 @@ +ignore-paths: + - south_migrations + - migrations From 7615faa5a23ce934603d810802c60523e7434e8f Mon Sep 17 00:00:00 2001 From: Basil Shubin Date: Thu, 6 Aug 2015 10:33:25 +0500 Subject: [PATCH 39/49] Update .landscape.yaml --- .landscape.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.landscape.yaml b/.landscape.yaml index 28db37d..ae7ea33 100644 --- a/.landscape.yaml +++ b/.landscape.yaml @@ -1,3 +1,3 @@ ignore-paths: - - south_migrations - - migrations + - south_migrations + - migrations From 0dfd499c4ae1ce02fdb6a4b67bcedfa30dc9ee27 Mon Sep 17 00:00:00 2001 From: Basil Shubin Date: Thu, 6 Aug 2015 10:45:01 +0500 Subject: [PATCH 40/49] Update README.rst --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 527741c..169ac39 100644 --- a/README.rst +++ b/README.rst @@ -13,6 +13,10 @@ Authored by `Josh VanderLinden `_, and some great .. image:: https://img.shields.io/github/license/bashu/django-tracking.svg :target: https://pypi.python.org/pypi/django-tracking/ + +.. image:: https://landscape.io/github/bashu/django-tracking/develop/landscape.svg?style=flat + :target: https://landscape.io/github/bashu/django-tracking/develop + Features -------- From 365f219ae701e7eb3a7c14a4d7c2437a849261dc Mon Sep 17 00:00:00 2001 From: ice9at Date: Sun, 16 Sep 2012 13:21:53 +0400 Subject: [PATCH 41/49] Update tracking/middleware.py add support timezone. using timezone.now() --- tracking/middleware.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tracking/middleware.py b/tracking/middleware.py index ab35308..68260b6 100644 --- a/tracking/middleware.py +++ b/tracking/middleware.py @@ -1,4 +1,5 @@ from datetime import datetime, timedelta +from django.utils import timezone import logging import re import traceback @@ -16,6 +17,7 @@ title_re = re.compile('(.*?)') log = logging.getLogger('tracking.middleware') + class VisitorTrackingMiddleware(object): """ Keeps track of your active users. Anytime a visitor accesses a valid URL, @@ -93,7 +95,7 @@ def process_request(self, request): # if we get here, the URL needs to be tracked # determine what time it is - now = datetime.now() + now = timezone.now() # datetime.now() attrs = { 'session_key': session_key, @@ -159,7 +161,7 @@ def process_request(self, request): if str(timeout).isdigit(): log.debug('Cleaning up visitors older than %s hours' % timeout) - timeout = datetime.now() - timedelta(hours=int(timeout)) + timeout = timezone.now() - timedelta(hours=int(timeout)) # datetime.now() Visitor.objects.filter(last_update__lte=timeout).delete() class BannedIPMiddleware: From f6883f8759bc645a3aeb7b77cced8e95b84e46de Mon Sep 17 00:00:00 2001 From: Basil Shubin Date: Thu, 24 Sep 2015 07:57:57 +0500 Subject: [PATCH 42/49] Update .landscape.yaml --- .landscape.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.landscape.yaml b/.landscape.yaml index ae7ea33..bba38db 100644 --- a/.landscape.yaml +++ b/.landscape.yaml @@ -1,3 +1,4 @@ ignore-paths: - south_migrations - migrations + - example From d843ba65d927379d08d4017cf7aa4a7201de0380 Mon Sep 17 00:00:00 2001 From: Roman Vasilyev Date: Wed, 16 Dec 2015 13:15:51 -0800 Subject: [PATCH 43/49] django 1.9 fixes --- tracking/models.py | 3 ++- tracking/templates/tracking/_active_users.js | 2 +- tracking/templates/tracking/visitor_map.html | 4 ++-- tracking/views.py | 7 +++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tracking/models.py b/tracking/models.py index fd24738..4d3aa35 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -13,6 +13,7 @@ from django.db import models from django.utils.translation import ugettext, ugettext_lazy as _ from tracking import utils +from django.contrib.gis.geoip import HAS_GEOIP USE_GEOIP = getattr(settings, 'TRACKING_USE_GEOIP', False) CACHE_TYPE = getattr(settings, 'GEOIP_CACHE_TYPE', 4) @@ -107,7 +108,7 @@ def _get_geoip_data_json(self): geoip_data_json = property(_get_geoip_data_json) def __unicode__(self): return u'{0} at {1} '.format( - self.user.username, + self.user, self.ip_address ) diff --git a/tracking/templates/tracking/_active_users.js b/tracking/templates/tracking/_active_users.js index 1a2b409..3a966bc 100644 --- a/tracking/templates/tracking/_active_users.js +++ b/tracking/templates/tracking/_active_users.js @@ -58,7 +58,7 @@ $('html').ajaxSend(function(event, xhr, settings) { function createMarkers() { // Pull back all active users and create markers for them $.ajax({ - url : '{% url tracking-get-active-users %}', + url : '{% url "tracking-get-active-users" %}', type : 'POST', dataType : 'json', data: {}, diff --git a/tracking/templates/tracking/visitor_map.html b/tracking/templates/tracking/visitor_map.html index dbad188..396e4dd 100644 --- a/tracking/templates/tracking/visitor_map.html +++ b/tracking/templates/tracking/visitor_map.html @@ -1,11 +1,11 @@ -{% extends template %} +{% extends 'base.html' %} {% load i18n %} {% block title %}{% trans "Active Visitors Map" %}{% endblock %} {% block extra-head %} {{ block.super }} - + diff --git a/tracking/views.py b/tracking/views.py index 7b40fc5..76e7aab 100644 --- a/tracking/views.py +++ b/tracking/views.py @@ -70,10 +70,10 @@ def get_active_users(request): } for v in active]} except: log.error('There was a problem putting all of the visitor data together:\n%s\n\n%s' % (traceback.format_exc(), locals())) - return HttpResponse(content='{}', mimetype='text/javascript') + return HttpResponse(content='{}', content_type='text/javascript') response = HttpResponse(content=JSONEncoder().encode(data), - mimetype='text/javascript') + content_type='text/javascript') response['Content-Length'] = len(response.content) return response @@ -101,8 +101,7 @@ def friendly_time(last_update): return friendly_time or 0 -def display_map(request, template_name=DEFAULT_TRACKING_TEMPLATE, - extends_template='base.html'): +def display_map(request, template_name=DEFAULT_TRACKING_TEMPLATE): """ Displays a map of recently active users. Requires a Google Maps API key and GeoIP in order to be most effective. From ec42d3e763c6b6708e7e25e3969ed16f3bb8f5cd Mon Sep 17 00:00:00 2001 From: Roman Vasilyev Date: Wed, 16 Dec 2015 14:42:11 -0800 Subject: [PATCH 44/49] fix for multibyte --- tracking/templates/tracking/visitor_map.html | 2 +- tracking/utils.py | 20 +------------- tracking/views.py | 29 ++++++++------------ 3 files changed, 14 insertions(+), 37 deletions(-) diff --git a/tracking/templates/tracking/visitor_map.html b/tracking/templates/tracking/visitor_map.html index 396e4dd..699449f 100644 --- a/tracking/templates/tracking/visitor_map.html +++ b/tracking/templates/tracking/visitor_map.html @@ -1,4 +1,4 @@ -{% extends 'base.html' %} +{% extends 'tbase.html' %} {% load i18n %} {% block title %}{% trans "Active Visitors Map" %}{% endblock %} diff --git a/tracking/utils.py b/tracking/utils.py index 16f6790..1b8b696 100644 --- a/tracking/utils.py +++ b/tracking/utils.py @@ -50,22 +50,4 @@ def get_cleanup_timeout(): def u_clean(s): """A strange attempt at cleaning up unicode""" - uni = '' - try: - # try this first - uni = str(s).decode('iso-8859-1') - except UnicodeDecodeError: - try: - # try utf-8 next - uni = str(s).decode('utf-8') - except UnicodeDecodeError: - # last resort method... one character at a time (ugh) - if s and type(s) in (str, unicode): - for c in s: - try: - uni += unicodedata.normalize('NFKC', unicode(c)) - except UnicodeDecodeError: - uni += '-' - - return uni.encode('ascii', 'xmlcharrefreplace') - + return s diff --git a/tracking/views.py b/tracking/views.py index 76e7aab..d9e3428 100644 --- a/tracking/views.py +++ b/tracking/views.py @@ -56,21 +56,17 @@ def get_active_users(request): now = timezone.now() # we don't put the session key or IP address here for security reasons - try: - data = {'users': [{ - 'id': v.id, - #'user': uc(v.user), - 'user_agent': uc(v.user_agent), - 'referrer': uc(v.referrer), - 'url': uc(v.url), - 'page_views': v.page_views, - 'geoip': v.geoip_data_json, - 'last_update': (now - v.last_update).seconds, - 'friendly_time': ', '.join(friendly_time((now - v.last_update).seconds)), - } for v in active]} - except: - log.error('There was a problem putting all of the visitor data together:\n%s\n\n%s' % (traceback.format_exc(), locals())) - return HttpResponse(content='{}', content_type='text/javascript') + data = {'users': [{ + 'id': v.id, + #'user': uc(v.user), + 'user_agent': uc(v.user_agent), + 'referrer': uc(v.referrer), + 'url': uc(v.url), + 'page_views': v.page_views, + 'geoip': v.geoip_data_json, + 'last_update': (now - v.last_update).seconds, + 'friendly_time': ', '.join(friendly_time((now - v.last_update).seconds)), + } for v in active]} response = HttpResponse(content=JSONEncoder().encode(data), content_type='text/javascript') @@ -110,6 +106,5 @@ def display_map(request, template_name=DEFAULT_TRACKING_TEMPLATE): GOOGLE_MAPS_KEY = getattr(settings, 'GOOGLE_MAPS_KEY', None) return render_to_response(template_name, - {'GOOGLE_MAPS_KEY': GOOGLE_MAPS_KEY, - 'template': extends_template}, + {'GOOGLE_MAPS_KEY': GOOGLE_MAPS_KEY}, context_instance=RequestContext(request)) From 9140ff4b25aa9be18623f2f922062ad40d42b143 Mon Sep 17 00:00:00 2001 From: Roman Vasilyev Date: Wed, 16 Dec 2015 14:45:20 -0800 Subject: [PATCH 45/49] fix for right base --- tracking/templates/tracking/visitor_map.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/templates/tracking/visitor_map.html b/tracking/templates/tracking/visitor_map.html index 699449f..396e4dd 100644 --- a/tracking/templates/tracking/visitor_map.html +++ b/tracking/templates/tracking/visitor_map.html @@ -1,4 +1,4 @@ -{% extends 'tbase.html' %} +{% extends 'base.html' %} {% load i18n %} {% block title %}{% trans "Active Visitors Map" %}{% endblock %} From 47fd39839b7d36961270b1395e721604e52b3d80 Mon Sep 17 00:00:00 2001 From: Roman Vasilyev Date: Wed, 23 Dec 2015 11:55:33 -0800 Subject: [PATCH 46/49] user name can not exist --- tracking/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/admin.py b/tracking/admin.py index 31c2906..a6bd543 100644 --- a/tracking/admin.py +++ b/tracking/admin.py @@ -2,7 +2,7 @@ from tracking.models import Visitor, VisitorManager, BannedIP, UntrackedUserAgent class VisitorAdmin(admin.ModelAdmin): - search_fields = ['username'] + search_fields = ['ip_address'] admin.site.register(Visitor, VisitorAdmin) admin.site.register(BannedIP) admin.site.register(UntrackedUserAgent) From b806b92d40954710fc2802c6c3f59120ec9e2cad Mon Sep 17 00:00:00 2001 From: Roman Vasilyev Date: Wed, 18 May 2016 00:58:11 -0700 Subject: [PATCH 47/49] django 1.10 fix --- tracking/urls.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tracking/urls.py b/tracking/urls.py index d5ded8e..27cdedc 100644 --- a/tracking/urls.py +++ b/tracking/urls.py @@ -1,16 +1,16 @@ try: - from django.conf.urls import patterns, url, include + from django.conf.urls import url, include except ImportError: # Pre-Django 1.4 version from django.conf.urls.defaults import patterns, url, include from django.conf import settings from tracking import views -urlpatterns = patterns('', +urlpatterns = ( url(r'^refresh/$', views.update_active_users, name='tracking-refresh-active-users'), url(r'^refresh/json/$', views.get_active_users, name='tracking-get-active-users'), ) if getattr(settings, 'TRACKING_USE_GEOIP', False): - urlpatterns += patterns('', + urlpatterns += ( url(r'^map/$', views.display_map, name='tracking-visitor-map'), ) From ac2f2e8a9ac5ef92029b3dabfd4f9af53c2beb15 Mon Sep 17 00:00:00 2001 From: Roman Vasilyev Date: Mon, 8 May 2017 12:41:45 -0700 Subject: [PATCH 48/49] ipv6 fix --- tracking/models.py | 2 +- tracking/utils.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tracking/models.py b/tracking/models.py index 4d3aa35..0cf1422 100644 --- a/tracking/models.py +++ b/tracking/models.py @@ -36,7 +36,7 @@ def active(self, timeout=None): class Visitor(models.Model): session_key = models.CharField(max_length=40) - ip_address = models.CharField(max_length=20) + ip_address = models.GenericIPAddressField() user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True) user_agent = models.CharField(max_length=255) referrer = models.CharField(max_length=255) diff --git a/tracking/utils.py b/tracking/utils.py index 1b8b696..4ecf95c 100644 --- a/tracking/utils.py +++ b/tracking/utils.py @@ -18,6 +18,7 @@ def get_ip(request): # if neither header contain a value, just use local loopback ip_address = request.META.get('HTTP_X_FORWARDED_FOR', request.META.get('REMOTE_ADDR', '127.0.0.1')) + return ip_address if ip_address: # make sure we have one and only one IP try: From 4a466bc0e8da31339f866f0d7e6f5b1608ca62da Mon Sep 17 00:00:00 2001 From: Vasilyev Date: Tue, 9 May 2017 13:37:48 -0700 Subject: [PATCH 49/49] version --- tracking/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking/__init__.py b/tracking/__init__.py index b8df223..793fda6 100644 --- a/tracking/__init__.py +++ b/tracking/__init__.py @@ -1,4 +1,4 @@ -VERSION = (0, 4, 1) +VERSION = (0, 4, 2) __version__ = '.'.join([str(n) for n in VERSION])