From d1cc159a0423c84a74ba416af2878db6186899a8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 21 Aug 2009 08:23:52 -0400 Subject: facebook action correctly checks max notice length --- lib/facebookaction.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'lib/facebookaction.php') diff --git a/lib/facebookaction.php b/lib/facebookaction.php index 5be2f2fe6..08141177a 100644 --- a/lib/facebookaction.php +++ b/lib/facebookaction.php @@ -35,7 +35,6 @@ if (!defined('LACONICA')) require_once INSTALLDIR.'/lib/facebookutil.php'; require_once INSTALLDIR.'/lib/noticeform.php'; - class FacebookAction extends Action { @@ -201,7 +200,6 @@ class FacebookAction extends Action } - // Make this into a widget later function showLocalNav() { @@ -261,7 +259,6 @@ class FacebookAction extends Action $this->endHTML(); } - function showInstructions() { @@ -287,7 +284,6 @@ class FacebookAction extends Action $this->elementEnd('div'); } - function showLoginForm($msg = null) { @@ -332,7 +328,6 @@ class FacebookAction extends Action } - function updateProfileBox($notice) { @@ -414,7 +409,6 @@ class FacebookAction extends Action $this->xw->openURI('php://output'); } - /** * Generate pagination links * @@ -473,8 +467,9 @@ class FacebookAction extends Action } else { $content_shortened = common_shorten_links($content); - if (mb_strlen($content_shortened) > 140) { - $this->showPage(_('That\'s too long. Max notice size is 140 chars.')); + if (Notice::contentTooLong($content_shortened)) { + $this->showPage(sprintf(_('That\'s too long. Max notice size is %d chars.'), + Notice::maxContent())); return; } } -- cgit v1.2.3-54-g00ecf From 59beff6b46fb7693812558eaf728ca3709e4b066 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 21 Aug 2009 16:45:42 -0400 Subject: Revert "Added configuration option to only allow OpenID logins." This reverts commit 14b46e2183f10359cc53d597913a878f53e23719. This functionality will need to be rewritten to work with the new OpenIDPlugin. Conflicts: index.php lib/logingroupnav.php --- README | 2 -- actions/all.php | 4 +--- actions/confirmaddress.php | 6 +----- actions/favorited.php | 3 +-- actions/groupsearch.php | 3 +-- actions/invite.php | 2 +- actions/noticesearch.php | 4 +--- actions/public.php | 11 ++++------- actions/publictagcloud.php | 3 +-- actions/remotesubscribe.php | 12 +++++------- actions/replies.php | 4 +--- actions/showfavorites.php | 4 +--- actions/showgroup.php | 5 ++--- actions/showstream.php | 10 +++------- actions/subscribers.php | 4 +--- actions/userauthorization.php | 6 +----- config.php.sample | 2 -- lib/action.php | 15 +++++---------- lib/common.php | 1 - lib/facebookaction.php | 9 ++------- 20 files changed, 32 insertions(+), 78 deletions(-) (limited to 'lib/facebookaction.php') diff --git a/README b/README index 53ed0a0fe..ab25b9f3f 100644 --- a/README +++ b/README @@ -968,8 +968,6 @@ closed: If set to 'true', will disallow registration on your site. the service, *then* set this variable to 'true'. inviteonly: If set to 'true', will only allow registration if the user was invited by an existing user. -openidonly: If set to 'true', will only allow registrations and logins - through OpenID. private: If set to 'true', anonymous users will be redirected to the 'login' page. Also, API methods that normally require no authentication will require it. Note that this does not turn diff --git a/actions/all.php b/actions/all.php index 38aee65b6..82394922b 100644 --- a/actions/all.php +++ b/actions/all.php @@ -108,9 +108,7 @@ class AllAction extends ProfileAction } } else { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin', - $this->user->nickname); + $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname); } $this->elementStart('div', 'guide'); diff --git a/actions/confirmaddress.php b/actions/confirmaddress.php index 3c41a5c70..725c1f1e3 100644 --- a/actions/confirmaddress.php +++ b/actions/confirmaddress.php @@ -67,11 +67,7 @@ class ConfirmaddressAction extends Action parent::handle($args); if (!common_logged_in()) { common_set_returnto($this->selfUrl()); - if (!common_config('site', 'openidonly')) { - common_redirect(common_local_url('login')); - } else { - common_redirect(common_local_url('openidlogin')); - } + common_redirect(common_local_url('login')); return; } $code = $this->trimmed('code'); diff --git a/actions/favorited.php b/actions/favorited.php index a3d1a5e20..156c7a700 100644 --- a/actions/favorited.php +++ b/actions/favorited.php @@ -153,8 +153,7 @@ class FavoritedAction extends Action $message .= _('Be the first to add a notice to your favorites by clicking the fave button next to any notice you like.'); } else { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to add a notice to your favorites!'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message .= _('Why not [register an account](%%action.register%%) and be the first to add a notice to your favorites!'); } $this->elementStart('div', 'guide'); diff --git a/actions/groupsearch.php b/actions/groupsearch.php index 7437166e6..c50466ce6 100644 --- a/actions/groupsearch.php +++ b/actions/groupsearch.php @@ -82,8 +82,7 @@ class GroupsearchAction extends SearchAction $message = _('If you can\'t find the group you\'re looking for, you can [create it](%%action.newgroup%%) yourself.'); } else { - $message = sprintf(_('Why not [register an account](%%%%action.%s%%%%) and [create the group](%%%%action.newgroup%%%%) yourself!'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message = _('Why not [register an account](%%action.register%%) and [create the group](%%action.newgroup%%) yourself!'); } $this->elementStart('div', 'guide'); $this->raw(common_markup_to_html($message)); diff --git a/actions/invite.php b/actions/invite.php index bdc0d34cb..26c951ed2 100644 --- a/actions/invite.php +++ b/actions/invite.php @@ -235,7 +235,7 @@ class InviteAction extends CurrentUserDesignAction common_root_url(), $personal, common_local_url('showstream', array('nickname' => $user->nickname)), - common_local_url((!common_config('site', 'openidonly')) ? 'register' : 'openidlogin', array('code' => $invite->code))); + common_local_url('register', array('code' => $invite->code))); mail_send($recipients, $headers, $body); } diff --git a/actions/noticesearch.php b/actions/noticesearch.php index 90b3309cf..49b473d9e 100644 --- a/actions/noticesearch.php +++ b/actions/noticesearch.php @@ -121,9 +121,7 @@ class NoticesearchAction extends SearchAction $message = sprintf(_('Be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q)); } else { - $message = sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin', - urlencode($q)); + $message = sprintf(_('Why not [register an account](%%%%action.register%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q)); } $this->elementStart('div', 'guide'); diff --git a/actions/public.php b/actions/public.php index b68b2ff79..15bedb711 100644 --- a/actions/public.php +++ b/actions/public.php @@ -178,8 +178,7 @@ class PublicAction extends Action } else { if (! (common_config('site','closed') || common_config('site','inviteonly'))) { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to post!'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message .= _('Why not [register an account](%%action.register%%) and be the first to post!'); } } @@ -226,11 +225,9 @@ class PublicAction extends Action function showAnonymousMessage() { if (! (common_config('site','closed') || common_config('site','inviteonly'))) { - $m = sprintf(_('This is %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . - 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' . - '[Join now](%%%%action.%s%%%%) to share notices about yourself with friends, family, and colleagues! ' . - '([Read more](%%%%doc.help%%%%))'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . + 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' . + '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ([Read more](%%doc.help%%))'); } else { $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . 'based on the Free Software [Laconica](http://laconi.ca/) tool.'); diff --git a/actions/publictagcloud.php b/actions/publictagcloud.php index a2772869d..e9f33d58b 100644 --- a/actions/publictagcloud.php +++ b/actions/publictagcloud.php @@ -72,8 +72,7 @@ class PublictagcloudAction extends Action $message .= _('Be the first to post one!'); } else { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to post one!'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message .= _('Why not [register an account](%%action.register%%) and be the first to post one!'); } $this->elementStart('div', 'guide'); diff --git a/actions/remotesubscribe.php b/actions/remotesubscribe.php index 90499bbe2..353717beb 100644 --- a/actions/remotesubscribe.php +++ b/actions/remotesubscribe.php @@ -97,13 +97,11 @@ class RemotesubscribeAction extends Action if ($this->err) { $this->element('div', 'error', $this->err); } else { - $inst = sprintf(_('To subscribe, you can [login](%%%%action.%s%%%%),' . - ' or [register](%%%%action.%s%%%%) a new ' . - ' account. If you already have an account ' . - ' on a [compatible microblogging site](%%doc.openmublog%%), ' . - ' enter your profile URL below.'), - (!common_config('site','openidonly')) ? 'login' : 'openidlogin', - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $inst = _('To subscribe, you can [login](%%action.login%%),' . + ' or [register](%%action.register%%) a new ' . + ' account. If you already have an account ' . + ' on a [compatible microblogging site](%%doc.openmublog%%), ' . + ' enter your profile URL below.'); $output = common_markup_to_html($inst); $this->elementStart('div', 'instructions'); $this->raw($output); diff --git a/actions/replies.php b/actions/replies.php index fcfc3a272..47e01e279 100644 --- a/actions/replies.php +++ b/actions/replies.php @@ -192,9 +192,7 @@ class RepliesAction extends OwnerDesignAction } } else { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin', - $this->user->nickname); + $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname); } $this->elementStart('div', 'guide'); diff --git a/actions/showfavorites.php b/actions/showfavorites.php index 91287cc96..5be997306 100644 --- a/actions/showfavorites.php +++ b/actions/showfavorites.php @@ -196,9 +196,7 @@ class ShowfavoritesAction extends OwnerDesignAction } } else { - $message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.%s%%%%) and then post something interesting they would add to their favorites :)'), - $this->user->nickname, - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.register%%%%) and then post something interesting they would add to their favorites :)'), $this->user->nickname); } $this->elementStart('div', 'guide'); diff --git a/actions/showgroup.php b/actions/showgroup.php index b0cc1dbc7..c3471c195 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -450,9 +450,8 @@ class ShowgroupAction extends GroupDesignAction $m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' . 'short messages about their life and interests. '. - '[Join now](%%%%action.%s%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'), - $this->group->nickname, - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + '[Join now](%%%%action.register%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'), + $this->group->nickname); } else { $m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' . diff --git a/actions/showstream.php b/actions/showstream.php index 3f603d64f..cd5d4bb70 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -358,9 +358,7 @@ class ShowstreamAction extends ProfileAction } } else { - $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'), - (!common_config('site','openidonly')) ? 'register' : 'openidlogin', - $this->user->nickname); + $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname); } $this->elementStart('div', 'guide'); @@ -389,10 +387,8 @@ class ShowstreamAction extends ProfileAction if (!(common_config('site','closed') || common_config('site','inviteonly'))) { $m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' . - '[Join now](%%%%action.%s%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'), - $this->user->nickname, - (!common_config('site','openidonly')) ? 'register' : 'openidlogin', - $this->user->nickname); + '[Join now](%%%%action.register%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'), + $this->user->nickname, $this->user->nickname); } else { $m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . 'based on the Free Software [Laconica](http://laconi.ca/) tool. '), diff --git a/actions/subscribers.php b/actions/subscribers.php index 404738012..66ac00fb1 100644 --- a/actions/subscribers.php +++ b/actions/subscribers.php @@ -111,9 +111,7 @@ class SubscribersAction extends GalleryAction } } else { - $message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.%s%%%%) and be the first?'), - $this->user->nickname, - (!common_config('site','openidonly')) ? 'register' : 'openidlogin'); + $message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.register%%%%) and be the first?'), $this->user->nickname); } $this->elementStart('div', 'guide'); diff --git a/actions/userauthorization.php b/actions/userauthorization.php index 3e7be9747..cc8bfdaea 100644 --- a/actions/userauthorization.php +++ b/actions/userauthorization.php @@ -63,11 +63,7 @@ class UserauthorizationAction extends Action /* Go log in, and then come back. */ common_set_returnto($_SERVER['REQUEST_URI']); - if (!common_config('site', 'openidonly')) { - common_redirect(common_local_url('login')); - } else { - common_redirect(common_local_url('openidlogin')); - } + common_redirect(common_local_url('login')); return; } diff --git a/config.php.sample b/config.php.sample index e8cbf76d5..7877df716 100644 --- a/config.php.sample +++ b/config.php.sample @@ -38,8 +38,6 @@ $config['site']['path'] = 'laconica'; // $config['site']['closed'] = true; // Only allow registration for people invited by another user // $config['site']['inviteonly'] = true; -// Only allow registrations and logins through OpenID -// $config['site']['openidonly'] = true; // Make the site invisible to non-logged-in users // $config['site']['private'] = true; diff --git a/lib/action.php b/lib/action.php index 4d724fba5..ebd722719 100644 --- a/lib/action.php +++ b/lib/action.php @@ -439,17 +439,12 @@ class Action extends HTMLOutputter // lawsuit _('Logout'), _('Logout from the site'), false, 'nav_logout'); } else { - if (!common_config('site', 'openidonly')) { - if (!common_config('site', 'closed')) { - $this->menuItem(common_local_url('register'), - _('Register'), _('Create an account'), false, 'nav_register'); - } - $this->menuItem(common_local_url('login'), - _('Login'), _('Login to the site'), false, 'nav_login'); - } else { - $this->menuItem(common_local_url('openidlogin'), - _('OpenID'), _('Login with OpenID'), false, 'nav_openid'); + if (!common_config('site', 'closed')) { + $this->menuItem(common_local_url('register'), + _('Register'), _('Create an account'), false, 'nav_register'); } + $this->menuItem(common_local_url('login'), + _('Login'), _('Login to the site'), false, 'nav_login'); } $this->menuItem(common_local_url('doc', array('title' => 'help')), _('Help'), _('Help me!'), false, 'nav_help'); diff --git a/lib/common.php b/lib/common.php index 7b0afce51..62cf5640d 100644 --- a/lib/common.php +++ b/lib/common.php @@ -111,7 +111,6 @@ $config = 'broughtbyurl' => null, 'closed' => false, 'inviteonly' => false, - 'openidonly' => false, 'private' => false, 'ssl' => 'never', 'sslserver' => null, diff --git a/lib/facebookaction.php b/lib/facebookaction.php index 4edd3a077..1e0b2bda7 100644 --- a/lib/facebookaction.php +++ b/lib/facebookaction.php @@ -253,13 +253,8 @@ class FacebookAction extends Action $this->elementStart('dd'); $this->elementStart('p'); $this->text(sprintf($loginmsg_part1, common_config('site', 'name'))); - if (!common_config('site', 'openidonly')) { - $this->element('a', - array('href' => common_local_url('register')), _('Register')); - } else { - $this->element('a', - array('href' => common_local_url('openidlogin')), _('Register')); - } + $this->element('a', + array('href' => common_local_url('register')), _('Register')); $this->text($loginmsg_part2); $this->elementEnd('p'); $this->elementEnd('dd'); -- cgit v1.2.3-54-g00ecf From 89ac81c34464b2fc4f54b643d0d95d12bac765ab Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 29 Sep 2009 17:25:52 -0400 Subject: remove string-checks from code using Notice::saveNew() --- actions/newnotice.php | 7 ------- actions/twitapistatuses.php | 5 ----- lib/facebookaction.php | 10 +++++----- lib/oauthstore.php | 5 +---- scripts/maildaemon.php | 9 +++++---- scripts/xmppdaemon.php | 11 +++++++---- 6 files changed, 18 insertions(+), 29 deletions(-) (limited to 'lib/facebookaction.php') diff --git a/actions/newnotice.php b/actions/newnotice.php index 23ec2a1b5..d5b0332f4 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -255,13 +255,6 @@ class NewnoticeAction extends Action $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, ($replyto == 'false') ? null : $replyto); - if (is_string($notice)) { - if (isset($filename)) { - $this->deleteFile($filename); - } - $this->clientError($notice); - } - if (isset($mimetype)) { $this->attachFile($notice, $fileRecord); } diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 2f10ff966..87043b182 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -297,11 +297,6 @@ class TwitapistatusesAction extends TwitterapiAction html_entity_decode($status, ENT_NOQUOTES, 'UTF-8'), $source, 1, $reply_to); - if (is_string($notice)) { - $this->serverError($notice); - return; - } - common_broadcast_notice($notice); $apidata['api_arg'] = $notice->id; } diff --git a/lib/facebookaction.php b/lib/facebookaction.php index 411f79594..3f3a8d3b0 100644 --- a/lib/facebookaction.php +++ b/lib/facebookaction.php @@ -468,11 +468,11 @@ class FacebookAction extends Action $replyto = $this->trimmed('inreplyto'); - $notice = Notice::saveNew($user->id, $content, - 'web', 1, ($replyto == 'false') ? null : $replyto); - - if (is_string($notice)) { - $this->showPage($notice); + try { + $notice = Notice::saveNew($user->id, $content, + 'web', 1, ($replyto == 'false') ? null : $replyto); + } catch (Exception $e) { + $this->showPage($e->getMessage()); return; } diff --git a/lib/oauthstore.php b/lib/oauthstore.php index e69a00f55..d617a7df7 100644 --- a/lib/oauthstore.php +++ b/lib/oauthstore.php @@ -156,7 +156,6 @@ class StatusNetOAuthDataStore extends OAuthDataStore return $this->new_access_token($consumer); } - /** * Revoke specified OAuth token * @@ -363,9 +362,7 @@ class StatusNetOAuthDataStore extends OAuthDataStore false, null, $omb_notice->getIdentifierURI()); - if (is_string($notice)) { - throw new Exception($notice); - } + common_broadcast_notice($notice, true); } diff --git a/scripts/maildaemon.php b/scripts/maildaemon.php index 5705cfd50..586bef624 100755 --- a/scripts/maildaemon.php +++ b/scripts/maildaemon.php @@ -260,10 +260,11 @@ class MailerDaemon function add_notice($user, $msg, $fileRecords) { - $notice = Notice::saveNew($user->id, $msg, 'mail'); - if (is_string($notice)) { - $this->log(LOG_ERR, $notice); - return $notice; + try { + $notice = Notice::saveNew($user->id, $msg, 'mail'); + } catch (Exception $e) { + $this->log(LOG_ERR, $e->getMessage()); + return $e->getMessage(); } foreach($fileRecords as $fileRecord){ $this->attachFile($notice, $fileRecord); diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php index 1b1aec3e6..b2efc07c3 100755 --- a/scripts/xmppdaemon.php +++ b/scripts/xmppdaemon.php @@ -323,12 +323,15 @@ class XMPPDaemon extends Daemon mb_strlen($content_shortened))); return; } - $notice = Notice::saveNew($user->id, $content_shortened, 'xmpp'); - if (is_string($notice)) { - $this->log(LOG_ERR, $notice); - $this->from_site($user->jabber, $notice); + + try { + $notice = Notice::saveNew($user->id, $content_shortened, 'xmpp'); + } catch (Exception $e) { + $this->log(LOG_ERR, $e->getMessage()); + $this->from_site($user->jabber, $e->getMessage()); return; } + common_broadcast_notice($notice); $this->log(LOG_INFO, 'Added notice ' . $notice->id . ' from user ' . $user->nickname); -- cgit v1.2.3-54-g00ecf From 78e5a5980a21c04cfdacb993ca3c37bf65d21783 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 20 Oct 2009 16:32:30 -0700 Subject: Extract out Facebook app stuff into a plugin --- actions/facebookhome.php | 275 ------------ actions/facebookinvite.php | 145 ------- actions/facebooklogin.php | 101 ----- actions/facebookremove.php | 67 --- actions/facebooksettings.php | 157 ------- lib/facebookaction.php | 672 ------------------------------ lib/facebookutil.php | 260 ------------ lib/router.php | 8 - plugins/Facebook/FacebookPlugin.php | 151 +++++++ plugins/Facebook/README | 5 + plugins/Facebook/facebookaction.php | 650 +++++++++++++++++++++++++++++ plugins/Facebook/facebookhome.php | 277 ++++++++++++ plugins/Facebook/facebookinvite.php | 145 +++++++ plugins/Facebook/facebooklogin.php | 99 +++++ plugins/Facebook/facebookqueuehandler.php | 74 ++++ plugins/Facebook/facebookremove.php | 69 +++ plugins/Facebook/facebooksettings.php | 159 +++++++ plugins/Facebook/facebookutil.php | 260 ++++++++++++ scripts/facebookqueuehandler.php | 74 ---- scripts/getvaliddaemons.php | 1 - 20 files changed, 1889 insertions(+), 1760 deletions(-) delete mode 100644 actions/facebookhome.php delete mode 100644 actions/facebookinvite.php delete mode 100644 actions/facebooklogin.php delete mode 100644 actions/facebookremove.php delete mode 100644 actions/facebooksettings.php delete mode 100644 lib/facebookaction.php delete mode 100644 lib/facebookutil.php create mode 100644 plugins/Facebook/FacebookPlugin.php create mode 100644 plugins/Facebook/README create mode 100644 plugins/Facebook/facebookaction.php create mode 100644 plugins/Facebook/facebookhome.php create mode 100644 plugins/Facebook/facebookinvite.php create mode 100644 plugins/Facebook/facebooklogin.php create mode 100755 plugins/Facebook/facebookqueuehandler.php create mode 100644 plugins/Facebook/facebookremove.php create mode 100644 plugins/Facebook/facebooksettings.php create mode 100644 plugins/Facebook/facebookutil.php delete mode 100755 scripts/facebookqueuehandler.php (limited to 'lib/facebookaction.php') diff --git a/actions/facebookhome.php b/actions/facebookhome.php deleted file mode 100644 index 70f205205..000000000 --- a/actions/facebookhome.php +++ /dev/null @@ -1,275 +0,0 @@ -. - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -require_once INSTALLDIR.'/lib/facebookaction.php'; - -class FacebookhomeAction extends FacebookAction -{ - - var $page = null; - - function prepare($argarray) - { - parent::prepare($argarray); - - $this->page = $this->trimmed('page'); - - if (!$this->page) { - $this->page = 1; - } - - return true; - } - - function handle($args) - { - parent::handle($args); - - // If the user has opted not to initially allow the app to have - // Facebook status update permission, store that preference. Only - // promt the user the first time she uses the app - if ($this->arg('skip') || $args['fb_sig_request_method'] == 'GET') { - $this->facebook->api_client->data_setUserPreference( - FACEBOOK_PROMPTED_UPDATE_PREF, 'true'); - } - - if ($this->flink) { - - $this->user = $this->flink->getUser(); - - // If this is the first time the user has started the app - // prompt for Facebook status update permission - if (!$this->facebook->api_client->users_hasAppPermission('publish_stream')) { - - if ($this->facebook->api_client->data_getUserPreference( - FACEBOOK_PROMPTED_UPDATE_PREF) != 'true') { - $this->getUpdatePermission(); - return; - } - } - - // Make sure the user's profile box has the lastest notice - $notice = $this->user->getCurrentNotice(); - if ($notice) { - $this->updateProfileBox($notice); - } - - if ($this->arg('status_submit') == 'Send') { - $this->saveNewNotice(); - } - - // User is authenticated and has already been prompted once for - // Facebook status update permission? Then show the main page - // of the app - $this->showPage(); - - } else { - - // User hasn't authenticated yet, prompt for creds - $this->login(); - } - - } - - function login() - { - - $this->showStylesheets(); - - $nickname = common_canonical_nickname($this->trimmed('nickname')); - $password = $this->arg('password'); - - $msg = null; - - if ($nickname) { - - if (common_check_user($nickname, $password)) { - - $user = User::staticGet('nickname', $nickname); - - if (!$user) { - $this->showLoginForm(_("Server error - couldn't get user!")); - } - - $flink = DB_DataObject::factory('foreign_link'); - $flink->user_id = $user->id; - $flink->foreign_id = $this->fbuid; - $flink->service = FACEBOOK_SERVICE; - $flink->created = common_sql_now(); - $flink->set_flags(true, false, false, false); - - $flink_id = $flink->insert(); - - // XXX: Do some error handling here - - $this->setDefaults(); - - $this->getUpdatePermission(); - return; - - } else { - $msg = _('Incorrect username or password.'); - } - } - - $this->showLoginForm($msg); - $this->showFooter(); - - } - - function setDefaults() - { - $this->facebook->api_client->data_setUserPreference( - FACEBOOK_PROMPTED_UPDATE_PREF, 'false'); - } - - function showNoticeForm() - { - $post_action = "$this->app_uri/index.php"; - - $notice_form = new FacebookNoticeForm($this, $post_action, null, - $post_action, $this->user); - $notice_form->show(); - } - - function title() - { - if ($this->page > 1) { - return sprintf(_("%s and friends, page %d"), $this->user->nickname, $this->page); - } else { - return sprintf(_("%s and friends"), $this->user->nickname); - } - } - - function showContent() - { - $notice = $this->user->noticeInbox(($this->page-1) * NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); - - $nl = new NoticeList($notice, $this); - - $cnt = $nl->show(); - - $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, - $this->page, 'index.php', array('nickname' => $this->user->nickname)); - } - - function showNoticeList($notice) - { - - $nl = new NoticeList($notice, $this); - return $nl->show(); - } - - function getUpdatePermission() { - - $this->showStylesheets(); - - $this->elementStart('div', array('class' => 'facebook_guide')); - - $instructions = sprintf(_('If you would like the %s app to automatically update ' . - 'your Facebook status with your latest notice, you need ' . - 'to give it permission.'), $this->app_name); - - $this->elementStart('p'); - $this->element('span', array('id' => 'permissions_notice'), $instructions); - $this->elementEnd('p'); - - $this->elementStart('form', array('method' => 'post', - 'action' => "index.php", - 'id' => 'facebook-skip-permissions')); - - $this->elementStart('ul', array('id' => 'fb-permissions-list')); - $this->elementStart('li', array('id' => 'fb-permissions-item')); - - $next = urlencode("$this->app_uri/index.php"); - $api_key = common_config('facebook', 'apikey'); - - $auth_url = 'http://www.facebook.com/authorize.php?api_key=' . - $api_key . '&v=1.0&ext_perm=publish_stream&next=' . $next . - '&next_cancel=' . $next . '&submit=skip'; - - $this->elementStart('span', array('class' => 'facebook-button')); - $this->element('a', array('href' => $auth_url), - sprintf(_('Okay, do it!'), $this->app_name)); - $this->elementEnd('span'); - - $this->elementEnd('li'); - - $this->elementStart('li', array('id' => 'fb-permissions-item')); - $this->submit('skip', _('Skip')); - $this->elementEnd('li'); - $this->elementEnd('ul'); - - $this->elementEnd('form'); - $this->elementEnd('div'); - - } - - /** - * Generate pagination links - * - * @param boolean $have_before is there something before? - * @param boolean $have_after is there something after? - * @param integer $page current page - * @param string $action current action - * @param array $args rest of query arguments - * - * @return nothing - */ - function pagination($have_before, $have_after, $page, $action, $args=null) - { - - // Does a little before-after block for next/prev page - - // XXX: Fix so this uses common_local_url() if possible. - - if ($have_before || $have_after) { - $this->elementStart('div', array('class' => 'pagination')); - $this->elementStart('dl', null); - $this->element('dt', null, _('Pagination')); - $this->elementStart('dd', null); - $this->elementStart('ul', array('class' => 'nav')); - } - if ($have_before) { - $pargs = array('page' => $page-1); - $newargs = $args ? array_merge($args, $pargs) : $pargs; - $this->elementStart('li', array('class' => 'nav_prev')); - $this->element('a', array('href' => "$action?page=$newargs[page]", 'rel' => 'prev'), - _('After')); - $this->elementEnd('li'); - } - if ($have_after) { - $pargs = array('page' => $page+1); - $newargs = $args ? array_merge($args, $pargs) : $pargs; - $this->elementStart('li', array('class' => 'nav_next')); - $this->element('a', array('href' => "$action?page=$newargs[page]", 'rel' => 'next'), - _('Before')); - $this->elementEnd('li'); - } - if ($have_before || $have_after) { - $this->elementEnd('ul'); - $this->elementEnd('dd'); - $this->elementEnd('dl'); - $this->elementEnd('div'); - } - } - -} diff --git a/actions/facebookinvite.php b/actions/facebookinvite.php deleted file mode 100644 index 6dfc9d688..000000000 --- a/actions/facebookinvite.php +++ /dev/null @@ -1,145 +0,0 @@ -. - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once(INSTALLDIR.'/lib/facebookaction.php'); - -class FacebookinviteAction extends FacebookAction -{ - - function handle($args) - { - parent::handle($args); - $this->showForm(); - } - - /** - * Wrapper for showing a page - * - * Stores an error and shows the page - * - * @param string $error Error, if any - * - * @return void - */ - - function showForm($error=null) - { - $this->error = $error; - $this->showPage(); - } - - /** - * Show the page content - * - * Either shows the registration form or, if registration was successful, - * instructions for using the site. - * - * @return void - */ - - function showContent() - { - if ($this->arg('ids')) { - $this->showSuccessContent(); - } else { - $this->showFormContent(); - } - } - - function showSuccessContent() - { - - $this->element('h2', null, sprintf(_('Thanks for inviting your friends to use %s'), - common_config('site', 'name'))); - $this->element('p', null, _('Invitations have been sent to the following users:')); - - $friend_ids = $_POST['ids']; // XXX: Hmm... is this the best way to access the list? - - $this->elementStart('ul', array('id' => 'facebook-friends')); - - foreach ($friend_ids as $friend) { - $this->elementStart('li'); - $this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square')); - $this->element('fb:name', array('uid' => $friend, - 'capitalize' => 'true')); - $this->elementEnd('li'); - } - - $this->elementEnd("ul"); - - } - - function showFormContent() - { - $content = sprintf(_('You have been invited to %s'), common_config('site', 'name')) . - htmlentities(''); - - $this->elementStart('fb:request-form', array('action' => 'invite.php', - 'method' => 'post', - 'invite' => 'true', - 'type' => common_config('site', 'name'), - 'content' => $content)); - $this->hidden('invite', 'true'); - $actiontext = sprintf(_('Invite your friends to use %s'), common_config('site', 'name')); - - $multi_params = array('showborder' => 'false'); - $multi_params['actiontext'] = $actiontext; - $multi_params['bypass'] = 'cancel'; - - // Get a list of users who are already using the app for exclusion - $exclude_ids = $this->facebook->api_client->friends_getAppUsers(); - $exclude_ids_csv = null; - - // fbml needs these as a csv string, not an array - if ($exclude_ids) { - $exclude_ids_csv = implode(',', $exclude_ids); - $multi_params['exclude_ids'] = $exclude_ids_csv; - } - - $this->element('fb:multi-friend-selector', $multi_params); - $this->elementEnd('fb:request-form'); - - if ($exclude_ids) { - - $this->element('h2', null, sprintf(_('Friends already using %s:'), - common_config('site', 'name'))); - $this->elementStart('ul', array('id' => 'facebook-friends')); - - foreach ($exclude_ids as $friend) { - $this->elementStart('li'); - $this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square')); - $this->element('fb:name', array('uid' => $friend, - 'capitalize' => 'true')); - $this->elementEnd('li'); - } - - $this->elementEnd("ul"); - } - } - - function title() - { - return sprintf(_('Send invitations')); - } - -} diff --git a/actions/facebooklogin.php b/actions/facebooklogin.php deleted file mode 100644 index 8ac2477ab..000000000 --- a/actions/facebooklogin.php +++ /dev/null @@ -1,101 +0,0 @@ -. - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -require_once(INSTALLDIR.'/lib/facebookaction.php'); - -class FacebookinviteAction extends FacebookAction -{ - - function handle($args) - { - parent::handle($args); - - $this->error = $error; - - if ($this->flink) { - if (!$this->facebook->api_client->users_hasAppPermission('publish_stream') && - $this->facebook->api_client->data_getUserPreference( - FACEBOOK_PROMPTED_UPDATE_PREF) == 'true') { - - echo '

