[Checkins] SVN: Products.CMF SyndicationTool now uses an ISydnicationInfo adapter for all object settings.
Charlie Clark
charlie at begeistert.org
Tue Oct 5 14:24:36 EDT 2010
Log message for revision 117255:
SyndicationTool now uses an ISydnicationInfo adapter for all object settings.
Security added to previously public methods.
Additional public method added to expose syndication information.
getHTML4UpdateBase() method deprecated.
Changed:
U Products.CMFCore/trunk/Products/CMFCore/interfaces/_tools.py
U Products.CMFDefault/trunk/Products/CMFDefault/SyndicationTool.py
U Products.CMFDefault/trunk/Products/CMFDefault/tests/test_SyndicationTool.py
-=-
Modified: Products.CMFCore/trunk/Products/CMFCore/interfaces/_tools.py
===================================================================
--- Products.CMFCore/trunk/Products/CMFCore/interfaces/_tools.py 2010-10-05 17:59:37 UTC (rev 117254)
+++ Products.CMFCore/trunk/Products/CMFCore/interfaces/_tools.py 2010-10-05 18:24:36 UTC (rev 117255)
@@ -1289,6 +1289,15 @@
o falls back to retrieving the site-wide syndication flag
"""
+ def getSyndicationInfo(obj):
+ """ Return a dictionary of syndication information for an
+ an object:
+ * period
+ * frequency
+ * base as a DateTime object
+ * max_items
+ """
+
def getUpdatePeriod(obj=None):
""" Return the update period for the syndicated feed
@@ -1317,6 +1326,7 @@
"""
def getHTML4UpdateBase(obj=None):
+ ### Deprecated
""" return the HTML-formatted feed publishing base date
o falls back to the site-wide value if no object is passed in
Modified: Products.CMFDefault/trunk/Products/CMFDefault/SyndicationTool.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/SyndicationTool.py 2010-10-05 17:59:37 UTC (rev 117254)
+++ Products.CMFDefault/trunk/Products/CMFDefault/SyndicationTool.py 2010-10-05 18:24:36 UTC (rev 117255)
@@ -10,21 +10,24 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""
-CMFDefault portal_syndication tool.
+""" CMFDefault portal_syndication tool.
Manage outbound RSS syndication of folder content.
"""
+from warnings import warn
+
from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import aq_base
from App.class_init import InitializeClass
from App.special_dtml import HTMLFile
from DateTime.DateTime import DateTime
from OFS.SimpleItem import SimpleItem
+
+from zope.component import getAdapter, queryAdapter
from zope.interface import implements
-from Products.CMFCore.interfaces import ISyndicationTool
+from Products.CMFCore.interfaces import ISyndicationTool, ISyndicationInfo
from Products.CMFCore.PortalFolder import PortalFolderBase
from Products.CMFCore.utils import _checkPermission
from Products.CMFCore.utils import registerToolInterface
@@ -37,28 +40,28 @@
class SyndicationError(Exception):
-
+
pass
-
+
class SyndicationTool(UniqueObject, SimpleItem):
""" The syndication tool manages the site-wide policy for
syndication of folder content as RSS.
"""
implements(ISyndicationTool)
-
+
id = 'portal_syndication'
meta_type = 'Default Syndication Tool'
-
+
security = ClassSecurityInfo()
-
+
#Default Sitewide Values
isAllowed = 0
syUpdatePeriod = 'daily'
syUpdateFrequency = 1
syUpdateBase = DateTime()
max_items = 15
-
+
#ZMI Methods
manage_options = ( ( { 'label' : 'Overview'
, 'action' : 'overview'
@@ -67,10 +70,10 @@
},
)
)
-
+
security.declareProtected(ManagePortal, 'overview')
overview = HTMLFile('synOverview', _dtmldir)
-
+
security.declareProtected(ManagePortal, 'editProperties')
def editProperties( self
, updatePeriod=None
@@ -86,7 +89,7 @@
"""
if isAllowed is not None:
self.isAllowed = isAllowed
-
+
if updatePeriod is not None:
self.syUpdatePeriod = updatePeriod
else:
@@ -94,7 +97,7 @@
del self.syUpdatePeriod
except (AttributeError, KeyError):
pass
-
+
if updateFrequency is not None:
self.syUpdateFrequency = int(updateFrequency)
else:
@@ -102,7 +105,7 @@
del self.syUpdateFrequency
except (AttributeError, KeyError):
pass
-
+
if updateBase is not None:
if not hasattr(updateBase, 'ISO'):
updateBase = DateTime( updateBase )
@@ -112,7 +115,7 @@
del self.syUpdateBase
except (AttributeError, KeyError):
pass
-
+
if max_items is not None:
self.max_items = int(max_items)
else:
@@ -120,8 +123,17 @@
del self.max_items
except (AttributeError, KeyError):
pass
-
- security.declarePublic( 'editSyInformationProperties' )
+
+ def _syndication_info(self, obj):
+ """Get a SyndicationInfo adapter for managing object
+ syndication settings
+ """
+ adapter = queryAdapter(obj, ISyndicationInfo)
+ if adapter is None:
+ raise SyndicationError("Syndication is not possible")
+ return adapter
+
+ security.declareProtected(ManageProperties, 'editSyInformationProperties')
def editSyInformationProperties( self
, obj
, updatePeriod=None
@@ -135,69 +147,42 @@
These are held on the syndication_information object.
Not Sitewide Properties.
"""
- if not _checkPermission( ManageProperties, obj ):
- raise AccessControl_Unauthorized
-
- syInfo = getattr(obj, 'syndication_information', None)
-
- if syInfo is None:
+ info = self._syndication_info(obj)
+
+ if not info.enabled:
raise SyndicationError('Syndication is Disabled')
-
- if updatePeriod is not None:
- syInfo.syUpdatePeriod = updatePeriod
- else:
- syInfo.syUpdatePeriod = self.syUpdatePeriod
-
- if updateFrequency is not None:
- syInfo.syUpdateFrequency = int(updateFrequency)
- else:
- syInfo.syUpdateFrequency = self.syUpdateFrequency
-
+
+ updatePeriod = updatePeriod or self.syUpdatePeriod
+ updateFrequency = updateFrequency or self.syUpdateFrequency
+ updateBase = updateBase or self.syUpdateBase
+ max_items = max_items or self.max_items
if updateBase is not None:
if not hasattr(updateBase, 'ISO'):
updateBase = DateTime( updateBase )
- syInfo.syUpdateBase = updateBase
- else:
- syInfo.syUpdateBase = self.syUpdateBase
-
- if max_items is not None:
- syInfo.max_items = int(max_items)
- else:
- syInfo.max_items = self.max_items
-
- security.declarePublic('enableSyndication')
+
+ values = {'period': updatePeriod, 'frequency': int(updateFrequency),
+ 'base': updateBase, 'max_items': int(max_items)}
+ info.set_info(**values)
+
+ security.declareProtected(ManageProperties, 'enableSyndication')
def enableSyndication(self, obj):
"""
Enable syndication for the obj
"""
if not self.isSiteSyndicationAllowed():
raise SyndicationError('Syndication is Disabled')
-
- if hasattr(aq_base(obj), 'syndication_information'):
- raise SyndicationError('Syndication Information Exists')
-
- syInfo = SyndicationInformation()
- obj._setObject('syndication_information', syInfo)
- syInfo = obj._getOb('syndication_information')
- syInfo.syUpdatePeriod = self.syUpdatePeriod
- syInfo.syUpdateFrequency = self.syUpdateFrequency
- syInfo.syUpdateBase = self.syUpdateBase
- syInfo.max_items = self.max_items
- syInfo.description = "Channel Description"
-
- security.declarePublic('disableSyndication')
+
+ info = self._syndication_info(obj)
+ info.enable()
+
+ security.declareProtected(ManageProperties, 'disableSyndication')
def disableSyndication(self, obj):
"""
Disable syndication for the obj; and remove it.
"""
- syInfo = getattr(obj, 'syndication_information', None)
-
- if syInfo is None:
- raise SyndicationError('This object does not have Syndication \
- Information')
-
- obj._delObject('syndication_information')
-
+ info = self._syndication_info(obj)
+ info.disable()
+
security.declarePublic('getSyndicatableContent')
def getSyndicatableContent(self, obj):
"""
@@ -209,7 +194,7 @@
else:
values = PortalFolderBase.contentValues(obj)
return values
-
+
security.declarePublic('buildUpdatePeriods')
def buildUpdatePeriods(self):
"""
@@ -222,14 +207,14 @@
, ('yearly', 'Yearly')
)
return updatePeriods
-
+
security.declarePublic('isSiteSyndicationAllowed')
def isSiteSyndicationAllowed(self):
"""
Return sitewide syndication policy
"""
return self.isAllowed
-
+
security.declarePublic('isSyndicationAllowed')
def isSyndicationAllowed(self, obj=None):
"""
@@ -238,13 +223,19 @@
particular obj is enabled, allowing for turning on only
specific folders for syndication.
"""
- syInfo = getattr(aq_base(obj), 'syndication_information',
- None)
- if syInfo is None:
- return 0
- else:
- return self.isSiteSyndicationAllowed()
-
+ info = self._syndication_info(obj)
+ return info.enabled
+
+ security.declarePublic('getSyndicationInfo')
+ def getSyndicationInfo(self, obj):
+ """
+ Return a dictionary of syndication parameters
+ """
+ info = self._syndication_info(obj)
+ if not info.enabled:
+ raise SyndicationError('Syndication is not allowed')
+ return info.get_info()
+
security.declarePublic('getUpdatePeriod')
def getUpdatePeriod( self, obj=None ):
"""
@@ -252,22 +243,11 @@
This is either on the object being passed or the
portal_syndication tool (if a sitewide value or default
is set)
-
+
NOTE: Need to add checks for sitewide policies!!!
"""
- if not self.isSiteSyndicationAllowed():
- raise SyndicationError('Syndication is Not Allowed')
-
- if obj is None:
- return self.syUpdatePeriod
-
- syInfo = getattr(obj, 'syndication_information', None)
-
- if syInfo is not None:
- return syInfo.syUpdatePeriod
- else:
- return 'Syndication is Not Allowed'
-
+ return self.getSyndicationInfo(obj)['period']
+
security.declarePublic('getUpdateFrequency')
def getUpdateFrequency(self, obj=None):
"""
@@ -275,28 +255,17 @@
the syn namespace. This is either on the object being
pass or the portal_syndication tool (if a sitewide value
or default is set).
-
+
Note: Need to add checks for sitewide policies!!!
"""
- if not self.isSiteSyndicationAllowed():
- raise SyndicationError('Syndication is not Allowed')
-
- if obj is None:
- return self.syUpdateFrequency
-
- syInfo = getattr(obj, 'syndication_information',
- None)
- if syInfo is not None:
- return syInfo.syUpdateFrequency
- else:
- return 'Syndication is not Allowed'
-
+ return self.getSyndicationInfo(obj)['frequency']
+
security.declarePublic('getUpdateBase')
def getUpdateBase(self, obj=None):
"""
Return the base date to be used with the update frequency
and the update period to calculate a publishing schedule.
-
+
Note: I'm not sure what's best here, creation date, last
modified date (of the folder being syndicated) or some
arbitrary date. For now, I'm going to build a updateBase
@@ -304,57 +273,23 @@
Additionally, sitewide policy checks might have a place
here...
"""
- if not self.isSiteSyndicationAllowed():
- raise SyndicationError('Syndication is not Allowed')
-
- if obj is None:
- when = self.syUpdateBase
- return when.ISO()
-
- syInfo = getattr(obj, 'syndication_information',
- None)
- if syInfo is not None:
- when = syInfo.syUpdateBase
- return when.ISO()
- else:
- return 'Syndication is not Allowed'
-
+ return self.getSyndicationInfo(obj)['base'].ISO()
+
security.declarePublic('getHTML4UpdateBase')
def getHTML4UpdateBase(self, obj=None):
"""
Return HTML4 formated UpdateBase DateTime
"""
- if not self.isSiteSyndicationAllowed():
- raise SyndicationError('Syndication is not Allowed')
-
- if obj is None:
- when = self.syUpdateBase
- return when.HTML4()
-
- syInfo = getattr(obj, 'syndication_information',
- None)
- if syInfo is not None:
- when = syInfo.syUpdateBase
- return when.HTML4()
- else:
- return 'Syndication is not Allowed'
-
+ warn("RSS 2.0 uses RFC 822 formatting"
+ " this method will be removed in CMF 2.4",
+ DeprecationWarning, stacklevel=2)
+ return self.getSyndicationInfo(obj)['base'].HTML4()
+
def getMaxItems(self, obj=None):
"""
Return the max_items to be displayed in the syndication
"""
- if not self.isSiteSyndicationAllowed():
- raise SyndicationError('Syndication is not Allowed')
-
- if obj is None:
- return self.max_items
-
- syInfo = getattr(obj, 'syndication_information',
- None)
- if syInfo is not None:
- return syInfo.max_items
- else:
- return 'Syndication is not Allowed'
+ return self.getSyndicationInfo(obj)['max_items']
InitializeClass(SyndicationTool)
registerToolInterface('portal_syndication', ISyndicationTool)
Modified: Products.CMFDefault/trunk/Products/CMFDefault/tests/test_SyndicationTool.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/tests/test_SyndicationTool.py 2010-10-05 17:59:37 UTC (rev 117254)
+++ Products.CMFDefault/trunk/Products/CMFDefault/tests/test_SyndicationTool.py 2010-10-05 18:24:36 UTC (rev 117255)
@@ -17,6 +17,8 @@
import Testing
from DateTime.DateTime import DateTime
+from zope.component import getSiteManager
+from zope.interface import alsoProvides
from zope.interface.verify import verifyClass
from zope.testing.cleanup import cleanUp
@@ -29,6 +31,41 @@
return 'dummy'
+class DummyInfo:
+
+ def __init__(self, context):
+ self.context = context
+
+ def __call__(self):
+ pass
+
+ @property
+ def enabled(self):
+ if hasattr(self.context, 'enabled'):
+ return self.context.enabled
+ return False
+
+ def enable(self):
+ self.context.enabled = True
+
+ def disable(self):
+ self.context.enabled = False
+
+ def set_info(self, **kw):
+ for k, v in kw.items():
+ setattr(self.context, k, v)
+
+ def get_info(self):
+ if hasattr(self.context, 'frequency'):
+ # values set on context
+ return {'frequency': self.context.frequency,
+ 'period': self.context.period,
+ 'base': self.context.base,
+ 'max_items': self.context.max_items}
+ #values from syndication tool
+ return {'frequency': '1', 'period': 'daily',
+ 'base': DateTime('2010/10/04 12:00:00 GMT'), 'max_items': 15}
+
class SyndicationToolTests(SecurityTest):
def _getTargetClass(self):
@@ -38,6 +75,14 @@
def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)
+ def _makeContext(self):
+ from Products.CMFCore.interfaces import IFolderish, ISyndicationInfo
+ self.folder = folder = Dummy()
+ alsoProvides(folder, IFolderish)
+ sm = getSiteManager()
+ sm.registerAdapter(DummyInfo, [IFolderish], ISyndicationInfo)
+ return folder
+
def tearDown(self):
cleanUp()
SecurityTest.tearDown(self)
@@ -98,20 +143,29 @@
self.failUnless(tool.isAllowed)
self.assertEqual(tool.max_items, MAX_ITEMS)
- def test_editSyInformationProperties_disabled(self):
- from zExceptions import Unauthorized
+ def test_object_not_syndicatable(self):
+ from Products.CMFDefault.SyndicationTool import SyndicationError
+ tool = self._makeOne()
+ self.assertRaises(SyndicationError, tool._syndication_info, Dummy)
+ def test_object_is_syndicatable(self):
tool = self._makeOne()
- dummy = Dummy()
- try:
- tool.editSyInformationProperties(object, updateFrequency=1)
- except Unauthorized:
- raise
- except: # WAAA! it raises a string!
- pass
- else:
- assert 0, "Didn't raise"
+ context = self._makeContext()
+ tool._syndication_info(context)
+ def test_object_syndication_is_disabled(self):
+ tool = self._makeOne()
+ context = self._makeContext()
+ info = tool._syndication_info(context)
+ self.assertFalse(tool.isSyndicationAllowed(context))
+
+ def test_enable_object_syndication(self):
+ tool = self._makeOne()
+ tool.isAllowed = True
+ context = self._makeContext()
+ tool.enableSyndication(context)
+ self.assertTrue(tool.isSyndicationAllowed(context))
+
def test_editSyInformationProperties_normal(self):
PERIOD = 'hourly'
FREQUENCY = 4
@@ -119,21 +173,20 @@
MAX_ITEMS = 42
tool = self._makeOne()
- dummy = Dummy()
- info = dummy.syndication_information = Dummy()
+ tool.isAllowed = True
+ context = self._makeContext()
+ tool.enableSyndication(context)
- tool.editSyInformationProperties(dummy,
+ tool.editSyInformationProperties(context,
updatePeriod=PERIOD,
updateFrequency=FREQUENCY,
updateBase=NOW,
max_items=MAX_ITEMS,
)
+ self.assertEqual(tool.getSyndicationInfo(context),
+ {'frequency': FREQUENCY, 'period': PERIOD,
+ 'base': NOW, 'max_items': MAX_ITEMS})
- self.assertEqual(info.syUpdatePeriod, PERIOD)
- self.assertEqual(info.syUpdateFrequency, FREQUENCY)
- self.assertEqual(info.syUpdateBase, NOW)
- self.assertEqual(info.max_items, MAX_ITEMS)
-
def test_editSyInformationProperties_coercing(self):
PERIOD = 'hourly'
FREQUENCY = 4
@@ -141,21 +194,21 @@
MAX_ITEMS = 42
tool = self._makeOne()
- dummy = Dummy()
- info = dummy.syndication_information = Dummy()
+ tool.isAllowed = True
+ context = self._makeContext()
+ tool.enableSyndication(context)
- tool.editSyInformationProperties(dummy,
+ tool.editSyInformationProperties(context,
updatePeriod=PERIOD,
updateFrequency='%d' % FREQUENCY,
updateBase=NOW.ISO(),
max_items='%d' % MAX_ITEMS,
)
+ self.assertEqual(tool.getSyndicationInfo(context),
+ {'frequency': FREQUENCY, 'period': PERIOD,
+ 'base': DateTime(NOW.ISO()),
+ 'max_items': MAX_ITEMS})
- self.assertEqual(info.syUpdatePeriod, PERIOD)
- self.assertEqual(info.syUpdateFrequency, FREQUENCY)
- self.assertEqual(info.syUpdateBase, DateTime(NOW.ISO()))
- self.assertEqual(info.max_items, MAX_ITEMS)
-
def test_editProperties_isAllowedOnly(self):
# Zope 2.8 crashes if we don't edit all properties.
# This is because Zope now raises AttributeError
More information about the checkins
mailing list