Commits

kencochrane  committed dbd1b6d

initial checkin

  • Participants

Comments (0)

Files changed (18)

+syntax: glob
+*.pyc
+dist
+MANIFEST
+_build
+_static
+.DS_Store
+Requirements
+------------
+Django 1.1 or newer (http://djangoproject.com)
+Django sessions need to be enabled
+Django cache enabled (even if it is just dummy, or locmem )
+Django-visitor (http://bitbucket.org/kencochrane/django-visitor)
+jquery 1.4.2 or newer (django-pulse will automatically load it from google code's CDN.)
+
+------------------
+Settings
+------------------
+
+django-visitor (http://bitbucket.org/kencochrane/django-visitor)
+--------------
+Make sure you have django-visitor loaded or else django-pulse will not work. It rely's on django-visitor's to keep track of each visitor.
+
+Django caching 
+==========
+django-pulse depends on caching so that we don't overload the database with ping reads. Make sure you add CACHE_BACKEND to your
+django settings, at a minimum it needs to be locmem or dummy, but this should be memcached or database or something better in prod.
+Example: CACHE_BACKEND = 'locmem://'
+
+
+App
+===
+Add 'pulse' to INSTALLED_APPS
+
+
+Views and templates
+===================
+There are two views: example and pulse. example is just a very simple example of how to use django-pulse. pulse does all of the work, it is the view that gets called by the javascript, it logs the visitor's information and returns the current number of visitors on the site.
+
+There are only 3 templates, one is an example the other two are for the template tags.
+
+Template Tags
+=============
+pulse_tag : this is the tag that loads the javascript that will ping the pulse view every 15 seconds. 
+
+jquery
+------
+It depends on jquery to run, and right now it just pulls it down from google code's jquery CDN. In the future I'll add an option to turn this off in case you already have jquery loading on the page and don't need it to be pulled down automatically. In the meantime you can go into the templates/pulse/includes/pulse_tag.html and remove the jquery js call if you want.
+
+number_of_visitors : this just puts a place holder on the page if you want to show how many people are currently visiting your site. if installed pulse_tag will automatically update it every 15 seconds, after it's ping. Feel free to customize the look and feel. File is located in templates/pulse/includes/number_of_visitors_tag.html
+
+
+Urls
+====
+add "(r'^pulse/', include('pulse.urls'))," to your base urls.py file
+
+Sync Tables
+===========
+Run ./manage.py syncdb to load up the tables in your database.
+Copyright (c) 2010, Ken Cochrane
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of the author nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+django-pulse allows you to see how many people are on your website in real time, regardless if they are just sitting on a page and doing nothing.
+
+django-pulse installs a small piece of javascript that pings your server every few seconds letting you know who is on your site, and what page they are viewing. 
+
+This is pretty much a proof of concept right now, with very little features, but with time, it should expand into a nice tool that could duplicate a lot of other real time analytic tools.
+
+django-pulse depends on django-visitor in order to keep track of the visitors to the site.
+
+For install instructions please refer to the file labled INSTALL

File pulse/__init__.py

Empty file added.

File pulse/admin.py

+from django.contrib import admin
+from pulse.models import PulseLog
+
+class PulseLogAdmin(admin.ModelAdmin):
+    list_display = ['visitor', 'last_ping', 'domain', 'page']
+
+admin.site.register(PulseLog, PulseLogAdmin)

File pulse/managers.py

+from django.db import models
+from django.core.cache import cache
+
+from pulse.pulse_constants import PULSE_VISITOR_CACHE_KEY, LAST_ACTIVATE_LIMIT
+from pulse.pulse_utils import get_minutes_ago
+#===============================================================================
+class PulseLogManager(models.Manager):
+    
+    #---------------------------------------------------------------------------
+    def current_visitor_count(self):
+        current_count = cache.get(PULSE_VISITOR_CACHE_KEY, None)
+        
+        if not current_count:
+            current_count = self.filter(last_ping__gt=get_minutes_ago(LAST_ACTIVATE_LIMIT)).count()
+            cache.set(PULSE_VISITOR_CACHE_KEY, current_count, 30) # 30 seconds
+        
+        return current_count

File pulse/models.py

+from django.db import models
+from visitor.models import Visitor
+
+from datetime import datetime
+
+from pulse import managers
+
+#==============================================================================
+class PulseLog(models.Model):
+    visitor = models.OneToOneField(Visitor)
+    created = models.DateTimeField(default=datetime.now())
+    last_ping = models.DateTimeField(default=datetime.now())
+    page = models.CharField(max_length=250)
+    domain = models.CharField(max_length=100)
+    
+    objects = managers.PulseLogManager()

File pulse/pulse_constants.py

+PULSE_VISITOR_CACHE_KEY = 'PVC_KEY'
+LAST_ACTIVATE_LIMIT = 3 # minutes

File pulse/pulse_utils.py

+from datetime import datetime, timedelta
+
+def get_minutes_ago(minutes):
+    return datetime.now() - timedelta(minutes=minutes)
+    

File pulse/templates/pulse/example.html

+{% load pulse_tags %}
+<html>
+<head>
+<title>Home</title>
+</head>
+<body>
+<h1>Pulse Example</h1>
+{% number_of_visitors %}
+{% pulse_tag %}
+<body>
+</html>

File pulse/templates/pulse/include/number_of_visitors_tag.html

+<div id='num_visitors'><span id='pulse_count'></span> Visitors</div>

File pulse/templates/pulse/include/pulse_tag.html

+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript" language="javascript"></script>
+<script type="text/javascript">
+(function(){
+  function loadPulse() {
+    runPulse();
+    window.setInterval(runPulse, 10000);
+  }
+  function runPulse() {
+      $.ajax({
+        url: '{% url pulse_ping %}',
+        success: function(data) {
+            $('#pulse_count').html(data);
+          }
+      });
+  }
+  var oldonload = window.onload;
+  window.onload = (typeof window.onload != 'function') ? loadPulse : function() { oldonload(); loadPulse(); };
+})();
+</script>

File pulse/templatetags/__init__.py

Empty file added.

File pulse/templatetags/pulse_tags.py

+from django.template import Library, Node
+
+register = Library()
+
+#-------------------------------------------------------------------------------
+@register.inclusion_tag('pulse/include/pulse_tag.html', takes_context=True)
+def pulse_tag(context):
+    return {"request":context['request']}
+    
+#-------------------------------------------------------------------------------
+@register.inclusion_tag('pulse/include/number_of_visitors_tag.html', takes_context=True)
+def number_of_visitors(context):
+    return {"request":context['request']}

File pulse/tests.py

+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+
+TODO: ADD TESTS
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+

File pulse/urls.py

+from django.conf.urls.defaults import *
+
+from pulse.views import pulse, example
+
+urlpatterns = patterns('',
+    url(r'^ping$', view=pulse, name='pulse_ping'),
+    url(r'^example$', view=example, name='example'),
+)

File pulse/views.py

+# Create your views here.
+from django.http import Http404,HttpResponse
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+
+from datetime import datetime
+
+from visitor import visitor_utils
+
+from pulse.models import PulseLog
+
+def example(request):
+    return render_to_response('pulse/example.html', context_instance=RequestContext(request))
+    
+def pulse(request):
+     
+    host = request.META.get('HTTP_HOST',"")
+    full_ref = request.META.get('HTTP_REFERER',None)
+    if full_ref:
+        page = (full_ref.split("://")[1]).replace(host,"")
+    else:
+        page = "unKnown"
+    
+    visitor = visitor_utils.get_vistor_from_request(request)
+    if visitor:
+        try:
+            pulselog = visitor.pulselog
+        except PulseLog.DoesNotExist:
+            pulselog = PulseLog()
+            pulselog.visitor = visitor
+            
+        pulselog.page = page
+        pulselog.domain = host
+        pulselog.last_ping = datetime.now()
+        pulselog.save()
+    
+    current_count = PulseLog.objects.current_visitor_count()
+    print current_count
+    
+    response = HttpResponse("%s" % current_count ,status=200,mimetype='text/plain')
+    
+    return response