REDIRECT TO HOME

'; - } - } else { - $this->showPage(); - } - } - - - function showContent() - { - - // If the user has opted not to initially allow the app to have - // Facebook status update permission, store that preference. Only - // promt the user the first time she uses the app - if ($this->arg('skip')) { - $this->facebook->api_client->data_setUserPreference( - FACEBOOK_PROMPTED_UPDATE_PREF, 'true'); - } - - if ($this->flink) { - - $this->user = $this->flink->getUser(); - - // If this is the first time the user has started the app - // prompt for Facebook status update permission - if (!$this->facebook->api_client->users_hasAppPermission('publish_stream')) { - - if ($this->facebook->api_client->data_getUserPreference( - FACEBOOK_PROMPTED_UPDATE_PREF) != 'true') { - $this->getUpdatePermission(); - return; - } - } - - } else { - $this->showLoginForm(); - } - - } - - function showSuccessContent() - { - - - - } - - function showFormContent() - { - - - } - - function title() - { - return sprintf(_('Login')); - } - - function redirectHome() - { - - } - -} diff --git a/actions/facebookremove.php b/actions/facebookremove.php deleted file mode 100644 index ae231c0fb..000000000 --- a/actions/facebookremove.php +++ /dev/null @@ -1,67 +0,0 @@ -. - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -require_once INSTALLDIR.'/lib/facebookaction.php'; - -class FacebookremoveAction extends FacebookAction -{ - - function handle($args) - { - parent::handle($args); - - $secret = common_config('facebook', 'secret'); - - $sig = ''; - - ksort($_POST); - - foreach ($_POST as $key => $val) { - if (substr($key, 0, 7) == 'fb_sig_') { - $sig .= substr($key, 7) . '=' . $val; - } - } - - $sig .= $secret; - $verify = md5($sig); - - if ($verify == $this->arg('fb_sig')) { - - $flink = Foreign_link::getByForeignID($this->arg('fb_sig_user'), 2); - - common_debug("Removing foreign link to Facebook - local user ID: $flink->user_id, Facebook ID: $flink->foreign_id"); - - $result = $flink->delete(); - - if (!$result) { - common_log_db_error($flink, 'DELETE', __FILE__); - $this->serverError(_('Couldn\'t remove Facebook user.')); - return; - } - - } else { - # Someone bad tried to remove facebook link? - common_log(LOG_ERR, "Someone from $_SERVER[REMOTE_ADDR] " . - 'unsuccessfully tried to remove a foreign link to Facebook!'); - } - } - -} diff --git a/actions/facebooksettings.php b/actions/facebooksettings.php deleted file mode 100644 index b2b1d6807..000000000 --- a/actions/facebooksettings.php +++ /dev/null @@ -1,157 +0,0 @@ -. - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } - -require_once INSTALLDIR.'/lib/facebookaction.php'; - -class FacebooksettingsAction extends FacebookAction -{ - - function handle($args) - { - parent::handle($args); - $this->showPage(); - } - - /** - * Show the page content - * - * Either shows the registration form or, if registration was successful, - * instructions for using the site. - * - * @return void - */ - - function showContent() - { - if ($this->arg('save')) { - $this->saveSettings(); - } else { - $this->showForm(); - } - } - - function saveSettings() { - - $noticesync = $this->arg('noticesync'); - $replysync = $this->arg('replysync'); - $prefix = $this->trimmed('prefix'); - - $original = clone($this->flink); - $this->flink->set_flags($noticesync, $replysync, false, false); - $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) { - $this->showForm(_('There was a problem saving your sync preferences!')); - } else { - $this->showForm(_('Sync preferences saved.'), true); - } - } - - function showForm($msg = null, $success = false) { - - if ($msg) { - if ($success) { - $this->element('fb:success', array('message' => $msg)); - } else { - $this->element('fb:error', array('message' => $msg)); - } - } - - if ($this->facebook->api_client->users_hasAppPermission('publish_stream')) { - - $this->elementStart('form', array('method' => 'post', - 'id' => 'facebook_settings')); - - $this->elementStart('ul', 'form_data'); - - $this->elementStart('li'); - - $this->checkbox('noticesync', _('Automatically update my Facebook status with my notices.'), - ($this->flink) ? ($this->flink->noticesync & FOREIGN_NOTICE_SEND) : true); - - $this->elementEnd('li'); - - $this->elementStart('li'); - - $this->checkbox('replysync', _('Send "@" replies to Facebook.'), - ($this->flink) ? ($this->flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) : true); - - $this->elementEnd('li'); - - $this->elementStart('li'); - - $prefix = trim($this->facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX)); - - $this->input('prefix', _('Prefix'), - ($prefix) ? $prefix : null, - _('A string to prefix notices with.')); - - $this->elementEnd('li'); - - $this->elementStart('li'); - - $this->submit('save', _('Save')); - - $this->elementEnd('li'); - - $this->elementEnd('ul'); - - $this->elementEnd('form'); - - } else { - - $instructions = sprintf(_('If you would like %s to automatically update ' . - 'your Facebook status with your latest notice, you need ' . - 'to give it permission.'), $this->app_name); - - $this->elementStart('p'); - $this->element('span', array('id' => 'permissions_notice'), $instructions); - $this->elementEnd('p'); - - $this->elementStart('ul', array('id' => 'fb-permissions-list')); - $this->elementStart('li', array('id' => 'fb-permissions-item')); - $this->elementStart('fb:prompt-permission', array('perms' => 'publish_stream', - 'next_fbjs' => 'document.setLocation(\'' . "$this->app_uri/settings.php" . '\')')); - $this->element('span', array('class' => 'facebook-button'), - sprintf(_('Allow %s to update my Facebook status'), common_config('site', 'name'))); - $this->elementEnd('fb:prompt-permission'); - $this->elementEnd('li'); - $this->elementEnd('ul'); - } - - } - - function title() - { - return _('Sync preferences'); - } - -} diff --git a/lib/facebookaction.php b/lib/facebookaction.php deleted file mode 100644 index 3f3a8d3b0..000000000 --- a/lib/facebookaction.php +++ /dev/null @@ -1,672 +0,0 @@ -. - * - * @category Faceboook - * @package StatusNet - * @author Zach Copley - * @copyright 2008 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') && !defined('LACONICA')) -{ - exit(1); -} - -require_once INSTALLDIR.'/lib/facebookutil.php'; -require_once INSTALLDIR.'/lib/noticeform.php'; - -class FacebookAction extends Action -{ - - var $facebook = null; - var $fbuid = null; - var $flink = null; - var $action = null; - var $app_uri = null; - var $app_name = null; - - /** - * Constructor - * - * Just wraps the HTMLOutputter constructor. - * - * @param string $output URI to output to, default = stdout - * @param boolean $indent Whether to indent output, default true - * - * @see XMLOutputter::__construct - * @see HTMLOutputter::__construct - */ - function __construct($output='php://output', $indent=true, $facebook=null, $flink=null) - { - parent::__construct($output, $indent); - - $this->facebook = $facebook; - $this->flink = $flink; - - if ($this->flink) { - $this->fbuid = $flink->foreign_id; - $this->user = $flink->getUser(); - } - - $this->args = array(); - } - - function prepare($argarray) - { - parent::prepare($argarray); - - $this->facebook = getFacebook(); - $this->fbuid = $this->facebook->require_login(); - - $this->action = $this->trimmed('action'); - - $app_props = $this->facebook->api_client->Admin_getAppProperties( - array('canvas_name', 'application_name')); - - $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name']; - $this->app_name = $app_props['application_name']; - - $this->flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); - - return true; - - } - - function showStylesheets() - { - $this->cssLink('css/display.css', 'base'); - $this->cssLink('css/display.css',null,'screen, projection, tv'); - $this->cssLink('css/facebookapp.css', 'base'); - } - - function showScripts() - { - $this->script('js/facebookapp.js'); - } - - /** - * Start an Facebook ready HTML document - * - * For Facebook we don't want to actually output any headers, - * DTD info, etc. Just Stylesheet and JavaScript links. - * - * If $type isn't specified, will attempt to do content negotiation. - * - * @param string $type MIME type to use; default is to do negotation. - * - * @return void - */ - - function startHTML($type=null) - { - $this->showStylesheets(); - $this->showScripts(); - - $this->elementStart('div', array('class' => 'facebook-page')); - } - - /** - * Ends a Facebook ready HTML document - * - * @return void - */ - function endHTML() - { - $this->elementEnd('div'); - $this->endXML(); - } - - /** - * Show notice form. - * - * MAY overload if no notice form needed... or direct message box???? - * - * @return nothing - */ - function showNoticeForm() - { - // don't do it for most of the Facebook pages - } - - function showBody() - { - $this->elementStart('div', array('id' => 'wrap')); - $this->showHeader(); - $this->showCore(); - $this->showFooter(); - $this->elementEnd('div'); - } - - function showAside() - { - } - - function showHead($error, $success) - { - - if ($error) { - $this->element("h1", null, $error); - } - - if ($success) { - $this->element("h1", null, $success); - } - - $this->elementStart('fb:if-section-not-added', array('section' => 'profile')); - $this->elementStart('span', array('id' => 'add_to_profile')); - $this->element('fb:add-section-button', array('section' => 'profile')); - $this->elementEnd('span'); - $this->elementEnd('fb:if-section-not-added'); - - } - - // Make this into a widget later - function showLocalNav() - { - $this->elementStart('ul', array('class' => 'nav')); - - $this->elementStart('li', array('class' => - ($this->action == 'facebookhome') ? 'current' : 'facebook_home')); - $this->element('a', - array('href' => 'index.php', 'title' => _('Home')), _('Home')); - $this->elementEnd('li'); - - if (common_config('invite', 'enabled')) { - $this->elementStart('li', - array('class' => - ($this->action == 'facebookinvite') ? 'current' : 'facebook_invite')); - $this->element('a', - array('href' => 'invite.php', 'title' => _('Invite')), _('Invite')); - $this->elementEnd('li'); - } - - $this->elementStart('li', - array('class' => - ($this->action == 'facebooksettings') ? 'current' : 'facebook_settings')); - $this->element('a', - array('href' => 'settings.php', - 'title' => _('Settings')), _('Settings')); - $this->elementEnd('li'); - - $this->elementEnd('ul'); - } - - /** - * Show header of the page. - * - * Calls template methods - * - * @return nothing - */ - function showHeader() - { - $this->elementStart('div', array('id' => 'header')); - $this->showLogo(); - $this->showNoticeForm(); - $this->elementEnd('div'); - } - - /** - * Show page, a template method. - * - * @return nothing - */ - function showPage($error = null, $success = null) - { - $this->startHTML(); - $this->showHead($error, $success); - $this->showBody(); - $this->endHTML(); - } - - function showInstructions() - { - - $this->elementStart('div', array('class' => 'facebook_guide')); - - $this->elementStart('dl', array('class' => 'system_notice')); - $this->element('dt', null, 'Page Notice'); - - $loginmsg_part1 = _('To use the %s Facebook Application you need to login ' . - 'with your username and password. Don\'t have a username yet? '); - $loginmsg_part2 = _(' a new account.'); - - $this->elementStart('dd'); - $this->elementStart('p'); - $this->text(sprintf($loginmsg_part1, common_config('site', 'name'))); - $this->element('a', - array('href' => common_local_url('register')), _('Register')); - $this->text($loginmsg_part2); - $this->elementEnd('p'); - $this->elementEnd('dd'); - - $this->elementEnd('dl'); - $this->elementEnd('div'); - } - - function showLoginForm($msg = null) - { - - $this->elementStart('div', array('id' => 'content')); - $this->element('h1', null, _('Login')); - - if ($msg) { - $this->element('fb:error', array('message' => $msg)); - } - - $this->showInstructions(); - - $this->elementStart('div', array('id' => 'content_inner')); - - $this->elementStart('form', array('method' => 'post', - 'class' => 'form_settings', - 'id' => 'login', - 'action' => 'index.php')); - - $this->elementStart('fieldset'); - - $this->elementStart('ul', array('class' => 'form_datas')); - $this->elementStart('li'); - $this->input('nickname', _('Nickname')); - $this->elementEnd('li'); - $this->elementStart('li'); - $this->password('password', _('Password')); - $this->elementEnd('li'); - $this->elementEnd('ul'); - - $this->submit('submit', _('Login')); - $this->elementEnd('fieldset'); - $this->elementEnd('form'); - - $this->elementStart('p'); - $this->element('a', array('href' => common_local_url('recoverpassword')), - _('Lost or forgotten password?')); - $this->elementEnd('p'); - - $this->elementEnd('div'); - $this->elementEnd('div'); - - } - - function updateProfileBox($notice) - { - - // Need to include inline CSS for styling the Profile box - - $app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url')); - $icon_url = $app_props['icon_url']; - - $style = ''; - - $this->xw->openMemory(); - - $item = new FacebookProfileBoxNotice($notice, $this); - $item->show(); - - $fbml = "$style " . $this->xw->outputMemory(false) . ""; - $fbml .= "$style " . $this->xw->outputMemory(false) . ""; - - $fbml_main = "$style " . $this->xw->outputMemory(false) . ""; - - $this->facebook->api_client->profile_setFBML(null, $this->fbuid, $fbml, null, null, $fbml_main); - - $this->xw->openURI('php://output'); - } - - /** - * Generate pagination links - * - * @param boolean $have_before is there something before? - * @param boolean $have_after is there something after? - * @param integer $page current page - * @param string $action current action - * @param array $args rest of query arguments - * - * @return nothing - */ - function pagination($have_before, $have_after, $page, $action, $args=null) - { - // Does a little before-after block for next/prev page - if ($have_before || $have_after) { - $this->elementStart('div', array('class' => 'pagination')); - $this->elementStart('dl', null); - $this->element('dt', null, _('Pagination')); - $this->elementStart('dd', null); - $this->elementStart('ul', array('class' => 'nav')); - } - if ($have_before) { - $pargs = array('page' => $page-1); - $newargs = $args ? array_merge($args, $pargs) : $pargs; - $this->elementStart('li', array('class' => 'nav_prev')); - $this->element('a', array('href' => "$this->app_uri/$action?page=$newargs[page]", 'rel' => 'prev'), - _('After')); - $this->elementEnd('li'); - } - if ($have_after) { - $pargs = array('page' => $page+1); - $newargs = $args ? array_merge($args, $pargs) : $pargs; - $this->elementStart('li', array('class' => 'nav_next')); - $this->element('a', array('href' => "$this->app_uri/$action?page=$newargs[page]", 'rel' => 'next'), - _('Before')); - $this->elementEnd('li'); - } - if ($have_before || $have_after) { - $this->elementEnd('ul'); - $this->elementEnd('dd'); - $this->elementEnd('dl'); - $this->elementEnd('div'); - } - } - - function saveNewNotice() - { - - $user = $this->flink->getUser(); - - $content = $this->trimmed('status_textarea'); - - if (!$content) { - $this->showPage(_('No notice content!')); - return; - } else { - $content_shortened = common_shorten_links($content); - - if (Notice::contentTooLong($content_shortened)) { - $this->showPage(sprintf(_('That\'s too long. Max notice size is %d chars.'), - Notice::maxContent())); - return; - } - } - - $inter = new CommandInterpreter(); - - $cmd = $inter->handle_command($user, $content_shortened); - - if ($cmd) { - - // XXX fix this - - $cmd->execute(new WebChannel()); - return; - } - - $replyto = $this->trimmed('inreplyto'); - - try { - $notice = Notice::saveNew($user->id, $content, - 'web', 1, ($replyto == 'false') ? null : $replyto); - } catch (Exception $e) { - $this->showPage($e->getMessage()); - return; - } - - common_broadcast_notice($notice); - - // Also update the user's Facebook status - facebookBroadcastNotice($notice); - - } - -} - -class FacebookNoticeForm extends NoticeForm -{ - - var $post_action = null; - - /** - * Constructor - * - * @param HTMLOutputter $out output channel - * @param string $action action to return to, if any - * @param string $content content to pre-fill - */ - - function __construct($out=null, $action=null, $content=null, - $post_action=null, $user=null) - { - parent::__construct($out, $action, $content, $user); - $this->post_action = $post_action; - } - - /** - * Action of the form - * - * @return string URL of the action - */ - - function action() - { - return $this->post_action; - } - -} - -class FacebookNoticeList extends NoticeList -{ - - /** - * constructor - * - * @param Notice $notice stream of notices from DB_DataObject - */ - - function __construct($notice, $out=null) - { - parent::__construct($notice, $out); - } - - /** - * show the list of notices - * - * "Uses up" the stream by looping through it. So, probably can't - * be called twice on the same list. - * - * @return int count of notices listed. - */ - - function show() - { - $this->out->elementStart('div', array('id' =>'notices_primary')); - $this->out->element('h2', null, _('Notices')); - $this->out->elementStart('ul', array('class' => 'notices')); - - $cnt = 0; - - while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) { - $cnt++; - - if ($cnt > NOTICES_PER_PAGE) { - break; - } - - $item = $this->newListItem($this->notice); - $item->show(); - } - - $this->out->elementEnd('ul'); - $this->out->elementEnd('div'); - - return $cnt; - } - - /** - * returns a new list item for the current notice - * - * Overridden to return a Facebook specific list item. - * - * @param Notice $notice the current notice - * - * @return FacebookNoticeListItem a list item for displaying the notice - * formatted for display in the Facebook App. - */ - - function newListItem($notice) - { - return new FacebookNoticeListItem($notice, $this); - } - -} - -class FacebookNoticeListItem extends NoticeListItem -{ - - /** - * constructor - * - * Also initializes the profile attribute. - * - * @param Notice $notice The notice we'll display - */ - - function __construct($notice, $out=null) - { - parent::__construct($notice, $out); - } - - /** - * recipe function for displaying a single notice in the Facebook App. - * - * Overridden to strip out some of the controls that we don't - * want to be available. - * - * @return void - */ - - function show() - { - $this->showStart(); - $this->showNotice(); - $this->showNoticeInfo(); - - // XXX: Need to update to show attachements and controls - - $this->showEnd(); - } - -} - -class FacebookProfileBoxNotice extends FacebookNoticeListItem -{ - - /** - * constructor - * - * Also initializes the profile attribute. - * - * @param Notice $notice The notice we'll display - */ - - function __construct($notice, $out=null) - { - parent::__construct($notice, $out); - } - - /** - * Recipe function for displaying a single notice in the - * Facebook App profile notice box - * - * @return void - */ - - function show() - { - $this->showNotice(); - $this->showNoticeInfo(); - $this->showAppLink(); - } - - function showAppLink() - { - - $this->facebook = getFacebook(); - - $app_props = $this->facebook->api_client->Admin_getAppProperties( - array('canvas_name', 'application_name')); - - $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name']; - $this->app_name = $app_props['application_name']; - - $this->out->elementStart('a', array('id' => 'facebook_statusnet_app', - 'href' => $this->app_uri)); - $this->out->text($this->app_name); - $this->out->elementEnd('a'); - } - -} diff --git a/lib/facebookutil.php b/lib/facebookutil.php deleted file mode 100644 index c991c5439..000000000 --- a/lib/facebookutil.php +++ /dev/null @@ -1,260 +0,0 @@ -. - */ - -require_once INSTALLDIR.'/extlib/facebook/facebook.php'; -require_once INSTALLDIR.'/lib/facebookaction.php'; -require_once INSTALLDIR.'/lib/noticelist.php'; - -define("FACEBOOK_SERVICE", 2); // Facebook is foreign_service ID 2 -define("FACEBOOK_NOTICE_PREFIX", 1); -define("FACEBOOK_PROMPTED_UPDATE_PREF", 2); - -function getFacebook() -{ - static $facebook = null; - - $apikey = common_config('facebook', 'apikey'); - $secret = common_config('facebook', 'secret'); - - if ($facebook === null) { - $facebook = new Facebook($apikey, $secret); - } - - if (empty($facebook)) { - common_log(LOG_ERR, 'Could not make new Facebook client obj!', - __FILE__); - } - - return $facebook; -} - -function isFacebookBound($notice, $flink) { - - if (empty($flink)) { - return false; - } - - // Avoid a loop - - if ($notice->source == 'Facebook') { - common_log(LOG_INFO, "Skipping notice $notice->id because its " . - 'source is Facebook.'); - return false; - } - - // If the user does not want to broadcast to Facebook, move along - - if (!($flink->noticesync & FOREIGN_NOTICE_SEND == FOREIGN_NOTICE_SEND)) { - common_log(LOG_INFO, "Skipping notice $notice->id " . - 'because user has FOREIGN_NOTICE_SEND bit off.'); - return false; - } - - // If it's not a reply, or if the user WANTS to send @-replies, - // then, yeah, it can go to Facebook. - - if (!preg_match('/@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) || - ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY)) { - return true; - } - - return false; - -} - -function facebookBroadcastNotice($notice) -{ - $facebook = getFacebook(); - $flink = Foreign_link::getByUserID($notice->profile_id, FACEBOOK_SERVICE); - - if (isFacebookBound($notice, $flink)) { - - // Okay, we're good to go, update the FB status - - $status = null; - $fbuid = $flink->foreign_id; - $user = $flink->getUser(); - $attachments = $notice->attachments(); - - try { - - // Get the status 'verb' (prefix) the user has set - - // XXX: Does this call count against our per user FB request limit? - // If so we should consider storing verb elsewhere or not storing - - $prefix = trim($facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX, - $fbuid)); - - $status = "$prefix $notice->content"; - - $can_publish = $facebook->api_client->users_hasAppPermission('publish_stream', - $fbuid); - - $can_update = $facebook->api_client->users_hasAppPermission('status_update', - $fbuid); - if (!empty($attachments) && $can_publish == 1) { - $fbattachment = format_attachments($attachments); - $facebook->api_client->stream_publish($status, $fbattachment, - null, null, $fbuid); - common_log(LOG_INFO, - "Posted notice $notice->id w/attachment " . - "to Facebook user's stream (fbuid = $fbuid)."); - } elseif ($can_update == 1 || $can_publish == 1) { - $facebook->api_client->users_setStatus($status, $fbuid, false, true); - common_log(LOG_INFO, - "Posted notice $notice->id to Facebook " . - "as a status update (fbuid = $fbuid)."); - } else { - $msg = "Not sending notice $notice->id to Facebook " . - "because user $user->nickname hasn't given the " . - 'Facebook app \'status_update\' or \'publish_stream\' permission.'; - common_log(LOG_WARNING, $msg); - } - - // Finally, attempt to update the user's profile box - - if ($can_publish == 1 || $can_update == 1) { - updateProfileBox($facebook, $flink, $notice); - } - - } catch (FacebookRestClientException $e) { - - $code = $e->getCode(); - - common_log(LOG_WARNING, 'Facebook returned error code ' . - $code . ': ' . $e->getMessage()); - common_log(LOG_WARNING, - 'Unable to update Facebook status for ' . - "$user->nickname (user id: $user->id)!"); - - if ($code == 200 || $code == 250) { - - // 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; - -} - -function updateProfileBox($facebook, $flink, $notice) { - $fbaction = new FacebookAction($output = 'php://output', - $indent = true, $facebook, $flink); - $fbaction->updateProfileBox($notice); -} - -function format_attachments($attachments) -{ - $fbattachment = array(); - $fbattachment['media'] = array(); - - foreach($attachments as $attachment) - { - if($enclosure = $attachment->getEnclosure()){ - $fbmedia = get_fbmedia_for_attachment($enclosure); - }else{ - $fbmedia = get_fbmedia_for_attachment($attachment); - } - if($fbmedia){ - $fbattachment['media'][]=$fbmedia; - }else{ - $fbattachment['name'] = ($attachment->title ? - $attachment->title : $attachment->url); - $fbattachment['href'] = $attachment->url; - } - } - if(count($fbattachment['media'])>0){ - unset($fbattachment['name']); - unset($fbattachment['href']); - } - return $fbattachment; -} - -/** -* given an File objects, returns an associative array suitable for Facebook media -*/ -function get_fbmedia_for_attachment($attachment) -{ - $fbmedia = array(); - - if (strncmp($attachment->mimetype, 'image/', strlen('image/')) == 0) { - $fbmedia['type'] = 'image'; - $fbmedia['src'] = $attachment->url; - $fbmedia['href'] = $attachment->url; - } else if ($attachment->mimetype == 'audio/mpeg') { - $fbmedia['type'] = 'mp3'; - $fbmedia['src'] = $attachment->url; - }else if ($attachment->mimetype == 'application/x-shockwave-flash') { - $fbmedia['type'] = 'flash'; - - // http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29 - // says that imgsrc is required... but we have no value to put in it - // $fbmedia['imgsrc']=''; - - $fbmedia['swfsrc'] = $attachment->url; - }else{ - return false; - } - return $fbmedia; -} - -function remove_facebook_app($flink) -{ - - $user = $flink->getUser(); - - common_log(LOG_INFO, 'Removing Facebook App Foreign link for ' . - "user $user->nickname (user id: $user->id)."); - - $result = $flink->delete(); - - if (empty($result)) { - common_log(LOG_ERR, 'Could not remove Facebook App ' . - "Foreign_link for $user->nickname (user id: $user->id)!"); - common_log_db_error($flink, 'DELETE', __FILE__); - } - - // Notify the user that we are removing their FB app access - - $result = mail_facebook_app_removed($user); - - if (!$result) { - - $msg = 'Unable to send email to notify ' . - "$user->nickname (user id: $user->id) " . - 'that their Facebook app link was ' . - 'removed!'; - - common_log(LOG_WARNING, $msg); - } - -} diff --git a/lib/router.php b/lib/router.php index a5b6a9a30..4fb0834fd 100644 --- a/lib/router.php +++ b/lib/router.php @@ -86,14 +86,6 @@ class Router $m->connect('doc/:title', array('action' => 'doc')); - // facebook - - $m->connect('facebook', array('action' => 'facebookhome')); - $m->connect('facebook/index.php', array('action' => 'facebookhome')); - $m->connect('facebook/settings.php', array('action' => 'facebooksettings')); - $m->connect('facebook/invite.php', array('action' => 'facebookinvite')); - $m->connect('facebook/remove', array('action' => 'facebookremove')); - // main stuff is repetitive $main = array('login', 'logout', 'register', 'subscribe', diff --git a/plugins/Facebook/FacebookPlugin.php b/plugins/Facebook/FacebookPlugin.php new file mode 100644 index 000000000..127cf96e6 --- /dev/null +++ b/plugins/Facebook/FacebookPlugin.php @@ -0,0 +1,151 @@ +. + * + * @category Plugin + * @package StatusNet + * @author Zach Copley + * @copyright 2009 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); +} + +/** + * Facebook plugin to add a StatusNet Facebook application + * + * @category Plugin + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class FacebookPlugin extends Plugin +{ + + /** + * Add Facebook app actions to the router table + * + * Hook for RouterInitialized event. + * + * @param Net_URL_Mapper &$m path-to-action mapper + * + * @return boolean hook return + */ + + function onRouterInitialized(&$m) + { + $m->connect('facebook', array('action' => 'facebookhome')); + $m->connect('facebook/index.php', array('action' => 'facebookhome')); + $m->connect('facebook/settings.php', array('action' => 'facebooksettings')); + $m->connect('facebook/invite.php', array('action' => 'facebookinvite')); + $m->connect('facebook/remove', array('action' => 'facebookremove')); + + return true; + } + + /** + * Automatically load the actions and libraries used by the Facebook app + * + * @param Class $cls the class + * + * @return boolean hook return + * + */ + function onAutoload($cls) + { + switch ($cls) { + case 'FacebookAction': + case 'FacebookhomeAction': + case 'FacebookinviteAction': + case 'FacebookremoveAction': + case 'FacebooksettingsAction': + include_once INSTALLDIR . '/plugins/Facebook/' . + strtolower(mb_substr($cls, 0, -6)) . '.php'; + return false; + default: + return true; + } + } + + /** + * Add a Facebook queue item for each notice + * + * @param Notice $notice the notice + * @param array &$transports the list of transports (queues) + * + * @return boolean hook return + */ + function onStartEnqueueNotice($notice, &$transports) + { + array_push($transports, 'facebook'); + return true; + } + + /** + * broadcast the message when not using queuehandler + * + * @param Notice &$notice the notice + * @param array $queue destination queue + * + * @return boolean hook return + */ + function onUnqueueHandleNotice(&$notice, $queue) + { + if (($queue == 'facebook') && ($this->_isLocal($notice))) { + facebookBroadcastNotice($notice); + return false; + } + return true; + } + + /** + * Determine whether the notice was locally created + * + * @param Notice $notice + * + * @return boolean locality + */ + function _isLocal($notice) + { + return ($notice->is_local == Notice::LOCAL_PUBLIC || + $notice->is_local == Notice::LOCAL_NONPUBLIC); + } + + /** + * Add Facebook queuehandler to the list of daemons to start + * + * @param array $daemons the list fo daemons to run + * + * @return boolean hook return + * + */ + function onGetValidDaemons($daemons) + { + array_push($daemons, INSTALLDIR . + '/plugins/Facebook/facebookqueuehandler.php'); + return true; + } + +} \ No newline at end of file diff --git a/plugins/Facebook/README b/plugins/Facebook/README new file mode 100644 index 000000000..a350c5b5b --- /dev/null +++ b/plugins/Facebook/README @@ -0,0 +1,5 @@ + + +TODO: + +- Integrate this and the FB Connect plugin \ No newline at end of file diff --git a/plugins/Facebook/facebookaction.php b/plugins/Facebook/facebookaction.php new file mode 100644 index 000000000..f5ad3d06b --- /dev/null +++ b/plugins/Facebook/facebookaction.php @@ -0,0 +1,650 @@ +. + * + * @category Faceboook + * @package StatusNet + * @author Zach Copley + * @copyright 2008-2009 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') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR . '/plugins/Facebook/facebookutil.php'; +require_once INSTALLDIR . '/lib/noticeform.php'; + +class FacebookAction extends Action +{ + + var $facebook = null; + var $fbuid = null; + var $flink = null; + var $action = null; + var $app_uri = null; + var $app_name = null; + + function __construct($output='php://output', $indent=true, $facebook=null, $flink=null) + { + parent::__construct($output, $indent); + + $this->facebook = $facebook; + $this->flink = $flink; + + if ($this->flink) { + $this->fbuid = $flink->foreign_id; + $this->user = $flink->getUser(); + } + + $this->args = array(); + } + + function prepare($argarray) + { + parent::prepare($argarray); + + $this->facebook = getFacebook(); + $this->fbuid = $this->facebook->require_login(); + + $this->action = $this->trimmed('action'); + + $app_props = $this->facebook->api_client->Admin_getAppProperties( + array('canvas_name', 'application_name')); + + $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name']; + $this->app_name = $app_props['application_name']; + + $this->flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); + + return true; + + } + + function showStylesheets() + { + $this->cssLink('css/display.css', 'base'); + $this->cssLink('css/display.css',null,'screen, projection, tv'); + $this->cssLink('css/facebookapp.css', 'base'); + } + + function showScripts() + { + $this->script('js/facebookapp.js'); + } + + /** + * Start an Facebook ready HTML document + * + * For Facebook we don't want to actually output any headers, + * DTD info, etc. Just Stylesheet and JavaScript links. + * + * @param string $type MIME type to use; default is to do negotation. + * + * @return void + */ + + function startHTML($type=null) + { + $this->showStylesheets(); + $this->showScripts(); + + $this->elementStart('div', array('class' => 'facebook-page')); + } + + /** + * Ends a Facebook ready HTML document + * + * @return void + */ + function endHTML() + { + $this->elementEnd('div'); + $this->endXML(); + } + + /** + * Show notice form. + * + * @return nothing + */ + function showNoticeForm() + { + // don't do it for most of the Facebook pages + } + + function showBody() + { + $this->elementStart('div', array('id' => 'wrap')); + $this->showHeader(); + $this->showCore(); + $this->showFooter(); + $this->elementEnd('div'); + } + + function showHead($error, $success) + { + + if ($error) { + $this->element("h1", null, $error); + } + + if ($success) { + $this->element("h1", null, $success); + } + + $this->elementStart('fb:if-section-not-added', array('section' => 'profile')); + $this->elementStart('span', array('id' => 'add_to_profile')); + $this->element('fb:add-section-button', array('section' => 'profile')); + $this->elementEnd('span'); + $this->elementEnd('fb:if-section-not-added'); + + } + + // Make this into a widget later + function showLocalNav() + { + $this->elementStart('ul', array('class' => 'nav')); + + $this->elementStart('li', array('class' => + ($this->action == 'facebookhome') ? 'current' : 'facebook_home')); + $this->element('a', + array('href' => 'index.php', 'title' => _('Home')), _('Home')); + $this->elementEnd('li'); + + if (common_config('invite', 'enabled')) { + $this->elementStart('li', + array('class' => + ($this->action == 'facebookinvite') ? 'current' : 'facebook_invite')); + $this->element('a', + array('href' => 'invite.php', 'title' => _('Invite')), _('Invite')); + $this->elementEnd('li'); + } + + $this->elementStart('li', + array('class' => + ($this->action == 'facebooksettings') ? 'current' : 'facebook_settings')); + $this->element('a', + array('href' => 'settings.php', + 'title' => _('Settings')), _('Settings')); + $this->elementEnd('li'); + + $this->elementEnd('ul'); + } + + /** + * Show header of the page. + * + * @return nothing + */ + function showHeader() + { + $this->elementStart('div', array('id' => 'header')); + $this->showLogo(); + $this->showNoticeForm(); + $this->elementEnd('div'); + } + + /** + * Show page, a template method. + * + * @return nothing + */ + function showPage($error = null, $success = null) + { + $this->startHTML(); + $this->showHead($error, $success); + $this->showBody(); + $this->endHTML(); + } + + function showInstructions() + { + + $this->elementStart('div', array('class' => 'facebook_guide')); + + $this->elementStart('dl', array('class' => 'system_notice')); + $this->element('dt', null, 'Page Notice'); + + $loginmsg_part1 = _('To use the %s Facebook Application you need to login ' . + 'with your username and password. Don\'t have a username yet? '); + $loginmsg_part2 = _(' a new account.'); + + $this->elementStart('dd'); + $this->elementStart('p'); + $this->text(sprintf($loginmsg_part1, common_config('site', 'name'))); + $this->element('a', + array('href' => common_local_url('register')), _('Register')); + $this->text($loginmsg_part2); + $this->elementEnd('p'); + $this->elementEnd('dd'); + + $this->elementEnd('dl'); + $this->elementEnd('div'); + } + + function showLoginForm($msg = null) + { + + $this->elementStart('div', array('id' => 'content')); + $this->element('h1', null, _('Login')); + + if ($msg) { + $this->element('fb:error', array('message' => $msg)); + } + + $this->showInstructions(); + + $this->elementStart('div', array('id' => 'content_inner')); + + $this->elementStart('form', array('method' => 'post', + 'class' => 'form_settings', + 'id' => 'login', + 'action' => 'index.php')); + + $this->elementStart('fieldset'); + + $this->elementStart('ul', array('class' => 'form_datas')); + $this->elementStart('li'); + $this->input('nickname', _('Nickname')); + $this->elementEnd('li'); + $this->elementStart('li'); + $this->password('password', _('Password')); + $this->elementEnd('li'); + $this->elementEnd('ul'); + + $this->submit('submit', _('Login')); + $this->elementEnd('fieldset'); + $this->elementEnd('form'); + + $this->elementStart('p'); + $this->element('a', array('href' => common_local_url('recoverpassword')), + _('Lost or forgotten password?')); + $this->elementEnd('p'); + + $this->elementEnd('div'); + $this->elementEnd('div'); + + } + + function updateProfileBox($notice) + { + + // Need to include inline CSS for styling the Profile box + + $app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url')); + $icon_url = $app_props['icon_url']; + + $style = ''; + + $this->xw->openMemory(); + + $item = new FacebookProfileBoxNotice($notice, $this); + $item->show(); + + $fbml = "$style " . $this->xw->outputMemory(false) . ""; + $fbml .= "$style " . $this->xw->outputMemory(false) . ""; + + $fbml_main = "$style " . $this->xw->outputMemory(false) . ""; + + $this->facebook->api_client->profile_setFBML(null, $this->fbuid, $fbml, null, null, $fbml_main); + + $this->xw->openURI('php://output'); + } + + /** + * Generate pagination links + * + * @param boolean $have_before is there something before? + * @param boolean $have_after is there something after? + * @param integer $page current page + * @param string $action current action + * @param array $args rest of query arguments + * + * @return nothing + */ + function pagination($have_before, $have_after, $page, $action, $args=null) + { + // Does a little before-after block for next/prev page + if ($have_before || $have_after) { + $this->elementStart('div', array('class' => 'pagination')); + $this->elementStart('dl', null); + $this->element('dt', null, _('Pagination')); + $this->elementStart('dd', null); + $this->elementStart('ul', array('class' => 'nav')); + } + if ($have_before) { + $pargs = array('page' => $page-1); + $newargs = $args ? array_merge($args, $pargs) : $pargs; + $this->elementStart('li', array('class' => 'nav_prev')); + $this->element('a', array('href' => "$this->app_uri/$action?page=$newargs[page]", 'rel' => 'prev'), + _('After')); + $this->elementEnd('li'); + } + if ($have_after) { + $pargs = array('page' => $page+1); + $newargs = $args ? array_merge($args, $pargs) : $pargs; + $this->elementStart('li', array('class' => 'nav_next')); + $this->element('a', array('href' => "$this->app_uri/$action?page=$newargs[page]", 'rel' => 'next'), + _('Before')); + $this->elementEnd('li'); + } + if ($have_before || $have_after) { + $this->elementEnd('ul'); + $this->elementEnd('dd'); + $this->elementEnd('dl'); + $this->elementEnd('div'); + } + } + + function saveNewNotice() + { + + $user = $this->flink->getUser(); + + $content = $this->trimmed('status_textarea'); + + if (!$content) { + $this->showPage(_('No notice content!')); + return; + } else { + $content_shortened = common_shorten_links($content); + + if (Notice::contentTooLong($content_shortened)) { + $this->showPage(sprintf(_('That\'s too long. Max notice size is %d chars.'), + Notice::maxContent())); + return; + } + } + + $inter = new CommandInterpreter(); + + $cmd = $inter->handle_command($user, $content_shortened); + + if ($cmd) { + + // XXX fix this + + $cmd->execute(new WebChannel()); + return; + } + + $replyto = $this->trimmed('inreplyto'); + + try { + $notice = Notice::saveNew($user->id, $content, + 'web', 1, ($replyto == 'false') ? null : $replyto); + } catch (Exception $e) { + $this->showPage($e->getMessage()); + return; + } + + common_broadcast_notice($notice); + + // Also update the user's Facebook status + facebookBroadcastNotice($notice); + + } + +} + +class FacebookNoticeForm extends NoticeForm +{ + + var $post_action = null; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param string $action action to return to, if any + * @param string $content content to pre-fill + */ + + function __construct($out=null, $action=null, $content=null, + $post_action=null, $user=null) + { + parent::__construct($out, $action, $content, $user); + $this->post_action = $post_action; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return $this->post_action; + } + +} + +class FacebookNoticeList extends NoticeList +{ + + /** + * constructor + * + * @param Notice $notice stream of notices from DB_DataObject + */ + + function __construct($notice, $out=null) + { + parent::__construct($notice, $out); + } + + /** + * show the list of notices + * + * "Uses up" the stream by looping through it. So, probably can't + * be called twice on the same list. + * + * @return int count of notices listed. + */ + + function show() + { + $this->out->elementStart('div', array('id' =>'notices_primary')); + $this->out->element('h2', null, _('Notices')); + $this->out->elementStart('ul', array('class' => 'notices')); + + $cnt = 0; + + while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) { + $cnt++; + + if ($cnt > NOTICES_PER_PAGE) { + break; + } + + $item = $this->newListItem($this->notice); + $item->show(); + } + + $this->out->elementEnd('ul'); + $this->out->elementEnd('div'); + + return $cnt; + } + + /** + * returns a new list item for the current notice + * + * Overridden to return a Facebook specific list item. + * + * @param Notice $notice the current notice + * + * @return FacebookNoticeListItem a list item for displaying the notice + * formatted for display in the Facebook App. + */ + + function newListItem($notice) + { + return new FacebookNoticeListItem($notice, $this); + } + +} + +class FacebookNoticeListItem extends NoticeListItem +{ + + /** + * constructor + * + * Also initializes the profile attribute. + * + * @param Notice $notice The notice we'll display + */ + + function __construct($notice, $out=null) + { + parent::__construct($notice, $out); + } + + /** + * recipe function for displaying a single notice in the Facebook App. + * + * Overridden to strip out some of the controls that we don't + * want to be available. + * + * @return void + */ + + function show() + { + $this->showStart(); + $this->showNotice(); + $this->showNoticeInfo(); + + // XXX: Need to update to show attachements and controls + + $this->showEnd(); + } + +} + +class FacebookProfileBoxNotice extends FacebookNoticeListItem +{ + + /** + * constructor + * + * Also initializes the profile attribute. + * + * @param Notice $notice The notice we'll display + */ + + function __construct($notice, $out=null) + { + parent::__construct($notice, $out); + } + + /** + * Recipe function for displaying a single notice in the + * Facebook App profile notice box + * + * @return void + */ + + function show() + { + $this->showNotice(); + $this->showNoticeInfo(); + $this->showAppLink(); + } + + function showAppLink() + { + + $this->facebook = getFacebook(); + + $app_props = $this->facebook->api_client->Admin_getAppProperties( + array('canvas_name', 'application_name')); + + $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name']; + $this->app_name = $app_props['application_name']; + + $this->out->elementStart('a', array('id' => 'facebook_statusnet_app', + 'href' => $this->app_uri)); + $this->out->text($this->app_name); + $this->out->elementEnd('a'); + } + +} diff --git a/plugins/Facebook/facebookhome.php b/plugins/Facebook/facebookhome.php new file mode 100644 index 000000000..91c0cc6b8 --- /dev/null +++ b/plugins/Facebook/facebookhome.php @@ -0,0 +1,277 @@ +. + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php'; + +class FacebookhomeAction extends FacebookAction +{ + + var $page = null; + + function prepare($argarray) + { + parent::prepare($argarray); + + $this->page = $this->trimmed('page'); + + if (!$this->page) { + $this->page = 1; + } + + return true; + } + + function handle($args) + { + parent::handle($args); + + // If the user has opted not to initially allow the app to have + // Facebook status update permission, store that preference. Only + // promt the user the first time she uses the app + if ($this->arg('skip') || $args['fb_sig_request_method'] == 'GET') { + $this->facebook->api_client->data_setUserPreference( + FACEBOOK_PROMPTED_UPDATE_PREF, 'true'); + } + + if ($this->flink) { + + $this->user = $this->flink->getUser(); + + // If this is the first time the user has started the app + // prompt for Facebook status update permission + if (!$this->facebook->api_client->users_hasAppPermission('publish_stream')) { + + if ($this->facebook->api_client->data_getUserPreference( + FACEBOOK_PROMPTED_UPDATE_PREF) != 'true') { + $this->getUpdatePermission(); + return; + } + } + + // Make sure the user's profile box has the lastest notice + $notice = $this->user->getCurrentNotice(); + if ($notice) { + $this->updateProfileBox($notice); + } + + if ($this->arg('status_submit') == 'Send') { + $this->saveNewNotice(); + } + + // User is authenticated and has already been prompted once for + // Facebook status update permission? Then show the main page + // of the app + $this->showPage(); + + } else { + + // User hasn't authenticated yet, prompt for creds + $this->login(); + } + + } + + function login() + { + + $this->showStylesheets(); + + $nickname = common_canonical_nickname($this->trimmed('nickname')); + $password = $this->arg('password'); + + $msg = null; + + if ($nickname) { + + if (common_check_user($nickname, $password)) { + + $user = User::staticGet('nickname', $nickname); + + if (!$user) { + $this->showLoginForm(_("Server error - couldn't get user!")); + } + + $flink = DB_DataObject::factory('foreign_link'); + $flink->user_id = $user->id; + $flink->foreign_id = $this->fbuid; + $flink->service = FACEBOOK_SERVICE; + $flink->created = common_sql_now(); + $flink->set_flags(true, false, false, false); + + $flink_id = $flink->insert(); + + // XXX: Do some error handling here + + $this->setDefaults(); + + $this->getUpdatePermission(); + return; + + } else { + $msg = _('Incorrect username or password.'); + } + } + + $this->showLoginForm($msg); + $this->showFooter(); + + } + + function setDefaults() + { + $this->facebook->api_client->data_setUserPreference( + FACEBOOK_PROMPTED_UPDATE_PREF, 'false'); + } + + function showNoticeForm() + { + $post_action = "$this->app_uri/index.php"; + + $notice_form = new FacebookNoticeForm($this, $post_action, null, + $post_action, $this->user); + $notice_form->show(); + } + + function title() + { + if ($this->page > 1) { + return sprintf(_("%s and friends, page %d"), $this->user->nickname, $this->page); + } else { + return sprintf(_("%s and friends"), $this->user->nickname); + } + } + + function showContent() + { + $notice = $this->user->noticeInbox(($this->page-1) * NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); + + $nl = new NoticeList($notice, $this); + + $cnt = $nl->show(); + + $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, + $this->page, 'index.php', array('nickname' => $this->user->nickname)); + } + + function showNoticeList($notice) + { + + $nl = new NoticeList($notice, $this); + return $nl->show(); + } + + function getUpdatePermission() { + + $this->showStylesheets(); + + $this->elementStart('div', array('class' => 'facebook_guide')); + + $instructions = sprintf(_('If you would like the %s app to automatically update ' . + 'your Facebook status with your latest notice, you need ' . + 'to give it permission.'), $this->app_name); + + $this->elementStart('p'); + $this->element('span', array('id' => 'permissions_notice'), $instructions); + $this->elementEnd('p'); + + $this->elementStart('form', array('method' => 'post', + 'action' => "index.php", + 'id' => 'facebook-skip-permissions')); + + $this->elementStart('ul', array('id' => 'fb-permissions-list')); + $this->elementStart('li', array('id' => 'fb-permissions-item')); + + $next = urlencode("$this->app_uri/index.php"); + $api_key = common_config('facebook', 'apikey'); + + $auth_url = 'http://www.facebook.com/authorize.php?api_key=' . + $api_key . '&v=1.0&ext_perm=publish_stream&next=' . $next . + '&next_cancel=' . $next . '&submit=skip'; + + $this->elementStart('span', array('class' => 'facebook-button')); + $this->element('a', array('href' => $auth_url), + sprintf(_('Okay, do it!'), $this->app_name)); + $this->elementEnd('span'); + + $this->elementEnd('li'); + + $this->elementStart('li', array('id' => 'fb-permissions-item')); + $this->submit('skip', _('Skip')); + $this->elementEnd('li'); + $this->elementEnd('ul'); + + $this->elementEnd('form'); + $this->elementEnd('div'); + + } + + /** + * Generate pagination links + * + * @param boolean $have_before is there something before? + * @param boolean $have_after is there something after? + * @param integer $page current page + * @param string $action current action + * @param array $args rest of query arguments + * + * @return nothing + */ + function pagination($have_before, $have_after, $page, $action, $args=null) + { + + // Does a little before-after block for next/prev page + + // XXX: Fix so this uses common_local_url() if possible. + + if ($have_before || $have_after) { + $this->elementStart('div', array('class' => 'pagination')); + $this->elementStart('dl', null); + $this->element('dt', null, _('Pagination')); + $this->elementStart('dd', null); + $this->elementStart('ul', array('class' => 'nav')); + } + if ($have_before) { + $pargs = array('page' => $page-1); + $newargs = $args ? array_merge($args, $pargs) : $pargs; + $this->elementStart('li', array('class' => 'nav_prev')); + $this->element('a', array('href' => "$action?page=$newargs[page]", 'rel' => 'prev'), + _('After')); + $this->elementEnd('li'); + } + if ($have_after) { + $pargs = array('page' => $page+1); + $newargs = $args ? array_merge($args, $pargs) : $pargs; + $this->elementStart('li', array('class' => 'nav_next')); + $this->element('a', array('href' => "$action?page=$newargs[page]", 'rel' => 'next'), + _('Before')); + $this->elementEnd('li'); + } + if ($have_before || $have_after) { + $this->elementEnd('ul'); + $this->elementEnd('dd'); + $this->elementEnd('dl'); + $this->elementEnd('div'); + } + } + +} diff --git a/plugins/Facebook/facebookinvite.php b/plugins/Facebook/facebookinvite.php new file mode 100644 index 000000000..ecda1717c --- /dev/null +++ b/plugins/Facebook/facebookinvite.php @@ -0,0 +1,145 @@ +. + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php'; + +class FacebookinviteAction extends FacebookAction +{ + + function handle($args) + { + parent::handle($args); + $this->showForm(); + } + + /** + * Wrapper for showing a page + * + * Stores an error and shows the page + * + * @param string $error Error, if any + * + * @return void + */ + + function showForm($error=null) + { + $this->error = $error; + $this->showPage(); + } + + /** + * Show the page content + * + * Either shows the registration form or, if registration was successful, + * instructions for using the site. + * + * @return void + */ + + function showContent() + { + if ($this->arg('ids')) { + $this->showSuccessContent(); + } else { + $this->showFormContent(); + } + } + + function showSuccessContent() + { + + $this->element('h2', null, sprintf(_('Thanks for inviting your friends to use %s'), + common_config('site', 'name'))); + $this->element('p', null, _('Invitations have been sent to the following users:')); + + $friend_ids = $_POST['ids']; // XXX: Hmm... is this the best way to access the list? + + $this->elementStart('ul', array('id' => 'facebook-friends')); + + foreach ($friend_ids as $friend) { + $this->elementStart('li'); + $this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square')); + $this->element('fb:name', array('uid' => $friend, + 'capitalize' => 'true')); + $this->elementEnd('li'); + } + + $this->elementEnd("ul"); + + } + + function showFormContent() + { + $content = sprintf(_('You have been invited to %s'), common_config('site', 'name')) . + htmlentities(''); + + $this->elementStart('fb:request-form', array('action' => 'invite.php', + 'method' => 'post', + 'invite' => 'true', + 'type' => common_config('site', 'name'), + 'content' => $content)); + $this->hidden('invite', 'true'); + $actiontext = sprintf(_('Invite your friends to use %s'), common_config('site', 'name')); + + $multi_params = array('showborder' => 'false'); + $multi_params['actiontext'] = $actiontext; + $multi_params['bypass'] = 'cancel'; + + // Get a list of users who are already using the app for exclusion + $exclude_ids = $this->facebook->api_client->friends_getAppUsers(); + $exclude_ids_csv = null; + + // fbml needs these as a csv string, not an array + if ($exclude_ids) { + $exclude_ids_csv = implode(',', $exclude_ids); + $multi_params['exclude_ids'] = $exclude_ids_csv; + } + + $this->element('fb:multi-friend-selector', $multi_params); + $this->elementEnd('fb:request-form'); + + if ($exclude_ids) { + + $this->element('h2', null, sprintf(_('Friends already using %s:'), + common_config('site', 'name'))); + $this->elementStart('ul', array('id' => 'facebook-friends')); + + foreach ($exclude_ids as $friend) { + $this->elementStart('li'); + $this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square')); + $this->element('fb:name', array('uid' => $friend, + 'capitalize' => 'true')); + $this->elementEnd('li'); + } + + $this->elementEnd("ul"); + } + } + + function title() + { + return sprintf(_('Send invitations')); + } + +} diff --git a/plugins/Facebook/facebooklogin.php b/plugins/Facebook/facebooklogin.php new file mode 100644 index 000000000..f77aecca3 --- /dev/null +++ b/plugins/Facebook/facebooklogin.php @@ -0,0 +1,99 @@ +. + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php'; + +class FacebookinviteAction extends FacebookAction +{ + + function handle($args) + { + parent::handle($args); + + $this->error = $error; + + if ($this->flink) { + if (!$this->facebook->api_client->users_hasAppPermission('publish_stream') && + $this->facebook->api_client->data_getUserPreference( + FACEBOOK_PROMPTED_UPDATE_PREF) == 'true') { + + echo '

REDIRECT TO HOME

'; + } + } else { + $this->showPage(); + } + } + + function showContent() + { + + // If the user has opted not to initially allow the app to have + // Facebook status update permission, store that preference. Only + // promt the user the first time she uses the app + if ($this->arg('skip')) { + $this->facebook->api_client->data_setUserPreference( + FACEBOOK_PROMPTED_UPDATE_PREF, 'true'); + } + + if ($this->flink) { + + $this->user = $this->flink->getUser(); + + // If this is the first time the user has started the app + // prompt for Facebook status update permission + if (!$this->facebook->api_client->users_hasAppPermission('publish_stream')) { + + if ($this->facebook->api_client->data_getUserPreference( + FACEBOOK_PROMPTED_UPDATE_PREF) != 'true') { + $this->getUpdatePermission(); + return; + } + } + + } else { + $this->showLoginForm(); + } + + } + + function showSuccessContent() + { + + } + + function showFormContent() + { + + } + + function title() + { + return sprintf(_('Login')); + } + + function redirectHome() + { + + } + +} diff --git a/plugins/Facebook/facebookqueuehandler.php b/plugins/Facebook/facebookqueuehandler.php new file mode 100755 index 000000000..30de59efb --- /dev/null +++ b/plugins/Facebook/facebookqueuehandler.php @@ -0,0 +1,74 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); + +$shortoptions = 'i::'; +$longoptions = array('id::'); + +$helptext = <<log(LOG_INFO, "INITIALIZE"); + return true; + } + + function handle_notice($notice) + { + return facebookBroadcastNotice($notice); + } + + function finish() + { + } + +} + +if (have_option('i')) { + $id = get_option_value('i'); +} else if (have_option('--id')) { + $id = get_option_value('--id'); +} else if (count($args) > 0) { + $id = $args[0]; +} else { + $id = null; +} + +$handler = new FacebookQueueHandler($id); + +$handler->runOnce(); diff --git a/plugins/Facebook/facebookremove.php b/plugins/Facebook/facebookremove.php new file mode 100644 index 000000000..8531a8e6e --- /dev/null +++ b/plugins/Facebook/facebookremove.php @@ -0,0 +1,69 @@ +. + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php'; + +class FacebookremoveAction extends FacebookAction +{ + + function handle($args) + { + parent::handle($args); + + $secret = common_config('facebook', 'secret'); + + $sig = ''; + + ksort($_POST); + + foreach ($_POST as $key => $val) { + if (substr($key, 0, 7) == 'fb_sig_') { + $sig .= substr($key, 7) . '=' . $val; + } + } + + $sig .= $secret; + $verify = md5($sig); + + if ($verify == $this->arg('fb_sig')) { + + $flink = Foreign_link::getByForeignID($this->arg('fb_sig_user'), 2); + + common_debug("Removing foreign link to Facebook - local user ID: $flink->user_id, Facebook ID: $flink->foreign_id"); + + $result = $flink->delete(); + + if (!$result) { + common_log_db_error($flink, 'DELETE', __FILE__); + $this->serverError(_('Couldn\'t remove Facebook user.')); + return; + } + + } else { + # Someone bad tried to remove facebook link? + common_log(LOG_ERR, "Someone from $_SERVER[REMOTE_ADDR] " . + 'unsuccessfully tried to remove a foreign link to Facebook!'); + } + } + +} diff --git a/plugins/Facebook/facebooksettings.php b/plugins/Facebook/facebooksettings.php new file mode 100644 index 000000000..4bfdfc0ef --- /dev/null +++ b/plugins/Facebook/facebooksettings.php @@ -0,0 +1,159 @@ +. + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR . '/lib/facebookaction.php'; + +class FacebooksettingsAction extends FacebookAction +{ + + function handle($args) + { + parent::handle($args); + $this->showPage(); + } + + /** + * Show the page content + * + * Either shows the registration form or, if registration was successful, + * instructions for using the site. + * + * @return void + */ + + function showContent() + { + if ($this->arg('save')) { + $this->saveSettings(); + } else { + $this->showForm(); + } + } + + function saveSettings() { + + $noticesync = $this->arg('noticesync'); + $replysync = $this->arg('replysync'); + $prefix = $this->trimmed('prefix'); + + $original = clone($this->flink); + $this->flink->set_flags($noticesync, $replysync, false, false); + $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) { + $this->showForm(_('There was a problem saving your sync preferences!')); + } else { + $this->showForm(_('Sync preferences saved.'), true); + } + } + + function showForm($msg = null, $success = false) { + + if ($msg) { + if ($success) { + $this->element('fb:success', array('message' => $msg)); + } else { + $this->element('fb:error', array('message' => $msg)); + } + } + + if ($this->facebook->api_client->users_hasAppPermission('publish_stream')) { + + $this->elementStart('form', array('method' => 'post', + 'id' => 'facebook_settings')); + + $this->elementStart('ul', 'form_data'); + + $this->elementStart('li'); + + $this->checkbox('noticesync', _('Automatically update my Facebook status with my notices.'), + ($this->flink) ? ($this->flink->noticesync & FOREIGN_NOTICE_SEND) : true); + + $this->elementEnd('li'); + + $this->elementStart('li'); + + $this->checkbox('replysync', _('Send "@" replies to Facebook.'), + ($this->flink) ? ($this->flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) : true); + + $this->elementEnd('li'); + + $this->elementStart('li'); + + $prefix = trim($this->facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX)); + + $this->input('prefix', _('Prefix'), + ($prefix) ? $prefix : null, + _('A string to prefix notices with.')); + + $this->elementEnd('li'); + + $this->elementStart('li'); + + $this->submit('save', _('Save')); + + $this->elementEnd('li'); + + $this->elementEnd('ul'); + + $this->elementEnd('form'); + + } else { + + $instructions = sprintf(_('If you would like %s to automatically update ' . + 'your Facebook status with your latest notice, you need ' . + 'to give it permission.'), $this->app_name); + + $this->elementStart('p'); + $this->element('span', array('id' => 'permissions_notice'), $instructions); + $this->elementEnd('p'); + + $this->elementStart('ul', array('id' => 'fb-permissions-list')); + $this->elementStart('li', array('id' => 'fb-permissions-item')); + $this->elementStart('fb:prompt-permission', array('perms' => 'publish_stream', + 'next_fbjs' => 'document.setLocation(\'' . "$this->app_uri/settings.php" . '\')')); + $this->element('span', array('class' => 'facebook-button'), + sprintf(_('Allow %s to update my Facebook status'), common_config('site', 'name'))); + $this->elementEnd('fb:prompt-permission'); + $this->elementEnd('li'); + $this->elementEnd('ul'); + } + + } + + function title() + { + return _('Sync preferences'); + } + +} diff --git a/plugins/Facebook/facebookutil.php b/plugins/Facebook/facebookutil.php new file mode 100644 index 000000000..9817837f7 --- /dev/null +++ b/plugins/Facebook/facebookutil.php @@ -0,0 +1,260 @@ +. + */ + +require_once INSTALLDIR . '/extlib/facebook/facebook.php'; +require_once INSTALLDIR . '/plugins/Facebook/facebookaction.php'; +require_once INSTALLDIR . '/lib/noticelist.php'; + +define("FACEBOOK_SERVICE", 2); // Facebook is foreign_service ID 2 +define("FACEBOOK_NOTICE_PREFIX", 1); +define("FACEBOOK_PROMPTED_UPDATE_PREF", 2); + +function getFacebook() +{ + static $facebook = null; + + $apikey = common_config('facebook', 'apikey'); + $secret = common_config('facebook', 'secret'); + + if ($facebook === null) { + $facebook = new Facebook($apikey, $secret); + } + + if (empty($facebook)) { + common_log(LOG_ERR, 'Could not make new Facebook client obj!', + __FILE__); + } + + return $facebook; +} + +function isFacebookBound($notice, $flink) { + + if (empty($flink)) { + return false; + } + + // Avoid a loop + + if ($notice->source == 'Facebook') { + common_log(LOG_INFO, "Skipping notice $notice->id because its " . + 'source is Facebook.'); + return false; + } + + // If the user does not want to broadcast to Facebook, move along + + if (!($flink->noticesync & FOREIGN_NOTICE_SEND == FOREIGN_NOTICE_SEND)) { + common_log(LOG_INFO, "Skipping notice $notice->id " . + 'because user has FOREIGN_NOTICE_SEND bit off.'); + return false; + } + + // If it's not a reply, or if the user WANTS to send @-replies, + // then, yeah, it can go to Facebook. + + if (!preg_match('/@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) || + ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY)) { + return true; + } + + return false; + +} + +function facebookBroadcastNotice($notice) +{ + $facebook = getFacebook(); + $flink = Foreign_link::getByUserID($notice->profile_id, FACEBOOK_SERVICE); + + if (isFacebookBound($notice, $flink)) { + + // Okay, we're good to go, update the FB status + + $status = null; + $fbuid = $flink->foreign_id; + $user = $flink->getUser(); + $attachments = $notice->attachments(); + + try { + + // Get the status 'verb' (prefix) the user has set + + // XXX: Does this call count against our per user FB request limit? + // If so we should consider storing verb elsewhere or not storing + + $prefix = trim($facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX, + $fbuid)); + + $status = "$prefix $notice->content"; + + $can_publish = $facebook->api_client->users_hasAppPermission('publish_stream', + $fbuid); + + $can_update = $facebook->api_client->users_hasAppPermission('status_update', + $fbuid); + if (!empty($attachments) && $can_publish == 1) { + $fbattachment = format_attachments($attachments); + $facebook->api_client->stream_publish($status, $fbattachment, + null, null, $fbuid); + common_log(LOG_INFO, + "Posted notice $notice->id w/attachment " . + "to Facebook user's stream (fbuid = $fbuid)."); + } elseif ($can_update == 1 || $can_publish == 1) { + $facebook->api_client->users_setStatus($status, $fbuid, false, true); + common_log(LOG_INFO, + "Posted notice $notice->id to Facebook " . + "as a status update (fbuid = $fbuid)."); + } else { + $msg = "Not sending notice $notice->id to Facebook " . + "because user $user->nickname hasn't given the " . + 'Facebook app \'status_update\' or \'publish_stream\' permission.'; + common_log(LOG_WARNING, $msg); + } + + // Finally, attempt to update the user's profile box + + if ($can_publish == 1 || $can_update == 1) { + updateProfileBox($facebook, $flink, $notice); + } + + } catch (FacebookRestClientException $e) { + + $code = $e->getCode(); + + common_log(LOG_WARNING, 'Facebook returned error code ' . + $code . ': ' . $e->getMessage()); + common_log(LOG_WARNING, + 'Unable to update Facebook status for ' . + "$user->nickname (user id: $user->id)!"); + + if ($code == 200 || $code == 250) { + + // 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; + +} + +function updateProfileBox($facebook, $flink, $notice) { + $fbaction = new FacebookAction($output = 'php://output', + $indent = true, $facebook, $flink); + $fbaction->updateProfileBox($notice); +} + +function format_attachments($attachments) +{ + $fbattachment = array(); + $fbattachment['media'] = array(); + + foreach($attachments as $attachment) + { + if($enclosure = $attachment->getEnclosure()){ + $fbmedia = get_fbmedia_for_attachment($enclosure); + }else{ + $fbmedia = get_fbmedia_for_attachment($attachment); + } + if($fbmedia){ + $fbattachment['media'][]=$fbmedia; + }else{ + $fbattachment['name'] = ($attachment->title ? + $attachment->title : $attachment->url); + $fbattachment['href'] = $attachment->url; + } + } + if(count($fbattachment['media'])>0){ + unset($fbattachment['name']); + unset($fbattachment['href']); + } + return $fbattachment; +} + +/** +* given an File objects, returns an associative array suitable for Facebook media +*/ +function get_fbmedia_for_attachment($attachment) +{ + $fbmedia = array(); + + if (strncmp($attachment->mimetype, 'image/', strlen('image/')) == 0) { + $fbmedia['type'] = 'image'; + $fbmedia['src'] = $attachment->url; + $fbmedia['href'] = $attachment->url; + } else if ($attachment->mimetype == 'audio/mpeg') { + $fbmedia['type'] = 'mp3'; + $fbmedia['src'] = $attachment->url; + }else if ($attachment->mimetype == 'application/x-shockwave-flash') { + $fbmedia['type'] = 'flash'; + + // http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29 + // says that imgsrc is required... but we have no value to put in it + // $fbmedia['imgsrc']=''; + + $fbmedia['swfsrc'] = $attachment->url; + }else{ + return false; + } + return $fbmedia; +} + +function remove_facebook_app($flink) +{ + + $user = $flink->getUser(); + + common_log(LOG_INFO, 'Removing Facebook App Foreign link for ' . + "user $user->nickname (user id: $user->id)."); + + $result = $flink->delete(); + + if (empty($result)) { + common_log(LOG_ERR, 'Could not remove Facebook App ' . + "Foreign_link for $user->nickname (user id: $user->id)!"); + common_log_db_error($flink, 'DELETE', __FILE__); + } + + // Notify the user that we are removing their FB app access + + $result = mail_facebook_app_removed($user); + + if (!$result) { + + $msg = 'Unable to send email to notify ' . + "$user->nickname (user id: $user->id) " . + 'that their Facebook app link was ' . + 'removed!'; + + common_log(LOG_WARNING, $msg); + } + +} diff --git a/scripts/facebookqueuehandler.php b/scripts/facebookqueuehandler.php deleted file mode 100755 index e13ac4e85..000000000 --- a/scripts/facebookqueuehandler.php +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env php -. - */ - -define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); - -$shortoptions = 'i::'; -$longoptions = array('id::'); - -$helptext = <<log(LOG_INFO, "INITIALIZE"); - return true; - } - - function handle_notice($notice) - { - return facebookBroadcastNotice($notice); - } - - function finish() - { - } - -} - -if (have_option('i')) { - $id = get_option_value('i'); -} else if (have_option('--id')) { - $id = get_option_value('--id'); -} else if (count($args) > 0) { - $id = $args[0]; -} else { - $id = null; -} - -$handler = new FacebookQueueHandler($id); - -$handler->runOnce(); diff --git a/scripts/getvaliddaemons.php b/scripts/getvaliddaemons.php index 7caea1bb7..99ad41b37 100755 --- a/scripts/getvaliddaemons.php +++ b/scripts/getvaliddaemons.php @@ -39,7 +39,6 @@ $daemons = array(); $daemons[] = INSTALLDIR.'/scripts/pluginqueuehandler.php'; $daemons[] = INSTALLDIR.'/scripts/ombqueuehandler.php'; -$daemons[] = INSTALLDIR.'/scripts/facebookqueuehandler.php'; $daemons[] = INSTALLDIR.'/scripts/pingqueuehandler.php'; if(common_config('xmpp','enabled')) { -- cgit v1.2.3-54-g00ecf