Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/README.txt
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/README.txt (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/README.txt (revision 2841)
@@ -1,2 +1,6 @@
+===============================
+quintagroup.plonegooglesitemaps
+===============================
+
Plone Google Sitemaps product allows Plone websites to get better visibility for Google search engine by providing it with complete listing of URLs to website content.
@@ -15,5 +19,6 @@
Different Sitemap types index their own content and do not depend on other Sitemaps.
-Usage
+USAGE
+=====
To enable Google Sitemaps on your site:
@@ -25,9 +30,42 @@
See more detailed instructions on Plone Google Sitemaps usage at http://projects.quintagroup.com/products/wiki/qPloneGoogleSitemaps
-Screencast
+MIGRATION
+=========
+
+ If you UPGRADE older version of quintagroup.plonegooglesitemaps package to newer:
+ --------------------------------------------------------------------------------
+ 1. In your zope instance configuration or buildout - replace old package version
+ with new one.
+ 2. Run plone instance and reinstall package with Quickinstaller tool
+ ("Add-on Products" in plone control panel).
+
+ If your MIGRATE from Products.qPloneGoogleSitemaps to quintagroup.plonegooglesitemaps:
+ -------------------------------------------------------------------------------------
+ 1. Add to new plone instance/buildout both qPloneGoogleSitemaps product and
+ last version quintagroup.plonegooglesitemaps package.
+ 2. Copy Data.fs from old Plone instance to new one.
+ 3. Start your new zope instance/buildout.
+
+ _Following steps performs in the plone instance_
+ 4. With portal_migration (ZMI) - upgrade plone instance.
+ 5. With Quickinstaller tool ("Add-on Products" in plone control panel)
+ deinstall old "Plone Google Sitemaps" product and install new version.
+ 6. Go to *Import* tab in portal_setup tool (ZMI), choose.
+ Select "Migrate from qPloneGoogleSitemaps to quintagroup.plonegooglesitemaps"
+ profile from selection box and choose same-named import step and push
+ "Import selected steps" button.
+
+ _And last clean-up steps:_
+ 7. Remove qPloneGoogleSitemaps product from your zope instance/buildout
+ configuration.
+
+
+SCREENCAST
+==========
Watch Plone Google Sitemaps Screencasts at http://quintagroup.com/cms/screencasts/qplonegooglesitemaps to see how to use this products on your Plone instance. Learn about how to install and configure Sitemaps on your Plone instance, how to create new Google Sitemaps, and how to let Google know about them.
-Links
+LINKS
+=====
* See "Google Sitemaps": https://www.google.com/webmasters/sitemaps website for more information.
@@ -44,5 +82,6 @@
-Authors
+AUTHORS
+=======
The product was developed by Quintagroup.com team:
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/__init__.py
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/__init__.py (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/__init__.py (revision 2841)
@@ -1,2 +1,3 @@
+import sys
from AccessControl import allow_module
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/browser/configure.zcml
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/browser/configure.zcml (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/browser/configure.zcml (revision 2841)
@@ -13,4 +13,5 @@
allowed_interface=".commonview.ISitemapView"
permission="zope.Public"
+ layer="quintagroup.plonegooglesitemaps.interfaces.IGoogleSitemapsLayer"
/>
@@ -22,4 +23,5 @@
allowed_interface=".commonview.ISitemapView"
permission="zope.Public"
+ layer="quintagroup.plonegooglesitemaps.interfaces.IGoogleSitemapsLayer"
/>
@@ -31,4 +33,5 @@
allowed_interface=".commonview.ISitemapView"
permission="zope.Public"
+ layer="quintagroup.plonegooglesitemaps.interfaces.IGoogleSitemapsLayer"
/>
@@ -39,4 +42,5 @@
allowed_interface=".configletview.IConfigletSettingsView"
permission="cmf.ManagePortal"
+ layer="quintagroup.plonegooglesitemaps.interfaces.IGoogleSitemapsLayer"
/>
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/config.py
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/config.py (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/config.py (revision 2841)
@@ -27,2 +27,8 @@
# DO REBUILDING catalog
# UPDATE_CATALOG = True
+
+SUPPORT_BLAYER = True
+try:
+ from plone import browserlayer
+except ImportError:
+ SUPPORT_BLAYER = False
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/interfaces.py
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/interfaces.py (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/interfaces.py (revision 2841)
@@ -6,4 +6,5 @@
from Products.DCWorkflow.interfaces import IAfterTransitionEvent
+from plone.browserlayer.interfaces import ILocalBrowserLayerType
from quintagroup.plonegooglesitemaps import qPloneGoogleSitemapsMessageFactory as _
@@ -16,2 +17,6 @@
class INewsSitemapProvider(Interface):
"""Marker interface for News sitemap provider."""
+
+
+class IGoogleSitemapsLayer(ILocalBrowserLayerType):
+ """Marker interface that defines browser layer for the package."""
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/profiles.zcml
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/profiles.zcml (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/profiles.zcml (revision 2841)
@@ -2,4 +2,5 @@
xmlns="http://namespaces.zope.org/zope"
xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
i18n_domain="quintagroup.plonegooglesitemaps">
@@ -37,4 +38,13 @@
/>
+
+
+
+
+
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/profiles/migrate_qPGSM/gsm_migration.txt
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/profiles/migrate_qPGSM/gsm_migration.txt (revision 2841)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/profiles/migrate_qPGSM/gsm_migration.txt (revision 2841)
@@ -0,0 +1,1 @@
+#
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/profiles/migrate_qPGSM/import_steps.xml
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/profiles/migrate_qPGSM/import_steps.xml (revision 2841)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/profiles/migrate_qPGSM/import_steps.xml (revision 2841)
@@ -0,0 +1,10 @@
+
+
+
+ Clean-up qPloneGoogleSitemaps product artefacts and
+ recriate sitemaps from quintagroup.plonegooglesitemaps.
+ Run after quintagroup.plonegooglesitemap installation.
+
+
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/setuphandlers.py
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/setuphandlers.py (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/setuphandlers.py (revision 2841)
@@ -1,6 +1,11 @@
+import sys
import logging
from zope.component import getSiteManager
from zope.component import getGlobalSiteManager
+
+from Acquisition import aq_parent
from Products.CMFCore.utils import getToolByName
+
+from config import SUPPORT_BLAYER
from quintagroup.plonegooglesitemaps.content.newsextender import NewsExtender
@@ -39,4 +44,20 @@
logger.log(logging.INFO, "Unregistered \"%s\" configlet." % conf_id)
+def removeBrowserLayer(site):
+ """ Remove browser layer.
+ """
+ if not SUPPORT_BLAYER:
+ return
+
+ from plone.browserlayer.utils import unregister_layer
+ from plone.browserlayer.interfaces import ILocalBrowserLayerType
+
+ name="quintagroup.plonegooglesitemaps"
+ site = getSiteManager(site)
+ registeredLayers = [r.name for r in site.registeredUtilities()
+ if r.provided == ILocalBrowserLayerType]
+ if name in registeredLayers:
+ unregister_layer(name, site_manager=site)
+ logger.log(logging.INFO, "Unregistered \"%s\" browser layer." % name)
def uninstall(context):
@@ -48,2 +69,75 @@
unregisterSchemaExtenderAdapters(site)
removeConfiglet(site)
+ removeBrowserLayer(site)
+
+
+def cleanup(site):
+ """Clean-up qPloneGoogleSitemaps artefacts."""
+ old_product = "qPloneGoogleSitemaps"
+ # Get plone tools
+ pp = getToolByName(site, 'portal_properties')
+ skins = getToolByName(site, 'portal_skins')
+ controlpanel = getToolByName(site, 'portal_controlpanel')
+ # Remove old configlet from controlpanel
+ configlet_ids = [ai['id'] for ai in controlpanel.listActionInfos()]
+ if old_product in configlet_ids:
+ controlpanel.unregisterConfiglet(old_product)
+ logger.info("Unregistered '%s' configlet from "\
+ "portal_controlpanel tool." % old_product)
+ # Remove qPloneGoogleSitemaps skin layer
+ for skinName in skins.getSkinSelections():
+ skin_paths = skins.getSkinPath(skinName).split(',')
+ paths = [l.strip() for l in skin_paths if not l == old_product]
+ if len(paths) < len(skin_paths):
+ logger.info("Removed '%s' from '%s' skin." % (old_product, skinName))
+ skins.addSkinSelection(skinName, ','.join(paths))
+
+def recriateSitemaps(smaps):
+ msg = "Recriation Sitemaps: "
+ if smaps:
+ logger.info(msg + "Process %s sitemaps." % (
+ [sm.getPath() for sm in smaps]))
+ fields = ['id', 'sitemapType', 'portalTypes', 'states',
+ 'blackout_list','reg_exp', 'urls', 'pingTransitions']
+ for smb in smaps:
+ # get sitemap properties
+ sm_path = smb.getPath()
+ sm = smb.getObject()
+ container = aq_parent(sm)
+ data = {}
+ for fn in fields:
+ data[fn] = sm.getField(fn).getAccessor(sm)()
+ # Replace old GoogleSitemap by new one with
+ # previous properties
+ container.manage_delObjects(data['id'])
+ container.invokeFactory("Sitemap", id=data['id'])
+ new_sm = getattr(container, data['id'])
+ new_sm.update(**data)
+ new_sm.at_post_create_script()
+ logger.info("Successfully replaced '%s' Sitemap" % sm_path)
+
+def getOldGSitemaps(site):
+ catalog = getToolByName(site, 'portal_catalog')
+ smaps = catalog(portal_type="Sitemap")
+ old_smb = [smb for smb in smaps \
+ if 'qPloneGoogleSitemaps' in str(smb.getObject().__class__)]
+ return old_smb
+
+def migrate_qPGSM(context):
+ """ Clean-up qPloneGoogleSitemaps product artefacts and
+ recriate sitemaps from quintagroup.plonegooglesitemaps
+ package version 1.0.
+ """
+ if context.readDataFile('gsm_migration.txt') is None:
+ return
+
+ site = context.getSite()
+ cleanup(site)
+ old_gsmaps = getOldGSitemaps(site)
+ if old_gsmaps:
+ recriateSitemaps(old_gsmaps)
+ logger.info("Successfully migrated old GoogleSitemaps.")
+ else:
+ logger.info("No old GoogleSitemaps found.")
+
+
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/base.py
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/base.py (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/base.py (revision 2841)
@@ -11,4 +11,5 @@
from zope.interface import Interface
from zope.component import testing
+from zope.interface import alsoProvides
from Testing import ZopeTestCase as ztc
@@ -27,5 +28,7 @@
from quintagroup.plonegooglesitemaps.config import PROJECTNAME
from quintagroup.plonegooglesitemaps.config import ping_googlesitemap
+from quintagroup.plonegooglesitemaps.config import SUPPORT_BLAYER
from quintagroup.plonegooglesitemaps.browser import mobilesitemapview
+from quintagroup.plonegooglesitemaps.interfaces import IGoogleSitemapsLayer
quintagroup.plonegooglesitemaps.config.testing = 1
@@ -70,4 +73,5 @@
self.workflow = self.portal.portal_workflow
self.orig_mobile_ifaces = None
+ alsoProvides(self.portal.REQUEST, IGoogleSitemapsLayer)
def patchMobile(self):
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/testInstallation.py
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/testInstallation.py (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/testInstallation.py (revision 2841)
@@ -103,4 +103,12 @@
self.assertEqual(brain.gsm_stock, gsm_stock)
+ def test_browser_layer(self):
+ if not SUPPORT_BLAYER:
+ return
+
+ from plone.browserlayer import utils
+ self.assert_(IGoogleSitemapsLayer in utils.registered_layers(),
+ "Not registered 'IGoogleSitemapsLayer' browser layer")
+
class TestGoogleSitemapsUninstallation(TestCase):
@@ -125,4 +133,12 @@
'Configlet found after uninstallation')
+ def test_browserlayer_uninstall(self):
+ if not SUPPORT_BLAYER:
+ return
+
+ from plone.browserlayer import utils
+ self.assertEqual(IGoogleSitemapsLayer in utils.registered_layers(), False,
+ "Still registered 'IGoogleSitemapsLayer' browser layer")
+
def test_suite():
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/testNewsSitemaps.py
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/testNewsSitemaps.py (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/testNewsSitemaps.py (revision 2841)
@@ -259,5 +259,7 @@
sitemapType="news")
context = self.portal['news-sitemaps']
- self.nsmv = queryMultiAdapter((context, TestRequest()), name="news-sitemap.xml")
+ request = TestRequest()
+ alsoProvides(request, IGoogleSitemapsLayer)
+ self.nsmv = queryMultiAdapter((context, request), name="news-sitemap.xml")
self.brain = self.portal.portal_catalog(portal_type="Document")[0]
Index: /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/testUpgrade.py
===================================================================
--- /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/testUpgrade.py (revision 2840)
+++ /quintagroup.plonegooglesitemaps/trunk/quintagroup/plonegooglesitemaps/tests/testUpgrade.py (revision 2841)
@@ -3,6 +3,8 @@
#
+import logging
from base import *
from zope.component import getSiteManager
+from StringIO import StringIO
from Products.CMFPlone.utils import _createObjectByType
@@ -11,4 +13,5 @@
from quintagroup.plonegooglesitemaps import config
from quintagroup.plonegooglesitemaps import upgrades as gsm_upgrades
+from quintagroup.plonegooglesitemaps import setuphandlers as sh
from quintagroup.canonicalpath.interfaces import ICanonicalPath
from quintagroup.canonicalpath.interfaces import ICanonicalLink
@@ -104,4 +107,79 @@
self.setup.setLastVersionForProfile(self.profile, orig_ver)
+try:
+ from Products.qPloneGoogleSitemaps.content.sitemap import Sitemap as OldSitemap
+except ImportError:
+ PRESENT_OLD_PRODUCT = False
+else:
+ PRESENT_OLD_PRODUCT = True
+
+class TestMigrationFromProduct(TestCase):
+
+ def afterSetUp(self):
+ super(TestMigrationFromProduct, self).afterSetUp()
+ self.patch_logger()
+ self.gs = self.portal.portal_setup
+ self.profile = u'profile-quintagroup.plonegooglesitemaps:migrate_qPGSM'
+ self.step = "migrate_qPGSM"
+
+ def patch_logger(self):
+ logger = logging.Logger("test:GSM", logging.NOTSET)
+ self.log = StringIO()
+ self.thndlr = logging.StreamHandler(self.log)
+ self.thndlr.setLevel(logging.DEBUG)
+ self.thndlr.setFormatter(logging.Formatter("%(message)s"))
+ logger.addHandler(self.thndlr)
+
+ self.orig_logger = sh.logger
+ sh.logger = logger
+
+ def beforeTearDown(self):
+ sh.logger = self.orig_logger
+
+ def chkLog(self, chkstr):
+ self.thndlr.flush()
+ self.log.seek(0)
+ logs = self.log.getvalue().split('\n')
+ return chkstr in logs
+
+ def testRemoveOldConfiglet(self):
+ chk_str = "Unregistered 'qPloneGoogleSitemaps' "\
+ "configlet from portal_controlpanel tool."
+ # 1. No qPloneGoogleSitemaps configlet
+ self.gs.runImportStepFromProfile(self.profile, self.step)
+ self.assert_(not self.chkLog(chk_str), self.log.getvalue())
+ # 2. qPloneGoogleSitemaps configlet in portal
+ self.portal.portal_controlpanel.registerConfiglet(
+ id="qPloneGoogleSitemaps", name="qPloneGoogleSitemaps",
+ action="string:")
+ self.gs.runImportStepFromProfile(self.profile, self.step)
+ self.assert_(self.chkLog(chk_str), self.log.getvalue())
+
+ def testRemoveOldSkinLayer(self):
+ chk_str = "Removed 'qPloneGoogleSitemaps' from 'Plone Default' skin."
+ # 1. No qPloneGoogleSitemaps layer in portal_skins
+ self.gs.runImportStepFromProfile(self.profile, self.step)
+ self.assert_(not self.chkLog(chk_str), self.log.getvalue())
+ # 2. qPloneGoogleSitemaps layer in portal_skins
+ skins = self.portal.portal_skins
+ skinpath = 'qPloneGoogleSitemaps,' + skins.getSkinPath("Plone Default")
+ skins._getSelections()["Plone Default"] = skinpath
+ self.gs.runImportStepFromProfile(self.profile, self.step)
+ self.assert_(self.chkLog(chk_str), self.log.getvalue())
+
+ def testRecriateOldSitemaps(self):
+ chk_str = "Successfully replaced '/%s/sitemap.xml' Sitemap" \
+ % self.portal.id
+ # 1. No old sitemap present in portal
+ self.gs.runImportStepFromProfile(self.profile, self.step)
+ self.assert_(not self.chkLog(chk_str), self.log.getvalue())
+ # 2. Add old sitemap object in to portal
+ self.portal.invokeFactory("Sitemap", 'sitemap.xml')
+ self.assert_('sitemap.xml' in self.portal.objectIds(), self.portal.objectIds())
+ sm = self.portal['sitemap.xml']
+ sm.__class__ = OldSitemap
+ self.gs.runImportStepFromProfile(self.profile, self.step)
+ self.assert_(self.chkLog(chk_str), self.log.getvalue())
+
def test_suite():
@@ -109,4 +187,7 @@
suite = TestSuite()
suite.addTest(makeSuite(TestUpgrade))
+ if PRESENT_OLD_PRODUCT:
+ suite.addTest(makeSuite(TestMigrationFromProduct))
+
return suite