diff --git a/MANIFEST.in b/MANIFEST.in
index d688a50c6..b0f3135c7 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -8,3 +8,4 @@ recursive-include data/themes/default/ *.html *.css *.png *.gif *.jpg *.js *.ezt
recursive-include data/themes/alto/ *.html *.css *.png *.gif *.jpg *.js *.ezt *.xml
recursive-include data/vendor/ *.dat
recursive-include wcs/qommon/static/ *.css *.png *.gif *.jpg *.js *.eot *.svg *.ttf *.woff
+recursive-include wcs/templates *.html
diff --git a/tests/test_workflows.py b/tests/test_workflows.py
index de9391d6c..8768653d5 100644
--- a/tests/test_workflows.py
+++ b/tests/test_workflows.py
@@ -521,30 +521,38 @@ def test_register_comment(pub):
item = RegisterCommenterWorkflowStatusItem()
item.perform(formdata)
+ formdata.evolution[-1]._display_parts = None
assert formdata.evolution[-1].display_parts()[-1] == ''
item.comment = 'Hello world'
item.perform(formdata)
+ formdata.evolution[-1]._display_parts = None
assert formdata.evolution[-1].display_parts()[-1] == '
Hello world
'
item.comment = 'Hello world
'
item.perform(formdata)
+ formdata.evolution[-1]._display_parts = None
assert formdata.evolution[-1].display_parts()[-1] == 'Hello world
'
item.comment = '[test]'
item.perform(formdata)
+ formdata.evolution[-1]._display_parts = None
assert formdata.evolution[-1].display_parts()[-1] == '[test]
'
item.comment = '[bar]'
item.perform(formdata)
+ formdata.evolution[-1]._display_parts = None
+ formdata.evolution[-1]._display_parts = None
assert formdata.evolution[-1].display_parts()[-1] == 'Foobar
'
item.comment = '[foo]'
item.perform(formdata)
+ formdata.evolution[-1]._display_parts = None
assert formdata.evolution[-1].display_parts()[-1] == '1 < 3
'
item.comment = '[foo]
'
item.perform(formdata)
+ formdata.evolution[-1]._display_parts = None
assert formdata.evolution[-1].display_parts()[-1] == '1 < 3
'
def test_register_comment_attachment(pub):
@@ -561,6 +569,7 @@ def test_register_comment_attachment(pub):
item = RegisterCommenterWorkflowStatusItem()
item.perform(formdata)
+ formdata.evolution[-1]._display_parts = None
assert formdata.evolution[-1].display_parts()[-1] == ''
if os.path.exists(os.path.join(get_publisher().app_dir, 'attachments')):
diff --git a/wcs/formdata.py b/wcs/formdata.py
index b6b0fab0e..03697f891 100644
--- a/wcs/formdata.py
+++ b/wcs/formdata.py
@@ -143,17 +143,29 @@ class Evolution(object):
return self._formdata
def get_author_name(self):
+ user_id = self.who
if self.who == '_submitter':
+ user_id = self.formdata.user_id
+ try:
+ return get_publisher().user_class.get(user_id).display_name
+ except KeyError:
+ return None
+
+ def get_author_qualification(self):
+ if self.who == '_submitter' and not self.formdata.is_submitter(get_request().user):
return _('Original Submitter')
- else:
- return get_publisher().user_class.get(self.who).display_name
+ return None
def add_part(self, part):
if not self.parts:
self.parts = []
self.parts.append(part)
+ _display_parts = None # cache
def display_parts(self):
+ if self._display_parts is not None:
+ return self._display_parts
+
if not self.parts:
return []
@@ -162,7 +174,8 @@ class Evolution(object):
if not hasattr(p, 'view'):
continue
l.append(p.view())
- return l
+ self._display_parts = l
+ return self._display_parts
def get_json_export_dict(self, user, anonymise=False):
data = {
@@ -194,8 +207,27 @@ class Evolution(object):
odict = self.__dict__.copy()
if odict.has_key('_formdata'):
del odict['_formdata']
+ if odict.has_key('_display_parts'):
+ del odict['_display_parts']
return odict
+ @property
+ def datetime(self):
+ return datetime.datetime(*self.time[:6])
+
+ def is_hidden(self):
+ if self.status:
+ wf_status = self.formdata.get_status(self.status)
+ if wf_status and not wf_status.is_visible(self.formdata, get_request().user):
+ return True
+ return False
+
+ def get_status(self):
+ return self.formdata.get_status(status=self.status)
+
+ def get_status_label(self):
+ return self.formdata.get_status_label(status=self.status)
+
class FormData(StorableObject):
_names = 'XX'
@@ -451,6 +483,22 @@ class FormData(StorableObject):
return wf_status
return None
+ def get_visible_evolution_parts(self):
+ last_seen_status = None
+ last_seen_author = None
+ for evolution_part in self.evolution or []:
+ if evolution_part.is_hidden():
+ continue
+ if (evolution_part.status is None or last_seen_status == evolution_part.status) and (
+ evolution_part.who is None or last_seen_author == evolution_part.who):
+ # don't include empty evolution parts if status and author
+ # didn't change.
+ if not evolution_part.comment and not evolution_part.display_parts():
+ continue
+ last_seen_status = evolution_part.status or last_seen_status
+ last_seen_author = evolution_part.who or last_seen_author
+ yield evolution_part
+
def get_workflow_form(self, user):
wf_status = self.get_status()
if not wf_status:
diff --git a/wcs/forms/common.py b/wcs/forms/common.py
index 6397c721b..cebae12cd 100644
--- a/wcs/forms/common.py
+++ b/wcs/forms/common.py
@@ -25,6 +25,8 @@ from wcs.api_utils import get_user_from_api_query_string, is_url_signed
from wcs.fields import WidgetField, FileField
from wcs.workflows import EditableWorkflowStatusItem
+from django.template import RequestContext
+
from qommon import _
from qommon import template
from qommon import get_logger
@@ -94,6 +96,8 @@ class FormStatusPage(Directory):
_q_extra_exports = []
form_page_class = None
+ history_templates = ['wcs/formdata_history.html']
+
def html_top(self, title = None):
template.html_top(title = title, default_org = _('Forms'))
@@ -251,108 +255,9 @@ class FormStatusPage(Directory):
return
if not self.formdef.is_user_allowed_read_status_and_history(get_request().user, self.filled):
return
- r = TemplateIO(html=True)
- r += htmltext('')
- r += htmltext('
%s
') % _('Log')
- r += htmltext('
')
- hidden = False
- previous_status = None
- for evo in self.filled.evolution:
- status_css_class = ''
- if evo.status:
- wf_status = self.filled.get_status(evo.status)
- if wf_status:
- status_css_class = wf_status.extra_css_class
- if wf_status and not wf_status.is_visible(self.filled, get_request().user):
- hidden = True
- else:
- hidden = False
- if hidden:
- continue
- evo_author = None
- evo_author_more = None
- klass = 'msg-system'
- if evo.who:
- if evo.who == '_submitter':
- klass = 'msg-in'
- evo_author = _('Original Submitter')
- if get_request().user and self.filled.is_submitter(get_request().user):
- evo_author = get_request().user.display_name
- elif self.filled.user_id:
- try:
- evo_author = get_publisher().user_class.get(self.filled.user_id).display_name
- evo_author_more = _('(Original Submitter)')
- except KeyError:
- pass
- else:
- klass = 'msg-out'
- try:
- evo_author = evo.get_author_name()
- except KeyError:
- pass
-
- status_block = TemplateIO(html=True)
- if evo.status:
- status_block += htmltext('')
- status_block += htmltext('%s '
- ) % self.filled.get_status_label(evo.status)
- status_block += htmltext('%s '
- ) % misc.localstrftime(evo.time)
- status_block += htmltext('
') # <-- .evolution-metadata -->
-
- parts = TemplateIO(html=True)
- if evo_author:
- parts += htmltext('%s') % evo_author
- if evo_author_more:
- parts += htmltext(' %s') % evo_author_more
- parts += htmltext('')
- if not evo.status:
- parts += htmltext('%s ') % misc.localstrftime(evo.time)
-
- if evo.comment:
- if evo.comment.startswith(str('#pre')):
- parts += htmltext('') % evo.comment[4:]
- else:
- parts += htmltext('')
- for t in evo.display_parts():
- parts += t
-
- parts_value = parts.getvalue()
-
- if not (parts_value or evo.status != previous_status):
- continue
-
- if evo.status:
- previous_status = evo.status
-
- try:
- status_colour = self.filled.get_status(previous_status).colour
- except AttributeError:
- status_colour = 'ffffff'
- fg_colour = misc.get_foreground_colour(status_colour)
-
- r += htmltext('- ' % (klass, status_css_class))
- r += htmltext('' %
- (status_colour, fg_colour))
- r += htmltext('
')
- r += status_block.getvalue()
-
- if parts_value:
- r += htmltext('
')
- r += htmltext(parts_value)
- r += htmltext('
')
-
- r += htmltext('
')
- r += htmltext(' ')
- r += htmltext('
')
- r += htmltext('
') # .bo-block #evolution-log
- return r.getvalue()
+ context = RequestContext(get_request(), {'formdata': self.filled})
+ return template.render(self.history_templates, context)
def check_receiver(self):
session = get_session()
diff --git a/wcs/forms/root.py b/wcs/forms/root.py
index ab9dbf034..c0471d26f 100644
--- a/wcs/forms/root.py
+++ b/wcs/forms/root.py
@@ -1577,6 +1577,7 @@ class RootDirectory(AccessControlled, Directory):
class PublicFormStatusPage(FormStatusPage):
_q_exports_orig = ['', 'download', 'status']
form_page_class = FormPage
+ history_templates = ['wcs/front/formdata_history.html', 'wcs/formdata_history.html']
def __init__(self, *args, **kwargs):
FormStatusPage.__init__(self, *args, **kwargs)
diff --git a/wcs/qommon/template.py b/wcs/qommon/template.py
index cd02358ec..e6eab9998 100644
--- a/wcs/qommon/template.py
+++ b/wcs/qommon/template.py
@@ -19,6 +19,8 @@ import os
import glob
import xml.etree.ElementTree as ET
+from django.template.loader import render_to_string
+
from quixote import get_session, get_request, get_response, get_publisher
from quixote.directory import Directory
from quixote.util import StaticDirectory, StaticFile
@@ -405,3 +407,7 @@ def decorate(body, response):
template.generate(fd, vars)
return fd.getvalue()
+
+
+def render(template_name, context):
+ return htmltext(render_to_string(template_name, context).encode('utf-8'))
diff --git a/wcs/templates/wcs/formdata_history.html b/wcs/templates/wcs/formdata_history.html
new file mode 100644
index 000000000..e85f4d3eb
--- /dev/null
+++ b/wcs/templates/wcs/formdata_history.html
@@ -0,0 +1,39 @@
+{% load i18n %}
+
+
{% trans "Log" %}
+
+ {% for evolution in formdata.get_visible_evolution_parts %}
+ {% with status=evolution.get_status display_parts=evolution.display_parts %}
+
+ {% endwith %}
+ {% endfor %}
+
+
diff --git a/wcs/workflows.py b/wcs/workflows.py
index 67fe86f11..dff5ce50c 100644
--- a/wcs/workflows.py
+++ b/wcs/workflows.py
@@ -29,7 +29,7 @@ import uuid
from quixote import get_request, redirect
from qommon import _
-from qommon.misc import C_, get_as_datetime, file_digest
+from qommon.misc import C_, get_as_datetime, file_digest, get_foreground_colour
from qommon.storage import StorableObject, atomic_write
from qommon.form import *
from qommon.humantime import seconds2humanduration
@@ -1411,6 +1411,10 @@ class WorkflowStatus(object):
waitpoint = item.waitpoint or waitpoint
return bool(endpoint or waitpoint)
+ def get_contrast_color(self):
+ colour = self.colour or 'ffffff'
+ return misc.get_foreground_colour(colour)
+
def __getstate__(self):
odict = self.__dict__.copy()
if odict.has_key('parent'):