source: trunk/lib/OpenGuides/JSON.pm @ 1227

Last change on this file since 1227 was 1227, checked in by nick, 13 years ago

Start to support metadata discovery stuff

File size: 9.3 KB
Line 
1package OpenGuides::JSON;
2
3use strict;
4
5use vars qw( $VERSION );
6$VERSION = '0.01';
7
8use Wiki::Toolkit::Plugin::JSON;
9use Time::Piece;
10use URI::Escape;
11use Carp 'croak';
12
13sub new {
14    my ( $class, @args ) = @_;
15    my $self = {};
16    bless $self, $class;
17    $self->_init(@args);
18}
19
20sub _init {
21    my ( $self, %args ) = @_;
22
23    my $wiki = $args{wiki};
24
25    unless ( $wiki && UNIVERSAL::isa( $wiki, "Wiki::Toolkit" ) ) {
26        croak "No Wiki::Toolkit object supplied.";
27    }
28    $self->{wiki} = $wiki;
29
30    my $config = $args{config};
31
32    unless ( $config && UNIVERSAL::isa( $config, "OpenGuides::Config" ) ) {
33        croak "No OpenGuides::Config object supplied.";
34    }
35    $self->{config} = $config;
36
37    $self->{make_node_url} = sub {
38        my ( $node_name, $version ) = @_;
39
40        my $config = $self->{config};
41
42        my $node_url = $config->script_url;
43        if ( $config->script_name ) {
44            $node_url .= uri_escape( $config->script_name ) . '?';
45        }
46        $node_url .= 'id=' if defined $version;
47        $node_url .=
48          uri_escape(
49            $self->{wiki}->formatter->node_name_to_node_param($node_name) );
50        $node_url .= ';version=' . uri_escape($version) if defined $version;
51
52        $node_url;
53    };
54    $self->{site_name}        = $config->site_name;
55    $self->{default_city}     = $config->default_city || "";
56    $self->{default_country}  = $config->default_country || "";
57    $self->{site_description} = $config->site_desc || "";
58    $self->{og_version}       = $args{og_version};
59
60    $self;
61}
62
63=item B<emit_json>
64Renders the given node as JSON
65=cut
66sub emit_json {
67    my ( $self, %args ) = @_;
68
69    my $node_name = $args{node};
70    my $wiki      = $self->{wiki};
71
72    my %node_data = $wiki->retrieve_node($node_name);
73    my $data      = {};
74    $data->{phone}   = $node_data{metadata}{phone}[0]   || '';
75    $data->{fax}     = $node_data{metadata}{fax}[0]     || '';
76    $data->{website} = $node_data{metadata}{website}[0] || '';
77    $data->{opening_hours_text} = $node_data{metadata}{opening_hours_text}[0]
78      || '';
79    $data->{address}  = $node_data{metadata}{address}[0]  || '';
80    $data->{postcode} = $node_data{metadata}{postcode}[0] || '';
81    $data->{city} = $node_data{metadata}{city}[0] || $self->{default_city};
82    $data->{country} = $node_data{metadata}{country}[0]
83      || $self->{default_country};
84    $data->{latitude}   = $node_data{metadata}{latitude}[0]  || '';
85    $data->{longitude}  = $node_data{metadata}{longitude}[0] || '';
86    $data->{version}    = $node_data{version};
87    $data->{username}   = $node_data{metadata}{username}[0]  || '';
88    $data->{os_x}       = $node_data{metadata}{os_x}[0]      || '';
89    $data->{os_y}       = $node_data{metadata}{os_y}[0]      || '';
90    $data->{categories} = $node_data{metadata}{category}     || [];
91    $data->{locales}    = $node_data{metadata}{locale}       || [];
92    $data->{summary}    = $node_data{metadata}{summary}[0]   || '';
93
94    $data->{timestamp} = $node_data{last_modified};
95
96    # Make a Time::Piece object.
97    my $timestamp_fmt = $Wiki::Toolkit;
98
99    if ( $data->{timestamp} ) {
100        my $time = Time::Piece->strptime( $data->{timestamp}, $timestamp_fmt );
101        $data->{timestamp} = $time->strftime("%Y-%m-%dT%H:%M:%S");
102    }
103
104    $data->{url} = $self->{make_node_url}->( $node_name, $data->{version} );
105    $data->{version_indpt_url} = $self->{make_node_url}->($node_name);
106    return $self->json_maker->make_json($data);
107}
108
109=item B<output_as_json>
110Renders the given arbitary data as JSON
111=cut
112sub output_as_json {
113    my ( $self, %args ) = @_;
114    return $self->json_maker->make_json(\%args);
115}
116
117sub json_maker {
118    my $self = shift;
119
120    # OAOO, please.
121    unless ( $self->{json_maker} ) {
122        $self->{json_maker} = Wiki::Toolkit::Plugin::JSON->new(
123            wiki                => $self->{wiki},
124            site_name           => $self->{site_name},
125            site_url            => $self->{config}->script_url,
126            site_description    => $self->{site_description},
127            make_node_url       => $self->{make_node_url},
128            recent_changes_link => $self->{config}->script_url . '?action=rc',
129            software_name       => 'OpenGuides',
130            software_homepage   => 'http://openguides.org/',
131            software_version    => $self->{og_version},
132        );
133    }
134
135    return $self->{json_maker};
136}
137
138sub make_recentchanges_json {
139    my ( $self, %args ) = @_;
140
141    $self->json_maker->recent_changes(%args);
142}
143
144sub json_timestamp {
145    my ( $self, %args ) = @_;
146
147    # RSS and JSON timestamps are close, I think...
148    $self->json_maker->rss_timestamp(%args);
149}
150
151=head1 NAME
152
153OpenGuides::JSON - An OpenGuides plugin to output JSON.
154
155=head1 DESCRIPTION
156
157Does all the JSON stuff for OpenGuides.  Distributed and installed as
158part of the OpenGuides project, not intended for independent
159installation.  This documentation is probably only useful to OpenGuides
160developers.
161
162=head1 SYNOPSIS
163
164    use Wiki::Toolkit;
165    use OpenGuides::Config;
166    use OpenGuides::JSON;
167
168    my $wiki = Wiki::Toolkit->new( ... );
169    my $config = OpenGuides::Config->new( file => "wiki.conf" );
170    my $json_writer = OpenGuides::JSON->new( wiki   => $wiki,
171                                         config => $config );
172
173    # JSON version of a node.
174    print "Content-Type: application/javascript\n\n";
175    print $json_writer->emit_json( node => "Masala Zone, N1 0NU" );
176
177    # Ten most recent changes.
178    print "Content-Type: application/javascript\n";
179    print "Last-Modified: " . $self->json_timestamp( items => 10 ) . "\n\n";
180    print $json_writer->make_recentchanges_json( items => 10 );
181
182=head1 METHODS
183
184=over 4
185
186=item B<new>
187
188    my $json_writer = OpenGuides::JSON->new( wiki   => $wiki,
189                                           config => $config );
190
191C<wiki> must be a L<Wiki::Toolkit> object and C<config> must be an
192L<OpenGuides::Config> object.  Both arguments mandatory.
193
194
195=item B<emit_json>
196
197    $wiki->write_node( "Masala Zone, N1 0NU",
198                     "Quick and tasty Indian food",
199                     $checksum,
200                     { comment  => "New page",
201                       username => "Kake",
202                       locale   => "Islington" }
203    );
204
205    print "Content-Type: application/javascript\n\n";
206    print $json_writer->emit_json( node => "Masala Zone, N1 0NU" );
207
208B<Note:> Some of the fields emitted by the JSON generator are taken
209from the node metadata. The form of this metadata is I<not> mandated
210by L<Wiki::Toolkit>. Your wiki application should make sure to store some or
211all of the following metadata when calling C<write_node>:
212
213=over 4
214
215=item B<postcode> - The postcode or zip code of the place discussed by the node.  Defaults to the empty string.
216
217=item B<city> - The name of the city that the node is in.  If not supplied, then the value of C<default_city> in the config object supplied to C<new>, if available, otherwise the empty string.
218
219=item B<country> - The name of the country that the node is in.  If not supplied, then the value of C<default_country> in the config object supplied to C<new> will be used, if available, otherwise the empty string.
220
221=item B<username> - An identifier for the person who made the latest edit to the node.  This person will be listed as a contributor (Dublin Core).  Defaults to empty string.
222
223=item B<locale> - The value of this can be a scalar or an arrayref, since some places have a plausible claim to being in more than one locale.  Each of these is put in as a C<Neighbourhood> attribute.
224
225=item B<phone> - Only one number supported at the moment.  No validation.
226
227=item B<website> - No validation.
228
229=item B<opening_hours_text> - A freeform text field.
230
231=back
232
233=item B<json_maker>
234
235Returns a raw L<Wiki::Toolkit::Plugin::JSON> object created with the values you
236invoked this module with.
237
238=item B<make_recentchanges_json>
239
240    # Ten most recent changes.
241    print "Content-Type: application/javascript\n";
242    print "Last-Modified: " . $json_writer->json_timestamp( items => 10 ) . "\n\n";
243    print $json_writer->make_recentchanges_json( items => 10 );
244
245    # All the changes made by bob in the past week, ignoring minor edits.
246
247    my %args = (
248                 days               => 7,
249                 ignore_minor_edits => 1,
250                 filter_on_metadata => { username => "bob" },
251               );
252
253    print "Content-Type: application/javascript\n";
254    print "Last-Modified: " . $json_writer->json_timestamp( %args ) . "\n\n";
255    print $json_writer->make_recentchanges_json( %args );
256
257=item B<json_timestamp>
258
259    print "Last-Modified: " . $json_writer->json_timestamp( %args ) . "\n\n";
260
261Returns the timestamp of the RSS feed in POSIX::strftime style ("Tue, 29 Feb 2000
26212:34:56 GMT"), which is equivalent to the timestamp of the most recent item
263in the feed. Takes the same arguments as make_recentchanges_json(). You will most
264likely need this to print a Last-Modified HTTP header so user-agents can determine
265whether they need to reload the feed or not.
266
267=back
268
269=head1 SEE ALSO
270
271=over 4
272
273=item * L<Wiki::Toolkit>
274
275=item * L<http://openguides.org/>
276
277=item * L<http://chefmoz.org/>
278
279=back
280
281=head1 AUTHOR
282
283The OpenGuides Project (openguides-dev@openguides.org)
284
285=head1 COPYRIGHT
286
287Copyright (C) 2003-2005 The OpenGuides Project.  All Rights Reserved.
288
289This module is free software; you can redistribute it and/or modify it
290under the same terms as Perl itself.
291
292=head1 CREDITS
293
294Code in this module is mostly pirated from OpenGuides::RDF, those authors deserve all the credit. Chris Prather
295did the pirating.
296
297=cut
298
2991;
Note: See TracBrowser for help on using the repository browser.