]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/WikiBlog.php
support new BLOG_EMPTY_DEFAULT_PREFIX
[SourceForge/phpwiki.git] / lib / plugin / WikiBlog.php
1 <?php // -*-php-*-
2 rcs_id('$Id: WikiBlog.php,v 1.21 2004-12-14 21:35:15 rurban Exp $');
3 /*
4  Copyright 2002, 2003 $ThePhpWikiProgrammingTeam
5  
6  This file is part of PhpWiki.
7
8  PhpWiki is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  PhpWiki is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with PhpWiki; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 /**
23  * @author: MichaelVanDam, major refactor by JeffDairiki
24  */
25
26 require_once('lib/TextSearchQuery.php');
27
28 /**
29  * This plugin shows 'blogs' (comments/news) associated with a
30  * particular page and provides an input form for adding a new blog.
31  *
32  * Now it is also the base class for all attachable pagetypes: 
33  *    wikiblog, comment and wikiforum
34  *
35  * HINTS/COMMENTS:
36  *
37  * To have comments show up on a separate page:
38  * On TopPage, use
39  *   <?plugin WikiBlog mode=add?>
40  * Create TopPage/Comments with:
41  *   <?plugin WikiBlog page=TopPage mode=show?>
42  *
43  * TODO:
44  *
45  * It also works as an action-page if you create a page called 'WikiBlog'
46  * containing this plugin.  This allows adding comments to any page
47  * by linking "PageName?action=WikiBlog".  Maybe a nice feature in
48  * lib/display.php would be to automatically check if there are
49  * blogs for the given page, then provide a link to them somewhere on
50  * the page.  Or maybe this just creates a huge mess...
51  *
52  * Maybe it would be a good idea to ENABLE blogging of only certain
53  * pages by setting metadata or something...?  If a page is non-bloggable
54  * the plugin is ignored (perhaps with a warning message).
55  *
56  * Should blogs be by default filtered out of RecentChanges et al???
57  *
58  * Think of better name for this module: Blog? WikiLog? WebLog? WikiDot?
59  *
60  * Have other 'styles' for the plugin?... e.g. 'quiet'.  Display only
61  * 'This page has 23 associated comments. Click here to view / add.'
62  *
63  * For admin user, put checkboxes beside comments to allow for bulk removal.
64  *
65  * Permissions for who can add blogs?  Display entry box only if
66  * user meets these requirements...?
67  *
68  * Code cleanup: break into functions, use templates (or at least remove CSS)
69  */
70
71 class WikiPlugin_WikiBlog
72 extends WikiPlugin
73 {
74     function getName () {
75         return _("WikiBlog");
76     }
77
78     function getDescription () {
79         return sprintf(_("Show and add blogs for %s"),'[pagename]');
80     }
81
82     function getVersion() {
83         return preg_replace("/[Revision: $]/", '',
84                             "\$Revision: 1.21 $");
85     }
86
87     // Arguments:
88     //  page - page which is blogged to (default current page)
89     //
90     //  order - 'normal' - place in chronological order
91     //        - 'reverse' - place in reverse chronological order
92     //
93     //  mode - 'show' - only show old blogs
94     //         'add' - only show entry box for new blog
95     //         'show,add' - show old blogs then entry box
96     //         'add,show' - show entry box followed by old blogs
97     //
98     // TODO:
99     //
100     // - arguments to allow selection of time range to display
101     // - arguments to display only XX blogs per page (can this 'paging'
102     //    co-exist with the wiki??  difficult)
103     // - arguments to allow comments outside this range to be
104     //    display as e.g. June 2002 archive, July 2002 archive, etc..
105     // - captions for 'show' and 'add' sections
106
107
108     function getDefaultArguments() {
109         return array('pagename'   => '[pagename]',
110                      'order'      => 'normal',
111                      'mode'       => 'show,add',
112                      'noheader'   => false
113                     );
114     }
115
116     function run($dbi, $argstr, &$request, $basepage) {
117         $args = $this->getArgs($argstr, $request);
118         // allow empty pagenames for ADMIN_USER style blogs: "Blogs/day"
119         //if (!$args['pagename'])
120         //    return $this->error(_("No pagename specified"));
121
122         // Get our form args.
123         $blog = $request->getArg("blog");
124         $request->setArg('blog', false);
125             
126         if ($request->isPost() and !empty($blog['addblog'])) {
127             $this->add($request, $blog); // noreturn
128         }
129
130         // Now we display previous comments and/or provide entry box
131         // for new comments
132         $html = HTML();
133         foreach (explode(',', $args['mode']) as $show) {
134             if (!empty($seen[$show]))
135                 continue;
136             $seen[$show] = 1;
137                 
138             switch ($show) {
139             case 'show':
140                 $html->pushContent($this->showAll($request, $args));
141                 break;
142             case 'add':
143                 $html->pushContent($this->showForm($request, $args));
144                 break;
145             default:
146                 return $this->error(sprintf("Bad mode ('%s')", $show));
147             }
148         }
149         return $html;
150     }
151
152     function add (&$request, $blog, $type='wikiblog') {
153         $parent = $blog['pagename'];
154         if (empty($parent)) {
155             $prefix = "";   // allow empty parent for default "Blogs/day"
156             $parent = HOME_PAGE;
157         } else {
158             $prefix = $parent . SUBPAGE_SEPARATOR;
159         }
160         //$request->finish(fmt("No pagename specified for %s",$type));
161
162         $now = time();
163         $dbi = $request->getDbh();
164         $user = $request->getUser();
165         
166         /*
167          * Page^H^H^H^H Blog meta-data
168          * This method is reused for all attachable pagetypes: wikiblog, comment and wikiforum
169          *
170          * This is info that won't change for each revision.
171          * Nevertheless, it's now stored in the revision meta-data.
172          * Several reasons:
173          *  o It's more convenient to have all information required
174          *    to render a page revision in the revision meta-data.
175          *  o We can avoid a race condition, since version meta-data
176          *    updates are atomic with the version creation.
177          */
178
179         $blog_meta = array('ctime'      => $now,
180                            'creator'    => $user->getId(),
181                            'creator_id' => $user->getAuthenticatedId(),
182                            );
183         
184
185         // Version meta-data
186         $summary = trim($blog['summary']);
187         $version_meta = array('author'    => $blog_meta['creator'],
188                               'author_id' => $blog_meta['creator_id'],
189                               'markup'    => 2.0,   // assume new markup
190                               'summary'   => $summary ? $summary : _("New comment."),
191                               'mtime'     => $now,
192                               'pagetype'  => $type,
193                               $type       => $blog_meta,
194                               );
195         if ($type == 'comment')
196             unset($version_meta['summary']);
197
198         // Comment body.
199         $body = trim($blog['body']);
200
201         $saved = false;
202         while (!$saved) {
203             // Generate the page name.  For now, we use the format:
204             //   Rootname/Blog/2003-01-11/14:03:02+00:00
205             // This gives us natural chronological order when sorted
206             // alphabetically.
207
208             $time = Iso8601DateTime();
209             if ($type == 'wikiblog')
210                 $pagename = "Blog";
211             elseif ($type == 'comment')
212                 $pagename = "Comment";
213             elseif ($type == 'wikiforum')
214                 $pagename = substr($summary,0,12);
215
216             // Check intermediate pages. If not existing they should RedirectTo the parent page.
217             // Maybe add the BlogArchives plugin instead for new interim subpage.
218             $redirected = $prefix . $pagename;
219             if (!$dbi->isWikiPage($redirected)) {
220                 require_once('lib/loadsave.php');
221                 $pageinfo = array('pagename' => $redirected,
222                                   'content'  => '<?plugin RedirectTo page='.$parent.' ?>',
223                                   'pagedata' => array(),
224                                   'versiondata' => array('author' => $blog_meta['creator']),
225                                   );
226                 SavePage($request, $pageinfo, '', '');
227             }
228             $redirected = $prefix . $pagename . SUBPAGE_SEPARATOR . preg_replace("/T.*/", "", "$time");
229             if (!$dbi->isWikiPage($redirected)) {
230                 require_once('lib/loadsave.php');
231                 $pageinfo = array('pagename' => $redirected,
232                                   'content'  => '<?plugin RedirectTo page='.$parent.' ?>',
233                                   'pagedata' => array(),
234                                   'versiondata' => array('author' => $blog_meta['creator']),
235                                   );
236                 SavePage($request, $pageinfo, '', '');
237             }
238
239             $p = $dbi->getPage($prefix . $pagename . SUBPAGE_SEPARATOR 
240                                . str_replace("T", SUBPAGE_SEPARATOR, "$time"));
241             $pr = $p->getCurrentRevision();
242
243             // Version should be zero.  If not, page already exists
244             // so increment timestamp and try again.
245             if ($pr->getVersion() > 0) {
246                 $now++;
247                 continue;
248             }
249
250             // FIXME: there's a slight, but currently unimportant
251             // race condition here.  If someone else happens to
252             // have just created a blog with the same name,
253             // we'll have locked it before we discover that the name
254             // is taken.
255             /*
256              * FIXME:  For now all blogs are locked.  It would be
257              * nice to allow only the 'creator' to edit by default.
258              */
259             $p->set('locked', true); //lock by default
260             $saved = $p->save($body, 1, $version_meta);
261
262             $now++;
263         }
264         
265         $dbi->touch();
266         $request->redirect($request->getURLtoSelf()); // noreturn
267
268         // FIXME: when submit a comment from preview mode,
269         // adds the comment properly but jumps to browse mode.
270         // Any way to jump back to preview mode???
271     }
272
273     function showAll (&$request, $args, $type="wikiblog") {
274         // FIXME: currently blogSearch uses WikiDB->titleSearch to
275         // get results, so results are in alphabetical order.
276         // When PageTypes fully implemented, could have smarter
277         // blogSearch implementation / naming scheme.
278         
279         $dbi = $request->getDbh();
280
281         $parent = $args['pagename'];
282         $blogs = $this->findBlogs($dbi, $parent, $type);
283         $html = HTML();
284         if ($blogs) {
285             // First reorder
286             usort($blogs, array("WikiPlugin_WikiBlog",
287                                 "cmp"));
288             if ($args['order'] == 'reverse')
289                 $blogs = array_reverse($blogs);
290
291             $name = $this->_blogPrefix($type);
292             if (!$args['noheader'])
293                 $html->pushContent(HTML::h4(array('class' => "$type-heading"),
294                                             fmt("%s on %s:", $name, WikiLink($parent))));
295             foreach ($blogs as $rev) {
296                 if (!$rev->get($type)) {
297                     // Ack! this is an old-style blog with data ctime in page meta-data.
298                     $content = $this->_transformOldFormatBlog($rev, $type);
299                 }
300                 else {
301                     $content = $rev->getTransformedContent($type);
302                 }
303                 $html->pushContent($content);
304             }
305             
306         }
307         return $html;
308     }
309
310     // all Blogs/Forum/Comment entries are subpages under this pagename, to find them faster.
311     function _blogPrefix($type='wikiblog') {
312         if ($type == 'wikiblog')
313             $name = _("Blogs");
314         elseif ($type == 'comment')
315             $name = _("Comments");
316         elseif ($type == 'wikiforum')
317             $name = _("Messages");
318         return $name;
319     }
320
321     function _transformOldFormatBlog($rev, $type='wikiblog') {
322         $page = $rev->getPage();
323         $metadata = array();
324         foreach (array('ctime', 'creator', 'creator_id') as $key)
325             $metadata[$key] = $page->get($key);
326         if (empty($metadata) and $type != 'wikiblog')
327             $metadata[$key] = $page->get('wikiblog');
328         $meta = $rev->getMetaData();
329         $meta[$type] = $metadata;
330         return new TransformedText($page, $rev->getPackedContent(), $meta, $type);
331     }
332
333     function findBlogs (&$dbi, $parent, $type='wikiblog') {
334         $prefix = (empty($parent) ? "" :  $parent . SUBPAGE_SEPARATOR) . $this->_blogPrefix($type);
335         $pages = $dbi->titleSearch(new TextSearchQuery("^".$prefix, true, 'posix'));
336
337         $blogs = array();
338         while ($page = $pages->next()) {
339             if (!string_starts_with($page->getName(), $prefix))
340                 continue;
341             $current = $page->getCurrentRevision();
342             if ($current->get('pagetype') == $type) {
343                 $blogs[] = $current;
344             }
345         }
346         return $blogs;
347     }
348
349     function cmp($a, $b) {
350         return(strcmp($a->get('mtime'),
351                       $b->get('mtime')));
352     }
353     
354     function showForm (&$request, $args, $template='blogform') {
355         // Show blog-entry form.
356         return new Template($template, $request,
357                             array('PAGENAME' => $args['pagename']));
358     }
359 };
360
361 // $Log: not supported by cvs2svn $
362 // Revision 1.20  2004/12/13 13:22:57  rurban
363 // new BlogArchives plugin for the new blog theme. enable default box method
364 // for all plugins. Minor search improvement.
365 //
366 // Revision 1.19  2004/11/26 18:39:02  rurban
367 // new regex search parser and SQL backends (90% complete, glob and pcre backends missing)
368 //
369 // Revision 1.18  2004/05/14 20:55:04  rurban
370 // simplified RecentComments
371 //
372 // Revision 1.17  2004/05/14 17:33:12  rurban
373 // new plugin RecentChanges
374 //
375 // Revision 1.16  2004/04/19 18:27:46  rurban
376 // Prevent from some PHP5 warnings (ref args, no :: object init)
377 //   php5 runs now through, just one wrong XmlElement object init missing
378 // Removed unneccesary UpgradeUser lines
379 // Changed WikiLink to omit version if current (RecentChanges)
380 //
381 // Revision 1.15  2004/04/18 05:42:17  rurban
382 // more fixes for page="0"
383 // better WikiForum support
384 //
385 // Revision 1.14  2004/03/29 21:33:32  rurban
386 // possible fix for problem reported by Whit Blauvelt
387 //   Message-ID: <20040327211707.GA22374@free.transpect.com>
388 // create intermediate redirect subpages for blog/comment/forum
389 //
390 // Revision 1.13  2004/03/15 10:59:40  rurban
391 // fix also early attach type bug, attached as wikiblog pagetype
392 //
393 // Revision 1.11  2004/03/12 20:59:31  rurban
394 // important cookie fix by Konstantin Zadorozhny
395 // new editpage feature: JS_SEARCHREPLACE
396 //
397 // Revision 1.10  2004/03/12 17:32:41  rurban
398 // new base class PageType_attach as base class for WikiBlog, Comment, and WikiForum.
399 // new plugin AddComment, which is a WikiBlog with different pagetype and template,
400 //   based on WikiBlog. WikiForum comes later.
401 //
402 // Revision 1.9  2004/02/27 02:10:50  rurban
403 // Patch #891133 by pablom517
404 //   "WikiBlog Plugin now sorts logs correctly"
405 //
406 // Revision 1.8  2004/02/17 12:11:36  rurban
407 // added missing 4th basepage arg at plugin->run() to almost all plugins. This caused no harm so far, because it was silently dropped on normal usage. However on plugin internal ->run invocations it failed. (InterWikiSearch, IncludeSiteMap, ...)
408 //
409 // Revision 1.7  2003/11/17 16:23:55  carstenklapp
410 // Switched to Iso8601DateTime and more use of SUBPAGE_SEPARATOR. This
411 // allows plugin UnfoldSubpages (for example) to be added to page
412 // XxYy/Blog/ where desired, for a view of all Blogs in one day. This
413 // change should not break existing BLOGs, we are only checking for
414 // pagetype == 'wikiblog' now instead of relying on the subpage name to
415 // collect blog subpages. (** WARNING: Do not add UnfoldSubpages to both
416 // XxYy/Blog/ and XxYy/Blog/2003-11/16/ pages, due to recursion bug in
417 // UnfoldSubpages plugin.)
418 //
419 // Revision 1.6  2003/02/21 04:20:09  dairiki
420 // Big refactor. Formatting now done by the stuff in PageType.php.
421 // Split the template into two separate ones: one for the add comment form,
422 // one for comment display.
423 //
424 // Revision 1.5  2003/02/16 19:47:17  dairiki
425 // Update WikiDB timestamp when editing or deleting pages.
426 //
427 // Revision 1.4  2003/01/11 22:23:00  carstenklapp
428 // More refactoring to use templated output. Use page meta "summary" field.
429 //
430 // Revision 1.3  2003/01/06 02:29:02  carstenklapp
431 // New: use blog.tmpl template to format output. Some cosmetic
432 // issues, it mostly works but code still needs cleanup. Added
433 // getVersion() for PluginManager.
434 //
435
436 // For emacs users
437 // Local Variables:
438 // mode: php
439 // tab-width: 8
440 // c-basic-offset: 4
441 // c-hanging-comment-ender-p: nil
442 // indent-tabs-mode: nil
443 // End:
444 ?>