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:
parent
857ccf9ccc
commit
ff7049432b
@ -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 = []
|
||||
|
@ -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
|
||||
|
@ -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"),
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user