diff --git a/.htaccess b/.htaccess index 7e563745cc9c3328e9a45db4bcdd1a5457c9b737..473a5ec3d0782139c375d32d6754070603dcc4f3 100644 --- a/.htaccess +++ b/.htaccess @@ -8,11 +8,6 @@ deny from all </Files> -# Syndicate content: -<Files export> - ForceType application/x-httpd-php -</Files> - # Customized server error messages: ErrorDocument 400 /error.php ErrorDocument 402 /error.php diff --git a/CHANGELOG b/CHANGELOG index c416ffc414b0846e10c7ec0f1ee8cc67d3ea524b..164a321be23a875d0d171ae16eb2eb5353bd5284 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ drupal x.xx, xx/xx/xxxx (CVS, unstable) - removed ban module and integrated it into account.module as "access control": * access control is based on much more powerful regular expressions (regex) now rather than on MySQL pattern matching. - rewrote watchdog and submission throttle +- rewrote headline code and renamed it to import.module and export.module + * added a various new features compared with the old headline code. - rewrote section code and renamed it to structure.module: * supports both "categories" and "topics" (cfr. Scoop, SlashCode). Topics can be nested to create a multi-level hierarchy. * added "auto-post new submissions" feature versus "moderate new submissions". diff --git a/export b/export.php similarity index 67% rename from export rename to export.php index c11073879d09bd10f336175663021aada8fb4fe1..5b2142a151eab39aaf821472864eb742a449de3a 100644 --- a/export +++ b/export.php @@ -2,6 +2,8 @@ include_once "includes/common.inc"; -foreach (module_list() as $module) module_invoke($module, "export", explode("/", $REQUEST_URI)); +$uri = parse_url($REQUEST_URI); + +foreach (module_list() as $module) module_invoke($module, "export", $uri["query"]); ?> \ No newline at end of file diff --git a/modules/syndication.module b/modules/aggregator.module similarity index 75% rename from modules/syndication.module rename to modules/aggregator.module index 952088fcb1eab916017a4e3c35daea916a6ea1ec..a4b85041ea7c8d30f091a7db08908b07a4be7468 100644 --- a/modules/syndication.module +++ b/modules/aggregator.module @@ -2,30 +2,30 @@ include_once "modules/backend.class"; -function syndication_help() { +function import_help() { ?> <P>TODO - anyone?</P> <?php } -function syndication_cron() { +function import_cron() { $result = db_query("SELECT * FROM feed"); while ($feed = db_fetch_array($result)) { // remove expired items: db_query("DELETE FROM item WHERE fid = '$feed[fid]' AND timestamp - ". time() ." > $feed[uncache]"); // update feeds: - if ($feed[timestamp] + $feed[refresh] < time()) syndication_update($feed); + if ($feed[timestamp] + $feed[refresh] < time()) import_update($feed); } } -function syndication_bundle($attribute) { +function import_bundle($attribute, $limit = 100) { if ($attribute) { // compose query: $keys = explode(",", $attribute); foreach ($keys as $key) $where[] = "attribute LIKE '%". trim($key) ."%'"; - $result = db_query("SELECT * FROM item WHERE ". implode(" OR ", $where) ." ORDER BY timestamp DESC"); + $result = db_query("SELECT * FROM item WHERE ". implode(" OR ", $where) ." ORDER BY timestamp DESC LIMIT $limit"); while ($item = db_fetch_object($result)) { $output .= "<LI><A HREF=\"". check_output($item->link) ."\">". check_output($item->title) ."</A></LI>"; @@ -35,15 +35,26 @@ function syndication_bundle($attribute) { } } -function syndication_view_bundle() { +function import_view_bundle() { $result = db_query("SELECT * FROM bundle ORDER BY title"); while ($bundle = db_fetch_object($result)) { - $output .= "<B>$bundle->title</B><UL>". syndication_bundle($bundle->attribute) ."</UL>"; + $output .= "<B>$bundle->title</B><UL>". import_bundle($bundle->attribute) ."</UL>"; } return $output; } -function syndication_update($feed) { +function import_block() { + $result = db_query("SELECT * FROM bundle ORDER BY title"); + while ($bundle = db_fetch_object($result)) { + $i++; + $blocks[$i][subject] = $bundle->title; + $blocks[$i][content] = import_bundle($bundle->attribute, 10); + $blocks[$i][info] = "$bundle->title bundle"; + } + return $blocks; +} + +function import_update($feed) { // open socket: $url = parse_url($feed[link]); @@ -65,7 +76,7 @@ function syndication_update($feed) { $d = eregi("<description>(.*)</description>", $item, $description); if ($l || $t || $a || $d) { - syndication_save_item(array(fid => $feed[fid], title => $title[0], link => $link[0], author => $author[0], description => $description[0], attribute => $feed[attribute])); + import_save_item(array(fid => $feed[fid], title => $title[0], link => $link[0], author => $author[0], description => $description[0], attribute => $feed[attribute])); } } @@ -77,7 +88,7 @@ function syndication_update($feed) { } } -function syndication_save_item($edit) { +function import_save_item($edit) { if ($edit[iid] && $edit[title]) { db_query("UPDATE item SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', author = '". check_input($edit[author]) ."', description = '". check_input($edit[description]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE iid = '$edit[iid]'"); } @@ -91,7 +102,7 @@ function syndication_save_item($edit) { } } -function syndication_form_bundle($edit = array()) { +function import_form_bundle($edit = array()) { global $REQUEST_URI; $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the bundle."); @@ -107,7 +118,7 @@ function syndication_form_bundle($edit = array()) { return form($REQUEST_URI, $form); } -function syndication_save_bundle($edit) { +function import_save_bundle($edit) { if ($edit[bid] && $edit[title]) { db_query("UPDATE bundle SET title = '". check_input($edit[title]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE bid = '". check_input($edit[bid]) ."'"); } @@ -117,9 +128,11 @@ function syndication_save_bundle($edit) { else { db_query("INSERT INTO bundle (title, attribute) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[attribute]) ."')"); } + + module_rehash_blocks("import"); } -function syndication_form_feed($edit = array()) { +function import_form_feed($edit = array()) { global $REQUEST_URI; $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)); @@ -140,7 +153,7 @@ function syndication_form_feed($edit = array()) { return form($REQUEST_URI, $form); } -function syndication_save_feed($edit) { +function import_save_feed($edit) { if ($edit[fid] && $edit[title]) { db_query("UPDATE feed SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', attribute = '". check_input($edit[attribute]) ."', refresh = '". check_input($edit[refresh]) ."', uncache = '". check_input($edit[uncache]) ."' WHERE fid = '". check_input($edit[fid]) ."'"); db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'"); @@ -154,29 +167,29 @@ function syndication_save_feed($edit) { } } -function syndication_save_attributes($edit) { +function import_save_attributes($edit) { foreach($edit as $iid => $value) { db_query("UPDATE item SET attribute = '". check_input($value) ."' WHERE iid = '". check_input($iid) ."'"); } return "attributes has been saved"; } -function syndication_get_feed($fid) { +function import_get_feed($fid) { return db_fetch_array(db_query("SELECT * FROM feed WHERE fid = '". check_input($fid) ."'")); } -function syndication_get_bundle($bid) { +function import_get_bundle($bid) { return db_fetch_array(db_query("SELECT * FROM bundle WHERE bid = '". check_input($bid) ."'")); } -function syndication_view_feed() { +function import_view_feed() { $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 ORDER BY f.title"); $output .= "<H3>Feed overview</H3>"; $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n"; $output .= " <TR><TH>title</TH><TH>attributes</TH><TH>items</TH><TH>last update</TH><TH>next update</TH><TH COLSPAN=\"2\">operations</TH></TR>\n"; while ($feed = db_fetch_object($result)) { - $output .= " <TR><TD>". check_output($feed->title) ."</TD><TD>". check_output($feed->attribute) ."</TD><TD>". format_plural($feed->items, "item", "items") ."</TD><TD>". ($feed->timestamp ? format_interval(time() - $feed->timestamp) ." ago" : "never") ."</TD><TD>". ($feed->timestamp ? format_interval($feed->timestamp + $feed->refresh - time()) ." left" : "never") ."</TD><TD><A HREF=\"admin.php?mod=syndication&type=feed&op=edit&id=$feed->fid\">edit feed</A></TD><TD><A HREF=\"admin.php?mod=syndication&type=feed&op=update&id=$feed->fid\">update items</A></TD></TR>\n"; + $output .= " <TR><TD>". check_output($feed->title) ."</TD><TD>". check_output($feed->attribute) ."</TD><TD>". format_plural($feed->items, "item", "items") ."</TD><TD>". ($feed->timestamp ? format_interval(time() - $feed->timestamp) ." ago" : "never") ."</TD><TD>". ($feed->timestamp ? format_interval($feed->timestamp + $feed->refresh - time()) ." left" : "never") ."</TD><TD><A HREF=\"admin.php?mod=import&type=feed&op=edit&id=$feed->fid\">edit feed</A></TD><TD><A HREF=\"admin.php?mod=import&type=feed&op=update&id=$feed->fid\">update items</A></TD></TR>\n"; } $output .= "</TABLE>\n"; @@ -186,14 +199,14 @@ function syndication_view_feed() { $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n"; $output .= " <TR><TH>title</TH><TH>attributes</TH><TH>operations</TH></TR>\n"; while ($bundle = db_fetch_object($result)) { - $output .= " <TR><TD>". check_output($bundle->title) ."</TD><TD>". check_output($bundle->attribute) ."</TD><TD><A HREF=\"admin.php?mod=syndication&type=bundle&op=edit&id=$bundle->bid\">edit bundle</A></TD></TR>\n"; + $output .= " <TR><TD>". check_output($bundle->title) ."</TD><TD>". check_output($bundle->attribute) ."</TD><TD><A HREF=\"admin.php?mod=import&type=bundle&op=edit&id=$bundle->bid\">edit bundle</A></TD></TR>\n"; } $output .= "</TABLE>\n"; return $output; } -function syndication_view_item() { +function import_view_item() { global $REQUEST_URI; $result = db_query("SELECT i.*, f.title AS feed FROM item i LEFT JOIN feed f ON i.fid = f.fid ORDER BY i.timestamp DESC LIMIT 50"); @@ -202,7 +215,7 @@ function syndication_view_item() { $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n"; $output .= " <TR><TH>time</TH><TH>feed</TH><TH>item</TH></TR>\n"; while ($item = db_fetch_object($result)) { - $output .= " <TR><TD VALIGN=\"top\" NOWRAP>". format_date($item->timestamp, "custom", "m/d/y") ."<BR>".format_date($item->timestamp, "custom", "H:i") ."</TD><TD ALIGN=\"center\" VALIGN=\"top\" NOWRAP><A HREF=\"admin.php?mod=syndication&type=feed&op=edit&id=$item->fid\">". check_output($item->feed) ."</A></TD><TD><A HREF=\"". check_output($item->link) ."\">". check_output($item->title) ."</A>". ($item->description ? "<BR><SMALL><I>". check_output($item->description) ."</I></SMALL>" : "") ."<BR><INPUT TYPE=\"text\" NAME=\"edit[$item->iid]\" VALUE=\"". check_form($item->attribute) ."\" SIZE=\"50\"></TD></TR>\n"; + $output .= " <TR><TD VALIGN=\"top\" NOWRAP>". format_date($item->timestamp, "custom", "m/d/y") ."<BR>".format_date($item->timestamp, "custom", "H:i") ."</TD><TD ALIGN=\"center\" VALIGN=\"top\" NOWRAP><A HREF=\"admin.php?mod=import&type=feed&op=edit&id=$item->fid\">". check_output($item->feed) ."</A></TD><TD><A HREF=\"". check_output($item->link) ."\">". check_output($item->title) ."</A>". ($item->description ? "<BR><SMALL><I>". check_output($item->description) ."</I></SMALL>" : "") ."<BR><INPUT TYPE=\"text\" NAME=\"edit[$item->iid]\" VALUE=\"". check_form($item->attribute) ."\" SIZE=\"50\"></TD></TR>\n"; } $output .= "</TABLE>\n"; $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save attributes\">\n"; @@ -211,51 +224,51 @@ function syndication_view_item() { return $output; } -function syndication_admin() { +function import_admin() { global $op, $id, $type, $edit; - print "<SMALL><A HREF=\"admin.php?mod=syndication&type=bundle&op=add\">add new bundle</A> | <A HREF=\"admin.php?mod=syndication&type=feed&op=add\">add new feed</A> | <A HREF=\"admin.php?mod=syndication&type=bundle&op=view\">available bundles</A> | <A HREF=\"admin.php?mod=syndication&type=item&op=view\">available items</A> | <A HREF=\"admin.php?mod=syndication&op=view\">overview</A> | <A HREF=\"admin.php?mod=syndication&op=help\">help</A></SMALL><HR>"; + print "<SMALL><A HREF=\"admin.php?mod=import&type=bundle&op=add\">add new bundle</A> | <A HREF=\"admin.php?mod=import&type=feed&op=add\">add new feed</A> | <A HREF=\"admin.php?mod=import&type=bundle&op=view\">available bundles</A> | <A HREF=\"admin.php?mod=import&type=item&op=view\">available items</A> | <A HREF=\"admin.php?mod=import&op=view\">overview</A> | <A HREF=\"admin.php?mod=import&op=help\">help</A></SMALL><HR>"; switch($op) { case "help": - print syndication_help(); + print import_help(); break; case "add": if ($type == "bundle") - print syndication_form_bundle(); + print import_form_bundle(); else - print syndication_form_feed(); + print import_form_feed(); break; case "edit": if ($type == "bundle") - print syndication_form_bundle(syndication_get_bundle($id)); + print import_form_bundle(import_get_bundle($id)); else - print syndication_form_feed(syndication_get_feed($id)); + print import_form_feed(import_get_feed($id)); break; case "update": - print syndication_update(syndication_get_feed($id)); - print syndication_view_feed(); + print import_update(import_get_feed($id)); + print import_view_feed(); break; case "Save attributes": - print status(syndication_save_attributes($edit)); - print syndication_view_item(); + print status(import_save_attributes($edit)); + print import_view_item(); break; case "Delete": $edit[title] = 0; // fall through: case "Submit": if ($type == "bundle") - print status(syndication_save_bundle($edit)); + print status(import_save_bundle($edit)); else - print status(syndication_save_feed($edit)); + print status(import_save_feed($edit)); // fall through: default: if ($type == "bundle") - print syndication_view_bundle(); + print import_view_bundle(); else if ($type == "item") - print syndication_view_item(); + print import_view_item(); else - print syndication_view_feed(); + print import_view_feed(); } } diff --git a/modules/aggregator/aggregator.module b/modules/aggregator/aggregator.module new file mode 100644 index 0000000000000000000000000000000000000000..a4b85041ea7c8d30f091a7db08908b07a4be7468 --- /dev/null +++ b/modules/aggregator/aggregator.module @@ -0,0 +1,275 @@ +<?php + +include_once "modules/backend.class"; + +function import_help() { + ?> + <P>TODO - anyone?</P> + <?php +} + +function import_cron() { + $result = db_query("SELECT * FROM feed"); + while ($feed = db_fetch_array($result)) { + // remove expired items: + db_query("DELETE FROM item WHERE fid = '$feed[fid]' AND timestamp - ". time() ." > $feed[uncache]"); + + // update feeds: + if ($feed[timestamp] + $feed[refresh] < time()) import_update($feed); + } +} + +function import_bundle($attribute, $limit = 100) { + if ($attribute) { + // compose query: + $keys = explode(",", $attribute); + foreach ($keys as $key) $where[] = "attribute LIKE '%". trim($key) ."%'"; + + $result = db_query("SELECT * FROM item WHERE ". implode(" OR ", $where) ." ORDER BY timestamp DESC LIMIT $limit"); + + while ($item = db_fetch_object($result)) { + $output .= "<LI><A HREF=\"". check_output($item->link) ."\">". check_output($item->title) ."</A></LI>"; + } + + return "$output"; + } +} + +function import_view_bundle() { + $result = db_query("SELECT * FROM bundle ORDER BY title"); + while ($bundle = db_fetch_object($result)) { + $output .= "<B>$bundle->title</B><UL>". import_bundle($bundle->attribute) ."</UL>"; + } + return $output; +} + +function import_block() { + $result = db_query("SELECT * FROM bundle ORDER BY title"); + while ($bundle = db_fetch_object($result)) { + $i++; + $blocks[$i][subject] = $bundle->title; + $blocks[$i][content] = import_bundle($bundle->attribute, 10); + $blocks[$i][info] = "$bundle->title bundle"; + } + return $blocks; +} + +function import_update($feed) { + + // open socket: + $url = parse_url($feed[link]); + $fp = fsockopen($url[host], ($url[port] ? $url[port] : 80), $errno, $errstr, 15); + + if ($fp) { + // fetch data: + fputs($fp, "GET $url[path]?$url[query] HTTP/1.0\nUser-Agent: ". variable_get(site_name, "drupal") ."\nHost: $url[host]\nAccept: */*\n\n"); + while(!feof($fp)) $data .= fgets($fp, 128); + + if (strstr($data, "200 OK")) { + + eregi("<item(.*)</item>", $data, $data); + + foreach (explode("</item>", $data[0]) as $item) { + $l = eregi("<link>(.*)</link>", $item, $link); + $t = eregi("<title>(.*)</title>", $item, $title); + $a = eregi("<author>(.*)</author>", $item, $author); + $d = eregi("<description>(.*)</description>", $item, $description); + + if ($l || $t || $a || $d) { + import_save_item(array(fid => $feed[fid], title => $title[0], link => $link[0], author => $author[0], description => $description[0], attribute => $feed[attribute])); + } + } + + db_query("UPDATE feed SET timestamp = '". time() ."' WHERE fid = '". $feed[fid] ."'"); + } + else { + watchdog("error", "failed to syndicate from '$feed[title]'"); + } + } +} + +function import_save_item($edit) { + if ($edit[iid] && $edit[title]) { + db_query("UPDATE item SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', author = '". check_input($edit[author]) ."', description = '". check_input($edit[description]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE iid = '$edit[iid]'"); + } + else if ($edit[iid]) { + db_query("DELETE FROM item WHERE iid = '". check_input($edit[iid]) ."'"); + } + else { + if (!db_fetch_object(db_query("SELECT iid FROM item WHERE link = '". check_input($edit[link]) ."'"))) { + db_query("INSERT INTO item (fid, title, link, author, description, attribute, timestamp) VALUES ('". check_input($edit[fid]) ."', '". check_input($edit[title]) ."', '". check_input($edit[link]) ."', '". check_input($edit[author]) ."', '". check_input($edit[description]) ."', '". check_input($edit[attribute]) ."', '". time() ."')"); + } + } +} + +function import_form_bundle($edit = array()) { + global $REQUEST_URI; + + $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the bundle."); + $form .= form_textfield("Attributes", "attribute", $edit[attribute], 50, 128, "A comma-seperated list of keywords describing the bundle."); + + $form .= form_submit("Submit"); + + if ($edit[bid]) { + $form .= form_submit(t("Delete")); + $form .= form_hidden("bid", $edit[bid]); + } + + return form($REQUEST_URI, $form); +} + +function import_save_bundle($edit) { + if ($edit[bid] && $edit[title]) { + db_query("UPDATE bundle SET title = '". check_input($edit[title]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE bid = '". check_input($edit[bid]) ."'"); + } + else if ($edit[bid]) { + db_query("DELETE FROM bundle WHERE bid = '". check_input($edit[bid]) ."'"); + } + else { + db_query("INSERT INTO bundle (title, attribute) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[attribute]) ."')"); + } + + module_rehash_blocks("import"); +} + +function import_form_feed($edit = array()) { + global $REQUEST_URI; + + $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)); + + $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the feed; typically the name of the website you syndicate content from."); + $form .= form_textfield("Link", "link", $edit[link], 50, 64, "The fully-qualified URL of the feed."); + $form .= form_textfield("Attributes", "attribute", $edit[attribute], 50, 128, "A comma-seperated list of keywords describing the feed."); + $form .= form_select("Update interval", "refresh", $edit[refresh], $period, "The refresh interval indicating how often you want to update this feed. Requires crontab."); + $form .= form_select("Expiration time", "uncache", $edit[uncache], $period, "The time cached items should be kept. Older items will be automatically discarded. Requires crontab."); + + $form .= form_submit("Submit"); + + if ($edit[fid]) { + $form .= form_submit(t("Delete")); + $form .= form_hidden("fid", $edit[fid]); + } + + return form($REQUEST_URI, $form); +} + +function import_save_feed($edit) { + if ($edit[fid] && $edit[title]) { + db_query("UPDATE feed SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', attribute = '". check_input($edit[attribute]) ."', refresh = '". check_input($edit[refresh]) ."', uncache = '". check_input($edit[uncache]) ."' WHERE fid = '". check_input($edit[fid]) ."'"); + db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'"); + } + else if ($edit[fid]) { + db_query("DELETE FROM feed WHERE fid = '". check_input($edit[fid]) ."'"); + db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'"); + } + else { + db_query("INSERT INTO feed (title, link, attribute, refresh, uncache) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[link]) ."', '". check_input($edit[attribute]) ."', '". check_input($edit[refresh]) ."', '". check_input($edit[uncache]) ."')"); + } +} + +function import_save_attributes($edit) { + foreach($edit as $iid => $value) { + db_query("UPDATE item SET attribute = '". check_input($value) ."' WHERE iid = '". check_input($iid) ."'"); + } + return "attributes has been saved"; +} + +function import_get_feed($fid) { + return db_fetch_array(db_query("SELECT * FROM feed WHERE fid = '". check_input($fid) ."'")); +} + +function import_get_bundle($bid) { + return db_fetch_array(db_query("SELECT * FROM bundle WHERE bid = '". check_input($bid) ."'")); +} + +function import_view_feed() { + $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 ORDER BY f.title"); + + $output .= "<H3>Feed overview</H3>"; + $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n"; + $output .= " <TR><TH>title</TH><TH>attributes</TH><TH>items</TH><TH>last update</TH><TH>next update</TH><TH COLSPAN=\"2\">operations</TH></TR>\n"; + while ($feed = db_fetch_object($result)) { + $output .= " <TR><TD>". check_output($feed->title) ."</TD><TD>". check_output($feed->attribute) ."</TD><TD>". format_plural($feed->items, "item", "items") ."</TD><TD>". ($feed->timestamp ? format_interval(time() - $feed->timestamp) ." ago" : "never") ."</TD><TD>". ($feed->timestamp ? format_interval($feed->timestamp + $feed->refresh - time()) ." left" : "never") ."</TD><TD><A HREF=\"admin.php?mod=import&type=feed&op=edit&id=$feed->fid\">edit feed</A></TD><TD><A HREF=\"admin.php?mod=import&type=feed&op=update&id=$feed->fid\">update items</A></TD></TR>\n"; + } + $output .= "</TABLE>\n"; + + $result = db_query("SELECT * FROM bundle ORDER BY title"); + + $output .= "<H3>Bundle overview</H3>"; + $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n"; + $output .= " <TR><TH>title</TH><TH>attributes</TH><TH>operations</TH></TR>\n"; + while ($bundle = db_fetch_object($result)) { + $output .= " <TR><TD>". check_output($bundle->title) ."</TD><TD>". check_output($bundle->attribute) ."</TD><TD><A HREF=\"admin.php?mod=import&type=bundle&op=edit&id=$bundle->bid\">edit bundle</A></TD></TR>\n"; + } + $output .= "</TABLE>\n"; + + return $output; +} + +function import_view_item() { + global $REQUEST_URI; + + $result = db_query("SELECT i.*, f.title AS feed FROM item i LEFT JOIN feed f ON i.fid = f.fid ORDER BY i.timestamp DESC LIMIT 50"); + + $output .= "<FORM ACTION=\"$REQUEST_URI\" METHOD=\"post\">\n"; + $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n"; + $output .= " <TR><TH>time</TH><TH>feed</TH><TH>item</TH></TR>\n"; + while ($item = db_fetch_object($result)) { + $output .= " <TR><TD VALIGN=\"top\" NOWRAP>". format_date($item->timestamp, "custom", "m/d/y") ."<BR>".format_date($item->timestamp, "custom", "H:i") ."</TD><TD ALIGN=\"center\" VALIGN=\"top\" NOWRAP><A HREF=\"admin.php?mod=import&type=feed&op=edit&id=$item->fid\">". check_output($item->feed) ."</A></TD><TD><A HREF=\"". check_output($item->link) ."\">". check_output($item->title) ."</A>". ($item->description ? "<BR><SMALL><I>". check_output($item->description) ."</I></SMALL>" : "") ."<BR><INPUT TYPE=\"text\" NAME=\"edit[$item->iid]\" VALUE=\"". check_form($item->attribute) ."\" SIZE=\"50\"></TD></TR>\n"; + } + $output .= "</TABLE>\n"; + $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save attributes\">\n"; + $output .= "</FORM>\n"; + + return $output; +} + +function import_admin() { + global $op, $id, $type, $edit; + + print "<SMALL><A HREF=\"admin.php?mod=import&type=bundle&op=add\">add new bundle</A> | <A HREF=\"admin.php?mod=import&type=feed&op=add\">add new feed</A> | <A HREF=\"admin.php?mod=import&type=bundle&op=view\">available bundles</A> | <A HREF=\"admin.php?mod=import&type=item&op=view\">available items</A> | <A HREF=\"admin.php?mod=import&op=view\">overview</A> | <A HREF=\"admin.php?mod=import&op=help\">help</A></SMALL><HR>"; + + switch($op) { + case "help": + print import_help(); + break; + case "add": + if ($type == "bundle") + print import_form_bundle(); + else + print import_form_feed(); + break; + case "edit": + if ($type == "bundle") + print import_form_bundle(import_get_bundle($id)); + else + print import_form_feed(import_get_feed($id)); + break; + case "update": + print import_update(import_get_feed($id)); + print import_view_feed(); + break; + case "Save attributes": + print status(import_save_attributes($edit)); + print import_view_item(); + break; + case "Delete": + $edit[title] = 0; + // fall through: + case "Submit": + if ($type == "bundle") + print status(import_save_bundle($edit)); + else + print status(import_save_feed($edit)); + // fall through: + default: + if ($type == "bundle") + print import_view_bundle(); + else if ($type == "item") + print import_view_item(); + else + print import_view_feed(); + } +} + +?> diff --git a/modules/backend.class b/modules/backend.class deleted file mode 100644 index c77418e0354a6a6b77b97a6821268554ee3abc63..0000000000000000000000000000000000000000 --- a/modules/backend.class +++ /dev/null @@ -1,154 +0,0 @@ -<?php -class backend { - - // Channel properties: - var $id; - var $url; - var $site; - var $file; - var $contact; - var $timestamp; - - // Contains the raw rdf/rss/xml file: - var $data; - - // Contains the parsed rdf/rss/xml file: - var $headlines = array(); // latest headlines - - function backend($id, $site = "", $url = "", $file = "", $contact = "", $timout = 10800) { - // Get channel info: - $result = db_query("SELECT * FROM channel WHERE id = '$id' OR site = '$site'"); - - if ($channel = db_fetch_object($result)) { - // Initialize internal variables: - $this->id = $channel->id; - $this->site = $channel->site; - $this->file = $channel->file; - $this->url = $channel->url; - $this->contact = $channel->contact; - $this->timestamp = $channel->timestamp; - - // Check to see whether we have to update our headlines first: - if (time() - $this->timestamp > $timout) $this->url2sql(); - - // Read headlines: - $result = db_query("SELECT * FROM headlines WHERE id = '$this->id' ORDER BY number"); - while ($headline = db_fetch_object($result)) { - array_push($this->headlines, "<A HREF=\"$headline->link\">$headline->title</A>"); - } - } - else { - $this->site = $site; - $this->url = $url; - $this->file = $file; - $this->contact = $contact; - } - } - - function url2sql($timout = 10) { - if ($this->file) { - // Decode URL: - $url = parse_url($this->file); - - // Retrieve data from website: - $fp = fsockopen($url[host], ($url[port] ? $url[port] : 80), $errno, $errstr, $timout); - - if ($fp) { - // Request data via URL: - fputs($fp, "GET $url[path]?$url[query] HTTP/1.0\nUser-Agent: ". variable_get(site_name, "drupal") ."\nHost: $url[host]\nAccept: */*\n\n"); - - // Read data from socket: - while(!feof($fp)) $data .= fgets($fp, 128); - - if (strstr($data, "200 OK")) { - - // Remove existing entries: - $result = db_query("DELETE FROM headlines WHERE id = '$this->id'"); - - // Strip all 'junk': - $data = ereg_replace("<?phpxml.*/image>", "", $data); - $data = ereg_replace("</rdf.*", "", $data); - $data = chop($data); - - // Iterating through our data processing each entry/item: - $items = explode("</item>", $data); - $number = 0; - - for (reset($items); $item = current($items); next($items)) { - // Extract data: - $link = ereg_replace(".*<link>", "", $item); - $link = ereg_replace("</link>.*", "", $link); - $title = ereg_replace(".*<title>", "", $item); - $title = ereg_replace("</title>.*", "", $title); - - // Increase the number of headlines: - $number += 1; - - // Insert item in database: - $result = db_query("INSERT INTO headlines (id, title, link, number) VALUES('". check_input($this->id) ."', '". check_input($title) ."', '". check_input($link) ."', '". check_input($number) ."')"); - } - - // Mark channels as being updated: - $result = db_query("UPDATE channel SET timestamp = '". time() ."' WHERE id = '$this->id'"); - $this->timestamp = time(); - } - else { - watchdog("error", "failed to grab headlines from '$this->site': <PRE>$data</PRE>"); - } - } - } - } - - function displayHeadlines($timout = 1800) { - global $theme; - - // Get channel info: - $result = db_query("SELECT * FROM channel WHERE site = '$this->site'"); - - if ($this->id) { - - // Check to see whether we have to update our headlines first: - if (time() - $this->timestamp > $timout) $this->url2sql(); - - // Grab headlines from database: - $result = db_query("SELECT * FROM headlines WHERE id = '$this->id' ORDER BY number"); - while ($headline = db_fetch_object($result)) { - $content .= "<LI><A HREF=\"$headline->link\">$headline->title</A></LI>"; - } - // Add timestamp: - $update = round((time() - $this->timestamp) / 60); - - // Display box: - $theme->box($this->site, $content); - } - else print "<P>Warning: something funky happened: specified channel could not be found in database.</P>"; - } - - function add() { - // Add channel: - $result = db_query("INSERT INTO channel (site, file, url, contact, timestamp) VALUES ('". check_input($this->site) ."', '". check_input($this->file) ."', '". check_input($this->url) ."', '". check_input($this->contact) ."', 1)"); - } - - function save() { - // Save channel: - $result = db_query("UPDATE channel SET site='". check_input($this->site) ."', file='". check_input($this->file) ."', url='". check_input($this->url) ."', contact='". check_input($this->contact) ."' WHERE id='". check_input($this->id) ."'"); - } - - function delete() { - // Delete channel: - $result = db_query("DELETE FROM channel WHERE id = '$this->id'"); - - // Delete headlines: - $result = db_query("DELETE FROM headlines WHERE id = '$this->id'"); - } - - function refresh() { - // Delete headlines: - $result = db_query("DELETE FROM headlines WHERE id = '$this->id'"); - - // Mark channel as invalid to enforce an update: - $result = db_query("UPDATE channel SET timestamp = 1 WHERE id = '$this->id'"); - } -} - -?> diff --git a/modules/export.module b/modules/export.module new file mode 100644 index 0000000000000000000000000000000000000000..b65fa569b0507bb583344b895a2d27b296e46954 --- /dev/null +++ b/modules/export.module @@ -0,0 +1,87 @@ +<?php + +function export_export_rdf() { + global $status; + + header("Content-Type: text/plain"); + + print "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; + print "<rdf:RDF\n"; + print " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"; + print " xmlns=\"http://my.netscape.com/rdf/simple/0.9/\">\n"; + + print "<channel>\n"; + print " <title>". variable_get(site_name, "drupal") ."</title>\n"; + print " <link>". path_uri() ."</link>\n"; + print " <description>". variable_get(site_name, "drupal") ."</description>\n"; + print "</channel>\n"; + + $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); + + while ($node = db_fetch_object($result)) { + print "<item>\n"; + print " <title>". check_export($node->title) ."</title>\n"; + print " <link>". path_uri() ."node.php?id=$node->nid</link>\n"; + print "</item>\n"; + } + + print "</rdf:RDF>\n"; +} + +function export_export_rss() { + global $status; + + header("Content-Type: text/plain"); + + print "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; + print "<rdf:RDF\n"; + + print "xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"; + print "xmlns=\"http://purl.org/rss/1.0/\">\n\n"; + + print "<channel rdf:about=\"". path_uri() ."export/exportsRSS10.rdf\">\n"; + print " <title>". variable_get(site_name, "drupal") ."</title>\n"; + print " <link>". path_uri() ."</link>\n"; + print " <description>". variable_get(site_name, "drupal") ."</description>\n"; + + print " <items>\n"; + print " <rdf:Seq>\n"; + + $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); + + while ($node = db_fetch_object($result)) { + print " <rdf:li resource=\"". path_uri() ."node.php?id=$node->nid\" />\n"; + } + + print " </rdf:Seq>\n"; + print " </items>\n"; + print "</channel>\n\n"; + + $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); + + while ($node = db_fetch_object($result)) { + print "<item rdf:about=\"". path_uri() ."node.php?id=$node->nid\">\n"; + print " <title>". check_export($node->title) ."</title>\n"; + print " <link>". path_uri() ."node.php?id=$node->nid</link>\n"; + + if ($node->abstract) print " <description>". check_output($node->abstract, 1) ."</description>\n"; + if ($node->body) print " <description>". check_output($node->body, 1) ."</description>\n"; + + print "</item>\n"; + } + + print "</rdf:RDF>\n"; +} + +function export_export($query) { + switch ($query) { + case "headlines.rss": + export_export_rss(); + break; + case "headlines.rdf": + case "default": + export_export_rdf(); + } +} + +?> diff --git a/modules/headline.module b/modules/headline.module deleted file mode 100644 index 7d30bae509fe200e0af39cc1a74bdde93dc6e6f1..0000000000000000000000000000000000000000 --- a/modules/headline.module +++ /dev/null @@ -1,326 +0,0 @@ -<?php - -include_once "modules/backend.class"; - -function headline_help() { - ?> - <P>Drupal's headline module both imports and exports RDF/RSS headlines.</P> - <P>A lot of news-oriented websites are now publishing news (headlines) and making their content available through XML, RSS and RDF backend files. They syndicate free content and allow retrieval and further transmission, aggregation, and online publication. In its current state, drupal's headline module supports RDF and RSS backends.</P> - <P>RSS was originally developed by Netscape to allow adding news channels to "My Netscape" sites, but it has since become adopted as the <I>de facto</I> net standard for distributing headlines and brief dynamic texts.</P> - <P>The headline module goes out to a list of configured news sites once an hour or so (driven by cron), downloads new RSS/RDF data and makes it available to your visitors. In addition, your headlines are exported as well and can be retrieved by other sites from <CODE><?php echo path_uri(); ?>export/headlines.rdf</CODE>.</P> - <?php -} - -function headline_conf_options() { - $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), 1000000000 => t("Never")); - $output .= form_select(t("Update interval"), "headline_cron_time" , variable_get("headline_cron_time", 86400), $period, t("The update interval indicating how often you want to update your headline channels. Requires crontab.")); - return $output; -} - - -function headline_cron() { - if (time() - variable_get("headline_cron_last", 0) > variable_get("headline_cron_time", time())) { - variable_set("headline_cron_last", time()); - - $result = db_query("SELECT * FROM channel"); - while ($channel = db_fetch_object($result)) { - $backend = new Backend($channel->id); - } - } -} - -function headline_blocks() { - global $theme; - - // Get channel info: - $result = db_query("SELECT * FROM channel ORDER BY id"); - - $theme->header(); - - print "<TABLE BORDER=\"0\">\n"; - while ($channel = db_fetch_object($result)) { - if ($state % 3 == 0) print " <TR>\n"; - - print " <TD ALIGN=\"center\" VALIGN=\"top\" WIDTH=\"33%\">\n"; - - // Load backend from database: - $backend = new backend($channel->id); - - if ($backend->headlines) { - unset($content); - foreach ($backend->headlines as $headline) $content .= "<LI>$headline</LI>\n"; - } - else { - $content = "no headlines available\n"; - } - - // Print backend box to screen: - $theme->box($backend->site, $content); - print " </TD>\n"; - - if ($state % 3 == 2) print " </TR>\n"; - - $state += 1; - } - print "</TABLE>\n"; - - $theme->footer(); -} - -function headline_page() { - global $type; - - switch($type) { - case "rdf": - headline_rdf(); - break; - default: - headline_blocks(); - } -} - - -function headline_block() { - $result = db_query("SELECT * FROM channel"); - while ($channel = db_fetch_object($result)) { - $backend = new Backend($channel->id); - - if ($backend->headlines) { - unset($content); - foreach ($backend->headlines as $headline) { - $content .= "<LI>$headline</LI>\n"; - } - } - else { - $content = "no headlines available"; - } - - $blocks[$channel->id]["subject"] = $backend->site; - $blocks[$channel->id]["content"] = $content; - $blocks[$channel->id]["info"] = "$backend->site headlines"; - $blocks[$channel->id]["link"] = $backend->url; - } - return $blocks; -} - -function headline_admin_display() { - global $theme; - - // Get channel info: - $result = db_query("SELECT * FROM channel ORDER BY id"); - - $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n"; - $output .= " <TH>site</TH><TH>contact</TH><TH>last update</TH><TH COLSPAN=\"3\">operations</TH></TR>\n"; - - while ($channel = db_fetch_object($result)) { - // Load backend from database: - $backend = new backend($channel->id); - - $output .= "<TR>\n"; - $output .= " <TD>". format_url($backend->url, $backend->site) ."</TD>\n"; - $output .= " <TD>". format_email($backend->contact) ."</TD>\n"; - $output .= " <TD ALIGN=\"center\">". ($backend->timestamp == 1 ? "failed" : format_interval(time() - $backend->timestamp) ." ago") ."</TD>\n"; - $output .= " <TD ALIGN=\"center\"><A HREF=\"admin.php?mod=headline&op=refresh&id=$backend->id\">refresh</A></TD>\n"; - $output .= " <TD ALIGN=\"center\"><A HREF=\"admin.php?mod=headline&op=edit&id=$backend->id\">edit</A></TD>\n"; - $output .= " <TD ALIGN=\"center\"><A HREF=\"admin.php?mod=headline&op=delete&id=$backend->id\">delete</A></TD>\n"; - $output .= "</TR>\n"; - } - - $output .= "</TABLE>\n"; - - print $output; -} - -function headline_admin_add() { - $output .= " <FORM ACTION=\"admin.php?mod=headline\" METHOD=\"post\">\n"; - $output .= " <P>\n"; - $output .= " <B>Site name:</B><BR>\n"; - $output .= " <INPUT TYPE=\"text\" NAME=\"site\" SIZE=\"50\">\n"; - $output .= " </P>\n"; - $output .= " <P>\n"; - $output .= " <B>URL:</B><BR>\n"; - $output .= " <INPUT TYPE=\"text\" NAME=\"url\" SIZE=\"50\">\n"; - $output .= " </P>\n"; - $output .= " <P>\n"; - $output .= " <B>Backend file:</B><BR>\n"; - $output .= " <INPUT TYPE=\"text\" NAME=\"backend\" SIZE=\"50\">\n"; - $output .= " </P>\n"; - $output .= " <P>\n"; - $output .= " <B>Contact information:</B><BR>\n"; - $output .= " <INPUT TYPE=\"text\" NAME=\"contact\" SIZE=\"50\">\n"; - $output .= " </P>\n"; - $output .= " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Add backend\">\n"; - $output .= " </FORM>\n"; - - print $output; -} - -function headline_admin_edit($id) { - $result = db_query("SELECT * FROM channel WHERE id='$id' ORDER BY id"); - - if ($channel = db_fetch_object($result)) { - $output .= " <FORM ACTION=\"admin.php?mod=headline\" METHOD=\"post\">\n"; - $output .= " <INPUT TYPE=\"hidden\" NAME=\"id\" VALUE=\"$id\">\n"; - $output .= " <P>\n"; - $output .= " <B>Site name:</B><BR>\n"; - $output .= " <INPUT TYPE=\"text\" NAME=\"site\" SIZE=\"50\" VALUE=\"$channel->site\">\n"; - $output .= " </P>\n"; - $output .= " <P>\n"; - $output .= " <B>URL:</B><BR>\n"; - $output .= " <INPUT TYPE=\"text\" NAME=\"url\" SIZE=\"50\" VALUE=\"$channel->url\">\n"; - $output .= " </P>\n"; - $output .= " <P>\n"; - $output .= " <B>Backend file:</B><BR>\n"; - $output .= " <INPUT TYPE=\"text\" NAME=\"backend\" SIZE=\"50\" VALUE=\"$channel->file\">\n"; - $output .= " </P>\n"; - $output .= " <P>\n"; - $output .= " <B>Contact information:</B><BR>\n"; - $output .= " <INPUT TYPE=\"text\" NAME=\"contact\" SIZE=\"50\" VALUE=\"$channel->contact\">\n"; - $output .= " </P>\n"; - $output .= " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save backend\">\n"; - $output .= " </FORM>\n"; - } else { - $output .= "Invalid Channel ID.\n"; - } - print $output; -} - -function headline_admin_rehash() { - module_rehash_blocks("headline"); -} - -function headline_admin() { - global $op, $id, $site, $url, $backend, $contact; - - print "<SMALL><A HREF=\"admin.php?mod=headline&op=add\">add new channel</A> | <A HREF=\"admin.php?mod=headline\">overview</A> | <A HREF=\"admin.php?mod=headline&op=help\">help</A></SMALL><HR>"; - - switch($op) { - case "add": - headline_admin_add(); - break; - case "edit": - headline_admin_edit(check_input($id)); - break; - case "delete": - $channel = new backend($id); - $channel->delete(); - headline_admin_rehash(); - headline_admin_display(); - break; - case "help": - headline_help(); - break; - case "refresh": - $channel = new backend($id); - $channel->refresh(); - headline_admin_display(); - break; - case "Add backend": - $channel = new backend(check_input($id), check_input($site), check_input($url), check_input($backend), check_input($contact)); - $channel->add(); - headline_admin_rehash(); - headline_admin_display(); - break; - case "Save backend": - $channel = new backend(check_input($id)); - $channel->site = $site; - $channel->url = $url; - $channel->file = $backend; - $channel->contact = $contact; - $channel->save(); - headline_admin_rehash(); - // fall through: - default: - headline_admin_display(); - } -} - -function headline_export_rdf() { - global $status; - - $uri = substr(path_uri(), 0, strlen(path_uri()) - strlen("export/")); - - header("Content-Type: text/plain"); - - print "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; - print "<rdf:RDF\n"; - print " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"; - print " xmlns=\"http://my.netscape.com/rdf/simple/0.9/\">\n"; - - print "<channel>\n"; - print " <title>". variable_get(site_name, "drupal") ."</title>\n"; - print " <link>". $uri ."</link>\n"; - print " <description>". variable_get(site_name, "drupal") ."</description>\n"; - print "</channel>\n"; - - $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); - - while ($node = db_fetch_object($result)) { - print "<item>\n"; - print " <title>". check_export($node->title) ."</title>\n"; - print " <link>". $uri ."node.php?id=$node->nid</link>\n"; - print "</item>\n"; - } - - print "</rdf:RDF>\n"; -} - -function headline_export_rss() { - global $status; - - $uri = substr(path_uri(), 0, strlen(path_uri()) - strlen("export/")); - - header("Content-Type: text/plain"); - - print "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; - print "<rdf:RDF\n"; - - print "xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"; - print "xmlns=\"http://purl.org/rss/1.0/\">\n\n"; - - print "<channel rdf:about=\"". $uri ."export/headlinesRSS10.rdf\">\n"; - print " <title>". variable_get(site_name, "drupal") ."</title>\n"; - print " <link>". $uri ."</link>\n"; - print " <description>". variable_get(site_name, "drupal") ."</description>\n"; - - print " <items>\n"; - print " <rdf:Seq>\n"; - - $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); - - while ($node = db_fetch_object($result)) { - print " <rdf:li resource=\"". $uri ."node.php?id=$node->nid\" />\n"; - } - - print " </rdf:Seq>\n"; - print " </items>\n"; - print "</channel>\n\n"; - - $result = db_query("SELECT * FROM node WHERE promote = '1' AND status = '$status[posted]' ORDER BY timestamp DESC LIMIT 10"); - - while ($node = db_fetch_object($result)) { - print "<item rdf:about=\"". $uri ."node.php?id=$node->nid\">\n"; - print " <title>". check_export($node->title) ."</title>\n"; - print " <link>". $uri ."node.php?id=$node->nid</link>\n"; - - if ($node->abstract) print " <description>". check_output($node->abstract, 1) ."</description>\n"; - if ($node->body) print " <description>". check_output($node->body, 1) ."</description>\n"; - - print "</item>\n"; - } - - print "</rdf:RDF>\n"; -} - -function headline_export($uri) { - switch ($uri[2]) { - case "headlines.rss": - headline_export_rss(); - break; - case "headlines.rdf": - case "default": - headline_export_rdf(); - } -} - -?> diff --git a/modules/import.module b/modules/import.module new file mode 100644 index 0000000000000000000000000000000000000000..a4b85041ea7c8d30f091a7db08908b07a4be7468 --- /dev/null +++ b/modules/import.module @@ -0,0 +1,275 @@ +<?php + +include_once "modules/backend.class"; + +function import_help() { + ?> + <P>TODO - anyone?</P> + <?php +} + +function import_cron() { + $result = db_query("SELECT * FROM feed"); + while ($feed = db_fetch_array($result)) { + // remove expired items: + db_query("DELETE FROM item WHERE fid = '$feed[fid]' AND timestamp - ". time() ." > $feed[uncache]"); + + // update feeds: + if ($feed[timestamp] + $feed[refresh] < time()) import_update($feed); + } +} + +function import_bundle($attribute, $limit = 100) { + if ($attribute) { + // compose query: + $keys = explode(",", $attribute); + foreach ($keys as $key) $where[] = "attribute LIKE '%". trim($key) ."%'"; + + $result = db_query("SELECT * FROM item WHERE ". implode(" OR ", $where) ." ORDER BY timestamp DESC LIMIT $limit"); + + while ($item = db_fetch_object($result)) { + $output .= "<LI><A HREF=\"". check_output($item->link) ."\">". check_output($item->title) ."</A></LI>"; + } + + return "$output"; + } +} + +function import_view_bundle() { + $result = db_query("SELECT * FROM bundle ORDER BY title"); + while ($bundle = db_fetch_object($result)) { + $output .= "<B>$bundle->title</B><UL>". import_bundle($bundle->attribute) ."</UL>"; + } + return $output; +} + +function import_block() { + $result = db_query("SELECT * FROM bundle ORDER BY title"); + while ($bundle = db_fetch_object($result)) { + $i++; + $blocks[$i][subject] = $bundle->title; + $blocks[$i][content] = import_bundle($bundle->attribute, 10); + $blocks[$i][info] = "$bundle->title bundle"; + } + return $blocks; +} + +function import_update($feed) { + + // open socket: + $url = parse_url($feed[link]); + $fp = fsockopen($url[host], ($url[port] ? $url[port] : 80), $errno, $errstr, 15); + + if ($fp) { + // fetch data: + fputs($fp, "GET $url[path]?$url[query] HTTP/1.0\nUser-Agent: ". variable_get(site_name, "drupal") ."\nHost: $url[host]\nAccept: */*\n\n"); + while(!feof($fp)) $data .= fgets($fp, 128); + + if (strstr($data, "200 OK")) { + + eregi("<item(.*)</item>", $data, $data); + + foreach (explode("</item>", $data[0]) as $item) { + $l = eregi("<link>(.*)</link>", $item, $link); + $t = eregi("<title>(.*)</title>", $item, $title); + $a = eregi("<author>(.*)</author>", $item, $author); + $d = eregi("<description>(.*)</description>", $item, $description); + + if ($l || $t || $a || $d) { + import_save_item(array(fid => $feed[fid], title => $title[0], link => $link[0], author => $author[0], description => $description[0], attribute => $feed[attribute])); + } + } + + db_query("UPDATE feed SET timestamp = '". time() ."' WHERE fid = '". $feed[fid] ."'"); + } + else { + watchdog("error", "failed to syndicate from '$feed[title]'"); + } + } +} + +function import_save_item($edit) { + if ($edit[iid] && $edit[title]) { + db_query("UPDATE item SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', author = '". check_input($edit[author]) ."', description = '". check_input($edit[description]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE iid = '$edit[iid]'"); + } + else if ($edit[iid]) { + db_query("DELETE FROM item WHERE iid = '". check_input($edit[iid]) ."'"); + } + else { + if (!db_fetch_object(db_query("SELECT iid FROM item WHERE link = '". check_input($edit[link]) ."'"))) { + db_query("INSERT INTO item (fid, title, link, author, description, attribute, timestamp) VALUES ('". check_input($edit[fid]) ."', '". check_input($edit[title]) ."', '". check_input($edit[link]) ."', '". check_input($edit[author]) ."', '". check_input($edit[description]) ."', '". check_input($edit[attribute]) ."', '". time() ."')"); + } + } +} + +function import_form_bundle($edit = array()) { + global $REQUEST_URI; + + $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the bundle."); + $form .= form_textfield("Attributes", "attribute", $edit[attribute], 50, 128, "A comma-seperated list of keywords describing the bundle."); + + $form .= form_submit("Submit"); + + if ($edit[bid]) { + $form .= form_submit(t("Delete")); + $form .= form_hidden("bid", $edit[bid]); + } + + return form($REQUEST_URI, $form); +} + +function import_save_bundle($edit) { + if ($edit[bid] && $edit[title]) { + db_query("UPDATE bundle SET title = '". check_input($edit[title]) ."', attribute = '". check_input($edit[attribute]) ."' WHERE bid = '". check_input($edit[bid]) ."'"); + } + else if ($edit[bid]) { + db_query("DELETE FROM bundle WHERE bid = '". check_input($edit[bid]) ."'"); + } + else { + db_query("INSERT INTO bundle (title, attribute) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[attribute]) ."')"); + } + + module_rehash_blocks("import"); +} + +function import_form_feed($edit = array()) { + global $REQUEST_URI; + + $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)); + + $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the feed; typically the name of the website you syndicate content from."); + $form .= form_textfield("Link", "link", $edit[link], 50, 64, "The fully-qualified URL of the feed."); + $form .= form_textfield("Attributes", "attribute", $edit[attribute], 50, 128, "A comma-seperated list of keywords describing the feed."); + $form .= form_select("Update interval", "refresh", $edit[refresh], $period, "The refresh interval indicating how often you want to update this feed. Requires crontab."); + $form .= form_select("Expiration time", "uncache", $edit[uncache], $period, "The time cached items should be kept. Older items will be automatically discarded. Requires crontab."); + + $form .= form_submit("Submit"); + + if ($edit[fid]) { + $form .= form_submit(t("Delete")); + $form .= form_hidden("fid", $edit[fid]); + } + + return form($REQUEST_URI, $form); +} + +function import_save_feed($edit) { + if ($edit[fid] && $edit[title]) { + db_query("UPDATE feed SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', attribute = '". check_input($edit[attribute]) ."', refresh = '". check_input($edit[refresh]) ."', uncache = '". check_input($edit[uncache]) ."' WHERE fid = '". check_input($edit[fid]) ."'"); + db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'"); + } + else if ($edit[fid]) { + db_query("DELETE FROM feed WHERE fid = '". check_input($edit[fid]) ."'"); + db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'"); + } + else { + db_query("INSERT INTO feed (title, link, attribute, refresh, uncache) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[link]) ."', '". check_input($edit[attribute]) ."', '". check_input($edit[refresh]) ."', '". check_input($edit[uncache]) ."')"); + } +} + +function import_save_attributes($edit) { + foreach($edit as $iid => $value) { + db_query("UPDATE item SET attribute = '". check_input($value) ."' WHERE iid = '". check_input($iid) ."'"); + } + return "attributes has been saved"; +} + +function import_get_feed($fid) { + return db_fetch_array(db_query("SELECT * FROM feed WHERE fid = '". check_input($fid) ."'")); +} + +function import_get_bundle($bid) { + return db_fetch_array(db_query("SELECT * FROM bundle WHERE bid = '". check_input($bid) ."'")); +} + +function import_view_feed() { + $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 ORDER BY f.title"); + + $output .= "<H3>Feed overview</H3>"; + $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n"; + $output .= " <TR><TH>title</TH><TH>attributes</TH><TH>items</TH><TH>last update</TH><TH>next update</TH><TH COLSPAN=\"2\">operations</TH></TR>\n"; + while ($feed = db_fetch_object($result)) { + $output .= " <TR><TD>". check_output($feed->title) ."</TD><TD>". check_output($feed->attribute) ."</TD><TD>". format_plural($feed->items, "item", "items") ."</TD><TD>". ($feed->timestamp ? format_interval(time() - $feed->timestamp) ." ago" : "never") ."</TD><TD>". ($feed->timestamp ? format_interval($feed->timestamp + $feed->refresh - time()) ." left" : "never") ."</TD><TD><A HREF=\"admin.php?mod=import&type=feed&op=edit&id=$feed->fid\">edit feed</A></TD><TD><A HREF=\"admin.php?mod=import&type=feed&op=update&id=$feed->fid\">update items</A></TD></TR>\n"; + } + $output .= "</TABLE>\n"; + + $result = db_query("SELECT * FROM bundle ORDER BY title"); + + $output .= "<H3>Bundle overview</H3>"; + $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n"; + $output .= " <TR><TH>title</TH><TH>attributes</TH><TH>operations</TH></TR>\n"; + while ($bundle = db_fetch_object($result)) { + $output .= " <TR><TD>". check_output($bundle->title) ."</TD><TD>". check_output($bundle->attribute) ."</TD><TD><A HREF=\"admin.php?mod=import&type=bundle&op=edit&id=$bundle->bid\">edit bundle</A></TD></TR>\n"; + } + $output .= "</TABLE>\n"; + + return $output; +} + +function import_view_item() { + global $REQUEST_URI; + + $result = db_query("SELECT i.*, f.title AS feed FROM item i LEFT JOIN feed f ON i.fid = f.fid ORDER BY i.timestamp DESC LIMIT 50"); + + $output .= "<FORM ACTION=\"$REQUEST_URI\" METHOD=\"post\">\n"; + $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n"; + $output .= " <TR><TH>time</TH><TH>feed</TH><TH>item</TH></TR>\n"; + while ($item = db_fetch_object($result)) { + $output .= " <TR><TD VALIGN=\"top\" NOWRAP>". format_date($item->timestamp, "custom", "m/d/y") ."<BR>".format_date($item->timestamp, "custom", "H:i") ."</TD><TD ALIGN=\"center\" VALIGN=\"top\" NOWRAP><A HREF=\"admin.php?mod=import&type=feed&op=edit&id=$item->fid\">". check_output($item->feed) ."</A></TD><TD><A HREF=\"". check_output($item->link) ."\">". check_output($item->title) ."</A>". ($item->description ? "<BR><SMALL><I>". check_output($item->description) ."</I></SMALL>" : "") ."<BR><INPUT TYPE=\"text\" NAME=\"edit[$item->iid]\" VALUE=\"". check_form($item->attribute) ."\" SIZE=\"50\"></TD></TR>\n"; + } + $output .= "</TABLE>\n"; + $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save attributes\">\n"; + $output .= "</FORM>\n"; + + return $output; +} + +function import_admin() { + global $op, $id, $type, $edit; + + print "<SMALL><A HREF=\"admin.php?mod=import&type=bundle&op=add\">add new bundle</A> | <A HREF=\"admin.php?mod=import&type=feed&op=add\">add new feed</A> | <A HREF=\"admin.php?mod=import&type=bundle&op=view\">available bundles</A> | <A HREF=\"admin.php?mod=import&type=item&op=view\">available items</A> | <A HREF=\"admin.php?mod=import&op=view\">overview</A> | <A HREF=\"admin.php?mod=import&op=help\">help</A></SMALL><HR>"; + + switch($op) { + case "help": + print import_help(); + break; + case "add": + if ($type == "bundle") + print import_form_bundle(); + else + print import_form_feed(); + break; + case "edit": + if ($type == "bundle") + print import_form_bundle(import_get_bundle($id)); + else + print import_form_feed(import_get_feed($id)); + break; + case "update": + print import_update(import_get_feed($id)); + print import_view_feed(); + break; + case "Save attributes": + print status(import_save_attributes($edit)); + print import_view_item(); + break; + case "Delete": + $edit[title] = 0; + // fall through: + case "Submit": + if ($type == "bundle") + print status(import_save_bundle($edit)); + else + print status(import_save_feed($edit)); + // fall through: + default: + if ($type == "bundle") + print import_view_bundle(); + else if ($type == "item") + print import_view_item(); + else + print import_view_feed(); + } +} + +?>