src/pyams_security/widget/__init__.py
changeset 33 c422e7f61f19
parent 7 7920b5e679ec
child 42 07229ac2497b
--- a/src/pyams_security/widget/__init__.py	Mon Apr 20 09:50:51 2015 +0200
+++ b/src/pyams_security/widget/__init__.py	Mon Apr 20 09:51:14 2015 +0200
@@ -18,15 +18,18 @@
 
 # import interfaces
 from pyams_form.interfaces.form import IFormLayer
-from pyams_security.interfaces import ISecurityManager
-from pyams_security.schema import IPrincipal, IPrincipalsSet
-from pyams_security.widget.interfaces import IPrincipalWidget, IPrincipalsSetWidget
-from z3c.form.interfaces import IDataConverter, IFieldWidget
+from pyams_security.interfaces import ISecurityManager, IPermission
+from pyams_security.schema import IPrincipal, IPrincipalsSet, IPermissionField, IPermissionsSetField
+from pyams_security.widget.interfaces import IPrincipalWidget, IPrincipalsSetWidget, IPermissionWidget, \
+    IPermissionsSetWidget
+from z3c.form.interfaces import IDataConverter, IFieldWidget, NO_VALUE
+from zope.schema.interfaces import ITitledTokenizedTerm
 
 # import packages
 from pyams_form.widget import widgettemplate_config
 from pyams_utils.adapter import adapter_config
-from pyams_utils.registry import query_utility
+from pyams_utils.registry import query_utility, get_all_utilities_registered_for, get_utilities_for
+from z3c.form.browser.select import SelectWidget
 from z3c.form.browser.widget import HTMLInputWidget
 from z3c.form.converter import BaseDataConverter
 from z3c.form.widget import Widget, FieldWidget
@@ -34,6 +37,148 @@
 
 
 #
+# Permission widget
+#
+
+@adapter_config(context=(IPermissionField, IPermissionWidget), provides=IDataConverter)
+class PermissionDataConverter(BaseDataConverter):
+    """Permission data converter"""
+
+    def toWidgetValue(self, value):
+        # Permission widget is waiting for a Permission object
+        if not value:
+            return None
+        return query_utility(IPermission, name=value)
+
+    def toFieldValue(self, value):
+        # Permission widget only returns selected permission ID
+        return value
+
+
+@widgettemplate_config(mode='input', template='templates/permission-input.pt', layer=IFormLayer)
+@widgettemplate_config(mode='display', template='templates/permission-display.pt', layer=IFormLayer)
+@implementer_only(IPermissionWidget)
+class PermissionWidget(SelectWidget):
+    """Principal widget"""
+
+    def isSelected(self, term):
+        return term.token == self.value.id
+
+    def items(self):
+        if self.terms is None:  # update() has not been called yet
+            return ()
+        items = []
+        if (not self.required or self.prompt) and self.multiple is None:
+            message = self.noValueMessage
+            if self.prompt:
+                message = self.promptMessage
+            items.append({'id': self.id + '-novalue',
+                          'value': self.noValueToken,
+                          'content': message,
+                          'selected': self.value == []})
+
+        ignored = {self.value.id} if self.value else set()
+
+        def addItem(idx, term, prefix=''):
+            selected = self.isSelected(term)
+            if selected and term.token in ignored:
+                ignored.remove(term.token)
+            id = '%s-%s%i' % (self.id, prefix, idx)
+            content = term.token
+            if ITitledTokenizedTerm.providedBy(term):
+                content = self.request.localizer.translate(term.title)
+            items.append({'id': id, 'value': term.token, 'content': content, 'selected': selected})
+
+        for idx, term in enumerate(self.terms):
+            addItem(idx, term)
+
+        if ignored:
+            # some values are not displayed, probably they went away from the vocabulary
+            for idx, token in enumerate(sorted(ignored)):
+                try:
+                    term = self.terms.getTermByToken(token)
+                except LookupError:
+                    # just in case the term really went away
+                    continue
+
+                addItem(idx, term, prefix='missing-')
+        return items
+
+    @property
+    def value_map(self):
+        if not self.value:
+            return ''
+        translate = self.request.localizer.translate
+        return json.dumps({self.value.id: translate(self.value.title)})
+
+    def extract(self, default=NO_VALUE):
+        result = super(PermissionWidget, self).extract(default)
+        if result != default:
+            result = result[0]
+        return result
+
+
+@adapter_config(context=(IPermissionField, IFormLayer), provides=IFieldWidget)
+def PermissionFieldWidget(field, request):
+    """Permission field widget factory"""
+    return FieldWidget(field, PermissionWidget(request))
+
+
+#
+# Permissions set widget
+#
+
+@adapter_config(context=(IPermissionsSetField, IPermissionsSetWidget), provides=IDataConverter)
+class PermissionsSetDataConverter(BaseDataConverter):
+    """Permissions set data converter"""
+
+    def toWidgetValue(self, value):
+        # Permissions set widget is waiting for a set of Permission object
+        if not value:
+            return ()
+        return sorted((query_utility(IPermission, name=permission_id) for permission_id in value),
+                      key=lambda x: x.title)
+
+    def toFieldValue(self, value):
+        # Permissions set widget only returns selected permissions IDs in a single input
+        if not value:
+            return set()
+        return set(value.split('|'))
+
+
+@widgettemplate_config(mode='input', template='templates/permissions-set-input.pt', layer=IFormLayer)
+@widgettemplate_config(mode='display', template='templates/permissions-set-display.pt', layer=IFormLayer)
+@implementer_only(IPermissionsSetWidget)
+class PermissionsSetWidget(HTMLInputWidget, Widget):
+    """Permissions set widget"""
+
+    @property
+    def values_data(self):
+        translate = self.request.localizer.translate
+        registry = self.request.registry
+        return json.dumps(sorted([{'id': permission.id, 'text': translate(permission.title)}
+                                  for name, permission in registry.getUtilitiesFor(IPermission)],
+                                 key=lambda x: x['text']))
+
+    @property
+    def values_str(self):
+        return '|'.join((permission.id for permission in (self.value or ())))
+
+    @property
+    def values_map(self):
+        result = {}
+        translate = self.request.localizer.translate
+        [result.update({value.id: translate(value.title)}) for value in (self.value or ())]
+        return json.dumps(result)
+
+
+@adapter_config(context=(IPermissionsSetField, IFormLayer), provides=IFieldWidget)
+def PermissionsSetFieldWidget(field, request):
+    """Permissions set field widget factory"""
+    return FieldWidget(field, PermissionsSetWidget(request))
+
+
+#
 # Principal widget
 #