Adding basic structure for recommended feeds.

This commit is contained in:
Samuel Clay 2011-02-28 23:27:58 -05:00
parent 6c8926d8bf
commit 8833dd793d
16 changed files with 398 additions and 34 deletions

View file

@ -17,6 +17,7 @@ from django.core.mail import mail_admins
from collections import defaultdict
from operator import itemgetter
from mongoengine.queryset import OperationError
from apps.recommendations.models import RecommendedFeed, RecommendedFeedUserFeedback
from apps.analyzer.models import MClassifierTitle, MClassifierAuthor, MClassifierFeed, MClassifierTag
from apps.analyzer.models import apply_classifier_titles, apply_classifier_feeds, apply_classifier_authors, apply_classifier_tags
from apps.analyzer.models import get_classifiers_for_user
@ -65,6 +66,9 @@ def index(request):
feed_count = UserSubscription.objects.filter(user=request.user).count()
active_count = UserSubscription.objects.filter(user=request.user, active=True).count()
train_count = UserSubscription.objects.filter(user=request.user, active=True, is_trained=False, feed__stories_last_month__gte=1).count()
recommended_feed = RecommendedFeed.objects.filter(is_public=True)[0]
recommended_feed_feedback = RecommendedFeedUserFeedback.objects.filter(recommendation=recommended_feed)
howitworks_page = random.randint(0, 5)
return render_to_response('reader/feeds.xhtml', {
@ -79,6 +83,8 @@ def index(request):
'active_count': active_count,
'train_count': active_count - train_count,
'account_images': range(1, 4),
'recommended_feed': recommended_feed,
'recommended_feed_feedback': recommended_feed_feedback,
}, context_instance=RequestContext(request))
@never_cache

View file

View file

@ -0,0 +1,105 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'RecommendedFeed'
db.create_table('recommendations_recommendedfeed', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('feed', self.gf('django.db.models.fields.related.ForeignKey')(related_name='recommendations', to=orm['rss_feeds.Feed'])),
('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='recommendations', to=orm['auth.User'])),
('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
('is_public', self.gf('django.db.models.fields.BooleanField')(default=False)),
('created_date', self.gf('django.db.models.fields.DateField')(auto_now_add=True, blank=True)),
('approved_date', self.gf('django.db.models.fields.DateField')(null=True)),
))
db.send_create_signal('recommendations', ['RecommendedFeed'])
def backwards(self, orm):
# Deleting model 'RecommendedFeed'
db.delete_table('recommendations_recommendedfeed')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'recommendations.recommendedfeed': {
'Meta': {'object_name': 'RecommendedFeed'},
'approved_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'created_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'feed': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'recommendations'", 'to': "orm['rss_feeds.Feed']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'recommendations'", 'to': "orm['auth.User']"})
},
'rss_feeds.feed': {
'Meta': {'ordering': "['feed_title']", 'object_name': 'Feed', 'db_table': "'feeds'"},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
'active_subscribers': ('django.db.models.fields.IntegerField', [], {'default': '-1', 'db_index': 'True'}),
'average_stories_per_month': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'creation': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'days_to_trim': ('django.db.models.fields.IntegerField', [], {'default': '90'}),
'etag': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'exception_code': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'feed_address': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '255'}),
'feed_link': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '1000', 'null': 'True', 'blank': 'True'}),
'feed_title': ('django.db.models.fields.CharField', [], {'default': "'[Untitled]'", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'fetched_once': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'has_feed_exception': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
'has_page_exception': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_load_time': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'last_modified': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'last_update': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
'min_to_decay': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'next_scheduled_update': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
'num_subscribers': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'premium_subscribers': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'queued_date': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
'stories_last_month': ('django.db.models.fields.IntegerField', [], {'default': '0'})
}
}
complete_apps = ['recommendations']

View file

