changeset 827:5103edd3acc4

Bandmap: initial version complete. Javascript queries server for band data. View created to handle query. Test created for view. Link added to map in sidebar. Template tweaks.
author Brian Neal <bgneal@gmail.com>
date Sat, 27 Sep 2014 19:41:41 -0500
parents d7e4c08b2e8b
children d02e8d7a0bcd
files bandmap/admin.py bandmap/static/css/bandmap.css bandmap/static/js/bandmap.js bandmap/tests/test_views.py bandmap/urls.py bandmap/views.py sg101/templates/bandmap/add.html sg101/templates/bandmap/balloon.html sg101/templates/bandmap/map.html sg101/templates/base.html
diffstat 10 files changed, 208 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/bandmap/admin.py	Sat Sep 27 15:14:47 2014 -0500
+++ b/bandmap/admin.py	Sat Sep 27 19:41:41 2014 -0500
@@ -21,7 +21,7 @@
     readonly_fields = ['lat', 'lon']
     search_fields = ['name', 'location', 'note']
     raw_id_fields = ['user']
-    actions = ['approve_bands', 'update_location']
+    actions = ['update_location', 'approve_bands']
 
     def approve_bands(self, request, qs):
         """This admin action awards a map pin to the user who added the band.
@@ -31,10 +31,12 @@
         count = qs.count()
         now = datetime.datetime.now()
         for band in qs:
-            bio.badges.award_badge(bio.badges.MAP_PIN, band.user)
-            band.date_approved = now
-            band.is_approved = True
-            band.save()
+            if not band.is_approved:
+                if band.date_approved is None:
+                    bio.badges.award_badge(bio.badges.MAP_PIN, band.user)
+                band.date_approved = now
+                band.is_approved = True
+                band.save()
 
         self.message_user(request, "%d band(s) approved." % count)
 
--- a/bandmap/static/css/bandmap.css	Sat Sep 27 15:14:47 2014 -0500
+++ b/bandmap/static/css/bandmap.css	Sat Sep 27 19:41:41 2014 -0500
@@ -4,3 +4,6 @@
    border: 1px solid black;
    margin: 0 auto;
 }
+#map-info {
+   margin-top: 2em;
+}
--- a/bandmap/static/js/bandmap.js	Sat Sep 27 15:14:47 2014 -0500
+++ b/bandmap/static/js/bandmap.js	Sat Sep 27 19:41:41 2014 -0500
@@ -1,5 +1,11 @@
 var bandmap = null;
 var geocoder = null;
+var surfbands = [];
+var map_options = {
+   center: {lat: 15.0, lng: -30.0},
+   zoom: 2
+};
+var info_win = null;
 
 function addBandOnSubmit(event) {
    var location = $('#id_location').val();
@@ -26,14 +32,54 @@
    return false;
 }
 
+
+function refreshMap() {
+   bandmap.setOptions(map_options);
+   $.each(surfbands, function(i, band) {
+      band.marker.setMap(null);
+   });
+   surfbands.length = 0;
+   var band_sel = $('#map-bands');
+   band_sel[0].length = 0;
+   band_sel.append($('<option>', {value: -1}).html('(select)'));
+   var count_span = $('#map-band-count');
+   count_span.html('0');
+   var filter = $('#map-filter option:selected').val();
+
+   $.getJSON('/bandmap/query/', {show: filter},
+         function(data) {
+            $.each(data, function(i, band) {
+               band_sel.append($('<option>', {value: i, text: band.name}));
+               var marker = new google.maps.Marker({
+                  position: {lat: band.lat, lng: band.lon},
+                  title: band.name,
+                  map: bandmap
+               });
+               google.maps.event.addListener(marker, 'click', function() {
+                  info_win.setContent(band.note);
+                  info_win.open(bandmap, marker);
+               });
+               surfbands[i] = band;
+               surfbands[i].marker = marker;
+            });
+            count_span.html(data.length);
+         });
+}
+
 $(document).ready(function() {
    var map_div = $('#map-canvas');
    if (map_div.length) {
-      var map_options = {
-         center: {lat: 15.0, lng: -30.0},
-         zoom: 2
-      };
       bandmap = new google.maps.Map(map_div[0], map_options);
+      info_win = new google.maps.InfoWindow();
+      $('#map-filter-go').click(refreshMap);
+      $('#map-bands').change(function() {
+         var n = $('option:selected', this).val();
+         if (n != -1) {
+            info_win.setContent(surfbands[n].note);
+            info_win.open(bandmap, surfbands[n].marker);
+         }
+      });
+      refreshMap();
    }
 
    var add_form = $('#bandmap-add-form');
--- a/bandmap/tests/test_views.py	Sat Sep 27 15:14:47 2014 -0500
+++ b/bandmap/tests/test_views.py	Sat Sep 27 19:41:41 2014 -0500
@@ -3,6 +3,7 @@
 
 """
 import datetime
