diff --git a/sites/scrapy.org/scrapyorg/blog/__init__.py b/sites/scrapy.org/scrapyorg/blog/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sites/scrapy.org/scrapyorg/blog/admin.py b/sites/scrapy.org/scrapyorg/blog/admin.py new file mode 100644 index 000000000..0b1568c9d --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/admin.py @@ -0,0 +1,17 @@ +from django.contrib import admin +from scrapyorg.blog.models import * + + +class CategoryAdmin(admin.ModelAdmin): + prepopulated_fields = {'slug': ('title',)} + +admin.site.register(Category, CategoryAdmin) + + +class PostAdmin(admin.ModelAdmin): + list_display = ('title', 'publish', 'status') + list_filter = ('publish', 'categories', 'status') + search_fields = ('title', 'body') + prepopulated_fields = {'slug': ('title',)} + +admin.site.register(Post, PostAdmin) \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/feeds.py b/sites/scrapy.org/scrapyorg/blog/feeds.py new file mode 100644 index 000000000..2cd11cb28 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/feeds.py @@ -0,0 +1,42 @@ +from django.contrib.syndication.feeds import FeedDoesNotExist +from django.core.exceptions import ObjectDoesNotExist +from django.contrib.sites.models import Site +from django.contrib.syndication.feeds import Feed +from django.core.urlresolvers import reverse +from scrapyorg.blog.models import Post, Category + + +class BlogPostsFeed(Feed): + _site = Site.objects.get_current() + title = '%s feed' % _site.name + description = '%s posts feed.' % _site.name + + def link(self): + return reverse('blog_index') + + def items(self): + return Post.objects.published()[:10] + + def item_pubdate(self, obj): + return obj.publish + + +class BlogPostsByCategory(Feed): + _site = Site.objects.get_current() + title = '%s posts category feed' % _site.name + + def get_object(self, bits): + if len(bits) != 1: + raise ObjectDoesNotExist + return Category.objects.get(slug__exact=bits[0]) + + def link(self, obj): + if not obj: + raise FeedDoesNotExist + return obj.get_absolute_url() + + def description(self, obj): + return "Posts recently categorized as %s" % obj.title + + def items(self, obj): + return obj.post_set.published()[:10] \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/managers.py b/sites/scrapy.org/scrapyorg/blog/managers.py new file mode 100644 index 000000000..d5bcdb005 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/managers.py @@ -0,0 +1,9 @@ +from django.db.models import Manager +import datetime + + +class PublicManager(Manager): + """Returns published posts that are not in the future.""" + + def published(self): + return self.get_query_set().filter(status__gte=2, publish__lte=datetime.datetime.now()) \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/models.py b/sites/scrapy.org/scrapyorg/blog/models.py new file mode 100644 index 000000000..24c6e448d --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/models.py @@ -0,0 +1,81 @@ +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from django.db.models import permalink +from django.contrib.auth.models import User +#from tagging.fields import TagField +from scrapyorg.blog.managers import PublicManager + +#import tagging + + +class Category(models.Model): + """Category model.""" + title = models.CharField(_('title'), max_length=100) + slug = models.SlugField(_('slug'), unique=True) + + class Meta: + verbose_name = _('category') + verbose_name_plural = _('categories') + db_table = 'blog_categories' + ordering = ('title',) + + class Admin: + pass + + def __unicode__(self): + return u'%s' % self.title + + @permalink + def get_absolute_url(self): + return ('blog_category_detail', None, {'slug': self.slug}) + + +class Post(models.Model): + """Post model.""" + STATUS_CHOICES = ( + (1, _('Draft')), + (2, _('Public')), + ) + title = models.CharField(_('title'), max_length=200) + slug = models.SlugField(_('slug'), unique_for_date='publish') + author = models.ForeignKey(User, blank=True, null=True) + body = models.TextField(_('body')) + tease = models.TextField(_('tease'), blank=True) + status = models.IntegerField(_('status'), choices=STATUS_CHOICES, default=2) + allow_comments = models.BooleanField(_('allow comments'), default=True) + publish = models.DateTimeField(_('publish')) + created = models.DateTimeField(_('created'), auto_now_add=True) + modified = models.DateTimeField(_('modified'), auto_now=True) + categories = models.ManyToManyField(Category, blank=True) +# tags = TagField() + objects = PublicManager() + + class Meta: + verbose_name = _('post') + verbose_name_plural = _('posts') + db_table = 'blog_posts' + ordering = ('-publish',) + get_latest_by = 'publish' + + class Admin: + list_display = ('title', 'publish', 'status') + list_filter = ('publish', 'categories', 'status') + search_fields = ('title', 'body') + + def __unicode__(self): + return u'%s' % self.title + + @permalink + def get_absolute_url(self): + return ('blog_detail', None, { + 'year': self.publish.year, + 'month': self.publish.strftime('%b').lower(), + 'day': self.publish.day, + 'slug': self.slug + }) + + def get_previous_post(self): + return self.get_previous_by_publish(status__gte=2) + + def get_next_post(self): + return self.get_next_by_publish(status__gte=2) diff --git a/sites/scrapy.org/scrapyorg/blog/sitemap.py b/sites/scrapy.org/scrapyorg/blog/sitemap.py new file mode 100644 index 000000000..7b1ed9d25 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/sitemap.py @@ -0,0 +1,13 @@ +from django.contrib.sitemaps import Sitemap +from scrapyorg.blog.models import Post + + +class BlogSitemap(Sitemap): + changefreq = "never" + priority = 0.5 + + def items(self): + return Post.objects.published() + + def lastmod(self, obj): + return obj.publish \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/base.html b/sites/scrapy.org/scrapyorg/blog/templates/base.html new file mode 100644 index 000000000..880d8a996 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/base.html @@ -0,0 +1,21 @@ + + + + + + {% block title %}{% endblock %} + + +
+ {% block body %} +
+ {% block content_title %}{% endblock %} +
+
+ {% block content %}{% endblock %} +
+ {% endblock %} +
+ + \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/blog/base_blog.html b/sites/scrapy.org/scrapyorg/blog/templates/blog/base_blog.html new file mode 100644 index 000000000..48a039f7d --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/blog/base_blog.html @@ -0,0 +1,5 @@ +{% extends "base.html" %} +oaihdasasihjsd + + +{% block body_class %}blog{% endblock %} diff --git a/sites/scrapy.org/scrapyorg/blog/templates/blog/category_detail.html b/sites/scrapy.org/scrapyorg/blog/templates/blog/category_detail.html new file mode 100644 index 000000000..23a257976 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/blog/category_detail.html @@ -0,0 +1,25 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Posts for {{ category.title }}{% endblock %} +{% block body_class %}{{ block.super }} category_detail{% endblock %} +{% block body_id %}category_{{ category.id }}{% endblock %} + + +{% block content_title %} +

