1. Carlos Ramos
  2. django-articles-es_mx

Commits

Josh VanderLinden  committed 4b62881

Doing a lot of house cleaning

  • Participants
  • Parent commits a55ff75
  • Branches default

Comments (0)

Files changed (29)

File articles/admin.py

View file
  • Ignore whitespace
 from django.contrib import admin
 from django.contrib.auth.models import User
-from codekoala.articles.models import Category, Article
+from models import Category, Article
 
 class CategoryAdmin(admin.ModelAdmin):
     list_display = ('name', 'image')
     date_hierarchy = 'publish_date'
 
     fieldsets = (
-        (None, {'fields': ('title', 'content', 'categories')}),
+        (None, {'fields': ('title', 'content', 'markup', 'categories')}),
         ('Metadata', {
             'fields': ('keywords', 'description',),
             'classes': ('collapse',)
         }),
         ('Scheduling', {'fields': ('publish_date', 'expiration_date')}),
         ('Advanced', {
-            'fields': ('slug', 'is_active', 'is_commentable', 'make_pdf'),
+            'fields': ('slug', 'is_active', 'is_commentable',),
             'classes': ('collapse',)
         }),
     )

File articles/models.py

View file
  • Ignore whitespace
 from django.contrib.comments.models import Comment
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.sitemaps import ping_google
-from django.contrib.markup.templatetags.markup import restructuredtext
+from django.contrib.markup.templatetags import markup
 from django.core.urlresolvers import reverse
+from django.core.cache import cache
 from django.conf import settings
+from django.utils.translation import ugettext_lazy as _
 from datetime import datetime
-import commands
+from base64 import encodestring
 import os
 import re
-import xmlrpclib
+import urllib
 import unicodedata
 
 WORD_LIMIT = getattr(settings, 'ARTICLES_TEASER_LIMIT', 75)
+MARKUP_OPTIONS = getattr(settings, 'ARTICLE_MARKUP_OPTIONS', (
+        ('h', _('HTML/Plain Text')),
+        ('m', _('Markdown')),
+        ('r', _('ReStructured Text')),
+        ('t', _('Textile'))
+    ))
+MARKUP_DEFAULT = getattr(settings, 'ARTICLE_MARKUP_DEFAULT', 'h')
+
+# regex used to find links in an article
+LINK_RE = re.compile('<a.*?href="(.*?)".*?>(.*?)</a>', re.I|re.M)
+TITLE_RE = re.compile('<title>(.*?)</title>', re.I|re.M)
+
+def get_name(user):
+    """
+    Provides a way to fall back to a user's username if their full name has not
+    been entered.
+    """
+    if len(user.get_full_name().strip()):
+        return user.get_full_name()
+    else:
+        return user.username
+User.get_name = get_name
 
 class CategoryManager(models.Manager):
     def active(self):
 
 class Category(models.Model):
     name = models.CharField(max_length=50)
-    slug = models.SlugField()
+    slug = models.SlugField(unique=True)
     image = models.ImageField(upload_to='categories/', blank=True, null=True)
     is_active = models.BooleanField(default=True, blank=True)
 
 
 class Article(models.Model):
     title = models.CharField(max_length=100)
-    slug = models.SlugField(unique_for_date='publish_date')
+    slug = models.SlugField(unique_for_year='publish_date')
+    author = models.ForeignKey(User)
+
     keywords = models.TextField(blank=True)
-    description = models.TextField(blank=True, help_text="If omitted, the description will be determined by the first bit of the article's content.")
-    author = models.ForeignKey(User)
+    description = models.TextField(blank=True, help_text=_("If omitted, the description will be determined by the first bit of the article's content."))
+
+    markup = models.CharField(max_length=1, choices=MARKUP_OPTIONS, default=MARKUP_DEFAULT, help_text=_('Select the type of markup you are using in this article.'))
     content = models.TextField()
     rendered_content = models.TextField()
-    categories = models.ManyToManyField(Category, help_text='Select any categories to classify this article.', blank=True)
-    followup_for = models.ManyToManyField('self', symmetrical=False, blank=True, help_text='Select any other articles that this article follows up on.', related_name='followups')
+
+    categories = models.ManyToManyField(Category, help_text=_('Select any categories to classify the content of this article.'), blank=True)
+    followup_for = models.ManyToManyField('self', symmetrical=False, blank=True, help_text=_('Select any other articles that this article follows up on.'), related_name='followups')
     related_articles = models.ManyToManyField('self', blank=True)
+
+    publish_date = models.DateTimeField(default=datetime.now, help_text=_('The date and time this article shall appear online.'))
+    expiration_date = models.DateTimeField(blank=True, null=True, help_text=_('Leave blank if the article does not expire.'))
+
     is_active = models.BooleanField(default=True, blank=True)
     is_commentable = models.BooleanField(default=True, blank=True)
-    make_pdf = models.BooleanField(default=True, blank=True)
-    publish_date = models.DateTimeField(default=datetime.now)
-    expiration_date = models.DateTimeField(blank=True, null=True)
+    login_required = models.BooleanField(blank=True, help_text=_('Enable this if users must login before they can read this article.'))
 
     objects = ArticleManager()
 
     def __init__(self, *args, **kwargs):
+        """
+        Make sure that we have some rendered content to use.
+        """
         super(Article, self).__init__(*args, **kwargs)
 
         if self.id:
-            if not self.rendered_content or not len(self.rendered_content):
+            if not self.rendered_content or not len(self.rendered_content.strip()):
                 self.save()
 
     def __unicode__(self):
         return self.title
 
     def save(self):
