=== modified file 'planet.info' --- planet.info 2009-03-01 02:54:23 +0000 +++ planet.info 2009-03-13 08:51:04 +0000 @@ -1,6 +1,7 @@ ; $Id: planet.info,v 1.2 2007/05/30 03:22:01 daryl Exp $ name = Planet description = Planet blog aggregator +; TODO better module definition, including specificity if possible. package = Community - optional version = 6.x core = 6.x === modified file 'planet.install' --- planet.install 2009-03-01 03:00:14 +0000 +++ planet.install 2009-03-13 08:46:18 +0000 @@ -10,37 +10,43 @@ 'description' => t('The base table for planet.'), 'fields' => array( 'fid' => array( - 'description' => t('The primary identifier for a planet_feeds table.'), + 'description' => t('Primary Key: Unique identifier for a planet RSS feed.'), 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, ), 'uid' => array( + 'description' => t('Foreign key to {users}.uid . Identifies user who choose the feed.'), 'type' => 'int', 'unsigned' => 1, 'not null' => FALSE, ), 'title' => array( 'type' => 'varchar', + 'description' => t('Title of the feed.'), 'length' => 50, 'not null' => TRUE, ), 'link' => array( 'type' => 'varchar', + 'description' => t('URL to the feed'), 'length' => 80, 'not null' => TRUE, ), 'image' => array( + 'description' => t('An image representing the feed'), 'type' => 'varchar', 'length' => 120, 'not null' => FALSE, ), 'checked' => array( + 'description' => t('Last time feed was checked for new items, as Unix timestamp'), 'type' => 'int', 'not null' => FALSE, ), 'frozen' => array( - 'type' => 'int', + // TODO: add field description 'description' => t(''), + 'type' => 'int', // TODO change to boolean when supported 'not null' => TRUE, 'default' => 0, ), @@ -52,7 +58,7 @@ 'description' => t('contain feed id and its corresponding nid'), 'fields' => array( 'id' => array( - 'description' => t('The primary identifier for a planet_items table'), + 'description' => t('Primary key: Unique identifier for a planet feed item'), 'type' => 'serial', 'unsigned' => 1, 'not null' => TRUE, @@ -91,11 +97,9 @@ /** * Implementation of hook_install() * - * This will automatically install the database tables for the planet module for MySQL. + * This will automatically install the database tables for the planet + * module, using Drupal's data abstraction layer. * - * If you are using another database, you will have to install the tables by hand, using the queries below as a reference. - * - * */ function planet_install() { @@ -106,9 +110,9 @@ /** * Implementation of hook_uninstall() * - * This will automatically uninstall the database tables for the planet module for MySQL. + * Uninstalls planet module by removing its own database tables, nodes + * and persistent variables. * - * */ function planet_uninstall() { === modified file 'planet.module' --- planet.module 2009-03-08 19:00:05 +0000 +++ planet.module 2009-03-13 21:27:34 +0000 @@ -3,7 +3,13 @@ /** * @file - * The planet module + * The planet module. + * + * Planet is an aggregator that allows you to aggregate the blogs for + * users in a given role (e.g. staff) and associate content with the + * users rather than as a detached feed. This provides the benefit of + * showing avatars with content, providing per-user aggregation of + * planet content in addition to blog content, etc. * */ @@ -33,6 +39,7 @@ $output .= '
  • General Settings. The role to select bloggers from lets you narrow the user list for when you\'re adding a feed and associating it with a user. A common setting will be to create a staff role and use this for planet.
  • '; $output .= '
  • Feeds. This section lets you add a new feed. Give it a title, select an author, provide the feed url, and you\'re off. You\'ll have to manually refresh it or wait for a cron run for items to be imported.
  • '; $output .= '
  • Feeds. This section lists current feeds, when they were last updated, how many items they have, and it allows you to edit, refresh, or freeze them. Freezing is a quick way to temporarily suspend updates from the given feed.
  • '; + $output .= ''; return $output; case 'admin/modules#description': return t('Aggregates RSS feeds and faciliates their association with site users who belong to a given role.'); @@ -41,8 +48,10 @@ function planet_view($node, $teaser = FALSE, $page = FALSE, $links = TRUE) { if ($page === true && variable_get('planet_redirect_page', 0) == 1) { - $obj = db_fetch_object(db_query('SELECT * FROM {planet_items} WHERE nid = %d', $node->nid)); - if ($obj->nid == $node->nid && $obj->link != '') { + $obj = db_fetch_object(db_query('SELECT link FROM {planet_items} WHERE nid = %d', $node->nid)); + // if the query succeeds, $obj->nid == $node->nid , otherwise, $obj==FALSE, + // only 'link' field is used, so I restricted the query + if ($obj && $obj->link != '') { header('Location: '. $obj->link); exit; } @@ -128,6 +137,10 @@ return $items; } + +/** + * Page callback for 'admin/settings/planet/refresh/%' ("planet refresh") + */ function planet_call_refresh() { $title = planet_refresh(); watchdog('planet', 'Feed "'. $title .'" refreshed.'); @@ -135,6 +148,9 @@ drupal_goto('admin/settings/planet'); } +/** + * Page callback for 'admin/settings/planet/(un|)freeze/%' ("planet freeze") + */ function planet_toggle_frozen() { $fid = intval(arg(4)); @@ -144,53 +160,47 @@ } -function planet_user_feeds() { -global $user; -if ($_POST) { - $edit = $_POST; - if ($_POST['op'] == 'Delete' && intval($edit['fid']) > 0) { +/** + * Deletes a feed and related items + * @param $fid the feed identifier key (integer) + */ +function planet__drop_feed($fid) { $result = db_query('SELECT nid FROM {planet_items} WHERE fid = %d', intval($edit['fid'])); while ($node = db_fetch_object($result)) { $nodes[$node->nid] = TRUE; } - return drupal_get_form('planet_multiple_delete_confirm', $nodes, intval($edit['fid']), 'user/'. $user->uid .'/planet'); - } - else if ($_POST['op'] == 'Delete all' && $_POST['confirm'] == 1) { - $edit['fid'] = intval(arg(3)); + return drupal_get_form('planet_multiple_delete_confirm', $nodes, + intval($edit['fid']), 'user/'. $user->uid .'/planet'); +} + +/** + * Page callback for 'user/%user/planet' ("Planet Feeds") + */ +function planet_user_feeds() { + global $user; + if ($_POST) { + $edit = $_POST; + $fid = intval($edit['fid']); + if (($_POST['op'] == 'Delete') && ($fid != 0)) { + return planet__drop_feed($fid); + } else if ($_POST['op'] == 'Delete all' && $_POST['confirm'] == 1) { + $edit['fid'] = intval(arg(3)); // @deprecated arg() $edit['redirect'] = 'user/'. $user->uid .'/planet'; return drupal_get_form('planet_multiple_delete_confirm_submit', $edit); - } - else { - if (isset($edit['fid']) && intval($edit['fid']) == 0) { - db_query('INSERT INTO {planet_feeds} (uid, title, link, image, checked, frozen) VALUES(%d, "%s", "%s", "%s", 0, 0)', $user->uid, $edit['title'], $edit['link'], $edit['image']); - $edit_r = db_fetch_array(db_query('SELECT fid FROM {planet_feeds} WHERE uid = %d AND title = "%s" AND link = "%s"', $user->uid, $edit['title'], $edit['link'])); - $title = planet_refresh(intval($edit_r['fid'])); - drupal_set_message('Added new feed: ' . $title); - } - else if ($edit['fid'] && intval($edit['fid']) > 0) { - db_query('UPDATE {planet_feeds} SET uid = %d, title="%s", link = "%s", image="%s" WHERE fid=%d', $user->uid, $edit['title'], $edit['link'], $edit['image'], $edit['fid']); - drupal_set_message('Edited "'. $edit['title'] .'" feed.'); - } - else { - if ($edit['planet_author_roles']) { - variable_set('planet_author_roles', $edit['planet_author_roles']); - } - if ($edit['planet_filter_formats']) { - variable_set('planet_filter_formats', $edit['planet_filter_formats']); - } - if ($edit['planet_redirect_page'] == 1) { - variable_set('planet_redirect_page', $edit['planet_redirect_page']); + } else { + if (isset($edit['fid'])) { + if (intval($edit['fid']) == 0) { + planet__add_feed($edit); + } else { + planet__update_feed($edit); } - else { - variable_del('planet_redirect_page'); - } - drupal_set_message('Edited general planet settings.'); + } else { + planet__update_vars($edit); } } drupal_goto('user/'. $user->uid .'/planet'); - } - else { - $fid = intval(arg(3)); + } else { // no $_POST + $fid = intval(arg(3)); // @deprecated: arg() if ($fid > 0) { $edit = db_fetch_array(db_query('SELECT * FROM {planet_feeds} WHERE fid = %d', $fid)); $output .= drupal_get_form('planet_feed_form', $edit, true, $user); @@ -199,32 +209,100 @@ $output .= drupal_get_form('planet_feed_form', $edit, false, $user); - // $result = db_query('SELECT *, (UNIX_TIMESTAMP(NOW()) - checked) _checked FROM {planet_feeds}'); - $result = db_query('SELECT COUNT(f.fid) cnt, f.*, (UNIX_TIMESTAMP(NOW()) - checked) _checked FROM {planet_feeds} f LEFT OUTER JOIN {planet_items} i ON i.fid = f.fid WHERE f.uid = %d GROUP BY f.fid;', $user->uid); + $output .= '

    Feeds

    '; + $output .= planet__build_feeds_table1(); + } + print theme('page', $output); + } +} + +// Note: I use 'planet__' prefix to name internal (private) functions +// TODO: apply the same naming convention (this one or another) in whole module +/** + * TODO merge with planet__build_feeds_table() + */ +function planet__build_feeds_table1() { + global $user; + $feeds = db_query('SELECT fid, title, checked FROM {planet_feeds} ' + . ' WHERE uid = %d;', $user->uid); $rows = array(); $headers = array('Feed', 'Items', 'Edit', 'Last checked'); - while ($feed = db_fetch_object($result)) { - $checked = intval($feed->_checked / 60) .' minutes'; - if ($feed->_checked % 60 > 0) { + $now = time(); + $items_statement = 'SELECT count(*) FROM {planet_items}' + . ' WHERE fid=%d'; + // TODO: change this to prepared statement when support by drupal DB abastraction layer. + while ($feed = db_fetch_object($feeds)) { + $_checked = $now - $feed->checked; + $checked = intval($_checked / 60) .' minutes'; + if ($_checked % 60 > 0) { $checked .= ', '. $feed->_checked % 60 .' seconds'; } $checked .= ' ago'; + $items = db_query($items_statement, $feed->fid); + if (!$items) trigger_error('ERROR while counting feed items.'); + $cnt = db_result($items); array_push($rows, array( $feed->title, - $feed->cnt, + $cnt, l('edit', 'user/'. $user->uid .'/planet/'. intval($feed->fid)), $checked, ) ); } - $output .= '

    Feeds

    '; - $output .= theme('table', $headers, $rows); - } - print theme('page', $output); - } + return theme('table', $headers, $rows); } +/** + * Adds a new feed to planet_feeds table. + * @param $data associative array with keys + * 'uid' (optional), 'title', 'link', 'image' (optional) + */ +function planet__add_feed($data) { + $data['checked'] = 0; + $data['frozen'] = 0; + $rslt = drupal_write_record('planet_feeds', $data); + if ($rslt!=SAVED_NEW) trigger_error('Failed to add new feed'); + $title = planet_refresh(intval($data['fid'])); + drupal_set_message('Added new feed: ' . $title); +} +/** + * Updates an existing feed in planet_feeds table. + * @param $data associative array with keys + * 'fid' (mandatory, primary key), + * other fields as needed: + * 'uid', 'title', 'link', 'image', 'checked', 'frozen' + */ +function planet__update_feed($data) { + $rslt = drupal_write_record('planet_feeds', $data, 'fid'); + if ($rslt!=SAVED_UPDATED) trigger_error('Failed to edit feed'); + drupal_set_message('Edited "'. $data['title'] .'" feed.'); +} + +/** + * Updates an planet settings persistent variables. + * @param $data associative array with all optional keys + * 'planet_author_roles', 'planet_filter_formats', + * 'planet_redirect_page'. + */ +function planet__update_vars($data) { + if ($edit['planet_author_roles']) { + variable_set('planet_author_roles', $edit['planet_author_roles']); + } + if ($edit['planet_filter_formats']) { + variable_set('planet_filter_formats', $edit['planet_filter_formats']); + } + if ($edit['planet_redirect_page'] == 1) { + variable_set('planet_redirect_page', $edit['planet_redirect_page']); + } else { + variable_del('planet_redirect_page'); + } + drupal_set_message('Edited general planet settings.'); +} + +/** + * Page callback for 'admin/settings/planet' ("Planet Settings") + */ function _planet_settings() { if ($_POST) { $edit = $_POST; @@ -241,37 +319,23 @@ $edit['redirect'] = 'admin/settings/planet'; return drupal_get_form('planet_multiple_delete_confirm_submit', $edit); } - else { - if (isset($edit['fid']) && intval($edit['fid']) == 0) { - db_query('INSERT INTO {planet_feeds} (uid, title, link, image, checked, frozen) VALUES(%d, "%s", "%s", "%s", 0, 0)', $edit['uid'], $edit['title'], $edit['link'], $edit['image']); - $edit_r = db_fetch_array(db_query('SELECT fid FROM {planet_feeds} WHERE uid = %d AND title = "%s" AND link = "%s"', $edit['uid'], $edit['title'], $edit['link'])); - $title = planet_refresh(intval($edit_r['fid'])); - drupal_set_message('Added new feed: ' . $title); - } - else if ($edit['fid'] && intval($edit['fid']) > 0) { - db_query('UPDATE {planet_feeds} SET uid = %d, title="%s", link = "%s", image="%s" WHERE fid=%d', $edit['uid'], $edit['title'], $edit['link'], $edit['image'], $edit['fid']); - drupal_set_message('Edited "'. $edit['title'] .'" feed.'); - } - else { - if ($edit['planet_author_roles']) { - variable_set('planet_author_roles', $edit['planet_author_roles']); - } - if ($edit['planet_filter_formats']) { - variable_set('planet_filter_formats', $edit['planet_filter_formats']); - } - if ($edit['planet_redirect_page'] == 1) { - variable_set('planet_redirect_page', $edit['planet_redirect_page']); - } - else { - variable_del('planet_redirect_page'); - } - drupal_set_message('Edited general planet settings.'); + else { + if (isset($edit['fid'])) { + if (intval($edit['fid']) == 0) { + planet__add_feed($edit); + } else { + planet__update_feed($edit); + } + } else { + // TODO if user needs to click separately for each fieldset, + // why not using different forms ? + // or conversely, allow setting everything at once ? + planet__update_vars($edit); } } drupal_goto('admin/settings/planet'); - } - else { - $fid = intval(arg(3)); + } else { + $fid = intval(arg(3)); // @deprecated arg() if ($fid > 0) { $edit = db_fetch_array(db_query('SELECT * FROM {planet_feeds} WHERE fid = %d', $fid)); $output .= drupal_get_form('planet_feed_form', $edit, true); @@ -279,38 +343,49 @@ else { $output .= drupal_get_form('planet_settings_form'); - //$output .= drupal_get_form('settings', $form); - //$output .= $form; $output .= drupal_get_form('planet_feed_form', $edit); - // $result = db_query('SELECT *, (UNIX_TIMESTAMP(NOW()) - checked) _checked FROM {planet_feeds}'); - $result = db_query('SELECT COUNT(f.fid) cnt, f.*, (UNIX_TIMESTAMP(NOW()) - checked) _checked FROM {planet_feeds} f LEFT OUTER JOIN {planet_items} i ON i.fid = f.fid GROUP BY f.fid;'); - $rows = array(); - $headers = array('Feed', 'Items', 'Edit', 'Last checked', 'Refresh', 'Freeze'); - while ($feed = db_fetch_object($result)) { - $checked = intval($feed->_checked / 60) .' minutes'; - if ($feed->_checked % 60 > 0) { - $checked .= ', '. $feed->_checked % 60 .' seconds'; - } - $checked .= ' ago'; - array_push($rows, array( - $feed->title, - $feed->cnt, - l('edit', 'admin/settings/planet/'. intval($feed->fid)), - $checked, - l('refresh', 'admin/settings/planet/refresh/'. intval($feed->fid)), - l($feed->frozen ? 'unfreeze' : 'freeze', 'admin/settings/planet/'. ($feed->frozen ? 'unfreeze/' : 'freeze/') . intval($feed->fid)) - ) - ); - } $output .= '

    Feeds

    '; - $output .= theme('table', $headers, $rows); + $output .= planet__build_feeds_table(); } print theme('page', $output); } } +function planet__build_feeds_table() { + global $user; + $feeds = db_query('SELECT fid, title, checked, frozen FROM {planet_feeds} ' + . ' WHERE uid = %d;', $user->uid); + $rows = array(); + $headers = array('Feed', 'Items', 'Edit', 'Last checked', 'Refresh', 'Freeze'); + $now = time(); + $items_statement = 'SELECT count(*) FROM {planet_items} WHERE fid=%'; + // TODO: change this to prepared statement when supported by drupal DB Abstraction Layer. + while ($feed = db_fetch_object($feeds)) { + $_checked = $now - $feed->checked; + $checked = intval($_checked / 60) .' minutes'; + if ($_checked % 60 > 0) { + $checked .= ', '. $feed->_checked % 60 .' seconds'; + } + $checked .= ' ago'; + $items = db_query($items_statement, $feed->fid); + if (!$items) trigger_error('ERROR while counting feed items.'); + $cnt = db_result($items); + $fid = strval($feed->fid); + array_push($rows, array( + $feed->title, + $cnt, + l('edit', 'admin/settings/planet/'. $fid), + $checked, + l('refresh', 'admin/settings/planet/refresh/'. $fid), + l($feed->frozen ? 'unfreeze' : 'freeze', 'admin/settings/planet/'. ($feed->frozen ? 'unfreeze/' : 'freeze/') . $fid) + ) + ); + } + return theme('table', $headers, $rows); +} + function planet_multiple_delete_confirm(&$form_state, $nodes, $fid, $redirect) { $form_state['values']['fid'] = $fid; $form_state['values']['redirect'] = $redirect; @@ -1229,10 +1304,16 @@ } //print '
    '. print_r($entry, 1) .'
    '; node_save($entry); - db_query('INSERT INTO {planet_items} (fid, nid, guid, link, created) VALUES(%d, %d, "%s", "%s", UNIX_TIMESTAMP(NOW()))', $feed->fid, $entry->nid, $guid, $link); + $item_record = array('fid' => $feed->fid, + 'nid' => $entry->nid, + 'guid'=> $guid, + 'link' =>$link, + 'created' => time()); + drupal_write_record('planet_items', $item_record); watchdog('planet', 'Adding '. $title); drupal_set_message('Adding '. $title); } + // TODO split this huge function } return $items_added; @@ -1333,6 +1414,9 @@ } } +/** + * Page callback for 'planet' ("Planet") + */ function planet_page_last() { global $user; @@ -1351,6 +1435,9 @@ print theme('page', $output); } +/** + * Page callback for 'planet/feed' ("Planet") + */ function planet_feed() { $result = db_query_range(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE n.type = 'planet' AND n.status = 1 ORDER BY n.created DESC"), 0, 15); $title = db_fetch_array(db_query("SELECT link_title FROM {menu_links} WHERE link_path = 'planet'")); @@ -1409,6 +1496,9 @@ } } +/** + * Page callback for 'planet/%' ("planet") + */ function planet_page_user($uid) { global $user;