Skip to content
This repository has been archived by the owner on Aug 26, 2022. It is now read-only.

Commit

Permalink
Add Jinja function datetimeformat, use babel and pytz, add tests, add…
Browse files Browse the repository at this point in the history
… 'New thread' link.
  • Loading branch information
Paul Craciunoiu committed May 12, 2010
1 parent 0c729c1 commit aa13ae9
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 18 deletions.
2 changes: 1 addition & 1 deletion apps/forums/templates/posts.html
Expand Up @@ -29,7 +29,7 @@ <h2>{{ thread.title }}</h2>
{{ post.content }}
</div>
<div class="info">
{{ post.created.strftime(_('%a %d of %b, %Y %H:%M %Z', 'forum_post_date')) }}
{{ datetimeformat(post.created, format='longdatetime') }}
<a href="#post-{{ post.id }}" class="permalink" title="{{ _('Link to this post.') }}">#</a>
<span class="post-action">
<a href="#thread-reply">{{ _('Reply') }}</a>
Expand Down
4 changes: 3 additions & 1 deletion apps/forums/templates/threads.html
Expand Up @@ -7,8 +7,10 @@
{% block content %}
<h2>{{ forum.name }}</h2>

<a id="new-question" href="{{ url('forums.new_thread', forum_slug=forum.slug) }}">{{ _('Post a new thread') }}</a>

<ol class="threads-columns {% if not desc_toggle %}desc{% endif %}">
<li class="type">{{ _('Type') }}</li>
<li class="type"><a href="{{ url('forums.threads', forum_slug=forum.slug) }}">{{ _('Type') }}</a></li>
<li class="title">{{ _('Title') }}</a></li>
<li class="author{% if sort == 3 %} sort{% endif %}"><a href="{{ request.path|urlparams(sort=3, desc=desc_toggle) }}">{{ _('Author') }}</a></li>
<li class="replies{% if sort == 4 %} sort{% endif %}"><a href="{{ request.path|urlparams(sort=4, desc=desc_toggle) }}">{{ _('Replies') }}</a></li>
Expand Down
44 changes: 33 additions & 11 deletions apps/sumo/helpers.py
@@ -1,6 +1,6 @@
import cgi
import urlparse
import time
import datetime

from django.utils.encoding import smart_unicode
from django.conf import settings
Expand All @@ -9,12 +9,17 @@
from jingo import register, env
from tower import ugettext_lazy as _lazy
from babel import localedata
from babel.dates import format_date, format_time
from babel.dates import format_date, format_time, format_datetime
from pytz import timezone

from sumo.urlresolvers import reverse
from sumo.utils import urlencode


class DateTimeFormatError(Exception):
pass


@register.filter
def paginator(pager):
return Paginator(pager).render()
Expand Down Expand Up @@ -139,22 +144,39 @@ def profile_url(user):

@register.function
@jinja2.contextfunction
def datetimeformat(context, value, format_delimiter=86400):
def datetimeformat(context, value, format='shortdatetime'):
"""
Returns date/time formatted using babel's locale settings. If the date is
within `format_delimiter` seconds from the present, the time is shown,
otherwise the date is shown.
Set `format_delimiter=0` to always show the date.
Returns date/time formatted using babel's locale settings. Uses the
timezone from settings.py
"""
if not isinstance(value, datetime.datetime):
# Expecting date value
raise ValueError

tzinfo = timezone(settings.TIME_ZONE)
tzvalue = tzinfo.localize(value)
# Babel uses underscore as separator.
locale = context['request'].locale
if not localedata.exists(locale):
locale = settings.LANGUAGE_CODE
locale = locale.replace('-', '_')

# If within a day, 24 * 60 * 60 = 86400s
if abs(time.time() - time.mktime(value.timetuple())) < format_delimiter:
return format_time(value, locale=locale)
if format == 'shortdatetime':
# Check if the date is today
if value.toordinal() == datetime.date.today().toordinal():
return _lazy('Today at %s') % format_time(
tzvalue, format='short', locale=locale)
else:
return format_datetime(tzvalue, format='short', locale=locale)
elif format == 'longdatetime':
return format_datetime(tzvalue, format='long', locale=locale)
elif format == 'date':
return format_date(tzvalue, locale=locale)
elif format == 'time':
return format_time(tzvalue, locale=locale)
elif format == 'datetime':
return format_datetime(tzvalue, locale=locale)
else:
return format_date(value, locale=locale)
# Unknown format
raise DateTimeFormatError
93 changes: 89 additions & 4 deletions apps/sumo/tests/test_helpers.py
@@ -1,13 +1,20 @@
# -*- coding: utf-8 -*-
import datetime

from nose.tools import eq_
from nose.tools import assert_raises
import test_utils

