Archive for the ‘plone’ Category

Exit code, colors, etc. when testing Plone

Do you want to have colored output showing problems with your tests? Are you looking to setup an automated system like Buildbot to run your tests? If so then this little tip could help you.

When you run your Plone tests you normally use zope.testing. The version shipped with Zope 2 that
you normally get is outdated. The newer versions have a lot of extra functionality. Fortunately it is pretty easy to get a newer version setup.

Edit your buildout.cfg and add versions section and a reference to it in you buildout section:

[buildout]
versions = versions

[versions]
zope.testing = 3.7.1

The last line tells buildout what version it needs to enforce. Now edit your instance section (the part with recipe = plone.recipe.zope2instance) and add zope.testing to the eggs = option.

Now enjoy your new version.

Advertisements

Stuff the catalog

Adding extra information to the portal catalog can be an easy way to get information from across your site. Plone let’s you easily create extra indexes using a generic setup profile. If you have an existing profile you can add a file catalog.xml with the following contents:

<?xml version=”1.0″?>
<object name=”portal_catalog” meta_type=”Plone Catalog Tool”>
<column value=”FirstLetter”/>
<index name=”FirstLetter” meta_type=”FieldIndex”>
<indexed_attr value=”FirstLetter”/>
</index>
</object>
This will create both a field index named FirstLetter and a corresponding meta data column (this will be available on the result objects when querying the catalog). There are many kind of indexes you can create this way. You can see how to use some of them in Plone’s own catalog.xml file.

Now we need to make sure we that our FirstLetter index will be filled. We can do this by creating a simple Python function. Let’s create a new file for this in our project named catalog.py with this content:

from Products.CMFPlone.CatalogTool import registerIndexableAttribute

def first_letter(obj, portal, vars, **kwargs):
     # Make sure we have a title with something in it
    if obj.Title():
        # Return the first letter
        return obj.Title()[0].lower()

registerIndexableAttribute('FirstLetter', first_letter)

This will register an extra handler for Plone’s indexing system. To make sure it is registered we need to import the catalog module from the __init__.py of the project/product. Just add a line like this to your project (replace exampleproject with your project’s name):

import exampleproject.catalog

This should make the FirstName index available when the project is installed. Now you query your catalog against this with something like:

portal_catalog(FirstLetter='a')

Hiding your dependencies

A few days ago Wichert showed me something interesting. You can hide profiles / products from both the quickinstaller and the Plone site creation screen. This came in handy for a project we were working on.

The project is for a client that delivers a customized version of a product we developed for them. So each of their clients receives a tailored version (think branding, default settings etc.).

Code wise this means we have a base package for all installaties. On top of this we built the branded versions. To minimize installation problems the possibility to hide dependent products came in really handy.

Hiding products can be done by registering two utilities. One for disabling products in the quickinstaller. The other for disabling extension profiles from the Plone site creation.

To register these utilities add something like this your configure.zcml:

<utility factory=".profile.HiddenProducts" name="my.special.project" />
<utility factory=".profile.HiddenProfiles" name="my.special.project" />

Now create a profile.py file in your project and add the following lines:

from zope.interface import implements
from Products.CMFQuickInstallerTool.interfaces import INonInstallable as INonInstallableProducts
from Products.CMFPlone.interfaces import INonInstallable as INonInstallableProfiles

class HiddenProducts(object):
implements(INonInstallableProducts)

def getNonInstallableProducts(self):
return [
u'some.package',
u'another.product',
]

class HiddenProfiles(object):
implements(INonInstallableProfiles)

def getNonInstallableProfiles(self):
return [
u'some.package:default',
u'another.product:default',
]

Backgrounds for all

We at Pareto just improved our website. Aside from things like minor style changes, new Plone version etc. there is also something which may be of general interest to the Plone community. That something is wallpapers. For the recently held Baarn sprint I convinced Pareto and a colleague of mine to create T-Shirts for the attendees. It is this design that has been used as a base for the freely available wallpapers.

So if you want some Plone on your desktop you can now visit the Pareto website. If your favorite resolution is not available drop me a note so we can include it.

Crossing Alaska for KiKa

Crossing Alaska for KiKaCancer has devastating effects on people. Children are not spared from its horrors. Fortunately organisations like KiKa exist which try to make a difference. To raise money for KiKa a team is going to cross Alaska. They maintain their website using our favorite CMS; Plone. It is nice to work at a company which helps to make nice sites like this come into existence. Check out the site: Crossing Alaska for KiKa.

Publishing XML with Plone

Integrating Plone with external systems always seems to cost more effort than it really should. In the past I have integrated Plone with ERP systems using CSV exports, IBM DB2 databases with text dumps, VCARD import’s from a CRM system and also some relational databases. Fortunately the story for relation databases is improving. Of course this only works with databases you can access directly.

Because writing synchronisation scripts is not only very tedious but also very error prone I wanted to fix this once and for all. One of the lessons I learned from previous experiences is not to try to sync everything in one step. Converting the data to an intermediate format you understand and is under your own control gives a lot of advantages.

This post is not going to go on with complaining about all the troubles with external systems. The reason is I made something which should solve it (or solves it for me). You can take a look at the code in the collective. What enables you to do is create a simple piece of content in Plone. In this content you can specify a location on the filesystem you want to publish. When you traverse the piece of content it reads the XML with the same name from the filesystem and wrap it in a proxy. This proxy is then decorated with a view ready for publishing. And the nice thing is it can publish any piece of XML you can think of.

Well that is not completely true, there has to be one little thing in there. The XML must have declare an interface. This interface is an identifier for an Zope 3 interface. It is this interface that is used when looking up views etc.