@ -0,0 +1,111 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'RecommendedFeedUserFeedback'
db.create_table('recommendations_recommendedfeeduserfeedback', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('recommendation', self.gf('django.db.models.fields.related.ForeignKey')(related_name='feedback', to=orm['recommendations.RecommendedFeed'])),
('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='feed_feedback', to=orm['auth.User'])),
('score', self.gf('django.db.models.fields.IntegerField')(default=0)),
('created_date', self.gf('django.db.models.fields.DateField')(auto_now_add=True, blank=True)),
))
db.send_create_signal('recommendations', ['RecommendedFeedUserFeedback'])
def backwards(self, orm):
# Deleting model 'RecommendedFeedUserFeedback'
db.delete_table('recommendations_recommendedfeeduserfeedback')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'recommendations.recommendedfeed': {
'Meta': {'object_name': 'RecommendedFeed'},
'approved_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'created_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'feed': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'recommendations'", 'to': "orm['rss_feeds.Feed']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'recommendations'", 'to': "orm['auth.User']"})
},
'recommendations.recommendedfeeduserfeedback': {
'Meta': {'object_name': 'RecommendedFeedUserFeedback'},
'created_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'recommendation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'feedback'", 'to': "orm['recommendations.RecommendedFeed']"}),
'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'feed_feedback'", 'to': "orm['auth.User']"})
},
'rss_feeds.feed': {
'Meta': {'ordering': "['feed_title']", 'object_name': 'Feed', 'db_table': "'feeds'"},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
'active_subscribers': ('django.db.models.fields.IntegerField', [], {'default': '-1', 'db_index': 'True'}),
'average_stories_per_month': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'creation': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'days_to_trim': ('django.db.models.fields.IntegerField', [], {'default': '90'}),
'etag': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'exception_code': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'feed_address': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '255'}),
'feed_link': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '1000', 'null': 'True', 'blank': 'True'}),
'feed_title': ('django.db.models.fields.CharField', [], {'default': "'[Untitled]'", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'fetched_once': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'has_feed_exception': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
'has_page_exception': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_load_time': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'last_modified': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'last_update': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
'min_to_decay': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'next_scheduled_update': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
'num_subscribers': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'premium_subscribers': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'queued_date': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
'stories_last_month': ('django.db.models.fields.IntegerField', [], {'default': '0'})
}
}
complete_apps = ['recommendations']

View file

@ -0,0 +1,24 @@
from django.db import models
from django.contrib.auth.models import User
from apps.rss_feeds.models import Feed
class RecommendedFeed(models.Model):
feed = models.ForeignKey(Feed, related_name='recommendations')
user = models.ForeignKey(User, related_name='recommendations')
description = models.TextField(null=True, blank=True)
is_public = models.BooleanField(default=False)
created_date = models.DateField(auto_now_add=True)
approved_date = models.DateField(null=True)
def __unicode__(self):
return "%s (%s)" % (self.feed, self.approved_date or self.created_date)
class Meta:
ordering = ['-approved_date']
class RecommendedFeedUserFeedback(models.Model):
recommendation = models.ForeignKey(RecommendedFeed, related_name='feedback')
user = models.ForeignKey(User, related_name='feed_feedback')
score = models.IntegerField(default=0)
created_date = models.DateField(auto_now_add=True)

View file

