| 1 |
<?php
|
| 2 |
// $Id: planet.module Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* The planet module.
|
| 7 |
*
|
| 8 |
* Planet is an aggregator that allows you to aggregate the blogs for
|
| 9 |
* users in a given role (e.g. staff) and associate content with the
|
| 10 |
* users rather than as a detached feed. This provides the benefit of
|
| 11 |
* showing avatars with content, providing per-user aggregation of
|
| 12 |
* planet content in addition to blog content, etc.
|
| 13 |
*
|
| 14 |
*/
|
| 15 |
|
| 16 |
/**
|
| 17 |
* Implementation of hook_node_info.
|
| 18 |
*
|
| 19 |
* @return An array of information on the module's node types.
|
| 20 |
*
|
| 21 |
* @ingroup planet_node
|
| 22 |
*/
|
| 23 |
function planet_node_info() {
|
| 24 |
return array(
|
| 25 |
'planet' => array(
|
| 26 |
'name' => t('Planet Entry'),
|
| 27 |
'module' => 'planet',
|
| 28 |
'description' => t('Node to contain posts aggregated from various blogs.'),
|
| 29 |
)
|
| 30 |
);
|
| 31 |
}
|
| 32 |
|
| 33 |
/**
|
| 34 |
* Implementation of hook_perm - Defines user permissions.
|
| 35 |
* The suggested naming convention for permissions is "action_verb modulename".
|
| 36 |
*
|
| 37 |
* @return An array of permissions strings.
|
| 38 |
*
|
| 39 |
* @ingroup base
|
| 40 |
*/
|
| 41 |
function planet_perm() {
|
| 42 |
return array('administer planet', 'administer own planet feeds', 'view all planet nodes');
|
| 43 |
}
|
| 44 |
|
| 45 |
/**
|
| 46 |
* Implementation of hook_help - Provides online user help.
|
| 47 |
*
|
| 48 |
* @param $path A Drupal menu router path the help is being requested for
|
| 49 |
* @param $arg
|
| 50 |
* @return A localized string containing the help text.
|
| 51 |
*
|
| 52 |
* @ingroup base
|
| 53 |
*/
|
| 54 |
function planet_help($path, $arg) {
|
| 55 |
switch ($path) {
|
| 56 |
case 'admin/help#planet':
|
| 57 |
// The module's help text, displayed on the admin/help page and through the module's individual help link.
|
| 58 |
$output = '<p>Planet is an aggregator that allows you to aggregate your users blogs and to display them in a "planet" fashion. Associating content with the users rather than as a detached feed.</p>';
|
| 59 |
$output .= '<p>To use planet, go to admin/settings/planet and note the following sections:</p>';
|
| 60 |
$output .= '<ul>';
|
| 61 |
$output .= '<li><strong>General Settings</strong>. The filter format drop down will allow you to select the filter format that will be used to show planet entry nodes.</li>';
|
| 62 |
$output .= '<li><strong>Feeds</strong>. 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.</li>';
|
| 63 |
$output .= '<li><strong>Feeds</strong>. 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.</li>';
|
| 64 |
// @DIFFGROUP output syntax
|
| 65 |
$output .= '</ul>';
|
| 66 |
return $output;
|
| 67 |
// @DIFFINFO in D6, admin/modules#description is moved to .info file
|
| 68 |
}
|
| 69 |
}
|
| 70 |
|
| 71 |
/**
|
| 72 |
* Implementation of hook_view() - Displays a planet node.
|
| 73 |
*
|
| 74 |
* @param $node The node to be displayed.
|
| 75 |
* @param $teaser Whether to generate only a summary ("teaser") of the node.
|
| 76 |
* @param $page Whether the node is being displayed as a standalone page.
|
| 77 |
* @return The modified $node parameter, properly presented for output.
|
| 78 |
*
|
| 79 |
* @ingroup planet_node
|
| 80 |
* @CRUD{variables,R}
|
| 81 |
* @CRUD{planet_items,R}
|
| 82 |
*/
|
| 83 |
function planet_view($node, $teaser = FALSE, $page = FALSE) {
|
| 84 |
// @DIFFINFO removed $link param to match D6 hook definition
|
| 85 |
if ($page === true && variable_get('planet_redirect_page', 0) == 1) {
|
| 86 |
// @DIFFINFO only 'link' field is used, so I restricted the query
|
| 87 |
$obj = db_fetch_object(db_query('SELECT link FROM {planet_items} WHERE nid = %d', $node->nid));
|
| 88 |
// @DIFFINFO if the query succeeds, $obj->nid == $node->nid , otherwise, $obj==FALSE,
|
| 89 |
if ($obj && $obj->link != '') {
|
| 90 |
header('Location: '. $obj->link);
|
| 91 |
exit;
|
| 92 |
}
|
| 93 |
}
|
| 94 |
else {
|
| 95 |
return node_prepare($node, $teaser);
|
| 96 |
}
|
| 97 |
}
|
| 98 |
|
| 99 |
/**
|
| 100 |
* Implementation of hook_access() - Define access permissions for planet nodes (aka CRUD) .
|
| 101 |
* @param $op The operation to be performed: 'create', 'view', 'update', 'delete'
|
| 102 |
* @param $node The node on which the operation is to be performed, or, if it does not yet exist, the type of node to be created.
|
| 103 |
* @param $account A user object representing the user for whom the operation is to be performed.
|
| 104 |
* @return true if the user is allowed to perform operation, false otherwise.
|
| 105 |
*
|
| 106 |
* @ingroup planet_node
|
| 107 |
*/
|
| 108 |
function planet_access($op, $node, $account) {
|
| 109 |
// @DIFFINFO using planet-dedicated permissions
|
| 110 |
// Planet administrator has all permissions related to planet module
|
| 111 |
if (user_access('administer planet', $account))
|
| 112 |
return TRUE;
|
| 113 |
// Users allowed to edit their own planet nodes, are also allowed to create them, others are not.
|
| 114 |
$author = user_access('edit own planet feeds', $account);
|
| 115 |
if ($op == 'create') {
|
| 116 |
return $author;
|
| 117 |
}
|
| 118 |
|
| 119 |
// Does current user own requested node ?
|
| 120 |
$own = $account->uid == $node->uid;
|
| 121 |
if ($op == 'view')
|
| 122 |
return $own || user_access('view all planet nodes');
|
| 123 |
if ($op == 'update' || $op == 'delete') {
|
| 124 |
return $author && $own; // ok if $author owns the node
|
| 125 |
}
|
| 126 |
trigger_error("Unknown operation requested: $op");
|
| 127 |
return FALSE;
|
| 128 |
}
|
| 129 |
|
| 130 |
/**
|
| 131 |
* Implementation of hook_menu() - Defines menu items and page callbacks.
|
| 132 |
*
|
| 133 |
* @return An array of menu items.
|
| 134 |
* Each menu item has a key corresponding to the Drupal path being registered.
|
| 135 |
*
|
| 136 |
* @ingroup base
|
| 137 |
*
|
| 138 |
* This diagram shows how requests are handled.
|
| 139 |
* Each arrow is labeled with the permission required to access link.
|
| 140 |
* The menu item colors reflect the item type.
|
| 141 |
* @dotfile menu-links.dot "Menus and Pages"
|
| 142 |
*/
|
| 143 |
function planet_menu() {
|
| 144 |
$items['admin/settings/planet'] = array(
|
| 145 |
'title' => 'Planet Settings',
|
| 146 |
'description' => 'Configure settings for the planet module.',
|
| 147 |
'page callback' => '_planet_settings',
|
| 148 |
'access arguments' => array('administer nodes'),
|
| 149 |
'type' => MENU_NORMAL_ITEM);
|
| 150 |
|
| 151 |
$items['user/%user/planet'] = array(
|
| 152 |
'title' => 'Planet Feeds',
|
| 153 |
'page callback' => 'planet_user_feeds',
|
| 154 |
'page arguments' => array(1),
|
| 155 |
'access arguments' => array('administer own planet feeds'),
|
| 156 |
'type' => MENU_LOCAL_TASK,
|
| 157 |
);
|
| 158 |
|
| 159 |
// if (arg(0) == 'planet' && is_numeric(arg(1))) {
|
| 160 |
// FIXME access denied http://localhost/drupal/?q=planet/1
|
| 161 |
$items['planet/'. '%'] = array(
|
| 162 |
'title' => 'planet',
|
| 163 |
'page callback' => 'planet_page_user',
|
| 164 |
'page arguments' => array(arg(1))
|
| 165 |
);
|
| 166 |
|
| 167 |
// if (arg(3) == 'refresh' && is_numeric(arg(4))) {
|
| 168 |
$items['admin/settings/planet/refresh/%'] = array(
|
| 169 |
'title' => 'planet refresh',
|
| 170 |
'page callback' => 'planet_call_refresh',
|
| 171 |
'access arguments' => array('administer nodes'),
|
| 172 |
'type' => MENU_CALLBACK
|
| 173 |
);
|
| 174 |
|
| 175 |
// if (is_numeric(arg(4)) && (arg(3) == 'freeze' || arg(3) == 'unfreeze')) {
|
| 176 |
$items['admin/settings/planet/'. arg(3) .'/%'] = array(
|
| 177 |
'title' => 'planet freeze',
|
| 178 |
'page callback' => 'planet_toggle_frozen',
|
| 179 |
'access arguments' => array('administer nodes'),
|
| 180 |
'type' => MENU_CALLBACK
|
| 181 |
);
|
| 182 |
|
| 183 |
$items['planet'] = array(
|
| 184 |
'title' => 'Planet',
|
| 185 |
'description' => 'Planet Page',
|
| 186 |
'page callback' => 'planet_page_last',
|
| 187 |
'access arguments' => array('access content'),
|
| 188 |
'type' => MENU_NORMAL_ITEM
|
| 189 |
);
|
| 190 |
|
| 191 |
$items['planet/feed'] = array(
|
| 192 |
'title' => 'Planet',
|
| 193 |
'page callback' => 'planet_feed',
|
| 194 |
'access arguments' => array('access content'),
|
| 195 |
'type' => MENU_CALLBACK
|
| 196 |
);
|
| 197 |
|
| 198 |
return $items;
|
| 199 |
}
|
| 200 |
|
| 201 |
|
| 202 |
/**
|
| 203 |
* Page callback for 'admin/settings/planet/refresh/%' ("planet refresh")
|
| 204 |
*
|
| 205 |
* @ingroup page
|
| 206 |
*/
|
| 207 |
function planet_call_refresh() {
|
| 208 |
$title = planet_refresh();
|
| 209 |
watchdog('planet', 'Feed "'. $title .'" refreshed.');
|
| 210 |
drupal_set_message('Feed "'. $title .'" refreshed.');
|
| 211 |
drupal_goto('admin/settings/planet');
|
| 212 |
}
|
| 213 |
|
| 214 |
/**
|
| 215 |
* Page callback for 'admin/settings/planet/(un|)freeze/%' ("planet freeze")
|
| 216 |
*
|
| 217 |
* @ingroup page
|
| 218 |
* @CRUD{planet_feeds,U}
|
| 219 |
*/
|
| 220 |
function planet_toggle_frozen() {
|
| 221 |
|
| 222 |
$fid = intval(arg(4));
|
| 223 |
db_query('UPDATE {planet_feeds} SET frozen = %d WHERE fid = %d', arg(3) == 'unfreeze' ? 0 : 1, $fid);
|
| 224 |
drupal_set_message('Feed '. (arg(3) == 'unfreeze' ? 'un' : '') .'frozen.');
|
| 225 |
drupal_goto('admin/settings/planet');
|
| 226 |
}
|
| 227 |
|
| 228 |
|
| 229 |
/**
|
| 230 |
* Deletes a feed and related items
|
| 231 |
* @param $fid the feed identifier key (integer)
|
| 232 |
* @param $path the drupal path for redirection after user confirmed.
|
| 233 |
*
|
| 234 |
* @internal
|
| 235 |
* @ingroup planet_feed
|
| 236 |
* @CRUD{planet_items,R}
|
| 237 |
* @invoke{drupal_get_form,planet_multiple_delete_confirm}
|
| 238 |
*/
|
| 239 |
function planet__drop_feed($fid, $path) {
|
| 240 |
// @DIFFINFO documented $path param, removed unused $edit param
|
| 241 |
|
| 242 |
$result = db_query('SELECT nid FROM {planet_items} WHERE fid = %d', $fid);
|
| 243 |
$nodes = array(); // @DIFFINFO needs to be defined even empty (@FIXME it shouldn't be !)
|
| 244 |
while ($node = db_fetch_object($result)) {
|
| 245 |
$nodes[$node->nid] = TRUE;
|
| 246 |
}
|
| 247 |
return drupal_get_form('planet_multiple_delete_confirm', $nodes,
|
| 248 |
$fid, $path);
|
| 249 |
}
|
| 250 |
|
| 251 |
/**
|
| 252 |
* Page callback for 'user/%user/planet' ("Planet Feeds")
|
| 253 |
*
|
| 254 |
* @ingroup page
|
| 255 |
* @CRUD{planet_feeds,R}
|
| 256 |
* @invoke{drupal_get_form,planet_multiple_delete_confirm_submit}
|
| 257 |
* @invoke{drupal_get_form,planet_feed_form}
|
| 258 |
*/
|
| 259 |
function planet_user_feeds() {
|
| 260 |
global $user;
|
| 261 |
if ($_POST) {
|
| 262 |
return planet__update($_POST, 'user/'. $user->uid .'/planet');
|
| 263 |
}
|
| 264 |
else { // no $_POST
|
| 265 |
$fid = intval(arg(3)); // @deprecated: arg()
|
| 266 |
if ($fid > 0) {
|
| 267 |
$edit = db_fetch_array(db_query('SELECT * FROM {planet_feeds} WHERE fid = %d', $fid));
|
| 268 |
$output .= drupal_get_form('planet_feed_form', $edit, true, $user);
|
| 269 |
}
|
| 270 |
else {
|
| 271 |
|
| 272 |
$output .= drupal_get_form('planet_feed_form', $edit, false, $user);
|
| 273 |
|
| 274 |
$output .= '<h2>Feeds</h2>';
|
| 275 |
$output .= planet__build_user_feeds_table();
|
| 276 |
}
|
| 277 |
print theme('page', $output);
|
| 278 |
}
|
| 279 |
}
|
| 280 |
|
| 281 |
// Note: I use 'planet__' prefix to name internal functions
|
| 282 |
// TODO: apply the same naming convention (this one or another) in whole module
|
| 283 |
/**
|
| 284 |
* @todo merge with planet__build_admin_feeds_table()
|
| 285 |
*
|
| 286 |
* @ingroup planet_feed
|
| 287 |
* @internal
|
| 288 |
* @CRUD{planet_feeds,R}
|
| 289 |
* @CRUD{planet_items,R}
|
| 290 |
*/
|
| 291 |
function planet__build_user_feeds_table() {
|
| 292 |
// @DIFFINFO renamed planet__build_feeds_table1
|
| 293 |
global $user;
|
| 294 |
$feeds = db_query('SELECT fid, title, checked FROM {planet_feeds} '
|
| 295 |
. ' WHERE uid = %d;', $user->uid);
|
| 296 |
$rows = array();
|
| 297 |
$headers = array('Feed', 'Items', 'Edit', 'Last checked');
|
| 298 |
$now = time();
|
| 299 |
$items_statement = 'SELECT count(*) FROM {planet_items}'
|
| 300 |
. ' WHERE fid=%d';
|
| 301 |
// TODO: change this to prepared statement when supported by drupal DB abstraction layer.
|
| 302 |
while ($feed = db_fetch_object($feeds)) {
|
| 303 |
$_checked = $now - $feed->checked;
|
| 304 |
$checked = intval($_checked / 60) .' minutes';
|
| 305 |
if ($_checked % 60 > 0) {
|
| 306 |
$checked .= ', '. $feed->_checked % 60 .' seconds';
|
| 307 |
}
|
| 308 |
$checked .= ' ago';
|
| 309 |
$items = db_query($items_statement, $feed->fid);
|
| 310 |
if (!$items) trigger_error('ERROR while counting feed items.');
|
| 311 |
$cnt = db_result($items);
|
| 312 |
array_push($rows, array(
|
| 313 |
$feed->title,
|
| 314 |
$cnt,
|
| 315 |
l('edit', 'user/'. $user->uid .'/planet/'. intval($feed->fid)),
|
| 316 |
$checked,
|
| 317 |
)
|
| 318 |
);
|
| 319 |
}
|
| 320 |
return theme('table', $headers, $rows);
|
| 321 |
}
|
| 322 |
|
| 323 |
/**
|
| 324 |
* Updates a feed
|
| 325 |
*/
|
| 326 |
function planet__update($edit, $path) {
|
| 327 |
// @DIFFINFO Username can change, so we need to store the ID, not the username.
|
| 328 |
$edit['uid'] = db_result(db_query("SELECT uid from {users} WHERE name = '%s'", $edit['username']));
|
| 329 |
unset($edit['username']);
|
| 330 |
$fid = intval($edit['fid']);
|
| 331 |
if (($edit['op'] == 'Delete') && ($fid != 0)) {
|
| 332 |
return planet__drop_feed($fid, $path);
|
| 333 |
}
|
| 334 |
else if ($edit['op'] == 'Delete all' && $edit['confirm'] == 1) {
|
| 335 |
$edit['fid'] = intval(arg(3)); // @deprecated arg()
|
| 336 |
$edit['redirect'] = $path;
|
| 337 |
return drupal_get_form('planet_multiple_delete_confirm_submit', $edit);
|
| 338 |
}
|
| 339 |
else {
|
| 340 |
planet__submit_feed_data($edit);
|
| 341 |
}
|
| 342 |
drupal_goto($path);
|
| 343 |
}
|
| 344 |
|
| 345 |
/**
|
| 346 |
* Submit the feed's data to the appropriate update or add function
|
| 347 |
*/
|
| 348 |
function planet__submit_feed_data($data) {
|
| 349 |
if (isset($data['fid'])) {
|
| 350 |
if (intval($data['fid']) == 0) {
|
| 351 |
planet__add_feed($data);
|
| 352 |
} else {
|
| 353 |
planet__update_feed($data);
|
| 354 |
}
|
| 355 |
} else {
|
| 356 |
// TODO if user needs to click separately for each fieldset,
|
| 357 |
// why not using different forms ?
|
| 358 |
// or conversely, allow setting everything at once ?
|
| 359 |
planet__update_vars($data);
|
| 360 |
}
|
| 361 |
}
|
| 362 |
|
| 363 |
/**
|
| 364 |
* Adds a new feed to planet_feeds table.
|
| 365 |
* @param $data associative array with keys
|
| 366 |
* 'uid' (optional), 'title', 'link', 'image' (optional)
|
| 367 |
* @return success status
|
| 368 |
*
|
| 369 |
* @ingroup planet_feed
|
| 370 |
* @internal
|
| 371 |
* @CRUD{planet_feeds,C}
|
| 372 |
*/
|
| 373 |
function planet__add_feed($data) {
|
| 374 |
$data['checked'] = 0;
|
| 375 |
$data['frozen'] = 0;
|
| 376 |
// @DIFFINFO Removed debugging block. Internal function is supposed to receive clean arguments. Checking will be left to planet_feed class
|
| 377 |
|
| 378 |
$rslt = drupal_write_record('planet_feeds', $data);
|
| 379 |
if ($rslt==SAVED_NEW) {
|
| 380 |
$title = planet_refresh(intval($data['fid']));
|
| 381 |
drupal_set_message('Added new feed: ' . $title);
|
| 382 |
return TRUE;
|
| 383 |
}
|
| 384 |
trigger_error('Failed to add new feed');
|
| 385 |
return FALSE;
|
| 386 |
}
|
| 387 |
|
| 388 |
/**
|
| 389 |
* Updates an existing feed in planet_feeds table.
|
| 390 |
* @param $data associative array with keys
|
| 391 |
* 'fid' (mandatory, primary key),
|
| 392 |
* other fields as needed:
|
| 393 |
* 'uid', 'title', 'link', 'image', 'checked', 'frozen'
|
| 394 |
* @return success status
|
| 395 |
*
|
| 396 |
* @ingroup planet_feed
|
| 397 |
* @internal
|
| 398 |
* @CRUD{planet_feeds,U}
|
| 399 |
*/
|
| 400 |
function planet__update_feed($data) {
|
| 401 |
$rslt = drupal_write_record('planet_feeds', $data, 'fid');
|
| 402 |
|
| 403 |
if ($rslt==SAVED_UPDATED) {
|
| 404 |
drupal_set_message('Edited "'. $data['title'] .'" feed.');
|
| 405 |
return TRUE;
|
| 406 |
}
|
| 407 |
if ($rslt==SAVED_NEW) // @DEBUGGING
|
| 408 |
trigger_error('Feed {$data->fid} didn\'t exist. Record added.', E_ERROR);
|
| 409 |
else
|
| 410 |
trigger_error('Failed to edit feed');
|
| 411 |
return FALSE;
|
| 412 |
}
|
| 413 |
|
| 414 |
/**
|
| 415 |
* Updates an planet settings persistent variables.
|
| 416 |
* @param $data associative array with all optional keys
|
| 417 |
* 'planet_filter_formats', 'planet_redirect_page'.
|
| 418 |
*
|
| 419 |
* @ingroup isettings
|
| 420 |
* @internal
|
| 421 |
* @CRUD{variables,CUD}
|
| 422 |
*/
|
| 423 |
function planet__update_vars($data) {
|
| 424 |
if ($data['planet_filter_formats']) {
|
| 425 |
variable_set('planet_filter_formats', $data['planet_filter_formats']);
|
| 426 |
}
|
| 427 |
if ($data['planet_redirect_page'] == 1) {
|
| 428 |
variable_set('planet_redirect_page', $data['planet_redirect_page']);
|
| 429 |
} else {
|
| 430 |
variable_del('planet_redirect_page');
|
| 431 |
}
|
| 432 |
drupal_set_message('Edited general planet settings.');
|
| 433 |
}
|
| 434 |
|
| 435 |
/**
|
| 436 |
* Page callback for 'admin/settings/planet' ("Planet Settings")
|
| 437 |
*
|
| 438 |
* @ingroup page
|
| 439 |
* @CRUD{planet_items,R}
|
| 440 |
* @CRUD{planet_feeds,R}
|
| 441 |
* @invoke{drupal_get_form,planet_multiple_delete_confirm}
|
| 442 |
* @invoke{drupal_get_form,planet_multiple_delete_confirm_submit}
|
| 443 |
* @invoke{drupal_get_form,planet_feed_form}
|
| 444 |
* @invoke{drupal_get_form,planet_settings_form}
|
| 445 |
*/
|
| 446 |
function _planet_settings() {
|
| 447 |
if ($_POST) {
|
| 448 |
return planet__update($_POST, 'admin/settings/planet');
|
| 449 |
} else {
|
| 450 |
$fid = intval(arg(3)); // @deprecated arg()
|
| 451 |
if ($fid > 0) {
|
| 452 |
$edit = db_fetch_array(db_query('SELECT * FROM {planet_feeds} WHERE fid = %d', $fid));
|
| 453 |
$output .= drupal_get_form('planet_feed_form', $edit, true);
|
| 454 |
}
|
| 455 |
else {
|
| 456 |
|
| 457 |
$output .= drupal_get_form('planet_settings_form');
|
| 458 |
|
| 459 |
$output .= drupal_get_form('planet_feed_form', $edit);
|
| 460 |
|
| 461 |
$output .= '<h2>Feeds</h2>';
|
| 462 |
$output .= planet__build_admin_feeds_table();
|
| 463 |
}
|
| 464 |
print theme('page', $output);
|
| 465 |
}
|
| 466 |
}
|
| 467 |
|
| 468 |
/**
|
| 469 |
* builds an HTML table of feeds for administrator interaction.
|
| 470 |
*
|
| 471 |
* @return
|
| 472 |
*
|
| 473 |
* @ingroup planet_feed
|
| 474 |
* @internal
|
| 475 |
* @CRUD{planet_feeds,R}
|
| 476 |
* @CRUD{planet_items,R}
|
| 477 |
*/
|
| 478 |
function planet__build_admin_feeds_table() {
|
| 479 |
// @DIFFINFO renamed planet__build_feeds_table() {
|
| 480 |
// @DIFFINFO the admin section is supposed to let you administer everyone not just the admin.. ;P
|
| 481 |
$feeds = db_query('SELECT fid, title, checked, frozen FROM {planet_feeds}');
|
| 482 |
$rows = array();
|
| 483 |
$headers = array('Feed', 'Items', 'Edit', 'Last checked', 'Refresh', 'Freeze');
|
| 484 |
$now = time();
|
| 485 |
$items_statement = 'SELECT count(*) FROM {planet_items} WHERE fid=%d';
|
| 486 |
// TODO: change this to prepared statement when supported by drupal DB Abstraction Layer.
|
| 487 |
while ($feed = db_fetch_object($feeds)) {
|
| 488 |
$_checked = $now - $feed->checked;
|
| 489 |
$checked = intval($_checked / 60) .' minutes';
|
| 490 |
if ($_checked % 60 > 0) {
|
| 491 |
$checked .= ', '. $feed->_checked % 60 .' seconds';
|
| 492 |
}
|
| 493 |
$checked .= ' ago';
|
| 494 |
$items = db_query($items_statement, $feed->fid);
|
| 495 |
if (!$items) trigger_error('ERROR while counting feed items.');
|
| 496 |
$cnt = db_result($items);
|
| 497 |
$fid = strval($feed->fid);
|
| 498 |
array_push($rows, array(
|
| 499 |
$feed->title,
|
| 500 |
$cnt,
|
| 501 |
l('edit', 'admin/settings/planet/'. $fid),
|
| 502 |
$checked,
|
| 503 |
l('refresh', 'admin/settings/planet/refresh/'. $fid),
|
| 504 |
l($feed->frozen ? 'unfreeze' : 'freeze', 'admin/settings/planet/'. ($feed->frozen ? 'unfreeze/' : 'freeze/') . $fid)
|
| 505 |
)
|
| 506 |
);
|
| 507 |
}
|
| 508 |
return theme('table', $headers, $rows);
|
| 509 |
}
|
| 510 |
|
| 511 |
/**
|
| 512 |
* TODO.
|
| 513 |
*
|
| 514 |
* @param &$form_state
|
| 515 |
* @param $nodes
|
| 516 |
* @param $fid
|
| 517 |
* @param $redirect
|
| 518 |
* @return
|
| 519 |
*
|
| 520 |
* @ingroup iforms
|
| 521 |
* @CRUD{node,R}
|
| 522 |
*/
|
| 523 |
function planet_multiple_delete_confirm(&$form_state, $nodes, $fid, $redirect) {
|
| 524 |
$form_state['values']['fid'] = $fid;
|
| 525 |
$form_state['values']['redirect'] = $redirect;
|
| 526 |
$form['nodes'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
|
| 527 |
// array_filter returns only elements with TRUE values
|
| 528 |
foreach ($nodes as $nid => $value) {
|
| 529 |
$title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $nid));
|
| 530 |
$form['nodes'][$nid] = array(
|
| 531 |
'#type' => 'hidden',
|
| 532 |
'#value' => $nid,
|
| 533 |
'#prefix' => '<li>',
|
| 534 |
'#suffix' => check_plain($title) ."</li>\n",
|
| 535 |
);
|
| 536 |
}
|
| 537 |
$form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
|
| 538 |
$form['#submit'][] = 'planet_multiple_delete_confirm_submit';
|
| 539 |
return confirm_form($form,
|
| 540 |
t('Are you sure you want to delete these items?'),
|
| 541 |
$redirect, t('This action cannot be undone.'),
|
| 542 |
t('Delete all'), t('Cancel'));
|
| 543 |
}
|
| 544 |
|
| 545 |
/**
|
| 546 |
* TODO.
|
| 547 |
*
|
| 548 |
* @param &$form_state
|
| 549 |
* @param $edit
|
| 550 |
* @return
|
| 551 |
*
|
| 552 |
* @ingroup iforms
|
| 553 |
* @CRUD{node,D}
|
| 554 |
* @CRUD{planet_items,D}
|
| 555 |
* @CRUD{planet_feeds,D}
|
| 556 |
*/
|
| 557 |
function planet_multiple_delete_confirm_submit(&$form_state, $edit) {
|
| 558 |
$fid = $edit['fid'];
|
| 559 |
if ($edit['confirm']) {
|
| 560 |
foreach ($edit['nodes'] as $nid => $value) {
|
| 561 |
node_delete($nid);
|
| 562 |
}
|
| 563 |
// @DIFFINFO inverted drop order to respect foreign keys
|
| 564 |
db_query('DELETE FROM {planet_items} WHERE fid = %d', $fid);
|
| 565 |
db_query('DELETE FROM {planet_feeds} WHERE fid = %d', $fid);
|
| 566 |
drupal_set_message(t('The feed and items have been deleted.'));
|
| 567 |
}
|
| 568 |
drupal_goto($edit['redirect']);
|
| 569 |
}
|
| 570 |
|
| 571 |
|
| 572 |
/**
|
| 573 |
* TODO.
|
| 574 |
*
|
| 575 |
* @param &$form_state
|
| 576 |
* @return
|
| 577 |
* @ingroup iforms
|
| 578 |
* @CRUD{role,R}
|
| 579 |
* @CRUD{variables,R}
|
| 580 |
*/
|
| 581 |
function planet_settings_form(&$form_state) {
|
| 582 |
$result = db_query('SELECT format, name FROM {filter_formats}');
|
| 583 |
while ($format = db_fetch_object($result)) {
|
| 584 |
$formats[$format->format] = $format->name;
|
| 585 |
}
|
| 586 |
|
| 587 |
$form = array();
|
| 588 |
|
| 589 |
$form['general'] = array(
|
| 590 |
'#type' => 'fieldset',
|
| 591 |
'#title' => t('General Settings')
|
| 592 |
);
|
| 593 |
|
| 594 |
$form['general']['planet_filter_formats'] = array(
|
| 595 |
'#type' => 'select',
|
| 596 |
'#title' => t('Filter format for planet entry nodes'),
|
| 597 |
'#options' => $formats,
|
| 598 |
'#default_value' => variable_get('planet_filter_formats', 1),
|
| 599 |
'#description' => t('Select the filter format that will be used to show planet entry nodes.')
|
| 600 |
);
|
| 601 |
|
| 602 |
$form['general']['planet_redirect_page'] = array(
|
| 603 |
'#type' => 'checkbox',
|
| 604 |
'#title' => t('Redirect node?'),
|
| 605 |
'#return_value' => 1,
|
| 606 |
'#value' => (variable_get('planet_redirect_page', 0) == 1) ? 1 : null,
|
| 607 |
'#description' => t('Check this if you want the node view to redirect to the original content link; this is useful if you want the feed to forward through instead of showing the planet node.')
|
| 608 |
);
|
| 609 |
|
| 610 |
$form['general']['submit'] = array(
|
| 611 |
'#type' => 'submit',
|
| 612 |
'#value' => 'Save Configuration'
|
| 613 |
);
|
| 614 |
|
| 615 |
return $form;
|
| 616 |
}
|
| 617 |
|
| 618 |
/**
|
| 619 |
* TODO.
|
| 620 |
*
|
| 621 |
* @param &$form_state
|
| 622 |
* @param $edit
|
| 623 |
* @param $individual
|
| 624 |
* @param $user
|
| 625 |
* @return
|
| 626 |
* @ingroup iforms
|
| 627 |
* @CRUD{users,R}
|
| 628 |
* @CRUD{role,R}
|
| 629 |
* @CRUD{users_roles,R}
|
| 630 |
* @CRUD{variables,R}
|
| 631 |
*/
|
| 632 |
function planet_feed_form(&$form_state, $edit = array(), $individual = false, $user = NULL) {
|
| 633 |
|
| 634 |
if ($individual) {
|
| 635 |
$g_user = db_fetch_array(db_query('SELECT uid, name FROM {users} WHERE uid = %d', $edit['uid']));
|
| 636 |
}
|
| 637 |
|
| 638 |
$form = array();
|
| 639 |
|
| 640 |
$form['feeds'] = array(
|
| 641 |
'#type' => 'fieldset',
|
| 642 |
'#title' => 'Feeds'
|
| 643 |
);
|
| 644 |
|
| 645 |
$form['feeds']['fid'] = array(
|
| 646 |
'#type' => 'hidden',
|
| 647 |
'#value' => $edit['fid']
|
| 648 |
);
|
| 649 |
|
| 650 |
$form['feeds']['title'] = array(
|
| 651 |
'#type' => 'textfield',
|
| 652 |
'#title' => t('Title'),
|
| 653 |
'#value' => $edit['title'],
|
| 654 |
'#size' => 40,
|
| 655 |
'#maxlength' => 40
|
| 656 |
);
|
| 657 |
|
| 658 |
if ($user == NULL) {
|
| 659 |
$form['feeds']['username'] = array(
|
| 660 |
'#type' => 'textfield',
|
| 661 |
'#title' => t('Original author'),
|
| 662 |
'#size' => 40,
|
| 663 |
'#maxlength' => 60,
|
| 664 |
'#default_value' => $g_user['name'],
|
| 665 |
'#required' => TRUE,
|
| 666 |
'#autocomplete_path' => 'user/autocomplete',
|
| 667 |
'#description' => t('Select a user to associate this feed with')
|
| 668 |
);
|
| 669 |
}
|
| 670 |
else {
|
| 671 |
$form['feeds']['username'] = array(
|
| 672 |
'#type' => 'hidden',
|
| 673 |
'#value' => $user->name,
|
| 674 |
);
|
| 675 |
}
|
| 676 |
$form['feeds']['link'] = array(
|
| 677 |
'#type' => 'textfield',
|
| 678 |
'#title' => t('URL'),
|
| 679 |
'#value' => $edit['link'],
|
| 680 |
'#size' => 40,
|
| 681 |
'#maxlength' => 80
|
| 682 |
);
|
| 683 |
|
| 684 |
$form['feeds']['submit'] = array(
|
| 685 |
'#type' => 'submit',
|
| 686 |
'#value' => $edit['fid'] > 0 ? 'Save' : 'Add'.' Feed'
|
| 687 |
);
|
| 688 |
|
| 689 |
if ($individual) {
|
| 690 |
$form['feeds']['delete'] = array(
|
| 691 |
'#type' => 'submit',
|
| 692 |
'#value' => 'Delete',
|
| 693 |
);
|
| 694 |
}
|
| 695 |
|
| 696 |
return $form;
|
| 697 |
}
|
| 698 |
|
| 699 |
/**
|
| 700 |
* Implementation of hook_cron - Perform periodic actions.
|
| 701 |
*
|
| 702 |
* @return none
|
| 703 |
* @ingroup system
|
| 704 |
* @CRUD{planet_feeds,R}
|
| 705 |
*/
|
| 706 |
function planet_cron() {
|
| 707 |
$result = db_query('SELECT fid FROM {planet_feeds} WHERE frozen = 0');
|
| 708 |
while ($feed = db_fetch_object($result)) {
|
| 709 |
$title = planet_refresh($feed->fid);
|
| 710 |
watchdog('planet', 'Cron updated feed "'. $title .'".');
|
| 711 |
}
|
| 712 |
}
|
| 713 |
|
| 714 |
|
| 715 |
/**
|
| 716 |
* Private function; Checks a news feed for new items.
|
| 717 |
*
|
| 718 |
* @param $fid feed identifier (defaults to arg(4))
|
| 719 |
* @return
|
| 720 |
*
|
| 721 |
* @private
|
| 722 |
* @CRUD{planet_feeds,U}
|
| 723 |
* @invoke{module_invoke,taxonomy_node_get_terms}
|
| 724 |
*/
|
| 725 |
function planet_refresh($fid = null) {
|
| 726 |
if (!$fid) {
|
| 727 |
$fid = intval(arg(4));
|
| 728 |
}
|
| 729 |
// initialize simplepie
|
| 730 |
// we want to do this only once and not each time per feed, which would be slower
|
| 731 |
include_once './'. drupal_get_path('module', 'planet') .'/simplepie.inc';
|
| 732 |
|
| 733 |
$process_feed = db_fetch_object(db_query('SELECT * FROM {planet_feeds} WHERE fid = %d', $fid));
|
| 734 |
|
| 735 |
$feed = new SimplePie();
|
| 736 |
$feed->enable_cache(FALSE);
|
| 737 |
$feed->set_timeout(15);
|
| 738 |
// prevent SimplePie from using all of it's data santization since we use Drupal's input formats to handle this
|
| 739 |
$feed->set_stupidly_fast(TRUE);
|
| 740 |
$feed->set_feed_url($process_feed->link);
|
| 741 |
// FeedBurner requires this check otherwise it won't work well with SimplePie
|
| 742 |
// also performance improvement
|
| 743 |
header('If-Modified-Since:'. $process_feed->checked);
|
| 744 |
$success = $feed->init();
|
| 745 |
|
| 746 |
if ($success && $feed->data) {
|
| 747 |
// get a unique hash of the headers in the feed, fast and easy way to compare if this feed is updated or not
|
| 748 |
$hash = md5(serialize($feed->data));
|
| 749 |
|
| 750 |
// hashes don't match so likely the feed is updated
|
| 751 |
if ($process_feed->hash != $hash) {
|
| 752 |
// above we define hook_view() which then performs check_url() on the $url in the feed node
|
| 753 |
// the problem is check_url() calls filter_xss_bad_protocol() which does it thing to prevent XSS
|
| 754 |
// but it returns the string through check_plain() which calls htmlspecialchars()
|
| 755 |
// this converts & in a url to & and then causes SimplePie not to be able to parse it
|
| 756 |
// because of this, we decode this URL since we are passing it directly to SimplePie
|
| 757 |
// it is still encoded everywhere else it is output to prevent XSS
|
| 758 |
$process_feed->link = htmlspecialchars_decode($process_feed->link, ENT_QUOTES);
|
| 759 |
|
| 760 |
// turn each feed item into a node
|
| 761 |
planet_item_feed_parse($process_feed, $feed);
|
| 762 |
}
|
| 763 |
|
| 764 |
// finished processing this feed so we can mark it checked
|
| 765 |
db_query("UPDATE {planet_feeds} SET checked = %d, hash = '%s', error = 0 WHERE fid = %d", time(), $hash, $process_feed->fid);
|
| 766 |
}
|
| 767 |
else if (isset($feed->error)) {
|
| 768 |
db_query("UPDATE {planet_feeds} SET error = 1 WHERE fid = %d", $process_feed->fid);
|
| 769 |
watchdog('planet', 'The feed %feed could not be processed due to the following error: %error', array('%feed' => $process_feed->title, '%error' => $feed->error), WATCHDOG_ERROR, l('view', $process_feed->link));
|
| 770 |
}
|
| 771 |
else {
|
| 772 |
watchdog('planet', 'You shouldn\'t be here. Something has gone terribly wrong.');
|
| 773 |
}
|
| 774 |
|
| 775 |
return $process_feed->title;
|
| 776 |
}
|
| 777 |
|
| 778 |
// @DIFFINFO removed orphaned doc-block
|
| 779 |
|
| 780 |
/**
|
| 781 |
* Private function; Convert relative URLs
|
| 782 |
* @ingroup rss
|
| 783 |
* @private
|
| 784 |
*/
|
| 785 |
function planet_convert_relative_urls(&$data, $base_url) {
|
| 786 |
$src = '%( href| src)="(?!\w+://)/?([^"]*)"%';
|
| 787 |
$dst = '$1="'. trim($base_url, '/') .'/$2"';
|
| 788 |
return preg_replace($src, $dst, $data);
|
| 789 |
}
|
| 790 |
|
| 791 |
/**
|
| 792 |
* Page callback for 'planet' ("Planet").
|
| 793 |
* @ingroup page
|
| 794 |
* @CRUD{node,R}
|
| 795 |
* @CRUD{variables,R}
|
| 796 |
*/
|
| 797 |
function planet_page_last() {
|
| 798 |
global $user;
|
| 799 |
|
| 800 |
$output = '<br />';
|
| 801 |
|
| 802 |
$result = pager_query(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE n.type = 'planet' AND n.status = 1 ORDER BY n.created DESC"), variable_get('default_nodes_main', 10));
|
| 803 |
|
| 804 |
while ($node = db_fetch_object($result)) {
|
| 805 |
$node = node_load($node->nid);
|
| 806 |
$node->format = variable_get('planet_filter_formats', 1);
|
| 807 |
$output .= node_view($node);
|
| 808 |
}
|
| 809 |
$output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
|
| 810 |
$output .= theme('xml_icon', url('planet/feed'));
|
| 811 |
|
| 812 |
print theme('page', $output);
|
| 813 |
}
|
| 814 |
|
| 815 |
/**
|
| 816 |
* Page callback for 'planet/feed' ("Planet").
|
| 817 |
* @ingroup page
|
| 818 |
* @CRUD{node,R}
|
| 819 |
* @CRUD{menu_links,R}
|
| 820 |
*/
|
| 821 |
function planet_feed() {
|
| 822 |
$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);
|
| 823 |
$title = db_fetch_array(db_query("SELECT link_title FROM {menu_links} WHERE link_path = 'planet'"));
|
| 824 |
|
| 825 |
$channel['title'] = $title['link_title'];
|
| 826 |
$channel['link'] = url('planet', array('absolute' => TRUE));
|
| 827 |
$channel['description'] = 'Planet feed';
|
| 828 |
|
| 829 |
$items = array();
|
| 830 |
while ($row = db_fetch_object($result)) {
|
| 831 |
$items[] = $row->nid;
|
| 832 |
}
|
| 833 |
// generate RSS feed from $items set of nodes.
|
| 834 |
node_feed($items, $channel);
|
| 835 |
}
|
| 836 |
|
| 837 |
/**
|
| 838 |
* Implementation of hook_user() - React when operations are performed on user accounts.
|
| 839 |
* @ingroup system
|
| 840 |
* @CRUD{planet_feeds,R}
|
| 841 |
*/
|
| 842 |
function planet_user($type, &$edit, &$user) {
|
| 843 |
if ($type == 'view' && user_access('edit own blog', $user)) {
|
| 844 |
$items[] = array('title' => t('Blog'),
|
| 845 |
'value' => /* TODO
|
| 846 |
Please manually fix the parameters on the l() or url() function on the next line.
|
| 847 |
Typically, this was not changed because of a function call inside an array call like
|
| 848 |
array('title' => t('View user profile.')).*/
|
| 849 |
l(t('view recent blog entries'), "planet/$user->uid", array('title' => t("Read %username's latest blog entries.", array('%username' => $user->name)))),
|
| 850 |
'class' => 'blog',
|
| 851 |
);
|
| 852 |
return array(t('History') => $items);
|
| 853 |
}
|
| 854 |
if ($type == 'load') {
|
| 855 |
$obj = db_fetch_object(db_query('SELECT link FROM {planet_feeds} WHERE uid = %d', $user->uid));
|
| 856 |
$user->planet_feed = $obj->link;
|
| 857 |
}
|
| 858 |
}
|
| 859 |
|
| 860 |
/**
|
| 861 |
* Menu callback; displays a Drupal page containing recent planet entries.
|
| 862 |
*
|
| 863 |
* @todo remove orphan function, or reuse it
|
| 864 |
* @ingroup page
|
| 865 |
*/
|
| 866 |
function planet_page($a = NULL, $b = NULL) {
|
| 867 |
// @DIFFINFO I keep this for now to keep showing, in API doc, historic relation between called functions
|
| 868 |
if (is_numeric($a)) { // $a is a user ID
|
| 869 |
if ($b == 'feed') {
|
| 870 |
return planet_feed_user($a);
|
| 871 |
}
|
| 872 |
else {
|
| 873 |
return planet_page_user($a);
|
| 874 |
}
|
| 875 |
}
|
| 876 |
else if ($a == 'feed') {
|
| 877 |
return planet_feed_last();
|
| 878 |
}
|
| 879 |
else {
|
| 880 |
return planet_page_last();
|
| 881 |
}
|
| 882 |
}
|
| 883 |
|
| 884 |
/**
|
| 885 |
* Page callback for 'planet/%' ("planet").
|
| 886 |
* @ingroup page
|
| 887 |
*
|
| 888 |
* @CRUD{node,R}
|
| 889 |
* @CRUD{variables,R}
|
| 890 |
*/
|
| 891 |
function planet_page_user($uid) {
|
| 892 |
global $user;
|
| 893 |
|
| 894 |
$account = user_load(array((is_numeric($uid) ? 'uid' : 'name') => $uid, 'status' => 1));
|
| 895 |
|
| 896 |
if ($account->uid) {
|
| 897 |
drupal_set_title($title = t("%name's planet", array('%name' => $account->name)));
|
| 898 |
|
| 899 |
if ($output) {
|
| 900 |
$output = '<ul>'. $output .'</ul>';
|
| 901 |
}
|
| 902 |
else {
|
| 903 |
$output = '';
|
| 904 |
}
|
| 905 |
$result = pager_query(db_rewrite_sql("SELECT n.nid, n.sticky, n.created FROM {node} n WHERE type = 'planet' AND n.uid = %d AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10), 0, NULL, $account->uid);
|
| 906 |
while ($node = db_fetch_object($result)) {
|
| 907 |
$output .= node_view(node_load($node->nid), 1);
|
| 908 |
}
|
| 909 |
$output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
|
| 910 |
$output .= theme('feed_icon', url("planet/$account->uid/feed"));
|
| 911 |
|
| 912 |
drupal_add_link(array('rel' => 'alternate',
|
| 913 |
'type' => 'application/rss+xml',
|
| 914 |
'title' => t('RSS - %title', array('%title' => $title)),
|
| 915 |
'href' => url("planet/$account->uid/feed")));
|
| 916 |
return $output;
|
| 917 |
}
|
| 918 |
else {
|
| 919 |
drupal_not_found();
|
| 920 |
}
|
| 921 |
}
|
| 922 |
|
| 923 |
/**
|
| 924 |
* Implementation of hook_load - Load node-type-specific information.
|
| 925 |
*
|
| 926 |
* @param $node The node being loaded.
|
| 927 |
* @return An object containing properties of the node being loaded.
|
| 928 |
* @ingroup system
|
| 929 |
* @CRUD{planet_items,R}
|
| 930 |
*/
|
| 931 |
function planet_load($node) {
|
| 932 |
$additions = db_fetch_object(db_query('SELECT link, guid FROM {planet_items} WHERE nid = %d', $node->nid));
|
| 933 |
return $additions;
|
| 934 |
}
|
| 935 |
|
| 936 |
/**
|
| 937 |
* Implementation of hook_form - Display a node editing form.
|
| 938 |
*
|
| 939 |
* @param &$node The node being added or edited.
|
| 940 |
* @param $form_state The form state array (unused).
|
| 941 |
* @return An array containing the form elements to be displayed in the node edit form.
|
| 942 |
* @ingroup planet_node
|
| 943 |
*/
|
| 944 |
function planet_form(&$node, &$form_state) {
|
| 945 |
$form = array();
|
| 946 |
$form['title'] = array('#type' => 'textfield', '#title' => 'Title', '#value' => $node->title, '#size' => 30, '#maxlength' => 80);
|
| 947 |
$form['body'] = array('#type' => 'textarea', '#title' => 'Body', '#value' => $node->body);
|
| 948 |
return $form;
|
| 949 |
}
|
| 950 |
|
| 951 |
/**
|
| 952 |
* Turn each feed item into a node.
|
| 953 |
*
|
| 954 |
* @param $process_feed
|
| 955 |
* Feed node object
|
| 956 |
* @param $feed
|
| 957 |
* SimplePie feed object instaniated.
|
| 958 |
*/
|
| 959 |
function planet_item_feed_parse($process_feed, $feed) {
|
| 960 |
// loop through all of the items in the feed, faster than foreach
|
| 961 |
$max = $feed->get_item_quantity();
|
| 962 |
$count = 0;
|
| 963 |
module_load_include('inc', 'node', 'node.pages');
|
| 964 |
module_load_include('inc', 'node', 'content_types');
|
| 965 |
$node = node_get_types('type', 'feed_item');
|
| 966 |
|
| 967 |
for ($i = 0; $i < $max; $i++) {
|
| 968 |
$item = $feed->get_item($i);
|
| 969 |
|
| 970 |
// we don't use $item->get_id(true) from SimplePie because it is slightly buggy
|
| 971 |
// and requires a lot of overhead to compute each time (since it uses a gigantic array structure)
|
| 972 |
// instead we opt for a much lighter weight comparison of just the title and body, eliminating the
|
| 973 |
// possibility of any date changes or other tiny changes causing duplicate nodes that otherwise
|
| 974 |
// appear to be the same
|
| 975 |
// that is why the body and title processing appears out here, so we can check for duplicates
|
| 976 |
// it is fast enough to not make much of a difference otherwise
|
| 977 |
$body = $item->get_content();
|
| 978 |
// this strips out any tags that may appear as <b> in the title, and makes sure " -> " for display
|
| 979 |
$title = strip_tags(decode_entities($item->get_title()));
|
| 980 |
|
| 981 |
// some feeds don't provide titles so we construct one with the first 72 characters of the body
|
| 982 |
if (!$title) {
|
| 983 |
// remove any HTML or line breaks so these don't appear in the title
|
| 984 |
$title = trim(str_replace(array("\n", "\r"), ' ', strip_tags($body)));
|
| 985 |
$title = trim(substr($title, 0, 72));
|
| 986 |
$lastchar = substr($title, -1, 1);
|
| 987 |
// check to see if the last character in the title is a non-alphanumeric character, except for ? or !
|
| 988 |
// if it is strip it off so you don't get strange looking titles
|
| 989 |
if (preg_match('/[^0-9A-Za-z\!\?]/', $lastchar)) {
|
| 990 |
$title = substr($title, 0, -1);
|
| 991 |
}
|
| 992 |
// ? and ! are ok to end a title with since they make sense
|
| 993 |
if ($lastchar != '!' and $lastchar != '?') {
|
| 994 |
$title .= '...';
|
| 995 |
}
|
| 996 |
}
|
| 997 |
|
| 998 |
// unique id for each feed item, try and use item permalink, otherwise use feed permalink
|
| 999 |
if (!$link = $item->get_permalink()) {
|
| 1000 |
$link = $feed->get_permalink();
|
| 1001 |
}
|
| 1002 |
// we don't need serialize() since we already have strings
|
| 1003 |
$iid = md5($title . $link);
|
| 1004 |
$guid = md5("$title - . " . $process_feed->fid);
|
| 1005 |
// make sure we don't already have this feed item
|
| 1006 |
$duplicate = db_result(db_query("SELECT COUNT(iid) FROM {planet_items} WHERE iid = '%s'", $iid));
|
| 1007 |
|
| 1008 |
if (!$duplicate) {
|
| 1009 |
|
| 1010 |
|
| 1011 |
$entry = NULL;
|
| 1012 |
if ($guid && strlen($guid) > 0) {
|
| 1013 |
$entry = db_fetch_object(db_query("SELECT nid FROM {planet_items} WHERE guid = '%s' AND fid = %d", $guid, $process_feed->fid));
|
| 1014 |
}
|
| 1015 |
else if ($link && $link != $feed->link && $link != $feed->url) {
|
| 1016 |
$entry = db_fetch_object(db_query("SELECT nid FROM {planet_items} WHERE guid = '%s' AND fid = %d", $link, $process_feed->fid));
|
| 1017 |
}
|
| 1018 |
else {
|
| 1019 |
$entry = db_fetch_object(db_query("SELECT ai.nid AS nid FROM {node} n, {planet_items} ai WHERE ai.fid = %d AND ai.nid = n.nid AND n.title = '%s'", $process_feed->fid, $title));
|
| 1020 |
}
|
| 1021 |
|
| 1022 |
$link = $item->get_permalink();
|
| 1023 |
// this is node created date format for Drupal
|
| 1024 |
$date = $item->get_date('Y-m-d H:i:s O');
|
| 1025 |
|
| 1026 |
$entry->changed = $date;
|
| 1027 |
$entry->title = $title;
|
| 1028 |
$entry->body = $body;
|
| 1029 |
$entry->body = planet_convert_relative_urls($body, $link);
|
| 1030 |
$entry->teaser = node_teaser($entry->body);
|
| 1031 |
$entry->revision = true;
|
| 1032 |
|
| 1033 |
if (!isset($entry->nid)) {
|
| 1034 |
//print "Planet item " . $entry->title . "<br />";
|
| 1035 |
$entry->type = 'planet';
|
| 1036 |
|
| 1037 |
$options = variable_get('node_options_planet', array());
|
| 1038 |
|
| 1039 |
$entry->uid = $process_feed->uid;
|
| 1040 |
$entry->status = 1;
|
| 1041 |
$entry->moderate = 0;
|
| 1042 |
$entry->promote = in_array('promote', $options) ? 1 : 0;
|
| 1043 |
$entry->sticky = in_array('sticky', $options) ? 1 : 0;
|
| 1044 |
$entry->comment = in_array('comment', $options) ? 2 : 0;
|
| 1045 |
$entry->format = variable_get('planet_filter_formats', 1);
|
| 1046 |
$entry->created = $date;
|
| 1047 |
$entry->revision = true;
|
| 1048 |
|
| 1049 |
}
|
| 1050 |
|
| 1051 |
node_save($entry);
|
| 1052 |
$item_record = array('fid' => $process_feed->fid,
|
| 1053 |
'nid' => $entry->nid,
|
| 1054 |
'iid' => $iid,
|
| 1055 |
'guid'=> $guid,
|
| 1056 |
'link' =>$link,
|
| 1057 |
'created' => time());
|
| 1058 |
drupal_write_record('planet_items', $item_record);
|
| 1059 |
watchdog('planet', 'Adding '. $title);
|
| 1060 |
drupal_set_message('Adding '. $title);
|
| 1061 |
}
|
| 1062 |
|
| 1063 |
// we unset $item each time to prevent any pass by reference memory leaks that PHP encounters with objects in foreach loops
|
| 1064 |
unset($item);
|
| 1065 |
}
|
| 1066 |
|
| 1067 |
}
|