wiki-archive/twiki/lib/TWiki/Plugin.pm

297 lines
9.2 KiB
Perl

# Module of TWiki Enterprise Collaboration Platform, http://TWiki.org/
#
# Copyright (C) 2000-2001 Andrea Sterbini, a.sterbini@flashnet.it
# Copyright (C) 2001-2007 Peter Thoeny, peter@thoeny.org
# and TWiki Contributors. All Rights Reserved. TWiki Contributors
# are listed in the AUTHORS file in the root of this distribution.
# NOTE: Please extend that file, not this notice.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. For
# more details read LICENSE in the root of this distribution.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# As per the GPL, removal of this notice is prohibited.
# PRIVATE CLASS TWiki::Plugin
#
# Reference information for a single plugin.
package TWiki::Plugin;
use strict;
use TWiki;
use TWiki::Sandbox;
use Assert;
use vars qw( @registrableHandlers %deprecated );
@registrableHandlers =
( # VERSION:
'afterAttachmentSaveHandler', # 1.022
'afterCommonTagsHandler', # 1.024
'afterEditHandler', # 1.010
'afterRenameHandler', # 1.110
'afterSaveHandler', # 1.020
'beforeAttachmentSaveHandler', # 1.022
'beforeCommonTagsHandler', # 1.024
'beforeEditHandler', # 1.010
'beforeSaveHandler', # 1.010
'commonTagsHandler', # 1.000
'earlyInitPlugin', # 1.020
'endRenderingHandler', # 1.000 DEPRECATED
'initPlugin', # 1.000
'initializeUserHandler', # 1.010
'insidePREHandler', # 1.000 DEPRECATED
'modifyHeaderHandler', # 1.026
'mergeHandler', # 1.026
'outsidePREHandler', # 1.000 DEPRECATED
'postRenderingHandler', # 1.026
'preRenderingHandler', # 1.026
'redirectCgiQueryHandler', # 1.010
'registrationHandler', # 1.010
'renderFormFieldForEditHandler',# ?
'renderWikiWordHandler', # 1.023
'startRenderingHandler', # 1.000 DEPRECATED
'writeHeaderHandler', # 1.010 DEPRECATED
);
# deprecated handlers
%deprecated =
(
startRenderingHandler => 1,
outsidePREHandler => 1,
insidePREHandler => 1,
endRenderingHandler => 1,
writeHeaderHandler => 1,
);
=pod
---++ ClassMethod new( $session, $name, $module )
* =$session= - TWiki object
* =$name= - name of the plugin e.g. MyPlugin
* =$module= - (options) name of the plugin class. Default is TWiki::Plugins::$name
=cut
sub new {
my ( $class, $session, $name, $module ) = @_;
ASSERT($session->isa( 'TWiki')) if DEBUG;
my $this = bless( {}, $class );
$name = TWiki::Sandbox::untaintUnchecked( $name );
$this->{name} = $name || '';
$this->{session} = $session;
$this->{module} = $module || 'TWiki::Plugins::'.$name;
return $this;
}
# Load and verify a plugin, invoking any early registration
# handlers. Return the user resulting from the user handler call.
sub load {
my ( $this ) = @_;
ASSERT($this->isa( 'TWiki::Plugin')) if DEBUG;
# look for the plugin installation web (needed for attached files)
# in the order:
# 1 fully specified web.plugin
# 2 TWiki.plugin
# 3 Plugins.plugin
# 4 thisweb.plugin
my $p = $this->{module};
$this->{installWeb} = $TWiki::cfg{SystemWebName};
#use Benchmark qw(:all :hireswallclock);
#my $begin = new Benchmark;
eval "use $p;";
if ($@) {
push( @{$this->{errors}}, $p.
' could not be loaded. Errors were: '."\n$@\n".'----' );
$this->{disabled} = 1;
return undef;
}
my $noTopic = eval '$'.$p.'::NO_PREFS_IN_TOPIC';
$this->{no_topic} = $noTopic;
unless ($noTopic) {
my $store = $this->{session}->{store};
if ( $store->topicExists(
$TWiki::cfg{SystemWebName}, $this->{name} ) ) {
# found plugin in TWiki web
} elsif ( $store->topicExists( 'Plugins', $this->{name} ) ) {
# found plugin in Plugins web (compatibility, deprecated)
$this->{installWeb} = 'Plugins';
} elsif ( $store->topicExists( $this->{session}->{webName},
$this->{name} ) ) {
# found plugin in current web
$this->{installWeb} = $this->{session}->{webName};
} else {
# not found
push( @{$this->{errors}}, 'Plugins: could not fully register '.
$this->{name}.', no plugin topic' );
$noTopic = 1;
}
}
# Get the description from the code, if present. if it's not there, it'll
# be loaded as a preference from the plugin topic later
$this->{description} = eval '$'.$p.'::SHORTDESCRIPTION';
# Set the session for this call stack
local $TWiki::Plugins::SESSION = $this->{session};
my $sub = $p . '::earlyInitPlugin';
if( defined( &$sub ) ) {
no strict 'refs';
my $error = &$sub();
if( $error ) {
push( @{$this->{errors}}, $sub.' failed: '.$error );
$this->{disabled} = 1;
return undef;
}
use strict 'refs';
}
my $user;
$sub = $p. '::initializeUserHandler';
if( defined( &$sub ) ) {
no strict 'refs';
$user = &$sub( $this->{session}->{remoteUser},
$this->{session}->{cgiQuery}->url(),
$this->{session}->{pathInfo} );
use strict 'refs';
}
#print STDERR "Compile $p: ".timestr(timediff(new Benchmark, $begin))."\n";
return $user;
}
# register plugin settings
sub registerSettings {
my ( $this, $plugins ) = @_;
ASSERT($this->isa( 'TWiki::Plugin')) if DEBUG;
return if $this->{disabled};
my $p = $this->{module};
my $sub = $p . "::initPlugin";
if( ! defined( &$sub ) ) {
push( @{$this->{errors}}, $sub.' is not defined');
$this->{disabled} = 1;
return;
}
my $prefs = $this->{session}->{prefs};
if( !$this->{no_topic} ) {
$prefs->pushPreferences( $this->{installWeb}, $this->{name}, 'PLUGIN',
uc( $this->{name} ) . '_');
}
}
# invoke plugin initialisation and register handlers.
sub registerHandlers {
my ( $this, $plugins ) = @_;
ASSERT($this->isa( 'TWiki::Plugin')) if DEBUG;
return if $this->{disabled};
my $p = $this->{module};
my $sub = $p . "::initPlugin";
no strict 'refs';
my $status = &$sub( $TWiki::Plugins::SESSION->{topicName},
$TWiki::Plugins::SESSION->{webName},
$TWiki::Plugins::SESSION->{user}->login(),
$this->{installWeb} );
use strict 'refs';
unless( $status ) {
push( @{$this->{errors}}, $sub.' did not return true ('.$status.')' );
$this->{disabled} = 1;
return;
}
my $compat = eval '\%'.$p.'::TWikiCompatibility';
foreach my $h ( @registrableHandlers ) {
my $sub = $p.'::'.$h;
if( defined( &$sub )) {
if( $deprecated{$h} && $compat && $compat->{$h} &&
$compat->{$h} <= $TWiki::Plugins::VERSION ) {
# Compatibility handler not required in this version
next;
}
$plugins->addListener( $h, $this );
}
}
$this->{session}->enterContext( $this->{name}.'Enabled' );
}
# Invoke a handler
sub invoke {
my $this = shift; # remove from parameter vector
my $handlerName = shift;
my $handler = $this->{module}.'::'.$handlerName;
no strict 'refs';
return &$handler( @_ );;
use strict 'refs';
}
# Get the VERSION number of the specified plugin.
# SMELL: may die if the plugin doesn't compile
sub getVersion {
my $this = shift;
ASSERT($this->isa( 'TWiki::Plugin')) if DEBUG;
no strict 'refs';
return ${$this->{module}.'::VERSION'} || '';
use strict 'refs';
}
# Get the RELEASE of the specified plugin.
# SMELL: may die if the plugin doesn't compile
sub getRelease {
my $this = shift;
ASSERT($this->isa( 'TWiki::Plugin')) if DEBUG;
no strict 'refs';
return ${$this->{module}.'::RELEASE'} || '';
use strict 'refs';
}
# Get the description string for the given plugin
sub getDescription {
my $this = shift;
ASSERT($this->isa( 'TWiki::Plugin')) if DEBUG;
unless( defined $this->{description} ) {
my $pref = uc( $this->{name} ) . '_SHORTDESCRIPTION';
my $prefs = $this->{session}->{prefs};
$this->{description} = $prefs->getPreferencesValue( $pref ) || '';
}
if( $this->{disabled} ) {
return ' !'.$this->{name}.': (disabled)';
}
my $release = $this->getRelease();
my $version = $this->getVersion();
$version =~ s/\$Rev: (\d+) \$/$1/g;
$version = $release.', '.$version if $release;
my $result = ' '.$this->{installWeb}.'.'.$this->{name}.' ';
$result .= CGI::span( { class=> 'twikiGrayText twikiSmall'}, '('.$version.')' );
$result .= ': '.$this->{description};
return $result;
}
1;