# HG changeset patch # User Brian Neal # Date 1285437884 0 # Node ID 4532ed27bed83d2bc8bc1607652d3cf34520679b # Parent 1ba2c6bf6eb77304df5851b61684226a846520b1 Fixing #112. Rework member map to untangle user profile and avatar cache from the membermap (since it wasn't really working anyway). diff -r 1ba2c6bf6eb7 -r 4532ed27bed8 gpp/membermap/__init__.py --- a/gpp/membermap/__init__.py Fri Sep 24 02:12:09 2010 +0000 +++ b/gpp/membermap/__init__.py Sat Sep 25 18:04:44 2010 +0000 @@ -1,1 +0,0 @@ -import membermap.signals diff -r 1ba2c6bf6eb7 -r 4532ed27bed8 gpp/membermap/admin.py --- a/gpp/membermap/admin.py Fri Sep 24 02:12:09 2010 +0000 +++ b/gpp/membermap/admin.py Sat Sep 25 18:04:44 2010 +0000 @@ -7,7 +7,7 @@ from membermap.models import MapEntry class MapEntryAdmin(admin.ModelAdmin): - exclude = ('json', ) + exclude = ('html', ) list_display = ('user', 'location', 'lat', 'lon', 'date_updated') list_filter = ('date_updated', ) date_hierarchy = 'date_updated' diff -r 1ba2c6bf6eb7 -r 4532ed27bed8 gpp/membermap/models.py --- a/gpp/membermap/models.py Fri Sep 24 02:12:09 2010 +0000 +++ b/gpp/membermap/models.py Sat Sep 25 18:04:44 2010 +0000 @@ -1,11 +1,9 @@ """ Models for the member map application. """ +import datetime from django.db import models from django.contrib.auth.models import User -from django.template.loader import render_to_string -from django.template.defaultfilters import escapejs -import django.utils.simplejson as json from core.markup import site_markup @@ -17,25 +15,18 @@ lat = models.FloatField() lon = models.FloatField() message = models.TextField(blank=True) - json = models.TextField(blank=True) - date_updated = models.DateTimeField(auto_now_add=True) + html = models.TextField(blank=True) + date_updated = models.DateTimeField() def __unicode__(self): - return u'Entry for %s' % self.user.username + return u'Map entry for %s' % self.user.username class Meta: ordering = ('-date_updated', ) verbose_name_plural = 'map entries' def save(self, *args, **kwargs): - msg = render_to_string('membermap/markdown.html', { - 'user': self.user, - 'msg': site_markup(self.message)}).strip() - - self.json = json.dumps({'name': self.user.username, - 'lat': '%10.6f' % self.lat, - 'lon': '%10.6f' % self.lon, - 'message': msg, - }) + self.html = site_markup(self.message) + self.date_updated = datetime.datetime.now() super(MapEntry, self).save(*args, **kwargs) diff -r 1ba2c6bf6eb7 -r 4532ed27bed8 gpp/membermap/signals.py --- a/gpp/membermap/signals.py Fri Sep 24 02:12:09 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -""" -Signal handlers for the membermap application. -We want to detect changes to the UserProfile model. If that person is on -the map, re-save her MapEntry so that any avatar changes get picked up. -""" -from django.db.models.signals import post_save -from bio.models import UserProfile -from membermap.models import MapEntry - - -def on_profile_save(sender, **kwargs): - if 'instance' in kwargs: - profile = kwargs['instance'] - try: - map_entry = MapEntry.objects.get(user=profile.user) - except MapEntry.DoesNotExist: - # Not on the map, no harm, no foul - return - if map_entry is not None: - map_entry.save() - - -post_save.connect(on_profile_save, - sender=UserProfile, - dispatch_uid='membermap.signals') diff -r 1ba2c6bf6eb7 -r 4532ed27bed8 gpp/membermap/views.py --- a/gpp/membermap/views.py Fri Sep 24 02:12:09 2010 +0000 +++ b/gpp/membermap/views.py Sat Sep 25 18:04:44 2010 +0000 @@ -2,14 +2,21 @@ Views for the membermap application. """ from django.shortcuts import render_to_response +from django.template.loader import render_to_string from django.template import RequestContext from django.http import HttpResponse from django.http import HttpResponseBadRequest from django.http import HttpResponseForbidden from django.views.decorators.http import require_POST +import django.utils.simplejson as json +from django.core.cache import cache from membermap.models import MapEntry from membermap.forms import MapEntryForm +from bio.models import UserProfile + +CACHE_KEY = 'membermap_json' +CACHE_TIMEOUT = 5 * 60 def index(request): @@ -39,16 +46,51 @@ "users" : array of user objects "recent" : array of usernames recently modified """ - if request.user.is_authenticated(): - qs = MapEntry.objects.values_list('json', flat=True).order_by('user__username') - s = '{"users":[' + ','.join(qs) + '], "recent":[' + if not request.user.is_authenticated(): + return HttpResponseForbidden('You must be logged in.') - names = MapEntry.objects.values_list('user__username', flat=True)[:10] - s += ','.join(['"%s"' % name for name in names]) - s += ']}' + # Do we have all the JSON cached? + s = cache.get(CACHE_KEY) + if s: return HttpResponse(s, content_type='application/json') - return HttpResponseForbidden('You must be logged in.') + # Compute JSON for the map + entries = MapEntry.objects.all().select_related().order_by('user__username') + users = [] + user_ids = [] + recent = [] + for entry in entries.iterator(): + users.append(dict(name=entry.user.username, + lat=entry.lat, + lon=entry.lon, + message=entry.html, + )) + user_ids.append(entry.user.id) + recent.append((entry.date_updated, entry.user.username)) + + # Get avatars for all users + profiles = UserProfile.objects.filter(user__in=user_ids).select_related() + avatars = {} + for profile in profiles.iterator(): + if profile.avatar and profile.avatar.url: + avatars[profile.user.username] = profile.avatar.url + + # Render the messages that go in the balloons + for user in users: + user['message'] = render_to_string('membermap/balloon.html', + dict(user=user, avatar_url=avatars.get(user['name']))) + + # Produce the list of recent updates + recent.sort(reverse=True) + del recent[10:] + recent = [entry[1] for entry in recent] + + # Create the JSON for the map + result = dict(users=users, recent=recent) + s = json.dumps(result, ensure_ascii=False) + + cache.set(CACHE_KEY, s, CACHE_TIMEOUT) + return HttpResponse(s, content_type='application/json') @require_POST @@ -85,7 +127,23 @@ entry.message = msg entry.save() - return HttpResponse(entry.json, content_type='application/json') + cache.delete(CACHE_KEY) + + avatar_url = None + profile = entry.user.get_profile() + if profile.avatar and profile.avatar.url: + avatar_url = profile.avatar.url + + u = dict(name=entry.user.username, + lat=entry.lat, + lon=entry.lon, + message=entry.html) + + u['message'] = render_to_string('membermap/balloon.html', + dict(user=u, avatar_url=avatar_url)) + + result = json.dumps(u, ensure_ascii=False) + return HttpResponse(result, content_type='application/json') @require_POST @@ -102,7 +160,6 @@ pass else: entry.delete() + cache.delete(CACHE_KEY) return HttpResponse('') - -# vim: ts=4 sw=4 diff -r 1ba2c6bf6eb7 -r 4532ed27bed8 gpp/templates/membermap/balloon.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/templates/membermap/balloon.html Sat Sep 25 18:04:44 2010 +0000 @@ -0,0 +1,6 @@ +{% if avatar_url %} + +{{ user.name }} +{% endif %} +{{ user.name }}:
+{{ user.message|safe }}