/[drupal]/contributions/modules/leech/leech.module
ViewVC logotype

Contents of /contributions/modules/leech/leech.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.6 - (show annotations) (download) (as text)
Tue Jan 23 11:58:46 2007 UTC (2 years, 10 months ago) by aronnovak
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +9 -4 lines
File MIME type: text/x-php
Fixing groups settings lost after each cron run bug
1 <?php
2 /* $Id: leech.module,v 1.5 2007/01/22 16:38:22 aronnovak Exp $ */
3
4 /**
5 * @file
6 * Used to automatically download content (RSS, RDF, Atom, OPML, images, whatever else) and inform other modules about new data.
7 * Sponsored by Development Seed.
8 * Sponsored by John Bransford.
9 */
10
11 /*
12 Copyright (C) 2006 by Marcin Konicki <ahwayakchih@gmail.com>
13 Based on parts of Aggregator2 module,
14 Also depends on other modules from Drupal basic distribution and, in some cases, contains parts of their code.
15
16 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY.
20
21 See the LICENSE file for more details.
22 */
23
24 // Permissions
25 define('LEECH_PERM_CREATE', 'create feed');
26 define('LEECH_PERM_EDIT_OWN', 'edit own feeds');
27 define('LEECH_PERM_REFRESH_OWN', 'manually leech data');
28 define('LEECH_PERM_ACCESS', 'access feeds');
29 define('LEECH_NEWS_PERM_EDIT_OWN_ITEM', 'edit own news items');
30
31 define("LEECH_SHOW_LINK_ALWAYS", 0);
32 define("LEECH_SHOW_LINK_NEVER", 1);
33 define("LEECH_SHOW_LINK_TEASER_ONLY", 2);
34 define("LEECH_SHOW_LINK_PAGE_ONLY", 3);
35 define("LEECH_SHOW_LINK_IN_LINKS", 1);
36 define("LEECH_SHOW_LINK_INLINE", 2);
37
38 /**
39 * Implementation of hook_help().
40 */
41 function leech_help($section) {
42 switch ($section) {
43 case 'admin/help#leech':
44 return t('Feed aggretagor, creates nodes from RSS or ATOM feeds. <em>Requires node_template.module</em>');
45 case 'admin/modules#description':
46 return t('Feed aggretagor, creates nodes from RSS or ATOM feeds. <em>Requires node_template.module</em>');
47 }
48 }
49
50 /**
51 * Implementation of hook_perm().
52 */
53 function leech_perm() {
54 return array(LEECH_PERM_CREATE,
55 LEECH_PERM_EDIT_OWN,
56 LEECH_PERM_REFRESH_OWN,
57 LEECH_PERM_ACCESS,
58 LEECH_NEWS_PERM_EDIT_OWN_ITEM);
59 }
60
61 /**
62 * Implementation of hook_menu().
63 * heads up: there are a couple of renamed paths here, old paths are kept
64 * for a while for backwards compatibility. check out what's new and change your
65 * site accordingly.
66 */
67 function leech_menu($may_cache) {
68 $items = array();
69
70 if ($may_cache) {
71 $items[] = array('path' => 'leech/list', 'title' => t('leech'),
72 'callback' => 'leech_page_feed_list', 'access' => user_access(LEECH_PERM_ACCESS),
73 'type' => MENU_CALLBACK);
74 $items[] = array('path' => 'admin/leech', 'title' => t('leech'),
75 'callback' => 'leech_page_admin');
76 // DEPRECATED, use leech/feed without any further argument instead
77 $items[] = array('path' => 'leech/sources', 'title' => t('sources'),
78 'callback' => 'leech_news_page_default', 'access' => user_access(LEECH_PERM_ACCESS),
79 'type' => MENU_CALLBACK);
80 // DEPRECATED, use leech/feed/opml instead
81 $items[] = array('path' => 'leech/sources/opml', 'title' => t('opml'),
82 'callback' => 'leech_page_opml', 'access' => user_access(LEECH_PERM_ACCESS),
83 'type' => MENU_CALLBACK);
84 $items[] = array('path' => 'leech/feed/opml', 'title' => t('opml'),
85 'callback' => 'leech_page_opml', 'access' => user_access(LEECH_PERM_ACCESS),
86 'type' => MENU_CALLBACK);
87 // TODO: find a nice way to allow refresh only to feed owner
88 $items[] = array('path' => 'leech/refresh', 'title' => t('refresh data'),
89 'callback' => 'leech_page_refresh', 'access' => user_access(LEECH_PERM_REFRESH_OWN),
90 'type' => MENU_CALLBACK);
91 $items[] = array('path' => 'leech/get/form', 'title' => t('get addons form'),
92 'callback' => 'leech_get_form', 'access' => user_access(LEECH_PERM_CREATE),
93 'type' => MENU_CALLBACK);
94 $items[] = array('path' => 'leech.js', 'title' => t('javascript file'),
95 'callback' => 'leech_javascript', 'access' => user_access(LEECH_PERM_CREATE),
96 'type' => MENU_CALLBACK);
97 // DEPRECATED, use leech/feed instead
98 $items[] = array('path' => 'leech_news/feed', 'title' => t('leech news'),
99 'callback' => 'leech_news_page_default', 'access' => user_access(LEECH_PERM_ACCESS),
100 'type' => MENU_CALLBACK);
101 $items[] = array('path' => 'leech/feed', 'title' => t('All feeds'),
102 'callback' => 'leech_news_page_default', 'access' => user_access(LEECH_PERM_ACCESS));
103 // DEPRECATED, use leech/remove_items instead
104 $items[] = array('path' => 'leech_news/remove', 'title' => t('leech news'),
105 'callback' => 'leech_news_page_remove', 'access' => user_access(LEECH_NEWS_PERM_EDIT_OWN_ITEM),
106 'type' => MENU_CALLBACK);
107 $items[] = array('path' => 'leech/remove_items', 'title' => t('leech news'),
108 'callback' => 'leech_news_page_remove', 'access' => user_access(LEECH_NEWS_PERM_EDIT_OWN_ITEM),
109 'type' => MENU_CALLBACK);
110 }
111
112 return $items;
113 }
114
115 /**
116 * prints view of latest cron times
117 */
118 function _leech_cron_times_view($crontimes = array()){
119 $output = '<div class="crontimes">';
120
121 $last_time = 0;
122 if (count($crontimes) > 1) {
123 $output .= '<div><strong>'.t('Latest').' '.(count($crontimes)-1).' '.t('cron runs').'</strong></div>';
124 foreach ($crontimes as $t) {
125 if ($last_time != 0) {
126 $output .= '<div>';
127 $output .= format_date($t, 'large');
128 $output .= ', '.t('after').' '.format_interval($t-$last_time);
129 $output .= '</div>';
130 }
131 $last_time = $t;
132 }
133 }
134 else {
135 $output .= '<div><strong>'.t('Latest').' '.t('cron runs').'</strong></div>';
136 $output .= t('Cron has not been run.');
137 }
138 $output .= '</div>';
139
140 return $output;
141 }
142
143 /**
144 * Implementation of hook_settings().
145 */
146 function leech_settings() {
147 $form = array();
148
149 $form['leech_info_cURL'] = array(
150 '#value' => (function_exists('curl_init') ? '' : t('cURL module for PHP is not available. Some features may be not available because of that.')));
151
152
153
154 $form['leech_display'] = array(
155 '#type' => 'fieldset',
156 '#title' => t('Display settings'),
157 '#tree' => FALSE,
158 );
159 $form['leech_display']['leech_news_show_feed_link'] = array(
160 '#type' => 'select',
161 '#title' => t('Show link to feed with each item'),
162 '#default_value' => variable_get('leech_news_show_feed_link', 0),
163 '#options' => array(0 => t('Don\'t show'),
164 LEECH_SHOW_LINK_IN_LINKS => t('In links list'),
165 LEECH_SHOW_LINK_INLINE => t('Inline in body/teaser')),
166 '#description' => t('If "In links list" selected, Leech News will show link to source feed on each item in links list, if "Inline in body/teaser" selected, it will show this link in the feed item\'s body.'));
167
168 $form['leech_display']['leech_news_show_items_link'] = array(
169 '#type' => 'select',
170 '#title' => t('Show link to items with each feed'),
171 '#default_value' => variable_get('leech_news_show_items_link', 0),
172 '#options' => array(0 => t('Don\'t show'),
173 LEECH_SHOW_LINK_IN_LINKS => t('In links list')) ,
174 '#description' => t('If "In links list" selected, Leech News will show "items" link with each feed. It will point to list of all items created by that feed.'));
175
176 $form['leech_blacklist'] = array(
177 '#type' => 'fieldset',
178 '#title' => t('Blacklist'),
179 '#tree' => FALSE,
180 );
181 $form['leech_blacklist']['leech_blacklist_url'] = array(
182 '#type' => 'textarea',
183 '#title' => t('Blacklist URLs'),
184 '#default_value' => variable_get('leech_blacklist_url', ''),
185 '#rows' => 5,
186 '#description' => t('One entry per line. You can enter full URLs or domain names only. You can also enter regular expression (find out more about what it is at %link. more examples can be found also at %link2). For example "http://some.url.com/some/page.html" will blacklist that specific URL. ".url.com" will blacklist all URLs from url.com domain, and all it\'s subdomains. "some.url.com" will blacklist all URLs from "some" subdomain. "/^ftp\:\/\//" will blacklist any ftp:// URL. Leech module will not download any data from URL which matches any of the rules on blacklist.', array('%link' => l('http://www.php.net/manual/en/reference.pcre.pattern.syntax.php', 'http://www.php.net/manual/en/reference.pcre.pattern.syntax.php'), '%link2' => l('http://www.php.net/manual/en/function.preg-match.php', 'http://www.php.net/manual/en/function.preg-match.php'))));
187
188 $form['leech_url_profile'] = array(
189 '#type' => 'fieldset',
190 '#title' => t('URL profile'),
191 '#tree' => FALSE,
192 );
193 $msg = '<div class="msg-description">'.t('The URL profile module allows you to surf feed items per original source and optionally retrieve information from third parties such as Alexa or Technorati.').'</div>';
194 if (module_exist('url_profile')) {
195 $msg .= '<div class="msg-moduledetected">'.t('<strong>URL profile module detected.</strong> Leech feed item URLs are being profiled.').'</div>';
196 }
197 else {
198 $msg .= '<div class="msg-modulenotdetected">'.t('<strong>URL profile module not installed.</strong>').'</div>';
199 }
200 $form['leech_url_profile']['detected'] = array(
201 '#type' => 'markup',
202 '#value' => $msg,
203 );
204
205 $form['leech_og'] = array(
206 '#type' => 'fieldset',
207 '#title' => t('Organic groups'),
208 '#tree' => FALSE,
209 );
210 if (module_exist('og')) {
211 $msg = '<div class="msg-moduledetected">'.t('<strong>Organic groups (og) module detected.</strong> Leech feeds are passing on their group association to their feed items.').'</div>';
212 }
213 else {
214 $msg = '<div class="msg-modulenotdetected">'.t('<strong>Organic groups (og) module not installed.</strong>').'</div>';
215 }
216 $form['leech_og']['detected'] = array(
217 '#type' => 'markup',
218 '#value' => $msg,
219 );
220
221 $form['leech_advanced'] = array(
222 '#type' => 'fieldset',
223 '#title' => t('Advanced settings'),
224 '#collapsible' => TRUE,
225 '#collapsed' => TRUE,
226 '#tree' => FALSE,
227 );
228 $parsers = array('leech_news' => 'leech_news');
229 foreach (module_implements('parse_news_feed') as $name) {
230 $parsers[$name] = $name;
231 }
232 $form['leech_advanced']['leech_news_parser'] = array(
233 '#type' => 'select',
234 '#title' => t('Select parser'),
235 '#default_value' => variable_get('leech_news_parser', 'leech_news'),
236 '#options' => $parsers,
237 '#description' => t('Select which parser to use to parse RSS/ATOM feed.'));
238 $form['leech_advanced']['leech_news_original_links'] = array(
239 '#type' => 'checkbox',
240 '#title' => t('Use source link'),
241 '#default_value' => variable_get('leech_news_original_links', 1),
242 '#description' => t('Use link to original source of article when possible - usually the source link is preferrable.'),
243 );
244 $form['leech_advanced']['leech_news_verbose'] = array(
245 '#type' => 'checkbox',
246 '#title' => t('Verbose output to watchdog'),
247 '#default_value' => variable_get('leech_news_verbose', 0),
248 '#description' => t('Check if you would like to have more verbose output about leech on the %watchdoglink.', array('%watchdoglink' => l('watchdog', 'admin', array('title' => 'watchdog')))),
249 );
250 if (module_exist('taxonomy')) {
251 $form['leech_advanced']['leech_news_pass_on_taxonomy'] = array(
252 '#type' => 'checkbox',
253 '#title' => t('Pass on taxonomy from feed to feed items'),
254 '#default_value' => variable_get('leech_news_pass_on_taxonomy', 0),
255 '#description' => t('If enabled, taxonomy of a feed node will be passed on
256 to its existing and future child feed items. Only those
257 taxonomies will get passed on, that are enabled for both,
258 feed and feed item.'),
259 );
260 }
261 $form['leech_advanced']['cron'] = array(
262 '#type' => 'fieldset',
263 '#title' => t('Cron settings'),
264 '#tree' => FALSE,
265 );
266
267 // list last n times cron was called
268 $form['leech_advanced']['cron']['leech_cron_times_overview'] = array(
269 '#type' => 'markup',
270 '#value' => _leech_cron_times_view(variable_get('leech_cron_times', array())),
271 );
272
273 // how many leeches to update at one cron run
274 $leech_count['9999999'] = t('All');
275 $leech_count = drupal_map_assoc(array(0, 1, 2, 3, 4, 5, 10, 15, 20, 25, 50, 100));
276 $form['leech_advanced']['cron']['leech_cron_count'] = array(
277 '#type' => 'select',
278 '#title' => t('Update count'),
279 '#default_value' => variable_get('leech_cron_count', 5),
280 '#options' => $leech_count,
281 '#description' => t('Select how many leeches can be updated at one cron run.'));
282 // how long sleep interval should be
283 $interval = drupal_map_assoc(array(0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15));
284 $form['leech_advanced']['cron']['leech_sleep_interval'] = array(
285 '#type' => 'select',
286 '#title' => t('Sleep time'),
287 '#default_value' => variable_get('leech_sleep_interval', 3),
288 '#options' => $leech_count,
289 '#description' => t('Select how many seconds module should wait before updating next leech.'));
290
291 return $form;
292 }
293
294 /**
295 * url_profile hook - list urls to be url_profiled. interface to url_profile.module
296 */
297 function leech_url_profile(&$object, $op, $arg = NULL) {
298
299 switch ($op) {
300 case 'list':
301
302
303 /*
304 no profiling for leech feeds - we could make this optional
305 if ($node->leech_news && $node->leech_news->link) {
306 $list[] = $node->leech_news->link;
307 }
308 */
309 $list = array();
310 // sometimes stuff comes in as array - todo: clean this up
311 if ($object->leech_news_item) {
312 if ($object->leech_news_item->link) {
313 $list[] = $object->leech_news_item->link;
314 }
315 else if ($object->leech_news_item['link']) {
316 $list[] = $object->leech_news_item['link'];
317 }
318 if ($object->leech_news_item->source_link) {
319 $list[] = $object->leech_news_item->source_link;
320 }
321 else if ($object->leech_news_item['source_link']) {
322 $list[] = $object->leech_news_item['source_link'];
323 }
324 }
325 return $list;
326 case 'list_matches':
327 $result = db_query ('SELECT DISTINCT li.nid, li.link as url
328 FROM {leech_news_item} li
329 JOIN {node} n ON n.nid = li.nid
330 WHERE li.link LIKE "%s%%"
331 AND li.link LIKE "%%%s%%" ',
332 $object->url, $object->criteria);
333 while ($feed_item = db_fetch_object($result)) {
334 $list[] = $feed_item;
335 }
336 return $list;
337 }
338 }
339
340 /**
341 * This function gives control of contents and functions on the link of 'full article'.
342 */
343 function theme_leech_link_full_article($node) {
344 $link = $node->leech_news_item->link;
345 if (variable_get('leech_news_original_links', 0) && $node->leech_news->source_link) {
346 $link = $node->leech_news->source_link;
347 }
348 return '<a href="'. $link .'" title="'. t('Read original article.') .'">'. t('original article') .'</a>';
349 }
350
351
352
353 /**
354 * This function gives control of contents and functions on the link of 'visit site'.
355 */
356 function theme_leech_link_visit_site($node) {
357 return '<a href="'. $node->leech_news->link .'" title="'. t('Visit the site where this news was first published.') .'">'. t('visit site') .'</a>';
358 }
359
360 /**
361 * Menu callback; Generate a listing of feed items.
362 */
363 function leech_news_page_default($nid = NULL) {
364 $output = '';
365
366 if ($nid != NULL && is_numeric($nid)) {
367 drupal_set_title(t('Feed'));
368 $feed = node_load($nid);
369 if ($feed && $feed->leech_news) {
370 $output .= node_view($feed, 1);
371 $result = pager_query(db_rewrite_sql('SELECT n.nid, n.sticky, n.created FROM {node} n INNER JOIN {leech_news_item} i ON i.nid = n.nid WHERE i.fid = %d AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC'), variable_get('default_nodes_main', 10), 0, NULL, $feed->nid);
372 while ($node = db_fetch_object($result)) {
373 $output .= node_view(node_load($node->nid), 1);
374 }
375 $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
376 }
377 else {
378 drupal_goto('node/'. $nid);
379 }
380 }
381 else {
382 // If there's no nid given, then show page with feed nodes
383 $result = pager_query(db_rewrite_sql('SELECT n.nid, n.sticky, n.created FROM {node} n INNER JOIN {leech_news_feed} f ON f.nid = n.nid WHERE n.status = 1 ORDER BY n.sticky DESC, n.created DESC'), variable_get('default_nodes_main', 10), 0, NULL);
384 while ($node = db_fetch_object($result)) {
385 $output .= node_view(node_load($node->nid), 1);
386 }
387 $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
388 }
389
390 return $output;
391 }
392
393 /**
394 * Menu callback; Remove items.
395 */
396 function leech_news_page_remove($nid = NULL) {
397 if ($nid == NULL && is_numeric(arg(1))) {
398 $nid = arg(1);
399 }
400
401 // Handle operations
402 $op = $_POST['op'];
403 $edit = $_POST['edit'];
404
405 $feed = node_load($nid);
406 if ($feed->leech_news) {
407 global $user;
408 if (!user_access(LEECH_NEWS_PERM_EDIT_OWN_ITEM) || ($user->uid != $feed->uid)) {
409 if (!user_access('administer nodes')) {
410 drupal_access_denied();
411 return;
412 }
413 // We don't need to fake user here as we don't really need nodes to be deleted by owner
414 }
415
416 // Mass delete
417 if ($edit['confirm']) {
418 // Stop Timeouts Whilst Processing Feed
419 set_time_limit(0);
420
421 // Remove each feed item node
422 if (is_array($edit['nodes'])) {
423 foreach ($edit['nodes'] as $nid => $value) {
424 node_delete($nid);
425 }
426 }
427
428 drupal_set_message(t('The items have been deleted.'));
429 drupal_goto('admin/leech');
430 }
431 else {
432 $form = array();
433
434 $result = db_query('SELECT n.title, n.nid FROM {node} n LEFT JOIN {leech_news_item} i ON i.nid = n.nid WHERE i.fid = %d ORDER BY n.title', $feed->nid);
435 $items = array();
436 while ($item = db_fetch_object($result)) {
437 $items[$item->nid] = $item->title;
438 }
439
440 $form['nodes'] = array(
441 '#type' => 'checkboxes',
442 '#title' => t('Delete following items:'),
443 '#default_value' => array_keys($items),
444 '#options' => $items);
445 return confirm_form('items_delete_confirm', $form, t('Please confirm which items You really want to delete'), 'admin/leech', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
446 }
447 }
448 }
449
450 /**
451 * Create an XML document header and tail for opml
452 */
453 function _opml_skeleton($content) {
454 $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
455 $output .= "<opml version=\"1.1\">\n";
456 $output .= "<head>\n";
457 $output .= '<title>'. variable_get('site_name', 'drupal') .' - '. variable_get('site_slogan', '') ."</title>\n";
458 $output .= '<dateModified>'. gmdate('r') ."</dateModified>\n";
459 $output .= "</head>\n";
460 $output .= "<body>\n";
461 $output .= $content;
462 $output .= "</body>\n";
463 $output .= "</opml>\n";
464 return $output;
465 }
466
467 /**
468 * Parse xml into feed data
469 */
470 function _leech_news_parse($xml) {
471 $parser = variable_get('leech_news_parser', 'leech_news');
472 if ($parser == 'leech_news') {
473 include_once('leech_news_parser.inc');
474 }
475
476 if ($parser) {
477 $function = $parser .'_parse_news_feed';
478 return $function($xml);
479 }
480 }
481
482 /**
483 * Implementation of hook_form_alter().
484 */
485 function leech_form_alter($form_id, &$form) {
486
487 // Add leech fields to node edit form
488 if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id && variable_get('leech_for#'.$form['#node']->type, 0)) {
489 $node = $form['#node'];
490 if (isset($form['body_filter']['body'])) {
491 $form['body_filter']['body']['#required'] = 0;
492 }
493 $form['leech'] = array(
494 '#type' => 'fieldset',
495 '#title' => t('Leech'),
496 '#collapsible' => TRUE,
497 '#collapsed' => FALSE,
498 '#tree' => TRUE
499 );
500 $form['leech']['nid'] = array(
501 '#type' => 'hidden',
502 '#value' => $node->nid,
503 '#attributes' => array('id' => 'edit-leech-nid')
504 );
505 drupal_add_js('?q=leech.js');
506 $form['leech']['url'] = array(
507 '#type' => 'textfield',
508 '#title' => t('URL'),
509 '#default_value' => $node->leech->url,
510 '#size' => 60,
511 '#maxlength' => 2048,
512 '#description' => t('URL from which data will be downloaded.'),
513 '#weight' => -99,
514 '#attributes' => array('onFocus' => 'leech_prepare_check_url(this)', 'onBlur' => 'leech_close_check_url(this)')
515 );
516 $period = drupal_map_assoc(array(0, 900, 1800, 3600, 7200, 10800, 21600, 32400, 43200, 64800, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval');
517 $period[0] = t('Freezed');
518 $form['leech']['refresh'] = array (
519 '#type' => 'select',
520 '#title' => t('Frequency'),
521 '#default_value' => 10800, // hack- todo: check, wether what happens on node edit. $node->leech->refresh,
522 '#options' => $period,
523 '#description' => t('Frequency at which new data will be downloaded.'),
524 '#weight' => -97
525 );
526
527 // Add fields from other modules which want to work with us through leechapi
528 $form['leech']['addons'] = array(
529 '#type' => 'fieldset',
530 '#title' => t('Additional options'),
531 '#collapsible' => TRUE,
532 '#collapsed' => FALSE,
533 '#weight' => 1,
534 '#prefix' => '<div id="edit-leech-addons">',
535 '#suffix' => '</div>'
536 );
537
538 // Mark if there was leech data with node or not
539 if (!$node->leech->nid) {
540 $form['leech']['is_new'] = array(
541 '#type' => 'hidden',
542 '#value' => 1
543 );
544 }
545
546 // since 4.7.2 (or .3) there is no easy way to get node type html field cause now it's ID is like: node-[type]-node-form
547 // so just create our own ;p
548 $form['leech']['node_type'] = array(
549 '#type' => 'hidden',
550 '#value' => $node->type
551 );
552
553
554 // Some values we may want to use
555 if (isset($node->leech->connection)) {
556 $form['leech']['mime'] = array('#type' => 'value', '#value' => $node->leech->mime);
557 $form['leech']['connection'] = array('#type' => 'value', '#value' => $node->leech->connection);
558 }
559
560 if ($node->leech->_prerender_id) {
561 // Hookup prerendering of addons part for our ajax magic ;]
562 if (!is_array($form['#pre_render'])) {
563 $form['#pre_render'] = array();
564 }
565 $form['#pre_render'][] = 'leech_pre_render_addons';
566 }
567 }
568 // "Workflow" form
569 if (isset($form['type']) && $form['type']['#value'] .'_node_settings' == $form_id) {
570 $form['workflow']['leech_defs'] = array(
571 '#type' => 'fieldset',
572 '#title' => t('Default leech options'),
573 '#collapsible' => FALSE,
574 '#collapsed' => FALSE
575 );
576 $form['workflow']['leech_defs']['leech_for#'.$form['type']['#value']] = array (
577 '#type' => 'checkbox',
578 '#title' => t('Enable leech'),
579 '#default_value' => variable_get('leech_for#'.$form['type']['#value'], 0),
580 '#attributes' => array(
581 'onclick' => 'if(isJsEnabled()) toggleClass(this.parentNode.parentNode.parentNode, "collapsed");',
582 )
583 );
584 if (!variable_get('leech_for#'.$form['type']['#value'], 0)) {
585 $form['workflow']['leech_defs']['#attributes']['class'] = 'collapsed';
586 }
587 $form['workflow']['leech_defs']['leech_news_template_for#'.$form['type']['#value']] = array (
588 '#type' => 'select',
589 '#title' => t('Template'),
590 '#options' => node_template_list(),
591 '#default_value' => variable_get('leech_news_template_for#'.$form['type']['#value'], 0),
592 '#description' => t('Select which node template should be used as template for new items')
593 );
594 $form['workflow']['leech_defs']['leech_news_items_guid_for#'.$form['type']['#value']] = array(
595 '#type' => 'checkbox',
596 '#title' => t('Generate GUIDs'),
597 '#default_value' => variable_get('leech_news_items_guid_for#'.$form['type']['#value'], 0)
598 );
599 $form['workflow']['leech_defs']['leech_news_items_status_for#'.$form['type']['#value']] = array(
600 '#type' => 'checkbox',
601 '#title' => t('Publish news items'),
602 '#default_value' => variable_get('leech_news_items_status_for#'.$form['type']['#value'], 1)
603 );
604 $form['workflow']['leech_defs']['leech_news_items_update_for#'.$form['type']['#value']] = array(
605 '#type' => 'checkbox',
606 '#title' => t('Update already existing news items'),
607 '#default_value' => variable_get('leech_news_items_update_for#'.$form['type']['#value'], 0)
608 );
609 $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 3628800, 4838400, 7257600, 15724800, 31536000), 'format_interval');
610 $period['1000000000'] = t('Never');
611 $form['workflow']['leech_defs']['leech_news_items_delete_for#'.$form['type']['#value']] = array(
612 '#type' => 'select',
613 '#title' => t('Delete news items older than'),
614 '#options' => $period,
615 '#default_value' => variable_get('leech_news_items_delete_for#'.$form['type']['#value'], 15724800)
616 );
617 $promote = drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30));
618 $promote['0'] = t('None');
619 $promote['1000000000'] = t('All');
620 $form['workflow']['leech_defs']['leech_news_items_promote_for#'.$form['type']['#value']] = array(
621 '#type' => 'select',
622 '#title' => t('Promote items'),
623 '#options' => $promote,
624 '#default_value' => variable_get('leech_news_items_promote_for#'.$form['type']['#value'], 3)
625 );
626 $form['workflow']['leech_defs']['leech_news_items_date_for#'.$form['type']['#value']] = array(
627 '#type' => 'checkbox',
628 '#title' => t('Use dates found in feed (if possible)'),
629 '#default_value' => variable_get('leech_news_items_date_for#'.$form['type']['#value'], 1)
630 );
631 $form['workflow']['leech_defs']['leech_news_links_for#'.$form['type']['#value']] = array (
632 '#type' => 'select',
633 '#title' => t('Show "original article"/"visit site" link'),
634 '#options' => array(
635 LEECH_SHOW_LINK_ALWAYS => t('Always'),
636 LEECH_SHOW_LINK_NEVER => t('Do not display'),
637 LEECH_SHOW_LINK_TEASER_ONLY => t('Only with teaser'),
638 LEECH_SHOW_LINK_PAGE_ONLY => t('Only on full page')
639 ),
640 '#default_value' => variable_get('leech_news_links_for#'.$form['type']['#value'], LEECH_SHOW_LINK_ALWAYS),
641 '#description' => t('Select place(s) where link to original article (for news items) or visit site (for news feeds) will be shown.')
642 );
643 $form['#after_build'][] = 'leech_after_build_defs';
644 }
645 // Add item's data to node edit form
646 if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id && $form['#node']->leech_news_item) {
647 $node = $form['#node'];
648
649 $form['leech_news_item'] = array(
650 '#type' => 'fieldset',
651 '#title' => t('Leeched news item'),
652 '#collapsible' => TRUE,
653 '#collapsed' => FALSE,
654 '#tree' => TRUE
655 );
656 if (user_access('administer nodes')) {
657 // don't allow regular user's to "steal fame" :)
658 $feeds = array();
659 $result = db_query(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n, {leech_news_feed} f WHERE f.nid = n.nid'));
660 while ($temp = db_fetch_array($result)) {
661 $feeds[$temp['nid']] = $temp['title'];
662 }
663 $form['leech_news_item']['fid'] = array (
664 '#type' => 'select',
665 '#title' => t('Feed Name'),
666 '#default_value' => $node->leech_news_item->fid,
667 '#options' => $feeds,
668 '#required' => TRUE,
669 '#description' => t('The RSS/ATOM feed which this item belongs to.')
670 );
671 $form['leech_news_item']['link'] = array(
672 '#type' => 'textfield',
673 '#title' => t('Link'),
674 '#default_value' => $node->leech_news_item->link,
675 '#size' => 60,
676 '#maxlength' => 250
677 );
678 $form['leech_news_item']['author'] = array(
679 '#type' => 'textfield',
680 '#title' => t('Original author'),
681 '#default_value' => $node->leech_news_item->author,
682 '#size' => 60,
683 '#maxlength' => 60
684 );
685 }
686 else {
687 // don't allow regular user's to "steal fame" :)
688 $form['leech_news_item']['fid'] = array(
689 '#type' => 'hidden',
690 '#value' => $node->leech_news_item->fid
691 );
692 $form['leech_news_item']['link'] = array(
693 '#type' => 'hidden',
694 '#value' => $node->leech_news_item->link
695 );
696 $form['leech_news_item']['author'] = array(
697 '#type' => 'hidden',
698 '#value' => $node->leech_news_item->author
699 );
700 }
701
702 $form['leech_news_item']['source_link'] = array(
703 '#value' => $node->leech_news_item->source_link
704 );
705 $form['leech_news_item']['source_xml'] = array(
706 '#value' => $node->leech_news_item->source_xml
707 );
708 $form['leech_news_item']['source_title'] = array(
709 '#value' => $node->leech_news_item->source_title
710 );
711 }
712
713 // Add leech fields to node edit form
714 if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id && variable_get('leech_for#'.$form['#node']->type, 0)) {
715 $node = $form['#node'];
716
717 if (!isset($node->leech->connection) || !isset($node->leech->connection->news_feed)) {
718 return;
719 }
720
721 // Shortcut to make things more readable ;)
722 $feed = &$node->leech->connection->news_feed;
723 /*
724 // All seems ok, we can present additional settings to user
725 $form['leech']['addons']['news'] = array(
726 '#type' => 'fieldset'
727 //,'#title' => t('News feed options'),
728 //'#collapsible' => TRUE,
729 //'#collapsed' => FALSE
730 );
731 */
732 if (user_access('administer nodes')) {
733 $form['leech']['addons']['news']['template'] = array(
734 '#type' => 'select',
735 '#title' => t('Template'),
736 '#options' => node_template_list(),
737 '#default_value' => $node->leech_news->template,
738 '#description' => t('Select which node template should be used as template for new items')
739 );
740 }
741 $form['leech']['addons']['news']['logo'] = array(
742 '#type' => 'textfield',
743 '#title' => t('URL of logo image'),
744 '#default_value' => ($node->leech_news->logo ? $node->leech_news->logo : $feed->logo)
745 );
746 $form['leech']['addons']['news']['link'] = array(
747 '#type' => 'textfield',
748 '#title' => t('URL of site'),
749 '#default_value' => ($node->leech_news->link ? $node->leech_news->link : $feed->link)
750 );
751 $form['leech']['addons']['news']['author'] = array(
752 '#type' => 'textfield',
753 '#title' => t('Author of feed'),
754 '#default_value' => ($node->leech_news->author ? $node->leech_news->author : $feed->author)
755 );
756 $form['leech']['addons']['news']['title'] = array(
757 '#type' => 'textfield',
758 '#default_value' => (!$node->title ? $feed->channel[TITLE][0][VALUE] : $node->title),
759 '#attributes' => array('style' => 'display:none')
760 );
761 if (user_access('administer nodes')) {
762 $form['leech']['addons']['news']['items_guid'] = array(
763 '#type' => 'checkbox',
764 '#title' => t('Generate GUIDs'),
765 '#default_value' => ($node->leech_news->items_guid ? $node->leech_news->items_guid : (($feed->has_guids || $feed->has_unique_links) ? FALSE : variable_get('leech_news_items_guid_for#'.$form['type']['#value'], 0)))
766 );
767 $form['leech']['addons']['news']['items_status'] = array(
768 '#type' => 'checkbox',
769 '#title' => t('Publish news items'),
770 '#default_value' => ($node->leech_news->items_status ? $node->leech_news->items_status : variable_get('leech_news_items_status_for#' . $form['type']['#value'], 1))
771 );
772 $form['leech']['addons']['news']['items_update'] = array(
773 '#type' => 'checkbox',
774 '#title' => t('Update already existing news items'),
775 '#default_value' => ($node->leech_news->items_update ? $node->leech_news->items_update : variable_get('leech_news_items_update_for#'.$form['type']['#value'], 0)),
776 );
777 $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 3628800, 4838400, 7257600, 15724800, 31536000), 'format_interval');
778 $period['1000000000'] = t('Never');
779 $form['leech']['addons']['news']['items_delete'] = array(
780 '#type' => 'select',
781 '#title' => t('Delete news items older than'),
782 '#options' => $period,
783 '#default_value' => ($node->leech_news->items_delete ? $node->leech_news->items_delete : variable_get('leech_news_items_delete_for#'.$form['type']['#value'], 15724800))
784 );
785 $promote = drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30));
786 $promote['0'] = t('None');
787 $promote['1000000000'] = t('All');
788 $form['leech']['addons']['news']['items_promote'] = array(
789 '#type' => 'select',
790 '#title' => t('Promote items'),
791 '#options' => $promote,
792 '#default_value' => ($node->leech_news->items_promote ? $node->leech_news->items_promote : variable_get('leech_news_items_promote_for#'.$form['type']['#value'], 3))
793 );
794 $form['leech']['addons']['news']['items_date'] = array(
795 '#type' => 'checkbox',
796 '#title' => t('Use dates found in feed if available'),
797 '#default_value' => ($node->leech_news->items_date ? $node->leech_news->items_date : ($feed->has_dates && variable_get('leech_news_items_date_for#'.$form['type']['#value'], 0) ? TRUE : FALSE))
798 );
799 $form['leech']['addons']['news']['links_display_mode'] = array (
800 '#type' => 'select',
801 '#title' => t('Show "original article"/"visit site" link'),
802 '#options' => array(
803 LEECH_SHOW_LINK_ALWAYS => t('Always'),
804 LEECH_SHOW_LINK_NEVER => t('Do not display'),
805 LEECH_SHOW_LINK_TEASER_ONLY => t('Only with teaser'),
806 LEECH_SHOW_LINK_PAGE_ONLY => t('Only on full page')
807 ),
808 '#default_value' => (isset($node->leech_news->links_display_mode) ? $node->leech_news->links_display_mode : variable_get('leech_news_links_for#'.$form['type']['#value'], LEECH_SHOW_LINK_ALWAYS)),
809 '#description' => t('Select place(s) where link to original article (for news items) or visit site (for news feeds) will be shown.')
810 );
811 }
812 // Mark if there was leech_news data with node or not
813 if ($node->leech_news->nid) {
814 $form['leech']['addons']['news']['nid'] = array(
815 '#type' => 'hidden',
816 '#value' => $node->leech_news->nid
817 );
818 }
819 }
820 // For OPML
821 if (isset($form['type']) && $form['type']['#value'] .'_node_settings' == $form_id) {
822 $form['workflow']['leech_defs']['opml'] = array(
823 '#type' => 'fieldset',
824 '#title' => t('Default leech opml options'),
825 '#collapsible' => FALSE,
826 '#collapsed' => FALSE
827 );
828 $form['workflow']['leech_defs']['opml']['leech_opml_template_for#'.$form['type']['#value']] = array (
829 '#type' => 'select',
830 '#title' => t('Template'),
831 '#options' => node_template_list(),
832 '#default_value' => variable_get('leech_opml_template_for#'.$form['type']['#value'], 0),
833 '#description' => t('Select which node template should be used as template for opml items')
834 );
835 }
836 }
837
838 function leech_pre_render_addons($form_id, $form) {
839 global $LEECH_PRERENDERED_ADDONS;
840 if (is_array($LEECH_PRERENDERED_ADDONS) && isset($form['#node']) && isset($form['leech']['addons'])) {
841 $node = $form['#node'];
842 if (isset($node->leech->_prerender_id)) {
843 $LEECH_PRERENDERED_ADDONS[$node->leech->_prerender_id] = str_replace(array('<div id="edit-leech-addons">', '</div>'), '', form_render($form['leech']['addons']));
844 }
845 }
846 }
847
848 /**
849 * Move "Enable leech" checkbox to be used as a legend for leech defs fieldset
850 */
851 function leech_after_build_defs($form, $form_values) {
852 // To do that first we render checkbox field and remove divs around it (so we have label and input left)
853 preg_match('%\<label.*\</label\>%U', form_render($form['workflow']['leech_defs']['leech_for#'.$form['type']['#value']]), $matches);
854 // Finally we put it as title of fieldset :)
855 $form['workflow']['leech_defs']['#title'] = $matches[0];
856
857 return $form;
858 }
859
860
861 /**
862 * Implementation of hook_nodeapi().
863 */
864 function leech_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
865
866 switch ($op) {
867 case 'insert':
868 if (leech_access('create', $node)) {
869 leech_insert($node);
870 }
871 break;
872 case 'update':
873 if (leech_access('update', $node)) {
874 leech_update($node);
875 }
876 break;
877 case 'delete':
878 if (leech_access('delete', $node)) {
879 leech_delete($node);
880 }
881 break;
882 case 'load':
883 return leech_load($node);
884 break;
885 case 'prepare':
886 leech_prepare($node, $teaser);
887 break;
888 case 'validate':
889 leech_validate($node, $teaser);
890 break;
891 case 'submit':
892 leech_submit($node);
893 break;
894 case 'view':
895 if (leech_access('view', $node)) {
896 leech_view($node, $teaser, $page);
897 }
898 break;
899 case 'rss item':
900 if ($node->leech_news_item) {
901 return array(array('key' => 'source',
902 'attributes' => array('url' => ($node->leech_news_item->source_xml ? $node->leech_news_item->source_xml : $node->leech_news_item->feed_url)),
903 'value' => check_plain(($node->leech_news_item->source_title ? $node->leech_news_item->source_title : $node->leech_news_item->feed_title))),
904 array('key' => 'dc:source',
905 'value' => check_plain(($node->leech_news_item->source_link ? $node->leech_news_item->source_link : $node->leech_news_item->link))));
906 }
907 if ($node->leech_news) {
908 return array(array('key' => 'source',
909 'attributes' => array('url' => $node->leech->url),
910 'value' => check_plain($node->title)),
911 array('key' => 'dc:source',
912 'value' => check_plain($node->leech_news->link)));
913 }
914 break;
915 }
916 }
917
918 /**
919 * Implementation of hook_link().
920 */
921 function leech_link($type, $node = NULL, $teaser = FALSE) {
922 $links = array();
923 global $user;
924
925 if ($type == 'node' && $node != NULL) {
926
927 if (variable_get('leech_for#'.$node->type, 0) && isset($node->leech)) {
928 if ((user_access(LEECH_PERM_REFRESH_OWN) && ($user->uid == $node->uid)) || user_access('administer nodes')) {
929 $links[] = l(t('leech data now'), "leech/refresh/{$node->nid}", array(), 'destination='.$_GET['q']);
930 }
931 }
932
933 $show = ($node->leech_news_item ? $node->leech_news_item->links_display_mode : $node->leech_news->links_display_mode);
934 if (($show == LEECH_SHOW_LINK_ALWAYS) ||
935 ($teaser && $show == LEECH_SHOW_LINK_TEASER_ONLY) ||
936 (!$teaser && $show == LEECH_SHOW_LINK_PAGE_ONLY)) {
937 if ($node->leech_news_item) {
938 $links[] = theme('leech_link_full_article', $node);
939 }
940 if ($node->leech_news) {
941 $links[] = theme('leech_link_visit_site', $node);
942 }
943 }
944 if ($node->leech_news) {
945 if ((user_access(LEECH_NEWS_PERM_EDIT_OWN_ITEM) && ($user->uid == $node->uid)) || user_access('administer nodes')) {
946 $links[] = l(t('remove items'), "leech/remove_items/{$node->nid}");
947 }
948 if (variable_get('leech_news_show_items_link', 0) && arg(1) != 'sources') {
949 $links[] = l(t('view items'), "leech/feed/{$node->nid}");
950 }
951 }
952 else if ($node->leech_news_item && arg(1) != 'feed') {
953 if (variable_get('leech_news_show_feed_link', 0) == LEECH_SHOW_LINK_IN_LINKS) {
954 $links[] = l(t('feed'), "leech/feed/{$node->leech_news_item->fid}", array('title' => t('view other articles from %title', array('%title' => $node->leech_news_item->feed_title))));
955 }
956 }
957 }
958
959 return $links;
960 }
961
962 /**
963 * Implementation of hook_cron().
964 *
965 * Checks news feeds for updates once their refresh interval has elapsed.
966 */
967 function leech_cron() {
968 global $user;
969 $old_user = $user;
970
971 timer_start("leech_cron");
972
973 $crontimes = variable_get('leech_cron_times', array());
974 $crontimes[] = time();
975 if (count($crontimes) > 6) {
976 array_shift($crontimes);
977 }
978 variable_set('leech_cron_times', $crontimes);
979
980 $updated = array();
981 $result = db_query_range('SELECT l.nid, n.uid FROM {leech} l, {node} n WHERE l.refresh > 0 AND l.checked + l.refresh <= %d AND l.nid = n.nid ORDER BY l.checked ASC ', time(),