aggregator.module 31.4 KB
Newer Older
1
<?php
2
// $Id$
3

Dries's avatar
 
Dries committed
4
function import_help() {
Dries's avatar
 
Dries committed
5 6 7 8 9 10
  $output .= "<p>**REWRITE** In Drupal you have <i>feeds</i> and <i>bundles</i>.   Feeds define news sources and bundles categorize syndicated content by source, topic or any other heuristic.   Bundles provide a generalized way of creating composite feeds.  They allow you, for example, to combine various sport-related feeds into one bundle called \"Sport\".</p>";
  $output .= "<p>You can have several providers of news feeds.  You can add a feed by clicking the \"add feed\" link on the import administration pages.  Give the feed a name, supply the URI and a comma-separated list of attributes that you want to associate the feed with.  The update interval defines how often Drupal should go out to try and grab fresh content.  The expiration time defines how long syndicated content is kept in the database.  So set the update and expiration time and save your settings.  You have just defined your first feed.  If you have more feeds repeat as necessary.</p>";
  $output .= "<p>To verify whether your feed works, press \"update items\" at the overview page.  The number of news items that have been sucessfully fetched, should then become visible in the third column of the feed overview.</p>";
  $output .= "<p>Now you have to define some bundles.  Bundles look for feeds that contain one of the keywords associated with the bundle and display those feeds together.  To define a bundle you have to give it a name and a comma-separated list of keywords just like this is the case for feeds.</p>";
  $output .= "<p>Your newly created bundle will now show up in the list of blocks that you can see at the block related administration pages.  There you can customize where and when your bundles will be displayed.</p>";
  return t($output);
11 12
}

13
function import_system($field){
Kjartan's avatar
Kjartan committed
14
  $system["description"] = t("Used to aggregate syndicated content (RSS and RDF).");
Dries's avatar
 
Dries committed
15
  $system["admin_help"] = t("Drupal's news aggregator controls how many RSS/RDF items from a single source are displayed in a \"Block\", and on the page that goes with that block.");
16 17 18
  return $system[$field];
}

19
function import_settings() {
Dries's avatar
 
Dries committed
20
  $number = array(5 => 5, 10 => 10, 15 => 15, 20 => 20, 25 => 25, 30 => 30, 35 => 35, 40 => 40, 45 => 45, 50 => 50, 55 => 55, 60 => 60, 65 => 65, 70 => 70, 75 => 75, 80 => 80, 85 => 85, 90 => 90, 95 => 95, 100 => 100);
Dries's avatar
 
Dries committed
21 22
  $output .= form_select("Items per block", "import_block_limit", variable_get("import_block_limit", 15), $number, "The maximum number of news items displayed in one block.");
  $output .= form_select("Items per page", "import_page_limit", variable_get("import_page_limit", 75), $number, "The maximum number of news items displayed on one page.");
Dries's avatar
 
Dries committed
23

Dries's avatar
 
Dries committed
24 25 26
  return $output;
}

Dries's avatar
 
Dries committed
27
function import_perm() {
Dries's avatar
 
Dries committed
28
  return array("administer news feeds", "access news feeds");
Dries's avatar
 
Dries committed
29 30 31
}

function import_link($type) {
Dries's avatar
 
Dries committed
32

Dries's avatar
 
Dries committed
33 34
  $links = array();

Dries's avatar
 
Dries committed
35
  if ($type == "page" && user_access("access news feeds")) {
Dries's avatar
 
Dries committed
36
    $links[] = l(t("news feeds"), "import", array("title" => t("Read the latest news from syndicated web sites.")));
Dries's avatar
 
Dries committed
37 38
  }

Dries's avatar
 
Dries committed
39
  if ($type == "admin" && user_access("administer news feeds")) {
Dries's avatar
 
Dries committed
40 41 42 43 44
    $help["general"] = t("Several web sites, especially news related sites, syndicate parts of their site's content for other web sites to display. Usually, the syndicated content includes the latest headlines with a direct link to that story on the remote site. Some syndicated content also includes a description of the headline. The standard method of syndication is using the XML based Rich Site Summary (RSS). To get a feed to work you <b>must</b> run \"cron.php\". To display the feed in a block you must turn on the <a href=\"%block\">feed's block</a>. <br /><ul><li>To delete a feed choose \"edit feed\"</li><li>To clear all of the entries from a feed choose \"Remove items\"</li><li>To check whether a feed is working, and to get new items <b>now</b> click on \"update items\"</li></ul><ul><li>To delete a bundle choose \"edit bundle\".</li></ul>", array("%block" => url("admin/block")));
    $help["addfeed"] = t("Add a site to that has an RSS/RDF feed. The URL is the full path to the RSS feed file. For the feed to update you must run \"cron.php\". The \"Attributes\" are used to bundle this feed with other feeds (See <a href=\"%bundle\">add new bundle</a>, and to tag articles from this feed.<br />Note: If you already have another feed with the URL you are planning to use, the system will not accept your entry.", array("%bundle" => url("admin/syndication/news/add/bundle")));
    $help["bundles"] = t("Bundles provide a generalized way of creating composite feeds. They allow you, for example, to combine various sport-related feeds into one bundle called <i>Sport</i>. If an article from a feed has been \"tag\"-ged (See <a href=\"%tag\">tag news item</a> too look at and change tags.) with a matching \"Attribute\" then it will be added to the bundle.", array("%tag" => url("admin/syndication/news/tag")));
    $help["tag"] = t("This allows you to see and change an news item's \"tag\". All articles are originally tagged with the \"Attributes\" of their feed.");

Dries's avatar
 
Dries committed
45 46
    menu("admin/syndication", "content syndication", NULL, NULL, 5);
    menu("admin/syndication/news", "news aggregation", "import_admin", $help["general"]);
Dries's avatar
 
Dries committed
47
    menu("admin/syndication/news/add/feed", "add new feed", "import_admin", $help["addfeed"], 2);
48
    menu("admin/syndication/news/add/bundle", "add new bundle", "import_admin", $help["bundles"], 3);
Dries's avatar
 
Dries committed
49
    menu("admin/syndication/news/tag", "tag news items", "import_admin", $help["tag"], 4);
Dries's avatar
 
Dries committed
50
    menu("admin/syndication/news/help", "help", "import_help", NULL, 9);
Dries's avatar
 
Dries committed
51 52
  }

Dries's avatar
 
Dries committed
53
  return $links;
Dries's avatar
 
Dries committed
54 55
}

