forked from GNUsocial/gnu-social
		
	Merge branch 'master' of gitorious.org:statusnet/mainline
This commit is contained in:
		| @@ -120,18 +120,11 @@ class ApiStatusesDestroyAction extends ApiAuthAction | |||||||
|              $replies->get('notice_id', $this->notice_id); |              $replies->get('notice_id', $this->notice_id); | ||||||
|              $replies->delete(); |              $replies->delete(); | ||||||
|              $this->notice->delete(); |              $this->notice->delete(); | ||||||
|  | 	     $this->showNotice(); | ||||||
|              if ($this->format == 'xml') { |  | ||||||
|                  $this->showSingleXmlStatus($this->notice); |  | ||||||
|              } elseif ($this->format == 'json') { |  | ||||||
|                  $this->show_single_json_status($this->notice); |  | ||||||
|              } |  | ||||||
|          } else { |          } else { | ||||||
|              $this->clientError(_('You may not delete another user\'s status.'), |              $this->clientError(_('You may not delete another user\'s status.'), | ||||||
|                  403, $this->format); |                  403, $this->format); | ||||||
|          } |          } | ||||||
|  |  | ||||||
|         $this->showNotice(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -150,7 +150,7 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction | |||||||
|  |  | ||||||
|             header('Content-Type: application/atom+xml; charset=utf-8'); |             header('Content-Type: application/atom+xml; charset=utf-8'); | ||||||
|  |  | ||||||
|             $atom = new AtomNoticeFeed(); |             $atom = new AtomNoticeFeed($this->auth_user); | ||||||
|  |  | ||||||
|             $atom->setId($id); |             $atom->setId($id); | ||||||
|             $atom->setTitle($title); |             $atom->setTitle($title); | ||||||
|   | |||||||
| @@ -152,7 +152,7 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction | |||||||
|  |  | ||||||
|             header('Content-Type: application/atom+xml; charset=utf-8'); |             header('Content-Type: application/atom+xml; charset=utf-8'); | ||||||
|  |  | ||||||
|             $atom = new AtomNoticeFeed(); |             $atom = new AtomNoticeFeed($this->auth_user); | ||||||
|  |  | ||||||
|             $atom->setId($id); |             $atom->setId($id); | ||||||
|             $atom->setTitle($title); |             $atom->setTitle($title); | ||||||
|   | |||||||
| @@ -105,7 +105,7 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction | |||||||
|     function showTimeline() |     function showTimeline() | ||||||
|     { |     { | ||||||
|         // We'll pull common formatting out of this for other formats |         // We'll pull common formatting out of this for other formats | ||||||
|         $atom = new AtomGroupNoticeFeed($this->group); |         $atom = new AtomGroupNoticeFeed($this->group, $this->auth_user); | ||||||
|  |  | ||||||
|         $self = $this->getSelfUri(); |         $self = $this->getSelfUri(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -151,7 +151,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction | |||||||
|  |  | ||||||
|             header('Content-Type: application/atom+xml; charset=utf-8'); |             header('Content-Type: application/atom+xml; charset=utf-8'); | ||||||
|  |  | ||||||
|             $atom = new AtomNoticeFeed(); |             $atom = new AtomNoticeFeed($this->auth_user); | ||||||
|  |  | ||||||
|             $atom->setId($id); |             $atom->setId($id); | ||||||
|             $atom->setTitle($title); |             $atom->setTitle($title); | ||||||
|   | |||||||
| @@ -151,7 +151,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction | |||||||
|  |  | ||||||
|             header('Content-Type: application/atom+xml; charset=utf-8'); |             header('Content-Type: application/atom+xml; charset=utf-8'); | ||||||
|  |  | ||||||
|             $atom = new AtomNoticeFeed(); |             $atom = new AtomNoticeFeed($this->auth_user); | ||||||
|  |  | ||||||
|             $atom->setId($id); |             $atom->setId($id); | ||||||
|             $atom->setTitle($title); |             $atom->setTitle($title); | ||||||
|   | |||||||
| @@ -130,7 +130,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction | |||||||
|  |  | ||||||
|             header('Content-Type: application/atom+xml; charset=utf-8'); |             header('Content-Type: application/atom+xml; charset=utf-8'); | ||||||
|  |  | ||||||
|             $atom = new AtomNoticeFeed(); |             $atom = new AtomNoticeFeed($this->auth_user); | ||||||
|  |  | ||||||
|             $atom->setId($id); |             $atom->setId($id); | ||||||
|             $atom->setTitle($title); |             $atom->setTitle($title); | ||||||
|   | |||||||
| @@ -117,7 +117,7 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction | |||||||
|  |  | ||||||
|             header('Content-Type: application/atom+xml; charset=utf-8'); |             header('Content-Type: application/atom+xml; charset=utf-8'); | ||||||
|  |  | ||||||
|             $atom = new AtomNoticeFeed(); |             $atom = new AtomNoticeFeed($this->auth_user); | ||||||
|  |  | ||||||
|             $atom->setId($id); |             $atom->setId($id); | ||||||
|             $atom->setTitle($title); |             $atom->setTitle($title); | ||||||
|   | |||||||
| @@ -138,7 +138,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction | |||||||
|  |  | ||||||
|             header('Content-Type: application/atom+xml; charset=utf-8'); |             header('Content-Type: application/atom+xml; charset=utf-8'); | ||||||
|  |  | ||||||
|             $atom = new AtomNoticeFeed(); |             $atom = new AtomNoticeFeed($this->auth_user); | ||||||
|  |  | ||||||
|             $atom->setId($id); |             $atom->setId($id); | ||||||
|             $atom->setTitle($title); |             $atom->setTitle($title); | ||||||
|   | |||||||
| @@ -115,7 +115,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction | |||||||
|  |  | ||||||
|         // We'll use the shared params from the Atom stub |         // We'll use the shared params from the Atom stub | ||||||
|         // for other feed types. |         // for other feed types. | ||||||
|         $atom = new AtomUserNoticeFeed($this->user); |         $atom = new AtomUserNoticeFeed($this->user, $this->auth_user); | ||||||
|  |  | ||||||
|         $link = common_local_url( |         $link = common_local_url( | ||||||
|             'showstream', |             'showstream', | ||||||
|   | |||||||
| @@ -95,7 +95,9 @@ class FoafAction extends Action | |||||||
|         // Would be nice to tell if they were a Person or not (e.g. a #person usertag?) |         // Would be nice to tell if they were a Person or not (e.g. a #person usertag?) | ||||||
|         $this->elementStart('Agent', array('rdf:about' => |         $this->elementStart('Agent', array('rdf:about' => | ||||||
|                                              $this->user->uri)); |                                              $this->user->uri)); | ||||||
|  |         if ($this->user->email) { | ||||||
|             $this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email)); |             $this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email)); | ||||||
|  |         } | ||||||
|         if ($this->profile->fullname) { |         if ($this->profile->fullname) { | ||||||
|             $this->element('name', null, $this->profile->fullname); |             $this->element('name', null, $this->profile->fullname); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -116,7 +116,11 @@ class File extends Memcached_DataObject | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function processNew($given_url, $notice_id=null) { |     /** | ||||||
|  |      * @fixme refactor this mess, it's gotten pretty scary. | ||||||
|  |      * @param bool $followRedirects | ||||||
|  |      */ | ||||||
|  |     function processNew($given_url, $notice_id=null, $followRedirects=true) { | ||||||
|         if (empty($given_url)) return -1;   // error, no url to process |         if (empty($given_url)) return -1;   // error, no url to process | ||||||
|         $given_url = File_redirection::_canonUrl($given_url); |         $given_url = File_redirection::_canonUrl($given_url); | ||||||
|         if (empty($given_url)) return -1;   // error, no url to process |         if (empty($given_url)) return -1;   // error, no url to process | ||||||
| @@ -124,6 +128,10 @@ class File extends Memcached_DataObject | |||||||
|         if (empty($file)) { |         if (empty($file)) { | ||||||
|             $file_redir = File_redirection::staticGet('url', $given_url); |             $file_redir = File_redirection::staticGet('url', $given_url); | ||||||
|             if (empty($file_redir)) { |             if (empty($file_redir)) { | ||||||
|  |                 // @fixme for new URLs this also looks up non-redirect data | ||||||
|  |                 // such as target content type, size, etc, which we need | ||||||
|  |                 // for File::saveNew(); so we call it even if not following | ||||||
|  |                 // new redirects. | ||||||
|                 $redir_data = File_redirection::where($given_url); |                 $redir_data = File_redirection::where($given_url); | ||||||
|                 if (is_array($redir_data)) { |                 if (is_array($redir_data)) { | ||||||
|                     $redir_url = $redir_data['url']; |                     $redir_url = $redir_data['url']; | ||||||
| @@ -134,11 +142,19 @@ class File extends Memcached_DataObject | |||||||
|                     throw new ServerException("Can't process url '$given_url'"); |                     throw new ServerException("Can't process url '$given_url'"); | ||||||
|                 } |                 } | ||||||
|                 // TODO: max field length |                 // TODO: max field length | ||||||
|                 if ($redir_url === $given_url || strlen($redir_url) > 255) { |                 if ($redir_url === $given_url || strlen($redir_url) > 255 || !$followRedirects) { | ||||||
|                     $x = File::saveNew($redir_data, $given_url); |                     $x = File::saveNew($redir_data, $given_url); | ||||||
|                     $file_id = $x->id; |                     $file_id = $x->id; | ||||||
|                 } else { |                 } else { | ||||||
|                     $x = File::processNew($redir_url, $notice_id); |                     // This seems kind of messed up... for now skipping this part | ||||||
|  |                     // if we're already under a redirect, so we don't go into | ||||||
|  |                     // horrible infinite loops if we've been given an unstable | ||||||
|  |                     // redirect (where the final destination of the first request | ||||||
|  |                     // doesn't match what we get when we ask for it again). | ||||||
|  |                     // | ||||||
|  |                     // Seen in the wild with clojure.org, which redirects through | ||||||
|  |                     // wikispaces for auth and appends session data in the URL params. | ||||||
|  |                     $x = File::processNew($redir_url, $notice_id, /*followRedirects*/false); | ||||||
|                     $file_id = $x->id; |                     $file_id = $x->id; | ||||||
|                     File_redirection::saveNew($redir_data, $file_id, $given_url); |                     File_redirection::saveNew($redir_data, $file_id, $given_url); | ||||||
|                 } |                 } | ||||||
|   | |||||||
| @@ -97,6 +97,10 @@ class Notice extends Memcached_DataObject | |||||||
|         // For auditing purposes, save a record that the notice |         // For auditing purposes, save a record that the notice | ||||||
|         // was deleted. |         // was deleted. | ||||||
|  |  | ||||||
|  |         // @fixme we have some cases where things get re-run and so the | ||||||
|  |         // insert fails. | ||||||
|  |         $deleted = Deleted_notice::staticGet('id', $this->id); | ||||||
|  |         if (!$deleted) { | ||||||
|             $deleted = new Deleted_notice(); |             $deleted = new Deleted_notice(); | ||||||
|  |  | ||||||
|             $deleted->id         = $this->id; |             $deleted->id         = $this->id; | ||||||
| @@ -106,6 +110,7 @@ class Notice extends Memcached_DataObject | |||||||
|             $deleted->deleted    = common_sql_now(); |             $deleted->deleted    = common_sql_now(); | ||||||
|  |  | ||||||
|             $deleted->insert(); |             $deleted->insert(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // Clear related records |         // Clear related records | ||||||
|  |  | ||||||
| @@ -1235,7 +1240,7 @@ class Notice extends Memcached_DataObject | |||||||
|  |  | ||||||
|         $noticeInfoAttr = array( |         $noticeInfoAttr = array( | ||||||
|             'local_id'   => $this->id,    // local notice ID (useful to clients for ordering) |             'local_id'   => $this->id,    // local notice ID (useful to clients for ordering) | ||||||
|             'source'     => $this->source // the client name (source attribution) |             'source'     => $this->source, // the client name (source attribution) | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         $ns = $this->getSource(); |         $ns = $this->getSource(); | ||||||
| @@ -1246,7 +1251,11 @@ class Notice extends Memcached_DataObject | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!empty($cur)) { |         if (!empty($cur)) { | ||||||
|             $noticeInfoAttr['favorited'] = ($cur->hasFave($this)) ? 'true' : 'false'; |             $noticeInfoAttr['favorite'] = ($cur->hasFave($this)) ? "true" : "false"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!empty($this->repeat_of)) { | ||||||
|  |             $noticeInfoAttr['repeat_of'] = $this->repeat_of; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         $xs->element('statusnet:notice_info', $noticeInfoAttr, null); |         $xs->element('statusnet:notice_info', $noticeInfoAttr, null); | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ VALUES | |||||||
|     ('bti','bti','http://gregkh.github.com/bti/', now()), |     ('bti','bti','http://gregkh.github.com/bti/', now()), | ||||||
|     ('choqok', 'Choqok', 'http://choqok.gnufolks.org/', now()), |     ('choqok', 'Choqok', 'http://choqok.gnufolks.org/', now()), | ||||||
|     ('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()), |     ('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()), | ||||||
|  |     ('DarterosStatus', 'Darteros Status', 'http://www.darteros.com/doc/Darteros_Status', now()), | ||||||
|     ('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()), |     ('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()), | ||||||
|     ('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()), |     ('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()), | ||||||
|     ('drupal','Drupal','http://drupal.org/', now()), |     ('drupal','Drupal','http://drupal.org/', now()), | ||||||
|   | |||||||
| @@ -50,12 +50,13 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed | |||||||
|      * Constructor |      * Constructor | ||||||
|      * |      * | ||||||
|      * @param Group   $group   the group for the feed |      * @param Group   $group   the group for the feed | ||||||
|  |      * @param User    $cur     the current authenticated user, if any | ||||||
|      * @param boolean $indent  flag to turn indenting on or off |      * @param boolean $indent  flag to turn indenting on or off | ||||||
|      * |      * | ||||||
|      * @return void |      * @return void | ||||||
|      */ |      */ | ||||||
|     function __construct($group, $indent = true) { |     function __construct($group, $cur = null, $indent = true) { | ||||||
|         parent::__construct($indent); |         parent::__construct($cur, $indent); | ||||||
|         $this->group = $group; |         $this->group = $group; | ||||||
|  |  | ||||||
|         $title      = sprintf(_("%s timeline"), $group->nickname); |         $title      = sprintf(_("%s timeline"), $group->nickname); | ||||||
|   | |||||||
| @@ -44,9 +44,22 @@ if (!defined('STATUSNET')) | |||||||
|  */ |  */ | ||||||
| class AtomNoticeFeed extends Atom10Feed | class AtomNoticeFeed extends Atom10Feed | ||||||
| { | { | ||||||
|     function __construct($indent = true) { |     var $cur; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Constructor - adds a bunch of XML namespaces we need in our | ||||||
|  |      * notice-specific Atom feeds, and allows setting the current | ||||||
|  |      * authenticated user (useful for API methods). | ||||||
|  |      * | ||||||
|  |      * @param User    $cur     the current authenticated user (optional) | ||||||
|  |      * @param boolean $indent  Whether to indent XML output | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |     function __construct($cur = null, $indent = true) { | ||||||
|         parent::__construct($indent); |         parent::__construct($indent); | ||||||
|  |  | ||||||
|  |         $this->cur = $cur; | ||||||
|  |  | ||||||
|         // Feeds containing notice info use these namespaces |         // Feeds containing notice info use these namespaces | ||||||
|  |  | ||||||
|         $this->addNamespace( |         $this->addNamespace( | ||||||
| @@ -115,7 +128,7 @@ class AtomNoticeFeed extends Atom10Feed | |||||||
|         $source = $this->showSource(); |         $source = $this->showSource(); | ||||||
|         $author = $this->showAuthor(); |         $author = $this->showAuthor(); | ||||||
|  |  | ||||||
|         $cur = common_current_user(); |         $cur = empty($this->cur) ? common_current_user() : $this->cur; | ||||||
|  |  | ||||||
|         $this->addEntryRaw($notice->asAtomEntry(false, $source, $author, $cur)); |         $this->addEntryRaw($notice->asAtomEntry(false, $source, $author, $cur)); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -50,13 +50,14 @@ class AtomUserNoticeFeed extends AtomNoticeFeed | |||||||
|      * Constructor |      * Constructor | ||||||
|      * |      * | ||||||
|      * @param User    $user    the user for the feed |      * @param User    $user    the user for the feed | ||||||
|  |      * @param User    $cur     the current authenticated user, if any | ||||||
|      * @param boolean $indent  flag to turn indenting on or off |      * @param boolean $indent  flag to turn indenting on or off | ||||||
|      * |      * | ||||||
|      * @return void |      * @return void | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     function __construct($user, $indent = true) { |     function __construct($user, $cur = null, $indent = true) { | ||||||
|         parent::__construct($indent); |         parent::__construct($cur, $indent); | ||||||
|         $this->user = $user; |         $this->user = $user; | ||||||
|         if (!empty($user)) { |         if (!empty($user)) { | ||||||
|             $profile = $user->getProfile(); |             $profile = $user->getProfile(); | ||||||
|   | |||||||
| @@ -61,7 +61,7 @@ if (!function_exists('dpgettext')) { | |||||||
|      * Not currently exposed in PHP's gettext module; implemented to be compat |      * Not currently exposed in PHP's gettext module; implemented to be compat | ||||||
|      * with gettext.h's macros. |      * with gettext.h's macros. | ||||||
|      * |      * | ||||||
|      * @param string $domain domain identifier, or null for default domain |      * @param string $domain domain identifier | ||||||
|      * @param string $context context identifier, should be some key like "menu|file" |      * @param string $context context identifier, should be some key like "menu|file" | ||||||
|      * @param string $msgid English source text |      * @param string $msgid English source text | ||||||
|      * @return string original or translated message |      * @return string original or translated message | ||||||
| @@ -106,7 +106,7 @@ if (!function_exists('dnpgettext')) { | |||||||
|      * Not currently exposed in PHP's gettext module; implemented to be compat |      * Not currently exposed in PHP's gettext module; implemented to be compat | ||||||
|      * with gettext.h's macros. |      * with gettext.h's macros. | ||||||
|      * |      * | ||||||
|      * @param string $domain domain identifier, or null for default domain |      * @param string $domain domain identifier | ||||||
|      * @param string $context context identifier, should be some key like "menu|file" |      * @param string $context context identifier, should be some key like "menu|file" | ||||||
|      * @param string $msg singular English source text |      * @param string $msg singular English source text | ||||||
|      * @param string $plural plural English source text |      * @param string $plural plural English source text | ||||||
| @@ -180,7 +180,11 @@ function _m($msg/*, ...*/) | |||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Looks for which plugin we've been called from to set the gettext domain. |  * Looks for which plugin we've been called from to set the gettext domain; | ||||||
|  |  * if not in a plugin subdirectory, we'll use the default 'statusnet'. | ||||||
|  |  * | ||||||
|  |  * Note: we can't return null for default domain since most of the PHP gettext | ||||||
|  |  * wrapper functions turn null into "" before passing to the backend library. | ||||||
|  * |  * | ||||||
|  * @param array $backtrace debug_backtrace() output |  * @param array $backtrace debug_backtrace() output | ||||||
|  * @return string |  * @return string | ||||||
| @@ -205,12 +209,20 @@ function _mdomain($backtrace) | |||||||
|         if (DIRECTORY_SEPARATOR !== '/') { |         if (DIRECTORY_SEPARATOR !== '/') { | ||||||
|             $path = strtr($path, DIRECTORY_SEPARATOR, '/'); |             $path = strtr($path, DIRECTORY_SEPARATOR, '/'); | ||||||
|         } |         } | ||||||
|         $cut = strpos($path, '/plugins/') + 9; |         $plug = strpos($path, '/plugins/'); | ||||||
|  |         if ($plug === false) { | ||||||
|  |             // We're not in a plugin; return default domain. | ||||||
|  |             return 'statusnet'; | ||||||
|  |         } else { | ||||||
|  |             $cut = $plug + 9; | ||||||
|             $cut2 = strpos($path, '/', $cut); |             $cut2 = strpos($path, '/', $cut); | ||||||
|         if ($cut && $cut2) { |             if ($cut2) { | ||||||
|                 $cached[$path] = substr($path, $cut, $cut2 - $cut); |                 $cached[$path] = substr($path, $cut, $cut2 - $cut); | ||||||
|             } else { |             } else { | ||||||
|             return null; |                 // We might be running directly from the plugins dir? | ||||||
|  |                 // If so, there's no place to store locale info. | ||||||
|  |                 return 'statusnet'; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return $cached[$path]; |     return $cached[$path]; | ||||||
|   | |||||||
| @@ -122,7 +122,19 @@ class StompQueueManager extends QueueManager | |||||||
|     public function enqueue($object, $queue) |     public function enqueue($object, $queue) | ||||||
|     { |     { | ||||||
|         $this->_connect(); |         $this->_connect(); | ||||||
|         return $this->_doEnqueue($object, $queue, $this->defaultIdx); |         if (common_config('queue', 'stomp_enqueue_on')) { | ||||||
|  |             // We're trying to force all writes to a single server. | ||||||
|  |             // WARNING: this might do odd things if that server connection dies. | ||||||
|  |             $idx = array_search(common_config('queue', 'stomp_enqueue_on'), | ||||||
|  |                                 $this->servers); | ||||||
|  |             if ($idx === false) { | ||||||
|  |                 common_log(LOG_ERR, 'queue stomp_enqueue_on setting does not match our server list.'); | ||||||
|  |                 $idx = $this->defaultIdx; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             $idx = $this->defaultIdx; | ||||||
|  |         } | ||||||
|  |         return $this->_doEnqueue($object, $queue, $idx); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ In Facebook's application editor, specify the following URLs for your app: | |||||||
|  |  | ||||||
| - Canvas Callback URL         : http://example.net/mublog/facebook/app/ | - Canvas Callback URL         : http://example.net/mublog/facebook/app/ | ||||||
| - Post-Remove Callback URL    : http://example.net/mublog/facebook/app/remove | - Post-Remove Callback URL    : http://example.net/mublog/facebook/app/remove | ||||||
| - Post-Add Redirect URL   : http://apps.facebook.com/yourapp/ | - Post-Authorize Redirect URL : http://apps.facebook.com/yourapp/ | ||||||
| - Canvas Page URL             : http://apps.facebook.com/yourapp/ | - Canvas Page URL             : http://apps.facebook.com/yourapp/ | ||||||
| - Connect URL                 : http://example.net/mublog/ | - Connect URL                 : http://example.net/mublog/ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -45,7 +45,9 @@ class Facebook { | |||||||
|   public $user; |   public $user; | ||||||
|   public $profile_user; |   public $profile_user; | ||||||
|   public $canvas_user; |   public $canvas_user; | ||||||
|  |   public $ext_perms = array(); | ||||||
|   protected $base_domain; |   protected $base_domain; | ||||||
|  |  | ||||||
|   /* |   /* | ||||||
|    * Create a Facebook client like this: |    * Create a Facebook client like this: | ||||||
|    * |    * | ||||||
| @@ -104,17 +106,17 @@ class Facebook { | |||||||
|    * |    * | ||||||
|    * For nitty-gritty details of when each of these is used, check out |    * For nitty-gritty details of when each of these is used, check out | ||||||
|    * http://wiki.developers.facebook.com/index.php/Verifying_The_Signature |    * http://wiki.developers.facebook.com/index.php/Verifying_The_Signature | ||||||
|    * |  | ||||||
|    * @param bool  resolve_auth_token  convert an auth token into a session |  | ||||||
|    */ |    */ | ||||||
|   public function validate_fb_params($resolve_auth_token=true) { |   public function validate_fb_params() { | ||||||
|     $this->fb_params = $this->get_valid_fb_params($_POST, 48 * 3600, 'fb_sig'); |     $this->fb_params = $this->get_valid_fb_params($_POST, 48 * 3600, 'fb_sig'); | ||||||
|  |  | ||||||
|     // note that with preload FQL, it's possible to receive POST params in |     // note that with preload FQL, it's possible to receive POST params in | ||||||
|     // addition to GET, so use a different prefix to differentiate them |     // addition to GET, so use a different prefix to differentiate them | ||||||
|     if (!$this->fb_params) { |     if (!$this->fb_params) { | ||||||
|       $fb_params = $this->get_valid_fb_params($_GET, 48 * 3600, 'fb_sig'); |       $fb_params = $this->get_valid_fb_params($_GET, 48 * 3600, 'fb_sig'); | ||||||
|       $fb_post_params = $this->get_valid_fb_params($_POST, 48 * 3600, 'fb_post_sig'); |       $fb_post_params = $this->get_valid_fb_params($_POST, | ||||||
|  |                                                    48 * 3600, // 48 hours | ||||||
|  |                                                    'fb_post_sig'); | ||||||
|       $this->fb_params = array_merge($fb_params, $fb_post_params); |       $this->fb_params = array_merge($fb_params, $fb_post_params); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -128,6 +130,9 @@ class Facebook { | |||||||
|                             $this->fb_params['canvas_user'] : null; |                             $this->fb_params['canvas_user'] : null; | ||||||
|       $this->base_domain  = isset($this->fb_params['base_domain']) ? |       $this->base_domain  = isset($this->fb_params['base_domain']) ? | ||||||
|                             $this->fb_params['base_domain'] : null; |                             $this->fb_params['base_domain'] : null; | ||||||
|  |       $this->ext_perms    = isset($this->fb_params['ext_perms']) ? | ||||||
|  |                             explode(',', $this->fb_params['ext_perms']) | ||||||
|  |                             : array(); | ||||||
|  |  | ||||||
|       if (isset($this->fb_params['session_key'])) { |       if (isset($this->fb_params['session_key'])) { | ||||||
|         $session_key =  $this->fb_params['session_key']; |         $session_key =  $this->fb_params['session_key']; | ||||||
| @@ -141,13 +146,11 @@ class Facebook { | |||||||
|       $this->set_user($user, |       $this->set_user($user, | ||||||
|                       $session_key, |                       $session_key, | ||||||
|                       $expires); |                       $expires); | ||||||
|     } |     } else if ($cookies = | ||||||
|  |                $this->get_valid_fb_params($_COOKIE, null, $this->api_key)) { | ||||||
|       // if no Facebook parameters were found in the GET or POST variables, |       // if no Facebook parameters were found in the GET or POST variables, | ||||||
|       // then fall back to cookies, which may have cached user information |       // then fall back to cookies, which may have cached user information | ||||||
|       // Cookies are also used to receive session data via the Javascript API |       // Cookies are also used to receive session data via the Javascript API | ||||||
|     else if ($cookies = |  | ||||||
|              $this->get_valid_fb_params($_COOKIE, null, $this->api_key)) { |  | ||||||
|  |  | ||||||
|       $base_domain_cookie = 'base_domain_' . $this->api_key; |       $base_domain_cookie = 'base_domain_' . $this->api_key; | ||||||
|       if (isset($_COOKIE[$base_domain_cookie])) { |       if (isset($_COOKIE[$base_domain_cookie])) { | ||||||
|         $this->base_domain = $_COOKIE[$base_domain_cookie]; |         $this->base_domain = $_COOKIE[$base_domain_cookie]; | ||||||
| @@ -160,25 +163,6 @@ class Facebook { | |||||||
|                       $cookies['session_key'], |                       $cookies['session_key'], | ||||||
|                       $expires); |                       $expires); | ||||||
|     } |     } | ||||||
|     // finally, if we received no parameters, but the 'auth_token' GET var |  | ||||||
|     // is present, then we are in the middle of auth handshake, |  | ||||||
|     // so go ahead and create the session |  | ||||||
|     else if ($resolve_auth_token && isset($_GET['auth_token']) && |  | ||||||
|              $session = $this->do_get_session($_GET['auth_token'])) { |  | ||||||
|       if ($this->generate_session_secret && |  | ||||||
|           !empty($session['secret'])) { |  | ||||||
|         $session_secret = $session['secret']; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       if (isset($session['base_domain'])) { |  | ||||||
|         $this->base_domain = $session['base_domain']; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       $this->set_user($session['uid'], |  | ||||||
|                       $session['session_key'], |  | ||||||
|                       $session['expires'], |  | ||||||
|                       isset($session_secret) ? $session_secret : null); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return !empty($this->fb_params); |     return !empty($this->fb_params); | ||||||
|   } |   } | ||||||
| @@ -309,11 +293,28 @@ class Facebook { | |||||||
|  |  | ||||||
|   // require_add and require_install have been removed. |   // require_add and require_install have been removed. | ||||||
|   // see http://developer.facebook.com/news.php?blog=1&story=116 for more details |   // see http://developer.facebook.com/news.php?blog=1&story=116 for more details | ||||||
|   public function require_login() { |   public function require_login($required_permissions = '') { | ||||||
|     if ($user = $this->get_loggedin_user()) { |     $user = $this->get_loggedin_user(); | ||||||
|  |     $has_permissions = true; | ||||||
|  |  | ||||||
|  |     if ($required_permissions) { | ||||||
|  |       $this->require_frame(); | ||||||
|  |       $permissions = array_map('trim', explode(',', $required_permissions)); | ||||||
|  |       foreach ($permissions as $permission) { | ||||||
|  |         if (!in_array($permission, $this->ext_perms)) { | ||||||
|  |           $has_permissions = false; | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ($user && $has_permissions) { | ||||||
|       return $user; |       return $user; | ||||||
|     } |     } | ||||||
|     $this->redirect($this->get_login_url(self::current_url(), $this->in_frame())); |  | ||||||
|  |     $this->redirect( | ||||||
|  |       $this->get_login_url(self::current_url(), $this->in_frame(), | ||||||
|  |                            $required_permissions)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function require_frame() { |   public function require_frame() { | ||||||
| @@ -342,10 +343,11 @@ class Facebook { | |||||||
|     return $page . '?' . http_build_query($params); |     return $page . '?' . http_build_query($params); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function get_login_url($next, $canvas) { |   public function get_login_url($next, $canvas, $req_perms = '') { | ||||||
|     $page = self::get_facebook_url().'/login.php'; |     $page = self::get_facebook_url().'/login.php'; | ||||||
|     $params = array('api_key'   => $this->api_key, |     $params = array('api_key'   => $this->api_key, | ||||||
|                     'v'       => '1.0'); |                     'v'         => '1.0', | ||||||
|  |                     'req_perms' => $req_perms); | ||||||
|  |  | ||||||
|     if ($next) { |     if ($next) { | ||||||
|       $params['next'] = $next; |       $params['next'] = $next; | ||||||
|   | |||||||
| @@ -569,7 +569,7 @@ function toggleDisplay(id, type) { | |||||||
|     return $this->call_method('facebook.events.invite', |     return $this->call_method('facebook.events.invite', | ||||||
|                               array('eid' => $eid, |                               array('eid' => $eid, | ||||||
|                                     'uids' => $uids, |                                     'uids' => $uids, | ||||||
|                                     'personal_message', $personal_message)); |                                     'personal_message' => $personal_message)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -1350,53 +1350,6 @@ function toggleDisplay(id, type) { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * Dashboard API |  | ||||||
|    */ |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * Set the news for the specified user. |  | ||||||
|    * |  | ||||||
|    * @param int    $uid     The user for whom you are setting news for |  | ||||||
|    * @param string $news    Text of news to display |  | ||||||
|    * |  | ||||||
|    * @return bool   Success |  | ||||||
|    */ |  | ||||||
|   public function dashboard_setNews($uid, $news) { |  | ||||||
|     return $this->call_method('facebook.dashboard.setNews', |  | ||||||
|                               array('uid'  => $uid, |  | ||||||
|                                     'news' => $news) |  | ||||||
|                              ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * Get the current news of the specified user. |  | ||||||
|    * |  | ||||||
|    * @param int    $uid     The user to get the news of |  | ||||||
|    * |  | ||||||
|    * @return string   The text of the current news for the user |  | ||||||
|    */ |  | ||||||
|   public function dashboard_getNews($uid) { |  | ||||||
|     return json_decode( |  | ||||||
|       $this->call_method('facebook.dashboard.getNews', |  | ||||||
|                          array('uid' => $uid) |  | ||||||
|                         ), true); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * Set the news for the specified user. |  | ||||||
|    * |  | ||||||
|    * @param int    $uid     The user you are clearing the news of |  | ||||||
|    * |  | ||||||
|    * @return bool   Success |  | ||||||
|    */ |  | ||||||
|   public function dashboard_clearNews($uid) { |  | ||||||
|     return $this->call_method('facebook.dashboard.clearNews', |  | ||||||
|                               array('uid' => $uid) |  | ||||||
|                              ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Creates a note with the specified title and content. |    * Creates a note with the specified title and content. | ||||||
| @@ -2005,7 +1958,7 @@ function toggleDisplay(id, type) { | |||||||
|    * @return  array  A list of strings describing any compile errors for the |    * @return  array  A list of strings describing any compile errors for the | ||||||
|    *                 submitted FBML |    *                 submitted FBML | ||||||
|    */ |    */ | ||||||
|   function profile_setFBML($markup, |   public function profile_setFBML($markup, | ||||||
|                            $uid=null, |                            $uid=null, | ||||||
|                            $profile='', |                            $profile='', | ||||||
|                            $profile_action='', |                            $profile_action='', | ||||||
| @@ -3267,9 +3220,8 @@ function toggleDisplay(id, type) { | |||||||
|     } else { |     } else { | ||||||
|       $get['v'] = '1.0'; |       $get['v'] = '1.0'; | ||||||
|     } |     } | ||||||
|     if (isset($this->use_ssl_resources) && |     if (isset($this->use_ssl_resources)) { | ||||||
|         $this->use_ssl_resources) { |       $post['return_ssl_resources'] = (bool) $this->use_ssl_resources; | ||||||
|       $post['return_ssl_resources'] = true; |  | ||||||
|     } |     } | ||||||
|     return array($get, $post); |     return array($get, $post); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -54,22 +54,11 @@ class FacebooksettingsAction extends FacebookAction | |||||||
|  |  | ||||||
|         $noticesync = $this->boolean('noticesync'); |         $noticesync = $this->boolean('noticesync'); | ||||||
|         $replysync  = $this->boolean('replysync'); |         $replysync  = $this->boolean('replysync'); | ||||||
|         $prefix     = $this->trimmed('prefix'); |  | ||||||
|  |  | ||||||
|         $original = clone($this->flink); |         $original = clone($this->flink); | ||||||
|         $this->flink->set_flags($noticesync, false, $replysync, false); |         $this->flink->set_flags($noticesync, false, $replysync, false); | ||||||
|         $result = $this->flink->update($original); |         $result = $this->flink->update($original); | ||||||
|  |  | ||||||
|         if ($prefix == '' || $prefix == '0') { |  | ||||||
|             // Facebook bug: saving empty strings to prefs now fails |  | ||||||
|             // http://bugs.developers.facebook.com/show_bug.cgi?id=7110 |  | ||||||
|             $trimmed = $prefix . ' '; |  | ||||||
|         } else { |  | ||||||
|             $trimmed = substr($prefix, 0, 128); |  | ||||||
|         } |  | ||||||
|         $this->facebook->api_client->data_setUserPreference(FACEBOOK_NOTICE_PREFIX, |  | ||||||
|             $trimmed); |  | ||||||
|  |  | ||||||
|         if ($result === false) { |         if ($result === false) { | ||||||
|             $this->showForm(_m('There was a problem saving your sync preferences!')); |             $this->showForm(_m('There was a problem saving your sync preferences!')); | ||||||
|         } else { |         } else { | ||||||
| @@ -110,16 +99,6 @@ class FacebooksettingsAction extends FacebookAction | |||||||
|  |  | ||||||
|             $this->elementStart('li'); |             $this->elementStart('li'); | ||||||
|  |  | ||||||
|             $prefix = trim($this->facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX)); |  | ||||||
|  |  | ||||||
|             $this->input('prefix', _m('Prefix'), |  | ||||||
|                          ($prefix) ? $prefix : null, |  | ||||||
|                          _m('A string to prefix notices with.')); |  | ||||||
|  |  | ||||||
|             $this->elementEnd('li'); |  | ||||||
|  |  | ||||||
|             $this->elementStart('li'); |  | ||||||
|  |  | ||||||
|             $this->submit('save', _m('Save')); |             $this->submit('save', _m('Save')); | ||||||
|  |  | ||||||
|             $this->elementEnd('li'); |             $this->elementEnd('li'); | ||||||
|   | |||||||
| @@ -81,101 +81,251 @@ function isFacebookBound($notice, $flink) { | |||||||
| function facebookBroadcastNotice($notice) | function facebookBroadcastNotice($notice) | ||||||
| { | { | ||||||
|     $facebook = getFacebook(); |     $facebook = getFacebook(); | ||||||
|     $flink = Foreign_link::getByUserID($notice->profile_id, FACEBOOK_SERVICE); |     $flink = Foreign_link::getByUserID( | ||||||
|  |         $notice->profile_id, | ||||||
|  |         FACEBOOK_SERVICE | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     if (isFacebookBound($notice, $flink)) { |     if (isFacebookBound($notice, $flink)) { | ||||||
|  |  | ||||||
|         // Okay, we're good to go, update the FB status |         // Okay, we're good to go, update the FB status | ||||||
|  |  | ||||||
|         $status = null; |  | ||||||
|         $fbuid = $flink->foreign_id; |         $fbuid = $flink->foreign_id; | ||||||
|         $user = $flink->getUser(); |         $user = $flink->getUser(); | ||||||
|         $attachments  = $notice->attachments(); |  | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|  |  | ||||||
|             // Get the status 'verb' (prefix) the user has set |             // Check permissions | ||||||
|  |  | ||||||
|             // XXX: Does this call count against our per user FB request limit? |             common_debug( | ||||||
|             // If so we should consider storing verb elsewhere or not storing |                 'FacebookPlugin - checking for publish_stream permission for user ' | ||||||
|  |                 . "$user->nickname ($user->id), Facebook UID: $fbuid" | ||||||
|  |             ); | ||||||
|  |  | ||||||
|             $prefix = trim($facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX, |             // NOTE: $facebook->api_client->users_hasAppPermission('publish_stream', $fbuid) | ||||||
|                                                                          $fbuid)); |             // has been returning bogus results, so we're using FQL to check for | ||||||
|  |             // publish_stream permission now | ||||||
|  |  | ||||||
|             $status = "$prefix $notice->content"; |             $fql = "SELECT publish_stream FROM permissions WHERE uid = $fbuid"; | ||||||
|  |             $result = $facebook->api_client->fql_query($fql); | ||||||
|  |  | ||||||
|             common_debug("FacebookPlugin - checking for publish_stream permission for user $user->id"); |             $canPublish = 0; | ||||||
|  |  | ||||||
|             $can_publish = $facebook->api_client->users_hasAppPermission('publish_stream', |             if (!empty($result)) { | ||||||
|                                                                          $fbuid); |                 $canPublish = $result[0]['publish_stream']; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             common_debug("FacebookPlugin - checking for status_update permission for user $user->id"); |             if ($canPublish == 1) { | ||||||
|  |                 common_debug( | ||||||
|  |                     "FacebookPlugin - $user->nickname ($user->id), Facebook UID: $fbuid " | ||||||
|  |                     . 'has publish_stream permission.' | ||||||
|  |                 ); | ||||||
|  |             } else { | ||||||
|  |                 common_debug( | ||||||
|  |                     "FacebookPlugin - $user->nickname ($user->id), Facebook UID: $fbuid " | ||||||
|  |                     . 'does NOT have publish_stream permission. Facebook ' | ||||||
|  |                     . 'returned: ' . var_export($result, true) | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             $can_update  = $facebook->api_client->users_hasAppPermission('status_update', |             common_debug( | ||||||
|                                                                          $fbuid); |                 'FacebookPlugin - checking for status_update permission for user ' | ||||||
|             if (!empty($attachments) && $can_publish == 1) { |                 . "$user->nickname ($user->id), Facebook UID: $fbuid. " | ||||||
|                 $fbattachment = format_attachments($attachments); |             ); | ||||||
|                 $facebook->api_client->stream_publish($status, $fbattachment, |  | ||||||
|                                                       null, null, $fbuid); |             $canUpdate = $facebook->api_client->users_hasAppPermission( | ||||||
|                 common_log(LOG_INFO, |                 'status_update', | ||||||
|                            "FacebookPlugin - Posted notice $notice->id w/attachment " . |                 $fbuid | ||||||
|                            "to Facebook user's stream (fbuid = $fbuid)."); |             ); | ||||||
|             } elseif ($can_update == 1 || $can_publish == 1) { |  | ||||||
|                 $facebook->api_client->users_setStatus($status, $fbuid, false, true); |             if ($canUpdate == 1) { | ||||||
|                 common_log(LOG_INFO, |                 common_debug( | ||||||
|                            "FacebookPlugin - Posted notice $notice->id to Facebook " . |                     "FacebookPlugin - $user->nickname ($user->id), Facebook UID: $fbuid " | ||||||
|                            "as a status update (fbuid = $fbuid)."); |                     . 'has status_update permission.' | ||||||
|  |                 ); | ||||||
|  |             } else { | ||||||
|  |                 common_debug( | ||||||
|  |                     "FacebookPlugin - $user->nickname ($user->id), Facebook UID: $fbuid " | ||||||
|  |                     .'does NOT have status_update permission. Facebook ' | ||||||
|  |                     . 'returned: ' . var_export($canPublish, true) | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Post to Facebook | ||||||
|  |  | ||||||
|  |             if ($notice->hasAttachments() && $canPublish == 1) { | ||||||
|  |                 publishStream($notice, $user, $fbuid); | ||||||
|  |             } elseif ($canUpdate == 1 || $canPublish == 1) { | ||||||
|  |                 statusUpdate($notice, $user, $fbuid); | ||||||
|             } else { |             } else { | ||||||
|                 $msg = "FacebookPlugin - Not sending notice $notice->id to Facebook " . |                 $msg = "FacebookPlugin - Not sending notice $notice->id to Facebook " . | ||||||
|                   "because user $user->nickname hasn't given the " . |                   "because user $user->nickname has not given the " . | ||||||
|                   'Facebook app \'status_update\' or \'publish_stream\' permission.'; |                   'Facebook app \'status_update\' or \'publish_stream\' permission.'; | ||||||
|                 common_log(LOG_WARNING, $msg); |                 common_log(LOG_WARNING, $msg); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Finally, attempt to update the user's profile box |             // Finally, attempt to update the user's profile box | ||||||
|  |  | ||||||
|             if ($can_publish == 1 || $can_update == 1) { |             if ($canPublish == 1 || $canUpdate == 1) { | ||||||
|                 updateProfileBox($facebook, $flink, $notice); |                 updateProfileBox($facebook, $flink, $notice, $user); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|         } catch (FacebookRestClientException $e) { |         } catch (FacebookRestClientException $e) { | ||||||
|  |             return handleFacebookError($e, $notice, $flink); | ||||||
|             $code = $e->getCode(); |  | ||||||
|  |  | ||||||
|             $msg = "FacebookPlugin - Facebook returned error code $code: " . |  | ||||||
|               $e->getMessage() . ' - ' . |  | ||||||
|               "Unable to update Facebook status (notice $notice->id) " . |  | ||||||
|               "for $user->nickname (user id: $user->id)!"; |  | ||||||
|  |  | ||||||
|             common_log(LOG_WARNING, $msg); |  | ||||||
|  |  | ||||||
|             if ($code == 100 || $code == 200 || $code == 250) { |  | ||||||
|  |  | ||||||
|                 // 100 The account is 'inactive' (probably - this is not well documented) |  | ||||||
|                 // 200 The application does not have permission to operate on the passed in uid parameter. |  | ||||||
|                 // 250 Updating status requires the extended permission status_update or publish_stream. |  | ||||||
|                 // see: http://wiki.developers.facebook.com/index.php/Users.setStatus#Example_Return_XML |  | ||||||
|  |  | ||||||
|                 remove_facebook_app($flink); |  | ||||||
|  |  | ||||||
|         } else { |  | ||||||
|  |  | ||||||
|                 // Try sending again later. |  | ||||||
|  |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return true; |     return true; | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| function updateProfileBox($facebook, $flink, $notice) { | function handleFacebookError($e, $notice, $flink) | ||||||
|     $fbaction = new FacebookAction($output = 'php://output', | { | ||||||
|                                    $indent = null, $facebook, $flink); |     $fbuid  = $flink->foreign_id; | ||||||
|  |     $user   = $flink->getUser(); | ||||||
|  |     $code   = $e->getCode(); | ||||||
|  |     $errmsg = $e->getMessage(); | ||||||
|  |  | ||||||
|  |     // XXX: Check for any others? | ||||||
|  |     switch($code) { | ||||||
|  |      case 100: // Invalid parameter | ||||||
|  |         $msg = "FacebookPlugin - Facebook claims notice %d was posted with an invalid parameter (error code 100):" | ||||||
|  |             . "\"%s\" (Notice details: nickname=%s, user ID=%d, Facebook ID=%d, notice content=\"%s\"). " | ||||||
|  |             . "Removing notice from the Facebook queue for safety."; | ||||||
|  |         common_log( | ||||||
|  |             LOG_ERR, sprintf( | ||||||
|  |                 $msg, | ||||||
|  |                 $notice->id, | ||||||
|  |                 $errmsg, | ||||||
|  |                 $user->nickname, | ||||||
|  |                 $user->id, | ||||||
|  |                 $fbuid, | ||||||
|  |                 $notice->content | ||||||
|  |             ) | ||||||
|  |         ); | ||||||
|  |         return true; | ||||||
|  |         break; | ||||||
|  |      case 200: // Permissions error | ||||||
|  |      case 250: // Updating status requires the extended permission status_update | ||||||
|  |         remove_facebook_app($flink); | ||||||
|  |         return true; // dequeue | ||||||
|  |         break; | ||||||
|  |      case 341: // Feed action request limit reached | ||||||
|  |             $msg = "FacebookPlugin - User %s (User ID=%d, Facebook ID=%d) has exceeded " | ||||||
|  |                    . "his/her limit for posting notices to Facebook today. Dequeuing " | ||||||
|  |                    . "notice %d."; | ||||||
|  |             common_log( | ||||||
|  |                 LOG_INFO, sprintf( | ||||||
|  |                     $msg, | ||||||
|  |                     $user->nickname, | ||||||
|  |                     $user->id, | ||||||
|  |                     $fbuid, | ||||||
|  |                     $notice->id | ||||||
|  |                 ) | ||||||
|  |             ); | ||||||
|  | 	// @fixme: We want to rety at a later time when the throttling has expired | ||||||
|  | 	// instead of just giving up. | ||||||
|  |         return true; | ||||||
|  |         break; | ||||||
|  |      default: | ||||||
|  |         $msg = "FacebookPlugin - Facebook returned an error we don't know how to deal with while trying to " | ||||||
|  |             . "post notice %d. Error code: %d, error message: \"%s\". (Notice details: " | ||||||
|  |             . "nickname=%s, user ID=%d, Facebook ID=%d, notice content=\"%s\"). Removing notice " | ||||||
|  | 	    . "from the Facebook queue for safety."; | ||||||
|  |         common_log( | ||||||
|  |             LOG_ERR, sprintf( | ||||||
|  |                 $msg, | ||||||
|  |                 $notice->id, | ||||||
|  |                 $code, | ||||||
|  |                 $errmsg, | ||||||
|  |                 $user->nickname, | ||||||
|  |                 $user->id, | ||||||
|  |                 $fbuid, | ||||||
|  |                 $notice->content | ||||||
|  |             ) | ||||||
|  |         ); | ||||||
|  |         return true; // dequeue | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function statusUpdate($notice, $user, $fbuid) | ||||||
|  | { | ||||||
|  |     common_debug( | ||||||
|  |         "FacebookPlugin - Attempting to post notice $notice->id " | ||||||
|  |         . "as a status update for $user->nickname ($user->id), " | ||||||
|  |         . "Facebook UID: $fbuid" | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     $facebook = getFacebook(); | ||||||
|  |     $result = $facebook->api_client->users_setStatus( | ||||||
|  |          $notice->content, | ||||||
|  |          $fbuid, | ||||||
|  |          false, | ||||||
|  |          true | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     common_debug('Facebook returned: ' . var_export($result, true)); | ||||||
|  |  | ||||||
|  |     common_log( | ||||||
|  |         LOG_INFO, | ||||||
|  |         "FacebookPlugin - Posted notice $notice->id as a status " | ||||||
|  |         . "update for $user->nickname ($user->id), " | ||||||
|  |         . "Facebook UID: $fbuid" | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function publishStream($notice, $user, $fbuid) | ||||||
|  | { | ||||||
|  |     common_debug( | ||||||
|  |         "FacebookPlugin - Attempting to post notice $notice->id " | ||||||
|  |         . "as stream item with attachment for $user->nickname ($user->id), " | ||||||
|  |         . "Facebook UID: $fbuid" | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     $fbattachment = format_attachments($notice->attachments()); | ||||||
|  |  | ||||||
|  |     $facebook = getFacebook(); | ||||||
|  |     $facebook->api_client->stream_publish( | ||||||
|  |         $notice->content, | ||||||
|  |         $fbattachment, | ||||||
|  |         null, | ||||||
|  |         null, | ||||||
|  |         $fbuid | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     common_log( | ||||||
|  |         LOG_INFO, | ||||||
|  |         "FacebookPlugin - Posted notice $notice->id as a stream " | ||||||
|  |         . "item with attachment for $user->nickname ($user->id), " | ||||||
|  |         . "Facebook UID: $fbuid" | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function updateProfileBox($facebook, $flink, $notice, $user) { | ||||||
|  |  | ||||||
|  |     $facebook = getFacebook(); | ||||||
|  |     $fbaction = new FacebookAction( | ||||||
|  |         $output = 'php://output', | ||||||
|  |         $indent = null, | ||||||
|  |         $facebook, | ||||||
|  |         $flink | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     $fbuid = $flink->foreign_id; | ||||||
|  |  | ||||||
|  |     common_debug( | ||||||
|  |           'FacebookPlugin - Attempting to update profile box with ' | ||||||
|  |           . "content from notice $notice->id for $user->nickname ($user->id), " | ||||||
|  |           . "Facebook UID: $fbuid" | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     $fbaction->updateProfileBox($notice); |     $fbaction->updateProfileBox($notice); | ||||||
|  |  | ||||||
|  |     common_debug( | ||||||
|  |         'FacebookPlugin - finished updating profile box for ' | ||||||
|  |         . "$user->nickname ($user->id) Facebook UID: $fbuid" | ||||||
|  |     ); | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| function format_attachments($attachments) | function format_attachments($attachments) | ||||||
|   | |||||||
| @@ -125,8 +125,8 @@ class MapstractionPlugin extends Plugin | |||||||
|             $action->script('http://tile.cloudmade.com/wml/0.2/web-maps-lite.js'); |             $action->script('http://tile.cloudmade.com/wml/0.2/web-maps-lite.js'); | ||||||
|             break; |             break; | ||||||
|         case 'google': |         case 'google': | ||||||
|             $action->script(sprintf('http://maps.google.com/maps?file=api&v=2&sensor=false&key=%s', |             $action->script(sprintf('http://maps.google.com/maps?file=api&v=2&sensor=false&key=%s', | ||||||
|                                     $this->apikey)); |                                     urlencode($this->apikey))); | ||||||
|             break; |             break; | ||||||
|         case 'microsoft': |         case 'microsoft': | ||||||
|             $action->script('http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6'); |             $action->script('http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6'); | ||||||
| @@ -137,7 +137,7 @@ class MapstractionPlugin extends Plugin | |||||||
|             break; |             break; | ||||||
|         case 'yahoo': |         case 'yahoo': | ||||||
|             $action->script(sprintf('http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=%s', |             $action->script(sprintf('http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=%s', | ||||||
|                                     $this->apikey)); |                                     urlencode($this->apikey))); | ||||||
|             break; |             break; | ||||||
|         case 'geocommons': // don't support this yet |         case 'geocommons': // don't support this yet | ||||||
|         default: |         default: | ||||||
|   | |||||||
| @@ -104,7 +104,7 @@ function showMapstraction(element, notices) { | |||||||
|           pt = new mxn.LatLonPoint(lat, lon); |           pt = new mxn.LatLonPoint(lat, lon); | ||||||
|           mkr = new mxn.Marker(pt); |           mkr = new mxn.Marker(pt); | ||||||
|  |  | ||||||
|           mkr.setIcon(n['user']['profile_image_url']); |           mkr.setIcon(n['user']['profile_image_url'], [24, 24]); | ||||||
|           mkr.setInfoBubble('<a href="'+ n['user']['profile_url'] + '">' + n['user']['screen_name'] + '</a>' + ' ' + n['html'] + |           mkr.setInfoBubble('<a href="'+ n['user']['profile_url'] + '">' + n['user']['screen_name'] + '</a>' + ' ' + n['html'] + | ||||||
|                             '<br/><a href="'+ n['url'] + '">'+ n['created_at'] + '</a>'); |                             '<br/><a href="'+ n['url'] + '">'+ n['created_at'] + '</a>'); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ | |||||||
|  * @category  Plugin |  * @category  Plugin | ||||||
|  * @package   StatusNet |  * @package   StatusNet | ||||||
|  * @author    Evan Prodromou <evan@status.net> |  * @author    Evan Prodromou <evan@status.net> | ||||||
|  * @copyright 2009 StatusNet, Inc. |  * @copyright 2009-2010 StatusNet, Inc. | ||||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 |  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 | ||||||
|  * @link      http://status.net/ |  * @link      http://status.net/ | ||||||
|  */ |  */ | ||||||
| @@ -45,7 +45,19 @@ if (!defined('STATUSNET')) { | |||||||
|  |  | ||||||
| class OpenIDPlugin extends Plugin | class OpenIDPlugin extends Plugin | ||||||
| { | { | ||||||
|     public $openidOnly = false; |     // Plugin parameter: set true to disallow non-OpenID logins | ||||||
|  |     // If set, overrides the setting in database or $config['site']['openidonly'] | ||||||
|  |     public $openidOnly = null; | ||||||
|  |  | ||||||
|  |     function initialize() | ||||||
|  |     { | ||||||
|  |         parent::initialize(); | ||||||
|  |         if ($this->openidOnly !== null) { | ||||||
|  |             global $config; | ||||||
|  |             $config['site']['openidonly'] = (bool)$this->openidOnly; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Add OpenID-related paths to the router table |      * Add OpenID-related paths to the router table | ||||||
| @@ -67,6 +79,7 @@ class OpenIDPlugin extends Plugin | |||||||
|         $m->connect('index.php?action=finishaddopenid', |         $m->connect('index.php?action=finishaddopenid', | ||||||
|                     array('action' => 'finishaddopenid')); |                     array('action' => 'finishaddopenid')); | ||||||
|         $m->connect('main/openidserver', array('action' => 'openidserver')); |         $m->connect('main/openidserver', array('action' => 'openidserver')); | ||||||
|  |         $m->connect('admin/openid', array('action' => 'openidadminpanel')); | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @@ -84,7 +97,7 @@ class OpenIDPlugin extends Plugin | |||||||
|  |  | ||||||
|     function onStartConnectPath(&$path, &$defaults, &$rules, &$result) |     function onStartConnectPath(&$path, &$defaults, &$rules, &$result) | ||||||
|     { |     { | ||||||
|         if ($this->openidOnly) { |         if (common_config('site', 'openidonly')) { | ||||||
|             static $block = array('main/login', |             static $block = array('main/login', | ||||||
|                                   'main/register', |                                   'main/register', | ||||||
|                                   'main/recoverpassword', |                                   'main/recoverpassword', | ||||||
| @@ -108,7 +121,7 @@ class OpenIDPlugin extends Plugin | |||||||
|  |  | ||||||
|     function onArgsInitialize($args) |     function onArgsInitialize($args) | ||||||
|     { |     { | ||||||
|         if ($this->openidOnly) { |         if (common_config('site', 'openidonly')) { | ||||||
|             if (array_key_exists('action', $args)) { |             if (array_key_exists('action', $args)) { | ||||||
|                 $action = trim($args['action']); |                 $action = trim($args['action']); | ||||||
|                 if (in_array($action, array('login', 'register'))) { |                 if (in_array($action, array('login', 'register'))) { | ||||||
| @@ -199,7 +212,7 @@ class OpenIDPlugin extends Plugin | |||||||
|  |  | ||||||
|     function onStartPrimaryNav($action) |     function onStartPrimaryNav($action) | ||||||
|     { |     { | ||||||
|         if ($this->openidOnly && !common_logged_in()) { |         if (common_config('site', 'openidonly') && !common_logged_in()) { | ||||||
|             // TRANS: Tooltip for main menu option "Login" |             // TRANS: Tooltip for main menu option "Login" | ||||||
|             $tooltip = _m('TOOLTIP', 'Login to the site'); |             $tooltip = _m('TOOLTIP', 'Login to the site'); | ||||||
|             // TRANS: Main menu option when not logged in to log in |             // TRANS: Main menu option when not logged in to log in | ||||||
| @@ -241,7 +254,7 @@ class OpenIDPlugin extends Plugin | |||||||
|  |  | ||||||
|     function onStartLoginGroupNav(&$action) |     function onStartLoginGroupNav(&$action) | ||||||
|     { |     { | ||||||
|         if ($this->openidOnly) { |         if (common_config('site', 'openidonly')) { | ||||||
|             $this->showOpenIDLoginTab($action); |             $this->showOpenIDLoginTab($action); | ||||||
|             // Even though we replace this code, we |             // Even though we replace this code, we | ||||||
|             // DON'T run the End* hook, to keep others from |             // DON'T run the End* hook, to keep others from | ||||||
| @@ -297,7 +310,7 @@ class OpenIDPlugin extends Plugin | |||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     function onStartAccountSettingsPasswordMenuItem($menu, &$unused) { |     function onStartAccountSettingsPasswordMenuItem($menu, &$unused) { | ||||||
|         if ($this->openidOnly) { |         if (common_config('site', 'openidonly')) { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         return true; |         return true; | ||||||
| @@ -345,13 +358,19 @@ class OpenIDPlugin extends Plugin | |||||||
|         case 'OpenidsettingsAction': |         case 'OpenidsettingsAction': | ||||||
|         case 'OpenidserverAction': |         case 'OpenidserverAction': | ||||||
|         case 'OpenidtrustAction': |         case 'OpenidtrustAction': | ||||||
|             require_once INSTALLDIR.'/plugins/OpenID/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; |         case 'OpenidadminpanelAction': | ||||||
|  |             require_once dirname(__FILE__) . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; | ||||||
|             return false; |             return false; | ||||||
|         case 'User_openid': |         case 'User_openid': | ||||||
|             require_once INSTALLDIR.'/plugins/OpenID/User_openid.php'; |             require_once dirname(__FILE__) . '/User_openid.php'; | ||||||
|             return false; |             return false; | ||||||
|         case 'User_openid_trustroot': |         case 'User_openid_trustroot': | ||||||
|             require_once INSTALLDIR.'/plugins/OpenID/User_openid_trustroot.php'; |             require_once dirname(__FILE__) . '/User_openid_trustroot.php'; | ||||||
|  |             return false; | ||||||
|  |         case 'Auth_OpenID_TeamsExtension': | ||||||
|  |         case 'Auth_OpenID_TeamsRequest': | ||||||
|  |         case 'Auth_OpenID_TeamsResponse': | ||||||
|  |             require_once dirname(__FILE__) . '/extlib/teams-extension.php'; | ||||||
|             return false; |             return false; | ||||||
|         default: |         default: | ||||||
|             return true; |             return true; | ||||||
| @@ -442,7 +461,7 @@ class OpenIDPlugin extends Plugin | |||||||
|  |  | ||||||
|     function onRedirectToLogin($action, $user) |     function onRedirectToLogin($action, $user) | ||||||
|     { |     { | ||||||
|         if ($this->openidOnly || (!empty($user) && User_openid::hasOpenID($user->id))) { |         if (common_config('site', 'openid_only') || (!empty($user) && User_openid::hasOpenID($user->id))) { | ||||||
|             common_redirect(common_local_url('openidlogin'), 303); |             common_redirect(common_local_url('openidlogin'), 303); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
| @@ -577,6 +596,32 @@ class OpenIDPlugin extends Plugin | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add an OpenID tab to the admin panel | ||||||
|  |      * | ||||||
|  |      * @param Widget $nav Admin panel nav | ||||||
|  |      * | ||||||
|  |      * @return boolean hook value | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     function onEndAdminPanelNav($nav) | ||||||
|  |     { | ||||||
|  |         if (AdminPanelAction::canAdmin('openid')) { | ||||||
|  |  | ||||||
|  |             $action_name = $nav->action->trimmed('action'); | ||||||
|  |  | ||||||
|  |             $nav->out->menuItem( | ||||||
|  |                 common_local_url('openidadminpanel'), | ||||||
|  |                 _m('OpenID'), | ||||||
|  |                 _m('OpenID configuration'), | ||||||
|  |                 $action_name == 'openidadminpanel', | ||||||
|  |                 'nav_openid_admin_panel' | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Add our version information to output |      * Add our version information to output | ||||||
|      * |      * | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								plugins/OpenID/extlib/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								plugins/OpenID/extlib/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | team-extension.php | ||||||
|  |     Support for Launchpad's OpenID Teams extension | ||||||
|  |     Maintainer: Canonical | ||||||
|  |     Source: https://code.edge.launchpad.net/wordpress-teams-integration | ||||||
|  |             r27 2010-04-27 | ||||||
|  |     License: AGPLv3 | ||||||
							
								
								
									
										175
									
								
								plugins/OpenID/extlib/teams-extension.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								plugins/OpenID/extlib/teams-extension.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | |||||||
|  | <?php | ||||||
|  | /* | ||||||
|  |  *  Wordpress Teams plugin | ||||||
|  |  *  Copyright (C) 2009-2010 Canonical Ltd. | ||||||
|  |  * | ||||||
|  |  *  This program is free software: you can redistribute it and/or modify | ||||||
|  |  *  it under the terms of the GNU Affero General Public License as published by | ||||||
|  |  *  the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  *  (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  *  This program is distributed in the hope that it will be useful, | ||||||
|  |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  *  GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  *  You should have received a copy of the GNU Affero General Public License | ||||||
|  |  *  along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Provides an example OpenID extension to query user team/group membership | ||||||
|  |  * | ||||||
|  |  * This code is based on code supplied with the openid library for simple | ||||||
|  |  * registration data. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Require the Message implementation. | ||||||
|  |  */ | ||||||
|  | require_once 'Auth/OpenID/Message.php'; | ||||||
|  | require_once 'Auth/OpenID/Extension.php'; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The team/group extension base class | ||||||
|  |  */ | ||||||
|  | class Auth_OpenID_TeamsExtension extends Auth_OpenID_Extension { | ||||||
|  |   var $ns_uri = 'http://ns.launchpad.net/2007/openid-teams'; | ||||||
|  |   var $ns_alias = 'lp'; | ||||||
|  |   var $request_field = 'query_membership'; | ||||||
|  |   var $response_field = 'is_member'; | ||||||
|  |    | ||||||
|  |   /** | ||||||
|  |    * Get the string arguments that should be added to an OpenID | ||||||
|  |    * message for this extension. | ||||||
|  |    */ | ||||||
|  |   function getExtensionArgs() { | ||||||
|  |     $args = array(); | ||||||
|  |  | ||||||
|  |     if ($this->_teams) { | ||||||
|  |       $args[$this->request_field] = implode(',', $this->_teams); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $args; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Add the arguments from this extension to the provided message. | ||||||
|  |    * | ||||||
|  |    * Returns the message with the extension arguments added. | ||||||
|  |    */ | ||||||
|  |   function toMessage(&$message) { | ||||||
|  |     if ($message->namespaces->addAlias($this->ns_uri, $this->ns_alias) === null) { | ||||||
|  |       if ($message->namespaces->getAlias($this->ns_uri) != $this->ns_alias) { | ||||||
|  |         return null; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $message->updateArgs($this->ns_uri, $this->getExtensionArgs()); | ||||||
|  |     return $message; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   /** | ||||||
|  |    * Extract the team/group namespace URI from the given OpenID message. | ||||||
|  |    * Handles OpenID 1 and 2. | ||||||
|  |    * | ||||||
|  |    * $message: The OpenID message from which to parse team/group data. | ||||||
|  |    * This may be a request or response message. | ||||||
|  |    * | ||||||
|  |    * Returns the sreg namespace URI for the supplied message. | ||||||
|  |    * | ||||||
|  |    * @access private | ||||||
|  |    */ | ||||||
|  |   function _getExtensionNS(&$message) { | ||||||
|  |     $alias = null; | ||||||
|  |     $found_ns_uri = null; | ||||||
|  |  | ||||||
|  |     // See if there exists an alias for the namespace | ||||||
|  |     $alias = $message->namespaces->getAlias($this->ns_uri); | ||||||
|  |      | ||||||
|  |     if ($alias !== null) { | ||||||
|  |       $found_ns_uri = $this->ns_uri; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ($alias === null) { | ||||||
|  |       // There is no alias for this extension, so try to add one. | ||||||
|  |       $found_ns_uri = Auth_OpenID_TYPE_1_0; | ||||||
|  |        | ||||||
|  |       if ($message->namespaces->addAlias($this->ns_uri, $this->ns_alias) === null) { | ||||||
|  |         // An alias for the string 'lp' already exists, but | ||||||
|  |         // it's defined for something other than team/group membership | ||||||
|  |         return null; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return $found_ns_uri; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The team/group extension request class | ||||||
|  |  */ | ||||||
|  | class Auth_OpenID_TeamsRequest extends Auth_OpenID_TeamsExtension { | ||||||
|  |   function __init($teams) { | ||||||
|  |     if (!is_array($teams)) { | ||||||
|  |       if (!empty($teams)) { | ||||||
|  |         $teams = explode(',', $teams); | ||||||
|  |       } else { | ||||||
|  |         $teams = Array(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     $this->_teams = $teams; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   function Auth_OpenID_TeamsRequest($teams) { | ||||||
|  |     $this->__init($teams); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The team/group extension response class | ||||||
|  |  */ | ||||||
|  | class Auth_OpenID_TeamsResponse extends Auth_OpenID_TeamsExtension { | ||||||
|  |   var $_teams = array(); | ||||||
|  |    | ||||||
|  |   function __init(&$resp, $signed_only=true) { | ||||||
|  |     $this->ns_uri = $this->_getExtensionNS($resp->message); | ||||||
|  |      | ||||||
|  |     if ($signed_only) { | ||||||
|  |       $args = $resp->getSignedNS($this->ns_uri); | ||||||
|  |     } else { | ||||||
|  |       $args = $resp->message->getArgs($this->ns_uri); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if ($args === null) { | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // An OpenID 2.0 response will handle the namespaces | ||||||
|  |     if (in_array($this->response_field, array_keys($args)) && !empty($args[$this->response_field])) { | ||||||
|  |       $this->_teams = explode(',', $args[$this->response_field]); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Piggybacking on a 1.x request, however, won't so the field name will | ||||||
|  |     // be different | ||||||
|  |     elseif (in_array($this->ns_alias.'.'.$this->response_field, array_keys($args)) && !empty($args[$this->ns_alias.'.'.$this->response_field])) { | ||||||
|  |       $this->_teams = explode(',', $args[$this->ns_alias.'.'.$this->response_field]); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   function Auth_OpenID_TeamsResponse(&$resp, $signed_only=true) { | ||||||
|  |     $this->__init($resp, $signed_only); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   /** | ||||||
|  |    * Get the array of teams the user is a member of | ||||||
|  |    * | ||||||
|  |    * @return array | ||||||
|  |    */ | ||||||
|  |   function getTeams() { | ||||||
|  |     return $this->_teams; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ?> | ||||||
| @@ -103,6 +103,12 @@ class FinishaddopenidAction extends Action | |||||||
|                 $sreg = $sreg_resp->contents(); |                 $sreg = $sreg_resp->contents(); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             // Launchpad teams extension | ||||||
|  |             if (!oid_check_teams($response)) { | ||||||
|  |                 $this->message(_m('OpenID authentication aborted: you are not allowed to login to this site.')); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             $cur = common_current_user(); |             $cur = common_current_user(); | ||||||
|  |  | ||||||
|             $other = oid_get_user($canonical); |             $other = oid_get_user($canonical); | ||||||
| @@ -126,12 +132,15 @@ class FinishaddopenidAction extends Action | |||||||
|                 $this->message(_m('Error connecting user.')); |                 $this->message(_m('Error connecting user.')); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |             if (Event::handle('StartOpenIDUpdateUser', array($cur, $canonical, &$sreg))) { | ||||||
|                 if ($sreg) { |                 if ($sreg) { | ||||||
|                     if (!oid_update_user($cur, $sreg)) { |                     if (!oid_update_user($cur, $sreg)) { | ||||||
|                         $this->message(_m('Error updating profile')); |                         $this->message(_m('Error updating profile')); | ||||||
|                         return; |                         return; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
|  |             Event::handle('EndOpenIDUpdateUser', array($cur, $canonical, $sreg)); | ||||||
|  |  | ||||||
|             // success! |             // success! | ||||||
|  |  | ||||||
|   | |||||||
| @@ -177,6 +177,12 @@ class FinishopenidloginAction extends Action | |||||||
|                 $sreg = $sreg_resp->contents(); |                 $sreg = $sreg_resp->contents(); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             // Launchpad teams extension | ||||||
|  |             if (!oid_check_teams($response)) { | ||||||
|  |                 $this->message(_m('OpenID authentication aborted: you are not allowed to login to this site.')); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             $user = oid_get_user($canonical); |             $user = oid_get_user($canonical); | ||||||
|  |  | ||||||
|             if ($user) { |             if ($user) { | ||||||
| @@ -280,6 +286,8 @@ class FinishopenidloginAction extends Action | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         Event::handle('StartOpenIDCreateNewUser', array($canonical, &$sreg)); | ||||||
|  |  | ||||||
|         $location = ''; |         $location = ''; | ||||||
|         if (!empty($sreg['country'])) { |         if (!empty($sreg['country'])) { | ||||||
|             if ($sreg['postcode']) { |             if ($sreg['postcode']) { | ||||||
| @@ -319,6 +327,8 @@ class FinishopenidloginAction extends Action | |||||||
|  |  | ||||||
|         $result = oid_link_user($user->id, $canonical, $display); |         $result = oid_link_user($user->id, $canonical, $display); | ||||||
|  |  | ||||||
|  |         Event::handle('EndOpenIDCreateNewUser', array($user, $canonical, $sreg)); | ||||||
|  |  | ||||||
|         oid_set_last($display); |         oid_set_last($display); | ||||||
|         common_set_user($user); |         common_set_user($user); | ||||||
|         common_real_login(true); |         common_real_login(true); | ||||||
| @@ -358,7 +368,11 @@ class FinishopenidloginAction extends Action | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (Event::handle('StartOpenIDUpdateUser', array($user, $canonical, &$sreg))) { | ||||||
|             oid_update_user($user, $sreg); |             oid_update_user($user, $sreg); | ||||||
|  |         } | ||||||
|  |         Event::handle('EndOpenIDUpdateUser', array($user, $canonical, $sreg)); | ||||||
|  |  | ||||||
|         oid_set_last($display); |         oid_set_last($display); | ||||||
|         common_set_user($user); |         common_set_user($user); | ||||||
|         common_real_login(true); |         common_real_login(true); | ||||||
|   | |||||||
| @@ -144,8 +144,10 @@ function oid_authenticate($openid_url, $returnto, $immediate=false) | |||||||
|  |  | ||||||
|     // Handle failure status return values. |     // Handle failure status return values. | ||||||
|     if (!$auth_request) { |     if (!$auth_request) { | ||||||
|  |         common_log(LOG_ERR, __METHOD__ . ": mystery fail contacting $openid_url"); | ||||||
|         return _m('Not a valid OpenID.'); |         return _m('Not a valid OpenID.'); | ||||||
|     } else if (Auth_OpenID::isFailure($auth_request)) { |     } else if (Auth_OpenID::isFailure($auth_request)) { | ||||||
|  |         common_log(LOG_ERR, __METHOD__ . ": OpenID fail to $openid_url: $auth_request->message"); | ||||||
|         return sprintf(_m('OpenID failure: %s'), $auth_request->message); |         return sprintf(_m('OpenID failure: %s'), $auth_request->message); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -164,6 +166,15 @@ function oid_authenticate($openid_url, $returnto, $immediate=false) | |||||||
|         $auth_request->addExtension($sreg_request); |         $auth_request->addExtension($sreg_request); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     $requiredTeam = common_config('openid', 'required_team'); | ||||||
|  |     if ($requiredTeam) { | ||||||
|  |         // LaunchPad OpenID extension | ||||||
|  |         $team_request = new Auth_OpenID_TeamsRequest(array($requiredTeam)); | ||||||
|  |         if ($team_request) { | ||||||
|  |             $auth_request->addExtension($team_request); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     $trust_root = common_root_url(true); |     $trust_root = common_root_url(true); | ||||||
|     $process_url = common_local_url($returnto); |     $process_url = common_local_url($returnto); | ||||||
|  |  | ||||||
| @@ -212,11 +223,14 @@ function _oid_print_instructions() | |||||||
|                       'OpenID provider.')); |                       'OpenID provider.')); | ||||||
| } | } | ||||||
|  |  | ||||||
| # update a user from sreg parameters | /** | ||||||
|  |  * Update a user from sreg parameters | ||||||
| function oid_update_user(&$user, &$sreg) |  * @param User $user | ||||||
|  |  * @param array $sreg fields from OpenID sreg response | ||||||
|  |  * @access private | ||||||
|  |  */ | ||||||
|  | function oid_update_user($user, $sreg) | ||||||
| { | { | ||||||
|  |  | ||||||
|     $profile = $user->getProfile(); |     $profile = $user->getProfile(); | ||||||
|  |  | ||||||
|     $orig_profile = clone($profile); |     $orig_profile = clone($profile); | ||||||
| @@ -286,6 +300,33 @@ function oid_assert_allowed($url) | |||||||
|     return; |     return; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Check the teams available in the given OpenID response | ||||||
|  |  * Using Launchpad's OpenID teams extension | ||||||
|  |  * | ||||||
|  |  * @return boolean whether this user is acceptable | ||||||
|  |  */ | ||||||
|  | function oid_check_teams($response) | ||||||
|  | { | ||||||
|  |     $requiredTeam = common_config('openid', 'required_team'); | ||||||
|  |     if ($requiredTeam) { | ||||||
|  |         $team_resp = new Auth_OpenID_TeamsResponse($response); | ||||||
|  |         if ($team_resp) { | ||||||
|  |             $teams = $team_resp->getTeams(); | ||||||
|  |         } else { | ||||||
|  |             $teams = array(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $match = in_array($requiredTeam, $teams); | ||||||
|  |         $is = $match ? 'is' : 'is not'; | ||||||
|  |         common_log(LOG_DEBUG, "Remote user $is in required team $requiredTeam: [" . implode(', ', $teams) . "]"); | ||||||
|  |  | ||||||
|  |         return $match; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
| class AutosubmitAction extends Action | class AutosubmitAction extends Action | ||||||
| { | { | ||||||
|     var $form_html = null; |     var $form_html = null; | ||||||
|   | |||||||
							
								
								
									
										280
									
								
								plugins/OpenID/openidadminpanel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								plugins/OpenID/openidadminpanel.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,280 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * StatusNet, the distributed open-source microblogging tool | ||||||
|  |  * | ||||||
|  |  * OpenID bridge administration panel | ||||||
|  |  * | ||||||
|  |  * PHP version 5 | ||||||
|  |  * | ||||||
|  |  * LICENCE: This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  * | ||||||
|  |  * @category  Settings | ||||||
|  |  * @package   StatusNet | ||||||
|  |  * @author    Zach Copley <zach@status.net> | ||||||
|  |  * @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 OpenID settings | ||||||
|  |  * | ||||||
|  |  * @category Admin | ||||||
|  |  * @package  StatusNet | ||||||
|  |  * @author   Zach Copley <zach@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/ | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class OpenidadminpanelAction extends AdminPanelAction | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Returns the page title | ||||||
|  |      * | ||||||
|  |      * @return string page title | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     function title() | ||||||
|  |     { | ||||||
|  |         return _m('OpenID'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Instructions for using this form. | ||||||
|  |      * | ||||||
|  |      * @return string instructions | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     function getInstructions() | ||||||
|  |     { | ||||||
|  |         return _m('OpenID settings'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Show the OpenID admin panel form | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     function showForm() | ||||||
|  |     { | ||||||
|  |         $form = new OpenIDAdminPanelForm($this); | ||||||
|  |         $form->show(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Save settings from the form | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     function saveSettings() | ||||||
|  |     { | ||||||
|  |         static $settings = array( | ||||||
|  |             'openid' => array('trusted_provider', 'required_team') | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         static $booleans = array( | ||||||
|  |             'openid' => array('append_username'), | ||||||
|  |             'site' => array('openidonly') | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $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['openid']['trusted_provider']) > 255) { | ||||||
|  |             $this->clientError( | ||||||
|  |                 _m("Invalid provider URL. Max length is 255 characters.") | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (mb_strlen($values['openid']['required_team']) > 255) { | ||||||
|  |             $this->clientError( | ||||||
|  |                 _m("Invalid team name. Max length is 255 characters.") | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class OpenIDAdminPanelForm extends AdminForm | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * ID of the form | ||||||
|  |      * | ||||||
|  |      * @return int ID of the form | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     function id() | ||||||
|  |     { | ||||||
|  |         return 'openidadminpanel'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 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('openidadminpanel'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Data elements of the form | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      * | ||||||
|  |      * @todo Some of the options could prevent users from logging in again. | ||||||
|  |      *       Make sure that the acting administrator has a valid OpenID matching, | ||||||
|  |      *       or more carefully warn folks. | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     function formData() | ||||||
|  |     { | ||||||
|  |         $this->out->elementStart( | ||||||
|  |             'fieldset', | ||||||
|  |             array('id' => 'settings_openid') | ||||||
|  |         ); | ||||||
|  |         $this->out->element('legend', null, _m('Trusted provider')); | ||||||
|  |         $this->out->element('p', 'form_guide', | ||||||
|  |             _m('By default, users are allowed to authenticate with any OpenID provider. ' . | ||||||
|  |                'If you are using your own OpenID service for shared sign-in, ' . | ||||||
|  |                'you can restrict access to only your own users here.')); | ||||||
|  |         $this->out->elementStart('ul', 'form_data'); | ||||||
|  |  | ||||||
|  |         $this->li(); | ||||||
|  |         $this->input( | ||||||
|  |             'trusted_provider', | ||||||
|  |             _m('Provider URL'), | ||||||
|  |             _m('All OpenID logins will be sent to this URL; other providers may not be used.'), | ||||||
|  |             'openid' | ||||||
|  |         ); | ||||||
|  |         $this->unli(); | ||||||
|  |  | ||||||
|  |         $this->li(); | ||||||
|  |         $this->out->checkbox( | ||||||
|  |             'append_username', _m('Append a username to base URL'), | ||||||
|  |             (bool) $this->value('append_username', 'openid'), | ||||||
|  |             _m('Login form will show the base URL and prompt for a username to add at the end. Use when OpenID provider URL should be the profile page for individual users.'), | ||||||
|  |             'true' | ||||||
|  |         ); | ||||||
|  |         $this->unli(); | ||||||
|  |  | ||||||
|  |         $this->li(); | ||||||
|  |         $this->input( | ||||||
|  |             'required_team', | ||||||
|  |              _m('Required team'), | ||||||
|  |             _m('Only allow logins from users in the given team (Launchpad extension).'), | ||||||
|  |             'openid' | ||||||
|  |         ); | ||||||
|  |         $this->unli(); | ||||||
|  |  | ||||||
|  |         $this->out->elementEnd('ul'); | ||||||
|  |         $this->out->elementEnd('fieldset'); | ||||||
|  |  | ||||||
|  |         $this->out->elementStart( | ||||||
|  |             'fieldset', | ||||||
|  |             array('id' => 'settings_openid-options') | ||||||
|  |         ); | ||||||
|  |         $this->out->element('legend', null, _m('Options')); | ||||||
|  |  | ||||||
|  |         $this->out->elementStart('ul', 'form_data'); | ||||||
|  |  | ||||||
|  |         $this->li(); | ||||||
|  |  | ||||||
|  |         $this->out->checkbox( | ||||||
|  |             'openidonly', _m('Enable OpenID-only mode'), | ||||||
|  |             (bool) $this->value('openidonly', 'site'), | ||||||
|  |             _m('Require all users to login via OpenID. WARNING: disables password authentication for all users!'), | ||||||
|  |             '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 OpenID settings')); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -29,7 +29,15 @@ class OpenidloginAction extends Action | |||||||
|         if (common_is_real_login()) { |         if (common_is_real_login()) { | ||||||
|             $this->clientError(_m('Already logged in.')); |             $this->clientError(_m('Already logged in.')); | ||||||
|         } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { |         } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { | ||||||
|  |             $provider = common_config('openid', 'trusted_provider'); | ||||||
|  |             if ($provider) { | ||||||
|  |                 $openid_url = $provider; | ||||||
|  |                 if (common_config('openid', 'append_username')) { | ||||||
|  |                     $openid_url .= $this->trimmed('openid_username'); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|                 $openid_url = $this->trimmed('openid_url'); |                 $openid_url = $this->trimmed('openid_url'); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             oid_assert_allowed($openid_url); |             oid_assert_allowed($openid_url); | ||||||
|  |  | ||||||
| @@ -89,8 +97,16 @@ class OpenidloginAction extends Action | |||||||
|     function showScripts() |     function showScripts() | ||||||
|     { |     { | ||||||
|         parent::showScripts(); |         parent::showScripts(); | ||||||
|  |         if (common_config('openid', 'trusted_provider')) { | ||||||
|  |             if (common_config('openid', 'append_username')) { | ||||||
|  |                 $this->autofocus('openid_username'); | ||||||
|  |             } else { | ||||||
|  |                 $this->autofocus('rememberme'); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|             $this->autofocus('openid_url'); |             $this->autofocus('openid_url'); | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     function title() |     function title() | ||||||
|     { |     { | ||||||
| @@ -116,9 +132,25 @@ class OpenidloginAction extends Action | |||||||
|  |  | ||||||
|         $this->elementStart('ul', 'form_data'); |         $this->elementStart('ul', 'form_data'); | ||||||
|         $this->elementStart('li'); |         $this->elementStart('li'); | ||||||
|  |         $provider = common_config('openid', 'trusted_provider'); | ||||||
|  |         $appendUsername = common_config('openid', 'append_username'); | ||||||
|  |         if ($provider) { | ||||||
|  |             $this->element('label', array(), _m('OpenID provider')); | ||||||
|  |             $this->element('span', array(), $provider); | ||||||
|  |             if ($appendUsername) { | ||||||
|  |                 $this->element('input', array('id' => 'openid_username', | ||||||
|  |                                               'name' => 'openid_username', | ||||||
|  |                                               'style' => 'float: none')); | ||||||
|  |             } | ||||||
|  |             $this->element('p', 'form_guide', | ||||||
|  |                            ($appendUsername ? _m('Enter your username.') . ' ' : '') . | ||||||
|  |                            _m('You will be sent to the provider\'s site for authentication.')); | ||||||
|  |             $this->hidden('openid_url', $provider); | ||||||
|  |         } else { | ||||||
|             $this->input('openid_url', _m('OpenID URL'), |             $this->input('openid_url', _m('OpenID URL'), | ||||||
|                          $this->openid_url, |                          $this->openid_url, | ||||||
|                          _m('Your OpenID URL')); |                          _m('Your OpenID URL')); | ||||||
|  |         } | ||||||
|         $this->elementEnd('li'); |         $this->elementEnd('li'); | ||||||
|         $this->elementStart('li', array('id' => 'settings_rememberme')); |         $this->elementStart('li', array('id' => 'settings_rememberme')); | ||||||
|         $this->checkbox('rememberme', _m('Remember me'), false, |         $this->checkbox('rememberme', _m('Remember me'), false, | ||||||
|   | |||||||
| @@ -90,12 +90,14 @@ class OpenidsettingsAction extends AccountSettingsAction | |||||||
|     { |     { | ||||||
|         $user = common_current_user(); |         $user = common_current_user(); | ||||||
|  |  | ||||||
|  |         if (!common_config('openid', 'trusted_provider')) { | ||||||
|             $this->elementStart('form', array('method' => 'post', |             $this->elementStart('form', array('method' => 'post', | ||||||
|                                               'id' => 'form_settings_openid_add', |                                               'id' => 'form_settings_openid_add', | ||||||
|                                               'class' => 'form_settings', |                                               'class' => 'form_settings', | ||||||
|                                               'action' => |                                               'action' => | ||||||
|                                               common_local_url('openidsettings'))); |                                               common_local_url('openidsettings'))); | ||||||
|             $this->elementStart('fieldset', array('id' => 'settings_openid_add')); |             $this->elementStart('fieldset', array('id' => 'settings_openid_add')); | ||||||
|  |      | ||||||
|             $this->element('legend', null, _m('Add OpenID')); |             $this->element('legend', null, _m('Add OpenID')); | ||||||
|             $this->hidden('token', common_session_token()); |             $this->hidden('token', common_session_token()); | ||||||
|             $this->element('p', 'form_guide', |             $this->element('p', 'form_guide', | ||||||
| @@ -117,7 +119,7 @@ class OpenidsettingsAction extends AccountSettingsAction | |||||||
|                                           'value' => _m('Add'))); |                                           'value' => _m('Add'))); | ||||||
|             $this->elementEnd('fieldset'); |             $this->elementEnd('fieldset'); | ||||||
|             $this->elementEnd('form'); |             $this->elementEnd('form'); | ||||||
|  |         } | ||||||
|         $oid = new User_openid(); |         $oid = new User_openid(); | ||||||
|  |  | ||||||
|         $oid->user_id = $user->id; |         $oid->user_id = $user->id; | ||||||
| @@ -234,11 +236,15 @@ class OpenidsettingsAction extends AccountSettingsAction | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if ($this->arg('add')) { |         if ($this->arg('add')) { | ||||||
|  |             if (common_config('openid', 'trusted_provider')) { | ||||||
|  |                 $this->showForm(_m("Can't add new providers.")); | ||||||
|  |             } else { | ||||||
|                 $result = oid_authenticate($this->trimmed('openid_url'), |                 $result = oid_authenticate($this->trimmed('openid_url'), | ||||||
|                                            'finishaddopenid'); |                                            'finishaddopenid'); | ||||||
|                 if (is_string($result)) { // error message |                 if (is_string($result)) { // error message | ||||||
|                     $this->showForm($result); |                     $this->showForm($result); | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
|         } else if ($this->arg('remove')) { |         } else if ($this->arg('remove')) { | ||||||
|             $this->removeOpenid(); |             $this->removeOpenid(); | ||||||
|         } else if($this->arg('remove_trustroots')) { |         } else if($this->arg('remove_trustroots')) { | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								plugins/WikiHowProfile/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								plugins/WikiHowProfile/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | This is an additional plugin which piggybacks on OpenID authentication to pull | ||||||
|  | profile information from WikiHow user pages when creating or updating accounts. | ||||||
|  |  | ||||||
|  | WikiHow runs a customized MediaWiki setup, with locally-built extensions to add | ||||||
|  | profile features such as an avatar. As this additional info isn't yet exposed | ||||||
|  | through OpenID, we need to pull it separately. | ||||||
							
								
								
									
										196
									
								
								plugins/WikiHowProfile/WikiHowProfilePlugin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								plugins/WikiHowProfile/WikiHowProfilePlugin.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,196 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * StatusNet - the distributed open-source microblogging tool | ||||||
|  |  * Copyright (C) 2010, StatusNet, Inc. | ||||||
|  |  * | ||||||
|  |  * Plugin to pull WikiHow-style user avatars at OpenID setup time. | ||||||
|  |  * These are not currently exposed via OpenID. | ||||||
|  |  * | ||||||
|  |  * PHP version 5 | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  * | ||||||
|  |  * @category  Plugins | ||||||
|  |  * @package   StatusNet | ||||||
|  |  * @author    Brion Vibber <brion@status.net> | ||||||
|  |  * @copyright 2010 StatusNet, Inc. | ||||||
|  |  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||||
|  |  * @link      http://status.net/ | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | if (!defined('STATUSNET')) { | ||||||
|  |     // This check helps protect against security problems; | ||||||
|  |     // your code file can't be executed directly from the web. | ||||||
|  |     exit(1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Sample plugin main class | ||||||
|  |  * | ||||||
|  |  * Each plugin requires a main class to interact with the StatusNet system. | ||||||
|  |  * | ||||||
|  |  * @category  Plugins | ||||||
|  |  * @package   WikiHowProfilePlugin | ||||||
|  |  * @author    Brion Vibber <brion@status.net> | ||||||
|  |  * @copyright 2010 StatusNet, Inc. | ||||||
|  |  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||||
|  |  * @link      http://status.net/ | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class WikiHowProfilePlugin extends Plugin | ||||||
|  | { | ||||||
|  |     function onPluginVersion(&$versions) | ||||||
|  |     { | ||||||
|  |         $versions[] = array('name' => 'WikiHow avatar fetcher', | ||||||
|  |                             'version' => STATUSNET_VERSION, | ||||||
|  |                             'author' => 'Brion Vibber', | ||||||
|  |                             'homepage' => 'http://status.net/wiki/Plugin:Sample', | ||||||
|  |                             'rawdescription' => | ||||||
|  |                             _m('Fetches avatar and other profile info for WikiHow users when setting up an account via OpenID.')); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Hook for OpenID user creation; we'll pull the avatar. | ||||||
|  |      * | ||||||
|  |      * @param User $user | ||||||
|  |      * @param string $canonical OpenID provider URL | ||||||
|  |      * @param array $sreg query data from provider | ||||||
|  |      */ | ||||||
|  |     function onEndOpenIDCreateNewUser($user, $canonical, $sreg) | ||||||
|  |     { | ||||||
|  |         $this->updateProfile($user, $canonical); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Hook for OpenID profile updating; we'll pull the avatar. | ||||||
|  |      * | ||||||
|  |      * @param User $user | ||||||
|  |      * @param string $canonical OpenID provider URL (wiki profile page) | ||||||
|  |      * @param array $sreg query data from provider | ||||||
|  |      */ | ||||||
|  |     function onEndOpenIDUpdateUser($user, $canonical, $sreg) | ||||||
|  |     { | ||||||
|  |         $this->updateProfile($user, $canonical); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param User $user | ||||||
|  |      * @param string $canonical OpenID provider URL (wiki profile page) | ||||||
|  |      */ | ||||||
|  |     private function updateProfile($user, $canonical) | ||||||
|  |     { | ||||||
|  |         $prefix = 'http://www.wikihow.com/User:'; | ||||||
|  |  | ||||||
|  |         if (substr($canonical, 0, strlen($prefix)) == $prefix) { | ||||||
|  |             // Yes, it's a WikiHow user! | ||||||
|  |             $profile = $this->fetchProfile($canonical); | ||||||
|  |  | ||||||
|  |             if (!empty($profile['avatar'])) { | ||||||
|  |                 $this->saveAvatar($user, $profile['avatar']); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Given a user's WikiHow profile URL, find their avatar. | ||||||
|  |      *  | ||||||
|  |      * @param string $profileUrl user page on the wiki | ||||||
|  |      *  | ||||||
|  |      * @return array of data; possible members: | ||||||
|  |      *               'avatar' => full URL to avatar image | ||||||
|  |      *  | ||||||
|  |      * @throws Exception on various low-level failures | ||||||
|  |      *  | ||||||
|  |      * @todo pull location, web site, and about sections -- they aren't currently marked up cleanly. | ||||||
|  |      */ | ||||||
|  |     private function fetchProfile($profileUrl) | ||||||
|  |     { | ||||||
|  |         $client = HTTPClient::start(); | ||||||
|  |         $response = $client->get($profileUrl); | ||||||
|  |         if (!$response->isOk()) { | ||||||
|  |             throw new Exception("WikiHow profile page fetch failed."); | ||||||
|  |             // HTTP error response already logged. | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Suppress warnings during HTML parsing; non-well-formed bits will | ||||||
|  |         // spew horrible warning everywhere even though it works fine. | ||||||
|  |         $old = error_reporting(); | ||||||
|  |         error_reporting($old & ~E_WARNING); | ||||||
|  |  | ||||||
|  |         $dom = new DOMDocument(); | ||||||
|  |         $ok = $dom->loadHTML($response->getBody()); | ||||||
|  |  | ||||||
|  |         error_reporting($old); | ||||||
|  |  | ||||||
|  |         if (!$ok) { | ||||||
|  |             throw new Exception("HTML parse failure during check for WikiHow avatar."); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $data = array(); | ||||||
|  |  | ||||||
|  |         $avatar = $dom->getElementById('avatarULimg'); | ||||||
|  |         if ($avatar) { | ||||||
|  |             $src = $avatar->getAttribute('src'); | ||||||
|  |  | ||||||
|  |             $base = new Net_URL2($profileUrl); | ||||||
|  |             $absolute = $base->resolve($src); | ||||||
|  |             $avatarUrl = strval($absolute); | ||||||
|  |  | ||||||
|  |             common_log(LOG_DEBUG, "WikiHow avatar found for $profileUrl - $avatarUrl"); | ||||||
|  |             $data['avatar'] = $avatarUrl; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Actually save the avatar we found locally. | ||||||
|  |      * | ||||||
|  |      * @param User $user | ||||||
|  |      * @param string $url to avatar URL | ||||||
|  |      * @todo merge wrapper funcs for this into common place for 1.0 core | ||||||
|  |      */ | ||||||
|  |     private function saveAvatar($user, $url) | ||||||
|  |     { | ||||||
|  |         if (!common_valid_http_url($url)) { | ||||||
|  |             throw new ServerException(sprintf(_m("Invalid avatar URL %s"), $url)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // @fixme this should be better encapsulated | ||||||
|  |         // ripped from OStatus via oauthstore.php (for old OMB client) | ||||||
|  |         $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); | ||||||
|  |         if (!copy($url, $temp_filename)) { | ||||||
|  |             throw new ServerException(sprintf(_m("Unable to fetch avatar from %s"), $url)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $profile = $user->getProfile(); | ||||||
|  |         $id = $profile->id; | ||||||
|  |         // @fixme should we be using different ids? | ||||||
|  |  | ||||||
|  |         $imagefile = new ImageFile($id, $temp_filename); | ||||||
|  |         $filename = Avatar::filename($id, | ||||||
|  |                                      image_type_to_extension($imagefile->type), | ||||||
|  |                                      null, | ||||||
|  |                                      common_timestamp()); | ||||||
|  |         rename($temp_filename, Avatar::path($filename)); | ||||||
|  |         $profile->setOriginal($filename); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user