@ -0,0 +1,10 @@
from django import template
register = template.Library()
@register.inclusion_tag('recommendations/render_recommended_feed.xhtml', takes_context=True)
def render_recommended_feed(context, recommended_feed):
return {
'recommended_feed': recommended_feed,
'user': context['user'],
}

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
"""}

View file

@ -0,0 +1 @@
# Create your views here.

Binary file not shown.

View file

@ -60,9 +60,23 @@
.NB-module h5 {
margin: 0;
padding: 8px 8px 6px;
background-color: #D9DDF9;
text-shadow: 0 1px 0 #F6F6F6;
border-bottom: 1px solid #A0A0A0;
background-color: #D1E1FA;
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0.16, #C5D7FB),
color-stop(0.84, #D8E1FF)
);
background-image: -moz-linear-gradient(
center bottom,
#C5D7FB 16%,
#D8E1FF 84%
);
text-shadow: 1px 1px 0 #E9E9E9;
border-top: 1px solid #D1DAF7;
border-bottom: 1px solid #A1A9CF;
color:#505050;
font-size: 14px;
font-family: "Gill Sans", inherit;

View file

@ -3114,7 +3114,7 @@ background: transparent;
width: 16px;
height: 16px;
float: left;
padding: 2px 3px 0px;
padding: 0 3px 0px;
}
.NB-module .NB-module-direction.NB-disabled {
@ -3170,6 +3170,39 @@ background: transparent;
/* = Main Page = */
/* ============= */
.NB-module a {
text-decoration: none;
/* color: #3E4773;*/
}
.NB-module a:hover {
/* color: #0E1763;*/
}
#NB-splash .NB-module h5 {
margin: 0 0 12px;
padding: 8px 12px 6px;
}
.NB-module .NB-module-header-left {
float: left;
}
.NB-module .NB-module-header-center {
text-align: center;
margin: 0 auto;
width: 132px;
}
.NB-module .NB-module-header-right {
font-size: 13px;
line-height: 16px;
font-weight: normal;
float: right;
}
/* =========================== */
/* = Right Modules - Account = */
/* =========================== */
.NB-account .NB-module {
margin: 24px 0 0;
padding: 0;
@ -3178,35 +3211,6 @@ background: transparent;
overflow: hidden;
}
.NB-account .NB-module a {
text-decoration: none;
/* color: #3E4773;*/
}
.NB-account .NB-module a:hover {
/* color: #0E1763;*/
}
.NB-account .NB-module h5 {
margin: 0 0 12px;
padding: 8px 12px 6px;
}
.NB-account .NB-module .NB-module-header-left {
float: left;
}
.NB-account .NB-module .NB-module-header-center {
text-align: center;
margin: 0 auto;
width: 132px;
}
.NB-account .NB-module .NB-module-header-right {
font-size: 13px;
line-height: 16px;
font-weight: normal;
float: right;
}
.NB-account .NB-module .NB-module-account {
position: relative;
min-height: 77px;
@ -3406,6 +3410,37 @@ background: transparent;
text-align: center;
}
/* ================== */
/* = Center Modules = */
/* ================== */
.NB-modules-center {
margin-left: 284px;
margin-right: 478px;
padding: 24px;
}
/* ============================ */
/* = Module: Recommended Feed = */
/* ============================ */
.NB-module-recommended {
}
.NB-module-recommended .NB-module-recommended-date {
line-height: 14px;
float: left;
color: #8493CD;
margin: 1px 2px 0 0;
text-shadow: 0 1px 0 #E9E9E9;
}
.NB-module-recommended .NB-module-recommended-date span {
vertical-align: text-top;
margin: 0 0 0 -3px;
font-size: 8px;
color: #8487C4;
}
/* ========= */
/* = Menus = */
/* ========= */

View file

@ -246,6 +246,7 @@ INSTALLED_APPS = (
'apps.analyzer',
'apps.feed_import',
'apps.profile',
'apps.recommendations',
'south',
'utils',
'utils.typogrify',

View file

@ -1,6 +1,6 @@
{% extends 'base.html' %}
{% load typogrify_tags %}
{% load typogrify_tags recommendations_tags %}
{% block content %}
@ -17,6 +17,10 @@ $(document).ready(function() {
<div id="NB-splash">
<div class="NB-modules-center">
{# {% render_recommended_feed recommended_feed %} #}
</div>
<div class="NB-account">
{% if not user.is_authenticated %}

View file

@ -0,0 +1,30 @@
<div class="NB-module-recommended NB-module">
<h5 class="NB-module-header">
Recommended Site
<div class="NB-module-header-right">
<div class="NB-module-recommended-date">
{{ recommended_feed.approved_date|date:"M j" }}
<span>{{ recommended_feed.approved_date|date:"S" }}</span>,
{{ recommended_feed.approved_date|date:"Y" }}
</div>
{% if user.is_staff %}
<div class="NB-module-recommended-add">
<a href="#" id="add-feature-button" class="NB-splash-link">Add</a>
</div>
<script>
$(document).ready(function() {
$('#add-feature-button').click(function(e) {
e.preventDefault();
$('#add-feature-form').fadeIn(500);
});
});
</script>
{% endif %}
<a href="#" class="NB-module-direction NB-module-previous-page NB-disabled"></a>
<a href="#" class="NB-module-direction NB-module-next-page"></a>
</div>
</h5>
<div class="NB-module-title">{{ recommended_feed.feed.feed_title }}</div>
{{ recommended_feed.feed.data.feed_tagline }}
</div>