Skip to content

Commit

Permalink
Merged redomino branch. Thanks!
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.plone.org/svn/collective/feedfeeder/trunk@229079 db7f04ef-aaf3-0310-a811-c281ed44c4ad
  • Loading branch information
maurits committed Dec 17, 2010
1 parent ee46815 commit d88d738
Show file tree
Hide file tree
Showing 13 changed files with 228 additions and 2 deletions.
15 changes: 14 additions & 1 deletion Products/feedfeeder/HISTORY.txt
Expand Up @@ -4,7 +4,20 @@ History of feedfeeder
2.0.2 (unreleased)
------------------

- Nothing changed yet.
- Modified import RSS and added a new field on feed items named
objectInfo. All feed data will be stored on this field,
as a python dict.
Just changing the remote RSS template, you will able to memoize
additional info without having to modify the feed item schema.
[dmoro]

- Added an option on feed folder that let you choose to redirect
automatically to remote resources. If you have modify permissions
on feed items there will not be any redirect
[dmoro]

- Added new tests
[sithmel]


2.0.1 (2010-11-26)
Expand Down
1 change: 1 addition & 0 deletions Products/feedfeeder/README.txt
Expand Up @@ -64,6 +64,7 @@ filename (md5 hex hash of the atom id of the entry), that way you can
detect whether there are new items.

New items are turned into feed items.
Feed data are filled into feed items (see field named objectInfo).

Scheduled updates for feed folders

Expand Down
1 change: 1 addition & 0 deletions Products/feedfeeder/browser/configure.zcml
Expand Up @@ -39,6 +39,7 @@
<page
name="feed-item.html"
for="Products.feedfeeder.interfaces.item.IFeedItem"
class=".feeditem.FeedItemView"
permission="zope2.View"
template="feed-item.pt"
/>
Expand Down
111 changes: 111 additions & 0 deletions Products/feedfeeder/browser/feeditem.py
@@ -0,0 +1,111 @@
from zope.interface import Interface
from zope.interface import implements
from zope.component import getMultiAdapter

from Products.Five import BrowserView

from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile


class IFeedItemView(Interface):
""" """

def redirect_url():
""" Returns empty string or the url to be redirected, depending on
the configuration of the feed folder.
Returns an empty string if redirect is not enabled or if
you have modify permissions
"""

def parent():
""" Returns the feed item parent """

def checkEditPermission():
""" Returns if you have the edit permission"""


class FeedItemView(BrowserView):
"""
Verify class test
>>> from zope.interface.verify import verifyClass
>>> verifyClass(IFeedItemView, FeedItemView)
True
Fake objects
------------
>>> fake_request = {}
>>> class FakeFolder(object):
... def __init__(self, redirect):
... self.redirect = redirect
... def getRedirect(self):
... return self.redirect
>>> class FakeItem(object):
... def __init__(self, redirect):
... self.folder = FakeFolder(redirect)
... def getObjectInfo(self):
... return {'link':'http://somewhere'}
... def getFeedFolder(self):
... return self.folder
>>> class FakeFeedItemView(FeedItemView):
... def checkEditPermission(self):
... return True
Test redirects
--------------
Item with a folder with redirect enabled
>>> item1 = FakeItem(True)
>>> view1 = FakeFeedItemView(item1, fake_request)
>>> bool(view1.redirect_url())
False
Item with a folder with redirect not enabled
>>> item2 = FakeItem(False)
>>> view2 = FakeFeedItemView(item2, fake_request)
>>> bool(view2.redirect_url())
False
Test redirects with no edit permissions
---------------------------------------
>>> class FakeFeedItemView(FeedItemView):
... def checkEditPermission(self):
... return False
Item with a folder with redirect enabled
>>> item1 = FakeItem(True)
>>> view1 = FakeFeedItemView(item1, fake_request)
>>> view1.redirect_url()
'http://somewhere'
Item with a folder with redirect not enabled
>>> item2 = FakeItem(False)
>>> view2 = FakeFeedItemView(item2, fake_request)
>>> bool(view2.redirect_url())
False
"""
implements(IFeedItemView)

