Skip to content

Commit

Permalink
Add an optional 'default' argument to plone.api.content.get_state. Refs
Browse files Browse the repository at this point in the history
#246.

The default value is returned when there is no workflow defined for the object.
  • Loading branch information
jaroel committed Jun 23, 2015
1 parent e9ca5af commit 8a21470
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 7 deletions.
4 changes: 4 additions & 0 deletions docs/CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Changelog
1.3.3 (unreleased)
------------------

- plone.api.content.get_state now allows for an optional default value.
This is used when no workflow is defined for the object. Refs #246
[jaroel]

- Fixed tests for Plone 5. Refs #241.
[jaroel]

Expand Down
12 changes: 12 additions & 0 deletions docs/content.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Consider the following portal structure::
.. invisible-code-block: python
portal = api.portal.get()
image = api.content.create(type='Image', id='image', container=portal)
blog = api.content.create(type='Link', id='blog', container=portal)
about = api.content.create(type='Folder', id='about', container=portal)
events = api.content.create(type='Folder', id='events', container=portal)
Expand Down Expand Up @@ -395,6 +396,17 @@ To find out the current workflow state of your content, use the :meth:`api.conte
self.assertEqual(state, 'private')
The optional `default` argument is returned if no workflow is defined for the object.

.. code-block:: python
from plone import api
portal = api.portal.get()
state = api.content.get_state(obj=portal['image'], default='Unknown')
.. invisible-code-block: python
self.assertEqual(state, 'Unknown')
.. _content_transition_example:

Expand Down
15 changes: 12 additions & 3 deletions src/plone/api/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class IBaseObject(Interface):
else:
from Products.Archetypes.interfaces.base import IBaseObject

_marker = []


@required_parameters('container', 'type')
@at_least_one_of('id', 'title')
Expand Down Expand Up @@ -283,19 +285,26 @@ def delete(obj=None, objects=None):


@required_parameters('obj')
def get_state(obj=None):
def get_state(obj=None, default=_marker):
"""Get the current workflow state of the object.
:param obj: [required] Object that we want to get the state for.
:type obj: Content object
:returns: Object's current workflow state
:param default: The value returned if the object has no workflow defined.
:returns: Object's current workflow state, or `default`.
:rtype: string
:raises:
Products.CMFCore.WorkflowCore.WorkflowException
:Example: :ref:`content_get_state_example`
"""
workflow = portal.get_tool('portal_workflow')
return workflow.getInfoFor(obj, 'review_state')

if default is not _marker and not workflow.getWorkflowsFor(obj):
return default

# This still raises WorkflowException when the workflow state is broken,
# ie 'review_state' is absent
return workflow.getInfoFor(ob=obj, name='review_state')


def _wf_transitions_for(workflow, from_state, to_state):
Expand Down
31 changes: 27 additions & 4 deletions src/plone/api/tests/test_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from OFS.event import ObjectWillBeMovedEvent
from OFS.interfaces import IObjectWillBeMovedEvent
from Products.CMFCore.interfaces import IContentish
from Products.CMFCore.WorkflowCore import WorkflowException
from Products.ZCatalog.interfaces import IZCatalog
from plone import api
from plone.api.tests.base import INTEGRATION_TESTING
Expand Down Expand Up @@ -41,6 +42,7 @@ def setUp(self):
"""Create a portal structure which we can test against.
Plone (portal root)
|-- image
|-- blog
|-- about
| |-- team
Expand Down Expand Up @@ -71,6 +73,9 @@ def setUp(self):
self.sprint = api.content.create(
container=self.events, type='Event', id='sprint')

self.image = api.content.create(
container=self.portal, type='Image', id='image')

def test_create_constraints(self):
"""Test the constraints when creating content."""
from plone.api.exc import InvalidParameterError
Expand Down Expand Up @@ -657,11 +662,13 @@ def test_find_depth(self):
def test_find_interface(self):
# Find documents by interface or it's identifier
identifier = IContentish.__identifier__
documents = api.content.find(object_provides=identifier)
self.assertEqual(len(documents), 8)
brains = api.content.find(object_provides=identifier)
by_identifier = [x.getObject() for x in brains]

brains = api.content.find(object_provides=IContentish)
by_interface = [x.getObject() for x in brains]

documents = api.content.find(object_provides=IContentish)
self.assertEqual(len(documents), 8)
self.assertEqual(by_identifier, by_interface)

def test_find_dict(self):
# Pass arguments using dict
Expand Down Expand Up @@ -692,6 +699,22 @@ def test_get_state(self):
review_state = api.content.get_state(obj=self.blog)
self.assertEqual(review_state, 'private')

def test_get_state_default_value(self):
"""Test passing in a default value.
"""
# A WorkflowException is raise if no workflow is defined for the obj.
# This is normally the case for Images and Files.
with self.assertRaises(WorkflowException):
review_state = api.content.get_state(obj=self.image)

default = 'my default value'
review_state = api.content.get_state(obj=self.image, default=default)
review_state is default

# the default should not override the actual state.
review_state = api.content.get_state(obj=self.blog, default=default)
review_state is not default

def test_transition(self):
"""Test transitioning the workflow state on a content item."""
from plone.api.exc import InvalidParameterError
Expand Down

0 comments on commit 8a21470

Please sign in to comment.