/** * Backwards compatibility for MediaWiki < 1.17. * * This hook was added in MediaWiki 1.14. If we are not 1.14 or later, this * function is called from BeforePageDisplay via MGVS_hack() to retain * backward compatibility. * * And then this hook was deprecated in 1.17, so it calls the new hook. */ public static function MakeGlobalVariablesScript(&$vars) { global $wgVersion, $wgUser; if (version_compare($wgVersion, '1.17', '<')) { self::ResourceLoaderGetConfigVars($vars); unset($vars['fbScript']); // Made obsolete by ResourceLoader } // We want fbAppAccessToken to be set here instead of loaded through // ResourceLoader. I forget why this is the case, unfortunately. global $wgFbAllowDebug; if (!empty($wgFbAllowDebug)) { $title = $wgUser->getSkin()->getTitle(); if ($title instanceof Title && SpecialPage::getTitleFor('Connect', 'Debug')->equals($title)) { $app = new FacebookApplication(); if ($app->canEdit()) { global $wgFbAppId, $wgFbSecret; $vars['fbAppAccessToken'] = $wgFbAppId . '|' . $wgFbSecret; } } } return true; }
/** * Requests info about the application from Facebook. * * The 'id' field will always be returned. If there was an error, this will * be the only field in the returned array. */ public function getInfo() { if (empty(self::$info)) { global $facebook; // Generate an array of the fields we wish to fetch $fields = array('name', 'link', 'description', 'icon_url', 'logo_url', 'daily_active_users', 'weekly_active_users', 'monthly_active_users', 'namespace', 'app_domains', 'auth_dialog_description', 'auth_dialog_headline', 'auth_dialog_perms_explanation', 'contact_email', 'creator_uid', 'deauth_callback_url', 'privacy_policy_url', 'terms_of_service_url', 'user_support_email', 'website_url'); // Calls to an app's properties must be made with an app access token // https://developers.facebook.com/docs/reference/api/application/#application_access_tokens $user_access_token = $facebook->getAccessToken(); $facebook->setAccessToken($this->id . '|' . $this->secret); try { self::$info = $facebook->api("/{$this->id}?fields=" . implode(',', $fields)); // Fill in missing fields with false values foreach ($fields as $field) { if (!isset(self::$info[$field])) { self::$info[$field] = false; } } } catch (FacebookApiException $e) { error_log($e->getMessage()); self::$info = array('id' => $this->id); } // Restore the user access_token $facebook->setAccessToken($user_access_token); } return self::$info; }
/** * Special:Connect/Debug * * This is the only subpage that can be called directly. It allows an admin * to verify that the app is set up correctly inside Facebook, and offers * to automatically fix some of the problems it detects. */ private function debugView() { global $wgRequest, $wgOut, $wgFbNamespace, $wgFbLogo, $wgEmergencyContact, $wgStylePath, $wgVersion; // "Enter a page name to view it as an object in the Open Graph." Render a button that // submits the wpPageName field to Special:Connect/Debug and handle the submission here. // TODO: handle the redirect in execute() maybe // The following code is untested $pageName = $wgRequest->getText('wpPageName'); if ($pageName != '') { $title = Title::newFromText($pageName); if (!$title instanceof Title) { $title = Title::newMainPage(); } $url = 'https://developers.facebook.com/tools/debug/og/object?q=' . urlencode($title->getFullURL()); $wgOut->redirect($url); return; } $wgOut->setPageTitle(wfMsg('facebook-debug-title')); // Include the JavaScript that lets us change the application properties if (version_compare($wgVersion, '1.17', '>=')) { $wgOut->addModules('ext.facebook.application'); } $app = new FacebookApplication(); $info = $app->getInfo(); // If the request failed, 'id' will be the only field $id = $info['id']; unset($info['id']); if (empty($info)) { $wgOut->addHTML("No application information could be retrieved from Facebook."); return; } $server = ''; // Lookup the server name if (isset($_SERVER['SERVER_NAME'])) { $server = $_SERVER['SERVER_NAME']; } elseif (isset($_SERVER['HOSTNAME'])) { $server = $_SERVER['HOSTNAME']; } elseif (isset($_SERVER['HTTP_HOST'])) { $server = $_SERVER['HTTP_HOST']; } elseif (isset($_SERVER['SERVER_ADDR'])) { $server = $_SERVER['SERVER_ADDR']; } // Might as well not show a blank logo if (!$info['icon_url'] && !empty($wgFbLogo)) { $info['icon_url'] = $wgFbLogo; } // Get a link to the creator's wiki page or Facebook profile page $creatorLink = ''; if ($info['creator_uid']) { $creator = new FacebookUser($info['creator_uid']); if ($creator->getMWUser()->getId()) { $creatorLink = '<a href="' . $creator->getMWUser()->getUserPage()->getFullURL() . '">' . $creator->getMWUser()->getName() . '</a>'; } else { $creatorLink = '<span class="mw-facebook-logo"><a ' . 'href="https://www.facebook.com/profile.php?id=' . $info['creator_uid'] . '">' . $info['creator_uid'] . '</a></span>'; } } // The values of these fields are pulled from the extension messages $fields_with_msgs = array('privacy_policy_url' => 'privacypage', 'terms_of_service_url' => 'facebook-termsofservicepage', 'auth_dialog_headline' => 'facebook-auth-dialog-headline', 'auth_dialog_description' => 'facebook-auth-dialog-description', 'auth_dialog_perms_explanation' => 'facebook-auth-dialog-explanation'); // Format is: (field_name, Display name, Description, Suggested value) $field_array = array(array('namespace', 'Namespace', 'Namespace your app uses for Open Graph', FacebookAPI::isNamespaceSetup() ? $wgFbNamespace : ''), array('website_url', 'Website URL', 'URL of the Main Page', Title::newMainPage()->getFullURL()), array('deauth_callback_url', 'Deauthorize URL', 'Set this to Special:Connect/Deauth', self::getTitleFor('Connect', 'Deauth')->getFullURL()), array('privacy_policy_url', 'Privacy policy URL', 'The Facebook Platform Terms of Service require a privacy policy URL', Title::newFromText(wfMsg($fields_with_msgs['privacy_policy_url']))->getFullURL()), array('terms_of_service_url', 'Terms of service URL', '', Title::newFromText(wfMsg($fields_with_msgs['terms_of_service_url']))->getFullURL()), array('app_domains', 'App domains', 'Domains and subdomains this app can use (e.g., "example.com" will enable *.example.com)', $server), array('contact_email', 'Contact email', 'Primary email used for important communication related to your app ($wgEmergencyContact)', !empty($wgEmergencyContact) ? $wgEmergencyContact : ''), array('user_support_email', 'User support email', 'Required by Facebook: Main contact email for this app ($wgEmergencyContact)', !empty($wgEmergencyContact) ? $wgEmergencyContact : ''), array('auth_dialog_headline', 'Auth dialog headline', 'Description that appears in the Auth Dialog (30 characters or less)', $this->trimPTags(wfMsgWikiHtml($fields_with_msgs['auth_dialog_headline']))), array('auth_dialog_description', 'Auth dialog description', 'Description that appears in the Auth Dialog (140 characters or less)', $this->trimPTags(wfMsgWikiHtml($fields_with_msgs['auth_dialog_description']))), array('auth_dialog_perms_explanation', 'Explanation for permissions', 'Provide an explanation for how your app plans to use extended permissions, if any (140 characters or less)', $this->trimPTags(wfMsgWikiHtml($fields_with_msgs['auth_dialog_perms_explanation']))), array('daily_active_users', 'Daily active users', '', ''), array('weekly_active_users', 'Weekly active users', '', ''), array('monthly_active_users', 'Monthly active users', '', '')); // Build the html $html = ' <table> <tr> <td> <a href="' . $info['link'] . '"> <img src="' . $info['logo_url'] . '" style="width:75px; height:75px; margin-right:8px;"> </a> </td> <td><div> <h3 style="float:left;padding:0 !important;"> <span style="padding-left: 22px; background:url(\'' . $info['icon_url'] . '\') no-repeat left center;"> ' . $info['name'] . ' </span> </h3> <div style="font-size:0.9em;"><table cellpadding="0" cellspacing="0"> <tr> <td><b>App ID:</b></td> <td style="padding:0 14px;"><a href="' . $info['link'] . '">' . $id . '</a></td> </tr> <tr> <td><b>App creator:</b></td> <td style="padding:0 14px;">' . $creatorLink . '</td> </td> <tr> <td colspan="2" style="font-size:0.95em"> <a href="https://developers.facebook.com/apps/' . $id . '/summary">(Edit settings)</a> </td> </tr> </table></div> </div></td> </tr> </table> ' . wfMsgWikiHtml('facebook-debug-msg') . '<br/> <table>'; // The icons we use are included in MW 1.17 (use bits.wikimedia.org if not available) if (version_compare($wgVersion, '1.17', '>=')) { $icon_base = $wgStylePath; } else { $icon_base = 'http://bits.wikimedia.org/skins-1.18'; } $icons = array('ok' => array('tooltip' => 'OK', 'src' => $icon_base . '/common/images/tick-32.png'), 'warning' => array('tooltip' => 'Click to update', 'src' => $icon_base . '/common/images/warning-32.png'), 'error' => array('tooltip' => 'Click to update', 'src' => $icon_base . '/common/images/critical-32.png')); // Render each setting field of the application as a table row foreach ($field_array as $item) { $field = $item[0]; // field_name $title = $item[1]; // Display name $tip = $item[2]; // Description $correct = $item[3]; // Suggested value if ($field == 'app_domains') { continue; } // TODO: $field is an array and involves wildcards $icon = false; if ($correct != '') { if ($info[$field] == $correct) { $icon = 'ok'; } else { switch ($field) { // Critical errors case 'namespace': case 'deauth_callback_url': case 'privacy_policy_url': // Necessary per Facebook's TOS // Necessary per Facebook's TOS case 'user_support_email': // Required: https://developers.facebook.com/blog/post/630/ $icon = 'error'; break; default: $icon = 'warning'; } } } // If the field's value came from a message, link to the message in NS_MEDIAWIKI foreach ($fields_with_msgs as $field_name => $msg_name) { if ($field == $field_name) { $title = '<a href="' . Title::newFromText($fields_with_msgs[$field], NS_MEDIAWIKI)->getFullURL() . '">' . $title . '</a>'; break; } } // Also, if the message is a page name, link to the page (in red) if it doesn't exist if ($field == 'privacy_policy_url' || $field == 'terms_of_service_url') { $titleObj = Title::newFromText(wfMsg($fields_with_msgs[$field])); // Don't add a link to an empty $info[$field] if (!$titleObj->exists() && $info[$field] != '') { $info[$field] = '<a href="' . $titleObj->getFullURL() . '" class="new">' . $info[$field] . '</a>'; } } // Placeholder indicating particular field is empty if ($info[$field] == '') { $info[$field] = '<em>empty</em>'; } // Generate the html for the row $html .= ' <tr> <td style="text-align:right; padding:0;"> ' . ($tip == '' ? '' : '<img class="mw-facebook-tip" id="facebook-tip-' . $field . '" src="' . $wgStylePath . '/common/images/tooltip_icon.png" title="' . $tip . '" /> ') . ' <b>' . $title . ':</b> </td> <td class="facebook-field" id="facebook-field-' . $field . '" style="padding:0 0 0 16px; height:22px;"> <div class="facebook-field-current"> <span>' . $info[$field] . '</span> ' . ($icon ? ' ' . ($icon != 'ok' ? '<a href="#">' : '') . '<img src="' . $icons[$icon]['src'] . '" style="width:22px; height:22px;" title="' . $icons[$icon]['tooltip'] . '" />' . ($icon != 'ok' ? '</a>' : '') : '') . ' </div>' . ($icon ? ' <div class="facebook-field-' . $icon . '" style="display:none;"> <span>' . $correct . '</span> <img src="' . $icons['ok']['src'] . '" style="width:22px; height:22px;" title="' . $icons['ok']['tooltip'] . ' " /> </div>' : '') . ' </td> </tr>'; } $html .= ' </table><br/>'; // Add an option to debug Open Graph objects $html .= ' <form action="' . $this->getTitle('Debug')->getLocalUrl() . '" method="POST" style="padding-left:14px;"> <h3>' . wfMsg('facebook-object-debug-title') . '</h3> <label for="wpPageName"><p>' . wfMsg('facebook-object-debug') . '</p></label> <input name="wpPageName" id="wpPageName" size="42" value="" style="font-size:1.75em;" /> <input type="submit" value="' . wfMsg('facebook-debug') . '" name="Debug" /> </form>'; $html .= "\n<br/><br/>\n"; $wgOut->addHTML($html); }