source: trunk/lib/OpenGuides.pm @ 833

Last change on this file since 833 was 833, checked in by nick, 15 years ago

Finish moderation support

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.3 KB
Line 
1package OpenGuides;
2use strict;
3
4use Carp "croak";
5use CGI;
6use Wiki::Toolkit::Plugin::Diff;
7use Wiki::Toolkit::Plugin::Locator::Grid;
8use OpenGuides::CGI;
9use OpenGuides::Feed;
10use OpenGuides::Template;
11use OpenGuides::Utils;
12use Time::Piece;
13use URI::Escape;
14
15use vars qw( $VERSION );
16
17$VERSION = '0.56';
18
19=head1 NAME
20
21OpenGuides - A complete web application for managing a collaboratively-written guide to a city or town.
22
23=head1 DESCRIPTION
24
25The OpenGuides software provides the framework for a collaboratively-written
26city guide.  It is similar to a wiki but provides somewhat more structured
27data storage allowing you to annotate wiki pages with information such as
28category, location, and much more.  It provides searching facilities
29including "find me everything within a certain distance of this place".
30Every page includes a link to a machine-readable (RDF) version of the page.
31
32=head1 METHODS
33
34=over
35
36=item B<new>
37
38  my $config = OpenGuides::Config->new( file => "wiki.conf" );
39  my $guide = OpenGuides->new( config => $config );
40
41=cut
42
43sub new {
44    my ($class, %args) = @_;
45    my $self = {};
46    bless $self, $class;
47    my $wiki = OpenGuides::Utils->make_wiki_object( config => $args{config} );
48    $self->{wiki} = $wiki;
49    $self->{config} = $args{config};
50    my $geo_handler = $self->config->geo_handler;
51    my $locator;
52    if ( $geo_handler == 1 ) {
53        $locator = Wiki::Toolkit::Plugin::Locator::Grid->new(
54                                             x => "os_x",    y => "os_y" );
55    } elsif ( $geo_handler == 2 ) {
56        $locator = Wiki::Toolkit::Plugin::Locator::Grid->new(
57                                             x => "osie_x",  y => "osie_y" );
58    } else {
59        $locator = Wiki::Toolkit::Plugin::Locator::Grid->new(
60                                             x => "easting", y => "northing" );
61    }
62    $wiki->register_plugin( plugin => $locator );
63    $self->{locator} = $locator;
64    my $differ = Wiki::Toolkit::Plugin::Diff->new;
65    $wiki->register_plugin( plugin => $differ );
66    $self->{differ} = $differ;
67    return $self;
68}
69
70=item B<wiki>
71
72An accessor, returns the underlying L<Wiki::Toolkit> object.
73
74=cut
75
76sub wiki {
77    my $self = shift;
78    return $self->{wiki};
79}
80
81=item B<config>
82
83An accessor, returns the underlying L<OpenGuides::Config> object.
84
85=cut
86
87sub config {
88    my $self = shift;
89    return $self->{config};
90}
91
92=item B<locator>
93
94An accessor, returns the underlying L<Wiki::Toolkit::Plugin::Locator::UK> object.
95
96=cut
97
98sub locator {
99    my $self = shift;
100    return $self->{locator};
101}
102
103=item B<differ>
104
105An accessor, returns the underlying L<Wiki::Toolkit::Plugin::Diff> object.
106
107=cut
108
109sub differ {
110    my $self = shift;
111    return $self->{differ};
112}
113
114=item B<display_node>
115
116  # Print node to STDOUT.
117  $guide->display_node(
118                          id      => "Calthorpe Arms",
119                          version => 2,
120                      );
121
122  # Or return output as a string (useful for writing tests).
123  $guide->display_node(
124                          id            => "Calthorpe Arms",
125                          return_output => 1,
126                      );
127
128  # Or return the hash of variables that will be passed to the template
129  # (not including those set additionally by OpenGuides::Template).
130  $guide->display_node(
131                          id             => "Calthorpe Arms",
132                          return_tt_vars => 1,
133                      );
134
135If C<version> is omitted then the latest version will be displayed.
136
137=cut
138
139sub display_node {
140    my ($self, %args) = @_;
141    my $return_output = $args{return_output} || 0;
142    my $version = $args{version};
143    my $id = $args{id} || $self->config->home_name;
144    my $wiki = $self->wiki;
145    my $config = $self->config;
146    my $oldid = $args{oldid} || '';
147    my $do_redirect = $args{redirect} || 1;
148
149    my %tt_vars;
150
151    if ( $id =~ /^(Category|Locale) (.*)$/ ) {
152        my $type = $1;
153        $tt_vars{is_indexable_node} = 1;
154        $tt_vars{index_type} = lc($type);
155        $tt_vars{index_value} = $2;
156        $tt_vars{"rss_".lc($type)."_url"} =
157                           $config->script_name . "?action=rc;format=rss;"
158                           . lc($type) . "=" . lc(CGI->escape($2));
159        $tt_vars{"atom_".lc($type)."_url"} =
160                           $config->script_name . "?action=rc;format=atom;"
161                           . lc($type) . "=" . lc(CGI->escape($2));
162    }
163
164    my %current_data = $wiki->retrieve_node( $id );
165    my $current_version = $current_data{version};
166    undef $version if ($version && $version == $current_version);
167    my %criteria = ( name => $id );
168    $criteria{version} = $version if $version; # retrieve_node default is current
169
170    my %node_data = $wiki->retrieve_node( %criteria );
171
172    # Fixes passing undefined values to Text::Wikiformat if node doesn't exist.
173    my $raw        = $node_data{content} || " ";
174    my $content    = $wiki->format($raw);
175    my $modified   = $node_data{last_modified};
176    my $moderated  = $node_data{moderated};
177    my %metadata   = %{$node_data{metadata}};
178
179    my ($wgs84_long, $wgs84_lat) = OpenGuides::Utils->get_wgs84_coords(
180                                        longitude => $metadata{longitude}[0],
181                                        latitude => $metadata{latitude}[0],
182                                        config => $config);
183    if ($args{format} && $args{format} eq 'raw') {
184      print "Content-Type: text/plain\n\n";
185      print $raw;
186      return 0;
187    }
188   
189    my %metadata_vars = OpenGuides::Template->extract_metadata_vars(
190                            wiki     => $wiki,
191                            config   => $config,
192                            metadata => $node_data{metadata}
193                        );
194
195    %tt_vars = (
196                   %tt_vars,
197                   %metadata_vars,
198                   content       => $content,
199                   last_modified => $modified,
200                   version       => $node_data{version},
201                   node          => $id,
202                   language      => $config->default_language,
203                   moderated     => $moderated,
204                   oldid         => $oldid,
205                   enable_gmaps  => 1,
206                   display_google_maps => $self->get_cookie("display_google_maps"),
207                   wgs84_long    => $wgs84_long,
208                   wgs84_lat     => $wgs84_lat
209               );
210
211    if ( $raw =~ /^#REDIRECT\s+(.+?)\s*$/ ) {
212        my $redirect = $1;
213        # Strip off enclosing [[ ]] in case this is an extended link.
214        $redirect =~ s/^\[\[//;
215        $redirect =~ s/\]\]\s*$//;
216
217        # Don't redirect if the parameter "redirect" is given as 0.
218        if ($do_redirect == 0) {
219            return %tt_vars if $args{return_tt_vars};
220            $tt_vars{current} = 1;
221            my $output = $self->process_template(
222                                                  id            => $id,
223                                                  template      => "node.tt",
224                                                  tt_vars       => \%tt_vars,
225                                                );
226            return $output if $return_output;
227            print $output;
228        } elsif ( $wiki->node_exists($redirect) && $redirect ne $id && $redirect ne $oldid ) {
229            # Avoid loops by not generating redirects to the same node or the previous node.
230            my $output = $self->redirect_to_node($redirect, $id);
231            return $output if $return_output;
232            print $output;
233            return 0;
234        }
235    }
236
237    # We've undef'ed $version above if this is the current version.
238    $tt_vars{current} = 1 unless $version;
239
240    if ($id eq "RecentChanges") {
241        $self->display_recent_changes(%args);
242    } elsif ( $id eq $self->config->home_name ) {
243        my @recent = $wiki->list_recent_changes(
244            last_n_changes => 10,
245            metadata_was   => { edit_type => "Normal edit" },
246        );
247        @recent = map {
248                          {
249                              name          => CGI->escapeHTML($_->{name}),
250                              last_modified => CGI->escapeHTML($_->{last_modified}),
251                              version       => CGI->escapeHTML($_->{version}),
252                              comment       => CGI->escapeHTML($_->{metadata}{comment}[0]),
253                              username      => CGI->escapeHTML($_->{metadata}{username}[0]),
254                              url           => $config->script_name . "?"
255                                               . CGI->escape($wiki->formatter->node_name_to_node_param($_->{name}))
256                          }
257                      } @recent;
258        $tt_vars{recent_changes} = \@recent;
259        return %tt_vars if $args{return_tt_vars};
260        my $output = $self->process_template(
261                                                id            => $id,
262                                                template      => "home_node.tt",
263                                                tt_vars       => \%tt_vars,
264                                            );
265        return $output if $return_output;
266        print $output;
267    } else {
268        return %tt_vars if $args{return_tt_vars};
269        my $output = $self->process_template(
270                                                id            => $id,
271                                                template      => "node.tt",
272                                                tt_vars       => \%tt_vars,
273                                            );
274        return $output if $return_output;
275        print $output;
276    }
277}
278
279=item B<display_recent_changes> 
280
281  $guide->display_recent_changes;
282
283As with other methods, the C<return_output> parameter can be used to
284return the output instead of printing it to STDOUT.
285
286=cut
287
288sub display_recent_changes {
289    my ($self, %args) = @_;
290    my $config = $self->config;
291    my $wiki = $self->wiki;
292    my $minor_edits = $self->get_cookie( "show_minor_edits_in_rc" );
293    my $id = $args{id} || $self->config->home_name;
294    my $return_output = $args{return_output} || 0;
295    my (%tt_vars, %recent_changes);
296    my $q = CGI->new;
297    my $since = $q->param("since");
298    if ( $since ) {
299        $tt_vars{since} = $since;
300        my $t = localtime($since); # overloaded by Time::Piece
301        $tt_vars{since_string} = $t->strftime;
302        my %criteria = ( since => $since );   
303        $criteria{metadata_was} = { edit_type => "Normal edit" }
304          unless $minor_edits;
305        my @rc = $self->{wiki}->list_recent_changes( %criteria );
306 
307        @rc = map {
308            {
309              name        => CGI->escapeHTML($_->{name}),
310              last_modified => CGI->escapeHTML($_->{last_modified}),
311              version     => CGI->escapeHTML($_->{version}),
312              comment     => CGI->escapeHTML($_->{metadata}{comment}[0]),
313              username    => CGI->escapeHTML($_->{metadata}{username}[0]),
314              host        => CGI->escapeHTML($_->{metadata}{host}[0]),
315              username_param => CGI->escape($_->{metadata}{username}[0]),
316              edit_type   => CGI->escapeHTML($_->{metadata}{edit_type}[0]),
317              url         => $config->script_name . "?"
318      . CGI->escape($wiki->formatter->node_name_to_node_param($_->{name})),
319        }
320                   } @rc;
321        if ( scalar @rc ) {
322            $recent_changes{since} = \@rc; 
323        }
324    } else {
325        for my $days ( [0, 1], [1, 7], [7, 14], [14, 30] ) {
326            my %criteria = ( between_days => $days );
327            $criteria{metadata_was} = { edit_type => "Normal edit" }
328              unless $minor_edits;
329            my @rc = $self->{wiki}->list_recent_changes( %criteria );
330
331            @rc = map {
332            {
333              name        => CGI->escapeHTML($_->{name}),
334              last_modified => CGI->escapeHTML($_->{last_modified}),
335              version     => CGI->escapeHTML($_->{version}),
336              comment     => CGI->escapeHTML($_->{metadata}{comment}[0]),
337              username    => CGI->escapeHTML($_->{metadata}{username}[0]),
338              host        => CGI->escapeHTML($_->{metadata}{host}[0]),
339              username_param => CGI->escape($_->{metadata}{username}[0]),
340              edit_type   => CGI->escapeHTML($_->{metadata}{edit_type}[0]),
341              url         => $config->script_name . "?"
342      . CGI->escape($wiki->formatter->node_name_to_node_param($_->{name})),
343        }
344                       } @rc;
345            if ( scalar @rc ) {
346                $recent_changes{$days->[1]} = \@rc;
347        }
348        }
349    }
350    $tt_vars{recent_changes} = \%recent_changes;
351    my %processing_args = (
352                            id            => $id,
353                            template      => "recent_changes.tt",
354                            tt_vars       => \%tt_vars,
355                           );
356    if ( !$since && $self->get_cookie("track_recent_changes_views") ) {
357    my $cookie =
358           OpenGuides::CGI->make_recent_changes_cookie(config => $config );
359        $processing_args{cookies} = $cookie;
360        $tt_vars{last_viewed} = OpenGuides::CGI->get_last_recent_changes_visit_from_cookie( config => $config );
361    }
362    return %tt_vars if $args{return_tt_vars};
363    my $output = $self->process_template( %processing_args );
364    return $output if $return_output;
365    print $output;
366}
367
368=item B<display_diffs>
369
370  $guide->display_diffs(
371                           id            => "Home Page",
372                           version       => 6,
373                           other_version => 5,
374                       );
375
376  # Or return output as a string (useful for writing tests).
377  my $output = $guide->display_diffs(
378                                        id            => "Home Page",
379                                        version       => 6,
380                                        other_version => 5,
381                                        return_output => 1,
382                                    );
383
384  # Or return the hash of variables that will be passed to the template
385  # (not including those set additionally by OpenGuides::Template).
386  my %vars = $guide->display_diffs(
387                                      id             => "Home Page",
388                                      version        => 6,
389                                      other_version  => 5,
390                                      return_tt_vars => 1,
391                                  );
392
393=cut
394
395sub display_diffs {
396    my ($self, %args) = @_;
397    my %diff_vars = $self->differ->differences(
398                                                  node          => $args{id},
399                                                  left_version  => $args{version},
400                                                  right_version => $args{other_version},
401                                              );
402    $diff_vars{not_deletable} = 1;
403    $diff_vars{not_editable}  = 1;
404    $diff_vars{deter_robots}  = 1;
405    return %diff_vars if $args{return_tt_vars};
406    my $output = $self->process_template(
407                                            id       => $args{id},
408                                            template => "differences.tt",
409                                            tt_vars  => \%diff_vars
410                                        );
411    return $output if $args{return_output};
412    print $output;
413}
414
415=item B<find_within_distance>
416
417  $guide->find_within_distance(
418                                  id => $node,
419                                  metres => $q->param("distance_in_metres")
420                              );
421
422=cut
423
424sub find_within_distance {
425    my ($self, %args) = @_;
426    my $node = $args{id};
427    my $metres = $args{metres};
428    my %data = $self->wiki->retrieve_node( $node );
429    my $lat = $data{metadata}{latitude}[0];
430    my $long = $data{metadata}{longitude}[0];
431    my $script_url = $self->config->script_url;
432    my $q = CGI->new;
433    print $q->redirect( $script_url . "search.cgi?lat=$lat;long=$long;distance_in_metres=$metres" );
434}
435
436=item B<show_backlinks>
437
438  $guide->show_backlinks( id => "Calthorpe Arms" );
439
440As with other methods, parameters C<return_tt_vars> and
441C<return_output> can be used to return these things instead of
442printing the output to STDOUT.
443
444=cut
445
446sub show_backlinks {
447    my ($self, %args) = @_;
448    my $wiki = $self->wiki;
449    my $formatter = $wiki->formatter;
450
451    my @backlinks = $wiki->list_backlinks( node => $args{id} );
452    my @results = map {
453                          {
454                              url   => CGI->escape($formatter->node_name_to_node_param($_)),
455                              title => CGI->escapeHTML($_)
456                          }
457                      } sort @backlinks;
458    my %tt_vars = ( results       => \@results,
459                    num_results   => scalar @results,
460                    not_deletable => 1,
461                    deter_robots  => 1,
462                    not_editable  => 1 );
463    return %tt_vars if $args{return_tt_vars};
464    my $output = OpenGuides::Template->output(
465                                                 node    => $args{id},
466                                                 wiki    => $wiki,
467                                                 config  => $self->config,
468                                                 template=>"backlink_results.tt",
469                                                 vars    => \%tt_vars,
470                                             );
471    return $output if $args{return_output};
472    print $output;
473}
474
475=item B<show_index>
476
477  $guide->show_index(
478                        type   => "category",
479                        value  => "pubs",
480                    );
481
482  # RDF version.
483  $guide->show_index(
484                        type   => "locale",
485                        value  => "Holborn",
486                        format => "rdf",
487                    );
488
489  # RSS / Atom version (recent changes style).
490  $guide->show_index(
491                        type   => "locale",
492                        value  => "Holborn",
493                        format => "rss",
494                    );
495
496  # Or return output as a string (useful for writing tests).
497  $guide->show_index(
498                        type          => "category",
499                        value         => "pubs",
500                        return_output => 1,
501                    );
502
503=cut
504
505sub show_index {
506    my ($self, %args) = @_;
507    my $wiki = $self->wiki;
508    my $formatter = $wiki->formatter;
509    my %tt_vars;
510    my @selnodes;
511
512    if ( $args{type} and $args{value} ) {
513        if ( $args{type} eq "fuzzy_title_match" ) {
514            my %finds = $wiki->fuzzy_title_match( $args{value} );
515            @selnodes = sort { $finds{$a} <=> $finds{$b} } keys %finds;
516            $tt_vars{criterion} = {
517                type  => $args{type},  # for RDF version
518                value => $args{value}, # for RDF version
519                name  => CGI->escapeHTML("Fuzzy Title Match on '$args{value}'")
520            };
521            $tt_vars{not_editable} = 1;
522        } else {
523            @selnodes = $wiki->list_nodes_by_metadata(
524                metadata_type  => $args{type},
525                metadata_value => $args{value},
526                ignore_case    => 1
527            );
528            my $name = ucfirst($args{type}) . " $args{value}";
529            my $url = $self->config->script_name
530                      . "?"
531                      . ucfirst( $args{type} )
532                      . "_"
533                      . uri_escape(
534                                      $formatter->node_name_to_node_param($args{value})
535                                  );
536            $tt_vars{criterion} = {
537                type  => $args{type},
538                value => $args{value}, # for RDF version
539                name  => CGI->escapeHTML( $name ),
540                url   => $url
541            };
542            $tt_vars{not_editable} = 1;
543        }
544    } else {
545        @selnodes = $wiki->list_all_nodes();
546    }
547
548    my @nodes = map {
549                        {
550                            name      => $_,
551                            node_data => { $wiki->retrieve_node( name => $_ ) },
552                            param     => $formatter->node_name_to_node_param($_) }
553                        } sort @selnodes;
554
555    $tt_vars{nodes} = \@nodes;
556
557    my ($template, %conf);
558
559    if ( $args{format} ) {
560        if ( $args{format} eq "rdf" ) {
561            $template = "rdf_index.tt";
562            $conf{content_type} = "application/rdf+xml";
563        }
564        elsif ( $args{format} eq "plain" ) {
565            $template = "plain_index.tt";
566            $conf{content_type} = "text/plain";
567        } elsif ( $args{format} eq "map" ) {
568            my $q = CGI->new;
569            $tt_vars{zoom} = $q->param('zoom') || '';
570            $tt_vars{lat} = $q->param('lat') || '';
571            $tt_vars{long} = $q->param('long') || '';
572            $tt_vars{centre_long} = $self->config->centre_long;
573            $tt_vars{centre_lat} = $self->config->centre_lat;
574            $tt_vars{default_gmaps_zoom} = $self->config->default_gmaps_zoom;
575            $tt_vars{enable_gmaps} = 1;
576            $tt_vars{display_google_maps} = 1; # override for this page
577            $template = "map_index.tt";
578           
579        } elsif( $args{format} eq "rss" || $args{format} eq "atom") {
580            # They really wanted a recent changes style rss/atom feed
581            my $feed_type = $args{format};
582            my ($feed,$content_type) = $self->get_feed_and_content_type($feed_type);
583            $feed->set_feed_name_and_url_params(
584                        "Index of $args{type} $args{value}",
585                        "action=index;index_type=$args{type};index_value=$args{value}"
586            );
587
588            # Grab the actual node data out of @nodes
589            my @node_data;
590            foreach my $node (@nodes) {
591                $node->{node_data}->{name} = $node->{name};
592                push @node_data, $node->{node_data};
593            }
594
595            my $output = "Content-Type: ".$content_type."\n";
596            $output .= $feed->build_feed_for_nodes($feed_type, @node_data);
597
598            return $output if $args{return_output};
599            print $output;
600            return;
601        }
602    } else {
603        $template = "site_index.tt";
604    }
605
606    %conf = (
607                %conf,
608                node        => "$args{type} index", # KLUDGE
609                template    => $template,
610                tt_vars     => \%tt_vars,
611            );
612
613    my $output = $self->process_template( %conf );
614    return $output if $args{return_output};
615    print $output;
616}
617
618=item B<list_all_versions>
619
620  $guide->list_all_versions ( id => "Home Page" );
621
622  # Or return output as a string (useful for writing tests).
623  $guide->list_all_versions (
624                                id            => "Home Page",
625                                return_output => 1,
626                            );
627
628  # Or return the hash of variables that will be passed to the template
629  # (not including those set additionally by OpenGuides::Template).
630  $guide->list_all_versions (
631                                id             => "Home Page",
632                                return_tt_vars => 1,
633                            );
634
635=cut
636
637sub list_all_versions {
638    my ($self, %args) = @_;
639    my $return_output = $args{return_output} || 0;
640    my $node = $args{id};
641    my %curr_data = $self->wiki->retrieve_node($node);
642    my $curr_version = $curr_data{version};
643    my @history;
644    for my $version ( 1 .. $curr_version ) {
645        my %node_data = $self->wiki->retrieve_node( name    => $node,
646                                                    version => $version );
647        # $node_data{version} will be zero if this version was deleted.
648        push @history, {
649            version  => CGI->escapeHTML( $version ),
650            modified => CGI->escapeHTML( $node_data{last_modified} ),
651            username => CGI->escapeHTML( $node_data{metadata}{username}[0] ),
652            comment  => CGI->escapeHTML( $node_data{metadata}{comment}[0] ),
653                       } if $node_data{version};
654    }
655    @history = reverse @history;
656    my %tt_vars = (
657                      node          => $node,
658                      version       => $curr_version,
659                      not_deletable => 1,
660                      not_editable  => 1,
661                      deter_robots  => 1,
662                      history       => \@history
663                  );
664    return %tt_vars if $args{return_tt_vars};
665    my $output = $self->process_template(
666                                            id       => $node,
667                                            template => "node_history.tt",
668                                            tt_vars  => \%tt_vars,
669                                        );
670    return $output if $return_output;
671    print $output;
672}
673
674=item B<get_feed_and_content_type>
675
676Fetch the OpenGuides feed object, and the output content type, for the
677supplied feed type.
678
679Handles all the setup for the OpenGuides feed object.
680=cut
681sub get_feed_and_content_type {
682    my ($self, $feed_type) = @_;
683
684    my $feed = OpenGuides::Feed->new(
685                                        wiki       => $self->wiki,
686                                        config     => $self->config,
687                                        og_version => $VERSION,
688                                    );
689
690    my $content_type = $feed->default_content_type($feed_type);
691
692    return ($feed, $content_type);
693}
694
695=item B<display_feed>
696
697  # Last ten non-minor edits to Hammersmith pages in RSS 1.0 format
698  $guide->display_feed(
699                         feed_type          => 'rss',
700                         feed_listing       => 'recent_changes',
701                         items              => 10,
702                         ignore_minor_edits => 1,
703                         locale             => "Hammersmith",
704                     );
705
706  # All edits bob has made to pub pages in the last week in Atom format
707  $guide->display_feed(
708                         feed_type    => 'atom',
709                         feed_listing => 'recent_changes',
710                         days         => 7,
711                         username     => "bob",
712                         category     => "Pubs",
713                     );
714
715C<feed_type> is a mandatory parameter. Supported values at present are
716"rss" and "atom".
717
718C<feed_listing> is a mandatory parameter. Supported values at present
719are "recent_changes". (More values are coming soon though!)
720
721As with other methods, the C<return_output> parameter can be used to
722return the output instead of printing it to STDOUT.
723
724=cut
725
726sub display_feed {
727    my ($self, %args) = @_;
728
729    my $feed_type = $args{feed_type};
730    croak "No feed type given" unless $feed_type;
731
732    my $feed_listing = $args{feed_listing};
733    croak "No feed listing given" unless $feed_listing;
734   
735    my $return_output = $args{return_output} ? 1 : 0;
736
737    # Basic criteria, whatever the feed listing type is
738    my %criteria = (
739                       feed_type             => $feed_type,
740                       feed_listing          => $feed_listing,
741                       also_return_timestamp => 1,
742                   );
743
744    # Feed listing specific criteria
745    if($feed_listing eq "recent_changes") {
746        $criteria{items} = $args{items} || "";
747        $criteria{days}  = $args{days}  || "";
748        $criteria{ignore_minor_edits} = $args{ignore_minor_edits} ? 1 : 0;
749
750        my $username = $args{username} || "";
751        my $category = $args{category} || "";
752        my $locale   = $args{locale}   || "";
753
754        my %filter;
755        $filter{username} = $username if $username;
756        $filter{category} = $category if $category;
757        $filter{locale}   = $locale   if $locale;
758        if ( scalar keys %filter ) {
759            $criteria{filter_on_metadata} = \%filter;
760        }
761    }
762    elsif($feed_listing eq "node_all_versions") {
763        $criteria{name} = $args{name};
764    }
765
766
767    # Get the feed object, and the content type
768    my ($feed,$content_type) = $self->get_feed_and_content_type($feed_type);
769
770    my $output = "Content-Type: ".$content_type."\n";
771   
772    # Get the feed, and the timestamp, in one go
773    my ($feed_output, $feed_timestamp) = 
774        $feed->make_feed( %criteria );
775
776    $output .= "Last-Modified: " . $feed_timestamp . "\n\n";
777    $output .= $feed_output;
778
779    return $output if $return_output;
780    print $output;
781}
782
783sub display_about {
784    my ($self, %args) = @_;
785
786    my $output;
787
788    if ($args{format} && $args{format} =~ /^rdf$/i) {
789        $output = qq{Content-Type: application/rdf+xml
790
791<?xml version="1.0" encoding="UTF-8"?>
792<rdf:RDF xmlns      = "http://usefulinc.com/ns/doap#"
793         xmlns:rdf  = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
794         xmlns:foaf = "http://xmlns.com/foaf/0.1/">
795<Project rdf:ID="OpenGuides">
796  <name>OpenGuides</name>
797
798  <created>2003-04-29</created>
799 
800  <shortdesc xml:lang="en">
801    A wiki engine for collaborative description of places with specialised
802    geodata metadata features.
803  </shortdesc>
804
805  <description xml:lang="en">
806    OpenGuides is a collaborative wiki environment, written in Perl, for
807    building guides and sharing information, as both human-readable text
808    and RDF. The engine contains a number of geodata-specific metadata
809    mechanisms such as locale search, node classification and integration
810    with Google Maps.
811  </description>
812
813  <homepage rdf:resource="http://openguides.org/" />
814  <mailing-list rdf:resource="http://openguides.org/mm/listinfo/openguides-dev/" />
815  <mailing-list rdf:resource="http://urchin.earth.li/mailman/listinfo/openguides-commits/" />
816
817  <maintainer>
818    <foaf:Person rdf:ID="OpenGuidesMaintainer">
819      <foaf:name>Dominic Hargreaves</foaf:name>
820      <foaf:homepage rdf:resource="http://www.larted.org.uk/~dom/" />
821    </foaf:Person>
822  </maintainer>
823
824  <repository>
825    <SVNRepository rdf:ID="OpenGuidesSVN">
826      <location rdf:resource="https://urchin.earth.li/svn/openguides/" />
827      <browse rdf:resource="http://dev.openguides.org/browser" />
828    </SVNRepository>
829  </repository>
830
831  <release>
832    <Version rdf:ID="OpenGuidesVersion">
833      <revision>$VERSION</revision>
834    </Version>
835  </release>
836
837  <download-page rdf:resource="http://search.cpan.org/dist/OpenGuides/" />
838 
839  <!-- Freshmeat category: Internet :: WWW/HTTP :: Dynamic Content -->
840  <category rdf:resource="http://freshmeat.net/browse/92/" />
841 
842  <license rdf:resource="http://www.opensource.org/licenses/gpl-license.php" />
843  <license rdf:resource="http://www.opensource.org/licenses/artistic-license.php" />
844
845</Project>
846
847</rdf:RDF>};
848    }
849    else {
850        my $site_name  = $self->config->{site_name};
851        my $script_name = $self->config->{script_name};
852        $output = qq{Content-Type: text/html; charset=utf-8
853
854<html>
855<head>
856  <title>About $site_name</title>
857<style type="text/css">
858body        { margin: 0px; }
859#content    { padding: 50px; margin: auto; width: 50%; }
860h1          { margin-bottom: 0px; font-style: italic; }
861h2          { margin-top: 0px; }
862#logo       { text-align: center; }
863#about      { margin: 0em 0em 1em 0em; border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; }
864#meta       { font-size: small; text-align: center;}
865</style>
866<link rel="alternate"
867  type="application/rdf+xml"
868  title="DOAP (Description Of A Project) profile for this site's software"
869  href="$script_name?action=about;format=rdf" />
870</head>
871<body>
872<div id="content">
873<div id="logo">
874<a href="http://openguides.org/"><img
875src="http://openguides.org/img/logo.png" alt="OpenGuides"></a>
876<h1><a href="$script_name">$site_name</a></h1>
877<h2>is powered by <a href="http://openguides.org/">OpenGuides</a> -<br>
878the guides made by you.</h2>
879<h3>version <a href="http://search.cpan.org/~dom/OpenGuides-$VERSION">$VERSION</a></h3>
880</div>
881<div id="about">
882<p>
883<a href="http://www.w3.org/RDF/"><img
884src="http://openguides.org/img/rdf_icon.png" width="44" height="48"
885style="float: right; margin-left: 10px; border: 0px"></a> OpenGuides is a
886web-based collaborative <a href="http://wiki.org/wiki.cgi?WhatIsWiki">wiki</a>
887environment for building guides and sharing information, as both
888human-readable text and <a href="http://www.w3.org/RDF/"><acronym
889title="Resource Description Framework">RDF</acronym></a>. The engine contains
890a number of geodata-specific metadata mechanisms such as locale search, node
891classification and integration with <a href="http://maps.google.com/">Google
892Maps</a>.
893</p>
894<p>
895OpenGuides is written in <a href="http://www.perl.org/">Perl</a>, and is
896made available under the same license as Perl itself (dual <a
897href="http://dev.perl.org/licenses/artistic.html" title='The "Artistic Licence"'>Artistic</a> and <a
898href="http://www.opensource.org/licenses/gpl-license.php"><acronym
899title="GNU Public Licence">GPL</acronym></a>). Developer information for the
900project is available from the <a href="http://dev.openguides.org/">OpenGuides
901development site</a>.
902</p>
903<p>
904Copyright &copy;2003-2006, <a href="http://openguides.org/">The OpenGuides
905Project</a>. "OpenGuides", "[The] Open Guide To..." and "The guides made by
906you" are trademarks of The OpenGuides Project. Any uses on this site are made
907with permission.
908</p>
909</div>
910<div id="meta">
911<a href="$script_name?action=about;format=rdf"><acronym
912title="Description Of A Project">DOAP</acronym> RDF version of this
913information</a>
914</div>
915</div>
916</body>
917</html>};
918    }
919   
920    return $output if $args{return_output};
921    print $output;
922}
923
924=item B<commit_node>
925
926  $guide->commit_node(
927                         id      => $node,
928                         cgi_obj => $q,
929                     );
930
931As with other methods, parameters C<return_tt_vars> and
932C<return_output> can be used to return these things instead of
933printing the output to STDOUT.
934
935The geographical data that you should provide in the L<CGI> object
936depends on the handler you chose in C<wiki.conf>.
937
938=over
939
940=item *
941
942B<British National Grid> - provide either C<os_x> and C<os_y> or
943C<latitude> and C<longitude>; whichever set of data you give, it will
944be converted to the other and both sets will be stored.
945
946=item *
947
948B<Irish National Grid> - provide either C<osie_x> and C<osie_y> or
949C<latitude> and C<longitude>; whichever set of data you give, it will
950be converted to the other and both sets will be stored.
951
952=item *
953
954B<UTM ellipsoid> - provide C<latitude> and C<longitude>; these will be
955converted to easting and northing and both sets of data will be stored.
956
957=back
958
959=cut
960
961sub commit_node {
962    my ($self, %args) = @_;
963    my $node = $args{id};
964    my $q = $args{cgi_obj};
965    my $return_output = $args{return_output};
966    my $wiki = $self->wiki;
967    my $config = $self->config;
968
969    my $content  = $q->param("content");
970    $content =~ s/\r\n/\n/gs;
971    my $checksum = $q->param("checksum");
972
973    my %metadata = OpenGuides::Template->extract_metadata_vars(
974        wiki    => $wiki,
975        config  => $config,
976    cgi_obj => $q
977    );
978
979    delete $metadata{website} if $metadata{website} eq 'http://';
980
981    $metadata{opening_hours_text} = $q->param("hours_text") || "";
982
983    # Pick out the unmunged versions of lat/long if they're set.
984    # (If they're not, it means they weren't munged in the first place.)
985    $metadata{latitude} = delete $metadata{latitude_unmunged}
986        if $metadata{latitude_unmunged};
987    $metadata{longitude} = delete $metadata{longitude_unmunged}
988        if $metadata{longitude_unmunged};
989
990    # Check to make sure all the indexable nodes are created
991    # Skip this for nodes needing moderation - this occurs for them once
992    #  they've been moderated
993    unless($wiki->node_required_moderation($node)) {
994        $self->_autoCreateCategoryLocale(
995                                          id       => $node,
996                                          metadata => \%metadata
997        );
998    }
999   
1000    foreach my $var ( qw( summary username comment edit_type ) ) {
1001        $metadata{$var} = $q->param($var) || "";
1002    }
1003    $metadata{host} = $ENV{REMOTE_ADDR};
1004
1005    # Wiki::Toolkit::Plugin::RSS::ModWiki wants "major_change" to be set.
1006    $metadata{major_change} = ( $metadata{edit_type} eq "Normal edit" )
1007                            ? 1
1008                            : 0;
1009
1010    my $written = $wiki->write_node($node, $content, $checksum, \%metadata );
1011
1012    if ($written) {
1013        my $output = $self->redirect_to_node($node);
1014        return $output if $return_output;
1015        print $output;
1016    } else {
1017        my %node_data = $wiki->retrieve_node($node);
1018        my %tt_vars = ( checksum       => $node_data{checksum},
1019                        new_content    => $content,
1020                        stored_content => $node_data{content} );
1021        foreach my $mdvar ( keys %metadata ) {
1022            if ($mdvar eq "locales") {
1023                $tt_vars{"stored_$mdvar"} = $node_data{metadata}{locale};
1024                $tt_vars{"new_$mdvar"}    = $metadata{locale};
1025            } elsif ($mdvar eq "categories") {
1026                $tt_vars{"stored_$mdvar"} = $node_data{metadata}{category};
1027                $tt_vars{"new_$mdvar"}    = $metadata{category};
1028            } elsif ($mdvar eq "username" or $mdvar eq "comment"
1029                      or $mdvar eq "edit_type" ) {
1030                $tt_vars{$mdvar} = $metadata{$mdvar};
1031            } else {
1032                $tt_vars{"stored_$mdvar"} = $node_data{metadata}{$mdvar}[0];
1033                $tt_vars{"new_$mdvar"}    = $metadata{$mdvar};
1034            }
1035        }
1036        return %tt_vars if $args{return_tt_vars};
1037        my $output = $self->process_template(
1038                                              id       => $node,
1039                                              template => "edit_conflict.tt",
1040                                              tt_vars  => \%tt_vars,
1041                                            );
1042        return $output if $args{return_output};
1043        print $output;
1044    }
1045}
1046
1047=item B<_autoCreateCategoryLocale>
1048
1049  $guide->_autoCreateCategoryLocale(
1050                         id       => "FAQ",
1051                         metadata => \%metadata,
1052                     );
1053
1054When a new node is added, or a previously un-moderated node is moderated,
1055identifies if any of its Categories or Locales are missing, and creates them.
1056
1057For nodes not requiring moderation, should be called on writing the node
1058For nodes requiring moderation, should only be called on moderation
1059=cut
1060sub _autoCreateCategoryLocale {
1061    my ($self, %args) = @_;
1062
1063    my $wiki = $self->wiki;
1064    my $id = $args{'id'};
1065    my %metadata = %{$args{'metadata'}};
1066
1067    # Check to make sure all the indexable nodes are created
1068    foreach my $type (qw(Category Locale)) {
1069        my $lctype = lc($type);
1070        foreach my $index (@{$metadata{$lctype}}) {
1071            $index =~ s/(.*)/\u$1/;
1072            my $node = $type . " " . $index;
1073            # Uppercase the node name before checking for existence
1074            $node =~ s/ (\S+)/ \u$1/g;
1075            unless ( $wiki->node_exists($node) ) {
1076                my $category = $type eq "Category" ? "Category" : "Locales";
1077                $wiki->write_node(
1078                                     $node,
1079                                     "\@INDEX_LINK [[$node]]",
1080                                     undef,
1081                                     {
1082                                         username => "Auto Create",
1083                                         comment  => "Auto created $lctype stub page",
1084                                         category => $category
1085                                     }
1086                );
1087            }
1088        }
1089    }
1090}
1091
1092
1093=item B<delete_node>
1094
1095  $guide->delete_node(
1096                         id       => "FAQ",
1097                         version  => 15,
1098                         password => "beer",
1099                     );
1100
1101C<version> is optional - if it isn't supplied then all versions of the
1102node will be deleted; in other words the node will be entirely
1103removed.
1104
1105If C<password> is not supplied then a form for entering the password
1106will be displayed.
1107
1108As with other methods, parameters C<return_tt_vars> and
1109C<return_output> can be used to return these things instead of
1110printing the output to STDOUT.
1111
1112=cut
1113
1114sub delete_node {
1115    my ($self, %args) = @_;
1116    my $node = $args{id} or croak "No node ID supplied for deletion";
1117    my $return_tt_vars = $args{return_tt_vars} || 0;
1118    my $return_output = $args{return_output} || 0;
1119
1120    my %tt_vars = (
1121                      not_editable  => 1,
1122                      not_deletable => 1,
1123                      deter_robots  => 1,
1124                  );
1125    $tt_vars{delete_version} = $args{version} || "";
1126
1127    my $password = $args{password};
1128
1129    if ($password) {
1130        if ($password ne $self->config->admin_pass) {
1131            return %tt_vars if $return_tt_vars;
1132            my $output = $self->process_template(
1133                                                    id       => $node,
1134                                                    template => "delete_password_wrong.tt",
1135                                                    tt_vars  => \%tt_vars,
1136                                                );
1137            return $output if $return_output;
1138            print $output;
1139        } else {
1140            $self->wiki->delete_node(
1141                                        name    => $node,
1142                                        version => $args{version},
1143                                    );
1144            # Check whether any versions of this node remain.
1145            my %check = $self->wiki->retrieve_node( name => $node );
1146            $tt_vars{other_versions_remain} = 1 if $check{version};
1147            return %tt_vars if $return_tt_vars;
1148            my $output = $self->process_template(
1149                                                    id       => $node,
1150                                                    template => "delete_done.tt",
1151                                                    tt_vars  => \%tt_vars,
1152                                                );
1153            return $output if $return_output;
1154            print $output;
1155        }
1156    } else {
1157        return %tt_vars if $return_tt_vars;
1158        my $output = $self->process_template(
1159                                                id       => $node,
1160                                                template => "delete_confirm.tt",
1161                                                tt_vars  => \%tt_vars,
1162                                            );
1163        return $output if $return_output;
1164        print $output;
1165    }
1166}
1167
1168=item B<set_node_moderation>
1169
1170  $guide->set_node_moderation(
1171                         id       => "FAQ",
1172                         password => "beer",
1173                         moderation_flag => 1,
1174                     );
1175
1176Sets the moderation needed flag on a node, either on or off.
1177
1178If C<password> is not supplied then a form for entering the password
1179will be displayed.
1180=cut
1181sub set_node_moderation {
1182    my ($self, %args) = @_;
1183    my $node = $args{id} or croak "No node ID supplied for node moderation";
1184    my $return_tt_vars = $args{return_tt_vars} || 0;
1185    my $return_output = $args{return_output} || 0;
1186
1187    # Get the moderation flag into something sane
1188    if($args{moderation_flag} eq "1" || $args{moderation_flag} eq "yes" ||
1189       $args{moderation_flag} eq "on" || $args{moderation_flag} eq "true") {
1190        $args{moderation_flag} = 1;
1191    } else {
1192        $args{moderation_flag} = 0;
1193    }
1194
1195    # Set up the TT variables
1196    my %tt_vars = (
1197                      not_editable  => 1,
1198                      not_deletable => 1,
1199                      deter_robots  => 1,
1200                      moderation_action => 'set_moderation',
1201                      moderation_flag   => $args{moderation_flag},
1202                      moderation_url_args => 'action=set_moderation;moderation_flag='.$args{moderation_flag},
1203                  );
1204
1205    my $password = $args{password};
1206
1207    if ($password) {
1208        if ($password ne $self->config->admin_pass) {
1209            return %tt_vars if $return_tt_vars;
1210            my $output = $self->process_template(
1211                                                    id       => $node,
1212                                                    template => "moderate_password_wrong.tt",
1213                                                    tt_vars  => \%tt_vars,
1214                                                );
1215            return $output if $return_output;
1216            print $output;
1217        } else {
1218            $self->wiki->set_node_moderation(
1219                                        name    => $node,
1220                                        required => $args{moderation_flag},
1221                                    );
1222
1223            # Send back to the admin interface
1224            my $script_url = $self->config->script_url;
1225            my $script_name = $self->config->script_name;
1226            my $q = CGI->new;
1227            my $output = $q->redirect( $script_url.$script_name."?action=admin&moderation=changed" );
1228            return $output if $return_output;
1229            print $output;
1230        }
1231    } else {
1232        return %tt_vars if $return_tt_vars;
1233        my $output = $self->process_template(
1234                                                id       => $node,
1235                                                template => "moderate_confirm.tt",
1236                                                tt_vars  => \%tt_vars,
1237                                            );
1238        return $output if $return_output;
1239        print $output;
1240    }
1241}
1242
1243=item B<moderate_node>
1244
1245  $guide->moderate_node(
1246                         id       => "FAQ",
1247                         version  => 12,
1248                         password => "beer",
1249                     );
1250
1251Marks a version of a node as moderated. Will also auto-create and Locales
1252and Categories for the newly moderated version.
1253
1254If C<password> is not supplied then a form for entering the password
1255will be displayed.
1256=cut
1257sub moderate_node {
1258    my ($self, %args) = @_;
1259    my $node = $args{id} or croak "No node ID supplied for node moderation";
1260    my $version = $args{version} or croak "No node version supplied for node moderation";
1261    my $return_tt_vars = $args{return_tt_vars} || 0;
1262    my $return_output = $args{return_output} || 0;
1263
1264    # Set up the TT variables
1265    my %tt_vars = (
1266                      not_editable  => 1,
1267                      not_deletable => 1,
1268                      deter_robots  => 1,
1269                      version       => $version,
1270                      moderation_action => 'moderate_node',
1271                      moderation_url_args => 'action=moderate_node&version='.$version
1272                  );
1273
1274    my $password = $args{password};
1275
1276    if ($password) {
1277        if ($password ne $self->config->admin_pass) {
1278            return %tt_vars if $return_tt_vars;
1279            my $output = $self->process_template(
1280                                                    id       => $node,
1281                                                    template => "moderate_password_wrong.tt",
1282                                                    tt_vars  => \%tt_vars,
1283                                                );
1284            return $output if $return_output;
1285            print $output;
1286        } else {
1287            $self->wiki->moderate_node(
1288                                        name    => $node,
1289                                        version => $version
1290                                    );
1291
1292            # Create any categories or locales for it
1293            my %details = $self->wiki->retrieve_node(
1294                                        name    => $node,
1295                                        version => $version
1296                                    );
1297            $self->_autoCreateCategoryLocale(
1298                                          id       => $node,
1299                                          metadata => $details{'metadata'}
1300            );
1301
1302            # Send back to the admin interface
1303            my $script_url = $self->config->script_url;
1304            my $script_name = $self->config->script_name;
1305            my $q = CGI->new;
1306            my $output = $q->redirect( $script_url.$script_name."?action=admin&moderation=moderated" );
1307            return $output if $return_output;
1308            print $output;
1309        }
1310    } else {
1311        return %tt_vars if $return_tt_vars;
1312        my $output = $self->process_template(
1313                                                id       => $node,
1314                                                template => "moderate_confirm.tt",
1315                                                tt_vars  => \%tt_vars,
1316                                            );
1317        return $output if $return_output;
1318        print $output;
1319    }
1320}
1321
1322=item B<show_missing_metadata>
1323Search for nodes which don't have a certain kind of metadata. Optionally
1324also excludes Locales and Categories
1325=cut
1326sub show_missing_metadata {
1327    my ($self, %args) = @_;
1328    my $return_tt_vars = $args{return_tt_vars} || 0;
1329    my $return_output = $args{return_output} || 0;
1330
1331    my $wiki = $self->wiki;
1332    my $formatter = $self->wiki->formatter;
1333    my $script_url = $self->config->script_url;
1334
1335    my ($metadata_type, $metadata_value, $exclude_locales, $exclude_categories)
1336        = @args{ qw( metadata_type metadata_value exclude_locales exclude_categories ) };
1337
1338    my @nodes;
1339    my $done_search = 0;
1340
1341    # Only search if they supplied at least a metadata type
1342    if($metadata_type) {
1343        $done_search = 1;
1344        @nodes = $wiki->list_nodes_by_missing_metadata(
1345                            metadata_type => $metadata_type,
1346                            metadata_value => $metadata_value,
1347                            ignore_case    => 1,
1348        );
1349
1350        # Do we need to filter some nodes out?
1351        if($exclude_locales || $exclude_categories) {
1352            my @all_nodes = @nodes;
1353            @nodes = ();
1354
1355            foreach my $node (@all_nodes) {
1356                if($exclude_locales && $node =~ /^Locale /) { next; }
1357                if($exclude_categories && $node =~ /^Category /) { next; }
1358                push @nodes, $node;
1359            }
1360        }
1361    }
1362
1363    # Build nice edit etc links for our nodes
1364    my @tt_nodes;
1365    for my $node (@nodes) {
1366        my %n;
1367
1368        # Make the URLs
1369        my $node_param = uri_escape( $formatter->node_name_to_node_param( $node ) );
1370
1371        # Save into the hash
1372        $n{'name'} = $node;
1373        $n{'view_url'} = $script_url . "?id=" . $node_param;
1374        $n{'edit_url'} = $script_url . "?id=" . $node_param . ";action=edit";
1375        push @tt_nodes, \%n;
1376    }
1377
1378    # Set up our TT variables, including the search parameters
1379    my %tt_vars = (
1380                      not_editable  => 1,
1381                      not_deletable => 1,
1382                      deter_robots  => 1,
1383
1384                      nodes => \@tt_nodes,
1385                      done_search    => $done_search,
1386                      metadata_type  => $metadata_type,
1387                      metadata_value => $metadata_value,
1388                      exclude_locales => $exclude_locales,
1389                      exclude_categories => $exclude_categories
1390                  );
1391    return %tt_vars if $return_tt_vars;
1392
1393    # Render to the page
1394    my $output = $self->process_template(
1395                                           id       => "",
1396                                           template => "missing_metadata.tt",
1397                                           tt_vars  => \%tt_vars,
1398                                        );
1399    return $output if $return_output;
1400    print $output;
1401}
1402
1403=item B<display_admin_interface>
1404Fetch everything we need to display the admin interface, and passes it off
1405 to the template
1406=cut
1407sub display_admin_interface {
1408    my ($self, %args) = @_;
1409    my $return_tt_vars = $args{return_tt_vars} || 0;
1410    my $return_output = $args{return_output} || 0;
1411
1412    my $wiki = $self->wiki;
1413    my $formatter = $self->wiki->formatter;
1414    my $script_url = $self->config->script_url;
1415
1416    # Grab all the nodes
1417    my @all_nodes = $wiki->list_all_nodes(with_details=>1);
1418    @all_nodes = sort { $a->{'name'} cmp $b->{'name'} } @all_nodes;
1419
1420
1421    # Split into nodes, Locales and Categories
1422    my @nodes;
1423    my @categories;
1424    my @locales;
1425    for my $node (@all_nodes) {
1426        # Make the URLs
1427        my $node_param = uri_escape( $formatter->node_name_to_node_param( $node->{'name'} ) );
1428        $node->{'view_url'} = $script_url . "?id=" . $node_param;
1429        $node->{'versions_url'} = $script_url . "?action=list_all_versions;id=" . $node_param;
1430        $node->{'moderation_url'} = $script_url . "?action=set_moderation;id=" . $node_param;
1431
1432        # Filter
1433        if($node->{'name'} =~ /^Category /) {
1434            $node->{'page_name'} = $node->{'name'};
1435            $node->{'name'} =~ s/^Category //;
1436            push @categories, $node;
1437        } elsif($node->{'name'} =~ /^Locale /) {
1438            $node->{'page_name'} = $node->{'name'};
1439            $node->{'name'} =~ s/^Locale //;
1440            push @locales, $node;
1441        } else {
1442            push @nodes, $node;
1443        }
1444    }
1445
1446    # Render in a template
1447    my %tt_vars = (
1448                      not_editable  => 1,
1449                      not_deletable => 1,
1450                      deter_robots  => 1,
1451                      nodes => \@nodes,
1452                      categories => \@categories,
1453                      locales => \@locales
1454                  );
1455    return %tt_vars if $return_tt_vars;
1456    my $output = $self->process_template(
1457                                           id       => "",
1458                                           template => "admin_home.tt",
1459                                           tt_vars  => \%tt_vars,
1460                                        );
1461    return $output if $return_output;
1462    print $output;
1463}
1464
1465sub process_template {
1466    my ($self, %args) = @_;
1467    my %output_conf = (
1468                          wiki     => $self->wiki,
1469                          config   => $self->config,
1470                          node     => $args{id},
1471                          template => $args{template},
1472                          vars     => $args{tt_vars},
1473                          cookies  => $args{cookies},
1474                      );
1475    if ( $args{content_type} ) {
1476        $output_conf{content_type} = $args{content_type};
1477    }
1478    return OpenGuides::Template->output( %output_conf );
1479}
1480
1481sub redirect_to_node {
1482    my ($self, $node, $redirected_from) = @_;
1483   
1484    my $script_url = $self->config->script_url;
1485    my $script_name = $self->config->script_name;
1486    my $formatter = $self->wiki->formatter;
1487
1488    my $id = $formatter->node_name_to_node_param( $node );
1489    my $oldid;
1490    $oldid = $formatter->node_name_to_node_param( $redirected_from ) if $redirected_from;
1491
1492    my $redir_param = "$script_url$script_name?";
1493    $redir_param .= 'id=' if $oldid;
1494    $redir_param .= $id;
1495    $redir_param .= ";oldid=$oldid" if $oldid;
1496   
1497    my $q = CGI->new;
1498    return $q->redirect( $redir_param );
1499}
1500
1501sub get_cookie {
1502    my $self = shift;
1503    my $config = $self->config;
1504    my $pref_name = shift or return "";
1505    my %cookie_data = OpenGuides::CGI->get_prefs_from_cookie(config=>$config);
1506    return $cookie_data{$pref_name};
1507}
1508
1509
1510=head1 BUGS AND CAVEATS
1511
1512UTF8 data are currently not handled correctly throughout.
1513
1514Other bugs are documented at
1515L<http://dev.openguides.org/>
1516
1517=head1 SEE ALSO
1518
1519=over 4
1520
1521=item * L<http://london.openguides.org/|The Open Guide to London>, the first and biggest OpenGuides site.
1522
1523=item * L<http://openguides.org/|The OpenGuides website>, with a list of all live OpenGuides installs.
1524
1525=item * L<Wiki::Toolkit>, the Wiki toolkit which does the heavy lifting for OpenGuides
1526
1527=back
1528
1529=head1 FEEDBACK
1530
1531If you have a question, a bug report, or a patch, or you're interested
1532in joining the development team, please contact openguides-dev@openguides.org
1533(moderated mailing list, will reach all current developers but you'll have
1534to wait for your post to be approved) or file a bug report at
1535L<http://dev.openguides.org/>
1536
1537=head1 AUTHOR
1538
1539The OpenGuides Project (openguides-dev@openguides.org)
1540
1541=head1 COPYRIGHT
1542
1543     Copyright (C) 2003-2006 The OpenGuides Project.  All Rights Reserved.
1544
1545The OpenGuides distribution is free software; you can redistribute it
1546and/or modify it under the same terms as Perl itself.
1547
1548=head1 CREDITS
1549
1550Programming by Dominic Hargreaves, Earle Martin, Kake Pugh, and Ivor
1551Williams.  Testing and bug reporting by Billy Abbott, Jody Belka,
1552Kerry Bosworth, Simon Cozens, Cal Henderson, Steve Jolly, and Bob
1553Walker (among others).  Much of the Module::Build stuff copied from
1554the Siesta project L<http://siesta.unixbeard.net/>
1555
1556=cut
1557
15581;
Note: See TracBrowser for help on using the repository browser.