aggregator.pages.inc 15.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<?php
// $Id$

/**
 * @file
 * User page callbacks for the aggregator module.
 */

/**
 * Menu callback; displays the most recent items gathered from any feed.
 */
function aggregator_page_last() {
  drupal_add_feed(url('aggregator/rss'), variable_get('site_name', 'Drupal') .' '. t('aggregator'));

15 16 17
  $items = aggregator_feed_items_load('SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_item} i INNER JOIN {aggregator_feed} f ON i.fid = f.fid ORDER BY i.timestamp DESC, i.iid DESC');

  return _aggregator_page_list($items, arg(1));
18 19 20 21 22 23 24 25 26 27 28
}

/**
 * Menu callback; displays all the items captured from a particular feed.
 */
function aggregator_page_source($arg1, $arg2 = NULL) {
  // If there are two arguments then this function is the categorize form, and
  // $arg1 is $form_state and $arg2 is $feed. Otherwise, $arg1 is $feed.
  $feed = is_array($arg2) ? $arg2 : $arg1;
  $feed = (object)$feed;
  drupal_set_title(check_plain($feed->title));
29 30 31 32 33 34 35
  $feed_source = theme('aggregator_feed_source', $feed);
  
  // It is safe to include the fid in the query because it's loaded from the
  // database by aggregator_feed_load.  
  $items = aggregator_feed_items_load('SELECT * FROM {aggregator_item} WHERE fid = '. $feed->fid .' ORDER BY timestamp DESC, iid DESC');
  
  return _aggregator_page_list($items, arg(3), $feed_source);
36 37 38 39 40 41 42 43 44 45 46 47 48
}

/**
 * Menu callback; displays all the items aggregated in a particular category.
 */
function aggregator_page_category($arg1, $arg2 = NULL) {
  // If there are two arguments then we are called as a form, $arg1 is
  // $form_state and $arg2 is $category. Otherwise, $arg1 is $category.
  $category = is_array($arg2) ? $arg2 : $arg1;

  drupal_add_feed(url('aggregator/rss/'. $category['cid']), variable_get('site_name', 'Drupal') .' '. t('aggregator - @title', array('@title' => $category['title'])));

  // It is safe to include the cid in the query because it's loaded from the
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  // database by aggregator_category_load.  
  $items = aggregator_feed_items_load('SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_category_item} c LEFT JOIN {aggregator_item} i ON c.iid = i.iid LEFT JOIN {aggregator_feed} f ON i.fid = f.fid WHERE cid = '. $category['cid'] .' ORDER BY timestamp DESC, i.iid DESC');
    
  return _aggregator_page_list($items, arg(3));
}

/**
 * Load feed items by passing a sql query.
 */
function aggregator_feed_items_load($sql) {  
  $items = array();
  if (isset($sql)) {
    $result = pager_query($sql, 20);
    while ($item = db_fetch_object($result)) {
      $result_category = db_query('SELECT c.title, c.cid FROM {aggregator_category_item} ci LEFT JOIN {aggregator_category} c ON ci.cid = c.cid WHERE ci.iid = %d ORDER BY c.title', $item->iid);
      $item->categories = array();
      while ($item_categories = db_fetch_object($result_category)) {
        $item->categories[] = $item_categories;
      }
      $items[$item->iid] = $item;
    }
  }
  return $items;
72 73 74 75 76 77
}

/**
 * Prints an aggregator page listing a number of feed items. Various
 * menu callbacks use this function to print their feeds.
 */
78 79 80 81
function _aggregator_page_list($items, $op, $feed_source = '') {
  if (user_access('administer news feeds') && ($op == 'categorize')) {
    // Get form data.
    $output = aggregator_categorize_items($items, $feed_source);
82 83
  }
  else {
84 85 86 87
    // Assemble themed output.
    $output = $feed_source;    
    foreach ($items as $item) {
      $output .= theme('aggregator_item', $item);
88
    }
89
    $output = theme('aggregator_wrapper', $output);
90
  }
91
  return $output;
92 93 94 95 96 97
}

/**
 * Form builder; build the page list form.
 *
 * @ingroup forms
98 99
 * @see aggregator_categorize_items_validate().
 * @see aggregator_categorize_items_submit().
100
 */