+import json
 
 from django.test import TestCase
 from django.core.urlresolvers import reverse
@@ -81,3 +82,74 @@
         self.assertEqual(entry.note, post_data['note'])
         self.assertTrue(entry.is_active)
         self.assertFalse(entry.is_approved)
+
+class QueryTestCase(TestCase):
+    """Testing the query view function which returns JSON."""
+
+    def setUp(self):
+        self.user = User.objects.create_user(
+            username='pj', email='pj@example.com', password='top_secret')
+
+        now = datetime.datetime.now()
+
+        kwargs = {
+            'name': 'Test Band 1',
+            'user': self.user,
+            'date_submitted': now,
+            'date_approved': now,
+            'url': 'http://example.com',
+            'location': 'Somewhere',
+            'lat': 42.0,
+            'lon': -30.0,
+            'note': 'Some text here',
+            'is_active': True,
+            'is_approved': True,
+        }
+        BandEntry.objects.create(**kwargs)
+
+        kwargs['name'] = 'Test Band 2'
+        kwargs['is_active'] = False
+        BandEntry.objects.create(**kwargs)
+
+        kwargs['name'] = 'Test Band 3'
+        kwargs['is_active'] = True
+        kwargs['is_approved'] = False
+        BandEntry.objects.create(**kwargs)
+
+    def test_query(self):
+        url = reverse('bandmap-query')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+
+        result = json.loads(response.content)
+        self.assertEqual(len(result), 2)
+        self.assertEqual(result[0]['name'], 'Test Band 1')
+        self.assertEqual(result[1]['name'], 'Test Band 2')
+
+    def test_query_all(self):
+        url = reverse('bandmap-query')
+        response = self.client.get(url, {'show': 'all'})
+        self.assertEqual(response.status_code, 200)
+
+        result = json.loads(response.content)
+        self.assertEqual(len(result), 2)
+        self.assertEqual(result[0]['name'], 'Test Band 1')
+        self.assertEqual(result[1]['name'], 'Test Band 2')
+
+    def test_query_active(self):
+        url = reverse('bandmap-query')
+        response = self.client.get(url, {'show': 'active'})
+        self.assertEqual(response.status_code, 200)
+
+        result = json.loads(response.content)
+        self.assertEqual(len(result), 1)
+        self.assertEqual(result[0]['name'], 'Test Band 1')
+
+    def test_query_inactive(self):
+        url = reverse('bandmap-query')
+        response = self.client.get(url, {'show': 'inactive'})
+        self.assertEqual(response.status_code, 200)
+
+        result = json.loads(response.content)
+        self.assertEqual(len(result), 1)
+        self.assertEqual(result[0]['name'], 'Test Band 2')
--- a/bandmap/urls.py	Sat Sep 27 15:14:47 2014 -0500
+++ b/bandmap/urls.py	Sat Sep 27 19:41:41 2014 -0500
@@ -8,4 +8,7 @@
     url(r'^add/$',
         'bandmap.views.add_band',
         name='bandmap-add'),
+    url(r'^query/$',
+        'bandmap.views.query',
+        name='bandmap-query'),
 )
--- a/bandmap/views.py	Sat Sep 27 15:14:47 2014 -0500
+++ b/bandmap/views.py	Sat Sep 27 19:41:41 2014 -0500
@@ -1,11 +1,17 @@
 """Views for the bandmap application.
 
 """
+import json
+
 from django.contrib.auth.decorators import login_required
 from django.shortcuts import redirect, render
 from django.contrib import messages as django_messages
