Initial commit

This commit is contained in:
Ryan McGrath 2010-10-27 14:53:51 -04:00
commit d5c605e4ad
22 changed files with 1372 additions and 0 deletions

BIN
redditors/.models.py.swp Normal file

Binary file not shown.

BIN
redditors/.views.py.swp Normal file

Binary file not shown.

0
redditors/__init__.py Normal file
View file

16
redditors/admin.py Normal file
View file

@ -0,0 +1,16 @@
from django.contrib import admin
from drinkkit.redditors.models import LocationCategory, Location, Checkin, Tip
class CheckinInline(admin.StackedInline):
model = Checkin
extra = 1
class TipInline(admin.StackedInline):
model = Tip
extra = 1
class LocationAdmin(admin.ModelAdmin):
inlines = [CheckinInline, TipInline]
admin.site.register(Location, LocationAdmin)
admin.site.register(LocationCategory)

62
redditors/models.py Normal file
View file

@ -0,0 +1,62 @@
from datetime import datetime, timedelta
from django.contrib.gis.db import models
from django.contrib.auth.models import User
class LocationCategory(models.Model):
"""
Table/class to hold categories for locations to fall under. Let this
be fairly agnostic of everything.
"""
name = models.CharField(max_length = 200)
def __str__(self):
return "%s" % str(self.name)
class Location(models.Model):
"""
Locations, yo. Street Address is optional, don't make the user
have to fuck with something they don't know offhand unless they care.
Category is self explanatory, geometry is a GeoDjango model type to handle
storing lat/long coordinates for distance equations.
"""
name = models.CharField(max_length=200)
street_address = models.CharField(max_length=200, blank=True)
category = models.ForeignKey(LocationCategory, blank=True, null=True)
geometry = models.PointField(srid=4326)
objects = models.GeoManager()
def __str__(self):
return "%s" % str(self.name)
def get_recent_checkins_count(self):
"""
Tally up how many checkins this location had in the past day.
"""
print self.checkin_set.filter(timestamp__gte = datetime.now() + timedelta(days=-1))
return self.checkin_set.filter(timestamp__gte = datetime.now() + timedelta(days=-1)).count()
def address_for_geocode(self):
return self.street_address.replace(" ", "+")
class Checkin(models.Model):
"""
Checkin model - pretty self explanatory all around.
"""
user = models.ForeignKey(User)
location = models.ForeignKey(Location)
timestamp = models.DateTimeField(auto_now=True)
estimated_time_here = models.CharField(max_length=200, blank=True, null=True)
identify_by = models.CharField(max_length=200, blank=True, null=True)
class Tip(models.Model):
"""
Tips - again, fairly self explanatory.
"""
tip = models.TextField(blank=False)
user = models.ForeignKey(User)
timestamp = models.DateTimeField(auto_now=True)
location = models.ForeignKey(Location)
def __str__(self):
return "%s" % str(self.title)

23
redditors/tests.py Normal file
View file