def __call__(self):
redirect_url = self.redirect_url()
if redirect_url:
return self.request.response.redirect(redirect_url)
# Render our template as set in the zcml.
return self.index()

def redirect_url(self):
object_info = self.context.getObjectInfo()
parent = self.parent()
if parent.getRedirect() and not self.checkEditPermission():
return object_info.get('link')
else:
return ''

def parent(self):
return self.context.getFeedFolder()

def checkEditPermission(self):
""" Returns if you have the edit permission"""
membership = getMultiAdapter((self.context, self.request),
name=u'plone_tools').membership()
return membership.checkPermission(
'Modify portal content', self.context)
19 changes: 19 additions & 0 deletions Products/feedfeeder/content/folder.py
Expand Up @@ -19,6 +19,17 @@
)
),

BooleanField(
name='redirect',
widget=BooleanWidget(
description="If checked the feed item will be automatically redirected if you don't have the edit permission.",
description_msgid="help_redirect",
label='Automatic redirect of feed items',
label_msgid='label_redirect',
i18n_domain='feedfeeder',
)
),

StringField(
name='defaultTransition',
vocabulary='getAvailableTransitions',
Expand All @@ -40,6 +51,10 @@

class FeedfeederFolder(ATBTreeFolder):
"""
Verify class test
>>> from zope.interface.verify import verifyClass
>>> verifyClass(IFeedsContainer, FeedfeederFolder)
True
"""
security = ClassSecurityInfo()
# zope3 interfaces
Expand Down Expand Up @@ -137,6 +152,10 @@ def addItem(self, id):
comment='Automatic transition triggered by FeedFolder')
return self[id]

security.declarePublic('getFeedFolder')
def getFeedFolder(self):
return self


registerType(FeedfeederFolder, PROJECTNAME)
# end of class FeedfeederFolder
Expand Down
9 changes: 9 additions & 0 deletions Products/feedfeeder/content/item.py
Expand Up @@ -71,6 +71,15 @@
i18n_domain='feedfeeder',
)
),
ObjectField(
name='objectInfo',
# read_permission=ManagePortal,
# write_permission=ManagePortal,
widget=StringWidget(
visible={'view':'invisible', 'edit':'invisible'},
),
default={},
),

),
)
Expand Down
19 changes: 19 additions & 0 deletions Products/feedfeeder/doc/feedconsuming.txt
Expand Up @@ -55,6 +55,8 @@ are pretty minimal. The class merely has to implement IFeedsContainer.
... self.enclosures[new_id] = self.enclosures[orig_id]
... del self.enclosures[orig_id]
... self.enclosures[new_id].id = new_id
... def getObjectInfo(self): return self.objectInfo
... def setObjectInfo(self, value): self.objectInfo = value
... def objectIds(self): return self.enclosures.keys()
... def getFeedItemUpdated(self): return self.feedItemUpdated
... def setFeedItemUpdated(self, x): self.feedItemUpdated = x
Expand Down Expand Up @@ -137,6 +139,14 @@ Make sure the content all matches up.
1000
>>> test_doc.feed_tags
[u'example']

Object info field filled?
>>> object_info = test_doc.getObjectInfo()
>>> test_doc.getFeedItemAuthor() == object_info['author']
True
>>> 'summary' in object_info
True


Lets check out the document's feed item metadata.

Expand Down Expand Up @@ -174,3 +184,12 @@ Now someone could have added an enclosure that is actually just a link. We appe

>>> thesis.getText()
u'<div>\nGreat news: a final thesis defence date!\n</div>'

Now refresh feeds and check changes