+from django.http import HttpResponse
+from django.template.loader import render_to_string
+from django.core.cache import cache
 
 from bandmap.forms import BandForm
+from bandmap.models import BandEntry
 
 
 SUCCESS = "Successfully submitted {} for admin review. Thanks!"
@@ -35,3 +41,41 @@
     return render(request, 'bandmap/add.html', {
         'form': form,
         })
+
+
+def query(request):
+    """Retrieves the band map entries and returns them as JSON.
+
+    """
+    show_param = request.GET.get('show', 'all')
+    if show_param not in ['all', 'active', 'inactive']:
+        show_param = 'all'
+
+    # Do we have the results cached already?
+    cache_key = 'bandmap-results-{}'.format(show_param)
+    results = cache.get(cache_key)
+    if results:
+        return HttpResponse(results, content_type='application/json')
+
+    # Generate results
+    qs = BandEntry.objects.filter(is_approved=True)
+    if show_param == 'active':
+        qs = qs.filter(is_active=True)
+    elif show_param == 'inactive':
+        qs = qs.filter(is_active=False)
+
+    bands = []
+    for band in qs.iterator():
+        bands.append({
+            'name': band.name,
+            'url': band.url,
+            'lat': band.lat,
+            'lon': band.lon,
+            'note': render_to_string('bandmap/balloon.html', {'band': band}),
+        })
+    results = json.dumps(bands)
+
+    # Store in cache
+    cache.set(cache_key, results, 300)
+
+    return HttpResponse(results, content_type='application/json')
--- a/sg101/templates/bandmap/add.html	Sat Sep 27 15:14:47 2014 -0500
+++ b/sg101/templates/bandmap/add.html	Sat Sep 27 19:41:41 2014 -0500
@@ -40,4 +40,5 @@
 </tr>
 </table>
 </form>
+<p>Back to the <a href="{% url 'bandmap-map' %}">surf band map</a>.</p>
 {% endblock %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sg101/templates/bandmap/balloon.html	Sat Sep 27 19:41:41 2014 -0500
@@ -0,0 +1,15 @@
+<div class="band-balloon">
+{% if band.url %}
+<strong><a href="{{ band.url }}">{{ band.name }}</a></strong>
+{% else %}
+<strong>{{ band.name }}</strong>
+{% endif %}
+<em>
+{% if band.is_active %}
+(Active)
+{% else %}
+(Inactive)
+{% endif %}
+</em><br />
+{{ band.note }}
+</div>
--- a/sg101/templates/bandmap/map.html	Sat Sep 27 15:14:47 2014 -0500
+++ b/sg101/templates/bandmap/map.html	Sat Sep 27 19:41:41 2014 -0500
@@ -3,5 +3,16 @@
 <p>Welcome to our surf band map! This map is updated by our users and displays
 the locations of both active and inactive surf bands from around the world.</p>
 <div id="map-canvas"></div>
-<p><a href="{% url 'bandmap-add' %}">Add a band to the map</a>.
+<div id="map-info">
+   <ul>
+      <li>Number of bands: <span id="map-band-count">0</span></li>
+      <li>Bands: <select id="map-bands"></select></li>
+      <li>Show: <select id="map-filter">
+                  <option value="all">all bands</option>
+                  <option value="active">active bands</option>
+                  <option value="inactive">inactive bands</option>
+               </select> <button id="map-filter-go">Go</button></li>
+      <li><a href="{% url 'bandmap-add' %}">Add a band to the map</a></li>
+   </ul>
+</div>
 {% endblock %}
--- a/sg101/templates/base.html	Sat Sep 27 15:14:47 2014 -0500
+++ b/sg101/templates/base.html	Sat Sep 27 19:41:41 2014 -0500
@@ -60,6 +60,7 @@
       <li><a href="{% url 'weblinks-main' %}">Links</a></li>
       <li><a href="{% url 'haystack_search' %}">Search</a></li>
       <li><a href="/store/">Store</a></li>
+      <li><a href="{% url 'bandmap-map' %}">Surf Band Map</a></li>
       <li><a href="http://wiki.surfguitar101.com">Wiki</a></li>
       <li><a href="{% url 'ygroup-thread_index' %}">Yahoo Group</a></li>
    </ul>