Skip to content

Commit

Permalink
Fix several issues with branch before being ready to merge
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Vetter committed Dec 20, 2012
1 parent 57cad65 commit 05798bf
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 103 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ django-webtest==1.5.3
pyflakes==0.5.0
pinocchio==0.3.1
git+git://github.com/tinio/pysqlite.git@extension-enabled#egg=pysqlite
django-oscar-testsupport==0.2
8 changes: 6 additions & 2 deletions runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
from oscar.defaults import OSCAR_SETTINGS
from oscar import OSCAR_MAIN_TEMPLATE_DIR, OSCAR_CORE_APPS

from stores.defaults import STORES_SETTINGS

location = lambda x: os.path.join(os.path.dirname(os.path.realpath(__file__)), x)

def configure():
if not settings.configured:
default_settings = OSCAR_SETTINGS
default_settings.update(STORES_SETTINGS)

settings.configure(
DATABASES={
'default': {
Expand Down Expand Up @@ -72,8 +77,7 @@ def configure():
},
GEOIP_PATH = 'sandbox/geoip',
NOSE_ARGS=['-s', '-x', '--with-spec'],
STORES_SRID=32140, # Flat projection so spatialite can do distances
**OSCAR_SETTINGS
**default_settings
)

logging.disable(logging.CRITICAL)
Expand Down
11 changes: 2 additions & 9 deletions sandbox/sandbox/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@

# Oscar settings
from oscar.defaults import *
# Oscar stores settings
from stores.defaults import *

OSCAR_ALLOW_ANON_CHECKOUT = True

Expand Down Expand Up @@ -207,15 +209,6 @@
}
}

# SRID that ist used for distance calculations. If a geodetic coordinate
# system is used to calculate distances in kilometers, miles, etc. this
# SRID will be used to transform the geometries into a geographic
# coordinate system. There are many different SRIDs that can be used. I
# recommend taking a look at http://spatialreference.org/ to find the one
# that is most suitable for you.
# We use Autstralian Albers here (http://spatialreference.org/ref/epsg/3577/)
STORES_SRID = 3577

# This is set here to make spatialite work with Mac OS X it should
# not impact other linux-based systems. It has been tested on Ubuntu
# and works fine.
Expand Down
13 changes: 13 additions & 0 deletions stores/defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# SRID that ist used for distance calculations. If a geodetic coordinate
# system is used to calculate distances in kilometers, miles, etc. this
# SRID will be used to transform the geometries into a geographic
# coordinate system. There are many different SRIDs that can be used. I
# recommend taking a look at http://spatialreference.org/ to find the one
# that is most suitable for you.
# We use Autstralian Albers here (http://spatialreference.org/ref/epsg/3577/)
STORES_GEOGRAPHIC_SRID = 3577
STORES_GEODETIC_SRID = 4326

STORES_SETTINGS = dict(
[(k, v) for k, v in locals().items() if k.startswith('STORES_')]
)
7 changes: 3 additions & 4 deletions stores/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from oscar.apps.address.abstract_models import AbstractAddress

from stores.managers import StoreManager
from stores.utils import get_geographic_srid
from stores.utils import get_geodetic_srid


class StoreAddress(AbstractAddress):
Expand All @@ -20,8 +20,7 @@ class StoreAddress(AbstractAddress):

class StoreGroup(models.Model):
name = models.CharField(_('Name'), max_length=100, unique=True)
slug = models.SlugField(_('Slug'), max_length=100, unique=True, blank=True)

slug = models.SlugField(_('Slug'), max_length=100, unique=True, blank=True)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
Expand Down Expand Up @@ -74,7 +73,7 @@ class Store(models.Model):
)
location = PointField(
_("Location"),
srid=get_geographic_srid()
srid=get_geodetic_srid(),
)

group = models.ForeignKey(
Expand Down
52 changes: 20 additions & 32 deletions stores/static/js/stores.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ stores.maps = {
var latLng = stores.maps.getCurrentLatLng();
var map = stores.maps.createOverviewMap(latLng);


// init autocomplete
var input = $('#id_store_search'),
autocomplete = new google.maps.places.Autocomplete(input[0]);
Expand All @@ -35,15 +34,14 @@ stores.maps = {
}, 500);
});