Posts for {{ category.title }}

+{% endblock %} + + +{% block content %} + {% load markup %} +
+ {% for post in object_list %} +
+

{{ post.title }}

+

{{ post.publish|date:"Y F d" }}

+

{{ post.tease }}

+
+ {% endfor %} +
+{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/blog/category_list.html b/sites/scrapy.org/scrapyorg/blog/templates/blog/category_list.html new file mode 100644 index 000000000..6ec01e46b --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/blog/category_list.html @@ -0,0 +1,20 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post categories{% endblock %} +{% block body_class %}{{ block.super }} category_list{% endblock %} + + +{% block content_title %} +

Post categories

+{% endblock %} + + +{% block content %} + {% load markup %} + +{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/blog/post_archive_day.html b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_archive_day.html new file mode 100644 index 000000000..b9d9ab97f --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_archive_day.html @@ -0,0 +1,23 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post archive for {{ day|date:"d F Y" }}{% endblock %} +{% block body_class %}{{ block.super }} post_archive_day{% endblock %} + + +{% block content_title %} +

Post archive for {{ day|date:"d F Y" }}

+{% endblock %} + + +{% block content %} +
+ {% for post in object_list %} +
+

{{ post.title }}

+

{{ post.publish|date:"Y F d" }}

+

{{ post.tease }}

+
+ {% endfor %} +
+{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/blog/post_archive_month.html b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_archive_month.html new file mode 100644 index 000000000..947a1cc7d --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_archive_month.html @@ -0,0 +1,23 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post archive for {{ month|date:"F Y" }}{% endblock %} +{% block body_class %}{{ block.super }} post_archive_month{% endblock %} + + +{% block content_title %} +

Post archive for {{ month|date:"F Y" }}

+{% endblock %} + + +{% block content %} +
+ {% for post in object_list %} +
+

{{ post.title }}

+

{{ post.publish|date:"Y F d" }}

+

{{ post.tease }}

+
+ {% endfor %} +
+{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/blog/post_archive_year.html b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_archive_year.html new file mode 100644 index 000000000..f0255220b --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_archive_year.html @@ -0,0 +1,21 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post archive for {{ year }}{% endblock %} +{% block body_class %}{{ block.super }} post_archive_year{% endblock %} + + +{% block content_title %} +

Post archive for {{ year }}

+{% endblock %} + + +{% block content %} + {% load markup %} + + +{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/blog/post_detail.html b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_detail.html new file mode 100644 index 000000000..a4247dcc4 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_detail.html @@ -0,0 +1,67 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}{{ object.title }}{% endblock %} +{% block body_class %}{{ block.super }} post_detail{% endblock %} +{% block body_id %}post_{{ object.id }}{% endblock %} + + +{% block content_title %} +

{{ object.title }}

+ +{% endblock %} + + +{% block content %} + {% load blog markup comments tagging_tags %} + +

{{ object.publish|date:"j F Y" }}

+ +
+ {{ object.body|markdown:"safe" }} +
+ + {% tags_for_object object as tag_list %} + {% if tag_list %} +

Related tags: + {% for tag in tag_list %} + {{ tag }}{% if not forloop.last %}, {% endif %} + {% endfor %} +

+ {% endif %} + + {% get_comment_list for object as comment_list %} + {% if comment_list %} +
+ +

Comments

+ {% for comment in comment_list %} + {% if comment.is_public %} +
+
+ {{ forloop.counter }} + {% if comment.user_url %}{{ comment.user_name }}{% else %}{{ comment.user_name }}{% endif %} says... +
+ {{ comment.comment|urlizetrunc:"60"|markdown:"safe" }} +

Posted at {{ comment.submit_date|date:"P" }} on {{ comment.submit_date|date:"F j, Y" }}

+
+ {% endif %} + {% endfor %} +
+ {% endif %} + {% if object.allow_comments %} + {% render_comment_form for object %} + {% else %} +
+

Comments are closed.

+

Comments have been close for this post.

+
+ {% endif %} +{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/blog/post_list.html b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_list.html new file mode 100644 index 000000000..399b1f0e6 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_list.html @@ -0,0 +1,35 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post archive{% endblock %} +{% block body_class %}{{ block.super }} post_list{% endblock %} + + +{% block content_title %} +

Post archive

+{% endblock %} + + +{% block content %} +
+ {% for post in object_list %} +
+

{{ post.title }}

+

{{ post.publish|date:"Y F d" }}

+

{{ post.tease }}

+
+ {% endfor %} +
+ + {% if is_paginated %} +

+ {% if has_next %} + Older + {% endif %} + {% if has_next and has_previous %} | {% endif %} + {% if has_previous %} + Newer + {% endif %} +

+ {% endif %} +{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/blog/post_search.html b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_search.html new file mode 100644 index 000000000..2884333f8 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/blog/post_search.html @@ -0,0 +1,37 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post search{% endblock %} +{% block body_class %}{{ block.super }} post_search{% endblock %} + + +{% block content_title %} +

Search

+{% endblock %} + + +{% block content %} +
+

+ + +

+
+ + {% if message %} +

{{ message }}

+ {% endif %} + + {% if object_list %} +
+ {% for post in object_list %} +
+

{{ post.title }}

+

{{ post.publish|date:"Y F d" }}

+

{{ post.tease }}

+

{% if comment_count %}{{ comment_count }} comment{{ comment_count|pluralize }}{% endif %}

+
+ {% endfor %} +
+ {% endif %} +{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/feeds/posts_description.html b/sites/scrapy.org/scrapyorg/blog/templates/feeds/posts_description.html new file mode 100644 index 000000000..99216e812 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/feeds/posts_description.html @@ -0,0 +1 @@ +{{ obj.tease }} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates/feeds/posts_title.html b/sites/scrapy.org/scrapyorg/blog/templates/feeds/posts_title.html new file mode 100644 index 000000000..7899fce3e --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates/feeds/posts_title.html @@ -0,0 +1 @@ +{{ obj.title }} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates_backup/admin/blog/post/change_form.html b/sites/scrapy.org/scrapyorg/blog/templates_backup/admin/blog/post/change_form.html new file mode 100644 index 000000000..08c034b77 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates_backup/admin/blog/post/change_form.html @@ -0,0 +1,56 @@ +{% extends "admin/change_form.html" %} + +{% block extrahead %} + {% load adminmedia inlines %} + {{ block.super }} + +{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templates_backup/inlines/default.html b/sites/scrapy.org/scrapyorg/blog/templates_backup/inlines/default.html new file mode 100644 index 000000000..5510ba952 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templates_backup/inlines/default.html @@ -0,0 +1,7 @@ +{% if object %} + {{ object }} +{% else %} + {% for object in object_list %} + {{ object }} + {% endfor %} +{% endif %} \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/templatetags/__init__.py b/sites/scrapy.org/scrapyorg/blog/templatetags/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sites/scrapy.org/scrapyorg/blog/templatetags/blog.py b/sites/scrapy.org/scrapyorg/blog/templatetags/blog.py new file mode 100644 index 000000000..e80918cb3 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/templatetags/blog.py @@ -0,0 +1,103 @@ +from django import template +from django.conf import settings +from django.db import models + +import re + +Post = models.get_model('blog', 'post') +Category = models.get_model('blog', 'category') + +register = template.Library() + + +class LatestPosts(template.Node): + def __init__(self, limit, var_name): + self.limit = limit + self.var_name = var_name + + def render(self, context): + posts = Post.objects.published()[:int(self.limit)] + if posts and (int(self.limit) == 1): + context[self.var_name] = posts[0] + else: + context[self.var_name] = posts + return '' + +@register.tag +def get_latest_posts(parser, token): + """ + Gets any number of latest posts and stores them in a varable. + + Syntax:: + + {% get_latest_posts [limit] as [var_name] %} + + Example usage:: + + {% get_latest_posts 10 as latest_post_list %} + """ + try: + tag_name, arg = token.contents.split(None, 1) + except ValueError: + raise template.TemplateSyntaxError, "%s tag requires arguments" % token.contents.split()[0] + m = re.search(r'(.*?) as (\w+)', arg) + if not m: + raise template.TemplateSyntaxError, "%s tag had invalid arguments" % tag_name + format_string, var_name = m.groups() + return LatestPosts(format_string, var_name) + + +class BlogCategories(template.Node): + def __init__(self, var_name): + self.var_name = var_name + + def render(self, context): + categories = Category.objects.all() + context[self.var_name] = categories + return '' + +@register.tag +def get_blog_categories(parser, token): + """ + Gets all blog categories. + + Syntax:: + + {% get_blog_categories as [var_name] %} + + Example usage:: + + {% get_blog_categories as category_list %} + """ + try: + tag_name, arg = token.contents.split(None, 1) + except ValueError: + raise template.TemplateSyntaxError, "%s tag requires arguments" % token.contents.split()[0] + m = re.search(r'as (\w+)', arg) + if not m: + raise template.TemplateSyntaxError, "%s tag had invalid arguments" % tag_name + var_name = m.groups()[0] + return BlogCategories(var_name) + + +@register.filter +def get_links(value): + """ + Extracts links from a ``Post`` body and returns a list. + + Template Syntax:: + + {{ post.body|markdown:"safe"|get_links }} + + """ + try: + try: + from BeautifulSoup import BeautifulSoup + except ImportError: + from beautifulsoup import BeautifulSoup + soup = BeautifulSoup(value) + return soup.findAll('a') + except ImportError: + if settings.DEBUG: + raise template.TemplateSyntaxError, "Error in 'get_links' filter: BeautifulSoup isn't installed." + return value diff --git a/sites/scrapy.org/scrapyorg/blog/tests.py b/sites/scrapy.org/scrapyorg/blog/tests.py new file mode 100644 index 000000000..1dd87451d --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/tests.py @@ -0,0 +1,66 @@ +""" +>>> from django.test import Client +>>> from scrapyorg.blog.models import Post, Category +>>> import datetime +>>> from django.core.urlresolvers import reverse +>>> client = Client() + +>>> category = Category(title='Django', slug='django') +>>> category.save() +>>> category2 = Category(title='Rails', slug='rails') +>>> category2.save() + +>>> post = Post(title='DJ Ango', slug='dj-ango', body='Yo DJ! Turn that music up!', status=2, publish=datetime.datetime(2008,5,5,16,20)) +>>> post.save() + +>>> post2 = Post(title='Where my grails at?', slug='where', body='I Can haz Holy plez?', status=2, publish=datetime.datetime(2008,4,2,11,11)) +>>> post2.save() + +>>> post.categories.add(category) +>>> post2.categories.add(category2) + +>>> response = client.get(reverse('blog_index')) +>>> response.context[-1]['object_list'] +[, ] +>>> response.status_code +200 + +>>> response = client.get(reverse('blog_category_list')) +>>> response.context[-1]['object_list'] +[, ] +>>> response.status_code +200 + +>>> response = client.get(category.get_absolute_url()) +>>> response.context[-1]['object_list'] +[] +>>> response.status_code +200 + +>>> response = client.get(post.get_absolute_url()) +>>> response.context[-1]['object'] + +>>> response.status_code +200 + +>>> response = client.get(reverse('blog_search'), {'q': 'DJ'}) +>>> response.context[-1]['object_list'] +[] +>>> response.status_code +200 +>>> response = client.get(reverse('blog_search'), {'q': 'Holy'}) +>>> response.context[-1]['object_list'] +[] +>>> response.status_code +200 +>>> response = client.get(reverse('blog_search'), {'q': ''}) +>>> response.context[-1]['message'] +'Search term was too vague. Please try again.' + +>>> response = client.get(reverse('blog_detail', args=[2008, 'apr', 2, 'where'])) +>>> response.context[-1]['object'] + +>>> response.status_code +200 +""" + diff --git a/sites/scrapy.org/scrapyorg/blog/urls.py b/sites/scrapy.org/scrapyorg/blog/urls.py new file mode 100644 index 000000000..53aa0f404 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/urls.py @@ -0,0 +1,41 @@ +from django.conf.urls.defaults import * +from scrapyorg.blog import views as blog_views + + +urlpatterns = patterns('', + url(r'^(?P\d{4})/(?P\w{3})/(?P\d{1,2})/(?P[-\w]+)/$', + view=blog_views.post_detail, + name='blog_detail'), + + url(r'^(?P\d{4})/(?P\w{3})/(?P\d{1,2})/$', + view=blog_views.post_archive_day, + name='blog_archive_day'), + + url(r'^(?P\d{4})/(?P\w{3})/$', + view=blog_views.post_archive_month, + name='blog_archive_month'), + + url(r'^(?P\d{4})/$', + view=blog_views.post_archive_year, + name='blog_archive_year'), + + url(r'^categories/(?P[-\w]+)/$', + view=blog_views.category_detail, + name='blog_category_detail'), + + url (r'^categories/$', + view=blog_views.category_list, + name='blog_category_list'), + + url (r'^search/$', + view=blog_views.search, + name='blog_search'), + + url(r'^page/(?P\w)/$', + view=blog_views.post_list, + name='blog_index_paginated'), + + url(r'^$', + view=blog_views.post_list, + name='blog_index'), +) \ No newline at end of file diff --git a/sites/scrapy.org/scrapyorg/blog/views.py b/sites/scrapy.org/scrapyorg/blog/views.py new file mode 100644 index 000000000..ad65484b5 --- /dev/null +++ b/sites/scrapy.org/scrapyorg/blog/views.py @@ -0,0 +1,160 @@ +from django.shortcuts import render_to_response, get_object_or_404 +from django.template import RequestContext +from django.http import Http404 +from django.views.generic import date_based, list_detail +from django.db.models import Q +from scrapyorg.blog.models import * + +import datetime +import re + + +def post_list(request, page=0, **kwargs): + return list_detail.object_list( + request, + queryset = Post.objects.published(), + paginate_by = 20, + page = page, + **kwargs + ) +post_list.__doc__ = list_detail.object_list.__doc__ + + +def post_archive_year(request, year, **kwargs): + return date_based.archive_year( + request, + year = year, + date_field = 'publish', + queryset = Post.objects.published(), + make_object_list = True, + **kwargs + ) +post_archive_year.__doc__ = date_based.archive_year.__doc__ + + +def post_archive_month(request, year, month, **kwargs): + return date_based.archive_month( + request, + year = year, + month = month, + date_field = 'publish', + queryset = Post.objects.published(), + **kwargs + ) +post_archive_month.__doc__ = date_based.archive_month.__doc__ + + +def post_archive_day(request, year, month, day, **kwargs): + return date_based.archive_day( + request, + year = year, + month = month, + day = day, + date_field = 'publish', + queryset = Post.objects.published(), + **kwargs + ) +post_archive_day.__doc__ = date_based.archive_day.__doc__ + + +def post_detail(request, slug, year, month, day, **kwargs): + return date_based.object_detail( + request, + year = year, + month = month, + day = day, + date_field = 'publish', + slug = slug, + queryset = Post.objects.published(), + **kwargs + ) +post_detail.__doc__ = date_based.object_detail.__doc__ + + +def category_list(request, template_name = 'blog/category_list.html', **kwargs): + """ + Category list + + Template: ``blog/category_list.html`` + Context: + object_list + List of categories. + """ + return list_detail.object_list( + request, + queryset = Category.objects.all(), + template_name = template_name, + **kwargs + ) + +def category_detail(request, slug, template_name = 'blog/category_detail.html', **kwargs): + """ + Category detail + + Template: ``blog/category_detail.html`` + Context: + object_list + List of posts specific to the given category. + category + Given category. + """ + category = get_object_or_404(Category, slug__iexact=slug) + + return list_detail.object_list( + request, + queryset = category.post_set.published(), + extra_context = {'category': category}, + template_name = template_name, + **kwargs + ) + + +# Stop Words courtesy of http://www.dcs.gla.ac.uk/idom/ir_resources/linguistic_utils/stop_words +STOP_WORDS = r"""\b(a|about|above|across|after|afterwards|again|against|all|almost|alone|along|already|also| +although|always|am|among|amongst|amoungst|amount|an|and|another|any|anyhow|anyone|anything|anyway|anywhere|are| +around|as|at|back|be|became|because|become|becomes|becoming|been|before|beforehand|behind|being|below|beside| +besides|between|beyond|bill|both|bottom|but|by|call|can|cannot|cant|co|computer|con|could|couldnt|cry|de|describe| +detail|do|done|down|due|during|each|eg|eight|either|eleven|else|elsewhere|empty|enough|etc|even|ever|every|everyone| +everything|everywhere|except|few|fifteen|fify|fill|find|fire|first|five|for|former|formerly|forty|found|four|from| +front|full|further|get|give|go|had|has|hasnt|have|he|hence|her|here|hereafter|hereby|herein|hereupon|hers|herself| +him|himself|his|how|however|hundred|i|ie|if|in|inc|indeed|interest|into|is|it|its|itself|keep|last|latter|latterly| +least|less|ltd|made|many|may|me|meanwhile|might|mill|mine|more|moreover|most|mostly|move|much|must|my|myself|name| +namely|neither|never|nevertheless|next|nine|no|nobody|none|noone|nor|not|nothing|now|nowhere|of|off|often|on|once| +one|only|onto|or|other|others|otherwise|our|ours|ourselves|out|over|own|part|per|perhaps|please|put|rather|re|same| +see|seem|seemed|seeming|seems|serious|several|she|should|show|side|since|sincere|six|sixty|so|some|somehow|someone| +something|sometime|sometimes|somewhere|still|such|system|take|ten|than|that|the|their|them|themselves|then|thence| +there|thereafter|thereby|therefore|therein|thereupon|these|they|thick|thin|third|this|those|though|three|through| +throughout|thru|thus|to|together|too|top|toward|towards|twelve|twenty|two|un|under|until|up|upon|us|very|via|was| +we|well|were|what|whatever|when|whence|whenever|where|whereafter|whereas|whereby|wherein|whereupon|wherever|whether| +which|while|whither|who|whoever|whole|whom|whose|why|will|with|within|without|would|yet|you|your|yours|yourself| +yourselves)\b""" + + +def search(request, template_name='blog/post_search.html'): + """ + Search for blog posts. + + This template will allow you to setup a simple search form that will try to return results based on + given search strings. The queries will be put through a stop words filter to remove words like + 'the', 'a', or 'have' to help imporve the result set. + + Template: ``blog/post_search.html`` + Context: + object_list + List of blog posts that match given search term(s). + search_term + Given search term. + """ + context = {} + if request.GET: + stop_word_list = re.compile(STOP_WORDS, re.IGNORECASE) + search_term = '%s' % request.GET['q'] + cleaned_search_term = stop_word_list.sub('', search_term) + cleaned_search_term = cleaned_search_term.strip() + if len(cleaned_search_term) != 0: + post_list = Post.objects.published().filter(Q(body__icontains=cleaned_search_term) | Q(tags__icontains=cleaned_search_term) | Q(categories__title__icontains=cleaned_search_term)) + context = {'object_list': post_list, 'search_term':search_term} + else: + message = 'Search term was too vague. Please try again.' + context = {'message':message} + return render_to_response(template_name, context, context_instance=RequestContext(request)) diff --git a/sites/scrapy.org/scrapyorg/settings.py b/sites/scrapy.org/scrapyorg/settings.py index bd9bd45f1..817b820b7 100644 --- a/sites/scrapy.org/scrapyorg/settings.py +++ b/sites/scrapy.org/scrapyorg/settings.py @@ -77,9 +77,11 @@ INSTALLED_APPS = ( 'django.contrib.sites', 'django.contrib.admin', 'django.contrib.markup', + 'django.contrib.comments', 'scrapyorg.article', 'scrapyorg.download', 'scrapyorg.docs', + 'scrapyorg.blog', ) DOC_PICKLE_ROOT = os.path.join(PROJECT_ROOT, 'docs', 'pickle') diff --git a/sites/scrapy.org/scrapyorg/urls.py b/sites/scrapy.org/scrapyorg/urls.py index c401bdadb..c61fe0d13 100644 --- a/sites/scrapy.org/scrapyorg/urls.py +++ b/sites/scrapy.org/scrapyorg/urls.py @@ -13,6 +13,8 @@ urlpatterns = patterns('', # docs url(r"^docs/", include("scrapyorg.docs.urls")), + # blog + url(r"^blog/", include("scrapyorg.blog.urls")), ) diff --git a/sites/scrapy.org/templates/blog/base_blog.html b/sites/scrapy.org/templates/blog/base_blog.html new file mode 100644 index 000000000..48a039f7d --- /dev/null +++ b/sites/scrapy.org/templates/blog/base_blog.html @@ -0,0 +1,5 @@ +{% extends "base.html" %} +oaihdasasihjsd + + +{% block body_class %}blog{% endblock %} diff --git a/sites/scrapy.org/templates/blog/category_detail.html b/sites/scrapy.org/templates/blog/category_detail.html new file mode 100644 index 000000000..880c37515 --- /dev/null +++ b/sites/scrapy.org/templates/blog/category_detail.html @@ -0,0 +1,25 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Posts for {{ category.title }}{% endblock %} +{% block body_class %}{{ block.super }} category_detail{% endblock %} +{% block body_id %}category_{{ category.id }}{% endblock %} + + +{% block main-content_title %} +

Posts for {{ category.title }}

+{% endblock %} + + +{% block main-content %} + {% load markup %} +
+ {% for post in object_list %} +
+

{{ post.title }}

+

{{ post.publish|date:"Y F d" }}

+

{{ post.tease }}

+
+ {% endfor %} +
+{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/templates/blog/category_list.html b/sites/scrapy.org/templates/blog/category_list.html new file mode 100644 index 000000000..d136b4bd1 --- /dev/null +++ b/sites/scrapy.org/templates/blog/category_list.html @@ -0,0 +1,20 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post categories{% endblock %} +{% block body_class %}{{ block.super }} category_list{% endblock %} + + +{% block main-content_title %} +

Post categories

+{% endblock %} + + +{% block main-content %} + {% load markup %} + +{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/templates/blog/post_archive_day.html b/sites/scrapy.org/templates/blog/post_archive_day.html new file mode 100644 index 000000000..4c95f8cf0 --- /dev/null +++ b/sites/scrapy.org/templates/blog/post_archive_day.html @@ -0,0 +1,23 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post archive for {{ day|date:"d F Y" }}{% endblock %} +{% block body_class %}{{ block.super }} post_archive_day{% endblock %} + + +{% block main-content_title %} +

Post archive for {{ day|date:"d F Y" }}

+{% endblock %} + + +{% block main-content %} +
+ {% for post in object_list %} +
+

{{ post.title }}

+

{{ post.publish|date:"Y F d" }}

+

{{ post.tease }}

+
+ {% endfor %} +
+{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/templates/blog/post_archive_month.html b/sites/scrapy.org/templates/blog/post_archive_month.html new file mode 100644 index 000000000..45c4c53e4 --- /dev/null +++ b/sites/scrapy.org/templates/blog/post_archive_month.html @@ -0,0 +1,23 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post archive for {{ month|date:"F Y" }}{% endblock %} +{% block body_class %}{{ block.super }} post_archive_month{% endblock %} + + +{% block main-content_title %} +

Post archive for {{ month|date:"F Y" }}

+{% endblock %} + + +{% block main-content %} +
+ {% for post in object_list %} +
+

{{ post.title }}

+

{{ post.publish|date:"Y F d" }}

+

{{ post.tease }}

+
+ {% endfor %} +
+{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/templates/blog/post_archive_year.html b/sites/scrapy.org/templates/blog/post_archive_year.html new file mode 100644 index 000000000..1a176ef9d --- /dev/null +++ b/sites/scrapy.org/templates/blog/post_archive_year.html @@ -0,0 +1,21 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post archive for {{ year }}{% endblock %} +{% block body_class %}{{ block.super }} post_archive_year{% endblock %} + + +{% block main-content_title %} +

Post archive for {{ year }}

+{% endblock %} + + +{% block main-content %} + {% load markup %} + + +{% endblock %} \ No newline at end of file diff --git a/sites/scrapy.org/templates/blog/post_detail.html b/sites/scrapy.org/templates/blog/post_detail.html new file mode 100644 index 000000000..15bcbb2c1 --- /dev/null +++ b/sites/scrapy.org/templates/blog/post_detail.html @@ -0,0 +1,72 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}{{ object.title }}{% endblock %} +{% block body_class %}{{ block.super }} post_detail{% endblock %} +{% block body_id %}post_{{ object.id }}{% endblock %} + + +{% block main-content_title %} +

{{ object.title }}

+ +{% endblock %} + + +{% block main-content %} + {% load blog markup comments %} + {% comment %} + {% load tagging_tags %} + {% endcomment %} + +

{{ object.publish|date:"j F Y" }}

+ +
+ {{ object.body|markdown:"safe" }} +
+ + {% comment %} + {% tags_for_object object as tag_list %} + {% if tag_list %} +

Related tags: + {% for tag in tag_list %} + {{ tag }}{% if not forloop.last %}, {% endif %} + {% endfor %} +

+ {% endif %} + {% endcomment %} + + {% get_comment_list for object as comment_list %} + {% if comment_list %} +
+ +

Comments

+ {% for comment in comment_list %} + {% if comment.is_public %} +
+
+ {{ forloop.counter }} + {% if comment.user_url %}{{ comment.user_name }}{% else %}{{ comment.user_name }}{% endif %} says... +
+ {{ comment.comment|urlizetrunc:"60"|markdown:"safe" }} +

Posted at {{ comment.submit_date|date:"P" }} on {{ comment.submit_date|date:"F j, Y" }}

+
+ {% endif %} + {% endfor %} +
+ {% endif %} + {% if object.allow_comments %} + {% render_comment_form for object %} + {% else %} +
+

Comments are closed.

+

Comments have been close for this post.

+
+ {% endif %} +{% endblock %} diff --git a/sites/scrapy.org/templates/blog/post_list.html b/sites/scrapy.org/templates/blog/post_list.html new file mode 100644 index 000000000..5f8d8c1cd --- /dev/null +++ b/sites/scrapy.org/templates/blog/post_list.html @@ -0,0 +1,35 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post archive{% endblock %} +{% block body_class %}{{ block.super }} post_list{% endblock %} + + +{% block main-content_title %} +

Post archive

+{% endblock %} + + +{% block main-content %} +
+ {% for post in object_list %} +
+

{{ post.title }}

+

{{ post.publish|date:"Y F d" }}

+

{{ post.tease }}

+
+ {% endfor %} +
+ + {% if is_paginated %} +

+ {% if has_next %} + Older + {% endif %} + {% if has_next and has_previous %} | {% endif %} + {% if has_previous %} + Newer + {% endif %} +

+ {% endif %} +{% endblock %} diff --git a/sites/scrapy.org/templates/blog/post_search.html b/sites/scrapy.org/templates/blog/post_search.html new file mode 100644 index 000000000..271000351 --- /dev/null +++ b/sites/scrapy.org/templates/blog/post_search.html @@ -0,0 +1,37 @@ +{% extends "blog/base_blog.html" %} + + +{% block title %}Post search{% endblock %} +{% block body_class %}{{ block.super }} post_search{% endblock %} + + +{% block main-content_title %} +

Search

+{% endblock %} + + +{% block main-content %} +
+

+ + +

+
+ + {% if message %} +

{{ message }}

+ {% endif %} + + {% if object_list %} +
+ {% for post in object_list %} +
+

{{ post.title }}

+

{{ post.publish|date:"Y F d" }}

+

{{ post.tease }}

+

{% if comment_count %}{{ comment_count }} comment{{ comment_count|pluralize }}{% endif %}

+
+ {% endfor %} +
+ {% endif %} +{% endblock %} \ No newline at end of file