101 102 103 104 105
function aggregator_categorize_items($items, $feed_source = '') {
  $form['#submit'][] = 'aggregator_categorize_items_submit';
  $form['#validate'][] = 'aggregator_categorize_items_validate';
  $form['#theme'] = 'aggregator_categorize_items';
  $form['feed_source'] = array('#value' => $feed_source);
106 107 108
  $categories = array();
  $done = FALSE;
  $form['items'] = array();
109 110 111
  $form['categories'] = array('#tree' => TRUE);    
  foreach ($items as $item) {
    $form['items'][$item->iid] = array('#value' => theme('aggregator_item', $item));
112
    $form['categories'][$item->iid] = array();
113 114 115 116 117 118 119 120
    $categories_result = db_query('SELECT c.cid, c.title, ci.iid FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid AND ci.iid = %d', $item->iid);
    $selected = array();
    while ($category = db_fetch_object($categories_result)) {
      if (!$done) {
        $categories[$category->cid] = check_plain($category->title);
      }
      if ($category->iid) {
        $selected[] = $category->cid;
121 122
      }
    }
123 124 125 126 127 128 129 130
    $done = TRUE;
    $form['categories'][$item->iid] = array(
      '#type' => variable_get('aggregator_category_selector', 'checkboxes'),
      '#default_value' => $selected,
      '#options' => $categories,
      '#size' => 10,
      '#multiple' => TRUE
    );
131 132 133 134 135 136
  }
  $form['submit'] = array('#type' => 'submit', '#value' => t('Save categories'));

  return $form;
}

137
function aggregator_categorize_items_validate($form_id, &$form) {
138 139 140 141 142
  if (!user_access('administer news feeds')) {
    form_error($form, t('You are not allowed to categorize this feed item.'));
  }
}

143
function aggregator_categorize_items_submit($form, &$form_state) {
144 145 146 147 148 149 150 151 152 153 154 155
  foreach ($form_state['values']['categories'] as $iid => $selection) {
    db_query('DELETE FROM {aggregator_category_item} WHERE iid = %d', $iid);
    foreach ($selection as $cid) {
      if ($cid) {
        db_query('INSERT INTO {aggregator_category_item} (cid, iid) VALUES (%d, %d)', $cid, $iid);
      }
    }
  }
  drupal_set_message(t('The categories have been saved.'));
}

/**
156
 * Theme the page list form for assigning categories.
157 158 159
 *
 * @ingroup themeable
 */
160 161
function theme_aggregator_categorize_items($form) {
  $output = drupal_render($form['feed_source']);
162 163 164 165
  $rows = array();
  if ($form['items']) {
    foreach (element_children($form['items']) as $key) {
      if (is_array($form['items'][$key])) {
166 167 168 169
        $rows[] = array(
          drupal_render($form['items'][$key]),
          array('data' => drupal_render($form['categories'][$key]), 'class' => 'categorize-item'),
        );
170 171 172 173 174 175
      }
    }
  }
  $output .= theme('table', array('', t('Categorize')), $rows);
  $output .= drupal_render($form['submit']);
  $output .= drupal_render($form);
176
  return theme('aggregator_wrapper', $output);
177 178
}

179 180 181 182 183 184 185 186 187 188 189
/**
 * Process variables for aggregator-wrapper.tpl.php.
 *
 * The $variables array contains the following arguments:
 * - $content
 *
 * @see aggregator-wrapper.tpl.php
 */
function template_preprocess_aggregator_wrapper(&$variables) {
  $variables['pager'] = theme('pager', NULL, 20, 0);
}
190 191

/**
192
 * Process variables for aggregator-item.tpl.php.
193
 *
194 195 196 197
 * The $variables array contains the following arguments:
 * - $item
 *
 * @see aggregator-item.tpl.php
198
 */
199 200 201 202 203 204
function template_preprocess_aggregator_item(&$variables) {
  $item = $variables['item'];

  $variables['feed_url'] = check_url($item->link);
  $variables['feed_title'] = check_plain($item->title);
  $variables['content'] = aggregator_filter_xss($item->description);
205

206 207
  $variables['source_url'] = '';
  $variables['source_title'] = '';
208
  if (isset($item->ftitle) && isset($item->fid)) {
209 210
    $variables['source_url'] = url("aggregator/sources/$item->fid");
    $variables['source_title'] = check_plain($item->ftitle);
211 212
  }
  if (date('Ymd', $item->timestamp) == date('Ymd')) {
213
    $variables['source_date'] = t('%ago ago', array('%ago' => format_interval(time() - $item->timestamp)));
214 215
  }
  else {
216
    $variables['source_date'] = format_date($item->timestamp, 'custom', variable_get('date_format_medium', 'D, m/d/Y - H:i'));
217 218
  }

219 220 221
  $variables['categories'] = array();
  foreach ($item->categories as $category) {
    $variables['categories'][$category->cid] = l($category->title, 'aggregator/categories/'. $category->cid);
222 223 224 225 226 227 228 229 230
  }
}

/**
 * Menu callback; displays all the feeds used by the aggregator.
 */
