Initial commit of H4 changes to Jonah, merged from the H4-Jonah branch.
authorMichael J. Rubinsky <mrubinsk@horde.org>
Mon, 13 Sep 2010 14:58:50 +0000 (10:58 -0400)
committerMichael J. Rubinsky <mrubinsk@horde.org>
Mon, 13 Sep 2010 14:58:50 +0000 (10:58 -0400)
Squashed commit of the following:

commit a57fb8ab6805d93e24c32adfe4f900fd9723ed83
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Aug 13 18:51:52 2010 -0400

    Use ckeditor, not fckeditor

commit 596101806148a1d0aebb1964c5e7bf8eb0656858
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Aug 13 18:46:18 2010 -0400

    Fix path to sidebar

commit 8a057adee7be185b7c60ad1be2db1928439e4577
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Aug 13 18:42:31 2010 -0400

    More H4 changes

commit dd0bf24f4f69f88e760586061b14147b73fce849
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Sat Jul 17 11:54:09 2010 -0400

    no more composite feeds either

commit 8ca4604b21b0f5f53fec362c600ee9e6714dba67
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 19:45:33 2010 -0400

    Start working on routable feed delivery requests.

commit 85f74642c1869644b97f08657ede339119269abb
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 17:58:07 2010 -0400

    re-add routes definition file, instantiate the mapper in dispatch.php

commit 6bd49d1c31bca54c9fbf9af8a3fe6912af4a3588
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 17:22:05 2010 -0400

    pdf generation view

commit 4d0ba9c055dc45b8ad59c584a30a9b4f4ff256eb
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 16:59:02 2010 -0400

    story deletion view

commit 691cf253cee9340e8646cf36195a3c866fbad2b6
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 16:45:28 2010 -0400

    move story editing to a view object.

    This will probably get refactored again, to remove the Horde_Form usage to
    give more control over the RTE, but for now, just leave it based on Horde_Form

commit 80205df3710417a4bd88ea1d11d1e277b3ea313e
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 16:32:27 2010 -0400

    story lists and story views to Jonah_View

commit 37c65c5b819bba634686bd1ddfbb4ce5d46f0fc6
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 15:14:03 2010 -0400

    view for channel editing

commit 348406b09781fd0868ab0b804af3ccfe9556c79f
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 14:56:41 2010 -0400

    ChannelDelete view

commit 9b72046aa762f45d58c639d928d8d8825c793f9c
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 13:57:40 2010 -0400

    this method needs to take an array

commit c2fe084894ad8421a274ca0257da090b5146d047
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 13:56:49 2010 -0400

    Start adding formal Jonah_View classes.

    This adds the channel list view.

commit 0775dea7ea23c4d2dbbfc16f19914225d5103ff2
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 11:18:42 2010 -0400

    remove deprecated method

commit 94bb499433bb89ea263a4b000bf0b37fb0848aeb
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 16 11:14:18 2010 -0400

    Resolve conflict - missed this during last merge.

commit 52f7f22598c20c104cc38368faa6987955a88146
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Thu Jul 15 17:47:16 2010 -0400

    simplify

commit 02a19dafff869dbc187a5c2dc3d8ad301aaf8fab
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Thu Jul 15 17:39:41 2010 -0400

    Horde_View style templating for story view.

commit b7bec9e96df0ec6d77a70f05896fae72ed0ca4bd
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Thu Jul 15 13:48:52 2010 -0400

    only show sidebar if not in an ajax view

commit d7095ab0cc85050f4185db0be1b5567fe933e8d0
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Thu Jul 15 13:47:54 2010 -0400

    Horde_View for the stories index page.

    This just moves existing templates to Horde_View, still need to
    rethink the layout, use of renderPartial, helpers etc...

commit 419ca9a3e914198d649c387330b87e5f86c50a08
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Wed Jul 14 16:14:58 2010 -0400

    Hopefully the last of the Jonah_News usage is now removed.

commit 2a6760a484a70cd43f20e89b8013c253ea181791
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 9 18:50:40 2010 -0400

    we still have composite channels

commit 968d42008125617bee6c1a834a10678ca86a9fc0
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 9 18:49:53 2010 -0400

    Use Horde_View for channel listing, remove needlessly complicated template rendering
    for channel views

commit 10e46cc2d98a99f43c29b62fa9619d810a329b0e
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 9 18:48:22 2010 -0400

    no need for aggregate view

commit 7ffd42aab69fe45dafa275848ecb886fe2417d71
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 9 17:18:47 2010 -0400

    getAvailableTypes() should be in Jonah::

commit cd9df0094b965cc11755e16cfd159630ebe8a8c0
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Fri Jul 9 16:48:16 2010 -0400

    This doesn't look right to me.

    Not sure why we wouldn't want the application's webroot if we
    are generating a full url.

commit f80000f601a3ad579f1e77a4325caa9eb038d7a0
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Tue Jul 6 17:27:04 2010 -0400

    Further work on making Jonah a content authoring application.

    Move all code over to use Jonah_Driver, and not Jonah_News
    (this means Jonah now now longer has anything to do with external channels)

    H4-ify, exceptions, prune dead code

commit 1700e73ac10461dcdd1db099af44ebd1da403ee7
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Sat Jul 3 18:18:45 2010 -0400

    fix timezone determination when user's timezone pref is empty/default.

commit 73d6b4073173f32d153a62ecf3d7cbeec2e04a45
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Sat Jul 3 15:14:42 2010 -0400

    Horde 4 CS, minor logic tweaks.

commit 2d0a3ca5b83ea5ee9cff65a446a7896d377e9eea
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Sat Jul 3 15:13:14 2010 -0400

    Horde 4 cleanup, catch exceptions.

    This block is deprecated and will be going away...

commit 68c4bef361ee907c9de3bde63f4254a93058fc25
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Sat Jul 3 13:38:15 2010 -0400

    This block doesn't need the deprecated News object, use the new Jonah_Driver.

    Some other H4 fixes as well.

commit 7f4c3e3b785499cc798ea3096d9edefe6f439580
Author: Michael J. Rubinsky <mrubinsk@horde.org>
Date:   Sat Jul 3 13:31:14 2010 -0400

    remove unused method, note that this file will be removed in the future

57 files changed:
jonah/channels/aggregate.php [deleted file]
jonah/channels/delete.php
jonah/channels/edit.php
jonah/channels/index.php
jonah/config/routes.php.dist [new file with mode: 0644]
jonah/delivery/html.php
jonah/delivery/index.php
jonah/delivery/rss.php
jonah/dispatcher.php
jonah/docs/lighttpd-jonah.conf [new file with mode: 0644]
jonah/lib/Api.php
jonah/lib/Application.php
jonah/lib/Block/cloud.php
jonah/lib/Block/delivery.php
jonah/lib/Block/latest.php
jonah/lib/Block/news.php
jonah/lib/Block/news_popular.php
jonah/lib/Block/story.php
jonah/lib/Driver.php
jonah/lib/Driver/Sql.php
jonah/lib/FeedParser.php
jonah/lib/Form/Feed.php [new file with mode: 0644]
jonah/lib/Form/Story.php [new file with mode: 0644]
jonah/lib/Forms/Feed.php [deleted file]
jonah/lib/Forms/Story.php [deleted file]
jonah/lib/Jonah.php
jonah/lib/View/Base.php [new file with mode: 0644]
jonah/lib/View/ChannelDelete.php [new file with mode: 0644]
jonah/lib/View/ChannelEdit.php [new file with mode: 0644]
jonah/lib/View/ChannelList.php [new file with mode: 0644]
jonah/lib/View/DeliveryHtml.php [new file with mode: 0644]
jonah/lib/View/StoryDelete.php [new file with mode: 0644]
jonah/lib/View/StoryEdit.php [new file with mode: 0644]
jonah/lib/View/StoryList.php [new file with mode: 0644]
jonah/lib/View/StoryPdf.php [new file with mode: 0644]
jonah/lib/View/StoryView.php [new file with mode: 0644]
jonah/stories/delete.php
jonah/stories/edit.php
jonah/stories/index.php
jonah/stories/pdf.php
jonah/stories/results.php
jonah/stories/share.php
jonah/stories/view.php
jonah/templates/channels/index.html [deleted file]
jonah/templates/common-header.inc
jonah/templates/delivery/rss.xml
jonah/templates/delivery/rss2.xml
jonah/templates/delivery/rss2_full.xml
jonah/templates/delivery/rss_full.xml
jonah/templates/menu.inc [new file with mode: 0644]
jonah/templates/stories/index.html [deleted file]
jonah/templates/stories/index.html.php [new file with mode: 0644]
jonah/templates/stories/layout/view.html.php [new file with mode: 0644]
jonah/templates/stories/partial/_story.html.php [new file with mode: 0644]
jonah/templates/stories/story.html [deleted file]
jonah/templates/stories/view.html [deleted file]
jonah/templates/view/channellist.html.php [new file with mode: 0644]

diff --git a/jonah/channels/aggregate.php b/jonah/channels/aggregate.php
deleted file mode 100644 (file)
index 38d9c36..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-<?php
-/**
- * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file LICENSE for license information (BSD). If you
- * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
- *
- * @author Jan Schneider <jan@horde.org>
- */
-
-require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah');
-
-function _getLinks($id, $subid, $name, $title)
-{
-    $url = Horde::url('channels/aggregate.php');
-    $url = Horde_Util::addParameter($url, 'channel_id', $id);
-    $url = Horde_Util::addParameter($url, 'subchannel_id', $subid);
-    $edit = array('url' => Horde_Util::addParameter($url,'action', 'edit'), 'text' => sprintf(_("Edit channel \"%s\""), $name), 'title' => $title);
-    $delete = array('url' => Horde_Util::addParameter($url, 'action', 'delete'), 'text' => sprintf(_("Remove channel \"%s\""), $name), 'title' => $title);
-    return array($edit, $delete);
-}
-
-$news = Jonah_News::factory();
-$renderer = new Horde_Form_Renderer();
-$vars = Horde_Variables::getDefaultVariables();
-
-/* Set up some variables. */
-$channel_id = $vars->get('channel_id');
-$channel = $news->getChannel($channel_id);
-if ($channel instanceof PEAR_Error) {
-    throw new Jonah_Exception($channel);
-}
-$channel_name = $channel['channel_name'];
-$ids = preg_split('/:/', $channel['channel_url'], -1, PREG_SPLIT_NO_EMPTY);
-
-/* Get the vars for channel type. */
-$channel_type = $channel['channel_type'];
-if ($channel_type != Jonah::AGGREGATED_CHANNEL) {
-    $notification->push(_("This is no aggregated channel."), 'horde.error');
-    Horde::url('channels/edit.php', true)
-        ->add('channel_id', $channel_id)
-        ->redirect();
-}
-
-/* Check permissions and deny if not allowed. */
-if (!Jonah::checkPermissions(Jonah::typeToPermName($channel_type), Horde_Perms::EDIT, $channel_id)) {
-    $notification->push(_("You are not authorised for this action."), 'horde.warning');
-    Horde::authenticationFailureRedirect();
-}
-
-/* Set up the form. */
-$form = new Horde_Form($vars, sprintf(_("Aggregated channels for channel \"%s\""), $channel_name), 'channel_aggregate');
-$form->setButtons(_("Add"));
-$form->addHidden('', 'channel_id', 'int', false);
-$form->addVariable(_("Channel Name"), 'channel_name', 'text', true);
-$form->addVariable(_("Source URL"), 'channel_url', 'text', true, false, _("The url to use to fetch the stories, for example 'http://www.example.com/stories.rss'"));
-$form->addVariable(_("Link"), 'channel_link', 'text', false);
-$form->addVariable(_("Image"), 'channel_img', 'text', false);
-
-if ($form->validate($vars)) {
-    $subchannel = array('channel_url' => $vars->get('channel_url'),
-                        'channel_name' => $vars->get('channel_name'),
-                        'channel_link' => $vars->get('channel_link'),
-                        'channel_img' => $vars->get('channel_img'),
-                        'channel_type' => Jonah::EXTERNAL_CHANNEL);
-    if ($vars->get('subchannel_id')) {
-        $subchannel['channel_id'] = $vars->get('subchannel_id');
-    }
-    $save = $news->saveChannel($subchannel);
-    if (is_a($save, 'PEAR_Error')) {
-        $notification->push(sprintf(_("There was an error saving the channel: %s"), $save->getMessage()), 'horde.error');
-    } else {
-        $notification->push(sprintf(_("The channel \"%s\" has been saved."), $vars->get('channel_name')), 'horde.success');
-        if (!$vars->get('subchannel_id')) {
-            $ids[] = $save;
-            $channel['channel_url'] = implode(':', $ids);
-            $save = $news->saveChannel($channel);
-            if (is_a($save, 'PEAR_Error')) {
-                $notification->push(sprintf(_("There was an error updating the channel: %s"), $save->getMessage()), 'horde.error');
-            } else {
-                $notification->push(sprintf(_("The channel \"%s\" has been updated."), $channel['channel_name']), 'horde.success');
-            }
-        }
-
-        Horde::url('channels/aggregate.php', true)
-            ->add('channel_id', $channel_id)
-            ->redirect();
-    }
-} elseif ($vars->get('action') == 'delete') {
-    $subchannel = $news->getChannel($vars->get('subchannel_id'));
-    $result = $news->deleteChannel($vars->get('subchannel_id'));
-    if (is_a($result, 'PEAR_Error')) {
-        $notification->push(sprintf(_("There was an error removing the channel: %s"), $result->getMessage()), 'horde.error');
-    } else {
-        $notification->push(sprintf(_("The channel \"%s\" has been removed."), $subchannel['channel_name']), 'horde.success');
-        array_splice($ids, array_search($subchannel['channel_id'], $ids), 1);
-        $channel['channel_url'] = implode(':', $ids);
-        $save = $news->saveChannel($channel);
-        if (is_a($save, 'PEAR_Error')) {
-            $notification->push(sprintf(_("There was an error updating the channel: %s"), $save->getMessage()), 'horde.error');
-        } else {
-            $notification->push(sprintf(_("The channel \"%s\" has been updated."), $channel['channel_name']), 'horde.success');
-        }
-    }
-
-    Horde::url('channels/aggregate.php', true)
-        ->add('channel_id', $channel_id)
-        ->redirect();
-} elseif ($vars->get('action') == 'edit') {
-    $form->addHidden('', 'subchannel_id', 'int', false);
-    $form->setButtons(_("Update"));
-    $subchannel = $news->getChannel($vars->get('subchannel_id'));
-    $vars->set('channel_name', $subchannel['channel_name']);
-    $vars->set('channel_url', $subchannel['channel_url']);
-    $vars->set('channel_link', $subchannel['channel_link']);
-    $vars->set('channel_img', $subchannel['channel_img']);
-}
-
-foreach ($ids as $id) {
-    $subchannel = $news->getChannel($id);
-    if (is_a($subchannel, 'PEAR_Error')) {
-        $name = $subchannel->getMessage();
-        $url = '';
-    } elseif (empty($subchannel['channel_name'])) {
-        $name = $subchannel['channel_url'];
-        $url = $subchannel['channel_url'];
-    } else {
-        $name = $subchannel['channel_name'];
-        $url = $subchannel['channel_url'];
-    }
-    $form->insertVariableBefore('channel_name', '', 'subchannel' . $id, 'link', false, false, null, array(_getLinks($channel_id, $id, $name, $url)));
-}
-
-Horde::startBuffer();
-$form->renderActive($renderer, $vars, 'aggregate.php', 'post');
-$main = Horde::endBuffer();
-
-$template = new Horde_Template();
-$template->set('main', $main);
-$template->set('menu', Horde::menu());
-
-// Buffer the notifications and send to the template
-Horde::startBuffer();
-$GLOBALS['notification']->notify(array('listeners' => 'status'));
-$template->set('notify', Horde::endBuffer());
-
-require JONAH_TEMPLATES . '/common-header.inc';
-echo $template->fetch(JONAH_TEMPLATES . '/main/main.html');
-require $registry->get('templates', 'horde') . '/common-footer.inc';
index 670cc2d..b31f761 100644 (file)
@@ -1,89 +1,22 @@
 <?php
 /**
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
- *
- * $Horde: jonah/channels/delete.php,v 1.36 2009/11/24 04:15:37 chuck Exp $
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author Chuck Hagenbuch <chuck@horde.org>
  * @author Marko Djukic <marko@oblo.com>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
  */
-
 require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah');
-require_once 'Horde/Form.php';
-require_once 'Horde/Form/Renderer.php';
-
-$news = Jonah_News::factory();
+Horde_Registry::appInit('jonah');
 
 /* Set up the form variables and the form. */
-$vars = Horde_Variables::getDefaultVariables();
-$form_submit = $vars->get('submitbutton');
-$channel_id = $vars->get('channel_id');
-
-$channel = $news->getChannel($channel_id);
-if (is_a($channel, 'PEAR_Error')) {
-    $notification->push(_("Invalid channel specified for deletion."), 'horde.message');
-    Horde::url('channels/index.php', true)->redirect();
-}
-
-/* Check permissions and deny if not allowed. */
-if (!Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::DELETE, $channel_id)) {
-    $notification->push(_("You are not authorised for this action."), 'horde.warning');
-    Horde::authenticationFailureRedirect();
-}
-
-/* If not yet submitted set up the form vars from the fetched
- * channel. */
-if (empty($form_submit)) {
-    $vars = new Horde_Variables($channel);
-}
-
-$title = sprintf(_("Delete News Channel \"%s\"?"), $vars->get('channel_name'));
-$form = new Horde_Form($vars, $title);
-
-$form->setButtons(array(_("Delete"), _("Do not delete")));
-$form->addHidden('', 'channel_id', 'int', true, true);
-
-$msg = _("Really delete this News Channel?");
-if ($vars->get('channel_type') == Jonah::INTERNAL_CHANNEL) {
-    $msg .= ' ' . _("All stories created in this channel will be lost!");
-} else {
-    $msg .= ' ' . _("Any cached stories for this channel will be lost!");
-}
-$form->addVariable($msg, 'confirm', 'description', false);
-
-if ($form_submit == _("Delete")) {
-    if ($form->validate($vars)) {
-        $form->getInfo($vars, $info);
-        $delete = $news->deleteChannel($info);
-        if (is_a($delete, 'PEAR_Error')) {
-            $notification->push(sprintf(_("There was an error deleting the channel: %s"), $delete->getMessage()), 'horde.error');
-        } else {
-            $notification->push(_("The channel has been deleted."), 'horde.success');
-            Horde::url('channels/index.php', true)->redirect();
-        }
-    }
-} elseif (!empty($form_submit)) {
-    $notification->push(_("Channel has not been deleted."), 'horde.message');
-    Horde::url('channels/index.php', true)->redirect();
-}
-
-$template = new Horde_Template();
-
-// Buffer the main form and send to the template
-Horde::startBuffer();
-$form->renderActive(null, $vars, 'delete.php', 'post');
-$template->set('main', Horde::endBuffer());
-$template->set('menu', Horde::menu());
-
-// Buffer the notifications and send to the template
-Horde::startBuffer();
-$GLOBALS['notification']->notify(array('listeners' => 'status'));
-$template->set('notify', Horde::endBuffer());
+$params = array('vars' => Horde_Variables::getDefaultVariables(),
+                'registry' => &$registry,
+                'notification' => &$notification);
 
-require JONAH_TEMPLATES . '/common-header.inc';
-echo $template->fetch(JONAH_TEMPLATES . '/main/main.html');
-require $registry->get('templates', 'horde') . '/common-footer.inc';
+$view = new Jonah_View_ChannelDelete($params);
+$view->run();
index b7c198d..8890dbb 100644 (file)
@@ -1,95 +1,22 @@
 <?php
 /**
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
- *
- * $Horde: jonah/channels/edit.php,v 1.37 2009/11/24 04:15:37 chuck Exp $
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author Chuck Hagenbuch <chuck@horde.org>
  * @author Marko Djukic <marko@oblo.com>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
  */
 
 require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah');
-require_once JONAH_BASE . '/lib/Forms/Feed.php';
-require_once 'Horde/Form/Renderer.php';
-
-$news = Jonah_News::factory();
-
-/* Set up the form variables and the form. */
-$vars = Horde_Variables::getDefaultVariables();
-$form = new FeedForm($vars);
-
-/* Set up some variables. */
-$formname = $vars->get('formname');
-$channel_id = $vars->get('channel_id');
-
-/* Form not yet submitted and is being edited. */
-if (!$formname && $channel_id) {
-    $vars = new Horde_Variables($news->getChannel($channel_id));
-}
-
-/* Get the vars for channel type. */
-$channel_type = $vars->get('channel_type');
-$old_channel_type = $vars->get('old_channel_type');
-$changed_type = false;
-
-/* Check permissions and deny if not allowed. */
-if (!Jonah::checkPermissions(Jonah::typeToPermName($channel_type), Horde_Perms::EDIT, $channel_id)) {
-    $notification->push(_("You are not authorised for this action."), 'horde.warning');
-    Horde::authenticationFailureRedirect();
-}
-
-/* If this is null then new form, so set both to default. */
-if (is_null($channel_type)) {
-    $channel_type = Jonah_News::getDefaultType();
-    $old_channel_type = $channel_type;
-}
-
-/* Check if channel type has been changed and notify. */
-if ($channel_type != $old_channel_type && $formname) {
-    $changed_type = true;
-    $notification->push(_("Feed type changed."), 'horde.message');
-}
-$vars->set('old_channel_type', $channel_type);
-
-/* Output the extra fields required for this channel type. */
-$form->setExtraFields($channel_type, $channel_id);
-
-if ($formname && !$changed_type) {
-    if ($form->validate($vars)) {
-        $form->getInfo($vars, $info);
-        $save = $news->saveChannel($info);
-        if (is_a($save, 'PEAR_Error')) {
-            $notification->push(sprintf(_("There was an error saving the feed: %s"), $save->getMessage()), 'horde.error');
-        } else {
-            $notification->push(sprintf(_("The feed \"%s\" has been saved."), $info['channel_name']), 'horde.success');
-            if ($channel_type == Jonah::AGGREGATED_CHANNEL) {
-                $notification->push(_("You can now edit the sub-feeds."), 'horde.message');
-            } else {
-                Horde::url('channels/index.php', true)->redirect();
-            }
-        }
-    }
-}
-
-$renderer = new Horde_Form_Renderer();
-Horde::startBuffer();
-$form->renderActive($renderer, $vars, 'edit.php', 'post');
-$main = Horde::endBuffer();
-
-$template = new Horde_Template();
-$template->set('main', $main);
-$template->set('menu', Horde::menu());
+Horde_Registry::appInit('jonah');
 
-// Buffer the notifications and send to the template
-Horde::startBuffer();
-$GLOBALS['notification']->notify(array('listeners' => 'status'));
-$template->set('notify', Horde::endBuffer());
+$params = array('vars' => Horde_Variables::getDefaultVariables(),
+                'registry' => &$registry,
+                'notification' => &$notification);
 
-$title = $form->getTitle();
-require JONAH_TEMPLATES . '/common-header.inc';
-echo $template->fetch(JONAH_TEMPLATES . '/main/main.html');
-require $registry->get('templates', 'horde') . '/common-footer.inc';
+$view = new Jonah_View_ChannelEdit($params);
+$view->run();
index cb252f3..9eea17b 100644 (file)
@@ -1,99 +1,37 @@
 <?php
 /**
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
- *
- * $Horde: jonah/channels/index.php,v 1.49 2009/11/24 04:15:37 chuck Exp $
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author Chuck Hagenbuch <chuck@horde.org>
  * @author Marko Djukic <marko@oblo.com>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
  */
 
 require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah');
+Horde_Registry::appInit('jonah');
 
 if (!Jonah::checkPermissions('jonah:news', Horde_Perms::EDIT)) {
     $notification->push(_("You are not authorised for this action."), 'horde.warning');
     $registry->authenticateFailure();
 }
 
-$have_news = Jonah_News::getAvailableTypes();
+$have_news = Jonah::getAvailableTypes();
 if (empty($have_news)) {
     $notification->push(_("News is not enabled."), 'horde.warning');
-    Horde::url('index.php', true)->redirect();
-}
-
-$news = Jonah_News::factory();
-
-$channels = $news->getChannels(array_keys($have_news));
-if (is_a($channels, 'PEAR_Error')) {
-    $notification->push(sprintf(_("An error occurred fetching channels: %s"), $channels->getMessage()), 'horde.error');
-    $channels = false;
-} elseif ($channels) {
-    $channels = Jonah::checkPermissions('channels', Horde_Perms::SHOW, $channels);
-    /* Build channel specific fields. */
-    foreach ($channels as $key => $channel) {
-        /* Edit channel link. */
-        $url = Horde::url('channels/edit.php');
-        $url = Horde_Util::addParameter($url, 'channel_id', $channel['channel_id']);
-        $channels[$key]['edit_link'] = Horde::link($url, _("Edit channel"), '', '', '', _("Edit channel")) . Horde::img('edit.png') . '</a>';
-
-        /* Delete channel link. */
-        $url = Horde::url('channels/delete.php');
-        $url = Horde_Util::addParameter($url, 'channel_id', $channel['channel_id']);
-        $channels[$key]['delete_link'] = Horde::link($url, _("Delete channel"), '', '', '', _("Delete channel")) . Horde::img('delete.png') . '</a>';
 
-        /* View stories link. */
-        $url = Horde::url('stories/index.php');
-        $url = Horde_Util::addParameter($url, 'channel_id', $channel['channel_id']);
-        $channels[$key]['stories_url'] = $url;
-
-        /* Channel type specific links. */
-        $channels[$key]['addstory_link'] = '';
-        $channels[$key]['refresh_link'] = '';
-
-        switch ($channel['channel_type']) {
-        case Jonah::INTERNAL_CHANNEL:
-            /* Add story link. */
-            $url = Horde::url('stories/edit.php');
-            $url = Horde_Util::addParameter($url, 'channel_id', $channel['channel_id']);
-            $channels[$key]['addstory_link'] = Horde::link($url, _("Add story"), '', '', '', _("Add story")) . Horde::img('new.png') . '</a>';
-            break;
-
-        case Jonah::EXTERNAL_CHANNEL:
-        case Jonah::AGGREGATED_CHANNEL:
-            /* Refresh cache link. */
-            $url = Horde::url('stories/index.php');
-            $url = Horde_Util::addParameter($url, array('channel_id' => $channel['channel_id'], 'refresh' => '1', 'url' => Horde::selfUrl()));
-            $channels[$key]['refresh_link'] = Horde::link($url, _("Refresh channel"), '', '', '', _("Refresh channel")) . Horde::img('reload.png') . '</a>';
-            break;
-        }
-
-        $channels[$key]['channel_type'] = Jonah::getChannelTypeLabel($channel['channel_type']);
-        /* TODO: pref setting for date display. */
-        $channels[$key]['channel_updated'] = ($channel['channel_updated'] ? date('M d, Y H:i', (int)$channel['channel_updated']) : '-');
-    }
+    $url = Horde::url('index.php');
+    header('Location: ' . $url);
+    exit;
 }
 
