Integrate external content in Plone

by Alan Runyan last modified Dec 30, 2008 03:01 PM

Describes how I managed to integrate some external content into my plone site using the plone look.

Background

I have some content sitting on another server that I wanted to integrate into the rest of my plone site. This describes how to do it (in probably completely the wrong way, but it works for me!)...

WARNING this method fiddles with traversal and is slightly magic. It works for me on zope 2.5.1 and plone 1.0beta2 and Zope 2.7.0 and plone 2.0.4. Your milage may vary... In particular, relative links inside your external document may not work correctly. As always, try it on a test Plone instance before putting it on a production site!

What to do

Put all of these files in your custom skin folder

  • getBody.py - an external method, mounted as getBody:
      import urllib
      import pre
      def getBody(self, REQUEST, url):
         page = urllib.urlopen(url)
         data = page.read()
         contents = page.info().getheader('Content-Type')
         page.close()
         REQUEST.RESPONSE.setHeader('Content-Type', contents)
    
         #check that it is an html document
         if pre.search('<(h|H)(t|T)(m|M)(l|L)',data):
             #find start of body conents
             #assumes <body *>tag is on one line (?)
             start = pre.search('<(b|B)(o|O)(d|D)(y|Y)[^>]*>',data).end()
             end = pre.search('</(b|B)(o|O)(d|D)(y|Y)',data).start()
             return {'data': data[start:end], 'Content-Type': contents}
         else:
             return {'data': data, 'Content-Type': contents}
    

This gets the external page, and if that page is an html document, strips it down to the body.

  • external - a python script:
      import string
      request = context.REQUEST
      extpath = request['ExternalPath']
      exturl = context.link + extpath
      obj = context.getBody(context, request, exturl)
      if obj['Content-Type'] == 'text/html':
          return context.external_view(contents=(obj['data']), extpath=extpath)
      else:
          return obj['data']
    

This script marshalls whether to put the external page through a page template or not (so images come through in one piece)

  • external_view - a page template:
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"
            lang="en-US"
            metal:use-macro="here/main_template/macros/master">
    
      <head metal:use-macro="here/header/macros/html_header">
        <metal:block metal:fill-slot="base">
              <base href="" tal:attributes="href string:${here/absolute_url}/${options/extpath}" />
        </metal:block>
      </head>
    
      <body>
          <div metal:fill-slot="main">
              <div tal:replace="structure options/contents">
                    replaced site contents
              </div>
          </div>
      </body>
      </html>
    

This is the page template that defines the look of the external conten. Note the fiddling with teh base fill-slot, this ensures that relative links in the external content work properly

  • Next create a new plone folder to act as the root of the external content

Give the folder a string property named link, containing the url for the external site, ie http://somwhere/somefolder/

  • create a python script in the folder called 'access_rule':
      #use /_SUPPRESS_ACCESSRULE/manage to access this
      from string import split,join
      request = container.REQUEST
    
      #The stack of URL path items after here
      stack = request['TraversalRequestNameStack']
    
      #make a copy of the remaining path to be used later
      extpath = stack[:]
      extpath.reverse()
      request.set('ExternalPath', join(extpath, '/'))
    
      #consume the rest of the stack so that external path items are ignored in traversal
       while stack:
          stack.pop()
    
      #add the path of objects in the title to the stack
      add_path = filter(None, split(script.title, '/'))
      add_path.reverse()
      stack.extend(add_path)
    

Set the script title to the path that should be appended during traversal, here /external

This bit can be dangerous and stop your Zope Management Interface from working

use http://url/to/folder/_SUPPRESS_ACCESSRULE/manage to remove it if you're having problems

finally set the access rule for the folder to access_rule (add Set Access Rule in the zope management interface)

Hopefully everything should now be working... have a look at http://umiststudents.com/about/minutes/meetings/ for a demo. (Plone 1)

References

Laurence Rowe ( l at lrowe dot co dot uk )