tagging: Allow using titles in for related stories.
[matthijs/upstream/blosxom-plugins.git] / general / writeback
1 # Blosxom Plugin: writeback
2 # Author(s): Rael Dornfest <rael@oreilly.com> 
3 # Version: 2003-09-18
4 # Documentation: See the bottom of this file or type: perldoc writeback
5
6 package writeback;
7
8 # --- Configurable variables -----
9
10 # Where should I keep the writeback hierarchy?
11 # I suggest: $writeback_dir = "$blosxom::plugin_state_dir/writeback";
12 #
13 # NOTE: By setting this variable, you are telling the plug-in to go ahead
14 # and create a writeback directory for you.
15 my $writeback_dir = "";
16
17 # What flavour should I consider an incoming trackback ping?
18 # Otherwise trackback pings will be ignored!
19 my $trackback_flavour = "trackback";
20
21 # What file extension should I use for writebacks? 
22 # Make sure this is different from that used for your Blosxom weblog
23 # entries, usually txt.
24 my $file_extension = "wb";
25
26 # What fields are used in your comments form and by trackbacks?
27 my @fields = qw! name url title comment excerpt blog_name !;
28
29 # --------------------------------
30  
31 # Comments for a story; use as $writeback::writebacks in flavour templates
32 $writebacks;
33
34 # Count of writebacks for a story; use as $writeback::count in flavour templates
35 $count;
36
37 # The path and filename of the last story on the page (ideally, only 1 story
38 # in this view) for displaying the trackback URL;
39 # use as $writeback::trackback_path_and_filename in your foot flavour templates
40 $trackback_path_and_filename;
41
42 # Response to writeback; use as $writeback::writeback_response in 
43 # flavour templates
44 $writeback_response;
45
46 # Response to a trackback ping; use as $writeback::trackback_response in
47 # head.trackback flavour template
48 $trackback_response =<<'TRACKBACK_RESPONSE';
49 <?xml version="1.0" encoding="iso-8859-1"?>
50 <response>
51 <error></error>
52 <message></message>
53 </response>
54 TRACKBACK_RESPONSE
55
56 $blosxom::template{'trackback'} = {
57   'content_type' => 'text/xml',
58   'head'         => '$writeback::trackback_response',
59   'date'         => ' ',
60   'story'        => ' ',
61   'foot'         => ' '
62 };
63  
64 # --------------------------------
65
66 use CGI qw/:standard/;
67 use FileHandle;
68
69 my $fh = new FileHandle;
70
71 # Strip potentially confounding bits from user-configurable variables
72 $writeback_dir =~ s!/$!!; $file_extension =~ s!^\.!!;
73
74 # Save Name and URL/Email via cookie if the cookies plug-in is available
75 $cookie;
76
77 sub start {
78
79   # $writeback_dir must be set to activate writebacks
80   unless ( $writeback_dir ) { 
81     warn "blosxom : writeback plugin > The \$writeback_dir configurable variable is not set; please set it to enable writebacks. Writebacks are disabled!\n";
82     return 0;
83   }
84
85   # the $writeback_dir exists, but is not a directory
86   if ( -e $writeback_dir and ( !-d $writeback_dir or !-w $writeback_dir ) ) { 
87     warn "blosxom : writeback plugin > The \$writeback_dir, $writeback_dir, must be a writeable directory; please move or remove it and Blosxom will create it properly for you.  Writebacks are disabled!\n";
88     return 0;
89   }
90   
91   # the $writeback_dir does not yet exist, so Blosxom will create it
92   if ( !-e  $writeback_dir )  {
93
94     my $mkdir_r = mkdir("$writeback_dir", 0755);
95
96     warn $mkdir_r 
97       ? "blosxom : writeback plugin > \$writeback_dir, $writeback_dir, created.\n"
98       : "blosxom : writeback plugin > There was a problem creating your \$writeback_dir, $writeback_dir. Writebacks are disabled!\n";
99
100     $mkdir_r or return 0;
101
102     my $chmod_r = chmod 0755, $writeback_dir;
103
104     warn $chmod_r 
105       ? "blosxom : writeback plugin > \$writeback_dir, $writeback_dir, set to 0755 permissions.\n"
106       : "blosxom : writeback plugin > There was a problem setting permissions on \$writeback_dir, $writeback_dir. Writebacks are disabled!\n";
107
108     $chmod_r or return 0;
109
110     warn "blosxom : writeback plugin > writebacks are enabled!\n";
111   }
112
113   $path_info = path_info();
114   my($path,$fn) = $path_info =~ m!^(?:(.*)/)?(.*)\.$blosxom::flavour!;
115   $path =~ m!^/! or $path = "/$path";
116   $path = "/$path";
117
118   # Only spring into action if POSTing to the writeback plug-in
119   if ( request_method() eq 'POST' and (param('plugin') eq 'writeback' or $blosxom::flavour eq $trackback_flavour) ) {
120
121     foreach ( ('', split /\//, $path) ) {
122       $p .= "/$_";
123       $p =~ s!^/!!;
124       -d "$writeback_dir/$p" or mkdir "$writeback_dir/$p", 0755;
125     }
126
127     if ( $fh->open(">> $writeback_dir$path/$fn.$file_extension") ) {
128       foreach ( @fields ) {
129         my $p = param($_);
130         $p =~ s/<.*?>//mg; # a gross way to prevent tomfoolery, to be redone
131         $p =~ s/\r?\n\r?/\r/mg;
132         print $fh "$_: $p\n";
133       }
134       print $fh "-----\n";
135       $fh->close();
136
137       $trackback_response =~ s!<error></error>!<error>0</error>!m;
138       $trackback_response =~ s!<message></message>\n!!s;
139       $writeback_response = "Thanks for the writeback.";
140
141       # Make a note to save Name and URL/Email if save_preferences checked
142       param('save_preferences') and $cookie++;
143       # Pre-set Name and URL/Email based on submitted values
144       $pref_name = param('name') || '';
145       $pref_url = param('url') || '';
146
147     } else {
148       warn "couldn't >> $writeback_dir$path/$fn.$file_extension\n";
149
150       $trackback_response =~ s!<error></error>!<error>1</error>!m;
151       $trackback_response =~ s!<message>trackback error</message>!!m;
152       $writeback_response = "There was a problem posting your writeback.";
153     }
154   }
155
156   1;
157 }
158
159 sub story {
160   my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
161     
162   $path =~ s!^/*!!; $path &&= "/$path";
163
164   ($writebacks, $count)  = ('', 0);
165   my %param = ();
166
167   # Prepopulate Name and URL/Email with cookie-baked preferences, if any
168   if ( $blosxom::plugins{cookies} > 0 and my $cookie = &cookies::get('writeback') ) {
169     $pref_name ||= $cookie->{'name'};
170     $pref_url ||= $cookie->{'url'};
171   }
172
173   if ( $fh->open("$writeback_dir$path/$filename.$file_extension") ) {
174     foreach my $line (<$fh>) {
175       $line =~ /^(.+?):\s*(.*)$/ and $param{$1} = $2;
176       if ( $line =~ /^-----$/ ) {
177
178         my $writeback = &$blosxom::template($path,'writeback',$blosxom::flavour) || '<p><b>Name/Blog:</b> $writeback::name$writeback::blog_name<br /><b>URL:</b> $writeback::url<br /><b>Title:</b> $writeback::title<br /><b>Comment/Excerpt:</b> $writeback::comment$writeback::excerpt</p>';
179
180         $writeback =~ s/\$writeback::(\w+)/$param{$1}/ge;
181         $writebacks .= $writeback;
182         $count++;
183       }
184     }
185
186   }
187
188   $trackback_path_and_filename = "$path/$filename";
189
190   1;
191 }
192
193 sub foot {
194   $blosxom::plugins{cookies} > 0 and $cookie and &cookies::add(
195     cookie(
196           -name=>'writeback', 
197           -value=>{ 'name' => param('name'), 'url' => param('url') }, 
198           -path=>$cookies::path,
199           -domain=>$cookies::domain,
200           -expires=>$cookies::expires
201     )
202   );
203 }
204
205 1;
206
207 __END__
208
209 =head1 NAME
210
211 Blosxom Plug-in: writeback
212
213 =head1 SYNOPSIS
214
215 Provides WriteBacks, a combination of comments and TrackBacks 
216 [http://www.movabletype.org/trackback/].
217
218 All comments and TrackBack pings for a particular story are kept in
219 $writeback_dir/$path/$filename.cmt.
220
221 =head2 QUICK START
222
223 Drop this writeback plug-in file into your plug-ins directory 
224 (whatever you set as $plugin_dir in blosxom.cgi).
225
226 Writeback, being a well-behaved plug-in, won't do anything until you set 
227 $writeback_dir.
228
229 While you can use the same directory as your blosxom $datadir (WriteBacks
230 are saved as path/weblog_entry_name.wb), it's probably better to keep
231 them separate.
232
233 Once set, the next time you visit your site, the writeback plug-in will
234 perform some checks, creating the $writeback_dir and setting appropriate
235 permissions if it doesn't already exist.  (Check your error_log for details
236 of what's happening behind the scenes.)
237
238 Move the contents of the flavours folder included in this distribution 
239 into your Blosxom data directory (whatever you set as $datadir in blosxom.cgi).
240 Don't move the folder itself, only the files it contains!  If you don't
241 have the the sample flavours handy, you can download them from:
242
243 http://www.raelity.org/apps/blosxom/downloads/plugins/writeback.zip
244
245 Point your browser at one of your Blosxom entries, specifying the writeback 
246 flavour (e.g. http://localhost/cgi-bin/blosxom.cgi/path/to/a/post.writeback)
247
248 Enjoy!
249
250 =back
251
252 =head2 FLAVOUR TEMPLATE VARIABLES
253
254 Wherever you wish all the WriteBacks for a particular story to appear
255 in your flavour templates, use $writeback::writebacks.
256
257 A count of WriteBacks for each story may be embedded in your flavour
258 templates with $writeback::count.
259
260 If you'd like, you can embed a "Thanks for the writeback." or 
261 "There was a problem posting your writeback." message after posting with
262 $writeback::writeback_response.
263
264 =head2 SAMPLE FLAVOUR TEMPLATES
265
266 I've made sample flavour templates available to you to help with any
267 learning curve this plug-in might require.
268
269 Take a gander at the source HTML/XML for:
270
271 =item * story.writeback, a basic example of a single-entry story
272 flavour with WriteBacks embedded.  You should not use this as your
273 default flavour since every story on the home page would have WriteBacks
274 right there with the story itself.
275
276 =item * foot.writeback provides a simple comment form for posting to the
277 WriteBack plug-in.  NOTE: The writeback plug-in requires the presence
278 of a "plugin" form variable with the value set to "writeback"; this tells
279 the plug-in that it should handle the incoming POSTing data rather than
280 leaving it for another plug-in.
281
282 =item * writeback.writeback is a sample flavour file for WriteBacks themselves. 
283 Think of a WriteBacks flavour file as a story flavour file for individual 
284 WriteBacks.
285
286 =back
287
288 =head2 FLAVOURING WRITEBACKS
289
290 While the default does a pretty good job, you can flavour your WriteBacks
291 in the writeback flavour file (e.g. writeback.writeback) using the following 
292 variables:
293
294 =item * $writeback::name$writeback::blog_name - Name entered in comment form or weblog name used in TrackBack ping.
295
296 =item * $writeback::url - URL entered in comment form or that of writing citing your weblog entry via TrackBack ping.
297
298 =item * $writeback::title - Title entered into comment form or that of writing citing your weblog entry via TrackBack ping.
299
300 =item * $writeback::comment$writeback::excerpt - Comment entered into comment aorm or excerpt of writing citing your weblog entry via TrackBack ping.
301
302 =item * $writeback::pref_name and $writeback::pref_url are prepopulated with the values of the form you just submitted or preferences stored in a 'writeback' cookie, if you've the cookie plug-in installed an enabled.
303
304 =back
305
306 =head2 INVITING AND SUPPORTING TRACKBACKS
307
308 You should provide the TrackBack ping URL for each story so that those
309 wanting to TrackBack ping you manually know where to ping.  
310 $writeback::trackback_path_and_filename, together with $url and 
311 a TrackBack flavour will provide them all they need.
312
313 e.g. $url$writeback::trackback_path_and_filename.trackback
314
315 The writeback plugin provides an XML response to TrackBack pings in the form
316 of a baked-in trackback flavour.  If you alter the value of $trackback_flavour
317 (why would you?), you'll have to create a set of flavour templates by hand; all 
318 should be blank save the content_type (text/xml) and head ($writeback::trackback_response).
319
320 =head1 INSTALLATION
321
322 Drop writeback into your plug-ins directory ($blosxom::plugin_dir).
323
324 =head1 CONFIGURATION
325
326 =head2 (REQUIRED) SPECIFYING A WRITEBACK DIRECTORY
327
328 Writeback, being a well-behaved plug-in, won't do anything until you set 
329 $writeback_dir, create the directory, and make it write-able by Blosxom.
330
331 Create a directory to save WriteBacks to (e.g. $plugin_state_dir/writeback),
332 and set $writeback_dir to the path to that directory.
333
334 While you can use the same directory as your blosxom $datadir (WriteBacks
335 are saved as path/weblog_entry_name.wb), it's probably better to keep
336 them separate.
337
338 The writeback plug-in will create the appropriate paths to mimick your
339 $datadir hierarchy on-the-fly.  So, for a weblog entry in 
340 $datadir/some/path/or/other/entry.txt, WriteBacks will be kept in
341 $writeback_dir/some/path/or/other/entry.wb.
342
343 =head2 (OPTIONAL) ALTERING THE TRACKBACK FLAVOUR
344
345 The $trackback_flavour sets the flavour the plug-in associates with incoming TrackBack pings.  Unless this corresponds to the flavour associated with your trackback URL, the writeback plug-in will ignore incoming pings.
346
347 =head2 (OPTIONAL) SPECIFYING AN EXTENSION FOR WRITEBACK FILES
348
349 The default extension for WriteBacks is wb.  You can change this if
350 you wish by altering the $file_extension value.
351
352 =head2 (OPTIONAL) SPECIFYING WHAT FIELDS YOU EXPECT IN YOUR COMMENTS FORM
353
354 The defaults are probably ok here, but you can specify that the writeback
355 plug-in should look for more fields in your comments form by adding to this
356 list.  You should keep at least the defaults in place so as not to break
357 anything.
358
359 my @fields = qw! name url title comment excerpt blog_name !;
360
361 =head1 VERSION
362
363 2003-09-18
364
365 =head1 AUTHOR
366
367 Rael Dornfest  <rael@oreilly.com>, http://www.raelity.org/
368
369 This plugin is now maintained by the Blosxom Sourceforge Team,
370 <blosxom-devel@lists.sourceforge.net>.
371
372 =head1 SEE ALSO
373
374 Blosxom Home/Docs/Licensing: http://blosxom.sourceforge.net/
375
376 Blosxom Plugin Docs: http://blosxom.sourceforge.net/documentation/users/plugins.html
377
378 =head1 BUGS
379
380 None known; please send bug reports and feedback to the Blosxom
381 development mailing list <blosxom-devel@lists.sourceforge.net>.
382
383 =head1 LICENSE
384
385 Blosxom and this Blosxom Plug-in
386 Copyright 2003, Rael Dornfest 
387
388 Permission is hereby granted, free of charge, to any person obtaining a
389 copy of this software and associated documentation files (the "Software"),
390 to deal in the Software without restriction, including without limitation
391 the rights to use, copy, modify, merge, publish, distribute, sublicense,
392 and/or sell copies of the Software, and to permit persons to whom the
393 Software is furnished to do so, subject to the following conditions:
394
395 The above copyright notice and this permission notice shall be included
396 in all copies or substantial portions of the Software.
397
398 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
399 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
400 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
401 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
402 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
403 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
404 OTHER DEALINGS IN THE SOFTWARE.