Skip to content

Commit d0a722f

Browse files
committed
changed analytics to segment.io, piwik, and owa
1 parent 63afedb commit d0a722f

20 files changed

+322
-126
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# -*- coding: utf-8 -*-
2+
from south.utils import datetime_utils as datetime
3+
from south.db import db
4+
from south.v2 import SchemaMigration
5+
from django.db import models
6+
7+
8+
class Migration(SchemaMigration):
9+
10+
def forwards(self, orm):
11+
# Adding field 'Hotspot.tolerance'
12+
db.add_column(u'api_hotspot', 'tolerance',
13+
self.gf('django.db.models.fields.FloatField')(default=5, blank=True),
14+
keep_default=False)
15+
16+
17+
def backwards(self, orm):
18+
# Deleting field 'Hotspot.tolerance'
19+
db.delete_column(u'api_hotspot', 'tolerance')
20+
21+
22+
models = {
23+
u'api.business': {
24+
'Meta': {'object_name': 'Business'},
25+
'admins': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['api.User']", 'symmetrical': 'False'}),
26+
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
27+
'logo': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
28+
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
29+
'nickname': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '40', 'blank': 'True'}),
30+
'website': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'})
31+
},
32+
u'api.checkin': {
33+
'Meta': {'object_name': 'CheckIn'},
34+
'hotspot': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['api.Hotspot']"}),
35+
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
36+
'time_in': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
37+
'time_out': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1969, 12, 31, 0, 0)'}),
38+
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['api.User']"})
39+
},
40+
u'api.hotspot': {
41+
'LAT': ('django.db.models.fields.FloatField', [], {'blank': 'True'}),
42+
'LNG': ('django.db.models.fields.FloatField', [], {'blank': 'True'}),
43+
'Meta': {'object_name': 'Hotspot'},
44+
'address': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '500', 'blank': 'True'}),
45+
'business': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['api.Business']", 'blank': 'True'}),
46+
'capacity': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
47+
'description': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2000', 'blank': 'True'}),
48+
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
49+
'logo': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'}),
50+
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
51+
'nickname': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '40', 'blank': 'True'}),
52+
'telephone': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '25', 'blank': 'True'}),
53+
'tolerance': ('django.db.models.fields.FloatField', [], {'default': '5', 'blank': 'True'}),
54+
'website': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '200', 'blank': 'True'})
55+
},
56+
u'api.user': {
57+
'Meta': {'object_name': 'User'},
58+
'birthdate': ('django.db.models.fields.DateField', [], {'default': 'None', 'blank': 'True'}),
59+
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
60+
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
61+
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
62+
'gender': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1', 'blank': 'True'}),
63+
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
64+
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
65+
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
66+
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
67+
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
68+
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
69+
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
70+
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
71+
'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
72+
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
73+
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
74+
},
75+
u'auth.group': {
76+
'Meta': {'object_name': 'Group'},
77+
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
78+
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
79+
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
80+
},
81+
u'auth.permission': {
82+
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
83+
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
84+
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
85+
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
86+
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
87+
},
88+
u'contenttypes.contenttype': {
89+
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
90+
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
91+
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
92+
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
93+
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
94+
}
95+
}
96+
97+
complete_apps = ['api']

hotspot/api/models.py

+33-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Hotspot API v1.0
2+
Hotspot API v1.0
33
Nick Sweeting 2014
44
"""
55

@@ -51,7 +51,7 @@ class User(AbstractUser):
5151

5252
gender = models.CharField(max_length=1, blank=True, default="")
5353
status = models.IntegerField(blank=True, default=0)
54-
birthdate = models.DateField(blank=True, null=True, default=None)
54+
birthdate = models.DateField(blank=True, default=None)
5555

5656
def checkin(self, hotspot, time_in=timezone.now(), time_out=epoch):
5757
"""
@@ -342,9 +342,10 @@ class Hotspot(models.Model):
342342
343343
"""
344344
name = models.CharField(max_length=100)
345-
business = models.ForeignKey(Business, blank=True, null=True)
345+
business = models.ForeignKey(Business, blank=True)
346346
LAT = models.FloatField(blank=True)
347347
LNG = models.FloatField(blank=True)
348+
tolerance = models.FloatField(blank=True, default=5)
348349
address = models.CharField(max_length=500, blank=True, default="")
349350

350351
nickname = models.CharField(max_length=40, blank=True, default="")
@@ -365,7 +366,7 @@ def score(self):
365366
"""
366367
Returns the number of people checked in (number to display on maps)
367368
"""
368-
369+
369370
# Legit Version
370371
#return checkins_checkedin().count()
371372
# "augmented" results
@@ -475,7 +476,7 @@ def search_by_radius(lat, lng, radius=10, limit=200):
475476
"""
476477

