collective.behavior.talcondition 1.0a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. collective/behavior/talcondition/__init__.py +14 -0
  2. collective/behavior/talcondition/behavior.py +89 -0
  3. collective/behavior/talcondition/configure.zcml +55 -0
  4. collective/behavior/talcondition/extender.py +74 -0
  5. collective/behavior/talcondition/interfaces.py +15 -0
  6. collective/behavior/talcondition/locales/es/LC_MESSAGES/collective.behavior.talcondition.po +35 -0
  7. collective/behavior/talcondition/locales/fr/LC_MESSAGES/collective.behavior.talcondition.po +31 -0
  8. collective/behavior/talcondition/profiles/default/browserlayer.xml +7 -0
  9. collective/behavior/talcondition/profiles/default/collectivebehaviortalcondition_marker.txt +0 -0
  10. collective/behavior/talcondition/profiles/default/metadata.xml +4 -0
  11. collective/behavior/talcondition/profiles/testing/metadata.xml +7 -0
  12. collective/behavior/talcondition/profiles/testing/types/testtype.xml +41 -0
  13. collective/behavior/talcondition/profiles/testing/types.xml +5 -0
  14. collective/behavior/talcondition/profiles/uninstall/browserlayer.xml +7 -0
  15. collective/behavior/talcondition/setuphandlers.py +11 -0
  16. collective/behavior/talcondition/testing.py +95 -0
  17. collective/behavior/talcondition/testing.zcml +21 -0
  18. collective/behavior/talcondition/tests/__init__.py +0 -0
  19. collective/behavior/talcondition/tests/robot/.gitkeep +0 -0
  20. collective/behavior/talcondition/tests/test_behavior.py +51 -0
  21. collective/behavior/talcondition/tests/test_extender.py +30 -0
  22. collective/behavior/talcondition/tests/test_robot.py +24 -0
  23. collective/behavior/talcondition/tests/test_setup.py +63 -0
  24. collective/behavior/talcondition/tests/test_utils.py +111 -0
  25. collective/behavior/talcondition/utils.py +173 -0
  26. collective.behavior.talcondition-1.0a2-py3.11-nspkg.pth +2 -0
  27. collective.behavior.talcondition-1.0a2.dist-info/METADATA +228 -0
  28. collective.behavior.talcondition-1.0a2.dist-info/RECORD +32 -0
  29. collective.behavior.talcondition-1.0a2.dist-info/WHEEL +5 -0
  30. collective.behavior.talcondition-1.0a2.dist-info/entry_points.txt +2 -0
  31. collective.behavior.talcondition-1.0a2.dist-info/namespace_packages.txt +2 -0
  32. collective.behavior.talcondition-1.0a2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Init and utils."""
3
+
4
+ from plone import api
5
+ from zope.i18nmessageid import MessageFactory
6
+
7
+
8
+ _ = MessageFactory('collective.behavior.talcondition')
9
+
10
+ PLONE_VERSION = int(api.env.plone_version()[0])
11
+
12
+
13
+ def initialize(context):
14
+ """Initializer called when used as a Zope 2 product."""
@@ -0,0 +1,89 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from collective.behavior.talcondition import _
4
+ from collective.behavior.talcondition.utils import evaluateExpressionFor
5
+ from plone.autoform import directives as form
6
+ from plone.autoform.interfaces import IFormFieldProvider
7
+ from plone.dexterity.interfaces import IDexterityContent
8
+ from plone.supermodel import model
9
+ from z3c.form.browser.checkbox import CheckBoxFieldWidget
10
+ from zope import schema
11
+ from zope.component import adapts
12
+ from zope.interface import alsoProvides
13
+ from zope.interface import implementer
14
+
15
+
16
+ class ITALCondition(model.Schema):
17
+
18
+ form.widget("tal_condition", size=80)
19
+ tal_condition = schema.TextLine(
20
+ title=_(u"TAL condition expression"),
21
+ description=_(
22
+ u"Enter a TAL expression that once evaluated "
23
+ "will return 'True' if content should be "
24
+ "available. Elements 'member', 'context' "
25
+ "and 'portal' are available for the "
26
+ "expression."
27
+ ),
28
+ required=False,
29
+ default=u"",
30
+ )
31
+
32
+ form.widget(
33
+ "roles_bypassing_talcondition",
34
+ CheckBoxFieldWidget,
35
+ multiple="multiple",
36
+ size=15,
37
+ )
38
+ roles_bypassing_talcondition = schema.Set(
39
+ title=_(u"Roles that will bypass the TAL condition"),
40
+ description=_(
41
+ u"Choose the different roles for which the TAL "
42
+ "condition will not be evaluated and always "
43
+ "considered 'True'."
44
+ ),
45
+ required=False,
46
+ value_type=schema.Choice(vocabulary="plone.app.vocabularies.Roles"),
47
+ )
48
+
49
+ def evaluate(self):
50
+ """Evaluate the condition and returns True or False."""
51
+
52
+
53
+ alsoProvides(ITALCondition, IFormFieldProvider)
54
+
55
+
56
+ @implementer(ITALCondition)
57
+ class TALCondition(object):
58
+ """ """
59
+
60
+ adapts(IDexterityContent)
61
+
62
+ def __init__(self, context):
63
+ self.context = context
64
+
65
+ def get_tal_condition(self):
66
+ return getattr(self.context, "tal_condition", "")
67
+
68
+ def set_tal_condition(self, value):
69
+ self.context.tal_condition = value
70
+
71
+ tal_condition = property(get_tal_condition, set_tal_condition)
72
+
73
+ def get_roles_bypassing_talcondition(self):
74
+ return getattr(self.context, "roles_bypassing_talcondition", [])
75
+
76
+ def set_roles_bypassing_talcondition(self, value):
77
+ self.context.roles_bypassing_talcondition = value
78
+
79
+ roles_bypassing_talcondition = property(
80
+ get_roles_bypassing_talcondition, set_roles_bypassing_talcondition
81
+ )
82
+
83
+ def complete_extra_expr_ctx(self, extra_expr_ctx):
84
+ """Complete extra_expr_ctx, this is made to be overrided."""
85
+ return extra_expr_ctx
86
+
87
+ def evaluate(self, extra_expr_ctx={}):
88
+ extra_expr_ctx = self.complete_extra_expr_ctx(extra_expr_ctx)
89
+ return evaluateExpressionFor(self, extra_expr_ctx=extra_expr_ctx)
@@ -0,0 +1,55 @@
1
+ <configure
2
+ xmlns="http://namespaces.zope.org/zope"
3
+ xmlns:five="http://namespaces.zope.org/five"
4
+ xmlns:i18n="http://namespaces.zope.org/i18n"
5
+ xmlns:plone="http://namespaces.plone.org/plone"
6
+ xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
7
+ xmlns:zcml="http://namespaces.zope.org/zcml"
8
+ i18n_domain="collective.behavior.talcondition">
9
+
10
+ <i18n:registerTranslations directory="locales" />
11
+
12
+ <five:registerPackage package="." initialize=".initialize" />
13
+
14
+ <include package="plone.behavior" file="meta.zcml" />
15
+ <include package="plone.app.dexterity" />
16
+
17
+ <plone:behavior
18
+ title="TALCondition"
19
+ description="Add a TAL condition field useable to check if content should be available."
20
+ provides=".behavior.ITALCondition"
21
+ for="plone.dexterity.interfaces.IDexterityContent"
22
+ factory=".behavior.TALCondition"
23
+ marker=".interfaces.ITALConditionable"
24
+ />
25
+
26
+ <adapter zcml:condition="not-have plone-5"
27
+ factory=".extender.TALConditionExtender"
28
+ for=".interfaces.ITALConditionable"
29
+ provides="archetypes.schemaextender.interfaces.ISchemaExtender"
30
+ name="collective.behavior.talcondition.extender" />
31
+
32
+ <genericsetup:registerProfile
33
+ name="default"
34
+ title="collective.behavior.talcondition"
35
+ directory="profiles/default"
36
+ description="Installs the collective.behavior.talcondition add-on."
37
+ provides="Products.GenericSetup.interfaces.EXTENSION"
38
+ />
39
+
40
+ <genericsetup:registerProfile
41
+ name="uninstall"
42
+ title="collective.behavior.talcondition"
43
+ directory="profiles/uninstall"
44
+ description="Uninstalls the collective.behavior.talcondition add-on."
45
+ provides="Products.GenericSetup.interfaces.EXTENSION"
46
+ />
47
+
48
+ <genericsetup:importStep
49
+ name="collective.behavior.talcondition-postInstall"
50
+ title="collective.behavior.talcondition post_install import step"
51
+ description="Post install import step from collective.behavior.talcondition"
52
+ handler=".setuphandlers.post_install">
53
+ </genericsetup:importStep>
54
+
55
+ </configure>
@@ -0,0 +1,74 @@
1
+ # -*- coding: utf-8 -*-
2
+ from archetypes.schemaextender.field import ExtensionField
3
+ from archetypes.schemaextender.interfaces import IBrowserLayerAwareExtender
4
+ from archetypes.schemaextender.interfaces import ISchemaExtender
5
+ from collective.behavior.talcondition.interfaces import ICollectiveBehaviorTalconditionLayer
6
+ from collective.behavior.talcondition.interfaces import ITALConditionable
7
+ from Products.Archetypes.public import LinesField
8
+ from Products.Archetypes.public import MultiSelectionWidget
9
+ from Products.Archetypes.public import StringField
10
+ from Products.Archetypes.public import StringWidget
11
+ from zope.component import adapts
12
+ from zope.interface import implementer
13
+
14
+
15
+ class TALConditionStringField(ExtensionField, StringField):
16
+ """A string field that will contain an eventual TAL condition expression."""
17
+
18
+
19
+ class TALConditionLinesField(ExtensionField, LinesField):
20
+ """A Lines field that will contain all roles
21
+ that will bypass the tal condition."""
22
+
23
+
24
+ @implementer(ISchemaExtender, IBrowserLayerAwareExtender)
25
+ class TALConditionExtender(object):
26
+ """TALCondition class"""
27
+
28
+ adapts(ITALConditionable)
29
+
30
+ layer = ICollectiveBehaviorTalconditionLayer
31
+
32
+ fields = [
33
+ TALConditionStringField(
34
+ 'tal_condition',
35
+ required=False,
36
+ default='',
37
+ searchable=False,
38
+ languageIndependent=True,
39
+ widget=StringWidget(
40
+ label=(u"TAL condition expression"),
41
+ description=(u'Enter a TAL expression that once evaluated '
42
+ 'will return \'True\' if content should be '
43
+ 'available. Elements \'member\', \'context\' '
44
+ 'and \'portal\' are available for the '
45
+ 'expression.'),
46
+ i18n_domain='collective.behavior.talcondition',
47
+ size="80",
48
+ ),
49
+ ),
50
+ TALConditionLinesField(
51
+ 'roles_bypassing_talcondition',
52
+ required=False,
53
+ searchable=False,
54
+ languageIndependent=True,
55
+ widget=MultiSelectionWidget(
56
+ size=10,
57
+ label=(u'Roles that will bypass the TAL condition'),
58
+ description=(u'Choose the different roles for which the TAL '
59
+ 'condition will not be evaluated and always '
60
+ 'considered \'True\'.'
61
+ ),
62
+ i18n_domain='collective.behavior.talcondition',
63
+ ),
64
+ enforceVocabulary=True,
65
+ multiValued=1,
66
+ vocabulary_factory='plone.app.vocabularies.Roles',
67
+ ),
68
+ ]
69
+
70
+ def __init__(self, context):
71
+ self.context = context
72
+
73
+ def getFields(self):
74
+ return self.fields
@@ -0,0 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Module where all interfaces, events and exceptions live."""
3
+
4
+ from zope.interface import Interface
5
+ from zope.publisher.interfaces.browser import IDefaultBrowserLayer
6
+
7
+
8
+ class ICollectiveBehaviorTalconditionLayer(IDefaultBrowserLayer):
9
+ """Marker interface that defines a browser layer."""
10
+
11
+
12
+ class ITALConditionable(Interface):
13
+ """
14
+ Marker interface for tal_condition field schema extender
15
+ """
@@ -0,0 +1,35 @@
1
+ # Translation of collective.behavior.talcondition.pot to Spanish
2
+ # Leonardo J. Caballero G. <leonardocaballero@gmail.com>, 2020.
3
+ #
4
+ msgid ""
5
+ msgstr ""
6
+ "Project-Id-Version: collective.behavior.talcondition\n"
7
+ "POT-Creation-Date: 2015-06-05 07:17+0000\n"
8
+ "PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
9
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
10
+ "Language-Team: LANGUAGE <LL@li.org>\n"
11
+ "MIME-Version: 1.0\n"
12
+ "Content-Type: text/plain; charset=utf-8\n"
13
+ "Content-Transfer-Encoding: 8bit\n"
14
+ "Plural-Forms: nplurals=1; plural=0\n"
15
+ "Language-Code: es\n"
16
+ "Language-Name: Spanish\n"
17
+ "Preferred-Encodings: utf-8 latin1\n"
18
+ "Domain: collective.behavior.talcondition\n"
19
+ "X-Is-Fallback-For: es-ar es-bo es-cl es-co es-cr es-do es-ec es-es es-sv es-gt es-hn es-mx es-ni es-pa es-py es-pe es-pr es-us es-uy es-ve\n"
20
+
21
+ #: ../behavior.py:28
22
+ msgid "Choose the different roles for which the TAL condition will not be evaluated and always considered 'True'."
23
+ msgstr "Seleccione los roles para los cuales la condición TAL no se evaluará y siempre será 'True'."
24
+
25
+ #: ../behavior.py:17
26
+ msgid "Enter a TAL expression that once evaluated will return 'True' if content should be available. Elements 'member', 'context' and 'portal' are available for the expression."
27
+ msgstr "Ingrese una expresión TAL que, cuando se evalúe, devolverá 'True' si el elemento va a estar disponible. Los elementos 'member', 'context' y 'portal' están disponibles en la expresión."
28
+
29
+ #: ../behavior.py:27
30
+ msgid "Roles that will bypass the TAL condition"
31
+ msgstr "Roles que omiten la expresión TAL"
32
+
33
+ #: ../behavior.py:16
34
+ msgid "TAL condition expression"
35
+ msgstr "Condición en formato TAL"
@@ -0,0 +1,31 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: PACKAGE VERSION\n"
4
+ "POT-Creation-Date: 2015-06-05 07:17+0000\n"
5
+ "PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
6
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
7
+ "Language-Team: LANGUAGE <LL@li.org>\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=utf-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
+ "Plural-Forms: nplurals=1; plural=0\n"
12
+ "Language-Code: en\n"
13
+ "Language-Name: English\n"
14
+ "Preferred-Encodings: utf-8 latin1\n"
15
+ "Domain: DOMAIN\n"
16
+
17
+ #: ../behavior.py:28
18
+ msgid "Choose the different roles for which the TAL condition will not be evaluated and always considered 'True'."
19
+ msgstr "Sélectionnez les rôles pour lesquels la condition TAL ne sera pas évaluée et sera toujours 'vraie'."
20
+
21
+ #: ../behavior.py:17
22
+ msgid "Enter a TAL expression that once evaluated will return 'True' if content should be available. Elements 'member', 'context' and 'portal' are available for the expression."
23
+ msgstr "Entrez une expression TAL qui une fois évaluée, retournera 'Vrai' si l'élément doit être disponible. Les éléments 'member', 'context' et 'portal' sont disponibles dans l'expression."
24
+
25
+ #: ../behavior.py:27
26
+ msgid "Roles that will bypass the TAL condition"
27
+ msgstr "Rôles qui by-passent l'expression TAL"
28
+
29
+ #: ../behavior.py:16
30
+ msgid "TAL condition expression"
31
+ msgstr "Condition au format TAL"
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0"?>
2
+ <layers>
3
+ <layer
4
+ name="collective.behavior.talcondition"
5
+ interface="collective.behavior.talcondition.interfaces.ICollectiveBehaviorTalconditionLayer"
6
+ />
7
+ </layers>
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0"?>
2
+ <metadata>
3
+ <version>1</version>
4
+ </metadata>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0"?>
2
+ <metadata>
3
+ <version>1</version>
4
+ <dependencies>
5
+ <dependency>profile-collective.behavior.talcondition:default</dependency>
6
+ </dependencies>
7
+ </metadata>
@@ -0,0 +1,41 @@
1
+ <?xml version="1.0"?>
2
+ <object name="testtype" meta_type="Dexterity FTI" i18n:domain="plone"
3
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n">
4
+ <property name="title" i18n:translate="">Test type</property>
5
+ <property name="description" i18n:translate="">None</property>
6
+ <property name="icon_expr">string:${portal_url}/folder_icon.png</property>
7
+ <property name="factory">testtype</property>
8
+ <property name="add_view_expr">string:${folder_url}/++add++testtype</property>
9
+ <property name="link_target"></property>
10
+ <property name="immediate_view">view</property>
11
+ <property name="global_allow">True</property>
12
+ <property name="filter_content_types">True</property>
13
+ <property name="allowed_content_types" />
14
+ <property name="allow_discussion">False</property>
15
+ <property name="default_view">view</property>
16
+ <property name="view_methods">
17
+ <element value="view"/>
18
+ </property>
19
+ <property name="default_view_fallback">False</property>
20
+ <property name="add_permission">cmf.AddPortalContent</property>
21
+ <property name="behaviors">
22
+ <element value="collective.behavior.talcondition.behavior.ITALCondition" />
23
+ </property>
24
+ <property name="schema" />
25
+ <!-- DO NOT use a model_source or it removes manually added fields while reapplying the profile -->
26
+ <!--property name="model_source" /-->
27
+ <alias from="(Default)" to="(dynamic view)"/>
28
+ <alias from="edit" to="@@edit"/>
29
+ <alias from="sharing" to="@@sharing"/>
30
+ <alias from="view" to="(selected layout)"/>
31
+ <action title="View" action_id="view" category="object" condition_expr=""
32
+ description="" icon_expr="" link_target="" url_expr="string:${object_url}"
33
+ visible="True">
34
+ <permission value="View"/>
35
+ </action>
36
+ <action title="Edit" action_id="edit" category="object" condition_expr=""
37
+ description="" icon_expr="" link_target=""
38
+ url_expr="string:${object_url}/edit" visible="True">
39
+ <permission value="Modify portal content"/>
40
+ </action>
41
+ </object>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0"?>
2
+ <object name="portal_types" meta_type="Plone Types Tool">
3
+ <property name="title">Controls the available content types in your portal</property>
4
+ <object name="testtype" meta_type="Dexterity FTI"/>
5
+ </object>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0"?>
2
+ <layers>
3
+ <layer
4
+ name="collective.behavior.talcondition"
5
+ interface="collective.behavior.talcondition.interfaces.ICollectiveBehaviorTalconditionLayer" remove="True"
6
+ />
7
+ </layers>
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+
4
+ def isNotCurrentProfile(context):
5
+ return context.readDataFile("collectivebehaviortalcondition_marker.txt") is None
6
+
7
+
8
+ def post_install(context):
9
+ """Post install script"""
10
+ if isNotCurrentProfile(context):
11
+ return
@@ -0,0 +1,95 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Base module for unittesting."""
3
+
4
+ from collective.behavior.talcondition import PLONE_VERSION
5
+ from plone import api
6
+ from plone.app.robotframework.testing import AUTOLOGIN_LIBRARY_FIXTURE
7
+ from plone.app.testing import applyProfile
8
+ from plone.app.testing import FunctionalTesting
9
+ from plone.app.testing import IntegrationTesting
10
+ from plone.app.testing import login
11
+ from plone.app.testing import PLONE_FIXTURE
12
+ from plone.app.testing import PloneSandboxLayer
13
+ from plone.app.testing import setRoles
14
+ from plone.app.testing import TEST_USER_ID
15
+ from plone.app.testing import TEST_USER_NAME
16
+ from plone.testing import z2
17
+
18
+ import collective.behavior.talcondition
19
+ import unittest
20
+
21
+
22
+ class CollectiveBehaviorTalconditionLayer(PloneSandboxLayer):
23
+
24
+ defaultBases = (PLONE_FIXTURE,)
25
+ products = ("collective.behavior.talcondition",)
26
+
27
+ def setUpZope(self, app, configurationContext):
28
+ """Set up Zope."""
29
+ # Load ZCML
30
+ self.loadZCML(package=collective.behavior.talcondition, name="testing.zcml")
31
+ for p in self.products:
32
+ z2.installProduct(app, p)
33
+
34
+ def setUpPloneSite(self, portal):
35
+ """Set up Plone."""
36
+ # Set default chain for plone.app.contenttypes
37
+ wftool = portal["portal_workflow"]
38
+ wftool.setDefaultChain("simple_publication_workflow")
39
+
40
+ # Install into Plone
41
+ if PLONE_VERSION < 5:
42
+ installer = portal["portal_quickinstaller"]
43
+ installer.installProduct("collective.behavior.talcondition")
44
+ applyProfile(portal, "collective.behavior.talcondition:testing")
45
+
46
+ try:
47
+ applyProfile(portal, "plone.app.contenttypes:plone-content")
48
+ except KeyError:
49
+ # BBB Plone 4
50
+ pass
51
+
52
+ # Login and create some test content
53
+ setRoles(portal, TEST_USER_ID, ["Manager"])
54
+ login(portal, TEST_USER_NAME)
55
+ api.content.create(container=portal, type="Folder", id="folder")
56
+
57
+ # Commit so that the test browser sees these objects
58
+ import transaction
59
+
60
+ transaction.commit()
61
+
62
+ def tearDownZope(self, app):
63
+ """Tear down Zope."""
64
+ for p in reversed(self.products):
65
+ z2.uninstallProduct(app, p)
66
+
67
+
68
+ FIXTURE = CollectiveBehaviorTalconditionLayer(name="FIXTURE")
69
+
70
+
71
+ INTEGRATION = IntegrationTesting(bases=(FIXTURE,), name="INTEGRATION")
72
+
73
+
74
+ FUNCTIONAL = FunctionalTesting(bases=(FIXTURE,), name="FUNCTIONAL")
75
+
76
+
77
+ ACCEPTANCE = FunctionalTesting(
78
+ bases=(FIXTURE, AUTOLOGIN_LIBRARY_FIXTURE, z2.ZSERVER_FIXTURE), name="ACCEPTANCE"
79
+ )
80
+
81
+
82
+ class IntegrationTestCase(unittest.TestCase):
83
+ """Base class for integration tests."""
84
+
85
+ layer = INTEGRATION
86
+
87
+ def setUp(self):
88
+ super(IntegrationTestCase, self).setUp()
89
+ self.portal = self.layer["portal"]
90
+
91
+
92
+ class FunctionalTestCase(unittest.TestCase):
93
+ """Base class for functional tests."""
94
+
95
+ layer = FUNCTIONAL
@@ -0,0 +1,21 @@
1
+ <configure
2
+ xmlns="http://namespaces.zope.org/zope"
3
+ xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
4
+ xmlns:zcml="http://namespaces.zope.org/zcml"
5
+ i18n_domain="collective.behavior.talcondition">
6
+
7
+ <include file="configure.zcml" />
8
+
9
+ <class zcml:condition="not-have plone-5"
10
+ class="Products.ATContentTypes.content.document.ATDocument">
11
+ <implements interface="collective.behavior.talcondition.interfaces.ITALConditionable" />
12
+ </class>
13
+
14
+ <genericsetup:registerProfile
15
+ name="testing"
16
+ title="collective.behavior.talcondition tests"
17
+ directory="profiles/testing"
18
+ description="Steps to ease tests of collective.behavior.talcondition"
19
+ provides="Products.GenericSetup.interfaces.EXTENSION" />
20
+
21
+ </configure>
File without changes
File without changes
@@ -0,0 +1,51 @@
1
+ # -*- coding: utf-8 -*-
2
+ from collective.behavior.talcondition import PLONE_VERSION
3
+ from collective.behavior.talcondition.behavior import ITALCondition
4
+ from collective.behavior.talcondition.interfaces import ITALConditionable
5
+ from collective.behavior.talcondition.testing import IntegrationTestCase
6
+ from plone.app.testing import login
7
+ from plone.app.testing import TEST_USER_NAME
8
+
9
+
10
+ class TestBehavior(IntegrationTestCase):
11
+
12
+ def setUp(self):
13
+ """ """
14
+ super(TestBehavior, self).setUp()
15
+ # create a testitem
16
+ login(self.portal, TEST_USER_NAME)
17
+ self.portal.invokeFactory(id='testitem',
18
+ type_name='testtype',
19
+ title='Test type')
20
+ self.testitem = self.portal.testitem
21
+ self.adapted = ITALCondition(self.testitem)
22
+
23
+ def test_behavior(self):
24
+ """Test that once enabled, the behavior do the job."""
25
+ if PLONE_VERSION < 5:
26
+ # in Plone 4, a behavior attribute is not set (until saved ?)
27
+ self.assertFalse(hasattr(self.testitem, 'tal_condition'))
28
+ # it has a 'tal_condition' attribute
29
+ self.assertTrue(hasattr(self.adapted, 'tal_condition'))
30
+ self.assertTrue(ITALConditionable.providedBy(self.portal.testitem))
31
+ # set a tal_condition and evaluate
32
+ # this is True
33
+ self.adapted.tal_condition = u"python:context.portal_type=='testtype'"
34
+ self.assertTrue(self.adapted.evaluate())
35
+ # this is False
36
+ self.adapted.tal_condition = u"python:context.portal_type=='unexisting_portal_type'"
37
+ self.assertFalse(self.adapted.evaluate())
38
+
39
+ def test_wrong_condition(self):
40
+ """In case the condition is wrong, it just returns False
41
+ and a message is added to the Zope log."""
42
+ # using a wrong expression does not break anything
43
+ self.adapted.tal_condition = u'python: context.some_unexisting_method()'
44
+ self.assertFalse(self.adapted.evaluate())
45
+
46
+ def test_evaluate_extra_expr_ctx(self):
47
+ """The 'evaluate' method can receive a 'extra_expr_ctx' dict
48
+ that will extend the TAL expression context."""
49
+ self.adapted.tal_condition = "python: value == '122'"
50
+ self.assertFalse(self.adapted.evaluate())
51
+ self.assertTrue(self.adapted.evaluate(extra_expr_ctx={'value': '122'}))
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+ from collective.behavior.talcondition import PLONE_VERSION
3
+ from collective.behavior.talcondition.interfaces import ITALConditionable
4
+ from collective.behavior.talcondition.testing import IntegrationTestCase
5
+ from collective.behavior.talcondition.utils import evaluateExpressionFor
6
+ from plone.app.testing import login
7
+ from plone.app.testing import TEST_USER_NAME
8
+
9
+ import unittest
10
+
11
+
12
+ class TestExtender(IntegrationTestCase):
13
+
14
+ @unittest.skipIf(PLONE_VERSION >= 5, 'Archetypes extender test skipped in Plone 5')
15
+ def test_extender(self):
16
+ """The extender is enabled on ATDocument in testing.zcml.
17
+ Check that 'tal_condition' is available."""
18
+ login(self.portal, TEST_USER_NAME)
19
+ self.portal.invokeFactory(id='doc',
20
+ type_name='Document',
21
+ title='Test document')
22
+ doc = self.portal.doc
23
+ self.assertTrue(ITALConditionable.providedBy(doc))
24
+ # set a tal_condition and evaluate
25
+ # this is True
26
+ doc.tal_condition = u"python:context.portal_type=='Document'"
27
+ self.assertTrue(evaluateExpressionFor(doc))
28
+ # this is False
29
+ doc.tal_condition = u"python:context.portal_type=='unexisting_portal_type'"
30
+ self.assertFalse(evaluateExpressionFor(doc))
@@ -0,0 +1,24 @@
1
+ from ..testing import ACCEPTANCE
2
+ from plone.testing import layered
3
+
4
+ import os
5
+ import robotsuite
6
+ import unittest
7
+
8
+
9
+ def test_suite():
10
+ suite = unittest.TestSuite()
11
+ current_dir = os.path.abspath(os.path.dirname(__file__))
12
+ robot_dir = os.path.join(current_dir, 'robot')
13
+ robot_tests = [
14
+ os.path.join('robot', doc) for doc in os.listdir(robot_dir)
15
+ if doc.endswith('.robot') and doc.startswith('test_')
16
+ ]
17
+ for test in robot_tests:
18
+ suite.addTests([
19
+ layered(
20
+ robotsuite.RobotTestSuite(test),
21
+ layer=ACCEPTANCE
22
+ ),
23
+ ])
24
+ return suite
@@ -0,0 +1,63 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Setup/installation tests for this package."""
3
+ from collective.behavior.talcondition import PLONE_VERSION
4
+ from collective.behavior.talcondition.testing import IntegrationTestCase
5
+ from plone import api
6
+
7
+
8
+ if PLONE_VERSION >= 5:
9
+ from Products.CMFPlone.utils import get_installer
10
+
11
+
12
+ class TestInstall(IntegrationTestCase):
13
+ """Test installation of collective.behavior.talcondition into Plone."""
14
+
15
+ def setUp(self):
16
+ """Custom shared utility setup for tests."""
17
+ self.portal = self.layer["portal"]
18
+ if PLONE_VERSION < 5:
19
+ self.installer = api.portal.get_tool("portal_quickinstaller")
20
+ else:
21
+ self.installer = get_installer(self.portal, self.layer["request"])
22
+
23
+ def test_product_installed(self):
24
+ """Test if collective.behavior.talcondition is installed with portal_quickinstaller."""
25
+ if PLONE_VERSION < 5:
26
+ self.assertTrue(
27
+ self.installer.isProductInstalled("collective.behavior.talcondition")
28
+ )
29
+ else:
30
+ self.assertTrue(
31
+ self.installer.is_product_installed("collective.behavior.talcondition")
32
+ )
33
+
34
+ # browserlayer.xml
35
+ def test_browserlayer(self):
36
+ """Test that ICollectiveBehaviorTalconditionLayer is registered."""
37
+ from collective.behavior.talcondition.interfaces import ICollectiveBehaviorTalconditionLayer
38
+ from plone.browserlayer import utils
39
+
40
+ self.assertIn(ICollectiveBehaviorTalconditionLayer, utils.registered_layers())
41
+
42
+
43
+ class TestUninstall(IntegrationTestCase):
44
+ def setUp(self):
45
+ """Custom shared utility setup for tests."""
46
+ self.portal = self.layer["portal"]
47
+ if PLONE_VERSION < 5:
48
+ self.installer = api.portal.get_tool("portal_quickinstaller")
49
+ self.installer.uninstallProducts(["collective.behavior.talcondition"])
50
+ else:
51
+ self.installer = get_installer(self.portal, self.layer["request"])
52
+ self.installer.uninstall_product("collective.behavior.talcondition")
53
+
54
+ def test_uninstall(self):
55
+ """Test if collective.behavior.talcondition is cleanly uninstalled."""
56
+ if PLONE_VERSION < 5:
57
+ self.assertFalse(
58
+ self.installer.isProductInstalled("collective.behavior.talcondition")
59
+ )
60
+ else:
61
+ self.assertFalse(
62
+ self.installer.is_product_installed("collective.behavior.talcondition")
63
+ )
@@ -0,0 +1,111 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from AccessControl import Unauthorized
4
+ from collective.behavior.talcondition import PLONE_VERSION
5
+ from collective.behavior.talcondition.behavior import ITALCondition
6
+ from collective.behavior.talcondition.interfaces import ITALConditionable
7
+ from collective.behavior.talcondition.testing import IntegrationTestCase
8
+ from collective.behavior.talcondition.utils import _evaluateExpression
9
+ from collective.behavior.talcondition.utils import applyExtender
10
+ from collective.behavior.talcondition.utils import evaluateExpressionFor
11
+ from plone.app.testing import login
12
+ from plone.app.testing import TEST_USER_NAME
13
+ from zope.interface import alsoProvides
14
+
15
+ import unittest
16
+
17
+
18
+ class TestUtils(IntegrationTestCase):
19
+
20
+ def setUp(self):
21
+ """ """
22
+ super(TestUtils, self).setUp()
23
+ # create a testitem
24
+ login(self.portal, TEST_USER_NAME)
25
+ self.portal.invokeFactory(id='testitem',
26
+ type_name='testtype',
27
+ title='Test type')
28
+ self.adapted = ITALCondition(self.portal.testitem)
29
+
30
+ def test_wrong_condition(self):
31
+ """In case the condition is wrong, it just returns False
32
+ and a message is added to the Zope log."""
33
+ # using a wrong expression does not break anything
34
+ self.adapted.tal_condition = u'python: context.some_unexisting_method()'
35
+ self.assertFalse(self.adapted.evaluate())
36
+
37
+ @unittest.skipIf(PLONE_VERSION >= 5, 'Archetypes extender test skipped in Plone 5')
38
+ def test_apply_extender(self):
39
+ """Test that existing objects are correctly updated
40
+ after enabling extender for their meta_type."""
41
+ # the extender is not enabled for "Folder"
42
+ login(self.portal, TEST_USER_NAME)
43
+ self.portal.invokeFactory(id='testfolder',
44
+ type_name='Folder',
45
+ title='Test folder')
46
+ testfolder = self.portal.testfolder
47
+ self.assertFalse(hasattr(testfolder, 'tal_condition'))
48
+ self.assertFalse(ITALConditionable.providedBy(testfolder))
49
+ # enable the extender for testfolder
50
+ alsoProvides(testfolder, ITALConditionable)
51
+ # the schema is not updated until we do it
52
+ self.assertFalse(hasattr(testfolder, 'tal_condition'))
53
+ applyExtender(self.portal, meta_types=('ATFolder', ))
54
+ # now the field is available
55
+ self.assertTrue(hasattr(testfolder, 'tal_condition'))
56
+
57
+ def test_empty_condition(self):
58
+ # using an empty expression is considered True
59
+ self.adapted.tal_condition = None
60
+ self.assertTrue(self.adapted.evaluate())
61
+
62
+ def test_bypass_for_manager(self):
63
+ """In this case, no matter the expression is False,
64
+ it will return True if current user is 'Manager'."""
65
+ # using a wrong expression does not break anything
66
+ self.adapted.tal_condition = "python:False"
67
+ self.assertFalse(evaluateExpressionFor(self.adapted))
68
+ self.adapted.roles_bypassing_talcondition = [u'Manager']
69
+ # as current user is Manager, he can bypass the expression result
70
+ self.assertTrue(evaluateExpressionFor(self.adapted))
71
+
72
+ def test_extra_expr_ctx(self):
73
+ """It is possible to pass extra values that will be available
74
+ in the context of the expression."""
75
+ self.adapted.tal_condition = "python: value == '122'"
76
+ self.assertFalse(evaluateExpressionFor(self.adapted))
77
+ self.assertTrue(evaluateExpressionFor(self.adapted, {'value': '122'}))
78
+
79
+ def test_empty_expr_is_true(self):
80
+ """Test parameter used by utils._evaluateExpression making an empty
81
+ expression to be considered True or False."""
82
+ # True by default
83
+ self.assertTrue(_evaluateExpression(self.portal,
84
+ expression=''))
85
+ self.assertTrue(_evaluateExpression(self.portal,
86
+ expression=None))
87
+ self.assertFalse(_evaluateExpression(self.portal,
88
+ expression='',
89
+ empty_expr_is_true=False))
90
+ self.assertFalse(_evaluateExpression(self.portal,
91
+ expression=None,
92
+ empty_expr_is_true=False))
93
+
94
+ def test_raise_on_error(self):
95
+ """By default, a wrong expression will return False, except if raise_on_error=True,
96
+ in this case the exception will be raised."""
97
+ self.adapted.tal_condition = u'python: context.some_unexisting_method()'
98
+ self.assertFalse(evaluateExpressionFor(self.adapted))
99
+ self.assertRaises(AttributeError, evaluateExpressionFor, self.adapted, raise_on_error=True)
100
+
101
+ def test_trusted(self):
102
+ self.assertRaises(Unauthorized,
103
+ _evaluateExpression,
104
+ self.portal,
105
+ expression='python: context.unrestrictedTraverse("view")',
106
+ raise_on_error=True)
107
+ self.assertTrue(_evaluateExpression(
108
+ self.portal,
109
+ expression='python: context.unrestrictedTraverse("view")',
110
+ raise_on_error=True,
111
+ trusted=True))
@@ -0,0 +1,173 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from AccessControl.class_init import InitializeClass
4
+ from collective.behavior.talcondition import PLONE_VERSION
5
+ from plone import api
6
+ from Products.CMFCore.Expression import createExprContext
7
+ from Products.CMFCore.Expression import Expression
8
+ from Products.PageTemplates.Expressions import createTrustedZopeEngine
9
+ from Products.PageTemplates.Expressions import SecureModuleImporter
10
+
11
+ import logging
12
+ import unittest
13
+
14
+
15
+ logger = logging.getLogger("collective.behavior.talcondition")
16
+ WRONG_TAL_CONDITION = (
17
+ "The TAL expression '{0}' for element at '{1}' is wrong. Original exception : {2}"
18
+ )
19
+
20
+
21
+ def evaluateExpressionFor(
22
+ obj,
23
+ extra_expr_ctx={},
24
+ error_pattern=WRONG_TAL_CONDITION,
25
+ raise_on_error=False,
26
+ trusted=False,
27
+ ):
28
+ """Evaluate the expression stored in 'tal_condition' of given p_obj."""
29
+ # get tal_condition
30
+ tal_condition = obj.tal_condition and obj.tal_condition.strip() or ""
31
+
32
+ roles_bypassing_talcondition = obj.roles_bypassing_talcondition
33
+
34
+ if hasattr(obj, "context"):
35
+ obj = obj.context
36
+ return _evaluateExpression(
37
+ obj,
38
+ expression=tal_condition,
39
+ roles_bypassing_expression=roles_bypassing_talcondition,
40
+ extra_expr_ctx=extra_expr_ctx,
41
+ error_pattern=error_pattern,
42
+ raise_on_error=raise_on_error,
43
+ trusted=trusted,
44
+ )
45
+
46
+
47
+ def _evaluateExpression(
48
+ obj,
49
+ expression,
50
+ roles_bypassing_expression=[],
51
+ extra_expr_ctx={},
52
+ empty_expr_is_true=True,
53
+ error_pattern=WRONG_TAL_CONDITION,
54
+ raise_on_error=False,
55
+ trusted=False,
56
+ ):
57
+ """Evaluate given p_expression extending expression context with p_extra_expr_ctx."""
58
+ if not expression or not expression.strip():
59
+ return empty_expr_is_true
60
+
61
+ res = True
62
+ member = api.user.get_current()
63
+ for role in roles_bypassing_expression or []:
64
+ if member.has_role(str(role), obj):
65
+ return res
66
+ portal = api.portal.get()
67
+ if trusted:
68
+ ctx = createTrustedExprContext(obj.aq_inner.aq_parent, portal, obj)
69
+ expr_handler = TrustedExpression
70
+ else:
71
+ ctx = createExprContext(obj.aq_inner.aq_parent, portal, obj)
72
+ expr_handler = Expression
73
+ ctx.setGlobal("member", member)
74
+ ctx.setGlobal("context", obj)
75
+ ctx.setGlobal("portal", portal)
76
+ for extra_key, extra_value in list(extra_expr_ctx.items()):
77
+ ctx.setGlobal(extra_key, extra_value)
78
+
79
+ if raise_on_error:
80
+ res = expr_handler(expression)(ctx)
81
+ else:
82
+ try:
83
+ res = expr_handler(expression)(ctx)
84
+ except Exception as e:
85
+ logger.warn(error_pattern.format(expression, obj.absolute_url(), str(e)))
86
+ res = False
87
+ return res
88
+
89
+
90
+ def createTrustedExprContext(folder, portal, object):
91
+ """
92
+ Expression evaluator trusted (not restricted python)
93
+ Same as createExprContext but use the trusted engine.
94
+ """
95
+ pm = api.portal.get_tool("portal_membership")
96
+ if object is None:
97
+ object_url = ""
98
+ else:
99
+ object_url = object.absolute_url()
100
+ if pm.isAnonymousUser():
101
+ member = None
102
+ else:
103
+ member = pm.getAuthenticatedMember()
104
+ data = {
105
+ "object_url": object_url,
106
+ "folder_url": folder.absolute_url(),
107
+ "portal_url": portal.absolute_url(),
108
+ "object": object,
109
+ "folder": folder,
110
+ "portal": portal,
111
+ "nothing": None,
112
+ "request": getattr(portal, "REQUEST", None),
113
+ "modules": SecureModuleImporter,
114
+ "member": member,
115
+ "here": object,
116
+ }
117
+ return getTrustedEngine().getContext(data)
118
+
119
+
120
+ _trusted_engine = createTrustedZopeEngine()
121
+
122
+
123
+ def getTrustedEngine():
124
+ """ """
125
+ return _trusted_engine
126
+
127
+
128
+ class TrustedExpression(Expression):
129
+ """ """
130
+
131
+ text = ""
132
+ _v_compiled = None
133
+
134
+ def __init__(self, text):
135
+ self.text = text
136
+ if text.strip():
137
+ self._v_compiled = getTrustedEngine().compile(text)
138
+
139
+ def __call__(self, econtext):
140
+ if not self.text.strip():
141
+ return ""
142
+ compiled = self._v_compiled
143
+ if compiled is None:
144
+ compiled = self._v_compiled = getTrustedEngine().compile(self.text)
145
+ # ?? Maybe expressions should manipulate the security
146
+ # context stack.
147
+ res = compiled(econtext)
148
+ if isinstance(res, Exception):
149
+ raise res
150
+ return res
151
+
152
+
153
+ InitializeClass(Expression)
154
+
155
+
156
+ @unittest.skipIf(PLONE_VERSION >= 5, "Archetypes extender skipped in Plone 5")
157
+ def applyExtender(portal, meta_types):
158
+ """
159
+ We add some fields using archetypes.schemaextender to every given p_meta_types.
160
+ """
161
+ logger.info(
162
+ "Adding talcondition fields : updating the schema for meta_types %s"
163
+ % ",".join(meta_types)
164
+ )
165
+ at_tool = api.portal.get_tool("archetype_tool")
166
+ catalog = api.portal.get_tool("portal_catalog")
167
+ catalog.ZopeFindAndApply(
168
+ portal,
169
+ obj_metatypes=meta_types,
170
+ search_sub=True,
171
+ apply_func=at_tool._updateObject,
172
+ )
173
+ logger.info("Done!")
@@ -0,0 +1,2 @@
1
+ import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('collective',));importlib = __import__('importlib.util');__import__('importlib.machinery');m = sys.modules.setdefault('collective', importlib.util.module_from_spec(importlib.machinery.PathFinder.find_spec('collective', [os.path.dirname(p)])));m = m or sys.modules.setdefault('collective', types.ModuleType('collective'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p)
2
+ import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('collective', 'behavior'));importlib = __import__('importlib.util');__import__('importlib.machinery');m = sys.modules.setdefault('collective.behavior', importlib.util.module_from_spec(importlib.machinery.PathFinder.find_spec('collective.behavior', [os.path.dirname(p)])));m = m or sys.modules.setdefault('collective.behavior', types.ModuleType('collective.behavior'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p);m and setattr(sys.modules['collective'], 'behavior', m)
@@ -0,0 +1,228 @@
1
+ Metadata-Version: 2.1
2
+ Name: collective.behavior.talcondition
3
+ Version: 1.0a2
4
+ Summary: This package contains a Dexterity behavior and AT schemaextender to add a TAL condition on a content type.
5
+ Home-page: http://pypi.python.org/pypi/collective.behavior.talcondition
6
+ Author: IMIO
7
+ Author-email: dev@imio.be
8
+ License: GPL V2
9
+ Keywords: Python Zope Plone
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Framework :: Plone
12
+ Classifier: Framework :: Plone :: Addon
13
+ Classifier: Framework :: Plone :: 4.3
14
+ Classifier: Framework :: Plone :: 5.0
15
+ Classifier: Framework :: Plone :: 5.1
16
+ Classifier: Framework :: Plone :: 5.2
17
+ Classifier: Framework :: Plone :: 6.0
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Programming Language :: Python :: 2.7
20
+ Classifier: Programming Language :: Python :: 3.7
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Operating System :: OS Independent
23
+ Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
24
+ Requires-Dist: plone.api
25
+ Requires-Dist: setuptools
26
+ Requires-Dist: plone.app.dexterity
27
+ Provides-Extra: test
28
+ Requires-Dist: plone.app.testing ; extra == 'test'
29
+ Requires-Dist: plone.app.robotframework ; extra == 'test'
30
+
31
+ .. image:: https://travis-ci.org/collective/collective.behavior.talcondition.svg?branch=master
32
+ :target: https://travis-ci.org/collective/collective.behavior.talcondition
33
+
34
+ .. image:: https://coveralls.io/repos/collective/collective.behavior.talcondition/badge.png
35
+ :target: https://coveralls.io/r/collective/collective.behavior.talcondition
36
+
37
+
38
+ ==========================================================================
39
+ collective.behavior.talcondition
40
+ ==========================================================================
41
+
42
+ This package works for dexterity (behavior) and archetypes (schema extender).
43
+
44
+ It adds two fields on a content type or class:
45
+
46
+ * tal_condition : enter a `TAL expression <http://docs.zope.org/zope2/zope2book/AppendixC.html>`_ that once evaluated will return 'True' if content should be available. By default, elements 'member', 'context' and 'portal' are available for the expression but the TAL expression context may be extended using the 'extra_expr_ctx' parameter.
47
+
48
+ * roles_bypassing_talcondition : choose the different roles for which the TAL condition will not be evaluated and always considered \'True\'
49
+
50
+ It's then possible to use the 'evaluate' method to test the TAL condition.
51
+
52
+ How to use it
53
+ =============
54
+
55
+ For AT you have to provide the ITALConditionable on your class (see testing.zcml).
56
+
57
+ For DX you just have to activate the behavior on your content type.
58
+
59
+ Plone versions
60
+ ==============
61
+ It has been developed and tested for Plone 4 and 5.
62
+
63
+
64
+ Translations
65
+ ============
66
+
67
+ This product has been translated into
68
+
69
+ - French.
70
+
71
+ - Spanish.
72
+
73
+ You can contribute for any message missing or other new languages, join us at `Plone Collective Team <https://www.transifex.com/plone/plone-collective/>`_ into *Transifex.net* service with all world Plone translators community.
74
+
75
+
76
+
77
+ Changelog
78
+ =========
79
+
80
+
81
+ 1.0a2 (2024-09-16)
82
+ ------------------
83
+
84
+ - Fix dict iteration for Python 3
85
+ [laulaz]
86
+ - Updated Makefile
87
+ [sgeulette]
88
+ - Used pyenv in gha
89
+ [sgeulette]
90
+
91
+ 1.0a1 (2023-06-21)
92
+ ------------------
93
+
94
+ - Fix deprecated import AccessControl.class_init instead of App.class_init
95
+ (Plone6 compatibility)
96
+ [boulch]
97
+ - Set simplier setup with Makefile
98
+ [sgeulette]
99
+
100
+ 0.14 (2021-06-29)
101
+ -----------------
102
+
103
+ - Fix pypi broken package
104
+ [boulch]
105
+
106
+
107
+ 0.13 (2021-06-29)
108
+ -----------------
109
+
110
+ - Add uninstall profile
111
+ [boulch]
112
+ - Add Plone6 compatibily
113
+ [boulch]
114
+
115
+
116
+ 0.12 (2021-04-20)
117
+ -----------------
118
+
119
+ - Add Transifex.net service integration to manage the translation process.
120
+ [macagua]
121
+ - Add Spanish translation
122
+ [macagua]
123
+ - Do not consider the `archetypes.schemaextender` on Plone5.
124
+ [gbastien]
125
+ - Adapted code (except, implementer) to be Python3 compatible.
126
+ [gbastien]
127
+ - Added parameter `trusted=False` to `utils._evaluateExpression`, this will use
128
+ a trusted expression handler instead the restricted python default.
129
+ [gbastien]
130
+
131
+ 0.11 (2019-05-16)
132
+ -----------------
133
+
134
+ - Added parameter `raise_on_error` to `utils.evaluateExpressionFor` to raise an
135
+ error when an exception occurs instead returning False.
136
+ [gbastien]
137
+ - Added method `TALCondition.complete_extra_expr_ctx` to the behavior to
138
+ formalize the way to get `extra_expr_ctx` to avoid the `evaluate` method
139
+ to be overrided.
140
+ [gbastien]
141
+
142
+ 0.10 (2018-11-20)
143
+ -----------------
144
+
145
+ - Do not break if parameter `expression` passed to
146
+ `utils._evaluateExpression` is None.
147
+ [gbastien]
148
+
149
+ 0.9 (2018-10-12)
150
+ ----------------
151
+
152
+ - Added new parameter `error_pattern=WRONG_TAL_CONDITION` to
153
+ `utils.evaluateExpressionFor` and underlying `utils._evaluateExpression` to
154
+ be able to log a custom message in case an error occurs during
155
+ expression evaluation.
156
+ [gbastien]
157
+
158
+ 0.8 (2018-06-12)
159
+ ----------------
160
+
161
+ - Mark elements using behavior with `ITALConditionable` interface so it behaves
162
+ like element using the AT extender.
163
+ [gbastien]
164
+
165
+ 0.7 (2017-03-22)
166
+ ----------------
167
+
168
+ - Use CheckBoxWidget for `ITALCondition.roles_bypassing_talcondition` to ease
169
+ selection when displaying several elements.
170
+ [gbastien]
171
+
172
+ 0.6 (2016-01-12)
173
+ ----------------
174
+
175
+ - Added parameter `empty_expr_is_true` to utils._evaluateExpression than may be True
176
+ or False depending that we want an empty expression to be considered True or False.
177
+ Previous behavior is kept in utils.evaluateExpressionFor where an empty expression
178
+ is considered True. This avoid managing an empty expression in the caller method
179
+ [gbastien]
180
+
181
+
182
+ 0.5 (2015-12-17)
183
+ ----------------
184
+
185
+ - Added method utils._evaluateExpression that receives an expression
186
+ to evaluate, it is called by utils.evaluateExpressionFor. This way, this
187
+ method may evaluate a TAL expression without getting it from the `tal_condition`
188
+ attribute on the context, in case we want to evaluate arbitrary expression
189
+ [gbastien]
190
+
191
+
192
+ 0.4 (2015-09-16)
193
+ ----------------
194
+
195
+ - Make the tal_condition field larger (from 30 to 80) for the
196
+ AT extender as well as for the DX behavior
197
+ [gbastien]
198
+ - Added possibility to extend TAL expression context by passing
199
+ an `extra_expr_ctx` dict to utils.evaluateExpressionFor, also
200
+ integrated to the `evaluate` method of the DX behavior
201
+ [gbastien]
202
+
203
+
204
+ 0.3 (2015-07-14)
205
+ ----------------
206
+
207
+ - Corrected default value
208
+ [sgeulette]
209
+ - Little optimization
210
+ [sgeulette]
211
+
212
+
213
+ 0.2 (2015-06-18)
214
+ ----------------
215
+
216
+ - Added field `role_bypassing_talcondition` to define who can bypass the condition
217
+ [anuyens]
218
+ - Added translations for new field
219
+ [gbastien]
220
+
221
+
222
+ 0.1 (2015-06-01)
223
+ ----------------
224
+
225
+ - Initial release.
226
+ [IMIO]
227
+
228
+
@@ -0,0 +1,32 @@
1
+ collective.behavior.talcondition-1.0a2-py3.11-nspkg.pth,sha256=8ssgqEuqS0ZiVuimfRty8lTM8d_9gCEdbC3ovq8TMBE,1077
2
+ collective/behavior/talcondition/__init__.py,sha256=LcX1iez83P4ovdTlWnrAMFGE8tDnoYVhLbUc-LSCruA,308
3
+ collective/behavior/talcondition/behavior.py,sha256=d4bvIeo21YD2sk5NGO-mJJQgYNHwyehHo9CQOJRjAnU,2824
4
+ collective/behavior/talcondition/configure.zcml,sha256=RkFMsZNh5h9HrFwZ9wc6nWZG8LefVd3FJiEc1pX3RIc,2172
5
+ collective/behavior/talcondition/extender.py,sha256=mVM0-nCgdyuAbwM7p0EBwo41lUdbqbKjtCF0hIGJX_s,2806
6
+ collective/behavior/talcondition/interfaces.py,sha256=553o_qz9KihxgWwHQPayjbKmic-1brFRFJX3V02s58w,432
7
+ collective/behavior/talcondition/setuphandlers.py,sha256=yOHG-PwzJ9w2XRmxz40QvBSd9lo84Rve7JCpKlxCe_E,256
8
+ collective/behavior/talcondition/testing.py,sha256=9s_Nd5BOVCDN2tufG9T45n80DM3b6gqHokKdrSr3Vxo,2894
9
+ collective/behavior/talcondition/testing.zcml,sha256=A8ITPtLBVw7dji7tX8-saImpAjj1Rz3f8De9TlNYeak,771
10
+ collective/behavior/talcondition/utils.py,sha256=SzK5ZEgUFj6IhFLniw_yLpFTRQ8cHp49i-hRPU_tz50,5037
11
+ collective/behavior/talcondition/locales/es/LC_MESSAGES/collective.behavior.talcondition.po,sha256=RZGb3WMN_9e9vEmQXx2VW7Y_6BLY-25uqjsMmZcZFE4,1644
12
+ collective/behavior/talcondition/locales/fr/LC_MESSAGES/collective.behavior.talcondition.po,sha256=dhk-pCBMIbVyrXC1rCWV73t1meM3GHUlonLUpEbqIq4,1339
13
+ collective/behavior/talcondition/profiles/default/browserlayer.xml,sha256=sKQd1RtLVWeUrOGsXGoDiyBNao4lPJf_-Z9eLQz3cas,196
14
+ collective/behavior/talcondition/profiles/default/collectivebehaviortalcondition_marker.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ collective/behavior/talcondition/profiles/default/metadata.xml,sha256=grYUSMlCKb0kl1ivG9K842y6xncDXoJQcYJ96YhfvTU,67
16
+ collective/behavior/talcondition/profiles/testing/metadata.xml,sha256=pcOw5lpsd7qgUxIDpPhMtaiviIU5jOLUn4wOXa-GabI,181
17
+ collective/behavior/talcondition/profiles/testing/types.xml,sha256=Cxf94scAK_n0a29rLkRBO2TjCMDHCwDqOH1MYl95_BA,227
18
+ collective/behavior/talcondition/profiles/testing/types/testtype.xml,sha256=vnK75Tr-j4hnz8zUxD0BNVJbLcmra60k7EbPwkWujBg,1916
19
+ collective/behavior/talcondition/profiles/uninstall/browserlayer.xml,sha256=pi4OhQBeCcEUhbuz5z4EadAJE-SrA3ZIIvB4_dxl7ao,210
20
+ collective/behavior/talcondition/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ collective/behavior/talcondition/tests/test_behavior.py,sha256=uXjHPp2NCC7ECBrgQnj_jfMb_ZdlUNxtY_CvcA8nIhc,2352
22
+ collective/behavior/talcondition/tests/test_extender.py,sha256=goXwqPBMODNob_Qtif8svd1vJ0fBNEhQWvUJiPtkdiI,1321
23
+ collective/behavior/talcondition/tests/test_robot.py,sha256=4bSKzSOaLMuirgdQ_kzZiMh02THRvzrAhik79h73h8k,633
24
+ collective/behavior/talcondition/tests/test_setup.py,sha256=vvObzrvsPmLzSelqHWwEYDLifoFaSD-s4daSQvf5VUk,2483
25
+ collective/behavior/talcondition/tests/test_utils.py,sha256=bsEy_BL2HqEtXdXiTBrZIGhSH03aBF4Sf4Oettukmt4,5289
26
+ collective/behavior/talcondition/tests/robot/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ collective.behavior.talcondition-1.0a2.dist-info/METADATA,sha256=oSY1vaAac-SLWE3kAYJ_4eY6vVVvx6Zzu1Uu3mIwHZY,6612
28
+ collective.behavior.talcondition-1.0a2.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
29
+ collective.behavior.talcondition-1.0a2.dist-info/entry_points.txt,sha256=b5cHz9FINNyhunUZ6BJOQMhgeAi2x9UcnAkA9l8KEC4,40
30
+ collective.behavior.talcondition-1.0a2.dist-info/namespace_packages.txt,sha256=NmZRn6gW7dnyJ88Ktn-wkFv_xKxDhHkifpxxdnroaaA,31
31
+ collective.behavior.talcondition-1.0a2.dist-info/top_level.txt,sha256=FyC0xnd95fkjCaKazR3nfIgNqhWMpB0mYBlzALyXKTg,11
32
+ collective.behavior.talcondition-1.0a2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (70.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [z3c.autoinclude.plugin]
2
+ target = plone
@@ -0,0 +1,2 @@
1
+ collective
2
+ collective.behavior