// callback function for when coordinates are found
$('[data-behaviours~=geo-location]').live('click', function(ev) {
$('[data-behaviours~=geo-location]').live('click', function (ev) {
ev.preventDefault();

// get location from browser
if (navigator.geolocation) {
// callback function for when location could not be determined
var error = function(msg) {
var error = function (msg) {
oscar.messages.error(msg);
};

Expand All @@ -65,10 +63,9 @@ stores.maps = {
}
});

$('[data-behaviours~=filter-group]').on('change', function() {
$('[data-behaviours~=filter-group]').on('change', function () {
$('#store-search').submit();
});

},

addStoreMarkers: function (map, bounds) {
Expand Down Expand Up @@ -150,38 +147,29 @@ stores.maps = {
scrollwheel: true,
zoom: 17
});


var bounds = new google.maps.LatLngBounds();



if (!!latLng) {
setTimeout(function () {
var marker = new google.maps.Marker({
position: latLng,
map: map,
title: 'You are here',
visible: true,
icon: 'http://www.google.com/mapfiles/arrow.png'
});
bounds.extend(latLng);
map.fitBounds(bounds);
map.setZoom(11);
map.setCenter(latLng);

var infowindow = new google.maps.InfoWindow({
content: 'You are here'
});
google.maps.event.addListener(marker, "click", function () {
infowindow.open(map, marker);
});
var marker = new google.maps.Marker({
position: latLng,
map: map,
title: 'You are here',
visible: true,
icon: 'http://www.google.com/mapfiles/arrow.png'
});
bounds.extend(latLng);
map.fitBounds(bounds);
map.setZoom(11);
map.setCenter(latLng);

}, 500);
var infowindow = new google.maps.InfoWindow({
content: 'You are here'
});
google.maps.event.addListener(marker, "click", function () {
infowindow.open(map, marker);
});
}

google.maps.event.addDomListener(window, 'load', stores.maps.overview.addStoreMarkers(map, bounds));

return map;
},

Expand Down
3 changes: 3 additions & 0 deletions stores/templatetags/store_stock.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
def store_stock_for_product(product, location=None, limit=20):
query_set = StoreStock.objects.filter(product=product)
if location:
#FIXME: this query currently only works on PostGIS. This is described in
# the geodjango docs. This restricts the use of the stores package to only
# be used with that backend which should be changed.
query_set = query_set.distance(
location,
field_name='store__location'
Expand Down
11 changes: 9 additions & 2 deletions stores/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@ def get_current_ip(request):
ip = request.META.get('REMOTE_ADDR')
return ip


def get_geographic_srid():
try:
return settings.STORES_SRID
return settings.STORES_GEOGRAPHIC_SRID
except AttributeError:
raise ImproperlyConfigured(
"A geographic SRID is required for distance calculation in"
"kilometers, miles, etc."
)

def get_geodetic_srid():
try:
return settings.STORES_GEODETIC_SRID
except AttributeError:
raise ImproperlyConfigured(
"A geodetic SRID is required to use with the standard"
"latitude, longitude coordinates for locations"
)
35 changes: 19 additions & 16 deletions stores/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.contrib.gis.geos import GEOSGeometry

from stores.forms import StoreSearchForm
from stores.utils import get_geographic_srid
from stores.utils import get_geographic_srid, get_geodetic_srid


Store = get_model('stores', 'store')
Expand All @@ -15,25 +15,28 @@ class StoreListView(generic.ListView):
context_object_name = 'store_list'

def get_queryset(self):
qs = self.model.objects.filter(is_active=True)

if self.request.POST:
if self.request.POST['group']:
qs = qs.filter(group=self.request.POST['group'])

if self.request.POST['location']:
point = GEOSGeometry(self.request.POST['location'])
# save to session
self.request.session['request_location'] = point
qs = qs.transform(
get_geographic_srid()
).distance(point).order_by('distance')
return qs
queryset = self.model.objects.filter(is_active=True)

group = self.request.POST.get('group', None)
if group:
queryset = queryset.filter(group=group)

location = self.request.POST.get('location', None)
if location:
point = GEOSGeometry(location)
queryset = queryset.transform(
get_geographic_srid()
).distance(
point
).transform(
get_geodetic_srid()
).order_by('distance')
return queryset

def get_search_form(self):
if self.request.POST:
return StoreSearchForm(self.request.POST)
return StoreSearchForm
return StoreSearchForm()

def get_context_data(self, **kwargs):
ctx = super(StoreListView, self).get_context_data(**kwargs)
Expand Down
Empty file added tests/functional/__init__.py
Empty file.
69 changes: 69 additions & 0 deletions tests/functional/search_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from django.db.models import get_model
from django.core.urlresolvers import reverse

from django_dynamic_fixture import get as G
from oscar_testsupport.testcases import WebTestCase

Store = get_model("stores", "Store")
StoreGroup = get_model("stores", "StoreGroup")


class TestTheListOfStores(WebTestCase):
anonymous = True

def setUp(self):
super(TestTheListOfStores, self).setUp()
self.main_location = '{"type": "Point", "coordinates": [144.917908,-37.815751]}'
self.other_location = '{"type": "Point", "coordinates": [144.998401,-37.772895]}'

self.main_store = G(
Store,
name="Main store in Southbank",
is_pickup_store=True,
location=self.main_location,
ignore_fields=['group'],
)
self.other_store = G(
Store,
name="Other store in Northcote",
is_pickup_store=True,
location=self.other_location,
ignore_fields=['group'],
)

def test_displays_all_stores_unfiltered(self):
page = self.get(reverse('stores:index'))
self.assertContains(page, self.main_store.name)
self.assertContains(page, self.other_store.name)

def test_can_be_filtered_by_location(self):
page = self.get(reverse('stores:index'))
search_form = page.forms['store-search']
search_form['location'] = '{"type":"Point","coordinates":[144.9997396,-37.7736132]}'
page = search_form.submit()

self.assertContains(page, self.main_store.name)
self.assertContains(page, self.other_store.name)

stores = page.context[0].get('object_list')
self.assertSequenceEqual(stores, [self.other_store, self.main_store])

def test_can_be_filtered_by_store_group(self):
north_group = StoreGroup.objects.create(name="North")
south_group = StoreGroup.objects.create(name="South")

self.main_store.group = south_group
self.main_store.save()
self.other_store.group = north_group
self.other_store.save()

page = self.get(reverse('stores:index'))
search_form = page.forms['store-search']
search_form['group'] = south_group.id
page = search_form.submit()

self.assertContains(page, self.main_store.name)
self.assertNotContains(page, self.other_store.name)

stores = page.context[0].get('object_list')
self.assertSequenceEqual(stores, [self.main_store])
Loading

0 comments on commit 05798bf

Please sign in to comment.