-        # make sure each article has a heading
-        if not self.content.startswith('==='):
-            line = '=' * len(self.title)
-            self.content = """%s
-%s
-%s
-
-:author: Josh VanderLinden <codekoala@gmail.com>
-:date: %s
-:Homepage: http://www.codekoala.com/
-
-%s
-""" % (line, self.title, line,
-       self.publish_date.strftime('%d %b %Y'), self.content)
-
-        # no more page breaks please
-        self.content = self.content.replace(PAGE_BREAK, '')
-
-        # let's use "code-block" instead of "sourcecode" for the PDFs
-        self.content = self.content.replace('.. sourcecode:: ',
-                                            '.. code-block:: ')
-
-        self.rendered_content = restructuredtext(self.content)
-        super(Article, self).save()
-
-        # don't save any .rst or .pdf files if we're in debug mode or it's
-        # specifically checked
-        #if settings.DEBUG or not self.make_pdf: return
-
-        # create a PDF version of the article
-        out_dir = os.path.join(settings.MEDIA_ROOT, 'articles')
-        rst_dir = os.path.join(out_dir, 'rst')
-        pdf_dir = os.path.join(out_dir, 'pdfs')
-
-        # ensure that the RST directory exists
-        try: os.makedirs(rst_dir)
-        except OSError: pass
-
-        # ensure that the PDF directory exists
-        try: os.makedirs(pdf_dir)
-        except OSError: pass
-
-        # save the RST
-        pdf_file = os.path.join(pdf_dir, self.slug + '.pdf')
-        rst_file = os.path.join(rst_dir, self.slug + '.rst')
-
-        real_content = clean_content = u_clean(self.content)
-
-        # now clean it up a bit more for the PDF
-        #clean_content = clean_content.replace('    :linenos:\r\n', '    :linenos: true\r\n')
-        clean_content = re.sub('(:(H|h)omepage:.*\n)',
-                                r'\1:URL: http://www.codekoala.com%s\n\n .. header::\n\n    Copyright (c) %i Josh VanderLinden\n\n .. footer::\n\n    page ###Page###\n' % (self.get_absolute_url(), self.publish_date.year), clean_content)
-        clean_content = re.sub('( .. image:: http://www.codekoala.com/static/)',
-                              r' .. image:: %s/' % settings.MEDIA_ROOT,
-                              clean_content)
-
-        # see if we have any comments on this article
-        content_type = ContentType.objects.get_for_model(Article)
-        comments = Comment.objects.filter(content_type=content_type, object_pk=str(self.id))
-        if comments.count():
-            # we do, so tack on the comments for the PDF
-            clean_content += '\n\nComments\n========\n\n'
-            for comment in comments:
-                clean_content += """%s said...\n%s
-
-%s
-
-Posted: %s
-
-""" % (u_clean(comment.name),
-        '-' * len(comment.name + ' said...'),
-        u_clean(comment.comment),
-        comment.submit_date)
-
-        #print clean_content
-        self.__save_pdf(rst_file, pdf_file, clean_content)
-
-        # try to access the PDF file.  If it's there, we can assume that all
-        # went well.  If it's not there, try removing the :linenos: option
-        if not os.access(pdf_file, os.R_OK):
-            clean_content = clean_content.replace('    :linenos:\r\n', '')
-            self.__save_pdf(rst_file, pdf_file, clean_content)
-
-        # now save the "real" RST
-        rst = open(rst_file, 'w')
-        rst.write(real_content)
-        rst.close()
+        """
+        Renders the article using the appropriate markup language.  Pings
+        Google to let it know that this article has been updated.
+        """
+        if self.markup == 'm':
+            self.rendered_content = markup.markdown(self.content)
+        elif self.markup == 'r':
+            self.rendered_content = markup.restructuredtext(self.content)
+        elif self.markup == 't':
+            self.rendered_content = markup.textile(self.content)
+        else:
+            self.rendered_content = self.content
 
         if not settings.DEBUG:
             # try to tell google that we have a new article
             except Exception:
                 pass
 
-    def __save_pdf(self, rst_file, pdf_file, content):
-        """
-        Attempts to save a PDF version of the article.
-        """
+    def _get_article_links(self):
+        links = {}
 
-        # save the PDF-appropriate RST
-        rst = open(rst_file, 'w')
-        rst.write(u_clean(content))
-        rst.close()
+        for link in LINK_RE.finditer(self.rendered_content):
+            key = 'href_title_' + encodestring(link.group(1)).strip()
+            if not cache.get(key):
+                c = urllib.urlopen(link.group(1))
+                html = c.read()
+                c.close()
+                title = TITLE_RE.search(html)
+                if title: title = title.group(1)
+                else: title = link.group(2)
 
-        # generate the PDF
-        commands.getoutput('rst2pdf %s -o %s' % (rst_file, pdf_file))
+                cache.set(key, title, 86400)
+
+            links[link.group(1)] = cache.get(key)
+
+        return links
+    links = property(_get_article_links)
 
     def get_absolute_url(self):
-        info = self.publish_date.strftime('%Y/%b/%d').lower().split('/') + [self.slug]
-        return reverse('articles_display_article', args=info)
+        return reverse('articles_display_article', args=[self.publish_date.year, self.slug])
 
     def _get_teaser(self):
         if len(self.description.strip()):
         return text
     teaser = property(_get_teaser)
 
-    def next_article(self):
-        try:
-            article = Article.objects.active().exclude(id__exact=self.id).filter(publish_date__gte=self.publish_date).order_by('publish_date')[0]
-        except (Article.DoesNotExist, IndexError):
-            article = None
-        return article
-
-    def previous_article(self):
-        try:
-            article = Article.objects.active().exclude(id__exact=self.id).filter(publish_date__lte=self.publish_date).order_by('-publish_date')[0]
-        except (Article.DoesNotExist, IndexError):
-            article = None
-        return article
-
     class Meta:
         ordering = ('-publish_date', 'title')
-
-# wrap the save comment method so the PDF will be regenerated as soon as a new
-# comment is posted
-def update_pdf(func):
-    def new(obj, *args, **kwargs):
-        result = func(obj, *args, **kwargs)
-
-        # only save the object whose comment was just saved if it's an Article
-        if isinstance(obj.content_object, Article):
-            obj.content_object.save()
-
-        return result
-    return new
-
-Comment.save = update_pdf(Comment.save)
-
-def u_clean(s):
-    """
-    Cleans up dirty unicode text.
-    """
-    uni = ''
-    try:
-        # try this first
-        uni = str(s).decode('iso-8859-1')
-    except:
-        try:
-            # try utf-8 next
-            uni = str(s).decode('utf-8')
-        except:
-            # last resort method... one character at a time
-            if s and type(s) in (str, unicode):
-                for c in s:
-                    try:
-                        uni += unicodedata.normalize('NFKC', unicode(c))
-                    except:
-                        uni += '-'
-
-    return uni.encode('ascii', 'xmlcharrefreplace')

File articles/templates/articles/_article_pages.html

  • Ignore whitespace
-{% if pages %}
-{% ifnotequal page_count 1 %}
-{% with article.publish_date as date %}
-
-{% if next %}<div class="continued-on">Continued on <a href="{% url articles-display-article-page date.year,date|date:"b",date.day,article.slug,next %}">page {{ next }}</a>...</div>{% endif %}
-
-Pages: {% if first %}<a href="{% url articles-display-article-page date.year,date|date:"b",date.day,article.slug,first %}">&laquo;</a> {% endif %}
-{% if previous %}<a href="{% url articles-display-article-page date.year,date|date:"b",date.day,article.slug,previous %}">&lsaquo;</a> {% endif %}
-
-{% for p in pages %}
-{% ifequal p page %}
-<span class="articles-current-page">{{ p }}</span>
-{% else %}
-<a href="{% url articles-display-article-page date.year,date|date:"b",date.day,article.slug,p %}">{{ p }}</a>
-{% endifequal %}
-{% endfor %}
-
-{% if next %}<a href="{% url articles-display-article-page date.year,date|date:"b",date.day,article.slug,next %}">&rsaquo;</a> {% endif %}
-{% if last %}<a href="{% url articles-display-article-page date.year,date|date:"b",date.day,article.slug,last %}">&raquo;</a> {% endif %}
-
-{% endwith %}
-{% endifnotequal %}
-{% endif %}

File articles/templates/articles/_article_teaser.html

  • Ignore whitespace
