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

Contents of /contributions/modules/fooaggregator/fooaggregator.module

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


Revision 1.4 - (show annotations) (download) (as text)
Tue Jul 17 22:40:53 2007 UTC (2 years, 4 months ago) by msameer
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5
Changes since 1.3: +1 -21 lines
File MIME type: text/x-php
remove _fooaggregator_prepare_item()
1 <?php // -*-php-*-
2 /* $Id: fooaggregator.module,v 1.3 2007/07/15 15:02:13 msameer Exp $ */
3
4 require_once('fooaggregator_feed.inc');
5 require_once('fooaggregator_item.inc');
6 require_once('fooaggregator_views.inc');
7
8 // todo:
9 // don't update checked if the feed fails.
10 // set up a custom user agent ;-)
11 // update items if the feed has updated ones ?
12 // a way to set the defaults (admin -> content type -> aggregator feed)
13 // a way to support libcurl.
14 // import/export: opml or CSV
15 // cron should process published nodes only. And unpublish them if there's an error.
16
17 /**
18 * Implementation of hook_node_info()
19 */
20 function fooaggregator_node_info() {
21 return array(
22 'fooaggregator_item' => array(
23 'name' => t('RSS feed item.'),
24 'module' => 'fooaggregator_item',
25 'description' => t('RSS feed item.'),
26 ),
27 'fooaggregator_feed' => array(
28 'name' => t('RSS feed'),
29 'module' => 'fooaggregator_feed',
30 'description' => t('RSS feed.'),
31 ),
32 );
33 }
34
35 /**
36 * Implementation of hook_menu()
37 */
38 function fooaggregator_menu($may_cache) {
39 $items = array();
40
41 if ($may_cache) {
42 $items[] = array(
43 'path' => 'admin/content/fooaggregator/settings',
44 'callback' => 'drupal_get_form',
45 'callback arguments' => array('fooaggregator_admin_settings'),
46 'access' => user_access('administer fooaggregator'),
47 'title' => t('Settings'),
48 'type' => MENU_LOCAL_TASK,
49 'weight' => 2,
50 );
51 }
52 else if ((arg(0) == 'node') && (is_numeric(arg(1))) && arg(2)) {
53 $node = node_load(arg(1));
54 if ($node->type == 'fooaggregator_feed') {
55 switch (arg(2)) {
56 case 'clear':
57 $items[] = array(
58 'path' => 'node/'.$node->nid.'/clear',
59 'callback' => 'fooaggregator_clear',
60 'callback arguments' => array(arg(1)),
61 'access' => user_access('administer fooaggregator'),
62 'title' => t('Clear feed items'),
63 'type' => MENU_CALLBACK,
64 );
65 break;
66 case 'refresh':
67 $items[] = array(
68 'path' => 'node/'.$node->nid.'/refresh',
69 'callback' => 'fooaggregator_refresh',
70 'callback arguments' => array(arg(1)),
71 'access' => user_access('administer fooaggregator'),
72 'title' => t('Refresh the feed and update it in case of new items.'),
73 'type' => MENU_CALLBACK,
74 );
75 break;
76 }
77 }
78 }
79
80 return $items;
81 }
82
83 /**
84 * Implementation of hook_nodeapi()
85 *
86 * We delete the feed items belonging to a feed if that feed is being deleted.
87 */
88 function fooaggregator_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
89 if ($node->type == 'fooaggregator_feed') {
90 switch ($op) {
91 case 'delete':
92 $result = db_query("select nid from {fooaggregator_item} where fid=%d", $node->nid);
93 while ($o = db_fetch_object($result)) {
94 node_delete($o->nid);
95 }
96 break;
97 }
98 }
99 }
100
101 /**
102 * Implementation of hook_perm()
103 */
104 function fooaggregator_perm() {
105 return array('administer fooaggregator', 'access fooaggregator');
106 }
107
108 /**
109 * Implementation of hook_access();
110 */
111 function fooaggregator_access($op, $node) {
112 switch ($op) {
113 case 'view':
114 return user_access('access fooaggregator');
115 case 'create':
116 case 'update':
117 case 'delete':
118 return user_access('administer fooaggregator');
119 }
120 }
121
122
123 /**
124 * Implementation of hook_cron()
125 *
126 * This will refresh our feeds.
127 */
128 function fooaggregator_cron() {
129 $limit = variable_get('fooaggregator_per_cron', 5);
130 $parser = _fooaggregator_parser_load();
131
132 if ($limit == -1) {
133 $result = db_query("select n.nid as nid from {node} n inner join {fooaggregator_feed} f on f.nid=n.nid where n.status=1 and f.refresh > 0 and f.checked+f.refresh < %d order by RAND()", time());
134 }
135 else {
136 $result = db_query_range("select n.nid as nid from {node} n inner join {fooaggregator_feed} f on f.nid=n.nid where n.status=1 and f.refresh > 0 and f.checked+f.refresh < %d order by RAND()", time(), 0, $limit);
137 }
138
139 while ($res = db_fetch_array($result)) {
140 $feed = node_load($res['nid'], NULL, true);
141 $parser['callback']($feed);
142 }
143 }
144
145 /**
146 * Download a feed logging any problems via the drupal watchdog system.
147 * This is based on the core aggregator module.
148 *
149 * We will include $feed->etag and $feed->modified if they exist in the request.
150 * This will also update $feed->checked and will change $feed->url if we are being redirected from the old URL.
151 * It will also update $feed->etag and $feed->modified from the values in the corresponding HTTP headers.
152 *
153 * @param $feed a feed object.
154 * @param $xml where to put the contents of the feed.
155 * @return false if we have an error and it will be logged otherwise true even if the feed has no new content.
156 */
157 function _fooaggregator_download(&$feed, &$xml) {
158 $headers = array();
159
160 if ($feed->etag) {
161 $headers['If-None-Match'] = $feed->etag;
162 }
163
164 if ($feed->modified) {
165 $headers['If-Modified-Since'] = gmdate('D, d M Y H:i:s', $feed->modified) .' GMT';
166 }
167
168 $result = drupal_http_request($feed->url, $headers);
169
170 switch ($result->code) {
171 case 304:
172 _fooaggregator_log_notice(t('No new content for %url', array('%url' => $feed->url)));
173 $feed->checked = time();
174 break;
175
176 case 301:
177 _fooaggregator_log_warning(t('Updated URL for feed from %old to %new', array(
178 '%old' => $feed->url,
179 '%new' => $result->redirect_url,
180 )));
181 $feed->url = $result->redirect_url;
182
183 case 200:
184 case 302:
185 case 307:
186 $feed->checked = time();
187 if (($result->headers['Content-Length']) && ($result->headers['Content-Length'] == 0)) {
188 break;
189 }
190
191 if ($result->data == '') {
192 break;
193 }
194
195 $feed->updated = $feed->checked;
196 $xml = $result->data;
197 break;
198 default:
199 _fooaggregator_log_error(t('HTTP error %number - "%error" while getting %url', array(
200 '%number' => $result->code,
201 '%error' => $result->error,
202 '%url' => $feed->url,
203 )));
204 $feed->checked = time();
205 $result = Null;
206 return false;
207 }
208
209 // update etag and modified
210 if ($result->headers['Last-Modified']) {
211 $feed->modified = strtotime($result->headers['Last-Modified']);
212 }
213
214 $feed->etag = $result->headers['ETag'];
215
216 $result = Null;
217
218 return true;
219 }
220
221 /**
222 * log a warning via watchdog
223 *
224 * @param $error a string to log
225 */
226 function _fooaggregator_log_warning($error) {
227 watchdog('fooaggregator', $error, WATCHDOG_WARNING);
228 }
229
230 /**
231 * log an error via watchdog
232 *
233 * @param $error a string to log
234 */
235 function _fooaggregator_log_error($error) {
236 watchdog('fooaggregator', $error, WATCHDOG_ERROR);
237 }
238
239 /**
240 * log a notice via watchdog
241 *
242 * @param $error a string to log
243 */
244 function _fooaggregator_log_notice($error) {
245 watchdog('fooaggregator', $error, WATCHDOG_NOTICE);
246 }
247
248 /**
249 * Check the existance of a guid for a feed item.
250 *
251 * @param $guid the guid to check for
252 * @param $fid the feed id
253 * @return the node ID or 0 if nothing exists.
254 */
255 function _fooaggregator_guid_exists($guid, $fid) {
256 $nid = db_result(db_query("select nid from {fooaggregator_item} where fid=%d and guid='%s' limit 1", $fid, $guid));
257 return $nid === FALSE ? 0 : $nid;
258 }
259
260 /**
261 * This is the settings page.
262 */
263 function fooaggregator_admin_settings() {
264 $form = array();
265 $form['fooaggregator_per_cron'] = array(
266 '#title' => t('Number of feeds to update per cron run'),
267 '#type' => 'textfield',
268 '#description' => t('-1 for all. 0 to disable the cron refresh. Decrease this if you get out of memory problems.'),
269 '#default_value' => variable_get('fooaggregator_per_cron', 5),
270 );
271
272 $users = array();
273
274 $res = db_query("select uid, name from {users}");
275 while ($o = db_fetch_object($res)) {
276 $users[$o->uid] = $o->name;
277 }
278 $users[0] = variable_get('anonymous', t('Anonymous'));
279
280 $form['fooaggregator_uid'] = array(
281 '#title' => t('Owner of the nodes created'),
282 '#type' => 'select',
283 '#options' => $users,
284 '#default_value' => variable_get('fooaggregator_uid', 1),
285 );
286
287 $formats = filter_formats();
288 $filters = array();
289 foreach ($formats as $format) {
290 $filters[$format->format] = check_plain($format->name);
291 }
292 $form['fooaggregator_filter'] = array(
293 '#title' => t('Default input format'),
294 '#type' => 'select',
295 '#options' => $filters,
296 '#default_value' => variable_get('fooaggregator_filter', 1),
297 );
298
299 $form['fooaggregator_parser'] = array(
300 '#title' => t('The parser to use'),
301 '#type' => 'select',
302 '#options' => _fooaggregator_parsers_list(),
303 '#default_value' => variable_get('fooaggregator_parser', 'simplepie'),
304 );
305
306 $form['fooaggregator_update_items']= array(
307 '#title' => t('Update feed items'),
308 '#type' => 'checkbox',
309 '#default_value' => variable_get('fooaggregator_update_items', 1),
310 '#description' => t('Uncheck this to disable updating existing nodes even if they were changed in the feed.'),
311 );
312 return system_settings_form($form);
313 }
314
315 /**
316 * list the parsers in the parsers subdirectory
317 *
318 * @return a hash table of the parsers or an empty array in case of error.
319 */
320 function _fooaggregator_parsers_list() {
321 $res = array();
322 $path = dirname(__FILE__)."/parsers/";
323 $dir = opendir($path);
324 if (!$dir) {
325 drupal_set_message(t('Cannot scan the parsers subdirectory'), 'error');
326 return $res;
327 }
328
329 while (($file = readdir($dir)) !== false) {
330 if (is_file($path.'/'.$file.'/parser.inc')) {
331 $res[$file] = $file;
332 }
333
334 }
335 closedir($dir);
336
337 return $res;
338 }
339
340 /**
341 * Load the configured parser.
342 *
343 * @return A hash table with 2 keys: name and callback.
344 */
345 function _fooaggregator_parser_load() {
346 $parser = variable_get('fooaggregator_parser', 'simplepie');
347 require_once drupal_get_path('module', 'fooaggregator')."/parsers/${parser}/parser.inc";
348
349 return array('name' => $parser, 'callback' => "_fooaggregator_${parser}_refresh");
350 }
351
352 /**
353 * implementation of hook_node_operations()
354 */
355 function fooaggregator_node_operations() {
356 $operations = array(
357 'clear feeds' => array(
358 'label' => t('Clear Feeds'),
359 'callback' => 'fooaggregator_operations_clear',
360 ),
361 );
362 return $operations;
363 }
364
365 /**
366 * a node operations callback
367 * clear multiple feeds
368 *
369 * @param $feeds array of feed IDs
370 */
371 function fooaggregator_operations_clear($feeds) {
372 // MSameer: todo: performance...
373 //todo: a confirmation dialog
374 foreach ($feeds as $fid) {
375 $result = db_query("select nid from {node} where nid in (select nid from {fooaggregator_item} where fid=%d)", $fid);
376 while ($o = db_fetch_object($result)) {
377 node_delete($o->nid);
378 }
379
380 fooaggregator_feed_clear($fid);
381 drupal_set_message(t("feed $fid cleared."));
382 }
383 }
384
385 /**
386 * A menu callback.
387 * Clear a feed items given a feed ID
388 * This function will also redirect to the feed node.
389 *
390 * @param $fid a feed ID
391 */
392 function fooaggregator_clear($fid) {
393 // todo: a confirmation dialog.
394 $result = db_query("select nid from {node} where nid in (select nid from {fooaggregator_item} where fid=%d)", $fid);
395 while ($o = db_fetch_object($result)) {
396 node_delete($o->nid);
397 }
398
399 fooaggregator_feed_clear($fid);
400 drupal_set_message(t('The feed was cleared.'));
401 drupal_goto('node/'.$fid);
402 }
403
404
405 /**
406 * Refresh a feed.
407 *
408 * @param $fid a feed ID
409 */
410 function fooaggregator_refresh($fid) {
411 $parser = _fooaggregator_parser_load();
412
413 $message = "";
414 $feed = node_load($fid);
415 if ($parser['callback']($feed)) {
416 $message = t('Updated items for feed %title', array('%title' => $feed->title));
417 }
418 else {
419 $message = t('Failed to update items for feed %title', array('%title' => $feed->title));
420 }
421 drupal_set_message($message);
422 _fooaggregator_log_notice($message);
423 drupal_goto('node/'.$fid);
424 }
425
426 /**
427 * Implementation of hook_link()
428 */
429 function fooaggregator_link($type, $node = NULL, $teaser = FALSE) {
430 $links = array();
431
432 if (($type == 'node') && ($node->type == 'fooaggregator_item')){
433 $links['fooaggregator_view_original'] = array(
434 'title' => t('view original'),
435 'href' => $node->link,
436 );
437 }
438 else if (($type == 'node') && ($node->type == 'fooaggregator_feed')) {
439 // Too bad they are showing at the end of the page if we use the fooaggregator_page module.
440 // I guess it has to be fixed using a theme hack or something.
441 if (user_access('administer aggregator')) {
442 $links['fooaggregator_clear'] = array(
443 'title' => t('clear items'),
444 'href' => 'node/'.$node->nid.'/clear',
445 );
446 $links['fooaggregator_refresh'] = array(
447 'title' => t('refresh feed'),
448 'href' => 'node/'.$node->nid.'/refresh',
449 );
450 }
451 }
452
453 return $links;
454 }

  ViewVC Help
Powered by ViewVC 1.1.2