aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemsen2012-03-27 23:15:04 +0200
committerGravatar Tom Willemsen2012-03-27 23:15:04 +0200
commit39b95ff93cc1e836c8c6b2f205a90b937898d7ca (patch)
tree44c2b5ecaebd3b4e1278b691d76b1cf0e794ef6e
parentc54880b03f9732cf659d2b143165fd54bd7f3383 (diff)
parentd959e7dc954553913f66fe133a80e3e9f7d63bd8 (diff)
downloadryuslash.org-39b95ff93cc1e836c8c6b2f205a90b937898d7ca.tar.gz
ryuslash.org-39b95ff93cc1e836c8c6b2f205a90b937898d7ca.zip
Merge branch 'categories'
Conflicts: static/main.css
-rw-r--r--aggregator/fixtures/initial_data.json35
-rw-r--r--aggregator/management/commands/loadfeeds.py18
-rw-r--r--aggregator/migrations/0003_auto__add_category.py70
-rw-r--r--aggregator/models.py10
-rw-r--r--aggregator/views.py20
-rw-r--r--requirements.txt4
-rw-r--r--static/main.css15
-rw-r--r--templates/aggregator/base.html8
-rw-r--r--templates/aggregator/posts.html6
-rw-r--r--urls.py5
10 files changed, 163 insertions, 28 deletions
diff --git a/aggregator/fixtures/initial_data.json b/aggregator/fixtures/initial_data.json
index cb4ab5e..a07594b 100644
--- a/aggregator/fixtures/initial_data.json
+++ b/aggregator/fixtures/initial_data.json
@@ -1,5 +1,19 @@
[
{
+ "model": "aggregator.Category",
+ "pk": 1,
+ "fields": {
+ "name": "posts"
+ }
+ },
+ {
+ "model": "aggregator.Category",
+ "pk": 2,
+ "fields": {
+ "name": "activity"
+ }
+ },
+ {
"model": "aggregator.Feed",
"pk": 1,
"fields": {
@@ -7,7 +21,8 @@
"base_url": "http://www.advogato.org/",
"feed_url": "person/ryuslash/rss.xml",
"profile_url": "person/ryuslash",
- "favicon_ext": "ico"
+ "favicon_ext": "ico",
+ "categories": [ 1 ]
}
},
{
@@ -19,7 +34,8 @@
"feed_url": "public/ryuslash.atom",
"profile_url": "public/ryuslash",
"br2nl": true,
- "with_markdown": true
+ "with_markdown": true,
+ "categories": [ 1 ]
}
},
{
@@ -30,7 +46,8 @@
"base_url": "http://identi.ca/",
"feed_url": "api/statuses/user_timeline/107950.rss",
"profile_url": "ryuslash",
- "favicon_ext": "ico"
+ "favicon_ext": "ico",
+ "categories": [ 1 ]
}
},
{
@@ -40,7 +57,8 @@
"name": "Github",
"base_url": "https://github.com/",
"feed_url": "ryuslash.atom",
- "profile_url": "ryuslash"
+ "profile_url": "ryuslash",
+ "categories": [ 2 ]
}
},
{
@@ -50,7 +68,8 @@
"name": "Gitorious",
"base_url": "https://gitorious.org/",
"feed_url": "~ryuslash/feed.atom",
- "profile_url": "~ryuslash"
+ "profile_url": "~ryuslash",
+ "categories": [ 2 ]
}
},
{
@@ -60,7 +79,8 @@
"name": "Ikiwiki",
"base_url": "http://ryuslash.org/wiki/",
"feed_url": "index.rss",
- "uses_title": true
+ "uses_title": true,
+ "categories": [ 1 ]
}
},
{
@@ -72,7 +92,8 @@
"feed_url": "user/ryuslash/.rss",
"profile_url": "usr/ryuslash/",
"uses_title": true,
- "favicon_ext": "ico"
+ "favicon_ext": "ico",
+ "categories": [ 1 ]
}
},
{
diff --git a/aggregator/management/commands/loadfeeds.py b/aggregator/management/commands/loadfeeds.py
index 04316b3..2bee069 100644
--- a/aggregator/management/commands/loadfeeds.py
+++ b/aggregator/management/commands/loadfeeds.py
@@ -20,13 +20,15 @@ class Command(BaseCommand):
for entry in parsed.entries:
if not Post.objects.filter(post_id=entry.id).exists():
- updated = datetime.datetime(
- entry.updated_parsed.tm_year,
- entry.updated_parsed.tm_mon,
- entry.updated_parsed.tm_mday,
- entry.updated_parsed.tm_hour,
- entry.updated_parsed.tm_min,
- entry.updated_parsed.tm_sec)
+ dt = entry.updated_parsed \
+ or entry.published_parsed
+
+ if dt:
+ updated = datetime.datetime(
+ dt.tm_year, dt.tm_mon, dt.tm_mday,
+ dt.tm_hour, dt.tm_min, dt.tm_sec)
+ else:
+ updated = datetime.datetime.now()
post = Post(post_id=entry.id,
title=entry.title,
@@ -38,7 +40,7 @@ class Command(BaseCommand):
content = entry.content[0]['value']
else:
content = entry.summary
-
+
if feed.with_markdown:
post.body = markdown.markdown(content)
else:
diff --git a/aggregator/migrations/0003_auto__add_category.py b/aggregator/migrations/0003_auto__add_category.py
new file mode 100644
index 0000000..9997320
--- /dev/null
+++ b/aggregator/migrations/0003_auto__add_category.py
@@ -0,0 +1,70 @@
+# 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 'Category'
+ db.create_table('aggregator_category', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.SlugField')(max_length=50, db_index=True)),
+ ))
+ db.send_create_signal('aggregator', ['Category'])
+
+ # Adding M2M table for field categories on 'Feed'
+ db.create_table('aggregator_feed_categories', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('feed', models.ForeignKey(orm['aggregator.feed'], null=False)),
+ ('category', models.ForeignKey(orm['aggregator.category'], null=False))
+ ))
+ db.create_unique('aggregator_feed_categories', ['feed_id', 'category_id'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Category'
+ db.delete_table('aggregator_category')
+
+ # Removing M2M table for field categories on 'Feed'
+ db.delete_table('aggregator_feed_categories')
+
+
+ models = {
+ 'aggregator.category': {
+ 'Meta': {'object_name': 'Category'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'})
+ },
+ 'aggregator.feed': {
+ 'Meta': {'ordering': "['-updated']", 'object_name': 'Feed'},
+ 'base_url': ('django.db.models.fields.URLField', [], {'max_length': '255'}),
+ 'br2nl': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['aggregator.Category']", 'symmetrical': 'False'}),
+ 'favicon_ext': ('django.db.models.fields.CharField', [], {'default': "'png'", 'max_length': '4'}),
+ 'feed_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'profile_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '500', 'blank': 'True'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'uses_title': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'with_markdown': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'aggregator.post': {
+ 'Meta': {'ordering': "['-updated']", 'object_name': 'Post'},
+ 'added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'feed': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['aggregator.Feed']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'remote_url': ('django.db.models.fields.URLField', [], {'max_length': '255'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
+ }
+ }
+
+ complete_apps = ['aggregator']
diff --git a/aggregator/models.py b/aggregator/models.py
index b5c4f3c..4936821 100644
--- a/aggregator/models.py
+++ b/aggregator/models.py
@@ -1,5 +1,11 @@
from django.db import models
+class Category(models.Model):
+ name = models.SlugField()
+
+ def __unicode__(self):
+ return self.name.capitalize()
+
class Feed(models.Model):
name = models.CharField(max_length=200)
base_url = models.URLField(max_length=255)
@@ -11,6 +17,7 @@ class Feed(models.Model):
uses_title = models.BooleanField(default=False)
br2nl = models.BooleanField(default=False)
with_markdown = models.BooleanField(default=False)
+ categories = models.ManyToManyField(Category)
def get_profile_url(self):
return self.base_url + self.profile_url
@@ -21,6 +28,9 @@ class Feed(models.Model):
def get_favicon_url(self):
return self.base_url + 'favicon.' + self.favicon_ext
+ def __unicode__(self):
+ return self.name
+
class Meta:
ordering = [ '-updated' ]
diff --git a/aggregator/views.py b/aggregator/views.py
index b0fdf3b..aaea0f9 100644
--- a/aggregator/views.py
+++ b/aggregator/views.py
@@ -1,12 +1,14 @@
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.http import Http404
-from django.shortcuts import render_to_response
+from django.shortcuts import render
+from django.views.generic.base import TemplateView
-from .models import Post, Feed
+from .models import Post, Feed, Category
-def posts(request, page=1):
- queryset = Post.objects.all()
- feeds = Feed.objects.all()
+def posts(request, cat, page=1):
+ category = cat or 'posts'
+ queryset = Post.objects.filter(feed__categories__name=category)
+ feeds = Feed.objects.filter(categories__name=category)
paginator = Paginator(queryset, 20)
if page == None:
@@ -17,6 +19,8 @@ def posts(request, page=1):
except (EmptyPage, InvalidPage):
raise Http404
- return render_to_response('aggregator/posts.html',
- { 'list': object_list,
- 'feeds': feeds })
+ return render(request, 'aggregator/posts.html',
+ { 'list': object_list,
+ 'feeds': feeds,
+ 'category': category,
+ 'categories': Category.objects.order_by('name') })
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..a7f9cbf
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,4 @@
+Django==1.3
+South==0.7.4
+Feedparser==5.1.1
+Markdown==2.1.1
diff --git a/static/main.css b/static/main.css
index 8ac46a2..e60a570 100644
--- a/static/main.css
+++ b/static/main.css
@@ -22,6 +22,21 @@ pre {
margin: 20px 0;
}
+.category {
+ display: block;
+ float: right;
+ padding: 0 5px;
+ border-left: 1px #202020 solid;
+ margin-left: 5px;
+}
+
+.category:hover {
+ border-left: 1px #ffffff solid;
+ background-color: #dddddd;
+ color: #404040;
+ text-decoration: none;
+}
+
.clear {
clear: both;
}
diff --git a/templates/aggregator/base.html b/templates/aggregator/base.html
index 6a37f5a..0826711 100644
--- a/templates/aggregator/base.html
+++ b/templates/aggregator/base.html
@@ -14,7 +14,13 @@
<h1 id="sitetitle">
<span id="blue">ryu</span><span id="orange">slash</span>
</h1>
- <div id="sitesubtitle">Will this ever really be my website?</div>
+ <div id="sitesubtitle">
+ Will this ever really be my website?
+ {% for category in categories %}
+ <a class="category"
+ href="/{{ category.name|slugify }}/">{{ category.name }}</a>
+ {% endfor %}
+ </div>
{% block menu %}{% endblock %}
diff --git a/templates/aggregator/posts.html b/templates/aggregator/posts.html
index 2a5b8a1..efd1cb1 100644
--- a/templates/aggregator/posts.html
+++ b/templates/aggregator/posts.html
@@ -24,13 +24,15 @@
<div id="pager">
{% if list.has_previous %}
<div class="nav-prev">
- <a href="/{{ list.previous_page_number }}/" id="previous">previous</a>
+ <a href="/{{ category }}/{{ list.previous_page_number }}/"
+ id="previous">previous</a>
</div>
{% endif %}
{% if list.has_next %}
<div class="nav-next">
- <a href="/{{ list.next_page_number }}/" id="next">next</a>
+ <a href="/{{ category }}/{{ list.next_page_number }}/"
+ id="next">next</a>
</div>
{% endif %}
diff --git a/urls.py b/urls.py
index 039dff2..d3248a9 100644
--- a/urls.py
+++ b/urls.py
@@ -6,8 +6,9 @@ from aggregator.models import Post
from aggregator.feeds import LatestPostsFeed, LatestCommentsFeed
urlpatterns = patterns('',
- url(r'^((?P<page>\d+)/)?$', 'aggregator.views.posts'),
- url(r'^post/((?P<pk>\d+)/)?$', DetailView.as_view(model=Post)),
+ url(r'^post/(?P<pk>\d+)/$', DetailView.as_view(model=Post)),
+ url(r'^((?P<cat>[a-z_-]+)/)?((?P<page>\d+)/)?$',
+ 'aggregator.views.posts'),
url(r'^feed/posts/$', LatestPostsFeed()),
url(r'^feed/comments/$', LatestCommentsFeed()),
url(r'^comments/', include('django.contrib.comments.urls')))