-{% load humanize markup comments %}
-{% get_comment_count for articles.article article.id as comment_count %}
-{% with article.publish_date as date %}
-<div class="article-teaser">
-    <h3><a href="{{ article.get_absolute_url }}" title="Read the full article">{{ article.title }}</a></h3>
-    <h6 class="teaser-date">Posted {{ date|timesince }} ago by <a href="{% url articles-by-author article.author.username %}" title="View all articles by this author">{{ article.author }}</a></h6>
-    <div class="teaser">
-        {{ article.teaser|safe }}
-    </div>
-    <div class="infobar">
-        <div class="categories quiet">Filed in {% if article.categories.count %}{% for category in article.categories.all %}{% if not forloop.first %}{% ifnotequal article.categories.count 2 %},{% endifnotequal %} {% if forloop.last %}and{% endif %} {% endif %}<a href="{% url articles-display-category category.slug %}" title="View all articles in this category">{{ category }}</a>{% endfor %}{% else %}<a href="{% url articles-display-uncategorized %}" title="View all uncategorized articles">Uncategorized</a>{% endif %}</div>
-
-        <div class="commentsbar">
-            <a href="{{ article.get_absolute_url }}#comments">{{ comment_count }}</a> comment{{ comment_count|pluralize }} |
-            <a href="{{ article.get_absolute_url }}" title="Read the full article">read more...</a>
-        </div>
-        <div style="clear: both"></div>
-    </div>
-    
-    <hr class="content" />
-</div>
-{% endwith %}

File articles/templates/articles/_articles.html

View file
  • Ignore whitespace
+{% load i18n %}
+{% if forloop.first %}<ol class="article-list">{% endif %}
+    <li>
+        <h3><a href="{{ article.get_absolute_url }}" title="{% trans 'Read this article' %}">{{ article.title }}</a><h3>
+        <div class="quiet">{% trans 'Posted on' %} {{ article.publish_date|date:"F jS, Y" }}</div>
+    </li>
+{% if forloop.last %}</ol>{% endif %}

File articles/templates/articles/_calendar.html

  • Ignore whitespace
-<table class="calendar">
-    <tr>
-        <th colspan="7">{{ date|date:"F Y" }}</th>
-    </tr>
-    <tr class="articles-calendar-weekdays">
-      <th>Sun</th>
-      <th>Mon</th>
-      <th>Tue</th>
-      <th>Wed</th>
-      <th>Thu</th>
-      <th>Fri</th>
-      <th>Sat</th>
-    </tr>
-    {% for week in days %}
-    <tr>
-      {% for day in week %}
-      <td{% ifequal day today.day %} class="today"{% endifequal %}>
-        {% with day|stringformat:"02i" as long_day %}
-        {% if day %}<a href="{% url articles-day-archive date.year,date|date:"b",long_day %}">{{ day }}</a>{% else %}&nbsp;{% endif %}
-        {% endwith %}
-      </td>
-      {% endfor %}
-    </tr>
-    {% endfor %}
-</table>

File articles/templates/articles/_categories.html

  • Ignore whitespace
-<ul class="articles-categories">
-{% for category in categories %}
-<li><a href="{% url articles-display-category category.slug %}" title="View all articles in this category">{{ category.name }}</a> ({{ category.article_set.count }})</li>
-{% endfor %}
-<li><a href="{% url articles-display-uncategorized %}" title="View all uncategorized articles">Uncategorized</a> ({{ uncategorized }})</li>
-</ul>

File articles/templates/articles/_pagination.html

  • Ignore whitespace
-{% if is_paginated %}
-<div class="pagination">
-<ul>
-    {% if page_obj.has_previous %}<li><a href="{% url URLname params %}">&lsaquo; newer</a></li>{% endif %}
-    {% for p in paginator.page_range %}
-    <li>
-        {% ifequal p page_obj.number %}<span class="active">{{ p }}</span>
-        {% else %}<a href="{{ page_urls.p }}">{{ p }}</a>{% endifequal %}
-    </li>
-    {% endfor %}
-    {% if page_obj.has_next %}<li><a href="{{ next_url }}">older &rsaquo;</a></li>{% endif %}
-</ul>
-</div>
-{% endif %}

File articles/templates/articles/_recent_articles.html

  • Ignore whitespace
-{% if articles %}
-{% for article in articles %}
-{% include 'articles/_article_teaser.html' %}
-{% endfor %}
-
-<div class="recent-articles-archive">
-    <h5><a href="{% url articles-archive %}">Article Archive</a></h5>
-</div>
-{% else %}
-<p>No articles to show.</p>
-{% endif %}

File articles/templates/articles/article_archive.html

  • Ignore whitespace
-{% extends 'base.html' %}
-
-{% block title %}Article Archive{% endblock %}
-
-{% block content %}
-<h2>Article Archives</h2>
-
-{% for date in date_list %}
-{% if forloop.first %}<ul class="articles-year-archive">{% endif %}
-<li><a href="{% url articles-year-archive date.year %}" title="View all articles published in {{ date|date:"Y" }}">{{ date|date:"Y" }}</a></li>
-{% if forloop.last %}</ul>
-<div style="clear: both;"></div>{% endif %}
-{% endfor %}
-
-{% if latest %}
-<h2>Latest Articles</h2>
-{% for article in latest %}
-{% include 'articles/_article_teaser.html' %}
-{% endfor %}
-{% endif %}
-{% endblock %}

File articles/templates/articles/article_archive_day.html

  • Ignore whitespace
-{% extends 'base.html' %}
-{% load humanize %}
-
-{% block title %}Article Archive: {{ day|naturalday }}{% endblock %}
-
-{% block content %}
-<h2>Article Archives: {{ day|naturalday }}</h2>
-
-{% if object_list %}
-{% for article in object_list %}
-{% include 'articles/_article_teaser.html' %}
-{% endfor %}
-{% else %}
-<p>No articles were posted on {{ day|date:"d F Y" }}.</p>
-{% endif %}
-
-<div style="text-align: center;">
-{% if previous_day %}<a href="{% url articles-day-archive previous_day.year,previous_day|date:"b",previous_day.day %}" title="View articles from {{ day|naturalday }}">&lsaquo; {{ previous_day|naturalday }}</a>{% endif %}
-{% if previous_day and next_day %} : {% endif %}
-{% if next_day %}<a href="{% url articles-day-archive next_day.year,next_day|date:"b",next_day.day %}" title="View articles from {{ day|naturalday }}">{{ next_day|naturalday }} &rsaquo;</a>{% endif %}
-</div>
-{% endblock %}

File articles/templates/articles/article_archive_month.html

  • Ignore whitespace
