/[drupal]/contributions/modules/fb/fb_app.module
ViewVC logotype

Contents of /contributions/modules/fb/fb_app.module

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


Revision 1.31 - (show annotations) (download) (as text)
Thu Aug 6 22:47:49 2009 UTC (3 months, 3 weeks ago) by yogadex
Branch: MAIN
Changes since 1.30: +1 -1 lines
File MIME type: text/x-php
improved text in form field description
1 <?php
2 /**
3 * @file
4 * Defines a custom node type that stores a facebook application configuration.
5 */
6
7 define('FB_APP_REQ_API_KEY', 'fb_sig_api_key');
8
9 // Events that a facebook app might need to know about:
10 define('FB_APP_EVENT_POST_AUTHORIZE', 'post_authorize');
11 define('FB_APP_EVENT_POST_REMOVE', 'post_remove');
12 define('FB_APP_PATH_EVENT', 'fb_app/event');
13 define('FB_APP_OP_EVENT', 'fb_app_event');
14
15 /**
16 * hook_fb
17 */
18 function fb_app_fb($op, $data, &$return) {
19 $fb = $data['fb'];
20 $fb_app = $data['fb_app'];
21
22 if ($op == FB_OP_GET_APP) {
23 // Load app data, using the criteria passed in
24 if ($data['nid'])
25 $fb_app = db_fetch_object(db_query("SELECT * FROM {fb_app} fb INNER JOIN {node} n ON n.nid=fb.nid WHERE fb.nid=%d and status=1",
26 $data['nid']));
27 else if ($data['apikey']) {
28 $fb_app = db_fetch_object(db_query("SELECT * FROM {fb_app} fb INNER JOIN {node} n ON n.nid=fb.nid WHERE apikey='%s' and status=1",
29 $data['apikey']));
30 }
31 else if ($data['label']) {
32 $fb_app = db_fetch_object(db_query("SELECT * FROM {fb_app} fb INNER JOIN {node} n ON n.nid=fb.nid WHERE label='%s' and status=1",
33 $data['label']));
34 }
35 if ($fb_app)
36 $return = $fb_app;
37 // If we didn't find the app, maybe someone else has written a module that
38 // stores app info in a different way.
39 }
40 else if ($op == FB_OP_GET_ALL_APPS) {
41 // Return all known applications
42 $result = _fb_app_query_all();
43 while ($app = db_fetch_object($result)) {
44 $return[] = $app;
45 }
46 }
47 else if ($op == FB_OP_SET_PROPERTIES) {
48 $url = url(FB_SETTINGS_APP_NID . '/' . $fb_app->nid . '/' . FB_APP_PATH_EVENT, array('absolute' => TRUE)) . '/';
49 $return['uninstall_url'] = $url . FB_APP_EVENT_POST_REMOVE;
50 $return['authorize_url'] = $url . FB_APP_EVENT_POST_AUTHORIZE;
51 }
52 else if ($op == FB_OP_LIST_PROPERTIES) {
53 $return[t('Application Name')] = 'application_name';
54 $return[t('About URL')] = 'about_url';
55 $return[t('Post-Authorize Callback URL')] = 'authorize_url';
56 $return[t('Post-Remove Callback URL')] = 'uninstall_url';
57 }
58 }
59
60 /**
61 * Loader callback for drupal menu api.
62 */
63 function fb_app_nid_load($nid) {
64 $node = node_load($nid);
65 if ($node->type == 'fb_app') {
66 return $node;
67 }
68 }
69
70 /**
71 * Implementation of hook_menu().
72 */
73 function fb_app_menu() {
74 $items = array();
75 // Allow facebook to notify on various events, like adding or removing an app.
76 $items[FB_APP_PATH_EVENT] =
77 array('access callback' => TRUE,
78 'page callback' => 'fb_app_event_cb',
79 'type' => MENU_CALLBACK,
80 );
81 return $items;
82 }
83
84 /**
85 * Callback for FB_APP_PATH_EVENT.
86 *
87 * We don't act on the events directly. We pass the information along via
88 * hook_fb. Other modules are thus notified of the event and can take action.
89 */
90 function fb_app_event_cb($event_type) {
91 fb_invoke(FB_APP_OP_EVENT, array('event_type' => $event_type,
92 'fb_app' => $GLOBALS['fb_app'],
93 'fb' => $GLOBALS['fb']));
94 // This page is called by facebook, not a user's browser.
95 print('Thanks Facebook, for your fancy API!');
96 // Problems if we save session during Facebook Connect, because the event callback's share session with normal pages.
97 session_save_session(FALSE);
98 exit();
99 }
100
101 /**
102 * hook_node_info.
103 */
104 function fb_app_node_info() {
105 return array('fb_app' =>
106 array('name' => t('Facebook Application'),
107 'module' => 'fb_app',
108 'description' => t('Information such as apikey and secret for a facebook.com application.'),
109 'help' => t('Configure the behavior of your Facebook Application.'),
110 ),
111 );
112 }
113
114 function fb_app_access($op, $node, $account) {
115 if (user_access('administer fb apps', $account))
116 return TRUE;
117 if ($op == 'create' && user_access('create fb apps', $account))
118 return TRUE;
119 else if ($op == 'update' || $op == 'delete') {
120 if ($node->uid == $account->uid &&
121 user_access('edit own fb apps', $account))
122 return TRUE;
123 }
124 }
125
126 function fb_app_perm() {
127 return array('administer fb apps', 'create fb apps', 'edit own fb apps');
128 }
129
130 function fb_app_form(&$node, &$param) {
131 // Helpful link
132 if (!$node->nid) {
133 drupal_set_message(t("Before completing this form, <a href=!url>create your application</a> on Facebook.",
134 array('!url' => 'http://www.facebook.com/developers/editapp.php?new')));
135 }
136 $form = array();
137 $type = node_get_types('type', $node);
138 // We need to define form elements for the node's title and body.
139 $form['title'] = array('#type' => 'textfield',
140 '#title' => check_plain($type->title_label),
141 '#required' => TRUE,
142 '#default_value' => $node->title,
143 '#weight' => -5,
144 '#description' => t('Identifies the application to site administrators.'),
145 );
146 // We want the body and filter elements to be adjacent. We could try doing
147 // this by setting their weights, but another module might add elements to the
148 // form with the same weights and end up between ours. By putting them into a
149 // sub-array together, we're able force them to be rendered together.
150 $form['body_filter']['body'] =
151 array('#type' => 'textarea',
152 '#title' => check_plain($type->body_label),
153 '#default_value' => $node->body,
154 '#required' => FALSE,
155 '#description' => 'A brief description of the application.',
156 );
157 $form['body_filter']['filter'] = filter_form($node->format);
158
159 // Now we define the form elements specific to our node type.
160
161 $form['fb_app'] = array('#tree' => TRUE,
162 '#weight' => -4,
163 '#validate' => array('fb_app_validate_fb_app' => array()),
164 );
165 $form['fb_app']['label'] = array('#type' => 'textfield',
166 '#title' => t('Label'),
167 '#required' => TRUE,
168 '#default_value' => $node->fb_app->label,
169 '#description' => t('Used behind the scenes, for naming roles, styles, etc. Use no spaces or weird characters.<br/>Working with multiple copies of a site (i.e. development, staging, production)? Use the <strong>same</strong> label for each. Node id and apikey will change from server to server, but the label remains the same.'),
170 );
171 $form['fb_app']['apikey'] = array('#type' => 'textfield',
172 '#title' => t('API Key'),
173 '#required' => TRUE,
174 '#default_value' => $node->fb_app->apikey,
175 '#description' => t('Facebook will generate this value when you create the application.'),
176 );
177 $form['fb_app']['secret'] = array('#type' => 'textfield',
178 '#title' => t('Secret'),
179 '#required' => TRUE,
180 '#default_value' => $node->fb_app->secret,
181 '#description' => t('Facebook will generate this value when you create the application.'),
182 );
183
184 $form['fb_app']['id'] = array('#type' => 'textfield',
185 '#title' => t('Facebook App ID'),
186 '#required' => FALSE,
187 '#default_value' => $node->fb_app->id,
188 '#description' => t('To learn this number, visit your app\'s About Page (or other links from Facebook\'s Developer App). The URL will end in ?id=1234... Enter the number that follows "?id=" here.'),
189 );
190
191 // fb_app_data is a placeholder to make it easier for other module to attach
192 // various settings to the node.
193 $form['fb_app_data'] = array('#tree' => TRUE);
194
195 // Add our own fields to fb_app_data. Other modules use hook_form_alter to do this.
196 $fb_app_data = fb_app_get_data($node->fb_app);
197 $data = $fb_app_data['fb_app'];
198 if (!$data)
199 $data = array('set_app_props' => TRUE); // defaults
200
201 $form['fb_app_data']['fb_app']['set_app_props'] = array(
202 '#type' => 'checkbox',
203 '#title' => t('Set Application Properties Automatically'),
204 '#description' => t('Automatically update Facebook settings for this application. Disable to prevent customized settings from being overwritten.'),
205 '#default_value' => $data['set_app_props'],
206 );
207
208 return $form;
209 }
210
211 function fb_app_validate($node) {
212 // TODO: check label is unique, and role name will be unique.
213 // check apikey is unique, canvas page is unique
214
215 $fb_app = (object) $node->fb_app;
216 fb_app_get_app_properties($fb_app);
217 if (!$fb_app->application_name) {
218 form_set_error('fb_app][apikey', t('Unable to get application properties. Confirm both apikey and secret.'));
219 }
220 }
221
222 function fb_app_validate_fb_app() {
223 //dpm(func_get_args(), 'fb_app_validate_fb_app');
224 }
225
226 function fb_app_load($node) {
227 $fb_app = db_fetch_object(db_query('SELECT * FROM {fb_app} WHERE nid=%d',
228 $node->nid));
229 $fb_app_data = fb_app_get_data($fb_app);
230 return array('fb_app' => $fb_app,
231 'fb_app_data' => $fb_app_data,
232 );
233 }
234
235 function fb_app_view($node, $teaser=FALSE, $page=FALSE) {
236 $node = node_prepare($node, $teaser);
237
238 $fb_app = (object) $node->fb_app; // cast in case of preview
239 fb_app_get_app_properties($fb_app);
240 // Perhaps this info should be hidden, unless user can edit node.
241 if (user_access('administer fb apps')) {
242 if($fb_app->edit_url) {
243 $node->content['edit_link'] = array(
244 '#value' => '<p>' . t('<a href="!url">Edit this application</a> on Facebook.', array('!url' => $fb_app->edit_url)) . '</p>',
245 '#type' => 'markup',
246 );
247 }
248
249 $node->content['fb_app'] =
250 array('#value' => theme('fb_app', $fb_app),
251 '#weight' => 1);
252
253 }
254 return $node;
255 }
256
257 function fb_app_theme() {
258 return array(
259 'fb_app' => array(
260 'arguments' => array('data' => NULL),
261 ),
262 'dl' => array(
263 'arguments' => array('items' => NULL),
264 ),
265 'fb_app_user_info' => array(
266 'arguments' => array('fb_app' => NULL, 'info' => NULL),
267 ),
268 );
269 }
270
271 function fb_app_get_about_url($fb_app) {
272 if ($fb_app->id)
273 return url("http://www.facebook.com/apps/application.php",
274 array('query' => array('id' => $fb_app->id)));
275 }
276
277 function theme_fb_app($fb_app) {
278 // Get known properties
279 $props_map = fb_invoke(FB_OP_LIST_PROPERTIES, array('fb_app' => $fb_app), array());
280 $data = array(
281 t('Label') => $fb_app->label,
282 t('API Key') => $fb_app->apikey,
283 t('Secret') => $fb_app->secret,
284 );
285 foreach ($props_map as $name => $key) {
286 if ($fb_app->$key)
287 $data[$name] = $fb_app->$key;
288 }
289
290 $output .= theme('dl', $data);
291 return $output;
292 }
293
294 // this belongs elsewhere
295 function theme_dl($items) {
296 if (count($items)) {
297 $output = "<dl>\n";
298 foreach ($items as $term => $data) {
299 $output .= " <dt>$term</dt><dd>$data</dd>\n";
300 }
301 $output .= "</dl>\n";
302 return $output;
303 }
304 }
305
306 /**
307 * Get properties from Facebook. Fills in the data that we need to
308 * know by querying facebook.
309 */
310 function fb_app_get_app_properties(&$fb_app) {
311 static $cache;
312 static $props_map;
313 if (!isset($cache)) {
314 $cache = array();
315 // http://wiki.developers.facebook.com/index.php/ApplicationProperties
316 $props_map = array(
317 t('About URL') => 'about_url',
318 t('Application Name') => 'application_name',
319 t('Edit URL') => 'edit_url',
320 );
321 $props_map = fb_invoke(FB_OP_LIST_PROPERTIES, array('fb_app' => $fb_app), $props_map);
322 }
323
324 if (!isset($cache[$fb_app->apikey])) {
325 if ($fb = fb_api_init($fb_app, FB_FBU_CURRENT)) {
326 try {
327 $props = $fb->api_client->admin_getAppProperties(array_values($props_map));
328 $cache[$fb_app->apikey] = $props;
329 } catch (Exception $e) {
330 fb_log_exception($e, t('Failed to get application properties from Facebook'));
331 }
332 }
333 }
334 else {
335 $props = $cache[$fb_app->apikey];
336 }
337
338 // Update $fb_app with the values we got from facebook api.
339 foreach ($props_map as $key) {
340 if ($props[$key]) {
341 $fb_app->$key = $props[$key];
342 }
343 }
344 }
345
346 function fb_app_set_app_properties($fb_app) {
347 $fb_app_data = fb_app_get_data($fb_app);
348 if ($fb_app_data['fb_app']['set_app_props']) {
349 $props = fb_invoke(FB_OP_SET_PROPERTIES, array('fb_app' => $fb_app), array());
350 if (count($props)) {
351 if ($fb = fb_api_init($fb_app, FB_FBU_CURRENT)) {
352 try {
353 $fb->api_client->admin_setAppProperties($props);
354 } catch (Exception $e) {
355 fb_log_exception($e, t('Failed to set application properties on Facebook'));
356 }
357 }
358 }
359 }
360 }
361
362 function fb_app_insert($node) {
363 $fb_app = (object) $node->fb_app;
364 fb_app_get_app_properties($fb_app); // Get canvas and possible other props
365 $fb_app->data = serialize($node->fb_app_data);
366 $fb_app->nid = $node->nid;
367
368 db_query("INSERT INTO {fb_app} (nid, label, apikey, secret, id, canvas, data) VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s')",
369 $node->nid, $fb_app->label, $fb_app->apikey, $fb_app->secret,
370 $fb_app->id,
371 $fb_app->canvas_name,
372 $fb_app->data
373 );
374
375 watchdog('fb_app', 'Created Facebook Application %label.',
376 array('%label' => $fb_app->label,
377 ),
378 WATCHDOG_NOTICE,
379 l($node->title, 'node/'.$node->nid));
380
381 fb_app_set_app_properties($fb_app); // Set callback URL, etc.
382 }
383
384 function fb_app_update($node) {
385 $fb_app = (object) $node->fb_app;
386 fb_app_get_app_properties($fb_app); // Get canvas and possible other props
387 $fb_app->data = serialize($node->fb_app_data);
388 $fb_app->nid = $node->nid;
389
390 db_query("UPDATE {fb_app} SET label='%s', apikey='%s', secret='%s', id='%s', canvas='%s', data='%s' WHERE nid=%d",
391 $fb_app->label, $fb_app->apikey, $fb_app->secret,
392 $fb_app->id,
393 $fb_app->canvas_name,
394 $fb_app->data,
395 $node->nid);
396
397 fb_app_set_app_properties($fb_app); // Set callback URL, etc.
398 }
399
400 function fb_app_delete($node) {
401 db_query('DELETE FROM {fb_app} WHERE nid=%d',
402 $node->nid);
403 // Should we unset properties on facebook?
404 }
405
406
407 /**
408 * Convenience method for other modules to attach data to the fb_app object.
409 */
410 function fb_app_get_data(&$fb_app) {
411 if (!$fb_app->fb_app_data) {
412 $fb_app->fb_app_data = unserialize($fb_app->data);
413 }
414 return $fb_app->fb_app_data;
415 }
416
417 /**
418 * Helper function returns a database query for all apps.
419 */
420 function _fb_app_query_all() {
421 $result = db_query("SELECT fb.*, n.title FROM {fb_app} fb INNER JOIN {node} n ON n.nid=fb.nid WHERE status=1");
422 return $result;
423 }
424 function _fb_app_query_by_label($label) {
425 $result = db_query("SELECT fb.*, n.title FROM {fb_app} fb INNER JOIN {node} n ON n.nid=fb.nid WHERE n.status=1 AND fb.label = '%s'",
426 $label);
427 return $result;
428 }
429
430 /**
431 * Implementation of hook_user.
432 */
433 function fb_app_user($op, &$edit, &$account, $category = NULL) {
434 $items = array();
435 if ($op == 'view') {
436 $result = _fb_app_query_all();
437 while ($fb_app = db_fetch_object($result)) {
438 // Learn this user's FB id
439 $fbu = fb_get_fbu($account->uid, $fb_app);
440 if ($fbu) {
441 // The drupal user is a facebook user. Now, learn more from facebook.
442 $fb = fb_api_init($fb_app, FB_FBU_ANY);
443 if (fb_facebook_user($fb)) {
444 try {
445 $info = $fb->api_client->users_getInfo(array($fbu),
446 array('about_me',
447 'affiliations',
448 'name',
449 'is_app_user',
450 'pic_big',
451 'profile_update_time',
452 'status',
453 ));
454 } catch (Exception $e) {
455 fb_log_exception($e, "Failed to get Facebook user info for account $fbu");
456 }
457 }
458 if (count($info)) {
459 $output = theme('fb_app_user_info', $fb_app, $info[0]);
460
461 $items[$fb_app->label] = array('title' => $fb_app->title,
462 'value' => $output,
463 'class' => 'fb_app');
464 }
465 else
466 fb_report_errors($fb);
467 }
468 }
469 if (count($items))
470 return array(t('Facebook') => $items);
471 }
472 }
473
474 function theme_fb_app_user_info($fb_app, $info) {
475 if ($info['pic_big'])
476 $output .= '<p><img src="'.$info['pic_big'].'" /></p>';
477 $fb_link = l($info['name'], 'http://www.facebook.com/profile.php', array('query' => 'id=' . $info['uid']));
478 if ($info['is_app_user'])
479 $output .= '<p>' . t('!fb_link uses %title',
480 array('!fb_link' => $fb_link,
481 '%title' => $fb_app->title)) . '</p>';
482 else
483 $output .= '<p>'. t('!fb_link does not use %title',
484 array('!fb_link' => $fb_link,
485 '%title' => $fb_app->title)) . '</p>';
486
487 return $output;
488 }
489
490 function fb_app_token_list($type = 'all') {
491 if ($type == 'all' || $type == 'fb' || $type == 'fb_app') {
492 $tokens['fb_app']['fb-app-nid'] = t('Facebook application ID');
493 $tokens['fb_app']['fb-app-title'] = t('Facebook application title');
494 $tokens['fb_app']['fb-app-url'] = t('Facebook application URL (base path)');
495 }
496 return $tokens;
497 }
498
499 function fb_app_token_values($type = 'all', $object = NULL) {
500 if ($type == 'fb_app' && $object) {
501 $fb_app = $object;
502 $values['fb-app-title'] = $fb_app->title;
503 $values['fb-app-nid'] = $fb_app->nid;
504 $values['fb-app-url'] = 'http://apps.facebook.com/'.$fb_app->canvas;
505 }
506 return $values;
507 }
508 ?>

  ViewVC Help
Powered by ViewVC 1.1.2