477478
find_by_radius_sql = \
478-
'''SELECT api_hotspot.id, api_hotspot.LAT, api_hotspot.LNG,
479+
'''SELECT api_hotspot.id, api_hotspot.LAT, api_hotspot.LNG,
479480
( 3959 * acos(cos(radians( %(ILAT)s ) ) * cos( radians( LAT )) * cos(radians( LNG ) - radians( %(ILNG)s )) + sin(radians( %(ILAT)s )) * sin(radians( LAT )))) AS distance FROM api_hotspot
480481
HAVING distance < %(IRAD)s
481482
ORDER BY distance
@@ -485,6 +486,22 @@ def search_by_radius(lat, lng, radius=10, limit=200):
485486
ids = [x.id for x in Hotspot.objects.raw(find_by_radius_sql, {"ILAT":float(lat),"ILNG":float(lng),"IRAD":float(radius), "ILIM":int(limit)+1})]
486487
return Hotspot.objects.filter(id__in=ids)
487488

489+
# Scanners
490+
@staticmethod
491+
def raw_search_by_radius(lat, lng, radius=10, limit=200):
492+
"""
493+
Find all hotspots within a given radius (limited to 50km)
494+
"""
495+
496+
find_by_radius_sql = \
497+
'''SELECT api_hotspot.id, api_hotspot.LAT, api_hotspot.LNG,
498+
( 3959 * acos(cos(radians( %(ILAT)s ) ) * cos( radians( LAT )) * cos(radians( LNG ) - radians( %(ILNG)s )) + sin(radians( %(ILAT)s )) * sin(radians( LAT )))) AS distance FROM api_hotspot
499+
HAVING distance < %(IRAD)s
500+
ORDER BY distance
501+
LIMIT 0, %(ILIM)s'''
502+
503+
return Hotspot.objects.raw(find_by_radius_sql, {"ILAT":float(lat),"ILNG":float(lng),"IRAD":float(radius), "ILIM":int(limit)+1})
504+
488505
class CheckIn(models.Model):
489506
"""
490507
CheckIns are linked many-to-one with model:`Hotspot` and many-to-one with model:`User`
@@ -522,7 +539,7 @@ def is_checkedin(self):
522539
else:
523540
return False
524541

525-
542+
526543
# Returns QuerySet of <object>s that are currently checked into
527544
@staticmethod
528545
@sortable
@@ -548,7 +565,7 @@ def merge_objects(primary_object, alias_objects=[], keep_old=False):
548565
Use this function to merge model objects (i.e. Users, Organizations, Polls,
549566
etc.) and migrate all of the related fields from the alias objects to the
550567
primary object.
551-
568+
552569
Usage:
553570
from django.contrib.auth.models import User
554571
primary_user = User.objects.get(email='[email protected]')
@@ -557,28 +574,28 @@ def merge_objects(primary_object, alias_objects=[], keep_old=False):
557574
"""
558575
if not isinstance(alias_objects, list):
559576
alias_objects = [alias_objects]
560-
577+
561578
# check that all aliases are the same class as primary one and that
562579
# they are subclass of model
563580
primary_class = primary_object.__class__
564-
581+
565582
if not issubclass(primary_class, Model):
566583
raise TypeError('Only django.db.models.Model subclasses can be merged')
567-
584+
568585
for alias_object in alias_objects:
569586
if not isinstance(alias_object, primary_class):
570587
raise TypeError('Only models of same class can be merged')
571-
588+
572589
# Get a list of all GenericForeignKeys in all models
573590
# TODO: this is a bit of a hack, since the generics framework should provide a similar
574591
# method to the ForeignKey field for accessing the generic related fields.
575592
generic_fields = []
576593
for model in get_models():
577594
for field_name, field in filter(lambda x: isinstance(x[1], GenericForeignKey), model.__dict__.iteritems()):
578595
generic_fields.append(field)
579-
596+
580597
local_fields = set([field.attname for field in primary_object._meta.local_fields])
581-
598+
582599
# Loop through all alias objects and migrate their data to the primary object.
583600
for alias_object in alias_objects:
584601
# Migrate all foreign key references from alias object to primary object.
@@ -596,7 +613,7 @@ def merge_objects(primary_object, alias_objects=[], keep_old=False):
596613
for related_many_object in alias_object._meta.get_all_related_many_to_many_objects():
597614
alias_varname = related_many_object.get_accessor_name()
598615
obj_varname = related_many_object.field.name
599-
616+
600617
if alias_varname is not None:
601618
# standard case
602619
related_many_objects = getattr(alias_object, alias_varname).all()
@@ -615,7 +632,7 @@ def merge_objects(primary_object, alias_objects=[], keep_old=False):
615632
for generic_related_object in field.model.objects.filter(**filter_kwargs):
616633
setattr(generic_related_object, field.name, primary_object)
617634
generic_related_object.save()
618-
635+
619636
# Try to fill all missing values in primary object by values of duplicates
620637
filled_up = set()
621638
for field_name in local_fields:
@@ -625,7 +642,7 @@ def merge_objects(primary_object, alias_objects=[], keep_old=False):
625642
setattr(primary_object, field_name, val)
626643
filled_up.add(field_name)
627644
local_fields -= filled_up
628-
645+
629646
if not keep_old:
630647
alias_object.delete()
631648
primary_object.save()

