Skip to content

Commit

Permalink
view tracking and search enhancements
Browse files Browse the repository at this point in the history
- track views on maps/layers by counting playback ticks

- show views in various results

- add more link to search results

- add some cached bulk functions for ratings/views
  • Loading branch information
ischneider committed May 24, 2012
1 parent e00f14c commit 5abf53e
Show file tree
Hide file tree
Showing 15 changed files with 185 additions and 32 deletions.
15 changes: 9 additions & 6 deletions media/script/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ Ext.onReady(function() {
var start = 0,
limit = 10,
loadnotify = Ext.get('loading'),
itemTemplate = "<li class='tile' id='item{iid}'><img class='thumb {thumbclass}' src='{thumb}'></img>" +
itemTemplate = "<li class='tile' id='item{iid}'><a href='{detail}'><img class='thumb {thumbclass}' src='{thumb}'></img></a>" +
"<div class='infoBox'><div class='itemTitle'><a href='{detail}'>{title}</a></div>" +
"<div class='itemInfo'>{_display_type}, by <a href='{owner_detail}'>{owner}</a> on {last_modified}</div>" +
"<div class='itemAbstract'>Abstract: {abstract}</div>"+
"<div class='rating'>{rating} stars</div>"+
"<div class='rating'>{views} Views | {rating} stars <span class='more'>More &#9656;</span></div>"+
"<div class='actions' id='{_type}-{id}'></div>"+
"</li>",
ownerTemplate = "<li class='tile' id='item{iid}'><img class='thumb {thumbclass}' src='{thumb}'></img>" +
Expand Down Expand Up @@ -94,7 +94,7 @@ Ext.onReady(function() {
click: handleSave
};
Ext.each(results.rows,function(r,i) {
var item;
var item, more;
if (r.thumb == null) {
r.thumb = static_url + "theme/img/silk/map.png";
r.thumbclass = "missing";
Expand All @@ -113,9 +113,12 @@ Ext.onReady(function() {
html: r['abstract']
});
}
item.select('.thumb').item(0).on('click',function(ev) {
expandTile(this.parent());
});
more = item.select('.more');
if (more.getCount()) {
more.item(0).on('click',function(ev) {
expandTile(this.parent('.tile'));
});
}
});
}

Expand Down
12 changes: 10 additions & 2 deletions media/theme/search.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
height: 173px;
width: auto;
}
#bigtile .more {
display: none;
}
#search_results #bigtile .infoBox {
float: right;
width: 333px;
Expand All @@ -72,11 +75,11 @@
background: #454238;
padding: 10px;
}
#favorites-container #searchForm {
#searchForm {
margin: 0;
padding: 0;
}
#favorites-container #searchForm input {
#searchForm input {
margin: 0;
padding: 0;
background: url("/static/theme/img/icons/search.png") no-repeat scroll 194px center #FFFFFF;
Expand All @@ -97,6 +100,11 @@
#favorites li btn {
margin-right: 5px;
}
.more {
float: right;
margin-right: 1em;
cursor: pointer;
}
.searchLinks li {
list-style: none;
}
Expand Down
14 changes: 9 additions & 5 deletions media/theme/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,10 @@ form#quicksearch {
font-size:13px;
}

#carousel .tile .views {
font-weight:bold;
.viewcnt i {
font-style: normal;
}

