products/CPSRSS

changeset 237:c3313b2c9e08

Channels management view
author Georges Racinet on purity.racinet.fr <georges@racinet.fr>
date Sun, 05 Dec 2010 16:36:22 +0100
parents 245fa28df4da
children f5702e848eb5
files browser/__init__.py browser/channels.py tests/basetests.py tests/test_rss.py tests/test_views.py
diffstat 5 files changed, 156 insertions(+), 38 deletions(-) [+]
line diff
     1.1 --- a/browser/__init__.py
     1.2 +++ b/browser/__init__.py
     1.3 @@ -1,36 +1,1 @@
     1.4  # python package
     1.5 -
     1.6 -from Products.Five import BrowserView
     1.7 -from Products.CMFCore.utils import getToolByName
     1.8 -from Products.CPSonFive.browser import AqSafeBrowserView
     1.9 -
    1.10 -class LocalRSSChannelsManagement(AqSafeBrowserView):
    1.11 -
    1.12 -    def __init__(self, *args, **kwargs):
    1.13 -        AqSafeBrowserView.__init__(self, *args, *kwargs)
    1.14 -        self.aqSafeSet('container', self.lookupContainer())
    1.15 -
    1.16 -    def lookupContainer(self):
    1.17 -        """Lookup the relevant container and set it up on self."""
    1.18 -        folder = self.context.aq_inner
    1.19 -
    1.20 -        if cont_id is not None:
    1.21 -            try:
    1.22 -                cont = folder[cont_id]
    1.23 -            except KeyError:
    1.24 -                return None
    1.25 -            if not IRSSChannelContainer.providedBy(cont):
    1.26 -                return None
    1.27 -
    1.28 -        # coding style that works if objectValues turns out to be a generator
    1.29 -        for cont in folder.objectValues([RSSChannelContainer.meta_type]):
    1.30 -            return cont
    1.31 -
    1.32 -    def has_container(self):
    1.33 -        return self.aqSafeGet('container') is not None
    1.34 -
    1.35 -    def channels(self):
    1.36 -        cont = self.aqSafeGet('container')
    1.37 -        if cont is None:
    1.38 -            return ()
    1.39 -        return cont.objectValues([RSSChannel.meta_type])
     2.1 new file mode 100644
     2.2 --- /dev/null
     2.3 +++ b/browser/channels.py
     2.4 @@ -0,0 +1,76 @@
     2.5 +# (C) Copyright 2010 CPS-CMS Community <http://cps-cms.org/>
     2.6 +# Authors:
     2.7 +# G. Racinet <georges@racinet.fr>
     2.8 +#
     2.9 +# This program is free software: you can redistribute it and/or modify
    2.10 +# it under the terms of the GNU General Public License as published by
    2.11 +# the Free Software Foundation, either version 2 of the License, or
    2.12 +# (at your option) any later version.
    2.13 +#
    2.14 +# This program is distributed in the hope that it will be useful,
    2.15 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.16 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.17 +# GNU General Public License for more details.
    2.18 +#
    2.19 +# You should have received a copy of the GNU General Public License
    2.20 +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    2.21 +
    2.22 +from Products.CMFCore.utils import getToolByName
    2.23 +from Products.CPSonFive.browser import AqSafeBrowserView
    2.24 +
    2.25 +from Products.CPSUtil.id import generateId
    2.26 +from Products.CPSRSS.RSSChannel import RSSChannel
    2.27 +from Products.CPSRSS.RSSChannelContainer import RSSChannelContainer
    2.28 +from Products.CPSRSS.interfaces import IRSSChannelContainer
    2.29 +
    2.30 +class ManageChannels(AqSafeBrowserView):
    2.31 +
    2.32 +    def __init__(self, *args, **kwargs):
    2.33 +        AqSafeBrowserView.__init__(self, *args, **kwargs)
    2.34 +        self.aqSafeSet('container', self.lookupContainer())
    2.35 +
    2.36 +    def lookupContainer(self, cont_id=None):
    2.37 +        """Lookup the relevant container and set it up on self."""
    2.38 +        folder = self.context.aq_inner
    2.39 +
    2.40 +        if cont_id is not None:
    2.41 +            try:
    2.42 +                cont = folder[cont_id]
    2.43 +            except KeyError:
    2.44 +                return None
    2.45 +            if not IRSSChannelContainer.providedBy(cont):
    2.46 +                return None
    2.47 +
    2.48 +        # coding style that works if objectValues turns out to be a generator
    2.49 +        for cont in folder.objectValues([RSSChannelContainer.meta_type]):
    2.50 +            return cont
    2.51 +
    2.52 +    def hasContainer(self):
    2.53 +        return self.aqSafeGet('container') is not None
    2.54 +
    2.55 +    def channels(self):
    2.56 +        cont = self.aqSafeGet('container')
    2.57 +        if cont is None:
    2.58 +            return ()
    2.59 +        return tuple(dict(id=chan.getId(), title=chan.title)
    2.60 +                     for chan in cont.objectValues([RSSChannel.meta_type]))
    2.61 +
    2.62 +    def addChannel(self, url):
    2.63 +        """Create a channel, deriving all properties from the feed.
    2.64 +        """
    2.65 +
    2.66 +        cont = self.aqSafeGet('container')
    2.67 +        if cont is None:
    2.68 +            cont = addRSSChannelContainer(self.context)
    2.69 +        channel = RSSChannel('channel', url).__of__(cont)
    2.70 +        d = channel.getData() # might be quite empty if feed has problems
    2.71 +
    2.72 +        title = d.get('title', '')
    2.73 +        description = d.get('description', '')
    2.74 +        cid = generateId(title, container=cont)
    2.75 +        channel._setId(cid)
    2.76 +        channel.manage_changeProperties(title=title, description=description)
    2.77 +
    2.78 +        cont._setObject(cid, channel)
    2.79 +        self.request.RESPONSE.redirect('/'.join((
    2.80 +                cont.absolute_url_path(), cid, 'edit.html')))
     3.1 --- a/tests/basetests.py
     3.2 +++ b/tests/basetests.py
     3.3 @@ -15,6 +15,8 @@
     3.4  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
     3.5  # 02111-1307, USA.
     3.6  
     3.7 +import os
     3.8 +
     3.9  from Testing.ZopeTestCase import ZopeTestCase
    3.10  
    3.11  from Products.CPSDefault.tests.CPSTestCase import CPSTestCase
    3.12 @@ -22,6 +24,10 @@
    3.13  
    3.14  from Products.CPSRSS.RSSTool import RSSTool
    3.15  
    3.16 +def get_feed_url(feed_file):
    3.17 +    return os.path.abspath(os.path.join(os.path.dirname(__file__), feed_file))
    3.18 +
    3.19 +
    3.20  class LayerClass(ExtensionProfileLayerClass):
    3.21      extension_ids = ('CPSRSS:default',)
    3.22  
     4.1 --- a/tests/test_rss.py
     4.2 +++ b/tests/test_rss.py
     4.3 @@ -5,13 +5,11 @@
     4.4  from OFS.Folder import Folder
     4.5  from basetests import CPSRSSTestCase
     4.6  from basetests import ZopeRSSTestCase
     4.7 +from basetests import get_feed_url
     4.8  
     4.9  from Products.CPSRSS.RSSChannelContainer import RSSChannelContainer
    4.10  from Products.CPSRSS.RSSChannelContainer import addRSSChannelContainer
    4.11  
    4.12 -def get_feed_url(feed_file):
    4.13 -    return os.path.abspath(os.path.join(os.path.dirname(__file__), feed_file))
    4.14 -
    4.15  
    4.16  class TestRSS(object):
    4.17  
     5.1 new file mode 100644
     5.2 --- /dev/null
     5.3 +++ b/tests/test_views.py
     5.4 @@ -0,0 +1,73 @@
     5.5 +# (C) Copyright 2010 CPS-CMS Community <http://cps-cms.org/>
     5.6 +# Authors:
     5.7 +# G. Racinet <georges@racinet.fr>
     5.8 +#
     5.9 +# This program is free software: you can redistribute it and/or modify
    5.10 +# it under the terms of the GNU General Public License as published by
    5.11 +# the Free Software Foundation, either version 2 of the License, or
    5.12 +# (at your option) any later version.
    5.13 +#
    5.14 +# This program is distributed in the hope that it will be useful,
    5.15 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.16 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.17 +# GNU General Public License for more details.
    5.18 +#
    5.19 +# You should have received a copy of the GNU General Public License
    5.20 +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    5.21 +
    5.22 +import unittest
    5.23 +
    5.24 +from basetests import ZopeRSSTestCase
    5.25 +from basetests import get_feed_url
    5.26 +
    5.27 +from Products.CPSRSS.browser.channels import ManageChannels
    5.28 +from Products.CPSRSS.RSSChannelContainer import addRSSChannelContainer
    5.29 +from Products.CPSRSS.RSSTool import RSSTool
    5.30 +
    5.31 +
    5.32 +class FakeUrlTool(object):
    5.33 +    """Needed by generateID."""
    5.34 +
    5.35 +    def __init__(self, portal=None):
    5.36 +        self.portal = portal
    5.37 +
    5.38 +    def getPortalObject(self):
    5.39 +        return self.portal
    5.40 +
    5.41 +
    5.42 +class ManageChannelsTestCase(ZopeRSSTestCase):
    5.43 +
    5.44 +    def afterSetUp(self):
    5.45 +        self.folder.portal_url = FakeUrlTool(portal=self.folder)
    5.46 +        self.folder.portal_rss = RSSTool()
    5.47 +
    5.48 +    def makeView(self, folder=None):
    5.49 +        if folder is None:
    5.50 +            folder = self.folder
    5.51 +        return ManageChannels(folder, self.app.REQUEST)
    5.52 +
    5.53 +    def test_has_container(self):
    5.54 +        view = self.makeView()
    5.55 +        self.assertFalse(view.hasContainer())
    5.56 +
    5.57 +        addRSSChannelContainer(self.folder)
    5.58 +        view = self.makeView()
    5.59 +        self.assertTrue(view.hasContainer())
    5.60 +
    5.61 +    def test_channels(self):
    5.62 +        view = self.makeView()
    5.63 +        self.assertEquals(view.channels(), ())
    5.64 +
    5.65 +        container = addRSSChannelContainer(self.folder)
    5.66 +        view = self.makeView()
    5.67 +        view.addChannel(get_feed_url('zope.rss'))
    5.68 +        view.addChannel(get_feed_url('trac_cps.rss'))
    5.69 +
    5.70 +        self.assertEquals(view.channels(),
    5.71 +                          (dict(id='zope-org', title='Zope.org'),
    5.72 +                           dict(id='cps-cms-ticket-query',
    5.73 +                                title='CPS CMS: Ticket Query')))
    5.74 +
    5.75 +
    5.76 +def test_suite():
    5.77 +    return unittest.makeSuite(ManageChannelsTestCase)