Dries's avatar
 
Dries committed
56
function import_cron() {
Dries's avatar
Dries committed
57
  $result = db_query("SELECT * FROM feed WHERE timestamp + refresh < ". time());
Dries's avatar
 
Dries committed
58 59 60 61 62 63
  while ($feed = db_fetch_array($result)) {
    import_refresh($feed);
  }
}

function import_update() {
64 65
  $result = db_query("SELECT * FROM feed");
  while ($feed = db_fetch_array($result)) {
Dries's avatar
 
Dries committed
66 67 68 69
    import_refresh($feed);
  }
}

Dries's avatar
 
Dries committed
70
function import_format_item($item, $feed = 0) {
Dries's avatar
 
Dries committed
71
  global $user;
Dries's avatar
 
Dries committed
72

Dries's avatar
 
Dries committed
73
  if ($user->uid && user_access("maintain personal blog")) {
Dries's avatar
 
Dries committed
74
//    $output .= "&nbsp;". l("<img src=\"". theme("image", "blog.gif") ."\" border=\"0\" width=\"12\" height=\"16\" alt=\"". t("Blog this item") ."\" />", "node/add/blog&amp;iid=$item->iid", array("title" => t("Comment on this news item in your personal blog.")));
Dries's avatar
 
Dries committed
75
    $output .= "<div class=\"icon\">(". l("b", "node/add/blog&amp;iid=$item->iid", array("title" => t("Comment on this news item in your personal blog."))) .")</div>";
Dries's avatar
 
Dries committed
76 77
  }

Dries's avatar
 
Dries committed
78
  // external link
Dries's avatar
 
Dries committed
79
  $output .= "<a href=\"$item->link\">$item->title</a>";
80

Dries's avatar
 
Dries committed
81
  return $output;
82 83
}

Dries's avatar
 
Dries committed
84 85
function import_bundle_block($attributes) {

86 87 88
  if ($attributes) {
    $keys = explode(",", $attributes);
    foreach ($keys as $key) $where[] = "attributes LIKE '%". trim($key) ."%'";
89

Dries's avatar
 
Dries committed
90
    $result = db_query_range("SELECT * FROM item WHERE ". implode(" OR ", $where) ." ORDER BY iid DESC", 0, variable_get("import_block_limit", 15));
Dries's avatar
 
Dries committed
91
  }
92

Dries's avatar
 
Dries committed
93
  $items = array();
Dries's avatar
 
Dries committed
94
  while ($item = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
95
    $items[] = import_format_item($item);
96
  }
Dries's avatar
 
Dries committed
97 98 99 100

  $output = "<div class=\"import-block\"><div class=\"bundle\">";
  $output .= theme("theme_item_list", $items);
  $output .= "</div></div>";
Dries's avatar
 
Dries committed
101 102

  return $output;
103 104
}

Dries's avatar
 
Dries committed
105
function import_feed_block($feed) {
Dries's avatar
 
Dries committed
106
  $result = db_query_range("SELECT * FROM item WHERE fid = %d ORDER BY iid DESC ", $feed->fid, 0, variable_get("import_block_limit", 15));
Dries's avatar
 
Dries committed
107 108

  $items = array();
Dries's avatar
 
Dries committed
109
  while ($item = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
110
    $items[] = import_format_item($item);
Dries's avatar
 
Dries committed
111
  }
Dries's avatar
 
Dries committed
112 113 114 115

  $output = "<div class=\"import-block\"><div class=\"feed\">";
  $output .= theme("theme_item_list", $items);
  $output .= "</div></div>";
Dries's avatar
 
Dries committed
116

Dries's avatar
 
Dries committed
117 118 119
  return $output;
}

Dries's avatar
 
Dries committed
120 121 122 123
function import_block($op, $delta) {
  if ($op == "list") {
    $result = db_query("SELECT * FROM bundle ORDER BY title");
    while ($bundle = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
124
      $block["bundle:$bundle->bid"]["info"] = "$bundle->title bundle";
Dries's avatar
 
Dries committed
125 126 127 128
    }

    $result = db_query("SELECT * FROM feed ORDER BY fid");
    while ($feed = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
129
      $block["feed:$feed->fid"]["info"] = "$feed->title feed";
Dries's avatar
 
Dries committed
130 131 132 133 134
    }

    return $block;
  }
  else {
Dries's avatar
 
Dries committed
135 136 137
    list($type, $id) = split(":", $delta);
    switch ($type) {
      case "feed":
Dries's avatar
 
Dries committed
138
        $feed = db_fetch_object(db_query("SELECT * FROM feed WHERE fid = %d", $id));
Dries's avatar
 
Dries committed
139 140 141 142 143
        $block["subject"] = $feed->title;
        $block["content"] .= import_feed_block($feed) ."<div align=\"right\">".  l(t("more"), "import/feed/$feed->fid", array("title" => t("View this feed's recent news."))) ."</div>";
        break;

      case "bundle":
Dries's avatar
 
Dries committed
144
        $bundle = db_fetch_object(db_query("SELECT * FROM bundle WHERE bid = %d", $id));
Dries's avatar
 
Dries committed
145 146 147
        $block["subject"] = $bundle->title;
        $block["content"] .= import_bundle_block($bundle->attributes) ."<div align=\"right\">". l(t("more"), "import/bundle/$bundle->bid", array("title" => t("View this bundle's recent news."))) ."</div>";
        break;
Dries's avatar
 
Dries committed
148 149 150 151
    }

    return $block;
  }
Dries's avatar
 
Dries committed
152 153
}

Dries's avatar
 