@ -0,0 +1,23 @@
"""
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.
"""
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
"""}

242
redditors/views.py Normal file
View file

@ -0,0 +1,242 @@
from datetime import datetime, timedelta
from django.contrib.gis.geos import *
from django.contrib.gis.measure import D
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
from django.utils import simplejson
from django.contrib.auth.models import User
from django.template import RequestContext, Context
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from drinkkit.redditors.models import LocationCategory, Location, Tip, Checkin
def home(request):
"""
Main page shows the checkins that have occured over the past day or so. Paginate it
so we don't completely crush things.
"""
queryset = Checkin.objects.filter(timestamp__gte = datetime.now() + timedelta(days=-1))
paginator = Paginator(queryset, 15)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
checkins = paginator.page(page)
except (EmptyPage, InvalidPage):
checkins = paginator.page(paginator.num_pages)
return render_to_response('locations/home.html',
context_instance = RequestContext(request, {'checkins': checkins})
)
def register(request):
"""
Registration junk for a new user.
"""
if request.POST:
form = UserCreationForm(request.POST)
if form.is_valid():
# Create User and junk
new_user = form.save()
return HttpResponseRedirect('/')
else:
# You done goofed
return render_to_response('registration/register.html',
context_instance = RequestContext(request, {'form': form})
)
else:
form = UserCreationForm()
return render_to_response('registration/register.html',
context_instance = RequestContext(request, {'form': form})
)
def nearby_locations(request):
"""
This is a bit of an interesting method. To deal with older phones,
we employ a somewhat odd trick here.
We first direct the phone to a page that grabs their coordinates (whether
by geolocation API, or IP location). We do this for phones where we can go ahead and
get the IP location, but they might not support AJAX requests or some shit like that.
The page then submits automatically with JS after it gets the coordinates, with a button
for the user to hit if the browser is also gonna hang on stupid shit like that.
"""
if request.POST:
if not request.POST['lat'] or not request.POST['long']:
return render_to_response('locations/get_coords_nearby.html',
context_instance = RequestContext(request, {
'error': "Seems we're unable to get ahold of the GPS/location for where you are. Try again in a few minutes!"
})
)
searchpnts = fromstr('POINT(%s %s)' % (request.POST['lat'], request.POST['long']), srid=4326)
nearby = Location.objects.filter(geometry__distance_lte=(searchpnts, D(mi=2)))
return render_to_response('locations/show_nearby.html',
context_instance = RequestContext(request, {'nearby': nearby})
)
else:
return render_to_response('locations/get_coords_nearby.html',
context_instance = RequestContext(request)
)
def find_locations(request):
"""
A weak and very basic search. Should be rewritten down the road if this goes anywhere.
"""
if request.POST:
queryset = Location.objects.filter(name__icontains = request.POST['search_query'])
paginator = Paginator(queryset, 10)
performed_search = False
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
results = paginator.page(page)
performed_search = True
except (EmptyPage, InvalidPage):
results = paginator.page(paginator.num_pages)
return render_to_response('locations/search.html',
context_instance = RequestContext(request, {
'search_query': request.POST['search_query'],
'results': results,
'performed_search': performed_search # sucks, but whatever for now
})
)
else:
return render_to_response('locations/search.html',
context_instance = RequestContext(request)
)
@login_required
def checkin_location(request, location_id):
"""
Check a user into a location.
"""
try:
location = Location.objects.get(id = location_id)
except Location.DoesNotExist:
return HttpResponse(status=400)
if request.POST:
new_checkin = Checkin()
new_checkin.user = request.user
new_checkin.location = location
new_checkin.estimated_time_here = request.POST['estimated_time_here']
new_checkin.identify_by = request.POST['identify_by']
new_checkin.save()
return HttpResponseRedirect('/locations/%s/' % location_id)
else:
return render_to_response('locations/checkin.html',
context_instance = RequestContext(request, {'location': location})
)
@login_required
def add_location(request):
"""
Add a new location to be checked into by others.
Fairly custom logic, kind of ugly, 5:30AM, I don't care right now. None of these form fields are bound,
but considering that only two of them are mandatory, I'm fine with this for a first release. It should be
fixed at some point. ;P
"""
if request.POST:
if request.POST['location_name'] and request.POST['lat'] and request.POST['long']:
new_location = Location()
new_location.name = request.POST['location_name']
new_location.geometry = 'POINT(%s %s)' %(request.POST['lat'], request.POST['long'])
# If they've supplied a street address, sweet, use it.
if request.POST['street_address']:
new_location.street_address = request.POST['street_address']
# If they set a location, let's record it... (5AM code)
if request.POST['location_type']:
try:
category = LocationCategory.objects.get(id = request.POST['location_type'])
new_location.category = category
except LocationCategory.DoesNotExist:
pass
new_location.save()
return HttpResponseRedirect('/locations/%s/' % str(new_location.id))
else:
if not request.POST['lat'] or not request.POST['lat']:
errmsg = "We weren't able to get coordinates for where you are right now. Does your phone or device have GPS?"
if not request.POST['location_name']:
errmsg = "You didn't even bother to enter a name for this location. Wtf?"
return render_to_response('locations/add.html',
context_instance = RequestContext(request, {'error': errmsg, 'category_choices': LocationCategory.objects.all()})
)
else:
return render_to_response('locations/add.html',
context_instance = RequestContext(request, {'category_choices': LocationCategory.objects.all()})
)
def view_location(request, location_id):
"""
Serve up information about a location.
Note: this could probably be more efficient.
"""
try:
location = Location.objects.get(id = location_id)
checkins = location.checkin_set
recent_checkins = checkins.all().reverse()[:5]
allow_checkin = True
# Only one checkin in a day long period.
if request.user.is_authenticated():
if checkins.filter(user = request.user).filter(timestamp__gte = datetime.now() + timedelta(days=-1)):
allow_checkin = False
return render_to_response('locations/view.html',
context_instance = RequestContext(request, {
'location': location,
'recent_checkins': recent_checkins,
'allow_checkin': allow_checkin
})
)
except Location.DoesNotExist:
return HttpResponse(status=404)
@login_required
def add_tip(request, location_id):
"""
Add a new tip about a location.
"""
if request.POST:
try:
location = Location.objects.get(id = location_id)
new_tip = Tip()
new_tip.tip = request.POST['tip_body']
new_tip.user = request.user
new_tip.location = location
new_tip.save()
return HttpResponseRedirect('/locations/%s/' % location.id)
except Location.DoesNotExist:
return HttpResponse(status=404)
else:
return HttpResponse(status=404)
def find_redditors(request):
"""
Handles locating all Redditors in a given area who recently checked in.
"""
pass