-{% extends 'base.html' %}
-{% load articles %}
-
-{% block title %}Article Archive: {{ month|date:"F Y" }}{% endblock %}
-
-{% block content %}
-{% comment %}
-<h2>Article Distribution</h2>
-
-<div style="text-align: center">
-<img src="http://chart.apis.google.com/chart?chs=200x875&amp;chd=t:{% articles_on_days month %}&amp;chm=N*f0*,000000,0,-1,11&amp;chds=0,{% most_articles_in_a_day month %},1,{% days_in_month month %}&amp;chxr=0,0,{% most_articles_in_a_day month %}&amp;cht=bhs&amp;chxt=x,y&amp;chxl=1:|{% days_in_month_range month %}|" alt="Article distribution for {{ month|date:"F Y" }}" title="Article distribution for {{ month|date:"F Y" }}" style="background-color: #fff; border: 1px solid #333; padding: 10px; margin: auto;" />
-</div>
-{% endcomment %}
-
-<h2>Article Archives: {{ month|date:"F Y" }} ({{ object_list|length }})</h2>
-
-{% for date in date_list %}
-{% if forloop.first %}<ul class="articles-month-archive">{% endif %}
-<li><a href="{% url articles-month-archive date.year,date|date:"b" %}" title="View all articles published in {{ date|date:"F Y" }}">{{ date|date:"F Y" }}</a></li>
-{% if forloop.last %}</ul>
-<div style="clear: both;"></div>{% endif %}
-{% endfor %}
-
-{% if object_list %}
-{% for article in object_list %}
-{% include 'articles/_article_teaser.html' %}
-{% endfor %}
-{% else %}
-<p>No articles have been posted for this month</p>
-{% endif %}
-
-<div style="text-align: center;">
-{% if previous_month %}<a href="{% url articles-month-archive previous_month.year,previous_month|date:"b" %}" title="View articles from the previous month">&lsaquo; {{ previous_month|date:"F Y" }}</a>{% endif %}
-{% if previous_month and next_month %} : {% endif %}
-{% if next_month %}<a href="{% url articles-month-archive next_month.year,next_month|date:"b" %}" title="View articles from the next month">{{ next_month|date:"F Y" }} &rsaquo;</a>{% endif %}
-</div>
-{% endblock %}

File articles/templates/articles/article_archive_year.html

  • Ignore whitespace
-{% extends 'base.html' %}
-{% load articles %}
-
-{% block title %}Article Archive: {{ year }}{% endblock %}
-
-{% block content %}
-<h2>Article Archives: {{ year }} ({{ object_list|length }})</h2>
-
-{% for date in date_list %}
-{% if forloop.first %}<ul class="articles-month-archive">{% endif %}
-<li><a href="{% url articles-month-archive date.year,date|date:"b" %}" title="View all articles published in {{ date|date:"F Y" }}">{{ date|date:"M Y" }}</a></li>
-{% if forloop.last %}</ul>
-<div style="clear: both;"></div>{% endif %}
-{% endfor %}
-
-<h2>Article Distribution</h2>
-
-<div style="text-align: center">
-<img src="http://chart.apis.google.com/chart?chs=350x200&amp;chd=t:{% articles_in_months year %}&amp;chm=N*f0*,000000,0,-1,11&amp;chds=0,{% most_articles_in_a_month year %}&amp;chxr=1,0,{% most_articles_in_a_month year %}&amp;cht=bvs&amp;chxt=x,y&amp;chxl=0:|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sept|Oct|Nov|Dec|" alt="Article distribution for {{ year }}" title="Article distribution for {{ year }}" style="background-color: #fff; border: 1px solid #333; padding: 10px; margin: auto;" />
-</div>
-
-{% if object_list %}
-<h2>Latest Articles</h2>
-{% for article in object_list %}
-{% include 'articles/_article_teaser.html' %}
-{% endfor %}
-{% endif %}
-{% endblock %}

File articles/templates/articles/article_detail.html

View file
  • Ignore whitespace
-{% extends 'base.html' %}
-{% load articles markup comments humanize smiley_tags gravatar cache %}
+{% extends 'articles/base.html' %}
+{% load i18n %}
 
-{% block title %}Article: {{ object.title }}{% ifnotequal page 1 %}, page {{ page }}{% endifnotequal %}{% endblock %}
-
-{% block keywords %}{{ object.keywords }}{% endblock %}
-{% block description %}{{ object.description }}{% endblock %}
-{% block extra-head %}
-{{ block.super }}
-
-<style type="text/css">
-blockquote.quote {
-    margin: 20px;
-    padding: 5px;
-    background-color: #cfc880;
-    color: #333;
-    border: 5px solid #333;
-    -moz-border-radius: 5px;
-    -webkit-border-radius: 5px;
-}
-</style>
-<script type="text/javascript">
-$(document).ready(function () {
-    $('blockquote').addClass('quote');
-    $('blockquote:has(div.codeblock)').removeClass('quote');
-    $('blockquote:has(img)').removeClass('quote');
-});
-</script>
-{% endblock %}
+{% block title %}{% trans article.title %}{% endblock %}
 
 {% block content %}
-{% cache 300 article object %}
-<h1>{{ object.title }}{% ifnotequal page 1 %}, page {{ page }}{% endifnotequal %}</h1>
+<div id="article-content">
+    <h2>{% trans article.title %}</h2>
 
-<h6 class="article-date">Posted {{ object.publish_date|naturalday }} at {{ object.publish_date|date:"P" }} by <a href="{% url articles-by-author object.author.username %}" title="View all articles by this author">{{ object.author }}</a></h6>
-
-<div class="bookmark-links">
-    <a href="{% url send-article object.id %}" title="E-mail this article to someone"><img src="{{ MEDIA_URL }}images/mail.png" height="16" width="16" alt="E-mail this article" /></a>
-
-    <a href="http://reddit.com/submit" onclick="window.location='http://reddit.com/submit?url='+encodeURIComponent(location.href)+'&amp;title={{ object.title|urlencode }}';return false;" title="Bookmark this article on Reddit"><img src="{{ MEDIA_URL }}images/Reddit-16x16.png" height="16" width="16" alt="Reddit" /></a>
-
-    <a href="http://delicious.com/post" onclick="window.open('http://delicious.com/post?v=5&amp;noui&amp;jump=close&amp;url='+encodeURIComponent(location.href)+'&amp;title='+encodeURIComponent(document.title), 'delicious','toolbar=no,width=550,height=550'); return false;" title="Bookmark this on Delicious"><img src="{{ MEDIA_URL }}images/delicious-16x16.png" height="16" width="16" alt="del.icio.us" /></a>
-
-    <a href="http://digg.com/submit" onclick="window.location='http://digg.com/submit?url='+encodeURIComponent(location.href)+'&amp;title={{ object.title|urlencode }}';return false;" title="Digg this!"><img src="{{ MEDIA_URL }}images/digg-16x16.png" height="16" width="16" alt="digg" /></a>
-
-    <a href="http://www.mixx.com/submit" onclick="window.location='http://www.mixx.com/submit?page_url='+encodeURIComponent(location.href)+'&amp;title={{ object.title|urlencode }}&amp;description={{ object.description|urlencode }}';return false;" title="Add to Mixx!"><img src="http://www.mixx.com/images/buttons/mixx-button4.png" alt="Add to Mixx!" height="16" width="16" /></a>
-
-    <a href="http://www.stumbleupon.com/submit" onclick="window.location='http://www.stumbleupon.com/submit?url='+encodeURIComponent(location.href)+'&amp;title={{ object.title|urlencode }}';return false;"><img src="{{ MEDIA_URL }}images/Stumbleupon-16x16.png" alt="StumbleUpon" height="16" width="16"></a>
-
-    <a href="{{ MEDIA_URL }}articles/pdfs/{{ object.slug }}.pdf"><img src="{{ MEDIA_URL }}images/pdf-16x16.png" alt="Get the PDF version" height="16" width="16"></a>
-
-    {% if user.is_superuser %}
-    <a href="{% url admin_articles_article_change object.id %}"><img src="{{ MEDIA_URL }}images/edit.png" alt="Edit this article" height="16" width="16"></a>
-    {% endif %}
-</div>
-<div class="clear"></div>
-
-<div style="text-align: center">
-    <script type="text/javascript">
-    <!--
-    google_ad_client = "pub-7828344619183032";
-    /* 468x60, created 7/10/08 */
-    google_ad_slot = "3750736994";
-    google_ad_width = 468;
-    google_ad_height = 60;
-    //-->
-    </script>
-    <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
+    {{ article.rendered_content|safe }}
 </div>
 
