forked from GNUsocial/gnu-social
Merge branch 'master' of gitorious.org:statusnet/mainline
This commit is contained in:
commit
a5de215267
@ -57,7 +57,7 @@ require_once INSTALLDIR . '/lib/apiauth.php';
|
|||||||
|
|
||||||
class ApiStatusesDestroyAction extends ApiAuthAction
|
class ApiStatusesDestroyAction extends ApiAuthAction
|
||||||
{
|
{
|
||||||
var $status = null;
|
var $status = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take arguments for running
|
* Take arguments for running
|
||||||
@ -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));
|
||||||
$this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email));
|
if ($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,15 +97,20 @@ 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.
|
||||||
|
|
||||||
$deleted = new Deleted_notice();
|
// @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->id = $this->id;
|
$deleted->id = $this->id;
|
||||||
$deleted->profile_id = $this->profile_id;
|
$deleted->profile_id = $this->profile_id;
|
||||||
$deleted->uri = $this->uri;
|
$deleted->uri = $this->uri;
|
||||||
$deleted->created = $this->created;
|
$deleted->created = $this->created;
|
||||||
$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/');
|
||||||
$cut2 = strpos($path, '/', $cut);
|
if ($plug === false) {
|
||||||
if ($cut && $cut2) {
|
// We're not in a plugin; return default domain.
|
||||||
$cached[$path] = substr($path, $cut, $cut2 - $cut);
|
return 'statusnet';
|
||||||
} else {
|
} else {
|
||||||
return null;
|
$cut = $plug + 9;
|
||||||
|
$cut2 = strpos($path, '/', $cut);
|
||||||
|
if ($cut2) {
|
||||||
|
$cached[$path] = substr($path, $cut, $cut2 - $cut);
|
||||||
|
} else {
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,11 +38,11 @@ editor or write them down.
|
|||||||
|
|
||||||
In Facebook's application editor, specify the following URLs for your app:
|
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/
|
||||||
|
|
||||||
*** ATTENTION ***
|
*** ATTENTION ***
|
||||||
These URLs have changed slightly since StatusNet version 0.8.1,
|
These URLs have changed slightly since StatusNet version 0.8.1,
|
||||||
|
@ -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 =
|
||||||
// if no Facebook parameters were found in the GET or POST variables,
|
$this->get_valid_fb_params($_COOKIE, null, $this->api_key)) {
|
||||||
// then fall back to cookies, which may have cached user information
|
// if no Facebook parameters were found in the GET or POST variables,
|
||||||
// Cookies are also used to receive session data via the Javascript API
|
// then fall back to cookies, which may have cached user information
|
||||||
else if ($cookies =
|
// Cookies are also used to receive session data via the Javascript API
|
||||||
$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 ($sreg) {
|
if (Event::handle('StartOpenIDUpdateUser', array($cur, $canonical, &$sreg))) {
|
||||||
if (!oid_update_user($cur, $sreg)) {
|
if ($sreg) {
|
||||||
$this->message(_m('Error updating profile'));
|
if (!oid_update_user($cur, $sreg)) {
|
||||||
return;
|
$this->message(_m('Error updating profile'));
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
oid_update_user($user, $sreg);
|
if (Event::handle('StartOpenIDUpdateUser', array($user, $canonical, &$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') {
|
||||||
$openid_url = $this->trimmed('openid_url');
|
$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');
|
||||||
|
}
|
||||||
|
|
||||||
oid_assert_allowed($openid_url);
|
oid_assert_allowed($openid_url);
|
||||||
|
|
||||||
@ -89,7 +97,15 @@ class OpenidloginAction extends Action
|
|||||||
function showScripts()
|
function showScripts()
|
||||||
{
|
{
|
||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
$this->autofocus('openid_url');
|
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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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');
|
||||||
$this->input('openid_url', _m('OpenID URL'),
|
$provider = common_config('openid', 'trusted_provider');
|
||||||
$this->openid_url,
|
$appendUsername = common_config('openid', 'append_username');
|
||||||
_m('Your OpenID URL'));
|
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->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,34 +90,36 @@ class OpenidsettingsAction extends AccountSettingsAction
|
|||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
$this->elementStart('form', array('method' => 'post',
|
if (!common_config('openid', 'trusted_provider')) {
|
||||||
'id' => 'form_settings_openid_add',
|
$this->elementStart('form', array('method' => 'post',
|
||||||
'class' => 'form_settings',
|
'id' => 'form_settings_openid_add',
|
||||||
'action' =>
|
'class' => 'form_settings',
|
||||||
common_local_url('openidsettings')));
|
'action' =>
|
||||||
$this->elementStart('fieldset', array('id' => 'settings_openid_add'));
|
common_local_url('openidsettings')));
|
||||||
$this->element('legend', null, _m('Add OpenID'));
|
$this->elementStart('fieldset', array('id' => 'settings_openid_add'));
|
||||||
$this->hidden('token', common_session_token());
|
|
||||||
$this->element('p', 'form_guide',
|
$this->element('legend', null, _m('Add OpenID'));
|
||||||
_m('If you want to add an OpenID to your account, ' .
|
$this->hidden('token', common_session_token());
|
||||||
'enter it in the box below and click "Add".'));
|
$this->element('p', 'form_guide',
|
||||||
$this->elementStart('ul', 'form_data');
|
_m('If you want to add an OpenID to your account, ' .
|
||||||
$this->elementStart('li');
|
'enter it in the box below and click "Add".'));
|
||||||
$this->element('label', array('for' => 'openid_url'),
|
$this->elementStart('ul', 'form_data');
|
||||||
_m('OpenID URL'));
|
$this->elementStart('li');
|
||||||
$this->element('input', array('name' => 'openid_url',
|
$this->element('label', array('for' => 'openid_url'),
|
||||||
'type' => 'text',
|
_m('OpenID URL'));
|
||||||
'id' => 'openid_url'));
|
$this->element('input', array('name' => 'openid_url',
|
||||||
$this->elementEnd('li');
|
'type' => 'text',
|
||||||
$this->elementEnd('ul');
|
'id' => 'openid_url'));
|
||||||
$this->element('input', array('type' => 'submit',
|
$this->elementEnd('li');
|
||||||
'id' => 'settings_openid_add_action-submit',
|
$this->elementEnd('ul');
|
||||||
'name' => 'add',
|
$this->element('input', array('type' => 'submit',
|
||||||
'class' => 'submit',
|
'id' => 'settings_openid_add_action-submit',
|
||||||
'value' => _m('Add')));
|
'name' => 'add',
|
||||||
$this->elementEnd('fieldset');
|
'class' => 'submit',
|
||||||
$this->elementEnd('form');
|
'value' => _m('Add')));
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
$this->elementEnd('form');
|
||||||
|
}
|
||||||
$oid = new User_openid();
|
$oid = new User_openid();
|
||||||
|
|
||||||
$oid->user_id = $user->id;
|
$oid->user_id = $user->id;
|
||||||
@ -234,10 +236,14 @@ class OpenidsettingsAction extends AccountSettingsAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->arg('add')) {
|
if ($this->arg('add')) {
|
||||||
$result = oid_authenticate($this->trimmed('openid_url'),
|
if (common_config('openid', 'trusted_provider')) {
|
||||||
'finishaddopenid');
|
$this->showForm(_m("Can't add new providers."));
|
||||||
if (is_string($result)) { // error message
|
} else {
|
||||||
$this->showForm($result);
|
$result = oid_authenticate($this->trimmed('openid_url'),
|
||||||
|
'finishaddopenid');
|
||||||
|
if (is_string($result)) { // error message
|
||||||
|
$this->showForm($result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if ($this->arg('remove')) {
|
} else if ($this->arg('remove')) {
|
||||||
$this->removeOpenid();
|
$this->removeOpenid();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user