misc changes to callback url handling
[project/fb.git] / fb_app.admin.inc
CommitLineData
67523320 1<?php
456be90c
DC
2/**
3 * @file
4 * Admin pages and forms for facebook applications.
19092d2f 5 *
456be90c 6 */
67523320
DC
7
8include drupal_get_path('module', 'fb') . '/fb.admin.inc';
9
10/**
3cf45120 11 * Implements hook_fb_admin().
67523320
DC
12 */
13function fb_app_fb_admin($op, $data, &$return) {
14 $fb = isset($data['fb']) ? $data['fb'] : NULL;
15 $fb_app = isset($data['fb_app']) ? $data['fb_app'] : NULL;
19092d2f 16
67523320
DC
17 if ($op == FB_ADMIN_OP_SET_PROPERTIES) {
18 // URLs for Facebook events we support.
7afb2a55 19 $return['uninstall_url'] = url(FB_APP_PATH_EVENT . '/' . $fb_app->label . "/" . FB_APP_EVENT_POST_REMOVE . '/',
f54b3a2b 20 array('absolute' => TRUE));
7afb2a55 21 $return['authorize_url'] = url(FB_APP_PATH_EVENT . '/' . $fb_app->label . "/" . FB_APP_EVENT_POST_AUTHORIZE . '/',
f54b3a2b 22 array('absolute' => TRUE));
67523320 23 }
456be90c 24 elseif ($op == FB_ADMIN_OP_LIST_PROPERTIES) {
67523320
DC
25 $return[t('Application Name')] = 'application_name';
26 $return[t('About URL')] = 'about_url';
27 $return[t('Post-Authorize Callback URL')] = 'authorize_url';
28 $return[t('Post-Remove Callback URL')] = 'uninstall_url';
29 // Learn canvas name regardless of whether fb_canvas is enabled.
30 $return[t('Canvas Name')] = 'canvas_name';
31 }
29be740a 32 elseif (($op == FB_ADMIN_OP_LOCAL_LINKS) && isset($fb_app->fba_id)) {
67523320 33 // Path to edit this app.
29be740a 34 $return[t('edit')] = FB_PATH_ADMIN_APPS . '/' . $fb_app->label . '/fb_app';
67523320
DC
35 }
36}
37
38/**
39 * Builds the form used to edit an application.
f77127b5
DC
40 *
41 * This form supports both create and edit.
67523320 42 */
3cf45120 43function fb_app_edit_form($form, $form_state, $fb_app = NULL) {
f77127b5
DC
44 // If app is managed by this module, it has fba_id.
45 if (isset($fb_app) && !$fb_app->fba_id) {
29be740a 46 drupal_set_message(t('Application %label not found.', array(
fa767fc5 47 '%label' => $fb_app->label)),
6178c18c 48 'warning');
f77127b5
DC
49 drupal_not_found();
50 exit();
67523320 51 }
19092d2f 52
67523320 53 if (!isset($fb_app)) {
29be740a
DC
54 // Defaults for new app.
55 $fb_app = (object) array(
56 'label' => NULL,
b3adf089 57 'apikey' => NULL, // deprecated.
29be740a
DC
58 'canvas' => NULL,
59 'fba_id' => NULL,
60 'id' => NULL,
61 'status' => 1,
62 'data' => serialize(array('fb_app' => array('set_app_props' => TRUE))),
63 );
64 //drupal_set_title(t('Create Facebook Application'));
67523320
DC
65 }
66 else {
f77127b5 67 //drupal_set_title(t('Edit %label', array('%label' => $fb_app->label)));
67523320 68 }
19092d2f
DC
69
70 $form['#fb_app'] = $fb_app; // Similar to #node
71
f77127b5 72 //$form['#node'] = (object) array('fb_app' => $fb_app); // deprecated! backward compatibility!
19092d2f 73
f77127b5 74 if (!$fb_app->label) {
67523320
DC
75 // Helpful link
76 // http://wiki.developers.facebook.com/index.php/How_To_Write_A_Good_Connect_Plugin
77 $helptext = '<ol>
78<li>Visit the Facebook application creation page: <a target="_blank" href="http://www.facebook.com/developers/createapp.php">http://www.facebook.com/developers/createapp.php</a>.</li>
79<li>Enter a descriptive name in the Application Name field. Users will see this when signing up for your site.</li>
80<li>Accept the Facebook Terms of Service.</li>
81<li>If building a Canvas Page App, specify a Canvas Path.</li>
82<li>Upload icon and logo images. The icon appears in News Feed stories and the logo appears in the Connect dialog when the user connects with your site.</li>
83<li>Click Submit.</li>
b3adf089 84<li>Copy the displayed App ID and Application Secret into this form.</li>
67523320
DC
85</ol>';
86
87 $form['helptext'] = array(
3cf45120 88 '#markup' => t($helptext),
67523320
DC
89 '#weight' => -10,
90 );
1240cc5f
DC
91 $form['helptext2'] = array(
92 '#markup' => t('It is recommended to administer drupal in one browser (this one) and log into facebook in another browser, so no cookies are shared. So for example if using Chrome, follow the create app link above in an incognito window.'),
93 '#prefix' => '<p><em>', '#suffix' => '</em></p>',
94 );
95
67523320 96 }
19092d2f 97
67523320
DC
98 $form['label'] = array(
99 '#type' => 'textfield',
100 '#title' => t('Label'),
101 '#required' => TRUE,
102 '#default_value' => $fb_app->label,
f17f7dff 103 '#description' => t('A short name for this application. Use letters and numerals only (no spaces, etc). <br/>Module code may refer to this label, in order to customize the behavior of this app.<br/>When working with multiple copies of an application (i.e. development, staging, production), use the <strong>same label</strong> on all servers. Apikey, secret and ID will change from server to server, but <strong>the label remains the same</strong>.'),
67523320
DC
104 );
105 $form['status'] = array(
106 '#type' => 'checkbox',
107 '#title' => t('Enabled'),
108 '#default_value' => $fb_app->status,
f17f7dff 109 '#description' => t('Uncheck if this server no longer hosts this application, but you prefer not to delete the settings.'),
67523320 110 );
0c4a9f92
DC
111
112 // ID, apikey and secret are shown on facebook. User copies and pastes values.
f7e75cc6
DC
113 $form['id'] = array(
114 '#type' => 'textfield',
115 '#title' => t('Facebook App ID'),
49c58876 116 '#required' => TRUE,
f7e75cc6
DC
117 '#default_value' => $fb_app->id,
118 '#description' => t('Facebook will generate this value when you create the application.'),
119 );
67523320
DC
120 $form['secret'] = array(
121 '#type' => 'textfield',
122 '#title' => t('Secret'),
123 '#required' => TRUE,
d8f85b06 124 '#default_value' => isset($fb_app->secret) ? $fb_app->secret : NULL,
67523320
DC
125 '#description' => t('Facebook will generate this value when you create the application.'),
126 );
19092d2f 127
67523320 128 // fb_app_data is a placeholder where other modules can attach settings.
19092d2f
DC
129 $form['fb_app_data'] = array('#tree' => TRUE);
130
67523320
DC
131 // Add our own fields to fb_app_data. Other modules use hook_form_alter to do this.
132
133 $data = fb_get_app_data($fb_app);
134 $form['fb_app_data']['fb_app']['set_app_props'] = array(
f7951091 135 '#type' => 'checkbox',
038f3ecf 136 '#title' => t('Set application properties automatically'),
f17f7dff 137 '#default_value' => isset($data['fb_app']) ? $data['fb_app']['set_app_props'] : NULL,
f404514e 138 '#description' => t('Synchronize Facebook settings for this application when you save this form. Disable this if you have customized your callback URL, or other settings on facebook.com. Also disable if another Drupal instance hosts the same application (i.e. with shared subdomain).'),
67523320 139 );
09898fe2
DC
140
141 $form['buttons'] = array();
142 $form['buttons']['submit'] = array(
67523320
DC
143 '#type' => 'submit',
144 '#value' => t('Save'),
09898fe2 145 '#weight' => 5,
3cf45120 146 '#submit' => array('fb_app_admin_form_submit'),
67523320 147 );
19092d2f 148
09898fe2
DC
149 if ($fb_app->fba_id) {
150 $form['buttons']['delete'] = array(
151 '#type' => 'submit',
152 '#value' => t('Delete'),
153 '#weight' => 15,
154 '#submit' => array('fb_app_admin_form_delete_submit'),
155 );
156 }
157
67523320
DC
158 return $form;
159}
160
09898fe2
DC
161/**
162 * Form validation.
163 */
67523320 164function fb_app_edit_form_validate($form, &$form_state) {
09898fe2 165 $fb_app = (object) $form_state['values'];
67523320 166 $fb_app->data = serialize($fb_app->fb_app_data);
19092d2f 167
6178c18c 168 if ($form_state['values']['op'] != t('Delete')) {
f17f7dff 169 // Labels must be alphanumeric.
b389f367
DC
170 if (preg_match('/[^a-z0-9_]/', $fb_app->label)) {
171 form_error($form['label'], t('Label must be lower-case alphanumeric or underscores only.'));
f17f7dff
DC
172 }
173
6178c18c
DC
174 // Labels must be unique.
175 $apps = fb_get_all_apps();
176 foreach ($apps as $app) {
177 if ($app->label == $fb_app->label &&
178 (!isset($form['#fb_app']) || $form['#fb_app']->label != $fb_app->label)) {
179 form_set_error('fb_app][label', t('The label %label is in use by another application.', array(
180 '%label' => $fb_app->label,
181 )));
182 }
183 }
184 // Getting properties confirms apikey and secret.
185 fb_admin_get_app_properties($fb_app);
186 if (!$fb_app->application_name) {
f404514e 187 // Don't use form_set_error(), as that will prevent the user from saving any data.
b3adf089 188 drupal_set_message(t("Unable to get application properties. Possibly, you've given the wrong id or secret. Possibly, this server is unable to reach facebook's servers. Your application will not work properly!"), 'error');
51ecb79f 189 $fb_app->application_name = 'UNKOWN';
09898fe2 190 }
67523320
DC
191 }
192}
193
09898fe2 194function fb_app_admin_form_submit($form, &$form_state) {
67523320
DC
195 $fb_app = (object)$form_state['values'];
196 $fb_app->data = serialize($fb_app->fb_app_data);
19092d2f 197
29be740a
DC
198 // Get canvas_name, application_name from facebook.
199 fb_admin_get_app_properties($fb_app);
19092d2f 200
0c4a9f92 201 $orig_app = $form['#fb_app'];
3cf45120 202
0c4a9f92 203 if ($orig_app->fba_id) {
67523320 204 // Updating.
3cf45120
DC
205 try {
206 db_update('fb_app')
207 ->fields(array(
208 'label' => $fb_app->label,
209 'status' => $fb_app->status,
b3adf089 210 'apikey' => $fb_app->id, // Note, apikey deprecated. Using ID.
3cf45120
DC
211 'secret' => $fb_app->secret,
212 'id' => $fb_app->id,
61ee6ce4
DC
213 // Canvas and title are learned from facebook, not the form.
214 'canvas' => $fb_app->canvas_name ? $fb_app->canvas_name : '',
215 'title' => $fb_app->application_name ? $fb_app->application_name : $fb_app->label,
3cf45120
DC
216 'data' => $fb_app->data,
217 ))
218 ->condition('fba_id', $orig_app->fba_id)
219 ->execute();
220
221 watchdog('fb_app', 'Updated Facebook Application %label.',
222 array('%label' => $fb_app->label,
223 ),
224 WATCHDOG_NOTICE,
225 l(t('view apps'), FB_PATH_ADMIN_APPS));
226
227 drupal_set_message(t('Saved changes to facebook application %title (%label).',
228 array('%title' => $fb_app->application_name,
229 '%label' => $fb_app->label)));
230 }
231 catch (Exception $e) {
232 // Log the exception to watchdog.
233 watchdog_exception('fb_app', $e);
19092d2f 234
3cf45120
DC
235 drupal_set_message(t('Failed to save changes to facebook application %title (%label). Check the log.',
236 array('%label' => $fb_app->label,
237 '%title' => $fb_app->application_name)));
238 }
67523320
DC
239 }
240 else {
241 // Inserting.
3cf45120
DC
242 try {
243 db_insert('fb_app')
244 ->fields(array(
61ee6ce4
DC
245 'label' => $fb_app->label,
246 'status' => $fb_app->status,
b3adf089 247 'apikey' => $fb_app->id, // Note, apikey deprecated. Using ID.
61ee6ce4
DC
248 'secret' => $fb_app->secret,
249 'id' => $fb_app->id,
250 // Canvas and title are learned from facebook, not the form.
251 'canvas' => $fb_app->canvas_name ? $fb_app->canvas_name : '',
252 'title' => $fb_app->application_name ? $fb_app->application_name : $fb_app->label,
253 'data' => $fb_app->data,
254 ))
3cf45120
DC
255 ->execute();
256
b3adf089
DC
257 watchdog('fb_app', 'Created Facebook Application %label.', array(
258 '%label' => $fb_app->label,
3cf45120
DC
259 ),
260 WATCHDOG_NOTICE,
261 l(t('view apps'), FB_PATH_ADMIN_APPS));
262
b3adf089
DC
263 drupal_set_message(t('Created facebook application %title (%label).', array(
264 '%label' => $fb_app->label,
265 '%title' => $fb_app->application_name,
266 )));
3cf45120
DC
267 }
268 catch (Exception $e) {
269 // Log the exception to watchdog.
270 watchdog_exception('fb_app', $e);
271
272 drupal_set_message(t('Failed to create facebook application %title (%label). Check the log.',
273 array('%label' => $fb_app->label,
274 '%title' => $fb_app->application_name)));
275 }
67523320 276 }
19092d2f 277
831444a5
DC
278 if ($fb_app->status) {
279 fb_app_set_app_properties($fb_app); // Set callback URL, etc.
280 }
19092d2f 281
67523320
DC
282 $form_state['redirect'] = FB_PATH_ADMIN;
283}
284
285/**
09898fe2
DC
286 * Button submit function. Use has clicked delete, send them to confirm page.
287 */
288function fb_app_admin_form_delete_submit($form, &$form_state) {
289 $destination = '';
290 if (isset($_REQUEST['destination'])) {
291 $destination = drupal_get_destination();
292 unset($_REQUEST['destination']);
293 }
294 $fb_app = $form['#fb_app'];
180c6450 295 $form_state['redirect'] = array(FB_PATH_ADMIN_APPS . '/' . $fb_app->label . '/fb_app/delete', array('query' => $destination));
09898fe2
DC
296}
297
298
299/**
300 * Form creator -- ask for confirmation of deletion
301 */
180c6450 302function fb_app_admin_delete_confirm_form($form, &$form_state, $fb_app) {
09898fe2
DC
303 $form['fba_id'] = array(
304 '#type' => 'value',
305 '#value' => $fb_app->fba_id,
306 );
19092d2f 307
09898fe2
DC
308 return confirm_form($form,
309 t('Are you sure you want to delete %title?', array('%title' => $fb_app->title)),
310 isset($_GET['destination']) ? $_GET['destination'] : FB_PATH_ADMIN_APPS . '/' . $fb_app->label,
311 t('This action cannot be undone.'),
312 t('Delete'),
313 t('Cancel')
314 );
315}
316
317/**
318 * Execute node deletion
319 */
320function fb_app_admin_delete_confirm_form_submit($form, &$form_state) {
321 if ($form_state['values']['confirm']) {
322 $fba_id = $form_state['values']['fba_id'];
323
f7951091 324 // @TODO: invoke hooks so that third-party modules may act.
19092d2f 325
3cf45120
DC
326 db_delete('fb_app')
327 ->condition('fba_id', $fba_id)
328 ->execute();
09898fe2
DC
329 }
330
331 $form_state['redirect'] = FB_PATH_ADMIN_APPS;
332}
333
334
335
336/**
19092d2f 337 * Sets callback URLs and other properties of a facebook app. Calls the facebook
67523320
DC
338 */
339function fb_app_set_app_properties($fb_app) {
340 $data = fb_get_app_data($fb_app);
341 $fb_app_data = $data['fb_app'];
7ef49cce 342 // Collect properties from all modules.
67523320
DC
343 $props = fb_invoke(FB_ADMIN_OP_SET_PROPERTIES, array('fb_app' => $fb_app), array(), FB_ADMIN_HOOK);
344 if (count($props)) {
345 if ($fb_app_data['set_app_props']) {
3946309e 346 if ($fb = fb_api_init($fb_app)) {
67523320 347 try {
d3ef187d 348 $result = fb_call_method($fb, 'admin.setAppProperties', array(
3946309e 349 'properties' => json_encode($props),
3946309e 350 ));
52cc0254 351 drupal_set_message(t('Note that it may take several minutes for property changes to propagate to all facebook servers.'));
67523320
DC
352 if (fb_verbose()) {
353 drupal_set_message(t('Set the following properties for %label application:<br/><pre>!props</pre>', array('%label' => $fb_app->label, '!props' => print_r($props, 1))));
354 watchdog('fb_app', 'Set facebook app properties for %label.',
355 array('%label' => $fb_app->label,
356 ),
357 WATCHDOG_NOTICE,
358 l(t('view apps'), FB_PATH_ADMIN));
359 }
7ef49cce
DC
360
361 // Allow third-parties to set additional "properties" such as restrictions.
362 fb_invoke(FB_ADMIN_OP_POST_SET_PROPERTIES, array(
363 'fb_app' => $fb_app,
364 'fb' => $fb,
365 'properties' => $props,
366 ), array(), FB_ADMIN_HOOK);
67523320 367 } catch (Exception $e) {
d3ef187d 368 drupal_set_message(t('Failed to set the following properties for %label application. You may need to manually editing remote settings!<br/><pre>!props</pre>', array('%label' => $fb_app->label, '!props' => print_r($props, 1))), 'error');
67523320
DC
369 fb_log_exception($e, t('Failed to set application properties on Facebook'));
370 }
371 }
372 }
456be90c 373 elseif (fb_verbose()) {
09898fe2 374 drupal_set_message(t('The following recommended properties for %label application have <strong>not been set automatically</strong>, consider editing remote settings manually:<br/><pre>!props</pre>', array('%label' => $fb_app->label, '!props' => print_r($props, 1))), 'warning');
67523320
DC
375 }
376 }
377}