-{% comment %}{% if object.description %}<p class="articles-description">{{ object.description|restructuredtext }}</p>{% endif %}{% endcomment %}
+<div id="article-meta">
+    <p>Posted by <a href="{% url articles_by_author article.author.username %}" title="{% trans 'Read other articles by this author' %}">{{ article.author.get_name }}</a></p>
 
-<div class="article">
-{{ object.rendered_content|smileys|safe }}
+    {{ article.links }}
 </div>
-
-<div class="categories" style="width: 100%; font-size: 0.8em">Filed in {% if object.categories.count %}{% for category in object.categories.all %}{% if not forloop.first %}{% ifnotequal object.categories.count 2 %},{% endifnotequal %} {% if forloop.last %}and{% endif %} {% endif %}<a href="{% url articles-display-category category.slug %}" title="View all articles in this category">{{ category }}</a>{% endfor %}{% else %}<a href="{% url articles-display-uncategorized %}" title="View all uncategorized articles">Uncategorized</a>{% endif %}</div>
-<div style="clear: both"></div>
-
-{% if object.followups.active.count %}
-<hr class="content" />
-
-<h4 class="hasfollowup-header">Follow-Up Articles for "{{ object.title }}"</h4>
-{% for fu in object.followups.active %}
-{% if forloop.first %}<ul class="followups">{% endif %}
-    <li>
-        <a href="{{ fu.get_absolute_url }}" title="Read this follow-up article">{{ fu.title }}</a>, posted
-        {{ fu.publish_date|naturalday }} at {{ fu.publish_date|date:"P" }}
-    </li>
-{% if forloop.last %}</ul>{% endif %}
-{% endfor %}
-{% endif %}
-
-{% if object.followup_for.active.count %}
-<hr class="content" />
-
-<h4 class="followup-header">"{{ object.title }}" follows up on th{{ object.followup_for.count|pluralize:"is,ese" }} article{{ object.followup_for.count|pluralize }}</h4>
-{% for fu in object.followup_for.active %}
-{% if forloop.first %}<ul class="followups">{% endif %}
-    <li>
-        <a href="{{ fu.get_absolute_url }}" title="Read this article">{{ fu.title }}</a>, posted
-        {{ fu.publish_date|naturalday }} at {{ fu.publish_date|date:"P" }}
-    </li>
-{% if forloop.last %}</ul>{% endif %}
-{% endfor %}
-{% endif %}
-
-{% if object.related_articles.active.count %}
-<hr class="content" />
-
-<h4 class="related-header">Articles Related to "{{ object.title }}"</h4>
-{% for ra in object.related_articles.active %}
-{% if forloop.first %}<ul class="related-articles">{% endif %}
-    <li>
-        <a href="{{ ra.get_absolute_url }}" title="Read this related article">{{ ra.title }}</a>, posted
-        {{ ra.publish_date|naturalday }} at {{ ra.publish_date|date:"P" }}
-    </li>
-{% if forloop.last %}</ul>{% endif %}
-{% endfor %}
-{% endif %}
-
-<hr class="content" />
-
-{% if object.previous_article %}<div>
-    <strong>Previous Article:</strong>
-    <a href="{{ object.previous_article.get_absolute_url }}">{{ object.previous_article.title }}</a>
-</div>{% endif %}
-{% if object.next_article %}<div>
-    <strong>Next Article:</strong>
-    <a href="{{ object.next_article.get_absolute_url }}">{{ object.next_article.title }}</a>
-</div>{% endif %}
-
-{% ifequal page object.page_count %}
-<hr class="content" />
-
-<h4 class="comments-header" id="comments">Comments</h4>
-{% get_comment_list for object as comment_list %}
-{% if comment_list|length %}
-
-{% for comment in comment_list %}
-{% if forloop.first %}<table width="100%" class="comment-list">{% endif %}
-    <tr class="{% ifequal comment.user object.author %}author{% endifequal %} {% if forloop.last %}last{% endif %}" id="c{{ comment.id }}">
-        <td class="avatar">
-            {% if comment.user %}<a href="{% url articles-by-author comment.user_name %}">{% endif %}
-            <img src="{% gravatar_for_email comment.email %}" class="gravatar" alt="Gravatar for {{ comment.user }}" /><br />
-
-            {% if comment.user %}
-            </a><a href="{% url articles-by-author comment.user_name %}">{{ comment.user_name }}</a>
-            {% else %}
-            {{ comment.name|escape }}
-            {% endif %}
-        </td>
-        <td>
-            {{ comment.comment|striptags|escape|linebreaksbr|smileys|safe|urlizetrunc:40 }}
-            <div class="posted-by quiet">
-                Posted on
-                {{ comment.submit_date|date:"j N Y \a\t P" }}
-            </div>
-        </td>
-    </tr>
-{% if forloop.last %}</table>{% endif %}
-{% endfor %}
-{% else %}
-<p>No comments have been posted for this article.</p>
-{% endif %}
-
-<hr class="content" />
-
-<h4 class="postcomment-header">Post a Comment</h4>
-{% render_comment_form for object %}
-{% endifequal %}
-{% endcache %}
-{% endblock %}
+{% endblock %}

File articles/templates/articles/article_list.html

View file
  • Ignore whitespace
-{% extends 'base.html' %}
-{% load articles humanize %}
+{% extends 'articles/base.html' %}
+{% load i18n %}
 
-{% block title %}Article List, page {{ page_obj.number }}{% endblock %}
+{% block title %}{% trans 'Articles' %}{% endblock %}
 
-{% block content %}
-<h2>Article Archives, page {{ page_obj.number }}</h2>
-<div class="quiet">
-    Viewing article{{ page_obj.object_list|length|pluralize }} {{ page_obj.start_index }} - {{ page_obj.end_index }} of {{ paginator.count|intcomma }} total article{{ paginator.count|pluralize }}.
-</div>
+{% block articles-content %}
+<h2>{% trans 'Articles' %}{% ifnotequal paginator.num_pages 1 %}, {% trans 'page' %} {{ page_obj.number }}{% endifnotequal %}</h2>
 
-{% for article in object_list %}
-{% include 'articles/_article_teaser.html' %}
-{% empty %}
-<p>No articles to display.</p>
+{% for article in page_obj.object_list %}
+{% include 'articles/_articles.html' %}
 {% endfor %}
-
-{% if is_paginated %}
-<div class="pagination">
-<ul>
-    {% if page_obj.has_previous %}<li><a href="{% url articles-archive-page page_obj.previous_page_number %}">&lsaquo; newer</a></li>{% endif %}
-    {% for p in paginator.page_range %}
-    <li>
-        {% ifequal p page_obj.number %}<span class="active">{{ p }}</span>
-        {% else %}<a href="{% url articles-archive-page p %}">{{ p }}</a>{% endifequal %}
-    </li>
-    {% endfor %}
-    {% if page_obj.has_next %}<li><a href="{% url articles-archive-page page_obj.next_page_number %}">older &rsaquo;</a></li>{% endif %}
-</ul>
-</div>
-{% endif %}
-{% endblock %}
+{% endblock %}

