diff --git a/CHANGES.rst b/CHANGES.rst index 08f0a4e..539e306 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,11 @@ Changelog 1.2b2 (unreleased) ------------------ -- Avoid ComponentLookupError when plonectl adduser. +- Add support for logging workflow transitions. + [hvelarde] + +- Avoid ComponentLookupError when plonectl adduser. + [jianaijun] 1.2b1 (2016-09-28) diff --git a/src/collective/fingerpointing/interfaces.py b/src/collective/fingerpointing/interfaces.py index d003806..c3b86bd 100644 --- a/src/collective/fingerpointing/interfaces.py +++ b/src/collective/fingerpointing/interfaces.py @@ -27,6 +27,12 @@ class IFingerPointingSettings(Interface): default=True, ) + audit_workflow = schema.Bool( + title=_(u'Audit Workflow Transitions?'), + description=_(u'Log workflow transitions like object publishing.'), + default=True, + ) + audit_registry = schema.Bool( title=_(u'Audit Registry?'), description=_(u'Log registry events like records being modified.'), diff --git a/src/collective/fingerpointing/profiles/default/metadata.xml b/src/collective/fingerpointing/profiles/default/metadata.xml index a44cc34..dab4dc0 100644 --- a/src/collective/fingerpointing/profiles/default/metadata.xml +++ b/src/collective/fingerpointing/profiles/default/metadata.xml @@ -1,4 +1,4 @@ - 3 + 4 diff --git a/src/collective/fingerpointing/subscribers/__init__.py b/src/collective/fingerpointing/subscribers/__init__.py index 00cf810..d2876a5 100644 --- a/src/collective/fingerpointing/subscribers/__init__.py +++ b/src/collective/fingerpointing/subscribers/__init__.py @@ -3,3 +3,4 @@ from .lifecycle_logger import lifecycle_logger # noqa from .pas_logger import pas_logger # noqa from .registry_logger import registry_logger # noqa +from .workflow_logger import workflow_logger # noqa: F401 diff --git a/src/collective/fingerpointing/subscribers/configure.zcml b/src/collective/fingerpointing/subscribers/configure.zcml index d31a2ee..4a8be21 100644 --- a/src/collective/fingerpointing/subscribers/configure.zcml +++ b/src/collective/fingerpointing/subscribers/configure.zcml @@ -97,4 +97,10 @@ handler=".iterate_logger" /> + + + diff --git a/src/collective/fingerpointing/subscribers/workflow_logger.py b/src/collective/fingerpointing/subscribers/workflow_logger.py new file mode 100644 index 0000000..bc6f6d1 --- /dev/null +++ b/src/collective/fingerpointing/subscribers/workflow_logger.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +"""Event subscriber handler for IActionSucceededEvent.""" +from collective.fingerpointing.config import AUDIT_MESSAGE +from collective.fingerpointing.interfaces import IFingerPointingSettings +from collective.fingerpointing.logger import log_info +from collective.fingerpointing.utils import get_request_information +from plone import api +from plone.api.exc import InvalidParameterError + + +def workflow_logger(event): + """Log workflow transitions.""" + try: + record = IFingerPointingSettings.__identifier__ + '.audit_workflow' + audit_workflow = api.portal.get_registry_record(record) + except InvalidParameterError: + return # package is not installed + + if audit_workflow: + user, ip = get_request_information() + action = 'workflow transition' + extras = u'object={0} transition={1}'.format(event.object, event.action) + log_info(AUDIT_MESSAGE.format(user, ip, action, extras)) diff --git a/src/collective/fingerpointing/testing.py b/src/collective/fingerpointing/testing.py index 0cb8e1b..2951538 100644 --- a/src/collective/fingerpointing/testing.py +++ b/src/collective/fingerpointing/testing.py @@ -43,17 +43,16 @@ def setUpZope(self, app, configurationContext): def setUpPloneSite(self, portal): self.applyProfile(portal, 'collective.fingerpointing:default') + portal.portal_workflow.setDefaultChain('simple_publication_workflow') FIXTURE = Fixture() INTEGRATION_TESTING = IntegrationTesting( - bases=(FIXTURE,), - name='collective.fingerpointing:Integration') + bases=(FIXTURE,), name='collective.fingerpointing:Integration') FUNCTIONAL_TESTING = FunctionalTesting( - bases=(FIXTURE,), - name='collective.fingerpointing:Functional') + bases=(FIXTURE,), name='collective.fingerpointing:Functional') ROBOT_TESTING = FunctionalTesting( bases=(FIXTURE, AUTOLOGIN_LIBRARY_FIXTURE, z2.ZSERVER_FIXTURE), diff --git a/src/collective/fingerpointing/tests/test_controlpanel.py b/src/collective/fingerpointing/tests/test_controlpanel.py index 0e504c4..7713d31 100644 --- a/src/collective/fingerpointing/tests/test_controlpanel.py +++ b/src/collective/fingerpointing/tests/test_controlpanel.py @@ -66,6 +66,10 @@ def test_audit_lifecycle_record_in_registry(self): self.assertTrue(hasattr(self.settings, 'audit_lifecycle')) self.assertEqual(self.settings.audit_lifecycle, True) + def test_audit_workflow_record_in_registry(self): + self.assertTrue(hasattr(self.settings, 'audit_workflow')) + self.assertEqual(self.settings.audit_workflow, True) + def test_audit_registry_record_in_registry(self): self.assertTrue(hasattr(self.settings, 'audit_registry')) self.assertEqual(self.settings.audit_registry, True) @@ -83,6 +87,7 @@ def test_records_removed_on_uninstall(self): records = [ IFingerPointingSettings.__identifier__ + '.audit_pas', IFingerPointingSettings.__identifier__ + '.audit_lifecycle', + IFingerPointingSettings.__identifier__ + '.audit_workflow', IFingerPointingSettings.__identifier__ + '.audit_registry', IFingerPointingSettings.__identifier__ + '.audit_iterate', ] diff --git a/src/collective/fingerpointing/tests/test_upgrades.py b/src/collective/fingerpointing/tests/test_upgrades.py index c46cf8a..71b87f0 100644 --- a/src/collective/fingerpointing/tests/test_upgrades.py +++ b/src/collective/fingerpointing/tests/test_upgrades.py @@ -120,3 +120,41 @@ def test_update_user_actions(self): self._do_upgrade(step) self.assertEqual(user_actions.keys()[-1], 'logout') self.assertEqual(user_actions.keys()[-2], 'audit-log') + + +class To4TestCase(BaseUpgradeTestCase): + + from_ = '3' + to_ = '4' + + def test_profile_version(self): + version = self.setup.getLastVersionForProfile(self.profile_id)[0] + self.assertEqual(version, self.from_) + + def test_registered_steps(self): + steps = len(self.setup.listUpgrades(self.profile_id)[0]) + self.assertEqual(steps, 1) + + def test_update_user_actions(self): + # check if the upgrade step is registered + title = u'Add new field audit_workflow to configlet' + step = self._get_upgrade_step_by_title(title) + assert step is not None + + from collective.fingerpointing.interfaces import IFingerPointingSettings + from plone.registry.interfaces import IRegistry + from zope.component import getUtility + registry = getUtility(IRegistry) + + # simulate state on previous version + record = IFingerPointingSettings.__identifier__ + '.audit_workflow' + del registry.records[record] + + with self.assertRaises(KeyError): + registry.forInterface(IFingerPointingSettings) + + # execute upgrade step and verify changes were applied + self._do_upgrade(step) + settings = registry.forInterface(IFingerPointingSettings) + self.assertTrue(hasattr(settings, 'audit_workflow')) + self.assertEqual(settings.audit_workflow, True) diff --git a/src/collective/fingerpointing/tests/test_workflow_subscriber.py b/src/collective/fingerpointing/tests/test_workflow_subscriber.py new file mode 100644 index 0000000..120bb5b --- /dev/null +++ b/src/collective/fingerpointing/tests/test_workflow_subscriber.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +"""Tests for workflow subscriber.""" +from collective.fingerpointing.config import PROJECTNAME +from collective.fingerpointing.interfaces import IFingerPointingSettings +from collective.fingerpointing.testing import INTEGRATION_TESTING +from logging import INFO +from plone import api +from plone.app.testing import setRoles +from plone.app.testing import TEST_USER_ID +from testfixtures import LogCapture + +import unittest + + +class WorkflowSubscribersTestCase(unittest.TestCase): + + """Tests content type life cycle subscribers.""" + + layer = INTEGRATION_TESTING + + def setUp(self): + self.portal = self.layer['portal'] + setRoles(self.portal, TEST_USER_ID, ['Manager']) + + # disable lifecycle audit + record = IFingerPointingSettings.__identifier__ + '.audit_lifecycle' + api.portal.set_registry_record(record, False) + + def test_workflow_transitions(self): + expected = ( + ('collective.fingerpointing', 'INFO', u'user=test ip=127.0.0.1 action=workflow transition object= transition=submit'), + ('collective.fingerpointing', 'INFO', u'user=test ip=127.0.0.1 action=workflow transition object= transition=publish'), + ('collective.fingerpointing', 'INFO', u'user=test ip=127.0.0.1 action=workflow transition object= transition=retract'), + ) + + with LogCapture('collective.fingerpointing', level=INFO) as log: + obj = api.content.create(self.portal, 'News Item', 'foo') + api.content.transition(obj=obj, transition='submit') + api.content.transition(obj=obj, transition='publish') + api.content.transition(obj=obj, transition='retract') + log.check(*expected) + + def test_susbcriber_ignored_when_package_not_installed(self): + # events should not raise errors if package is not installed + qi = self.portal['portal_quickinstaller'] + qi.uninstallProducts(products=[PROJECTNAME]) + + obj = api.content.create(self.portal, 'News Item', 'foo') + api.content.transition(obj=obj, transition='submit') + api.content.transition(obj=obj, transition='publish') + api.content.transition(obj=obj, transition='retract') diff --git a/src/collective/fingerpointing/upgrades/configure.zcml b/src/collective/fingerpointing/upgrades/configure.zcml index 115301e..ed8f198 100644 --- a/src/collective/fingerpointing/upgrades/configure.zcml +++ b/src/collective/fingerpointing/upgrades/configure.zcml @@ -1,4 +1,5 @@ + diff --git a/src/collective/fingerpointing/upgrades/v4/__init__.py b/src/collective/fingerpointing/upgrades/v4/__init__.py new file mode 100644 index 0000000..40a96af --- /dev/null +++ b/src/collective/fingerpointing/upgrades/v4/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/src/collective/fingerpointing/upgrades/v4/configure.zcml b/src/collective/fingerpointing/upgrades/v4/configure.zcml new file mode 100644 index 0000000..5f2828c --- /dev/null +++ b/src/collective/fingerpointing/upgrades/v4/configure.zcml @@ -0,0 +1,19 @@ + + + + + + + + +