-$template = new Horde_Template();
-$template->set('header', _("Manage Feeds"));
-$template->set('listheaders', array(array('attrs' => ' class="sortdown"', 'label' => _("Name")),
-                                    array('attrs' => '', 'label' => _("Type")),
-                                    array('attrs' => '', 'label' => _("Last Update"))));
-$template->set('channels', $channels, true);
-$template->set('menu', Horde::menu());
-$template->set('search_img', Horde::img('search.png'));
-
-// Buffer the notifications and send to the template
-Horde::startBuffer();
-$GLOBALS['notification']->notify(array('listeners' => 'status'));
-$template->set('notify', Horde::endBuffer());
+$params = array('notification' => &$notification,
+                'prefs' => &$prefs,
+                'registry' => &$registry
+          );
 
-$title = _("Feeds");
-Horde::addScriptFile('tables.js', 'horde', true);
-Horde::addScriptFile('quickfinder.js', 'horde', true);
-require JONAH_TEMPLATES . '/common-header.inc';
-echo $template->fetch(JONAH_TEMPLATES . '/channels/index.html');
-require $registry->get('templates', 'horde') . '/common-footer.inc';
+$view = new Jonah_View_ChannelList($params);
+$view->run();
\ No newline at end of file
diff --git a/jonah/config/routes.php.dist b/jonah/config/routes.php.dist
new file mode 100644 (file)
index 0000000..12942c1
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Setup default routes
+ */
+$m->connect('Admin', '/admin/:section/:page', array(
+     'controller' => 'admin',
+     'section' => '',
+     'page' => '',
+));
+
+// Valid filter names are "author", "tag" and "date"
+// @TODO represent those with route requirements
+$m->connect('Default', '/feeds/:feed/:filter/:value', array(
+    'controller' => 'feed',
+    'feed' => '',
+    'filter' => '',
+    'value' => '',
+));
+
+// api endpoint for getting post counts?
+//$m->connect('/feeds/:feed/-/posts/count', array(
+//    'controller' => 'api',
+//    'action' => 'count'));
+
+
+// Local route overrides
+if (file_exists(dirname(__FILE__) . '/routes.local.php')) {
+    include dirname(__FILE__) . '/routes.local.php';
+}
index 06cecdf..cbc79b7 100644 (file)
@@ -2,7 +2,7 @@
 /**
  * Script to handle requests for html delivery of stories.
  *
- * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you did not
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
@@ -15,56 +15,22 @@ $jonah = Horde_Registry::appInit('jonah', array(
     'authentication' => 'none',
     'session_control' => 'readonly'
 ));
-require JONAH_BASE . '/config/templates.php';
-
-// TODO - check if a user, have button to add channel to their
-// personal aggregated channel.
-
-$news = Jonah_News::factory();
 
 /* Get the id and format of the channel to display. */
 $criteria = Horde_Util::nonInputVar('criteria');
 if (!$criteria) {
-    $criteria['channel_id'] = Horde_Util::getFormData('channel_id');
-    $criteria['channel_format'] = Horde_Util::getFormData('format');
+    $criteria['feed'] = Horde_Util::getFormData('channel_id');
+    $criteria['format'] = Horde_Util::getFormData('format');
 }