File articles/templates/articles/article_list_uncategorized.html

  • Ignore whitespace
-{% extends 'base.html' %}
-{% load articles %}
-
-{% block title %}Uncategorized Articles{% endblock %}
-
-{% block content %}
-<h2>Uncategorized Articles ({{ object_list|length }})</h2>
-
-{% for article in object_list %}
-{% include 'articles/_article_teaser.html' %}
-{% empty %}
-<p>No articles to display.</p>
-{% endfor %}
-{% endblock %}

File articles/templates/articles/base.html

View file
  • Ignore whitespace
+{% extends 'base.html' %}
+{% load article_tags i18n %}
+
+{% block content %}
+<div id="article-archives">
+    <h2>{% trans 'Article Archives' %}</h2>
+    {% get_article_archives as archives %}
+    {% for year in archives %}
+    {% if forloop.first %}<ul>{% endif %}
+        <li>
+            <strong>{{ year.0 }}</strong>
+            <ul class="months">
+            {% for month in year.1 %}
+                <li><a href="{% url articles_in_month month.year,month.month %}" title="{% trans 'View articles posted in this month' %}">{{ month|date:"N" }}</a></li>
+            {% endfor %}
+            </ul>
+            <div class="clear">&nbsp;</div>
+        </li>
+    {% if forloop.last %}</ul>{% endif %}
+    {% endfor %}
+</div>
+
+{% block articles-content %}{% endblock %}
+{% endblock %}

File articles/templates/articles/by_author.html

View file
  • Ignore whitespace
+{% extends 'articles/base.html' %}
+{% load i18n %}
+
+{% block title %}{% trans 'Articles By Author' %}: {{ author.get_name }}{% endblock %}
+
+{% block articles-content %}
+<h2>{% trans 'Articles By' %} {{ author.get_name }}{% ifnotequal paginator.num_pages 1 %}, {% trans 'page' %} {{ page_obj.number }}{% endifnotequal %}</h2>
+
+{% for article in page_obj.object_list %}
+{% include 'articles/_articles.html' %}
+{% endfor %}
+{% endblock %}

File articles/templates/articles/category_detail.html

  • Ignore whitespace
-{% extends 'base.html' %}
-{% load articles humanize %}
-
-{% block title %}Article Category: {{ object.name }}, page {{ page_obj.number }}{% endblock %}
-
-{% block keywords %}article, category, {{ object.name }}{% endblock %}
-{% block description %}Articles posted in the {{ object.name }} category.{% endblock %}
-{% block extra-head %}
-<link rel="alternate" type="application/rss+xml" title="Code Koala Blog Articles Tagged: {{ object.name }}" href="/feeds/tags/{{ object.slug }}.rss" />
-{% endblock %}
-
-{% block content %}
-<h2>
-    Article Category: {{ object.name }}, page {{ page_obj.number }}
-    <a href="/feeds/tags/{{ object.slug }}.rss"><img src="/static/images/feed-icon-14x14.png" height="14" width="14" alt="RSS Feed" /></a>
-</h2>
-<div class="quiet">
-    Viewing article{{ page_obj.object_list|length|pluralize }} {{ page_obj.start_index }} - {{ page_obj.end_index }} of {{ paginator.count|intcomma }} total article{{ paginator.count|pluralize }}.
-</div>
-
-{% for article in page_obj.object_list %}
-{% include 'articles/_article_teaser.html' %}
-{% empty %}
-<p>No articles have been posted in this category.</p>
-{% endfor %}
-
-{% if is_paginated %}
-<div class="pagination">
-<ul>
-    {% if page_obj.has_previous %}<li><a href="{% url articles-display-category-page object.slug,page_obj.previous_page_number %}">&lsaquo; newer</a></li>{% endif %}
-    {% for p in paginator.page_range %}
-    <li>
-        {% ifequal p page_obj.number %}<span class="active">{{ p }}</span>
-        {% else %}<a href="{% url articles-display-category-page object.slug,p %}">{{ p }}</a>{% endifequal %}
-    </li>
-    {% endfor %}
-    {% if page_obj.has_next %}<li><a href="{% url articles-display-category-page object.slug,page_obj.next_page_number %}">older &rsaquo;</a></li>{% endif %}
-</ul>
-</div>
-{% endif %}
-{% endblock %}

File articles/templates/articles/display_category.html

View file
  • Ignore whitespace
+{% extends 'articles/base.html' %}
+{% load i18n %}
+
+{% block title %}{% trans 'Articles By Category' %}: {{ category.name }}{% endblock %}
+
+{% block articles-content %}
+<h2>{% trans 'Articles In Category' %} {{ category.name }}{% ifnotequal paginator.num_pages 1 %}, {% trans 'page' %} {{ page_obj.number }}{% endifnotequal %}</h2>
+
+{% for article in page_obj.object_list %}
+{% include 'articles/_articles.html' %}
+{% endfor %}
+{% endblock %}

File articles/templates/articles/in_month.html

View file
  • Ignore whitespace
+{% extends 'articles/base.html' %}
+{% load i18n %}
+
+{% block title %}{% trans 'Articles From' %} {{ month|date:"F Y" }}{% endblock %}
+
+{% block articles-content %}
+<h2>{% trans 'Articles From' %} {{ month|date:"F Y" }}{% ifnotequal paginator.num_pages 1 %}, {% trans 'page' %} {{ page_obj.number }}{% endifnotequal %}</h2>
+
+{% for article in page_obj.object_list %}
+{% include 'articles/_articles.html' %}
+{% endfor %}
+{% endblock %}

File articles/templates/articles/list_articles_by_author.html

  • Ignore whitespace
-{% extends 'base.html' %}
-
-{% block title %}Articles by {{ author }}{% endblock %}
-
-{% block content %}
-<h2>Articles by {{ author }}</h2>
-
-{% if articles %}
-{% for article in articles %}
-{% include 'articles/_article_teaser.html' %}
-{% endfor %}
-{% else %}
-<p>No articles have been posted by this author</p>
-{% endif %}
-{% endblock %}

File articles/templates/articles/list_uncategorized_articles.html

  • Ignore whitespace
-{% extends 'base.html' %}
-
-{% block title %}Uncategorized Articles{% endblock %}
-
-{% block content %}
-<h2>Uncategorized Articles</h2>
-
-{% if articles %}
-{% for article in articles %}
-{% include 'articles/_article_teaser.html' %}
-{% endfor %}
-{% else %}
-<p>There are no uncategorized articles</p>
-{% endif %}
-{% endblock %}

File articles/templates/articles/send_article.html

  • Ignore whitespace