Dries committed
154
function import_get_bundles($attributes = 0) {
Dries's avatar
 
Dries committed
155

Dries's avatar
 
Dries committed
156 157 158
  $block = array();

  $result = db_query("SELECT * FROM bundle ORDER BY title");
Dries's avatar
 
Dries committed
159
  while ($bundle = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
160 161 162 163 164
    $block["bundle:$bundle->bid"]["subject"] = $bundle->title;
    $block["bundle:$bundle->bid"]["content"] = import_bundle_block($bundle->attributes) ."<div align=\"right\">".
                                                l(t("more"), "import/bundle/$bundle->bid", array("title" => t("View this bundle's recent news.")))
                                                ."</div>";
    $block["bundle:$bundle->bid"]["info"] = "$bundle->title bundle";
Dries's avatar
 
Dries committed
165
  }
Dries's avatar
 
Dries committed
166

Dries's avatar
 
Dries committed
167
  return $block;
Dries's avatar
 
Dries committed
168 169
}

Dries's avatar
 
Dries committed
170
function import_get_feeds($attributes = 0) {
Dries's avatar
 
Dries committed
171

Dries's avatar
 
Dries committed
172 173 174
  $block = array();

  $result = db_query("SELECT * FROM feed ORDER BY fid");
Dries's avatar
 
Dries committed
175
  while ($feed = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
176 177 178 179 180
    $block["feed:$feed->fid"]["subject"] = $feed->title;
    $block["feed:$feed->fid"]["content"] = import_feed_block($feed) ."<div align=\"right\">".
                                            l(t("more"), "import/feed/$feed->fid", array("title" => t("View this feed's recent news.")))
                                            ."</div>";
    $block["feed:$feed->fid"]["info"] = "$feed->title feed";
Dries's avatar
 
Dries committed
181 182
  }

Dries's avatar
 
Dries committed
183
  return $block;
Dries's avatar
 
Dries committed
184 185
}

Dries's avatar
 
Dries committed
186
function import_remove($feed) {
Dries's avatar
 
Dries committed
187
  db_query("DELETE FROM item WHERE fid = %d", $feed["fid"]);
188
  return t("removed news items from '%site'.", array("%site" => $feed["title"]));
Dries's avatar
 
Dries committed
189 190
}

191 192
// Call-back function used by XML parser:
function import_element_start($parser, $name, $attributes) {
Dries's avatar
 
Dries committed
193 194 195 196 197 198 199 200 201 202
  global $item, $element, $tag;

  switch ($name) {
    case "IMAGE":
    case "TEXTINPUT":
      $element = $name;
      break;
    case "ITEM":
      $element = $name;
      $item += 1;
203 204 205 206 207 208 209
  }

  $tag = $name;
}

// Call-back function used by XML parser:
function import_element_end($parser, $name) {
Dries's avatar
 
Dries committed
210 211 212 213 214 215 216 217
  global $element;

   switch ($name) {
    case "IMAGE":
    case "TEXTINPUT":
    case "ITEM":
      $element = "";
  }
218 219 220 221
}

// Call-back function used by XML parser:
function import_element_data($parser, $data) {
Dries's avatar
 
Dries committed
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
  global $channel, $element, $items, $item, $tag;

  switch ($element) {
    case "ITEM":
      $items[$item][$tag] .= $data;
      break;
    case "IMAGE":
    case "TEXTINPUT":
      /*
      ** The sub-elements "image" and "textinput" are not supported
      ** but we have recognize them or their content will end up in
      ** the items-array.
      */
      break;
    default:
      $channel[$tag] .= $data;
238 239 240
  }
}

Dries's avatar
 
