= Creating Resources =

A 'resource' in modu is a Python class that returns some content when a particular URL path is accessed. The most common type of modu resource generates a number of name-value pairs, and uses a template engine to embed those values and generate content for the user. In the MVC development pattern, a resource would be considered a Controller.

This document will step you through the process of creating a simple resource using the Cheetah Template engine.

== Stub File ==
First, copy and paste the following stub file into a python class. You'll want to place it in your project's `resource` package.

{{{
#!python
from modu.web import resource

class DatetimeResource(resource.CheetahTemplateResource):
    def prepare_content(self, req):
        pass
    
    def get_template(self, req):
        return 'date.html.tmpl'
}}}

Although there are several more methods involved in generating content for a resource, for most basic usage you'll only need to deal with these three methods.

'''`prepare_content(self, req) `'''
    This method is where the essential work of content generation will be completed, and is called for each request. Code will call `self.set_slot()` to include variables in the resulting template.

'''`get_template(self, req) `'''
    The `get_template()` method is called after `prepare_content()`, so you can use calculations or variables created during the previous function call to determine which template to return, if you wish.

Note that Resource objects are instantiated for each request, so you can save values as attributes of `self`.

Next, let's create the template. Create this in your project's `template` directory, called `date.html.tmpl`:

{{{
#!text/html
<!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" lang="en">
<head>
	<title>$title</title>
</head>
<body>
	Hello, World. The date is $date.
</body>
</html>
}}}

Finally, we'll modify our resource stub to create the necessary template values:

{{{
#!python
    def prepare_content(self, req):
        now = datetime.datetime.now()
        self.set_slot('date', now)
        self.set_slot('title', "The Date Is...")
}}}

Now we just need to add this resource to our application. Here we'll add it to the stub application we created in [wiki:GettingStarted Getting Started]. We open up the file in `PROJECT/modu/sites/PROJECT_site.py`, which looks something like this:

{{{
#!python
class Site(object):
    classProvides(plugin.IPlugin, app.ISite)

    def initialize(self, application):
        application.base_domain = 'localhost'
        application.db_url = 'MySQLdb://myproject:myproject@localhost/myproject'

        modu_assets_path = os.path.join(os.path.dirname(modu.__file__), 'assets')
        application.activate('/assets', static.FileResource, modu_assets_path)

        application.activate('/admin', resource.AdminResource, default_path='/admin/listing/page')
        application.activate('/fck', fck.FCKEditorResource)
        application.activate('/fck', index.Resource)
}}}

To add our new resource, we'll just add one line in the `initialize()` function:

{{{
#!python
        ...
        ...
        application.activate(index.Resource)

        from PROJECT.resource import dt
        application.activate('/date', dt.DatetimeResource)
}}}

== Resource API ==

Once a resource has been found for the given request, the various methods that make up the content generation process are called in turn.

    '''IResourceDelegate::get_delegate()'''::
        First the resource is examined to see if it is a Resource Delegate. If so, its `get_delegate()` method is called, and the remaining methods in the content generation flow are called on *that* `Resource` instead.

    '''IResource::get_response()'''::
        The top-level `Resource` method is `get_response()`, which is responsible for setting up the response and returning the content.

Technically, a class needs only to implement `get_response()` to function properly as a `Resource`, but is then responsible for taking care of all bookkeeping and content generation.

Most resources are subclasses of `modu.web.resource.Resource`, and so the `get_response()` method is already defined. It calls the following methods:

    '''IResource::get_content_provider()'''::
        Resources are not required to implement `IContent`, but if they do not, they must return an instance of an `IContent` implementor from this method.

    '''IContent::prepare_content()'''::
        Once an `IContent` implementor is found, `prepare_content()` is called to setup whatever instance data is needed to render this content. If `IContent` is also an `ITemplate` implementor, this is where `ITemplate::set_slot()` is called to populate the template dictionary.

    '''IContent::get_content_type()'''::
        For most superclasses, `get_content_type()` is already defined, returning the string 'text/html'. This can be overridden as necessary; for example, returning 'text/html; charset=utf-8' will force UTF-8 encoding in the browser.

    '''IContent::get_content()'''::
        As a final step, return the content that was prepared in `prepare_content()`. The separation of these two functions allows template engines to render the template here, so the particular `Resource` implementation can override `prepare_content()` without clobbering the template compilation.

Finally, there are a few functions that are called for templates. Currently modu only actively supports Cheetah templates, but this is the order used in that case. Ideally alternate template engines would follow a similar flow.

    '''ITemplate::get_template()'''::
        Return some kind of template. In the case of the CheetahTemplate implementation, this can be either a filename (relative to the template dir) or a string containing the template code.

    '''ITemplate::get_template_type()'''::
        Return a description of what the result of `get_template()` is supposed to be. Currently the two options used for Cheetah templates are 'filename' (the default), or 'str' (for inline templates).

    '''ITemplate::get_template_root()'''::
        Only relevant for 'filename' type templates, this function specifies the location of the template directory. The default behavior is to look in 'templates' in the application's `approot`, or to use the `Resource`'s `template_dir` variable, if it exists. This method can be overridden if desired, however.

=== WSGI Passthrough ===

There's one special `Resource` implementation included with modu that may be useful to various applications, and that's the `WSGIPassthroughResource`. If you wish to install a WSGI app under a path on a modu web application, this resource will allow you to manipulate the request environment before sending it to the WSGI app.

Here's an example of embedding the Trac project management app inside a modu Resource:

{{{
#!python
class Resource(resource.WSGIPassthroughResource):
    def __init__(self):
        from trac.web import main
        # provide the WSGI app object as the first argument
        super(Resource, self).__init__(main.dispatch_request)

    def prepare_content(self, req):
        # Depending on the WSGI container we're in, PATH_INFO
        # may or may not have a leading slash
        path_info = req['PATH_INFO']
        if(path_info.startswith('/trac')):
            req['PATH_INFO'] = path_info[5:]
        elif(path_info.startswith('trac')):
            req['PATH_INFO'] = path_info[4:]
    
        req['SCRIPT_NAME'] = '/trac'
    
        # here we trick Trac into using modu authentication
        req['REMOTE_USER'] = 'anonymous'
        if(req.user.get_id() and req.user.is_allowed('access trac')):
            req['REMOTE_USER'] = req.user.username
    
        from trac.web.api import HTTPForbidden
        try:
            super(Resource, self).prepare_content(req)
        except HTTPForbidden, e:
            # you should handle permission denied, etc. errors here.
            pass
}}}