function aggregator_page_sources() {
  $result = db_query('SELECT f.fid, f.title, f.description, f.image, MAX(i.timestamp) AS last FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.description, f.image ORDER BY last DESC, f.title');

231 232
  $output = '';
  while ($feed = db_fetch_object($result)) {
233
    // Most recent items:
234
    $summary_items = array();
235 236 237
    if (variable_get('aggregator_summary_items', 3)) {
      $items = db_query_range('SELECT i.title, i.timestamp, i.link FROM {aggregator_item} i WHERE i.fid = %d ORDER BY i.timestamp DESC', $feed->fid, 0, variable_get('aggregator_summary_items', 3));
      while ($item = db_fetch_object($items)) {
238
        $summary_items[] = theme('aggregator_summary_item', $item);
239 240
      }
    }
241 242
    $feed->url = url('aggregator/sources/'. $feed->fid);
    $output .= theme('aggregator_summary_items', $summary_items, $feed);
243 244
  }
  $output .= theme('feed_icon', url('aggregator/opml'), t('OPML feed'));
245 246

  return theme('aggregator_wrapper', $output);
247 248 249 250 251 252 253 254
}

/**
 * Menu callback; displays all the categories used by the aggregator.
 */
function aggregator_page_categories() {
  $result = db_query('SELECT c.cid, c.title, c.description FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid LEFT JOIN {aggregator_item} i ON ci.iid = i.iid GROUP BY c.cid, c.title, c.description');

255
  $output = '';
256 257
  while ($category = db_fetch_object($result)) {
    if (variable_get('aggregator_summary_items', 3)) {
258
      $summary_items = array();
259 260
      $items = db_query_range('SELECT i.title, i.timestamp, i.link, f.title as feed_title, f.link as feed_link FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON i.iid = ci.iid LEFT JOIN {aggregator_feed} f ON i.fid = f.fid WHERE ci.cid = %d ORDER BY i.timestamp DESC', $category->cid, 0, variable_get('aggregator_summary_items', 3));
      while ($item = db_fetch_object($items)) {
261
        $summary_items[] = theme('aggregator_summary_item', $item);
262 263
      }
    }
264 265
    $category->url = url('aggregator/categories/'. $category->cid);
    $output .= theme('aggregator_summary_items', $summary_items, $category);
266 267
  }

268
  return theme('aggregator_wrapper', $output);
269 270 271 272 273 274 275
}

/**
 * Menu callback; generate an RSS 0.92 feed of aggregator items or categories.
 */
function aggregator_page_rss() {
  $result = NULL;
276
  // arg(2) is the passed cid, only select for that category
277 278 279 280 281 282 283
  if (arg(2)) {
    $category = db_fetch_object(db_query('SELECT cid, title FROM {aggregator_category} WHERE cid = %d', arg(2)));
    $sql = 'SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_category_item} c LEFT JOIN {aggregator_item} i ON c.iid = i.iid LEFT JOIN {aggregator_feed} f ON i.fid = f.fid WHERE cid = %d ORDER BY timestamp DESC, i.iid DESC';
    $result = db_query_range($sql, $category->cid, 0, variable_get('feed_default_items', 10));
  }
  // or, get the default aggregator items
  else {
284
    $category = NULL;
285 286 287
    $sql = 'SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_item} i INNER JOIN {aggregator_feed} f ON i.fid = f.fid ORDER BY i.timestamp DESC, i.iid DESC';
    $result = db_query_range($sql, 0, variable_get('feed_default_items', 10));
  }
288
  
289
  while ($item = db_fetch_object($result)) {
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
    $feeds[] = $item;
  }
  return theme('aggregator_page_rss', $feeds, $category);
}

/**
 * Theme the rss output.
 *
 * @ingroup themeable
 */
function theme_aggregator_page_rss($feeds, $category = NULL) {

  drupal_set_header('Content-Type: application/rss+xml; charset=utf-8');

  $title = '';
  $url = '';
  if (isset($category)) {
    $title = ' '. t('in category') .' '. check_plain($category->title);
    $url = '/categories/'. $category->cid;
  }

  $items = '';
  $feed_length = variable_get('feed_item_length', 'teaser');
  foreach ($feeds as $feed) {
    switch ($feed_length) {
315
      case 'teaser':
316 317 318
        $teaser = node_teaser($feed->description);
        if ($teaser != $feed->description) {
          $teaser .= '<p><a href="'. check_url($feed->link) .'">'. t('read more') ."</a></p>\n";
319
        }
320
        $feed->description = $teaser;
321 322
        break;
      case 'title':
323
        $feed->description = '';
324 325
        break;
    }
326
    $items .= format_rss_item($feed->ftitle .': '. $feed->title, $feed->link, $feed->description, array('pubDate' => date('r', $feed->timestamp)));
327 328
  }

329 330 331 332
  $site_name = variable_get('site_name', 'Drupal');
  $url = url('aggregator'. $url, array('absolute' => TRUE));

  $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
333
  $output .= "<rss version=\"2.0\">\n";
334
  $output .= format_rss_channel($site_name .' '. t('aggregator'), $url, $site_name .' - '. t('aggregated feeds') . $title, $items);
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
  $output .= "</rss>\n";

  print $output;
}