Dries committed
241
function import_refresh($feed) {
242

Dries's avatar
Dries committed
243 244 245 246
  // unset the global variables before we use them:
  unset($GLOBALS["channel"], $GLOBALS["element"], $GLOBALS["item"], $GLOBALS["items"], $GLOBALS["tag"]);

  // after we unset the variables, we can global them again:
247 248
  global $items, $channel;

Dries's avatar
 
Dries committed
249 250 251 252
  /*
  ** Check whether the feed is properly configured:
  */

Dries's avatar
 
Dries committed
253
  if (!ereg("^http://|ftp://", $feed["url"])) {
254
    return t("failed to parse RSS feed '%site': incorrect or missing URL.", array("%side" => $feed["title"]));
Dries's avatar
 
Dries committed
255 256 257
  }

  /*
Dries's avatar
 
Dries committed
258
  ** Grab the news items:
Dries's avatar
 
Dries committed
259 260
  */

Dries's avatar
 
Dries committed
261
  if ($fp = @fopen($feed["url"], "r")) {
262
    // fetch data:
Dries's avatar
 
Dries committed
263 264 265
    while (!feof($fp)) {
      $data .= fgets($fp, 128);
    }
Dries's avatar
Dries committed
266
    fclose($fp);
Dries's avatar
 
Dries committed
267

Dries's avatar
 
Dries committed
268
    // parse the data:
269 270 271 272 273 274 275 276
    $xml_parser = xml_parser_create();
    xml_set_element_handler($xml_parser, "import_element_start", "import_element_end");
    xml_set_character_data_handler($xml_parser, "import_element_data");
    if (!xml_parse($xml_parser, $data, 1)) {
      return t("failed to parse RSS feed '%site': %error at line %line.", array("%site" => $feed["title"], "%error" => xml_error_string(xml_get_error_code($xml_parser)), "%line" => xml_get_current_line_number($xml_parser)));
    }
    xml_parser_free($xml_parser);

Dries's avatar
 
Dries committed
277 278 279 280
    // initialize the translation table:
    $tt = array_flip(get_html_translation_table(HTML_ENTITIES));
    $tt["&apos;"] = "'";

Dries's avatar
 
Dries committed
281 282 283 284
    /*
    ** Strip invalid tags and provide default values (if required):
    */

Dries's avatar
 
Dries committed
285
    foreach ($channel as $key => $value) {
286
      $channel[$key] = node_filter(strtr(trim($value), $tt));
Dries's avatar
 
Dries committed
287
    }
Dries's avatar
 
Dries committed
288

Dries's avatar
 
Dries committed
289
    db_query("UPDATE feed SET timestamp = %d, link = '%s', description = '%s' WHERE fid = %d", time(), $channel["LINK"], $channel["DESCRIPTION"], $feed["fid"]);
Dries's avatar
 
Dries committed
290

Dries's avatar
 
Dries committed
291
    /*
292 293 294
    ** We reverse the array such that we store the first item last,
    ** and the last item first.  In the database, the newest item
    ** should be at the top.
Dries's avatar
 
Dries committed
295
    */
Dries's avatar
 
Dries committed
296

297
    $items = array_reverse($items);
Dries's avatar
 
Dries committed
298

Dries's avatar
 
Dries committed
299 300
    foreach ($items as $item) {
      unset($title, $link, $author, $description);
Dries's avatar
 
Dries committed
301

Dries's avatar
 
Dries committed
302 303
      // Prepare the item:
      foreach ($item as $key => $value) {
304
        $item[$key] = node_filter(strtr(trim($value), $tt));
Dries's avatar
 
Dries committed
305
      }
306

307
      if ($item["TITLE"]) {
Dries's avatar
 
Dries committed
308
        $title = $item["TITLE"];
309 310
      }
      else {
Dries's avatar
 
Dries committed
311
        /*
Dries's avatar
 
Dries committed
312
         ** Use up to 40 characters of the description, ending at
313 314
         ** word boundary, but don't split potential entities.
         */
Dries's avatar
 
Dries committed
315
        $title = preg_replace('/^(.*)[^\w;&].*?$/', "\\1", substr($item["DESCRIPTION"], 0, 40));
316
      }
Dries's avatar
 
Dries committed
317

318
      if ($item["LINK"]) {
Dries's avatar
 
Dries committed
319
        $link = $item["LINK"];
320 321
      }
      elseif ($item["GUID"] && (strncmp($item["GUID"], "http://", 7) == 0)) {
Dries's avatar
 
Dries committed
322
        $link = $item["GUID"];
323 324 325 326
      }
      else {
        $link = $feed["link"];
      }
Dries's avatar
Dries committed
327

328
      /*
Dries's avatar
 
Dries committed
329 330 331 332
      ** Save this item.  Try to avoid duplicate entries as much as
      ** possible.  If we find a duplicate entry, we resolve it and
      ** pass along it's ID such that we can update it if needed.
      */
Dries's avatar
 
Dries committed
333

334
      if ($link && $link != $feed["link"] && $link != $feed["url"]) {
Dries's avatar
 
Dries committed
335
        $entry = db_fetch_object(db_query("SELECT iid FROM item WHERE fid = %d AND link = '%s'", $feed["fid"], $link));
336 337
      }
      else {
Dries's avatar
 
Dries committed
338
        $entry = db_fetch_object(db_query("SELECT iid FROM item WHERE fid = %d AND title = '%s'", $feed["fid"], $title));
339
      }
340

Dries's avatar
 
Dries committed
341
      import_save_item(array(iid => $entry->iid, fid => $feed["fid"], title => $title, link => $link, author => $item["AUTHOR"], description => $item["DESCRIPTION"], attributes => $feed["attributes"]));
342
    }
Dries's avatar
 
Dries committed
343 344

    /*
Dries's avatar
 
Dries committed
345
    ** Remove all the old, expired items:
Dries's avatar
 
Dries committed
346 347 348 349
    */

    unset($items);

Dries's avatar
 
Dries committed
350
    $result = db_query("SELECT iid FROM item WHERE fid = %d ORDER BY timestamp", $feed["fid"]);
Dries's avatar
 
Dries committed
351 352 353 354 355

    while ($item = db_fetch_object($result)) {
      $items[] = "iid = '$item->iid'";
    }

Dries's avatar
 
Dries committed
356
    if (sizeof($items) > 50) {
Dries's avatar
 
Dries committed
357 358 359
      db_query("DELETE FROM item WHERE ". implode(" OR ", array_slice($items, 0, - 50)));
    }

Dries's avatar
 
Dries committed
360 361
  }
  else {
362
    return t("failed to parse RSS feed '%site': no data.", array("%site" => $feed["tite"]));
363
  }
Dries's avatar
 
Dries committed
364

365
  return t("syndicated content from '%site'.", array("%site" => $feed["title"]));
366 367
}

Dries's avatar
 
Dries committed
368
function import_save_item($edit) {
Dries's avatar
 
Dries committed
369
  if ($edit["iid"] && $edit["title"]) {
Dries's avatar
 
Dries committed
370
    db_query("UPDATE item SET title = '%s', link = '%s', author = '%s', description = '%s', attributes = '%s' WHERE iid = %d", $edit["title"], $edit["link"], $edit["author"], $edit["description"], $edit["attributes"], $edit["iid"]);
371
  }
Dries's avatar
 
Dries committed
372
  else if ($edit["iid"]) {
Dries's avatar
 
Dries committed
373
    db_query("DELETE FROM item WHERE iid = %d", $edit["iid"]);
374
  }
Dries's avatar
 
Dries committed
375
  else if ($edit["title"] && $edit["link"]) {
Dries's avatar
 
Dries committed
376
    db_query("INSERT INTO item (fid, title, link, author, description, attributes, timestamp) VALUES (%d, '%s', '%s', '%s', '%s', '%s', %d)", $edit["fid"], $edit["title"], $edit["link"], $edit["author"], $edit["description"], $edit["attributes"], time());
377 378 379
  }
}

Dries's avatar
 
Dries committed
380
function import_form_bundle($edit = array()) {
381

Dries's avatar
 
Dries committed
382
  $form .= form_textfield("Title", "title", $edit["title"], 50, 64, "The name of the bundle.");
Dries's avatar
 
Dries committed
383
  $form .= form_textfield("Attributes", "attributes", $edit["attributes"], 50, 128, "A comma-separated list of keywords describing the bundle.");
384 385 386

  $form .= form_submit("Submit");

Dries's avatar
 
Dries committed
387
  if ($edit["bid"]) {
Dries's avatar
 
Dries committed
388
    $form .= form_submit("Delete");
Dries's avatar
 
Dries committed
389
    $form .= form_hidden("bid", $edit["bid"]);
390 391
  }

Dries's avatar
 
Dries committed
392
  return form($form);
393 394
}

