CGI-Wiki-Kwiki
view release on metacpan or search on metacpan
lib/CGI/Wiki/Kwiki.pm view on Meta::CPAN
Make sure that the webserver will be able to write to the database
file and to the directory it lives in.
=item B<Install the script and its templates>
Put the script somewhere suitable so that your webserver will execute it.
Make a subdirectory of the directory the script is in, called
C<templates>. Copy the templates from the L<CGI::Wiki::Kwiki> tarball
into this directory. The webserver will need to read from here but it
doesn't need to be able to write.
=item B<Set up a place for the searcher to index your wiki into>
Make a subdirectory of the directory the script is in, called
C<search_map>. Make this writeable by the webserver.
=back
You can have all kinds of other fun with it though; see EXAMPLES
below. In particular, a nicer formatter to use is
L<CGI::Wiki::Formatter::UseMod>.
=head1 METHODS
=over 4
=item B<new>
Creates a new CGI::Wiki::Kwiki object. Expects some options, most have
defaults, a few are required. Here's how you'd call the constructor -
all values here (apart from C<formatters>) are defaults; the values
you must provide are marked.
my $wiki = CGI::Wiki::Kwiki->new(
db_type => 'MySQL',
db_user => '',
db_pass => '',
db_name => undef, # required
db_host => '',
formatters => {
documentation => 'CGI::Wiki::Formatter::Pod',
tests => 'My::Own::PlainText::Formatter',
discussion => [
'CGI::Wiki::Formatter::UseMod',
allowed_tags => [ qw( p b i pre ) ],
extended_links => 1,
implicit_links => 0,
],
_DEFAULT => [ # if upgrading from pre-0.4
'CGI::Wiki::Formatter::UseMod;
],
}, # example only, not default
site_name => 'CGI::Wiki::Kwiki site',
admin_email => 'email@invalid',
template_path => './templates',
stylesheet_url => "",
home_node => 'HomePage',
cgi_path => CGI::url(),
search_map => './search_map',
prefs_expire => '+1M', # passed to CGI::Cookie; see its docs
charset => 'iso-8859-1', # characterset for the wiki
);
The C<db_type> parameter refers to a CGI::Wiki::Store::[type] class.
Valid values are 'MySQL', SQLite', etc: see the L<CGI::Wiki> man page
and any other CGI::Wiki::Store classes you have on your
system. C<db_user> and C<db_pass> will be used to access this
database.
C<formatters> should be a reference to a hash listing all the
formatters that you wish to support. Different wiki pages can be
formatted with different formatters; this allows you to do things like
have documentation pages written in POD, test suite pages written in
plain text, and discussion pages written in your favourite Wiki
syntax. If this hash has more than one entry, its keys will be
supplied in a drop-down list on every edit screen, and the selected
one will be used when displaying that page.
(If you I<do> wish to supply more than one entry to the hash, you will
need L<CGI::Wiki::Formatter::Multiple> installed on your system.)
Each value of the C<formatters> hash can be either a simple scalar
giving the class of the required formatter, or an anonymous array
whose first entry is the class name and whose other entries will be
passed through to the formatter instantiation, parsed as a hash. (See
the C<discussion> formatter entry in the example code above if this
sounds confusing.)
B<Note:> Even if your C<formatters> hash has only one entry, you
should make its key be meaningful, since it will be stored in the
node's metadata and will appear in dropdowns if you ever decide to
support another kind of formatter.
B<Backwards Compatibility Note:> If you are upgrading from a version
of L<CGI::Wiki::Kwiki> earlier than 0.4, and you have an existing wiki
running on it, you should supply a C<_DEFAULT> entry in the
C<formatters> hash so it knows what to do with nodes that have no
formatter metadata stored.
This method tries to create the store, formatter and wiki objects, and will
die() if it has a problem. It is the calling script's responsibility to
catch any exceptions and tell the user.
=item B<run>
Runs the wiki object, and outputs to STDOUT the result, including the CGI
header. Takes no options.
$wiki->run();
=back
=head1 EXAMPLES
Just for fun, here is the configuration part of the wiki script Kake
uses at work, full of horrid little hacks. Kake is thoroughly ashamed
of herself but feels this is worth showing around in case anyone
accidentally gets a useful idea from it.
#!/usr/bin/perl -w
lib/CGI/Wiki/Kwiki.pm view on Meta::CPAN
L<CGI::Wiki>
=item *
L<http://london-crafts.org> - a wiki for a local crafts group, running on CGI::Wiki::Kwiki
=back
=head1 AUTHORS
Tom Insam (tom@jerakeen.org)
Kake Pugh (kake@earth.li)
=head1 CREDITS
Thanks to Kake for writing CGI::Wiki, and providing the initial
patches to specify store and formatter types in the config. And for
complaining at me till I released things. Thanks to Ivor Williams for
diff support.
=head1 COPYRIGHT
Copyright (C) 2003-2004 Tom Insam. All Rights Reserved.
This module is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=cut
use strict;
use warnings;
use CGI;
use CGI::Cookie;
use CGI::Wiki;
use CGI::Wiki::Search::DB;
use CGI::Wiki::Plugin::Diff;
use Template;
use Algorithm::Merge qw(merge);
our $VERSION = '0.59';
my $default_options = {
db_type => 'MySQL',
db_user => '',
db_pass => '',
db_name => undef,
db_host => '',
formatters => {
default => [
'CGI::Wiki::Formatter::Default',
allowed_tags => [ qw( p b i pre ) ],
],
},
site_name => 'CGI::Wiki::Kwiki site',
admin_email => 'email@invalid',
template_path => './templates',
stylesheet_url => "",
home_node => 'HomePage',
cgi_path => CGI::url(),
search_map => "./search_map",
prefs_expire => '+1M',
charset => 'iso-8859-1',
};
our $diff_plugin = CGI::Wiki::Plugin::Diff->new;
sub new {
my $class = shift;
my $self = bless {}, $class;
my %args = @_;
for (keys(%args)) {
if (exists($default_options->{$_})) {
$self->{$_} = $args{$_};
} else {
die "Unknown option $_";
}
}
for (keys(%$default_options)) {
$self->{$_} = $default_options->{$_}
unless defined($self->{$_});
die "Option '$_' is required" unless defined($self->{$_});
}
my $store_class = "CGI::Wiki::Store::$self->{db_type}";
eval "require $store_class";
if ( $@ ) {
die "Couldn't 'use' $store_class: $@";
}
$self->{store} = $store_class->new(
dbname => $self->{db_name},
dbuser => $self->{db_user},
dbpass => $self->{db_pass},
dbhost => $self->{db_host},
charset => $self->{charset},
) or die "Couldn't create store of class $store_class";
my %formatter_objects;
while ( my ($label, $formatter) = each %{ $self->{formatters} } ) {
my $formatter_class = ref $formatter ? shift @$formatter : $formatter;
eval "require $formatter_class";
if ( $@ ) {
die "Couldn't 'use' $formatter_class: $@\n";
}
my %formatter_args = ref $formatter ? @$formatter : ( );
$formatter_args{node_prefix} ||= $self->{cgi_path} . "?node=";
$formatter_args{edit_prefix} ||= $self->{cgi_path}."?action=edit;node=";
my $formatter_obj = $formatter_class->new( %formatter_args )
or die "Can't create formatter object of class $formatter_class";
$formatter_objects{$label} = $formatter_obj;
}
if ( scalar keys %formatter_objects > 1 ) {
require CGI::Wiki::Formatter::Multiple;
$self->{formatter} =
CGI::Wiki::Formatter::Multiple->new(%formatter_objects );
} else {
my ($label, $formatter_object) = each %formatter_objects;
lib/CGI/Wiki/Kwiki.pm view on Meta::CPAN
recent_changes => \%recent_changes,
not_editable => 1,
);
$self->process_template(
template => "recent_changes.tt",
vars => \%tt_vars,
);
}
sub preview_node {
my ($self, $node, $content, $checksum, $metadata) = @_;
if ( $self->{wiki}->verify_checksum( $node, $checksum ) ) {
my @formatter_labels = sort keys %{ $self->{formatters} };
my %tt_vars = (
content => CGI::escapeHTML($content),
preview_html => $self->{wiki}->format($content, $metadata),
checksum => CGI::escapeHTML($checksum),
formatter_labels => \@formatter_labels,
map { $_ => CGI::escapeHTML($metadata->{$_}||"") } keys %$metadata,
);
$self->process_template(
template => "edit_form.tt",
node => $node,
vars => \%tt_vars,
);
} else {
my %node_data = $self->{wiki}->retrieve_node($node);
my ( $stored, $checksum ) = @node_data{qw( content checksum )};
my @formatter_labels = sort keys %{ $self->{formatters} };
my %tt_vars = (
checksum => CGI::escapeHTML($checksum),
new_content => CGI::escapeHTML($content),
stored => CGI::escapeHTML($stored),
formatter_labels => \@formatter_labels,
map { $_ => CGI::escapeHTML($metadata->{$_}||"") } keys %$metadata,
);
$self->process_template(
template => "edit_conflict.tt",
node => $node,
vars => \%tt_vars,
);
}
}
sub edit_node {
my ($self, $node, $version) = @_;
my %data = $self->{wiki}->retrieve_node($node);
$version ||= $data{version};
my %criteria = ( name => $node, version => $version );
my %node_data = $self->{wiki}->retrieve_node( %criteria );
my ( $content, $checksum ) = @node_data{qw( content checksum )};
my @formatter_labels = sort keys %{ $self->{formatters} };
my %prefs_data = $self->get_prefs_from_cookie;
my $username = $prefs_data{username};
my %tt_vars = (
content => CGI::escapeHTML($content),
checksum => CGI::escapeHTML($checksum),
version => $version,
formatter_labels => \@formatter_labels,
formatter => CGI::escapeHTML($data{metadata}{formatter}[0]||""),
username => $username,
);
$self->process_template(
template => "edit_form.tt",
node => $node,
vars => \%tt_vars,
);
}
sub process_template {
my ($self, %args) = @_;
my $template = $args{template};
my $node = $args{node};
my $vars = $args{vars} || {};
my $conf = $args{conf} || {};
my %tt_vars = (
%$vars,
site_name => $self->{site_name},
cgi_url => $self->{cgi_path},
contact_email => $self->{admin_email},
description => "",
keywords => "",
home_link => $self->{cgi_path},
home_name => "Home",
stylesheet_url => $self->{stylesheet_url},
dist_version => "$VERSION",
charset => $self->{charset},
);
if ($node) {
$tt_vars{node_name} = CGI::escapeHTML($node);
$tt_vars{node_param} = CGI::escape($node);
}
if ( $self->{return_tt_vars} ) {
return %tt_vars;
}
my %tt_conf = ( %$conf, INCLUDE_PATH => $self->{template_path} );
# Create Template object, print CGI header, process template.
my $tt = Template->new( \%tt_conf );
my $output = CGI::header( -cookie => $args{cookies}, -charset => $self->{charset} );
if ($CGI::Wiki::CAN_USE_ENCODE) {
binmode STDOUT, ":encoding($self->{charset})";
}
die $tt->error
unless ( $tt->process( $template, \%tt_vars, \$output ) );
lib/CGI/Wiki/Kwiki.pm view on Meta::CPAN
my %tt_vars = ( results => \@results,
num_results => scalar @results,
not_editable => 1 );
$self->process_template(
template => "backlink_results.tt",
node => $node,
vars => \%tt_vars,
);
}
sub search {
my ($self, $search) = @_;
my %results = $self->{wiki}->search_nodes($search);
my @results = map { $_ }
( sort { $results{$a} <=> $results{$b} } keys(%results) );
my %tt_vars = ( results => \@results,
num_results => scalar @results,
search => $search,
not_editable => 1 );
$self->process_template(
template => "search_results.tt",
vars => \%tt_vars,
);
}
sub do_userstats {
my ($self, %args) = @_;
my $username = $args{username};
my $num_changes = $args{n} || 5;
die "No username supplied to show_userstats" unless $username;
my @nodes = $self->{wiki}->list_recent_changes(
last_n_changes => $num_changes,
metadata_is => { username => $username }
);
@nodes = map {
{
name => CGI::escapeHTML($_->{name}),
last_modified => CGI::escapeHTML($_->{last_modified}),
comment => CGI::escapeHTML($_->{metadata}{comment}[0]),
url => $self->{cgi_path} . "?node=" . CGI::escape($_->{name}),
}
} @nodes;
my %tt_vars = ( nodes => \@nodes,
username => CGI::escapeHTML($username),
not_editable => 1,
);
$self->process_template(
template => "userstats.tt",
vars => \%tt_vars,
);
}
sub show_preferences_form {
my $self = shift;
# Get defaults for form fields from cookie.
my %prefs = $self->get_prefs_from_cookie;
$self->process_template(
template => "preferences.tt",
vars => {
%prefs,
show_prefs_form => 1,
not_editable => 1,
},
);
}
sub get_prefs_from_cookie {
my $self = shift;
my %cookies = CGI::Cookie->fetch;
my $cookie_name = $self->prefs_cookie_name;
my %data;
if ( $cookies{$cookie_name} ) {
%data = $cookies{$cookie_name}->value; # call ->value in list context
}
return ( username => $data{username} || "",
);
}
sub set_preferences {
my ($self, %args) = @_;
my $cookie = $self->make_prefs_cookie( %args );
$self->process_template(
template => "preferences.tt",
vars => {
not_editable => 1,
},
cookies => $cookie,
);
}
sub make_prefs_cookie {
my ($self, %args) = @_;
my $cookie_name = $self->prefs_cookie_name;
my $cookie = CGI::Cookie->new(
-name => $cookie_name,
-value => {
username => $args{username},
},
-expires => $self->prefs_expire,
);
return $cookie;
}
sub prefs_expire {
my $self = shift;
return $self->{prefs_expire};
}
sub prefs_cookie_name {
my $self = shift;
my $name = $self->{site_name} . "_userprefs";
$name =~ s/\W//g;
}
1;
( run in 2.665 seconds using v1.01-cache-2.11-cpan-d7f47b0818f )