/**
 * Menu callback; generates an OPML representation of all feeds.
 */
function aggregator_page_opml($cid = NULL) {
  if ($cid) {
    $result = db_query('SELECT f.title, f.url FROM {aggregator_feed} f LEFT JOIN {aggregator_category_feed} c on f.fid = c.fid WHERE c.cid = %d ORDER BY title', $cid);
  }
  else {
    $result = db_query('SELECT * FROM {aggregator_feed} ORDER BY title');
  }
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
  
  while ($item = db_fetch_object($result)) {
    $feeds[] = $item;
  }
  
  return theme('aggregator_page_opml', $feeds);
}

/**
 * Theme the opml feed output.
 *
 * @ingroup themeable
 */
function theme_aggregator_page_opml($feeds) {

  drupal_set_header('Content-Type: text/xml; charset=utf-8');
366 367 368 369 370 371 372 373

  $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
  $output .= "<opml version=\"1.1\">\n";
  $output .= "<head>\n";
  $output .= '<title>'. check_plain(variable_get('site_name', 'Drupal')) ."</title>\n";
  $output .= '<dateModified>'. gmdate('r') ."</dateModified>\n";
  $output .= "</head>\n";
  $output .= "<body>\n";
374
  foreach ($feeds as $feed) {
375 376
    $output .= '<outline text="'. check_plain($feed->title) .'" xmlUrl="'. check_url($feed->url) ."\" />\n";
  }
377
  $output .= implode('', $content);
378 379 380 381 382 383 384
  $output .= "</body>\n";
  $output .= "</opml>\n";

  print $output;
}

/**
385
 * Process variables for aggregator-summary-items.tpl.php.
386
 *
387 388 389
 * The $variables array contains the following arguments:
 * - $summary_items
 * - $source
390
 *
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
 * @see aggregator-summary-item.tpl.php
 */
function template_preprocess_aggregator_summary_items(&$variables) {
  $variables['title'] = check_plain($variables['source']->title);
  $variables['summary_list'] = theme('item_list', $variables['summary_items']);
  $variables['source_url'] = $variables['source']->url;
}

/**
 * Process variables for aggregator-summary-item.tpl.php.
 *
 * The $variables array contains the following arguments:
 * - $item
 *
 * @see aggregator-summary-item.tpl.php
406
 */
407 408 409 410 411 412 413 414 415
function template_preprocess_aggregator_summary_item(&$variables) {
  $item = $variables['item'];

  $variables['feed_url'] = check_url($item->link);
  $variables['feed_title'] = check_plain($item->title);
  $variables['source_age'] = t('%age old', array('%age' => format_interval(time() - $item->timestamp)));

  $variables['source_url'] = '';
  $variables['source_title'] = '';
416
  if (!empty($item->feed_link)) {
417 418
    $variables['source_url'] = check_url($item->feed_link);
    $variables['source_title'] = check_plain($item->feed_title);
419 420 421 422
  }
}

/**
423
 * Process variables for aggregator-feed-source.tpl.php.
424
 *
425 426 427 428
 * The $variables array contains the following arguments:
 * - $feed
 *
 * @see aggregator-feed-source.tpl.php
429
 */
430 431 432 433 434 435 436
function template_preprocess_aggregator_feed_source(&$variables) {
  $feed = $variables['feed'];
  
  $variables['source_icon'] = theme('feed_icon', $feed->url, t('!title feed', array('!title' => $feed->title)));
  $variables['source_image'] = $feed->image;
  $variables['source_description'] = aggregator_filter_xss($feed->description);
  $variables['source_url'] = check_url(url($feed->link, array('absolute' => TRUE)));
437 438

  if ($feed->checked) {
439
    $variables['last_checked'] = t('@time ago', array('@time' => format_interval(time() - $feed->checked)));
440 441
  }
  else {
442
    $variables['last_checked'] = t('never');
443 444 445
  }

  if (user_access('administer news feeds')) {
446
    $variables['last_checked'] = l($variables['last_checked'], 'admin/content/aggregator');
447 448
  }
}