Dries's avatar
 
Dries committed
395
function import_save_bundle($edit) {
Dries's avatar
 
Dries committed
396
  if ($edit["bid"] && $edit["title"]) {
Dries's avatar
 
Dries committed
397
    db_query("UPDATE bundle SET title = '%s', attributes = '%s' WHERE bid = %d", $edit["title"], $edit["attributes"], $edit["bid"]);
398
  }
Dries's avatar
 
Dries committed
399
  else if ($edit["bid"]) {
Dries's avatar
 
Dries committed
400
    db_query("DELETE FROM bundle WHERE bid = %d", $edit["bid"]);
401
  }
Dries's avatar
 
Dries committed
402
  else if ($edit["title"]) {
Dries's avatar
 
Dries committed
403
    // a single unique id for bundles and feeds, to use in blocks
Dries's avatar
 
Dries committed
404 405
    $next_id = db_next_id("bundle_bid");
    db_query("INSERT INTO bundle (bid, title, attributes) VALUES (%d, '%s', '%s')", $next_id, $edit["title"], $edit["attributes"]);
406 407 408
  }
}

Dries's avatar
 
Dries committed
409
function import_form_feed($edit = array()) {
410 411 412

  $period = array(900 => format_interval(900), 1800 => format_interval(1800), 3600 => format_interval(3600), 7200 => format_interval(7200), 10800 => format_interval(10800), 21600 => format_interval(21600), 32400 => format_interval(32400), 43200 => format_interval(43200), 64800 => format_interval(64800), 86400 => format_interval(86400), 172800 => format_interval(172800), 259200 => format_interval(259200), 604800 => format_interval(604800), 1209600 => format_interval(1209600), 2419200 => format_interval(2419200));

Dries's avatar
 
Dries committed
413 414 415
  if ($edit["refresh"] == "") {
    $edit["refresh"] = 3600;
  }
Dries's avatar
 
Dries committed
416

Dries's avatar
 
Dries committed
417
  $form .= form_textfield("Title", "title", $edit["title"], 50, 64, "The name of the feed; typically the name of the web site you syndicate content from.");
Dries's avatar
 
Dries committed
418
  $form .= form_textfield("Url", "url", $edit["url"], 50, 128, "The fully-qualified URL of the feed.");
Dries's avatar
 
Dries committed
419
  $form .= form_textfield("Attributes", "attributes", $edit["attributes"], 50, 128, "A comma-separated list of keywords describing the feed.");
Dries's avatar
 
Dries committed
420
  $form .= form_select("Update interval", "refresh", $edit["refresh"], $period, "The refresh interval indicating how often you want to update this feed.  Requires crontab.");
421 422 423

  $form .= form_submit("Submit");

Dries's avatar
 
Dries committed
424
  if ($edit["fid"]) {
Dries's avatar
 
Dries committed
425
    $form .= form_submit("Delete");
Dries's avatar
 
Dries committed
426
    $form .= form_hidden("fid", $edit["fid"]);
427 428
  }

Dries's avatar
 
Dries committed
429
  return form($form);
430 431
}

Dries's avatar
 
Dries committed
432
function import_save_feed($edit) {
Dries's avatar
 
Dries committed
433
  if ($edit["fid"] && $edit["title"]) {
Dries's avatar
 
Dries committed
434
    db_query("UPDATE feed SET title = '%s', url = '%s', attributes = '%s', refresh = %d WHERE fid = %d", $edit["title"], $edit["url"], $edit["attributes"], $edit["refresh"], $edit["fid"]);
Dries's avatar
 
Dries committed
435
    db_query("DELETE FROM item WHERE fid = %d", $edit["fid"]);
436
  }
Dries's avatar
 
Dries committed
437
  else if ($edit["fid"]) {
Dries's avatar
 
Dries committed
438 439
    db_query("DELETE FROM feed WHERE fid = %d", $edit["fid"]);
    db_query("DELETE FROM item WHERE fid = %d", $edit["fid"]);
440
  }
Dries's avatar
 
Dries committed
441
  else if ($edit["title"]) {
Dries's avatar
 
Dries committed
442
    // a single unique id for bundles and feeds, to use in blocks
Dries's avatar
 
Dries committed
443
    $next_id = db_next_id("feed_fid");
Dries's avatar
 
Dries committed
444
    db_query("INSERT INTO feed (fid, title, url, attributes, refresh) VALUES (%d, '%s', '%s', '%s', %d)", $next_id, $edit["title"], $edit["url"], $edit["attributes"], $edit["refresh"]);
445 446 447
  }
}

Dries's avatar
 
Dries committed
448
function import_save_attributes($edit) {
Dries's avatar
 
Dries committed
449
  foreach ($edit as $iid => $value) {
Dries's avatar
 
Dries committed
450
    db_query("UPDATE item SET attributes = '%s' WHERE iid = %d", $value, $iid);
451 452 453 454
  }
  return "attributes has been saved";
}

Dries's avatar
 
Dries committed
455
function import_get_feed($fid) {
Dries's avatar
 
Dries committed
456
  return db_fetch_array(db_query("SELECT * FROM feed WHERE fid = %d", $fid));
457 458
}

Dries's avatar
 
Dries committed
459
function import_get_bundle($bid) {
Dries's avatar
 
Dries committed
460
  return db_fetch_array(db_query("SELECT * FROM bundle WHERE bid = %d", $bid));
461 462
}

Dries's avatar
 
