def _update_syndication_info(portal): # now, go through all containers and look for syndication_info # objects from Products.CMFPlone.interfaces.syndication import IFeedSettings from Products.CMFPlone.interfaces.syndication import ISyndicatable catalog = getToolByName(portal, 'portal_catalog') # get all folder types from portal_types at_tool = getToolByName(portal, 'archetype_tool', None) folder_types = set([]) if at_tool is not None: for _type in at_tool.listPortalTypesWithInterfaces([ISyndicatable]): folder_types.add(_type.getId()) folder_types = folder_types | _getDexterityFolderTypes(portal) for brain in catalog(portal_type=tuple(folder_types)): try: obj = brain.getObject() except (AttributeError, KeyError): continue if 'syndication_information' not in obj.objectIds(): return # just having syndication info object means # syndication is enabled info = obj.syndication_information try: settings = IFeedSettings(obj) except TypeError: continue settings.enabled = True try: settings.max_items = info.max_items except AttributeError: pass settings.feed_types = ('RSS',) obj.manage_delObjects(['syndication_information'])
def __call__(self): settings = IFeedSettings(self.context) settings.enabled = True settings._p_changed = True transaction.commit() IStatusMessage(self.request).add('RSS enabled on %s' % self.context.getId()) self.request.RESPONSE.redirect(self.context.absolute_url())
def enableSyndication(self, obj): """ Enable syndication for the obj """ if not _checkPermission(ModifyPortalContent, obj): raise Unauthorized settings = IFeedSettings(obj) settings.enabled = True
def enable_syndication(event_listing_block, event=None): """ Enables syndication on the given event listing block. This must be called from a subscriber when an event listing block is created so the syndication is enabled by default on the event listing blocks. """ settings = IFeedSettings(event_listing_block) settings.enabled = True settings.feed_types = ('RSS', 'rss.xml', 'atom.xml')
def afterSetUp(self): self.syndication = getToolByName(self.portal, 'portal_syndication') self.folder.invokeFactory('Document', 'doc1') self.folder.invokeFactory('Document', 'doc2') self.folder.invokeFactory('File', 'file') self.doc1 = self.folder.doc1 self.doc2 = self.folder.doc2 self.file = self.folder.file # Enable syndication on folder registry = getUtility(IRegistry) self.site_settings = registry.forInterface(ISiteSyndicationSettings) settings = IFeedSettings(self.folder) settings.enabled = True self.folder_settings = settings
def __call__(self): if self.newsml_enabled(raise404=True): settings = IFeedSettings(self.context, None) if settings and self.__name__ not in settings.feed_types: raise NotFound self.request.response.setHeader('Content-Type', 'application/vnd.iptc.g2.newsitem+xml') return self.index()
def test_content_should_implement_empty_feed_settings_to_prevent_errors(self): doc = api.content.create( type='Document', id='docblah', container=self.portal) settings = IFeedSettings(doc) # should not cause TypeError self.assertEquals(settings.feed_types, ())
def enable_rss2(context): """ Enable the new-style RSS2 feed #14323 """ portal = getToolByName(context, 'portal_url').getPortalObject() catalog = getToolByName(portal, 'portal_catalog') at_tool = getToolByName(portal, 'archetype_tool') logger.info('Enabling new RSS2') registry = getUtility(IRegistry) synd_settings = registry.forInterface(ISiteSyndicationSettings) custom_rss2 = u'RSS2|RSS 2.0 EEA' current_allowed = synd_settings.allowed_feed_types if custom_rss2 not in current_allowed: new_allowed = current_allowed + (custom_rss2, ) new_allowed = tuple(unicode(x) for x in new_allowed) synd_settings.allowed_feed_types = new_allowed logger.info('Adding RSS2 to allowed views') folder_types = set([]) for _type in at_tool.listPortalTypesWithInterfaces([ISyndicatable]): folder_types.add(_type.getId()) folder_types = folder_types index = 0 for brain in catalog(portal_type=tuple(folder_types), Language='all'): obj = brain.getObject() try: settings = IFeedSettings(obj) except TypeError: continue if settings.enabled: current_feeds = list(settings.feed_types) if u'RSS2' in current_feeds: continue new_feeds = [u'RSS2'] current_feeds.extend(new_feeds) settings.feed_types = tuple(set(current_feeds)) message = 'Enabling RSS2 for %s' % brain.getURL() logger.info(message) if index % 100 == 0: transaction.commit() logger.info('Transaction commited') index += 1 logger.info('Done enable RSS2')
def rss_url(self): settings = IFeedSettings(self.context) types = settings.feed_types url = self.context.absolute_url() if len(types) == 0: return url _type = types[0] return f'{url}/{_type}'
def rss_url(self): settings = IFeedSettings(self.context) types = settings.feed_types url = self.context.absolute_url() if len(types) == 0: return url _type = types[0] return '%s/%s' % (url, _type)
def isSyndicationAllowed(self, obj=None): """ Check whether syndication is enabled for the site. This provides for extending the method to check for whether a particular obj is enabled, allowing for turning on only specific folders for syndication. """ settings = IFeedSettings(obj) return settings.enabled
def context_enabled(self, raise404=False): settings = IFeedSettings(self.context, None) if not self.context_allowed() or not settings.enabled: if raise404: raise NotFound else: return False else: return True
def afterSetUp(self): super(TestRenderBody, self).afterSetUp() self.folder.invokeFactory('News Item', 'news1') self.folder.invokeFactory('News Item', 'news2') self.news1 = self.folder.news1 self.news1.setTitle('News 1') self.news1.setDescription('The news item #1') self.news1.setText(BODY_TEXT) self.news2 = self.folder.news2 self.news2.setTitle('News 2') self.news2.setText(ROOTED_BODY_TEXT) # Enable syndication on folder registry = getUtility(IRegistry) self.site_settings = registry.forInterface(ISiteSyndicationSettings) settings = IFeedSettings(self.folder) settings.enabled = True settings.render_body = True self.folder_settings = settings
def allowed_feed_types(self): settings = IFeedSettings(self.context) factory = getUtility(IVocabularyFactory, "plone.app.vocabularies.SyndicationFeedTypes") vocabulary = factory(self.context) types = [] for typ in settings.feed_types: types.append(vocabulary.getTerm(typ)) return [{'path': t.value, 'title': t.title} for t in types]
def __init__(self, context): self.context = context self.settings = IFeedSettings(context) self.site = getSite() if self.show_about: self.pm = getToolByName(self.context, 'portal_membership') registry = getUtility(IRegistry) self.view_action_types = registry.get( 'plone.types_use_view_action_in_listings', [])
def __getattr__(self, name): default = None if name in ISiteSyndicationSettings.names(): default = getattr(self.site_settings, name) elif name == 'enabled' and self.site_settings.default_enabled: default = True elif name in IFeedSettings.names(): default = IFeedSettings[name].default return self._metadata.get(name, default)
def afterSetUp(self): self.syndication = getToolByName(self.portal, 'portal_syndication') self.folder.invokeFactory('Document', 'doc') self.folder.invokeFactory('Document', 'doc1') self.folder.invokeFactory('News Item', 'news1') self.folder.invokeFactory('News Item', 'news2') self.folder.invokeFactory('File', 'file') self.doc1 = self.folder.doc1 self.news1 = self.folder.news1 self.news1.setText(BODY_TEXT) self.news2 = self.folder.news2 self.news2.setText(ROOTED_BODY_TEXT) self.file = self.folder.file # Enable syndication on folder registry = getUtility(IRegistry) self.site_settings = registry.forInterface(ISiteSyndicationSettings) settings = IFeedSettings(self.folder) settings.enabled = True self.folder_settings = settings
def newsml_allowed(self): util = getMultiAdapter((self.context, self.request), name='syndication-util') if not util.site_enabled(): return False elif ISyndicatable.providedBy(self.context): settings = IFeedSettings(self.context, None) if settings.enabled: return True return False
def __init__(self, context): self.context = context self.settings = IFeedSettings(context) self.site = getSite() if self.show_about: self.pm = getToolByName(self.context, 'portal_membership') pprops = getToolByName(self.context, 'portal_properties') self.site_props = pprops.site_properties self.view_action_types = self.site_props.getProperty( 'typesUseViewActionInListings', ('File', 'Image'))
def __call__(self): util = getMultiAdapter((self.context, self.request), name='syndication-util') if util.context_enabled(raise404=True): settings = IFeedSettings(self.context) if self.__name__ not in settings.feed_types: raise NotFound self.request.response.setHeader('Content-Type', 'application/atom+xml') return self.index()
def __call__(self): util = getMultiAdapter((self.context, self.request), name='syndication-util') context_state = getMultiAdapter((self.context, self.request), name=u'plone_context_state') if context_state.is_portal_root() or util.context_enabled(raise404=True): settings = IFeedSettings(self.context) if self.__name__ not in settings.feed_types: raise NotFound self.request.response.setHeader('Content-Type', self.content_type) return self.index()
def rss2_is_enabled(self): """ :return: Return boolean value if rss2 type is in feed_types :rtype: bool """ try: settings = IFeedSettings(self.context) except TypeError: return False if settings.enabled: current_feeds = list(settings.feed_types) return u'rss.xml' in current_feeds
def getRssLinks(self, obj): settings = IFeedSettings(obj, None) if settings is None: return [] factory = getUtility(IVocabularyFactory, "plone.app.vocabularies.SyndicationFeedTypes") vocabulary = factory(self.context) urls = [] for typ in settings.feed_types: try: term = vocabulary.getTerm(typ) except LookupError: continue urls.append({ 'title': '%s - %s' % (obj.Title(), term.title), 'url': obj.absolute_url() + '/' + term.value }) return urls
def createEventsAndNews(portal): """ Inspired by Products.CMFPlone.setuphandlers """ language = portal.Language() wftool = getToolByName(portal, "portal_workflow") actu_folder = getattr(portal, "actualites") events_folder = getattr(portal, "evenements") # News topic if actu_folder: actu_folder.title = _(u"Actualités") actu_folder.description = _(u"Actualités du site") _createObjectByType( "Collection", portal.actualites, id="actualites", title=actu_folder.title, description=actu_folder.description, ) folder = portal.actualites alsoProvides(folder, IFolderViewSelectedContent) folder.setConstrainTypesMode(constraintypes.ENABLED) folder.setLocallyAllowedTypes(["News Item"]) folder.setImmediatelyAddableTypes(["News Item"]) folder.setDefaultPage("actualites") folder.unmarkCreationFlag() folder.setLanguage(language) alsoProvides(folder, IFolderViewSelectedContent) publishContent(wftool, folder) topic = portal.actualites.actualites IFeedSettings(topic).enabled = True topic.setLanguage(language) query = [ { "i": "portal_type", "o": "plone.app.querystring.operation.selection.is", "v": ["News Item"], }, { "i": "review_state", "o": "plone.app.querystring.operation.selection.is", "v": ["published"], }, ] topic.setQuery(query) topic.setSort_on("effective") topic.setSort_reversed(True) topic.setLayout("summary_view") topic.unmarkCreationFlag() publishContent(wftool, topic) # Events topic if events_folder: events_folder.title = _(u"Événements") events_folder.description = _(u"Événements du site") _createObjectByType( "Collection", portal.evenements, id="evenements", title=events_folder.title, description=events_folder.description, ) folder = portal.evenements alsoProvides(folder, IFolderViewSelectedContent) folder.setConstrainTypesMode(constraintypes.ENABLED) folder.setLocallyAllowedTypes(["Event"]) folder.setImmediatelyAddableTypes(["Event"]) folder.setDefaultPage("evenements") folder.unmarkCreationFlag() folder.setLanguage(language) publishContent(wftool, folder) topic = folder.evenements IFeedSettings(topic).enabled = True topic.unmarkCreationFlag() topic.setLanguage(language) query = [ { "i": "portal_type", "o": "plone.app.querystring.operation.selection.is", "v": ["Event"], }, { "i": "start", "o": "plone.app.querystring.operation.date.afterToday", "v": "", }, { "i": "review_state", "o": "plone.app.querystring.operation.selection.is", "v": ["published"], }, ] topic.setQuery(query) topic.setSort_on("start") topic.setLayout("summary_view") publishContent(wftool, topic)
def context_enabled(self): settings = IFeedSettings(self.context, None) if settings and not settings.enabled: raise NotFound else: return True
def upgradeSyndication(context): from zope.component import getUtility, getSiteManager from plone.registry.interfaces import IRegistry from Products.CMFCore.interfaces import ISyndicationTool from Products.CMFPlone.interfaces.syndication import ISyndicatable from Products.CMFPlone.interfaces.syndication import ( ISiteSyndicationSettings, IFeedSettings) portal = getToolByName(context, 'portal_url').getPortalObject() def getDexterityFolderTypes(): try: from plone.dexterity.interfaces import IDexterityFTI from plone.dexterity.utils import resolveDottedName except ImportError: return set([]) portal_types = getToolByName(portal, 'portal_types') types = [ fti for fti in portal_types.listTypeInfo() if IDexterityFTI.providedBy(fti) ] ftypes = set([]) for _type in types: klass = resolveDottedName(_type.klass) if ISyndicatable.implementedBy(klass): ftypes.add(_type.getId()) return ftypes logger.info('Migrating syndication tool') registry = getUtility(IRegistry) synd_settings = registry.forInterface(ISiteSyndicationSettings) # default settings work fine here if all settings are not # available try: old_synd_tool = portal.portal_syndication try: synd_settings.allowed = old_synd_tool.isAllowed except AttributeError: pass try: synd_settings.max_items = old_synd_tool.max_items except AttributeError: pass portal.manage_delObjects(['portal_syndication']) except AttributeError: pass sm = getSiteManager() sm.unregisterUtility(provided=ISyndicationTool) # now, go through all containers and look for syndication_info # objects catalog = getToolByName(portal, 'portal_catalog') # get all folder types from portal_types at_tool = getToolByName(portal, 'archetype_tool') folder_types = set([]) for _type in at_tool.listPortalTypesWithInterfaces([ISyndicatable]): folder_types.add(_type.getId()) folder_types = folder_types | getDexterityFolderTypes() for brain in catalog(portal_type=tuple(folder_types)): try: obj = brain.getObject() except (AttributeError, KeyError): continue if 'syndication_information' in obj.objectIds(): # just having syndication info object means # syndication is enabled info = obj.syndication_information try: settings = IFeedSettings(obj) except TypeError: continue settings.enabled = True try: settings.max_items = info.max_items except AttributeError: pass settings.feed_types = ('RSS', ) obj.manage_delObjects(['syndication_information'])
def upgradeSyndication(context): from zope.component import getUtility, getSiteManager from plone.registry.interfaces import IRegistry from Products.CMFCore.interfaces import ISyndicationTool from Products.CMFPlone.interfaces.syndication import ISyndicatable from Products.CMFPlone.interfaces.syndication import ( ISiteSyndicationSettings, IFeedSettings) portal = getToolByName(context, 'portal_url').getPortalObject() def getDexterityFolderTypes(): try: from plone.dexterity.interfaces import IDexterityFTI from plone.dexterity.utils import resolveDottedName except ImportError: return set([]) portal_types = getToolByName(portal, 'portal_types') types = [fti for fti in portal_types.listTypeInfo() if IDexterityFTI.providedBy(fti)] ftypes = set([]) for _type in types: klass = resolveDottedName(_type.klass) if ISyndicatable.implementedBy(klass): ftypes.add(_type.getId()) return ftypes logger.info('Migrating syndication tool') registry = getUtility(IRegistry) synd_settings = registry.forInterface(ISiteSyndicationSettings) # default settings work fine here if all settings are not # available try: old_synd_tool = portal.portal_syndication try: synd_settings.allowed = old_synd_tool.isAllowed except AttributeError: pass try: synd_settings.max_items = old_synd_tool.max_items except AttributeError: pass portal.manage_delObjects(['portal_syndication']) except AttributeError: pass sm = getSiteManager() sm.unregisterUtility(provided=ISyndicationTool) # now, go through all containers and look for syndication_info # objects catalog = getToolByName(portal, 'portal_catalog') # get all folder types from portal_types at_tool = getToolByName(portal, 'archetype_tool') folder_types = set([]) for _type in at_tool.listPortalTypesWithInterfaces([ISyndicatable]): folder_types.add(_type.getId()) folder_types = folder_types | getDexterityFolderTypes() for brain in catalog(portal_type=tuple(folder_types)): try: obj = brain.getObject() except (AttributeError, KeyError): continue if 'syndication_information' in obj.objectIds(): # just having syndication info object means # syndication is enabled info = obj.syndication_information try: settings = IFeedSettings(obj) except TypeError: continue settings.enabled = True try: settings.max_items = info.max_items except AttributeError: pass settings.feed_types = ('RSS',) obj.manage_delObjects(['syndication_information'])
def disableSyndication(self, obj): if not _checkPermission(ModifyPortalContent, obj): raise Unauthorized settings = IFeedSettings(obj) settings.enabled = False
def test_feeds(self): # Use a browser to log into the portal: admin = testbrowser.Browser() admin.handleErrors = False portal_url = self.portal.absolute_url() admin.open(portal_url) admin.getLink('Log in').click() admin.getControl(name='__ac_name').value = ptc.portal_owner admin.getControl(name='__ac_password').value = ptc.default_password admin.getControl('Log in').click() # Create a folder to act as the blog: admin.getLink(id='folder').click() admin.getControl(name='title').value = 'A Blog' admin.getControl(name='form.button.save').click() # Publish it: admin.getLink(id='workflow-transition-publish').click() # Save this url for easy access later: blog_url = admin.url # In the folder, create four content types, a Document, a News Item, # a File and an Event: admin.getLink(id='document').click() admin.getControl(name='title').value = 'A Document Blog Entry' admin.getControl(name='text').value = 'The main body of the Document' admin.getControl(name='form.button.save').click() admin.getLink(id='workflow-transition-publish').click() admin.open(blog_url) admin.getLink(id='news-item').click() admin.getControl(name='title').value = 'A News Item Blog Entry' admin.getControl(name='text').value = 'The main body of the News Item' testfile = os.path.join(os.path.dirname(__file__), 'testlogo.jpg') thefile = admin.getControl(name='image_file') thefile.filename = 'testlogo.jpg' thefile.value = open(testfile, 'rb') admin.getControl(name='form.button.save').click() admin.getLink(id='workflow-transition-publish').click() admin.open(blog_url) admin.getLink(id='file').click() admin.getControl(name='title').value = 'A File Blog Entry' testfile = os.path.join(os.path.dirname(__file__), 'testaudio.mp3') thefile = admin.getControl(name='file_file') thefile.filename = 'testaudio.mp3' thefile.value = open(testfile, 'rb') admin.getControl(name='form.button.save').click() admin.open(blog_url) admin.getLink(id='event').click() admin.getControl(name='title').value = 'An Event Blog Entry' admin.getControl(name='text').value = 'The main body of the Event' admin.getControl(name='form.button.save').click() admin.getLink(id='workflow-transition-publish').click() # Set up the Plone 4.3 syndication: if PLONE43: admin.open(portal_url + '/@@syndication-settings') form = admin.getForm(id='form') form.getControl(name='form.widgets.default_enabled:list').value = ['selected'] form.getControl(name='form.widgets.show_syndication_button:list').value = ['selected'] form.getControl(name='form.buttons.save').click() # And on the folder: # This can't be done through the test-browser, because the form apparently # *required* javascript. Hey ho. feed_settings = IFeedSettings(self.portal['a-blog']) feed_settings.render_body = True feed_settings.feed_types = ('rss.xml', 'RSS', 'atom.xml', 'itunes.xml') ############################# ## Now, make sure things work ############################# # First, check that the feeds are listed in the header: anon = testbrowser.Browser() anon.handleErrors = False anon.open(blog_url) # Atom and RSS are the only ones that are there both for # Fatsyndication and Plone 4.3, so we test for them. # (itunes exist as well, but is off by default). self.assert_('atom.xml' in anon.contents) self.assert_('rss.xml' in anon.contents) self.assert_('itunes.xml' in anon.contents) # Now check that the correct info is in the feeds. We'll assume that # basesyndication/fatsyndication is not broken, and check only atom.xml. # (because in fact, rss.xml *is* broken in Plone 4.3). anon.open(blog_url+'/atom.xml') # The document: self.assert_('The main body of the Document' in anon.contents) # The news item with image: self.assert_('The main body of the News Item' in anon.contents) self.assert_('/image' in anon.contents) # The file: self.assert_('<link rel="enclosure" length="16486" href="' in anon.contents) if not PLONE43: # But *not* the event, as it has no feed adapter. self.assert_('The main body of the Event' not in anon.contents) else: # But in 4.3 it does self.assert_('The main body of the Event' in anon.contents)
def rss_enabled(self): rss_settings = IFeedSettings(self.context) return rss_settings.enabled