From 8a9c2ffc7a27c5ebbc5a91716181a6e79a513e51 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 22:45:43 +0200 Subject: [PATCH 01/27] Cache permission lookup --- bika/lims/browser/header_table.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 6d7f41dc60..41f9e7cffd 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -25,6 +25,8 @@ from bika.lims.browser import BrowserView from bika.lims.interfaces import IHeaderTableFieldRenderer from bika.lims.utils import t +from plone.memoize import view as viewcache +from bika.lims.api import security from Products.Archetypes.event import ObjectEditedEvent from Products.CMFCore.permissions import ModifyPortalContent from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile @@ -66,6 +68,11 @@ def __call__(self): self.context.plone_utils.addPortalMessage(message, "info") return self.template() + @viewcache.memoize + def is_edit_allowed(self): + """Check permission 'ModifyPortalContent' on the context + """ + return security.check_permission(ModifyPortalContent, self.context) def three_column_list(self, input_list): list_len = len(input_list) @@ -179,8 +186,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())) From 9ffe88125f0712e0d956067767549561e81ed6a2 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 22:47:20 +0200 Subject: [PATCH 02/27] Use queryAdapter instead of getAdapter --- bika/lims/browser/header_table.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 41f9e7cffd..c46694340a 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -31,8 +31,7 @@ from Products.CMFCore.permissions import ModifyPortalContent from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile from zope import event -from zope.component import getAdapter -from zope.component.interfaces import ComponentLookupError +from zope.component import queryAdapter class HeaderTableView(BrowserView): @@ -96,17 +95,13 @@ 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)} + adapter = queryAdapter(self.context, + interface=IHeaderTableFieldRenderer, + name=fieldname) + if adapter is not None: + ret = {"fieldName": fieldname, + "mode": "structure", + "html": adapter(field)} else: if field.getWidgetName() == "BooleanWidget": value = field.get(self.context) From 20d5657c66f035e0c2054f8ccb4b3f63794f06a8 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 22:53:43 +0200 Subject: [PATCH 03/27] Whitespace only --- bika/lims/browser/header_table.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index c46694340a..551d042a5a 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -72,6 +72,7 @@ def is_edit_allowed(self): """Check permission 'ModifyPortalContent' on the context """ return security.check_permission(ModifyPortalContent, self.context) + def three_column_list(self, input_list): list_len = len(input_list) From d8d722a16884b2526f4ed3dcf05b2f4b4dca0bdb Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 22:58:49 +0200 Subject: [PATCH 04/27] Reduced code complexity --- bika/lims/browser/header_table.py | 109 ++++++++++++++++-------------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 551d042a5a..61ef43934a 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -99,69 +99,74 @@ def render_field_view(self, field): adapter = queryAdapter(self.context, interface=IHeaderTableFieldRenderer, name=fieldname) + + # return immediately if we have an adapter if adapter is not None: - ret = {"fieldName": fieldname, - "mode": "structure", - "html": adapter(field)} - else: - if field.getWidgetName() == "BooleanWidget": - value = field.get(self.context) - ret = { - "fieldName": fieldname, + return {"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]), - } + "html": adapter(field)} + + 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": "", + "html": ", ".join([ta.Title() for ta in targets]), } - elif field.getType().lower().find("datetime") > -1: - value = field.get(self.context) + else: ret = { "fieldName": fieldname, "mode": "structure", - "html": self.ulocalized_time(value, long_format=True) + "html": "", } + + elif field.getType().lower().find("datetime") > -1: + value = field.get(self.context) + ret = { + "fieldName": fieldname, + "mode": "structure", + "html": self.ulocalized_time(value, long_format=True) + } + return ret def get_field_visibility_mode(self, field): From deb9c924e955b062f4a0b719ef4bcdac171e30a1 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 23:00:01 +0200 Subject: [PATCH 05/27] Removed unnecessary field lookup --- bika/lims/browser/header_table.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 61ef43934a..07c4da08f1 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -94,7 +94,6 @@ def _list_end(num): # TODO Revisit this def render_field_view(self, field): fieldname = field.getName() - field = self.context.Schema()[fieldname] ret = {"fieldName": fieldname, "mode": "view"} adapter = queryAdapter(self.context, interface=IHeaderTableFieldRenderer, From 66d0fc9bc78e76ca87b51a5142c5e65ca4eab883 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 23:01:30 +0200 Subject: [PATCH 06/27] Lookup the field type only once --- bika/lims/browser/header_table.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 07c4da08f1..71eab7fbfb 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -94,6 +94,7 @@ def _list_end(num): # TODO Revisit this def render_field_view(self, field): fieldname = field.getName() + fieldtype = field.getType() ret = {"fieldName": fieldname, "mode": "view"} adapter = queryAdapter(self.context, interface=IHeaderTableFieldRenderer, @@ -113,7 +114,7 @@ def render_field_view(self, field): "html": t(_("Yes")) if value else t(_("No")) } - elif field.getType().find("Reference") > -1: + elif fieldtype.find("Reference") > -1: # Prioritize method retrieval over schema"s field targets = None if hasattr(self.context, "get%s" % fieldname): @@ -158,7 +159,7 @@ def render_field_view(self, field): "html": "", } - elif field.getType().lower().find("datetime") > -1: + elif fieldtype.lower().find("datetime") > -1: value = field.get(self.context) ret = { "fieldName": fieldname, From 6e0340264c2c5baa9b8564e5305e73a7f60dc40e Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 23:05:20 +0200 Subject: [PATCH 07/27] Use security API --- bika/lims/browser/header_table.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 71eab7fbfb..376b90665d 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -18,7 +18,6 @@ # Copyright 2018-2019 by it's authors. # Some rights reserved, see README and LICENSE. -from AccessControl import getSecurityManager from AccessControl.Permissions import view from bika.lims import bikaMessageFactory as _ from bika.lims import logger @@ -127,8 +126,7 @@ def render_field_view(self, field): if targets: if not type(targets) == list: targets = [targets, ] - sm = getSecurityManager() - if all([sm.checkPermission(view, ta) for ta in targets]): + if all([security.check_permission(view, ta) for ta in targets]): elements = [ "
" " " From ee0d6632f7729597380c3c2c199984c5839d1d70 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 23:05:29 +0200 Subject: [PATCH 08/27] Comment only --- bika/lims/browser/header_table.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 376b90665d..30f49e14d4 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -95,6 +95,8 @@ def render_field_view(self, field): fieldname = field.getName() fieldtype = field.getType() ret = {"fieldName": fieldname, "mode": "view"} + + # lookup custom render adapter adapter = queryAdapter(self.context, interface=IHeaderTableFieldRenderer, name=fieldname) From 6088458655fee15dee81c7654d909ee49865bf28 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 23:08:23 +0200 Subject: [PATCH 09/27] Minor refactoring --- bika/lims/browser/header_table.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 30f49e14d4..c27348938d 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -126,9 +126,10 @@ def render_field_view(self, field): targets = field.get(self.context) if targets: - if not type(targets) == list: + if not isinstance(targets, (list, tuple)): targets = [targets, ] - if all([security.check_permission(view, ta) for ta in targets]): + + if all([security.check_permission(view, t) for t in targets]): elements = [ "
" " " From 7b7344d8fc6a9317c2ac2f2eadbd2b6247bf49c6 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 23:12:13 +0200 Subject: [PATCH 10/27] Refactored import --- bika/lims/browser/header_table.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index c27348938d..8910237bc7 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -21,11 +21,11 @@ from AccessControl.Permissions import view from bika.lims import bikaMessageFactory as _ from bika.lims import logger +from bika.lims.api.security import check_permission from bika.lims.browser import BrowserView from bika.lims.interfaces import IHeaderTableFieldRenderer from bika.lims.utils import t from plone.memoize import view as viewcache -from bika.lims.api import security from Products.Archetypes.event import ObjectEditedEvent from Products.CMFCore.permissions import ModifyPortalContent from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile @@ -70,7 +70,7 @@ def __call__(self): def is_edit_allowed(self): """Check permission 'ModifyPortalContent' on the context """ - return security.check_permission(ModifyPortalContent, self.context) + return check_permission(ModifyPortalContent, self.context) def three_column_list(self, input_list): list_len = len(input_list) @@ -129,7 +129,7 @@ def render_field_view(self, field): if not isinstance(targets, (list, tuple)): targets = [targets, ] - if all([security.check_permission(view, t) for t in targets]): + if all([check_permission(view, ta) for ta in targets]): elements = [ "
" " " From c803aa4694cae5fb615020ef0dbb6e556a1cc4f5 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Fri, 16 Aug 2019 23:23:42 +0200 Subject: [PATCH 11/27] Removed unused variable --- bika/lims/browser/header_table.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 8910237bc7..ad58a8daf9 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -39,7 +39,6 @@ class HeaderTableView(BrowserView): template = ViewPageTemplateFile("templates/header_table.pt") def __call__(self): - self.errors = {} if "header_table_submitted" in self.request: schema = self.context.Schema() fields = schema.fields() From 59b18a86c2f404fadcc216c48226a2dc5fd693e8 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sat, 17 Aug 2019 21:35:12 +0200 Subject: [PATCH 12/27] simplified check --- bika/lims/browser/header_table.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index ad58a8daf9..ab41df4c22 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -125,7 +125,7 @@ def render_field_view(self, field): targets = field.get(self.context) if targets: - if not isinstance(targets, (list, tuple)): + if not isinstance(targets, list): targets = [targets, ] if all([check_permission(view, ta) for ta in targets]): From 5dca55be97154eaec8a7dcb8b4d27795b36d7ba6 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sat, 17 Aug 2019 21:43:13 +0200 Subject: [PATCH 13/27] Refactored field checker to methods --- bika/lims/browser/header_table.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index ab41df4c22..9aab62272c 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -71,6 +71,21 @@ def is_edit_allowed(self): """ return check_permission(ModifyPortalContent, self.context) + def is_reference_field(self, field): + """Check if the field is a reference field + """ + return field.getType().find("Reference") > -1 + + def is_boolean_field(self, field): + """Check if the field is a boolean + """ + return field.getWidgetName() == "BooleanWidget" + + def is_date_field(self, field): + """Check if the field is a date field + """ + return field.getType().lower().find("datetime") > -1 + def three_column_list(self, input_list): list_len = len(input_list) @@ -92,7 +107,6 @@ def _list_end(num): # TODO Revisit this def render_field_view(self, field): fieldname = field.getName() - fieldtype = field.getType() ret = {"fieldName": fieldname, "mode": "view"} # lookup custom render adapter @@ -106,7 +120,7 @@ def render_field_view(self, field): "mode": "structure", "html": adapter(field)} - if field.getWidgetName() == "BooleanWidget": + if self.is_boolean_field(field): value = field.get(self.context) ret = { "fieldName": fieldname, @@ -114,13 +128,15 @@ def render_field_view(self, field): "html": t(_("Yes")) if value else t(_("No")) } - elif fieldtype.find("Reference") > -1: + elif self.is_reference_field(field): # 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) @@ -159,7 +175,7 @@ def render_field_view(self, field): "html": "", } - elif fieldtype.lower().find("datetime") > -1: + elif self.is_date_field(field): value = field.get(self.context) ret = { "fieldName": fieldname, From 734f7bc5da27547838c6790bdc85d2d4d14e6380 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sat, 17 Aug 2019 22:00:28 +0200 Subject: [PATCH 14/27] Removed unneeded tal:define variables --- bika/lims/browser/templates/header_table.pt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/bika/lims/browser/templates/header_table.pt b/bika/lims/browser/templates/header_table.pt index 34ca0b119a..c5b891faed 100644 --- a/bika/lims/browser/templates/header_table.pt +++ b/bika/lims/browser/templates/header_table.pt @@ -12,12 +12,9 @@
@@ -91,8 +88,7 @@ name="form.button.save" value="Save" i18n:domain="plone" - i18n:attributes="value label_save;" - /> + i18n:attributes="value label_save;"/>
From 75a1607d8a9ebbdcf0097c155c0db71fca201f07 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sat, 17 Aug 2019 22:06:22 +0200 Subject: [PATCH 15/27] Refactored field accessor --- bika/lims/browser/header_table.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 9aab62272c..240a2da6d2 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -132,12 +132,10 @@ def render_field_view(self, field): # 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: + accessor = getattr(self.context, "get%s" % fieldname, None) + if accessor and callable(accessor): + targets = accessor() + else: targets = field.get(self.context) if targets: From 3f01e3a4ee9e0434aec9e2d7604ec46aaac9c095 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sat, 17 Aug 2019 22:08:02 +0200 Subject: [PATCH 16/27] Removed TODO comment --- bika/lims/browser/header_table.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 240a2da6d2..b949314bc4 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -104,7 +104,6 @@ def _list_end(num): final.append(column) return final - # TODO Revisit this def render_field_view(self, field): fieldname = field.getName() ret = {"fieldName": fieldname, "mode": "view"} From 54ba395cd451479c40c58fb039cb5ebf17f0532e Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sat, 17 Aug 2019 22:20:38 +0200 Subject: [PATCH 17/27] Cache field type methods --- bika/lims/browser/header_table.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index b949314bc4..d1e3414cdd 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -26,6 +26,7 @@ from bika.lims.interfaces import IHeaderTableFieldRenderer from bika.lims.utils import t from plone.memoize import view as viewcache +from plone.memoize.volatile import cache from Products.Archetypes.event import ObjectEditedEvent from Products.CMFCore.permissions import ModifyPortalContent from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile @@ -33,6 +34,10 @@ from zope.component import queryAdapter +def field_type_cache_key(method, self, field): + return field.getName() + + class HeaderTableView(BrowserView): """Table rendered at the top in AR View """ @@ -71,16 +76,19 @@ def is_edit_allowed(self): """ return check_permission(ModifyPortalContent, self.context) + @cache(field_type_cache_key) def is_reference_field(self, field): """Check if the field is a reference field """ return field.getType().find("Reference") > -1 + @cache(field_type_cache_key) def is_boolean_field(self, field): """Check if the field is a boolean """ return field.getWidgetName() == "BooleanWidget" + @cache(field_type_cache_key) def is_date_field(self, field): """Check if the field is a date field """ From 14eee058c7566972b956c6720811c65d9c82a8b6 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sat, 17 Aug 2019 22:35:03 +0200 Subject: [PATCH 18/27] Use the portal object for cache --- bika/lims/browser/header_table.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index d1e3414cdd..70ebbc246a 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -19,6 +19,7 @@ # Some rights reserved, see README and LICENSE. from AccessControl.Permissions import view +from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims import logger from bika.lims.api.security import check_permission @@ -26,6 +27,8 @@ from bika.lims.interfaces import IHeaderTableFieldRenderer from bika.lims.utils import t from plone.memoize import view as viewcache +from plone.memoize.volatile import ATTR +from plone.memoize.volatile import CONTAINER_FACTORY from plone.memoize.volatile import cache from Products.Archetypes.event import ObjectEditedEvent from Products.CMFCore.permissions import ModifyPortalContent @@ -34,7 +37,16 @@ from zope.component import queryAdapter +def store_on_portal(method, obj, *args, **kwargs): + """Volatile cache storage on the portal object + """ + portal = api.get_portal() + return portal.__dict__.setdefault(ATTR, CONTAINER_FACTORY()) + + def field_type_cache_key(method, self, field): + """Cache key to distinguish the type evaluation of a field + """ return field.getName() @@ -76,19 +88,19 @@ def is_edit_allowed(self): """ return check_permission(ModifyPortalContent, self.context) - @cache(field_type_cache_key) + @cache(field_type_cache_key, get_cache=store_on_portal) def is_reference_field(self, field): """Check if the field is a reference field """ return field.getType().find("Reference") > -1 - @cache(field_type_cache_key) + @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) + @cache(field_type_cache_key, get_cache=store_on_portal) def is_date_field(self, field): """Check if the field is a date field """ From 71989eff57ca163390f99b69159a7497760ea9ea Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sat, 17 Aug 2019 22:40:17 +0200 Subject: [PATCH 19/27] Changelog updated --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) 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 From c24fcedc66bb1a8bd7d1a6e2c14212426c78b95a Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sat, 17 Aug 2019 22:48:20 +0200 Subject: [PATCH 20/27] Only show save button if edit is allowed on the context --- bika/lims/browser/templates/header_table.pt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bika/lims/browser/templates/header_table.pt b/bika/lims/browser/templates/header_table.pt index c5b891faed..22f48884db 100644 --- a/bika/lims/browser/templates/header_table.pt +++ b/bika/lims/browser/templates/header_table.pt @@ -83,7 +83,8 @@ - Date: Sun, 18 Aug 2019 08:57:50 +0200 Subject: [PATCH 21/27] Refactored code for lesser complexity and better understanding --- bika/lims/browser/header_table.py | 139 +++++++++++++++++------------- 1 file changed, 79 insertions(+), 60 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 70ebbc246a..682fe1fe5e 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -106,6 +106,77 @@ def is_date_field(self, 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) @@ -126,7 +197,6 @@ def _list_end(num): def render_field_view(self, field): fieldname = field.getName() - ret = {"fieldName": fieldname, "mode": "view"} # lookup custom render adapter adapter = queryAdapter(self.context, @@ -139,68 +209,17 @@ def render_field_view(self, field): "mode": "structure", "html": adapter(field)} - if self.is_boolean_field(field): - value = field.get(self.context) - ret = { - "fieldName": fieldname, - "mode": "structure", - "html": t(_("Yes")) if value else t(_("No")) - } + # 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): - # Prioritize method retrieval over schema"s field - targets = None - - 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, 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": "", - } - + data = self.get_reference_field_data(field) elif self.is_date_field(field): - value = field.get(self.context) - ret = { - "fieldName": fieldname, - "mode": "structure", - "html": self.ulocalized_time(value, long_format=True) - } - - return ret + 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 From f614d0f46d37d4910db4d4d511c4158cede05510 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sun, 18 Aug 2019 09:08:54 +0200 Subject: [PATCH 22/27] Added comment --- bika/lims/browser/header_table.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 682fe1fe5e..011469879d 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -203,6 +203,10 @@ def render_field_view(self, field): interface=IHeaderTableFieldRenderer, name=fieldname) + # Note: Adapter for client field: + # bika.lims.browser.analysisrequest.mailto_link_from_contacts + # -> TODO Remove? + # return immediately if we have an adapter if adapter is not None: return {"fieldName": fieldname, From af5b1820425500c806f54a6da29cf0898e329333 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sun, 18 Aug 2019 09:12:20 +0200 Subject: [PATCH 23/27] Added comment --- bika/lims/browser/analysisrequest/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bika/lims/browser/analysisrequest/__init__.py b/bika/lims/browser/analysisrequest/__init__.py index f7d6d981ec..2712c504f6 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: + """Custom header table field adapter + + see: bika.lims.browser.header_table + """ def __init__(self, context): self.context = context @@ -128,6 +133,11 @@ def __call__(self, field): def mailto_link_from_ccemails(ccemails): + """Custom header table field adapter + + see: bika.lims.browser.header_table + """ + def __init__(self, context): self.context = context From a5e4ed4b747346eba8e8bba173fc714ab64213b5 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sun, 18 Aug 2019 10:46:17 +0200 Subject: [PATCH 24/27] Fixed broken field adapters --- bika/lims/browser/analysisrequest/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bika/lims/browser/analysisrequest/__init__.py b/bika/lims/browser/analysisrequest/__init__.py index 2712c504f6..2a4f544279 100644 --- a/bika/lims/browser/analysisrequest/__init__.py +++ b/bika/lims/browser/analysisrequest/__init__.py @@ -110,7 +110,7 @@ def __call__(self, request, data): 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 @@ -132,7 +132,7 @@ 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 @@ -146,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) From bc07306b7af136675621b3da0b8a6cfdffce8a0f Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sun, 18 Aug 2019 10:46:34 +0200 Subject: [PATCH 25/27] Fixed invalid adapter name --- bika/lims/browser/analysisrequest/configure.zcml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/browser/analysisrequest/configure.zcml b/bika/lims/browser/analysisrequest/configure.zcml index 3f8d33e7a1..cf47ce09b8 100644 --- a/bika/lims/browser/analysisrequest/configure.zcml +++ b/bika/lims/browser/analysisrequest/configure.zcml @@ -67,7 +67,7 @@ for="bika.lims.interfaces.IAnalysisRequest" factory="bika.lims.browser.analysisrequest.mailto_link_from_contacts" provides="bika.lims.interfaces.IHeaderTableFieldRenderer" - name="CContact" + name="CCContact" /> Date: Sun, 18 Aug 2019 10:46:44 +0200 Subject: [PATCH 26/27] Comment only --- bika/lims/browser/header_table.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bika/lims/browser/header_table.py b/bika/lims/browser/header_table.py index 011469879d..da66866834 100644 --- a/bika/lims/browser/header_table.py +++ b/bika/lims/browser/header_table.py @@ -203,9 +203,11 @@ def render_field_view(self, field): interface=IHeaderTableFieldRenderer, name=fieldname) - # Note: Adapter for client field: + # Note: Adapters for contact fields: # bika.lims.browser.analysisrequest.mailto_link_from_contacts - # -> TODO Remove? + # bika.lims.browser.analysisrequest.mailto_link_from_ccemails + # + # -> TODO Remove? # return immediately if we have an adapter if adapter is not None: From 534d11d9201056db40f5edc461cc96ac5e86b4e8 Mon Sep 17 00:00:00 2001 From: Ramon Bartl Date: Sun, 18 Aug 2019 10:49:40 +0200 Subject: [PATCH 27/27] Comment only --- bika/lims/browser/analysisrequest/configure.zcml | 1 + 1 file changed, 1 insertion(+) diff --git a/bika/lims/browser/analysisrequest/configure.zcml b/bika/lims/browser/analysisrequest/configure.zcml index cf47ce09b8..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" /> +