Dries committed
463
function import_view() {
Dries's avatar
 
Dries committed
464
  $result = db_query("SELECT f.*, COUNT(i.iid) AS items FROM feed f LEFT JOIN item i ON f.fid = i.fid GROUP BY f.fid, f.title, f.url, f.refresh, f.timestamp, f.attributes, f.link, f.description ORDER BY f.title");
465

Dries's avatar
 
Dries committed
466
  $output .= "<h3>Feed overview</h3>";
Dries's avatar
 
Dries committed
467 468 469

  $header = array(t("title"), t("attributes"), t("items"), t("last update"), t("next update"), array("data" => t("operations"), "colspan" => 3));
  unset($rows);
470
  while ($feed = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
471
    $rows[] = array($feed->title, $feed->attributes, format_plural($feed->items, "1 item", "%count items"), ($feed->timestamp ? format_interval(time() - $feed->timestamp) ." ago" : "never"), ($feed->timestamp ? format_interval($feed->timestamp + $feed->refresh - time()) ." left" : "never"), l(t("edit feed"), "admin/syndication/news/edit/feed/$feed->fid"), l(t("remove items"), "admin/syndication/news/remove/$feed->fid"), l(t("update items"), "admin/syndication/news/update/$feed->fid"));
472
  }
Dries's avatar
 
Dries committed
473
  $output .= table($header, $rows);
474 475 476

  $result = db_query("SELECT * FROM bundle ORDER BY title");

Dries's avatar
 
Dries committed
477
  $output .= "<h3>Bundle overview</h3>";
Dries's avatar
 
Dries committed
478 479 480

  $header = array(t("title"), t("attributes"), t("operations"));
  unset($rows);
481
  while ($bundle = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
482
    $rows[] = array($bundle->title, $bundle->attributes, l(t("edit bundle"), "admin/syndication/news/edit/bundle/$bundle->bid"));
483
  }
Dries's avatar
 
Dries committed
484
  $output .= table($header, $rows);
485 486 487 488

  return $output;
}

Dries's avatar
 
Dries committed
489
function import_tag() {
490

Dries's avatar
 
Dries committed
491
  $result = db_query_range("SELECT i.*, f.title AS feed FROM item i LEFT JOIN feed f ON i.fid = f.fid ORDER BY i.iid DESC", 0, 50);
492

Dries's avatar
 
Dries committed
493
  $header = array(t("date"), t("feed"), t("news item"));
494
  while ($item = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
495
    $rows[] = array(array("data" => format_date($item->timestamp, "small"), "nowrap" => "nowrap", "valign" => "top"), array("data" => l($item->feed, "admin/syndication/news/edit/feed/$item->fid"), "valign" => "top"), "<a href=\"$item->link\">$item->title</a>". ($item->description ? "<br /><small><i>$item->description</i></small>" : "") ."<br /><input type=\"text\" name=\"edit[$item->iid]\" value=\"". check_form($item->attributes) ."\" size=\"50\" />");
496
  }
Dries's avatar
 
Dries committed
497 498

  $output .= table($header, $rows);
Dries's avatar
 
Dries committed
499
  $output .= "<input type=\"submit\" name=\"op\" value=\"Save attributes\" />\n";
500

Dries's avatar
 
Dries committed
501
  return form($output);
502 503
}

Dries's avatar
 
Dries committed
504
function import_admin() {
Dries's avatar
 
Dries committed
505 506
  $op = $_POST["op"];
  $edit = $_POST["edit"];
Dries's avatar
 
Dries committed
507

Dries's avatar
 
Dries committed
508
  if (user_access("administer news feeds")) {
Dries's avatar
 
Dries committed
509

Dries's avatar
 
Dries committed
510
    if (empty($op)) {
Dries's avatar
 
Dries committed
511
      $op = arg(3);
Dries's avatar
 
Dries committed
512 513
    }

Dries's avatar
 
Dries committed
514
    switch ($op) {
515 516 517 518 519 520 521
      case "add":
        if (arg(4) == "bundle") {
          print import_form_bundle();
        }
        else {
          print import_form_feed();
        }
Dries's avatar
 
Dries committed
522
        break;
Dries's avatar
 
Dries committed
523
      case "edit":
Dries's avatar
 
Dries committed
524 525
        if (arg(4) == "bundle") {
          print import_form_bundle(import_get_bundle(arg(5)));
Dries's avatar
 
Dries committed
526 527
        }
        else {
Dries's avatar
 
Dries committed
528
          print import_form_feed(import_get_feed(arg(5)));
Dries's avatar
 
Dries committed
529
        }
Dries's avatar
 
Dries committed
530 531
        break;
      case "remove":
Dries's avatar
 
Dries committed
532
        print status(import_remove(import_get_feed(arg(4))));
Dries's avatar
 
Dries committed
533
        print import_view();
Dries's avatar
 
Dries committed
534 535
        break;
      case "update":
Dries's avatar
 
Dries committed
536
        print status(import_refresh(import_get_feed(arg(4))));
Dries's avatar
 
Dries committed
537
        print import_view();
Dries's avatar
 
Dries committed
538
        break;
Dries's avatar
 
Dries committed
539 540 541
      case "tag":
        print import_tag();
        break;
Dries's avatar
 
Dries committed
542 543
      case "Save attributes":
        print status(import_save_attributes($edit));
Dries's avatar
 
Dries committed
544
        print import_tag();
Dries's avatar
 
Dries committed
545 546
        break;
      case "Delete":
Dries's avatar
 
Dries committed
547
        $edit["title"] = 0;
Dries's avatar
 
Dries committed
548 549
        // fall through:
      case "Submit":
550
        if (arg(4) == "bundle") {
Dries's avatar
 
Dries committed
551
          print status(import_save_bundle($edit));
Dries's avatar
 
Dries committed
552 553
        }
        else {
Dries's avatar
 
Dries committed
554
          print status(import_save_feed($edit));
Dries's avatar
 
Dries committed
555
        }
Dries's avatar
 
Dries committed
556 557
        // fall through:
      default:
Dries's avatar
 
Dries committed
558
        print import_view();
Dries's avatar
 
Dries committed
559 560 561 562
    }
  }
  else {
    print message_access();
563 564 565
  }
}

Dries's avatar
 