-{% extends 'base.html' %}
-
-{% block title %}Send Article: {{ article.title }}{% endblock %}
-
-{% block keywords %}send article link, e-mail link{% endblock %}
-{% block description %}This page allows you to send a link to {{ article.title }} to people you think might find it useful.{% endblock %}
-
-{% block content %}
-<h2>Send Article: {{ article.title }}</h2>
-
-{% if error %}<ul class="errorlist"><li>{{ error }}</li></ul>{% endif %}
-
-<p>Please fill out the form below in order to send a link to this article to whomever you think would benefit from reading it.</p>
-
-<form action="{% url send-article article.id %}" method="post">
-<table>
-{{ form }}
-    <tr>
-        <td colspan="2" class="buttons">
-            <input type="submit" value="Send Article" />
-        </td>
-    </tr>
-</table>
-</form>
-{% endblock %}

File articles/templates/articles/send_article_email.txt

  • Ignore whitespace
-{{ sender.name }} would like you to read an article entitled "{{ article.title }}" on {{ site.name }}.
-
-{% if message %}A personalized message from {{ sender.name }} follows:
-{{ message }}{% endif %}
-
-Click the following link to read the article!  http://{{ site.domain }}{{ article.get_absolute_url }}
-
-Thanks!

File articles/templatetags/article_tags.py

View file
  • Ignore whitespace
+from django import template
+from articles.models import Article, Category
+from datetime import datetime
+
+register = template.Library()
+
+class GetCategoriesNode(template.Node):
+    def __init__(self, varname):
+        self.varname = varname
+
+    def render(self, context):
+        categories = Category.objects.active()
+        context[self.varname] = categories
+        return ''
+
+def get_article_categories(parser, token):
+    args = token.split_contents()
+    argc = len(args)
+
+    assert argc == 3 and args[1] == 'as'
+
+    return GetCategoriesNode(args[2])
+
+class GetArticlesNode(template.Node):
+    def __init__(self, varname, count=None, start=None, end=None, order='desc'):
+        self.count = count
+        self.start = start
+        self.end = end
+        self.order = order
+        self.varname = varname.strip()
+
+    def render(self, context):
+        if self.order and self.order.lower() == 'desc':
+            order = '-publish_date'
+        else:
+            order = 'publish_date'
+
+        articles = Article.objects.active().order_by(order)
+
+        if self.count:
+            articles = articles[:self.count]
+        else:
+            articles = articles[(int(self.start) - 1):int(self.end)]
+
+        if len(articles) == 1: articles = articles[0]
+
+        context[self.varname] = articles
+        return ''
+
+def get_articles(parser, token):
+    """
+    Retrieves a list of Article objects for use in a template.
+    """
+    args = token.split_contents()
+    argc = len(args)
+
+    assert argc in (4,6) or (argc in (5,7) and args[-1].lower() in ('desc', 'asc'))
+
+    order = 'desc'
+    count = start = end = varname = None
+    if argc == 4: t, count, a, varname = args
+    elif argc == 5: t, count, a, varname, order = args
+    elif argc == 6: t, start, t, end, a, varname = args
+    elif argc == 7: t, start, t, end, a, varname, order = args
+
+    return GetArticlesNode(count=count,
+                           start=start,
+                           end=end,
+                           order=order,
+                           varname=varname)
+
+class GetArticleArchivesNode(template.Node):
+    def __init__(self, varname):
+        self.varname = varname
+
+    def render(self, context):
+        archives = {}
+        for article in Article.objects.active():
+            pub = article.publish_date
+            if not archives.has_key(pub.year):
+                archives[pub.year] = {}
+
+            archives[pub.year][pub.month] = True
+
+        dt_archives = []
+        years = list(int(k) for k in archives.keys())
+        years.sort()
+        years.reverse()
+
+        for year in years:
+            months = []
+            m = list(int(k) for k in archives[year].keys())
+            m.sort()
+            for month in m:
+                months.append(datetime(year, month, 1))
+            dt_archives.append((
+                year, tuple(months)
+            ))
+
+        context[self.varname] = dt_archives
+        return ''
+
+def get_article_archives(parser, token):
+    args = token.split_contents()
+    argc = len(args)
+
+    assert argc == 3
+
+    return GetArticleArchivesNode(args[2])
+
+register.tag(get_articles)
+register.tag(get_article_categories)
+register.tag(get_article_archives)

File articles/templatetags/articles.py

  • Ignore whitespace
-from django import template
-from django.conf import settings
-from django.contrib.auth.models import User
-from django.core.urlresolvers import reverse
-from pygments import highlight
-from pygments.lexers import get_lexer_by_name
-from pygments.formatters import HtmlFormatter
-from ..models import Article, Category
-import datetime, calendar
-
-register = template.Library()
-
-def show_recent_articles(context, count=5):
-    articles = Article.objects.active()[:count]
-    return {'articles': articles}
-register.inclusion_tag('articles/_recent_articles.html', takes_context=True)(show_recent_articles)
-
-def show_categories():
-    return {'categories': Category.objects.active(),
-            'uncategorized': len(Article.objects.uncategorized())}
-register.inclusion_tag('articles/_categories.html')(show_categories)
-
-def get_article_page(article, page=1):
-    return article.get_page(page)
-register.simple_tag(get_article_page)
-
-def month_counts(year):
-    months = [0 for i in range(12)]
-    for a in Article.objects.filter(publish_date__year=int(year)):
-        months[a.publish_date.month - 1] += 1
-    return months
-
-def most_articles_in_a_day(year):
-    return max(day_counts(year))
-register.simple_tag(most_articles_in_a_day)
-
-def most_articles_in_a_month(year):
-    return max(month_counts(year))
-register.simple_tag(most_articles_in_a_month)
-
-def articles_in_months(year):
-    return ','.join([str(c) for c in month_counts(year)])
-register.simple_tag(articles_in_months)

File articles/urls.py

View file
  • Ignore whitespace
 from django.conf.urls.defaults import *
 from django.views.generic import date_based, list_detail
-from .models import Category, Article
-import views
-from datetime import datetime
-
-categories = {
-    'queryset': Category.objects.active().iterator(),
-}
-
-articles = {
-    'queryset': Article.objects.active().iterator(),
-    'date_field': 'publish_date',
-    'extra_context': {'page': 1},
-}
-
-uncategorized = {
-    'queryset': Article.objects.uncategorized(),
-    'paginate_by': 10,
-    'allow_empty': True,
-    'template_name': 'articles/article_list_uncategorized.html'
-}
-
-articles_month = articles.copy()
-articles_month['allow_empty'] = True
-
-articles_year = articles_month.copy()
-articles_year['make_object_list'] = True
-
-articles_archive = articles_month.copy()
-articles_archive['paginate_by'] = 10
-del articles_archive['date_field']
+from articles import views
 
 urlpatterns = patterns('',
-    url(r'^author/(?P<user_id>[-\w]+)/$',
-        views.list_articles_by_author, name='articles_by_author'),
+    (r'^(?P<year>\d{4})/(?P<month>.{3})/(?P<day>\d{1,2})/(?P<slug>.*)/$', views.redirect_to_article),
+    url(r'^(?P<year>\d{4})/(?P<month>\d{1,2})/page/(?P<page>\d+)/$', views.display_blog_page, name='articles_in_month_page'),
+    url(r'^(?P<year>\d{4})/(?P<month>\d{1,2})/$', views.display_blog_page, name='articles_in_month'),
+)
 
