Site Root Plugins

Prerequisites

In order to understand how resource lookup works in Mantissa, you will already need to understand:

  • Resource lookup in Nevow
  • Rendering content in Nevow
  • Axiom powerups
  • Zope Interface, adaptation using interfaces, and the Twisted registerAdapter function.
  • Mantissa “site” and “user” stores

Introduction

In order to present information to the user via the web, Mantissa applications define models , which are Item s in an Axiom store, and web views , which are Nevow Element s.

There should be a link here to the high-level API documentation when we write some of that. See ticket #2707 for work on the new high-level API.

This document will explore how Mantissa uses an URL to find a model and hook it up to a view, and how you can write plugins to customize that process. This type of plugin can be helpful to applications which want to present custom URL hierarchies which are outside of the usual locations of /private , /users , and /static .

A Simple Example

Let’s say that you are replacing an old, PHP-based website with a new Mantissa one. Lots of people link to your old URLs, so you want them to continue to work. Two of your old URLs look like this:

  • http://example.com/about.php - this URL used to be a mostly static description of your site. The only dynamic component was the site navigation.
  • http://example.com/admin.php - this URL used to be an administrative configuration panel, only accessible to the administrator user. And of course, it was only accessible to them when they’re logged in!

In order to serve new versions of these pages at the same URLs, we’ll need to implement the ISiteRootPlugin interface from Mantissa, as well as install our implementation as a powerup on both site and user stores.

Resources for Everyone

Everyone should be able to view /about.php . In order to display something that looks nice, we need an implementation of ISiteRootPlugin that constructs a INavigableFragment and wraps it in a shell page.

from zope.interface import implements

from axiom.item import Item
from axiom.attributes import text

from nevow.page import Element, renderer
from nevow.loaders import stan
from nevow.tags import div, directive

from xmantissa.ixmantissa import ISiteRootPlugin, INavigableFragment

class AboutPlugin(Item):
    info = text(default=u'This is a great site!')
    powerupInterfaces = (ISiteRootPlugin,)
    implements(*powerupInterfaces)

    def produceResource(self, request, segments, viewer):
        if segments == tuple(['about.php']):
            return viewer.wrapModel(AboutText(self.info)), ()

class AboutText(Element):
    implements(INavigableFragment)
    docFactory = stan(div(render=directive("about")))
    def __init__(self, text):
        self.text = text

    @renderer
    def about(self, request, tag):
        return tag[self.text]

In this example, we define an AboutText element which renders a simple string, and an AboutPlugin that can plug in to a Mantissa site. It implements the produceResource method of ISiteRootPlugin , which must return a tuple of an IResource provider and tuple of child segments, similar to Nevow’s IResource.locateChild method.

The AboutText element is a fragment, not a resource. We want to wrap it in a shell page appropriate to the viewing user, with their navigation, theme, and so on. That’s what the viewer argument is for; it is an IWebViewer that you can use, among other things, to wrap something adaptable to INavigableFragment in a shell page. In this case our ‘model’ is actually a view that is already an INavigableFragment , but you can wrap anything with an appropriate adapter using this method.

This text is something that we want to be visible to everyone, so we want to add it to a Mantissa site store. Let’s create one:

$ axiomatic mantissa
Use database 'mantissa.axiom'? (Y/n) y
Enter Divmod™ Mantissa™ password for 'admin@localhost':
Confirm Divmod™ Mantissa™ password for 'admin@localhost':

Normally, to add something to a store like this, you’d want to create an offering and allow an administrator to install it. For the simplicity of this example, though, we’ll just install the plugin directly from a command prompt:

$ axiomatic -d mantissa.axiom browse
[axiom, version 0.5.28+r16643].  Autocommit is off.
>>> import aboutpage
>>> p = aboutpage.AboutPlugin(store=db)
>>> db.powerUp(p)
>>> ^D

Now that we’ve installed it, let’s get the server started.

$ axiomatic start -n
Use database 'mantissa.axiom'? (Y/n) y
2008-09-05 17:18:08-0400 [-] Log opened.
2008-09-05 17:18:08-0400 [-] twistd 8.1.0+r24685 (/usr/bin/python 2.5.1) starting up.
...

As usual, on http://localhost:8080/ you’ll see a Mantissa server. But now, if you hit http://localhost:8080/about.php, you should see the message text from your AboutText object.

Customized Per-User Plugins

Now we can do something similar for the administrator. What used to be under admin.php is now under /private . We can create a site root plugin that will redirect the administrator to the new page, then install it only on the administrative user’s store.

from zope.interface import implements

from axiom.item import Item
from axiom.attributes import bytes

from nevow.url import URL

from xmantissa.ixmantissa import ISiteRootPlugin

class RedirectPlugin(Item):
    redirectFrom = bytes(default='admin.php')
    redirectTo = bytes(default='private')
    powerupInterfaces = (ISiteRootPlugin,)
    implements(*powerupInterfaces)

    def produceResource(self, request, segments, viewer):
        if segments == tuple([self.redirectFrom]):
            return (URL.fromRequest(request).child(self.redirectTo), ())

In order to install this powerup for the administrator, we have to find their database, import the object, and install it. Normally, we would install a powerup via a product or signup mechanism, but for simplicity we’ll install it directly. First hit control-C to stop the server, then:

$ cd mantissa.axiom/files/account/localhost/
$ ls
admin.axiom
$ axiomatic -d admin.axiom browse
[axiom, version 0.5.28+r16643].  Autocommit is off.
>>> import adminpage
>>> p = adminpage.RedirectPlugin(store=db)
>>> db.powerUp(p)
>>> ^D
$ cd ../../../../

Now, if you start the server up again (the same “axiomatic start” as above), you can see in your browser that http://localhost:8080/admin.php is an error: there’s no page there. Click the ‘log in’ link on the front page, however, and you will see that “admin.php” takes you straight to /private.

Congratulations!

You now know how to customize a Mantissa server to respond to arbitrary URLs!

Table Of Contents

Previous topic

Manual

Next topic

Using Mantissa Interstore Messaging

This Page