From 51254ed85eaa755f676e0772d5406deb2cdc73a5 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 7 Oct 2010 12:03:33 -0700 Subject: Pull up the guts of my fixed bit.ly plugin from an old work branch (that had made other changes we weren't happy with in the plugin management). Now works if given a global API key. --- plugins/BitlyUrl/BitlyUrlPlugin.php | 88 ++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 7 deletions(-) (limited to 'plugins/BitlyUrl') diff --git a/plugins/BitlyUrl/BitlyUrlPlugin.php b/plugins/BitlyUrl/BitlyUrlPlugin.php index 10d99b358..ceabeb29c 100644 --- a/plugins/BitlyUrl/BitlyUrlPlugin.php +++ b/plugins/BitlyUrl/BitlyUrlPlugin.php @@ -2,7 +2,7 @@ /** * StatusNet, the distributed open-source microblogging tool * - * Plugin to push RSS/Atom updates to a PubSubHubBub hub + * Plugin to use bit.ly URL shortening services. * * PHP version 5 * @@ -22,7 +22,9 @@ * @category Plugin * @package StatusNet * @author Craig Andrews + * @author Brion Vibber * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org + * @copyright 2010 StatusNet, Inc http://status.net/ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ @@ -35,26 +37,98 @@ require_once INSTALLDIR.'/plugins/UrlShortener/UrlShortenerPlugin.php'; class BitlyUrlPlugin extends UrlShortenerPlugin { - public $serviceUrl; + public $shortenerName = 'bit.ly'; + public $serviceUrl = 'http://bit.ly/api?method=shorten&version=2.0.1&longUrl=%s'; + public $login; + public $apiKey; function onInitializePlugin(){ parent::onInitializePlugin(); if(!isset($this->serviceUrl)){ - throw new Exception(_m("You must specify a serviceUrl.")); + throw new Exception(_m("You must specify a serviceUrl for bit.ly shortening.")); + } + if(!isset($this->login)){ + throw new Exception(_m("You must specify a login name for bit.ly shortening.")); + } + if(!isset($this->login)){ + throw new Exception(_m("You must specify an API key for bit.ly shortening.")); } } + /** + * Short a URL + * @param url + * @return string shortened version of the url, or null if URL shortening failed + */ protected function shorten($url) { - $response = $this->http_get($url); - if(!$response) return; - return current(json_decode($response)->results)->hashUrl; + $response = $this->query($url); + if ($this->isOk($url, $response)) { + return $this->decode($url, $response->getBody()); + } else { + return null; + } + } + + /** + * Inject API key into query before sending out... + * + * @param string $url + * @return HTTPResponse + */ + protected function query($url) + { + // http://code.google.com/p/bitly-api/wiki/ApiDocumentation#/shorten + $params = http_build_query(array( + 'login' => $this->login, + 'apiKey' => $this->apiKey), '', '&'); + $serviceUrl = sprintf($this->serviceUrl, $url) . '&' . $params; + + $request = HTTPClient::start(); + return $request->get($serviceUrl); + } + + /** + * JSON decode for API result + */ + protected function decode($url, $body) + { + $json = json_decode($body, true); + return $json['results'][$url]['shortUrl']; + } + + /** + * JSON decode for API result + */ + protected function isOk($url, $response) + { + $code = 'unknown'; + $msg = ''; + if ($response->isOk()) { + $body = $response->getBody(); + common_log(LOG_INFO, $body); + $json = json_decode($body, true); + if ($json['statusCode'] == 'OK') { + $data = $json['results'][$url]; + if (isset($data['shortUrl'])) { + return true; + } else if (isset($data['statusCode']) && $data['statusCode'] == 'ERROR') { + $code = $data['errorCode']; + $msg = $data['errorMessage']; + } + } else if ($json['statusCode'] == 'ERROR') { + $code = $json['errorCode']; + $msg = $json['errorMessage']; + } + common_log(LOG_ERR, "bit.ly returned error $code $msg for $url"); + } + return false; } function onPluginVersion(&$versions) { $versions[] = array('name' => sprintf('BitlyUrl (%s)', $this->shortenerName), 'version' => STATUSNET_VERSION, - 'author' => 'Craig Andrews', + 'author' => 'Craig Andrews, Brion Vibber', 'homepage' => 'http://status.net/wiki/Plugin:BitlyUrl', 'rawdescription' => sprintf(_m('Uses %1$s URL-shortener service.'), -- cgit v1.2.3-54-g00ecf From 80f0b9421f63be2f4b8ebd7b722b138da220dc45 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 7 Oct 2010 12:30:32 -0700 Subject: bit.ly admin panel to set the API keys to use. --- plugins/BitlyUrl/BitlyUrlPlugin.php | 97 +++++++++-- plugins/BitlyUrl/bitlyadminpanelaction.php | 271 +++++++++++++++++++++++++++++ 2 files changed, 358 insertions(+), 10 deletions(-) create mode 100644 plugins/BitlyUrl/bitlyadminpanelaction.php (limited to 'plugins/BitlyUrl') diff --git a/plugins/BitlyUrl/BitlyUrlPlugin.php b/plugins/BitlyUrl/BitlyUrlPlugin.php index ceabeb29c..c9005e52e 100644 --- a/plugins/BitlyUrl/BitlyUrlPlugin.php +++ b/plugins/BitlyUrl/BitlyUrlPlugin.php @@ -39,20 +39,12 @@ class BitlyUrlPlugin extends UrlShortenerPlugin { public $shortenerName = 'bit.ly'; public $serviceUrl = 'http://bit.ly/api?method=shorten&version=2.0.1&longUrl=%s'; - public $login; - public $apiKey; function onInitializePlugin(){ parent::onInitializePlugin(); if(!isset($this->serviceUrl)){ throw new Exception(_m("You must specify a serviceUrl for bit.ly shortening.")); } - if(!isset($this->login)){ - throw new Exception(_m("You must specify a login name for bit.ly shortening.")); - } - if(!isset($this->login)){ - throw new Exception(_m("You must specify an API key for bit.ly shortening.")); - } } /** @@ -69,6 +61,26 @@ class BitlyUrlPlugin extends UrlShortenerPlugin } } + /** + * Get the user's or site-wide default bit.ly login name. + * + * @return string + */ + protected function getLogin() + { + return common_config('bitly', 'default_login'); + } + + /** + * Get the user's or site-wide default bit.ly API key. + * + * @return string + */ + protected function getApiKey() + { + return common_config('bitly', 'default_apikey'); + } + /** * Inject API key into query before sending out... * @@ -79,8 +91,8 @@ class BitlyUrlPlugin extends UrlShortenerPlugin { // http://code.google.com/p/bitly-api/wiki/ApiDocumentation#/shorten $params = http_build_query(array( - 'login' => $this->login, - 'apiKey' => $this->apiKey), '', '&'); + 'login' => $this->getLogin(), + 'apiKey' => $this->getApiKey()), '', '&'); $serviceUrl = sprintf($this->serviceUrl, $url) . '&' . $params; $request = HTTPClient::start(); @@ -136,4 +148,69 @@ class BitlyUrlPlugin extends UrlShortenerPlugin return true; } + + /** + * Hook for RouterInitialized event. + * + * @param Net_URL_Mapper $m path-to-action mapper + * @return boolean hook return + */ + function onRouterInitialized($m) + { + $m->connect('admin/bitly', + array('action' => 'bitlyadminpanel')); + return true; + } + + /** + * If the plugin's installed, this should be accessible to admins. + */ + function onAdminPanelCheck($name, &$isOK) + { + if ($name == 'bitly') { + $isOK = true; + return false; + } + + return true; + } + + /** + * Add the bit.ly admin panel to the list... + */ + function onEndAdminPanelNav($nav) + { + if (AdminPanelAction::canAdmin('bitly')) { + $action_name = $nav->action->trimmed('action'); + + $nav->out->menuItem(common_local_url('bitlyadminpanel'), + _m('bit.ly'), + _m('bit.ly URL shortening'), + $action_name == 'bitlyadminpanel', + 'nav_bitly_admin_panel'); + } + + return true; + } + + /** + * Automatically load the actions and libraries used by the plugin + * + * @param Class $cls the class + * + * @return boolean hook return + * + */ + function onAutoload($cls) + { + $base = dirname(__FILE__); + $lower = strtolower($cls); + switch ($lower) { + case 'bitlyadminpanelaction': + require_once "$base/$lower.php"; + return false; + default: + return true; + } + } } diff --git a/plugins/BitlyUrl/bitlyadminpanelaction.php b/plugins/BitlyUrl/bitlyadminpanelaction.php new file mode 100644 index 000000000..56f78e164 --- /dev/null +++ b/plugins/BitlyUrl/bitlyadminpanelaction.php @@ -0,0 +1,271 @@ +. + * + * @category Settings + * @package StatusNet + * @author Brion Vibber + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Administer global bit.ly URL shortener settings + * + * @category Admin + * @package StatusNet + * @author Brion Vibber + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class BitlyadminpanelAction extends AdminPanelAction +{ + /** + * Returns the page title + * + * @return string page title + */ + + function title() + { + return _m('bit.ly URL shortening'); + } + + /** + * Instructions for using this form. + * + * @return string instructions + */ + + function getInstructions() + { + return _m('URL shortening with bit.ly requires ' . + '[a bit.ly account and API key](http://bit.ly/a/your_api_key). ' . + 'This verifies that this is an authorized account, and ' . + 'allow you to use bit.ly\'s tracking features and custom domains.'); + } + + /** + * Show the bit.ly admin panel form + * + * @return void + */ + + function showForm() + { + $form = new BitlyAdminPanelForm($this); + $form->show(); + return; + } + + /** + * Save settings from the form + * + * @return void + */ + + function saveSettings() + { + static $settings = array( + 'bitly' => array('default_login', 'default_apikey') + ); + + static $booleans = array( + 'bitly' => array('allow_override') + ); + + $values = array(); + + foreach ($settings as $section => $parts) { + foreach ($parts as $setting) { + $values[$section][$setting] + = $this->trimmed($setting); + } + } + + foreach ($booleans as $section => $parts) { + foreach ($parts as $setting) { + $values[$section][$setting] + = ($this->boolean($setting)) ? 1 : 0; + } + } + + // This throws an exception on validation errors + + $this->validate($values); + + // assert(all values are valid); + + $config = new Config(); + + $config->query('BEGIN'); + + foreach ($settings as $section => $parts) { + foreach ($parts as $setting) { + Config::save($section, $setting, $values[$section][$setting]); + } + } + + foreach ($booleans as $section => $parts) { + foreach ($parts as $setting) { + Config::save($section, $setting, $values[$section][$setting]); + } + } + + $config->query('COMMIT'); + + return; + } + + function validate(&$values) + { + // Validate consumer key and secret (can't be too long) + + if (mb_strlen($values['bitly']['default_apikey']) > 255) { + $this->clientError( + _m("Invalid login. Max length is 255 characters.") + ); + } + + if (mb_strlen($values['bitly']['default_apikey']) > 255) { + $this->clientError( + _m("Invalid API key. Max length is 255 characters.") + ); + } + } +} + +class BitlyAdminPanelForm extends AdminForm +{ + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + return 'bitlyadminpanel'; + } + + /** + * class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_settings'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('bitlyadminpanel'); + } + + /** + * Data elements of the form + * + * @return void + */ + + function formData() + { + $this->out->elementStart( + 'fieldset', + array('id' => 'settings_bitly') + ); + $this->out->element('legend', null, _m('Default credentials')); + $this->out->element('p', 'form_guide', + _m('When users select the bit.ly shortening service, by default ' . + 'these credentials will be used. If you leave these empty, ' . + 'users will need to set up their own credentials in order to ' . + 'use bit.ly.')); + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + $this->input( + 'default_login', + _m('Login name'), + null, + 'bitly' + ); + $this->unli(); + + $this->li(); + $this->input( + 'default_apikey', + _m('API key'), + null, + 'bitly' + ); + $this->unli(); + + $this->out->elementEnd('ul'); + $this->out->elementEnd('fieldset'); + + $this->out->elementStart( + 'fieldset', + array('id' => 'settings_bitly-options') + ); + $this->out->element('legend', null, _m('Options')); + + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + + $this->out->checkbox( + 'allow_override', _m('Allow users to specify their own API key.'), + (bool) $this->value('bitly', 'allow_override'), + _m('If set, users will be able to specify their own bit.ly login and API key ' . + 'to be used for shortening their links.'), + 'true' + ); + $this->unli(); + + $this->out->elementEnd('ul'); + + $this->out->elementEnd('fieldset'); + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Save'), 'submit', null, _m('Save bit.ly settings')); + } +} -- cgit v1.2.3-54-g00ecf From cad480551675c05452df109e5c4d43018139d6a1 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 7 Oct 2010 13:05:51 -0700 Subject: Clean up bit.ly admin panel behavior, and hide it from the shorteners list if it's not fully configured. --- plugins/BitlyUrl/BitlyUrlPlugin.php | 45 ++++++++++++++++++++++++++++-- plugins/BitlyUrl/bitlyadminpanelaction.php | 17 +++++++---- 2 files changed, 55 insertions(+), 7 deletions(-) (limited to 'plugins/BitlyUrl') diff --git a/plugins/BitlyUrl/BitlyUrlPlugin.php b/plugins/BitlyUrl/BitlyUrlPlugin.php index c9005e52e..93a35b3f3 100644 --- a/plugins/BitlyUrl/BitlyUrlPlugin.php +++ b/plugins/BitlyUrl/BitlyUrlPlugin.php @@ -39,6 +39,8 @@ class BitlyUrlPlugin extends UrlShortenerPlugin { public $shortenerName = 'bit.ly'; public $serviceUrl = 'http://bit.ly/api?method=shorten&version=2.0.1&longUrl=%s'; + public $login; // To set a site-default when admins or users don't override it. + public $apiKey; function onInitializePlugin(){ parent::onInitializePlugin(); @@ -47,6 +49,21 @@ class BitlyUrlPlugin extends UrlShortenerPlugin } } + /** + * Add bit.ly to the list of available URL shorteners if it's configured, + * otherwise leave it out. + * + * @param array $shorteners + * @return boolean hook return value + */ + function onGetUrlShorteners(&$shorteners) + { + if ($this->getLogin() && $this->getApiKey()) { + return parent::onGetUrlShorteners($shorteners); + } + return true; + } + /** * Short a URL * @param url @@ -68,7 +85,11 @@ class BitlyUrlPlugin extends UrlShortenerPlugin */ protected function getLogin() { - return common_config('bitly', 'default_login'); + $login = common_config('bitly', 'default_login'); + if (!$login) { + $login = $this->login; + } + return $login; } /** @@ -78,7 +99,11 @@ class BitlyUrlPlugin extends UrlShortenerPlugin */ protected function getApiKey() { - return common_config('bitly', 'default_apikey'); + $key = common_config('bitly', 'default_apikey'); + if (!$key) { + $key = $this->apiKey; + } + return $key; } /** @@ -213,4 +238,20 @@ class BitlyUrlPlugin extends UrlShortenerPlugin return true; } } + + /** + * Internal hook point to check the default global credentials so + * the admin form knows if we have a fallback or not. + * + * @param string $login + * @param string $apiKey + * @return boolean hook return value + */ + function onBitlyDefaultCredentials(&$login, &$apiKey) + { + $login = $this->login; + $apiKey = $this->apiKey; + return false; + } + } diff --git a/plugins/BitlyUrl/bitlyadminpanelaction.php b/plugins/BitlyUrl/bitlyadminpanelaction.php index 56f78e164..805b56b85 100644 --- a/plugins/BitlyUrl/bitlyadminpanelaction.php +++ b/plugins/BitlyUrl/bitlyadminpanelaction.php @@ -206,11 +206,18 @@ class BitlyAdminPanelForm extends AdminForm array('id' => 'settings_bitly') ); $this->out->element('legend', null, _m('Default credentials')); - $this->out->element('p', 'form_guide', - _m('When users select the bit.ly shortening service, by default ' . - 'these credentials will be used. If you leave these empty, ' . - 'users will need to set up their own credentials in order to ' . - 'use bit.ly.')); + + // Do we have global defaults to fall back on? + $login = $apiKey = false; + Event::handle('BitlyDefaultCredentials', array(&$login, &$apiKey)); + $haveGlobalDefaults = ($login && $apiKey); + if ($login && $apiKey) { + $this->out->element('p', 'form_guide', + _m('Leave these empty to use the default credentials.')); + } else { + $this->out->element('p', 'form_guide', + _m('If you leave these empty, bit.ly will be unavailable to users.')); + } $this->out->elementStart('ul', 'form_data'); $this->li(); -- cgit v1.2.3-54-g00ecf From fbfd96dfb945712b60f5b9f34aaaec5118e7c641 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 7 Oct 2010 13:08:23 -0700 Subject: Drop out the 'allow user override' checkbox on bit.ly admin panel until we find a good way to shove the user settings in. :) --- plugins/BitlyUrl/bitlyadminpanelaction.php | 40 ------------------------------ 1 file changed, 40 deletions(-) (limited to 'plugins/BitlyUrl') diff --git a/plugins/BitlyUrl/bitlyadminpanelaction.php b/plugins/BitlyUrl/bitlyadminpanelaction.php index 805b56b85..046ae52c2 100644 --- a/plugins/BitlyUrl/bitlyadminpanelaction.php +++ b/plugins/BitlyUrl/bitlyadminpanelaction.php @@ -93,10 +93,6 @@ class BitlyadminpanelAction extends AdminPanelAction 'bitly' => array('default_login', 'default_apikey') ); - static $booleans = array( - 'bitly' => array('allow_override') - ); - $values = array(); foreach ($settings as $section => $parts) { @@ -106,13 +102,6 @@ class BitlyadminpanelAction extends AdminPanelAction } } - foreach ($booleans as $section => $parts) { - foreach ($parts as $setting) { - $values[$section][$setting] - = ($this->boolean($setting)) ? 1 : 0; - } - } - // This throws an exception on validation errors $this->validate($values); @@ -129,12 +118,6 @@ class BitlyadminpanelAction extends AdminPanelAction } } - foreach ($booleans as $section => $parts) { - foreach ($parts as $setting) { - Config::save($section, $setting, $values[$section][$setting]); - } - } - $config->query('COMMIT'); return; @@ -240,29 +223,6 @@ class BitlyAdminPanelForm extends AdminForm $this->out->elementEnd('ul'); $this->out->elementEnd('fieldset'); - - $this->out->elementStart( - 'fieldset', - array('id' => 'settings_bitly-options') - ); - $this->out->element('legend', null, _m('Options')); - - $this->out->elementStart('ul', 'form_data'); - - $this->li(); - - $this->out->checkbox( - 'allow_override', _m('Allow users to specify their own API key.'), - (bool) $this->value('bitly', 'allow_override'), - _m('If set, users will be able to specify their own bit.ly login and API key ' . - 'to be used for shortening their links.'), - 'true' - ); - $this->unli(); - - $this->out->elementEnd('ul'); - - $this->out->elementEnd('fieldset'); } /** -- cgit v1.2.3-54-g00ecf From bd5925a6dbe53d08cde01618c73a7be034401455 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 7 Oct 2010 13:17:20 -0700 Subject: Tweak bit.ly admin panel messages to distinguish the admin settings from config.php globals --- plugins/BitlyUrl/bitlyadminpanelaction.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins/BitlyUrl') diff --git a/plugins/BitlyUrl/bitlyadminpanelaction.php b/plugins/BitlyUrl/bitlyadminpanelaction.php index 046ae52c2..05b8e8326 100644 --- a/plugins/BitlyUrl/bitlyadminpanelaction.php +++ b/plugins/BitlyUrl/bitlyadminpanelaction.php @@ -188,7 +188,7 @@ class BitlyAdminPanelForm extends AdminForm 'fieldset', array('id' => 'settings_bitly') ); - $this->out->element('legend', null, _m('Default credentials')); + $this->out->element('legend', null, _m('Credentials')); // Do we have global defaults to fall back on? $login = $apiKey = false; @@ -196,7 +196,7 @@ class BitlyAdminPanelForm extends AdminForm $haveGlobalDefaults = ($login && $apiKey); if ($login && $apiKey) { $this->out->element('p', 'form_guide', - _m('Leave these empty to use the default credentials.')); + _m('Leave these empty to use global default credentials.')); } else { $this->out->element('p', 'form_guide', _m('If you leave these empty, bit.ly will be unavailable to users.')); -- cgit v1.2.3-54-g00ecf From 603e1dc563128c6e5ad0f5cd457563b7db7c787e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 7 Oct 2010 13:23:18 -0700 Subject: Add a README for BitlyUrlPlugin --- plugins/BitlyUrl/README | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 plugins/BitlyUrl/README (limited to 'plugins/BitlyUrl') diff --git a/plugins/BitlyUrl/README b/plugins/BitlyUrl/README new file mode 100644 index 000000000..0b3af1dd6 --- /dev/null +++ b/plugins/BitlyUrl/README @@ -0,0 +1,37 @@ +bit.ly URL shortening requires the login name and API key for a bit.ly account. +Register for an account or set up your API key here: + + http://bit.ly/a/your_api_key + +Administrators can configure a login and API key to use through the admin panels +on the site; these credentials will then be used for all users. + +(In the future, options will be added for individual users to override the keys +with their own login for URLs they post.) + +If the login and API key are left empty in the admin panel, then bit.ly will be +disabled and hidden from the list of available URL shorteners unless a global +default was provided in the plugin configuration. + + +To enable bit.ly with no default credentials, simply slip into your config.php: + + addPlugin('BitlyUrl'); + +To provide default credentials, add them as parameters: + + addPlugin('BitlyUrl', array( + 'login' => 'myname', + 'apiKey' => '############################' + )); + +These settings will not be individually exposed to the admin panels, but the +panel will indicate whether or not the global default settings are available; +this makes it suitable as a global default for multi-site hosting, where admins +on individual sites can change to use their own settings. + + +If you're using a bit.ly pro account with a custom domain etc, it should all +"just work" as long as you use the correct login name and API key for your +account. + -- cgit v1.2.3-54-g00ecf