-    # categories
-    url(r'^category/(?P<slug>[-\w]+)/$',
-        views.category_detail, name='articles_display_category'),
-    url(r'^category/(?P<slug>[-\w]+)/page/(?P<page>\d+)/$',
-        views.category_detail, name='articles_display_category_page'),
-    url(r'^uncategorized/$',
-        list_detail.object_list, uncategorized, name='articles_display_uncategorized'),
-    url(r'^uncategorized/page/(?P<page>\d+)/$',
-        list_detail.object_list, uncategorized, name='articles_display_uncategorized_page'),
+urlpatterns += patterns('',
+    url(r'^$', views.display_blog_page, name='articles_archive'),
+    url(r'^page/(?P<page>\d+)/$', views.display_blog_page, name='articles_archive_page'),
 
-    # articles
-    url(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/',
-        date_based.object_detail, articles, name='articles_display_article'),
-    url(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/$',
-        date_based.archive_day, articles_month, name='articles_day_archive'),
-    url(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$',
-        date_based.archive_month, articles_month, name='articles_month_archive'),
-    url(r'^(?P<year>\d{4})/$',
-        date_based.archive_year, articles_year, name='articles_year_archive'),
+    url(r'^uncategorized/$', views.display_blog_page, name='articles_uncategorized'),
+    url(r'^uncategorized/page/(?P<page>\d+)/$', views.display_blog_page, name='articles_uncategorized_page'),
 
-    url(r'^$',
-        list_detail.object_list, articles_archive, name='articles_archive'),
-    url(r'^page/(?P<page>\d+)/$',
-        list_detail.object_list, articles_archive, name='articles_archive_page'),
+    url(r'^category/(?P<category>.*)/page/(?P<page>\d+)/$', views.display_blog_page, name='articles_display_category_page'),
+    url(r'^category/(?P<category>.*)/$', views.display_blog_page, name='articles_display_category'),
 
-    url(r'^send/article/(?P<article_id>\d+)/$', views.send_article, name='send_article'),
+    url(r'^author/(?P<username>.*)/page/(?P<page>\d+)/$', views.display_blog_page, name='articles_by_author_page'),
+    url(r'^author/(?P<username>.*)/$', views.display_blog_page, name='articles_by_author'),
+
+    url(r'^(?P<year>\d{4})/(?P<slug>.*)/$', views.display_article, name='articles_display_article'),
 )

File articles/views.py

View file
  • Ignore whitespace
+from django.conf import settings
+from django.contrib.auth.models import User
+from django.core.paginator import Paginator
+from django.http import HttpResponsePermanentRedirect
 from django.shortcuts import render_to_response, get_object_or_404
-from django.template import RequestContext, loader, Context
-from django.contrib.sites.models import Site
-from django.core.mail import send_mail
-from django.contrib.auth.models import User
-from django.core.urlresolvers import reverse
-from django.core.paginator import Paginator
-from django.http import HttpResponseRedirect
-from django.conf import settings
-from .models import Article, Category
-from .forms import SendArticleForm
+from django.template import RequestContext
+from articles.models import Article, Category
+from datetime import datetime
 
-def list_articles_by_author(request, user_id,
-                            template='articles/list_articles_by_author.html'):
-    user = get_object_or_404(User, username=user_id)
+ARTICLE_PAGINATION = getattr(settings, 'ARTICLE_PAGINATION', 20)
+
+def display_blog_page(request, category=None, username=None, year=None, month=None, page=1):
+    context = {}
+
+    if category:
+        category = get_object_or_404(Category, slug=category)
+        articles = category.article_set.all()
+        template = 'articles/display_category.html'
+        context['category'] = category
+    elif username:
+        user = get_object_or_404(User, username=username)
+        articles = user.article_set.all()
+        template = 'articles/by_author.html'
+        context['author'] = user
+    elif year and month:
+        year = int(year)
+        month = int(month)
+        articles = Article.objects.active().filter(publish_date__year=year, publish_date__month=month)
+        template = 'articles/in_month.html'
+        context['month'] = datetime(year, month, 1)
+    else:
+        if request.path.startswith('/uncategorized/'):
+            articles = Article.objects.uncategorized()
+        else:
+            articles = Article.objects.active()
+        template = 'articles/article_list.html'
+
+    paginator = Paginator(articles, ARTICLE_PAGINATION,
+                          orphans=int(ARTICLE_PAGINATION / 4))
+    page = paginator.page(page)
+
+    context.update({'paginator': paginator,
+                    'page_obj': page})
 
     return render_to_response(template,
-                              {'articles': user.article_set.active(),
-                               'author': user},
+                              context,
                               context_instance=RequestContext(request))
 
-def category_detail(request, slug, page=1, \
-                    template='articles/category_detail.html', paginate_by=10):
-    """
-    Displays a blog category and articles that have been assigned to that
-    category.  Articles within a given category are paginated by 10 entries.
-    """
-    category = get_object_or_404(Category,
-                                 slug=slug,
-                                 is_active=True)
-
-    paginator = Paginator(category.article_set.active(),
-                          paginate_by,
-                          orphans=5)
-    page_obj = paginator.page(int(page))
-
+def display_article(request, year, slug, template='articles/article_detail.html'):
+    article = get_object_or_404(Article, publish_date__year=year, slug=slug)
     return render_to_response(template,
-                              {'paginator': paginator,
-                               'page_obj': page_obj,
-                               'object': category,
-                               'is_paginated': (paginator.num_pages > 1)},
+                              {'article': article},
                               context_instance=RequestContext(request))
 
-def display_article_page(request, year, month, day, slug, page):
-    article = get_object_or_404(Article, slug=slug, is_active=True)
-
-    return render_to_response('articles/article_detail.html',
-                              {'object': article, 'page': int(page)},
-                              context_instance=RequestContext(request))
-
-def send_article(request, article_id):
-    article = get_object_or_404(Article,
-                                pk=int(article_id),
-                                is_active=True)
-    error = None
-
-    if request.method == 'POST':
-        form = SendArticleForm(request.POST)
-        if form.is_valid():
-            site = Site.objects.get_current()
-            name = form.cleaned_data['name']
-            email = form.cleaned_data['email']
-
-            c = Context({
-                'article': article,
-                'sender': {
-                    'name': name,
-                    'email': email
-                },
-                'message': form.cleaned_data['message'],
-                'site': site,
-            })
-            t = loader.get_template('articles/send_article_email.txt')
-
-            subject = '%s %s has sent you an article on %s!' % (settings.EMAIL_SUBJECT_PREFIX,
-                                                                name, site.name)
-            message = t.render(c)
-
-            try:
-                for r in form.cleaned_data['receivers'].split(','):
-                    send_mail(subject, message, email, [r.strip()])
-            except:
-                error = 'Failed to send article to %s' % r
-            else:
-                error = '%s was sent to all recipients' % article.title
-
-                return HttpResponseRedirect(article.get_absolute_url())
-    else:
-        form = SendArticleForm()
-
-    return render_to_response('articles/send_article.html',
-                              {'form': form,
-                               'article': article,
-                               'error': error},
-                              context_instance=RequestContext(request))
+def redirect_to_article(request, year, month, day, slug):
+    article = get_object_or_404(Article, publish_date__year=year, slug=slug)
+    return HttpResponsePermanentRedirect(article.get_absolute_url())