Handle "null" time values for Stacks

The timesince filter expects a date or datetime object, and would fail
when receiving an empty string. Create a new filter that returns the
string value "Never" under these circumstances.

Change-Id: I73f4dbb608fc143c3ac60d753e9e222762579e51
Closes-Bug: #1286959
This commit is contained in:
Julie Pichon 2014-03-12 16:31:06 +00:00
parent 857ccf9ccc
commit ff7049432b
6 changed files with 75 additions and 10 deletions

View File

@ -15,11 +15,11 @@
# under the License.
import datetime
import os
from django.core.exceptions import ValidationError # noqa
import django.template
from django.template import defaultfilters
from horizon.test import helpers as test
from horizon.utils import fields
@ -288,6 +288,50 @@ class FiltersTests(test.TestCase):
self.assertIsInstance(result, datetime.datetime)
class TimeSinceNeverFilterTests(test.TestCase):
default = u"Never"
def test_timesince_or_never_returns_default_for_empty_string(self):
c = django.template.Context({'time': ''})
t = django.template.Template('{{time|timesince_or_never}}')
self.assertEqual(t.render(c), self.default)
def test_timesince_or_never_returns_default_for_none(self):
c = django.template.Context({'time': None})
t = django.template.Template('{{time|timesince_or_never}}')
self.assertEqual(t.render(c), self.default)
def test_timesince_or_never_returns_default_for_gibberish(self):
c = django.template.Context({'time': django.template.Context()})
t = django.template.Template('{{time|timesince_or_never}}')
self.assertEqual(t.render(c), self.default)
def test_timesince_or_never_returns_with_custom_default(self):
custom = "Hello world"
c = django.template.Context({'date': ''})
t = django.template.Template('{{date|timesince_or_never:"%s"}}'
% custom)
self.assertEqual(t.render(c), custom)
def test_timesince_or_never_returns_with_custom_empty_string_default(self):
c = django.template.Context({'date': ''})
t = django.template.Template('{{date|timesince_or_never:""}}')
self.assertEqual(t.render(c), "")
def test_timesince_or_never_returns_same_output_as_django_date(self):
d = datetime.date(year=2014, month=3, day=7)
c = django.template.Context({'date': d})
t = django.template.Template('{{date|timesince_or_never}}')
self.assertEqual(t.render(c), defaultfilters.timesince(d))
def test_timesince_or_never_returns_same_output_as_django_datetime(self):
now = datetime.datetime.now()
c = django.template.Context({'date': now})
t = django.template.Template('{{date|timesince_or_never}}')
self.assertEqual(t.render(c), defaultfilters.timesince(now))
class MemoizedTests(test.TestCase):
def test_memoized_decorator_cache_on_next_call(self):
values_list = []

View File

@ -14,12 +14,15 @@
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import iso8601
from django.template.defaultfilters import register # noqa
from django.template.defaultfilters import timesince # noqa
from django.utils.safestring import mark_safe
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
@register.filter
@ -38,6 +41,21 @@ def parse_isotime(timestr, default=None):
return default or ''
@register.filter
def timesince_or_never(dt, default=None):
"""Call the Django ``timesince`` filter, but return the string
*default* if *dt* is not a valid ``date`` or ``datetime`` object.
When *default* is None, "Never" is returned.
"""
if default is None:
default = _("Never")
if isinstance(dt, datetime.date):
return timesince(dt)
else:
return default
@register.filter
def timesince_sortable(dt):
delta = timezone.now() - dt

View File

@ -14,7 +14,6 @@
from django.core import urlresolvers
from django.http import Http404 # noqa
from django.template.defaultfilters import timesince # noqa
from django.template.defaultfilters import title # noqa
from django.utils.http import urlencode # noqa
from django.utils.translation import ugettext_lazy as _
@ -90,10 +89,12 @@ class StacksTable(tables.DataTable):
link="horizon:project:stacks:detail",)
created = tables.Column("creation_time",
verbose_name=_("Created"),
filters=(filters.parse_isotime, timesince))
filters=(filters.parse_isotime,
filters.timesince_or_never))
updated = tables.Column("updated_time",
verbose_name=_("Updated"),
filters=(filters.parse_isotime, timesince))
filters=(filters.parse_isotime,
filters.timesince_or_never))
status = tables.Column("status",
filters=(title, filters.replace_underscores),
verbose_name=_("Status"),
@ -123,7 +124,8 @@ class EventsTable(tables.DataTable):
link=mappings.resource_to_url)
timestamp = tables.Column('event_time',
verbose_name=_("Time Since Event"),
filters=(filters.parse_isotime, timesince))
filters=(filters.parse_isotime,
filters.timesince_or_never))
status = tables.Column("resource_status",
filters=(title, filters.replace_underscores),
verbose_name=_("Status"),)
@ -169,7 +171,8 @@ class ResourcesTable(tables.DataTable):
verbose_name=_("Stack Resource Type"),)
updated_time = tables.Column('updated_time',
verbose_name=_("Date Updated"),
filters=(filters.parse_isotime, timesince))
filters=(filters.parse_isotime,
filters.timesince_or_never))
status = tables.Column("resource_status",
filters=(title, filters.replace_underscores),
verbose_name=_("Status"),

View File

@ -20,9 +20,9 @@
<hr class="header_rule">
<dl>
<dt>{% trans "Created" %}</dt>
<dd>{{ stack.creation_time|parse_isotime|timesince }}</dd>
<dd>{{ stack.creation_time|parse_isotime|timesince_or_never }}</dd>
<dt>{% trans "Last Updated" %}</dt>
<dd>{{ stack.updated_time|parse_isotime|timesince }}</dd>
<dd>{{ stack.updated_time|parse_isotime|timesince_or_never }}</dd>
<dt>{% trans "Status" %}</dt>
<dd>{{ stack.stack_status|title }}: {{ stack.stack_status_reason }}</dd>
</dl>

View File

@ -32,7 +32,7 @@
<hr class="header_rule">
<dl>
<dt>{% trans "Last Updated" %}</dt>
<dd>{{ resource.updated_time|parse_isotime|timesince }}</dd>
<dd>{{ resource.updated_time|parse_isotime|timesince_or_never }}</dd>
<dt>{% trans "Status" %}</dt>
<dd>{{ resource.resource_status|title|replace_underscores }}: {{ resource.resource_status_reason }}</dd>
</dl>

View File

@ -353,7 +353,7 @@ def data(TEST):
"stack_status_reason": "Stack successfully created",
"stack_name": "stack-test",
"creation_time": "2013-04-22T00:11:39Z",
"updated_time": "2013-04-22T00:11:39Z",
"updated_time": "null",
"stack_status": "CREATE_COMPLETE",
"id": "05b4f39f-ea96-4d91-910c-e758c078a089"
}