annotate modules/aggregator/aggregator.module @ 19:3edae6ecd6c6 6.9

Drupal 6.9
author Franck Deroche <franck@defr.org>
date Thu, 15 Jan 2009 10:15:56 +0100
parents acef7ccb09b5
children
rev   line source
webmaster@1 1 <?php
franck@19 2 // $Id: aggregator.module,v 1.374.2.4 2009/01/14 21:36:16 goba Exp $
webmaster@1 3
webmaster@1 4 /**
webmaster@1 5 * @file
webmaster@1 6 * Used to aggregate syndicated content (RSS, RDF, and Atom).
webmaster@1 7 */
webmaster@1 8
webmaster@1 9 /**
webmaster@1 10 * Implementation of hook_help().
webmaster@1 11 */
webmaster@1 12 function aggregator_help($path, $arg) {
webmaster@1 13 switch ($path) {
webmaster@1 14 case 'admin/help#aggregator':
webmaster@1 15 $output = '<p>'. t('The aggregator is a powerful on-site syndicator and news reader that gathers fresh content from RSS-, RDF-, and Atom-based feeds made available across the web. Thousands of sites (particularly news sites and blogs) publish their latest headlines and posts in feeds, using a number of standardized XML-based formats. Formats supported by the aggregator include <a href="@rss">RSS</a>, <a href="@rdf">RDF</a>, and <a href="@atom">Atom</a>.', array('@rss' => 'http://cyber.law.harvard.edu/rss/', '@rdf' => 'http://www.w3.org/RDF/', '@atom' => 'http://www.atomenabled.org')) .'</p>';
webmaster@1 16 $output .= '<p>'. t('Feeds contain feed items, or individual posts published by the site providing the feed. Feeds may be grouped in categories, generally by topic. Users view feed items in the <a href="@aggregator">main aggregator display</a> or by <a href="@aggregator-sources">their source</a>. Administrators can <a href="@feededit">add, edit and delete feeds</a> and choose how often to check each feed for newly updated items. The most recent items in either a feed or category can be displayed as a block through the <a href="@admin-block">blocks administration page</a>. A <a href="@aggregator-opml">machine-readable OPML file</a> of all feeds is available. A correctly configured <a href="@cron">cron maintenance task</a> is required to update feeds automatically.', array('@aggregator' => url('aggregator'), '@aggregator-sources' => url('aggregator/sources'), '@feededit' => url('admin/content/aggregator'), '@admin-block' => url('admin/build/block'), '@aggregator-opml' => url('aggregator/opml'), '@cron' => url('admin/reports/status'))) .'</p>';
webmaster@1 17 $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@aggregator">Aggregator module</a>.', array('@aggregator' => 'http://drupal.org/handbook/modules/aggregator/')) .'</p>';
webmaster@1 18 return $output;
webmaster@1 19 case 'admin/content/aggregator':
webmaster@7 20 $output = '<p>'. t('Thousands of sites (particularly news sites and blogs) publish their latest headlines and posts in feeds, using a number of standardized XML-based formats. Formats supported by the aggregator include <a href="@rss">RSS</a>, <a href="@rdf">RDF</a>, and <a href="@atom">Atom</a>.', array('@rss' => 'http://cyber.law.harvard.edu/rss/', '@rdf' => 'http://www.w3.org/RDF/', '@atom' => 'http://www.atomenabled.org')) .'</p>';
webmaster@1 21 $output .= '<p>'. t('Current feeds are listed below, and <a href="@addfeed">new feeds may be added</a>. For each feed or feed category, the <em>latest items</em> block may be enabled at the <a href="@block">blocks administration page</a>.', array('@addfeed' => url('admin/content/aggregator/add/feed'), '@block' => url('admin/build/block'))) .'</p>';
webmaster@1 22 return $output;
webmaster@1 23 case 'admin/content/aggregator/add/feed':
webmaster@1 24 return '<p>'. t('Add a feed in RSS, RDF or Atom format. A feed may only have one entry.') .'</p>';
webmaster@1 25 case 'admin/content/aggregator/add/category':
webmaster@1 26 return '<p>'. t('Categories allow feed items from different feeds to be grouped together. For example, several sport-related feeds may belong to a category named <em>Sports</em>. Feed items may be grouped automatically (by selecting a category when creating or editing a feed) or manually (via the <em>Categorize</em> page available from feed item listings). Each category provides its own feed page and block.') .'</p>';
webmaster@1 27 }
webmaster@1 28 }
webmaster@1 29
webmaster@1 30 /**
webmaster@1 31 * Implementation of hook_theme()
webmaster@1 32 */
webmaster@1 33 function aggregator_theme() {
webmaster@1 34 return array(
webmaster@1 35 'aggregator_wrapper' => array(
webmaster@1 36 'arguments' => array('content' => NULL),
webmaster@1 37 'file' => 'aggregator.pages.inc',
webmaster@1 38 'template' => 'aggregator-wrapper',
webmaster@1 39 ),
webmaster@1 40 'aggregator_categorize_items' => array(
webmaster@1 41 'arguments' => array('form' => NULL),
webmaster@1 42 'file' => 'aggregator.pages.inc',
webmaster@1 43 ),
webmaster@1 44 'aggregator_feed_source' => array(
webmaster@1 45 'arguments' => array('feed' => NULL),
webmaster@1 46 'file' => 'aggregator.pages.inc',
webmaster@1 47 'template' => 'aggregator-feed-source',
webmaster@1 48 ),
webmaster@1 49 'aggregator_block_item' => array(
webmaster@1 50 'arguments' => array('item' => NULL, 'feed' => 0),
webmaster@1 51 ),
webmaster@1 52 'aggregator_summary_items' => array(
webmaster@1 53 'arguments' => array('summary_items' => NULL, 'source' => NULL),
webmaster@1 54 'file' => 'aggregator.pages.inc',
webmaster@1 55 'template' => 'aggregator-summary-items',
webmaster@1 56 ),
webmaster@1 57 'aggregator_summary_item' => array(
webmaster@1 58 'arguments' => array('item' => NULL),
webmaster@1 59 'file' => 'aggregator.pages.inc',
webmaster@1 60 'template' => 'aggregator-summary-item',
webmaster@1 61 ),
webmaster@1 62 'aggregator_item' => array(
webmaster@1 63 'arguments' => array('item' => NULL),
webmaster@1 64 'file' => 'aggregator.pages.inc',
webmaster@1 65 'template' => 'aggregator-item',
webmaster@1 66 ),
webmaster@1 67 'aggregator_page_opml' => array(
webmaster@1 68 'arguments' => array('feeds' => NULL),
webmaster@1 69 'file' => 'aggregator.pages.inc',
webmaster@1 70 ),
webmaster@1 71 'aggregator_page_rss' => array(
webmaster@1 72 'arguments' => array('feeds' => NULL, 'category' => NULL),
webmaster@1 73 'file' => 'aggregator.pages.inc',
webmaster@1 74 ),
webmaster@1 75 );
webmaster@1 76 }
webmaster@1 77
webmaster@1 78 /**
webmaster@1 79 * Implementation of hook_menu().
webmaster@1 80 */
webmaster@1 81 function aggregator_menu() {
webmaster@1 82 $items['admin/content/aggregator'] = array(
webmaster@1 83 'title' => 'Feed aggregator',
webmaster@1 84 'description' => "Configure which content your site aggregates from other sites, how often it polls them, and how they're categorized.",
webmaster@1 85 'page callback' => 'aggregator_admin_overview',
webmaster@1 86 'access arguments' => array('administer news feeds'),
webmaster@1 87 'file' => 'aggregator.admin.inc',
webmaster@1 88 );
webmaster@1 89 $items['admin/content/aggregator/add/feed'] = array(
webmaster@1 90 'title' => 'Add feed',
webmaster@1 91 'page callback' => 'drupal_get_form',
webmaster@1 92 'page arguments' => array('aggregator_form_feed'),
webmaster@1 93 'access arguments' => array('administer news feeds'),
webmaster@1 94 'type' => MENU_LOCAL_TASK,
webmaster@1 95 'parent' => 'admin/content/aggregator',
webmaster@1 96 'file' => 'aggregator.admin.inc',
webmaster@1 97 );
webmaster@1 98 $items['admin/content/aggregator/add/category'] = array(
webmaster@1 99 'title' => 'Add category',
webmaster@1 100 'page callback' => 'drupal_get_form',
webmaster@1 101 'page arguments' => array('aggregator_form_category'),
webmaster@1 102 'access arguments' => array('administer news feeds'),
webmaster@1 103 'type' => MENU_LOCAL_TASK,
webmaster@1 104 'parent' => 'admin/content/aggregator',
webmaster@1 105 'file' => 'aggregator.admin.inc',
webmaster@1 106 );
webmaster@1 107 $items['admin/content/aggregator/remove/%aggregator_feed'] = array(
webmaster@1 108 'title' => 'Remove items',
webmaster@1 109 'page callback' => 'drupal_get_form',
webmaster@1 110 'page arguments' => array('aggregator_admin_remove_feed', 4),
webmaster@1 111 'access arguments' => array('administer news feeds'),
webmaster@1 112 'type' => MENU_CALLBACK,
webmaster@1 113 'file' => 'aggregator.admin.inc',
webmaster@1 114 );
webmaster@1 115 $items['admin/content/aggregator/update/%aggregator_feed'] = array(
webmaster@1 116 'title' => 'Update items',
webmaster@1 117 'page callback' => 'aggregator_admin_refresh_feed',
webmaster@1 118 'page arguments' => array(4),
webmaster@1 119 'access arguments' => array('administer news feeds'),
webmaster@1 120 'type' => MENU_CALLBACK,
webmaster@1 121 'file' => 'aggregator.admin.inc',
webmaster@1 122 );
webmaster@1 123 $items['admin/content/aggregator/list'] = array(
webmaster@1 124 'title' => 'List',
webmaster@1 125 'type' => MENU_DEFAULT_LOCAL_TASK,
webmaster@1 126 'weight' => -10,
webmaster@1 127 );
webmaster@1 128 $items['admin/content/aggregator/settings'] = array(
webmaster@1 129 'title' => 'Settings',
webmaster@1 130 'page callback' => 'drupal_get_form',
webmaster@1 131 'page arguments' => array('aggregator_admin_settings'),
webmaster@1 132 'type' => MENU_LOCAL_TASK,
webmaster@1 133 'weight' => 10,
webmaster@1 134 'access arguments' => array('administer news feeds'),
webmaster@1 135 'file' => 'aggregator.admin.inc',
webmaster@1 136 );
webmaster@1 137 $items['aggregator'] = array(
webmaster@1 138 'title' => 'Feed aggregator',
webmaster@1 139 'page callback' => 'aggregator_page_last',
webmaster@1 140 'access arguments' => array('access news feeds'),
webmaster@1 141 'weight' => 5,
webmaster@1 142 'file' => 'aggregator.pages.inc',
webmaster@1 143 );
webmaster@1 144 $items['aggregator/sources'] = array(
webmaster@1 145 'title' => 'Sources',
webmaster@1 146 'page callback' => 'aggregator_page_sources',
webmaster@1 147 'access arguments' => array('access news feeds'),
webmaster@1 148 'file' => 'aggregator.pages.inc',
webmaster@1 149 );
webmaster@1 150 $items['aggregator/categories'] = array(
webmaster@1 151 'title' => 'Categories',
webmaster@1 152 'page callback' => 'aggregator_page_categories',
webmaster@1 153 'access callback' => '_aggregator_has_categories',
webmaster@1 154 'file' => 'aggregator.pages.inc',
webmaster@1 155 );
webmaster@1 156 $items['aggregator/rss'] = array(
webmaster@1 157 'title' => 'RSS feed',
webmaster@1 158 'page callback' => 'aggregator_page_rss',
webmaster@1 159 'access arguments' => array('access news feeds'),
webmaster@1 160 'type' => MENU_CALLBACK,
webmaster@1 161 'file' => 'aggregator.pages.inc',
webmaster@1 162 );
webmaster@1 163 $items['aggregator/opml'] = array(
webmaster@1 164 'title' => 'OPML feed',
webmaster@1 165 'page callback' => 'aggregator_page_opml',
webmaster@1 166 'access arguments' => array('access news feeds'),
webmaster@1 167 'type' => MENU_CALLBACK,
webmaster@1 168 'file' => 'aggregator.pages.inc',
webmaster@1 169 );
webmaster@1 170 $items['aggregator/categories/%aggregator_category'] = array(
webmaster@1 171 'title callback' => '_aggregator_category_title',
webmaster@1 172 'title arguments' => array(2),
webmaster@1 173 'page callback' => 'aggregator_page_category',
webmaster@1 174 'page arguments' => array(2),
webmaster@1 175 'access callback' => 'user_access',
webmaster@1 176 'access arguments' => array('access news feeds'),
webmaster@1 177 'file' => 'aggregator.pages.inc',
webmaster@1 178 );
webmaster@1 179 $items['aggregator/categories/%aggregator_category/view'] = array(
webmaster@1 180 'title' => 'View',
webmaster@1 181 'type' => MENU_DEFAULT_LOCAL_TASK,
webmaster@1 182 'weight' => -10,
webmaster@1 183 );
webmaster@1 184 $items['aggregator/categories/%aggregator_category/categorize'] = array(
webmaster@1 185 'title' => 'Categorize',
webmaster@1 186 'page callback' => 'drupal_get_form',
webmaster@1 187 'page arguments' => array('aggregator_page_category', 2),
webmaster@1 188 'access arguments' => array('administer news feeds'),
webmaster@1 189 'type' => MENU_LOCAL_TASK,
webmaster@1 190 'file' => 'aggregator.pages.inc',
webmaster@1 191 );
webmaster@1 192 $items['aggregator/categories/%aggregator_category/configure'] = array(
webmaster@1 193 'title' => 'Configure',
webmaster@1 194 'page callback' => 'drupal_get_form',
webmaster@1 195 'page arguments' => array('aggregator_form_category', 2),
webmaster@1 196 'access arguments' => array('administer news feeds'),
webmaster@1 197 'type' => MENU_LOCAL_TASK,
webmaster@1 198 'weight' => 1,
webmaster@1 199 'file' => 'aggregator.admin.inc',
webmaster@1 200 );
webmaster@1 201 $items['aggregator/sources/%aggregator_feed'] = array(
webmaster@1 202 'page callback' => 'aggregator_page_source',
webmaster@1 203 'page arguments' => array(2),
webmaster@5 204 'access arguments' => array('access news feeds'),
webmaster@1 205 'type' => MENU_CALLBACK,
webmaster@1 206 'file' => 'aggregator.pages.inc',
webmaster@1 207 );
webmaster@1 208 $items['aggregator/sources/%aggregator_feed/view'] = array(
webmaster@1 209 'title' => 'View',
webmaster@1 210 'type' => MENU_DEFAULT_LOCAL_TASK,
webmaster@1 211 'weight' => -10,
webmaster@1 212 );
webmaster@1 213 $items['aggregator/sources/%aggregator_feed/categorize'] = array(
webmaster@1 214 'title' => 'Categorize',
webmaster@1 215 'page callback' => 'drupal_get_form',
webmaster@1 216 'page arguments' => array('aggregator_page_source', 2),
webmaster@1 217 'access arguments' => array('administer news feeds'),
webmaster@1 218 'type' => MENU_LOCAL_TASK,
webmaster@1 219 'file' => 'aggregator.pages.inc',
webmaster@1 220 );
webmaster@1 221 $items['aggregator/sources/%aggregator_feed/configure'] = array(
webmaster@1 222 'title' => 'Configure',
webmaster@1 223 'page callback' => 'drupal_get_form',
webmaster@1 224 'page arguments' => array('aggregator_form_feed', 2),
webmaster@1 225 'access arguments' => array('administer news feeds'),
webmaster@1 226 'type' => MENU_LOCAL_TASK,
webmaster@1 227 'weight' => 1,
webmaster@1 228 'file' => 'aggregator.admin.inc',
webmaster@1 229 );
webmaster@1 230 $items['admin/content/aggregator/edit/feed/%aggregator_feed'] = array(
webmaster@1 231 'title' => 'Edit feed',
webmaster@1 232 'page callback' => 'drupal_get_form',
webmaster@1 233 'page arguments' => array('aggregator_form_feed', 5),
webmaster@1 234 'access arguments' => array('administer news feeds'),
webmaster@1 235 'type' => MENU_CALLBACK,
webmaster@1 236 'file' => 'aggregator.admin.inc',
webmaster@1 237 );
webmaster@1 238 $items['admin/content/aggregator/edit/category/%aggregator_category'] = array(
webmaster@1 239 'title' => 'Edit category',
webmaster@1 240 'page callback' => 'drupal_get_form',
webmaster@1 241 'page arguments' => array('aggregator_form_category', 5),
webmaster@1 242 'access arguments' => array('administer news feeds'),
webmaster@1 243 'type' => MENU_CALLBACK,
webmaster@1 244 'file' => 'aggregator.admin.inc',
webmaster@1 245 );
webmaster@1 246
webmaster@1 247 return $items;
webmaster@1 248 }
webmaster@1 249
webmaster@1 250 /**
webmaster@1 251 * Menu callback.
webmaster@1 252 *
webmaster@1 253 * @return
webmaster@1 254 * An aggregator category title.
webmaster@1 255 */
webmaster@1 256 function _aggregator_category_title($category) {
webmaster@1 257 return $category['title'];
webmaster@1 258 }
webmaster@1 259
webmaster@1 260 /**
webmaster@1 261 * Implementation of hook_init().
webmaster@1 262 */
webmaster@1 263 function aggregator_init() {
webmaster@1 264 drupal_add_css(drupal_get_path('module', 'aggregator') .'/aggregator.css');
webmaster@1 265 }
webmaster@1 266
webmaster@1 267 /**
webmaster@1 268 * Find out whether there are any aggregator categories.
webmaster@1 269 *
webmaster@1 270 * @return
webmaster@1 271 * TRUE if there is at least one category and the user has access to them, FALSE otherwise.
webmaster@1 272 */
webmaster@1 273 function _aggregator_has_categories() {
webmaster@1 274 return user_access('access news feeds') && db_result(db_query('SELECT COUNT(*) FROM {aggregator_category}'));
webmaster@1 275 }
webmaster@1 276
webmaster@1 277 /**
webmaster@1 278 * Implementation of hook_perm().
webmaster@1 279 */
webmaster@1 280 function aggregator_perm() {
webmaster@1 281 return array('administer news feeds', 'access news feeds');
webmaster@1 282 }
webmaster@1 283
webmaster@1 284 /**
webmaster@1 285 * Implementation of hook_cron().
webmaster@1 286 *
webmaster@1 287 * Checks news feeds for updates once their refresh interval has elapsed.
webmaster@1 288 */
webmaster@1 289 function aggregator_cron() {
webmaster@1 290 $result = db_query('SELECT * FROM {aggregator_feed} WHERE checked + refresh < %d', time());
webmaster@1 291 while ($feed = db_fetch_array($result)) {
webmaster@1 292 aggregator_refresh($feed);
webmaster@1 293 }
webmaster@1 294 }
webmaster@1 295
webmaster@1 296 /**
webmaster@1 297 * Implementation of hook_block().
webmaster@1 298 *
webmaster@1 299 * Generates blocks for the latest news items in each category and feed.
webmaster@1 300 */
webmaster@1 301 function aggregator_block($op = 'list', $delta = 0, $edit = array()) {
webmaster@1 302 if (user_access('access news feeds')) {
webmaster@1 303 if ($op == 'list') {
webmaster@1 304 $result = db_query('SELECT cid, title FROM {aggregator_category} ORDER BY title');
webmaster@1 305 while ($category = db_fetch_object($result)) {
webmaster@1 306 $block['category-'. $category->cid]['info'] = t('!title category latest items', array('!title' => $category->title));
webmaster@1 307 }
webmaster@1 308 $result = db_query('SELECT fid, title FROM {aggregator_feed} ORDER BY fid');
webmaster@1 309 while ($feed = db_fetch_object($result)) {
webmaster@1 310 $block['feed-'. $feed->fid]['info'] = t('!title feed latest items', array('!title' => $feed->title));
webmaster@1 311 }
webmaster@1 312 }
webmaster@1 313 else if ($op == 'configure') {
webmaster@1 314 list($type, $id) = explode('-', $delta);
webmaster@1 315 if ($type == 'category') {
webmaster@1 316 $value = db_result(db_query('SELECT block FROM {aggregator_category} WHERE cid = %d', $id));
webmaster@1 317 }
webmaster@1 318 else {
webmaster@1 319 $value = db_result(db_query('SELECT block FROM {aggregator_feed} WHERE fid = %d', $id));
webmaster@1 320 }
webmaster@1 321 $form['block'] = array('#type' => 'select', '#title' => t('Number of news items in block'), '#default_value' => $value, '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)));
webmaster@1 322 return $form;
webmaster@1 323 }
webmaster@1 324 else if ($op == 'save') {
webmaster@1 325 list($type, $id) = explode('-', $delta);
webmaster@1 326 if ($type == 'category') {
webmaster@1 327 $value = db_query('UPDATE {aggregator_category} SET block = %d WHERE cid = %d', $edit['block'], $id);
webmaster@1 328 }
webmaster@1 329 else {
webmaster@1 330 $value = db_query('UPDATE {aggregator_feed} SET block = %d WHERE fid = %d', $edit['block'], $id);
webmaster@1 331 }
webmaster@1 332 }
webmaster@1 333 else if ($op == 'view') {
webmaster@1 334 list($type, $id) = explode('-', $delta);
webmaster@1 335 switch ($type) {
webmaster@1 336 case 'feed':
webmaster@1 337 if ($feed = db_fetch_object(db_query('SELECT fid, title, block FROM {aggregator_feed} WHERE fid = %d', $id))) {
webmaster@1 338 $block['subject'] = check_plain($feed->title);
webmaster@1 339 $result = db_query_range('SELECT * FROM {aggregator_item} WHERE fid = %d ORDER BY timestamp DESC, iid DESC', $feed->fid, 0, $feed->block);
webmaster@1 340 $read_more = theme('more_link', url('aggregator/sources/'. $feed->fid), t("View this feed's recent news."));
webmaster@1 341 }
webmaster@1 342 break;
webmaster@1 343
webmaster@1 344 case 'category':
webmaster@1 345 if ($category = db_fetch_object(db_query('SELECT cid, title, block FROM {aggregator_category} WHERE cid = %d', $id))) {
webmaster@1 346 $block['subject'] = check_plain($category->title);
webmaster@1 347 $result = db_query_range('SELECT i.* FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON ci.iid = i.iid WHERE ci.cid = %d ORDER BY i.timestamp DESC, i.iid DESC', $category->cid, 0, $category->block);
webmaster@1 348 $read_more = theme('more_link', url('aggregator/categories/'. $category->cid), t("View this category's recent news."));
webmaster@1 349 }
webmaster@1 350 break;
webmaster@1 351 }
webmaster@1 352 $items = array();
webmaster@1 353 while ($item = db_fetch_object($result)) {
webmaster@1 354 $items[] = theme('aggregator_block_item', $item);
webmaster@1 355 }
webmaster@1 356
webmaster@1 357 // Only display the block if there are items to show.
webmaster@1 358 if (count($items) > 0) {
webmaster@1 359 $block['content'] = theme('item_list', $items) . $read_more;
webmaster@1 360 }
webmaster@1 361 }
webmaster@1 362 if (isset($block)) {
webmaster@1 363 return $block;
webmaster@1 364 }
webmaster@1 365 }
webmaster@1 366 }
webmaster@1 367
webmaster@1 368 /**
webmaster@1 369 * Add/edit/delete aggregator categories.
webmaster@1 370 *
webmaster@1 371 * @param $edit
webmaster@1 372 * An associative array describing the category to be added/edited/deleted.
webmaster@1 373 */
webmaster@1 374 function aggregator_save_category($edit) {
webmaster@1 375 $link_path = 'aggregator/categories/';
webmaster@1 376 if (!empty($edit['cid'])) {
webmaster@1 377 $link_path .= $edit['cid'];
webmaster@1 378 if (!empty($edit['title'])) {
webmaster@1 379 db_query("UPDATE {aggregator_category} SET title = '%s', description = '%s' WHERE cid = %d", $edit['title'], $edit['description'], $edit['cid']);
webmaster@1 380 $op = 'update';
webmaster@1 381 }
webmaster@1 382 else {
webmaster@1 383 db_query('DELETE FROM {aggregator_category} WHERE cid = %d', $edit['cid']);
webmaster@9 384 // Make sure there is no active block for this category.
webmaster@9 385 db_query("DELETE FROM {blocks} WHERE module = '%s' AND delta = '%s'", 'aggregator', 'category-' . $edit['cid']);
webmaster@1 386 $edit['title'] = '';
webmaster@1 387 $op = 'delete';
webmaster@1 388 }
webmaster@1 389 }
webmaster@1 390 else if (!empty($edit['title'])) {
webmaster@1 391 // A single unique id for bundles and feeds, to use in blocks
webmaster@1 392 db_query("INSERT INTO {aggregator_category} (title, description, block) VALUES ('%s', '%s', 5)", $edit['title'], $edit['description']);
webmaster@1 393 $link_path .= db_last_insert_id('aggregator', 'cid');
webmaster@1 394 $op = 'insert';
webmaster@1 395 }
webmaster@1 396 if (isset($op)) {
webmaster@1 397 menu_link_maintain('aggregator', $op, $link_path, $edit['title']);
webmaster@1 398 }
webmaster@1 399 }
webmaster@1 400
webmaster@1 401 /**
webmaster@1 402 * Add/edit/delete an aggregator feed.
webmaster@1 403 *
webmaster@1 404 * @param $edit
webmaster@1 405 * An associative array describing the feed to be added/edited/deleted.
webmaster@1 406 */
webmaster@1 407 function aggregator_save_feed($edit) {
webmaster@1 408 if (!empty($edit['fid'])) {
webmaster@1 409 // An existing feed is being modified, delete the category listings.
webmaster@1 410 db_query('DELETE FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']);
webmaster@1 411 }
webmaster@1 412 if (!empty($edit['fid']) && !empty($edit['title'])) {
webmaster@1 413 db_query("UPDATE {aggregator_feed} SET title = '%s', url = '%s', refresh = %d WHERE fid = %d", $edit['title'], $edit['url'], $edit['refresh'], $edit['fid']);
webmaster@1 414 }
webmaster@1 415 else if (!empty($edit['fid'])) {
webmaster@1 416 $items = array();
webmaster@1 417 $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d', $edit['fid']);
webmaster@1 418 while ($item = db_fetch_object($result)) {
webmaster@1 419 $items[] = "iid = $item->iid";
webmaster@1 420 }
webmaster@1 421 if (!empty($items)) {
webmaster@1 422 db_query('DELETE FROM {aggregator_category_item} WHERE '. implode(' OR ', $items));
webmaster@1 423 }
webmaster@1 424 db_query('DELETE FROM {aggregator_feed} WHERE fid = %d', $edit['fid']);
webmaster@1 425 db_query('DELETE FROM {aggregator_item} WHERE fid = %d', $edit['fid']);
webmaster@9 426 // Make sure there is no active block for this feed.
webmaster@9 427 db_query("DELETE FROM {blocks} WHERE module = '%s' AND delta = '%s'", 'aggregator', 'feed-' . $edit['fid']);
webmaster@1 428 }
webmaster@1 429 else if (!empty($edit['title'])) {
webmaster@1 430 db_query("INSERT INTO {aggregator_feed} (title, url, refresh, block, description, image) VALUES ('%s', '%s', %d, 5, '', '')", $edit['title'], $edit['url'], $edit['refresh']);
webmaster@1 431 // A single unique id for bundles and feeds, to use in blocks.
webmaster@1 432 $edit['fid'] = db_last_insert_id('aggregator_feed', 'fid');
webmaster@1 433 }
webmaster@1 434 if (!empty($edit['title'])) {
webmaster@1 435 // The feed is being saved, save the categories as well.
webmaster@1 436 if (!empty($edit['category'])) {
webmaster@1 437 foreach ($edit['category'] as $cid => $value) {
webmaster@1 438 if ($value) {
webmaster@1 439 db_query('INSERT INTO {aggregator_category_feed} (fid, cid) VALUES (%d, %d)', $edit['fid'], $cid);
webmaster@1 440 }
webmaster@1 441 }
webmaster@1 442 }
webmaster@1 443 }
webmaster@1 444 }
webmaster@1 445
webmaster@1 446 /**
webmaster@1 447 * Removes all items from a feed.
webmaster@1 448 *
webmaster@1 449 * @param $feed
webmaster@1 450 * An associative array describing the feed to be cleared.
webmaster@1 451 */
webmaster@1 452 function aggregator_remove($feed) {
webmaster@1 453 $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d', $feed['fid']);
webmaster@1 454 while ($item = db_fetch_object($result)) {
webmaster@1 455 $items[] = "iid = $item->iid";
webmaster@1 456 }
webmaster@1 457 if (!empty($items)) {
webmaster@1 458 db_query('DELETE FROM {aggregator_category_item} WHERE '. implode(' OR ', $items));
webmaster@1 459 }
webmaster@1 460 db_query('DELETE FROM {aggregator_item} WHERE fid = %d', $feed['fid']);
webmaster@1 461 db_query("UPDATE {aggregator_feed} SET checked = 0, etag = '', modified = 0 WHERE fid = %d", $feed['fid']);
webmaster@1 462 drupal_set_message(t('The news items from %site have been removed.', array('%site' => $feed['title'])));
webmaster@1 463 }
webmaster@1 464
webmaster@1 465 /**
webmaster@1 466 * Call-back function used by the XML parser.
webmaster@1 467 */
webmaster@1 468 function aggregator_element_start($parser, $name, $attributes) {
webmaster@1 469 global $item, $element, $tag, $items, $channel;
webmaster@1 470
webmaster@1 471 switch ($name) {
webmaster@1 472 case 'IMAGE':
webmaster@1 473 case 'TEXTINPUT':
webmaster@1 474 case 'CONTENT':
webmaster@1 475 case 'SUMMARY':
webmaster@1 476 case 'TAGLINE':
webmaster@1 477 case 'SUBTITLE':
webmaster@1 478 case 'LOGO':
webmaster@1 479 case 'INFO':
webmaster@1 480 $element = $name;
webmaster@1 481 break;
webmaster@1 482 case 'ID':
webmaster@1 483 if ($element != 'ITEM') {
webmaster@1 484 $element = $name;
webmaster@1 485 }
webmaster@1 486 case 'LINK':
webmaster@1 487 if (!empty($attributes['REL']) && $attributes['REL'] == 'alternate') {
webmaster@1 488 if ($element == 'ITEM') {
webmaster@1 489 $items[$item]['LINK'] = $attributes['HREF'];
webmaster@1 490 }
webmaster@1 491 else {
webmaster@1 492 $channel['LINK'] = $attributes['HREF'];
webmaster@1 493 }
webmaster@1 494 }
webmaster@1 495 break;
webmaster@1 496 case 'ITEM':
webmaster@1 497 $element = $name;
webmaster@1 498 $item += 1;
webmaster@1 499 break;
webmaster@1 500 case 'ENTRY':
webmaster@1 501 $element = 'ITEM';
webmaster@1 502 $item += 1;
webmaster@1 503 break;
webmaster@1 504 }
webmaster@1 505
webmaster@1 506 $tag = $name;
webmaster@1 507 }
webmaster@1 508
webmaster@1 509 /**
webmaster@1 510 * Call-back function used by the XML parser.
webmaster@1 511 */
webmaster@1 512 function aggregator_element_end($parser, $name) {
webmaster@1 513 global $element;
webmaster@1 514
webmaster@1 515 switch ($name) {
webmaster@1 516 case 'IMAGE':
webmaster@1 517 case 'TEXTINPUT':
webmaster@1 518 case 'ITEM':
webmaster@1 519 case 'ENTRY':
webmaster@1 520 case 'CONTENT':
webmaster@1 521 case 'INFO':
webmaster@1 522 $element = '';
webmaster@1 523 break;
webmaster@1 524 case 'ID':
webmaster@1 525 if ($element == 'ID') {
webmaster@1 526 $element = '';
webmaster@1 527 }
webmaster@1 528 }
webmaster@1 529 }
webmaster@1 530
webmaster@1 531 /**
webmaster@1 532 * Call-back function used by the XML parser.
webmaster@1 533 */
webmaster@1 534 function aggregator_element_data($parser, $data) {
webmaster@1 535 global $channel, $element, $items, $item, $image, $tag;
webmaster@1 536 $items += array($item => array());
webmaster@1 537 switch ($element) {
webmaster@1 538 case 'ITEM':
webmaster@1 539 $items[$item] += array($tag => '');
webmaster@1 540 $items[$item][$tag] .= $data;
webmaster@1 541 break;
webmaster@1 542 case 'IMAGE':
webmaster@1 543 case 'LOGO':
webmaster@1 544 $image += array($tag => '');
webmaster@1 545 $image[$tag] .= $data;
webmaster@1 546 break;
webmaster@1 547 case 'LINK':
webmaster@1 548 if ($data) {
webmaster@1 549 $items[$item] += array($tag => '');
webmaster@1 550 $items[$item][$tag] .= $data;
webmaster@1 551 }
webmaster@1 552 break;
webmaster@1 553 case 'CONTENT':
webmaster@1 554 $items[$item] += array('CONTENT' => '');
webmaster@1 555 $items[$item]['CONTENT'] .= $data;
webmaster@1 556 break;
webmaster@1 557 case 'SUMMARY':
webmaster@1 558 $items[$item] += array('SUMMARY' => '');
webmaster@1 559 $items[$item]['SUMMARY'] .= $data;
webmaster@1 560 break;
webmaster@1 561 case 'TAGLINE':
webmaster@1 562 case 'SUBTITLE':
webmaster@1 563 $channel += array('DESCRIPTION' => '');
webmaster@1 564 $channel['DESCRIPTION'] .= $data;
webmaster@1 565 break;
webmaster@1 566 case 'INFO':
webmaster@1 567 case 'ID':
webmaster@1 568 case 'TEXTINPUT':
webmaster@1 569 // The sub-element is not supported. However, we must recognize
webmaster@1 570 // it or its contents will end up in the item array.
webmaster@1 571 break;
webmaster@1 572 default:
webmaster@1 573 $channel += array($tag => '');
webmaster@1 574 $channel[$tag] .= $data;
webmaster@1 575 }
webmaster@1 576 }
webmaster@1 577
webmaster@1 578 /**
webmaster@1 579 * Checks a news feed for new items.
webmaster@1 580 *
webmaster@1 581 * @param $feed
webmaster@1 582 * An associative array describing the feed to be refreshed.
webmaster@1 583 */
webmaster@1 584 function aggregator_refresh($feed) {
webmaster@1 585 global $channel, $image;
webmaster@1 586
webmaster@1 587 // Generate conditional GET headers.
webmaster@1 588 $headers = array();
webmaster@1 589 if ($feed['etag']) {
webmaster@1 590 $headers['If-None-Match'] = $feed['etag'];
webmaster@1 591 }
webmaster@1 592 if ($feed['modified']) {
webmaster@1 593 $headers['If-Modified-Since'] = gmdate('D, d M Y H:i:s', $feed['modified']) .' GMT';
webmaster@1 594 }
webmaster@1 595
webmaster@1 596 // Request feed.
webmaster@1 597 $result = drupal_http_request($feed['url'], $headers);
webmaster@1 598
webmaster@1 599 // Process HTTP response code.
webmaster@1 600 switch ($result->code) {
webmaster@1 601 case 304:
webmaster@1 602 db_query('UPDATE {aggregator_feed} SET checked = %d WHERE fid = %d', time(), $feed['fid']);
webmaster@1 603 drupal_set_message(t('There is no new syndicated content from %site.', array('%site' => $feed['title'])));
webmaster@1 604 break;
webmaster@1 605 case 301:
webmaster@1 606 $feed['url'] = $result->redirect_url;
webmaster@1 607 watchdog('aggregator', 'Updated URL for feed %title to %url.', array('%title' => $feed['title'], '%url' => $feed['url']));
webmaster@1 608 // Deliberate no break.
webmaster@1 609 case 200:
webmaster@1 610 case 302:
webmaster@1 611 case 307:
webmaster@1 612 // Filter the input data:
webmaster@1 613 if (aggregator_parse_feed($result->data, $feed)) {
webmaster@1 614 $modified = empty($result->headers['Last-Modified']) ? 0 : strtotime($result->headers['Last-Modified']);
webmaster@1 615
webmaster@1 616 // Prepare the channel data.
webmaster@1 617 foreach ($channel as $key => $value) {
webmaster@1 618 $channel[$key] = trim($value);
webmaster@1 619 }
webmaster@1 620
webmaster@1 621 // Prepare the image data (if any).
webmaster@1 622 foreach ($image as $key => $value) {
webmaster@1 623 $image[$key] = trim($value);
webmaster@1 624 }
webmaster@1 625
webmaster@1 626 if (!empty($image['LINK']) && !empty($image['URL']) && !empty($image['TITLE'])) {
webmaster@1 627 // Note, we should really use theme_image() here but that only works with local images it won't work with images fetched with a URL unless PHP version > 5
webmaster@1 628 $image = '<a href="'. check_url($image['LINK']) .'" class="feed-image"><img src="'. check_url($image['URL']) .'" alt="'. check_plain($image['TITLE']) .'" /></a>';
webmaster@1 629 }
webmaster@1 630 else {
webmaster@1 631 $image = NULL;
webmaster@1 632 }
webmaster@1 633
webmaster@1 634 $etag = empty($result->headers['ETag']) ? '' : $result->headers['ETag'];
webmaster@1 635 // Update the feed data.
webmaster@1 636 db_query("UPDATE {aggregator_feed} SET url = '%s', checked = %d, link = '%s', description = '%s', image = '%s', etag = '%s', modified = %d WHERE fid = %d", $feed['url'], time(), $channel['LINK'], $channel['DESCRIPTION'], $image, $etag, $modified, $feed['fid']);
webmaster@1 637
webmaster@1 638 // Clear the cache.
webmaster@1 639 cache_clear_all();
webmaster@1 640
webmaster@1 641 watchdog('aggregator', 'There is new syndicated content from %site.', array('%site' => $feed['title']));
webmaster@1 642 drupal_set_message(t('There is new syndicated content from %site.', array('%site' => $feed['title'])));
webmaster@1 643 break;
webmaster@1 644 }
webmaster@1 645 $result->error = t('feed not parseable');
webmaster@1 646 // Deliberate no break.
webmaster@1 647 default:
webmaster@1 648 watchdog('aggregator', 'The feed from %site seems to be broken, due to "%error".', array('%site' => $feed['title'], '%error' => $result->code .' '. $result->error), WATCHDOG_WARNING);
webmaster@1 649 drupal_set_message(t('The feed from %site seems to be broken, because of error "%error".', array('%site' => $feed['title'], '%error' => $result->code .' '. $result->error)));
webmaster@1 650 }
webmaster@1 651 }
webmaster@1 652
webmaster@1 653 /**
webmaster@1 654 * Parse the W3C date/time format, a subset of ISO 8601. PHP date parsing
webmaster@1 655 * functions do not handle this format.
webmaster@1 656 * See http://www.w3.org/TR/NOTE-datetime for more information.
webmaster@1 657 * Originally from MagpieRSS (http://magpierss.sourceforge.net/).
webmaster@1 658 *
webmaster@1 659 * @param $date_str
webmaster@1 660 * A string with a potentially W3C DTF date.
webmaster@1 661 * @return
webmaster@1 662 * A timestamp if parsed successfully or FALSE if not.
webmaster@1 663 */
webmaster@1 664 function aggregator_parse_w3cdtf($date_str) {
webmaster@1 665 if (preg_match('/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/', $date_str, $match)) {
webmaster@1 666 list($year, $month, $day, $hours, $minutes, $seconds) = array($match[1], $match[2], $match[3], $match[4], $match[5], $match[6]);
webmaster@1 667 // calc epoch for current date assuming GMT
webmaster@1 668 $epoch = gmmktime($hours, $minutes, $seconds, $month, $day, $year);
webmaster@1 669 if ($match[10] != 'Z') { // Z is zulu time, aka GMT
webmaster@1 670 list($tz_mod, $tz_hour, $tz_min) = array($match[8], $match[9], $match[10]);
webmaster@1 671 // zero out the variables
webmaster@1 672 if (!$tz_hour) {
webmaster@1 673 $tz_hour = 0;
webmaster@1 674 }
webmaster@1 675 if (!$tz_min) {
webmaster@1 676 $tz_min = 0;
webmaster@1 677 }
webmaster@1 678 $offset_secs = (($tz_hour * 60) + $tz_min) * 60;
webmaster@1 679 // is timezone ahead of GMT? then subtract offset
webmaster@1 680 if ($tz_mod == '+') {
webmaster@1 681 $offset_secs *= -1;
webmaster@1 682 }
webmaster@1 683 $epoch += $offset_secs;
webmaster@1 684 }
webmaster@1 685 return $epoch;
webmaster@1 686 }
webmaster@1 687 else {
webmaster@1 688 return FALSE;
webmaster@1 689 }
webmaster@1 690 }
webmaster@1 691
webmaster@1 692 /**
webmaster@1 693 * Parse a feed and store its items.
webmaster@1 694 *
webmaster@1 695 * @param $data
webmaster@1 696 * The feed data.
webmaster@1 697 * @param $feed
webmaster@1 698 * An associative array describing the feed to be parsed.
webmaster@1 699 * @return
webmaster@1 700 * 0 on error, 1 otherwise.
webmaster@1 701 */
webmaster@1 702 function aggregator_parse_feed(&$data, $feed) {
webmaster@1 703 global $items, $image, $channel;
webmaster@1 704
webmaster@1 705 // Unset the global variables before we use them:
webmaster@1 706 unset($GLOBALS['element'], $GLOBALS['item'], $GLOBALS['tag']);
webmaster@1 707 $items = array();
webmaster@1 708 $image = array();
webmaster@1 709 $channel = array();
webmaster@1 710
webmaster@1 711 // parse the data:
webmaster@1 712 $xml_parser = drupal_xml_parser_create($data);
webmaster@1 713 xml_set_element_handler($xml_parser, 'aggregator_element_start', 'aggregator_element_end');
webmaster@1 714 xml_set_character_data_handler($xml_parser, 'aggregator_element_data');
webmaster@1 715
webmaster@1 716 if (!xml_parse($xml_parser, $data, 1)) {
webmaster@1 717 watchdog('aggregator', 'The feed from %site seems to be broken, due to an error "%error" on line %line.', array('%site' => $feed['title'], '%error' => xml_error_string(xml_get_error_code($xml_parser)), '%line' => xml_get_current_line_number($xml_parser)), WATCHDOG_WARNING);
webmaster@1 718 drupal_set_message(t('The feed from %site seems to be broken, because of error "%error" on line %line.', array('%site' => $feed['title'], '%error' => xml_error_string(xml_get_error_code($xml_parser)), '%line' => xml_get_current_line_number($xml_parser))), 'error');
webmaster@1 719 return 0;
webmaster@1 720 }
webmaster@1 721 xml_parser_free($xml_parser);
webmaster@1 722
webmaster@1 723 // We reverse the array such that we store the first item last, and the last
webmaster@1 724 // item first. In the database, the newest item should be at the top.
webmaster@1 725 $items = array_reverse($items);
webmaster@1 726
webmaster@1 727 // Initialize variables.
webmaster@1 728 $title = $link = $author = $description = $guid = NULL;
webmaster@1 729 foreach ($items as $item) {
webmaster@1 730 unset($title, $link, $author, $description, $guid);
webmaster@1 731
webmaster@1 732 // Prepare the item:
webmaster@1 733 foreach ($item as $key => $value) {
webmaster@1 734 $item[$key] = trim($value);
webmaster@1 735 }
webmaster@1 736
webmaster@1 737 // Resolve the item's title. If no title is found, we use up to 40
webmaster@1 738 // characters of the description ending at a word boundary but not
webmaster@1 739 // splitting potential entities.
webmaster@1 740 if (!empty($item['TITLE'])) {
webmaster@1 741 $title = $item['TITLE'];
webmaster@1 742 }
webmaster@1 743 elseif (!empty($item['DESCRIPTION'])) {
webmaster@1 744 $title = preg_replace('/^(.*)[^\w;&].*?$/', "\\1", truncate_utf8($item['DESCRIPTION'], 40));
webmaster@1 745 }
webmaster@1 746 else {
webmaster@1 747 $title = '';
webmaster@1 748 }
webmaster@1 749
webmaster@1 750 // Resolve the items link.
webmaster@1 751 if (!empty($item['LINK'])) {
webmaster@1 752 $link = $item['LINK'];
webmaster@1 753 }
webmaster@1 754 else {
webmaster@1 755 $link = $feed['link'];
webmaster@1 756 }
webmaster@1 757 $guid = isset($item['GUID']) ? $item['GUID'] : '';
webmaster@1 758
webmaster@1 759 // Atom feeds have a CONTENT and/or SUMMARY tag instead of a DESCRIPTION tag.
webmaster@1 760 if (!empty($item['CONTENT:ENCODED'])) {
webmaster@1 761 $item['DESCRIPTION'] = $item['CONTENT:ENCODED'];
webmaster@1 762 }
webmaster@1 763 else if (!empty($item['SUMMARY'])) {
webmaster@1 764 $item['DESCRIPTION'] = $item['SUMMARY'];
webmaster@1 765 }
webmaster@1 766 else if (!empty($item['CONTENT'])) {
webmaster@1 767 $item['DESCRIPTION'] = $item['CONTENT'];
webmaster@1 768 }
webmaster@1 769
webmaster@1 770 // Try to resolve and parse the item's publication date. If no date is
webmaster@1 771 // found, we use the current date instead.
webmaster@1 772 $date = 'now';
webmaster@1 773 foreach (array('PUBDATE', 'DC:DATE', 'DCTERMS:ISSUED', 'DCTERMS:CREATED', 'DCTERMS:MODIFIED', 'ISSUED', 'CREATED', 'MODIFIED', 'PUBLISHED', 'UPDATED') as $key) {
webmaster@1 774 if (!empty($item[$key])) {
webmaster@1 775 $date = $item[$key];
webmaster@1 776 break;
webmaster@1 777 }
webmaster@1 778 }
webmaster@1 779
webmaster@1 780 $timestamp = strtotime($date); // As of PHP 5.1.0, strtotime returns FALSE on failure instead of -1.
webmaster@1 781 if ($timestamp <= 0) {
webmaster@1 782 $timestamp = aggregator_parse_w3cdtf($date); // Returns FALSE on failure
webmaster@1 783 if (!$timestamp) {
webmaster@1 784 $timestamp = time(); // better than nothing
webmaster@1 785 }
webmaster@1 786 }
webmaster@1 787
webmaster@1 788 // Save this item. Try to avoid duplicate entries as much as possible. If
webmaster@1 789 // we find a duplicate entry, we resolve it and pass along its ID is such
webmaster@1 790 // that we can update it if needed.
webmaster@1 791 if (!empty($guid)) {
webmaster@1 792 $entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND guid = '%s'", $feed['fid'], $guid));
webmaster@1 793 }
webmaster@1 794 else if ($link && $link != $feed['link'] && $link != $feed['url']) {
webmaster@1 795 $entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND link = '%s'", $feed['fid'], $link));
webmaster@1 796 }
webmaster@1 797 else {
webmaster@1 798 $entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND title = '%s'", $feed['fid'], $title));
webmaster@1 799 }
webmaster@1 800 $item += array('AUTHOR' => '', 'DESCRIPTION' => '');
webmaster@1 801 aggregator_save_item(array('iid' => (isset($entry->iid) ? $entry->iid: ''), 'fid' => $feed['fid'], 'timestamp' => $timestamp, 'title' => $title, 'link' => $link, 'author' => $item['AUTHOR'], 'description' => $item['DESCRIPTION'], 'guid' => $guid));
webmaster@1 802 }
webmaster@1 803
webmaster@1 804 // Remove all items that are older than flush item timer.
webmaster@1 805 $age = time() - variable_get('aggregator_clear', 9676800);
webmaster@1 806 $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d AND timestamp < %d', $feed['fid'], $age);
webmaster@1 807
webmaster@1 808 $items = array();
webmaster@1 809 $num_rows = FALSE;
webmaster@1 810 while ($item = db_fetch_object($result)) {
webmaster@1 811 $items[] = $item->iid;
webmaster@1 812 $num_rows = TRUE;
webmaster@1 813 }
webmaster@1 814 if ($num_rows) {
webmaster@1 815 db_query('DELETE FROM {aggregator_category_item} WHERE iid IN ('. implode(', ', $items) .')');
webmaster@1 816 db_query('DELETE FROM {aggregator_item} WHERE fid = %d AND timestamp < %d', $feed['fid'], $age);
webmaster@1 817 }
webmaster@1 818
webmaster@1 819 return 1;
webmaster@1 820 }
webmaster@1 821
webmaster@1 822 /**
webmaster@1 823 * Add/edit/delete an aggregator item.
webmaster@1 824 *
webmaster@1 825 * @param $edit
webmaster@1 826 * An associative array describing the item to be added/edited/deleted.
webmaster@1 827 */
webmaster@1 828 function aggregator_save_item($edit) {
webmaster@1 829 if ($edit['iid'] && $edit['title']) {
webmaster@1 830 db_query("UPDATE {aggregator_item} SET title = '%s', link = '%s', author = '%s', description = '%s', guid = '%s', timestamp = %d WHERE iid = %d", $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['guid'], $edit['timestamp'], $edit['iid']);
webmaster@1 831 }
webmaster@1 832 else if ($edit['iid']) {
webmaster@1 833 db_query('DELETE FROM {aggregator_item} WHERE iid = %d', $edit['iid']);
webmaster@1 834 db_query('DELETE FROM {aggregator_category_item} WHERE iid = %d', $edit['iid']);
webmaster@1 835 }
webmaster@1 836 else if ($edit['title'] && $edit['link']) {
webmaster@1 837 db_query("INSERT INTO {aggregator_item} (fid, title, link, author, description, timestamp, guid) VALUES (%d, '%s', '%s', '%s', '%s', %d, '%s')", $edit['fid'], $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['timestamp'], $edit['guid']);
webmaster@1 838 $edit['iid'] = db_last_insert_id('aggregator_item', 'iid');
webmaster@1 839 // file the items in the categories indicated by the feed
webmaster@1 840 $categories = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']);
webmaster@1 841 while ($category = db_fetch_object($categories)) {
webmaster@1 842 db_query('INSERT INTO {aggregator_category_item} (cid, iid) VALUES (%d, %d)', $category->cid, $edit['iid']);
webmaster@1 843 }
webmaster@1 844 }
webmaster@1 845 }
webmaster@1 846
webmaster@1 847 /**
webmaster@1 848 * Load an aggregator feed.
webmaster@1 849 *
webmaster@1 850 * @param $fid
webmaster@1 851 * The feed id.
webmaster@1 852 * @return
webmaster@1 853 * An associative array describing the feed.
webmaster@1 854 */
webmaster@1 855 function aggregator_feed_load($fid) {
webmaster@1 856 static $feeds;
webmaster@1 857 if (!isset($feeds[$fid])) {
webmaster@1 858 $feeds[$fid] = db_fetch_array(db_query('SELECT * FROM {aggregator_feed} WHERE fid = %d', $fid));
webmaster@1 859 }
webmaster@1 860 return $feeds[$fid];
webmaster@1 861 }
webmaster@1 862
webmaster@1 863 /**
webmaster@1 864 * Load an aggregator category.
webmaster@1 865 *
webmaster@1 866 * @param $cid
webmaster@1 867 * The category id.
webmaster@1 868 * @return
webmaster@1 869 * An associative array describing the category.
webmaster@1 870 */
webmaster@1 871 function aggregator_category_load($cid) {
webmaster@1 872 static $categories;
webmaster@1 873 if (!isset($categories[$cid])) {
webmaster@1 874 $categories[$cid] = db_fetch_array(db_query('SELECT * FROM {aggregator_category} WHERE cid = %d', $cid));
webmaster@1 875 }
webmaster@1 876 return $categories[$cid];
webmaster@1 877 }
webmaster@1 878
webmaster@1 879 /**
webmaster@1 880 * Format an individual feed item for display in the block.
webmaster@1 881 *
webmaster@1 882 * @param $item
webmaster@1 883 * The item to be displayed.
webmaster@1 884 * @param $feed
webmaster@1 885 * Not used.
webmaster@1 886 * @return
webmaster@1 887 * The item HTML.
webmaster@1 888 * @ingroup themeable
webmaster@1 889 */
webmaster@1 890 function theme_aggregator_block_item($item, $feed = 0) {
webmaster@1 891 global $user;
webmaster@1 892
webmaster@1 893 $output = '';
webmaster@1 894 if ($user->uid && module_exists('blog') && user_access('create blog entries')) {
webmaster@1 895 if ($image = theme('image', 'misc/blog.png', t('blog it'), t('blog it'))) {
webmaster@1 896 $output .= '<div class="icon">'. l($image, 'node/add/blog', array('attributes' => array('title' => t('Comment on this news item in your personal blog.'), 'class' => 'blog-it'), 'query' => "iid=$item->iid", 'html' => TRUE)) .'</div>';
webmaster@1 897 }
webmaster@1 898 }
webmaster@1 899
webmaster@1 900 // Display the external link to the item.
webmaster@1 901 $output .= '<a href="'. check_url($item->link) .'">'. check_plain($item->title) ."</a>\n";
webmaster@1 902
webmaster@1 903 return $output;
webmaster@1 904 }
webmaster@1 905
webmaster@1 906 /**
webmaster@1 907 * Safely render HTML content, as allowed.
webmaster@1 908 *
webmaster@1 909 * @param $value
webmaster@1 910 * The content to be filtered.
webmaster@1 911 * @return
webmaster@1 912 * The filtered content.
webmaster@1 913 */
webmaster@1 914 function aggregator_filter_xss($value) {
webmaster@1 915 return filter_xss($value, preg_split('/\s+|<|>/', variable_get('aggregator_allowed_html_tags', '<a> <b> <br> <dd> <dl> <dt> <em> <i> <li> <ol> <p> <strong> <u> <ul>'), -1, PREG_SPLIT_NO_EMPTY));
webmaster@1 916 }
webmaster@1 917
webmaster@1 918 /**
webmaster@1 919 * Helper function for drupal_map_assoc.
webmaster@1 920 *
webmaster@1 921 * @param $count
webmaster@1 922 * Items count.
webmaster@1 923 * @return
webmaster@1 924 * Plural-formatted "@count items"
webmaster@1 925 */
webmaster@1 926 function _aggregator_items($count) {
webmaster@1 927 return format_plural($count, '1 item', '@count items');
webmaster@1 928 }