diff -urN publish_47/publish.info publish_5/publish.info --- publish_47/publish.info 1969-12-31 19:00:00.000000000 -0500 +++ publish_5/publish.info 2007-06-11 18:24:19.526581928 -0400 @@ -0,0 +1,5 @@ +name = Publish +description = Allow site to send content to other Drupal sites. +version = 5.x-1.x-dev +dependencies = taxonomy +package = Publish \ No newline at end of file diff -urN publish_47/publish.install publish_5/publish.install --- publish_47/publish.install 2006-12-08 14:49:14.000000000 -0500 +++ publish_5/publish.install 2007-06-11 18:24:19.519582992 -0400 @@ -12,7 +12,7 @@ pub_vocab varchar(255) NOT NULL default '', UNIQUE KEY channel_id (channel_id,type) ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;"); - + db_query("CREATE TABLE {publish_channel} ( channel_id int(10) unsigned NOT NULL auto_increment, name varchar(255) NOT NULL default '', @@ -26,6 +26,11 @@ PRIMARY KEY (channel_id) ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;"); + db_query("CREATE TABLE {publish_views} ( + channel_id int(10) unsigned NOT NULL default '0', + view_name varchar(32) NOT NULL default '0' + ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;"); + db_query("CREATE TABLE {publish_subscribers} ( channel_id int(10) unsigned NOT NULL default '0', sid int(10) unsigned NOT NULL default '0', @@ -52,18 +57,6 @@ PRIMARY KEY (qid) ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;"); - db_query("CREATE TABLE {publish_cond} ( - fid int(10) NOT NULL default '0', - channel_id int(10) NOT NULL default '0', - sid int(10) NOT NULL default '0', - field varchar(128) NOT NULL default '', - cond varchar(16) NOT NULL default '', - value varchar(255) NOT NULL default '', - PRIMARY KEY (fid), - KEY channel_id (channel_id), - KEY sid (sid) - ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;"); - db_query("CREATE TABLE {publish_vocab_map} ( channel_id int(10) NOT NULL default '0', sid int(10) unsigned NOT NULL default '0', @@ -105,4 +98,25 @@ } return $ret; +} + +function publish_update_3() { + switch($GLOBALS['db_type']) { + case 'mysql': + case 'mysqli': + $r = db_query("CREATE TABLE {publish_views} ( + channel_id int(10) unsigned NOT NULL default '0', + view_name varchar(32) NOT NULL default '0' + ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;"); + break; + case 'pgsql': + $r = FALSE; + break; + } + + if($r) { + drupal_set_message(t("Publish updated to integrate with views.")); + } else { + drupal_set_message(t("Publish could not be updated to integrate with views. Perhaps you are running an unsupported database type."), 'error'); + } } \ No newline at end of file diff -urN publish_47/publish.module publish_5/publish.module --- publish_47/publish.module 2006-10-31 16:50:29.000000000 -0500 +++ publish_5/publish.module 2007-06-11 18:24:19.519582992 -0400 @@ -25,13 +25,11 @@ */ function publish_help($section) { switch ($section) { - case 'admin/modules#description': - return t('Allow site to send content to other Drupal sites.'); - case 'admin/publish' : + case 'admin/build/publish' : return t('

Channels can be subscribed to by other Drupal sites using the subscribe module.

'); - case strstr($section, 'admin/publish/pub/nodes'): + case strstr($section, 'admin/build/publish/pub/nodes'): return t('

Choose which which node types you would like to publish to other Drupal sites.

'); - case strstr($section, 'admin/publish/pub/vocabularies'): + case strstr($section, 'admin/build/publish/pub/vocabularies'): return t('

Choose which vocabularies will accompany the nodes you publish to other Drupal sites. If a checkbox does not appear next to a node type it is because the node type is not associated with the vocabulary (you can change associations using administer > categories > edit vocabulary.)

'); } } @@ -40,73 +38,107 @@ * Implementation of hook_menu(). */ function publish_menu($may_cache) { + $path = drupal_get_path('module', 'publish'); + require_once("$path/publish_views.inc"); + $items = array(); $admin = user_access('administer channels'); if (!$may_cache) { - if (arg(2) == 'pub' && is_numeric(arg(4))) { - $items[] = array( - 'path' => 'admin/publish/pub/edit/' . arg(4), - 'title' => t('edit'), - 'callback' => 'publish_channel_edit', - 'type' => MENU_CALLBACK, - 'access' => $admin); - } + /** + * Subscribers. + */ $items[] = array( - 'path' =>'admin/publish/subscribers/' . arg(3), - 'title' => t('subscribers'), + 'path' =>'admin/build/publish/subscribers/' . arg(4), + 'title' => t('Subscribers'), 'callback' => 'publish_subscribers', + 'callback arguments' => array( + arg(4), // Channel ID + ), 'type' => MENU_CALLBACK, - 'access' => $admin); - $items[] = array('path' => 'admin/publish/filters/' . arg(3), - 'title' => t('filters'), - 'callback' => 'publish_channel_filter_form', + 'access' => $admin, + ); + + /** + * Channel wizard. + */ + $items[] = array( + 'path' => 'admin/build/publish/pub/edit', + 'title' => t('Edit'), + 'callback arguments' => array( + arg(5), // Channel ID + ), + 'callback' => 'publish_channel_edit', + 'type' => MENU_CALLBACK, + 'access' => $admin, + ); + $items[] = array( + 'path' => 'admin/build/publish/pub/vocabularies', + 'title' => t('Vocabularies'), + 'callback' => 'drupal_get_form', + 'callback arguments' => array( + 'publish_vocabulary_form', // Form ID + arg(5), // Channel ID + ), 'type' => MENU_CALLBACK, - 'access' => $admin); - $items[] = array('path' => 'admin/publish/edit/' . arg(4), - 'title' => t('configure'), - 'callback' => 'publish_channel_edit', + 'access' => $admin, + ); + $items[] = array( + 'path' => 'admin/build/publish/pub/views', + 'title' => t('Views'), + 'callback' => 'publish_channel_views', + 'callback arguments' => array( + arg(5), // Channel ID + ), 'type' => MENU_CALLBACK, - 'access' => $admin); + 'access' => $admin, + ); + $items[] = array( + 'path' => 'admin/build/publish/pub/delete', + 'title' => t('Delete'), + 'callback' => 'drupal_get_form', + 'callback arguments' => array( + 'publish_channel_delete_form', // Form ID + arg(5), // Channel ID + ), + 'type' => MENU_CALLBACK, + 'access' => $admin, + ); } else { + /** + * Main UI. + */ $items[] = array( - 'path' => 'admin/publish', - 'title' => t('publish'), + 'path' => 'admin/build/publish', + 'title' => t('Publish'), 'callback' => 'publish_overview', - 'access' => $admin); - $items[] = array( - 'path' => 'admin/publish/pub/vocabularies', - 'title' => t('vocabularies'), - 'callback' => 'publish_vocabulary_form', - 'type' => MENU_CALLBACK, - 'access' => $admin); + 'access' => $admin, + ); + + /** + * Tabs + */ $items[] = array( - 'path' => 'admin/publish/list', - 'title' => t('channels'), + 'path' => 'admin/build/publish/list', + 'title' => t('Channels'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, 'callback' => 'publish_overview', - 'access' => $admin); + 'access' => $admin, + ); $items[] = array( - 'path' => 'admin/publish/add', - 'title' => t('add channel'), + 'path' => 'admin/build/publish/add', + 'title' => t('Add channel'), 'type' => MENU_LOCAL_TASK, - 'callback' => 'publish_channel_form', - 'access' => $admin); - $items[] = array( - 'path' => 'admin/publish/pub/delete', - 'title' => t('delete'), - 'callback' => 'publish_channel_delete_form', - 'type' => MENU_CALLBACK, - 'access' => $admin); - $items[] = array( - 'path' => 'admin/publish/pub/filters/delete', - 'title' => t('filters'), - 'callback' => 'publish_channel_filter_delete_form', - 'type' => MENU_CALLBACK, - 'access' => $admin); + 'callback' => 'drupal_get_form', + 'callback arguments' => array( + 'publish_channel_form', // Form ID + ), + 'access' => $admin, + ); } + return $items; } @@ -114,7 +146,10 @@ * Implementation of hook_perm(). */ function publish_perm() { - return array('subscribe to channels', 'administer channels'); + return array( + 'subscribe to channels', + 'administer channels', + ); } /******************************************************************** @@ -128,6 +163,9 @@ * */ function publish_cron() { + $path = drupal_get_path('module', 'publish'); + require_once("$path/publish_views.inc"); + publish_push(); } @@ -141,33 +179,47 @@ switch ($op) { case 'insert': case 'update': - // exit quickly if node is not in published state - if ($node->status != 1) { - return; - } if (PUBLISH_DEBUG_MODE) watchdog('publish', t('nodeapi firing')); - // Find all subscribers to this node. - $result = db_query("SELECT * FROM {publish_channel} p INNER JOIN {publish_nodetypes} n ON n.channel_id = p.channel_id INNER JOIN {publish_subscribers} s ON s.channel_id = p.channel_id WHERE n.type = '%s'", $node->type); - $exists = db_result(db_query("SELECT nid FROM {publish_queue} WHERE nid = %d", $node->nid)); - if ($exists) { // delete older version from queue - db_query("DELETE FROM {publish_queue} WHERE nid = %d", $node->nid); + //Get all channels + $qs = db_query("SELECT pc.channel_id, pc.name FROM {publish_channel} pc WHERE pc.whenpub = 1"); + while($obj = db_fetch_object($qs)) { + $channels[$obj->channel_id] = $obj->name; } - $publish_now = FALSE; - while ($data = db_fetch_object($result)) { - if ($data->whenpub == PUBLISH_WHENPUB_NODESUB) { - $publish_now = TRUE; - } - // add them to the queue to have the node pushed out to them - // TODO: we should run the node through the channel's condition filters here? - db_query("INSERT INTO {publish_queue} (qid, nid, sid, channel_id, changed) VALUES (%d, %d, %d, %d, %d)", db_next_id('publish_queue'), $node->nid, $data->sid, $data->channel_id, $node->changed); - if (PUBLISH_DEBUG_MODE) watchdog('publish', t('channel %cid added node %nid to q for subscriber id %sid', array('%cid' => $data->channel_id, '%nid' => $node->nid, '%sid' => $data->sid))); + + //Get all subscribers, keyed by channel_id and then by subscriber id. + $qs = db_query("SELECT ps.sid, ps.channel_id from {publish_subscribers} ps"); + while($obj = db_fetch_object($qs)) { + $subscribers[$obj->channel_id][$obj->sid] = $obj->sid; } - // set publish on exit if channel is set to publish at node submission time - if ($publish_now) { - if (PUBLISH_DEBUG_MODE) watchdog('publish', t('setting publish_exit')); - publish_exit(TRUE); + + //Check to see if this node already exists in the publish queue. If it does, delete it. + $exists = db_result(db_query("SELECT COUNT(pq.nid) FROM {publish_queue} pq WHERE pq.nid = %d", $node->nid)); + if($exists > 0) { + db_query("DELETE FROM {publish_queue} WHERE nid = %d", $node->nid); + } + + $publish_now = FALSE; + foreach($channels as $channel_id => $channel) { + $channel_subscribers = $subscribers[$channel_id]; + + //Get all nodes of the channel. + $nodes = publish_get_nodes_by_channel($channel_id, 'nid'); + + //If the node is in the channel, add it to the queue for each subscriber. + if(array_key_exists($node->nid, (array)$nodes)) { + $publish_now = TRUE; + foreach(array_keys((array)$channel_subscribers) as $sid) { + db_query("INSERT INTO {publish_queue} (qid, nid, sid, channel_id, changed) VALUES (%d, %d, %d, %d, %d)", db_next_id('publish_queue'), $node->nid, $sid, $channel_id, $node->changed); + if (PUBLISH_DEBUG_MODE) watchdog('publish', t('channel !cid added node !nid to q for subscriber id !sid', array('!cid' => $channel_id, '!nid' => $node->nid, '!sid' => $sid))); + } + } } - break; + + // Set publish on exit if channel is set to publish at node submission time + if ($publish_now) { + if (PUBLISH_DEBUG_MODE) watchdog('publish', t('setting publish_exit')); + publish_exit(TRUE); + } } } @@ -197,14 +249,26 @@ * Registering xml-rpc methods to callback functions. */ function publish_xmlrpc() { + return array( + 'drupal.publish.maySubscribe' => 'publish_xmls_may_subscribe', + 'drupal.publish.subscribe' => 'publish_xmls_receive_subscription', + 'drupal.publish.pull' => 'publish_xmls_publish', + 'drupal.publish.getNode' => 'publish_xmls_get_node', + 'drupal.publish.getChannels' => 'publish_xmls_get_channels', + 'drupal.publish.cancelSubscription' => 'publish_xmls_cancel_subscription', + ); + + /** + * TODO: Update function signatures to match what we currently have. return array( array('drupal.publish.maySubscribe', 'publish_xmls_may_subscribe', array('array', 'int','string','string'), t('Return channel info if caller supplies appropriate credentials.')), array('drupal.publish.subscribe', 'publish_xmls_receive_subscription', array('int', 'int', 'string', 'string', 'string', 'string', 'array', 'array', 'array'), t('Establish relationship with subscriber.')), - array('drupal.publish.pull', 'publish_xmls_publish', array('array', 'int', 'int', 'string', 'string', 'array'), t('Send nodes matching certain conditions to subscriber.')), + array('drupal.publish.pull', 'publish_xmls_publish', array('array', 'int', 'int', 'string', 'string'), t('Send nodes matching certain conditions to subscriber.')), array('drupal.publish.getNode', 'publish_xmls_get_node', array('array', 'int', 'string', 'string', 'int'), t('Send single node to subscriber.')), array('drupal.publish.getChannels', 'publish_xmls_get_channels', array('array'), t('Return list of public channels on this site.')), array('drupal.publish.cancelSubscription', 'publish_xmls_cancel_subscription', array('boolean', 'int', 'string'), t('Cancel subscription.')) ); + */ } /******************************************************************** @@ -223,20 +287,20 @@ $row = array(); while ($data = db_fetch_object($result)) { $edit_items = array(); - $edit_items[] = l(t('edit'), "admin/publish/pub/edit/$data->channel_id"); - $edit_items[] = l(t('vocabularies'), "admin/publish/pub/vocabularies/$data->channel_id"); - $edit_items[] = l(t('filters'), "admin/publish/filters/$data->channel_id"); + $edit_items[] = l(t('edit'), "admin/build/publish/pub/edit/$data->channel_id"); + $edit_items[] = l(t('vocabularies'), "admin/build/publish/pub/vocabularies/$data->channel_id"); + $edit_items[] = l(t('views'), "admin/build/publish/pub/views/$data->channel_id"); $count = db_result(db_query("SELECT COUNT(*) FROM {publish_subscribers} WHERE channel_id = %d", $data->channel_id)); - $edit_items[] = l(t('delete'), "admin/publish/pub/delete/$data->channel_id"); + $edit_items[] = l(t('delete'), "admin/build/publish/pub/delete/$data->channel_id"); $row[] = array( array('data' => $data->channel_id, 'valign' => 'top'), array('data' => "$data->name", 'valign' => 'top'), array('data' => $data->advertise ? t('yes') : t('no'), 'valign' => 'top'), - array('data' => $count ? l($count, "admin/publish/subscribers/$data->channel_id") : t('none'), 'valign' => 'top'), + array('data' => $count ? l($count, "admin/build/publish/subscribers/$data->channel_id") : t('none'), 'valign' => 'top'), array('data' => implode("
\n", $edit_items))); } - $output = $row ? theme('table', $header, $row) : t('No channels created. Would you like to create one?', array('%add-channel' => url('admin/publish/add'))); + $output = $row ? theme('table', $header, $row) : t('No channels created. Would you like to create one?', array('!add-channel' => url('admin/build/publish/add'))); return $output; } @@ -251,26 +315,147 @@ * An object representing a channel */ function publish_channel_load($channel_id) { + $channel = db_fetch_object(db_query('SELECT * FROM {publish_channel} WHERE channel_id = %d', $channel_id)); if ($channel) { - $result = db_query('SELECT * FROM {publish_cond} WHERE channel_id = %d AND sid = 0', $channel_id); - $channel->filters = array(); - while ($data = db_fetch_object($result)) { - $channel->filters[] = array('fid' => $data->fid, 'field' => $data->field, 'operator' => $data->cond, 'value' => $data->value); - } + $views = db_result(db_query("SELECT pv.view_name FROM {publish_views} pv WHERE pv.channel_id = %d", $channel_id)); + $channel->views['view'] = $views; + $arguments = views_argument_api_get('publish_channel_' . $channel_id, array()); + $channel->views['arguments'] = $arguments; } return $channel; } -function publish_channel_edit() { - $channel_id = arg(4); +function publish_channel_views($channel_id) { + $op = check_plain($_POST['op']); + $view_name = check_plain($_POST['channel_view']); + + if($op == t('Update')) { + publish_channel_view_save($channel_id, $view_name); + } + + $channel = publish_channel_load($channel_id); + + if(empty($channel)) { + drupal_set_message(t('No such channel.', 'error')); + drupal_goto('admin/build/publish'); + } else { + return drupal_get_form('publish_channel_views_form', $channel); + } +} + +function publish_channel_views_form($channel) { + //Todo: Good candidate for jQuery + + //Put together a views selector and an update button. + $form['channel_id'] = array( + '#type' => 'value', + '#value' => $channel->channel_id, + ); + + $form['view'] = array( + '#type' => 'fieldset', + '#title' => t('View'), + '#collapsible' => FALSE, + '#collasped' => FALSE, + ); + + $form['view']['channel_view'] = array( + '#title' => t('View'), + '#description' => t('Select a view to use with this channel.'), + '#type' => 'select', + '#default_value' => $channel->views['view'], + '#value' => $channel->views['view'], + '#options' => publish_get_views(), + ); + $form['view']['channel_update'] = array( + '#type' => 'button', + '#value' => t('Update'), + ); + + //Node types + $view = views_get_view($channel->views['view']); + $filters = $view->filter; + foreach((array)$filters as $filter) { + if($filter['field'] == 'node.type') { + $types = $filter['value']; + } + } + + if(empty($types)) { + foreach(node_get_types() as $type) { + $types[] = $type->type; + } + } + + $form['node_types'] = array( + '#type' => 'value', + '#value' => $types, + ); + + $typemsg = theme('item_list', $types); + + $form['node_types_message'] = array( + '#title' => t('Node types'), + '#description' => t('This channel currently uses a view that publishes nodes of the following types:'), + '#type' => 'fieldset', + '#collapsible' => TRUE, + '#collapsed' => FALSE, + ); + + $form['node_types_message']['list'] = array( + '#type' => 'item', + '#value' => $typemsg, + ); + + //Put together a place for arguments + $form['channel_arguments'] = array( + '#title' => t('View arguments'), + '#type' => 'fieldset', + '#collapsible' => TRUE, + '#collapsed' => FALSE, + '#theme' => 'views_argument_api_form_tabular', + ); + + $views_argument_api_form = views_argument_api_build_argument_form($channel->views['view']); + $views_argument_api_default_values = views_argument_api_get('publish_channel_' . $channel->channel_id, NULL); + + foreach($views_argument_api_form as $key => $element) { + $form['channel_arguments'][$key] = $element; + $form['channel_arguments'][$key]['#default_value'] = $views_argument_api_default_values[$key]; + } + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; +} + + +function publish_channel_views_form_submit($form_id, $form_values) { + //Save a channel's view. + publish_channel_view_save($form_values['channel_id'], $form_values['channel_view']); + + //Save a channel's view arguments. + views_argument_api_save_arguments('publish_channel_' . $form_values['channel_id'], $form_values, $form_values['channel_view']); + + //Save the node type information + publish_node_save($form_values); + + drupal_set_message(t('The channel was updated.')); + return 'admin/build/publish'; +} + +function publish_channel_edit($channel_id) { $channel = publish_channel_load($channel_id); if (!$channel) { drupal_set_message(t('No such channel.', 'error')); - drupal_goto('admin/publish'); + drupal_goto('admin/build/publish'); } - return publish_channel_form($channel); + return drupal_get_form('publish_channel_form', $channel); } /** @@ -282,16 +467,9 @@ * Array with form values * * @return - * HTML output + * An array of form elements. */ function publish_channel_form($channel = NULL, $edit = array()) { - if (!isset($channel->name)) { - $output = '

' . t('Adding channel') . '

'; - } - else { - $output = '

' . t('Configuring channel') . ' "' . $channel->name . '"' . '

'; - } - $form['name'] = array( '#type' => 'textfield', '#title' => t('Name'), @@ -314,22 +492,6 @@ '#description' => t('Show name and description of this channel when another site asks which channels are available.') ); - $published = array(); - $result = db_query("SELECT * FROM {publish_nodetypes} WHERE channel_id = '%s'", $channel->channel_id); - while ($data = db_fetch_object($result)) { - $published[] = $data->type; - } - - $form['node_types'] = array( - '#type' => 'fieldset', - '#title' => t('Node types') - ); - $form['node_types']['types'] = array( - '#type' => 'checkboxes', - '#title' => t('Publish the following node types'), - '#default_value' => $published, - '#options' => node_get_types(), - ); $form['authentication'] = array( '#type' => 'fieldset', '#title' => t('Who may subscribe to this channel?') @@ -338,7 +500,7 @@ '#type' => 'radios', '#title' => t('Choose an authorization model'), '#default_value' => isset($channel->authtype) ? $channel->authtype : 'none', - '#options' => array(t('None'), t('Users with %perm permission', array('%perm' => theme('placeholder', 'subscribe to channel'))), t('Username and password (enter below)')) + '#options' => array(t('None'), t('Users with %perm permission', array('%perm' => 'subscribe to channel')), t('Username and password (enter below)')) ); $form['authentication']['username'] = array( '#type' => 'textfield', @@ -362,7 +524,8 @@ '#type' => 'textarea', '#title' => t('Domains'), '#rows' => '2', - '#description' => t('Subscribers will be restricted to domains listed here, e.g. %example. If no domains are listed, all may subscribe.', array('%example' => theme('placeholder', 'example.org, example2.org'))) + '#description' => t('Subscribers will be restricted to domains listed here, e.g. %example. If no domains are listed, all may subscribe.', array('%example' => 'example.org, example2.org')), + '#default_value' => $channel->domains, ); $form['channel_id'] = array( '#type' => 'value', @@ -382,7 +545,7 @@ '#type' => 'submit', '#value' => t('Update Channel Settings') ); - return drupal_get_form('publish_channel_form', $form); + return $form; } /** @@ -416,9 +579,7 @@ form_set_value($form['domains']['allowed'], ltrim($clean_domains, ',')); } } - if (!array_filter($form_values['types'])) { - $errors['types'] = t('You must choose at least one node type to publish.'); - } + foreach ($errors as $name => $message) { form_set_error($name, $message); } @@ -426,210 +587,19 @@ function publish_channel_form_submit($form_id, $form_values) { // get an array of checked node types - $form_values['types'] = array_filter($form_values['types']); if ($form_values['channel_id']) { publish_channel_save($form_values); } else { // new channel $form_values['channel_id'] = publish_channel_save($form_values); } - publish_node_save($form_values); - return 'admin/publish'; -} - -/** - * Menu callback. Build form for editing channel filters - * - * @param $edit - * Array with form values - * - * @return - * HTML output - */ -function publish_channel_filter_form($edit = array()) { - $channel_id = arg(3); - $channel = publish_channel_load($channel_id); - if (!$channel) { - drupal_set_message(t('No such channel.'), 'error'); - drupal_goto('admin/publish'); - } - $form['field'] = array( - '#type' => 'select', - '#title' => t('Field'), - '#options' => publish_channel_filter_options() - ); - foreach (publish_supported_operators() as $operator) { - $operators[$operator] = $operator; - } - $form['operation'] = array( - '#type' => 'select', - '#title' => t('Condition'), - '#options' => $operators - ); - $form['value'] = array( - '#type' => 'textfield', - '#title' => t('Value'), - '#size' => '25', - '#maxlength' => '254' - ); - $form['submit'] = array( - '#type' => 'submit', - '#value' => t('Add filter') - ); - $form['channel_id'] = array( - '#type' => 'value', - '#value' => $channel_id); - return drupal_get_form('publish_channel_filter_form', $form); -} - -function theme_publish_channel_filter_form($form) { - $channel = publish_channel_load($form['channel_id']['#value']); - if (count($channel->filters)) { - $output = t('The following filters are in effect for this channel:'); - $header = array(t('Field'), t('Condition'), t('Value'), t('Operation')); - foreach ($channel->filters as $filter) { - $operation = l(t('delete'), 'admin/publish/pub/filters/delete/' . $channel->channel_id . '/' .$filter['fid']); - $rows[] = array( - array('data' => $filter['field']), - array('data' => $filter['condition']), - array('data' => $filter['value']), - array('data' => $operation) - ); - } - $output = theme('table', $header, $rows); - } - else { - $output = t('No filters are currently defined.'); - } - - // we don't want theming so we do a table the old-fashioned way - $output .= ''; - $output .= ''; - $output .= '
' . form_render($form['field']) . ''; - $output .= '' . form_render($form['operation']) . ''; - $output .= '' . form_render($form['value']) . ''; - $output .= '' . form_render($form['submit']) . '
'; - $output .= form_render($form); - - return $output; -} - -function publish_channel_filter_options() { - $v_names = array(); - if (module_exist('taxonomy')) { - $vocabularies = taxonomy_get_vocabularies(); - foreach ($vocabularies as $v) { - $v_names[$v->vid] = $v->name; - } - } - $merged = array_merge($v_names, publish_supported_fields()); - foreach ($merged as $name) { - $options[$name] = $name; - } - return $options; -} - -function publish_channel_filter_form_validate($form_id, $edit) { - $errors = array(); - - if ($edit['field'] == '') { - $errors['field'] = t('Please choose a field.'); - } - elseif (!array_key_exists($edit['field'], publish_channel_filter_options())) { - $errors['field'] = t('Invalid field.'); - } - - if (!in_array($edit['operation'], publish_supported_operators())) { - $errors['operation'] = t('Invalid condition.'); - } - - foreach ($errors as $name => $message) { - form_set_error($name, $message); - } -} - -function publish_channel_filter_form_submit($form_id, $form_values) { - $channel = publish_channel_load($form_values['channel_id']); - publish_channel_filter_save($channel, $form_values); - drupal_set_message(t('Filter added.')); - return 'admin/publish/filters/' . $form_values['channel_id']; -} - -function publish_channel_filter_save(&$channel, $edit = array()) { - $options = publish_channel_filter_options(); - $field = $options[$edit['field']]; - $condition = $edit['operation']; - $value = $edit['value']; - // get the new field, condition and value from the form - // validate them (make sure they're not already in - if (!isset($channel->filters)) { - $channel->filters = array(); - } - $duplicate = FALSE; - foreach ($channel->filters as $filter) { - if (($filter['field'] == $field) && ($filter['condition'] == $condition) && ($filter['value'] == $value)) { - $duplicate = TRUE; - } - } - if (!$duplicate) { - $fid = db_next_id('publish_filter'); - $channel->filters[] = array('fid' => $fid, 'field' => $field, 'condition' => $condition, 'value' => $value); - // the insertion of 0 into the sid (subscription id) field denotes - // that this condition is a local channel condition - db_query("INSERT INTO {publish_cond} (fid, channel_id, sid, field, cond, value) VALUES (%d, %d, 0, '%s', '%s', '%s')", $fid, $channel->channel_id, $field, $condition, $value); - } - else { - drupal_set_message(t('This filter already exists.'), 'error'); - } + return 'admin/build/publish'; } -function publish_channel_filter_delete_form() { - $channel_id = arg(5); - $filter_id = arg(6); - $channel = publish_channel_load($channel_id); - if (!$channel) { - drupal_set_message(t('No such channel.', 'error')); - drupal_goto('admin/publish'); - } - $form['channel_id'] = array('#type' => 'value', '#value' => $channel_id); - $form['filter_id'] = array('#type' => 'value', '#value' => $filter_id); - $output = confirm_form('publish_channel_filter_delete_form', $form, - t('Are you sure you want to delete this filter?'), - 'admin/publish', t('This action cannot be undone.'), - t('Delete'), t('Cancel') ); - return $output; -} - -function publish_channel_filter_delete_form_submit($form_id, $form_values) { - publish_channel_filter_delete($form_values['channel_id'], $form_values['filter_id']); - return 'admin/publish/filters/' . $form_values['channel_id']; -} -function publish_channel_filter_delete($channel_id, $fid) { - $data = db_fetch_object(db_query('SELECT pc.field, pc.cond, pc.value, pp.name FROM {publish_cond} as pc, {publish_channel} as pp WHERE pc.fid = %d AND pp.channel_id = %d', $fid, $channel_id)); - $filtertext = $data->field . ' ' . $data->cond . ' ' . $data->value; - db_query('DELETE FROM {publish_cond} WHERE fid = %d', $fid); - watchdog('special', t('Deleted filter %filter from channel %name.', array('%filter' => theme('placeholder', $filtertext), '%name' => $data->name))); - drupal_set_message(t('Deleted filter %filter.', array('%filter' => theme('placeholder', $filtertext)))); -} - -/** - * Load list of publishable node types from the database. - * - * @param $channel_id - * The ID of the channel in question. - * - * @return - * An array with node types as keys - */ -function publish_nodetypes_load($channel_id) { - $types = array(); - - $result = db_query('SELECT type FROM {publish_nodetypes} WHERE channel_id = %d', $channel_id); - while ($data = db_fetch_object($result)) { - $types[$data->type] = $data->type; - } - - return $types; +function publish_channel_view_save($channel_id, $view_name) { + db_query("DELETE FROM {publish_views} WHERE channel_id = %d", $channel_id); + $r = db_query("INSERT INTO {publish_views} (channel_id, view_name) VALUES (%d, '%s')", $channel_id, $view_name); + return $r; } /** @@ -638,7 +608,8 @@ * @param $edit */ function publish_channel_save($edit) { - if (!$edit['clean_domains']) $edit['clean_domains'] = ''; +// if (!$edit['clean_domains']) $edit['clean_domains'] = ''; + $edit['domains'] = $edit['allowed']; $channel_id = $edit['channel_id']; $fields = publish_db_fields('publish_channel'); @@ -652,8 +623,8 @@ } } db_query("UPDATE {publish_channel} SET ". implode(', ', $q) ." WHERE channel_id = ". db_escape_string($edit['channel_id']), $v); - watchdog('special', t('%type: updated channel %name', array('%type' => ''. t('publish') .'', '%name' => "" . $edit['name'] . ""))); - drupal_set_message(t('Updated channel %name', array('%name' => theme('placeholder', $edit['name'])))); + watchdog('special', t('%type: updated channel %name', array('%type' => t('publish'), '%name' => $edit['name']))); + drupal_set_message(t('Updated channel %name', array('%name' => $edit['name']))); } else { // create new channel @@ -672,35 +643,32 @@ // Insert the node into the database: $query = "INSERT INTO {publish_channel} (". implode(", ", $k) .") VALUES(". implode(", ", $s) .")"; db_query($query, $v); - watchdog('special', t('%type: created channel %name.', array('%type' => ''. t('publish') .'', '%name' => "" . $edit['name'] . ""))); - drupal_set_message(t('Created channel %name', array('%name' => theme('placeholder', $edit['name'])))); + watchdog('special', t('!type: created channel !name.', array('!type' => t('publish'), '!name' => $edit['name']))); + drupal_set_message(t('Created channel !name', array('!name' => $edit['name']))); } return $edit['channel_id']; } /** - * Menu callback. - * The HTML form to confirm deletion of a channel. + * The form to confirm deletion of a channel. */ -function publish_channel_delete_form() { - $channel_id = arg(4); - $channel = publish_channel_load($channel_id); +function publish_channel_delete_form($channel_id) { + $channel = publish_channel_load($channel_id); if (!$channel) { drupal_set_message(t('No such channel.', 'error')); - drupal_goto('admin/publish'); + drupal_goto('admin/build/publish'); } + $form['channel_id'] = array('#type' => 'value', '#value' => $channel_id); - $output = confirm_form('publish_delete_form', $form, - t('Are you sure you want to delete %title?', array('%title' => theme('placeholder', $channel->name))), - 'admin/publish', t('This action cannot be undone.'), - t('Delete'), t('Cancel') ); - return $output; + + return confirm_form($form, t('Are you sure you want to delete %title?', array('%title' => $channel->name)), 'admin/build/publish', t('This action cannot be undone.'), t('Delete'), t('Cancel'), 'publish_channel_delete_form'); + } -function publish_delete_form_submit($form_id, $form_values) { +function publish_channel_delete_form_submit($form_id, $form_values) { $channel = publish_channel_load($form_values['channel_id']); publish_channel_delete($channel); - return 'admin/publish'; + return 'admin/build/publish'; } /** @@ -711,71 +679,18 @@ */ function publish_channel_delete($channel) { db_query('DELETE FROM {publish_channel} WHERE channel_id = %d', $channel->channel_id); - db_query("DELETE FROM {publish_nodetypes} WHERE channel_id = '%s'", $channel->channel_id); - db_query('DELETE FROM {publish_cond} WHERE channel_id = %d', $channel->channel_id); watchdog('publish', t('deleted channel %name.', array('%name' => $channel->name))); } - -/** - * Form to set the publish settings for node types. - */ -function publish_node_form($channel_id, $edit = array()) { - - $nodetypes = array(); - foreach (node_list() as $type) { - $nodetypes[$type] = node_invoke($type, 'node_name'); - } - - $published = array(); - $result = db_query("SELECT * FROM {publish_nodetypes} WHERE channel_id = '%s'", $channel_id); - while ($data = db_fetch_object($result)) { - $published[] = $data->type; - } - - - $node_checkboxes = ''; - foreach ($nodetypes as $internal_type => $type) { - $node_checkboxes .= form_checkbox($type, 'pub_' . $internal_type, $internal_type, in_array($internal_type, $published)); - } - - $output = form_group(t('Publish the following node types'), $node_checkboxes); - $output .= form_hidden('channel_id', $channel_id); - - return $output; -} - /** * Save a nodetype config data to the database. */ function publish_node_save($edit) { - + $channel_id = $edit['channel_id']; - $submitted_nodetypes = $edit['types']; - - /* + $submitted_nodetypes = $edit['node_types']; - $nodetypes = array(); - foreach (node_list() as $type) { - $nodetypes[$type] = node_invoke($type, 'node_name'); - if ($edit['pub_' . $type]) { - $submitted_nodetypes[$type] = $type; - } - } - - $result = db_query("SELECT * FROM {publish_nodetypes} WHERE channel_id = '%s'", $channel_id); - while ($data = db_fetch_object($result)) { - if (key_exists($data->type, $submitted_nodetypes)) { - // node type exists in database and has been checked; no change so delete from array - unset($submitted_nodetypes[$data->type]); - } - else { - // node type exists in database but not checked; delete from database - db_query("DELETE FROM {publish_nodetypes} WHERE type = '%s'", $data->type); - } - } - */ db_query("DELETE FROM {publish_nodetypes} WHERE channel_id = %d", $channel_id); // now we are left with the node types to add @@ -792,12 +707,7 @@ $channel = publish_channel_load($channel_id); if (!$channel) { drupal_set_message(t('No such channel.', 'error')); - drupal_goto('admin/publish'); - } - - if (!module_exist('taxonomy')) { - drupal_set_message(t('The taxonomy module is disabled. Please enable the taxonomy module.'), 'warning'); - drupal_goto('/admin/publish'); + drupal_goto('admin/build/publish'); } $vocabularies = taxonomy_get_vocabularies(); @@ -842,7 +752,7 @@ '#name' => 'edit[' . $type . '|' . $v->name . ']', '#return_value' => 1 ); - $s = form_render($form[$type . '|' . $v->name]); + $s = drupal_render($form[$type . '|' . $v->name]); } $table .= '' . $s . ''; } @@ -864,10 +774,15 @@ else { // no node types have been chosen for publication drupal_set_message(t('No node types have been chosen for publication. Edit channel and choose at least one node type.')); - drupal_goto('/admin/publish'); + drupal_goto('/admin/build/publish'); } - return drupal_get_form('publish_vocabulary_form', $form); + $form['return'] = array( + '#type' => 'item', + '#value' => l(t('Return to Publish'), 'admin/build/publish/'), + ); + + return $form; } /** @@ -900,9 +815,9 @@ db_query("INSERT INTO {publish_nodetypes} (channel_id, type, pub_vocab) VALUES ('%s', '%s', '%s')", $channel_id, $type, serialize($vocs_this_node)); } $channel = publish_channel_load($channel_id); - drupal_set_message(t("Saved vocabulary publication configuration for channel %name.", array('%name' => theme('placeholder', $channel->name)))); + drupal_set_message(t("Saved vocabulary publication configuration for channel %name.", array('%name' => $channel->name))); - return 'admin/publish'; + return 'admin/build/publish'; } /** @@ -940,7 +855,9 @@ static $nodetypes = array(); static $published_vocabularies = array(); - $lookup = node_get_types(); + foreach(node_get_types() as $type) { + $lookup[$type->type] = $type->name; + } $result = db_query("SELECT * FROM {publish_nodetypes} WHERE channel_id = '%s'", $channel_id); while ($data = db_fetch_object($result)) { $nodetypes[$data->type] = $lookup[$data->type]; @@ -964,8 +881,7 @@ * @return * an HTML table of subscribers and related information */ - function publish_subscribers () { - $channel_id = arg(3); + function publish_subscribers($channel_id) { $channel = publish_channel_load($channel_id); $output = '

' . t('Subscribers to channel') . " '$channel->name':

"; $header = array(array('data' => t('Subscriber')), array('data' => t('Status')), array('data' => 'Operations', 'colspan' => '1')); @@ -982,73 +898,16 @@ } /** - * Compile array of publishable nodes according to given conditions. + * Compile array of publishable nodes. * * @param $channel_id * The ID of the channel in question. * - * @param $cond - * Array of triplet arrays containing field, condition, value. - * Example: array(array('created', '>', '0')) - * Example: array(array('created', '>', '0'), array('nid', '<', '5')) - * * @return * An array of node objects. */ -function publish_publish($channel_id, $cond) { - static $channels = array(); - - if (isset($channels[$channel_id])) { - $channel = $channels[$channel_id]; - } - else { - $channel = publish_channel_load($channel_id); - $channels[$channel_id] = $channel; - } - $node_ids = array(); - $published_types = publish_nodetypes_load($channel_id); - if (!$published_types) return array(); - - $where = ''; - foreach ($published_types as $type) { - $where .= "OR type = '" . (function_exists('db_escape_string') ? db_escape_string($type) : check_query($type)) . "' "; - } - // strip off leading 'OR ' - $where = $where ? '(' . strstr($where, " ") . ')' : ''; - - list($clean_cond, $taxonomy_cond) = publish_cond_validate(array_merge($channel->filters, $cond)); - $filter = array(); - - foreach ($clean_cond as $triplet) { - $field = $triplet['field']; - $operator = $triplet['operator']; - $value = $triplet['value']; - - // check if value is numeric. If not, put single quotes around it and clean it - $quot_start = ' '; - $quot_end = ' '; - $clean_value = null;; - - if (!is_numeric($value)) { - $quot_start = " '"; - $quot_end = "' "; - $clean_value = function_exists('db_escape_string') ? db_escape_string($value) : check_query($value); - } - - $filter[] = $field . ' ' . $operator . $quot_start . ($clean_value ? $clean_value : $value) . $quot_end; - } - - if ($filter) { - $where .= $filter[1] ? implode($filter, ' AND') : ' AND ' . $filter[0]; - } - - $query = "SELECT nid FROM {node} WHERE $where"; - $result = db_query($query); - while ($data = db_fetch_object($result)) { - $node_ids[] = $data->nid; - } - - return _publish_publish($node_ids, $taxonomy_cond); +function publish_publish($channel_id) { + return publish_get_nodes_by_channel($channel_id); } /** @@ -1071,76 +930,57 @@ // qtime should be long enough that an attempt to send each item // in the queue can be made within the time window // we use db_fetch_object() to get one node at a time - while ($data = db_fetch_object(db_query("SELECT * FROM {publish_queue} WHERE last_attempt < %d ORDER BY changed", time() - $qtime))) { - if (PUBLISH_DEBUG_MODE) watchdog('publish', t('beginning push for channel %channel, subscriber %subscriber', array('%channel' => $data->channel_id, '%subscriber' => $data->sid))); - - // see if there are any other nodes we can include for this subscriber - // while we have the overhead of sending xmlrpc anyway - $node_ids = array(); - $qids = array(); - $result = db_query("SELECT qid, nid, attempts FROM {publish_queue} WHERE sid = %d AND channel_id = %d", $data->sid, $data->channel_id); - while ($row = db_fetch_object($result)) { - if (PUBLISH_DEBUG_MODE) watchdog('publish', t('preparing to push qid %qid; nid %nid', array('%qid' => $row->qid, '%nid' => $row->nid))); - $node_ids[] = $row->nid; - $qids[$row->nid] = array('qid' => $row->qid, 'attempts' => $row->attempts); - } - $nodes = array(); - foreach ($node_ids as $nid) { - // run the nodes through the channel's condition filters - // note that if push is happening from nodeapi insert/update (not cron), - // _publish_publish is doing a node_load before modules after us - // have had a chance to respond to the nodeapi insert/update - // TODO: need to include the subscription's optional condition filters here; - // currently we ignore them (channel-specific filters are handled in publish_publish()) - $survived_filter = publish_publish($data->channel_id, array(array('field' => 'nid', 'operator' => '=', 'value' => $nid))); - if ($survived_filter) { - if (PUBLISH_DEBUG_MODE) watchdog('publish', t('keeping node %nid', array('%nid' => $nid))); - $nodes = array_merge($nodes, $survived_filter); - } - else { // this node did not pass conditions for this channel - // and thus will never be sent; delete it from the queue - if (PUBLISH_DEBUG_MODE) watchdog('publish', t('removing filtered node %nid from queue', array('%nid' => nid))); - db_query("DELETE FROM {publish_queue} WHERE qid = %d", $qids[$nid]['qid']); - } - } - - // we've got the nodes, now push them out - $subscription = publish_subscriptions_load($data->sid); - $message = array( - 'token' => $subscription->token, - 'rsid' => (int)$subscription->sid, - 'count' => count($nodes), - 'site_url' => $base_url, - 'site_name' => variable_get('site_name', 'drupal'), - 'nodes' => $nodes - ); - - $response = xmlrpc($subscription->url, 'drupal.subscribe.receive', $message); - if ($response) { - // we have successfully published the pending nodes for this channel to this subscriber - // thus, delete them from the queue - foreach ($nodes as $node) { - if (PUBLISH_DEBUG_MODE) watchdog('publish', t('removing node %nid from queue (qid %qid)', array('%nid' => $node->nid, '%qid' => $qids[$node->nid]['qid']))); - db_query("DELETE FROM {publish_queue} WHERE qid = %d", $qids[$node->nid]['qid']); - } - watchdog('publish', t('XMLRPC pushed %count nodes to %url (channel id %channel_id)', array('%count' => $message['count'], '%url' => check_plain($subscription->url), '%channel_id' => check_plain($data->channel_id)))); - } - else { // push failed - $error = xmlrpc_error_msg(); - foreach ($node_ids as $nid) { - $attempts = $qids[$nid]['attempts']; - $max_attempts = variable_get('publish_push_max_attempts', 5); - if ($attempts > $max_attempts) { - if (PUBLISH_DEBUG_MODE) watchdog('publish', t('max of %attempts attempts exceeded; removing node %nid from queue', array('%attempts' => $max_attempts, '%nid' => $node->nid))); - db_query("DELETE FROM {publish_queue} WHERE qid = %d", $qids[$nid]['qid']); - } - else { - db_query("UPDATE {publish_queue} SET attempts = %d, last_attempt = %d WHERE qid = %d", $attempts + 1, time(), $qids[$nid]['qid']); - } - } - watchdog('publish', t('XMLRPC push failed for %url (channel id %channel_id): %faultString', array('%url' => theme('placeholder', $subscription->url), '%channel_id' => theme('placeholder', $data->channel_id), '%faultString' => $error ? $error : t('unavailable'))), WATCHDOG_ERROR); - } - } + $qs = db_query("SELECT * FROM {publish_queue} WHERE last_attempt < %d ORDER BY changed", time() - $qtime); + while ($data = db_fetch_object($qs)) { + $queue[$data->channel_id][$data->sid][$data->nid] = $data; + } + + foreach($queue as $channel_id => $channel) { + $channel_nodes = publish_get_nodes_by_channel($channel_id, 'nid'); + + foreach($channel as $sid => $queue_items) { + if (PUBLISH_DEBUG_MODE) watchdog('publish', t('beginning push for channel %channel, subscriber %subscriber', array('%channel' => $channel_id, '%subscriber' => $sid))); + + foreach($queue_items as $queue_item) { + $nodes[$queue_item->nid] = $channel_nodes[$queue_item->nid]; + } + + // we've got the nodes, now push them out + $subscription = publish_subscriptions_load($sid); + $message = array( + 'token' => $subscription->token, + 'rsid' => (int)$subscription->sid, + 'count' => count($nodes), + 'site_url' => $base_url, + 'site_name' => variable_get('site_name', 'drupal'), + 'nodes' => $nodes + ); + + $response = xmlrpc($subscription->url, 'drupal.subscribe.receive', $message); + if ($response) { + // we have successfully published the pending nodes for this channel to this subscriber + // thus, delete them from the queue + if (PUBLISH_DEBUG_MODE) watchdog('publish', t('removing node %nid from queue (qid %qid)', array('%nid' => $node->nid, '%qid' => $queue_items[$node->nid]->qid))); + db_query("DELETE FROM {publish_queue} WHERE channel_id = %d AND sid = %d", $channel_id, $sid); + watchdog('publish', t('XMLRPC pushed !count nodes to !url (channel id !channel_id)', array('!count' => $message['count'], '!url' => check_plain($subscription->url), '!channel_id' => check_plain($channel_id)))); + } + else { // push failed + $error = xmlrpc_error_msg(); + foreach ($nodes as $nid => $node) { + $attempts = $queue_items[$nid]->attempts; + $max_attempts = variable_get('publish_push_max_attempts', 5); + if ($attempts > $max_attempts) { + if (PUBLISH_DEBUG_MODE) watchdog('publish', t('max of !attempts attempts exceeded; removing node !nid from queue', array('!attempts' => $max_attempts, '!nid' => $node->nid))); + db_query("DELETE FROM {publish_queue} WHERE qid = %d", $queue_items[$nid]->qid); + } + else { + db_query("UPDATE {publish_queue} SET attempts = %d, last_attempt = %d WHERE qid = %d", $attempts + 1, time(), $queue_items[$nid]->qid); + } + } + watchdog('publish', t('XMLRPC push failed for %url (channel id %channel_id): %faultString', array('%url' => $subscription->url, '%channel_id' => $channel_id, '%faultString' => $error ? $error : t('unavailable'))), WATCHDOG_ERROR); + } + } + } } /******************************************************************** @@ -1247,7 +1087,7 @@ } $who = $username? check_plain($username) : t('anonymous'); - watchdog('publish', t('XML-RPC: may subscribe to channel %channel_id? %name (%link).', array('%channel_id' => $channel_id, '%name' => "$who", '%link' => "$host"))); + watchdog('publish', t('XML-RPC: may subscribe to channel !channel_id? %name (%link).', array('!channel_id' => $channel_id, '%name' => $who, '%link' => $host))); return $response; } @@ -1264,14 +1104,12 @@ * @param * $dest the XMLRPC endpoint on the client to which publishing site * may publish nodes - * @param - * $cond array of condition triplets; see publish_publish() * * @return * An array containing a status message and the subscription id on the publishing site. */ - function publish_xmls_receive_subscription($channel_id, $username, $pass, $dest, $method, $remote_vids, $local_vids, $cond) { - + function publish_xmls_receive_subscription($channel_id, $username, $pass, $dest, $method, $remote_vids, $local_vids) { + $host = gethostbyaddr($_SERVER['REMOTE_ADDR']); // should check if $dest is in domain of $host here @@ -1314,14 +1152,12 @@ * $username (string) * @param * $password (string) - * @param - * $cond (array of condition triplets; see publish_publish() ) * * @return * An array of node objects keyed by node id. */ - function publish_xmls_publish($channel_id, $sid, $username, $pass, $cond) { - + function publish_xmls_publish($channel_id, $sid, $username, $pass) { +//MS: watchdog('publish-ms', 'channel_id: ' . $channel_id . ' | sid: ' . $sid . ' | username: ' . $username . ' | pass: ' . $pass); $ip = $_SERVER['REMOTE_ADDR']; $host = gethostbyaddr($ip); @@ -1331,9 +1167,8 @@ } if ($channel) { $may_subscribe = publish_may_subscribe($channel, $username, $pass, $host); - if ($may_subscribe && (publish_subscription_validate($sid))) { - $nodes = publish_publish($channel_id, $cond); + $nodes = publish_publish($channel_id); global $base_url; $response = array( @@ -1382,6 +1217,87 @@ * Module Functions :: Private ********************************************************************/ +/** + * Returns a list of views, including default views. + * @return + * An array of view names, keyed by view name. + */ +function publish_get_views() { + $views = array(); + $qs = db_query("SELECT v.vid, v.name FROM {view_view} v"); + while($obj = db_fetch_object($qs)) { + $views[$obj->name] = $obj->name; + } + $default_views = module_invoke_all('views_default_views'); + foreach($default_views as $default_view) { + $views[$default_view->name] = $default_view->name; + } + + return $views; +} + +/** + * Returns a list of nodes for a given channel. + * + * @param $channel_id + * A numeric channel_id. + * @param $key + * 'nid' to key by node IDs. Otherwise, NULL. + * @return + * An array of nodes, in the proper format to be published. + */ +function publish_get_nodes_by_channel($channel_id, $key = NULL) { + //Include this here so that we can work with the queries. + $path = drupal_get_path('module', 'views'); + require_once("./$path/views_query.inc"); + + $channel = publish_channel_load($channel_id); + if(!empty($channel)) { + $api_id = 'publish_channel_' . $channel_id; + $default = array(); + $view_name = $channel->views['view']; + $for_view = TRUE; + + $args = views_argument_api_get_processed($api_id, $default, $view_name, $for_view); + $view = views_get_view($view_name); + $filters = array(); + $queries = _views_build_query($view, $args); + + $query = $queries['query']; + $qs = call_user_func_array('db_query', array_merge(array($queries['query']), $queries['args'])); + while($obj = db_fetch_object($qs)) { + $node = node_load($obj->nid); + unset($node->data); + unset($node->revisions); + unset($node->picture); + unset($node->workspaces); + $node->url = url('node/' . $node->nid, NULL, NULL, TRUE); + + // we need to add vocabulary information ourselves, per the settings in the channel + $taxonomy_terms = taxonomy_node_get_terms($node->nid); + $published_vocabularies = publish_node_vocabularies($channel_id); + $published_vocabularies = array_pop($published_vocabularies); + $published_vocabularies = array_keys((array)$published_vocabularies[$node->type]); + + foreach($taxonomy_terms as $term) { + if(in_array($term->vid, $published_vocabularies)) { + $terms[$term->tid] = $term; + } + } + $node->taxonomy_terms = $terms; + + if($key == 'nid') { + $nodes[$node->nid] = $node; + } else { + $nodes[] = $node; + } + } + } else { + $nodes = array(); + } + + return $nodes; +} /** * Return an array of all vocabulary objects. @@ -1470,57 +1386,8 @@ function publish_db_fields($table_name) { switch ($table_name) { case 'publish_channel': - return array('channel_id', 'name', 'description', 'advertise', 'authtype', 'whenpub', 'username', 'pass', 'domain'); - } -} - -/** - * Instantiate some nodes and remove some unwanted properties. - * - * @param $node_ids - * Array of node IDs to instantiate - * @param $cond - * Array of triplets representing a filter (only vocabulary filters apply here) - * - * @return - * An array of node objects. - */ - function _publish_publish($node_ids = array(), $cond) { - $nodes = array(); - foreach ($node_ids as $nid) { - $node = node_load(array('nid' => $nid)); - unset($node->data); - unset($node->revisions); - unset($node->picture); - unset($node->workspaces); - $node->url = url('node/' . $nid, NULL, NULL, TRUE); - - // we need to add vocabulary information ourselves - $node->taxonomy_terms = taxonomy_node_get_terms($node->nid); - - if ($cond) { - // implement field = value - $conditions_met = FALSE; - foreach ($cond as $triplet) { - switch ($triplet['operator']) { - case '=': - foreach ($node->taxonomy_terms as $term) { - if($term->name == $triplet['value']) { - $conditions_met = TRUE; - continue; - } - } - } - } - if ($conditions_met) { - $nodes[$nid] = $node; - } - } - else { - $nodes[$nid] = $node; - } + return array('channel_id', 'name', 'description', 'advertise', 'authtype', 'whenpub', 'username', 'pass', 'domains'); } - return $nodes; } /** @@ -1536,14 +1403,12 @@ * to this subscriber * @param $dest * the URL of the XML-RPC endpoint to which content can be pushed - * @param $cond - * an array of triplets describing how to filter content * @param $sid * subscription id if not a new subscription * * @return $sid */ -function publish_subscription_save($channel_id, $username, $pass, $dest, $method, $remote_vids, $local_vids, $cond, $sid = null) { +function publish_subscription_save($channel_id, $username, $pass, $dest, $method, $remote_vids, $local_vids, $sid = null) { $sub = NULL; $op = 'insert'; @@ -1591,89 +1456,48 @@ } } - // save any additional conditions the subscriber requests - if ($cond) { - db_query("DELETE FROM {publish_cond} WHERE sid = %d", $sid); - - list($clean_cond, $taxonomy_cond) = publish_cond_validate($cond); - - foreach ($clean_cond as $triplet) { - $field = $triplet['field']; - $operator = $triplet['operator']; - $value = $triplet['value']; - db_query("INSERT INTO {publish_cond} (channel_id, sid, field, cond, value) VALUES %d, %d, '%s', '%s', '%s'", $channel_id, $sid, $field, $operator, $value); - } - - foreach ($taxonomy_cond as $triplet) { - $field = $triplet['field']; - $operator = $triplet['operator']; - $value = $triplet['value']; - db_query("INSERT INTO {publish_cond} (channel_id, sid, field, cond, value) VALUES %d, %d, '%s', '%s', '%s'", $channel_id, $sid, $field, $operator, $value); - } - } - return $sid; } -function publish_supported_operators() { - return array ( - '=', - '>', - '<' - ); -} - -function publish_supported_fields() { - return array ( - 'nid', 'type', - 'title', 'score', - 'votes', 'uid', - 'status', 'created', - 'changed', 'comment', - 'promote', 'moderate', - 'users', 'teaser', - 'body', 'sticky', - 'format' - ); -} +/******************************************************************** + * Views Hooks + ********************************************************************/ /** - * We only support a limited number of fields and conditions. - * This function filters out unsupported fields and conditions. - * - * @param $cond - * an array of triplets - * - * @return - * an array of triplets + * Provides a default view for views_multiblock */ -function publish_cond_validate($cond) { - - $supported_operators = array_flip(publish_supported_operators()); - - $supported_fields = array_flip(publish_supported_fields()); - - $vocabularies = publish_get_vocabularies(); - $voc_names = array(); - foreach ($vocabularies as $v) { - $voc_names[$v->name] = 0; - } - - $clean_cond = array(); - foreach ($cond as $triplet) { - $field = isset($triplet['field']) ? $triplet['field'] : $triplet[0]; - $operator = isset($triplet['operator']) ? $triplet['operator'] : $triplet[1]; - $value = isset($triplet['value']) ? $triplet['value'] : $triplet[2]; - - // we need to treat node conditions and taxonomy conditions separately - // since node conditions are used for SQL building and taxonomy conditions are not - if (key_exists($operator, $supported_operators) && key_exists ($field, $supported_fields)) { - $clean_cond[] = array('field' => $field, 'operator' => $operator, 'value' => $value); - } - elseif (key_exists($field, $voc_names)) { - $taxonomy_cond[] = array('field' => $field, 'operator' => $operator, 'value' => $value); - } - } - - return array($clean_cond, $taxonomy_cond); -} \ No newline at end of file +function publish_views_default_views() { + $view = new stdClass(); + $view->name = 'publish'; + $view->description = 'A default channel view for the Publish module.'; + $view->access = array ( +); + $view->view_args_php = ''; + $view->sort = array ( + ); + $view->argument = array ( + array ( + 'type' => 'taxid', + 'argdefault' => '1', + 'title' => '', + 'options' => '', + 'wildcard' => '', + 'wildcard_substitution' => '', + ), + ); + $view->field = array ( + array ( + 'tablename' => 'node', + 'field' => 'nid', + 'label' => '', + ), + ); + $view->filter = array ( + ); + $view->exposed_filter = array ( + ); + $view->requires = array(node); + $views[$view->name] = $view; + + return $views; +} diff -urN publish_47/publish_views.inc publish_5/publish_views.inc --- publish_47/publish_views.inc 1969-12-31 19:00:00.000000000 -0500 +++ publish_5/publish_views.inc 2007-06-11 18:24:19.526581928 -0400 @@ -0,0 +1,330 @@ + 'publish_queue', + 'join' => array( + 'left' => array( + 'table' => 'node', + 'field' => 'nid', + ), + 'right' => array( + 'field' => 'nid', + ), + ), + 'fields' => array( + 'qid' => array( + 'name' => t('Publish: Queue ID'), + 'help' => t('Use this field to show the Publish queue ID number.'), + 'sortable' => TRUE, + ), + 'sid' => array( + 'name' => t('Publish: Subscriber ID'), + 'help' => t('Use this field to show the subscriber ID number.'), + 'sortable' => TRUE, + ), + 'channel_id' => array( + 'name' => t('Publish: Channel ID'), + 'help' => t('Use this field to show the channel ID number.'), + 'sortable' => TRUE, + ), + 'attempts' => array( + 'name' => t('Publish: Attempts'), + 'help' => t('Use this field to show the number of attempts made to push a node.'), + 'sortable' => TRUE, + ), + 'last_attempt' => array( + 'name' => t('Publish: Last Attempt'), + 'help' => t('Use this field to show the last time that Publish attempted to push a node.'), + 'sortable' => TRUE, + ), + ), + 'sorts' => array( + 'qid' => array( + 'name' => t('Publish: Queue ID'), + 'help' => t('Sort by the Publish queue ID number.'), + ), + 'sid' => array( + 'name' => t('Publish: Subscriber ID'), + 'help' => t('Sort by the subscriber ID number.'), + ), + 'channel_id' => array( + 'name' => t('Publish: Channel ID'), + 'help' => t('Sort by the channel ID number.'), + ), + 'attempts' => array( + 'name' => t('Publish: Attempts'), + 'help' => t('Sort by the number of attempts made to push a node.'), + ), + 'last_attempt' => array( + 'name' => t('Publish: Last Attempt'), + 'help' => t('Sort by the last time that Publish attempted to push a node.'), + ), + ), + 'filters' => array( + 'channel_id' => array( + 'field' => 'channel_id', + 'name' => t('Publish: Channel ID'), + 'operator' => 'views_handler_operator_or', + 'list' => 'publish_views_get_channel_id_values', + 'help' => t('Filter by the channel ID number.'), + ), + ), + ); + + $tables['publish_channel'] = array( + 'name' => 'publish_channel', + 'join' => array( + 'left' => array( + 'table' => 'publish_queue', + 'field' => 'channel_id', + ), + 'right' => array( + 'field' => 'channel_id', + ), + ), + 'fields' => array( + 'name' => array( + 'name' => t('Publish: Channel Name'), + 'help' => t('Use this field to show the Publish Channel name.'), + 'sortable' => TRUE, + ), + 'description' => array( + 'name' => t('Publish: Channel Description'), + 'help' => t('Use this field to show the Publish Channel description.'), + 'sortable' => TRUE, + ), + 'advertise' => array( + 'name' => t('Publish: Channel is Advertised'), + 'help' => t('Use this field to show whether or not the Publish Channel is advertised.'), + 'sortable' => TRUE, + ), + ), + 'sorts' => array( + 'name' => array( + 'name' => t('Publish: Channel Name'), + 'help' => t('Sort by the Publish channel name.'), + ), + 'description' => array( + 'name' => t('Publish: Channel Description'), + 'help' => t('Sort by the Publish channel description.'), + ), + 'advertise' => array( + 'name' => t('Publish: Channel is Advertised'), + 'help' => t('Sort by the Publish channel advertised status.'), + ), + ), + 'filters' => array( + 'advertise' => array( + 'field' => 'advertise', + 'name' => t('Publish: Advertised'), + 'operator' => 'views_handler_operator_or', + 'list' => array( + t('Advertised'), + t('Not advertised'), + ), + 'help' => t('Filter by the Publish channel advertised status.'), + ), + ), + ); + + return $tables; +} + +/** + * Provides a default view for publish + * +function publish_views_default_views() { + $view = new stdClass(); + $view->name = 'publish'; + + $view->description = 'Publish'; + $view->access = array ('anonymous user'); + $view->view_args_php = ''; + $view->page = TRUE; + $view->page_title = ''; + $view->page_header = ''; + $view->page_header_format = '1'; + $view->page_footer = ''; + $view->page_footer_format = '1'; + $view->page_empty = ''; + $view->page_empty_format = '1'; + $view->page_type = 'teaser'; + $view->url = 'publish_view'; + $view->use_pager = TRUE; + $view->nodes_per_page = '10'; + $view->block = TRUE; + $view->block_title = ''; + $view->block_header = ''; + $view->block_header_format = '1'; + $view->block_footer = ''; + $view->block_footer_format = '1'; + $view->block_empty = ''; + $view->block_empty_format = '1'; + $view->block_type = 'publish'; + $view->nodes_per_block = '1'; + $view->block_more = TRUE; + $view->block_use_page_header = FALSE; + $view->block_use_page_footer = FALSE; + $view->block_use_page_empty = FALSE; + $view->sort = array ( + array ( + 'tablename' => 'node', + 'field' => 'sticky', + 'sortorder' => 'ASC', + 'options' => '', + ), + array ( + 'tablename' => 'node', + 'field' => 'changed', + 'sortorder' => 'DESC', + 'options' => 'normal', + ), + array ( + 'tablename' => 'node', + 'field' => 'title', + 'sortorder' => 'ASC', + 'options' => '', + ), + ); + $view->argument = array ( + array ( + 'type' => 'taxid', + 'argdefault' => '7', + 'title' => '%1', + 'options' => '', + 'wildcard' => '', + 'wildcard_substitution' => '', + ), + array ( + 'type' => 'node_feed', + 'argdefault' => '2', + 'title' => '', + 'options' => 'News Feed', + 'wildcard' => '', + 'wildcard_substitution' => '', + ), + ); + $view->field = array ( + array ( + 'tablename' => 'node', + 'field' => 'title', + 'label' => '', + 'handler' => 'views_handler_field_nodelink', + 'options' => 'link', + ), + array ( + 'tablename' => 'node', + 'field' => 'changed', + 'label' => '', + 'handler' => 'views_handler_field_date_small', + ), + array ( + 'tablename' => 'node', + 'field' => 'body', + 'label' => '', + 'handler' => 'views_handler_field_teaser', + ), + + ); + $view->filter = array ( + array ( + 'tablename' => 'node', + 'field' => 'status', + 'operator' => '=', + 'options' => '', + 'value' => '1', + ), + ); + + $view->exposed_filter = array (); + + $view->requires = array(node); + $views[$view->name] = $view; + + return $views; +} +*/ + +/** + * Define additional view type names. + */ +function publish_info() { + return array( + 'publish' => array('label' => 'Publish: Prepare for Channel'), + ); +} + +/** + * Implementation of hook_views_style_plugins() + */ +function publish_views_style_plugins() { + + $plugins = array(); + $types = publish_view_types(); + foreach ($types as $name => $type) { + $plugins[$name] = array( + 'name' => $type, + 'theme' => 'publish_display', + 'validate' => 'views_ui_plugin_validate_table', + 'needs_fields' => TRUE, + 'needs_table_header' => FALSE, + ); + } + + return $plugins; +} + +/** + * Possible views page display types + */ +function publish_view_types() { + return array('publish' => t('Publish: Prepare for Channel')); +} + +/** + * A form element for a view selector + */ +function _publish_view_type_form($view = NULL) { + $form['publish_view'] = array( + '#type' => 'select', + '#options' => publish_view_types(), + '#default_value' => $view ? $view->page_type : 'publish', + '#title' => t('View'), + ); + return $form; +} + +/*********************************************************** + * THEME FUNCTIONS + */ + +/** + * Publish: XML plugin theme, overrides default views theme + */ +function theme_publish_display($view, $nodes) { + drupal_set_message(t('This view is for the Publish module, only.'), 'error'); + return; +} +/********************************************************************* + * Helper Functions + */ + +function publish_views_get_channel_id_values() { + $qs = db_query("SELECT pc.channel_id, pc.name FROM {publish_channel} pc"); + while($obj = db_fetch_object($qs)) { + $filters[$obj->channel_id] = $obj->name; + } + + return $filters; +} + +?> \ No newline at end of file