Another nice thing is that the proxy can also delegate calls it does not understand. This allows it to play nice with the ZCatalog by diverting all queries for Title etc. to a specific adapter.

One word of caution is order before you get to excited, this code is not used in production. It is not finished yet and last but not least there is a problem running all tests simultaniosly. This has to do with a hack I stuck in to make PloneTestCase work with Zope 2.9 and pythonproducts. They should work without failing if you run them one at a time.

Comments on the architecture, system as a whole etc. are greatly appreciated. I hope some more people will find a use for this (or tell me why I am going at it the wrong way). Oh, before I forget it, tips for a better name are also welcome (it is called xmlcontent for now).

PAS human sniffer plugin

After the Seattle Plone Conf I had an idea how to implement a simple Pluggable Auth Service plugin to make authenticated RSS feeds accessible to desktop clients. The main problem with desktop RSS readers is that they need something like basic auth instead of a login form.

My first attempt was writing a challenger plugin which differentiated on user agent headers. This was not the most optimal sollution according to wiggy.

He advised me to create a protocol sniffer. So of I went and changed the plugin. It is now a proper protocol sniffer. This adds a protocol named Human Browser to the set of protocols. Using the challenger chooser you can set this protocol to use cookie auth. The normal browser protocol should then be set to http auth.

The plugin still uses the user agent header to detect if it is dealing with a human controlled browser. You can add browsers to this using a subscriber (look at detectors.py).

Second day of the sprint

The second and final day of the sprint is over now. I implemented portlet reloading for the navigation and recent items portlet. This code is now easy to use from any event handler so refreshing other portlets is easy.
Another thing I did was to add information on what fields where modified by the Ajax call. This allows us to check in the event handlers if we need to update anything. The navigation portlet reloader is an example of how this could work.
At night (after the sprint) I finished the final bits by adding reloading support for the portal tabs and the breadcrumb. This was so easy to do that I made a small screencast as well.

First day of the sprint

The first day of the sprint went pretty well. It was my first sprint so I can make no comperison. A was a bit anxious to get started. It took more time getting all the people in to the auditorium, introducing all the subjects than I liked at the time.

There were a lot of subjects to choose from. I chose for the Azax sprint. It was not as big of a group as the mebrane guys but still nice. We did a bit of introduction in the begin as well.

A lot of people had trouble setting up Zope on their Windows system. Furtonately I was prepared for this and had a custom build ready to go. I supplied all Windows user with a installer.

Then it was time to choose a subject. I chose to work on the event integration. The main idea was to support the follow use-case.

Let’s say you change the title of a document using Ajax. Now the title will be changed in the document view. But usually you also want to update the navigation menu, the navigation portlet etc.

So the thing I did today was to use Zope 3 events to add more Azax commands to the request. In layman’s terms this means that the Ajax handling code just generates and event. This will then activate any number of interested handlers. These handlers can add extra commands like changing the portlets.

At the end of the day I had made a doctest and a working system. Along the way we had discussions on how to implement it and I fixed the API a bit.

I am quite content with the results of the first day. Hopefully I can do some usefull stuff tomorrow as well.

The final day was really interesting. It started with a keynote from Eben Moglen. This got a quite emotional response from most people. After this Alexander Limi highlighted the fifteen most exiting features of Plone 3.

After a short break I went to the talk from Joel Burton about making Plone simpler for end users. He had some really good ideas and ready to go tweaks. A lot of these tweaks should be automatable so maybe I will write a burtonizer product.

Phillip had an interesting talk about viewlets in Zope 2. It seemed really nice but may be a bit difficult for scripters to understand. Although the current macro mess is pretty bad as well.

We had some great snacks during the break. This day they served mediterainian tapas.

One of the days highlights for me was Wichert’s talk about PAS (the Zope 2 version). He really made it clear for me where everything goes and what it does. So when I will need to use it I now know what to do. An example of a usecase I know have an idea about how to implement is RSS feeds that need authentication.

Most RSS readers don’t understand the Plone login form. So if you want to access the feeds from the reader you need to supply the proper credentials via basic authentication. What we want is that normal users go through the login form and RSS readers use basic auth.

To do this you create a challenger plugin. This can be used to differentiate based on the user agent or some detectable propertie in the url.

The lightning talks were the closing talks. It was fun to see these as they are always fun due to the frantic pace. After these the conference ended. As far as I am concerned this was the best IT conference I have ever been to. My thanks go out to all the people involved in making this happen.

Final day of the conference

The final day was really interesting. It started with a keynote from Eben Moglen. This got a quite emotional response from most people. After this Alexander Limi highlighted the fifteen most exiting features of Plone 3.

After a short break I went to the talk from Joel Burton about making Plone simpler for end users. He had some really good ideas and ready to go tweaks. A lot of these tweaks should be automatable so maybe I will write a burtonizer product.

Phillip had an interesting talk about viewlets in Zope 2. It seemed really nice but may be a bit difficult for scripters to understand. Although the current macro mess is pretty bad as well.

We had some great snacks during the break. This day they served mediterainian tapas.

One of the days highlights for me was Wichert’s talk about PAS (the Zope 2 version). He really made it clear for me where everything goes and what it does. So when I will need to use it I now know what to do. An example of a usecase I know have an idea about how to implement is RSS feeds that need authentication.

Most RSS readers don’t understand the Plone login form. So if you want to access the feeds from the reader you need to supply the proper credentials via basic authentication. What we want is that normal users go through the login form and RSS readers use basic auth.

To do this you create a challenger plugin. This can be used to differentiate based on the user agent or some detectable propertie in the url.

The lightning talks were the closing talks. It was fun to see these as they are always fun due to the frantic pace. After these the conference ended. As far as I am concerned this was the best IT conference I have ever been to. My thanks go out to all the people involved in making this happen.