Dries committed
566
function import_page_info() {
Dries's avatar
 
Dries committed
567

Dries's avatar
 
Dries committed
568

Dries's avatar
 
Dries committed
569
  $links[] = l(t("latest news"), "import", array("title" => t("Read the latest news from syndicated web sites.")));
Dries's avatar
 
Dries committed
570 571
  $links[] = l(t("news by source"), "import/feeds", array("title" => t("View the latest headlines sorted by source.")));
  $links[] = l(t("news by topic"), "import/bundles", array("title" => t("View the latest headlines sorted by topic.")));
Dries's avatar
 
Dries committed
572
  $links[] = l(t("news sources"), "import/sources", array("title" => t("View a list of all the web sites we syndicate from.")));
Dries's avatar
 
Dries committed
573

574
  if (user_access("administer news feeds")) {
Dries's avatar
 
Dries committed
575
    $links[] = l(t("administer news feeds"), "admin/syndication/news", array("title" => t("View the news feed administrative pages.")));
576
  }
Dries's avatar
 
Dries committed
577

Dries's avatar
 
Dries committed
578
  return "<div align=\"center\">". theme("links", $links) ."</div>";
Dries's avatar
 
Dries committed
579 580
}

Dries's avatar
 
Dries committed
581
function import_page_last() {
Dries's avatar
 
Dries committed
582

Dries's avatar
 
Dries committed
583

Dries's avatar
 
Dries committed
584
  $result = db_query_range("SELECT i.*, f.title AS ftitle, f.link AS flink FROM item i LEFT JOIN feed f ON i.fid = f.fid ORDER BY i.iid DESC", 0, variable_get("import_page_limit", 75));
Dries's avatar
 
Dries committed
585 586

  $output .= "<table border=\"0\" cellpadding=\"4\" cellspacing=\"2\">";
Dries's avatar
 
Dries committed
587
  while ($item = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
588
    if (module_exist("blog") && user_access("maintain personal blog")) {
589
      $links[] = l(t("blog it"), "node/add/blog", array("title" => t("Comment on this news item in your personal blog.")), "iid=$item->iid");
590
    }
Dries's avatar
 
Dries committed
591
    $links[] = l(t("feed"), "import/feed/$item->fid", array("title" => t("Read more syndicated news from this feed.")));
Dries's avatar
 
Dries committed
592 593

    if ($item->link) {
Dries's avatar
 
Dries committed
594
      $output .= "<tr><td><a href=\"$item->link\">$item->title</a> &middot; ". l($item->ftitle, "import/feed/$item->fid", array("title" => t("View more information about this feed."))) ."</td><td align=\"right\" nowrap=\"nowrap\" valign=\"top\">". theme("links", $links) ."</td></tr>\n";
Dries's avatar
 
Dries committed
595
    }
Dries's avatar
 
Dries committed
596

Dries's avatar
 
Dries committed
597
    if ($item->description) {
Dries's avatar
 
Dries committed
598
      $output .= "<tr><td colspan=\"2\"><div style=\"margin-left: 20px;\">$item->description</div><br /></td></tr>";
Dries's avatar
 
Dries committed
599 600 601
    }

    unset($links);
Dries's avatar
 
Dries committed
602
  }
Dries's avatar
 
Dries committed
603
  $output .= "</table>\n";
Dries's avatar
 
Dries committed
604

Dries's avatar
 
Dries committed
605 606 607 608
  theme("header");
  theme("box", t("News feeds"), import_page_info());
  theme("box", t("Latest news"), $output);
  theme("footer");
Dries's avatar
 
Dries committed
609 610 611
}

function import_page_feed($fid) {
Dries's avatar
 
Dries committed
612

Dries's avatar
 
Dries committed
613

Dries's avatar
 
Dries committed
614
  $feed = db_fetch_object(db_query("SELECT * FROM feed WHERE fid = %d", $fid));
Dries's avatar
 
Dries committed
615

Kjartan's avatar
Kjartan committed
616
  $header .= "<p><b>". t("Website") .":</b><div style=\"margin-left: 20px;\"><a href=\"$feed->link\">$feed->link</a></div></p>";
Dries's avatar
 
Dries committed
617
  $header .= "<p><b>". t("Description") .":</b><div style=\"margin-left: 20px;\">$feed->description</div></p>";
Dries's avatar
 
Dries committed
618
  $header .= "<p><b>". t("Last update") .":</b><div style=\"margin-left: 20px;\">". format_interval(time() - $feed->timestamp) ." ". t("ago") ." <a href=\"$feed->url\"><img src=\"". theme("image", "xml.gif") ."\" width=\"36\" height=\"14\" align=\"right\" border=\"0\" alt=\"\" /></a><br /><br /></div></p>\n";
Dries's avatar
 
Dries committed
619

Dries's avatar
 
Dries committed
620
  $result = db_query_range("SELECT * FROM item WHERE fid = %d ORDER BY iid DESC", $fid, 0, variable_get("import_page_limit", 75));
Dries's avatar
 
Dries committed
621 622

  $output .= "<table border=\"0\" cellpadding=\"4\" cellspacing=\"2\">";
Dries's avatar
 
Dries committed
623
  while ($item = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
624
    if (module_exist("blog") && user_access("maintain personal blog")) {
625
      $links[] = l(t("blog it"), "node/add/blog", array("title" => t("Comment on this news item in your personal blog.")), "iid=$item->iid");
626
    }
Dries's avatar
 
Dries committed
627
    $links[] = "<a href=\"$item->link\">". t("visit") ."</a>";
Dries's avatar
 
Dries committed
628

Dries's avatar
 
Dries committed
629
    if ($item->link) {
Dries's avatar
 
Dries committed
630
      $output .= "<tr><td><a href=\"$item->link\">$item->title</a></td><td align=\"right\" nowrap=\"nowrap\" valign=\"top\">". theme("links", $links) ."</td></tr>\n";
Dries's avatar
 
Dries committed
631 632
    }
    if ($item->description) {
Dries's avatar
 
Dries committed
633
      $output .= "<tr><td colspan=\"2\"><div style=\"margin-left: 20px;\">$item->description</div><br /></td></tr>";
Dries's avatar
 
Dries committed
634 635 636 637 638
    }

    unset($links);
  }
  $output .= "</table>\n";
Dries's avatar
 
Dries committed
639

Dries's avatar
 
Dries committed
640 641 642 643 644
  theme("header");
  theme("box", t("News feeds"), import_page_info());
  theme("box", $feed->title, $header);
  theme("box", t("Latest news"), $output);
  theme("footer");
Dries's avatar
 
Dries committed
645 646 647
}