>>> newsamplefile = os.path.join(samplesdir, 'samplefeed5.xml')
>>> container.feeds = ['file://' + newsamplefile]
>>> consumer.retrieveFeedItems(container)
>>> container.items[u'12dc2a55581a62b093b6ad611b3ba2d3'].title == 'The title is changed'
True

3 changes: 3 additions & 0 deletions Products/feedfeeder/interfaces/container.py
Expand Up @@ -20,3 +20,6 @@ def replaceItem(id):
def getItem(id):
"""
"""

def getFeedFolder():
""" """
Expand Up @@ -14,6 +14,8 @@
<property name="filter_content_types">True</property>
<property name="allowed_content_types">
<element value="FeedFeederItem"/>
<element value="News Item"/>
<element value="Event"/>
</property>
<property name="allow_discussion">False</property>
<property name="default_view">feed-folder.html</property>
Expand All @@ -28,7 +30,7 @@
<alias from="sharing" to="folder_localrole_form"/>
<alias from="view" to="(selected layout)"/>
<action title="view" action_id="view" category="object"
condition_expr="python:1" url_expr="string:$object_url/feed-folder.html"
condition_expr="python:1" url_expr="string:$object_url"
visible="True">
<permission value="View"/>
</action>
Expand Down
19 changes: 19 additions & 0 deletions Products/feedfeeder/tests/samples/samplefeed5.xml
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Philips Research Eindhoven News</title>
<subtitle>General news of Philips Research Eindhoven - for internal use only.</subtitle>
<updated>2007-07-30T23:32:36Z</updated>
<id>http://resweb2.natlab.research.philips.com/NlwwNews/rss/NlwwNewsAtom.xml</id>
<entry>
<title>The title is changed</title>
<id>oldnews</id>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
The content is changed
</div>
</content>
<updated></updated>
<published>2008-07-30T23:32:36Z</published>
<author><name>Not Reinout anymore</name></author>
</entry>
</feed>
2 changes: 2 additions & 0 deletions Products/feedfeeder/tests/testDocUnitTests.py
Expand Up @@ -9,4 +9,6 @@ def test_suite():
package='Products.feedfeeder.doc'),
doctestunit.DocFileSuite('extendeddatetime.txt',
package='Products.feedfeeder.doc'),
doctestunit.DocTestSuite(module='Products.feedfeeder.browser.feeditem'),

))
24 changes: 24 additions & 0 deletions Products/feedfeeder/tests/test_fields.py
@@ -0,0 +1,24 @@
from Products.feedfeeder.tests.MainTestCase import MainTestCase


class TestFields(MainTestCase):
""" """
def afterSetUp(self):
self.loginAsPortalOwner()

feedfolder_id = self.folder.invokeFactory('FeedfeederFolder', 'feedfolder')

self.feedfolder = getattr(self.folder, feedfolder_id)
# self.feedfolder.invokeFactor

def test_redirect_field(self):
""" Does exists the redirect field? """
self.assertTrue(getattr(self.feedfolder, 'getRedirect'))

def test_suite():
from unittest import TestSuite, makeSuite
suite = TestSuite()
suite.addTest(makeSuite(TestFields))
return suite


3 changes: 3 additions & 0 deletions Products/feedfeeder/utilities.py
Expand Up @@ -149,6 +149,8 @@ def _retrieveSingleFeed(self, feedContainer, url):
addItem = feedContainer.replaceItem
else:
# Not new, not refreshed: let it be, laddy.
prev.setObjectInfo(entry.copy())
prev.reindexObject()
continue

obj = addItem(id)
Expand Down Expand Up @@ -186,6 +188,7 @@ def _retrieveSingleFeed(self, feedContainer, url):
feedItemUpdated=updated,
link=link,
feedTitle=parsed['feed'].get('title', ''),
objectInfo=entry.copy(),
)
# Tags cannot be handled by the update method AFAIK,
# because it is not an Archetypes field.
Expand Down

0 comments on commit d88d738

Please sign in to comment.