from django.conf import settings
from django.test import TestCase
from django.contrib.auth.models import User

import jingo
from babel.dates import format_date, format_time, format_datetime
from pytz import timezone

from sumo.helpers import profile_url
from sumo.helpers import profile_url, datetimeformat, DateTimeFormatError
from sumo.urlresolvers import reverse


def render(s, context={}):
Expand All @@ -17,7 +24,7 @@ def render(s, context={}):

class TestHelpers(TestCase):

def setup(self):
def setUp(self):
jingo.load_helpers()

def test_fe_helper(self):
Expand All @@ -41,6 +48,84 @@ def test_urlparams_unicode(self):
eq_(u'/en-US/search?q=Fran%C3%A7ais', render(template, context))

def test_profile_url(self):
user = User.objects.create(username='testuser')
user = User.objects.create(pk=500000, username=u'testuser')
eq_(profile_url(user),
'/tiki-user_information.php?locale=en-US&userId=%s' % user.id)
u'/tiki-user_information.php?locale=en-US&userId=500000')


class TestDateTimeFormat(TestCase):

def setUp(self):
url = reverse('forums.threads', args=[u'testslug'])
self.context = {'request': test_utils.RequestFactory().get(url)}
self.context['request'].locale = u'en-US'

def test_today(self):
"""Expects shortdatetime, format: Today at {time}."""
date_today = datetime.datetime.today()
value_returned = unicode(datetimeformat(self.context, date_today))
value_expected = 'Today at %s' % format_time(date_today,
format='short',
locale=u'en_US')
eq_(value_returned, value_expected)

def test_locale(self):
"""Expects shortdatetime in French."""
self.context['request'].locale = u'fr'
value_test = datetime.datetime.fromordinal(733900)
value_expected = format_datetime(value_test, format='short',
locale=u'fr')
value_returned = datetimeformat(self.context, value_test)
eq_(value_returned, value_expected)

def test_default(self):
"""Expects shortdatetime."""
value_test = datetime.datetime.fromordinal(733900)
value_expected = format_datetime(value_test, format='short',
locale=u'en_US')
value_returned = datetimeformat(self.context, value_test)
eq_(value_returned, value_expected)

def test_longdatetime(self):
"""Expects long format."""
value_test = datetime.datetime.fromordinal(733900)
tzvalue = timezone(settings.TIME_ZONE).localize(value_test)
value_expected = format_datetime(tzvalue, format='long',
locale=u'en_US')
value_returned = datetimeformat(self.context, value_test,
format='longdatetime')
eq_(value_returned, value_expected)

def test_date(self):
"""Expects date format."""
value_test = datetime.datetime.fromordinal(733900)
value_expected = format_date(value_test, locale=u'en_US')
value_returned = datetimeformat(self.context, value_test,
format='date')
eq_(value_returned, value_expected)

def test_time(self):
"""Expects time format."""
value_test = datetime.datetime.fromordinal(733900)
value_expected = format_time(value_test, locale=u'en_US')
value_returned = datetimeformat(self.context, value_test,
format='time')
eq_(value_returned, value_expected)

def test_datetime(self):
"""Expects datetime format."""
value_test = datetime.datetime.fromordinal(733900)
value_expected = format_datetime(value_test, locale=u'en_US')
value_returned = datetimeformat(self.context, value_test,
format='datetime')
eq_(value_returned, value_expected)

def test_unknown_format(self):
"""Unknown format raises DateTimeFormatError."""
date_today = datetime.datetime.today()
assert_raises(DateTimeFormatError, datetimeformat, self.context,
date_today, format='unknown')

def test_invalid_value(self):
"""Passing invalid value raises ValueError."""
assert_raises(ValueError, datetimeformat, self.context, 'invalid')
9 changes: 9 additions & 0 deletions media/css/forums.css
Expand Up @@ -116,6 +116,15 @@ ol.posts li div.author a {
color: green;
font-weight: bold;
}

#new-question {
background: url(../img/forums/arrow.png) no-repeat scroll left center transparent;
float: left;
font-size: 115%;
margin: 0 0 1em 10px;
padding-left: 10px;
}

ol.posts li div.author a {
display: block;
}
Expand Down
Binary file added media/img/forums/arrow.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions requirements.txt
Expand Up @@ -26,3 +26,6 @@ South==0.7
# commonware, stuff we share
-e git://github.com/jsocol/commonware.git#egg=commonware

# timezone package used with babel
pytz

2 changes: 1 addition & 1 deletion settings.py
Expand Up @@ -51,7 +51,7 @@
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Los_Angeles'
TIME_ZONE = 'US/Pacific'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
Expand Down

0 comments on commit aa13ae9

Please sign in to comment.