-
-if (empty($criteria['channel_format'])) {
+if (empty($criteria['format'])) {
     // Select the default channel format
-    $criteria['channel_format'] = key($templates);
-}
-
-/* Get requested channel. */
-$channel = $news->getChannel($criteria['channel_id']);
-if (is_a($channel, 'PEAR_Error')) {
-    Horde::logMessage($channel, 'ERR');
-    $notification->push(_("Invalid channel."), 'horde.error');
-    Horde::url('delivery/index.php', true)->redirect();
+    // TODO: FIXME
+    $criteria['format'] = 'standard';
 }
 
-$title = sprintf(_("HTML Delivery for \"%s\""), $channel['channel_name']);
-
-$options = array();
-foreach ($templates as $key => $info) {
-    $options[] = '<option value="' . $key . '"' . ($key == $criteria['channel_format'] ? ' selected="selected"' : '') . '>' . $info['name'] . '</option>';
-}
-
-$template = new Horde_Template();
-$template->setOption('gettext', 'true');
-$template->set('url', Horde::selfUrl());
-$template->set('session', Horde_Util::formInput());
-$template->set('channel_id', $criteria['channel_id']);
-$template->set('channel_name', $channel['channel_name']);
-$template->set('format', $criteria['channel_format']);
-$template->set('options', $options);
-$template->set('stories', $news->renderChannel($criteria['channel_id'], $criteria['channel_format']));
-$template->set('menu', Horde::menu());
-
-// Buffer the notifications and send to the template
-Horde::startBuffer();
-$GLOBALS['notification']->notify(array('listeners' => 'status'));
-$template->set('notify', Horde::endBuffer());
-
-require JONAH_TEMPLATES . '/common-header.inc';
-echo $template->fetch(JONAH_TEMPLATES . '/delivery/html.html');
-require $registry->get('templates', 'horde') . '/common-footer.inc';
+$params = array('registry' => &$registry,
+                'notification' => &$notification,
+                'conf' => &$conf,
+                'criteria' => &$criteria);
+$view = new Jonah_View_DeliveryHtml($params);
+$view->run();
index 6669b3d..c23fbe3 100644 (file)
@@ -1,15 +1,13 @@
 <?php
 /**
- * $Horde: jonah/delivery/index.php,v 1.27 2009/06/10 05:24:47 slusarz Exp $
  *
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you did
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author Ben Klang <ben@alkaloid.net>
  */
-
 $parts = explode('/', Horde_Util::getPathInfo());
 $lastpart = null;
 $deliveryType = null;
index 197d922..d50b881 100644 (file)
@@ -1,42 +1,41 @@
 <?php
 /**
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you did
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author Chuck Hagenbuch <chuck@horde.org>
  */
-
 require_once dirname(__FILE__) . '/../lib/Application.php';
 $jonah = Horde_Registry::appInit('jonah', array(
     'authentication' => 'none',
     'session_control' => 'readonly'
 ));
 
-$news = Jonah_News::factory();
+$driver = $GLOBALS['injector']->getInstance('Jonah_Driver');
 
-// See if the criteria has already been loaded by the index page
+/* See if the criteria has already been loaded by the index page */
 $criteria = Horde_Util::nonInputVar('criteria');
 if (!$criteria) {
-    $criteria = array();
-    $criteria['channel_id'] = Horde_Util::getFormData('channel_id');
-    $criteria['tag_id'] = Horde_Util::getFormData('tag_id');
-    $criteria['feed_type'] = basename(Horde_Util::getFormData('type'));
+    $criteria = array(
+        'channel_id' => Horde_Util::getFormData('channel_id'),
+        'tag_id' => Horde_Util::getFormData('tag_id'),
+        'feed_type' => basename(Horde_Util::getFormData('type'))
+    );
 }
 
+/* Default to RSS2 */
 if (empty($criteria['feed_type'])) {
-    // If not specified, default to RSS2
     $criteria['feed_type'] = 'rss2';
 }
 
 /* Fetch the channel info and the story list and check they are both valid.
  * Do a simple exit in case of errors. */
-
-
-$channel = $news->getChannel($criteria['channel_id']);
-if (is_a($channel, 'PEAR_Error')) {
-    Horde::logMessage($channel, 'ERR');
+try {
+    $channel = $driver->getChannel($criteria['channel_id']);
+} catch (Exception $e) {
+    Horde::logMessage($e, 'ERR');
     header('HTTP/1.0 404 Not Found');
     echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
 <html><head>
@@ -48,19 +47,25 @@ if (is_a($channel, 'PEAR_Error')) {
     exit;
 }
 
-/* Check for a tag search. */
+/* Build search array */
+$search = array('channel_id' => $criteria['channel_id'],
+                'tags' => array($criteria['tag_id'],
+                'limit' => 10));
+
+/* Used in template for channel name */
 if (!empty($criteria['tag_id'])) {
-    $tag_name = array_shift($news->getTagNames(array($criteria['tag_id'])));
-    $stories = $news->searchTagsById(array($criteria['tag_id']), 10, 0, array($criteria['channel_id']));
-} else {
-    $stories = $news->getStories($criteria['channel_id'], 10, 0, false, time());
+    $tag_name = array_shift($driver->getTagNames(array($criteria['tag_id'])));
 }
-if (is_a($stories, 'PEAR_Error')) {
-    Horde::logMessage($stories, 'ERR');
+
+/* Fetch stories */
+try {
+    $stories = $driver->getStories($criteria);
+} catch (Exception $e) {
+    Horde::logMessage($e, 'ERR');
     $stories = array();
 }
 
-
+/* Build the template (@TODO: Use Horde_View) */
 $template = new Horde_Template();
 $template->set('charset', $GLOBALS['registry']->getCharset());
 $template->set('jonah', 'Jonah ' . $registry->getVersion() . ' (http://www.horde.org/jonah/)');
@@ -76,13 +81,12 @@ $template->set('channel_official', htmlspecialchars($channel['channel_official']
 $template->set('channel_rss', htmlspecialchars(Horde_Util::addParameter(Horde::url('delivery/rss.php', true, -1), array('type' => 'rss', 'channel_id' => $channel['channel_id']))));
 $template->set('channel_rss2', htmlspecialchars(Horde_Util::addParameter(Horde::url('delivery/rss.php', true, -1), array('type' => 'rss2', 'channel_id' => $channel['channel_id']))));
 foreach ($stories as &$story) {
-    $story['story_title'] = @htmlspecialchars($story['story_title'], ENT_COMPAT, $GLOBALS['registry']->getCharset());
-    $story['story_desc'] = @htmlspecialchars($story['story_desc'], ENT_COMPAT, $GLOBALS['registry']->getCharset());
-    $story['story_link'] = htmlspecialchars($story['story_link']);
-    $story['story_permalink'] = (isset($story['story_permalink']) ? htmlspecialchars($story['story_permalink']) : '');
-    $story['story_published'] = htmlspecialchars(date('r', $story['story_published']));
-    if (!empty($story['story_body_type']) && $story['story_body_type'] == 'text') {
-        $story['story_body'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['story_body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
+    $story['title'] = @htmlspecialchars($story['title'], ENT_COMPAT, $GLOBALS['registry']->getCharset());
+    $story['description'] = @htmlspecialchars($story['description'], ENT_COMPAT, $GLOBALS['registry']->getCharset());
+    $story['permalink'] = htmlspecialchars($story['permalink']);
+    $story['published'] = htmlspecialchars(date('r', $story['published']));
+    if (!empty($story['body_type']) && $story['body_type'] == 'text') {
+        $story['body'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
     }
 }
 $template->set('stories', $stories);
index 49e59f0..2de6623 100644 (file)
@@ -8,25 +8,32 @@
  * @author Ben Klang <ben@alkaloid.net>
  */
 
-require_once dirname(__FILE__) . '/../lib/Application.php';
+require_once dirname(__FILE__) . '/lib/Application.php';
 $jonah = Horde_Registry::appInit('jonah', array(
     'authentication' => 'none',
     'session_control' => 'readonly'
 ));
-$jonah = Horde_Registry::appInit('jonah');
 
+$m = new Horde_Routes_Mapper();
+
+require JONAH_BASE . '/config/routes.php';
 require JONAH_BASE . '/config/templates.php';
 
 // Grab, and hopefully match, the URL
-$url = Horde_Util::getPathInfo();
-parse_str($_SERVER['QUERY_STRING'], $args);
-Horde_Util::dispelMagicQuotes($args);
+$request = new Horde_Controller_Request_Http();
+$url = $request->getPath();
+
+$args = $request->getGetParams();
+$result = $m->match('/' . $url);
 
 $criteria = array();
-$result = $m->match($url);
-if (isset($result['controller']) && $result['controller'] == 'admin') {
-    // Insert admin controllers here.
-} elseif (isset($result['feed'])) {
+// @TODO: This should be handled by controller objects, but for now just use
+// a switch conditional until we move to Horde_Controller
+switch ($result['controller']) {
+case 'admin':
+    // TODO:
+    exit;
+case 'feed':
     // Default settings
     $defaults = array(
         'format' => 'html',
@@ -60,6 +67,8 @@ if (isset($result['controller']) && $result['controller'] == 'admin') {
                 break;
             }
 
+        // @TODO: These will be implemented as GData's categories, not as
+        // part of the route proper.
         case 'tag':
             $criteria['tags'] = array($result['value']);
             break;
@@ -145,7 +154,19 @@ if (isset($result['controller']) && $result['controller'] == 'admin') {
     }
 
     // Preserve remaining args
+    // @TODO: Don't think we need to preserve the query string once we get here.
     $criteria = array_merge($defaults, $args, $criteria);
-
-    require dirname(__FILE__) . '/feed.php';
+    $class = 'Jonah_View_Delivery' . $criteria['format'];
+
+    //@TODO: FIXME - format (html/rss/pdf) is dealt with by the view object we
+    // instantiate but html _currently_ needs a format. Think we'll just have to
+    // pick a default format to render when requested this way.
+    $criteria['format'] = 'standard';
+    $params = array('registry' => &$registry,
+                    'notification' => &$notification,
+                    'conf' => &$conf,
+                    'criteria' => &$criteria);
+    $view = new $class($params);
+    $view->run();
+    break;
 }
diff --git a/jonah/docs/lighttpd-jonah.conf b/jonah/docs/lighttpd-jonah.conf
new file mode 100644 (file)
index 0000000..059fe4e
--- /dev/null
@@ -0,0 +1,15 @@
+## This file should be reviewed prior to inclusion in your lighttpd
+## configuration.  Specifically, if you have jonah somewhere other than
+## /horde/jonah you will need to edit the following rules to match your server
+## configuration.
+
+## This file should be included in your lighttpd.conf file with the "include"
+## directive. Example:
+##   include "path/to/lighttpd-jonah.conf"
+## The exact path you use will of course depend on your specific configuration.
+
+## Rules for handling restful delivery requests
+url.rewrite-once += (
+     "^/horde/jonah/feeds/(.*)\?(.*)$" => "/horde/jonah/dispatcher.php?$2",
+     "^/horde/jonah/feeds/(.*)$" => "/horde/jonah/dispatcher.php"
+)
\ No newline at end of file
index a61f2c6..3f25a43 100644 (file)
@@ -5,6 +5,12 @@
  * This file defines Jonah's external API interface. Other
  * applications can interact with Jonah through this API.
  *
+ * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
  * @package Jonah
  */
 class Jonah_Api extends Horde_Registry_Api
@@ -12,44 +18,47 @@ class Jonah_Api extends Horde_Registry_Api
     /**
      * Get a list of stored channels.
      *
-     * @param integer $type  The type of channel to filter for. Possible
-     *                       values are either Jonah::INTERNAL_CHANNEL
-     *                       to fetch only a list of internal channels,
-     *                       or Jonah::EXTERNAL_CHANNEL for only external.
-     *                       If null both channel types are returned.
-     *
-     * @return mixed         An array of channels or PEAR_Error on error.
+     * @return array An array of channels
      */
-    public function listFeeds($type = null)
+    public function listFeeds()
     {
-        $news = Jonah_News::factory();
-        $channels = $news->getChannels($type);
-
-        return $channels;
+        return $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannels();
     }
 
     /**
      * Return the requested stories
      *
-     * @param int $channel_id   The channel to get the stories from.
-     * @param int $max_stories  The maximum number of stories to get.
-     * @param int $start_at     The story number to start retrieving.
-     * @param int $order        How to order the results.
+     * @param integer $channel_id   The channel to get the stories from.
+     * @param array   $filter       Additional, optional filters.
+     *   <pre>
+     *     max_stories  The maximum number of stories to get.
+     *     start_at     The story number to start retrieving.
+     *     order        How to order the results.
+     *   </pre>
      *
-     * @return An array of story information | PEAR_Error
+     * @return array An array of story information
      */
-    public function stories($channel_id, $max_stories = 10, $start_at = 0,
-                            $order = 0)
+    public function stories($channel_id, $filter = array())
     {
-        $news = Jonah_News::factory();
-        $stories = $news->getStories($channel_id, $max_stories, $start_at, false,
-                                     time(), false, $order);
+        $filter = new Horde_Support_Array($filter);
+
+        $stories = $GLOBALS['injector']
+            ->getInstance('Jonah_Driver')
+            ->getStories(
+                array(
+                    'channel_id' => $channel_id,
+                    'limit' => $filter->get('max_stories', 10),
+                    'startnumber' => $filter->get('start_at', 0),
+                    'published' => true,
+                ),
+                $order
+        );
 
         foreach (array_keys($stories) as $s) {
-            if (empty($stories[$s]['story_body_type']) || $stories[$s]['story_body_type'] == 'text') {
-                $stories[$s]['story_body_html'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($stories[$s]['story_body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
+            if (empty($stories[$s]['body_type']) || $stories[$s]['body_type'] == 'text') {
+                $stories[$s]['body_html'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($stories[$s]['story_body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
             } else {
-                $stories[$s]['story_body_html'] = $stories[$s]['story_body'];
+                $stories[$s]['body_html'] = $stories[$s]['body'];
             }
         }
 
@@ -63,20 +72,15 @@ class Jonah_Api extends Horde_Registry_Api
      * @param integer $story_id    The story id to fetch.
      * @param boolean $read        Whether to update the read count.
      *
-     * @return mixed  An array of story data | PEAR_Error
+     * @return array  An array of story data
      */
     public function story($channel_id, $story_id, $read = true)
     {
-        $news = Jonah_News::factory();
-        $story = $news->getStory($channel_id, $story_id, $read);
-        if (is_a($story, 'PEAR_Error')) {
-            Horde::logMessage($story, 'ERR');
-            return false;
-        }
-        if (empty($story['story_body_type']) || $story['story_body_type'] == 'text') {
-            $story['story_body_html'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['story_body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
+        $story = $GLOBALS['injector']->getInstance('Jonah_Driver')->getStory($channel_id, $story_id, $read);
+        if (empty($story['body_type']) || $story['body_type'] == 'text') {
+            $story['body_html'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
         } else {
-            $story['story_body_html'] = $story['story_body'];
+            $story['body_html'] = $story['body'];
         }
 
         return $story;
@@ -94,14 +98,9 @@ class Jonah_Api extends Horde_Registry_Api
         if (!$GLOBALS['conf']['comments']['allow']) {
             return false;
         }
+        $story = $GLOBALS['injector']->getInstance('Jonah_Driver')->getStory(null, $story_id);
 
-        $news = Jonah_News::factory();
-        $story = $news->getStory(null, $story_id);
-        if (is_a($story, 'PEAR_Error')) {
-            return false;
-        }
-
-        return $story['story_title'];
+        return $story['title'];
     }
 
     /**
@@ -123,12 +122,11 @@ class Jonah_Api extends Horde_Registry_Api
      *
      * @param array $channel_id  An optional array of channel_ids.
      *
-     * @return mixed  An array containing tag_name, and total | PEAR_Error
+     * @return array  An array containing tag_name, and total
      */
     public function listTagInfo($tags = array(), $channel_id = null)
     {
-        $news = Jonah_News::factory();
-        return $news->listTagInfo($tags, $channel_id);
+        return $GLOBALS['injector']->getInstance('Jonah_Driver')->listTagInfo($tags, $channel_id);
     }
 
     /**
@@ -136,46 +134,50 @@ class Jonah_Api extends Horde_Registry_Api
      *
      * @param array $names  An array of names to search for
      *
-     * @return mixed  An array of tag_name => tag_ids | PEAR_Error
+     * @return Array An array of tag_name => tag_ids
      */
     public function getTagIds($names)
     {
-        $news = Jonah_News::factory();
-        return $news->getTagIds($names);
+        return $GLOBALS['injector']->getInstance('Jonah_Driver')->getTagIds($names);
     }
 
     /**
      * Searches internal channels for stories tagged with all requested tags.
      * Returns an application-agnostic array (useful for when doing a tag search
-     * across multiple applications) containing the following keys:
-     * <pre>
-     *  'title'    - The title for this resource.
-     *  'desc'     - A terse description of this resource.
-     *  'view_url' - The URL to view this resource.
-     *  'app'      - The Horde application this resource belongs to.
-     * </pre>
+     * across multiple applications).
+     *
      *
      * The 'raw' story array can be returned instead by setting $raw = true.
      *
-     * @param array $names       An array of tag_names to search for (AND'd together).
-     * @param integer $max       The maximum number of stories to return.
-     * @param integer $from      The number of the story to start with.
-     * @param array $channel_id  An array of channel_ids to limit the search to.
-     * @param integer $order     How to order the results (a Jonah::ORDER_* constant)
+     * @param array $names       An array of tag_names to search for
+     *                           (AND'd together).
+     * @param array $filter      An array of optional filter parameters.
+     *   <pre>
+     *     max       The maximum number of stories to return.
+     *     from      The number of the story to start with.
+     *     channel_id  An array of channel_ids to limit the search to.
+     *     order     How to order the results (a Jonah::ORDER_* constant)
+     *  </pre>
      * @param boolean $raw       Return the raw story data?
      *
-     * @return mixed  An array of results | PEAR_Error
+     * @return  An array of results with the following structure:
+     *    <pre>
+     *      'title'    - The title for this resource.
+     *      'desc'     - A terse description of this resource.
+     *      'view_url' - The URL to view this resource.
+     *      'app'      - The Horde application this resource belongs to.
+     *    </pre>
      */
-    public function searchTags($names, $max = 10, $from = 0, $channel_id = array(),
-                               $order = 0, $raw = false)
+    public function searchTags($names, $filter = array(), $raw = false)
     {
         global $registry;
 
-        $news = Jonah_News::factory();
-        $results = $news->searchTags($names, $max, $from, $channel_id, $order);
-        if (is_a($results, 'PEAR_Error')) {
-            return $results;
-        }
+        // @TODO: Refactor when moving tag to content_tagger
+        $filter = new Horde_Support_Array($filter);
+        $results = $GLOBALS['injector']
+            ->getInstance('Jonah_Driver')
+            ->searchTags($names, $filter->max, $filter->from, $filter->channel_id, $filter->order);
+
         $return = array();
         if ($raw) {
             // Requesting the raw story information as returned from searchTags,
@@ -183,26 +185,26 @@ class Jonah_Api extends Horde_Registry_Api
             // find useful.
             $comments = $GLOBALS['conf']['comments']['allow'] && $registry->hasMethod('forums/numMessages');
             foreach ($results as $story) {
-                if (empty($story['story_body_type']) || $story['story_body_type'] == 'text') {
-                    $story['story_body_html'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['story_body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
+                if (empty($story['body_type']) || $story['body_type'] == 'text') {
+                    $story['body_html'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
                 } else {
-                    $story['story_body_html'] = $story['story_body'];
+                    $story['body_html'] = $story['body'];
                 }
 
                 if ($comments) {
                     $story['num_comments'] = $registry->call('forums/numMessages',
-                                                             array($story['story_id'],
+                                                             array($story['id'],
                                                                    $registry->getApp()));
                 }
 
-                $return[$story['story_id']] = $story;
+                $return[$story['id']] = $story;
             }
         } else {
             foreach($results as $story) {
                 if (!empty($story)) {
-                    $return[] = array('title' => $story['story_title'],
-                                                        'desc' => $story['story_desc'],
-                                                        'view_url' => $story['story_link'],
+                    $return[] = array('title' => $story['title'],
+                                                        'desc' => $story['desc'],
+                                                        'view_url' => $story['link'],
                                                         'app' => 'jonah');
                 }
             }
@@ -219,14 +221,7 @@ class Jonah_Api extends Horde_Registry_Api
      */
     public function storyCount($channel_id)
     {
-        global $registry;
-
-        $results = $GLOBALS['injector']->getInstance('Jonah_Driver')->getStoryCount($channel_id);
-        if (is_a($results, 'PEAR_Error')) {
-            return 0;
-        }
-
-        return $results;
+        return $GLOBALS['injector']->getInstance('Jonah_Driver')->getStoryCount($channel_id);
     }
 
 }
index 5a1b09c..dc1df58 100644 (file)
@@ -51,31 +51,17 @@ class Jonah_Application extends Horde_Registry_Application
             'news' => array(
                 'title' => _("News")
             ),
-            'news:internal_channels' => array(
-                'title' => _("Internal Channels")
-            ),
-            'news:external_channels' => array(
-                'title' => _("External Channels")
+            'news:channels' => array(
+                'title' => _("Channels")
             )
         );
 
         /* Loop through internal channels and add them to the perms
          * titles. */
-        $news = Jonah_News::factory();
-        $channels = $news->getChannels(Jonah::INTERNAL_CHANNEL);
-
-        foreach ($channels as $channel) {
-            $perms['news:internal_channels:' . $channel['channel_id']] = array(
-                'title' => $channel['channel_name']
-            );
-        }
-
-        /* Loop through external channels and add their ids to the
-         * perms. */
-        $channels = $news->getChannels(Jonah::EXTERNAL_CHANNEL);
+        $channels = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannels();
 
         foreach ($channels as $channel) {
-            $perms['news:external_channels:' . $channel['channel_id']] = array(
+            $perms['news:channels:' . $channel['channel_id']] = array(
                 'title' => $channel['channel_name']
             );
         }
@@ -142,13 +128,16 @@ class Jonah_Application extends Horde_Registry_Application
         }
 
         $url = Horde::url('stories/');
-        $news = Jonah_News::factory();
-        $channels = $news->getChannels('internal');
-        if ($channels instanceof PEAR_Error) {
+        $driver = $GLOBALS['injector']->getInstance('Jonah_Driver');
+
+        try {
+            $channels = $driver->getChannels('internal');
+        } catch (Jonah_Exception $e) {
+            var_dump($e);
             return;
         }
-        $channels = Jonah::checkPermissions('channels', Horde_Perms::SHOW, $channels);
 
+        $channels = Jonah::checkPermissions('channels', Horde_Perms::SHOW, $channels);
         foreach ($channels as $channel) {
             $tree->addNode(
                 $parent . $channel['channel_id'],
index d00acb6..a3f6ae4 100644 (file)
@@ -21,11 +21,8 @@ class Horde_Block_jonah_cloud extends Horde_Block {
      */
     function _params()
     {
-        return array(
-            'results_url' => array(
-                'name' => _("Results URL"),
-                'type' => 'text',
-                'default' => Horde::url('stories/results.php?tag_id=@id@')));
+        return array();
+
     }
 
     function _title()
@@ -35,19 +32,19 @@ class Horde_Block_jonah_cloud extends Horde_Block {
 
     function _content()
     {
-        $news = Jonah_News::factory();
-
         /* Get the tags */
-        $tags = $news->listTagInfo();
+        $tags = $GLOBALS['injector']->getInstance('Jonah_Driver')->listTagInfo();
         if (count($tags)) {
-            $cloud = new Horde_Core_Ui_TagCloud();
+            $url = Horde::url('stories/results.php');
+            $cloud = new Horde_Ui_TagCloud();
             foreach ($tags as $id => $tag) {
-                $cloud->addElement($tag['tag_name'], str_replace(array('@id@', '@tag@'), array($id, $tag['tag_name']), $this->_params['results_url']), $tag['total']);
+                $cloud->addElement($tag['tag_name'], $url->copy()->add('tag_id', $id), $tag['total']);
             }
             $html = $cloud->buildHTML();
         } else {
             $html = '';
         }
+
         return $html;
     }
 
index 7208340..57371d1 100644 (file)
@@ -6,7 +6,7 @@ $block_name = _("Feeds");
  * This class extends Horde_Block:: to provide a list of deliverable internal
  * channels.
  *
- * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
index 2425710..beae9b7 100644 (file)
@@ -6,18 +6,17 @@ $block_name = _("Latest News");
  * This class extends Horde_Block:: to provide the api to embed news
  * in other Horde applications.
  *
- * Copyright 2002-2007 Roel Gloudemans <roel@gloudemans.info>
+ * Copyright 2002-2010 Roel Gloudemans <roel@gloudemans.info>
  *
  * See the enclosed file LICENSE for license information (BSD). If you
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author  Roel Gloudemans <roel@gloudemans.info>
- * @package Horde_Block
+ * @package Jonah
  */
-class Horde_Block_Jonah_latest extends Horde_Block {
-
+class Horde_Block_Jonah_latest extends Horde_Block
+{
     var $_app = 'jonah';
-
     var $_story = null;
 
     /**
@@ -28,8 +27,7 @@ class Horde_Block_Jonah_latest extends Horde_Block {
                                   'type' => 'enum',
                                   'values' => array());
 
-        $news = Jonah_News::factory();
-        $channels = $news->getChannels(Jonah::INTERNAL_CHANNEL);
+        $channels = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannels();
         foreach ($channels as $channel) {
             $params['source']['values'][$channel['channel_id']] = $channel['channel_name'];
         }
@@ -55,13 +53,16 @@ class Horde_Block_Jonah_latest extends Horde_Block {
             return _("Latest News");
         }
 
-        $story = $this->_fetch();
-        return is_a($story, 'PEAR_Error')
-            ? @htmlspecialchars($story->getMessage(), ENT_COMPAT, $GLOBALS['registry']->getCharset())
-            : '<span class="storyDate">'
-                . @htmlspecialchars($story['story_updated_date'], ENT_COMPAT, $GLOBALS['registry']->getCharset())
-                . '</span> '
-                . @htmlspecialchars($story['story_title'], ENT_COMPAT, $GLOBALS['registry']->getCharset());
+        try {
+            $story = $this->_fetch();
+        } catch (Exception $e) {
+            return @htmlspecialchars($e->getMessage(), ENT_COMPAT, $GLOBALS['registry']->getCharset());
+        }
+
+        return '<span class="storyDate">'
+               . @htmlspecialchars($story['updated_date'], ENT_COMPAT, $GLOBALS['registry']->getCharset())
+               . '</span> '
+               . @htmlspecialchars($story['title'], ENT_COMPAT, $GLOBALS['registry']->getCharset());
     }
 
     /**
@@ -72,17 +73,17 @@ class Horde_Block_Jonah_latest extends Horde_Block {
             return _("No channel specified.");
         }
 
-        $story = $this->_fetch();
-        if (is_a($story, 'PEAR_Error')) {
-            return sprintf(_("Error fetching story: %s"), $story->getMessage());
+        try {
+            $story = $this->_fetch();
+        } catch (Exception $e) {
+            return sprintf(_("Error fetching story: %s"), $e->getMessage());
         }
 
-        if (empty($story['story_body_type']) || $story['story_body_type'] == 'text') {
-            $story['story_body'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['story_body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
+        if (empty($story['body_type']) || $story['body_type'] == 'text') {
+            $story['body'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
         }
 
-        return '<p class="storySubtitle">' . htmlspecialchars($story['story_desc']) .
-            '</p><div class="storyBody">' . $story['story_body'] . '</div>';
+        return '<p class="storySubtitle">' . htmlspecialchars($story['description']) . '</p><div class="storyBody">' . $story['body'] . '</div>';
     }
 
     /**
@@ -95,9 +96,9 @@ class Horde_Block_Jonah_latest extends Horde_Block {
         }
 
         if (is_null($this->_story)) {
-            $news = Jonah_News::factory();
-            $this->_story = $news->getStory($this->_params['source'],
-                                            $news->getLatestStoryId($this->_params['source']),
+            $driver = $GLOBALS['injector']->getInstance('Jonah_Driver');
+            $this->_story = $driver->getStory($this->_params['source'],
+                                            $driver->getLatestStoryId($this->_params['source']),
                                             !empty($this->_params['countReads']));
         }
 
index 4bd45c5..744db8b 100644 (file)
@@ -27,8 +27,7 @@ class Horde_Block_Jonah_news extends Horde_Block {
                                   'type' => 'enum',
                                   'values' => array());
 
-        $news = Jonah_News::factory();
-        $channels = $news->getChannels();
+        $channels = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannels();
         foreach ($channels as $channel) {
             $params['source']['values'][$channel['channel_id']] = $channel['channel_name'];
         }
@@ -57,10 +56,10 @@ class Horde_Block_Jonah_news extends Horde_Block {
 
     function _title()
     {
-        $news = Jonah_News::factory();
-        $channel = $news->getChannel($this->_params['source']);
-        if (is_a($channel, 'PEAR_Error')) {
-            return @htmlspecialchars($channel->getMessage(), ENT_COMPAT, $GLOBALS['registry']->getCharset());
+        try {
+            $channel = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannel($this->_params['source']);
+        } catch (Jonah_Exception $e) {
+            return @htmlspecialchars($e->getMessage(), ENT_COMPAT, $GLOBALS['registry']->getCharset());
         }
 
         if (!empty($channel['channel_link'])) {
@@ -80,18 +79,13 @@ class Horde_Block_Jonah_news extends Horde_Block {
             return _("No feed specified.");
         }
 
-        $news = Jonah_News::factory();
-        $params = $this->_params();
-
         $view = isset($this->_params['view']) ? $this->_params['view'] : 'standard';
-        if (!isset($this->_params['max'])) {
-            $this->_params['max'] = $params['max']['default'];
-        }
-        if (!isset($this->_params['from'])) {
-            $this->_params['from'] = $params['from']['default'];
-        }
 
-        return $news->renderChannel($this->_params['source'], $view, $this->_params['max'], $this->_params['from']);
+        return $GLOBALS['injector']->getInstance('Jonah_Driver')->renderChannel(
+                $this->_params['source'],
+                $view,
+                $this->_params['max'],
+                $this->_params['from']);
     }
 
 }
index 0c34b80..87db935 100644 (file)
@@ -28,8 +28,7 @@ class Horde_Block_Jonah_news_popular extends Horde_Block {
                                   'type' => 'enum',
                                   'values' => array());
 
-        $news = Jonah_News::factory();
-        $channels = $news->getChannels();
+        $channels = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannels();
         foreach ($channels as  $channel) {
             if ($channel['channel_type'] == Jonah::INTERNAL_CHANNEL) {
                 $params['source']['values'][$channel['channel_id']] = $channel['channel_name'];
@@ -54,10 +53,10 @@ class Horde_Block_Jonah_news_popular extends Horde_Block {
 
     function _title()
     {
-        $news = Jonah_News::factory();
-        $channel = $news->getChannel($this->_params['source']);
-        if (is_a($channel, 'PEAR_Error')) {
-            return @htmlspecialchars($channel->getMessage(), ENT_COMPAT, $GLOBALS['registry']->getCharset());
+        try {
+            $channel = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannel($this->_params['source']);
+        } catch (Exception $e) {
+            return @htmlspecialchars($e->getMessage(), ENT_COMPAT, $GLOBALS['registry']->getCharset());
         }
 
         if (!empty($channel['channel_link'])) {
@@ -78,7 +77,6 @@ class Horde_Block_Jonah_news_popular extends Horde_Block {
             return _("No feed specified.");
         }
 
-        $news = Jonah_News::factory();
         $params = $this->_params();
 
         $view = isset($this->_params['view']) ? $this->_params['view'] : 'standard';
@@ -87,7 +85,7 @@ class Horde_Block_Jonah_news_popular extends Horde_Block {
         }
 
 
-        return $news->renderChannel($this->_params['source'], $view, $this->_params['max'], 0, Jonah::ORDER_READ);
+        return $GLOBALS['injector']->getInstance('Jonah_Driver')->renderChannel($this->_params['source'], $view, $this->_params['max'], 0, Jonah::ORDER_READ);
     }
 
 }
index 9c3d66f..093a4a1 100644 (file)
@@ -24,8 +24,7 @@ class Horde_Block_Jonah_story extends Horde_Block {
      */
     function _params()
     {
-        $news = Jonah_News::factory();
-        $channels = $news->getChannels(Jonah::INTERNAL_CHANNEL);
+        $channels = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannels();
         $channel_choices = array();
         foreach ($channels as $channel) {
             $channel_choices[$channel['channel_id']] = $channel['channel_name'];
@@ -55,13 +54,15 @@ class Horde_Block_Jonah_story extends Horde_Block {
             return _("Story");
         }
 
-        $story = $this->_fetch();
-        return is_a($story, 'PEAR_Error')
-            ? @htmlspecialchars($story->getMessage(), ENT_COMPAT, $GLOBALS['registry']->getCharset())
-            : '<span class="storyDate">'
-                . @htmlspecialchars($story['story_updated_date'], ENT_COMPAT, $GLOBALS['registry']->getCharset())
+        try {
+            $story = $this->_fetch();
+        } catch (Jonah_Exception $e) {
+            return htmlspecialchars($e->getMessage(), ENT_COMPAT, $GLOBALS['registry']->getCharset());
+        }
+        return '<span class="storyDate">'
+                . htmlspecialchars($story['updated_date'], ENT_COMPAT,$GLOBALS['registry']->getCharset())
                 . '</span> '
-                . @htmlspecialchars($story['story_title'], ENT_COMPAT, $GLOBALS['registry']->getCharset());
+                . htmlspecialchars($story['title'], ENT_COMPAT, $GLOBALS['registry']->getCharset());
     }
 
     /**
@@ -72,26 +73,26 @@ class Horde_Block_Jonah_story extends Horde_Block {
             return _("No story is selected.");
         }
 
-        $story = $this->_fetch();
-        if (is_a($story, 'PEAR_Error')) {
-            return sprintf(_("Error fetching story: %s"), $story->getMessage());
+        try {
+            $story = $this->_fetch();
+        } catch (Jonah_Exception $e) {
+            return sprintf(_("Error fetching story: %s"), $e->getMessage());
         }
 
-        if (empty($story['story_body_type']) || $story['story_body_type'] == 'text') {
-            $story['story_body'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['story_body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
+        if (empty($story['body_type']) || $story['body_type'] == 'text') {
+            $story['body'] =  $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
         }
 
         $tag_html = array();
-        foreach ($story['story_tags'] as $id => $tag) {
-            $link = Horde_Util::addParameter('results.php', array('tag_id' => $id, 'channel_id' => $this->_params['source']));
-            $tag_html[] = Horde::link($link) . $tag . '</a>';
+        foreach ($story['tags'] as $id => $tag) {
+            $tag_html[] = Horde::url('results.php')->add(array('tag_id' => $id, 'channel_id' => $this->_prams['source']))->link() . $tag . '</a>';
         }
 
         return '<p class="storyTags">' . _("Tags: ")
-            . implode(', ', $story['story_tags'])
+            . implode(', ', $story['tags'])
             . '</p><p class="storySubtitle">'
-            . htmlspecialchars($story['story_desc'])
-            . '</p><div class="storyBody">' . $story['story_body']
+            . htmlspecialchars($story['desc'])
+            . '</p><div class="storyBody">' . $story['body']
             . '</div>';
     }
 
@@ -101,10 +102,10 @@ class Horde_Block_Jonah_story extends Horde_Block {
     function _fetch()
     {
         if (is_null($this->_story)) {
-            $news = Jonah_News::factory();
-            $this->_story = $news->getStory($this->_params['source'],
-                                            $this->_params['story'],
-                                            $this->_params['countReads']);
+            $this->_story = $GLOBALS['injector']->getInstance('Jonah_Driver')->getStory(
+                    $this->_params['source'],
+                    $this->_params['story'],
+                    !empty($this->_params['countReads']));
         }
 
         return $this->_story;
index 470ff87..c53852e 100644 (file)
@@ -133,7 +133,7 @@ class Jonah_Driver
      *                stories from the given channel.
      * @throws InvalidArgumentException
      */
-    public function getStories($criteria)
+    public function getStories($criteria, $order = Jonah::ORDER_PUBLISHED)
     {
         // Convert a channel slug into a channel ID if necessary
         if (isset($criteria['channel']) && !isset($criteria['channel_id'])) {
@@ -171,84 +171,17 @@ class Jonah_Driver
             $criteria['tagIDs'] = array_merge($criteria['tagIDs'], $this->getTagIds($criteria['alltags']));
         }
 
-        return $this->_getStories($criteria);
-    }
-
-    /**
-     * Returns the most recent or all stories from a channel.
-     * This method is deprecated.
-     *
-     * @param integer $channel_id  The news channel to get stories from.
-     * @param integer $max         The maximum number of stories to get. If
-     *                             null, all stories will be returned.
-     * @param integer $from        The number of the story to start with.
-     * @param boolean $refresh     Force a refresh of stories in case this is
-     *                             an external channel.
-     * @param integer $date        The timestamp of the date to start with.
-     * @param boolean $unreleased  Return stories that have not yet been
-     *                             published?
-     *                             Defaults to false - only published stories.
-     * @param integer $order       How to order the results for internal
-     *                             channels. Possible values are the
-     *                             Jonah::ORDER_* constants.
-     *
-     * @return array  The specified number (or less, if there are fewer) of
-     *                stories from the given channel.
-     */
-    public function legacyGetStories($channel, $max = 10, $from = 0, $refresh = false,
-                                     $date = null, $unreleased = false,
-                                     $order = Jonah::ORDER_PUBLISHED)
-    {
-        global $conf, $registry;
-
-        $channel['channel_link'] = Horde::url('delivery/html.php', true, -1)->add('channel_id', $channel['channel_id']);
-        $stories = $this->_legacyGetStories($channel['channel_id'], $max, $from, $date, $unreleased, $order);
-        $date_format = $GLOBALS['prefs']->getValue('date_format');
-        $comments = $conf['comments']['allow'] && $registry->hasMethod('forums/numMessages');
-        foreach ($stories as $key => $story) {
-            $stories[$key]['story_link'] = $this->getStoryLink($channel, $story);
-            $stories[$key]['story_updated'] = $story['story_updated'];
-            $stories[$key]['story_updated_date'] = strftime($date_format, $story['story_updated']);
-            if ($comments) {
-                try {
-                    $stories[$key]['num_comments'] = $registry->call('forums/numMessages', array($story['story_id'], $registry->getApp()));
-                } catch (Horde_Exception $e) {
-                    Horde::logMessage($e->getMessage(), 'ERR');
-                    $stories[$key]['num_comments'] = null;
-                }
-            }
-            $stories[$key] = array_merge($channel, $stories[$key]);
-        }
-
-        return $stories;
+        return $this->_getStories($criteria, $order);
     }
 
     /**
      * Save the provided story to storage.
      *
      * @param array $info  The story information array. Passed by reference so
-     *                     we can add/change the story_id when saved.
+     *                     we can add/change the id when saved.
      */
     public function saveStory(&$info)
     {
-        /* Used for checking whether to send out delivery or not. */
-        if (empty($info['story_published'])) {
-            /* Story is not being released. */
-            $deliver = false;
-        } elseif (empty($info['story_id'])) {
-            /* Story is new. */
-            $deliver = true;
-        } else {
-            /* Story is old, has it been released already? */
-            $oldstory = $this->getStory(null, $info['story_id']);
-            if ((empty($oldstory['story_published']) ||
-                 $oldstory['story_published'] > $oldstory['story_updated']) &&
-                $info['story_published'] <= time()) {
-                $deliver = true;
-            } else {
-                $deliver = false;
-            }
-        }
         $this->_saveStory($info);
     }
 
@@ -267,13 +200,13 @@ class Jonah_Driver
         $story = $this->_getStory($story_id, $read);
 
         /* Format story link. */
-        $story['story_link'] = $this->getStoryLink($channel, $story);
+        $story['link'] = $this->getStoryLink($channel, $story);
 
         /* Format dates. */
         $date_format = $GLOBALS['prefs']->getValue('date_format');
-        $story['story_updated_date'] = strftime($date_format, $story['story_updated']);
-        if (!empty($story['story_published'])) {
-            $story['story_published_date'] = strftime($date_format, $story['story_published']);
+        $story['updated_date'] = strftime($date_format, $story['updated']);
+        if (!empty($story['published'])) {
+            $story['published_date'] = strftime($date_format, $story['published']);
         }
 
         return $story;
@@ -289,14 +222,14 @@ class Jonah_Driver
      */
     public function getStoryLink($channel, $story)
     {
-        if ((empty($story['story_url']) || !empty($story['story_body'])) &&
+        if ((empty($story['url']) || !empty($story['body'])) &&
             !empty($channel['channel_story_url'])) {
             $url = $channel['channel_story_url'];
         } else {
-            $url = Horde::url('stories/view.php', true, -1)->add(array('channel_id' => '%c', 'story_id' => '%s'))->setRaw(false);
+            $url = Horde::url('stories/view.php', true, -1)->add(array('channel_id' => '%c', 'id' => '%s'))->setRaw(false);
         }
         return new Horde_Url(str_replace(array('%25c', '%25s', '%c', '%s'),
-                                         array('%c', '%s', $channel['channel_id'], $story['story_id']),
+                                         array('%c', '%s', $channel['channel_id'], $story['id']),
                                          $url));
     }
 
@@ -304,7 +237,7 @@ class Jonah_Driver
      */
     public function getChecksum($story)
     {
-        return md5($story['story_title'] . $story['story_desc']);
+        return md5($story['title'] . $story['description']);
     }
 
     /**
@@ -341,19 +274,15 @@ class Jonah_Driver
      *
      * @TODO: This doesn't belong in a storage driver class. Move it to a
      * view or possible a static method in Jonah::?
-     * 
+     *
      * @return string  The rendered story listing.
      */
     public function renderChannel($channel_id, $tpl, $max = 10, $from = 0, $order = Jonah::ORDER_PUBLISHED)
     {
         $channel = $this->getChannel($channel_id);
-        if (is_a($channel, 'PEAR_Error')) {
-            return sprintf(_("Error fetching feed: %s"), $channel->getMessage());
-        }
 
         include JONAH_BASE . '/config/templates.php';
-        $escape = !isset($templates[$tpl]['escape']) ||
-            !empty($templates[$tpl]['escape']);
+        $escape = !isset($templates[$tpl]['escape']) || !empty($templates[$tpl]['escape']);
         $template = new Horde_Template();
 
         if ($escape) {
@@ -362,18 +291,16 @@ class Jonah_Driver
         }
         $template->set('channel', $channel, true);
 
-        /* Get one story more than requested to see if there are more
-         * stories. */
+        /* Get one story more than requested to see if there are more stories. */
         if ($max !== null) {
-            $stories = $this->getStories($channel_id, $max + 1, $from, false, time(), false, $order);
-            if (is_a($stories, 'PEAR_Error')) {
-                return $stories->getMessage();
-            }
+            $stories = $this->getStories(
+                    array('channel_id' => $channel_id,
+                          'published' => true),
+                    $order);
         } else {
-            $stories = $this->getStories($channel_id, null, 0, false, time(), false, $order);
-            if (is_a($stories, 'PEAR_Error')) {
-                return $stories->getMessage();
-            }
+            $stories = $this->getStories(array('channel_id' => $channel_id,
+                                               'published' => true),
+                                         $order);
             $max = count($stories);
         }
 
@@ -439,13 +366,13 @@ class Jonah_Driver
      */
     protected function _escapeStories(&$value, $key)
     {
-        $value['story_title'] = htmlspecialchars($value['story_title']);
-        $value['story_desc'] = htmlspecialchars($value['story_desc']);
-        if (isset($value['story_link'])) {
-            $value['story_link'] = htmlspecialchars($value['story_link']);
+        $value['title'] = htmlspecialchars($value['title']);
+        $value['description'] = htmlspecialchars($value['description']);
+        if (isset($value['link'])) {
+            $value['link'] = htmlspecialchars($value['link']);
         }
-        if (empty($value['story_body_type']) || $value['story_body_type'] != 'richtext') {
-            $value['story_body'] = htmlspecialchars($value['story_body']);
+        if (empty($value['body_type']) || $value['body_type'] != 'richtext') {
+            $value['body'] = htmlspecialchars($value['body']);
         }
     }
 
@@ -454,7 +381,7 @@ class Jonah_Driver
      */
     protected function _escapeStoryDescriptions(&$value, $key)
     {
-        $value['story_desc'] = nl2br($value['story_desc']);
+        $value['description'] = nl2br($value['description']);
     }
 
     /**
@@ -470,15 +397,15 @@ class Jonah_Driver
         require_once 'Horde/MIME/Part.php';
 
         /* Add the story to the message based on the story's body type. */
-        switch ($story['story_body_type']) {
+        switch ($story['body_type']) {
         case 'richtext':
             /* Get a plain text version of a richtext story. */
-            $body_html = $story['story_body'];
+            $body_html = $story['body'];
             $body_text = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($body_html, 'html2text');
 
             /* Add description. */
-            $body_html = '<p>' . $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['story_desc'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO, 'callback' => null)) . "</p>\n" . $body_html;
-            $body_text = Horde_String::wrap('  ' . $story['story_desc'], 70) . "\n\n" . $body_text;
+            $body_html = '<p>' . $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['desc'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO, 'callback' => null)) . "</p>\n" . $body_html;
+            $body_text = Horde_String::wrap('  ' . $story['description'], 70) . "\n\n" . $body_text;
 
             /* Add the text version of the story to the base message. */
             $message_text = new MIME_Part('text/plain');
@@ -501,7 +428,7 @@ class Jonah_Driver
         case 'text':
             /* This is just a plain text story. */
             $message_text = new MIME_Part('text/plain');
-            $message_text->setContents($message_text->replaceEOL($story['story_desc'] . "\n\n" . $story['story_body']));
+            $message_text->setContents($message_text->replaceEOL($story['description'] . "\n\n" . $story['body']));
             $message_text->setCharset($GLOBALS['registry']->getCharset());
 
             return $message_text;
index 15a6354..2eb2918 100644 (file)
@@ -14,6 +14,7 @@
  * @author  Chuck Hagenbuch <chuck@horde.org>
  * @author  Jan Schneider <jan@horde.org>
  * @author  Ben Klang <ben@alkaloid.net>
+ * @author  Michael J. Rubinsky <mrubinsk@horde.org>
  * @package Jonah
  */
 class Jonah_Driver_Sql extends Jonah_Driver
@@ -33,6 +34,13 @@ class Jonah_Driver_Sql extends Jonah_Driver
      */
     protected $_connected = false;
 
+
+    public function __construct($params = array())
+    {
+        parent::__construct($params);
+        $this->_connect();
+    }
+
     /**
      * Saves a channel to the backend.
      *
@@ -51,20 +59,16 @@ class Jonah_Driver_Sql extends Jonah_Driver
      * 'channel_image'    A channel image.
      * </pre>
      *
-     * @return int|PEAR_Error  The channel ID on success, PEAR_Error on
-     *                         failure.
+     * @return integer The channel ID.
+     * @throws Jonah_Exception
      */
     public function saveChannel(&$info)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
         if (empty($info['channel_id'])) {
             $info['channel_id'] = $this->_db->nextId('jonah_channels');
-            if (is_a($info['channel_id'], 'PEAR_Error')) {
+            if ($info['channel_id'] instanceof PEAR_Error) {
                 Horde::logMessage($info['channel_id'], 'ERR');
-                return $info['channel_id'];
+                throw new Jonah_Exception($info['channel_id']);
             }
             $sql = 'INSERT INTO jonah_channels' .
                    ' (channel_id, channel_name, channel_type, channel_desc, channel_interval, channel_url, channel_link, channel_page_link, channel_story_url, channel_img)' .
@@ -90,9 +94,9 @@ class Jonah_Driver_Sql extends Jonah_Driver
                       isset($info['channel_img']) ? $info['channel_img'] : null);
         Horde::logMessage('SQL Query by Jonah_Driver_sql::saveChannel(): ' . $sql, 'DEBUG');
         $result = $this->_db->query($sql, $values);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result, 'ERR');
-            return $result;
+            throw new Jonah_Exception($result);
         }
 
         return $info['channel_id'];
@@ -101,21 +105,16 @@ class Jonah_Driver_Sql extends Jonah_Driver
     /**
      * Get a list of stored channels.
      *
-     * @return mixed         An array of channels or PEAR_Error on error.
+     * @return mixed         An array of channels.
      * @throws Jonah_Exception
      */
     public function getChannels()
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            throw new Jonah_Exception($result);
-        }
-
-        // @TODO: Remove the channel_type clause when we get rid of external channels
-        $wsql = 'WHERE channel_type = ' . Jonah::INTERNAL_CHANNEL;
-        $sql = sprintf('SELECT channel_id, channel_name, channel_type, channel_updated FROM jonah_channels WHERE channel_type = ' . Jonah::INTERNAL_CHANNEL . ' ORDER BY channel_name', $wsql);
+        // @TODO: Remove channel_type filter when tables are updated.
+        $sql = 'SELECT channel_id, channel_name, channel_type, channel_updated FROM jonah_channels WHERE channel_type = ' . Jonah::INTERNAL_CHANNEL . ' ORDER BY channel_name';
         Horde::logMessage('SQL Query by Jonah_Driver_sql::getChannels(): ' . $sql, 'DEBUG');
         $result = $this->_db->getAll($sql, DB_FETCHMODE_ASSOC);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result, 'ERR');
             throw new Jonah_Exception($result);
         }
@@ -127,113 +126,108 @@ class Jonah_Driver_Sql extends Jonah_Driver
     }
 
     /**
+     * Retrieve a single channel definition from storage.
+     *
+     * @return array  The channel definition array.
+     * @throws Jonah_Exception
+     * @throws Horde_Exception_NotFound
      */
     protected function _getChannel($channel_id)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
         $sql = 'SELECT * FROM jonah_channels WHERE channel_id = ' . (int)$channel_id;
 
         Horde::logMessage('SQL Query by Jonah_Driver_sql::_getChannel(): ' . $sql, 'DEBUG');
         $result = $this->_db->getRow($sql, DB_FETCHMODE_ASSOC);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result, 'ERR');
-            return $result;
+            throw new Jonah_Exception($result);
         } elseif (empty($result)) {
-            return PEAR::raiseError(sprintf(_("Channel id \"%s\" not found."), $channel_id));
-        }
-
-        $result['channel_name'] = Horde_String::convertCharset($result['channel_name'], $this->_params['charset']);
-        if ($result['channel_type'] == Jonah::COMPOSITE_CHANNEL) {
-            $channels = explode(':', $result['channel_url']);
-            if (count($channels)) {
-                $sql = 'SELECT MAX(channel_updated) FROM jonah_channels WHERE channel_id IN (' . implode(',', $channels) . ')';
-                Horde::logMessage('SQL Query by Jonah_Driver_sql::_getChannel(): ' . $sql, 'DEBUG');
-                $updated = $this->_db->getOne($sql);
-                if (is_a($updated, 'PEAR_Error')) {
-                    Horde::logMessage($result, 'ERR');
-                } else {
-                    $result['channel_updated'] = $updated;
-                    $this->_timestampChannel($channel_id, $updated);
-                }
-            }
+            throw new Horde_Exception_NotFound(sprintf(_("Channel id \"%s\" not found."), $channel_id));
         }
 
         return $result;
     }
 
     /**
+     * Update the channel's timestamp
+     *
+     * @param integer $channel_id  The channel id.
+     * @param integer $timestamp   The new timestamp.
+     *
+     * @return boolean
+     * @throws Jonah_Exception
      */
     protected function _timestampChannel($channel_id, $timestamp)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
         $sql = sprintf('UPDATE jonah_channels SET channel_updated = %s WHERE channel_id = %s',
                        (int)$timestamp,
                        (int)$channel_id);
         Horde::logMessage('SQL Query by Jonah_Driver_sql::_timestampChannel(): ' . $sql, 'DEBUG');
         $result = $this->_db->query($sql);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result, 'ERR');
+            throw new Jonah_Exception($result);
         }
+
         return $result;
     }
 
     /**
+     * Increment the story's read count.
+     *
+     * @param integer $story_id  The story_id to increment.
+     * @throws Jonah_Exception
      */
     protected function _readStory($story_id)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
         $sql = 'UPDATE jonah_stories SET story_read = story_read + 1 WHERE story_id = ' . (int)$story_id;
         Horde::logMessage('SQL Query by Jonah_Driver_sql::_readStory(): ' . $sql, 'DEBUG');
         $result = $this->_db->query($sql);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result, 'ERR');
+            throw new Jonah_Exception($result);
         }
+
         return $result;
     }
 
     /**
+     * Remove a channel from storage.
+     *
+     * @param integer $channel_id  The channel to remove.
+     *
+     * @return boolean.
+     * @throws Jonah_Exception
+     *
      */
     protected function _deleteChannel($channel_id)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
         $sql = 'DELETE FROM jonah_channels WHERE channel_id = ?';
         $values = array($channel_id);
 
         Horde::logMessage('SQL Query by Jonah_Driver_sql::deleteChannel(): ' . $sql, 'DEBUG');
         $result = $this->_db->query($sql, $values);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result, 'ERR');
+            throw new Jonah_Exception($result);
         }
 
         return $result;
     }
 
     /**
-     * @param array &$info
+     * Save a story to storage.
+     *
+     * @param array &$info  The story info array.
+     * @throws Jonah_Exception
      */
     protected function _saveStory(&$info)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
-        if (empty($info['story_id'])) {
-            $info['story_id'] = $this->_db->nextId('jonah_stories');
-            if (is_a($info['story_id'], 'PEAR_Error')) {
-                Horde::logMessage($info['story_id'], 'ERR');
-                return $info['story_id'];
+        if (empty($info['id'])) {
+            $info['id'] = $this->_db->nextId('jonah_stories');
+            if ($info['id'] instanceof PEAR_Error) {
+                Horde::logMessage($info['id'], 'ERR');
+                throw new Jonah_Exception($info['id']);
             }
             $channel = $this->getChannel($info['channel_id']);
             $permalink = $this->getStoryLink($channel, $info);
@@ -241,41 +235,41 @@ class Jonah_Driver_Sql extends Jonah_Driver
             $values = array($permalink);
         } else {
             $sql = 'UPDATE jonah_stories SET story_id = ?, channel_id = ?, story_title = ?, story_desc = ?, story_body_type = ?, story_body = ?, story_url = ?, story_published = ?, story_updated = ?, story_read = ? WHERE story_id = ?';
-            $values = array((int)$info['story_id']);
+            $values = array((int)$info['id']);
         }
 
-        if (empty($info['story_read'])) {
-            $info['story_read'] = 0;
+        if (empty($info['read'])) {
+            $info['read'] = 0;
         }
 
         /* Deal with any tags */
-        if (!empty($info['story_tags'])) {
-            $tags = explode(',', $info['story_tags']);
+        if (!empty($info['tags'])) {
+            $tags = explode(',', $info['tags']);
         } else {
             $tags = array();
         }
-        $this->writeTags($info['story_id'], $info['channel_id'], $tags);
+        $this->writeTags($info['id'], $info['channel_id'], $tags);
 
         array_unshift($values,
-                      (int)$info['story_id'],
+                      (int)$info['id'],
                       (int)$info['channel_id'],
-                      Horde_String::convertCharset($info['story_title'], $GLOBALS['registry']->getCharset(), $this->_params['charset']),
-                      Horde_String::convertCharset($info['story_desc'], $GLOBALS['registry']->getCharset(), $this->_params['charset']),
-                      $info['story_body_type'],
-                      isset($info['story_body']) ? Horde_String::convertCharset($info['story_body'], $GLOBALS['registry']->getCharset(), $this->_params['charset']) : null,
-                      isset($info['story_url']) ? $info['story_url'] : null,
-                      isset($info['story_published']) ? (int)$info['story_published'] : null,
+                      Horde_String::convertCharset($info['title'], $GLOBALS['registry']->getCharset(), $this->_params['charset']),
+                      Horde_String::convertCharset($info['description'], $GLOBALS['registry']->getCharset(), $this->_params['charset']),
+                      $info['body_type'],
+                      isset($info['body']) ? Horde_String::convertCharset($info['body'], $GLOBALS['registry']->getCharset(), $this->_params['charset']) : null,
+                      isset($info['url']) ? $info['url'] : null,
+                      isset($info['published']) ? (int)$info['published'] : null,
                       time(),
-                      (int)$info['story_read']);
+                      (int)$info['read']);
 
         Horde::logMessage('SQL Query by Jonah_Driver_sql::_saveStory(): ' . $sql, 'DEBUG');
         $result = $this->_db->query($sql, $values);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result, 'ERR');
-            return $result;
+            throw new Jonah_Exception($result);
         }
+        $this->_timestampChannel($info['id'], time());
 
-        $this->_timestampChannel($info['channel_id'], time());
         return true;
     }
 
@@ -289,14 +283,15 @@ class Jonah_Driver_Sql extends Jonah_Driver
      */
     protected function _convertFromBackend($story)
     {
-        $story['story_title'] = Horde_String::convertCharset($story['story_title'], $this->_params['charset'], $GLOBALS['registry']->getCharset());
-        $story['story_desc'] = Horde_String::convertCharset($story['story_desc'], $this->_params['charset'], $GLOBALS['registry']->getCharset());
-        if (isset($story['story_body'])) {
-            $story['story_body'] = Horde_String::convertCharset($story['story_body'], $this->_params['charset'], $GLOBALS['registry']->getCharset());
+        $story['title'] = Horde_String::convertCharset($story['title'], $this->_params['charset'], $GLOBALS['registry']->getCharset());
+        $story['description'] = Horde_String::convertCharset($story['description'], $this->_params['charset'], $GLOBALS['registry']->getCharset());
+        if (isset($story['body'])) {
+            $story['body'] = Horde_String::convertCharset($story['body'], $this->_params['charset'], $GLOBALS['registry']->getCharset());
         }
-        if (isset($story['story_tags'])) {
-            $story['story_tags'] = Horde_String::convertCharset($story['story_tags'], $this->_params['charset'], $GLOBALS['registry']->getCharset());
+        if (isset($story['tags'])) {
+            $story['tags'] = Horde_String::convertCharset($story['tags'], $this->_params['charset'], $GLOBALS['registry']->getCharset());
         }
+
         return $story;
     }
 
@@ -309,38 +304,29 @@ class Jonah_Driver_Sql extends Jonah_Driver
      */
     public function getChannelId($channel)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
         $sql = 'SELECT channel_id FROM jonah_channels WHERE channel_slug = ?';
         $values = array($channel);
         $result = $this->_db->getOne($sql, $values);
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
+        if ($result instanceof PEAR_Error) {
+            throw new Jonah_Exception($result);
         }
 
         return $result;
     }
 
     /**
-     * Returns the total number of stories in the specified
-     * channel
+     * Returns the total number of stories in the specified channel.
      *
-     * @param int $channel_id  The Channel ID
+     * @param integer $channel_id  The Channel Id
      *
-     * @return mixed  The count || PEAR_Error
+     * @return integer  The count
      */
     public function getStoryCount($channel_id)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
         $sql = 'SELECT count(*) FROM jonah_stories WHERE channel_id = ?';
         $result = $this->_db->getOne($sql, $channel_id);
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
+        if ($result instanceof PEAR_Error) {
+            throw new Jonah_Exception($result);
         }
 
         return (int)$result;
@@ -351,34 +337,48 @@ class Jonah_Driver_Sql extends Jonah_Driver
      * arbitrary criteria.
      * NOTE: $criteria['channel_id'] MUST be set for this method to work.
      *
-     * @param string $channel
      * @param array $criteria
      *
      * @return array
      *
      * @see Jonah_Driver#getStories
      */
-    protected function _getStories($criteria)
+    protected function _getStories($criteria, $order = Jonah::ORDER_PUBLISHED)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
-        $sql = 'SELECT DISTINCT(tags.story_id) AS id, ' .
-               'stories.story_author AS author, ' .
-               'stories.story_title AS title, ' .
-               'stories.story_desc AS description, ' .
-               'stories.story_body_type AS body_type, ' .
-               'stories.story_body AS body, ' .
-               'stories.story_url AS url, ' .
-               'stories.story_permalink AS permalink, ' .
-               'stories.story_published AS published, ' .
-               'stories.story_updated AS updated, ' .
-               'stories.story_read AS readcount ' .
-               'FROM jonah_stories_tags AS tags ' .
-               'LEFT JOIN jonah_stories AS stories ON ' .
-               'tags.story_id = stories.story_id ' .
-               'WHERE stories.channel_id=?';
+        // Assuming this was to save the extra tag queries, but this will not
+        // work, it will only return stories that have been tagged.
+//        $sql = 'SELECT DISTINCT(tags.story_id) AS id, ' .
+//               'stories.channel_id, ' .
+//               'stories.story_author AS author, ' .
+//               'stories.story_title AS title, ' .
+//               'stories.story_desc AS description, ' .
+//               'stories.story_body_type AS body_type, ' .
+//               'stories.story_body AS body, ' .
+//               'stories.story_url AS url, ' .
+//               'stories.story_permalink AS permalink, ' .
+//               'stories.story_published AS published, ' .
+//               'stories.story_updated AS updated, ' .
+//               'stories.story_read AS readcount ' .
+//               'FROM jonah_stories_tags AS tags ' .
+//               'LEFT JOIN jonah_stories AS stories ON ' .
+//               'tags.story_id = stories.story_id ' .
+//               'WHERE stories.channel_id=?';
+
+        $sql = 'SELECT stories.story_id AS id, ' .
+           'stories.channel_id, ' .
+           'stories.story_author AS author, ' .
+           'stories.story_title AS title, ' .
+           'stories.story_desc AS description, ' .
+           'stories.story_body_type AS body_type, ' .
+           'stories.story_body AS body, ' .
+           'stories.story_url AS url, ' .
+           'stories.story_permalink AS permalink, ' .
+           'stories.story_published AS published, ' .
+           'stories.story_updated AS updated, ' .
+           'stories.story_read AS readcount ' .
+           'FROM jonah_stories AS stories ' .
+           'WHERE stories.channel_id=?';
+
         $values = array($criteria['channel_id']);
 
         // Apply date filtering
@@ -448,61 +448,6 @@ class Jonah_Driver_Sql extends Jonah_Driver
             }
         }
 
-        Horde::logMessage('SQL Query by Jonah_Driver_sql::_getStories(): ' . $sql, 'DEBUG');
-        $results = $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
-        if (is_a($results, 'PEAR_Error')) {
-            return $results;
-        }
-
-        return $results;
-    }
-
-    protected function _getIdBySlug($slug)
-    {
-        return $slug;
-    }
-
-    /**
-     * Returns the most recent or all stories from a channel.
-     * This method is deprecated.
-     *
-     * @param integer $channel_id  The news channel to get stories from.
-     * @param integer $max         The maximum number of stories to get.
-     * @param integer $from        The number of the story to start with.
-     * @param integer $date        The timestamp of the date to start with.
-     * @param boolean $unreleased  Whether to return not yet released stories.
-     * @param integer $order       How to order the results for internal
-     *                             channels. Possible values are the
-     *                             JONAH_ORDER_* constants.
-     *
-     * @return array  The specified number (or less, if there are fewer) of
-     *                stories from the given channel.
-     */
-    protected function _legacyGetStories($channel_id, $max, $from = 0, $date = null,
-                         $unreleased = false, $order = Jonah::ORDER_PUBLISHED)
-    {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
-        $sql = 'SELECT * FROM jonah_stories WHERE channel_id = ?';
-        $values = array((int)$channel_id);
-
-        if ($unreleased) {
-            if ($date !== null) {
-                $sql .= ' AND story_published <= ?';
-                $values[] = $date;
-            }
-        } else {
-            if ($date === null) {
-                $date = time();
-            } else {
-                $date = max($date, time());
-            }
-            $sql .= ' AND story_published <= ?';
-            $values[] = $date;
-        }
-
         switch ($order) {
         case Jonah::ORDER_PUBLISHED:
             $sql .= ' ORDER BY story_published DESC';
@@ -515,83 +460,70 @@ class Jonah_Driver_Sql extends Jonah_Driver
             break;
         }
 
-        if (!is_null($max)) {
-            $sql = $this->_db->modifyLimitQuery($sql, (int)$from, (int)$max, $values);
-        }
+        Horde::logMessage('SQL Query by Jonah_Driver_sql::_getStories(): ' . $sql, 'DEBUG');
+        $results = $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
 
-        Horde::logMessage('SQL Query by Jonah_Driver_sql::_legacyGetStories(): ' . $sql, 'DEBUG');
-        $result = $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
-        if (is_a($result, 'PEAR_Error')) {
-            return $result;
+        if ($results instanceof PEAR_Error) {
+            throw new Jonah_Exception($results);
         }
-        for ($i = 0; $i < count($result); $i++) {
-            $result[$i] = $this->_convertFromBackend($result[$i]);
-            if (empty($result[$i]['story_permalink'])) {
-                $this->_addPermalink($result[$i]);
-            }
-            $tags = $this->readTags($result[$i]['story_id']);
-            if (is_a($tags, 'PEAR_Error')) {
-                return $tags;
-            }
-            $result[$i]['story_tags'] = $tags;
-        }
-        return $result;
+
+        return $results;
     }
 
     /**
+     * Obtain a channel id from a slug
+     *
+     * @param string $slug  The slug to search for.
+     *
+     * @return integer  The channel id.
      */
-    protected function _getStory($story_id, $read = false)
+    protected function _getIdBySlug($slug)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
-        $sql = 'SELECT * FROM jonah_stories WHERE story_id = ?';
-        $values = array((int)$story_id);
-
-        Horde::logMessage('SQL Query by Jonah_Driver_sql::_getStory(): ' . $sql, 'DEBUG');
-        $result = $this->_db->getRow($sql, $values, DB_FETCHMODE_ASSOC);
-        if (is_a($result, 'PEAR_Error')) {
-            Horde::logMessage($result, 'ERR');
-            return $result;
-        } elseif (empty($result)) {
-            return PEAR::raiseError(sprintf(_("Story id \"%s\" not found."), $story_id));
-        }
-        $result['story_tags'] = $this->readTags($story_id);
-        $result = $this->_convertFromBackend($result);
-        if (empty($result['story_permalink'])) {
-            $this->_addPermalink($result);
-        }
-        if ($read) {
-            $this->_readStory($story_id);
-        }
-
-        return $result;
+        // @TODO
+        throw new Jonah_Exception('Not implemented yet.');
     }
 
     /**
+     * Retrieve a story from storage.
+     *
+     * @param integer $story_id  They story id.
+     * @param boolean $read      Increment the read counter?
+     *
+     * @return The story array.
+     * @throws Horde_Exception_NotFound
+     * @throws Jonah_Exception
+     *
      */
-    protected function _getStoryByUrl($channel_id, $story_url)
+    protected function _getStory($story_id, $read = false)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
+        $sql = 'SELECT stories.story_id as id, ' .
+           'stories.channel_id, ' .
+           'stories.story_author AS author, ' .
+           'stories.story_title AS title, ' .
+           'stories.story_desc AS description, ' .
+           'stories.story_body_type AS body_type, ' .
+           'stories.story_body AS body, ' .
+           'stories.story_url AS url, ' .
+           'stories.story_permalink AS permalink, ' .
+           'stories.story_published AS published, ' .
+           'stories.story_updated AS updated, ' .
+           'stories.story_read AS readcount ' .
+           'FROM jonah_stories AS stories WHERE stories.story_id=?';
 
-        $sql = 'SELECT * FROM jonah_stories' .
-               ' WHERE channel_id = ? AND story_url = ?';
-        $values = array((int)$channel_id, $story_url);
+        $values = array((int)$story_id);
 
-        Horde::logMessage('SQL Query by Jonah_Driver_sql::_getStoryByUrl(): ' . $sql, 'DEBUG');
+        Horde::logMessage('SQL Query by Jonah_Driver_sql::_getStory(): ' . $sql, 'DEBUG');
         $result = $this->_db->getRow($sql, $values, DB_FETCHMODE_ASSOC);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result, 'ERR');
-            return $result;
+            throw new Jonah_Exception($result);
         } elseif (empty($result)) {
-            return PEAR::raiseError(sprintf(_("Story URL \"%s\" not found."), $story_url));
+            throw new Horde_Exception_NotFound(sprintf(_("Story id \"%s\" not found."), $story_id));
         }
+        $result['tags'] = $this->readTags($story_id);
         $result = $this->_convertFromBackend($result);
-        if (empty($result['story_permalink'])) {
-            $this->_addPermalink($result);
+        if ($read) {
+            $this->_readStory($story_id);
         }
 
         return $result;
@@ -601,20 +533,19 @@ class Jonah_Driver_Sql extends Jonah_Driver
      * Adds a missing permalink to a story.
      *
      * @param array $story  A story hash.
+     * @throws Jonah_Exception
      */
     protected function _addPermalink(&$story)
     {
         $channel = $this->getChannel($story['channel_id']);
-        if (is_a($channel, 'PEAR_Error')) {
-            return;
-        }
         $sql = 'UPDATE jonah_stories SET story_permalink = ? WHERE story_id = ?';
-        $values = array($this->getStoryLink($channel, $story), $story['story_id']);
+        $values = array($this->getStoryLink($channel, $story), $story['id']);
         Horde::logMessage('SQL Query by Jonah_Driver_sql::_addPermalink(): ' . $sql, 'DEBUG');
         $result = $this->_db->query($sql, $values);
-        if (!is_a($result, 'PEAR_Error')) {
-            $story['story_permalink'] = $values[0];
+        if ($result instanceof PEAR_Error) {
+            throw new Jonah_Exception($result);
         }
+        $story['permalink'] = $values[0];
     }
 
     /**
@@ -623,13 +554,11 @@ class Jonah_Driver_Sql extends Jonah_Driver
      * @param int $channel_id  The channel id.
      *
      * @return int  The story id.
+     * @throws Jonah_Exception
+     * @throws Horde_Exception_NotFound
      */
     public function getLatestStoryId($channel_id)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
         $sql = 'SELECT story_id FROM jonah_stories' .
                ' WHERE channel_id = ? AND story_published <= ?' .
                ' ORDER BY story_updated DESC';
@@ -637,11 +566,11 @@ class Jonah_Driver_Sql extends Jonah_Driver
 
         Horde::logMessage('SQL Query by Jonah_Driver_sql::getLatestStoryId(): ' . $sql, 'DEBUG');
         $result = $this->_db->getRow($sql, $values, DB_FETCHMODE_ASSOC);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result, 'ERR');
-            return $result;
+            throw new Jonah_Exception($result);
         } elseif (empty($result)) {
-            return PEAR::raiseError(sprintf(_("Channel \"%s\" not found."), $channel_id));
+            return Horde_Exception_NotFound(sprintf(_("Channel \"%s\" not found."), $channel_id));
         }
 
         return $result['story_id'];
@@ -651,27 +580,23 @@ class Jonah_Driver_Sql extends Jonah_Driver
      */
     public function deleteStory($channel_id, $story_id)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
         $sql = 'DELETE FROM jonah_stories' .
                ' WHERE channel_id = ? AND story_id = ?';
         $values = array((int)$channel_id, (int)$story_id);
 
         Horde::logMessage('SQL Query by Jonah_Driver_sql::deleteStory(): ' . $sql, 'DEBUG');
         $result = $this->_db->query($sql, $values);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result->getMessage(), 'ERR');
-            return $result;
+                throw new Jonah_Exception($result);
         }
 
         $sql = 'DELETE FROM jonah_stories_tags ' .
                'WHERE channel_id = ? AND story_id = ?';
         $result = $this->_db->query($sql, $values);
-        if (is_a($result, 'PEAR_Error')) {
+        if ($result instanceof PEAR_Error) {
             Horde::logMessage($result->getMessage(), 'ERR');
-            return $result;
+            throw new Jonah_Exception($result);
         }
 
         return true;
@@ -684,15 +609,14 @@ class Jonah_Driver_Sql extends Jonah_Driver
      * @param int    $channel_id     The channel id for the story we are tagging
      * @param array  $tags           An array of tags.
      *
-     * @return mixed True | PEAR_Error
+     * @TODO: Move this to a tagger class that uses Content_Tagger
+     * @return boolean
+     * @throws Jonah_Exception
      */
     public function writeTags($resource_id, $channel_id, $tags)
     {
         global $conf;
 
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
         // First, make sure all tag names exist in the DB.
         $tagkeys = array();
         $insert = $this->_db->prepare('INSERT INTO jonah_tags (tag_id, tag_name) VALUES(?, ?)');
@@ -700,8 +624,8 @@ class Jonah_Driver_Sql extends Jonah_Driver
         foreach ($tags as $tag) {
             $tag = Horde_String::lower(trim($tag));
             $results = $this->_db->execute($query, $this->_db->escapeSimple($tag));
-            if (is_a($results, 'PEAR_Error')) {
-                return $results;
+            if ($results instanceof PEAR_Error) {
+                throw new Jonah_Exception($results);
             } elseif ($results->numRows() == 0) {
                 $id = $this->_db->nextId('jonah_tags');
                 $result = $this->_db->execute($insert, array($id, $tag));
@@ -718,10 +642,7 @@ class Jonah_Driver_Sql extends Jonah_Driver
 
         $sql = 'DELETE FROM jonah_stories_tags WHERE story_id = ' . (int)$resource_id;
         $query = $this->_db->prepare('INSERT INTO jonah_stories_tags (story_id, channel_id, tag_id) VALUES(?, ?, ?)');
-
-        Horde::logMessage('SQL query by Jonah_Driver_sql::writeTags: ' . $sql,
-                          'DEBUG');
-
+        Horde::logMessage('SQL query by Jonah_Driver_sql::writeTags: ' . $sql, 'DEBUG');
         $this->_db->query($sql);
         foreach ($tagkeys as $key) {
             $this->_db->execute($query, array($resource_id, $channel_id, $key));
@@ -735,21 +656,18 @@ class Jonah_Driver_Sql extends Jonah_Driver
     /**
      * Retrieve the tags for a specified resource.
      *
-     * @param int     $resource_id    The resource to get tags for.
+     * @TODO: Move this to a tagger class that uses content_tagger
      *
-     * @return mixed  An array of tags | PEAR_Error
+     * @param integer     $resource_id    The resource to get tags for.
+     *
+     * @return array  An array of tags
      */
     public function readTags($resource_id)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
         $sql = 'SELECT jonah_tags.tag_id, tag_name FROM jonah_tags INNER JOIN jonah_stories_tags ON jonah_stories_tags.tag_id = jonah_tags.tag_id WHERE jonah_stories_tags.story_id = ?';
-
-        Horde::logMessage('SQL query by Jonah_Driver_sql::readTags ' . $sql,
-                          'DEBUG');
-
+        Horde::logMessage('SQL query by Jonah_Driver_sql::readTags ' . $sql, 'DEBUG');
        $tags = $this->_db->getAssoc($sql, false, array($resource_id), false);
+
        return $tags;
     }
 
@@ -762,14 +680,10 @@ class Jonah_Driver_Sql extends Jonah_Driver
      *
      * @param array $channel_id  An optional array of channel_ids.
      *
-     * @return mixed  An array containing tag_name, and total | PEAR_Error
+     * @return array  An array containing tag_name, and total
      */
     public function listTagInfo($tags = array(), $channel_id = null)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-
         if (!is_array($channel_id) && is_numeric($channel_id)) {
             $channel_id = array($channel_id);
         }
@@ -795,16 +709,17 @@ class Jonah_Driver_Sql extends Jonah_Driver
             $channels = array();
             foreach ($channel_id as $cid) {
                 $c = $this->_getChannel($cid);
-                if ($c['channel_type'] == Jonah::COMPOSITE_CHANNEL) {
-                    $channels = array_merge($channels, explode(':', $c['channel_url']));
-                }
             }
             $channel_id = array_merge($channel_id, $channels);
             $sql .= ' t.channel_id IN (' . implode(', ', $channel_id) . ')';
         }
         $sql .= ' GROUP BY tn.tag_id, tag_name ORDER BY total DESC;';
         $results = $this->_db->getAssoc($sql,true, array(), DB_FETCHMODE_ASSOC, false);
+        if ($results instanceof PEAR_Error) {
+            throw new Jonah_Exception($results);
+        }
         $cache->set($cache_key, serialize($results));
+
         return $results;
     }
 
@@ -822,14 +737,10 @@ class Jonah_Driver_Sql extends Jonah_Driver
      *                             channels. Possible values are the
      *                             JONAH_ORDER_* constants.
      *
-     * @return mixed  Array of stories| PEAR_Error
+     * @return mixed  Array of stories
      */
-    public function searchTagsById($ids, $max = 10, $from = 0, $channel_id = array(),
-                            $order = Jonah::ORDER_PUBLISHED)
+    public function searchTagsById($ids, $max = 10, $from = 0, $channel_id = array(), $order = Jonah::ORDER_PUBLISHED)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
         if (!is_array($ids) || !count($ids)) {
             $stories[] = array();
         } else {
@@ -851,14 +762,6 @@ class Jonah_Driver_Sql extends Jonah_Driver
                 $channels = array();
                 foreach ($channel_id as $cid) {
                     $c = $this->_getChannel($cid);
-                    if ($c['channel_type'] == Jonah::COMPOSITE_CHANNEL) {
-                        $temp = explode(':', $c['channel_url']);
-                        // Save a map of channels that are from composites.
-                        foreach ($temp as $t) {
-                            $cchannels[$t] = $cid;
-                        }
-                        $channels = array_merge($channels, $temp);
-                    }
                 }
                 $channels = array_merge($channel_id, $channels);
                 $timestamp = time();
@@ -886,8 +789,8 @@ class Jonah_Driver_Sql extends Jonah_Driver
             }
             Horde::logMessage('SQL query by Jonah_Driver_sql::searchTags: ' . $sql, 'DEBUG');
             $results = $this->_db->limitQuery($sql, $from, $max);
-            if (is_a($results, 'PEAR_Error')) {
-                return $results;
+            if ($results instanceof PEAR_Error) {
+                throw new Jonah_Exception($results);
             }
 
             for ($i = 0; $i < $results->numRows(); $i++) {
@@ -903,13 +806,14 @@ class Jonah_Driver_Sql extends Jonah_Driver
                 }
 
                 /* Format story link. */
-                $story['story_link'] = $this->getStoryLink($channel, $story);
+                $story['link'] = $this->getStoryLink($channel, $story);
                 $story = array_merge($story, $channel);
+
                 /* Format dates. */
                 $date_format = $GLOBALS['prefs']->getValue('date_format');
-                $story['story_updated_date'] = strftime($date_format, $story['story_updated']);
-                if (!empty($story['story_published'])) {
-                    $story['story_published_date'] = strftime($date_format, $story['story_published']);
+                $story['updated_date'] = strftime($date_format, $story['updated']);
+                if (!empty($story['published'])) {
+                    $story['published_date'] = strftime($date_format, $story['published']);
                 }
 
                 $stories[] = $story;
@@ -928,9 +832,10 @@ class Jonah_Driver_Sql extends Jonah_Driver
                         $order = Jonah::ORDER_PUBLISHED)
     {
         $ids = $this->getTagIds($names);
-        if (is_a($ids, 'PEAR_Error')) {
-            return $ids;
+        if ($ids instanceof PEAR_Error) {
+            throw new Jonah_Exception($ids);
         }
+
         return $this->searchTagsById(array_values($ids), $max, $from, $channel_id, $order);
     }
 
@@ -944,17 +849,12 @@ class Jonah_Driver_Sql extends Jonah_Driver
      */
     public function getTagNames($ids)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-        $sql = 'SELECT t.tag_name FROM jonah_tags as t WHERE t.tag_id IN(';
-        $needComma = false;
-        foreach ($ids as $id) {
-            $sql .= ($needComma ? ',' : '') . '\'' . $id . '\'';
-            $needComma = true;
-        }
-        $sql .= ')';
+        $sql = 'SELECT t.tag_name FROM jonah_tags as t WHERE t.tag_id IN(' . str_repeat('?,', count($ids) - 1) . '?)';
         $tags = $this->_db->getCol($sql);
+        if ($tags instanceof PEAR_Error) {
+            throw new Jonah_Exception($tags);
+        }
+
         return $tags;
     }
 
@@ -967,24 +867,22 @@ class Jonah_Driver_Sql extends Jonah_Driver
      */
     public function getTagIds($names)
     {
-        if (is_a(($result = $this->_connect()), 'PEAR_Error')) {
-            return $result;
-        }
-        $sql = 'SELECT t.tag_name, t.tag_id FROM jonah_tags as t WHERE t.tag_name IN(';
-        $needComma = false;
-        foreach ($names as $name) {
-            $sql .= ($needComma ? ',' : '') . '\'' . $name . '\'';
-            $needComma = true;
-        }
-        $sql .= ')';
+        $sql = 'SELECT t.tag_name, t.tag_id FROM jonah_tags as t WHERE t.tag_name IN(' . str_repeat('?,', count($names) - 1) . '?)';
         $tags = $this->_db->getAssoc($sql);
+        if ($tags instanceof PEAR_Error) {
+            throw new Jonah_Exception($tags);
+        }
+
         return $tags;
     }
 
     /**
      * Attempts to open a persistent connection to the SQL server.
      *
-     * @return boolean  True on success; PEAR_Error on failure.
+     * @TODO: This class needs to be refactored to use Horde_Db
+     *
+     * @return boolean    True on success.
+     * @throws Jonah_Exception
      */
     protected function _connect()
     {
@@ -997,7 +895,6 @@ class Jonah_Driver_Sql extends Jonah_Driver
         } catch (Horde_Exception $e) {
             return PEAR::raiseError($e->getMessage());
         }
-
         $this->_connected = true;
 
         return true;
index 5ffbd04..e9ff445 100644 (file)
@@ -9,6 +9,8 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * General Public License for more details.
  *
+ * @deprecated Will be removed once the Aggregator app (Hippo) is started.
+ *
  * @author  Chuck Hagenbuch <chuck@horde.org>
  * @package Jonah
  */
diff --git a/jonah/lib/Form/Feed.php b/jonah/lib/Form/Feed.php
new file mode 100644 (file)
index 0000000..933b0a1
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * This class extends Horde_Form to provide the form to add/edit
+ * feeds.
+ *
+ * Copyright 2002-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @package Jonah
+ */
+class Jonah_Form_Feed extends Horde_Form
+{
+    /**
+     */
+    function __construct(&$vars)
+    {
+        $channel_id = $vars->get('channel_id');
+        $editing = (!empty($channel_id));
+
+        parent::Horde_Form($vars, ($editing ? _("Edit Feed") : _("New Feed")));
+
+        $this->addHidden('', 'channel_id', 'int', false);
+        $this->addHidden('', 'old_channel_type', 'text', false);
+
+        $select_type =& $this->addVariable(_("Type"), 'channel_type', 'enum', true, false, null, array(Jonah::getAvailableTypes()));
+        $select_type->setDefault(Jonah::INTERNAL_CHANNEL);
+        $select_type->setHelp('feed-type');
+        $select_type->setAction(Horde_Form_Action::factory('submit'));
+
+        $this->addVariable(_("Name"), 'channel_name', 'text', true);
+        $this->addVariable(_("Extra information for this feed type"), 'extra_info', 'header', false);
+    }
+
+    /**
+     */
+    function setExtraFields($channel_id = null)
+    {
+        $this->addVariable(_("Description"), 'channel_desc', 'text', false);
+        $this->addVariable(
+            _("Channel Slug"), 'channel_slug', 'text', true, false,
+           sprintf(_("Slugs allows direct access to this channel's content by visiting: %s. <br /> Slug names may contain only letters, numbers or the _ (underscore) character."),
+                    Horde::url('slugname')),
+            array('/^[a-zA-Z1-9_]*$/'));
+
+        $this->addVariable(_("Include full story content in syndicated feeds?"), 'channel_full_feed', 'boolean', false);
+        $this->addVariable(_("Channel URL if not the default one. %c gets replaced by the feed ID."), 'channel_link', 'text', false);
+        $this->addVariable(_("Channel URL for further pages, if not the default one. %c gets replaced by the feed ID, %n by the story offset."), 'channel_page_link', 'text', false);
+        $this->addVariable(_("Story URL if not the default one. %c gets replaced by the feed ID, %s by the story ID."), 'channel_story_url', 'text', false);
+    }
+
+}
diff --git a/jonah/lib/Form/Story.php b/jonah/lib/Form/Story.php
new file mode 100644 (file)
index 0000000..f29a479
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+/**
+ * Form for editing a new Story.
+ *
+ * @package Jonah
+ */
+/**
+ * Horde_Form_Action
+ */
+require_once 'Horde/Form/Action.php';
+
+/**
+ * This class extends Horde_Form to provide the form to add/edit
+ * stories.
+ *
+ * Copyright 2002-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Marko Djukic <marko@oblo.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @package Jonah
+ */
+class Jonah_Form_Story extends Horde_Form
+{
+    /**
+     */
+    function __construct(&$vars)
+    {
+        parent::Horde_Form($vars, $vars->get('id') ? _("Edit Story") : _("Add New Story"));
+
+        $this->setButtons(_("Save"), true);
+        $channel_id = $this->addHidden('', 'channel_id', 'int', false);
+        $channel = $vars->get('channel_id');
+        if ($channel) {
+            $channel_id->setDefault($channel_id);
+        }
+        $this->addHidden('', 'id', 'int', false);
+        $this->addHidden('', 'read', 'int', false);
+        $this->addVariable(_("Story Title (Headline)"), 'title', 'text', true);
+        $this->addVariable(_("Short Description"), 'description', 'longtext', true, false, null, array(2, 80));
+        $this->addVariable(_("Publish Now?"), 'publish_now', 'boolean', false);
+
+        $published = $vars->get('published');
+        if ($published) {
+            $date_params = array(min(date('Y', $published), date('Y')),
+                                 max(date('Y', $published), date('Y') + 10));
+        } else {
+            $date_params = array();
+        }
+
+        $d = &$this->addVariable(_("Or publish on this date:"), 'publish_date', 'monthdayyear', false, false, null, $date_params);
+        $d->setDefault($published);
+
+        $t = &$this->addVariable('', 'publish_time', 'hourminutesecond', false);
+        $t->setDefault($published);
+
+        $v = &$this->addVariable(_("Story body type"), 'body_type', 'enum', false, false, null, array(Jonah::getBodyTypes()));
+        $v->setAction(Horde_Form_Action::factory('submit'));
+        $v->setOption('trackchange', true);
+
+        /* If no body type specified, default to one. */
+        $body_type = $vars->get('body_type');
+        if (empty($body_type)) {
+            $body_type = Jonah::getDefaultBodyType();
+            $vars->set('body_type', $body_type);
+        }
+
+        /* Set up the fields according to what the type of body requested. */
+        if ($body_type == 'text') {
+            $this->addVariable(_("Full Story Text"), 'body', 'longtext', false, false, null, array(15, 80));
+        } elseif ($body_type == 'richtext') {
+            $this->addVariable(_("Full Story Text"), 'body', 'longtext', false, false, null, array(20, 80, array('rte')));
+        }
+
+        $this->addVariable(_("Tags"), 'tags', 'text', false, false, _("Enter keywords to tag this story, separated by commas"));
+        /* Only show URL insertion if it has been enabled in config. */
+        if (in_array('links', $GLOBALS['conf']['news']['story_types'])) {
+            $this->addVariable(_("Story URL"), 'url', 'text', false, false, _("If you enter a URL without a full story text, clicking on the story will send the reader straight to the URL, otherwise it will be shown at the end of the full story."));
+        }
+    }
+
+    /**
+     */
+    function getInfo(&$vars, &$info)
+    {
+        parent::getInfo($vars, $info);
+
+        /* Build release date. */
+        if (!empty($info['publish_now'])) {
+            $info['published'] = time();
+        } elseif (!empty($info['publish_date'])) {
+            $info['published'] = mktime(
+                (int)$info['publish_time']['hour'],
+                (int)$info['publish_time']['minute'],
+                0,
+                date('n', $info['publish_date']),
+                date('j', $info['publish_date']),
+                date('Y', $info['publish_date']));
+        } else {
+            $info['published'] = null;
+        }
+
+        unset($info['publish_now']);
+        unset($info['publish_date']);
+        unset($info['publish_time']);
+    }
+
+}
diff --git a/jonah/lib/Forms/Feed.php b/jonah/lib/Forms/Feed.php
deleted file mode 100644 (file)
index a8fcb9e..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-<?php
-/**
- * @package Jonah
- */
-
-/**
- * Horde_Form
- */
-require_once 'Horde/Form.php';
-
-/**
- * Horde_Form_Action
- */
-require_once 'Horde/Form/Action.php';
-
-/**
- * This class extends Horde_Form to provide the form to add/edit
- * feeds.
- *
- * Copyright 2002-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file LICENSE for license information (BSD). If you
- * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
- *
- * @author Marko Djukic <marko@oblo.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @package Jonah
- */
-class FeedForm extends Horde_Form
-{
-    /**
-     */
-    function FeedForm(&$vars)
-    {
-        $channel_id = $vars->get('channel_id');
-        $editing = (!empty($channel_id));
-
-        parent::Horde_Form($vars, ($editing ? _("Edit Feed") : _("New Feed")));
-
-        $this->addHidden('', 'channel_id', 'int', false);
-        $this->addHidden('', 'old_channel_type', 'text', false);
-
-        $select_type =& $this->addVariable(_("Type"), 'channel_type', 'enum', true, false, null, array(Jonah_News::getAvailableTypes()));
-        $select_type->setDefault(Jonah_News::getDefaultType());
-        $select_type->setHelp('feed-type');
-        $select_type->setAction(Horde_Form_Action::factory('submit'));
-
-        $this->addVariable(_("Name"), 'channel_name', 'text', true);
-        $this->addVariable(_("Extra information for this feed type"), 'extra_info', 'header', false);
-    }
-
-    /**
-     */
-    function getInfo(&$vars, &$info)
-    {
-        parent::getInfo($vars, $info);
-        if ($vars->get('channel_type') == Jonah::COMPOSITE_CHANNEL &&
-            is_array($vars->get('subchannels'))) {
-                $info['channel_url'] = implode(':', $vars->get('subchannels'));
-        }
-    }
-
-    /**
-     */
-    function setExtraFields($type = null, $channel_id = null)
-    {
-        if (is_null($type)) {
-            $type = Jonah_News::getDefaultType();
-        }
-
-        switch ($type) {
-        case Jonah::INTERNAL_CHANNEL:
-            $this->addVariable(_("Description"), 'channel_desc', 'text', false);
-            $this->addVariable(
-                _("Channel Slug"), 'channel_slug', 'text', true, false,
-               sprintf(_("Slugs allows direct access to this channel's content by visiting: %s. <br /> Slug names may contain only letters, numbers or the _ (underscore) character."),
-                        Horde::url('slugname', true)),
-                array('/^[a-zA-Z1-9_]*$/'));
-
-            $this->addVariable(_("Include full story content in syndicated feeds?"), 'channel_full_feed', 'boolean', false);
-            $this->addVariable(_("Channel URL if not the default one. %c gets replaced by the feed ID."), 'channel_link', 'text', false);
-            $this->addVariable(_("Channel URL for further pages, if not the default one. %c gets replaced by the feed ID, %n by the story offset."), 'channel_page_link', 'text', false);
-            $this->addVariable(_("Story URL if not the default one. %c gets replaced by the feed ID, %s by the story ID."), 'channel_story_url', 'text', false);
-            break;
-
-        case Jonah::EXTERNAL_CHANNEL:
-            $interval = Jonah_News::getIntervalLabel();
-            $v = &$this->addVariable(_("Caching"), 'channel_interval', 'enum', false, false, _("The interval before stories in this feed are rechecked for updates. If none, then stories will always be refetched from the source."), array($interval));
-            $v->setDefault('86400');
-            $this->addVariable(_("Source URL"), 'channel_url', 'text', true, false, _("The url to use to fetch the stories, for example 'http://www.example.com/stories.rss'"));
-            $this->addVariable(_("Link"), 'channel_link', 'text', false);
-            $this->addVariable(_("Image"), 'channel_img', 'text', false);
-            break;
-
-        case Jonah::AGGREGATED_CHANNEL:
-            $this->addHidden('', 'channel_url', 'text', false);
-            $interval = Jonah_News::getIntervalLabel();
-            $this->addVariable(_("Description"), 'channel_desc', 'text', false);
-            $v = &$this->addVariable(_("Caching"), 'channel_interval', 'enum', false, false, _("The interval before stories aggregated into this feeds are rechecked for updates. If none, then stories will always be refetched from the sources."), array($interval));
-            $v->setDefault('86400');
-            if (!empty($channel_id)) {
-                $edit_url = Horde::url('channels/aggregate.php');
-                $edit_url = Horde_Util::addParameter($edit_url, 'channel_id', $channel_id);
-                $edit_url = Horde_Util::addParameter($edit_url, 'channel_id', $channel_id);
-                $this->addVariable(_("Source URLs"), 'channel_urls', 'link', false, false, null, array(array('text' => _("Edit aggregated feeds"), 'url' => $edit_url)));
-            }
-            break;
-
-        case Jonah::COMPOSITE_CHANNEL:
-            global $news;
-            $channels = $news->getChannels(Jonah::INTERNAL_CHANNEL);
-            $enum = array();
-            foreach ($channels as $channel) {
-                $enum[$channel['channel_id']] = $channel['channel_name'];
-            }
-            $this->addVariable(_("Description"), 'channel_desc', 'text', false);
-            $this->addVariable(_("Channel URL if not the default one. %c gets replaced by the feed ID, %n by the story offset."), 'channel_page_link', 'text', false);
-            $this->addVariable(_("Story URL if not the default one. %c gets replaced by the feed ID, %s by the story ID."), 'channel_story_url', 'text', false);
-            $v = &$this->addVariable(_("Composite feeds"), 'subchannels', 'multienum', false, false, '', array($enum));
-            if (!empty($channel_id)) {
-                $channel = $news->getChannel($channel_id);
-                $v->setDefault(explode(':', $channel['channel_url']));
-            }
-            break;
-        }
-    }
-
-}
diff --git a/jonah/lib/Forms/Story.php b/jonah/lib/Forms/Story.php
deleted file mode 100644 (file)
index 1d460cc..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-<?php
-/**
- * @package Jonah
- */
-
-/**
- * Horde_Form
- */
-require_once 'Horde/Form.php';
-
-/**
- * Horde_Form_Action
- */
-require_once 'Horde/Form/Action.php';
-
-/**
- * This class extends Horde_Form to provide the form to add/edit
- * stories.
- *
- * Copyright 2002-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file LICENSE for license information (BSD). If you
- * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
- *
- * @author Marko Djukic <marko@oblo.com>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @package Jonah
- */
-class StoryForm extends Horde_Form
-{
-    /**
-     */
-    function StoryForm(&$vars)
-    {
-        parent::Horde_Form($vars, $vars->get('story_id') ? _("Edit Story") : _("Add New Story"));
-
-        $this->setButtons(_("Save"), true);
-        $this->addHidden('', 'channel_id', 'int', false);
-        $this->addHidden('', 'story_id', 'int', false);
-        $this->addHidden('', 'story_read', 'int', false);
-        $this->addVariable(_("Story Title (Headline)"), 'story_title', 'text', true);
-        $this->addVariable(_("Short Description"), 'story_desc', 'longtext', true, false, null, array(2, 80));
-        $this->addVariable(_("Publish Now?"), 'publish_now', 'boolean', false);
-
-        $published = $vars->get('story_published');
-        if ($published) {
-            $date_params = array(min(date('Y', $published), date('Y')),
-                                 max(date('Y', $published), date('Y') + 10));
-        } else {
-            $date_params = array();
-        }
-
-        $d = &$this->addVariable(_("Or publish on this date:"), 'publish_date', 'monthdayyear', false, false, null, $date_params);
-        $d->setDefault($published);
-
-        $t = &$this->addVariable('', 'publish_time', 'hourminutesecond', false);
-        $t->setDefault($published);
-
-        $v = &$this->addVariable(_("Story body type"), 'story_body_type', 'enum', false, false, null, array(Jonah::getBodyTypes()));
-        $v->setAction(Horde_Form_Action::factory('submit'));
-        $v->setOption('trackchange', true);
-
-        /* If no body type specified, default to one. */
-        $body_type = $vars->get('story_body_type');
-        if (empty($body_type)) {
-            $body_type = Jonah::getDefaultBodyType();
-            $vars->set('story_body_type', $body_type);
-        }
-
-        /* Set up the fields according to what the type of body requested. */
-        if ($body_type == 'text') {
-            $this->addVariable(_("Full Story Text"), 'story_body', 'longtext', false, false, null, array(15, 80));
-        } elseif ($body_type == 'richtext') {
-            $this->addVariable(_("Full Story Text"), 'story_body', 'longtext', false, false, null, array(20, 80, array('rte')));
-        }
-
-        $this->addVariable(_("Tags"), 'story_tags', 'text', false, false, _("Enter keywords to tag this story, separated by commas"));
-        /* Only show URL insertion if it has been enabled in config. */
-        if (in_array('links', $GLOBALS['conf']['news']['story_types'])) {
-            $this->addVariable(_("Story URL"), 'story_url', 'text', false, false, _("If you enter a URL without a full story text, clicking on the story will send the reader straight to the URL, otherwise it will be shown at the end of the full story."));
-        }
-    }
-
-    /**
-     */
-    function getInfo(&$vars, &$info)
-    {
-        parent::getInfo($vars, $info);
-
-        /* Build release date. */
-        if (!empty($info['publish_now'])) {
-            $info['story_published'] = time();
-        } elseif (!empty($info['publish_date'])) {
-            $info['story_published'] = mktime(
-                (int)$info['publish_time']['hour'],
-                (int)$info['publish_time']['minute'],
-                0,
-                date('n', $info['publish_date']),
-                date('j', $info['publish_date']),
-                date('Y', $info['publish_date']));
-        } else {
-            $info['story_published'] = null;
-        }
-
-        unset($info['publish_now']);
-        unset($info['publish_date']);
-        unset($info['publish_time']);
-    }
-
-}
index 20506e7..4e9c3cf 100644 (file)
@@ -2,6 +2,11 @@
 /**
  * Jonah Base Class.
  *
+ * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
  * @author  Chuck Hagenbuch <chuck@horde.org>
  * @author  Eric Rechlin <eric@hpcalc.org>
  *
@@ -38,6 +43,8 @@ class Jonah
     /**
      * Obtain the list of stories from the passed in URI.
      *
+     * @deprecated Will be removed when external channels are removed.
+     *
      * @param string $url  The url to get the list of the channel's stories.
      */
     static public function readURL($url)
@@ -68,46 +75,13 @@ class Jonah
     }
 
     /**
-     * Returns a drop-down select box to choose which view to display.
-     *
-     * @param $name      Name to assign to select box.
-     * @param $selected  Currently selected item. (optional)
-     * @param $onchange  JavaScript onchange code. (optional)
-     *
-     * @return string Generated select box code
-     */
-    static public function buildViewWidget($name, $selected = 'standard', $onchange = '')
-    {
-        require JONAH_BASE . '/config/templates.php';
-
-        if ($onchange) {
-            $onchange = ' onchange="' . $onchange . '"';
-        }
-
-        $html = '<select name="' . $name . '"' . $onchange . '>' . "\n";
-        foreach ($templates as $key => $tinfo) {
-            $select = ($selected == $key) ? ' selected="selected"' : '';
-            $html .= '<option value="' . $key . '"' . $select . '>' . $tinfo['name'] . "</option>\n";
-        }
-        return $html . '</select>';
-    }
-
-    /**
+     * @deprecated Remove when external channels moved to hippo.
      */
     static public function getChannelTypeLabel($type)
     {
         switch ($type) {
         case Jonah::INTERNAL_CHANNEL:
             return _("Local Feed");
-
-        case Jonah::EXTERNAL_CHANNEL:
-            return _("External Feed");
-
-        case Jonah::AGGREGATED_CHANNEL:
-            return _("Aggregated Feed");
-
-        case Jonah::COMPOSITE_CHANNEL:
-            return _("Composite Feed");
         }
     }
 
@@ -140,7 +114,6 @@ class Jonah
 
         switch ($filter) {
         case 'internal_channels':
-        case 'external_channels':
             if (empty($in) || !$perms->exists('jonah:news:' . $filter . ':' . $in)) {
                 return $perms->hasPermission('jonah:news:' . $filter, $GLOBALS['registry']->getAuth(), $permission);
             } elseif (!is_array($in)) {
@@ -172,6 +145,7 @@ class Jonah
     }
 
     /**
+     * @deprecated Remove when external channels removed.
      *
      * @param string $type  The Jonah::* constant for the channel type.
      *
@@ -181,8 +155,6 @@ class Jonah
     {
         if ($type == Jonah::INTERNAL_CHANNEL) {
             return 'internal_channels';
-        } elseif ($type == Jonah::EXTERNAL_CHANNEL) {
-            return 'external_channels';
         }
     }
 
@@ -231,4 +203,27 @@ class Jonah
         return array_shift(array_keys($types));
     }
 
-}
+    /**
+     * Returns the available channel types based on what was set in the
+     * configuration.
+     *
+     * @return array  The available news channel types.
+     */
+    static public function getAvailableTypes()
+    {
+        $types = array();
+
+        if (empty($GLOBALS['conf']['news']['enable'])) {
+            return $types;
+        }
+        if (in_array('internal', $GLOBALS['conf']['news']['enable'])) {
+            $types[Jonah::INTERNAL_CHANNEL] = _("Local Feed");
+        }
+        if (in_array('composite', $GLOBALS['conf']['news']['enable'])) {
+            $types[Jonah::COMPOSITE_CHANNEL] = _("Composite Feed");
+        }
+
+        return $types;
+    }
+
+}
\ No newline at end of file
diff --git a/jonah/lib/View/Base.php b/jonah/lib/View/Base.php
new file mode 100644 (file)
index 0000000..b377526
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+/*
+ * Jonah_View:: class wraps display or the various channel and story views.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE
+ *
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
+ */
+abstract class Jonah_View_Base
+{
+    /**
+     * Values to include in the view's scope
+     *
+     * @var array
+     */
+    protected $_params;
+
+    /**
+     * Const'r
+     *
+     * @param array $params  View parameters
+     */
+    public function __construct($params = array())
+    {
+        $this->_params = $params;
+    }
+
+    protected function _exit($message)
+    {
+        extract($this->_params, EXTR_REFS);
+        $notification->push(sprintf(_("Error fetching story: %s"), $message), 'horde.error');
+        require JONAH_TEMPLATES . '/common-header.inc';
+        $notification->notify(array('listeners' => 'status'));
+        require $registry->get('templates', 'horde') . '/common-footer.inc';
+        exit;
+    }
+
+    /**
+     * Render this view.
+     *
+     */
+    abstract public function run();
+
+}
+
diff --git a/jonah/lib/View/ChannelDelete.php b/jonah/lib/View/ChannelDelete.php
new file mode 100644 (file)
index 0000000..5201430
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+/**
+ * View for handling deletion of channels.
+ *
+ * Copyright 2003 - 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Marko Djukic <marko@oblo.com>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
+ */
+class Jonah_View_ChannelDelete extends Jonah_View_Base
+{
+    /**
+     * Expects:
+     *   $vars
+     *   $registry
+     *   $notification
+     */
+    public function run()
+    {
+        extract($this->_params, EXTR_REFS);
+
+        /* Set up the form variables and the form. */
+        $form_submit = $vars->get('submitbutton');
+        $channel_id = $vars->get('channel_id');
+
+        try {
+            $channel = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannel($channel_id);
+        } catch (Exception $e) {
+            Horde::logMessage($e, 'ERR');
+            $notification->push(_("Invalid channel specified for deletion."), 'horde.message');
+            Horde::url('channels')->redirect();
+            exit;
+        }
+
+        /* If not yet submitted set up the form vars from the fetched channel. */
+        if (empty($form_submit)) {
+            $vars = new Horde_Variables($channel);
+        }
+
+        /* Check permissions and deny if not allowed. */
+        if (!Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::DELETE, $channel_id)) {
+            $notification->push(_("You are not authorised for this action."), 'horde.warning');
+            $registry->authenticationFailure();
+        }
+
+        $title = sprintf(_("Delete News Channel \"%s\"?"), $vars->get('channel_name'));
+        $form = new Horde_Form($vars, $title);
+        $form->setButtons(array(_("Delete"), _("Do not delete")));
+        $form->addHidden('', 'channel_id', 'int', true, true);
+        $msg = _("Really delete this News Channel? All stories created in this channel will be lost!");
+        $form->addVariable($msg, 'confirm', 'description', false);
+        if ($form_submit == _("Delete")) {
+            if ($form->validate($vars)) {
+                $form->getInfo($vars, $info);
+                try {
+                    $delete = $GLOBALS['injector']->getInstance('Jonah_Driver')->deleteChannel($info);
+                    $notification->push(_("The channel has been deleted."), 'horde.success');
+                    Horde::url('channels')->redirect();
+                    exit;
+                } catch (Exception $e) {
+                    $notification->push(sprintf(_("There was an error deleting the channel: %s"), $e->getMessage()), 'horde.error');
+                }
+            }
+        } elseif (!empty($form_submit)) {
+            $notification->push(_("Channel has not been deleted."), 'horde.message');
+            Horde::url('channels')->redirect();
+            exit;
+        }
+
+        require JONAH_TEMPLATES . '/common-header.inc';
+        require JONAH_TEMPLATES . '/menu.inc';
+        $form->renderActive(null, $vars, Horde::selfUrl(), 'post');
+        require $registry->get('templates', 'horde') . '/common-footer.inc';
+    }
+
+}
diff --git a/jonah/lib/View/ChannelEdit.php b/jonah/lib/View/ChannelEdit.php
new file mode 100644 (file)
index 0000000..ceebc31
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Marko Djukic <marko@oblo.com>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
+ */
+class Jonah_View_ChannelEdit extends Jonah_View_Base
+{
+    /**
+     * expects
+     *   $notification
+     *   $registry
+     *   $vars
+     */
+    public function run()
+    {
+        extract($this->_params, EXTR_REFS);
+
+        $form = new Jonah_Form_Feed($vars);
+
+        /* Set up some variables. */
+        $formname = $vars->get('formname');
+        $channel_id = $vars->get('channel_id');
+
+        /* Form not yet submitted and is being edited. */
+        if (!$formname && $channel_id) {
+            $vars = new Horde_Variables($GLOBALS['injector']->getInstance('Jonah_Driver')->getChannel($channel_id));
+        }
+
+        /* Get the vars for channel type. */
+        $channel_type = $vars->get('channel_type');
+
+        /* Check permissions and deny if not allowed. */
+        if (!Jonah::checkPermissions(Jonah::typeToPermName($channel_type), Horde_Perms::EDIT, $channel_id)) {
+            $notification->push(_("You are not authorised for this action."), 'horde.warning');
+            $registry->authenticationFailure();
+        }
+
+        /* Output the extra fields required for this channel type. */
+        $form->setExtraFields($channel_id);
+        if ($formname && empty($changed_type)) {
+            if ($form->validate($vars)) {
+                $form->getInfo($vars, $info);
+                try {
+                    $save = $GLOBALS['injector']->getInstance('Jonah_Driver')->saveChannel($info);
+                    $notification->push(sprintf(_("The feed \"%s\" has been saved."), $info['channel_name']), 'horde.success');
+                    Horde::url('channels')->redirect();
+                    exit;
+                } catch (Exception $e) {
+                    $notification->push(sprintf(_("There was an error saving the feed: %s"), $e->getMessage()), 'horde.error');
+                }
+            }
+        }
+
+        $renderer = new Horde_Form_Renderer();
+        $title = $form->getTitle();
+        require JONAH_TEMPLATES . '/common-header.inc';
+        require JONAH_TEMPLATES . '/menu.inc';
+        $form->renderActive($renderer, $vars, 'edit.php', 'post');
+        require $registry->get('templates', 'horde') . '/common-footer.inc';
+    }
+
+}
\ No newline at end of file
diff --git a/jonah/lib/View/ChannelList.php b/jonah/lib/View/ChannelList.php
new file mode 100644 (file)
index 0000000..8d76a9e
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+/**
+ * View for displaying Jonah channels.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Marko Djukic <marko@oblo.com>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
+ */
+class Jonah_View_ChannelList extends Jonah_View_Base
+{
+    /**
+     *
+     */
+    public function run()
+    {
+        extract($this->_params, EXTR_REFS);
+        try {
+            $channels = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannels();
+        } catch (Exception $e) {
+            $notification->push(sprintf(_("An error occurred fetching channels: %s"), $e->getMessage()), 'horde.error');
+            $channels = false;
+        }
+        if ($channels) {
+            $channels = Jonah::checkPermissions('channels', Horde_Perms::SHOW, $channels);
+            /* Build channel specific fields. */
+            foreach ($channels as $key => $channel) {
+                /* Edit channel link. */
+                $url = Horde::url('channels/edit.php')->add('channel_id', $channel['channel_id']);
+                $channels[$key]['edit_link'] = $url->link(array('title' => _("Edit channel"))) . Horde::img('edit.png') . '</a>';
+
+                /* Delete channel link. */
+                $url = Horde::url('channels/delete.php')->add('channel_id', $channel['channel_id']);
+                $channels[$key]['delete_link'] = $url->link(array('title' => _("Delete channel"))) . Horde::img('delete.png') . '</a>';
+
+                /* View stories link. */
+                $channels[$key]['stories_url'] = Horde::url('stories/index.php')->add('channel_id', $channel['channel_id']);
+
+                /* Channel type specific links. */
+                $channels[$key]['addstory_link'] = '';
+                $channels[$key]['refresh_link'] = '';
+
+                switch ($channel['channel_type']) {
+                case Jonah::INTERNAL_CHANNEL:
+                    /* Add story link. */
+                    $url = Horde::url('stories/edit.php')->add('channel_id', $channel['channel_id']);
+                    $channels[$key]['addstory_link'] = $url->link(array('title' => _("Add story"))) . Horde::img('new.png') . '</a>';
+                    break;
+                }
+                $channels[$key]['channel_type'] = Jonah::getChannelTypeLabel($channel['channel_type']);
+                $channels[$key]['channel_updated'] = ($channel['channel_updated'] ? strftime($prefs->getValue('date_format'), (int)$channel['channel_updated']) : '-');
+            }
+        }
+
+        $view = new Horde_View(array('templatePath' => JONAH_TEMPLATES . '/view'));
+        $view->addHelper('Tag');
+        $view->channels = $channels;
+        $view->search_img = Horde::img('search.png');
+        $title = _("Feeds");
+        Horde::addScriptFile('prototype.js', 'horde', true);
+        Horde::addScriptFile('tables.js', 'horde', true);
+        Horde::addScriptFile('quickfinder.js', 'horde', true);
+        require JONAH_TEMPLATES . '/common-header.inc';
+        require JONAH_TEMPLATES . '/menu.inc';
+        echo $view->render('channellist');
+        require $registry->get('templates', 'horde') . '/common-footer.inc';
+    }
+
+}
\ No newline at end of file
diff --git a/jonah/lib/View/DeliveryHtml.php b/jonah/lib/View/DeliveryHtml.php
new file mode 100644 (file)
index 0000000..5d73e8a
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Script to handle requests for html delivery of stories.
+ *
+ * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Jan Schneider <jan@horde.org>
+ */
+class Jonah_View_DeliveryHtml extends Jonah_View_Base
+{
+    /**
+     * $registry
+     * $notification
+     * $conf
+     * $criteria
+     *
+     */
+    public function run()
+    {
+        extract($this->_params, EXTR_REFS);
+        require JONAH_BASE . '/config/templates.php';
+
+        /* Get requested channel. */
+        try {
+            $channel = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannel($criteria['feed']);
+        } catch (Exception $e) {
+            Horde::logMessage($e, 'ERR');
+            $notification->push(_("Invalid channel."), 'horde.error');
+            Horde::url('delivery/index.php', true)->redirect();
+            exit;
+        }
+
+        $title = sprintf(_("HTML Delivery for \"%s\""), $channel['channel_name']);
+
+        $options = array();
+        foreach ($templates as $key => $info) {
+            $options[] = '<option value="' . $key . '"' . ($key == $criteria['format'] ? ' selected="selected"' : '') . '>' . $info['name'] . '</option>';
+        }
+
+        $template = new Horde_Template();
+        $template->setOption('gettext', 'true');
+        $template->set('url', Horde::selfUrl());
+        $template->set('session', Horde_Util::formInput());
+        $template->set('channel_id', $criteria['feed']);
+        $template->set('channel_name', $channel['channel_name']);
+        $template->set('format', $criteria['format']);
+        $template->set('options', $options);
+
+        // @TODO: This is ugly. storage driver shouldn't be rendering any display
+        // refactor this to use individual views possibly with a choice of different templates
+        $template->set('stories', $GLOBALS['injector']->getInstance('Jonah_Driver')->renderChannel($criteria['feed'], $criteria['format']));
+        $template->set('menu', Jonah::getMenu('string'));
+
+        // Buffer the notifications and send to the template
+        Horde::startBuffer();
+        $GLOBALS['notification']->notify(array('listeners' => 'status'));
+        $template->set('notify', Horde::endBuffer());
+
+        require JONAH_TEMPLATES . '/common-header.inc';
+        echo $template->fetch(JONAH_TEMPLATES . '/delivery/html.html');
+        require $registry->get('templates', 'horde') . '/common-footer.inc';
+    }
+
+}
\ No newline at end of file
diff --git a/jonah/lib/View/StoryDelete.php b/jonah/lib/View/StoryDelete.php
new file mode 100644 (file)
index 0000000..f95ecee
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+/**
+ * Jonah_View_StoryDelete:: handle story deletion
+ *
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Marko Djukic <marko@oblo.com>
+ * @package Jonah
+ */
+class Jonah_View_StoryDelete extends Jonah_View_Base
+{
+    public function run()
+    {
+        extract($this->_params, EXTR_REFS);
+
+        $form_submit = $vars->get('submitbutton');
+        $channel_id = $vars->get('channel_id');
+        $story_id = $vars->get('id');
+
+        /* Driver */
+        $driver = $GLOBALS['injector']->getInstance('Jonah_Driver');
+
+        /* Fetch the channel details, needed for later and to check if valid
+         * channel has been requested. */
+        try {
+            $channel = $driver->getChannel($channel_id);
+        } catch (Exception $e) {
+            $notification->push(sprintf(_("Story editing failed: %s"), $e->getMessage()), 'horde.error');
+            Horde::url('channels/index.php', true)->redirect();
+            exit;
+        }
+
+        /* Check permissions. */
+        if (!Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::DELETE, $channel_id)) {
+            $notification->push(_("You are not authorised for this action."), 'horde.warning');
+            $registry->authenticationFailure();
+        }
+
+        try {
+            $story = $driver->getStory($channel_id, $story_id);
+        } catch (Exception $e) {
+            $notification->push(_("No valid story requested for deletion."), 'horde.message');
+            Horde::url('channels/index.php', true)->redirect();
+            exit;
+        }
+
+        /* If not yet submitted set up the form vars from the fetched story. */
+        if (empty($form_submit)) {
+            $vars = new Horde_Variables($story);
+        }
+
+        $title = sprintf(_("Delete News Story \"%s\"?"), $vars->get('title'));
+
+        $form = new Horde_Form($vars, $title);
+        $form->setButtons(array(_("Delete"), _("Do not delete")));
+        $form->addHidden('', 'channel_id', 'int', true, true);
+        $form->addHidden('', 'id', 'int', true, true);
+        $form->addVariable(_("Really delete this News Story?"), 'confirm', 'description', false);
+
+        if ($form_submit == _("Delete")) {
+            if ($form->validate($vars)) {
+                $form->getInfo($vars, $info);
+                try {
+                    $delete = $driver->deleteStory($info['channel_id'], $info['id']);
+                    $notification->push(_("The story has been deleted."), 'horde.success');
+                    Horde::url('stories/index.php', true)->add('channel_id', $channel_id)->setRaw(true)->redirect();
+                    exit;
+                } catch (Exception $e) {
+                    $notification->push(sprintf(_("There was an error deleting the story: %s"), $e->getMessage()), 'horde.error');
+                }
+            }
+        } elseif (!empty($form_submit)) {
+            $notification->push(_("Story has not been deleted."), 'horde.message');
+            $url = Horde::url('stories/index.php', true)->add('channel_id', $channel_id)->setRaw(true);
+            Horde::url('stories/index.php', true)->add('channel_id', $channel_id)->setRaw(true)->redirect();
+            exit;
+        }
+        require JONAH_TEMPLATES . '/common-header.inc';
+        require JONAH_TEMPLATES . '/menu.inc';
+        $form->renderActive(null, $vars, 'delete.php', 'post');
+        require $registry->get('templates', 'horde') . '/common-footer.inc';
+    }
+
+}
\ No newline at end of file
diff --git a/jonah/lib/View/StoryEdit.php b/jonah/lib/View/StoryEdit.php
new file mode 100644 (file)
index 0000000..3bdcf6b
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Jonah_View_StoryEdit:: to add/edit stories.
+ *
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you did not
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Marko Djukic <marko@oblo.com>
+ * @package Jonah
+ *
+ * @TODO: This will be rewritten to NOT use Horde_Form since we want more
+ *        control over the form and, especially, the RTE.
+ */
+class Jonah_View_StoryEdit extends Jonah_View_Base
+{
+    /**
+     * $notification
+     * $registry
+     * $vars
+     *
+     */
+    public function run()
+    {
+        extract($this->_params, EXTR_REFS);
+
+        $driver = $GLOBALS['injector']->getInstance('Jonah_Driver');
+
+        /* Set up the form variables. */
+        $channel_id = $vars->get('channel_id');
+
+        /* Fetch the channel details, needed for later and to check if valid
+         * channel has been requested. */
+        try {
+            $channel = $driver->getChannel($channel_id);
+        } catch (Exception $e) {
+            $notification->push(sprintf(_("Story editing failed: %s"), $e->getMessage()), 'horde.error');
+            Horde::url('channels/index.php', true)->redirect();
+            exit;
+        }
+
+        /* Check permissions. */
+        if (!Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::EDIT, $channel_id)) {
+            $notification->push(_("You are not authorised for this action."), 'horde.warning');
+            $registry->authenticationFailure();
+        }
+
+        /* Check if a story is being edited. */
+        $story_id = $vars->get('id');
+        if ($story_id && !$vars->get('formname')) {
+            $story = $driver->getStory($channel_id, $story_id);
+            $story['tags'] = implode(',', array_values($story['tags']));
+            $vars = new Horde_Variables($story);
+        }
+
+        /* Set up the form. */
+        $form = new Jonah_Form_Story($vars);
+        if ($form->validate($vars)) {
+            $form->getInfo($vars, $info);
+            try {
+                $result = $driver->saveStory($info);
+                $notification->push(sprintf(_("The story \"%s\" has been saved."), $info['title']), 'horde.success');
+                Horde::url('stories/index.php')->add('channel_id', $channel_id)->redirect();
+                exit;
+            } catch (Exception $e) {
+                $notification->push(sprintf(_("There was an error saving the story: %s"), $e->getMessage()), 'horde.error');
+            }
+        }
+
+        /* Needed javascript. */
+        Horde::addScriptFile('open_calendar.js', 'horde');
+        $title = $form->getTitle();
+        require JONAH_TEMPLATES . '/common-header.inc';
+        require JONAH_TEMPLATES . '/menu.inc';
+        $form->renderActive($form->getRenderer(), $vars, 'edit.php', 'post');
+        require $registry->get('templates', 'horde') . '/common-footer.inc';
+    }
+
+}
\ No newline at end of file
diff --git a/jonah/lib/View/StoryList.php b/jonah/lib/View/StoryList.php
new file mode 100644 (file)
index 0000000..b6190d6
--- /dev/null
@@ -0,0 +1,120 @@
+<?php
+/**
+ * Turba_View_StoryList:: A view to handle displaying a list of stories in a
+ * channel.
+ *
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Marko Djukic <marko@oblo.com>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
+ */
+class Jonah_View_StoryList extends Jonah_View_Base
+{
+    /**
+     * expects
+     *   $registry
+     *   $notification
+     *   $prefs
+     *   $conf
+     *   $channel_id
+     */
+    public function run()
+    {
+        extract($this->_params, EXTR_REFS);
+
+        $channel = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannel($channel_id);
+        if (!Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::EDIT, $channel_id)) {
+            $notification->push(_("You are not authorised for this action."), 'horde.warning');
+            $registry->authenticationFailure();
+        }
+
+        /* Check if a URL has been passed. */
+        $url = Horde_Util::getFormData('url');
+        if ($url) {
+            $url = new Horde_Url($url);
+        }
+
+        try {
+            $stories = $GLOBALS['injector']->getInstance('Jonah_Driver')->getStories(array('channel_id' => $channel_id));
+        } catch (Exception $e) {
+            $notification->push(sprintf(_("Invalid channel requested. %s"), $e->getMessage()), 'horde.error');
+            Horde::url('channels/index.php', true)->redirect();
+            exit;
+        }
+
+        /* Do some state tests. */
+        if (empty($stories)) {
+            $notification->push(_("No available stories."), 'horde.warning');
+        }
+        if (!empty($refresh)) {
+            $notification->push(_("Channel refreshed."), 'horde.success');
+        }
+        if (!empty($url)) {
+            $url->redirect();
+            exit;
+        }
+
+        /* Get channel details, for title, etc. */
+        $allow_delete = Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::DELETE, $channel_id);
+
+        /* Build story specific fields. */
+        foreach ($stories as $key => $story) {
+            /* published is the publication/release date, updated is the last change date. */
+            if (!empty($stories[$key]['published'])) {
+                $stories[$key]['published_date'] = strftime($prefs->getValue('date_format') . ', ' . ($prefs->getValue('twentyFour') ? '%H:%M' : '%I:%M%p'), $stories[$key]['published']);
+            } else {
+                $stories[$key]['published_date'] = '';
+            }
+
+            /* Default to no links. */
+            $stories[$key]['pdf_link'] = '';
+            $stories[$key]['edit_link'] = '';
+            $stories[$key]['delete_link'] = '';
+            $stories[$key]['view_link'] = Horde::link(Horde::url($story['permalink']), $story['description']) . htmlspecialchars($story['title']) . '</a>';
+
+            /* PDF link. */
+            $url = Horde::url('stories/pdf.php');
+            $url = Horde_Util::addParameter($url, array('id' => $story['id'], 'channel_id' => $channel_id));
+            $stories[$key]['pdf_link'] = Horde::link($url, _("PDF version")) . Horde::img('mime/pdf.png') . '</a>';
+
+            /* Edit story link. */
+            $url = Horde::url('stories/edit.php');
+            $url = Horde_Util::addParameter($url, array('id' => $story['id'], 'channel_id' => $channel_id));
+            $stories[$key]['edit_link'] = Horde::link($url, _("Edit story")) . Horde::img('edit.png') . '</a>';
+
+            /* Delete story link. */
+            if ($allow_delete) {
+                $url = Horde::url('stories/delete.php');
+                $url = Horde_Util::addParameter($url, array('id' => $story['id'], 'channel_id' => $channel_id));
+                $stories[$key]['delete_link'] = Horde::link($url, _("Delete story")) . Horde::img('delete.png') . '</a>';
+            }
+
+            /* Comment counter. */
+            if ($conf['comments']['allow'] &&
+                $registry->hasMethod('forums/numMessages')) {
+                $comments = $registry->call('forums/numMessages', array($stories[$key]['id'], 'jonah'));
+                if (!is_a($comments, 'PEAR_Error')) {
+                    $stories[$key]['comments'] = $comments;
+                }
+            }
+
+        }
+
+        /* Render page */
+        $title = $channel['channel_name'];
+        $view = new Horde_View(array('templatePath' => JONAH_TEMPLATES . '/stories'));
+        $view->stories = $stories;
+        $view->read = true;
+        $view->comments = $conf['comments']['allow'] && $registry->hasMethod('forums/numMessages') && $channel['channel_type'] == Jonah::INTERNAL_CHANNEL;
+        require JONAH_TEMPLATES . '/common-header.inc';
+        require JONAH_TEMPLATES . '/menu.inc';
+        echo $view->render('index');
+        require $registry->get('templates', 'horde') . '/common-footer.inc';
+    }
+
+}
\ No newline at end of file
diff --git a/jonah/lib/View/StoryPdf.php b/jonah/lib/View/StoryPdf.php
new file mode 100644 (file)
index 0000000..373d46b
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @package Jonah
+ */
+class Jonah_View_StoryPdf extends Jonah_View
+{
+    public function run()
+    {
+        extract($this->_params, EXTR_REFS);
+
+        $driver = $GLOBALS['injector']->getInstance('Jonah_Driver');
+        if (!$story_id) {
+            try {
+                $story_id = $GLOBALS['injector']->getInstance('Jonah_Driver')->getLatestStoryId($channel_id);
+            } catch (Exception $e) {
+                $this->_exit($e->getMessage());
+            }
+        }
+        try {
+            $story = $driver->getStory($channel_id, $story_id, !$browser->isRobot());
+        } catch (Exception $e) {
+            $this->_exit($e->getMessage());
+        }
+
+        // Convert the body from HTML to text if necessary.
+        if (!empty($story['body_type']) && $story['body_type'] == 'richtext') {
+            $story['body'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['body'], 'html2text');
+        }
+
+        // Set up the PDF object.
+        $pdf = File_PDF::factory(array('format' => 'Letter', 'unit' => 'pt'));
+        $pdf->setMargins(50, 50);
+
+        // Enable automatic page breaks.
+        $pdf->setAutoPageBreak(true, 50);
+
+        // Start the document.
+        $pdf->open();
+
+        // Start a page.
+        $pdf->addPage();
+
+        // Publication date.
+        if (!empty($story['published_date'])) {
+            $pdf->setFont('Times', 'B', 14);
+            $pdf->cell(0, 14, $story['published_date'], 0, 1);
+            $pdf->newLine(10);
+        }
+
+        // Write the header in Times 24 Bold.
+        $pdf->setFont('Times', 'B', 24);
+        $pdf->multiCell(0, 24, $story['title'], 'B', 1);
+        $pdf->newLine(20);
+
+        // Write the story body in Times 14.
+        $pdf->setFont('Times', '', 14);
+        $pdf->write(14, $story['body']);
+
+        // Output the generated PDF.
+        $browser->downloadHeaders($story['title'] . '.pdf', 'application/pdf');
+        echo $pdf->getOutput();
+    }
+
+}
\ No newline at end of file
diff --git a/jonah/lib/View/StoryView.php b/jonah/lib/View/StoryView.php
new file mode 100644 (file)
index 0000000..737360e
--- /dev/null
@@ -0,0 +1,105 @@
+<?php
+/**
+ * Jonah_View_StoryView:: class to display an individual story.
+ *
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
+ */
+class Jonah_View_StoryView extends Jonah_View_Base
+{
+    /**
+     * Expects
+     *   $registry
+     *   $notification
+     *   $browser
+     *   $story_id
+     *   $channel_id
+     *
+     */
+    public function run()
+    {
+        extract($this->_params, EXTR_REFS);
+
+        $driver = $GLOBALS['injector']->getInstance('Jonah_Driver');
+        try {
+            $story = $driver->getStory($channel_id, $story_id, !$browser->isRobot());
+        } catch (Exception $e) {
+            $notification->push(sprintf(_("Error fetching story: %s"), $e->getMessage()), 'horde.warning');
+            require JONAH_TEMPLATES . '/common-header.inc';
+            require JONAH_TEMPLATES . '/menu.inc';
+            require $registry->get('templates', 'horde') . '/common-footer.inc';
+            exit;
+        }
+
+        /* Grab tag related content for entire channel */
+        $cloud = new Horde_Ui_TagCloud();
+        $allTags = $driver->listTagInfo(array(), $channel_id);
+        foreach ($allTags as $tag_id => $taginfo) {
+            $cloud->addElement($taginfo['tag_name'], Horde::url('results.php')->add(array('tag_id' => $tag_id, 'channel_id' => $channel_id)), $taginfo['total']);
+        }
+
+        /* Prepare the story's tags for display */
+        // FIXME - need to actually use these.
+        $tag_html = array();
+        $tag_link = Horde::url('stories/results.php')->add('channel_id', $channel_id);
+        foreach ($story['tags'] as $id => $tag) {
+            $link = $tag_link->copy()->add('tag_id', $id);
+            $tag_html[] = $link->link() . $tag . '</a>';
+        }
+
+        /* Filter and prepare story content. */
+        if (!empty($story['body_type']) && $story['body_type'] == 'text') {
+            $story['body'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
+        }
+
+        // @TODO: Where is this used and what for?
+        if (!empty($story['url'])) {
+            $story['body'] .= Horde::link(Horde::externalUrl($story['url'])) . htmlspecialchars($story['url']) . '</a></p>';
+        }
+
+        if (empty($story['published_date'])) {
+            $story['published_date'] = false;
+        }
+
+        $view = new Horde_View(array('templatePath' => array(JONAH_TEMPLATES . '/stories',
+                                                             JONAH_TEMPLATES . '/stories/partial',
+                                                             JONAH_TEMPLATES . '/stories/layout')));
+        $view->addHelper('Tag');
+        $view->tagcloud = $cloud->buildHTML();
+        $view->story = $story;
+
+        /* Insert link for sharing. */
+        if ($conf['sharing']['allow']) {
+            $url = Horde::url('stories/share.php')->add(array('id' => $story['id'], 'channel_id' => $channel_id));
+            $view->sharelink = $url->link() . _("Share this story") . '</a>';
+        }
+
+        /* Insert comments. */
+        if ($conf['comments']['allow']) {
+            if (!$registry->hasMethod('forums/doComments')) {
+                $err = 'User comments are enabled but the forums API is not available.';
+                Horde::logMessage($err, 'ERR');
+            } else {
+                try {
+                    $comments = $registry->call('forums/doComments', array('jonah', $story_id, 'commentCallback'));
+                } catch (Exception $e) {
+                    Horde::logMessage($e, 'ERR');
+                    $comments = array('threads' => '', 'comments' => '');
+                }
+                $view->comments = $comments;
+            }
+        }
+
+        require JONAH_TEMPLATES . '/common-header.inc';
+        require JONAH_TEMPLATES . '/menu.inc';
+        echo $view->render('view');
+        require $registry->get('templates', 'horde') . '/common-footer.inc';
+    }
+
+}
index 69a9ad3..ddc71df 100644 (file)
@@ -1,94 +1,19 @@
 <?php
 /**
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author Chuck Hagenbuch <chuck@horde.org>
  * @author Marko Djukic <marko@oblo.com>
+ * @package Jonah
  */
-
 require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah');
-require_once 'Horde/Form.php';
-require_once 'Horde/Form/Renderer.php';
-
-/* Set up the form variables. */
-$vars = Horde_Variables::getDefaultVariables();
-$form_submit = $vars->get('submitbutton');
-$channel_id = $vars->get('channel_id');
-$story_id = $vars->get('story_id');
-
-/* Driver */
-$news = Jonah_News::factory();
-
-/* Fetch the channel details, needed for later and to check if valid
- * channel has been requested. */
-$channel = $news->isChannelEditable($channel_id);
-if (is_a($channel, 'PEAR_Error')) {
-    $notification->push(sprintf(_("Story editing failed: %s"), $channel->getMessage()), 'horde.error');
-    Horde::url('channels/index.php', true)->redirect();
-}
-
-/* Check permissions. */
-if (!Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::DELETE, $channel_id)) {
-    $notification->push(_("You are not authorised for this action."), 'horde.warning');
-    Horde::authenticationFailureRedirect();
-}
-
-$story = $news->getStory($channel_id, $story_id);
-if (is_a($story, 'PEAR_Error')) {
-    $notification->push(_("No valid story requested for deletion."), 'horde.message');
-    Horde::url('channels/index.php', true)->redirect();
-}
-
-/* If not yet submitted set up the form vars from the fetched story. */
-if (empty($form_submit)) {
-    $vars = new Horde_Variables($story);
-}
-
-$title = sprintf(_("Delete News Story \"%s\"?"), $vars->get('story_title'));
-
-$form = new Horde_Form($vars, $title);
-
-$form->setButtons(array(_("Delete"), _("Do not delete")));
-$form->addHidden('', 'channel_id', 'int', true, true);
-$form->addHidden('', 'story_id', 'int', true, true);
-$form->addVariable(_("Really delete this News Story?"), 'confirm', 'description', false);
-
-if ($form_submit == _("Delete")) {
-    if ($form->validate($vars)) {
-        $form->getInfo($vars, $info);
-        $delete = $news->deleteStory($info['channel_id'], $info['story_id']);
-        if (is_a($delete, 'PEAR_Error')) {
-            $notification->push(sprintf(_("There was an error deleting the story: %s"), $delete->getMessage()), 'horde.error');
-        } else {
-            $notification->push(_("The story has been deleted."), 'horde.success');
-            Horde::url('stories/index.php', true)
-                ->add('channel_id', $channel_id)
-                ->redirect();
-        }
-    }
-} elseif (!empty($form_submit)) {
-    $notification->push(_("Story has not been deleted."), 'horde.message');
-    Horde::url('stories/index.php', true)
-        ->add('channel_id', $channel_id)
-        ->redirect();
-}
-
-$template = new Horde_Template();
-
-Horde::startBuffer();
-$form->renderActive(null, $vars, 'delete.php', 'post');
-$template->set('main', Horde::endBuffer());
-$template->set('menu', Horde::menu());
-
-// Buffer the notifications and send to the template
-Horde::startBuffer();
-$GLOBALS['notification']->notify(array('listeners' => 'status'));
-$template->set('notify', Horde::endBuffer());
 
-require JONAH_TEMPLATES . '/common-header.inc';
-echo $template->fetch(JONAH_TEMPLATES . '/main/main.html');
-require $registry->get('templates', 'horde') . '/common-footer.inc';
+Horde_Registry::appInit('jonah');
+$params = array('notification' => &$notification,
+                'registry' => &$registry,
+                'vars' => Horde_Variables::getDefaultVariables());
+$view = new Jonah_View_StoryDelete($params);
+$view->run();
index 6ca6f97..ec318b8 100644 (file)
@@ -2,80 +2,21 @@
 /**
  * Script to add/edit stories.
  *
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
- *
- * $Horde: jonah/stories/edit.php,v 1.48 2009/11/24 04:15:38 chuck Exp $
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you did not
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author Chuck Hagenbuch <chuck@horde.org>
  * @author Marko Djukic <marko@oblo.com>
+ * @package Jonah
  */
 
 require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah');
-require_once JONAH_BASE . '/lib/Forms/Story.php';
-require_once 'Horde/Form/Action.php';
-require_once 'Horde/Form/Renderer.php';
-
-$news = Jonah_News::factory();
-
-/* Set up the form variables. */
-$vars = Horde_Variables::getDefaultVariables();
-$channel_id = $vars->get('channel_id');
-
-/* Fetch the channel details, needed for later and to check if valid
- * channel has been requested. */
-$channel = $news->isChannelEditable($channel_id);
-if (is_a($channel, 'PEAR_Error')) {
-    $notification->push(sprintf(_("Story editing failed: %s"), $channel->getMessage()), 'horde.error');
-    Horde::url('channels/index.php', true)->redirect();
-}
-
-/* Check permissions. */
-if (!Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::EDIT, $channel_id)) {
-    $notification->push(_("You are not authorised for this action."), 'horde.warning');
-    Horde::authenticationFailureRedirect();
-}
-
-/* Check if a story is being edited. */
-$story_id = $vars->get('story_id');
-if ($story_id && !$vars->get('formname')) {
-    $story = $news->getStory($channel_id, $story_id);
-    $story['story_tags'] = implode(',', array_values($story['story_tags']));
-    $vars = new Horde_Variables($story);
-}
-
-/* Set up the form. */
-$form = new StoryForm($vars);
-if ($form->validate($vars)) {
-    $form->getInfo($vars, $info);
-    $result = $news->saveStory($info);
-    if (is_a($result, 'PEAR_Error')) {
-        $notification->push(sprintf(_("There was an error saving the story: %s"), $result->getMessage()), 'horde.error');
-    } else {
-        $notification->push(sprintf(_("The story \"%s\" has been saved."), $info['story_title']), 'horde.success');
-        Horde::url('stories/index.php', true)
-            ->add('channel_id', $channel_id)
-            ->redirect();
-    }
-}
-
-/* Render the form. */
-$template = new Horde_Template();
-
-Horde::startBuffer();
-$form->renderActive($form->getRenderer(), $vars, 'edit.php', 'post');
-$template->set('main', Horde::endBuffer());
-$template->set('menu', Horde::menu());
-
-// Buffer the notifications and send to the template
-Horde::startBuffer();
-$GLOBALS['notification']->notify(array('listeners' => 'status'));
-$template->set('notify', Horde::endBuffer());
+Horde_Registry::appInit('jonah');
 
-$title = $form->getTitle();
-require JONAH_TEMPLATES . '/common-header.inc';
-echo $template->fetch(JONAH_TEMPLATES . '/main/main.html');
-require $registry->get('templates', 'horde') . '/common-footer.inc';
+$params = array('notification' => &$notification,
+                'registry' => &$registry,
+                'vars' => Horde_Variables::getDefaultVariables());
+$view = new Jonah_View_StoryEdit($params);
+$view->run();
index 39bbbfe..1fa018d 100644 (file)
 <?php
 /**
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author Chuck Hagenbuch <chuck@horde.org>
  * @author Marko Djukic <marko@oblo.com>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
  */
-
 require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah');
-$news = Jonah_News::factory();
+Horde_Registry::appInit('jonah');
 
 /* Redirect to the news index if no channel_id is specified. */
 $channel_id = Horde_Util::getFormData('channel_id');
 if (empty($channel_id)) {
     $notification->push(_("No channel requested."), 'horde.error');
-    Horde::url('channels/index.php', true)->redirect();
-}
-
-$channel = $news->getChannel($channel_id);
-if (!Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::EDIT, $channel_id)) {
-    $notification->push(_("You are not authorised for this action."), 'horde.warning');
-    Horde::authenticationFailureRedirect();
-}
-
-/* Check if a forced refresh is being called for an external channel. */
-$refresh = Horde_Util::getFormData('refresh');
-
-/* Check if a URL has been passed. */
-$url = Horde_Util::getFormData('url');
-
-$stories = $news->getStories($channel_id, null, 0, !empty($refresh), null, true);
-if (is_a($stories, 'PEAR_Error')) {
-    $notification->push(sprintf(_("Invalid channel requested. %s"), $stories->getMessage()), 'horde.error');
-    Horde::url('channels/index.php', true)->redirect();
-}
-
-/* Do some state tests. */
-if (empty($stories)) {
-    $notification->push(_("No available stories."), 'horde.warning');
-}
-if (!empty($refresh)) {
-    $notification->push(_("Channel refreshed."), 'horde.success');
-}
-if (!empty($url)) {
-    header('Location: ' . $url);
+    header('Location: ' . Horde::url('channels/index.php', true));
     exit;
 }
 
-/* Get channel details, for title, etc. */
-$channel = $news->getChannel($channel_id);
-
-$allow_delete = Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::DELETE, $channel_id);
-
-/* Build story specific fields. */
-foreach ($stories as $key => $story) {
-    /* story_published is the publication/release date, story_updated
-     * is the last change date. */
-    if (!empty($stories[$key]['story_published'])) {
-        $stories[$key]['story_published_date'] = strftime($prefs->getValue('date_format') . ', ' . ($prefs->getValue('twentyFour') ? '%H:%M' : '%I:%M%p'), $stories[$key]['story_published']);
-    } else {
-        $stories[$key]['story_published_date'] = '';
-    }
-
-    /* Default to no links. */
-    $stories[$key]['pdf_link'] = '';
-    $stories[$key]['edit_link'] = '';
-    $stories[$key]['delete_link'] = '';
-
-    /* These links only if internal channel. */
-    if ($channel['channel_type'] == Jonah::INTERNAL_CHANNEL ||
-        $channel['channel_type'] == Jonah::COMPOSITE_CHANNEL) {
-        $stories[$key]['view_link'] = Horde::link(Horde::url($story['story_link']), $story['story_desc']) . htmlspecialchars($story['story_title']) . '</a>';
-
-        /* PDF link. */
-        $url = Horde::url('stories/pdf.php');
-        $url = Horde_Util::addParameter($url, array('story_id' => $story['story_id'], 'channel_id' => $channel_id));
-        $stories[$key]['pdf_link'] = Horde::link($url, _("PDF version")) . Horde::img('mime/pdf.png') . '</a>';
-
-        /* Edit story link. */
-        $url = Horde::url('stories/edit.php');
-        $url = Horde_Util::addParameter($url, array('story_id' => $story['story_id'], 'channel_id' => $channel_id));
-        $stories[$key]['edit_link'] = Horde::link($url, _("Edit story")) . Horde::img('edit.png') . '</a>';
-
-        /* Delete story link. */
-        if ($allow_delete) {
-            $url = Horde::url('stories/delete.php');
-            $url = Horde_Util::addParameter($url, array('story_id' => $story['story_id'], 'channel_id' => $channel_id));
-            $stories[$key]['delete_link'] = Horde::link($url, _("Delete story")) . Horde::img('delete.png') . '</a>';
-        }
-
-        /* Comment counter. */
-        if ($conf['comments']['allow'] &&
-            $registry->hasMethod('forums/numMessages')) {
-            $comments = $registry->call('forums/numMessages', array($stories[$key]['story_id'], 'jonah'));
-            if (!is_a($comments, 'PEAR_Error')) {
-                $stories[$key]['comments'] = $comments;
-            }
-        }
-    } else {
-        if (!empty($story['story_body'])) {
-            $stories[$key]['view_link'] = Horde::link(Horde::url($story['story_link']), $story['story_desc'], '', '_blank') . htmlspecialchars($story['story_title']) . '</a>';
-        } else {
-            $stories[$key]['view_link'] = Horde::link(Horde::externalUrl($story['story_url']), $story['story_desc'], '', '_blank') . htmlspecialchars($story['story_title']) . '</a>';
-        }
-    }
-}
-
-$template = new Horde_Template();
-$template->setOption('gettext', true);
-$template->set('header', htmlspecialchars($channel['channel_name']));
-$template->set('refresh', Horde::link(Horde_Util::addParameter(Horde::selfUrl(true), array('refresh' => 1)), _("Refresh Channel")) . Horde::img('reload.png') . '</a>');
-$template->set('listheaders', array(_("Story"), _("Date")));
-$template->set('stories', $stories, true);
-$template->set('read', $channel['channel_type'] == Jonah::INTERNAL_CHANNEL || $channel['channel_type'] == Jonah::COMPOSITE_CHANNEL, true);
-$template->set('comments', $conf['comments']['allow'] && $registry->hasMethod('forums/numMessages') && $channel['channel_type'] == Jonah::INTERNAL_CHANNEL, true);
-$template->set('menu', Horde::menu());
-
-// Buffer the notifications and send to the template
-Horde::startBuffer();
-$GLOBALS['notification']->notify(array('listeners' => 'status'));
-$template->set('notify', Horde::endBuffer());
-
-$title = $channel['channel_name'];
-require JONAH_TEMPLATES . '/common-header.inc';
-echo $template->fetch(JONAH_TEMPLATES . '/stories/index.html');
-require $registry->get('templates', 'horde') . '/common-footer.inc';
+$params = array('registry' => &$registry,
+                'notification' => &$notification,
+                'prefs' => &$prefs,
+                'conf' => &$conf,
+                'channel_id' => $channel_id);
+$view = new Jonah_View_StoryList($params);
+$view->run();
index 62baf08..e8956a7 100644 (file)
@@ -1,80 +1,23 @@
 <?php
 /**
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author Chuck Hagenbuch <chuck@horde.org>
+ * @package Jonah
  */
-
-function _exit($message)
-{
-    $GLOBALS['notification']->push(sprintf(_("Error fetching story: %s"), $message), 'horde.error');
-    require JONAH_TEMPLATES . '/common-header.inc';
-    $GLOBALS['notification']->notify(array('listeners' => 'status'));
-    require $GLOBALS['registry']->get('templates', 'horde') . '/common-footer.inc';
-    exit;
-}
-
 require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah', array(
+Horde_Registry::appInit('jonah', array(
     'authentication' => 'none',
     'session_control' => 'readonly'
 ));
 
-$news = Jonah_News::factory();
-
-$channel_id = Horde_Util::getFormData('channel_id');
-$story_id = Horde_Util::getFormData('story_id');
-if (!$story_id) {
-    $story_id = $news->getLatestStoryId($channel_id);
-    if (is_a($story_id, 'PEAR_Error')) {
-        _exit($story_id->getMessage());
-    }
-}
-
-$story = $news->getStory($channel_id, $story_id, !$browser->isRobot());
-if (is_a($story, 'PEAR_Error')) {
-    _exit($story->getMessage());
-} elseif (empty($story['story_body']) && !empty($story['story_url'])) {
-    _exit(_("Cannot generate PDFs of remote stories."));
-}
-
-// Convert the body from HTML to text if necessary.
-if (!empty($story['story_body_type']) && $story['story_body_type'] == 'richtext') {
-    $story['story_body'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['story_body'], 'html2text');
-}
-
-// Set up the PDF object.
-$pdf = File_PDF::factory(array('format' => 'Letter', 'unit' => 'pt'));
-$pdf->setMargins(50, 50);
-
-// Enable automatic page breaks.
-$pdf->setAutoPageBreak(true, 50);
-
-// Start the document.
-$pdf->open();
-
-// Start a page.
-$pdf->addPage();
-
-// Publication date.
-if (!empty($story['story_published_date'])) {
-    $pdf->setFont('Times', 'B', 14);
-    $pdf->cell(0, 14, $story['story_published_date'], 0, 1);
-    $pdf->newLine(10);
-}
-
-// Write the header in Times 24 Bold.
-$pdf->setFont('Times', 'B', 24);
-$pdf->multiCell(0, 24, $story['story_title'], 'B', 1);
-$pdf->newLine(20);
-
-// Write the story body in Times 14.
-$pdf->setFont('Times', '', 14);
-$pdf->write(14, $story['story_body']);
-
-// Output the generated PDF.
-$browser->downloadHeaders($story['story_title'] . '.pdf', 'application/pdf');
-echo $pdf->getOutput();
+$params = array('registry' => &$registry,
+                'notification' => &$notification,
+                'story_id' => Horde_Util::getFormData('id'),
+                'browser' => &$browser,
+                'channel_id' => Horde_Util::getFormData('channel_id'));
+$view = new Jonah_View_StoryPdf($params);
+$view->run();
index 72c3a3e..cba957f 100644 (file)
@@ -1,13 +1,18 @@
 <?php
 /**
- * Display list of articles that match a tag query from an internal
- * channel.
+ * Display list of articles that match a tag query.
+ *
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file LICENSE for license information (BSD). If you
+ * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
  */
-
 require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah');
-
-$news = Jonah_News::factory();
+Horde_Registry::appInit('jonah');
+$driver = $GLOBALS['injector']->getInstance('Jonah_Driver');
 
 /* Redirect to the news index if no tag_id is specified. */
 $tag_id = Horde_Util::getFormData('tag_id');
@@ -16,15 +21,15 @@ $tag_id = Horde_Util::getFormData('tag_id');
  * a search for tags for ALL visible internal channels. */
 $channel_id = Horde_Util::getFormData('channel_id', null);
 if (!is_null($channel_id)) {
-    $channel = $news->getChannel($channel_id);
+    $channel = $driver->getChannel($channel_id);
     if (!Jonah::checkPermissions(Jonah::typeToPermName($channel['channel_type']), Horde_Perms::SHOW, $channel_id)) {
         $notification->push(_("You are not authorised for this action."), 'horde.warning');
-        Horde::authenticationFailureRedirect();
+        $registry->authenticationFailure();
     }
     $channel_ids = array($channel_id);
 } else {
     $channel_ids = array();
-    $channels = $news->getChannels(Jonah::INTERNAL_CHANNEL);
+    $channels = $driver->getChannels();
     foreach ($channels as $ch) {
         if (Jonah::checkPermissions(Jonah::typeToPermName($ch['channel_type']), Horde_Perms::SHOW, $ch['channel_id'])) {
             $channel_ids[] = $ch['channel_id'];
@@ -37,12 +42,15 @@ if (empty($tag_id)) {
     $notification->push(_("No tag requested."), 'horde.error');
     Horde::url('channels/index.php', true)->redirect();
 }
-$tag_name = array_shift($news->getTagNames(array($tag_id)));
 
-$stories = $news->searchTagsById(array($tag_id), 10, 0, $channel_ids);
-if (is_a($stories, 'PEAR_Error')) {
-    $notification->push(sprintf(_("Invalid channel requested. %s"), $stories->getMessage()), 'horde.error');
+$tag_name = array_shift($driver->getTagNames(array($tag_id)));
+
+try {
+    $stories = $driver->searchTagsById(array($tag_id), 10, 0, $channel_ids);
+} catch (Exception $e) {
+    $notification->push(sprintf(_("Invalid channel requested. %s"), $e->getMessage()), 'horde.error');
     Horde::url('channels/index.php', true)->redirect();
+    exit;
 }
 
 /* Do some state tests. */
@@ -55,45 +63,41 @@ foreach ($stories as $key => $story) {
     with more than one channel. */
     $channel_id = $story['channel_id'];
 
-    if (!empty($stories[$key]['story_published'])) {
-        $stories[$key]['story_published_date'] = strftime($prefs->getValue('date_format') . ', ' . ($prefs->getValue('twentyFour') ? '%H:%M' : '%I:%M%p'), $stories[$key]['story_published']);
+    if (!empty($stories[$key]['published'])) {
+        $stories[$key]['published_date'] = strftime($prefs->getValue('date_format') . ', ' . ($prefs->getValue('twentyFour') ? '%H:%M' : '%I:%M%p'), $stories[$key]['published']);
     } else {
-        $stories[$key]['story_published_date'] = '';
+        $stories[$key]['published_date'] = '';
     }
 
     /* Default to no links. */
     $stories[$key]['pdf_link'] = '';
     $stories[$key]['edit_link'] = '';
     $stories[$key]['delete_link'] = '';
-
-    $stories[$key]['view_link'] = Horde::link(Horde::url($story['story_link']), $story['story_desc']) . htmlspecialchars($story['story_title']) . '</a>';
+    $stories[$key]['view_link'] = Horde::url($story['link'])->link(array('title' => $story['desc'])) . htmlspecialchars($story['title']) . '</a>';
 
     /* PDF link. */
-    $url = Horde::url('stories/pdf.php');
-    $url = Horde_Util::addParameter($url, array('story_id' => $story['story_id'], 'channel_id' => $channel_id));
-    $stories[$key]['pdf_link'] = Horde::link($url, _("PDF version")) . Horde::img('mime/pdf.png') . '</a>';
+    $url = Horde::url('stories/pdf.php')->add(array('id' => $story['id'], 'channel_id' => $channel_id));
+    $stories[$key]['pdf_link'] = $url->link(array('title' => _("PDF version"))) . Horde::img('mime/pdf.png') . '</a>';
 
     /* Edit story link. */
     if (Jonah::checkPermissions(Jonah::typeToPermName(Jonah::INTERNAL_CHANNEL), Horde_Perms::EDIT, $channel_id)) {
-        $url = Horde::url('stories/edit.php');
-        $url = Horde_Util::addParameter($url, array('story_id' => $story['story_id'], 'channel_id' => $channel_id));
-        $stories[$key]['edit_link'] = Horde::link($url, _("Edit story")) . Horde::img('edit.png') . '</a>';
+        $url = Horde::url('stories/edit.php')->add(array('id' => $story['id'], 'channel_id' => $channel_id));
+        $stories[$key]['edit_link'] = $url->link(array('title' => _("Edit story"))) . Horde::img('edit.png') . '</a>';
     }
 
     /* Delete story link. */
     if (Jonah::checkPermissions(Jonah::typeToPermName(Jonah::INTERNAL_CHANNEL), Horde_Perms::DELETE, $channel_id)) {
-        $url = Horde::url('stories/delete.php');
-        $url = Horde_Util::addParameter($url, array('story_id' => $story['story_id'], 'channel_id' => $channel_id));
-        $stories[$key]['delete_link'] = Horde::link($url, _("Delete story")) . Horde::img('delete.png') . '</a>';
+        $url = Horde::url('stories/delete.php')->add(array('id' => $story['id'], 'channel_id' => $channel_id));
+        $stories[$key]['delete_link'] = $url->link(array('title' => _("Delete story"))) . Horde::img('delete.png') . '</a>';
     }
 
     /* Comment counter. */
     if ($conf['comments']['allow'] &&
         $registry->hasMethod('forums/numMessages')) {
-        $comments = $registry->call('forums/numMessages', array($stories[$key]['story_id'], 'jonah'));
-        if (!is_a($comments, 'PEAR_Error')) {
-            $stories[$key]['comments'] = $comments;
-        }
+        try {
+            $comments = $registry->call('forums/numMessages', array($stories[$key]['id'], 'jonah'));
+        } catch (Exception $e) {}
+        $stories[$key]['comments'] = $comments;
     }
 }
 
index 13274e9..b84c585 100644 (file)
@@ -1,13 +1,23 @@
 <?php
 /**
- * $Horde: jonah/stories/share.php,v 1.33 2009/09/06 17:00:39 jan Exp $
- *
- * Copyright 1999-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 1999-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
+ *
+ * @package Jonah
  */
 
+/**
+ *
+ * @global <type> $conf
+ * @param <type> $story_part
+ * @param <type> $from
+ * @param <type> $recipients
+ * @param <type> $subject
+ * @param <type> $note
+ * @return <type>
+ */
 function _mail($story_part, $from, $recipients, $subject, $note)
 {
     global $conf;
@@ -40,33 +50,29 @@ function _mail($story_part, $from, $recipients, $subject, $note)
 }
 
 require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah', array(
+Horde_Registry::appInit('jonah', array(
     'authentication' => 'none',
     'session_control' => 'readonly'
 ));
 
-require_once 'Horde/Form.php';
-require_once 'Horde/Form/Renderer.php';
-
-$news = Jonah_News::factory();
-
 /* Set up the form variables. */
 $vars = Horde_Variables::getDefaultVariables();
 $channel_id = $vars->get('channel_id');
-$story_id = $vars->get('story_id');
+$story_id = $vars->get('id');
 
 if (!$conf['sharing']['allow']) {
     Horde::url('stories/view.php', true)
         ->add(array('story_id' => $story_id, 'channel_id' => $channel_id))
         ->redirect();
+    exit;
 }
 
-$story = $news->getStory($channel_id, $story_id);
+$story = $GLOBALS['injector']->getInstance('Jonah_Driver')->getStory($channel_id, $story_id);
 if (is_a($story, 'PEAR_Error')) {
     $notification->push(sprintf(_("Error fetching story: %s"), $story->getMessage()), 'horde.warning');
     $story = '';
 }
-$vars->set('subject', $story['story_title']);
+$vars->set('subject', $story['title']);
 
 /* Set up the form. */
 $form = new Horde_Form($vars);
@@ -74,7 +80,7 @@ $title = _("Share Story");
 $form->setTitle($title);
 $form->setButtons(_("Send"));
 $form->addHidden('', 'channel_id', 'int', false);
-$form->addHidden('', 'story_id', 'int', false);
+$form->addHidden('', 'id', 'int', false);
 $v = &$form->addVariable(_("From"), 'from', 'email', true, false);
 if ($GLOBALS['registry']->getAuth()) {
     $v->setDefault($injector->getInstance('Horde_Prefs_Identity')->getIdentity()->getValue('from_addr'));
@@ -87,16 +93,21 @@ $form->addVariable(_("Message"), 'message', 'longtext', false, false, null, arra
 if ($form->validate($vars)) {
     $form->getInfo($vars, $info);
 
-    $channel = $news->getChannel($channel_id);
+    $channel = $GLOBALS['injector']->getInstance('Jonah_Driver')->getChannel($channel_id);
     if (empty($channel['channel_story_url'])) {
+<<<<<<< HEAD
+        $story_url = Horde::url('stories/view.php', true);
+        $story_url = Horde_Util::addParameter($story_url, array('channel_id' => '%c', 'id' => '%s'));
+=======
         $story_url = Horde::url('stories/view.php', true);
         $story_url = Horde_Util::addParameter($story_url, array('channel_id' => '%c', 'story_id' => '%s'));
+>>>>>>> master
     } else {
         $story_url = $channel['channel_story_url'];
     }
 
     $story_url = str_replace(array('%25c', '%25s'), array('%c', '%s'), $story_url);
-    $story_url = str_replace(array('%c', '%s', '&amp;'), array($channel_id, $story['story_id'], '&'), $story_url);
+    $story_url = str_replace(array('%c', '%s', '&amp;'), array($channel_id, $story['id'], '&'), $story_url);
 
     if ($info['include'] == 0) {
         require_once 'Horde/MIME/Part.php';
@@ -106,7 +117,7 @@ if ($form->validate($vars)) {
         $message_part->setContents($message_part->replaceEOL($story_url));
         $message_part->setDescription(_("Story Link"));
     } else {
-        $message_part = Jonah_News::getStoryAsMessage($story);
+        $message_part = Jonah::getStoryAsMessage($story);
     }
 
     $result = _mail($message_part, $info['from'], $info['recipients'],
index c1cc8f9..75b1291 100644 (file)
 <?php
 /**
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 2003-2010 The Horde Project (http://www.horde.org/)
  *
  * See the enclosed file LICENSE for license information (BSD). If you
  * did not receive this file, see http://cvs.horde.org/co.php/jonah/LICENSE.
  *
  * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Jonah
  */
-
 require_once dirname(__FILE__) . '/../lib/Application.php';
-$jonah = Horde_Registry::appInit('jonah', array(
-    'authentication' => 'none'
-));
-
-$news = Jonah_News::factory();
+Horde_Registry::appInit('jonah', array('authentication' => 'none'));
 
 $channel_id = Horde_Util::getFormData('channel_id');
-$story_id = Horde_Util::getFormData('story_id');
+$story_id = Horde_Util::getFormData('id');
 if (!$story_id) {
-    $story_id = $news->getLatestStoryId($channel_id);
-    if (is_a($story_id, 'PEAR_Error')) {
-        $notification->push(sprintf(_("Error fetching story: %s"), $story_id->getMessage()), 'horde.warning');
+    try {
+        $story_id = $injector->getInstance('Jonah_Driver')->getLatestStoryId($channel_id);
+    } catch (Exception $e) {
+        $notification->push(sprintf(_("Error fetching story: %s"), $e->getMessage()), 'horde.warning');
         require JONAH_TEMPLATES . '/common-header.inc';
-        $notification->notify(array('listeners' => 'status'));
+        require JONAH_TEMPLATES . '/menu.inc';
         require $registry->get('templates', 'horde') . '/common-footer.inc';
         exit;
     }
 }
 
-$story = $news->getStory($channel_id, $story_id, !$browser->isRobot());
-if (is_a($story, 'PEAR_Error')) {
-    $notification->push(sprintf(_("Error fetching story: %s"), $story->getMessage()), 'horde.warning');
-    require JONAH_TEMPLATES . '/common-header.inc';
-    $notification->notify(array('listeners' => 'status'));
-    require $registry->get('templates', 'horde') . '/common-footer.inc';
-    exit;
-} elseif (empty($story['story_body']) && !empty($story['story_url'])) {
-    Horde::externalUrl($story['story_url'])->redirect();
-}
-
-/* Grab tag related content for entire channel */
-$cloud = new Horde_Core_Ui_TagCloud();
-$allTags = $news->listTagInfo(array(), $channel_id);
-foreach ($allTags as $tag_id => $taginfo) {
-    $cloud->addElement($taginfo['tag_name'], Horde_Util::addParameter('results.php', array('tag_id' => $tag_id, 'channel_id' => $channel_id)), $taginfo['total']);
-}
-
-/* Prepare the story's tags for display */
-$tag_html = array();
-$tag_link = Horde_Util::addParameter(Horde::url('stories/results.php'), 'channel_id', $channel_id);
-foreach ($story['story_tags'] as $id => $tag) {
-    $link = Horde_Util::addParameter($tag_link, 'tag_id', $id);
-    $tag_html[] = Horde::link($link) . $tag . '</a>';
-}
-
-/* Filter and prepare story content. */
-$story['story_title'] = htmlspecialchars($story['story_title']);
-$story['story_desc'] = htmlspecialchars($story['story_desc']);
-if (!empty($story['story_body_type']) && $story['story_body_type'] == 'text') {
-    $story['story_body'] = $GLOBALS['injector']->getInstance('Horde_Text_Filter')->filter($story['story_body'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
-}
-if (!empty($story['story_url'])) {
-    $story['story_body'] .= "\n<p>" . Horde::link(Horde::externalUrl($story['story_url'])) . htmlspecialchars($story['story_url']) . '</a></p>';
-}
-if (empty($story['story_published_date'])) {
-    $story['story_published_date'] = false;
-}
-
-$story_template = new Horde_Template();
-$story_template->set('story', $story, true);
-$story_template->set('storytags', implode(', ', $tag_html));
-
-$view_template = new Horde_Template();
-$view_template->setOption('gettext', true);
-$view_template->set('story', $story_template->fetch(JONAH_TEMPLATES . '/stories/story.html'));
-$view_template->set('cloud', '<div class="tagSelector" ' . $cloud->buildHTML() . '</div>', true);
-/* Insert link for sharing. */
-if ($conf['sharing']['allow']) {
-    $url = Horde::url('stories/share.php');
-    $url = Horde_Util::addParameter($url, array('story_id' => $story['story_id'], 'channel_id' => $channel_id));
-    $view_template->set('sharelink', Horde::link($url) . _("Share this story") . '</a>', true);
-} else {
-    $view_template->set('sharelink', false, true);
-}
-
-/* Insert comments. */
-if ($conf['comments']['allow']) {
-    if (!$registry->hasMethod('forums/doComments')) {
-        $err = 'User comments are enabled but the forums API is not available.';
-        Horde::logMessage($err, 'ERR');
-    } else {
-        $comments = $registry->call('forums/doComments', array('jonah', $story_id, 'commentCallback'));
-        if (is_a($comments, 'PEAR_Error')) {
-            Horde::logMessage($threads, 'ERR');
-            $comments = '';
-        }
-        $comments = $comments['threads'] . '<br />' . $comments['comments'];
-        $view_template->set('comments', $comments, true);
-    }
-} else {
-    $view_template->set('comments', false, true);
-}
-
-$view_template->set('menu', Horde::menu());
-
-// Buffer the notifications and send to the template
-Horde::startBuffer();
-$GLOBALS['notification']->notify(array('listeners' => 'status'));
-$template->set('notify', Horde::endBuffer());
-
-require JONAH_TEMPLATES . '/common-header.inc';
-echo $view_template->fetch(JONAH_TEMPLATES . '/stories/view.html');
-require $registry->get('templates', 'horde') . '/common-footer.inc';
+$params = array('registry' => &$registry,
+                'notification' => &$notification,
+                'channel_id' => $channel_id,
+                'browser' => &$browser,
+                'conf' => &$conf,
+                'story_id' => $story_id);
+$view = new Jonah_View_StoryView($params);
+$view->run();
\ No newline at end of file
diff --git a/jonah/templates/channels/index.html b/jonah/templates/channels/index.html
deleted file mode 100644 (file)
index faa15a7..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<tag:menu />
-<tag:notify />
-
-<div class="header">
- <tag:header />
- <a id="quicksearchL" href="#" title="<gettext>Search</gettext>" onclick="$('quicksearchL').hide(); $('quicksearch').show(); $('quicksearchT').focus(); return false;"><tag:search_img /></a>
- <div id="quicksearch" style="display:none">
-  <input type="text" name="quicksearchT" id="quicksearchT" for="feeds-body" empty="feeds-empty" />
-  <small>
-   <a title="<gettext>Close Search</gettext>" href="#" onclick="$('quicksearch').hide(); $('quicksearchT').value = ''; QuickFinder.filter($('quicksearchT')); $('quicksearchL').show(); return false;">X</a>
-  </small>
- </div>
-</div>
-
-<if:channels>
-<table id="feeds" width="100%" class="sortable" cellspacing="0">
-<thead>
- <tr>
-  <th width="1%">&nbsp;</th>
-  <loop:listheaders>
-  <th<tag:listheaders.attrs />>
-   <tag:listheaders.label />
-  </th>
-  </loop:listheaders>
- </tr>
-</thead>
-
-<tbody id="feeds-body">
- <loop:channels>
- <tr>
-  <td class="nowrap">
-   <tag:channels.edit_link />
-   <tag:channels.refresh_link />
-   <tag:channels.addstory_link />
-   <tag:channels.lists_link />
-   <tag:channels.delete_link />
-  </td>
-  <td>
-   <a href="<tag:channels.stories_url />"><tag:channels.channel_name /></a>
-  </td>
-  <td><tag:channels.channel_type /></td>
-  <td class="linedRow"><tag:channels.channel_updated /></td>
- </tr>
- </loop:channels>
-</tbody>
-</table>
-<div id="feeds-empty">
- <gettext>No feeds match</gettext>
-</div>
-<else:channels>
-<div class="text">
- <em><gettext>No channels are available.</gettext></em>
-</div>
-</else:channels>
-</if:channels>
index 43e0a09..36618df 100644 (file)
@@ -9,7 +9,7 @@ if (isset($language)) {
 <head>
 <?php
 
-$page_title = $registry->get('name');
+$page_title = $GLOBALS['registry']->get('name');
 if (!empty($title)) {
     $page_title .= ' :: ' . $title;
 }
index c473511..4c1040f 100644 (file)
@@ -10,9 +10,9 @@
   <pubDate><tag:channel_updated /></pubDate>
   <loop:stories>
   <item>
-   <title><tag:stories.story_title /></title>
-   <description><tag:stories.story_desc /></description>
-   <link><tag:stories.story_link /></link>
+   <title><tag:stories.title /></title>
+   <description><tag:stories.description /></description>
+   <link><tag:stories.permalink /></link>
   </item>
   </loop:stories>
  </channel>
index 0674c37..0c0cbd1 100644 (file)
   <generator><tag:jonah /></generator>
   <loop:stories>
   <item>
-     <title><tag:stories.story_title /></title>
-     <link><tag:stories.story_link /></link>
-     <description><tag:stories.story_desc /></description>
-     <pubDate><tag:stories.story_published /></pubDate>
-     <guid isPermaLink="true"><tag:stories.story_permalink /></guid>
+     <title><tag:stories.title /></title>
+     <link><tag:stories.permalink /></link>
+     <description><tag:stories.description /></description>
+     <pubDate><tag:stories.published /></pubDate>
+     <guid isPermaLink="true"><tag:stories.permalink /></guid>
   </item>
   </loop:stories>
  </channel>
index dd09f23..879f40e 100644 (file)
   <generator><tag:jonah /></generator>
   <loop:stories>
   <item>
-     <title><tag:stories.story_title /></title>
-     <link><tag:stories.story_link /></link>
-     <description><tag:stories.story_desc /></description>
-     <content:encoded><![CDATA[<tag:stories.story_body />
+     <title><tag:stories.title /></title>
+     <link><tag:stories.permalink /></link>
+     <description><tag:stories.description /></description>
+     <content:encoded><![CDATA[<tag:stories.body />
 ]]></content:encoded>
      <pubDate><tag:stories.story_published /></pubDate>
-     <guid isPermaLink="true"><tag:stories.story_permalink /></guid>
+     <guid isPermaLink="true"><tag:stories.permalink /></guid>
   </item>
   </loop:stories>
  </channel>
index cf2610f..cea633b 100644 (file)
   <pubDate><tag:channel_updated /></pubDate>
   <loop:stories>
   <item>
-   <title><tag:stories.story_title /></title>
-   <description><tag:stories.story_desc /></description>
-   <content:encoded><![CDATA[<tag:stories.story_body />
+   <title><tag:stories.title /></title>
+   <description><tag:stories.description /></description>
+   <content:encoded><![CDATA[<tag:stories.body />
 ]]></content:encoded>
-   <link><tag:stories.story_link /></link>
+   <link><tag:stories.permalink /></link>
   </item>
   </loop:stories>
  </channel>
diff --git a/jonah/templates/menu.inc b/jonah/templates/menu.inc
new file mode 100644 (file)
index 0000000..0a0e28a
--- /dev/null
@@ -0,0 +1,2 @@
+<?php echo Horde::menu();
+$GLOBALS['notification']->notify(array('listeners' => 'status'));
\ No newline at end of file
diff --git a/jonah/templates/stories/index.html b/jonah/templates/stories/index.html
deleted file mode 100644 (file)
index 7e8fc47..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<tag:menu />
-<tag:notify />
-
-<div class="header">
- <tag:header /> <tag:refresh />
-</div>
-
-<if:stories>
-<table width="100%" cellspacing="0" class="linedRow nowrap">
- <tr class="item">
-  <th width="1%">&nbsp;</th>
-  <loop:listheaders>
-  <th class="leftAlign">
-   <tag:listheaders />
-  </th>
-  </loop:listheaders>
-  <if:read>
-  <th class="leftAlign">
-   <gettext>Read</gettext>
-  </th>
-  </if:read>
-  <if:comments>
-  <th class="leftAlign">
-   <gettext>Comments</gettext>
-  </th>
-  </if:comments>
- </tr>
-
- <loop:stories>
- <tr>
-  <td>
-   <tag:stories.pdf_link />
-   <tag:stories.edit_link />
-   <tag:stories.delete_link />
-  </td>
-  <td>
-   <tag:stories.view_link />
-  </td>
-  <td>
-   <tag:stories.story_published_date />
-  </td>
-  <if:read>
-  <td>
-   <tag:stories.story_read />
-  </td>
-  </if:read>
-  <if:comments>
-  <td>
-   <tag:stories.comments />
-  </td>
-  </if:comments>
- </tr>
- </loop:stories>
-</table>
-</if:stories>
diff --git a/jonah/templates/stories/index.html.php b/jonah/templates/stories/index.html.php
new file mode 100644 (file)
index 0000000..e43c4bd
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Template for stories index page - lists available stories
+ *
+ *   ->stories
+ *   ->read
+ *   ->comments
+ *   ->stories
+ */
+?>
+<?php if (!empty($this->stories)): ?>
+<table width="100%" cellspacing="0" class="linedRow nowrap">
+ <tr class="item">
+  <th width="1%">&nbsp;</th>
+  <th class="leftAlign"><?php echo _("Story") ?></th>
+  <th class="leftAlign"><?php echo _("Date") ?></th>
+  <?php if ($this->read): ?>
+    <th class="leftAlign"><?php echo _("Read") ?></th>
+  <?php endif; ?>
+  <?php if ($this->comments): ?>
+    <th class="leftAlign"><?php echo _("Comments") ?></th>
+  <?php endif; ?>
+ </tr>
+ <?php foreach ($this->stories as $story): ?>
+   <tr>
+    <td>
+     <?php echo $story['pdf_link'] ?>
+     <?php echo $story['edit_link'] ?>
+     <?php echo $story['delete_link'] ?>
+    </td>
+    <td>
+     <?php echo $story['view_link'] ?>
+    </td>
+    <td>
+     <?php echo $story['published_date'] ?>
+    </td>
+    <?php if ($this->read): ?>
+    <td>
+     <?php echo $story['readcount'] ?>
+    </td>
+    <?php endif; ?>
+    <?php if ($this->comments): ?>
+    <td>
+     <?php echo $story['comments'] ?>
+    </td>
+    <?php endif; ?>
+   </tr>
+  <?php endforeach; ?>
+</table>
+<?php endif; ?>
diff --git a/jonah/templates/stories/layout/view.html.php b/jonah/templates/stories/layout/view.html.php
new file mode 100644 (file)
index 0000000..33454f2
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Main layout for viewing story entries
+ * Expects:
+ *   ->tagcloud
+ *   ->story
+ *   ->sharelink
+ *   ->comments
+ */
+?>
+<?php if (!empty($this->tagcloud)): ?>
+<?php echo $this->contentTag('div', $this->contentDiv('div', $this->tagcloud, array('class' => 'tagSelector')), array('style' => 'float:right;'));?>
+<div style="margin-right:170px;">
+<?php else:?>
+<div>
+<?php endif;?>
+  <?php echo $this->renderPartial('story', array('local' => array('story' => $this->story))); ?>
+  <?php echo $this->contentTag('div', (!empty($this->sharelink) ? $this->sharelink : ''), array('class' => 'storyLinks'));?>
+</div>
+<?php
+    if (!empty($this->comments)) {
+        echo $this->contentTag('div', $this->comments['threads'] . $this->tag('br') . $this->comments['comments'], array('class' => 'storyComments'));
+    }
\ No newline at end of file
diff --git a/jonah/templates/stories/partial/_story.html.php b/jonah/templates/stories/partial/_story.html.php
new file mode 100644 (file)
index 0000000..ae64174
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Default template for rendering individual stories.
+ * Expects:
+ *    ->published_date
+ *    ->title
+ *    ->tags
+ *    ->description
+ *    ->body
+ */
+
+echo $this->contentTag('h1',
+                  $this->contentTag('span',
+                                    $this->story['published_date'],
+                                    array('class' => 'storyDate')) . $this->escape($this->story['title']),
+                  array('class' => 'header'));
+
+echo $this->contentTag('div', _("Tags:") .  implode(', ', $this->story['tags']), array('class' => 'storyTags'));
+echo $this->contentTag('div', $this->escape($this->story['description']), array('class' => 'storySubtitle'));
+// body is already escaped in the View class.
+echo $this->contentTag('div', $this->story['body'], array('class' => 'storyBody'));
+?>
diff --git a/jonah/templates/stories/story.html b/jonah/templates/stories/story.html
deleted file mode 100644 (file)
index 1841947..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<h1 class="header">
- <span class="storyDate"><tag:story.story_published_date /></span> <tag:story.story_title />
-</h1>
-
-<p class="storyTags">
- <gettext>Tags: </gettext><tag:storytags />
-</p>
-
-<p class="storySubtitle">
- <tag:story.story_desc />
-</p>
-
-<div class="storyBody">
- <tag:story.story_body />
-</div>
diff --git a/jonah/templates/stories/view.html b/jonah/templates/stories/view.html
deleted file mode 100644 (file)
index 97801f6..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<tag:menu />
-<tag:notify />
-
-<if:cloud>
- <div style="float:right;"><tag:cloud /></div>
- <div style="margin-right:170px;">
-<else:cloud>
- <div>
-</else:cloud>
-</if:cloud>
-<tag:story />
-<div class="storyLinks">
-<if:sharelink>
- <tag:sharelink />
-</if:sharelink>
-</div>
-
-</div>
-<if:comments>
-<div class="storyComments">
-<tag:comments />
-</div>
-</if:comments>
diff --git a/jonah/templates/view/channellist.html.php b/jonah/templates/view/channellist.html.php
new file mode 100644 (file)
index 0000000..91aa5a4
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/**
+ * index view for rendering channel list. Expects:
+ *  ->search_img
+ *  ->channels
+ *
+ *
+ */
+?>
+<div class="header">
+ <?php echo _("Manage Feeds") ?>
+ <a id="quicksearchL" href="#" title="<?php echo _("Search")?>" onclick="$('quicksearchL').hide(); $('quicksearch').show(); $('quicksearchT').focus(); return false;"><?php echo $this->search_img?></a>
+ <div id="quicksearch" style="display:none;">
+  <input type="text" name="quicksearchT" id="quicksearchT" for="feeds-body" empty="feeds-empty" />
+  <small>
+   <a title="<?php echo _("Close Search")?>" href="#" onclick="$('quicksearch').hide(); $('quicksearchT').value = ''; QuickFinder.filter($('quicksearchT')); $('quicksearchL').show(); return false;">X</a>
+  </small>
+ </div>
+</div>
+
+<?php if (count($this->channels)):?>
+    <table id="feeds" width="100%" class="sortable" cellspacing="0">
+    <thead>
+     <tr>
+      <th width="1%">&nbsp;</th>
+      <th class="sortdown"><?php echo _("Name")?></th>
+      <th><?php echo _("Type")?></th>
+      <th><?php echo _("Last Update")?></th>
+     </tr>
+    </thead>
+
+    <tbody id="feeds-body">
+     <?php foreach ($this->channels as $channel):?>
+     <tr>
+      <td class="nowrap">
+       <?php echo $channel['edit_link'] . $channel['refresh_link'] . $channel['addstory_link'] . $channel['delete_link'];?>
+      </td>
+      <td>
+       <a href="<?php echo $channel['stories_url']?>"><?php echo $channel['channel_name']?></a>
+      </td>
+      <td><?php echo $channel['channel_type']?></td>
+      <td class="linedRow"><?php echo $channel['channel_updated']?></td>
+     </tr>
+     <?php endforeach?>
+    </tbody>
+    </table>
+    <div id="feeds-empty">
+     <?php echo _("No feeds match")?>
+    </div>
+<?php else:?>
+    <div class="text">
+     <em><?php echo _("No channels are available.")?></em>
+    </div>
+<?php endif;?>
\ No newline at end of file