source: trunk/lib/OpenGuides.pm @ 790

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

Pass the requested feed listing through all the feeds code, rather than just assuming it's recent_changes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.6 KB
RevLine 
[83]1package OpenGuides;
2use strict;
3
[375]4use Carp "croak";
[363]5use CGI;
[785]6use Wiki::Toolkit::Plugin::Diff;
7use Wiki::Toolkit::Plugin::Locator::Grid;
[473]8use OpenGuides::CGI;
[753]9use OpenGuides::Feed;
[363]10use OpenGuides::Template;
11use OpenGuides::Utils;
[473]12use Time::Piece;
[379]13use URI::Escape;
[363]14
[83]15use vars qw( $VERSION );
16
[787]17$VERSION = '0.54_01';
[83]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
[363]32=head1 METHODS
33
34=over
35
36=item B<new>
37
[587]38  my $config = OpenGuides::Config->new( file => "wiki.conf" );
[363]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};
[587]50    my $geo_handler = $self->config->geo_handler;
[559]51    my $locator;
52    if ( $geo_handler == 1 ) {
[785]53        $locator = Wiki::Toolkit::Plugin::Locator::Grid->new(
[559]54                                             x => "os_x",    y => "os_y" );
55    } elsif ( $geo_handler == 2 ) {
[785]56        $locator = Wiki::Toolkit::Plugin::Locator::Grid->new(
[559]57                                             x => "osie_x",  y => "osie_y" );
58    } else {
[785]59        $locator = Wiki::Toolkit::Plugin::Locator::Grid->new(
[559]60                                             x => "easting", y => "northing" );
61    }
[369]62    $wiki->register_plugin( plugin => $locator );
[370]63    $self->{locator} = $locator;
[785]64    my $differ = Wiki::Toolkit::Plugin::Diff->new;
[370]65    $wiki->register_plugin( plugin => $differ );
66    $self->{differ} = $differ;
[363]67    return $self;
68}
69
70=item B<wiki>
71
[785]72An accessor, returns the underlying L<Wiki::Toolkit> object.
[363]73
74=cut
75
76sub wiki {
77    my $self = shift;
78    return $self->{wiki};
79}
80
81=item B<config>
82
[587]83An accessor, returns the underlying L<OpenGuides::Config> object.
[363]84
85=cut
86
87sub config {
88    my $self = shift;
89    return $self->{config};
90}
91
[369]92=item B<locator>
93
[785]94An accessor, returns the underlying L<Wiki::Toolkit::Plugin::Locator::UK> object.
[369]95
96=cut
97
98sub locator {
99    my $self = shift;
100    return $self->{locator};
101}
102
[370]103=item B<differ>
104
[785]105An accessor, returns the underlying L<Wiki::Toolkit::Plugin::Diff> object.
[370]106
107=cut
108
109sub differ {
110    my $self = shift;
111    return $self->{differ};
112}
113
[363]114=item B<display_node>
115
[364]116  # Print node to STDOUT.
[363]117  $guide->display_node(
[681]118                          id      => "Calthorpe Arms",
119                          version => 2,
[363]120                      );
121
[364]122  # Or return output as a string (useful for writing tests).
123  $guide->display_node(
[681]124                          id            => "Calthorpe Arms",
125                          return_output => 1,
[364]126                      );
[363]127
[385]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(
[681]131                          id             => "Calthorpe Arms",
132                          return_tt_vars => 1,
[385]133                      );
134
[364]135If C<version> is omitted then the latest version will be displayed.
136
[363]137=cut
138
139sub display_node {
140    my ($self, %args) = @_;
141    my $return_output = $args{return_output} || 0;
142    my $version = $args{version};
[587]143    my $id = $args{id} || $self->config->home_name;
[363]144    my $wiki = $self->wiki;
145    my $config = $self->config;
[634]146    my $oldid = $args{oldid} || '';
[678]147    my $do_redirect = $args{redirect} || 1;
[363]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;
[522]156        $tt_vars{"rss_".lc($type)."_url"} =
[700]157                           $config->script_name . "?action=rc;format=rss;"
[490]158                           . lc($type) . "=" . lc(CGI->escape($2));
[784]159        $tt_vars{"atom_".lc($type)."_url"} =
160                           $config->script_name . "?action=rc;format=atom;"
161                           . lc($type) . "=" . lc(CGI->escape($2));
[363]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 );
[678]168    $criteria{version} = $version if $version; # retrieve_node default is current
[363]169
170    my %node_data = $wiki->retrieve_node( %criteria );
[652]171
[707]172    # Fixes passing undefined values to Text::Wikiformat if node doesn't exist.
173    my $raw        = $node_data{content} || " ";
[363]174    my $content    = $wiki->format($raw);
175    my $modified   = $node_data{last_modified};
176    my %metadata   = %{$node_data{metadata}};
177
[730]178    my ($wgs84_long, $wgs84_lat) = OpenGuides::Utils->get_wgs84_coords(
179                                        longitude => $metadata{longitude}[0],
180                                        latitude => $metadata{latitude}[0],
181                                        config => $config);
[687]182    if ($args{format} && $args{format} eq 'raw') {
183      print "Content-Type: text/plain\n\n";
184      print $raw;
[752]185      return 0;
[687]186    }
187   
[363]188    my %metadata_vars = OpenGuides::Template->extract_metadata_vars(
189                            wiki     => $wiki,
[678]190                            config   => $config,
[681]191                            metadata => $node_data{metadata}
192                        );
[363]193
194    %tt_vars = (
[681]195                   %tt_vars,
196                   %metadata_vars,
197                   content       => $content,
198                   last_modified => $modified,
199                   version       => $node_data{version},
200                   node          => $id,
201                   language      => $config->default_language,
202                   oldid         => $oldid,
[730]203                   enable_gmaps  => 1,
204                   display_google_maps => $self->get_cookie("display_google_maps"),
205                   wgs84_long    => $wgs84_long,
206                   wgs84_lat     => $wgs84_lat
[363]207               );
208
[678]209    if ( $raw =~ /^#REDIRECT\s+(.+?)\s*$/ ) {
210        my $redirect = $1;
211        # Strip off enclosing [[ ]] in case this is an extended link.
212        $redirect =~ s/^\[\[//;
213        $redirect =~ s/\]\]\s*$//;
214
215        # Don't redirect if the parameter "redirect" is given as 0.
216        if ($do_redirect == 0) {
217            return %tt_vars if $args{return_tt_vars};
218            $tt_vars{current} = 1;
219            my $output = $self->process_template(
220                                                  id            => $id,
221                                                  template      => "node.tt",
222                                                  tt_vars       => \%tt_vars,
223                                                );
224            return $output if $return_output;
225            print $output;
226        } elsif ( $wiki->node_exists($redirect) && $redirect ne $id && $redirect ne $oldid ) {
227            # Avoid loops by not generating redirects to the same node or the previous node.
228            my $output = $self->redirect_to_node($redirect, $id);
229            return $output if $return_output;
230            print $output;
[752]231            return 0;
[678]232        }
233    }
234
[363]235    # We've undef'ed $version above if this is the current version.
236    $tt_vars{current} = 1 unless $version;
237
238    if ($id eq "RecentChanges") {
[700]239        $self->display_recent_changes(%args);
[587]240    } elsif ( $id eq $self->config->home_name ) {
[363]241        my @recent = $wiki->list_recent_changes(
242            last_n_changes => 10,
243            metadata_was   => { edit_type => "Normal edit" },
244        );
[681]245        @recent = map {
246                          {
247                              name          => CGI->escapeHTML($_->{name}),
248                              last_modified => CGI->escapeHTML($_->{last_modified}),
249                              version       => CGI->escapeHTML($_->{version}),
250                              comment       => CGI->escapeHTML($_->{metadata}{comment}[0]),
251                              username      => CGI->escapeHTML($_->{metadata}{username}[0]),
252                              url           => $config->script_name . "?"
253                                               . CGI->escape($wiki->formatter->node_name_to_node_param($_->{name}))
254                          }
255                      } @recent;
[363]256        $tt_vars{recent_changes} = \@recent;
[385]257        return %tt_vars if $args{return_tt_vars};
[363]258        my $output = $self->process_template(
[681]259                                                id            => $id,
260                                                template      => "home_node.tt",
261                                                tt_vars       => \%tt_vars,
[363]262                                            );
263        return $output if $return_output;
264        print $output;
265    } else {
[385]266        return %tt_vars if $args{return_tt_vars};
[363]267        my $output = $self->process_template(
[681]268                                                id            => $id,
269                                                template      => "node.tt",
270                                                tt_vars       => \%tt_vars,
[363]271                                            );
272        return $output if $return_output;
273        print $output;
274    }
275}
276
[700]277=item B<display_recent_changes> 
278
279  $guide->display_recent_changes;
280
281As with other methods, the C<return_output> parameter can be used to
282return the output instead of printing it to STDOUT.
283
284=cut
285
286sub display_recent_changes {
287    my ($self, %args) = @_;
288    my $config = $self->config;
289    my $wiki = $self->wiki;
290    my $minor_edits = $self->get_cookie( "show_minor_edits_in_rc" );
291    my $id = $args{id} || $self->config->home_name;
292    my $return_output = $args{return_output} || 0;
293    my (%tt_vars, %recent_changes);
294    my $q = CGI->new;
295    my $since = $q->param("since");
296    if ( $since ) {
297        $tt_vars{since} = $since;
298        my $t = localtime($since); # overloaded by Time::Piece
299        $tt_vars{since_string} = $t->strftime;
300        my %criteria = ( since => $since );   
301        $criteria{metadata_was} = { edit_type => "Normal edit" }
302          unless $minor_edits;
303        my @rc = $self->{wiki}->list_recent_changes( %criteria );
304 
305        @rc = map {
306            {
307              name        => CGI->escapeHTML($_->{name}),
308              last_modified => CGI->escapeHTML($_->{last_modified}),
309              version     => CGI->escapeHTML($_->{version}),
310              comment     => CGI->escapeHTML($_->{metadata}{comment}[0]),
311              username    => CGI->escapeHTML($_->{metadata}{username}[0]),
312              host        => CGI->escapeHTML($_->{metadata}{host}[0]),
313              username_param => CGI->escape($_->{metadata}{username}[0]),
314              edit_type   => CGI->escapeHTML($_->{metadata}{edit_type}[0]),
315              url         => $config->script_name . "?"
316      . CGI->escape($wiki->formatter->node_name_to_node_param($_->{name})),
317        }
318                   } @rc;
319        if ( scalar @rc ) {
320            $recent_changes{since} = \@rc; 
321        }
322    } else {
323        for my $days ( [0, 1], [1, 7], [7, 14], [14, 30] ) {
324            my %criteria = ( between_days => $days );
325            $criteria{metadata_was} = { edit_type => "Normal edit" }
326              unless $minor_edits;
327            my @rc = $self->{wiki}->list_recent_changes( %criteria );
328
329            @rc = map {
330            {
331              name        => CGI->escapeHTML($_->{name}),
332              last_modified => CGI->escapeHTML($_->{last_modified}),
333              version     => CGI->escapeHTML($_->{version}),
334              comment     => CGI->escapeHTML($_->{metadata}{comment}[0]),
335              username    => CGI->escapeHTML($_->{metadata}{username}[0]),
336              host        => CGI->escapeHTML($_->{metadata}{host}[0]),
337              username_param => CGI->escape($_->{metadata}{username}[0]),
338              edit_type   => CGI->escapeHTML($_->{metadata}{edit_type}[0]),
339              url         => $config->script_name . "?"
340      . CGI->escape($wiki->formatter->node_name_to_node_param($_->{name})),
341        }
342                       } @rc;
343            if ( scalar @rc ) {
344                $recent_changes{$days->[1]} = \@rc;
345        }
346        }
347    }
348    $tt_vars{recent_changes} = \%recent_changes;
349    my %processing_args = (
350                            id            => $id,
351                            template      => "recent_changes.tt",
352                            tt_vars       => \%tt_vars,
353                           );
354    if ( !$since && $self->get_cookie("track_recent_changes_views") ) {
355    my $cookie =
356           OpenGuides::CGI->make_recent_changes_cookie(config => $config );
357        $processing_args{cookies} = $cookie;
358        $tt_vars{last_viewed} = OpenGuides::CGI->get_last_recent_changes_visit_from_cookie( config => $config );
359    }
360    return %tt_vars if $args{return_tt_vars};
361    my $output = $self->process_template( %processing_args );
362    return $output if $return_output;
363    print $output;
364}
365
[370]366=item B<display_diffs>
367
368  $guide->display_diffs(
[681]369                           id            => "Home Page",
370                           version       => 6,
371                           other_version => 5,
[370]372                       );
373
[376]374  # Or return output as a string (useful for writing tests).
375  my $output = $guide->display_diffs(
[681]376                                        id            => "Home Page",
377                                        version       => 6,
378                                        other_version => 5,
379                                        return_output => 1,
[376]380                                    );
381
382  # Or return the hash of variables that will be passed to the template
383  # (not including those set additionally by OpenGuides::Template).
384  my %vars = $guide->display_diffs(
[681]385                                      id             => "Home Page",
386                                      version        => 6,
387                                      other_version  => 5,
388                                      return_tt_vars => 1,
[376]389                                  );
390
[370]391=cut
392
393sub display_diffs {
394    my ($self, %args) = @_;
395    my %diff_vars = $self->differ->differences(
[681]396                                                  node          => $args{id},
397                                                  left_version  => $args{version},
398                                                  right_version => $args{other_version},
[370]399                                              );
[475]400    $diff_vars{not_deletable} = 1;
[681]401    $diff_vars{not_editable}  = 1;
402    $diff_vars{deter_robots}  = 1;
[376]403    return %diff_vars if $args{return_tt_vars};
404    my $output = $self->process_template(
[681]405                                            id       => $args{id},
406                                            template => "differences.tt",
407                                            tt_vars  => \%diff_vars
[376]408                                        );
409    return $output if $args{return_output};
410    print $output;
[370]411}
412
[372]413=item B<find_within_distance>
414
415  $guide->find_within_distance(
[681]416                                  id => $node,
417                                  metres => $q->param("distance_in_metres")
[372]418                              );
419
420=cut
421
422sub find_within_distance {
423    my ($self, %args) = @_;
[400]424    my $node = $args{id};
[372]425    my $metres = $args{metres};
[524]426    my %data = $self->wiki->retrieve_node( $node );
427    my $lat = $data{metadata}{latitude}[0];
428    my $long = $data{metadata}{longitude}[0];
[587]429    my $script_url = $self->config->script_url;
[735]430    my $q = CGI->new;
431    print $q->redirect( $script_url . "search.cgi?lat=$lat;long=$long;distance_in_metres=$metres" );
[372]432}
433
[563]434=item B<show_backlinks>
435
436  $guide->show_backlinks( id => "Calthorpe Arms" );
437
438As with other methods, parameters C<return_tt_vars> and
439C<return_output> can be used to return these things instead of
440printing the output to STDOUT.
441
442=cut
443
444sub show_backlinks {
445    my ($self, %args) = @_;
446    my $wiki = $self->wiki;
447    my $formatter = $wiki->formatter;
448
449    my @backlinks = $wiki->list_backlinks( node => $args{id} );
450    my @results = map {
[681]451                          {
452                              url   => CGI->escape($formatter->node_name_to_node_param($_)),
453                              title => CGI->escapeHTML($_)
454                          }
455                      } sort @backlinks;
[563]456    my %tt_vars = ( results       => \@results,
457                    num_results   => scalar @results,
458                    not_deletable => 1,
459                    deter_robots  => 1,
460                    not_editable  => 1 );
461    return %tt_vars if $args{return_tt_vars};
462    my $output = OpenGuides::Template->output(
[681]463                                                 node    => $args{id},
464                                                 wiki    => $wiki,
465                                                 config  => $self->config,
466                                                 template=>"backlink_results.tt",
467                                                 vars    => \%tt_vars,
[563]468                                             );
469    return $output if $args{return_output};
470    print $output;
471}
472
[373]473=item B<show_index>
474
475  $guide->show_index(
[681]476                        type   => "category",
477                        value  => "pubs",
[373]478                    );
479
480  # RDF version.
481  $guide->show_index(
[681]482                        type   => "locale",
483                        value  => "Holborn",
484                        format => "rdf",
[373]485                    );
486
[379]487  # Or return output as a string (useful for writing tests).
488  $guide->show_index(
[681]489                        type          => "category",
490                        value         => "pubs",
491                        return_output => 1,
[379]492                    );
493
[373]494=cut
495
496sub show_index {
497    my ($self, %args) = @_;
498    my $wiki = $self->wiki;
499    my $formatter = $wiki->formatter;
500    my %tt_vars;
501    my @selnodes;
502
503    if ( $args{type} and $args{value} ) {
504        if ( $args{type} eq "fuzzy_title_match" ) {
505            my %finds = $wiki->fuzzy_title_match( $args{value} );
506            @selnodes = sort { $finds{$a} <=> $finds{$b} } keys %finds;
507            $tt_vars{criterion} = {
508                type  => $args{type},  # for RDF version
509                value => $args{value}, # for RDF version
[575]510                name  => CGI->escapeHTML("Fuzzy Title Match on '$args{value}'")
[681]511            };
512            $tt_vars{not_editable} = 1;
[373]513        } else {
514            @selnodes = $wiki->list_nodes_by_metadata(
515                metadata_type  => $args{type},
[681]516                metadata_value => $args{value},
[575]517                ignore_case    => 1
[373]518            );
[681]519            my $name = ucfirst($args{type}) . " $args{value}";
[587]520            my $url = $self->config->script_name
[393]521                      . "?"
[373]522                      . ucfirst( $args{type} )
523                      . "_"
524                      . uri_escape(
[681]525                                      $formatter->node_name_to_node_param($args{value})
[373]526                                  );
527            $tt_vars{criterion} = {
528                type  => $args{type},
529                value => $args{value}, # for RDF version
[375]530                name  => CGI->escapeHTML( $name ),
[681]531                url   => $url
[373]532            };
[681]533            $tt_vars{not_editable} = 1;
[373]534        }
535    } else {
536        @selnodes = $wiki->list_all_nodes();
537    }
538
[681]539    my @nodes = map {
540                        {
541                            name      => $_,
542                            node_data => { $wiki->retrieve_node( name => $_ ) },
543                            param     => $formatter->node_name_to_node_param($_) }
544                        } sort @selnodes;
[373]545
546    $tt_vars{nodes} = \@nodes;
547
548    my ($template, %conf);
549
[681]550    if ( $args{format} ) {
551        if ( $args{format} eq "rdf" ) {
552            $template = "rdf_index.tt";
[718]553            $conf{content_type} = "application/rdf+xml";
[681]554        }
555        elsif ( $args{format} eq "plain" ) {
556            $template = "plain_index.tt";
557            $conf{content_type} = "text/plain";
[730]558        } elsif ( $args{format} eq "map" ) {
559            my $q = CGI->new;
560            $tt_vars{zoom} = $q->param('zoom') || '';
561            $tt_vars{lat} = $q->param('lat') || '';
562            $tt_vars{long} = $q->param('long') || '';
563            $tt_vars{centre_long} = $self->config->centre_long;
564            $tt_vars{centre_lat} = $self->config->centre_lat;
565            $tt_vars{default_gmaps_zoom} = $self->config->default_gmaps_zoom;
566            $tt_vars{enable_gmaps} = 1;
567            $tt_vars{display_google_maps} = 1; # override for this page
568            $template = "map_index.tt";
569           
[681]570        }
571    } else {
572        $template = "site_index.tt";
[373]573    }
574
575    %conf = (
[681]576                %conf,
577                node        => "$args{type} index", # KLUDGE
578                template    => $template,
579                tt_vars     => \%tt_vars,
580            );
[373]581
[379]582    my $output = $self->process_template( %conf );
583    return $output if $args{return_output};
584    print $output;
[373]585}
586
[374]587=item B<list_all_versions>
[373]588
[374]589  $guide->list_all_versions ( id => "Home Page" );
[373]590
[440]591  # Or return output as a string (useful for writing tests).
592  $guide->list_all_versions (
[681]593                                id            => "Home Page",
594                                return_output => 1,
[440]595                            );
596
597  # Or return the hash of variables that will be passed to the template
598  # (not including those set additionally by OpenGuides::Template).
599  $guide->list_all_versions (
[681]600                                id             => "Home Page",
601                                return_tt_vars => 1,
[440]602                            );
603
[374]604=cut
605
606sub list_all_versions {
607    my ($self, %args) = @_;
[440]608    my $return_output = $args{return_output} || 0;
[374]609    my $node = $args{id};
610    my %curr_data = $self->wiki->retrieve_node($node);
611    my $curr_version = $curr_data{version};
612    my @history;
613    for my $version ( 1 .. $curr_version ) {
614        my %node_data = $self->wiki->retrieve_node( name    => $node,
[681]615                                                    version => $version );
[429]616        # $node_data{version} will be zero if this version was deleted.
[681]617        push @history, {
[440]618            version  => CGI->escapeHTML( $version ),
[681]619            modified => CGI->escapeHTML( $node_data{last_modified} ),
[440]620            username => CGI->escapeHTML( $node_data{metadata}{username}[0] ),
621            comment  => CGI->escapeHTML( $node_data{metadata}{comment}[0] ),
[429]622                       } if $node_data{version};
[374]623    }
624    @history = reverse @history;
[681]625    my %tt_vars = (
626                      node          => $node,
627                      version       => $curr_version,
628                      not_deletable => 1,
629                      not_editable  => 1,
630                      deter_robots  => 1,
631                      history       => \@history
632                  );
[440]633    return %tt_vars if $args{return_tt_vars};
634    my $output = $self->process_template(
[681]635                                            id       => $node,
636                                            template => "node_history.tt",
637                                            tt_vars  => \%tt_vars,
[440]638                                        );
639    return $output if $return_output;
640    print $output;
[374]641}
642
[753]643=item B<display_feed>
[550]644
[753]645  # Last ten non-minor edits to Hammersmith pages in RSS 1.0 format
646  $guide->display_feed(
647                         feed_type          => 'rss',
[790]648                         feed_listing       => 'recent_changes',
[681]649                         items              => 10,
650                         ignore_minor_edits => 1,
651                         locale             => "Hammersmith",
[550]652                     );
653
[784]654  # All edits bob has made to pub pages in the last week in Atom format
655  $guide->display_feed(
[790]656                         feed_type    => 'atom',
657                         feed_listing => 'recent_changes',
658                         days         => 7,
659                         username     => "bob",
660                         category     => "Pubs",
[784]661                     );
662
[753]663C<feed_type> is a mandatory parameter. Supported values at present are
[784]664"rss" and "atom".
[753]665
[790]666C<feed_listing> is a mandatory parameter. Supported values at present
667are "recent_changes". (More values are coming soon though!)
668
[550]669As with other methods, the C<return_output> parameter can be used to
670return the output instead of printing it to STDOUT.
671
672=cut
673
[753]674sub display_feed {
[550]675    my ($self, %args) = @_;
[556]676
[753]677    my $feed_type = $args{feed_type};
678    croak "No feed type given" unless $feed_type;
[790]679
680    my $feed_listing = $args{feed_listing};
681    croak "No feed listing given" unless $feed_listing;
[753]682   
[550]683    my $return_output = $args{return_output} ? 1 : 0;
684
685    my $items = $args{items} || "";
686    my $days  = $args{days}  || "";
687    my $ignore_minor_edits = $args{ignore_minor_edits} ? 1 : 0;
688    my $username = $args{username} || "";
689    my $category = $args{category} || "";
690    my $locale   = $args{locale}   || "";
691    my %criteria = (
[681]692                       items              => $items,
693                       days               => $days,
694                       ignore_minor_edits => $ignore_minor_edits,
[753]695                       feed_type          => $feed_type,
[790]696                       feed_listing       => $feed_listing,
[550]697                   );
698    my %filter;
699    $filter{username} = $username if $username;
700    $filter{category} = $category if $category;
701    $filter{locale}   = $locale   if $locale;
702    if ( scalar keys %filter ) {
703        $criteria{filter_on_metadata} = \%filter;
704    }
705
[753]706    my $feed = OpenGuides::Feed->new(
707                                        wiki       => $self->wiki,
708                                        config     => $self->config,
709                                        og_version => $VERSION,
710                                    );
711
712    my $output;
713   
714    if ($feed_type eq 'rss') {
715        $output = "Content-Type: application/rdf+xml\n";
[784]716    }
717    elsif ($feed_type eq 'atom') {
718        $output = "Content-Type: application/atom+xml\n";
719    }
720    else {
[753]721        croak "Unknown feed type given: $feed_type";
722    }
723   
724    $output .= "Last-Modified: " . $feed->feed_timestamp( %criteria ) . "\n\n";
725
726    $output .= $feed->make_feed( %criteria );
727
[550]728    return $output if $return_output;
729    print $output;
730}
731
[758]732sub display_about {
733    my ($self, %args) = @_;
734
735    my $output;
736
737    if ($args{format} && $args{format} =~ /^rdf$/i) {
738        $output = qq{Content-Type: application/rdf+xml
739
740<?xml version="1.0" encoding="UTF-8"?>
741<rdf:RDF xmlns      = "http://usefulinc.com/ns/doap#"
742         xmlns:rdf  = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
743         xmlns:foaf = "http://xmlns.com/foaf/0.1/">
744<Project rdf:ID="OpenGuides">
745  <name>OpenGuides</name>
746
747  <created>2003-04-29</created>
748 
749  <shortdesc xml:lang="en">
750    A wiki engine for collaborative description of places with specialised
751    geodata metadata features.
752  </shortdesc>
753
754  <description xml:lang="en">
755    OpenGuides is a collaborative wiki environment, written in Perl, for
756    building guides and sharing information, as both human-readable text
757    and RDF. The engine contains a number of geodata-specific metadata
758    mechanisms such as locale search, node classification and integration
759    with Google Maps.
760  </description>
761
762  <homepage rdf:resource="http://openguides.org/" />
763  <mailing-list rdf:resource="http://openguides.org/mm/listinfo/openguides-dev/" />
764  <mailing-list rdf:resource="http://urchin.earth.li/mailman/listinfo/openguides-commits/" />
765
766  <maintainer>
[765]767    <foaf:Person rdf:ID="OpenGuidesMaintainer">
[758]768      <foaf:name>Dominic Hargreaves</foaf:name>
769      <foaf:homepage rdf:resource="http://www.larted.org.uk/~dom/" />
770    </foaf:Person>
771  </maintainer>
772
773  <repository>
[765]774    <SVNRepository rdf:ID="OpenGuidesSVN">
[758]775      <location rdf:resource="https://urchin.earth.li/svn/openguides/" />
776      <browse rdf:resource="http://dev.openguides.org/browser" />
777    </SVNRepository>
778  </repository>
779
780  <release>
[765]781    <Version rdf:ID="OpenGuidesVersion">
[758]782      <revision>$VERSION</revision>
783    </Version>
784  </release>
785
786  <download-page rdf:resource="http://search.cpan.org/dist/OpenGuides/" />
787 
788  <!-- Freshmeat category: Internet :: WWW/HTTP :: Dynamic Content -->
789  <category rdf:resource="http://freshmeat.net/browse/92/" />
790 
791  <license rdf:resource="http://www.opensource.org/licenses/gpl-license.php" />
792  <license rdf:resource="http://www.opensource.org/licenses/artistic-license.php" />
793
794</Project>
795
796</rdf:RDF>};
797    }
798    else {
799        my $site_name  = $self->config->{site_name};
[778]800        my $script_name = $self->config->{script_name};
[758]801        $output = qq{Content-Type: text/html; charset=utf-8
802
803<html>
804<head>
805  <title>About $site_name</title>
806<style type="text/css">
807body        { margin: 0px; }
808#content    { padding: 50px; margin: auto; width: 50%; }
809h1          { margin-bottom: 0px; font-style: italic; }
810h2          { margin-top: 0px; }
811#logo       { text-align: center; }
812#logo a img { border: 1px solid #000; }
813#about      { margin: 0em 0em 1em 0em; border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; }
814#meta       { font-size: small; text-align: center;}
815</style>
816<link rel="alternate"
817  type="application/rdf+xml"
818  title="DOAP (Description Of A Project) profile for this site's software"
[778]819  href="$script_name?action=about;format=rdf" />
[758]820</head>
821<body>
822<div id="content">
823<div id="logo">
824<a href="http://openguides.org/"><img
825src="http://openguides.org/img/logo.jpg" alt="OpenGuides.org"></a>
[778]826<h1><a href="$script_name">$site_name</a></h1>
[758]827<h2>is powered by <a href="http://openguides.org/">OpenGuides</a> -<br>
828the guides built by you.</h2>
829<h3>version <a href="http://search.cpan.org/~dom/OpenGuides-$VERSION">$VERSION</a></h3>
830</div>
831<div id="about">
832<p>
833<a href="http://www.w3.org/RDF/"><img
834src="http://openguides.org/img/rdf_icon.png" width="44" height="48"
835style="float: right; margin-left: 10px; border: 0px"></a> OpenGuides is a
836web-based collaborative <a href="http://wiki.org/wiki.cgi?WhatIsWiki">wiki</a>
837environment for building guides and sharing information, as both
838human-readable text and <a href="http://www.w3.org/RDF/"><acronym
839title="Resource Description Framework">RDF</acronym></a>. The engine contains
840a number of geodata-specific metadata mechanisms such as locale search, node
841classification and integration with <a href="http://maps.google.com/">Google
842Maps</a>.
843</p>
844<p>
845OpenGuides is written in <a href="http://www.perl.org/">Perl</a>, and is
846made available under the same license as Perl itself (dual <a
847href="http://dev.perl.org/licenses/artistic.html" title='The "Artistic Licence"'>Artistic</a> and <a
848href="http://www.opensource.org/licenses/gpl-license.php"><acronym
849title="GNU Public Licence">GPL</acronym></a>). Developer information for the
850project is available from the <a href="http://dev.openguides.org/">OpenGuides
851development site</a>.
852</p>
853<p>
854Copyright &copy;2003-2006, <a href="http://openguides.org/">The OpenGuides
855Project</a>. "OpenGuides", "[The] Open Guide To..." and "The guides built by
856you" are trademarks of The OpenGuides Project. Any uses on this site are made
857with permission.
858</p>
859</div>
860<div id="meta">
[778]861<a href="$script_name?action=about;format=rdf"><acronym
[758]862title="Description Of A Project">DOAP</acronym> RDF version of this
863information</a>
864</div>
865</div>
866</body>
867</html>};
868    }
869   
870    return $output if $args{return_output};
871    print $output;
872}
873
[466]874=item B<commit_node>
875
876  $guide->commit_node(
[681]877                         id      => $node,
878                         cgi_obj => $q,
[466]879                     );
880
881As with other methods, parameters C<return_tt_vars> and
882C<return_output> can be used to return these things instead of
883printing the output to STDOUT.
884
[559]885The geographical data that you should provide in the L<CGI> object
886depends on the handler you chose in C<wiki.conf>.
887
888=over
889
890=item *
891
892B<British National Grid> - provide either C<os_x> and C<os_y> or
893C<latitude> and C<longitude>; whichever set of data you give, it will
894be converted to the other and both sets will be stored.
895
896=item *
897
898B<Irish National Grid> - provide either C<osie_x> and C<osie_y> or
899C<latitude> and C<longitude>; whichever set of data you give, it will
900be converted to the other and both sets will be stored.
901
902=item *
903
904B<UTM ellipsoid> - provide C<latitude> and C<longitude>; these will be
905converted to easting and northing and both sets of data will be stored.
906
907=back
908
[466]909=cut
910
911sub commit_node {
912    my ($self, %args) = @_;
913    my $node = $args{id};
914    my $q = $args{cgi_obj};
[547]915    my $return_output = $args{return_output};
[466]916    my $wiki = $self->wiki;
917    my $config = $self->config;
918
919    my $content  = $q->param("content");
920    $content =~ s/\r\n/\n/gs;
921    my $checksum = $q->param("checksum");
922
923    my %metadata = OpenGuides::Template->extract_metadata_vars(
924        wiki    => $wiki,
925        config  => $config,
[676]926    cgi_obj => $q
[466]927    );
928
[728]929    delete $metadata{website} if $metadata{website} eq 'http://';
930
[466]931    $metadata{opening_hours_text} = $q->param("hours_text") || "";
932
[547]933    # Pick out the unmunged versions of lat/long if they're set.
934    # (If they're not, it means they weren't munged in the first place.)
935    $metadata{latitude} = delete $metadata{latitude_unmunged}
936        if $metadata{latitude_unmunged};
937    $metadata{longitude} = delete $metadata{longitude_unmunged}
938        if $metadata{longitude_unmunged};
939
[466]940    # Check to make sure all the indexable nodes are created
941    foreach my $type (qw(Category Locale)) {
942        my $lctype = lc($type);
943        foreach my $index (@{$metadata{$lctype}}) {
[681]944            $index =~ s/(.*)/\u$1/;
945            my $node = $type . " " . $index;
946            # Uppercase the node name before checking for existence
947            $node =~ s/ (\S+)/ \u$1/g;
948            unless ( $wiki->node_exists($node) ) {
949                my $category = $type eq "Category" ? "Category" : "Locales";
950                $wiki->write_node(
951                                     $node,
952                                     "\@INDEX_LINK [[$node]]",
953                                     undef,
954                                     {
955                                         username => "Auto Create",
956                                         comment  => "Auto created $lctype stub page",
957                                         category => $category
958                                     }
959                                 );
960            }
[676]961        }
[466]962    }
[676]963   
[683]964    foreach my $var ( qw( summary username comment edit_type ) ) {
[466]965        $metadata{$var} = $q->param($var) || "";
966    }
967    $metadata{host} = $ENV{REMOTE_ADDR};
968
[785]969    # Wiki::Toolkit::Plugin::RSS::ModWiki wants "major_change" to be set.
[483]970    $metadata{major_change} = ( $metadata{edit_type} eq "Normal edit" )
971                            ? 1
972                            : 0;
973
[466]974    my $written = $wiki->write_node($node, $content, $checksum, \%metadata );
975
976    if ($written) {
[547]977        my $output = $self->redirect_to_node($node);
978        return $output if $return_output;
979        print $output;
[466]980    } else {
981        my %node_data = $wiki->retrieve_node($node);
982        my %tt_vars = ( checksum       => $node_data{checksum},
983                        new_content    => $content,
984                        stored_content => $node_data{content} );
985        foreach my $mdvar ( keys %metadata ) {
986            if ($mdvar eq "locales") {
987                $tt_vars{"stored_$mdvar"} = $node_data{metadata}{locale};
988                $tt_vars{"new_$mdvar"}    = $metadata{locale};
989            } elsif ($mdvar eq "categories") {
990                $tt_vars{"stored_$mdvar"} = $node_data{metadata}{category};
991                $tt_vars{"new_$mdvar"}    = $metadata{category};
992            } elsif ($mdvar eq "username" or $mdvar eq "comment"
993                      or $mdvar eq "edit_type" ) {
994                $tt_vars{$mdvar} = $metadata{$mdvar};
995            } else {
996                $tt_vars{"stored_$mdvar"} = $node_data{metadata}{$mdvar}[0];
997                $tt_vars{"new_$mdvar"}    = $metadata{$mdvar};
998            }
999        }
1000        return %tt_vars if $args{return_tt_vars};
1001        my $output = $self->process_template(
1002                                              id       => $node,
1003                                              template => "edit_conflict.tt",
1004                                              tt_vars  => \%tt_vars,
1005                                            );
1006        return $output if $args{return_output};
1007        print $output;
1008    }
1009}
1010
1011
[429]1012=item B<delete_node>
1013
1014  $guide->delete_node(
[681]1015                         id       => "FAQ",
1016                         version  => 15,
1017                         password => "beer",
[429]1018                     );
1019
1020C<version> is optional - if it isn't supplied then all versions of the
1021node will be deleted; in other words the node will be entirely
1022removed.
1023
1024If C<password> is not supplied then a form for entering the password
1025will be displayed.
1026
[564]1027As with other methods, parameters C<return_tt_vars> and
1028C<return_output> can be used to return these things instead of
1029printing the output to STDOUT.
1030
[429]1031=cut
1032
1033sub delete_node {
1034    my ($self, %args) = @_;
1035    my $node = $args{id} or croak "No node ID supplied for deletion";
[564]1036    my $return_tt_vars = $args{return_tt_vars} || 0;
1037    my $return_output = $args{return_output} || 0;
[429]1038
1039    my %tt_vars = (
[681]1040                      not_editable  => 1,
1041                      not_deletable => 1,
1042                      deter_robots  => 1,
[429]1043                  );
1044    $tt_vars{delete_version} = $args{version} || "";
1045
1046    my $password = $args{password};
1047
1048    if ($password) {
[587]1049        if ($password ne $self->config->admin_pass) {
[564]1050            return %tt_vars if $return_tt_vars;
1051            my $output = $self->process_template(
[681]1052                                                    id       => $node,
1053                                                    template => "delete_password_wrong.tt",
1054                                                    tt_vars  => \%tt_vars,
1055                                                );
[564]1056            return $output if $return_output;
1057            print $output;
[429]1058        } else {
1059            $self->wiki->delete_node(
[681]1060                                        name    => $node,
1061                                        version => $args{version},
[429]1062                                    );
1063            # Check whether any versions of this node remain.
1064            my %check = $self->wiki->retrieve_node( name => $node );
1065            $tt_vars{other_versions_remain} = 1 if $check{version};
[564]1066            return %tt_vars if $return_tt_vars;
1067            my $output = $self->process_template(
[681]1068                                                    id       => $node,
1069                                                    template => "delete_done.tt",
1070                                                    tt_vars  => \%tt_vars,
1071                                                );
[564]1072            return $output if $return_output;
1073            print $output;
[429]1074        }
1075    } else {
[564]1076        return %tt_vars if $return_tt_vars;
1077        my $output = $self->process_template(
[681]1078                                                id       => $node,
1079                                                template => "delete_confirm.tt",
1080                                                tt_vars  => \%tt_vars,
1081                                            );
[564]1082        return $output if $return_output;
1083        print $output;
[429]1084    }
1085}
1086
[363]1087sub process_template {
1088    my ($self, %args) = @_;
[678]1089    my %output_conf = (
[681]1090                          wiki     => $self->wiki,
1091                          config   => $self->config,
1092                          node     => $args{id},
1093                          template => $args{template},
1094                          vars     => $args{tt_vars},
1095                          cookies  => $args{cookies},
1096                      );
[380]1097    if ( $args{content_type} ) {
[718]1098        $output_conf{content_type} = $args{content_type};
[380]1099    }
[718]1100    return OpenGuides::Template->output( %output_conf );
[363]1101}
1102
[392]1103sub redirect_to_node {
[656]1104    my ($self, $node, $redirected_from) = @_;
[652]1105   
[587]1106    my $script_url = $self->config->script_url;
1107    my $script_name = $self->config->script_name;
[392]1108    my $formatter = $self->wiki->formatter;
[652]1109
[634]1110    my $id = $formatter->node_name_to_node_param( $node );
1111    my $oldid;
[656]1112    $oldid = $formatter->node_name_to_node_param( $redirected_from ) if $redirected_from;
[652]1113
[659]1114    my $redir_param = "$script_url$script_name?";
1115    $redir_param .= 'id=' if $oldid;
1116    $redir_param .= $id;
1117    $redir_param .= ";oldid=$oldid" if $oldid;
[735]1118   
1119    my $q = CGI->new;
1120    return $q->redirect( $redir_param );
[392]1121}
1122
[363]1123sub get_cookie {
1124    my $self = shift;
1125    my $config = $self->config;
1126    my $pref_name = shift or return "";
1127    my %cookie_data = OpenGuides::CGI->get_prefs_from_cookie(config=>$config);
1128    return $cookie_data{$pref_name};
1129}
1130
1131
[83]1132=head1 BUGS AND CAVEATS
1133
[597]1134UTF8 data are currently not handled correctly throughout.
[83]1135
[596]1136Other bugs are documented at
[714]1137L<http://dev.openguides.org/>
[596]1138
[83]1139=head1 SEE ALSO
1140
1141=over 4
1142
[281]1143=item * L<http://london.openguides.org/|The Open Guide to London>, the first and biggest OpenGuides site.
[83]1144
[335]1145=item * L<http://openguides.org/|The OpenGuides website>, with a list of all live OpenGuides installs.
[90]1146
[785]1147=item * L<Wiki::Toolkit>, the Wiki toolkit which does the heavy lifting for OpenGuides
[179]1148
[83]1149=back
1150
1151=head1 FEEDBACK
1152
1153If you have a question, a bug report, or a patch, or you're interested
[202]1154in joining the development team, please contact openguides-dev@openguides.org
[83]1155(moderated mailing list, will reach all current developers but you'll have
[596]1156to wait for your post to be approved) or file a bug report at
[714]1157L<http://dev.openguides.org/>
[83]1158
1159=head1 AUTHOR
1160
[202]1161The OpenGuides Project (openguides-dev@openguides.org)
[83]1162
1163=head1 COPYRIGHT
1164
[736]1165     Copyright (C) 2003-2006 The OpenGuides Project.  All Rights Reserved.
[83]1166
1167The OpenGuides distribution is free software; you can redistribute it
1168and/or modify it under the same terms as Perl itself.
1169
[84]1170=head1 CREDITS
1171
[458]1172Programming by Dominic Hargreaves, Earle Martin, Kake Pugh, and Ivor
1173Williams.  Testing and bug reporting by Billy Abbott, Jody Belka,
1174Kerry Bosworth, Simon Cozens, Cal Henderson, Steve Jolly, and Bob
1175Walker (among others).  Much of the Module::Build stuff copied from
[448]1176the Siesta project L<http://siesta.unixbeard.net/>
[84]1177
[83]1178=cut
1179
11801;
Note: See TracBrowser for help on using the repository browser.