hotspot/api/urls.py

+1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55

66
urlpatterns = patterns('',
77
url(r'^$', views.docs),
8+
url(r'^locate', views.locate),
89
)

hotspot/api/views.py

+21
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def hotspot_json(hotspot, distance=0):
4444
"phone_number": hotspot.telephone,
4545
"latitude": str(hotspot.LAT),
4646
"longitude": str(hotspot.LNG),
47+
"tolerance": str(hotspot.tolerance),
4748
"full_address": hotspot.address,
4849
"distance": str(distance),
4950
"categories": None,
@@ -79,3 +80,23 @@ def scan(request):
7980
response["status"] = "ERROR-NO-AUTH"
8081

8182
return HttpResponse(json.dumps(response), content_type="application/json")
83+
84+
85+
@csrf_exempt
86+
def locate(request):
87+
lat = get_parameter(request, 'lat', '')
88+
lng = get_parameter(request, 'lng', '')
89+
tol = get_parameter(request, 'tolerance', '')
90+
91+
response = {"status":"ERROR-NO-RESULTS","hotspot": False}
92+
93+
if lat and lng:
94+
hotspot = Hotspot.raw_search_by_radius(lat, lng, radius=1, limit=10)
95+
if hotspot:
96+
response["status"] = "SUCCESS"
97+
response["hotspot"] = hotspot_json(hotspot[0])
98+
else:
99+
response["status"] = "ERROR-NO-RESULTS"
100+
101+
102+
return HttpResponse(json.dumps(response), content_type="application/json")

hotspot/apps/web/urls.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
import views
44

55
urlpatterns = patterns('',
6-
url(r'^$', views.index, name='index')
6+
url(r'^$', views.index, name='index'),
77
)

hotspot/apps/web/views.py

