2008/02/11 - Montreal Version 0.1.7.1 http://rym.waglo.com/modules/postalso/postalso-v0.1.7.1.tar.gz Free Software licenced under GPLv3 and GPLv2 More info: http://rym.waglo.com/wordpress/taxonomy/postalso/ INITIAL ANNOUNCEMENT ==================== Post Also is a module for Drupal 5.x that lets you post simultaneously to multiple sites. For example, I often post content on my blog but since I'm too lazy to just copy/paste it to other sites, generally for an association where it would belong, the content lives solely on my site. Or it might eventually get sniffed up through RSS, but sometimes, that's not fast or good enough. Post Also uses xmlrpc to talk to various web engines using so-called blog APIs. Currently, only metaWeblog is supported (allowing to post to other Drupal or Wordpress sites for example) but other APIs should soon follow (blogger, moveble type, atom) as well as autodiscovery. That means you will soon be able simultaneously post to other Drupal, Wordpress, TikiWiki, Plone, Xoops, Typo3 and many more supported web engines like CMSes, calendars and blogs. Configuration happens in two stages. First, the site admin (given the "post also destinations" access right) can setup destinations with names, xmlrpc endpoints and supported content types. Next, each user (given the "post also remote accounts" access right) can setup his remote accounts giving a destination, username and password. After this is done, the node submit forms, if supported, will allow the user to post also using his other remote accounts. The admin can also edit the users remote accounts. There was a module called blogclient for Drupal 4.6 originally written by chx for nowpublic and released by walkah, unfortunately I found it too late since it doesn't appear in the module directory anymore. I never used it but looking at the code, I note it did the configuration a little differently. TODO ==== * readme * let users edit their remote accounts * let admin edit/delete destinations and appropriate types * xmlrpc endpoint autodiscovery * support more blog apis (blogger, moveble type, atom) * map from one type to another * support for drupal cck * support for project module * support for events/calendar * edit/delete remote posts * docstrings * queue jobs * create a few blocks (stats, available destinations, etc) * port to Drupal 6 * get cvs account * cvs project (proper tag/branch, figure it out) * create project node * make it expandable through submodules (to post specifically to wordpress, twitter, del.icio.us, etc. according to users needs) */ /** * Implementation of hook_help(). */ function postalso_help($path, $arg) { //FIXME switch ($path) { case 'admin/help#postalso': return '
'. t('The Post Also module adds the ability to...') .'
'; case 'admin/content/postalso': return ''. t('Post Also works by...') .'
'; } } /** * Implementation of hook_perm(). */ function postalso_perm() { return array('post also destinations', 'post also remote accounts'); } /** * Implementation of hook_menu(). */ function postalso_menu() { $items = array(); $items['admin/content/postalso'] = array( 'description' => 'Administer Post Also destinations', 'title' => 'Post also', 'access arguments' => array('post also destinations'), 'page callback' => 'drupal_get_form', 'page arguments' => array('postalso_admin_settings'), 'type' => MENU_NORMAL_ITEM ); $items['user/%user/postalso'] = array( 'title' => 'Post also', 'page callback' => 'drupal_get_form', 'page arguments' => array('postalso_user_settings', 1), 'access callback' => 'postalso_user_access', 'access arguments' => array(1, 3), 'type' => MENU_LOCAL_TASK, ); $items['user/%user/postalso/%/delete'] = array( 'title' => 'Delete remote account', 'page callback' => 'postalso_delete_rid', 'page arguments' => array(1, 3), 'access callback' => 'postalso_user_access', 'access arguments' => array(1, 3), 'type' => MENU_CALLBACK ); return $items; } /** * Restrict access to postalso operations for users. * * @param integer $account * @param integer $rid * @return boolean */ function postalso_user_access($account, $rid) { global $user; // Let administrators do whatever they want. if (user_access('administer site configuration') || user_access('post also destinations')) { return TRUE; } // Only modify your own account. if ($user->uid != $account->uid) { return FALSE; } // Need to have this permission too. if (!user_access('post also remote accounts')) { return FALSE; } // TODO Check that the post ($rid) relates to the user. return TRUE; } /** * Implementation of hook_form_alter(). */ function postalso_form_alter(&$form, &$form_state, $form_id) { global $user; if (!($type_length = strrpos($form_id, '_node_form'))) { return; } $remote_accounts = variable_get('postalso_remotes_'. $user->uid, array()); if (!count($remote_accounts)) { return; } $destinations = variable_get('postalso_destinations', array()); $options = array(); $type = substr($form_id, 0, $type_length); foreach ($remote_accounts as $n => $remote) { $did = $remote['destination']; if (!in_array($type, $destinations[$did]['types'])) continue; $options[$n] = "{$destinations[$did]['name']} as {$remote['username']}"; } if (count($options)) { $default_value = array(); if (isset($form['#node']->nid)) { $nid = $form['#node']->nid; $uid = $form['uid']['#value']; $history = variable_get("postalso_history_$nid_$uid", array()); if ($history) { foreach ($history as $rid => $remote_post) { $default_value[] = $rid; } } } // any way to make this a bunch of checkboxes? $form['postalso'] = array( '#type' => 'select', '#title' => t('Select where to post also'), '#default_value' => $default_value, '#description' => t('CTRL+Click to select many remote accounts.'), '#options' => $options, '#weight' => -1, '#multiple' => TRUE, ); $form['#submit'][] = 'postalso_node_form_submit'; } } /** * Implementation of hook_submit(). */ function postalso_node_form_submit($form, &$form_state) { // dpm($form_state); return; // Code moved from postalso_nodeapi. // TODO Extract variables from the $form_state array and do your stuff. $uid = $node->uid; $nid = $node->nid; $remote_accounts = variable_get("postalso_remotes_$uid", array()); $destinations = variable_get('postalso_destinations', array()); $options = array(); $type = $node->type; $remote_infos = array(); foreach ($node->postalso as $rid) { $did = $remote_accounts[$rid]; if (!in_array($type, $destinations[$did['destination']]['types'])) continue; $remote_infos[$rid] = array( 'username' => $did['username'], 'password' => $did['password'], 'endpoint' => $destinations[$did['destination']]['url'] ); } $history = variable_get("postalso_history_$nid_$uid", array()); foreach ($remote_infos as $rid => $remote_info) { $post_result = _postalso_post( $remote_info['endpoint'], $node->type, $remote_info['username'], $remote_info['password'], $node->title, $node->body, $node->status ); $error = FALSE === $post_result; if ($error) { $post_result = xmlrpc_error_msg(); $message_type = 'error'; unset($link); } else { $xx = _postalso_get($remote_info['endpoint'], $remote_info['username'], $remote_info['password'], $post_result); if (isset($xx['link'])) { $link = $xx['link']; } $message_type = 'status'; } $history[$rid] = array( 'date' => time(), 'error' => $error, 'result' => $post_result, ); // we can't use form_set_error() since we're redirected away from the form. //FIXME: find something more meaningful than print_r drupal_set_message(print_r($post_result, TRUE), $message_type); watchdog('postalso', print_r($post_result, TRUE), // should I use WATCHDOG_ERROR? $error ? WATCHDOG_WARNING : WATCHDOG_NOTICE, $link); } variable_set("postalso_history_$nid_$uid", $history); } function postalso_delete_rid($uid, $rid) { //FIXME: add "Are you sure?" $remote_accounts = variable_get("postalso_remotes_$uid", array()); unset($remote_accounts[$rid]); variable_set("postalso_remotes_$uid", $remote_accounts); drupal_goto("user/$uid/postalso"); } function postalso_user_settings($uid) { $remote_accounts = variable_get("postalso_remotes_$uid", array()); $destinations = variable_get('postalso_destinations', array()); $known_remote_accounts = ''; foreach ($remote_accounts as $rid => $remote) { $did = $remote['destination']; $types = implode($destinations[$did]['types'], ', '); $known_remote_accounts .= "',
'#suffix' => '',
);
}
break;
}
}
# vim: set expandtab tabstop=2 shiftwidth=2 autoindent smartindent: