4 * Copyright 2002,2003,2007,2009 $ThePhpWikiProgrammingTeam
6 * This file is part of PhpWiki.
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.
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.
18 * You should have received a copy of the GNU General Public License along
19 * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 * @author: MichaelVanDam, major refactor by JeffDairiki (as AddComment)
24 * @author: Changed as baseclass to AddComment and WikiForum and EditToolbar integration by ReiniUrban.
27 require_once 'lib/TextSearchQuery.php';
30 * This plugin shows 'blogs' (comments/news) associated with a
31 * particular page and provides an input form for adding a new blog.
35 * It also works as an action-page if you create a page called 'WikiBlog'
36 * containing this plugin. This allows adding comments to any page
37 * by linking "PageName?action=WikiBlog". Maybe a nice feature in
38 * lib/display.php would be to automatically check if there are
39 * blogs for the given page, then provide a link to them somewhere on
40 * the page. Or maybe this just creates a huge mess...
42 * Maybe it would be a good idea to ENABLE blogging of only certain
43 * pages by setting metadata or something...? If a page is non-bloggable
44 * the plugin is ignored (perhaps with a warning message).
46 * Should blogs be by default filtered out of RecentChanges et al???
48 * Think of better name for this module: Blog? WikiLog? WebLog? WikiDot?
50 * Have other 'styles' for the plugin?... e.g. 'quiet'. Display only
51 * 'This page has 23 associated comments. Click here to view / add.'
53 * For admin user, put checkboxes beside comments to allow for bulk removal.
55 * Permissions for who can add blogs? Display entry box only if
56 * user meets these requirements...?
58 * Code cleanup: break into functions, use templates (or at least remove CSS)
61 class WikiPlugin_WikiBlog
64 function getDescription()
66 return sprintf(_("Show and add blogs for %s."), '[pagename]');
72 // - arguments to allow selection of time range to display
73 // - arguments to display only XX blogs per page (can this 'paging'
74 // co-exist with the wiki?? difficult)
75 // - arguments to allow comments outside this range to be
76 // display as e.g. June 2002 archive, July 2002 archive, etc..
77 // - captions for 'show' and 'add' sections
79 function getDefaultArguments()
81 return array('pagename' => '[pagename]',
90 * @param string $argstr
91 * @param WikiRequest $request
92 * @param string $basepage
95 function run($dbi, $argstr, &$request, $basepage)
97 $args = $this->getArgs($argstr, $request);
100 $blog = $request->getArg("edit");
101 $request->setArg("edit", false);
103 if ($request->isPost() and !empty($blog['save'])) {
104 $this->add($request, $blog, 'wikiblog', $basepage); // noreturn
108 // Now we display previous comments and/or provide entry box
111 foreach (explode(',', $args['mode']) as $show) {
112 if (!empty($seen[$show]))
118 $html->pushContent($this->showAll($request, $args));
121 $html->pushContent($this->showForm($request, $args));
124 return $this->error(sprintf("Bad mode (ā%sā)", $show));
131 * posted: required: pagename, content. optional: summary
133 * @param WikiRequest $request
134 * @param array $posted
135 * @param string $type
137 function add(&$request, $posted, $type = 'wikiblog')
139 // This is similar to editpage. Shouldn't we use just this for preview?
140 $parent = $posted['pagename'];
141 if (empty($parent)) {
142 $prefix = ''; // allow empty parent for default "Blog/day"
144 } elseif (($parent == 'Blog' or $parent == 'WikiBlog') and $type == 'wikiblog') { // avoid Blog/Blog/2003-01-11/14:03:02+00:00
146 $parent = ''; // 'Blog';
147 } elseif ($parent == 'Comment' and $type == "comment") {
149 $parent = ''; // 'Comment';
150 } elseif ($parent == 'Forum' and $type == "wikiforum") {
152 $parent = ''; // 'Forum';
154 $prefix = $parent . '/';
158 $dbi = $request->getDbh();
159 $user = $request->getUser();
162 * Page^H^H^H^H Blog meta-data
163 * This method is reused for all attachable pagetypes: wikiblog, comment and wikiforum
165 * This is info that won't change for each revision.
166 * Nevertheless, it's now stored in the revision meta-data.
168 * o It's more convenient to have all information required
169 * to render a page revision in the revision meta-data.
170 * o We can avoid a race condition, since version meta-data
171 * updates are atomic with the version creation.
174 $blog_meta = array('ctime' => $now,
175 'creator' => $user->getId(),
176 'creator_id' => $user->getAuthenticatedId(),
180 $summary = trim($posted['summary']);
181 // edit: private only
182 $perm = new PagePermission();
183 $perm->perm['edit'] = $perm->perm['remove'];
184 $version_meta = array('author' => $blog_meta['creator'],
185 'author_id' => $blog_meta['creator_id'],
186 'summary' => $summary ? $summary : _("New comment."),
190 'perm' => $perm->perm,
192 if ($type == 'comment')
193 unset($version_meta['summary']);
196 $body = trim($posted['content']);
199 if ($type != 'wikiforum')
200 $pagename = $this->blogPrefix($type);
202 $pagename = substr($summary, 0, 12);
203 if (empty($pagename)) {
205 trigger_error("Empty title", E_USER_WARNING);
209 // Generate the page name. For now, we use the format:
210 // Rootname/Blog/2003-01-11/14:03:02+00:00
211 // Rootname = $prefix, Blog = $pagename,
212 // This gives us natural chronological order when sorted
213 // alphabetically. "Rootname/" is optional.
214 // Esp. if Rootname is named Blog, it is omitted.
216 $time = Iso8601DateTime();
217 // Check intermediate pages. If not existing they should RedirectTo the parent page.
218 // Maybe add the BlogArchives plugin instead for the new interim subpage.
219 $redirected = $prefix . $pagename;
220 if (!$dbi->isWikiPage($redirected)) {
224 require_once 'lib/loadsave.php';
225 $pageinfo = array('pagename' => $redirected,
226 'content' => '<<RedirectTo page="' . $parent . '">>',
227 'pagedata' => array(),
228 'versiondata' => array('author' => $blog_meta['creator'], 'is_minor_edit' => 1),
230 SavePage($request, $pageinfo, '');
232 $redirected = $prefix . $pagename . '/' . preg_replace("/T.*/", '', "$time");
233 if (!$dbi->isWikiPage($redirected)) {
234 if (!$parent) $parent = HOME_PAGE;
235 require_once 'lib/loadsave.php';
236 $pageinfo = array('pagename' => $redirected,
237 'content' => '<<RedirectTo page="' . $parent . '">>',
238 'pagedata' => array(),
239 'versiondata' => array('author' => $blog_meta['creator'], 'is_minor_edit' => 1),
241 SavePage($request, $pageinfo, '');
244 $p = $dbi->getPage($prefix . $pagename . '/'
245 . str_replace("T", '/', "$time"));
246 $pr = $p->getCurrentRevision();
248 // Version should be zero. If not, page already exists
249 // so increment timestamp and try again.
250 if ($pr->getVersion() > 0) {
255 // FIXME: there's a slight, but currently unimportant
256 // race condition here. If someone else happens to
257 // have just created a blog with the same name,
258 // we'll have locked it before we discover that the name
260 $saved = $p->save($body, 1, $version_meta);
266 $request->setArg("mode", "show");
267 $request->redirect($request->getURLtoSelf()); // noreturn
269 // FIXME: when submit a comment from preview mode,
270 // adds the comment properly but jumps to browse mode.
271 // Any way to jump back to preview mode???
275 * @param WikiRequest $request
277 * @param string $type
280 function showAll(&$request, $args, $type = "wikiblog")
282 // FIXME: currently blogSearch uses WikiDB->titleSearch to
283 // get results, so results are in alphabetical order.
284 // When PageTypes fully implemented, could have smarter
285 // blogSearch implementation / naming scheme.
287 $dbi = $request->getDbh();
288 $basepage = $args['pagename'];
289 $blogs = $this->findBlogs($dbi, $basepage, $type);
293 usort($blogs, array("WikiPlugin_WikiBlog",
295 if ($args['order'] == 'reverse')
296 $blogs = array_reverse($blogs);
298 $name = $this->blogPrefix($type);
299 if (!$args['noheader'])
300 $html->pushContent(HTML::h4(array('class' => "$type-heading"),
301 fmt("%s on %s:", $name, WikiLink($basepage))));
302 foreach ($blogs as $rev) {
303 if (!$rev->get($type)) {
304 // Ack! this is an old-style blog with data ctime in page meta-data.
305 $content = $this->transformOldFormatBlog($rev, $type);
307 $content = $rev->getTransformedContent($type);
309 $html->pushContent($content);
317 * Subpage for the basepage. All Blogs/Forum/Comment entries are
318 * Subpages under this pagename, to find them faster.
320 * @param string $type
323 protected function blogPrefix($type = 'wikiblog')
325 if ($type == 'wikiblog')
327 elseif ($type == 'comment')
328 $basepage = "Comment";
329 elseif ($type == 'wikiforum')
330 // $basepage = substr($summary, 0, 12);
331 $basepage = _("Message"); // FIXME: we use now the first 12 chars of the summary
335 private function transformOldFormatBlog($rev, $type = 'wikiblog')
337 $page = $rev->getPage();
339 foreach (array('ctime', 'creator', 'creator_id') as $key)
340 $metadata[$key] = $page->get($key);
341 if (empty($metadata) and $type != 'wikiblog')
342 $metadata[$key] = $page->get('wikiblog');
343 $meta = $rev->getMetaData();
344 $meta[$type] = $metadata;
345 return new TransformedText($page, $rev->getPackedContent(), $meta, $type);
348 function findBlogs(&$dbi, $basepage = '', $type = 'wikiblog')
350 $prefix = (empty($basepage)
352 : $basepage . '/') . $this->blogPrefix($type);
353 $pages = $dbi->titleSearch(new TextSearchQuery('"' . $prefix . '"', true, 'none'));
356 while ($page = $pages->next()) {
357 if (!string_starts_with($page->getName(), $prefix))
359 $current = $page->getCurrentRevision();
360 if ($current->get('pagetype') == $type) {
369 return (strcmp($a->get('mtime'),
373 function showForm(&$request, $args, $template = 'blogform')
375 $user = $request->getUser();
376 if (!($user->isSignedIn())) {
377 // Cannot create entry
378 return HTML::p(array('class' => 'warning'),
379 _('You must be logged in to add blog entries.'));
382 // Show blog-entry form.
383 $args = array('PAGENAME' => $args['pagename'],
385 HiddenInputs($request->getArgs()));
386 return new Template($template, $request, $args);
389 // "2004-12" => "December 2004"
390 protected function monthTitle($month)
392 if (!$month) $month = strftime("%Y-%m");
393 //list($year,$mon) = explode("-",$month);
394 return strftime("%B %Y", strtotime($month . "-01"));
397 // "UserName/Blog/2004-12-13/12:28:50+01:00" => array('month' => "2004-12", ...)
398 protected function _blog($rev_or_page)
400 $pagename = $rev_or_page->getName();
401 if (preg_match("/^(.*Blog)\/(\d\d\d\d-\d\d)-(\d\d)\/(.*)/", $pagename, $m))
402 list(, $prefix, $month, $day, $time) = $m;
403 return array('pagename' => $pagename,
404 // page (list pages per month) or revision (list months)?
405 //'title' => is_a($rev_or_page,'WikiDB_PageRevision') ? $rev_or_page->get('summary') : '',
406 //'monthtitle' => $this->monthTitle($month),
410 'prefix' => $prefix);
413 protected function nonDefaultArgs($args)
415 return array_diff_assoc($args, $this->getDefaultArguments());
424 // c-hanging-comment-ender-p: nil
425 // indent-tabs-mode: nil