+36-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,42 @@ def index(request):
3535
socialaccount = request.user.socialaccount_set.filter(provider='facebook')
3636
if socialaccount:
3737
profile_img = socialaccount[0].get_avatar_url()
38-
38+
39+
context = {
40+
'hotspots': hotspots,
41+
'checkins': checkins,
42+
'hotspots_json': hotspots_json,
43+
'device': device,
44+
'profile_img': profile_img,
45+
}
46+
return render(request, 'web/index.html', context)
47+
48+
def add(request):
49+
hotspots = []
50+
for hotspot in Hotspot.objects.order_by('checkin__time_in'):
51+
hotspots.append({
52+
'id':hotspot.id,
53+
'name':hotspot.name,
54+
'LAT':hotspot.LAT,
55+
'LNG':hotspot.LNG,
56+
'logo':hotspot.logo,
57+
'description':hotspot.description,
58+
'address':hotspot.address,
59+
'nickname':hotspot.nickname,
60+
'capacity':hotspot.capacity,
61+
'website':hotspot.website,
62+
'telephone':hotspot.telephone,
63+
})
64+
65+
hotspots_json = json.dumps(hotspots)
66+
checkins = CheckIn.checkins_checkedin().count()
67+
68+
profile_img = "http://vpn.nicksweeting.com/images/up.gif"
69+
if request.user.is_authenticated():
70+
socialaccount = request.user.socialaccount_set.filter(provider='facebook')
71+
if socialaccount:
72+
profile_img = socialaccount[0].get_avatar_url()
73+
3974
context = {
4075
'hotspots': hotspots,
4176
'checkins': checkins,

hotspot/context_processors.py

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
from django.conf import settings
22
from django.template.loader import render_to_string
33

4-
def analytics(request):
5-
"""
6-
Returns Google analytics code.
4+
def get_ip(request):
5+
"""Returns the IP of the request, accounting for the possibility of being
6+
behind a proxy.
77
"""
8-
if not settings.DEBUG or settings.DEBUG_ANALYTICS:
9-
return { 'analytics_code': render_to_string("analytics.html", { 'google_analytics_key': settings.GOOGLE_ANALYTICS_KEY }) }
8+
ip = request.META.get("HTTP_X_FORWARDED_FOR", None)
9+
if ip:
10+
# X_FORWARDED_FOR returns client1, proxy1, proxy2,...
11+
ip = ip.split(", ")[0]
1012
else:
11-
return { 'analytics_code': "" }
13+
ip = request.META.get("REMOTE_ADDR", "")
14+
return ip
1215

13-
def uservoice(request):
16+
def analytics(request):
1417
"""
15-
Returns Uservoice feedback box code.
18+
Returns segment.io analytics itegration code.
1619
"""
17-
if not settings.DEBUG or settings.DEBUG_USERVOICE:
18-
return { 'uservoice_code': render_to_string("uservoice.html", {}) }
20+
if not settings.DEBUG or settings.DEBUG_ANALYTICS:
21+
return { 'analytics_code': render_to_string("analytics.html", { 'segment_api_key': settings.SEGMENT_ANALYTICS_KEY}) }
1922
else:
20-
return { 'uservoice_code': "" }
23+
return { 'analytics_code': "" }

hotspot/docs/hotspot.api.dot

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
digraph model_graph {
22
# Dotfile by Django-Extensions graph_models
3-
# Created: 2014-02-17 16:09
3+
# Created: 2014-02-27 21:56
44
# Cli Options: api
55

66
fontname = "Helvetica"
@@ -298,6 +298,12 @@ digraph model_graph {
298298
<FONT COLOR="#7B7B7B" FACE="Helvetica ">CharField</FONT>
299299
</TD></TR>
300300

301+
<TR><TD ALIGN="LEFT" BORDER="0">
302+
<FONT COLOR="#7B7B7B" FACE="Helvetica ">tolerance</FONT>
303+
</TD><TD ALIGN="LEFT">
304+
<FONT COLOR="#7B7B7B" FACE="Helvetica ">FloatField</FONT>
305+
</TD></TR>
306+
301307
<TR><TD ALIGN="LEFT" BORDER="0">
302308
<FONT COLOR="#7B7B7B" FACE="Helvetica ">website</FONT>
303309
</TD><TD ALIGN="LEFT">

0 commit comments

Comments
 (0)