line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# WebFetch::Output::TWiki - save data into a TWiki web site |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# Copyright (c) 2009 Ian Kluft. This program is free software; you can |
5
|
|
|
|
|
|
|
# redistribute it and/or modify it under the terms of the GNU General Public |
6
|
|
|
|
|
|
|
# License Version 3. See http://www.webfetch.org/GPLv3.txt |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package WebFetch::Output::TWiki; |
9
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
1713
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
36
|
|
11
|
1
|
|
|
1
|
|
6
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
29
|
|
12
|
1
|
|
|
1
|
|
43
|
use WebFetch; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
use base "WebFetch"; |
14
|
|
|
|
|
|
|
use DB_File; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# define exceptions/errors |
17
|
|
|
|
|
|
|
use Exception::Class ( |
18
|
|
|
|
|
|
|
"WebFetch::Output::TWiki::Exception::NoRoot" => { |
19
|
|
|
|
|
|
|
isa => "WebFetch::Exception", |
20
|
|
|
|
|
|
|
alias => "throw_twiki_no_root", |
21
|
|
|
|
|
|
|
description => "WebFetch::Output::TWiki needs to be provided " |
22
|
|
|
|
|
|
|
."a twiki_root parameter", |
23
|
|
|
|
|
|
|
}, |
24
|
|
|
|
|
|
|
"WebFetch::Output::TWiki::Exception::NotFound" => { |
25
|
|
|
|
|
|
|
isa => "WebFetch::Exception", |
26
|
|
|
|
|
|
|
alias => "throw_twiki_not_found", |
27
|
|
|
|
|
|
|
description => "the directory in the twiki_root parameter " |
28
|
|
|
|
|
|
|
."doesn't exist or doesn't have a lib subdirectory", |
29
|
|
|
|
|
|
|
}, |
30
|
|
|
|
|
|
|
"WebFetch::Output::TWiki::Exception::Require" => { |
31
|
|
|
|
|
|
|
isa => "WebFetch::Exception", |
32
|
|
|
|
|
|
|
alias => "throw_twiki_require", |
33
|
|
|
|
|
|
|
description => "failed to import TWiki or TWiki::Func modules", |
34
|
|
|
|
|
|
|
}, |
35
|
|
|
|
|
|
|
"WebFetch::Output::TWiki::Exception::NoConfig" => { |
36
|
|
|
|
|
|
|
isa => "WebFetch::Exception", |
37
|
|
|
|
|
|
|
alias => "throw_twiki_no_config", |
38
|
|
|
|
|
|
|
description => "WebFetch::Output::TWiki needs to be provided " |
39
|
|
|
|
|
|
|
."a config_topic parameter", |
40
|
|
|
|
|
|
|
}, |
41
|
|
|
|
|
|
|
"WebFetch::Output::TWiki::Exception::ConfigMissing" => { |
42
|
|
|
|
|
|
|
isa => "WebFetch::Exception", |
43
|
|
|
|
|
|
|
alias => "throw_twiki_config_missing", |
44
|
|
|
|
|
|
|
description => "WebFetch::Output::TWiki is missing a required " |
45
|
|
|
|
|
|
|
."configuration parameter", |
46
|
|
|
|
|
|
|
}, |
47
|
|
|
|
|
|
|
"WebFetch::Output::TWiki::Exception::Oops" => { |
48
|
|
|
|
|
|
|
isa => "WebFetch::Exception", |
49
|
|
|
|
|
|
|
alias => "throw_twiki_oops", |
50
|
|
|
|
|
|
|
description => "WebFetch::Output::TWiki returned errors from " |
51
|
|
|
|
|
|
|
."saving one or more entries", |
52
|
|
|
|
|
|
|
}, |
53
|
|
|
|
|
|
|
"WebFetch::Output::TWiki::Exception::FieldNotSpecified" => { |
54
|
|
|
|
|
|
|
isa => "WebFetch::Exception", |
55
|
|
|
|
|
|
|
alias => "throw_field_not_specified", |
56
|
|
|
|
|
|
|
description => "a required field was not defined or found", |
57
|
|
|
|
|
|
|
}, |
58
|
|
|
|
|
|
|
); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=head1 NAME |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
WebFetch::Output::TWiki - WebFetch output to TWiki web site |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=cut |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# globals/defaults |
67
|
|
|
|
|
|
|
our @Options = ( "twiki_root=s", "config_topic=s", "config_key=s" ); |
68
|
|
|
|
|
|
|
our $Usage = "--twiki_root path-to-twiki --config_topic web.topic " |
69
|
|
|
|
|
|
|
."--config_key keyword"; |
70
|
|
|
|
|
|
|
our @default_field_names = ( qw( key web parent prefix template form |
71
|
|
|
|
|
|
|
options )); |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# no user-servicable parts beyond this point |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# register capabilities with WebFetch |
76
|
|
|
|
|
|
|
__PACKAGE__->module_register( "cmdline", "output:twiki" ); |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=head1 SYNOPSIS |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
This is an output module for WebFetch which places the data in pages |
81
|
|
|
|
|
|
|
on a TWiki web site. Some of its configuration information is read from |
82
|
|
|
|
|
|
|
a TWiki page. Calling or command-line parameters point to the TWiki page |
83
|
|
|
|
|
|
|
which has the configuration and a search key to locate the correct line |
84
|
|
|
|
|
|
|
in a table. |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
From the command line... |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
perl -w -I$libdir -MWebFetch::Input::Atom -MWebFetch::Output::TWiki -e "&fetch_main" -- --dir "/path/to/fetch/worskspace" --source "http://search.twitter.com/search.atom?q=%23twiki" --dest=twiki --twiki_root=/var/www/twiki --config_topic=Feeds.WebFetchConfig --config_key=twiki |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
From Perl code... |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
use WebFetch; |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
my $obj = WebFetch->new( |
95
|
|
|
|
|
|
|
"dir" => "/path/to/fetch/workspace", |
96
|
|
|
|
|
|
|
"source" => "http://search.twitter.com/search.atom?q=%23twiki", |
97
|
|
|
|
|
|
|
"source_format" => "atom", |
98
|
|
|
|
|
|
|
"dest" => "twiki", |
99
|
|
|
|
|
|
|
"dest_format" = "twiki", |
100
|
|
|
|
|
|
|
"twiki_root" => "/var/www/twiki", |
101
|
|
|
|
|
|
|
"config_topic" => "Feeds.WebFetchConfig", |
102
|
|
|
|
|
|
|
"config_key" => "twiki", |
103
|
|
|
|
|
|
|
); |
104
|
|
|
|
|
|
|
$obj->do_actions; # process output |
105
|
|
|
|
|
|
|
$obj->save; # save results |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head1 configuration from TWiki topic |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
The configuration information on feeds is kept in a TWiki page. You can |
110
|
|
|
|
|
|
|
specify any page with a web and topic name, for example C<--config_topic=Feeds.WebFetchConfig> . |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
The contents of that configuration page could look like this, though with |
113
|
|
|
|
|
|
|
any feeds you want to configure. The "Key" field matches the --config_key |
114
|
|
|
|
|
|
|
command-line parameter, and then brings in the rest of the configuration |
115
|
|
|
|
|
|
|
info from that line. An example is shown below. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=over |
118
|
|
|
|
|
|
|
C<< ---+ !WebFetch Configuration >> |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
C<< The following table is used by !WebFetch to configure news feeds >> |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
C<< %STARTINCLUDE% >> |
123
|
|
|
|
|
|
|
C<< | *Key* | *Web* | *Parent* | *Prefix* | *Template* | *Form* | *Options* | *Modul >> |
124
|
|
|
|
|
|
|
e* | *Source* | |
125
|
|
|
|
|
|
|
C<< | ikluft-twitter | Feeds | TwitterIkluftFeed | TwitterIkluft | AtomFeedTemplate | AtomFeedForm | separate_topics | Atom | http://twitter.com/statuses/user_timeline/37786023.rss | >> |
126
|
|
|
|
|
|
|
C<< | twiki-twitter | Feeds | TwitterTwikiFeed | TwitterTwiki | AtomFeedTemplate | AtomFeedForm | separate_topics | Atom | http://search.twitter.com/search.atom?q=%23twiki | >> |
127
|
|
|
|
|
|
|
C<< | cnn | Feeds | RssCnn | RssCnn | RssFeedTemplate | RssFeedForm | separate_topics | RSS | http://rss.cnn.com/rss/cnn_topstories.rss | >> |
128
|
|
|
|
|
|
|
C<< %STOPINCLUDE% >> |
129
|
|
|
|
|
|
|
=back |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
The C<%STARTINCLUDE%> and C<%STOPINCLUDE%> are not required. However, if |
132
|
|
|
|
|
|
|
present, they are used as boundaries for the inclusion like in a normal |
133
|
|
|
|
|
|
|
INCLUDE operation on TWiki. |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=cut |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# read the TWiki configuation |
138
|
|
|
|
|
|
|
sub get_twiki_config |
139
|
|
|
|
|
|
|
{ |
140
|
|
|
|
|
|
|
my $self = shift; |
141
|
|
|
|
|
|
|
WebFetch::debug "in get_twiki_config"; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# find the TWiki modules |
144
|
|
|
|
|
|
|
if ( ! exists $self->{twiki_root}) { |
145
|
|
|
|
|
|
|
throw_twiki_no_root( "TWiki root directory not defined" ); |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
if (( ! -d $self->{twiki_root}) or ( ! -d $self->{twiki_root}."/lib" )) |
148
|
|
|
|
|
|
|
{ |
149
|
|
|
|
|
|
|
throw_twiki_not_found( "can't find TWiki root or lib at " |
150
|
|
|
|
|
|
|
.$self->{twiki_root}); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# load the TWiki modules |
154
|
|
|
|
|
|
|
WebFetch::debug "loading TWiki modules"; |
155
|
|
|
|
|
|
|
push @INC, $self->{twiki_root}."/lib"; |
156
|
|
|
|
|
|
|
eval { require TWiki; require TWiki::Func; }; |
157
|
|
|
|
|
|
|
if ( $@ ) { |
158
|
|
|
|
|
|
|
throw_twiki_require ( $@ ); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# initiate TWiki library, create session as user "WebFetch" |
162
|
|
|
|
|
|
|
$self->{twiki_obj} = TWiki->new( "WebFetch" ); |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# get the contents of the TWiki topic which contains our configuration |
165
|
|
|
|
|
|
|
if ( !exists $self->{config_topic}) { |
166
|
|
|
|
|
|
|
throw_twiki_no_config( "TWiki configuration page for WebFetch " |
167
|
|
|
|
|
|
|
."not defined" ); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
my ( $web, $topic ) = split /\./, $self->{config_topic}; |
170
|
|
|
|
|
|
|
WebFetch::debug "config_topic: ".$self->{config_topic} |
171
|
|
|
|
|
|
|
." -> $web, $topic"; |
172
|
|
|
|
|
|
|
if (( ! defined $web ) or ( ! defined $topic )) { |
173
|
|
|
|
|
|
|
throw_twiki_no_config( "TWiki configuration page for WebFetch " |
174
|
|
|
|
|
|
|
."must be defined in the format web.topic" ); |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# check if a config_key was specified before we read the configuration |
178
|
|
|
|
|
|
|
if ( !exists $self->{config_key}) { |
179
|
|
|
|
|
|
|
throw_twiki_no_config( "TWiki configuration key for WebFetch " |
180
|
|
|
|
|
|
|
."not defined" ); |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# read the configuration info |
184
|
|
|
|
|
|
|
my $config = TWiki::Func::readTopic( $web, $topic ); |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# if STARTINCLUDE and STOPINCLUDE are present, use only what's between |
187
|
|
|
|
|
|
|
if ( $config =~ /%STARTINCLUDE%\s*(.*)\s*%STOPINCLUDE%/s ) { |
188
|
|
|
|
|
|
|
$config = $1; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# parse the configuration |
192
|
|
|
|
|
|
|
WebFetch::debug "parsing configuration"; |
193
|
|
|
|
|
|
|
my ( @fnames, $line ); |
194
|
|
|
|
|
|
|
$self->{twiki_config_all} = []; |
195
|
|
|
|
|
|
|
$self->{twiki_keys} = {}; |
196
|
|
|
|
|
|
|
foreach $line ( split /\r*\n+/s, $config ) { |
197
|
|
|
|
|
|
|
if ( $line =~ /^\|\s*(.*)\s*\|\s*$/ ) { |
198
|
|
|
|
|
|
|
my @entries = split /\s*\|\s*/, $1; |
199
|
|
|
|
|
|
|
WebFetch::debug "read entries: ".join( ', ', @entries ); |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# first line contains field headings |
202
|
|
|
|
|
|
|
if ( ! @fnames) { |
203
|
|
|
|
|
|
|
# save table headings as field names |
204
|
|
|
|
|
|
|
my $field; |
205
|
|
|
|
|
|
|
foreach $field ( @entries ) { |
206
|
|
|
|
|
|
|
my $tmp = lc($field); |
207
|
|
|
|
|
|
|
$tmp =~ s/\W//g; |
208
|
|
|
|
|
|
|
push @fnames, $tmp; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
next; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
WebFetch::debug "field names: ".join " ", @fnames; |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# save the entries |
215
|
|
|
|
|
|
|
# it isn't a heading row if we got here |
216
|
|
|
|
|
|
|
# transfer array @entries to named fields in %config |
217
|
|
|
|
|
|
|
WebFetch::debug "data row: ".join " ", @entries; |
218
|
|
|
|
|
|
|
my ( $i, $key, %config ); |
219
|
|
|
|
|
|
|
for ( $i=0; $i < scalar @fnames; $i++ ) { |
220
|
|
|
|
|
|
|
$config{ $fnames[$i]} = $entries[$i]; |
221
|
|
|
|
|
|
|
if ( $fnames[$i] eq "key" ) { |
222
|
|
|
|
|
|
|
$key = $entries[$i]; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# save the %config row in @{$self->{twiki_config_all}} |
227
|
|
|
|
|
|
|
if (( defined $key ) |
228
|
|
|
|
|
|
|
and ( !exists $self->{twiki_keys}{$key})) |
229
|
|
|
|
|
|
|
{ |
230
|
|
|
|
|
|
|
push @{$self->{twiki_config_all}}, \%config; |
231
|
|
|
|
|
|
|
$self->{twiki_keys}{$key} = ( scalar |
232
|
|
|
|
|
|
|
@{$self->{twiki_config_all}}) - 1; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# select the line which is for this request |
238
|
|
|
|
|
|
|
if ( ! exists $self->{twiki_keys}{$self->{config_key}}) { |
239
|
|
|
|
|
|
|
throw_twiki_no_config "no configuration found for key " |
240
|
|
|
|
|
|
|
.$self->{config_key}; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
$self->{twiki_config} = $self->{twiki_config_all}[$self->{twiki_keys}{$self->{config_key}}]; |
243
|
|
|
|
|
|
|
WebFetch::debug "twiki_config: ".join( " ", %{$self->{twiki_config}}); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# write to a TWiki page |
247
|
|
|
|
|
|
|
sub write_to_twiki |
248
|
|
|
|
|
|
|
{ |
249
|
|
|
|
|
|
|
my $self = shift; |
250
|
|
|
|
|
|
|
my ( $config, $name ); |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# get config variables |
253
|
|
|
|
|
|
|
$config = $self->{twiki_config}; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# parse options |
256
|
|
|
|
|
|
|
my ( $option ); |
257
|
|
|
|
|
|
|
$self->{twiki_options} = {}; |
258
|
|
|
|
|
|
|
foreach $option ( split /\s+/, $self->{twiki_config}{options}) { |
259
|
|
|
|
|
|
|
if ( $option =~ /^([^=]+)=(.*)/ ) { |
260
|
|
|
|
|
|
|
$self->{twiki_options}{$1} = $2; |
261
|
|
|
|
|
|
|
} else { |
262
|
|
|
|
|
|
|
$self->{twiki_options}{$option} = 1; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# determine unique identifier field |
267
|
|
|
|
|
|
|
my $id_field; |
268
|
|
|
|
|
|
|
if ( exists $self->{twiki_options}{id_field}) { |
269
|
|
|
|
|
|
|
$id_field = $self->{twiki_options}{id_field}; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
if ( ! defined $id_field ) { |
272
|
|
|
|
|
|
|
$id_field = $self->wk2fname( "id" ); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
if ( ! defined $id_field ) { |
275
|
|
|
|
|
|
|
$id_field = $self->wk2fname( "url" ); |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
if ( ! defined $id_field ) { |
278
|
|
|
|
|
|
|
$id_field = $self->wk2fname( "title" ); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
if ( ! defined $id_field ) { |
281
|
|
|
|
|
|
|
throw_field_not_specified "identifier field not specified"; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
$self->{id_field} = $id_field; |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# determine from options whether each item is making metadata or topics |
286
|
|
|
|
|
|
|
if ( exists $self->{twiki_options}{separate_topics}) { |
287
|
|
|
|
|
|
|
$self->write_to_twiki_topics; |
288
|
|
|
|
|
|
|
} else { |
289
|
|
|
|
|
|
|
$self->write_to_twiki_metadata; |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# write to separate TWiki topics |
294
|
|
|
|
|
|
|
sub write_to_twiki_topics |
295
|
|
|
|
|
|
|
{ |
296
|
|
|
|
|
|
|
my $self = shift; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# get config variables |
299
|
|
|
|
|
|
|
my $config = $self->{twiki_config}; |
300
|
|
|
|
|
|
|
my $name; |
301
|
|
|
|
|
|
|
foreach $name ( qw( key web parent prefix template form )) { |
302
|
|
|
|
|
|
|
if ( !exists $self->{twiki_config}{$name}) { |
303
|
|
|
|
|
|
|
throw_twiki_config_missing( "missing config parameter " |
304
|
|
|
|
|
|
|
.$name ); |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# get text of template topic |
309
|
|
|
|
|
|
|
my ($meta, $template ) = TWiki::Func::readTopic( $config->{web}, |
310
|
|
|
|
|
|
|
$config->{template}); |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# open DB file for tracking unique IDs of articles already processed |
313
|
|
|
|
|
|
|
my %id_index; |
314
|
|
|
|
|
|
|
tie %id_index, 'DB_File', |
315
|
|
|
|
|
|
|
$self->{dir}."/".$config->{key}."_id_index.db", |
316
|
|
|
|
|
|
|
&DB_File::O_CREAT|&DB_File::O_RDWR, 0640; |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# determine initial topic name |
319
|
|
|
|
|
|
|
my ( %topics, @topics ); |
320
|
|
|
|
|
|
|
@topics = TWiki::Func::getTopicList( $config->{web}); |
321
|
|
|
|
|
|
|
foreach ( @topics ) { |
322
|
|
|
|
|
|
|
$topics{$_} = 1; |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
my $tnum_counter = 0; |
325
|
|
|
|
|
|
|
my $tnum_format = $config->{prefix}."-%07d"; |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# create topics with metadata from each WebFetch data record |
328
|
|
|
|
|
|
|
my $entry; |
329
|
|
|
|
|
|
|
my @oopses; |
330
|
|
|
|
|
|
|
my $id_field = $self->{id_field}; |
331
|
|
|
|
|
|
|
$self->data->reset_pos; |
332
|
|
|
|
|
|
|
while ( $entry = $self->data->next_record ) { |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
# check that this entry hasn't already been forwarded to TWiki |
335
|
|
|
|
|
|
|
if ( exists $id_index{$entry->byname( $id_field )}) { |
336
|
|
|
|
|
|
|
next; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
$id_index{$entry->byname( $id_field )} = time; |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# select topic name |
341
|
|
|
|
|
|
|
my $topicname = sprintf $tnum_format, $tnum_counter; |
342
|
|
|
|
|
|
|
while ( exists $topics{$topicname}) { |
343
|
|
|
|
|
|
|
$tnum_counter++; |
344
|
|
|
|
|
|
|
$topicname = sprintf $tnum_format, $tnum_counter; |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
$tnum_counter++; |
347
|
|
|
|
|
|
|
$topics{$topicname} = 1; |
348
|
|
|
|
|
|
|
my $text = $template; |
349
|
|
|
|
|
|
|
WebFetch::debug "write_to_twiki_topics: writing $topicname"; |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
# create topic metadata |
352
|
|
|
|
|
|
|
#my $meta = TWiki::Meta->new ( $self->{twiki_obj}, $config->{web}, $topicname ); |
353
|
|
|
|
|
|
|
$meta->put( "TOPICPARENT", |
354
|
|
|
|
|
|
|
{ name => $config->{parent}}); |
355
|
|
|
|
|
|
|
$meta->put( "FORM", { name => $config->{form}}); |
356
|
|
|
|
|
|
|
my $fnum; |
357
|
|
|
|
|
|
|
for ( $fnum = 0; $fnum <= $self->data->num_fields; $fnum++ ) { |
358
|
|
|
|
|
|
|
WebFetch::debug "meta: " |
359
|
|
|
|
|
|
|
.$self->data->field_bynum($fnum) |
360
|
|
|
|
|
|
|
." = ".$entry->bynum($fnum); |
361
|
|
|
|
|
|
|
( defined $self->data->field_bynum($fnum)) or next; |
362
|
|
|
|
|
|
|
( $self->data->field_bynum($fnum) eq "xml") and next; |
363
|
|
|
|
|
|
|
( defined $entry->bynum($fnum)) or next; |
364
|
|
|
|
|
|
|
WebFetch::debug "meta: OK"; |
365
|
|
|
|
|
|
|
$meta->putKeyed( "FIELD", { |
366
|
|
|
|
|
|
|
name => $self->data->field_bynum($fnum), |
367
|
|
|
|
|
|
|
value => $entry->bynum($fnum)}); |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# save a special title field for TWiki indexes |
371
|
|
|
|
|
|
|
my $index_title = $entry->title; |
372
|
|
|
|
|
|
|
$index_title =~ s/[\t\r\n\|]+/ /gs; |
373
|
|
|
|
|
|
|
$index_title =~ s/^\s*//; |
374
|
|
|
|
|
|
|
$index_title =~ s/\s*$//; |
375
|
|
|
|
|
|
|
if ( length($index_title) > 60 ) { |
376
|
|
|
|
|
|
|
substr( $index_title, 56 ) = "..."; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
WebFetch::debug "title: $index_title"; |
379
|
|
|
|
|
|
|
$meta->putKeyed( "FIELD", { |
380
|
|
|
|
|
|
|
name => "IndexTitle", |
381
|
|
|
|
|
|
|
title => "Indexing title", |
382
|
|
|
|
|
|
|
value => $index_title }); |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# save the topic |
385
|
|
|
|
|
|
|
my $oopsurl = TWiki::Func::saveTopic( $config->{web}, |
386
|
|
|
|
|
|
|
$topicname, $meta, $text ); |
387
|
|
|
|
|
|
|
if ( $oopsurl ) { |
388
|
|
|
|
|
|
|
WebFetch::debug "write_to_twiki_topics: " |
389
|
|
|
|
|
|
|
."$topicname - $oopsurl"; |
390
|
|
|
|
|
|
|
push @oopses, $entry->title." -> " |
391
|
|
|
|
|
|
|
.$topicname." ".$oopsurl; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
# check for errors |
396
|
|
|
|
|
|
|
if ( @oopses ) { |
397
|
|
|
|
|
|
|
throw_twiki_oops( "TWiki saves failed:\n".join "\n", @oopses ); |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
# write to successive items of TWiki metadata |
402
|
|
|
|
|
|
|
sub write_to_twiki_metadata |
403
|
|
|
|
|
|
|
{ |
404
|
|
|
|
|
|
|
my $self = shift; |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
# get config variables |
407
|
|
|
|
|
|
|
my $config = $self->{twiki_config}; |
408
|
|
|
|
|
|
|
my $name; |
409
|
|
|
|
|
|
|
foreach $name ( qw( key web parent )) { |
410
|
|
|
|
|
|
|
if ( !exists $self->{twiki_config}{$name}) { |
411
|
|
|
|
|
|
|
throw_twiki_config_missing( "missing config parameter " |
412
|
|
|
|
|
|
|
.$name ); |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
# determine metadata title field |
417
|
|
|
|
|
|
|
my $title_field; |
418
|
|
|
|
|
|
|
if ( exists $self->{twiki_options}{title_field}) { |
419
|
|
|
|
|
|
|
$title_field = $self->{twiki_options}{title_field}; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
if ( ! defined $title_field ) { |
422
|
|
|
|
|
|
|
$title_field = $self->wk2fname( "title" ); |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
if ( ! defined $title_field ) { |
425
|
|
|
|
|
|
|
throw_field_not_specified "title field not specified"; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
# determine metadata value field |
429
|
|
|
|
|
|
|
my $value_field; |
430
|
|
|
|
|
|
|
if ( exists $self->{twiki_options}{value_field}) { |
431
|
|
|
|
|
|
|
$value_field = $self->{twiki_options}{value_field}; |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
if ( ! defined $value_field ) { |
434
|
|
|
|
|
|
|
$value_field = $self->wk2fname( "summary" ); |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
if ( ! defined $value_field ) { |
437
|
|
|
|
|
|
|
throw_field_not_specified "value field not specified"; |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
# open DB file for tracking unique IDs of articles already processed |
441
|
|
|
|
|
|
|
my %id_index; |
442
|
|
|
|
|
|
|
tie %id_index, 'DB_File', |
443
|
|
|
|
|
|
|
$self->{dir}."/".$config->{key}."_id_index.db", |
444
|
|
|
|
|
|
|
&DB_File::O_CREAT|&DB_File::O_RDWR, 0640; |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
# get text of topic |
447
|
|
|
|
|
|
|
my ($meta, $text) = TWiki::Func::readTopic( $config->{web}, |
448
|
|
|
|
|
|
|
$config->{parent}); |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
# start metadata line counter |
451
|
|
|
|
|
|
|
my $mnum_counter = 0; |
452
|
|
|
|
|
|
|
my $mnum_format = "line-%07d"; |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
# create metadata lines for each entry |
455
|
|
|
|
|
|
|
my $entry; |
456
|
|
|
|
|
|
|
my @oopses; |
457
|
|
|
|
|
|
|
my $id_field = $self->{id_field}; |
458
|
|
|
|
|
|
|
$self->data->reset_pos; |
459
|
|
|
|
|
|
|
while ( $entry = $self->data->next_record ) { |
460
|
|
|
|
|
|
|
# check that this entry hasn't already been forwarded to TWiki |
461
|
|
|
|
|
|
|
if ( exists $id_index{$entry->byname( $id_field )}) { |
462
|
|
|
|
|
|
|
next; |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
$id_index{$entry->byname( $id_field )} = time; |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
# select metadata field name |
467
|
|
|
|
|
|
|
my ( $value, $metaname ); |
468
|
|
|
|
|
|
|
$value = $meta->get( "FIELD", |
469
|
|
|
|
|
|
|
$metaname = sprintf( $mnum_format, $mnum_counter )); |
470
|
|
|
|
|
|
|
while ( defined $value ) { |
471
|
|
|
|
|
|
|
$value = $meta->get( "FIELD", |
472
|
|
|
|
|
|
|
$metaname = sprintf( $mnum_format, |
473
|
|
|
|
|
|
|
++$mnum_counter )); |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
# write the value |
477
|
|
|
|
|
|
|
$meta->putKeyed( "FIELD", { |
478
|
|
|
|
|
|
|
name => $metaname, |
479
|
|
|
|
|
|
|
title => $entry->byname( $title_field ), |
480
|
|
|
|
|
|
|
value => $entry->byname( $value_field ), |
481
|
|
|
|
|
|
|
}); |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# save the topic |
485
|
|
|
|
|
|
|
my $oopsurl = TWiki::Func::saveTopic( $config->{web}, |
486
|
|
|
|
|
|
|
$config->{parent}, $meta, $text ); |
487
|
|
|
|
|
|
|
if ( $oopsurl ) { |
488
|
|
|
|
|
|
|
throw_twiki_oops "TWiki saves failed: " |
489
|
|
|
|
|
|
|
.$config->{parent}." ".$oopsurl; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# TWiki format handler |
494
|
|
|
|
|
|
|
sub fmt_handler_twiki |
495
|
|
|
|
|
|
|
{ |
496
|
|
|
|
|
|
|
my $self = shift; |
497
|
|
|
|
|
|
|
my $filename = shift; |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
# get configuration from TWiki |
500
|
|
|
|
|
|
|
$self->get_twiki_config; |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
# write to TWiki topic |
503
|
|
|
|
|
|
|
$self->write_to_twiki; |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
# no savables - mark it OK so WebFetch::save won't call it an error |
506
|
|
|
|
|
|
|
$self->no_savables_ok; |
507
|
|
|
|
|
|
|
1; |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=head1 TWiki software |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
TWiki is a wiki (user-editable web site) with features enabling |
513
|
|
|
|
|
|
|
collaboration in an enterprise environment. |
514
|
|
|
|
|
|
|
It implements the concept of a "structured wiki", allowing structure |
515
|
|
|
|
|
|
|
and automation as needed and retaining the informality of a wiki. |
516
|
|
|
|
|
|
|
Automated input/updates such as from WebFetch::Output::TWiki is one example. |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
See http://twiki.org/ for the Open Source community-maintained software |
519
|
|
|
|
|
|
|
or http://twiki.net/ for enterprise support. |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
WebFetch::Output::TWiki was developed for TWiki Inc (formerly TWiki.Net). |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=head1 AUTHOR |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
WebFetch was written by Ian Kluft |
526
|
|
|
|
|
|
|
Send patches, bug reports, suggestions and questions to |
527
|
|
|
|
|
|
|
C. |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=head1 BUGS |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
532
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
533
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=head1 SEE ALSO |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
=for html |
538
|
|
|
|
|
|
|
WebFetch |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
=for text |
541
|
|
|
|
|
|
|
WebFetch |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=for man |
544
|
|
|
|
|
|
|
WebFetch |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
=cut |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
1; # End of WebFetch::Output::TWiki |