NAME

OpenInteract::Handler::GenericDispatcher - Define task-dispatching, security-checking and other routines for Handlers to use

SYNOPSIS

use OpenInteract::Handler::GenericDispatcher qw( DEFAULT_SECURITY_KEY );
use SPOPS::Secure qw( :level );

@OpenInteract::Handler::MyHandler::ISA = qw( 
                            OpenInteract::Handler::GenericDispatcher SPOPS::Secure );
%OpenInteract::Handler::MyHandler::default_security = (
    DEFAULT_SECURITY_KEY() => SEC_LEVEL_READ,
    'edit'                 => SEC_LEVEL_WRITE );

DESCRIPTION

The Generic Dispatcher provides the methods to discern what task is supposed to execute, ensure that the current user is allowed to execute it, and returns the results of the task.

It is meant to be subclassed so that your handlers do not have to keep parsing the URL for the action to take. Each action the Generic Dispatcher takes can be overridden with your own.

This module provides the routine 'handler' for you, which does all the routines (security checking and other) for you, then calls the proper method.

There are also a couple of utility methods you can use, although they will probably be punted off to a separate module at some point.

NOTE: This module will likely be scrapped for a more robust dispatching system. Please see NOTES for a discussion.

METHODS

Even though there is only one primary method for this class (handler()), you may override individual aspects of the checking routine:

_get_task

Return a task name by whatever means necessary. Default behavior is to return the next element (lowercased) from:

$R->{path}->{current}

If that element is undefined (or blank), the default behavior returns the the package variable default_method.

Return a string corresponding to a method.

_no_task_found

Called when no task is found from the _get_task method. Default behavior is to email the author of the handler (found in the package variable author) and tell him/her to at least define a default method.

Method should either return or die() with html necessary for displaying an error.

_task_allowed( $task )

Called to ensure the $task found earlier is not forbidden from being run. Tasks beginning with '_' are automatically denied, and we look into the @forbidden_methods package variable for further enlightenment. Return 1 if allowed, 0 if forbidden.

_check_task_security

Called to ensure this $task can be run by the currently logged-in user. Default behavior is to check the security for this user and module against the package hash security, which has tasks as keys and security levels as values.

Note: you can define a default security for your methods and then specify security for only the ones you need using the exported constant 'DEFAULT_SECURITY_KEY'. For instance:

%My::Handler::Action = (
   DEFAULT_SECURITY_KEY() => SEC_LEVEL_READ,
   edit                   => SEC_LEVEL_WRITE,
);

So all methods except 'edit' are protected by SEC_LEVEL_READ.

Returns: the level for this user and this task.

_local_task

This is an empty method in the GenericDispatcher, but you can create a subclass of the dispatcher for your application to do application-wide actions. For instance, if you had a tag in every handler that was to be set in $R->{page} and parsed by the main template to select a particular 'tab' on your web page, you could do so in this method.

Utility

_create_object( \%params )

Create an object from the information passed in via GET/POST and \%params.

Parameters:

_id_field: \@ or $ with field name(s) used to find ID value
_class:    $ with class of object to create

Returns: object created with information, undef if object ID not found, die thrown if object class or ID field not given, or if the retrieval fails.

date_process( 'yyyy-mm-dd' )

WARNING: This method might be removed altogether.

Return a hashref formatted:

{ year  => 'yyyy',
  month => 'mm',
  day   => 'dd' }

date_read( $prefix, [ \%defaults ] )

Read in date information from GET/POST information. The fields are:

day    => ${prefix}_day
month  => ${prefix}_month
year   => ${prefix}_year

If you want a default set for the day, month or year, pass the information in a hashref as the second argument.

NOTES

Discussion about Creating a 'Real' Dispatcher

Think about making available to a handler its configuration information from the action.perl file, so you can set information there and have it available in your environment without having to know how your handler was called.

For instance, in your action.perl you might have:

{
   'news' => { 
       language => 'en',
       class    => 'OpenInteract::Handler::News',
       security => 'no',
       title    => 'Weekly News',
       posted_on_format => "Posted: DATE_FORMAT( posted_on, '%M %e, %Y' )",
   },

   'nouvelles' => {
       language => 'fr',
       title    => 'Les Nouvelles',
       redir    => 'news',
       posted_on_format => "Les Post: DATE_FORMAT( posted_on, '%M %e, %Y' )",
   },

}

A call to the URL '/nouvelles/' would make the information:

{ 
  language => 'fr',
  title    => 'Les Nouvelles',
  security => 'no',
  class    => 'OpenInteract::Handler::News', 
  posted_on_format => "Les Post: DATE_FORMAT( posted_on, '%M %e, %Y' )",
}

available to the handler via the $p variable passed in:

my $info = $p->{handler_info};
# $info->{language} is now 'fr'

Use this as the basis for a new class: 'OpenInteract::ActionDispatcher' which you use to call all actions. The ActionDispatcher can lookup the action (and remember all its properties, even through 'redir' calls like outlined above), can check the executor of an action for whether the task can be executed or not (whether the task exists, whether the task is allowed) and can check the security of the task as well. At each step the ActionDispatcher has the option of running its automated checks (which it might cache by website...) or checking callbacks defined in the content handler.

So each content handler would get two arguments: its own class and a hashref of metadata, which would include:

- task called ('task')

- action info compiled ('action_info', a hashref with basic things
like 'class', 'security', 'title' as well as any custom modifications
by the developer

- the security level for this user and this task ('security_level'
and 'security' to be backward compatible)

We will use 'can' to see whether the callback exists in the handler class so the callback could also be defined in a superclass of the handler. So I could define a hierarchy of content handlers and have things just work. (You can do this now, but it is a little more difficult.)

One sticky thing: every request for an action would have to be rewritten to use the dispatcher, although we could create a wrapper in OpenInteract::Request to try for backward compatibility ('lookup_request' and all).

TO DO

Move utility methods to separate class

BUGS

None known.

COPYRIGHT

Copyright (c) 2001-2002 intes.net, inc.. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

AUTHORS

Chris Winters <chris@cwinters.com>