#carousel .arrow {
cursor: pointer;
top: 40%;
Expand Down Expand Up @@ -1046,6 +1047,8 @@ article h3 {
.video-actions.tabbable {
overflow:hidden;
margin-top: 10px;
clear: both;

}

.video-actions.tab-content {
Expand Down Expand Up @@ -1100,19 +1103,20 @@ article h3 {
color:#e26a13;
}

.video-actions .metrics {
.story-detail .metrics {
width:95px;
float:right;
text-align:right;
height:26px;
}

.video-actions .metrics .views {
.story-detail .metrics .viewcnt {
display:block;
font-size:9px;
font-weight:bold;
}

.video-actions .metrics .views i {
.story-detail .metrics .viewcnt i {
font-size:17px;
font-style:normal;
}
Expand Down
59 changes: 59 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
import random
import operator
import re
import logging
import time

from django.conf import settings
from django.core.cache import cache
from django.db import models
from django.db.models import Count
from django.db.models import signals
Expand All @@ -21,6 +24,15 @@
from geonode.maps.models import Map
from geonode.maps.models import Layer

from hitcount.models import HitCount
from agon_ratings.models import OverallRating
from agon_ratings.categories import RATING_CATEGORY_LOOKUP

_logger = logging.getLogger('mapstory.models')
def _debug(msg,*args):
_logger.debug(msg,*args)
_debug_enabled = _logger.isEnabledFor(logging.DEBUG)

'''Settings API - allow regular expressions to filter our layer name results'''
if hasattr(settings,'SIMPLE_SEARCH_EXCLUSIONS'):
_exclude_patterns = settings.SIMPLE_SEARCH_EXCLUSIONS
Expand All @@ -31,6 +43,53 @@ def filtered_layers():
return Layer.objects.exclude(_layer_name_filter)
Layer.objects.filtered = filtered_layers

def get_view_cnt_for(obj):
'''Provide cached access to view cnts'''
return get_view_cnts(type(obj)).get(obj.id,0)

def get_view_cnts(model):
'''Provide cached access to view counts for a given model.
The current approach is to cache all values. An alternate approach, should
there be too many, is to partition by 'id mod some bucket size'.
'''
key = 'view_cnt_%s' % model.__name__
cached = cache.get(key)
hit = True
if _debug_enabled:
ts = time.time()
if not cached:
hit = False
ctype = ContentType.objects.get_for_model(model)
hits = HitCount.objects.filter(content_type=ctype)
cached = dict([ (int(h.object_pk),h.hits) for h in hits])
cache.set(key,cached)
if _debug_enabled:
_debug('view cnts for %s in %s, cached: %s',model.__name__,time.time() - ts,hit)
return cached

def get_ratings(model):
'''cached results for an objects rating'''
key = 'overall_rating_%s' % model.__name__
results = cache.get(key)
if not results:
# this next big is some hacky stuff related to rankings
choice = model.__name__.lower()
category = RATING_CATEGORY_LOOKUP.get(
"%s.%s-%s" % (model._meta.app_label, model._meta.object_name, choice)
)
try:
ct = ContentType.objects.get_for_model(model)
ratings = OverallRating.objects.filter(
content_type = ct,
category = category
)
results = dict([ (r.object_id, r.rating) or 0 for r in ratings])
cache.set(key, results)
except OverallRating.DoesNotExist:
return {}
return results


class SectionManager(models.Manager):
def sections_with_maps(self):
'''@todo this is broken - Get only those sections that have maps'''
Expand Down
5 changes: 5 additions & 0 deletions settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@
'django.contrib.webdesign',
'django.contrib.staticfiles',
'django_extensions',
'hitcount',
'registration',
'profiles',
'avatar',
Expand Down Expand Up @@ -299,6 +300,10 @@ def get_user_url(u):

AVATAR_DEFAULT_URL = "theme/img/storyteller.png"

HITCOUNT_KEEP_HIT_ACTIVE = { 'days': 1 }
HITCOUNT_HITS_PER_IP_LIMIT = 0
HITCOUNT_EXCLUDE_USER_GROUP = ( 'Editor', )

try:
from local_settings import *
except ImportError:
Expand Down
8 changes: 8 additions & 0 deletions templates/fullscreen.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
{% extends 'geonode/templates/fullscreen.html' %}
{% load mapstory_tags %}

{% block head %}
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}theme/geonode.css" />
{{ block.super }}
<script type="text/javascript">
{# hitcount library uses jquery, but core.js is not loaded for this page, so... #}
$(document).ajaxSend(function(event, xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", Ext.util.Cookies.get('csrftoken'));
});
</script>
{% map_view_hitcount_tracker request map %}
{% endblock %}
2 changes: 1 addition & 1 deletion templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
</li>
<li>
<div class="icn-storytellers">MapStoryTellers</div>
<a class="search noi" href="">SEARCH STORYTELLERS</a>
<a class="search" href="{% url search_owners %}">SEARCH STORYTELLERS</a>
<a class="action noi" href="">SIGN UP</a>
</li>
</ul>
Expand Down
37 changes: 37 additions & 0 deletions templates/maps/_widget_hitcount.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{% load hitcount_tags %}
<script type="text/javascript">
Ext.onReady(function() {
var tracker = false;
function checkload() {
var i, control, tickcnt = 0;
if (tracker) return;
for (i in app.mapPanel.map.controls) {
control = app.mapPanel.map.controls[i];
if (control.CLASS_NAME == "OpenLayers.Control.TimeManager") {
loaded = true;
tracker = function(ev) {
tickcnt++;
if (tickcnt == 3) {
{% get_hit_count_javascript for obj %}
control.events.unregister('tick',null,tracker);
}
}
control.events.register('tick',null,tracker);
return;
}
}
}
function listen() {
app.mapPanel.map.events.register("addlayer",null,function(ev) {
ev.layer.events.register("loadend",null,function(ev) {
checkload();
});
});
}
if (app.mapPanel) {
listen();
} else {
app.on("portalready",listen);
}
});
</script>
12 changes: 7 additions & 5 deletions templates/maps/layer.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ <h2 class="icn-storylayers">{{ layer.title }}</h2>
<div class="box mrg-btm describe-object">
<div class="story-detail">
<div id="preview_map"></div>

<div class="metrics">
{% map_view_hitcount layer %}
{% overall_rating layer "layer" as layer_rating %}
<span class="overall_rating" data-rating="{{ layer_rating }}"></span>
</div>
<div class="video-actions tabbable">
<ul class="actions-links nav nav-tabs fancyfont">
<li><a href="#describemap" class="icn info active" data-toggle="pill">Info</a></li>
Expand All @@ -145,10 +149,7 @@ <h2 class="icn-storylayers">{{ layer.title }}</h2>
<li><a href="#actions5" class="icn add" data-toggle="pill">Add</a></li>
<li><a href="#actions6" class="icn download" data-toggle="pill">Download</a></li>
</ul>
<div class="metrics">
{% overall_rating layer "layer" as layer_rating %}
<span class="overall_rating" data-rating="{{ layer_rating }}"></span>
</div>

</div>
<div class="video-actions tab-content">
<div class="tab-pane" id="describemap">
Expand Down Expand Up @@ -281,4 +282,5 @@ <h2>USING THIS STORYLAYER</h2>
})();
</script>
{% include "_fb_include.html" %}
{% map_view_hitcount_tracker request layer %}
{% endblock %}
12 changes: 7 additions & 5 deletions templates/maps/mapinfo.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ <h2 class="icn-storylayers">{{ map.title }}</h2>
<div class="box mrg-btm describe-object">
<div class="story-detail">
<div id="embedded_map"></div>

<div class="metrics">
{% map_view_hitcount map %}
{% overall_rating map "map" as map_rating %}
<span class="overall_rating" data-rating="{{ map_rating }}"></span>
</div>
<div class="video-actions tabbable">
<ul class="actions-links nav nav-tabs fancyfont">
<li><a href="#describemap" class="icn info active" data-toggle="pill">Info</a></li>
Expand All @@ -79,10 +83,7 @@ <h2 class="icn-storylayers">{{ map.title }}</h2>
<li><a href="#actions4" class="icn flag" data-toggle="pill">Flag</a></li>
<li><a href="#actions5" class="icn add" data-toggle="pill">Add</a></li>
</ul>
<div class="metrics">
{% overall_rating map "map" as map_rating %}
<span class="overall_rating" data-rating="{{ map_rating }}"></span>
</div>

</div>
<div class="video-actions tab-content">
<div class="tab-pane" id="describemap">
Expand Down Expand Up @@ -197,4 +198,5 @@ <h2>RELATED MAPSTORIES</h2>
})();
</script>
{% include "_fb_include.html" %}
{% map_view_hitcount_tracker request map %}
{% endblock %}
4 changes: 2 additions & 2 deletions templates/mapstory/_story_tile.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</div>
</div>
<footer>
{% overall_rating map "map" as map_rating %}
<span class="rating">{{ map_rating }} stars</span>
{% overall_rating map "map" as map_rating %}
{% map_view_hitcount map %}&nbsp;|&nbsp;<span class="rating">{{ map_rating }} stars</span>
</footer>
</div>
2 changes: 1 addition & 1 deletion templates/mapstory/_story_tile_left.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ <h6><a href="{{ map.get_absolute_url }}">{{map.title}}</a></h6>
<time pubdate datetime="{{ when|date:"Y-m-d" }}">on {{ when|date:"N j Y" }}</time>
<footer>
{% overall_rating map "map" as map_rating %}
<span class="rating">{{ map_rating }} stars</span>
{% map_view_hitcount map %}&nbsp;|&nbsp;<span class="rating">{{ map_rating }} stars</span>
</footer>
</div>
</article>
4 changes: 2 additions & 2 deletions templates/simplesearch/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,12 @@ <h3>Who</h3>
<form id="sortForm">
<strong>sort by</strong>
<select name="sortby">
<option disabled="true" value="relevance">Relevance</option>
<!-- <option disabled="true" value="relevance">Relevance</option>-->
<option value="newest" selected="true">Newest</option>
<option value="oldest">Oldest</option>
<option value="alphaaz">Alphabetical (A-Z)</option>
<option value="alphaza">Alphabetical (Z-A)</option>
<option disabled="true" value="popularity">Popularity</option>
<option value="popularity">Popularity</option>
</select>
</form>
<div id="search_results"><ul></ul><div class="clearfix"></div></div>
Expand Down
Loading

0 comments on commit 5abf53e

Please sign in to comment.