function import_page_bundle($bid) {
Dries's avatar
 
Dries committed
648

Dries's avatar
 
Dries committed
649

Dries's avatar
 
Dries committed
650
  $bundle = db_fetch_object(db_query("SELECT * FROM bundle WHERE bid = %d", $bid));
Dries's avatar
 
Dries committed
651

Dries's avatar
 
Dries committed
652
  $header .= "<p><b>". t("Website") .":</b><div style=\"margin-left: 20px;\">". l($bundle->title, "import/bundle/$bundle->bid") ."</div></p>";
Dries's avatar
 
Dries committed
653
  $header .= "<p><b>". t("Description") .":</b><div style=\"margin-left: 20px;\">". t("A composite news feed about") ." $bundle->attributes.</div></p>";
Dries's avatar
 
Dries committed
654 655 656

  $keys = explode(",", $bundle->attributes);
  foreach ($keys as $key) $where[] = "i.attributes LIKE '%". trim($key) ."%'";
Dries's avatar
 
Dries committed
657
  $result = db_query_range("SELECT i.*, f.title AS ftitle, f.link AS flink FROM item i, feed f WHERE (". implode(" OR ", $where) .") AND i.fid = f.fid ORDER BY iid DESC", 0, variable_get("import_page_limit", 75));
Dries's avatar
 
Dries committed
658

Dries's avatar
 
Dries committed
659
  $output .= "<table border=\"0\" cellpadding=\"4\" cellspacing=\"2\">";
Dries's avatar
 
Dries committed
660
  while ($item = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
661
    if (module_exist("blog") && user_access("maintain personal blog")) {
662
      $links[] = l(t("blog it"), "node/add/blog", array("title" => t("Comment on this news item in your personal blog.")), "iid=$item->iid");
663
    }
Dries's avatar
 
Dries committed
664
    $links[] = l(t("feed"), "import/feed/$item->fid", array("title" => t("Read more syndicated news from this feed.")));
Dries's avatar
 
Dries committed
665 666 667
    $links[] = "<a href=\"$item->link\">". t("visit") ."</a>";

    if ($item->link) {
Dries's avatar
 
Dries committed
668
      $output .= "<tr><td><a href=\"$item->link\">$item->title</a> &middot; ". l($item->ftitle, "import/feed/$item->fid", array("title" => t("View more information about this feed."))) ."</td><td align=\"right\" nowrap=\"nowrap\" valign=\"top\">". theme("links", $links) ."</td></tr>\n";
Dries's avatar
 
Dries committed
669
    }
Dries's avatar
 
Dries committed
670

Dries's avatar
 
Dries committed
671
    if ($item->description) {
Dries's avatar
 
Dries committed
672
      $output .= "<tr><td colspan=\"2\"><div style=\"margin-left: 20px;\">$item->description</div><br /></td></tr>";
Dries's avatar
 
Dries committed
673 674 675
    }

    unset($links);
Dries's avatar
 
Dries committed
676
  }
Dries's avatar
 
Dries committed
677
  $output .= "</table>\n";
Dries's avatar
 
Dries committed
678

Dries's avatar
 
Dries committed
679 680 681 682 683
  theme("header");
  theme("box", t("News feeds"), import_page_info());
  theme("box", $bundle->title, $header);
  theme("box", t("Latest news"), $output);
  theme("footer");
Dries's avatar
 
Dries committed
684

Dries's avatar
 
Dries committed
685 686
}

Dries's avatar
 
Dries committed
687
function import_page_sources() {
Dries's avatar
 
Dries committed
688

Dries's avatar
 
Dries committed
689 690 691 692

  $result = db_query("SELECT * FROM feed ORDER BY title");

  while ($feed = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
693
    $output .= l($feed->title, "import/feed/$feed->fid");
Dries's avatar
 
Dries committed
694
    $output .= "<div style=\"margin-left: 20px;\">$feed->description</div><br />";
Dries's avatar
 
Dries committed
695 696
  }

Dries's avatar
 
Dries committed
697
  $output .= l("<img src=\"". theme("image", "xml.gif") ."\" width=\"36\" height=\"14\" align=\"right\" border=\"0\" />", "import/fd", array("title" => t("View the list of syndicated web sites in XML format."))) ."<br />";
Dries's avatar
 
Dries committed
698

Dries's avatar
 
Dries committed
699 700 701 702
  theme("header");
  theme("box", t("News feeds"), import_page_info());
  theme("box", t("News sources"), $output);
  theme("footer");
Dries's avatar
 
Dries committed
703 704
}

Dries's avatar
 
Dries committed
705 706 707 708
function import_page_fd() {

  $result = db_query("SELECT * FROM feed ORDER BY title");

Dries's avatar
 
Dries committed
709
  $output .= "<?xml version=\"1.0\" encoding=\"". variable_get("site_charset", "iso-8859-1") ."\"?>\n\n";
Dries's avatar
 
Dries committed
710
  $output .= "<rssfeeds version=\"0.1\">\n\n";
Dries's avatar
 
Dries committed
711 712 713

  while ($feed = db_fetch_object($result)) {
    $output .= "<channel>\n";
Dries's avatar
 
Dries committed
714 715
    $output .= " <title>". drupal_specialchars($feed->title) ."</title>\n";
    $output .= " <link>". drupal_specialchars($feed->url) ."</link>\n";
Dries's avatar
 
Dries committed
716 717 718
    $output .= "</channel>\n\n";
  }

Dries's avatar
 
Dries committed
719 720
  $output .= "</rssfeeds>\n";

Dries's avatar
 
Dries committed
72