diff --git a/CHANGES.rst b/CHANGES.rst index b5d3da8f88..6d63973231 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -13,6 +13,7 @@ Changelog **Changed** +- #1427 Improved performance of Sample header table rendering - #1417 Cache allowed transitions for analyses on the request - #1413 Improved Email Publication diff --git a/bika/lims/browser/analysisrequest/__init__.py b/bika/lims/browser/analysisrequest/__init__.py index f7d6d981ec..2a4f544279 100644 --- a/bika/lims/browser/analysisrequest/__init__.py +++ b/bika/lims/browser/analysisrequest/__init__.py @@ -109,7 +109,12 @@ def __call__(self, request, data): if not self.include_fields or "Analyses" in self.include_fields: data['Analyses'] = self.ar_analysis_values() -class mailto_link_from_contacts: + +class mailto_link_from_contacts(object): + """Custom header table field adapter + + see: bika.lims.browser.header_table + """ def __init__(self, context): self.context = context @@ -127,7 +132,12 @@ def __call__(self, field): return ",".join(ret) -def mailto_link_from_ccemails(ccemails): +class mailto_link_from_ccemails(object): + """Custom header table field adapter + + see: bika.lims.browser.header_table + """ + def __init__(self, context): self.context = context @@ -136,6 +146,7 @@ def __call__(self, field): addresses = ccemails.split(",") ret = [] for address in addresses: + address = address.strip() mailto = "%s" % ( address, address) ret.append(mailto) diff --git a/bika/lims/browser/analysisrequest/configure.zcml b/bika/lims/browser/analysisrequest/configure.zcml index 3f8d33e7a1..a695e2556a 100644 --- a/bika/lims/browser/analysisrequest/configure.zcml +++ b/bika/lims/browser/analysisrequest/configure.zcml @@ -57,6 +57,7 @@ provides="bika.lims.interfaces.IJSONReadExtender" /> + -1 + + @cache(field_type_cache_key, get_cache=store_on_portal) + def is_boolean_field(self, field): + """Check if the field is a boolean + """ + return field.getWidgetName() == "BooleanWidget" + + @cache(field_type_cache_key, get_cache=store_on_portal) + def is_date_field(self, field): + """Check if the field is a date field + """ + return field.getType().lower().find("datetime") > -1 + + def get_boolean_field_data(self, field): + """Get boolean field view data for the template + """ + value = field.get(self.context) + fieldname = field.getName() + + return { + "fieldName": fieldname, + "mode": "structure", + "html": t(_("Yes")) if value else t(_("No")) + } + + def get_reference_field_data(self, field): + """Get reference field view data for the template + """ + targets = None + fieldname = field.getName() + + accessor = getattr(self.context, "get%s" % fieldname, None) + if accessor and callable(accessor): + targets = accessor() + else: + targets = field.get(self.context) + + if targets: + if not isinstance(targets, list): + targets = [targets, ] + + if all([check_permission(view, target) for target in targets]): + elements = [ + "" + .format(id=target.getId(), + uid=target.UID(), + url=target.absolute_url(), + title=target.Title()) + for target in targets] + + return { + "fieldName": fieldname, + "mode": "structure", + "html": "".join(elements), + } + else: + return { + "fieldName": fieldname, + "mode": "structure", + "html": ", ".join([ta.Title() for ta in targets]), + } + + return { + "fieldName": fieldname, + "mode": "structure", + "html": "" + } + + def get_date_field_data(self, field): + """Render date field view data for the template + """ + value = field.get(self.context) + fieldname = field.getName() + + return { + "fieldName": fieldname, + "mode": "structure", + "html": self.ulocalized_time(value, long_format=True) + } + def three_column_list(self, input_list): list_len = len(input_list) @@ -84,82 +195,37 @@ def _list_end(num): final.append(column) return final - # TODO Revisit this def render_field_view(self, field): fieldname = field.getName() - field = self.context.Schema()[fieldname] - ret = {"fieldName": fieldname, "mode": "view"} - try: - adapter = getAdapter(self.context, - interface=IHeaderTableFieldRenderer, - name=fieldname) - - except ComponentLookupError: - adapter = None - if adapter: - ret = {'fieldName': fieldname, - 'mode': 'structure', - 'html': adapter(field)} - else: - if field.getWidgetName() == "BooleanWidget": - value = field.get(self.context) - ret = { - "fieldName": fieldname, - "mode": "structure", - "html": t(_("Yes")) if value else t(_("No")) - } - elif field.getType().find("Reference") > -1: - # Prioritize method retrieval over schema"s field - targets = None - if hasattr(self.context, "get%s" % fieldname): - fieldaccessor = getattr(self.context, "get%s" % fieldname) - if callable(fieldaccessor): - targets = fieldaccessor() - if not targets: - targets = field.get(self.context) - - if targets: - if not type(targets) == list: - targets = [targets, ] - sm = getSecurityManager() - if all([sm.checkPermission(view, ta) for ta in targets]): - elements = [ - "" - .format(id=target.getId(), - uid=target.UID(), - url=target.absolute_url(), - title=target.Title()) - for target in targets] - - ret = { - "fieldName": fieldname, - "mode": "structure", - "html": "".join(elements), - } - else: - ret = { - "fieldName": fieldname, - "mode": "structure", - "html": ", ".join([ta.Title() for ta in targets]), - } - else: - ret = { - "fieldName": fieldname, - "mode": "structure", - "html": "", - } - elif field.getType().lower().find("datetime") > -1: - value = field.get(self.context) - ret = { - "fieldName": fieldname, + + # lookup custom render adapter + adapter = queryAdapter(self.context, + interface=IHeaderTableFieldRenderer, + name=fieldname) + + # Note: Adapters for contact fields: + # bika.lims.browser.analysisrequest.mailto_link_from_contacts + # bika.lims.browser.analysisrequest.mailto_link_from_ccemails + # + # -> TODO Remove? + + # return immediately if we have an adapter + if adapter is not None: + return {"fieldName": fieldname, "mode": "structure", - "html": self.ulocalized_time(value, long_format=True) - } - return ret + "html": adapter(field)} + + # field data for *view* mode for the template + data = {"fieldName": fieldname, "mode": "view"} + + if self.is_boolean_field(field): + data = self.get_boolean_field_data(field) + elif self.is_reference_field(field): + data = self.get_reference_field_data(field) + elif self.is_date_field(field): + data = self.get_date_field_data(field) + + return data def get_field_visibility_mode(self, field): """Returns "view" or "edit" modes, together with the place within where @@ -179,8 +245,7 @@ def get_field_visibility_mode(self, field): # modes) only if the current user has enough privileges. if field.checkPermission("edit", self.context): mode = "edit" - sm = getSecurityManager() - if not sm.checkPermission(ModifyPortalContent, self.context): + if not self.is_edit_allowed(): logger.warn("Permission '{}' granted for the edition of '{}', " "but 'Modify portal content' not granted" .format(field.write_permission, field.getName())) diff --git a/bika/lims/browser/templates/header_table.pt b/bika/lims/browser/templates/header_table.pt index 34ca0b119a..22f48884db 100644 --- a/bika/lims/browser/templates/header_table.pt +++ b/bika/lims/browser/templates/header_table.pt @@ -12,12 +12,9 @@
@@ -86,13 +83,13 @@ - + i18n:attributes="value label_save;"/>